Repository navigation
Conversation
Each account now has its own settings file, datastore/users/<id>.preferences_pb, which DefaultUserSettingsStores keeps open for the life of the process (DataStore allows one open store per file and the user graph is rebuilt on every session change). Signed out, an in-memory store stands in, so the welcome and login screens use the default theme. - LibraryViewSettings, the new UserThemeSettings (the app theme) and the new PerBookSettings (per-book speed and equalizer, moved off PlaybackSettings and EqualizerSettings) are bound in the user graph on that store. - App-wide code that outlives the user graph reaches the signed-in account's settings through SignedInSettings, which looks the user graph up in ComponentHolder on each call: the players for per-book speed and equalizer, and the theme repository, which now follows the account's theme across account switches. - Each account starts from the values the app kept for everyone, copied the first time its file opens; the app-wide values stay for a release. - Logging out deletes the account's file; being asked to sign in again keeps it. On Android the files are backed up with the app's settings. - The root UI takes library view settings from the user graph it already receives.
This was referenced Oct 5, 2026
Generated by 🚫 Danger Kotlin against 32983f6 |
This was referenced Oct 5, 2026
Merged
Owner
Author
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.
Stack
Closes #607. Replaces draft #1193.
Each account now keeps its own app theme, library sorting and layout, and per-book playback speed and equalizer. Light/dark mode, listening defaults, privacy, network and the rest stay app-wide, as decided in #607.
What changed
Storage.
datastore/users/<userId>.preferences_pb.DefaultUserSettingsStores(ported from Keep library view settings per account #1193 ontoSettingsStore) keeps one open store per account for the life of the process, because DataStore allows one open store per file and the user graph is rebuilt on every session change.API. These are bound in the user graph on that account's store (
@UserSettings):LibraryViewSettings, moved from the app graph;UserThemeSettings(the app theme id, moved offThemeSettings);PerBookSettings(per-book speeds and equalizer profiles, plusplaybackSpeedFor/equalizerProfileForand their setters, moved offPlaybackSettingsandEqualizerSettings).The per-book setters decide in the account's write order and write the app-wide value from there when the book has no setting of its own.
App-wide readers. The players and the theme repository outlive the user graph, so they reach the signed-in account through
SignedInSettings. It looks the user graph up inComponentHolderon each call, so a read or write always belongs to whoever is signed in at that moment. AScoped.onCreateattach would race the theme thatLoginPresentersets right after authentication.The theme repository now follows the account's theme, including across account switches.
Sheets. The speed and equalizer sheet components move to UserScope to read
PerBookSettings.Seeding.
SeedUserSettingsMigrationcopies the account's keys, with their types, from the app-wide store the first time an account's file opens. The app-wide values stay for a release.Logout. Signing out deletes the account's file. Being asked to sign in again keeps it.
Android backup.
datastore/users/is backed up with the app's settings. The files hold no device-bound keys.Root UI. It takes
LibraryViewSettingsfrom the user graph it already receives.Verification
./scripts/ktlint --checkpasses. Desktop, Android (alpha debug) and iOS (:app:ios) compile, and the Metro graph checks pass../gradlew jvmTest testpasses, with the native-FFmpeg modules excluded as in Organize settings into packages and write through setters #1195. New tests:PerBookSettingsTest: per-book and app-wide values across separate stores;SeedUserSettingsMigrationTest;DefaultUserSettingsStoresTeston real files: seeding, accounts kept apart, own file, delete then reopen, signed-out memory store, unsafe ids.On device (emulator, local testbed server, fossDebug, two accounts):
One ANR during an account switch: a Compose
SnapshotStateObserverdeadlock in a shared-bounds measure, with no settings code in the stack. It matches the known Compose layout regression.Follow-ups
🤖 Generated with Claude Code