setting to show close button on new/edit tab screen

This commit is contained in:
Fabian Freund
2026-06-06 08:26:03 +02:00
parent b0ac6c97b0
commit 69aad79b93
6 changed files with 95 additions and 2 deletions
@@ -22,6 +22,7 @@ import 'dart:async';
import 'package:fading_scroll/fading_scroll.dart'; import 'package:fading_scroll/fading_scroll.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:go_router/go_router.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:weblibre/core/design/app_colors.dart'; import 'package:weblibre/core/design/app_colors.dart';
import 'package:weblibre/core/routing/routes.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( return Scaffold(
body: SafeArea( body: SafeArea(
child: Form( child: Form(
@@ -638,11 +645,22 @@ class SearchScreen extends HookConsumerWidget {
floating: true, floating: true,
pinned: true, pinned: true,
automaticallyImplyLeading: false, automaticallyImplyLeading: false,
leading: showCloseButton
? IconButton(
tooltip: 'Close',
icon: const Icon(Icons.close),
onPressed: () => context.pop(),
)
: null,
backgroundColor: colorScheme.surface, backgroundColor: colorScheme.surface,
scrolledUnderElevation: 0, scrolledUnderElevation: 0,
shadowColor: Colors.transparent, shadowColor: Colors.transparent,
surfaceTintColor: 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, titleSpacing: 0.0,
title: isEditMode title: isEditMode
? null ? null
@@ -76,6 +76,21 @@ const List<SettingsSectionDefinition> generalSettingsSections = [
keywords: ['dialogs', 'bottom sheets', 'overlay'], keywords: ['dialogs', 'bottom sheets', 'overlay'],
child: _ShowModalBarrierTile(), 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( 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 { class _PureBlackTile extends HookConsumerWidget {
const _PureBlackTile(); const _PureBlackTile();
@@ -91,6 +91,11 @@ class GeneralSettings with FastEquatable {
final bool enableLocalAiFeatures; final bool enableLocalAiFeatures;
final bool showContainerUi; final bool showContainerUi;
final bool showIsolatedTabUi; 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') @JsonKey(name: 'defaultCreateTabType')
final TabType storedDefaultCreateTabType; final TabType storedDefaultCreateTabType;
final TabDirection tabListDirection; final TabDirection tabListDirection;
@@ -164,6 +169,7 @@ class GeneralSettings with FastEquatable {
required this.enableLocalAiFeatures, required this.enableLocalAiFeatures,
required this.showContainerUi, required this.showContainerUi,
required this.showIsolatedTabUi, required this.showIsolatedTabUi,
required this.showSearchCloseButton,
required this.storedDefaultCreateTabType, required this.storedDefaultCreateTabType,
required this.tabListDirection, required this.tabListDirection,
required this.tabBarDirection, required this.tabBarDirection,
@@ -225,6 +231,7 @@ class GeneralSettings with FastEquatable {
bool? enableLocalAiFeatures, bool? enableLocalAiFeatures,
bool? showContainerUi, bool? showContainerUi,
bool? showIsolatedTabUi, bool? showIsolatedTabUi,
bool? showSearchCloseButton,
TabType? storedDefaultCreateTabType, TabType? storedDefaultCreateTabType,
TabDirection? tabListDirection, TabDirection? tabListDirection,
TabDirection? tabBarDirection, TabDirection? tabBarDirection,
@@ -283,6 +290,7 @@ class GeneralSettings with FastEquatable {
enableLocalAiFeatures = enableLocalAiFeatures ?? true, enableLocalAiFeatures = enableLocalAiFeatures ?? true,
showContainerUi = showContainerUi ?? true, showContainerUi = showContainerUi ?? true,
showIsolatedTabUi = showIsolatedTabUi ?? true, showIsolatedTabUi = showIsolatedTabUi ?? true,
showSearchCloseButton = showSearchCloseButton ?? false,
storedDefaultCreateTabType = storedDefaultCreateTabType =
storedDefaultCreateTabType ?? TabType.regular, storedDefaultCreateTabType ?? TabType.regular,
tabListDirection = tabListDirection ?? TabDirection.newestFirst, tabListDirection = tabListDirection ?? TabDirection.newestFirst,
@@ -406,6 +414,7 @@ class GeneralSettings with FastEquatable {
enableLocalAiFeatures, enableLocalAiFeatures,
showContainerUi, showContainerUi,
showIsolatedTabUi, showIsolatedTabUi,
showSearchCloseButton,
storedDefaultCreateTabType, storedDefaultCreateTabType,
tabListDirection, tabListDirection,
tabBarDirection, tabBarDirection,
@@ -39,6 +39,8 @@ abstract class _$GeneralSettingsCWProxy {
GeneralSettings showIsolatedTabUi(bool showIsolatedTabUi); GeneralSettings showIsolatedTabUi(bool showIsolatedTabUi);
GeneralSettings showSearchCloseButton(bool showSearchCloseButton);
GeneralSettings storedDefaultCreateTabType( GeneralSettings storedDefaultCreateTabType(
TabType storedDefaultCreateTabType, TabType storedDefaultCreateTabType,
); );
@@ -167,6 +169,7 @@ abstract class _$GeneralSettingsCWProxy {
bool enableLocalAiFeatures, bool enableLocalAiFeatures,
bool showContainerUi, bool showContainerUi,
bool showIsolatedTabUi, bool showIsolatedTabUi,
bool showSearchCloseButton,
TabType storedDefaultCreateTabType, TabType storedDefaultCreateTabType,
TabDirection tabListDirection, TabDirection tabListDirection,
TabDirection tabBarDirection, TabDirection tabBarDirection,
@@ -279,6 +282,10 @@ class _$GeneralSettingsCWProxyImpl implements _$GeneralSettingsCWProxy {
GeneralSettings showIsolatedTabUi(bool showIsolatedTabUi) => GeneralSettings showIsolatedTabUi(bool showIsolatedTabUi) =>
call(showIsolatedTabUi: showIsolatedTabUi); call(showIsolatedTabUi: showIsolatedTabUi);
@override
GeneralSettings showSearchCloseButton(bool showSearchCloseButton) =>
call(showSearchCloseButton: showSearchCloseButton);
@override @override
GeneralSettings storedDefaultCreateTabType( GeneralSettings storedDefaultCreateTabType(
TabType storedDefaultCreateTabType, TabType storedDefaultCreateTabType,
@@ -490,6 +497,7 @@ class _$GeneralSettingsCWProxyImpl implements _$GeneralSettingsCWProxy {
Object? enableLocalAiFeatures = const $CopyWithPlaceholder(), Object? enableLocalAiFeatures = const $CopyWithPlaceholder(),
Object? showContainerUi = const $CopyWithPlaceholder(), Object? showContainerUi = const $CopyWithPlaceholder(),
Object? showIsolatedTabUi = const $CopyWithPlaceholder(), Object? showIsolatedTabUi = const $CopyWithPlaceholder(),
Object? showSearchCloseButton = const $CopyWithPlaceholder(),
Object? storedDefaultCreateTabType = const $CopyWithPlaceholder(), Object? storedDefaultCreateTabType = const $CopyWithPlaceholder(),
Object? tabListDirection = const $CopyWithPlaceholder(), Object? tabListDirection = const $CopyWithPlaceholder(),
Object? tabBarDirection = const $CopyWithPlaceholder(), Object? tabBarDirection = const $CopyWithPlaceholder(),
@@ -616,6 +624,12 @@ class _$GeneralSettingsCWProxyImpl implements _$GeneralSettingsCWProxy {
? _value.showIsolatedTabUi ? _value.showIsolatedTabUi
// ignore: cast_nullable_to_non_nullable // ignore: cast_nullable_to_non_nullable
: showIsolatedTabUi as bool, : showIsolatedTabUi as bool,
showSearchCloseButton:
showSearchCloseButton == const $CopyWithPlaceholder() ||
showSearchCloseButton == null
? _value.showSearchCloseButton
// ignore: cast_nullable_to_non_nullable
: showSearchCloseButton as bool,
storedDefaultCreateTabType: storedDefaultCreateTabType:
storedDefaultCreateTabType == const $CopyWithPlaceholder() || storedDefaultCreateTabType == const $CopyWithPlaceholder() ||
storedDefaultCreateTabType == null storedDefaultCreateTabType == null
@@ -916,6 +930,7 @@ GeneralSettings _$GeneralSettingsFromJson(
enableLocalAiFeatures: json['enableLocalAiFeatures'] as bool?, enableLocalAiFeatures: json['enableLocalAiFeatures'] as bool?,
showContainerUi: json['showContainerUi'] as bool?, showContainerUi: json['showContainerUi'] as bool?,
showIsolatedTabUi: json['showIsolatedTabUi'] as bool?, showIsolatedTabUi: json['showIsolatedTabUi'] as bool?,
showSearchCloseButton: json['showSearchCloseButton'] as bool?,
storedDefaultCreateTabType: $enumDecodeNullable( storedDefaultCreateTabType: $enumDecodeNullable(
_$TabTypeEnumMap, _$TabTypeEnumMap,
json['defaultCreateTabType'], json['defaultCreateTabType'],
@@ -1029,6 +1044,7 @@ Map<String, dynamic> _$GeneralSettingsToJson(
'enableLocalAiFeatures': instance.enableLocalAiFeatures, 'enableLocalAiFeatures': instance.enableLocalAiFeatures,
'showContainerUi': instance.showContainerUi, 'showContainerUi': instance.showContainerUi,
'showIsolatedTabUi': instance.showIsolatedTabUi, 'showIsolatedTabUi': instance.showIsolatedTabUi,
'showSearchCloseButton': instance.showSearchCloseButton,
'defaultCreateTabType': 'defaultCreateTabType':
_$TabTypeEnumMap[instance.storedDefaultCreateTabType]!, _$TabTypeEnumMap[instance.storedDefaultCreateTabType]!,
'tabListDirection': _$TabDirectionEnumMap[instance.tabListDirection]!, 'tabListDirection': _$TabDirectionEnumMap[instance.tabListDirection]!,
@@ -269,6 +269,10 @@ class GeneralSettingsRepository extends _$GeneralSettingsRepository {
DriftSqlType.bool, DriftSqlType.bool,
db.typeMapping, db.typeMapping,
), ),
'showSearchCloseButton': settings['showSearchCloseButton']?.readAs(
DriftSqlType.bool,
db.typeMapping,
),
}); });
} }
@@ -35,7 +35,7 @@ final class GeneralSettingsRepositoryProvider
} }
String _$generalSettingsRepositoryHash() => String _$generalSettingsRepositoryHash() =>
r'5036124c086e35c0e4616a0fd3b2276adb66dd5f'; r'6cf0832a8497c94a813e06556c048a1010be74e1';
abstract class _$GeneralSettingsRepository abstract class _$GeneralSettingsRepository
extends $StreamNotifier<GeneralSettings> { extends $StreamNotifier<GeneralSettings> {