170 lines
6.1 KiB
Dart
170 lines
6.1 KiB
Dart
|
|
import 'package:flutter/material.dart';
|
||
|
|
import 'package:signals/signals_flutter.dart' show SignalBuilder;
|
||
|
|
|
||
|
|
import '../../application/controllers/reader_settings_controller.dart';
|
||
|
|
import '../app.dart';
|
||
|
|
import 'reader_fonts.dart';
|
||
|
|
|
||
|
|
/// Opens the reader settings bottom sheet: fonts, text size, theme, colors,
|
||
|
|
/// bookmark and subscription for the current page.
|
||
|
|
void showReaderSettingsSheet(BuildContext context) {
|
||
|
|
showModalBottomSheet<void>(
|
||
|
|
context: context,
|
||
|
|
isScrollControlled: true,
|
||
|
|
builder: (context) => const SettingsSheet(),
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
class SettingsSheet extends StatelessWidget {
|
||
|
|
const SettingsSheet({super.key});
|
||
|
|
|
||
|
|
@override
|
||
|
|
Widget build(BuildContext context) {
|
||
|
|
final scope = AppScope.of(context);
|
||
|
|
final deps = scope.deps;
|
||
|
|
final strings = scope.strings;
|
||
|
|
|
||
|
|
return SignalBuilder(builder: (context) {
|
||
|
|
final settings = deps.settings;
|
||
|
|
final library = deps.library;
|
||
|
|
final page = deps.browser.currentPage.value;
|
||
|
|
final url = page?.url;
|
||
|
|
|
||
|
|
final percent = (settings.fontScale.value * 100).round();
|
||
|
|
|
||
|
|
return SafeArea(
|
||
|
|
child: ListView(
|
||
|
|
shrinkWrap: true,
|
||
|
|
padding: const EdgeInsets.fromLTRB(0, 12, 0, 16),
|
||
|
|
children: [
|
||
|
|
Padding(
|
||
|
|
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||
|
|
child: Text(
|
||
|
|
strings.t('settings-sheet-title'),
|
||
|
|
style: Theme.of(context).textTheme.titleMedium,
|
||
|
|
),
|
||
|
|
),
|
||
|
|
_heading(context, strings.t('settings-font-heading')),
|
||
|
|
RadioGroup<String>(
|
||
|
|
groupValue: settings.font.value,
|
||
|
|
onChanged: (value) => settings.setFont(value!),
|
||
|
|
child: Column(
|
||
|
|
children: [
|
||
|
|
for (final font in readerFonts)
|
||
|
|
RadioListTile<String>(
|
||
|
|
value: font.family,
|
||
|
|
title: Text(strings.t(font.labelId)),
|
||
|
|
),
|
||
|
|
],
|
||
|
|
),
|
||
|
|
),
|
||
|
|
_heading(context, strings.t('settings-size-heading')),
|
||
|
|
Row(
|
||
|
|
mainAxisAlignment: MainAxisAlignment.center,
|
||
|
|
children: [
|
||
|
|
IconButton(
|
||
|
|
tooltip: strings.t('settings-size-decrease'),
|
||
|
|
onPressed: settings.fontScale.value > ReaderSettingsController.minScale
|
||
|
|
? settings.decreaseSize
|
||
|
|
: null,
|
||
|
|
icon: const Icon(Icons.remove),
|
||
|
|
),
|
||
|
|
SizedBox(
|
||
|
|
width: 56,
|
||
|
|
child: Text(
|
||
|
|
'$percent%',
|
||
|
|
textAlign: TextAlign.center,
|
||
|
|
style: Theme.of(context).textTheme.titleMedium,
|
||
|
|
),
|
||
|
|
),
|
||
|
|
IconButton(
|
||
|
|
tooltip: strings.t('settings-size-increase'),
|
||
|
|
onPressed: settings.fontScale.value < ReaderSettingsController.maxScale
|
||
|
|
? settings.increaseSize
|
||
|
|
: null,
|
||
|
|
icon: const Icon(Icons.add),
|
||
|
|
),
|
||
|
|
],
|
||
|
|
),
|
||
|
|
_heading(context, strings.t('settings-theme-heading')),
|
||
|
|
RadioGroup<String>(
|
||
|
|
groupValue: settings.themeMode.value,
|
||
|
|
onChanged: (value) => settings.setThemeMode(value!),
|
||
|
|
child: Column(
|
||
|
|
children: [
|
||
|
|
for (final (mode, id) in [
|
||
|
|
('light', 'settings-theme-light'),
|
||
|
|
('dark', 'settings-theme-dark'),
|
||
|
|
('system', 'settings-theme-system'),
|
||
|
|
])
|
||
|
|
RadioListTile<String>(
|
||
|
|
value: mode,
|
||
|
|
title: Text(strings.t(id)),
|
||
|
|
),
|
||
|
|
],
|
||
|
|
),
|
||
|
|
),
|
||
|
|
_heading(context, strings.t('settings-variant-heading')),
|
||
|
|
RadioGroup<String>(
|
||
|
|
groupValue: settings.variant.value,
|
||
|
|
onChanged: (value) => settings.setVariant(value!),
|
||
|
|
child: Column(
|
||
|
|
children: [
|
||
|
|
for (final (variant, id) in [
|
||
|
|
('site', 'settings-variant-site'),
|
||
|
|
('warm', 'settings-variant-warm'),
|
||
|
|
('cool', 'settings-variant-cool'),
|
||
|
|
('green', 'settings-variant-green'),
|
||
|
|
('mono', 'settings-variant-mono'),
|
||
|
|
])
|
||
|
|
RadioListTile<String>(
|
||
|
|
value: variant,
|
||
|
|
title: Text(strings.t(id)),
|
||
|
|
),
|
||
|
|
],
|
||
|
|
),
|
||
|
|
),
|
||
|
|
const Divider(),
|
||
|
|
if (url != null) ...[
|
||
|
|
ListTile(
|
||
|
|
leading: Icon(library.isBookmarked(url) ? Icons.star : Icons.star_border),
|
||
|
|
title: Text(
|
||
|
|
library.isBookmarked(url)
|
||
|
|
? strings.t('settings-bookmark-remove')
|
||
|
|
: strings.t('settings-bookmark-add'),
|
||
|
|
),
|
||
|
|
onTap: () => library.toggleBookmark(url, page?.title),
|
||
|
|
),
|
||
|
|
ListTile(
|
||
|
|
leading: Icon(library.isSubscribed(url)
|
||
|
|
? Icons.notifications_active
|
||
|
|
: Icons.notifications_outlined),
|
||
|
|
title: Text(
|
||
|
|
library.isSubscribed(url)
|
||
|
|
? strings.t('settings-unsubscribe')
|
||
|
|
: strings.t('settings-subscribe'),
|
||
|
|
),
|
||
|
|
subtitle: library.isSubscribed(url)
|
||
|
|
? Text(strings.t('settings-subscribed-notice'))
|
||
|
|
: null,
|
||
|
|
onTap: () => library.toggleSubscription(url, page?.title, page?.entries ?? const []),
|
||
|
|
),
|
||
|
|
],
|
||
|
|
],
|
||
|
|
),
|
||
|
|
);
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
Widget _heading(BuildContext context, String text) => Padding(
|
||
|
|
padding: const EdgeInsets.fromLTRB(16, 16, 16, 4),
|
||
|
|
child: Text(
|
||
|
|
text,
|
||
|
|
style: Theme.of(context)
|
||
|
|
.textTheme
|
||
|
|
.labelLarge
|
||
|
|
?.copyWith(color: Theme.of(context).colorScheme.primary),
|
||
|
|
),
|
||
|
|
);
|
||
|
|
}
|