new setting to hide tab bar title

This commit is contained in:
Fabian Freund
2026-03-04 03:31:03 +01:00
parent ec14286177
commit 08a2fafc41
7 changed files with 227 additions and 2 deletions
@@ -35,6 +35,141 @@ import 'package:weblibre/features/geckoview/features/browser/presentation/widget
import 'package:weblibre/features/geckoview/features/tabs/data/entities/tab_mode.dart'; import 'package:weblibre/features/geckoview/features/tabs/data/entities/tab_mode.dart';
import 'package:weblibre/presentation/widgets/uri_breadcrumb.dart'; import 'package:weblibre/presentation/widgets/uri_breadcrumb.dart';
class CompactAppBarTitle extends HookConsumerWidget {
const CompactAppBarTitle({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
final theme = Theme.of(context);
final appColors = AppColors.of(context);
final tabState = ref.watch(selectedTabStateProvider);
final isTabTuneledAsync = ref.watch(isTabTunneledProvider(tabState?.id));
final showSiteSettingsBadge = ref.watch(
showSiteSettingsBadgeProvider.select((value) => value.value == true),
);
if (tabState == null) {
return const SizedBox.shrink();
}
final icon = useMemoized(() {
if (tabState.url.isHttp) {
return Icon(
MdiIcons.lockOff,
color: Theme.of(context).colorScheme.error,
size: 16,
);
} else if (tabState.readerableState.active) {
return const Icon(MdiIcons.lockMinus, size: 16);
} else if (!tabState.securityInfoState.secure) {
return Icon(
MdiIcons.lockAlert,
color: Theme.of(context).colorScheme.errorContainer,
size: 16,
);
} else if (!tabState.isLoading) {
return const Icon(MdiIcons.lock, size: 16);
} else {
return const Icon(MdiIcons.timerSand, size: 16);
}
}, [tabState]);
return Row(
children: [
ToolbarButton(
onTap: () {
ref
.read(bottomSheetControllerProvider.notifier)
.show(SiteSettingsSheet(tabState: tabState));
},
child: Padding(
padding: const EdgeInsets.only(right: 4.0),
child: Stack(
clipBehavior: Clip.none,
children: [
TabIcon(tabState: tabState, iconSize: 24),
Positioned(
top: -4,
right: -4,
child: Icon(
MdiIcons.shieldHalfFull,
size: 10,
color: showSiteSettingsBadge
? appColors.warningAmber
: Colors.green,
),
),
],
),
),
),
Expanded(
child: GestureDetector(
onTap: () async {
final searchText = tabState.url.scheme == 'about'
? ''
: tabState.url.toString();
await SearchRoute(
tabId: tabState.id,
searchText: searchText.isEmpty
? SearchRoute.emptySearchText
: searchText,
tabType: tabState.tabMode.toTabType(),
).push(context);
},
child: Container(
padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 12),
decoration: BoxDecoration(
color: theme.colorScheme.surfaceContainerHighest,
borderRadius: BorderRadius.circular(24),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: [
if (tabState.tabMode is PrivateTabMode) ...[
Icon(
MdiIcons.dominoMask,
color: appColors.privateTabPurple,
size: 16,
),
const SizedBox(width: 4),
] else if (tabState.tabMode is IsolatedTabMode) ...[
Icon(
MdiIcons.snowflake,
color: appColors.isolatedTabTeal,
size: 16,
),
const SizedBox(width: 4),
],
if (isTabTuneledAsync.hasValue &&
isTabTuneledAsync.value == true) ...[
const Icon(MdiIcons.tunnelOutline, size: 16),
const SizedBox(width: 4),
],
icon,
const SizedBox(width: 6),
Flexible(
child: UriBreadcrumb(
uri: tabState.url,
style: theme.textTheme.bodyMedium?.copyWith(
color: theme.colorScheme.onSurface,
),
),
),
],
),
),
),
),
const SizedBox(width: 8.0),
],
);
}
}
class AppBarTitle extends HookConsumerWidget { class AppBarTitle extends HookConsumerWidget {
const AppBarTitle({super.key}); const AppBarTitle({super.key});
@@ -291,7 +291,9 @@ class BrowserTabBar extends HookConsumerWidget {
: null, : null,
title: title:
(selectedTabId != null && displayedSheet is! ViewTabsSheet) (selectedTabId != null && displayedSheet is! ViewTabsSheet)
? const AppBarTitle() ? settings.tabBarLayout == TabBarLayout.compact
? const CompactAppBarTitle()
: const AppBarTitle()
: null, : null,
actions: [ actions: [
if (selectedTabId != null && displayedSheet is! ViewTabsSheet) if (selectedTabId != null && displayedSheet is! ViewTabsSheet)
@@ -76,6 +76,7 @@ class _TabBarLayoutSection extends StatelessWidget {
children: [ children: [
SettingSection(name: 'Tab Bar Layout'), SettingSection(name: 'Tab Bar Layout'),
_TabBarPositionSection(), _TabBarPositionSection(),
_TabBarLayoutModeSection(),
_ShowContextualTabBarTile(), _ShowContextualTabBarTile(),
_AutoHideTabBarTile(), _AutoHideTabBarTile(),
_BottomSheetTabViewTile(), _BottomSheetTabViewTile(),
@@ -287,6 +288,59 @@ class _TabBarPositionSection extends HookConsumerWidget {
} }
} }
class _TabBarLayoutModeSection extends HookConsumerWidget {
const _TabBarLayoutModeSection();
@override
Widget build(BuildContext context, WidgetRef ref) {
final tabBarLayout = ref.watch(
generalSettingsWithDefaultsProvider.select((s) => s.tabBarLayout),
);
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const ListTile(
title: Text('Tab Bar Style'),
leading: Icon(MdiIcons.tabUnselected),
contentPadding: EdgeInsets.zero,
),
RadioGroup(
groupValue: tabBarLayout,
onChanged: (value) async {
if (value != null) {
await ref
.read(saveGeneralSettingsControllerProvider.notifier)
.save(
(currentSettings) =>
currentSettings.copyWith.tabBarLayout(value),
);
}
},
child: const Column(
children: [
RadioListTile.adaptive(
value: TabBarLayout.withTitle,
title: Text('With Title'),
subtitle: Text('Shows page title and URL breadcrumb'),
),
RadioListTile.adaptive(
value: TabBarLayout.compact,
title: Text('Compact'),
subtitle: Text('Centered URL pill without page title'),
),
],
),
),
],
),
);
}
}
class _ShowContextualTabBarTile extends HookConsumerWidget { class _ShowContextualTabBarTile extends HookConsumerWidget {
const _ShowContextualTabBarTile(); const _ShowContextualTabBarTile();
@@ -42,6 +42,8 @@ enum TabIntentOpenSetting { regular, private, ask }
enum TabBarPosition { top, bottom } enum TabBarPosition { top, bottom }
enum TabBarLayout { withTitle, compact }
enum DeleteBrowsingDataType { enum DeleteBrowsingDataType {
tabs('Open tabs'), tabs('Open tabs'),
history('Browsing history'), history('Browsing history'),
@@ -82,6 +84,7 @@ class GeneralSettings with FastEquatable {
final bool tabBarShowContextualBar; final bool tabBarShowContextualBar;
final bool tabBarShowQuickTabSwitcherBar; final bool tabBarShowQuickTabSwitcherBar;
final TabBarPosition tabBarPosition; final TabBarPosition tabBarPosition;
final TabBarLayout tabBarLayout;
final QuickTabSwitcherMode quickTabSwitcherMode; final QuickTabSwitcherMode quickTabSwitcherMode;
final bool pullToRefreshEnabled; final bool pullToRefreshEnabled;
final bool useExternalDownloadManager; final bool useExternalDownloadManager;
@@ -127,6 +130,7 @@ class GeneralSettings with FastEquatable {
required this.tabBarShowContextualBar, required this.tabBarShowContextualBar,
required this.tabBarShowQuickTabSwitcherBar, required this.tabBarShowQuickTabSwitcherBar,
required this.tabBarPosition, required this.tabBarPosition,
required this.tabBarLayout,
required this.quickTabSwitcherMode, required this.quickTabSwitcherMode,
required this.pullToRefreshEnabled, required this.pullToRefreshEnabled,
required this.useExternalDownloadManager, required this.useExternalDownloadManager,
@@ -173,6 +177,7 @@ class GeneralSettings with FastEquatable {
bool? tabBarShowContextualBar, bool? tabBarShowContextualBar,
bool? tabBarShowQuickTabSwitcherBar, bool? tabBarShowQuickTabSwitcherBar,
TabBarPosition? tabBarPosition, TabBarPosition? tabBarPosition,
TabBarLayout? tabBarLayout,
QuickTabSwitcherMode? quickTabSwitcherMode, QuickTabSwitcherMode? quickTabSwitcherMode,
bool? pullToRefreshEnabled, bool? pullToRefreshEnabled,
bool? useExternalDownloadManager, bool? useExternalDownloadManager,
@@ -219,6 +224,7 @@ class GeneralSettings with FastEquatable {
tabBarShowContextualBar = tabBarShowContextualBar ?? true, tabBarShowContextualBar = tabBarShowContextualBar ?? true,
tabBarShowQuickTabSwitcherBar = tabBarShowQuickTabSwitcherBar ?? true, tabBarShowQuickTabSwitcherBar = tabBarShowQuickTabSwitcherBar ?? true,
tabBarPosition = tabBarPosition ?? TabBarPosition.bottom, tabBarPosition = tabBarPosition ?? TabBarPosition.bottom,
tabBarLayout = tabBarLayout ?? TabBarLayout.withTitle,
quickTabSwitcherMode = quickTabSwitcherMode =
quickTabSwitcherMode ?? QuickTabSwitcherMode.lastUsedTabs, quickTabSwitcherMode ?? QuickTabSwitcherMode.lastUsedTabs,
pullToRefreshEnabled = pullToRefreshEnabled ?? true, pullToRefreshEnabled = pullToRefreshEnabled ?? true,
@@ -292,6 +298,7 @@ class GeneralSettings with FastEquatable {
tabBarShowContextualBar, tabBarShowContextualBar,
tabBarShowQuickTabSwitcherBar, tabBarShowQuickTabSwitcherBar,
tabBarPosition, tabBarPosition,
tabBarLayout,
quickTabSwitcherMode, quickTabSwitcherMode,
pullToRefreshEnabled, pullToRefreshEnabled,
useExternalDownloadManager, useExternalDownloadManager,
@@ -59,6 +59,8 @@ abstract class _$GeneralSettingsCWProxy {
GeneralSettings tabBarPosition(TabBarPosition tabBarPosition); GeneralSettings tabBarPosition(TabBarPosition tabBarPosition);
GeneralSettings tabBarLayout(TabBarLayout tabBarLayout);
GeneralSettings quickTabSwitcherMode( GeneralSettings quickTabSwitcherMode(
QuickTabSwitcherMode quickTabSwitcherMode, QuickTabSwitcherMode quickTabSwitcherMode,
); );
@@ -140,6 +142,7 @@ abstract class _$GeneralSettingsCWProxy {
bool tabBarShowContextualBar, bool tabBarShowContextualBar,
bool tabBarShowQuickTabSwitcherBar, bool tabBarShowQuickTabSwitcherBar,
TabBarPosition tabBarPosition, TabBarPosition tabBarPosition,
TabBarLayout tabBarLayout,
QuickTabSwitcherMode quickTabSwitcherMode, QuickTabSwitcherMode quickTabSwitcherMode,
bool pullToRefreshEnabled, bool pullToRefreshEnabled,
bool useExternalDownloadManager, bool useExternalDownloadManager,
@@ -260,6 +263,10 @@ class _$GeneralSettingsCWProxyImpl implements _$GeneralSettingsCWProxy {
GeneralSettings tabBarPosition(TabBarPosition tabBarPosition) => GeneralSettings tabBarPosition(TabBarPosition tabBarPosition) =>
call(tabBarPosition: tabBarPosition); call(tabBarPosition: tabBarPosition);
@override
GeneralSettings tabBarLayout(TabBarLayout tabBarLayout) =>
call(tabBarLayout: tabBarLayout);
@override @override
GeneralSettings quickTabSwitcherMode( GeneralSettings quickTabSwitcherMode(
QuickTabSwitcherMode quickTabSwitcherMode, QuickTabSwitcherMode quickTabSwitcherMode,
@@ -386,6 +393,7 @@ class _$GeneralSettingsCWProxyImpl implements _$GeneralSettingsCWProxy {
Object? tabBarShowContextualBar = const $CopyWithPlaceholder(), Object? tabBarShowContextualBar = const $CopyWithPlaceholder(),
Object? tabBarShowQuickTabSwitcherBar = const $CopyWithPlaceholder(), Object? tabBarShowQuickTabSwitcherBar = const $CopyWithPlaceholder(),
Object? tabBarPosition = const $CopyWithPlaceholder(), Object? tabBarPosition = const $CopyWithPlaceholder(),
Object? tabBarLayout = const $CopyWithPlaceholder(),
Object? quickTabSwitcherMode = const $CopyWithPlaceholder(), Object? quickTabSwitcherMode = const $CopyWithPlaceholder(),
Object? pullToRefreshEnabled = const $CopyWithPlaceholder(), Object? pullToRefreshEnabled = const $CopyWithPlaceholder(),
Object? useExternalDownloadManager = const $CopyWithPlaceholder(), Object? useExternalDownloadManager = const $CopyWithPlaceholder(),
@@ -533,6 +541,11 @@ class _$GeneralSettingsCWProxyImpl implements _$GeneralSettingsCWProxy {
? _value.tabBarPosition ? _value.tabBarPosition
// ignore: cast_nullable_to_non_nullable // ignore: cast_nullable_to_non_nullable
: tabBarPosition as TabBarPosition, : tabBarPosition as TabBarPosition,
tabBarLayout:
tabBarLayout == const $CopyWithPlaceholder() || tabBarLayout == null
? _value.tabBarLayout
// ignore: cast_nullable_to_non_nullable
: tabBarLayout as TabBarLayout,
quickTabSwitcherMode: quickTabSwitcherMode:
quickTabSwitcherMode == const $CopyWithPlaceholder() || quickTabSwitcherMode == const $CopyWithPlaceholder() ||
quickTabSwitcherMode == null quickTabSwitcherMode == null
@@ -727,6 +740,10 @@ GeneralSettings _$GeneralSettingsFromJson(
_$TabBarPositionEnumMap, _$TabBarPositionEnumMap,
json['tabBarPosition'], json['tabBarPosition'],
), ),
tabBarLayout: $enumDecodeNullable(
_$TabBarLayoutEnumMap,
json['tabBarLayout'],
),
quickTabSwitcherMode: $enumDecodeNullable( quickTabSwitcherMode: $enumDecodeNullable(
_$QuickTabSwitcherModeEnumMap, _$QuickTabSwitcherModeEnumMap,
json['quickTabSwitcherMode'], json['quickTabSwitcherMode'],
@@ -795,6 +812,7 @@ Map<String, dynamic> _$GeneralSettingsToJson(
'tabBarShowContextualBar': instance.tabBarShowContextualBar, 'tabBarShowContextualBar': instance.tabBarShowContextualBar,
'tabBarShowQuickTabSwitcherBar': instance.tabBarShowQuickTabSwitcherBar, 'tabBarShowQuickTabSwitcherBar': instance.tabBarShowQuickTabSwitcherBar,
'tabBarPosition': _$TabBarPositionEnumMap[instance.tabBarPosition]!, 'tabBarPosition': _$TabBarPositionEnumMap[instance.tabBarPosition]!,
'tabBarLayout': _$TabBarLayoutEnumMap[instance.tabBarLayout]!,
'quickTabSwitcherMode': 'quickTabSwitcherMode':
_$QuickTabSwitcherModeEnumMap[instance.quickTabSwitcherMode]!, _$QuickTabSwitcherModeEnumMap[instance.quickTabSwitcherMode]!,
'pullToRefreshEnabled': instance.pullToRefreshEnabled, 'pullToRefreshEnabled': instance.pullToRefreshEnabled,
@@ -868,6 +886,11 @@ const _$TabBarPositionEnumMap = {
TabBarPosition.bottom: 'bottom', TabBarPosition.bottom: 'bottom',
}; };
const _$TabBarLayoutEnumMap = {
TabBarLayout.withTitle: 'withTitle',
TabBarLayout.compact: 'compact',
};
const _$QuickTabSwitcherModeEnumMap = { const _$QuickTabSwitcherModeEnumMap = {
QuickTabSwitcherMode.lastUsedTabs: 'lastUsedTabs', QuickTabSwitcherMode.lastUsedTabs: 'lastUsedTabs',
QuickTabSwitcherMode.containerTabs: 'containerTabs', QuickTabSwitcherMode.containerTabs: 'containerTabs',
@@ -126,6 +126,10 @@ class GeneralSettingsRepository extends _$GeneralSettingsRepository {
DriftSqlType.string, DriftSqlType.string,
db.typeMapping, db.typeMapping,
), ),
'tabBarLayout': settings['tabBarLayout']?.readAs(
DriftSqlType.string,
db.typeMapping,
),
'quickTabSwitcherMode': settings['quickTabSwitcherMode']?.readAs( 'quickTabSwitcherMode': settings['quickTabSwitcherMode']?.readAs(
DriftSqlType.string, DriftSqlType.string,
db.typeMapping, db.typeMapping,
@@ -35,7 +35,7 @@ final class GeneralSettingsRepositoryProvider
} }
String _$generalSettingsRepositoryHash() => String _$generalSettingsRepositoryHash() =>
r'2e987b58279ea638157324a03403dfac8437b888'; r'23b15af79f0f41771c20f7c0f7e94f93659ee1e8';
abstract class _$GeneralSettingsRepository abstract class _$GeneralSettingsRepository
extends $StreamNotifier<GeneralSettings> { extends $StreamNotifier<GeneralSettings> {