From 40085a701d1b4ee55d22fb45f12e134d020c38fc Mon Sep 17 00:00:00 2001 From: Fabian Freund Date: Thu, 3 Jul 2025 15:46:12 +0200 Subject: [PATCH] reorganize settings --- app/lib/core/routing/routes.dart | 1 + app/lib/core/routing/routes.g.dart | 27 ++++ app/lib/core/routing/routes.settings.dart | 11 ++ .../screens/developer_settings.dart | 137 ++++++++++++++++++ .../screens/general_settings.dart | 32 ---- .../presentation/screens/settings.dart | 17 +++ .../screens/web_engine_settings.dart | 74 ---------- 7 files changed, 193 insertions(+), 106 deletions(-) create mode 100644 app/lib/features/settings/presentation/screens/developer_settings.dart diff --git a/app/lib/core/routing/routes.dart b/app/lib/core/routing/routes.dart index 1cb5f9c4..c0925132 100644 --- a/app/lib/core/routing/routes.dart +++ b/app/lib/core/routing/routes.dart @@ -19,6 +19,7 @@ import 'package:weblibre/features/geckoview/features/tabs/presentation/screens/c import 'package:weblibre/features/geckoview/features/tabs/presentation/screens/container_list.dart'; import 'package:weblibre/features/onboarding/presentation/onboarding.dart'; import 'package:weblibre/features/settings/presentation/screens/bang_settings.dart'; +import 'package:weblibre/features/settings/presentation/screens/developer_settings.dart'; import 'package:weblibre/features/settings/presentation/screens/general_settings.dart'; import 'package:weblibre/features/settings/presentation/screens/settings.dart'; import 'package:weblibre/features/settings/presentation/screens/web_engine_hardening.dart'; diff --git a/app/lib/core/routing/routes.g.dart b/app/lib/core/routing/routes.g.dart index a261c31d..b3697f23 100644 --- a/app/lib/core/routing/routes.g.dart +++ b/app/lib/core/routing/routes.g.dart @@ -116,6 +116,12 @@ RouteBase get $settingsRoute => GoRouteData.$route( ), ], ), + GoRouteData.$route( + path: 'developer', + name: 'DeveloperSettingsRoute', + + factory: _$DeveloperSettingsRoute._fromState, + ), ], ); @@ -250,6 +256,27 @@ mixin _$WebEngineHardeningGroupRoute on GoRouteData { void replace(BuildContext context) => context.replace(location); } +mixin _$DeveloperSettingsRoute on GoRouteData { + static DeveloperSettingsRoute _fromState(GoRouterState state) => + DeveloperSettingsRoute(); + + @override + String get location => GoRouteData.$location('/settings/developer'); + + @override + void go(BuildContext context) => context.go(location); + + @override + Future push(BuildContext context) => context.push(location); + + @override + void pushReplacement(BuildContext context) => + context.pushReplacement(location); + + @override + void replace(BuildContext context) => context.replace(location); +} + RouteBase get $browserRoute => GoRouteData.$route( path: '/', name: 'BrowserRoute', diff --git a/app/lib/core/routing/routes.settings.dart b/app/lib/core/routing/routes.settings.dart index db98116f..dc537a18 100644 --- a/app/lib/core/routing/routes.settings.dart +++ b/app/lib/core/routing/routes.settings.dart @@ -25,6 +25,10 @@ part of 'routes.dart'; ), ], ), + TypedGoRoute( + name: 'DeveloperSettingsRoute', + path: 'developer', + ), ], ) class SettingsRoute extends GoRouteData with _$SettingsRoute { @@ -55,6 +59,13 @@ class WebEngineSettingsRoute extends GoRouteData with _$WebEngineSettingsRoute { } } +class DeveloperSettingsRoute extends GoRouteData with _$DeveloperSettingsRoute { + @override + Widget build(BuildContext context, GoRouterState state) { + return const DeveloperSettingsScreen(); + } +} + class WebEngineHardeningRoute extends GoRouteData with _$WebEngineHardeningRoute { @override diff --git a/app/lib/features/settings/presentation/screens/developer_settings.dart b/app/lib/features/settings/presentation/screens/developer_settings.dart new file mode 100644 index 00000000..f070744f --- /dev/null +++ b/app/lib/features/settings/presentation/screens/developer_settings.dart @@ -0,0 +1,137 @@ +import 'package:fading_scroll/fading_scroll.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:flutter_material_design_icons/flutter_material_design_icons.dart'; +import 'package:go_router/go_router.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:universal_io/io.dart'; +import 'package:weblibre/core/logger.dart'; +import 'package:weblibre/features/settings/presentation/controllers/save_settings.dart'; +import 'package:weblibre/features/settings/presentation/widgets/custom_list_tile.dart'; +import 'package:weblibre/features/user/data/models/engine_settings.dart'; +import 'package:weblibre/features/user/domain/repositories/engine_settings.dart'; +import 'package:weblibre/utils/ui_helper.dart'; + +class DeveloperSettingsScreen extends HookConsumerWidget { + const DeveloperSettingsScreen(); + + @override + Widget build(BuildContext context, WidgetRef ref) { + final engineSettings = ref.watch(engineSettingsRepositoryProvider); + + final userAgentTextController = useTextEditingController( + text: engineSettings.userAgent, + keys: [engineSettings.userAgent], + ); + + return Scaffold( + appBar: AppBar(title: const Text('Developer Settings')), + body: FadingScroll( + fadingSize: 25, + builder: (context, controller) { + return ListView( + controller: controller, + children: [ + SwitchListTile.adaptive( + title: const Text('Enable JavaScript'), + subtitle: const Text( + 'While turning off JavaScript can boost security, privacy, and speed, it may cause some sites to not work as intended.', + ), + // ignore: deprecated_member_use use this icon for now + secondary: const Icon(MdiIcons.languageJavascript), + value: engineSettings.javascriptEnabled, + onChanged: (value) async { + await ref + .read(saveEngineSettingsControllerProvider.notifier) + .save( + (currentSettings) => + currentSettings.copyWith.javascriptEnabled(value), + ); + }, + ), + ListTile( + leading: const Icon(MdiIcons.cardAccountDetails), + title: TextField( + controller: userAgentTextController, + decoration: const InputDecoration( + labelText: 'Custom User Agent', + floatingLabelBehavior: FloatingLabelBehavior.always, + hintText: 'Mozilla/5.0 …', + ), + onSubmitted: (value) async { + await ref + .read(saveEngineSettingsControllerProvider.notifier) + .save( + (currentSettings) => + currentSettings.copyWith.userAgent(value), + ); + + if (context.mounted) { + final restart = await showDialog( + context: context, + builder: (context) => AlertDialog( + title: const Text('User Agent Changed'), + content: const Text( + 'The app needs to restart for the new user agent to take effect', + ), + actions: [ + TextButton( + onPressed: () { + context.pop(false); + }, + child: const Text('Later'), + ), + TextButton( + onPressed: () { + context.pop(true); + }, + child: const Text('Restart Now'), + ), + ], + ), + ); + + if (restart == true) { + exit(0); + } + } + }, + ), + ), + CustomListTile( + title: 'Error Logs', + subtitle: 'Copy logs for issue reporting', + prefix: Padding( + padding: const EdgeInsets.only(right: 16.0), + child: Icon( + Icons.bug_report, + size: 24, + color: Theme.of(context).colorScheme.onSurfaceVariant, + ), + ), + suffix: FilledButton.icon( + onPressed: () async { + await Clipboard.setData( + ClipboardData( + text: loggerMemory.buffer + .map((e) => e.lines.join('\n')) + .join('\n\n'), + ), + ); + + if (context.mounted) { + showInfoMessage(context, 'Logs copied'); + } + }, + icon: const Icon(Icons.copy), + label: const Text('Copy'), + ), + ), + ], + ); + }, + ), + ); + } +} diff --git a/app/lib/features/settings/presentation/screens/general_settings.dart b/app/lib/features/settings/presentation/screens/general_settings.dart index 6eef664f..dc76f6aa 100644 --- a/app/lib/features/settings/presentation/screens/general_settings.dart +++ b/app/lib/features/settings/presentation/screens/general_settings.dart @@ -1,11 +1,9 @@ import 'package:fading_scroll/fading_scroll.dart'; import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; import 'package:flutter_material_design_icons/flutter_material_design_icons.dart'; import 'package:google_fonts/google_fonts.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:nullability/nullability.dart'; -import 'package:weblibre/core/logger.dart'; import 'package:weblibre/features/search/domain/entities/abstract/i_search_suggestion_provider.dart'; import 'package:weblibre/features/settings/presentation/controllers/save_settings.dart'; import 'package:weblibre/features/settings/presentation/widgets/bang_icon.dart'; @@ -15,7 +13,6 @@ import 'package:weblibre/features/user/data/models/general_settings.dart'; import 'package:weblibre/features/user/domain/providers.dart'; import 'package:weblibre/features/user/domain/repositories/cache.dart'; import 'package:weblibre/features/user/domain/repositories/general_settings.dart'; -import 'package:weblibre/utils/ui_helper.dart'; class GeneralSettingsScreen extends HookConsumerWidget { const GeneralSettingsScreen({super.key}); @@ -263,35 +260,6 @@ class GeneralSettingsScreen extends HookConsumerWidget { ); }, ), - CustomListTile( - title: 'Error Logs', - subtitle: 'Copy logs for issue reporting', - prefix: Padding( - padding: const EdgeInsets.only(right: 16.0), - child: Icon( - Icons.bug_report, - size: 24, - color: Theme.of(context).colorScheme.onSurfaceVariant, - ), - ), - suffix: FilledButton.icon( - onPressed: () async { - await Clipboard.setData( - ClipboardData( - text: loggerMemory.buffer - .map((e) => e.lines.join('\n')) - .join('\n\n'), - ), - ); - - if (context.mounted) { - showInfoMessage(context, 'Logs copied'); - } - }, - icon: const Icon(Icons.copy), - label: const Text('Copy'), - ), - ), ], ); }, diff --git a/app/lib/features/settings/presentation/screens/settings.dart b/app/lib/features/settings/presentation/screens/settings.dart index 5dbf893b..c4cf4f72 100644 --- a/app/lib/features/settings/presentation/screens/settings.dart +++ b/app/lib/features/settings/presentation/screens/settings.dart @@ -68,6 +68,23 @@ class SettingsScreen extends HookConsumerWidget { }, ), ), + const SizedBox(height: 8), + Card( + color: Theme.of(context).highlightColor, + clipBehavior: Clip.antiAlias, + child: ListTile( + title: const Text('Developer'), + contentPadding: const EdgeInsets.symmetric( + vertical: 8.0, + horizontal: 16.0, + ), + leading: const Icon(Icons.developer_mode), + trailing: const Icon(Icons.chevron_right), + onTap: () async { + await DeveloperSettingsRoute().push(context); + }, + ), + ), ], ); }, diff --git a/app/lib/features/settings/presentation/screens/web_engine_settings.dart b/app/lib/features/settings/presentation/screens/web_engine_settings.dart index 139f0aa1..e5cfc2d1 100644 --- a/app/lib/features/settings/presentation/screens/web_engine_settings.dart +++ b/app/lib/features/settings/presentation/screens/web_engine_settings.dart @@ -1,12 +1,9 @@ import 'package:fading_scroll/fading_scroll.dart'; import 'package:flutter/material.dart'; -import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:flutter_material_design_icons/flutter_material_design_icons.dart'; import 'package:flutter_mozilla_components/flutter_mozilla_components.dart'; -import 'package:go_router/go_router.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:nullability/nullability.dart'; -import 'package:universal_io/io.dart'; import 'package:weblibre/core/routing/routes.dart'; import 'package:weblibre/features/settings/presentation/controllers/save_settings.dart'; import 'package:weblibre/features/user/data/models/engine_settings.dart'; @@ -22,11 +19,6 @@ class WebEngineSettingsScreen extends HookConsumerWidget { final generalSettings = ref.watch(generalSettingsRepositoryProvider); final engineSettings = ref.watch(engineSettingsRepositoryProvider); - final userAgentTextController = useTextEditingController( - text: engineSettings.userAgent, - keys: [engineSettings.userAgent], - ); - return Scaffold( appBar: AppBar(title: const Text('Web Engine Settings')), body: FadingScroll( @@ -103,23 +95,6 @@ class WebEngineSettingsScreen extends HookConsumerWidget { ], ), ), - SwitchListTile.adaptive( - title: const Text('Enable JavaScript'), - subtitle: const Text( - 'While turning off JavaScript boosts security, privacy, and speed, it may cause some sites to not work as intended.', - ), - // ignore: deprecated_member_use use this icon for now - secondary: const Icon(MdiIcons.languageJavascript), - value: engineSettings.javascriptEnabled, - onChanged: (value) async { - await ref - .read(saveEngineSettingsControllerProvider.notifier) - .save( - (currentSettings) => - currentSettings.copyWith.javascriptEnabled(value), - ); - }, - ), SwitchListTile.adaptive( title: const Text('Enable Global Privacy Control (GPC)'), secondary: const Icon(MdiIcons.incognitoCircleOff), @@ -306,55 +281,6 @@ class WebEngineSettingsScreen extends HookConsumerWidget { ], ), ), - ListTile( - leading: const Icon(MdiIcons.cardAccountDetails), - title: TextField( - controller: userAgentTextController, - decoration: const InputDecoration( - labelText: 'Custom User Agent', - floatingLabelBehavior: FloatingLabelBehavior.always, - hintText: 'Mozilla/5.0 …', - ), - onSubmitted: (value) async { - await ref - .read(saveEngineSettingsControllerProvider.notifier) - .save( - (currentSettings) => - currentSettings.copyWith.userAgent(value), - ); - - if (context.mounted) { - final restart = await showDialog( - context: context, - builder: (context) => AlertDialog( - title: const Text('User Agent Changed'), - content: const Text( - 'The app needs to restart for the new user agent to take effect', - ), - actions: [ - TextButton( - onPressed: () { - context.pop(false); - }, - child: const Text('Later'), - ), - TextButton( - onPressed: () { - context.pop(true); - }, - child: const Text('Restart Now'), - ), - ], - ), - ); - - if (restart == true) { - exit(0); - } - } - }, - ), - ), ListTile( title: const Text('Web Engine Hardening'), contentPadding: const EdgeInsets.symmetric(