checkpoint: focus seed 1.0.1 localized dev switch

This commit is contained in:
2026-06-11 23:35:49 +08:00
parent c51abdfb73
commit d06dc35ee6
72 changed files with 6155 additions and 1390 deletions
+120 -7
View File
@@ -1,19 +1,132 @@
import 'package:flutter/material.dart';
import 'dart:async';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import '../core/ambience.dart';
import '../data/app_preferences_store.dart';
import '../features/shell/focus_seed_home.dart';
import '../l10n/generated/app_localizations.dart';
import '../models/appearance_preference.dart';
import '../models/language_preference.dart';
import 'app_theme.dart';
class FocusSeedApp extends StatelessWidget {
const FocusSeedApp({super.key});
@visibleForTesting
Locale focusSeedDefaultLocale({bool isRelease = kReleaseMode}) {
return isRelease ? const Locale('en') : const Locale('zh');
}
class FocusSeedApp extends StatefulWidget {
const FocusSeedApp({this.locale, super.key});
final Locale? locale;
@override
State<FocusSeedApp> createState() => _FocusSeedAppState();
}
class _FocusSeedAppState extends State<FocusSeedApp>
with WidgetsBindingObserver {
final _preferencesStore = AppPreferencesStore();
AppearancePreference _appearance = AppearancePreference.system;
LanguagePreference _language = LanguagePreference.defaultLocale;
DayPhase _dayPhase = dayPhaseFor(DateTime.now());
Timer? _phaseTimer;
@override
void initState() {
super.initState();
WidgetsBinding.instance.addObserver(this);
_loadPreferences();
_schedulePhaseRefresh();
}
@override
void didChangeAppLifecycleState(AppLifecycleState state) {
if (state == AppLifecycleState.resumed) {
_refreshDayPhase();
}
}
Future<void> _loadPreferences() async {
final appearance = await _preferencesStore.loadAppearance();
final language = await _preferencesStore.loadLanguage();
if (!mounted) {
return;
}
setState(() {
_appearance = appearance;
_language = language;
});
}
Future<void> _setAppearance(AppearancePreference appearance) async {
setState(() => _appearance = appearance);
await _preferencesStore.saveAppearance(appearance);
}
Future<void> _setLanguage(LanguagePreference language) async {
setState(() => _language = language);
await _preferencesStore.saveLanguage(language);
}
void _refreshDayPhase() {
final phase = dayPhaseFor(DateTime.now());
if (phase != _dayPhase && mounted) {
setState(() => _dayPhase = phase);
}
_schedulePhaseRefresh();
}
void _schedulePhaseRefresh() {
_phaseTimer?.cancel();
final now = DateTime.now();
final delay = nextDayPhaseBoundary(now).difference(now);
_phaseTimer = Timer(delay, _refreshDayPhase);
}
ThemeMode get _themeMode => switch (_appearance) {
AppearancePreference.system => ThemeMode.system,
AppearancePreference.light => ThemeMode.light,
AppearancePreference.dark => ThemeMode.dark,
};
Locale get _resolvedLocale {
return widget.locale ?? _language.locale ?? focusSeedDefaultLocale();
}
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Focus Seed',
onGenerateTitle: (context) => AppLocalizations.of(context).appTitle,
debugShowCheckedModeBanner: false,
theme: AppTheme.light(),
darkTheme: AppTheme.dark(),
home: const FocusSeedHome(),
theme: AppTheme.light(_dayPhase),
darkTheme: AppTheme.dark(_dayPhase),
themeMode: _themeMode,
themeAnimationDuration: const Duration(milliseconds: 240),
locale: _resolvedLocale,
localizationsDelegates: const [
AppLocalizations.delegate,
GlobalMaterialLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
],
supportedLocales: AppLocalizations.supportedLocales,
home: FocusSeedHome(
appearance: _appearance,
onAppearanceChanged: _setAppearance,
language: _language,
showLanguageTools: !kReleaseMode && widget.locale == null,
onLanguageChanged: _setLanguage,
),
);
}
@override
void dispose() {
WidgetsBinding.instance.removeObserver(this);
_phaseTimer?.cancel();
super.dispose();
}
}