feat: theme chrome by palette, selectable text, wap fallback, and library pages
This commit is contained in:
parent
c104c2026b
commit
56f3d959fa
12 changed files with 534 additions and 51 deletions
|
|
@ -5,26 +5,38 @@ import 'package:signals/signals_flutter.dart' show SignalBuilder;
|
|||
import '../application/actors/fetch_actor.dart';
|
||||
import '../application/controllers/browser_controller.dart';
|
||||
import '../application/controllers/reader_settings_controller.dart';
|
||||
import '../application/internal_pages.dart';
|
||||
import '../database/database.dart';
|
||||
import '../l10n/strings.dart';
|
||||
import '../mews/document.dart';
|
||||
import 'reader/palettes.dart';
|
||||
import 'reader/reader_screen.dart';
|
||||
/// Wires the app's dependencies together and provides them to the tree.
|
||||
/// Everything is local-first: the database is created up front and the fetch
|
||||
/// actor is the only path to the network.
|
||||
class AppDependencies {
|
||||
AppDependencies({MewsDatabase? database, Actor<FetchCommand, FetchResult>? fetch})
|
||||
: db = database ?? MewsDatabase(),
|
||||
fetch = fetch ?? Actor.create(FetchHandler.new) {
|
||||
browser = BrowserController(db: db, fetch: this.fetch);
|
||||
AppDependencies({
|
||||
MewsDatabase? database,
|
||||
Actor<FetchCommand, FetchResult>? fetch,
|
||||
Strings? strings,
|
||||
}) : db = database ?? MewsDatabase(),
|
||||
fetch = fetch ?? Actor.create(FetchHandler.new),
|
||||
strings = strings ?? Strings() {
|
||||
settings = ReaderSettingsController(db);
|
||||
library = LibraryController(db);
|
||||
internalPages = InternalPages(db: db, library: library, strings: this.strings);
|
||||
browser = BrowserController(db: db, fetch: this.fetch, internalPages: internalPages);
|
||||
}
|
||||
|
||||
/// Localized strings, also used to title the internal pages.
|
||||
final Strings strings;
|
||||
|
||||
final MewsDatabase db;
|
||||
final Actor<FetchCommand, FetchResult> fetch;
|
||||
late final BrowserController browser;
|
||||
late final ReaderSettingsController settings;
|
||||
late final LibraryController library;
|
||||
late final InternalPages internalPages;
|
||||
|
||||
Future<void> start() async {
|
||||
await settings.load();
|
||||
|
|
@ -70,6 +82,8 @@ class MewsApp extends StatelessWidget {
|
|||
}
|
||||
}
|
||||
|
||||
/// The chrome (address bar, FOB, sheet, dialogs) follows the same palette
|
||||
/// the reader selected for pages, so the whole app shares one color scheme.
|
||||
class _ThemedApp extends StatelessWidget {
|
||||
const _ThemedApp();
|
||||
|
||||
|
|
@ -82,21 +96,55 @@ class _ThemedApp extends StatelessWidget {
|
|||
'dark' => ThemeMode.dark,
|
||||
_ => ThemeMode.system,
|
||||
};
|
||||
final settings = deps.settings;
|
||||
final page = deps.browser.currentPage.value;
|
||||
final variant = settings.variant.value == 'site'
|
||||
? (page?.variant ?? MewsVariant.plain)
|
||||
: pageVariantFromName(settings.variant.value);
|
||||
|
||||
return MaterialApp(
|
||||
title: 'Mews',
|
||||
themeMode: mode,
|
||||
theme: ThemeData(
|
||||
useMaterial3: true,
|
||||
colorScheme: ColorScheme.fromSeed(seedColor: const Color(0xff1a4f9c)),
|
||||
),
|
||||
darkTheme: ThemeData(
|
||||
useMaterial3: true,
|
||||
brightness: Brightness.dark,
|
||||
colorScheme: ColorScheme.fromSeed(
|
||||
seedColor: const Color(0xff1a4f9c), brightness: Brightness.dark),
|
||||
),
|
||||
theme: _themeFor(paletteFor(pageVariant: variant, readerVariant: 'site', dark: false)),
|
||||
darkTheme: _themeFor(paletteFor(pageVariant: variant, readerVariant: 'site', dark: true)),
|
||||
home: const ReaderScreen(),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
ThemeData _themeFor(MewsPalette palette) {
|
||||
final dark = palette.background.computeLuminance() < 0.5;
|
||||
final scheme = ColorScheme(
|
||||
brightness: dark ? Brightness.dark : Brightness.light,
|
||||
primary: palette.link,
|
||||
onPrimary: palette.background,
|
||||
primaryContainer: palette.link,
|
||||
onPrimaryContainer: palette.background,
|
||||
secondary: palette.border,
|
||||
onSecondary: palette.foreground,
|
||||
surface: palette.background,
|
||||
onSurface: palette.foreground,
|
||||
onSurfaceVariant: palette.foreground,
|
||||
surfaceContainerHighest: palette.preBackground,
|
||||
outline: palette.border,
|
||||
error: const Color(0xffba1a1a),
|
||||
onError: Colors.white,
|
||||
);
|
||||
return ThemeData(
|
||||
useMaterial3: true,
|
||||
colorScheme: scheme,
|
||||
scaffoldBackgroundColor: palette.background,
|
||||
// The FOB follows the palette, not the M3 container defaults.
|
||||
floatingActionButtonTheme: FloatingActionButtonThemeData(
|
||||
backgroundColor: palette.link,
|
||||
foregroundColor: palette.background,
|
||||
),
|
||||
// Selection highlights and the caret follow the palette too.
|
||||
textSelectionTheme: TextSelectionThemeData(
|
||||
cursorColor: palette.link,
|
||||
selectionColor: palette.link.withValues(alpha: 0.3),
|
||||
selectionHandleColor: palette.link,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue