frosty/lib/screens/settings/general_settings.dart
copilot 9d392d8d6a
All checks were successful
Actions probe / probe (push) Successful in 0s
Release APK / Build & publish release (push) Successful in 7m41s
Add stream language filter and fix directory infinite scroll.
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>
2026-10-01 10:51:10 +02:00

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),
],
),
);
}
}