Skip to content

The app asks every new user about mirrors that do not exist - #164

Merged
xroche merged 2 commits into
masterfrom
fix/legacy-import-gate
Aug 24, 2026
Merged

The app asks every new user about mirrors that do not exist#164
xroche merged 2 commits into
masterfrom
fix/legacy-import-gate

Conversation

@xroche

@xroche xroche commented Aug 24, 2026

Copy link
Copy Markdown
Owner

The import offer was gated on a "have I asked before" preference and nothing else. A fresh install therefore got a question about 2017 mirrors it could not have, stacked on the storage-permission dialog beside it, and answering yes before settling that permission copied into app-private storage that an uninstall erases. Existing users were never cut off from their mirrors, so this is a question worth not asking rather than data worth recovering.

StoragePaths.legacyMirrorRoot() looks for the Download/HTTrack/Websites folder that builds before versionCode 61 wrote to, and returns it only when it holds a project with something in it. Without access the shared root is null, so it finds nothing and nothing is asked. onResume() asks again only when access has just appeared, the one resume that can reveal the folder, and by then the destination resolves to shared storage.

xroche and others added 2 commits August 24, 2026 20:02
The import offer was gated on a "have I asked" preference and nothing else,
so it greeted every fresh install with a question about mirrors that do not
exist, stacked on the storage-permission dialog it was shown beside. A user
who answered yes before settling that permission copied into app-private
storage, which an uninstall erases.

StoragePaths.legacyMirrors() looks for the Download/HTTrack/Websites folder
that builds before versionCode 61 wrote to, and returns it only when it
holds a project. Without access the shared root is null, so it finds
nothing and nothing is asked: a question the user has no way to answer is
worse than never offering the import. onResume() asks again after a grant,
which is the first moment the folder can be seen, and by then the
destination resolves to shared storage rather than the private one.

The offer is the only thing gated. The mirrors themselves were never
unreachable: builds 61 to 63, which is what production has served since
2017, already wrote to the shared HTTrack/ root this build reads.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Xavier Roche <roche@httrack.com>
Review found three ways the offer misbehaved. On a cold launch with mirrors
present, onCreate showed it and onResume immediately showed a second one on
top; tapping Yes on either opened its own document picker. "Not now" leaves
the latch clear by design, so the question came back on every return to the
app, including from Options or Help. And rotation skipped the onCreate call
but not the onResume one, defeating the guard whose comment says a rotation
must not bring the offer back.

The latch records that the user decided, not that we asked. So the resume
call now fires only when access has just appeared, which is the one resume
that can reveal anything; onCreate covers access granted before launch.

An empty project directory no longer counts as something to import, since
asking about it leads to a copy of nothing.

The Javadoc on the offer said no permission remains to detect the folder,
which this change makes false.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Xavier Roche <roche@httrack.com>
@xroche
xroche merged commit 704b2c2 into master Aug 24, 2026
6 checks passed
@xroche
xroche deleted the fix/legacy-import-gate branch August 24, 2026 18:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant