Files
MrbWebLibre/apps/weblibre/lib/features/user/data/models/general_settings.dart
T

670 lines
27 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*
* Copyright (c) 2024-2026 Fabian Freund.
*
* This file is part of WebLibre
* (see https://weblibre.eu).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import 'package:copy_with_extension/copy_with_extension.dart';
import 'package:fast_equatable/fast_equatable.dart';
import 'package:flutter/material.dart';
import 'package:flutter_mozilla_components/flutter_mozilla_components.dart'
show AppLinksMode;
import 'package:json_annotation/json_annotation.dart';
import 'package:weblibre/core/routing/routes.dart';
import 'package:weblibre/features/app_links/domain/entities/app_link_rule.dart';
import 'package:weblibre/features/app_links/domain/entities/context_app_link_policy.dart';
import 'package:weblibre/features/bangs/data/models/bang_group.dart';
import 'package:weblibre/features/bangs/data/models/bang_key.dart';
import 'package:weblibre/features/intent_gatekeeper/domain/entities/intent_source_policy.dart';
import 'package:weblibre/features/search/domain/entities/abstract/i_search_suggestion_provider.dart';
part 'general_settings.g.dart';
const _fallbackSearchProvider = BangKey(
group: BangGroup.general,
trigger: 'wikipedia',
);
const _fallbackAutocompleteProvider = SearchSuggestionProviders.none;
const defaultUiScaleFactor = 1.0;
const minUiScaleFactor = 0.5;
const maxUiScaleFactor = 1.5;
const uiScaleFactorStep = 0.05;
/// Max number of inline chevron glyphs shown on a quick tab switcher chip
/// before the depth indicator collapses into a single icon + count badge.
/// A value of 0 hides the hierarchy indicator entirely.
const defaultQuickTabSwitcherHierarchyGlyphs = 2;
const minQuickTabSwitcherHierarchyGlyphs = 0;
const maxQuickTabSwitcherHierarchyGlyphs = 4;
/// Max width (logical px) of the title text on a quick tab switcher chip.
/// The default of 64 sits at the 1/3 position of the slider scale.
const defaultQuickTabSwitcherTitleWidth = 64.0;
const minQuickTabSwitcherTitleWidth = 32.0;
const maxQuickTabSwitcherTitleWidth = 128.0;
const quickTabSwitcherTitleWidthStep = 8.0;
/// Controls the Android display refresh rate the app requests at startup.
///
/// Flutter does not request a high refresh rate by default, so on many devices
/// (Samsung, OnePlus, Xiaomi, …) the app is left at 60Hz even on a 90/120Hz
/// panel. [high] asks the OS for the fastest available mode, [low] for the
/// slowest (battery saving), and [system] leaves the OS-managed default in
/// place. Android-only; ignored on other platforms.
enum RefreshRateMode { system, high, low }
enum TabBarSwipeAction { switchLastOpened, navigateOrderedTabs }
/// Row kind rendered inside the quick tab switcher bar. [TabBarStackingMode]
/// decides which row(s) are shown; this enum identifies a single row.
enum QuickTabSwitcherMode { lastUsedTabs, containerTabs }
/// Layout of the quick tab switcher bar. Merges the former
/// "show tab switcher bar" toggle and [QuickTabSwitcherMode] selection.
///
/// [accordion] renders all containers as header chips with the selected
/// container's tabs expanded inline. [twoLevel] stacks a container-tabs row
/// on top of a recently-used row. [disabled] hides the bar entirely.
enum TabBarStackingMode {
lastUsedTabs,
containerTabs,
accordion,
twoLevel,
disabled,
}
enum TabIntentOpenSetting { regular, private, isolated, ask }
/// Determines what happens when a bookmark is tapped in the bookmark list.
/// [ask] shows the "open in..." sheet (today's behavior, and the default);
/// the other values open the bookmark directly with no intermediate prompt.
enum BookmarkOpenSetting { regular, isolated, customTab, ask }
enum TabDirection { newestFirst, oldestFirst }
enum TabBarPosition {
top,
bottom,
left,
right;
/// Whether the tab bar is rendered as a vertical side rail (left/right)
/// rather than a horizontal bar (top/bottom).
bool get isVertical =>
this == TabBarPosition.left || this == TabBarPosition.right;
/// Whether the tab bar is rendered as a horizontal bar (top/bottom).
bool get isHorizontal => !isVertical;
/// Main axis along which the bar's content flows.
Axis get axis => isVertical ? Axis.vertical : Axis.horizontal;
}
enum TabBarLayout { withTitle, compact }
enum DeleteBrowsingDataType {
tabs('Open tabs'),
history('Browsing history'),
recentSearches('Recent searches', 'Queries shown on the search page'),
cookies('Cookies and site data', 'Youll be logged out of most sites'),
cache('Cached images and files', 'Frees up storage space'),
permissions('Site permissions'),
downloads('Downloads');
final String title;
final String? description;
const DeleteBrowsingDataType(this.title, [this.description]);
}
@CopyWith()
@JsonSerializable(includeIfNull: true, constructor: 'withDefaults')
class GeneralSettings with FastEquatable {
final ThemeMode themeMode;
final double uiScaleFactor;
final bool disableAnimations;
/// Android display refresh rate requested at startup. See [RefreshRateMode].
final RefreshRateMode refreshRateMode;
final bool showModalBarrier;
final bool enableReadability;
final bool enforceReadability;
final Set<DeleteBrowsingDataType>? deleteBrowsingDataOnQuit;
final bool screenshotProtectionEnabled;
@BangKeyConverter()
final BangKey? defaultSearchProvider;
final SearchSuggestionProviders defaultSearchSuggestionsProvider;
final bool createChildTabsOption;
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;
final TabDirection tabBarDirection;
final TabIntentOpenSetting tabIntentOpenSetting;
/// Determines what happens when a bookmark is tapped. See
/// [BookmarkOpenSetting] and [effectiveBookmarkOpenSetting].
final BookmarkOpenSetting bookmarkOpenSetting;
final bool autoHideTabBar;
final TabBarSwipeAction tabBarSwipeAction;
final Duration historyAutoCleanInterval;
final bool tabViewBottomSheet;
final bool tabBarShowContextualBar;
final TabBarPosition tabBarPosition;
final TabBarLayout tabBarLayout;
final TabBarStackingMode tabBarStackingMode;
final bool pullToRefreshEnabled;
final bool useExternalDownloadManager;
final bool doubleBackCloseTab;
final Duration unassignedTabsAutoCleanInterval;
final int maxSearchHistoryEntries;
final bool allowClipboardAccess;
final bool tabListShowFavicons;
final bool quickTabSwitcherShowTitles;
final int quickTabSwitcherHierarchyGlyphs;
final bool quickTabSwitcherShowHistorySuggestions;
/// Max width (logical px) for chip titles in the quick tab switcher.
final double quickTabSwitcherTitleWidth;
/// Whether every tab chip in the quick tab switcher shows a close button.
/// The selected tab's chip always shows one regardless of this setting.
final bool quickTabSwitcherShowCloseButtonOnAllTabs;
final String syncServerOverride;
final String syncTokenServerOverride;
final bool urlCleanerEnabled;
final bool urlCleanerAutoApply;
final bool urlCleanerAllowReferralMarketing;
final String urlCleanerCatalogUrl;
final String urlCleanerHashUrl;
final bool urlCleanerAutoUpdate;
final int? urlCleanerLastCheckEpochMs;
final bool urlCleanerLastUpdateWasAuto;
final TabType smallWebTabType;
final bool tabBarLongPressUrlCopy;
final bool unshortenerEnabled;
final String unshortenerToken;
final bool allowNonManifestPwaInstall;
final bool blockExternalAppsEnabled;
final Map<String, IntentSourcePolicy> externalAppIntentPolicies;
/// Whether external Custom Tab intents (and URLs shared into WebLibre) open
/// in a lightweight custom-tab activity. When false, they open as normal
/// tabs in the main browser instead. Read natively by `IntentReceiverActivity`
/// via the intent gatekeeper prefs bridge. Defaults to true.
final bool customTabsEnabled;
/// Global app-links behaviour: always open in native apps, ask each time, or
/// never leave the browser. Defaults to [AppLinksMode.ask]. Per-site rules in
/// [appLinkRules] and container/proxy protection can override this per-target.
final AppLinksMode appLinksMode;
/// Remembered per-scope app-link rules, keyed by canonical scope
/// (`host:youtube.com` | `pkg:...`). One rule per scope, last write wins.
/// Malformed entries are dropped on read (see [parseAppLinkRules]).
@JsonKey(fromJson: parseAppLinkRules)
final Map<String, PersistedAppLinkRule> appLinkRules;
/// Per-container app-link overrides for containers with "isolated app link
/// settings" enabled, keyed by the container's Gecko contextId. Each entry
/// fully *replaces* the global mode + [appLinkRules] for navigations in that
/// container (replace semantics). Containers without isolation have no entry
/// and fall back to the global policy. Malformed entries dropped on read.
@JsonKey(fromJson: parseAppLinkContextOverrides)
final Map<String, ContextAppLinkPolicy> appLinkContextOverrides;
/// Whether an install-app (marketplace) intent is offered when an app link
/// resolves to no installed app and has no validated http(s) fallback.
/// Defaults to false — the wrong default for a de-Googled browser.
final bool appLinkMarketplaceFallback;
/// Whether the local search index (`history` table populated via tab→
/// history triggers) is active. When false, the SQL trigger guard returns
/// without writing; existing rows stay until the user clears them.
final bool enableLocalSearchIndex;
/// Whether private tabs feed the local search index. Defaults to false.
final bool indexPrivateTabs;
/// Whether pressing the keyboard submit/enter button should automatically
/// accept and complete an inline search suggestion. Defaults to false.
final bool acceptSuggestionOnSubmit;
/// Whether dark mode should use pure-black ("OLED"/high-contrast) surfaces.
/// Only takes effect when the effective brightness is dark. Defaults to false.
final bool pureBlack;
/// Browser-wide default desktop mode. When true, newly opened tabs request
/// the desktop version of sites by default. The per-tab desktop-mode toggle
/// still overrides this for an individual tab. Defaults to false.
final bool globalDesktopMode;
/// Hosts that should always load in desktop mode. A tab navigating to a
/// matching host (or any of its subdomains) is switched to desktop mode,
/// overriding [globalDesktopMode] for that visit. See `hostMatchesRule`.
final List<String> desktopModeSites;
/// Developer setting: when true, the GeckoView is unmounted whenever a
/// full-cover route (settings, tab tray, search, …) is on top, freeing the
/// engine's resources while it is occluded. On Android 12 and lower (API
/// <= 31) this behavior is always applied to work around a native
/// visibility bug; on Android 13+ the engine normally stays mounted to
/// avoid reload/flicker, and this flag opts into the off-route unmounting
/// there too. Defaults to false.
final bool unmountGeckoViewOffRoute;
GeneralSettings({
required this.themeMode,
required this.uiScaleFactor,
required this.disableAnimations,
required this.refreshRateMode,
required this.showModalBarrier,
required this.enableReadability,
required this.enforceReadability,
required this.deleteBrowsingDataOnQuit,
required this.screenshotProtectionEnabled,
required this.defaultSearchProvider,
required this.defaultSearchSuggestionsProvider,
required this.createChildTabsOption,
required this.enableLocalAiFeatures,
required this.showContainerUi,
required this.showIsolatedTabUi,
required this.showSearchCloseButton,
required this.storedDefaultCreateTabType,
required this.tabListDirection,
required this.tabBarDirection,
required this.tabIntentOpenSetting,
required this.bookmarkOpenSetting,
required this.autoHideTabBar,
required this.tabBarSwipeAction,
required this.historyAutoCleanInterval,
required this.tabViewBottomSheet,
required this.tabBarShowContextualBar,
required this.tabBarPosition,
required this.tabBarLayout,
required this.tabBarStackingMode,
required this.pullToRefreshEnabled,
required this.useExternalDownloadManager,
required this.doubleBackCloseTab,
required this.unassignedTabsAutoCleanInterval,
required this.maxSearchHistoryEntries,
required this.allowClipboardAccess,
required this.tabListShowFavicons,
required this.quickTabSwitcherShowTitles,
required this.quickTabSwitcherHierarchyGlyphs,
required this.quickTabSwitcherShowHistorySuggestions,
required this.quickTabSwitcherTitleWidth,
required this.quickTabSwitcherShowCloseButtonOnAllTabs,
required this.syncServerOverride,
required this.syncTokenServerOverride,
required this.urlCleanerEnabled,
required this.urlCleanerAutoApply,
required this.urlCleanerAllowReferralMarketing,
required this.urlCleanerCatalogUrl,
required this.urlCleanerHashUrl,
required this.urlCleanerAutoUpdate,
required this.urlCleanerLastCheckEpochMs,
required this.urlCleanerLastUpdateWasAuto,
required this.smallWebTabType,
required this.tabBarLongPressUrlCopy,
required this.unshortenerEnabled,
required this.unshortenerToken,
required this.allowNonManifestPwaInstall,
required this.blockExternalAppsEnabled,
required this.externalAppIntentPolicies,
required this.customTabsEnabled,
required this.appLinksMode,
required this.appLinkRules,
required this.appLinkContextOverrides,
required this.appLinkMarketplaceFallback,
required this.enableLocalSearchIndex,
required this.indexPrivateTabs,
required this.acceptSuggestionOnSubmit,
required this.pureBlack,
required this.globalDesktopMode,
required this.desktopModeSites,
required this.unmountGeckoViewOffRoute,
});
GeneralSettings.withDefaults({
ThemeMode? themeMode,
double? uiScaleFactor,
bool? disableAnimations,
RefreshRateMode? refreshRateMode,
bool? showModalBarrier,
bool? enableReadability,
bool? enforceReadability,
this.deleteBrowsingDataOnQuit,
bool? screenshotProtectionEnabled,
BangKey? defaultSearchProvider,
SearchSuggestionProviders? defaultSearchSuggestionsProvider,
bool? createChildTabsOption,
bool? enableLocalAiFeatures,
bool? showContainerUi,
bool? showIsolatedTabUi,
bool? showSearchCloseButton,
TabType? storedDefaultCreateTabType,
TabDirection? tabListDirection,
TabDirection? tabBarDirection,
TabIntentOpenSetting? tabIntentOpenSetting,
BookmarkOpenSetting? bookmarkOpenSetting,
bool? autoHideTabBar,
TabBarSwipeAction? tabBarSwipeAction,
Duration? historyAutoCleanInterval,
bool? tabViewBottomSheet,
bool? tabBarShowContextualBar,
TabBarPosition? tabBarPosition,
TabBarLayout? tabBarLayout,
TabBarStackingMode? tabBarStackingMode,
bool? pullToRefreshEnabled,
bool? useExternalDownloadManager,
bool? doubleBackCloseTab,
Duration? unassignedTabsAutoCleanInterval,
int? maxSearchHistoryEntries,
bool? allowClipboardAccess,
bool? tabListShowFavicons,
bool? quickTabSwitcherShowTitles,
int? quickTabSwitcherHierarchyGlyphs,
bool? quickTabSwitcherShowHistorySuggestions,
double? quickTabSwitcherTitleWidth,
bool? quickTabSwitcherShowCloseButtonOnAllTabs,
String? syncServerOverride,
String? syncTokenServerOverride,
bool? urlCleanerEnabled,
bool? urlCleanerAutoApply,
bool? urlCleanerAllowReferralMarketing,
String? urlCleanerCatalogUrl,
String? urlCleanerHashUrl,
bool? urlCleanerAutoUpdate,
this.urlCleanerLastCheckEpochMs,
bool? urlCleanerLastUpdateWasAuto,
TabType? smallWebTabType,
bool? tabBarLongPressUrlCopy,
bool? unshortenerEnabled,
String? unshortenerToken,
bool? allowNonManifestPwaInstall,
bool? blockExternalAppsEnabled,
Map<String, IntentSourcePolicy>? externalAppIntentPolicies,
bool? customTabsEnabled,
AppLinksMode? appLinksMode,
Map<String, PersistedAppLinkRule>? appLinkRules,
Map<String, ContextAppLinkPolicy>? appLinkContextOverrides,
bool? appLinkMarketplaceFallback,
bool? enableLocalSearchIndex,
bool? indexPrivateTabs,
bool? acceptSuggestionOnSubmit,
bool? pureBlack,
bool? globalDesktopMode,
List<String>? desktopModeSites,
bool? unmountGeckoViewOffRoute,
}) : themeMode = themeMode ?? ThemeMode.dark,
uiScaleFactor = uiScaleFactor ?? defaultUiScaleFactor,
disableAnimations = disableAnimations ?? false,
refreshRateMode = refreshRateMode ?? RefreshRateMode.high,
showModalBarrier = showModalBarrier ?? true,
enableReadability = enableReadability ?? true,
enforceReadability = enforceReadability ?? false,
screenshotProtectionEnabled = screenshotProtectionEnabled ?? false,
defaultSearchProvider = defaultSearchProvider ?? _fallbackSearchProvider,
defaultSearchSuggestionsProvider =
defaultSearchSuggestionsProvider ?? _fallbackAutocompleteProvider,
createChildTabsOption = createChildTabsOption ?? false,
enableLocalAiFeatures = enableLocalAiFeatures ?? true,
showContainerUi = showContainerUi ?? true,
showIsolatedTabUi = showIsolatedTabUi ?? true,
showSearchCloseButton = showSearchCloseButton ?? false,
storedDefaultCreateTabType =
storedDefaultCreateTabType ?? TabType.regular,
tabListDirection = tabListDirection ?? TabDirection.newestFirst,
tabBarDirection = tabBarDirection ?? TabDirection.newestFirst,
tabIntentOpenSetting = tabIntentOpenSetting ?? TabIntentOpenSetting.ask,
bookmarkOpenSetting = bookmarkOpenSetting ?? BookmarkOpenSetting.ask,
autoHideTabBar = autoHideTabBar ?? true,
tabBarSwipeAction =
tabBarSwipeAction ?? TabBarSwipeAction.switchLastOpened,
historyAutoCleanInterval =
historyAutoCleanInterval ?? const Duration(days: 90),
tabViewBottomSheet = tabViewBottomSheet ?? false,
tabBarShowContextualBar = tabBarShowContextualBar ?? true,
tabBarPosition = tabBarPosition ?? TabBarPosition.bottom,
tabBarLayout = tabBarLayout ?? TabBarLayout.compact,
tabBarStackingMode = tabBarStackingMode ?? TabBarStackingMode.accordion,
pullToRefreshEnabled = pullToRefreshEnabled ?? true,
useExternalDownloadManager = useExternalDownloadManager ?? false,
doubleBackCloseTab = doubleBackCloseTab ?? true,
unassignedTabsAutoCleanInterval =
unassignedTabsAutoCleanInterval ?? Duration.zero,
maxSearchHistoryEntries = maxSearchHistoryEntries ?? 5,
allowClipboardAccess = allowClipboardAccess ?? true,
tabListShowFavicons = tabListShowFavicons ?? false,
quickTabSwitcherShowTitles = quickTabSwitcherShowTitles ?? true,
quickTabSwitcherHierarchyGlyphs =
quickTabSwitcherHierarchyGlyphs ??
defaultQuickTabSwitcherHierarchyGlyphs,
quickTabSwitcherShowHistorySuggestions =
quickTabSwitcherShowHistorySuggestions ?? true,
quickTabSwitcherTitleWidth =
quickTabSwitcherTitleWidth ?? defaultQuickTabSwitcherTitleWidth,
quickTabSwitcherShowCloseButtonOnAllTabs =
quickTabSwitcherShowCloseButtonOnAllTabs ?? false,
syncServerOverride = syncServerOverride ?? '',
syncTokenServerOverride = syncTokenServerOverride ?? '',
urlCleanerEnabled = urlCleanerEnabled ?? true,
urlCleanerAutoApply = urlCleanerAutoApply ?? false,
urlCleanerAllowReferralMarketing =
urlCleanerAllowReferralMarketing ?? false,
urlCleanerCatalogUrl =
urlCleanerCatalogUrl ??
'https://rules2.clearurls.xyz/data.minify.json',
urlCleanerHashUrl =
urlCleanerHashUrl ??
'https://rules2.clearurls.xyz/rules.minify.hash',
urlCleanerAutoUpdate = urlCleanerAutoUpdate ?? false,
urlCleanerLastUpdateWasAuto = urlCleanerLastUpdateWasAuto ?? false,
smallWebTabType = smallWebTabType ?? TabType.private,
tabBarLongPressUrlCopy = tabBarLongPressUrlCopy ?? true,
unshortenerEnabled = unshortenerEnabled ?? false,
unshortenerToken = unshortenerToken ?? '',
allowNonManifestPwaInstall = allowNonManifestPwaInstall ?? false,
blockExternalAppsEnabled = blockExternalAppsEnabled ?? false,
externalAppIntentPolicies = externalAppIntentPolicies ?? const {},
customTabsEnabled = customTabsEnabled ?? true,
appLinksMode = appLinksMode ?? AppLinksMode.ask,
appLinkRules = appLinkRules ?? const {},
appLinkContextOverrides = appLinkContextOverrides ?? const {},
appLinkMarketplaceFallback = appLinkMarketplaceFallback ?? false,
enableLocalSearchIndex = enableLocalSearchIndex ?? true,
indexPrivateTabs = indexPrivateTabs ?? false,
acceptSuggestionOnSubmit = acceptSuggestionOnSubmit ?? true,
pureBlack = pureBlack ?? false,
globalDesktopMode = globalDesktopMode ?? false,
desktopModeSites = desktopModeSites ?? const [],
unmountGeckoViewOffRoute = unmountGeckoViewOffRoute ?? false;
factory GeneralSettings.fromJson(Map<String, dynamic> json) {
// Migrate legacy `newTabPosition` setting to direction settings.
// Old `first` (new tabs at top) → newestFirst; `end` → oldestFirst.
// TODO: Drop this fallback (and the `newTabPosition` row in the user
// settings DB) once enough releases have shipped that rolling back to a
// version without `tabListDirection`/`tabBarDirection` is no longer a
// concern.
final legacyNewTabPosition = json['newTabPosition'];
if (legacyNewTabPosition != null) {
final mapped = legacyNewTabPosition == 'end'
? 'oldestFirst'
: 'newestFirst';
json.putIfAbsent('tabListDirection', () => mapped);
json.putIfAbsent('tabBarDirection', () => mapped);
}
// Migrate the legacy `tabBarShowQuickTabSwitcherBar` toggle and
// `quickTabSwitcherMode` selection to the merged `tabBarStackingMode`.
// The legacy mode names are a subset of the new enum's, so values map
// verbatim.
// TODO: Drop this fallback (and the legacy rows in the user settings DB)
// once enough releases have shipped that rolling back to a version
// without `tabBarStackingMode` is no longer a concern.
final legacyShowSwitcherBar = json['tabBarShowQuickTabSwitcherBar'];
final legacySwitcherMode = json['quickTabSwitcherMode'];
if (json['tabBarStackingMode'] == null) {
if (legacyShowSwitcherBar == false) {
json['tabBarStackingMode'] = 'disabled';
} else if (legacySwitcherMode != null) {
json['tabBarStackingMode'] = legacySwitcherMode;
}
}
return _$GeneralSettingsFromJson(json);
}
Map<String, dynamic> toJson() => _$GeneralSettingsToJson(this);
TabType get effectiveDefaultCreateTabType {
if (!showIsolatedTabUi && storedDefaultCreateTabType == TabType.isolated) {
return TabType.regular;
}
return storedDefaultCreateTabType;
}
TabType get effectiveSmallWebTabType {
if (!showIsolatedTabUi && smallWebTabType == TabType.isolated) {
return TabType.private;
}
return smallWebTabType;
}
TabIntentOpenSetting get effectiveTabIntentOpenSetting {
if (!showIsolatedTabUi &&
tabIntentOpenSetting == TabIntentOpenSetting.isolated) {
return TabIntentOpenSetting.ask;
}
return tabIntentOpenSetting;
}
BookmarkOpenSetting get effectiveBookmarkOpenSetting {
if (!showIsolatedTabUi &&
bookmarkOpenSetting == BookmarkOpenSetting.isolated) {
return BookmarkOpenSetting.ask;
}
return bookmarkOpenSetting;
}
/// Container-dependent stacking modes degrade to a single recently-used
/// row when the container UI is disabled. Two-level stacking additionally
/// degrades to accordion (the default mode, which has a vertical form) on the
/// narrow vertical rail, where two stacked chip lists have no room.
TabBarStackingMode effectiveTabBarStackingMode() {
var mode = tabBarStackingMode;
if (tabBarPosition.isVertical && mode == TabBarStackingMode.twoLevel) {
mode = TabBarStackingMode.accordion;
}
if (!showContainerUi &&
const {
TabBarStackingMode.containerTabs,
TabBarStackingMode.accordion,
TabBarStackingMode.twoLevel,
}.contains(mode)) {
return TabBarStackingMode.lastUsedTabs;
}
return mode;
}
@override
List<Object?> get hashParameters => [
themeMode,
uiScaleFactor,
disableAnimations,
refreshRateMode,
showModalBarrier,
enableReadability,
enforceReadability,
deleteBrowsingDataOnQuit,
screenshotProtectionEnabled,
defaultSearchProvider,
defaultSearchSuggestionsProvider,
createChildTabsOption,
enableLocalAiFeatures,
showContainerUi,
showIsolatedTabUi,
showSearchCloseButton,
storedDefaultCreateTabType,
tabListDirection,
tabBarDirection,
tabIntentOpenSetting,
bookmarkOpenSetting,
autoHideTabBar,
tabBarSwipeAction,
historyAutoCleanInterval,
tabViewBottomSheet,
tabBarShowContextualBar,
tabBarPosition,
tabBarLayout,
tabBarStackingMode,
pullToRefreshEnabled,
useExternalDownloadManager,
doubleBackCloseTab,
unassignedTabsAutoCleanInterval,
maxSearchHistoryEntries,
allowClipboardAccess,
tabListShowFavicons,
quickTabSwitcherShowTitles,
quickTabSwitcherHierarchyGlyphs,
quickTabSwitcherShowHistorySuggestions,
quickTabSwitcherTitleWidth,
quickTabSwitcherShowCloseButtonOnAllTabs,
syncServerOverride,
syncTokenServerOverride,
urlCleanerEnabled,
urlCleanerAutoApply,
urlCleanerAllowReferralMarketing,
urlCleanerCatalogUrl,
urlCleanerHashUrl,
urlCleanerAutoUpdate,
urlCleanerLastCheckEpochMs,
urlCleanerLastUpdateWasAuto,
smallWebTabType,
tabBarLongPressUrlCopy,
unshortenerEnabled,
unshortenerToken,
allowNonManifestPwaInstall,
blockExternalAppsEnabled,
externalAppIntentPolicies,
customTabsEnabled,
appLinksMode,
appLinkRules,
appLinkContextOverrides,
appLinkMarketplaceFallback,
enableLocalSearchIndex,
indexPrivateTabs,
acceptSuggestionOnSubmit,
pureBlack,
globalDesktopMode,
desktopModeSites,
unmountGeckoViewOffRoute,
];
}