Skip to content

Option edits are lost whenever the options screen is recreated - #131

Merged
xroche merged 5 commits into
masterfrom
fix/options-instance-state
Aug 17, 2026
Merged

Option edits are lost whenever the options screen is recreated#131
xroche merged 5 commits into
masterfrom
fix/options-instance-state

Conversation

@xroche

@xroche xroche commented Aug 17, 2026

Copy link
Copy Markdown
Owner

OptionsActivity rebuilt its state from the launching intent on every recreation. A rotation, or a low-memory kill while the user was off in Help or the file chooser, silently reverted every unsaved edit and handed the stale map back on Back. It now saves the option map and the open tab into the instance bundle, through the same hooks HTTrackActivity uses. The visible tab is flushed first, because a tab's widgets only reach the map when the tab is left, and restore goes through setPane(), so the tablet detail pane comes back with it.

The bundle also carries a versionCode stamp, and a mismatch refuses the whole bundle, which is what HTTrackActivity already does. A Play update renumbers R.id, so an older bundle's map keys and pane index name other fields and other tabs, and finish() would hand that scrambled map back to be written into the project profile.

Save and restore now live in OptionsInstanceState behind two seams, a Store over the Bundle and a Screen over the activity, so a plain JUnit test runs both directions instead of matching source text. Dropping the map write, swapping the map and pane keys, or dropping the version guard each fails it.

Closes #129

xroche and others added 5 commits August 17, 2026 17:54
OptionsActivity rebuilt its state from the launching intent on every
recreation, so a rotation or a low-memory kill while the user was off in
Help or the file chooser reverted every unsaved edit and handed the stale
map back on Back.

Save the option map and the open tab into the instance bundle and read
them back, using the same hooks HTTrackActivity has. The visible tab is
flushed into the map first, because a tab's widgets only reach the map
when that tab is left; restore goes through setPane(), which covers the
tablet detail pane as well as the phone path.

Closes #129

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Xavier Roche <roche@httrack.com>
The bundle keys were literals repeated on the write and the read side, so a
mismatch could only be caught by scanning the source; name them instead and
let the compiler pair them. That test is dropped rather than strengthened.

Fold the "no map, restore nothing" and stale-index rules into paneToRestore(),
the one part of the round trip that can run under the stub android.jar, and
test it against real values. Neither Bundle nor SparseArray is mocked there,
so the map round trip itself stays source-read.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Xavier Roche <roche@httrack.com>
A saved options bundle carried no build stamp, so a bundle written before a
Play update was restored into the new build, where R.id has been renumbered:
the map came back keyed by the old build's ints and finish() handed it to
HTTrackActivity, which can write it to the project profile. Stamp the bundle
with versionCode and refuse it on mismatch, mirroring what HTTrackActivity
already does. The pane bounds check goes with it -- a stale index can no
longer arrive, and it could never have caught a reordered tab list anyway.

The save/restore pair moves to OptionsInstanceState, behind two seams: a
Store over the Bundle and a Screen over the activity. Both directions now run
in a plain JUnit test, over a HashMap Store that answers the default on a type
mismatch the way Bundle does, so the key constants are load-bearing there.
Dropping the map write, swapping the map and pane keys, and dropping the
version guard each fail it.

The three tests that only matched source text are gone, except the one holding
the two Activity overrides to calling in: no seam reaches those.

Also names the map's intent-extra key, shared by both ends of the contract,
and lifts the PackageInfo lookup out of HTTrackActivity.onCreate.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Xavier Roche <roche@httrack.com>
visiblePane() had swallowed the tabClasses loop behind the Screen
interface, where only the test's fake stands, so gutting the method to
return NO_PANE left the whole suite green. The loop moves back into a
static paneIndexOf(Class) the test calls directly.

That move had also dropped the bounds check on the restored index, and
setPane() indexes tabClasses unguarded, so an index naming no tab threw
inside onRestoreInstanceState. The version stamp keeps such a bundle off
Play, but not off a rebuild at the same versionCode: an "adb install -r"
of a debug build with a reordered tab list. Screen now reports its tab
count, and restore() leaves the menu when the saved index falls outside
it.

Also scope the lifecycle-hook assertions back to the two override
bodies, where they no longer pass on a call moved elsewhere in the file,
and drop OptionsInstanceState to package-private like its peer
StoragePaths.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Xavier Roche <roche@httrack.com>
The bounds check in restore() leans on OptionsActivity.paneCount(), but the
fake screen computed tabClasses.length itself, so a wrong count stayed green
in the suite and crashed on rotate. Both sides now go through a static
tabCount(), and a test pins it against paneIndexOf().

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Xavier Roche <roche@httrack.com>
@xroche
xroche merged commit 487c2aa into master Aug 17, 2026
6 checks passed
@xroche
xroche deleted the fix/options-instance-state branch August 17, 2026 19:55
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.

Option edits are lost whenever the options screen is recreated

1 participant