Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ Format basiert auf [Keep a Changelog](https://keepachangelog.com/de/1.1.0/).
- 10 neue Tests (`tests/test_gui_freeze.py`) messen die Blockadezeit der Ereignisschleife bei künstlich verzögerten Laufwerken.
- **Laufwerkswechsel ohne Hänger (de)**: Seitenleiste, Adressleiste, Tastatur und Favoriten wechseln über denselben Weg. Unbekannte Pfade werden im Hintergrund auf Erreichbarkeit geprüft (Hinweis „wird geladen …“, alte Ansicht bleibt bedienbar, nach 15 s „Keine Antwort – Laufwerk reagiert nicht“, neuere Navigation hat Vorrang). Die Startseite jedes Laufwerks wird nach dem Start im Hintergrund vorgeladen und vorgehalten (gedrosselt, lokale Platten zuerst, dann Wechsel- und Netzlaufwerke, mit Timeout); ein Klick darauf zeigt sie sofort.
- **Nicht erreichbares Laufwerk (de)**: Der Wechsel zeigt sofort eine leere Seite mit dem Ziel in der Adressleiste und dem Hinweis „wird geladen …“ bzw. „Laufwerk nicht erreichbar“ / „Keine Antwort – Laufwerk reagiert nicht“; der vorige Ordner bleibt nicht stehen und der Hinweis liegt nie über Einträgen. „Zurück“ funktioniert weiter, ein erneuter Klick prüft erneut. Bereits bekannte Wechsel-/Netzlaufwerke zeigen den vorgehaltenen Stand sofort und werden im Hintergrund nachgeprüft; schlägt das fehl, erscheint die leere Seite.
- **Stale Prüfung (de)**: Jede Navigation macht ältere Erreichbarkeitsprüfungen ungültig; ein später Fehlschlag oder Timeout eines früheren Ziels (z. B. E:) schaltet die inzwischen gewählte Ansicht (z. B. C:) nicht mehr auf „Laufwerk nicht erreichbar“ um.

### Fix: GUI no longer freezes on slow drives (en)
- **Folder tree**: expanding a folder lists subfolders in the background. First time shows "loading …", afterwards the last known state at once; the fresh list replaces it only when complete. Answers for collapsed nodes are discarded; a folder silent for 15 s shows a hint instead of hanging.
Expand All @@ -24,6 +25,7 @@ Format basiert auf [Keep a Changelog](https://keepachangelog.com/de/1.1.0/).
- 10 new tests (`tests/test_gui_freeze.py`) measure event-loop blocking with artificially delayed drives.
- **Drive switching without hangs (en)**: sidebar, address bar, keyboard and favorites share one path. Unknown paths are checked for reachability in the background ("loading …" hint, previous view stays usable, after 15 s "No response – drive is not answering", newer navigation wins). Each drive's start page is preloaded and kept ready in the background after startup (throttled, local disks first, then removable and network drives, with timeout); a click shows it at once.
- **Unreachable drive (en)**: switching shows an empty page at once with the target in the address bar and the hint "loading …" / "Drive not reachable" / "No response – drive is not answering"; the previous folder no longer stays and the hint never covers entries. Back keeps working, another click checks again. Known removable/network drives show the kept state at once and are re-checked in the background; if that fails the empty page appears.
- **Stale check (en)**: every navigation invalidates older reachability checks; a late failure or timeout of an earlier target (e.g. E:) no longer switches the view you moved on to (e.g. C:) to "Drive not reachable".

### Native ZIP- & Archiv-Suite (2026-10-08, TW-EP-12)
- **Core-Archiv-Service (`src/core/archive_service.py`)**:
Expand Down
4 changes: 2 additions & 2 deletions releases/windowsstore/v1.0.9/release-notes.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{
"de-de": "ExplorerPro 1.0.9\n• Die Oberfläche friert bei langsamen Laufwerken (Netzwerk, Google Drive, OneDrive-Platzhalter, leere Kartenleser) nicht mehr ein: Ordner im Baum und die Ordner-Vorschau laden im Hintergrund.\n• Es erscheint sofort der zuletzt bekannte Stand (auch die Speicherbelegung beim Start); neue Werte ersetzen ihn, sobald sie vollständig vorliegen.\n• Die Speicherbelegung wird seltener automatisch geprüft; die Schaltfläche aktualisiert auf Wunsch.\n• Der Wechsel zwischen Laufwerken hängt nicht mehr: Die Startseite jedes Laufwerks wird im Hintergrund vorgeladen und beim Klick sofort angezeigt.\n• Ist ein Laufwerk nicht erreichbar, zeigt ExplorerPro sofort eine leere Seite mit Hinweis statt des vorigen Ordners.\n• Neu: ZIP-Archive erstellen, durchsuchen, auf Integrität prüfen und sicher entpacken.",
"en-us": "ExplorerPro 1.0.9\n• The window no longer freezes on slow drives (network, Google Drive, OneDrive placeholders, empty card readers): folders in the tree and the folder preview load in the background.\n• The last known state (including drive capacity at startup) is shown immediately; new values replace it once they are complete.\n• Drive capacity is checked automatically less often; the button refreshes on demand.\n• Switching between drives no longer hangs: each drive's start page is preloaded in the background and shown instantly on click.\n• If a drive is not reachable, ExplorerPro shows an empty page with a hint at once instead of the previous folder.\n• New: create, browse, verify and safely extract ZIP archives."
"de-de": "ExplorerPro 1.0.9\n• Die Oberfläche friert bei langsamen Laufwerken (Netzwerk, Google Drive, OneDrive-Platzhalter, leere Kartenleser) nicht mehr ein: Ordner im Baum und die Ordner-Vorschau laden im Hintergrund.\n• Es erscheint sofort der zuletzt bekannte Stand (auch die Speicherbelegung beim Start); neue Werte ersetzen ihn, sobald sie vollständig vorliegen.\n• Die Speicherbelegung wird seltener automatisch geprüft; die Schaltfläche aktualisiert auf Wunsch.\n• Der Wechsel zwischen Laufwerken hängt nicht mehr: Die Startseite jedes Laufwerks wird im Hintergrund vorgeladen und beim Klick sofort angezeigt.\n• Ist ein Laufwerk nicht erreichbar, zeigt ExplorerPro sofort eine leere Seite mit Hinweis statt des vorigen Ordners; ein später Fehlschlag eines früheren Ziels überschreibt die aktuelle Ansicht nicht mehr.\n• Neu: ZIP-Archive erstellen, durchsuchen, auf Integrität prüfen und sicher entpacken.",
"en-us": "ExplorerPro 1.0.9\n• The window no longer freezes on slow drives (network, Google Drive, OneDrive placeholders, empty card readers): folders in the tree and the folder preview load in the background.\n• The last known state (including drive capacity at startup) is shown immediately; new values replace it once they are complete.\n• Drive capacity is checked automatically less often; the button refreshes on demand.\n• Switching between drives no longer hangs: each drive's start page is preloaded in the background and shown instantly on click.\n• If a drive is not reachable, ExplorerPro shows an empty page with a hint at once instead of the previous folder; a late failure of an earlier target no longer overrides the current view.\n• New: create, browse, verify and safely extract ZIP archives."
}
14 changes: 10 additions & 4 deletions src/gui/browser/file_browser.py
Original file line number Diff line number Diff line change
Expand Up @@ -323,22 +323,26 @@ def navigate_to(self, path: str):
self._switch(normalize_user_path(path), True)

def _switch(self, path: str, record: bool):
# Every navigation (also back/forward/up, which all end here) invalidates older
# checks with exactly ONE new token; the recheck/nav branches below reuse it.
# Without this a late failure of an earlier target (e.g. a dead E:) stayed
# "current" and blanked the view the user had moved on to.
self._nav_token += 1
token = self._nav_token
if _norm(path) in self._known_dirs:
self._go(path, record) # last known state at once ...
if self.ASYNC_VALIDATE and drive_kind(path) >= 1:
# ... but removable/network drives are re-checked in the background.
self._nav_token += 1
self._submit(self._nav_token, "recheck", path, _classify, self.NAV_TIMEOUT_MS)
self._submit(token, "recheck", path, _classify, self.NAV_TIMEOUT_MS)
elif not self.ASYNC_VALIDATE:
if record:
self._navigate_sync(path)
else:
self._go(path, False)
else:
self._nav_token += 1
self._nav_record = record
self._enter_pending(path, record)
self._submit(self._nav_token, "nav", path, _classify, self.NAV_TIMEOUT_MS)
self._submit(token, "nav", path, _classify, self.NAV_TIMEOUT_MS)

def _set_busy(self, text):
if text:
Expand Down Expand Up @@ -387,6 +391,8 @@ def _enter_pending(self, path: str, record: bool):
def _show_unreachable(self, path: str, text=None):
"""The empty page stays; history/back keep working and another click checks again."""
self._forget(path)
if _norm(path) not in (_norm(self._current_path or ""), _norm(self._pending_path or "")):
return # the user is elsewhere now: a stale failure must not touch the view
self._set_busy(text or t("Laufwerk nicht erreichbar"))
if not self.table.isHidden():
self._enter_pending(path, False)
Expand Down
28 changes: 28 additions & 0 deletions tests/test_drive_switch.py
Original file line number Diff line number Diff line change
Expand Up @@ -219,3 +219,31 @@ def test_known_network_path_is_rechecked_and_dropped_when_gone(filled, monkeypat
assert filled.current_path == str(target) and not filled.table.isHidden() # last state at once
assert pump(lambda: filled.table.isHidden()) # re-check failed: empty page
assert fb_mod._norm(str(target)) not in filled._known_dirs


# ---- a late failure of an OLD target must not blank the page the user moved on to ------

@pytest.mark.parametrize("mode", ["error", "timeout"])
def test_stale_failure_of_old_target_keeps_known_local_page(filled, monkeypatch, tmp_path, mode):
other = tmp_path / "other"
other.mkdir()
(other / "o.txt").write_text("x")
filled.navigate_to(str(other))
assert pump(lambda: filled.current_path == str(other) and rows(filled) >= 1)
filled.navigate_to(str(tmp_path)) # both now known
assert pump(lambda: rows(filled) >= 3)

def classify(path):
time.sleep(0.4)
if mode == "error":
raise OSError("drive not ready")
return "dir"

monkeypatch.setattr(fb_mod, "_classify", classify)
filled.NAV_TIMEOUT_MS = 100 if mode == "timeout" else 15000
filled.navigate_to(UNREACHABLE) # slow check pending ...
filled.navigate_to(str(other)) # ... user moves on to a known local folder at once
pump(lambda: False, timeout=1.0) # the old check fails / times out meanwhile
assert filled.current_path == str(other)
assert not filled.table.isHidden()
assert "nicht erreichbar" not in filled._busy.text() and "Keine Antwort" not in filled._busy.text()
Loading