The app asks every new user about mirrors that do not exist - #164
Merged
Conversation
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>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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 theDownload/HTTrack/Websitesfolder 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.