feat(app): appearance, language and version in Settings, and Settings from Home

Settings gets a card for how this device shows the app: its appearance
(as the device, light or dark) and its language (the device's, or one
the app speaks, each named in its own language), side by side from
medium windows on, as two outlined dropdowns. Both stay on the device
rather than following the person: they are kept in
<app support>/device_settings.json (written to a temporary file and
renamed into place), read before the app shows, so its first frame
already looks as chosen, and a file that can't be read falls back to
what the device does. DeviceSettingsBloc sits above SessionGate's keyed
subtree, since the settings outlive every person, and both the plain
app and the person's app take their theme mode and locale from it.

At the bottom of Settings, the release and its build, read once at
start together with the build the server is asked about.

Home has a Settings cog beside the streak, with the sync trouble dot as
on Profile. The library's create button reads "Create studyset", and
Delete is red in every menu that offers it: the studyset's card, screen
and rail, and the composer's draft.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
This commit is contained in:
Tizian 「ティツィアーン」 2026-10-07 01:43:28 +02:00
commit 55a0a7fdf0
Signed by: raisondetredev
GPG key ID: 07F6FCF405488B64

View file

@ -136,11 +136,11 @@ abstract class AppLocalizations {
/// **'Library'**
String get libraryTitle;
/// No description provided for @libraryNewStudyset.
/// No description provided for @libraryCreateStudyset.
///
/// In en, this message translates to:
/// **'New studyset'**
String get libraryNewStudyset;
/// **'Create studyset'**
String get libraryCreateStudyset;
/// No description provided for @libraryEmpty.
///
@ -1498,6 +1498,48 @@ abstract class AppLocalizations {
/// **'About Halkyon Learn'**
String get settingsAbout;
/// No description provided for @settingsAppearance.
///
/// In en, this message translates to:
/// **'Appearance'**
String get settingsAppearance;
/// No description provided for @settingsAppearanceDevice.
///
/// In en, this message translates to:
/// **'Device theme'**
String get settingsAppearanceDevice;
/// No description provided for @settingsAppearanceLight.
///
/// In en, this message translates to:
/// **'Light'**
String get settingsAppearanceLight;
/// No description provided for @settingsAppearanceDark.
///
/// In en, this message translates to:
/// **'Dark'**
String get settingsAppearanceDark;
/// No description provided for @settingsLanguage.
///
/// In en, this message translates to:
/// **'Language'**
String get settingsLanguage;
/// No description provided for @settingsLanguageDevice.
///
/// In en, this message translates to:
/// **'Device language'**
String get settingsLanguageDevice;
/// No description provided for @settingsVersion.
///
/// In en, this message translates to:
/// **'Version {version} (build {build})'**
String settingsVersion(String version, String build);
/// No description provided for @syncTitle.
///
/// In en, this message translates to: