From 69aad79b93a795d3c12fe70d81b7f7610ba6c35a Mon Sep 17 00:00:00 2001 From: Fabian Freund Date: Sat, 6 Jun 2026 08:26:03 +0200 Subject: [PATCH] setting to show close button on new/edit tab screen --- .../search/presentation/screens/search.dart | 20 +++++++- .../screens/general_settings.dart | 46 +++++++++++++++++++ .../user/data/models/general_settings.dart | 9 ++++ .../user/data/models/general_settings.g.dart | 16 +++++++ .../domain/repositories/general_settings.dart | 4 ++ .../repositories/general_settings.g.dart | 2 +- 6 files changed, 95 insertions(+), 2 deletions(-) diff --git a/apps/weblibre/lib/features/geckoview/features/search/presentation/screens/search.dart b/apps/weblibre/lib/features/geckoview/features/search/presentation/screens/search.dart index 127ea2c5..6b51ea81 100644 --- a/apps/weblibre/lib/features/geckoview/features/search/presentation/screens/search.dart +++ b/apps/weblibre/lib/features/geckoview/features/search/presentation/screens/search.dart @@ -22,6 +22,7 @@ import 'dart:async'; import 'package:fading_scroll/fading_scroll.dart'; 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 'package:weblibre/core/design/app_colors.dart'; import 'package:weblibre/core/routing/routes.dart'; @@ -627,6 +628,12 @@ class SearchScreen extends HookConsumerWidget { }; } + // Whether to surface an in-app close button so the page can be dismissed + // without a system back button/gesture (opt-in, e.g. for e-ink devices). + // Only meaningful when there is a route to pop back to. + final showCloseButton = + context.canPop() && settings.showSearchCloseButton; + return Scaffold( body: SafeArea( child: Form( @@ -638,11 +645,22 @@ class SearchScreen extends HookConsumerWidget { floating: true, pinned: true, automaticallyImplyLeading: false, + leading: showCloseButton + ? IconButton( + tooltip: 'Close', + icon: const Icon(Icons.close), + onPressed: () => context.pop(), + ) + : null, backgroundColor: colorScheme.surface, scrolledUnderElevation: 0, shadowColor: Colors.transparent, surfaceTintColor: Colors.transparent, - toolbarHeight: isEditMode ? 0 : kToolbarHeight, + // Collapse the toolbar in edit mode (no tab-type switcher), but + // keep it when the close button needs somewhere to render. + toolbarHeight: (isEditMode && !showCloseButton) + ? 0 + : kToolbarHeight, titleSpacing: 0.0, title: isEditMode ? null diff --git a/apps/weblibre/lib/features/settings/presentation/screens/general_settings.dart b/apps/weblibre/lib/features/settings/presentation/screens/general_settings.dart index 303a31f2..9faebeea 100644 --- a/apps/weblibre/lib/features/settings/presentation/screens/general_settings.dart +++ b/apps/weblibre/lib/features/settings/presentation/screens/general_settings.dart @@ -76,6 +76,21 @@ const List generalSettingsSections = [ keywords: ['dialogs', 'bottom sheets', 'overlay'], child: _ShowModalBarrierTile(), ), + SettingsEntryDefinition( + title: 'Show Close Button', + subtitle: 'Add a button to dismiss the search / new-tab page without ' + 'a back gesture', + keywords: [ + 'back', + 'close', + 'dismiss', + 'e-ink', + 'eink', + 'accessibility', + 'new tab', + ], + child: _ShowSearchCloseButtonTile(), + ), ], ), SettingsSectionDefinition( @@ -282,6 +297,37 @@ class _ShowModalBarrierTile extends HookConsumerWidget { } } +class _ShowSearchCloseButtonTile extends HookConsumerWidget { + const _ShowSearchCloseButtonTile(); + + @override + Widget build(BuildContext context, WidgetRef ref) { + final showSearchCloseButton = ref.watch( + generalSettingsWithDefaultsProvider.select( + (s) => s.showSearchCloseButton, + ), + ); + + return SwitchListTile.adaptive( + title: const Text('Show Close Button'), + subtitle: const Text( + 'Add a button to dismiss the search / new-tab page without a back ' + 'gesture, useful on devices without a back button', + ), + secondary: const Icon(Icons.close), + value: showSearchCloseButton, + onChanged: (value) async { + await ref + .read(saveGeneralSettingsControllerProvider.notifier) + .save( + (currentSettings) => + currentSettings.copyWith.showSearchCloseButton(value), + ); + }, + ); + } +} + class _PureBlackTile extends HookConsumerWidget { const _PureBlackTile(); diff --git a/apps/weblibre/lib/features/user/data/models/general_settings.dart b/apps/weblibre/lib/features/user/data/models/general_settings.dart index 7cba7581..4ad79df7 100644 --- a/apps/weblibre/lib/features/user/data/models/general_settings.dart +++ b/apps/weblibre/lib/features/user/data/models/general_settings.dart @@ -91,6 +91,11 @@ class GeneralSettings with FastEquatable { final bool enableLocalAiFeatures; final bool showContainerUi; final bool showIsolatedTabUi; + + /// Whether the search / new-tab page shows a leading close button so it can + /// be dismissed without a system back button or back gesture (e.g. on e-ink + /// devices). Defaults to false. Only shown when the route can be popped. + final bool showSearchCloseButton; @JsonKey(name: 'defaultCreateTabType') final TabType storedDefaultCreateTabType; final TabDirection tabListDirection; @@ -164,6 +169,7 @@ class GeneralSettings with FastEquatable { required this.enableLocalAiFeatures, required this.showContainerUi, required this.showIsolatedTabUi, + required this.showSearchCloseButton, required this.storedDefaultCreateTabType, required this.tabListDirection, required this.tabBarDirection, @@ -225,6 +231,7 @@ class GeneralSettings with FastEquatable { bool? enableLocalAiFeatures, bool? showContainerUi, bool? showIsolatedTabUi, + bool? showSearchCloseButton, TabType? storedDefaultCreateTabType, TabDirection? tabListDirection, TabDirection? tabBarDirection, @@ -283,6 +290,7 @@ class GeneralSettings with FastEquatable { enableLocalAiFeatures = enableLocalAiFeatures ?? true, showContainerUi = showContainerUi ?? true, showIsolatedTabUi = showIsolatedTabUi ?? true, + showSearchCloseButton = showSearchCloseButton ?? false, storedDefaultCreateTabType = storedDefaultCreateTabType ?? TabType.regular, tabListDirection = tabListDirection ?? TabDirection.newestFirst, @@ -406,6 +414,7 @@ class GeneralSettings with FastEquatable { enableLocalAiFeatures, showContainerUi, showIsolatedTabUi, + showSearchCloseButton, storedDefaultCreateTabType, tabListDirection, tabBarDirection, diff --git a/apps/weblibre/lib/features/user/data/models/general_settings.g.dart b/apps/weblibre/lib/features/user/data/models/general_settings.g.dart index 4d1cb27c..069e8866 100644 --- a/apps/weblibre/lib/features/user/data/models/general_settings.g.dart +++ b/apps/weblibre/lib/features/user/data/models/general_settings.g.dart @@ -39,6 +39,8 @@ abstract class _$GeneralSettingsCWProxy { GeneralSettings showIsolatedTabUi(bool showIsolatedTabUi); + GeneralSettings showSearchCloseButton(bool showSearchCloseButton); + GeneralSettings storedDefaultCreateTabType( TabType storedDefaultCreateTabType, ); @@ -167,6 +169,7 @@ abstract class _$GeneralSettingsCWProxy { bool enableLocalAiFeatures, bool showContainerUi, bool showIsolatedTabUi, + bool showSearchCloseButton, TabType storedDefaultCreateTabType, TabDirection tabListDirection, TabDirection tabBarDirection, @@ -279,6 +282,10 @@ class _$GeneralSettingsCWProxyImpl implements _$GeneralSettingsCWProxy { GeneralSettings showIsolatedTabUi(bool showIsolatedTabUi) => call(showIsolatedTabUi: showIsolatedTabUi); + @override + GeneralSettings showSearchCloseButton(bool showSearchCloseButton) => + call(showSearchCloseButton: showSearchCloseButton); + @override GeneralSettings storedDefaultCreateTabType( TabType storedDefaultCreateTabType, @@ -490,6 +497,7 @@ class _$GeneralSettingsCWProxyImpl implements _$GeneralSettingsCWProxy { Object? enableLocalAiFeatures = const $CopyWithPlaceholder(), Object? showContainerUi = const $CopyWithPlaceholder(), Object? showIsolatedTabUi = const $CopyWithPlaceholder(), + Object? showSearchCloseButton = const $CopyWithPlaceholder(), Object? storedDefaultCreateTabType = const $CopyWithPlaceholder(), Object? tabListDirection = const $CopyWithPlaceholder(), Object? tabBarDirection = const $CopyWithPlaceholder(), @@ -616,6 +624,12 @@ class _$GeneralSettingsCWProxyImpl implements _$GeneralSettingsCWProxy { ? _value.showIsolatedTabUi // ignore: cast_nullable_to_non_nullable : showIsolatedTabUi as bool, + showSearchCloseButton: + showSearchCloseButton == const $CopyWithPlaceholder() || + showSearchCloseButton == null + ? _value.showSearchCloseButton + // ignore: cast_nullable_to_non_nullable + : showSearchCloseButton as bool, storedDefaultCreateTabType: storedDefaultCreateTabType == const $CopyWithPlaceholder() || storedDefaultCreateTabType == null @@ -916,6 +930,7 @@ GeneralSettings _$GeneralSettingsFromJson( enableLocalAiFeatures: json['enableLocalAiFeatures'] as bool?, showContainerUi: json['showContainerUi'] as bool?, showIsolatedTabUi: json['showIsolatedTabUi'] as bool?, + showSearchCloseButton: json['showSearchCloseButton'] as bool?, storedDefaultCreateTabType: $enumDecodeNullable( _$TabTypeEnumMap, json['defaultCreateTabType'], @@ -1029,6 +1044,7 @@ Map _$GeneralSettingsToJson( 'enableLocalAiFeatures': instance.enableLocalAiFeatures, 'showContainerUi': instance.showContainerUi, 'showIsolatedTabUi': instance.showIsolatedTabUi, + 'showSearchCloseButton': instance.showSearchCloseButton, 'defaultCreateTabType': _$TabTypeEnumMap[instance.storedDefaultCreateTabType]!, 'tabListDirection': _$TabDirectionEnumMap[instance.tabListDirection]!, diff --git a/apps/weblibre/lib/features/user/domain/repositories/general_settings.dart b/apps/weblibre/lib/features/user/domain/repositories/general_settings.dart index 765dd93f..4ecea4fb 100644 --- a/apps/weblibre/lib/features/user/domain/repositories/general_settings.dart +++ b/apps/weblibre/lib/features/user/domain/repositories/general_settings.dart @@ -269,6 +269,10 @@ class GeneralSettingsRepository extends _$GeneralSettingsRepository { DriftSqlType.bool, db.typeMapping, ), + 'showSearchCloseButton': settings['showSearchCloseButton']?.readAs( + DriftSqlType.bool, + db.typeMapping, + ), }); } diff --git a/apps/weblibre/lib/features/user/domain/repositories/general_settings.g.dart b/apps/weblibre/lib/features/user/domain/repositories/general_settings.g.dart index fd3d0aeb..5dbcdb27 100644 --- a/apps/weblibre/lib/features/user/domain/repositories/general_settings.g.dart +++ b/apps/weblibre/lib/features/user/domain/repositories/general_settings.g.dart @@ -35,7 +35,7 @@ final class GeneralSettingsRepositoryProvider } String _$generalSettingsRepositoryHash() => - r'5036124c086e35c0e4616a0fd3b2276adb66dd5f'; + r'6cf0832a8497c94a813e06556c048a1010be74e1'; abstract class _$GeneralSettingsRepository extends $StreamNotifier {