refactor setting providers; include content blocking settings;

This commit is contained in:
Fabian Freund
2025-08-23 06:30:25 +02:00
parent 7a89c622dc
commit ce657dd26a
53 changed files with 958 additions and 404 deletions
@@ -54,6 +54,20 @@ class EngineSettings extends GeckoEngineSettings with FastEquatable {
WebContentIsolationStrategy get webContentIsolationStrategy =>
super.webContentIsolationStrategy!;
final QueryParameterStripping queryParameterStripping;
final BounceTrackingProtectionMode bounceTrackingProtectionMode;
@override
@JsonKey(includeFromJson: false, includeToJson: false)
ContentBlocking get contentBlocking => ContentBlocking(
queryParameterStripping: queryParameterStripping,
queryParameterStrippingAllowList: '',
queryParameterStrippingStripList:
'__hsfp __hssc __hstc __s _bhlid _branch_match_id _branch_referrer _gl _hsenc _kx _openstat at_recipient_id at_recipient_list bbeml bsft_clkid bsft_uid dclid et_rid fb_action_ids fb_comment_id fbclid gbraid gclid guce_referrer guce_referrer_sig hsCtaTracking igshid irclickid mc_eid mkt_tok ml_subscriber ml_subscriber_hash msclkid mtm_cid oft_c oft_ck oft_d oft_id oft_ids oft_k oft_lk oft_sk oly_anon_id oly_enc_id pk_cid rb_clickid s_cid sc_customer sc_eh sc_uid srsltid ss_email_id twclid unicorn_click_id vero_conv vero_id vgo_ee wbraid wickedid yclid ymclid ysclid',
bounceTrackingProtectionMode: bounceTrackingProtectionMode,
);
EngineSettings({
required super.javascriptEnabled,
required super.trackingProtectionPolicy,
@@ -66,6 +80,8 @@ class EngineSettings extends GeckoEngineSettings with FastEquatable {
required super.cookieBannerHandlingGlobalRulesSubFrames,
required super.webContentIsolationStrategy,
required super.userAgent,
required this.queryParameterStripping,
required this.bounceTrackingProtectionMode,
});
EngineSettings.withDefaults({
@@ -79,8 +95,15 @@ class EngineSettings extends GeckoEngineSettings with FastEquatable {
bool? cookieBannerHandlingGlobalRules,
bool? cookieBannerHandlingGlobalRulesSubFrames,
WebContentIsolationStrategy? webContentIsolationStrategy,
QueryParameterStripping? queryParameterStripping,
BounceTrackingProtectionMode? bounceTrackingProtectionMode,
super.userAgent,
}) : super(
}) : queryParameterStripping =
queryParameterStripping ?? QueryParameterStripping.disabled,
bounceTrackingProtectionMode =
bounceTrackingProtectionMode ??
BounceTrackingProtectionMode.disabled,
super(
javascriptEnabled: javascriptEnabled ?? true,
trackingProtectionPolicy:
trackingProtectionPolicy ?? TrackingProtectionPolicy.strict,
@@ -119,5 +142,7 @@ class EngineSettings extends GeckoEngineSettings with FastEquatable {
super.cookieBannerHandlingGlobalRulesSubFrames,
super.webContentIsolationStrategy,
super.userAgent,
queryParameterStripping,
bounceTrackingProtectionMode,
];
}
@@ -41,6 +41,14 @@ abstract class _$EngineSettingsCWProxy {
EngineSettings userAgent(String? userAgent);
EngineSettings queryParameterStripping(
QueryParameterStripping queryParameterStripping,
);
EngineSettings bounceTrackingProtectionMode(
BounceTrackingProtectionMode bounceTrackingProtectionMode,
);
/// This function **does support** nullification of nullable fields. All `null` values passed to `non-nullable` fields will be ignored. You can also use `EngineSettings(...).copyWith.fieldName(...)` to override fields one at a time with nullification support.
///
/// Usage
@@ -59,6 +67,8 @@ abstract class _$EngineSettingsCWProxy {
bool? cookieBannerHandlingGlobalRulesSubFrames,
WebContentIsolationStrategy? webContentIsolationStrategy,
String? userAgent,
QueryParameterStripping queryParameterStripping,
BounceTrackingProtectionMode bounceTrackingProtectionMode,
});
}
@@ -124,6 +134,16 @@ class _$EngineSettingsCWProxyImpl implements _$EngineSettingsCWProxy {
@override
EngineSettings userAgent(String? userAgent) => this(userAgent: userAgent);
@override
EngineSettings queryParameterStripping(
QueryParameterStripping queryParameterStripping,
) => this(queryParameterStripping: queryParameterStripping);
@override
EngineSettings bounceTrackingProtectionMode(
BounceTrackingProtectionMode bounceTrackingProtectionMode,
) => this(bounceTrackingProtectionMode: bounceTrackingProtectionMode);
@override
/// This function **does support** nullification of nullable fields. All `null` values passed to `non-nullable` fields will be ignored. You can also use `EngineSettings(...).copyWith.fieldName(...)` to override fields one at a time with nullification support.
///
@@ -145,6 +165,8 @@ class _$EngineSettingsCWProxyImpl implements _$EngineSettingsCWProxy {
const $CopyWithPlaceholder(),
Object? webContentIsolationStrategy = const $CopyWithPlaceholder(),
Object? userAgent = const $CopyWithPlaceholder(),
Object? queryParameterStripping = const $CopyWithPlaceholder(),
Object? bounceTrackingProtectionMode = const $CopyWithPlaceholder(),
}) {
return EngineSettings(
javascriptEnabled: javascriptEnabled == const $CopyWithPlaceholder()
@@ -201,6 +223,16 @@ class _$EngineSettingsCWProxyImpl implements _$EngineSettingsCWProxy {
? _value.userAgent
// ignore: cast_nullable_to_non_nullable
: userAgent as String?,
queryParameterStripping:
queryParameterStripping == const $CopyWithPlaceholder()
? _value.queryParameterStripping
// ignore: cast_nullable_to_non_nullable
: queryParameterStripping as QueryParameterStripping,
bounceTrackingProtectionMode:
bounceTrackingProtectionMode == const $CopyWithPlaceholder()
? _value.bounceTrackingProtectionMode
// ignore: cast_nullable_to_non_nullable
: bounceTrackingProtectionMode as BounceTrackingProtectionMode,
);
}
}
@@ -247,6 +279,14 @@ EngineSettings _$EngineSettingsFromJson(Map<String, dynamic> json) =>
_$WebContentIsolationStrategyEnumMap,
json['webContentIsolationStrategy'],
),
queryParameterStripping: $enumDecodeNullable(
_$QueryParameterStrippingEnumMap,
json['queryParameterStripping'],
),
bounceTrackingProtectionMode: $enumDecodeNullable(
_$BounceTrackingProtectionModeEnumMap,
json['bounceTrackingProtectionMode'],
),
userAgent: json['userAgent'] as String?,
);
@@ -271,6 +311,11 @@ Map<String, dynamic> _$EngineSettingsToJson(
'webContentIsolationStrategy':
_$WebContentIsolationStrategyEnumMap[instance
.webContentIsolationStrategy]!,
'queryParameterStripping':
_$QueryParameterStrippingEnumMap[instance.queryParameterStripping]!,
'bounceTrackingProtectionMode':
_$BounceTrackingProtectionModeEnumMap[instance
.bounceTrackingProtectionMode]!,
};
const _$TrackingProtectionPolicyEnumMap = {
@@ -303,3 +348,16 @@ const _$WebContentIsolationStrategyEnumMap = {
WebContentIsolationStrategy.isolateEverything: 'isolateEverything',
WebContentIsolationStrategy.isolateHighValue: 'isolateHighValue',
};
const _$QueryParameterStrippingEnumMap = {
QueryParameterStripping.disabled: 'disabled',
QueryParameterStripping.privateOnly: 'privateOnly',
QueryParameterStripping.enabled: 'enabled',
};
const _$BounceTrackingProtectionModeEnumMap = {
BounceTrackingProtectionMode.disabled: 'disabled',
BounceTrackingProtectionMode.enabled: 'enabled',
BounceTrackingProtectionMode.enabledStandby: 'enabledStandby',
BounceTrackingProtectionMode.enabledDryRun: 'enabledDryRun',
};
+1 -1
View File
@@ -42,7 +42,7 @@ Stream<double> iconCacheSizeMegabytes(Ref ref) {
@Riverpod()
bool incognitoModeEnabled(Ref ref) {
return ref.watch(
generalSettingsRepositoryProvider.select(
generalSettingsWithDefaultsProvider.select(
(value) => value.deleteBrowsingDataOnQuit != null,
),
);
@@ -43,7 +43,7 @@ final iconCacheSizeMegabytesProvider =
// ignore: unused_element
typedef IconCacheSizeMegabytesRef = AutoDisposeStreamProviderRef<double>;
String _$incognitoModeEnabledHash() =>
r'3968c2d4945be09a0bc08ce0d70b0390187c44e8';
r'36957b70a5261f9d3ad228e07cc8dd5c8f616082';
/// See also [incognitoModeEnabled].
@ProviderFor(incognitoModeEnabled)
@@ -20,6 +20,7 @@
import 'dart:async';
import 'package:drift/drift.dart';
import 'package:riverpod/riverpod.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
import 'package:weblibre/features/user/data/models/engine_settings.dart';
import 'package:weblibre/features/user/data/providers.dart';
@@ -33,9 +34,72 @@ typedef UpdateEngineSettingsFunc =
class EngineSettingsRepository extends _$EngineSettingsRepository {
final _partitionKey = 'engine';
Future<void> updateSettings(UpdateEngineSettingsFunc updateWithCurrent) {
final oldJson = state.toJson();
final newJson = updateWithCurrent(state).toJson();
EngineSettings _deserializeSettings(
List<MapEntry<String, DriftAny?>> entries,
) {
final db = ref.read(userDatabaseProvider);
final settings = Map.fromEntries(entries);
return EngineSettings.fromJson({
'incognitoMode': settings['incognitoMode']?.readAs(
DriftSqlType.bool,
db.typeMapping,
),
'javascriptEnabled': settings['javascriptEnabled']?.readAs(
DriftSqlType.bool,
db.typeMapping,
),
'trackingProtectionPolicy': settings['trackingProtectionPolicy']?.readAs(
DriftSqlType.string,
db.typeMapping,
),
'httpsOnlyMode': settings['httpsOnlyMode']?.readAs(
DriftSqlType.string,
db.typeMapping,
),
'globalPrivacyControlEnabled': settings['globalPrivacyControlEnabled']
?.readAs(DriftSqlType.bool, db.typeMapping),
'cookieBannerHandlingMode': settings['cookieBannerHandlingMode']?.readAs(
DriftSqlType.string,
db.typeMapping,
),
'cookieBannerHandlingModePrivateBrowsing':
settings['cookieBannerHandlingModePrivateBrowsing']?.readAs(
DriftSqlType.string,
db.typeMapping,
),
'cookieBannerHandlingGlobalRules':
settings['cookieBannerHandlingGlobalRules']?.readAs(
DriftSqlType.bool,
db.typeMapping,
),
'cookieBannerHandlingGlobalRulesSubFrames':
settings['cookieBannerHandlingGlobalRulesSubFrames']?.readAs(
DriftSqlType.bool,
db.typeMapping,
),
'webContentIsolationStrategy': settings['webContentIsolationStrategy']
?.readAs(DriftSqlType.string, db.typeMapping),
'userAgent': settings['userAgent']?.readAs(
DriftSqlType.string,
db.typeMapping,
),
'queryParameterStripping': settings['queryParameterStripping']?.readAs(
DriftSqlType.string,
db.typeMapping,
),
'bounceTrackingProtectionMode': settings['bounceTrackingProtectionMode']
?.readAs(DriftSqlType.string, db.typeMapping),
});
}
Future<void> updateSettings(
UpdateEngineSettingsFunc updateWithCurrent,
) async {
final current = await fetchSettings();
final oldJson = current.toJson();
final newJson = updateWithCurrent(current).toJson();
return ref.read(userDatabaseProvider).transaction(() async {
for (final MapEntry(:key, :value) in newJson.entries) {
@@ -49,69 +113,33 @@ class EngineSettingsRepository extends _$EngineSettingsRepository {
});
}
Future<EngineSettings> fetchSettings() {
return ref
.read(userDatabaseProvider)
.settingDao
.getAllSettingsOfPartitionKey(_partitionKey)
.get()
.then(_deserializeSettings);
}
@override
EngineSettings build() {
Stream<EngineSettings> build() {
final db = ref.watch(userDatabaseProvider);
final watchSub = db.settingDao
return db.settingDao
.getAllSettingsOfPartitionKey(_partitionKey)
.watch()
.listen((entries) {
final settings = Map.fromEntries(entries);
state = EngineSettings.fromJson({
'incognitoMode': settings['incognitoMode']?.readAs(
DriftSqlType.bool,
db.typeMapping,
),
'javascriptEnabled': settings['javascriptEnabled']?.readAs(
DriftSqlType.bool,
db.typeMapping,
),
'trackingProtectionPolicy': settings['trackingProtectionPolicy']
?.readAs(DriftSqlType.string, db.typeMapping),
'httpsOnlyMode': settings['httpsOnlyMode']?.readAs(
DriftSqlType.string,
db.typeMapping,
),
'globalPrivacyControlEnabled':
settings['globalPrivacyControlEnabled']?.readAs(
DriftSqlType.bool,
db.typeMapping,
),
'cookieBannerHandlingMode': settings['cookieBannerHandlingMode']
?.readAs(DriftSqlType.string, db.typeMapping),
'cookieBannerHandlingModePrivateBrowsing':
settings['cookieBannerHandlingModePrivateBrowsing']?.readAs(
DriftSqlType.string,
db.typeMapping,
),
'cookieBannerHandlingGlobalRules':
settings['cookieBannerHandlingGlobalRules']?.readAs(
DriftSqlType.bool,
db.typeMapping,
),
'cookieBannerHandlingGlobalRulesSubFrames':
settings['cookieBannerHandlingGlobalRulesSubFrames']?.readAs(
DriftSqlType.bool,
db.typeMapping,
),
'webContentIsolationStrategy':
settings['webContentIsolationStrategy']?.readAs(
DriftSqlType.string,
db.typeMapping,
),
'userAgent': settings['userAgent']?.readAs(
DriftSqlType.string,
db.typeMapping,
),
});
.map((entries) {
return _deserializeSettings(entries);
});
ref.onDispose(() async {
await watchSub.cancel();
});
return EngineSettings.withDefaults();
}
}
@Riverpod()
EngineSettings engineSettingsWithDefaults(Ref ref) {
return ref.watch(
engineSettingsRepositoryProvider.select(
(value) => value.valueOrNull ?? EngineSettings.withDefaults(),
),
);
}
@@ -6,13 +6,32 @@ part of 'engine_settings.dart';
// RiverpodGenerator
// **************************************************************************
String _$engineSettingsWithDefaultsHash() =>
r'018e37f31f893e203b86038e84b0ddf5e72454d4';
/// See also [engineSettingsWithDefaults].
@ProviderFor(engineSettingsWithDefaults)
final engineSettingsWithDefaultsProvider =
AutoDisposeProvider<EngineSettings>.internal(
engineSettingsWithDefaults,
name: r'engineSettingsWithDefaultsProvider',
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
? null
: _$engineSettingsWithDefaultsHash,
dependencies: null,
allTransitiveDependencies: null,
);
@Deprecated('Will be removed in 3.0. Use Ref instead')
// ignore: unused_element
typedef EngineSettingsWithDefaultsRef = AutoDisposeProviderRef<EngineSettings>;
String _$engineSettingsRepositoryHash() =>
r'87e308c8bd4390d1d5c401532a0c35cd96f6176e';
r'aa522c35377280c451f6ac9e5f7063eab7ba6efc';
/// See also [EngineSettingsRepository].
@ProviderFor(EngineSettingsRepository)
final engineSettingsRepositoryProvider =
NotifierProvider<EngineSettingsRepository, EngineSettings>.internal(
StreamNotifierProvider<EngineSettingsRepository, EngineSettings>.internal(
EngineSettingsRepository.new,
name: r'engineSettingsRepositoryProvider',
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
@@ -22,6 +41,6 @@ final engineSettingsRepositoryProvider =
allTransitiveDependencies: null,
);
typedef _$EngineSettingsRepository = Notifier<EngineSettings>;
typedef _$EngineSettingsRepository = StreamNotifier<EngineSettings>;
// ignore_for_file: type=lint
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package
@@ -22,6 +22,7 @@ import 'dart:convert';
import 'package:drift/drift.dart';
import 'package:nullability/nullability.dart';
import 'package:riverpod/riverpod.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
import 'package:weblibre/features/user/data/models/general_settings.dart';
import 'package:weblibre/features/user/data/providers.dart';
@@ -95,7 +96,7 @@ class GeneralSettingsRepository extends _$GeneralSettingsRepository {
}
//Eager fetch, when up to date settings are required
Future<GeneralSettings> fetch() {
Future<GeneralSettings> fetchSettings() {
return ref
.read(userDatabaseProvider)
.settingDao
@@ -104,9 +105,13 @@ class GeneralSettingsRepository extends _$GeneralSettingsRepository {
.then(_deserializeSettings);
}
Future<void> updateSettings(UpdateGeneralSettingsFunc updateWithCurrent) {
final oldJson = state.toJson();
final newJson = updateWithCurrent(state).toJson();
Future<void> updateSettings(
UpdateGeneralSettingsFunc updateWithCurrent,
) async {
final current = await fetchSettings();
final oldJson = current.toJson();
final newJson = updateWithCurrent(current).toJson();
final db = ref.read(userDatabaseProvider);
@@ -120,20 +125,23 @@ class GeneralSettingsRepository extends _$GeneralSettingsRepository {
}
@override
GeneralSettings build() {
Stream<GeneralSettings> build() {
final db = ref.watch(userDatabaseProvider);
final watchSub = db.settingDao
return db.settingDao
.getAllSettingsOfPartitionKey(_partitionKey)
.watch()
.listen((event) {
state = _deserializeSettings(event);
.map((event) {
return _deserializeSettings(event);
});
ref.onDispose(() async {
await watchSub.cancel();
});
return GeneralSettings.withDefaults();
}
}
@Riverpod()
GeneralSettings generalSettingsWithDefaults(Ref ref) {
return ref.watch(
generalSettingsRepositoryProvider.select(
(value) => value.valueOrNull ?? GeneralSettings.withDefaults(),
),
);
}
@@ -6,13 +6,33 @@ part of 'general_settings.dart';
// RiverpodGenerator
// **************************************************************************
String _$generalSettingsWithDefaultsHash() =>
r'd2a20cb527f8bf5a16e273933cf7ccc9d0851dc4';
/// See also [generalSettingsWithDefaults].
@ProviderFor(generalSettingsWithDefaults)
final generalSettingsWithDefaultsProvider =
AutoDisposeProvider<GeneralSettings>.internal(
generalSettingsWithDefaults,
name: r'generalSettingsWithDefaultsProvider',
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
? null
: _$generalSettingsWithDefaultsHash,
dependencies: null,
allTransitiveDependencies: null,
);
@Deprecated('Will be removed in 3.0. Use Ref instead')
// ignore: unused_element
typedef GeneralSettingsWithDefaultsRef =
AutoDisposeProviderRef<GeneralSettings>;
String _$generalSettingsRepositoryHash() =>
r'538e03e9eff8beefc0918614c86d8919224c3039';
r'7e1c4d6051c4c3972b6998dee89d13b49be32e48';
/// See also [GeneralSettingsRepository].
@ProviderFor(GeneralSettingsRepository)
final generalSettingsRepositoryProvider =
NotifierProvider<GeneralSettingsRepository, GeneralSettings>.internal(
StreamNotifierProvider<GeneralSettingsRepository, GeneralSettings>.internal(
GeneralSettingsRepository.new,
name: r'generalSettingsRepositoryProvider',
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
@@ -22,6 +42,6 @@ final generalSettingsRepositoryProvider =
allTransitiveDependencies: null,
);
typedef _$GeneralSettingsRepository = Notifier<GeneralSettings>;
typedef _$GeneralSettingsRepository = StreamNotifier<GeneralSettings>;
// ignore_for_file: type=lint
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package