Saving a project writes back settings nobody chose - #127
Conversation
Loading a project seeds Android's defaults and lays the file over the top, and serialize() then wrote a line for every key it knows, empty where the map held nothing. So every key came back present after a save, carrying our default or an empty value. Absent and empty differ to the other front ends: WinHTTrack applies its own default for a missing key and takes an empty one literally, so opening a WinHTTrack project on the phone and saving it left our footer template and our filter list behind. Write a key only when its value differs from the seeded default, which keeps a field the user deliberately cleared while leaving a setting nobody chose out of the file. initializeMap() and the writer now read the same defaults from one method, so the baseline being compared against cannot drift from the one seeded. Closes #126 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BHQdRcxpBhjGhdKwwmtj36 Signed-off-by: Xavier Roche <roche@httrack.com>
|
Holding this as a draft: the review found the omission baseline is the wrong one, and the result is silent corruption of a saved setting.
Repro, no code needed. Set Max transfer rate to 5000 and save it as the default options. Open a project, set the rate to 25000, save. That equals the built-in default, so Every key in The fix has two parts, neither in this diff. Compare against the state the project was actually seeded with, snapshotted after Reworking on that basis. |
The first cut of this fix omitted a key when its value matched the built-in fieldsDefaults table. That is the wrong baseline: what refills an absent key is resetMap(), which is initializeMap() plus loadDefaultPreferences(), so a user with saved default options loses settings. Set 5000 as the default transfer rate, set 25000 in a project, save, reopen: the key matched the table and was dropped, and the project comes back at 5000 with the crawl getting -A 5000. AcceptLanguage failed a second way, its default being derived from the device locale at call time. Snapshot the map once resetMap() has finished, and compare against that. Keep every key the loaded profile carried, whatever it holds, so saving can only stop adding keys and never start removing someone else's line; the profile on disk supplies that set when an activity restart has left the map without it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BHQdRcxpBhjGhdKwwmtj36 Signed-off-by: Xavier Roche <roche@httrack.com>
Two ways the previous commit still lost a setting. The crawl-start write opens winprofile.ini in append mode to hold its lock, and the reader takes the last line for a key, so a key left out of that write kept whatever an earlier block said. Build the settings first, then truncate under the lock and write them, which also stops the file growing a block per crawl. The baseline was snapshotted after resetMap(). OptionsActivity holds its own mapper, so resetting the saved default options there changed what a future load rebuilds while this snapshot stayed put, and a value matching the old preference was dropped and came back as the built-in default. Derive the baseline from the defaults and the saved options on each call instead, and let loadDefaultPreferences() build the map from the same method so the two cannot disagree. AcceptLanguage comes from the device locale rather than a fixed default, so it is always written: the device can change between saves. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BHQdRcxpBhjGhdKwwmtj36 Signed-off-by: Xavier Roche <roche@httrack.com>
Signed-off-by: Xavier Roche <roche@httrack.com> # Conflicts: # app/src/test/java/com/httrack/android/WinProfileParityTest.java
|
Closing this. It needs a different design, not another commit on the branch. The rule omits a key when Android's own next load would rebuild the same value. That baseline includes the device's saved default options, so what gets written into a file WinHTTrack and WebHTTrack also read depends on the phone's own preferences: two devices write different files from the same project. The shared key table, now vendored at Two other defects found in review, recorded so nobody rediscovers them. A key the profile carried that Android has no field for is dropped on save: The branch stays for reference. #126 stays open with a smaller approach. |
Loading a project seeds Android's defaults, then lays the profile on top.
serialize()wrote a line for every key it knows, using an empty value where the map held nothing, so every key came back present after a save.Absent and empty are different things across front ends: WinHTTrack applies its own default for a missing key and takes an empty one literally. Opening a WinHTTrack project on the phone, changing nothing and saving was enough to leave our footer template and filter list in the file. The next desktop crawl then used them.
A key is now written only when the next load would not put it back by itself. The baseline for that is the map snapshotted once
resetMap()has finished, not the built-infieldsDefaultstable: what refills an absent key isinitializeMap()plusloadDefaultPreferences(), so a user with saved default options would otherwise lose settings. The first version of this branch made exactly that mistake, and the second commit is the fix. Any key the loaded profile carried is kept whatever it holds, so saving can only stop adding keys and never start removing someone else's line.One consequence worth naming: a key left at the value the load rebuilds is no longer pinned in the file, so a project follows a later change to that baseline instead of holding the old value. For
Footerthat is what #122 wanted anyway.Closes #126