add setting to show favicon instead of thumbnail in tab list (#174)

This commit is contained in:
Fabian Freund
2026-02-11 11:51:46 +01:00
parent a1c4072a4f
commit f7496ff3e3
7 changed files with 70 additions and 11 deletions
@@ -41,7 +41,7 @@ final class TabRepositoryProvider
}
}
String _$tabRepositoryHash() => r'0158f3aeb942dda3dab07c1129ced1695c7703c7';
String _$tabRepositoryHash() => r'db35cef59703f15f1b099b6adb42f7623bec612f';
abstract class _$TabRepository extends $Notifier<void> {
void build();
@@ -32,6 +32,7 @@ import 'package:weblibre/features/geckoview/features/browser/presentation/widget
import 'package:weblibre/features/geckoview/features/find_in_page/domain/entities/find_in_page_state.dart';
import 'package:weblibre/features/geckoview/features/find_in_page/presentation/controllers/find_in_page.dart';
import 'package:weblibre/features/geckoview/features/tabs/domain/repositories/tab.dart';
import 'package:weblibre/features/user/domain/repositories/general_settings.dart';
import 'package:weblibre/presentation/hooks/menu_controller.dart';
import 'package:weblibre/presentation/widgets/safe_raw_image.dart';
import 'package:weblibre/presentation/widgets/uri_breadcrumb.dart';
@@ -275,8 +276,19 @@ class ListTabPreview extends HookConsumerWidget {
) ??
TabState.$default(tabId);
final tabListShowFavicons = ref.watch(
generalSettingsWithDefaultsProvider.select((s) => s.tabListShowFavicons),
);
final extendedDeleteMenuController = useMenuController();
final leadingWidget = switch ((tabListShowFavicons, tabState.thumbnail)) {
(false, final thumbnail?) when !thumbnail.isDisposed => RepaintBoundary(
child: SafeRawImage(image: thumbnail, fit: BoxFit.fitHeight),
),
_ => TabIcon(tabState: tabState, iconSize: 32),
};
return Container(
decoration: BoxDecoration(
color: tabState.isPrivate ? appColors.privateTabBackground : null,
@@ -291,14 +303,7 @@ class ListTabPreview extends HookConsumerWidget {
onTap: onTap,
onLongPress: onLongPress,
contentPadding: const EdgeInsets.only(left: 4),
leading: (tabState.thumbnail != null && !tabState.thumbnail!.isDisposed)
? RepaintBoundary(
child: SafeRawImage(
image: tabState.thumbnail,
fit: BoxFit.fitHeight,
),
)
: TabIcon(tabState: tabState, iconSize: 32),
leading: leadingWidget,
title: Text(
overflow: TextOverflow.ellipsis,
tabState.titleOrAuthority,
@@ -79,6 +79,7 @@ class _TabBarLayoutSection extends StatelessWidget {
_ShowContextualTabBarTile(),
_AutoHideTabBarTile(),
_BottomSheetTabViewTile(),
_TabListShowFaviconsTile(),
_ShowQuickTabSwitcherBarTile(),
_QuickTabSwitcherModeSection(),
],
@@ -377,6 +378,34 @@ class _BottomSheetTabViewTile extends HookConsumerWidget {
}
}
class _TabListShowFaviconsTile extends HookConsumerWidget {
const _TabListShowFaviconsTile();
@override
Widget build(BuildContext context, WidgetRef ref) {
final tabListShowFavicons = ref.watch(
generalSettingsWithDefaultsProvider.select((s) => s.tabListShowFavicons),
);
return SwitchListTile.adaptive(
title: const Text('Show Favicons in List View'),
subtitle: const Text(
'Display website icons instead of page thumbnails in tab list view',
),
secondary: const Icon(MdiIcons.web),
value: tabListShowFavicons,
onChanged: (value) async {
await ref
.read(saveGeneralSettingsControllerProvider.notifier)
.save(
(currentSettings) =>
currentSettings.copyWith.tabListShowFavicons(value),
);
},
);
}
}
class _PullToRefreshTile extends HookConsumerWidget {
const _PullToRefreshTile();
@@ -86,6 +86,7 @@ class GeneralSettings with FastEquatable {
final Duration unassignedTabsAutoCleanInterval;
final int maxSearchHistoryEntries;
final bool allowClipboardAccess;
final bool tabListShowFavicons;
GeneralSettings({
required this.themeMode,
@@ -114,6 +115,7 @@ class GeneralSettings with FastEquatable {
required this.unassignedTabsAutoCleanInterval,
required this.maxSearchHistoryEntries,
required this.allowClipboardAccess,
required this.tabListShowFavicons,
});
GeneralSettings.withDefaults({
@@ -143,6 +145,7 @@ class GeneralSettings with FastEquatable {
Duration? unassignedTabsAutoCleanInterval,
int? maxSearchHistoryEntries,
bool? allowClipboardAccess,
bool? tabListShowFavicons,
}) : themeMode = themeMode ?? ThemeMode.dark,
enableReadability = enableReadability ?? true,
enforceReadability = enforceReadability ?? false,
@@ -172,7 +175,8 @@ class GeneralSettings with FastEquatable {
unassignedTabsAutoCleanInterval =
unassignedTabsAutoCleanInterval ?? Duration.zero,
maxSearchHistoryEntries = maxSearchHistoryEntries ?? 5,
allowClipboardAccess = allowClipboardAccess ?? true;
allowClipboardAccess = allowClipboardAccess ?? true,
tabListShowFavicons = tabListShowFavicons ?? false;
factory GeneralSettings.fromJson(Map<String, dynamic> json) =>
_$GeneralSettingsFromJson(json);
@@ -207,5 +211,6 @@ class GeneralSettings with FastEquatable {
unassignedTabsAutoCleanInterval,
maxSearchHistoryEntries,
allowClipboardAccess,
tabListShowFavicons,
];
}
@@ -71,6 +71,8 @@ abstract class _$GeneralSettingsCWProxy {
GeneralSettings allowClipboardAccess(bool allowClipboardAccess);
GeneralSettings tabListShowFavicons(bool tabListShowFavicons);
/// Creates a new instance with the provided field values.
/// Passing `null` to a nullable field nullifies it, while `null` for a non-nullable field is ignored. To update a single field use `GeneralSettings(...).copyWith.fieldName(value)`.
///
@@ -105,6 +107,7 @@ abstract class _$GeneralSettingsCWProxy {
Duration unassignedTabsAutoCleanInterval,
int maxSearchHistoryEntries,
bool allowClipboardAccess,
bool tabListShowFavicons,
});
}
@@ -224,6 +227,10 @@ class _$GeneralSettingsCWProxyImpl implements _$GeneralSettingsCWProxy {
GeneralSettings allowClipboardAccess(bool allowClipboardAccess) =>
call(allowClipboardAccess: allowClipboardAccess);
@override
GeneralSettings tabListShowFavicons(bool tabListShowFavicons) =>
call(tabListShowFavicons: tabListShowFavicons);
@override
/// Creates a new instance with the provided field values.
/// Passing `null` to a nullable field nullifies it, while `null` for a non-nullable field is ignored. To update a single field use `GeneralSettings(...).copyWith.fieldName(value)`.
@@ -259,6 +266,7 @@ class _$GeneralSettingsCWProxyImpl implements _$GeneralSettingsCWProxy {
Object? unassignedTabsAutoCleanInterval = const $CopyWithPlaceholder(),
Object? maxSearchHistoryEntries = const $CopyWithPlaceholder(),
Object? allowClipboardAccess = const $CopyWithPlaceholder(),
Object? tabListShowFavicons = const $CopyWithPlaceholder(),
}) {
return GeneralSettings(
themeMode: themeMode == const $CopyWithPlaceholder() || themeMode == null
@@ -413,6 +421,12 @@ class _$GeneralSettingsCWProxyImpl implements _$GeneralSettingsCWProxy {
? _value.allowClipboardAccess
// ignore: cast_nullable_to_non_nullable
: allowClipboardAccess as bool,
tabListShowFavicons:
tabListShowFavicons == const $CopyWithPlaceholder() ||
tabListShowFavicons == null
? _value.tabListShowFavicons
// ignore: cast_nullable_to_non_nullable
: tabListShowFavicons as bool,
);
}
}
@@ -489,6 +503,7 @@ GeneralSettings _$GeneralSettingsFromJson(
),
maxSearchHistoryEntries: (json['maxSearchHistoryEntries'] as num?)?.toInt(),
allowClipboardAccess: json['allowClipboardAccess'] as bool?,
tabListShowFavicons: json['tabListShowFavicons'] as bool?,
);
Map<String, dynamic> _$GeneralSettingsToJson(
@@ -529,6 +544,7 @@ Map<String, dynamic> _$GeneralSettingsToJson(
instance.unassignedTabsAutoCleanInterval.inMicroseconds,
'maxSearchHistoryEntries': instance.maxSearchHistoryEntries,
'allowClipboardAccess': instance.allowClipboardAccess,
'tabListShowFavicons': instance.tabListShowFavicons,
};
const _$ThemeModeEnumMap = {
@@ -145,6 +145,10 @@ class GeneralSettingsRepository extends _$GeneralSettingsRepository {
DriftSqlType.bool,
db.typeMapping,
),
'tabListShowFavicons': settings['tabListShowFavicons']?.readAs(
DriftSqlType.bool,
db.typeMapping,
),
});
}
@@ -35,7 +35,7 @@ final class GeneralSettingsRepositoryProvider
}
String _$generalSettingsRepositoryHash() =>
r'302d33b57212a8f3affcf13a8ef5227d68e56ecb';
r'a4e4fb6f4e5b40d32b4cc676532af3bacdbe54d2';
abstract class _$GeneralSettingsRepository
extends $StreamNotifier<GeneralSettings> {