Settings multi-select filters Top/category/tag lists via Helix (with over-fetch for multiple languages). Larger Helix pages, safer cursors, and scroll near-end loading restore pagination; GQL page-2 integrity failures end the list cleanly. Co-authored-by: Cursor <cursoragent@cursor.com>
84 lines
3.3 KiB
Dart
84 lines
3.3 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:flutter_mobx/flutter_mobx.dart';
|
|
import 'package:frosty/models/stream_languages.dart';
|
|
import 'package:frosty/screens/settings/stores/settings_store.dart';
|
|
import 'package:frosty/screens/settings/widgets/settings_list_switch.dart';
|
|
import 'package:frosty/widgets/accent_color_setting.dart';
|
|
import 'package:frosty/widgets/external_browser_setting.dart';
|
|
import 'package:frosty/widgets/section_header.dart';
|
|
import 'package:frosty/widgets/settings_page_layout.dart';
|
|
import 'package:frosty/widgets/theme_selection_setting.dart';
|
|
|
|
class GeneralSettings extends StatelessWidget {
|
|
final SettingsStore settingsStore;
|
|
|
|
const GeneralSettings({super.key, required this.settingsStore});
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return Observer(
|
|
builder: (context) => SettingsPageLayout(
|
|
children: [
|
|
const SectionHeader('Theme', isFirst: true),
|
|
ThemeSelectionSetting(settingsStore: settingsStore),
|
|
AccentColorSetting(settingsStore: settingsStore),
|
|
const SectionHeader('Stream card'),
|
|
SettingsListSwitch(
|
|
title: 'Large stream cards',
|
|
value: settingsStore.largeStreamCard,
|
|
onChanged: (newValue) => settingsStore.largeStreamCard = newValue,
|
|
),
|
|
SettingsListSwitch(
|
|
title: 'Show thumbnails',
|
|
value: settingsStore.showThumbnails,
|
|
onChanged: (newValue) => settingsStore.showThumbnails = newValue,
|
|
),
|
|
const SectionHeader('Stream languages'),
|
|
Padding(
|
|
padding: const EdgeInsets.fromLTRB(16, 0, 16, 8),
|
|
child: Text(
|
|
settingsStore.streamLanguages.isEmpty
|
|
? 'Showing all languages. Select one or more to filter Top, category, and tag lists (like Twitch).'
|
|
: 'Only streams in the selected languages appear in Top, category, and tag lists.',
|
|
style: Theme.of(context).textTheme.bodySmall,
|
|
),
|
|
),
|
|
Padding(
|
|
padding: const EdgeInsets.fromLTRB(12, 0, 12, 8),
|
|
child: Wrap(
|
|
spacing: 8,
|
|
runSpacing: 8,
|
|
children: [
|
|
for (final entry in StreamLanguages.all)
|
|
FilterChip(
|
|
label: Text(entry.label),
|
|
selected: settingsStore.streamLanguages.contains(entry.code),
|
|
onSelected: (selected) {
|
|
final next = [...settingsStore.streamLanguages];
|
|
if (selected) {
|
|
if (!next.contains(entry.code)) next.add(entry.code);
|
|
} else {
|
|
next.remove(entry.code);
|
|
}
|
|
settingsStore.streamLanguages = next;
|
|
},
|
|
),
|
|
],
|
|
),
|
|
),
|
|
if (settingsStore.streamLanguages.isNotEmpty)
|
|
Align(
|
|
alignment: Alignment.centerLeft,
|
|
child: TextButton(
|
|
onPressed: () =>
|
|
settingsStore.streamLanguages = const <String>[],
|
|
child: const Text('Clear language filter'),
|
|
),
|
|
),
|
|
const SectionHeader('Links'),
|
|
ExternalBrowserSetting(settingsStore: settingsStore),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
}
|