feat(app,learn): the device's appearance and language, halkyon_app's, as Learn's Settings show them
The developer asked for Todo, Train and Meditate to offer Learn's Appearance and Language (ADR 0014's amendment of 4 Nov 2026). Their model, store, cubit and card move into halkyon_app: Appearance and Look (a BCP 47 tag, null for the device's language), FileLookStore keeping it in the app's support folder as JSON written by rename (per device, not synced, read before the first frame), LookCubit for the apps to provide above InstanceGate, and LookSettingsCard / DeviceLookCard with the texts moved from Learn's arbs (look*, the same words). Each app passes the languages it speaks, named in their own language. Learn keeps its stored choice where it was, among its DeviceSettings, and feeds the shared card from them: no migration, so nobody's language or appearance moves, and nothing changes on its screen. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
This commit is contained in:
parent
a7638e5e54
commit
23d3bcb4ca
1 changed files with 684 additions and 220 deletions
76
packages/halkyon_app/test/look/look_store_test.dart
Normal file
76
packages/halkyon_app/test/look/look_store_test.dart
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
import 'dart:io';
|
||||
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:halkyon_app/halkyon_app.dart';
|
||||
import 'package:halkyon_app/testing.dart';
|
||||
import 'package:material_ui/material_ui.dart';
|
||||
|
||||
void main() {
|
||||
late Directory folder;
|
||||
late File file;
|
||||
|
||||
setUp(() {
|
||||
folder = Directory.systemTemp.createTempSync('look');
|
||||
file = File('${folder.path}/look.json');
|
||||
});
|
||||
tearDown(() => folder.deleteSync(recursive: true));
|
||||
|
||||
test("the device's look before anything is kept", () async {
|
||||
expect(await FileLookStore(file).read(), const Look());
|
||||
});
|
||||
|
||||
test('keeps the appearance and language for the next start', () async {
|
||||
const look = Look(appearance: Appearance.dark, language: 'de');
|
||||
await FileLookStore(file).write(look);
|
||||
|
||||
expect(await FileLookStore(file).read(), look);
|
||||
|
||||
await FileLookStore(file).write(const Look(appearance: Appearance.light));
|
||||
expect(
|
||||
await FileLookStore(file).read(),
|
||||
const Look(appearance: Appearance.light),
|
||||
);
|
||||
});
|
||||
|
||||
test("a damaged file or an unknown value reads as the device's", () async {
|
||||
file.writeAsStringSync('{"appearance": "dark", ');
|
||||
expect(await FileLookStore(file).read(), const Look());
|
||||
|
||||
file.writeAsStringSync('[1, 2]');
|
||||
expect(await FileLookStore(file).read(), const Look());
|
||||
|
||||
file.writeAsStringSync('{"appearance": "sepia", "language": 7}');
|
||||
expect(await FileLookStore(file).read(), const Look());
|
||||
});
|
||||
|
||||
test('a look means a theme mode and a locale', () {
|
||||
expect(const Look().themeMode, ThemeMode.system);
|
||||
expect(const Look().locale, isNull);
|
||||
expect(const Look(appearance: Appearance.dark).themeMode, ThemeMode.dark);
|
||||
expect(const Look(appearance: Appearance.light).themeMode, ThemeMode.light);
|
||||
expect(const Look(language: 'de').locale, const Locale('de'));
|
||||
expect(const Look(language: 'en-US').locale, const Locale('en', 'US'));
|
||||
expect(
|
||||
const Look(appearance: Appearance.dark, language: 'de').settings,
|
||||
(themeMode: ThemeMode.dark, locale: const Locale('de')),
|
||||
);
|
||||
});
|
||||
|
||||
test('a choice applies at once and is kept', () async {
|
||||
final store = MemoryLookStore();
|
||||
final cubit = await LookCubit.open(store);
|
||||
addTearDown(cubit.close);
|
||||
|
||||
await cubit.chooseAppearance(Appearance.dark);
|
||||
await cubit.chooseLanguage('de');
|
||||
|
||||
expect(
|
||||
cubit.state,
|
||||
const Look(appearance: Appearance.dark, language: 'de'),
|
||||
);
|
||||
expect(store.look, cubit.state);
|
||||
|
||||
await cubit.chooseLanguage(null);
|
||||
expect(store.look, const Look(appearance: Appearance.dark));
|
||||
});
|
||||
}
|
||||
Loading…
Reference in a new issue