import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:go_router/go_router.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import '../../l10n/generated/app_localizations.dart'; import '../state/database.dart'; import '../state/source.dart'; const kHorizontalPadding = 18.0; class SettingsScreen extends HookConsumerWidget { const SettingsScreen({super.key}); @override Widget build(BuildContext context, WidgetRef ref) { final l = AppLocalizations.of(context); final textTheme = TextTheme.of(context); return Scaffold( appBar: AppBar( title: Text(l.navigationTabsSettings, style: textTheme.headlineLarge), ), body: ListView( children: [ _SectionHeader(l.settingsServersName), const _Sources(), // _SectionHeader(l.settingsNetworkName), // const _Network(), // _SectionHeader(l.settingsAboutName), // _About(), ], ), ); } } class _Section extends StatelessWidget { const _Section({ required this.children, }); final List children; @override Widget build(BuildContext context) { return Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ ...children, ], ); } } class _SectionHeader extends StatelessWidget { const _SectionHeader( this.title, ); final String title; @override Widget build(BuildContext context) { final text = TextTheme.of(context); return Padding( padding: EdgeInsetsGeometry.directional( start: kHorizontalPadding, end: kHorizontalPadding, top: 32, bottom: 8, ), child: Text(title, style: text.headlineMedium), ); } } // class _Network extends StatelessWidget { // const _Network(); // @override // Widget build(BuildContext context) { // return const _Section( // children: [ // _OfflineMode(), // _MaxBitrateWifi(), // _MaxBitrateMobile(), // _StreamFormat(), // ], // ); // } // } // class _About extends HookConsumerWidget { // _About(); // final _homepage = Uri.parse('https://github.com/austinried/subtracks'); // final _donate = Uri.parse('https://ko-fi.com/austinried'); // @override // Widget build(BuildContext context, WidgetRef ref) { // final l = AppLocalizations.of(context); // final pkg = ref.watch(packageInfoProvider).requireValue; // return _Section( // children: [ // ListTile( // title: const Text('subtracks'), // subtitle: Text(l.settingsAboutVersion(pkg.version)), // ), // ListTile( // title: Text(l.settingsAboutActionsLicenses), // // trailing: const Icon(Icons.open_in_new_rounded), // onTap: () {}, // ), // ListTile( // title: Text(l.settingsAboutActionsProjectHomepage), // subtitle: Text(_homepage.toString()), // trailing: const Icon(Icons.open_in_new_rounded), // onTap: () => launchUrl( // _homepage, // mode: LaunchMode.externalApplication, // ), // ), // ListTile( // title: Text(l.settingsAboutActionsSupport), // subtitle: Text(_donate.toString()), // trailing: const Icon(Icons.open_in_new_rounded), // onTap: () => launchUrl( // _donate, // mode: LaunchMode.externalApplication, // ), // ), // const SizedBox(height: 12), // const _ShareLogsButton(), // ], // ); // } // } // class _ShareLogsButton extends StatelessWidget { // const _ShareLogsButton(); // @override // Widget build(BuildContext context) { // final l = AppLocalizations.of(context); // return Row( // mainAxisAlignment: MainAxisAlignment.center, // children: [ // OutlinedButton.icon( // icon: const Icon(Icons.share), // label: Text(l.settingsAboutShareLogs), // onPressed: () async { // final files = await logFiles(); // if (files.isEmpty) return; // // ignore: use_build_context_synchronously // final value = await showDialog( // context: context, // builder: (context) => MultipleChoiceDialog( // title: l.settingsAboutChooseLog, // current: files.first.path, // options: files // .map( // (e) => MultiChoiceOption.string( // title: path.basename(e.path), // option: e.path, // ), // ) // .toIList(), // ), // ); // if (value == null) return; // Share.shareXFiles( // [XFile(value, mimeType: 'text/plain')], // subject: // 'Logs from subtracks: ${String.fromCharCodes( // List.generate(8, (_) => Random().nextInt(26) + 65), // )}', // ); // }, // ), // ], // ); // } // } // class _MaxBitrateWifi extends HookConsumerWidget { // const _MaxBitrateWifi(); // @override // Widget build(BuildContext context, WidgetRef ref) { // final bitrate = ref.watch( // settingsServiceProvider.select( // (value) => value.app.maxBitrateWifi, // ), // ); // final l = AppLocalizations.of(context); // return _MaxBitrateOption( // title: l.settingsNetworkOptionsMaxBitrateWifiTitle, // bitrate: bitrate, // onChange: (value) { // ref.read(settingsServiceProvider.notifier).setMaxBitrateWifi(value); // }, // ); // } // } // class _MaxBitrateMobile extends HookConsumerWidget { // const _MaxBitrateMobile(); // @override // Widget build(BuildContext context, WidgetRef ref) { // final bitrate = ref.watch( // settingsServiceProvider.select( // (value) => value.app.maxBitrateMobile, // ), // ); // final l = AppLocalizations.of(context); // return _MaxBitrateOption( // title: l.settingsNetworkOptionsMaxBitrateMobileTitle, // bitrate: bitrate, // onChange: (value) { // ref.read(settingsServiceProvider.notifier).setMaxBitrateMobile(value); // }, // ); // } // } // class _MaxBitrateOption extends HookConsumerWidget { // final String title; // final int bitrate; // final void Function(int value) onChange; // const _MaxBitrateOption({ // required this.title, // required this.bitrate, // required this.onChange, // }); // static const options = [0, 24, 32, 64, 96, 128, 192, 256, 320]; // String _bitrateText(AppLocalizations l, int bitrate) { // return bitrate == 0 // ? l.settingsNetworkValuesUnlimitedKbps // : l.settingsNetworkValuesKbps(bitrate.toString()); // } // @override // Widget build(BuildContext context, WidgetRef ref) { // final l = AppLocalizations.of(context); // return ListTile( // title: Text(title), // subtitle: Text(_bitrateText(l, bitrate)), // onTap: () async { // final value = await showDialog( // context: context, // builder: (context) => MultipleChoiceDialog( // title: title, // current: bitrate, // options: options // .map( // (opt) => MultiChoiceOption.int( // title: _bitrateText(l, opt), // option: opt, // ), // ) // .toIList(), // ), // ); // if (value != null) { // onChange(value); // } // }, // ); // } // } // class _StreamFormat extends HookConsumerWidget { // const _StreamFormat(); // static const options = ['', 'mp3', 'opus', 'ogg']; // @override // Widget build(BuildContext context, WidgetRef ref) { // final streamFormat = ref.watch( // settingsServiceProvider.select((value) => value.app.streamFormat), // ); // final l = AppLocalizations.of(context); // return ListTile( // title: Text(l.settingsNetworkOptionsStreamFormat), // subtitle: Text( // streamFormat ?? l.settingsNetworkOptionsStreamFormatServerDefault, // ), // onTap: () async { // final value = await showDialog( // context: context, // builder: (context) => MultipleChoiceDialog( // title: l.settingsNetworkOptionsStreamFormat, // current: streamFormat ?? '', // options: options // .map( // (opt) => MultiChoiceOption.string( // title: opt == '' // ? l.settingsNetworkOptionsStreamFormatServerDefault // : opt, // option: opt, // ), // ) // .toIList(), // ), // ); // if (value != null) { // ref // .read(settingsServiceProvider.notifier) // .setStreamFormat(value == '' ? null : value); // } // }, // ); // } // } // class _OfflineMode extends HookConsumerWidget { // const _OfflineMode(); // @override // Widget build(BuildContext context, WidgetRef ref) { // final offline = ref.watch(offlineModeProvider); // final l = AppLocalizations.of(context); // return SwitchListTile( // value: offline, // title: Text(l.settingsNetworkOptionsOfflineMode), // subtitle: offline // ? Text(l.settingsNetworkOptionsOfflineModeOn) // : Text(l.settingsNetworkOptionsOfflineModeOff), // onChanged: (value) { // ref.read(offlineModeProvider.notifier).setMode(value); // }, // ); // } // } class _Sources extends HookConsumerWidget { const _Sources(); @override Widget build(BuildContext context, WidgetRef ref) { final db = ref.watch(databaseProvider); final activeSourceId = ref.watch(sourceIdProvider); final sources = useStream(db.sourcesDao.listSources()).data; final l = AppLocalizations.of(context); if (sources == null) { return Container(); } return _Section( children: [ RadioGroup( groupValue: activeSourceId, onChanged: (value) { if (value != null) { db.sourcesDao.setActiveSource(value); } }, child: Column( children: [ for (final (:source, :subsonicSetting) in sources) RadioListTile( value: source.id, title: Text(source.name), subtitle: Text( subsonicSetting.address.toString(), maxLines: 1, softWrap: false, overflow: TextOverflow.fade, ), secondary: IconButton( icon: const Icon(Icons.edit_rounded), onPressed: () { context.push('/sources/${source.id}'); }, ), ), ], ), ), const SizedBox(height: 8), Row( mainAxisAlignment: MainAxisAlignment.center, children: [ OutlinedButton.icon( icon: const Icon(Icons.add_rounded), label: Text(l.settingsServersActionsAdd), onPressed: () { context.push('/sources/add'); }, ), ], ), ], ); } }