app links initial

This commit is contained in:
Fabian Freund
2026-07-30 03:58:46 +02:00
parent 1b0c2b0d06
commit 4bc267969b
97 changed files with 9138 additions and 1054 deletions
@@ -20,8 +20,12 @@
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';
@@ -202,6 +206,30 @@ class GeneralSettings with FastEquatable {
/// 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.
@@ -296,6 +324,10 @@ class GeneralSettings with FastEquatable {
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,
@@ -364,6 +396,10 @@ class GeneralSettings with FastEquatable {
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,
@@ -442,6 +478,10 @@ class GeneralSettings with FastEquatable {
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,
@@ -593,6 +633,10 @@ class GeneralSettings with FastEquatable {
blockExternalAppsEnabled,
externalAppIntentPolicies,
customTabsEnabled,
appLinksMode,
appLinkRules,
appLinkContextOverrides,
appLinkMarketplaceFallback,
enableLocalSearchIndex,
indexPrivateTabs,
acceptSuggestionOnSubmit,
@@ -143,6 +143,16 @@ abstract class _$GeneralSettingsCWProxy {
GeneralSettings customTabsEnabled(bool customTabsEnabled);
GeneralSettings appLinksMode(AppLinksMode appLinksMode);
GeneralSettings appLinkRules(Map<String, PersistedAppLinkRule> appLinkRules);
GeneralSettings appLinkContextOverrides(
Map<String, ContextAppLinkPolicy> appLinkContextOverrides,
);
GeneralSettings appLinkMarketplaceFallback(bool appLinkMarketplaceFallback);
GeneralSettings enableLocalSearchIndex(bool enableLocalSearchIndex);
GeneralSettings indexPrivateTabs(bool indexPrivateTabs);
@@ -223,6 +233,10 @@ abstract class _$GeneralSettingsCWProxy {
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,
@@ -490,6 +504,24 @@ class _$GeneralSettingsCWProxyImpl implements _$GeneralSettingsCWProxy {
GeneralSettings customTabsEnabled(bool customTabsEnabled) =>
call(customTabsEnabled: customTabsEnabled);
@override
GeneralSettings appLinksMode(AppLinksMode appLinksMode) =>
call(appLinksMode: appLinksMode);
@override
GeneralSettings appLinkRules(
Map<String, PersistedAppLinkRule> appLinkRules,
) => call(appLinkRules: appLinkRules);
@override
GeneralSettings appLinkContextOverrides(
Map<String, ContextAppLinkPolicy> appLinkContextOverrides,
) => call(appLinkContextOverrides: appLinkContextOverrides);
@override
GeneralSettings appLinkMarketplaceFallback(bool appLinkMarketplaceFallback) =>
call(appLinkMarketplaceFallback: appLinkMarketplaceFallback);
@override
GeneralSettings enableLocalSearchIndex(bool enableLocalSearchIndex) =>
call(enableLocalSearchIndex: enableLocalSearchIndex);
@@ -586,6 +618,10 @@ class _$GeneralSettingsCWProxyImpl implements _$GeneralSettingsCWProxy {
Object? blockExternalAppsEnabled = const $CopyWithPlaceholder(),
Object? externalAppIntentPolicies = const $CopyWithPlaceholder(),
Object? customTabsEnabled = const $CopyWithPlaceholder(),
Object? appLinksMode = const $CopyWithPlaceholder(),
Object? appLinkRules = const $CopyWithPlaceholder(),
Object? appLinkContextOverrides = const $CopyWithPlaceholder(),
Object? appLinkMarketplaceFallback = const $CopyWithPlaceholder(),
Object? enableLocalSearchIndex = const $CopyWithPlaceholder(),
Object? indexPrivateTabs = const $CopyWithPlaceholder(),
Object? acceptSuggestionOnSubmit = const $CopyWithPlaceholder(),
@@ -938,6 +974,28 @@ class _$GeneralSettingsCWProxyImpl implements _$GeneralSettingsCWProxy {
? _value.customTabsEnabled
// ignore: cast_nullable_to_non_nullable
: customTabsEnabled as bool,
appLinksMode:
appLinksMode == const $CopyWithPlaceholder() || appLinksMode == null
? _value.appLinksMode
// ignore: cast_nullable_to_non_nullable
: appLinksMode as AppLinksMode,
appLinkRules:
appLinkRules == const $CopyWithPlaceholder() || appLinkRules == null
? _value.appLinkRules
// ignore: cast_nullable_to_non_nullable
: appLinkRules as Map<String, PersistedAppLinkRule>,
appLinkContextOverrides:
appLinkContextOverrides == const $CopyWithPlaceholder() ||
appLinkContextOverrides == null
? _value.appLinkContextOverrides
// ignore: cast_nullable_to_non_nullable
: appLinkContextOverrides as Map<String, ContextAppLinkPolicy>,
appLinkMarketplaceFallback:
appLinkMarketplaceFallback == const $CopyWithPlaceholder() ||
appLinkMarketplaceFallback == null
? _value.appLinkMarketplaceFallback
// ignore: cast_nullable_to_non_nullable
: appLinkMarketplaceFallback as bool,
enableLocalSearchIndex:
enableLocalSearchIndex == const $CopyWithPlaceholder() ||
enableLocalSearchIndex == null
@@ -1110,6 +1168,17 @@ GeneralSettings _$GeneralSettingsFromJson(
(k, e) => MapEntry(k, $enumDecode(_$IntentSourcePolicyEnumMap, e)),
),
customTabsEnabled: json['customTabsEnabled'] as bool?,
appLinksMode: $enumDecodeNullable(
_$AppLinksModeEnumMap,
json['appLinksMode'],
),
appLinkRules: parseAppLinkRules(
json['appLinkRules'] as Map<String, dynamic>?,
),
appLinkContextOverrides: parseAppLinkContextOverrides(
json['appLinkContextOverrides'] as Map<String, dynamic>?,
),
appLinkMarketplaceFallback: json['appLinkMarketplaceFallback'] as bool?,
enableLocalSearchIndex: json['enableLocalSearchIndex'] as bool?,
indexPrivateTabs: json['indexPrivateTabs'] as bool?,
acceptSuggestionOnSubmit: json['acceptSuggestionOnSubmit'] as bool?,
@@ -1196,6 +1265,12 @@ Map<String, dynamic> _$GeneralSettingsToJson(
(k, e) => MapEntry(k, _$IntentSourcePolicyEnumMap[e]!),
),
'customTabsEnabled': instance.customTabsEnabled,
'appLinksMode': _$AppLinksModeEnumMap[instance.appLinksMode]!,
'appLinkRules': instance.appLinkRules.map((k, e) => MapEntry(k, e.toJson())),
'appLinkContextOverrides': instance.appLinkContextOverrides.map(
(k, e) => MapEntry(k, e.toJson()),
),
'appLinkMarketplaceFallback': instance.appLinkMarketplaceFallback,
'enableLocalSearchIndex': instance.enableLocalSearchIndex,
'indexPrivateTabs': instance.indexPrivateTabs,
'acceptSuggestionOnSubmit': instance.acceptSuggestionOnSubmit,
@@ -1283,3 +1358,9 @@ const _$IntentSourcePolicyEnumMap = {
IntentSourcePolicy.allow: 'allow',
IntentSourcePolicy.block: 'block',
};
const _$AppLinksModeEnumMap = {
AppLinksMode.always: 'always',
AppLinksMode.ask: 'ask',
AppLinksMode.never: 'never',
};