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/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 {
const AppBarTitle({super.key});
@@ -291,7 +291,9 @@ class BrowserTabBar extends HookConsumerWidget {
: null,
title:
(selectedTabId != null && displayedSheet is! ViewTabsSheet)
? const AppBarTitle()
? settings.tabBarLayout == TabBarLayout.compact
? const CompactAppBarTitle()
: const AppBarTitle()
: null,
actions: [
if (selectedTabId != null && displayedSheet is! ViewTabsSheet)
@@ -76,6 +76,7 @@ class _TabBarLayoutSection extends StatelessWidget {
children: [
SettingSection(name: 'Tab Bar Layout'),
_TabBarPositionSection(),
_TabBarLayoutModeSection(),
_ShowContextualTabBarTile(),
_AutoHideTabBarTile(),
_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 {
const _ShowContextualTabBarTile();
@@ -42,6 +42,8 @@ enum TabIntentOpenSetting { regular, private, ask }
enum TabBarPosition { top, bottom }
enum TabBarLayout { withTitle, compact }
enum DeleteBrowsingDataType {
tabs('Open tabs'),
history('Browsing history'),
@@ -82,6 +84,7 @@ class GeneralSettings with FastEquatable {
final bool tabBarShowContextualBar;
final bool tabBarShowQuickTabSwitcherBar;
final TabBarPosition tabBarPosition;
final TabBarLayout tabBarLayout;
final QuickTabSwitcherMode quickTabSwitcherMode;
final bool pullToRefreshEnabled;
final bool useExternalDownloadManager;
@@ -127,6 +130,7 @@ class GeneralSettings with FastEquatable {
required this.tabBarShowContextualBar,
required this.tabBarShowQuickTabSwitcherBar,
required this.tabBarPosition,
required this.tabBarLayout,
required this.quickTabSwitcherMode,
required this.pullToRefreshEnabled,
required this.useExternalDownloadManager,
@@ -173,6 +177,7 @@ class GeneralSettings with FastEquatable {
bool? tabBarShowContextualBar,
bool? tabBarShowQuickTabSwitcherBar,
TabBarPosition? tabBarPosition,
TabBarLayout? tabBarLayout,
QuickTabSwitcherMode? quickTabSwitcherMode,
bool? pullToRefreshEnabled,
bool? useExternalDownloadManager,
@@ -219,6 +224,7 @@ class GeneralSettings with FastEquatable {
tabBarShowContextualBar = tabBarShowContextualBar ?? true,
tabBarShowQuickTabSwitcherBar = tabBarShowQuickTabSwitcherBar ?? true,
tabBarPosition = tabBarPosition ?? TabBarPosition.bottom,
tabBarLayout = tabBarLayout ?? TabBarLayout.withTitle,
quickTabSwitcherMode =
quickTabSwitcherMode ?? QuickTabSwitcherMode.lastUsedTabs,
pullToRefreshEnabled = pullToRefreshEnabled ?? true,
@@ -292,6 +298,7 @@ class GeneralSettings with FastEquatable {
tabBarShowContextualBar,
tabBarShowQuickTabSwitcherBar,
tabBarPosition,
tabBarLayout,
quickTabSwitcherMode,
pullToRefreshEnabled,
useExternalDownloadManager,
@@ -59,6 +59,8 @@ abstract class _$GeneralSettingsCWProxy {
GeneralSettings tabBarPosition(TabBarPosition tabBarPosition);
GeneralSettings tabBarLayout(TabBarLayout tabBarLayout);
GeneralSettings quickTabSwitcherMode(
QuickTabSwitcherMode quickTabSwitcherMode,
);
@@ -140,6 +142,7 @@ abstract class _$GeneralSettingsCWProxy {
bool tabBarShowContextualBar,
bool tabBarShowQuickTabSwitcherBar,
TabBarPosition tabBarPosition,
TabBarLayout tabBarLayout,
QuickTabSwitcherMode quickTabSwitcherMode,
bool pullToRefreshEnabled,
bool useExternalDownloadManager,
@@ -260,6 +263,10 @@ class _$GeneralSettingsCWProxyImpl implements _$GeneralSettingsCWProxy {
GeneralSettings tabBarPosition(TabBarPosition tabBarPosition) =>
call(tabBarPosition: tabBarPosition);
@override
GeneralSettings tabBarLayout(TabBarLayout tabBarLayout) =>
call(tabBarLayout: tabBarLayout);
@override
GeneralSettings quickTabSwitcherMode(
QuickTabSwitcherMode quickTabSwitcherMode,
@@ -386,6 +393,7 @@ class _$GeneralSettingsCWProxyImpl implements _$GeneralSettingsCWProxy {
Object? tabBarShowContextualBar = const $CopyWithPlaceholder(),
Object? tabBarShowQuickTabSwitcherBar = const $CopyWithPlaceholder(),
Object? tabBarPosition = const $CopyWithPlaceholder(),
Object? tabBarLayout = const $CopyWithPlaceholder(),
Object? quickTabSwitcherMode = const $CopyWithPlaceholder(),
Object? pullToRefreshEnabled = const $CopyWithPlaceholder(),
Object? useExternalDownloadManager = const $CopyWithPlaceholder(),
@@ -533,6 +541,11 @@ class _$GeneralSettingsCWProxyImpl implements _$GeneralSettingsCWProxy {
? _value.tabBarPosition
// ignore: cast_nullable_to_non_nullable
: tabBarPosition as TabBarPosition,
tabBarLayout:
tabBarLayout == const $CopyWithPlaceholder() || tabBarLayout == null
? _value.tabBarLayout
// ignore: cast_nullable_to_non_nullable
: tabBarLayout as TabBarLayout,
quickTabSwitcherMode:
quickTabSwitcherMode == const $CopyWithPlaceholder() ||
quickTabSwitcherMode == null
@@ -727,6 +740,10 @@ GeneralSettings _$GeneralSettingsFromJson(
_$TabBarPositionEnumMap,
json['tabBarPosition'],
),
tabBarLayout: $enumDecodeNullable(
_$TabBarLayoutEnumMap,
json['tabBarLayout'],
),
quickTabSwitcherMode: $enumDecodeNullable(
_$QuickTabSwitcherModeEnumMap,
json['quickTabSwitcherMode'],
@@ -795,6 +812,7 @@ Map<String, dynamic> _$GeneralSettingsToJson(
'tabBarShowContextualBar': instance.tabBarShowContextualBar,
'tabBarShowQuickTabSwitcherBar': instance.tabBarShowQuickTabSwitcherBar,
'tabBarPosition': _$TabBarPositionEnumMap[instance.tabBarPosition]!,
'tabBarLayout': _$TabBarLayoutEnumMap[instance.tabBarLayout]!,
'quickTabSwitcherMode':
_$QuickTabSwitcherModeEnumMap[instance.quickTabSwitcherMode]!,
'pullToRefreshEnabled': instance.pullToRefreshEnabled,
@@ -868,6 +886,11 @@ const _$TabBarPositionEnumMap = {
TabBarPosition.bottom: 'bottom',
};
const _$TabBarLayoutEnumMap = {
TabBarLayout.withTitle: 'withTitle',
TabBarLayout.compact: 'compact',
};
const _$QuickTabSwitcherModeEnumMap = {
QuickTabSwitcherMode.lastUsedTabs: 'lastUsedTabs',
QuickTabSwitcherMode.containerTabs: 'containerTabs',
@@ -126,6 +126,10 @@ class GeneralSettingsRepository extends _$GeneralSettingsRepository {
DriftSqlType.string,
db.typeMapping,
),
'tabBarLayout': settings['tabBarLayout']?.readAs(
DriftSqlType.string,
db.typeMapping,
),
'quickTabSwitcherMode': settings['quickTabSwitcherMode']?.readAs(
DriftSqlType.string,
db.typeMapping,
@@ -35,7 +35,7 @@ final class GeneralSettingsRepositoryProvider
}
String _$generalSettingsRepositoryHash() =>
r'2e987b58279ea638157324a03403dfac8437b888';
r'23b15af79f0f41771c20f7c0f7e94f93659ee1e8';
abstract class _$GeneralSettingsRepository
extends $StreamNotifier<GeneralSettings> {