From 839824b5733da84c850961776140175c07fb26a5 Mon Sep 17 00:00:00 2001 From: Fabian Freund Date: Wed, 10 Sep 2025 07:32:52 +0200 Subject: [PATCH] wip --- .../services/proxy_settings_replication.dart | 4 +- .../proxy_settings_replication.g.dart | 2 +- .../controllers/save_settings.dart | 18 +++++ .../controllers/save_settings.g.dart | 17 ++++ .../tor/domain/services/tor_proxy.dart | 13 +++ .../tor/domain/services/tor_proxy.g.dart | 26 ------ .../tor/presentation/screens/tor_proxy.dart | 63 ++++++++++++--- .../user/data/models/general_settings.dart | 5 -- .../user/data/models/general_settings.g.dart | 14 ---- .../user/data/models/tor_settings.dart | 26 ++++++ .../user/data/models/tor_settings.g.dart | 80 +++++++++++++++++++ .../domain/repositories/general_settings.dart | 4 - .../repositories/general_settings.g.dart | 2 +- .../domain/repositories/tor_settings.dart | 80 +++++++++++++++++++ .../domain/repositories/tor_settings.g.dart | 46 +++++++++++ 15 files changed, 336 insertions(+), 64 deletions(-) delete mode 100644 app/lib/features/tor/domain/services/tor_proxy.g.dart create mode 100644 app/lib/features/user/data/models/tor_settings.dart create mode 100644 app/lib/features/user/data/models/tor_settings.g.dart create mode 100644 app/lib/features/user/domain/repositories/tor_settings.dart create mode 100644 app/lib/features/user/domain/repositories/tor_settings.g.dart diff --git a/app/lib/features/geckoview/features/browser/domain/services/proxy_settings_replication.dart b/app/lib/features/geckoview/features/browser/domain/services/proxy_settings_replication.dart index 2eb4e900..e816237c 100644 --- a/app/lib/features/geckoview/features/browser/domain/services/proxy_settings_replication.dart +++ b/app/lib/features/geckoview/features/browser/domain/services/proxy_settings_replication.dart @@ -24,7 +24,7 @@ import 'package:riverpod_annotation/riverpod_annotation.dart'; import 'package:weblibre/core/logger.dart'; import 'package:weblibre/features/geckoview/features/tabs/domain/providers.dart'; import 'package:weblibre/features/tor/domain/services/tor_proxy.dart'; -import 'package:weblibre/features/user/domain/repositories/general_settings.dart'; +import 'package:weblibre/features/user/domain/repositories/tor_settings.dart'; part 'proxy_settings_replication.g.dart'; @@ -84,7 +84,7 @@ class ProxySettingsReplication extends _$ProxySettingsReplication { ref.listen( fireImmediately: true, - generalSettingsWithDefaultsProvider.select( + torSettingsWithDefaultsProvider.select( (value) => value.proxyPrivateTabsTor, ), (previous, next) async { diff --git a/app/lib/features/geckoview/features/browser/domain/services/proxy_settings_replication.g.dart b/app/lib/features/geckoview/features/browser/domain/services/proxy_settings_replication.g.dart index 8377dc3b..1d1b8b4c 100644 --- a/app/lib/features/geckoview/features/browser/domain/services/proxy_settings_replication.g.dart +++ b/app/lib/features/geckoview/features/browser/domain/services/proxy_settings_replication.g.dart @@ -7,7 +7,7 @@ part of 'proxy_settings_replication.dart'; // ************************************************************************** String _$proxySettingsReplicationHash() => - r'e9f3adc73349c6d33fc7009412984b1daa4cc8da'; + r'95e68c06df280d11730ec35f0cd93cf2b1e3c02d'; /// See also [ProxySettingsReplication]. @ProviderFor(ProxySettingsReplication) diff --git a/app/lib/features/settings/presentation/controllers/save_settings.dart b/app/lib/features/settings/presentation/controllers/save_settings.dart index 59a53f2a..efde41d6 100644 --- a/app/lib/features/settings/presentation/controllers/save_settings.dart +++ b/app/lib/features/settings/presentation/controllers/save_settings.dart @@ -20,6 +20,7 @@ import 'package:riverpod_annotation/riverpod_annotation.dart'; import 'package:weblibre/features/user/domain/repositories/engine_settings.dart'; import 'package:weblibre/features/user/domain/repositories/general_settings.dart'; +import 'package:weblibre/features/user/domain/repositories/tor_settings.dart'; part 'save_settings.g.dart'; @@ -56,3 +57,20 @@ class SaveEngineSettingsController extends _$SaveEngineSettingsController { ); } } + +@Riverpod(keepAlive: true) +class SaveTorSettingsController extends _$SaveTorSettingsController { + @override + Future build() { + return Future.value(); + } + + Future save(UpdateTorSettingsFunc updateSettings) async { + state = const AsyncLoading(); + state = await AsyncValue.guard( + () => ref + .read(torSettingsRepositoryProvider.notifier) + .updateSettings(updateSettings), + ); + } +} diff --git a/app/lib/features/settings/presentation/controllers/save_settings.g.dart b/app/lib/features/settings/presentation/controllers/save_settings.g.dart index 36418339..b4eb8750 100644 --- a/app/lib/features/settings/presentation/controllers/save_settings.g.dart +++ b/app/lib/features/settings/presentation/controllers/save_settings.g.dart @@ -40,5 +40,22 @@ final saveEngineSettingsControllerProvider = ); typedef _$SaveEngineSettingsController = AsyncNotifier; +String _$saveTorSettingsControllerHash() => + r'd8aa04d7ae60c97bdad6c072f894189509dd35d3'; + +/// See also [SaveTorSettingsController]. +@ProviderFor(SaveTorSettingsController) +final saveTorSettingsControllerProvider = + AsyncNotifierProvider.internal( + SaveTorSettingsController.new, + name: r'saveTorSettingsControllerProvider', + debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product') + ? null + : _$saveTorSettingsControllerHash, + dependencies: null, + allTransitiveDependencies: null, + ); + +typedef _$SaveTorSettingsController = AsyncNotifier; // 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 diff --git a/app/lib/features/tor/domain/services/tor_proxy.dart b/app/lib/features/tor/domain/services/tor_proxy.dart index 1939b76c..ff0e06d5 100644 --- a/app/lib/features/tor/domain/services/tor_proxy.dart +++ b/app/lib/features/tor/domain/services/tor_proxy.dart @@ -27,6 +27,7 @@ import 'package:rxdart/rxdart.dart'; import 'package:weblibre/core/logger.dart'; import 'package:weblibre/features/geckoview/features/browser/domain/providers/lifecycle.dart'; import 'package:weblibre/features/tor/utils/tor_entrypoint.dart'; +import 'package:weblibre/features/user/domain/repositories/tor_settings.dart'; part 'tor_proxy.g.dart'; @@ -105,6 +106,18 @@ class TorProxyService extends _$TorProxyService { if (currentPort == null || forceReconnect) { state = const AsyncLoading(); + + final torSettings = await ref + .read(torSettingsRepositoryProvider.notifier) + .fetchSettings(); + + if (torSettings.autoConfig) { + final moat = MoatService(); + final config = await moat.autoConf(); + + todo + } + await _tor.start(); _enableHeartbeatTimer(); } diff --git a/app/lib/features/tor/domain/services/tor_proxy.g.dart b/app/lib/features/tor/domain/services/tor_proxy.g.dart deleted file mode 100644 index 25eb9524..00000000 --- a/app/lib/features/tor/domain/services/tor_proxy.g.dart +++ /dev/null @@ -1,26 +0,0 @@ -// GENERATED CODE - DO NOT MODIFY BY HAND - -part of 'tor_proxy.dart'; - -// ************************************************************************** -// RiverpodGenerator -// ************************************************************************** - -String _$torProxyServiceHash() => r'f991652e4e228d3e7fdc09a6088b6c5427d6231c'; - -/// See also [TorProxyService]. -@ProviderFor(TorProxyService) -final torProxyServiceProvider = - AsyncNotifierProvider.internal( - TorProxyService.new, - name: r'torProxyServiceProvider', - debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product') - ? null - : _$torProxyServiceHash, - dependencies: null, - allTransitiveDependencies: null, - ); - -typedef _$TorProxyService = AsyncNotifier; -// 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 diff --git a/app/lib/features/tor/presentation/screens/tor_proxy.dart b/app/lib/features/tor/presentation/screens/tor_proxy.dart index 4b47be3c..23164da4 100644 --- a/app/lib/features/tor/presentation/screens/tor_proxy.dart +++ b/app/lib/features/tor/presentation/screens/tor_proxy.dart @@ -22,8 +22,8 @@ import 'package:flutter_material_design_icons/flutter_material_design_icons.dart import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:weblibre/features/settings/presentation/controllers/save_settings.dart'; import 'package:weblibre/features/tor/domain/services/tor_proxy.dart'; -import 'package:weblibre/features/user/data/models/general_settings.dart'; -import 'package:weblibre/features/user/domain/repositories/general_settings.dart'; +import 'package:weblibre/features/user/data/models/tor_settings.dart'; +import 'package:weblibre/features/user/domain/repositories/tor_settings.dart'; import 'package:weblibre/presentation/hooks/on_initialization.dart'; import 'package:weblibre/presentation/icons/tor_icons.dart'; @@ -33,11 +33,7 @@ class TorProxyScreen extends HookConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { final torProxyPort = ref.watch(torProxyServiceProvider); - final proxyPrivateTabsTor = ref.watch( - generalSettingsWithDefaultsProvider.select( - (value) => value.proxyPrivateTabsTor, - ), - ); + final torSettings = ref.watch(torSettingsWithDefaultsProvider); useOnInitialization(() async { await ref.read(torProxyServiceProvider.notifier).requestSync(); @@ -136,7 +132,7 @@ class TorProxyScreen extends HookConsumerWidget { } return null; // Use the default color. }), - value: proxyPrivateTabsTor, + value: torSettings.proxyPrivateTabsTor, title: const Text('Proxy Private Tabs'), subtitle: const Text( 'When enabled, all Private Tabs will be tunneled through Tor', @@ -144,9 +140,7 @@ class TorProxyScreen extends HookConsumerWidget { secondary: const Icon(MdiIcons.arrowDecision), onChanged: (value) async { await ref - .read( - saveGeneralSettingsControllerProvider.notifier, - ) + .read(saveTorSettingsControllerProvider.notifier) .save( (currentSettings) => currentSettings.copyWith .proxyPrivateTabsTor(value), @@ -154,6 +148,53 @@ class TorProxyScreen extends HookConsumerWidget { }, ), ), + ListTileTheme( + iconColor: Colors.white, + textColor: Colors.white, + child: SwitchListTile.adaptive( + inactiveThumbColor: Colors.white, + activeColor: const Color(0xFF68B030), + trackColor: WidgetStateProperty.resolveWith(( + Set states, + ) { + if (states.isEmpty) { + return const Color(0xFF333A41); + } + return null; // Use the default color. + }), + trackOutlineColor: + WidgetStateProperty.resolveWith(( + Set states, + ) { + if (states.isEmpty) { + return Colors.white; + } + return null; // Use the default color. + }), + thumbIcon: WidgetStateProperty.resolveWith(( + Set states, + ) { + if (states.contains(WidgetState.selected)) { + return const Icon(MdiIcons.arrowDecisionAuto); + } + return null; // Use the default color. + }), + value: torSettings.autoConfig, + title: const Text('Configure Transport Automatically'), + subtitle: const Text( + 'From some locations, it is necessary to use a pluggable transport to connect to the Tor network that is otherwise blocked. Turn off automatic configuration to manually configure how Tor connects.', + ), + secondary: const Icon(MdiIcons.arrowDecision), + onChanged: (value) async { + await ref + .read(saveTorSettingsControllerProvider.notifier) + .save( + (currentSettings) => + currentSettings.copyWith.autoConfig(value), + ); + }, + ), + ), ], ), ), diff --git a/app/lib/features/user/data/models/general_settings.dart b/app/lib/features/user/data/models/general_settings.dart index ac2a2018..5c7fde52 100644 --- a/app/lib/features/user/data/models/general_settings.dart +++ b/app/lib/features/user/data/models/general_settings.dart @@ -59,7 +59,6 @@ class GeneralSettings with FastEquatable { final bool enableLocalAiFeatures; final TabType defaultCreateTabType; final TabType defaultIntentTabType; - final bool proxyPrivateTabsTor; final bool autoHideTabBar; final TabBarSwipeAction tabBarSwipeAction; @@ -71,7 +70,6 @@ class GeneralSettings with FastEquatable { required this.defaultSearchProvider, required this.defaultSearchSuggestionsProvider, required this.createChildTabsOption, - required this.proxyPrivateTabsTor, required this.showExtensionShortcut, required this.enableLocalAiFeatures, required this.defaultCreateTabType, @@ -88,7 +86,6 @@ class GeneralSettings with FastEquatable { String? defaultSearchProvider, SearchSuggestionProviders? defaultSearchSuggestionsProvider, bool? createChildTabsOption, - bool? proxyPrivateTabsTor, bool? showExtensionShortcut, bool? enableLocalAiFeatures, TabType? defaultCreateTabType, @@ -102,7 +99,6 @@ class GeneralSettings with FastEquatable { defaultSearchSuggestionsProvider = defaultSearchSuggestionsProvider ?? _fallbackAutocompleteProvider, createChildTabsOption = createChildTabsOption ?? false, - proxyPrivateTabsTor = proxyPrivateTabsTor ?? false, showExtensionShortcut = showExtensionShortcut ?? false, enableLocalAiFeatures = enableLocalAiFeatures ?? true, defaultCreateTabType = defaultCreateTabType ?? TabType.regular, @@ -129,7 +125,6 @@ class GeneralSettings with FastEquatable { enableLocalAiFeatures, defaultCreateTabType, defaultIntentTabType, - proxyPrivateTabsTor, autoHideTabBar, tabBarSwipeAction, ]; diff --git a/app/lib/features/user/data/models/general_settings.g.dart b/app/lib/features/user/data/models/general_settings.g.dart index ddb78cbe..03e979c2 100644 --- a/app/lib/features/user/data/models/general_settings.g.dart +++ b/app/lib/features/user/data/models/general_settings.g.dart @@ -25,8 +25,6 @@ abstract class _$GeneralSettingsCWProxy { GeneralSettings createChildTabsOption(bool createChildTabsOption); - GeneralSettings proxyPrivateTabsTor(bool proxyPrivateTabsTor); - GeneralSettings showExtensionShortcut(bool showExtensionShortcut); GeneralSettings enableLocalAiFeatures(bool enableLocalAiFeatures); @@ -53,7 +51,6 @@ abstract class _$GeneralSettingsCWProxy { String defaultSearchProvider, SearchSuggestionProviders defaultSearchSuggestionsProvider, bool createChildTabsOption, - bool proxyPrivateTabsTor, bool showExtensionShortcut, bool enableLocalAiFeatures, TabType defaultCreateTabType, @@ -98,10 +95,6 @@ class _$GeneralSettingsCWProxyImpl implements _$GeneralSettingsCWProxy { GeneralSettings createChildTabsOption(bool createChildTabsOption) => this(createChildTabsOption: createChildTabsOption); - @override - GeneralSettings proxyPrivateTabsTor(bool proxyPrivateTabsTor) => - this(proxyPrivateTabsTor: proxyPrivateTabsTor); - @override GeneralSettings showExtensionShortcut(bool showExtensionShortcut) => this(showExtensionShortcut: showExtensionShortcut); @@ -141,7 +134,6 @@ class _$GeneralSettingsCWProxyImpl implements _$GeneralSettingsCWProxy { Object? defaultSearchProvider = const $CopyWithPlaceholder(), Object? defaultSearchSuggestionsProvider = const $CopyWithPlaceholder(), Object? createChildTabsOption = const $CopyWithPlaceholder(), - Object? proxyPrivateTabsTor = const $CopyWithPlaceholder(), Object? showExtensionShortcut = const $CopyWithPlaceholder(), Object? enableLocalAiFeatures = const $CopyWithPlaceholder(), Object? defaultCreateTabType = const $CopyWithPlaceholder(), @@ -182,10 +174,6 @@ class _$GeneralSettingsCWProxyImpl implements _$GeneralSettingsCWProxy { ? _value.createChildTabsOption // ignore: cast_nullable_to_non_nullable : createChildTabsOption as bool, - proxyPrivateTabsTor: proxyPrivateTabsTor == const $CopyWithPlaceholder() - ? _value.proxyPrivateTabsTor - // ignore: cast_nullable_to_non_nullable - : proxyPrivateTabsTor as bool, showExtensionShortcut: showExtensionShortcut == const $CopyWithPlaceholder() ? _value.showExtensionShortcut @@ -241,7 +229,6 @@ GeneralSettings _$GeneralSettingsFromJson(Map json) => json['defaultSearchSuggestionsProvider'], ), createChildTabsOption: json['createChildTabsOption'] as bool?, - proxyPrivateTabsTor: json['proxyPrivateTabsTor'] as bool?, showExtensionShortcut: json['showExtensionShortcut'] as bool?, enableLocalAiFeatures: json['enableLocalAiFeatures'] as bool?, defaultCreateTabType: $enumDecodeNullable( @@ -277,7 +264,6 @@ Map _$GeneralSettingsToJson( 'enableLocalAiFeatures': instance.enableLocalAiFeatures, 'defaultCreateTabType': _$TabTypeEnumMap[instance.defaultCreateTabType]!, 'defaultIntentTabType': _$TabTypeEnumMap[instance.defaultIntentTabType]!, - 'proxyPrivateTabsTor': instance.proxyPrivateTabsTor, 'autoHideTabBar': instance.autoHideTabBar, 'tabBarSwipeAction': _$TabBarSwipeActionEnumMap[instance.tabBarSwipeAction]!, }; diff --git a/app/lib/features/user/data/models/tor_settings.dart b/app/lib/features/user/data/models/tor_settings.dart new file mode 100644 index 00000000..fb15df08 --- /dev/null +++ b/app/lib/features/user/data/models/tor_settings.dart @@ -0,0 +1,26 @@ +import 'package:copy_with_extension/copy_with_extension.dart'; +import 'package:fast_equatable/fast_equatable.dart'; +import 'package:json_annotation/json_annotation.dart'; + +part 'tor_settings.g.dart'; + +@CopyWith() +@JsonSerializable(includeIfNull: true, constructor: 'withDefaults') +class TorSettings with FastEquatable { + final bool proxyPrivateTabsTor; + final bool autoConfig; + + TorSettings({required this.proxyPrivateTabsTor, required this.autoConfig}); + + TorSettings.withDefaults({bool? proxyPrivateTabsTor, bool? autoConfig}) + : proxyPrivateTabsTor = proxyPrivateTabsTor ?? false, + autoConfig = autoConfig ?? true; + + factory TorSettings.fromJson(Map json) => + _$TorSettingsFromJson(json); + + Map toJson() => _$TorSettingsToJson(this); + + @override + List get hashParameters => [proxyPrivateTabsTor, autoConfig]; +} diff --git a/app/lib/features/user/data/models/tor_settings.g.dart b/app/lib/features/user/data/models/tor_settings.g.dart new file mode 100644 index 00000000..298363ee --- /dev/null +++ b/app/lib/features/user/data/models/tor_settings.g.dart @@ -0,0 +1,80 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'tor_settings.dart'; + +// ************************************************************************** +// CopyWithGenerator +// ************************************************************************** + +abstract class _$TorSettingsCWProxy { + TorSettings proxyPrivateTabsTor(bool proxyPrivateTabsTor); + + TorSettings autoConfig(bool autoConfig); + + /// This function **does support** nullification of nullable fields. All `null` values passed to `non-nullable` fields will be ignored. You can also use `TorSettings(...).copyWith.fieldName(...)` to override fields one at a time with nullification support. + /// + /// Usage + /// ```dart + /// TorSettings(...).copyWith(id: 12, name: "My name") + /// ```` + TorSettings call({bool proxyPrivateTabsTor, bool autoConfig}); +} + +/// Proxy class for `copyWith` functionality. This is a callable class and can be used as follows: `instanceOfTorSettings.copyWith(...)`. Additionally contains functions for specific fields e.g. `instanceOfTorSettings.copyWith.fieldName(...)` +class _$TorSettingsCWProxyImpl implements _$TorSettingsCWProxy { + const _$TorSettingsCWProxyImpl(this._value); + + final TorSettings _value; + + @override + TorSettings proxyPrivateTabsTor(bool proxyPrivateTabsTor) => + this(proxyPrivateTabsTor: proxyPrivateTabsTor); + + @override + TorSettings autoConfig(bool autoConfig) => this(autoConfig: autoConfig); + + @override + /// This function **does support** nullification of nullable fields. All `null` values passed to `non-nullable` fields will be ignored. You can also use `TorSettings(...).copyWith.fieldName(...)` to override fields one at a time with nullification support. + /// + /// Usage + /// ```dart + /// TorSettings(...).copyWith(id: 12, name: "My name") + /// ```` + TorSettings call({ + Object? proxyPrivateTabsTor = const $CopyWithPlaceholder(), + Object? autoConfig = const $CopyWithPlaceholder(), + }) { + return TorSettings( + proxyPrivateTabsTor: proxyPrivateTabsTor == const $CopyWithPlaceholder() + ? _value.proxyPrivateTabsTor + // ignore: cast_nullable_to_non_nullable + : proxyPrivateTabsTor as bool, + autoConfig: autoConfig == const $CopyWithPlaceholder() + ? _value.autoConfig + // ignore: cast_nullable_to_non_nullable + : autoConfig as bool, + ); + } +} + +extension $TorSettingsCopyWith on TorSettings { + /// Returns a callable class that can be used as follows: `instanceOfTorSettings.copyWith(...)` or like so:`instanceOfTorSettings.copyWith.fieldName(...)`. + // ignore: library_private_types_in_public_api + _$TorSettingsCWProxy get copyWith => _$TorSettingsCWProxyImpl(this); +} + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +TorSettings _$TorSettingsFromJson(Map json) => + TorSettings.withDefaults( + proxyPrivateTabsTor: json['proxyPrivateTabsTor'] as bool?, + autoConfig: json['autoConfig'] as bool?, + ); + +Map _$TorSettingsToJson(TorSettings instance) => + { + 'proxyPrivateTabsTor': instance.proxyPrivateTabsTor, + 'autoConfig': instance.autoConfig, + }; diff --git a/app/lib/features/user/domain/repositories/general_settings.dart b/app/lib/features/user/domain/repositories/general_settings.dart index c01eb5e7..d55b46a0 100644 --- a/app/lib/features/user/domain/repositories/general_settings.dart +++ b/app/lib/features/user/domain/repositories/general_settings.dart @@ -72,10 +72,6 @@ class GeneralSettingsRepository extends _$GeneralSettingsRepository { DriftSqlType.bool, db.typeMapping, ), - 'proxyPrivateTabsTor': settings['proxyPrivateTabsTor']?.readAs( - DriftSqlType.bool, - db.typeMapping, - ), 'showExtensionShortcut': settings['showExtensionShortcut']?.readAs( DriftSqlType.bool, db.typeMapping, diff --git a/app/lib/features/user/domain/repositories/general_settings.g.dart b/app/lib/features/user/domain/repositories/general_settings.g.dart index 5a1c8da2..0fc6484e 100644 --- a/app/lib/features/user/domain/repositories/general_settings.g.dart +++ b/app/lib/features/user/domain/repositories/general_settings.g.dart @@ -27,7 +27,7 @@ final generalSettingsWithDefaultsProvider = typedef GeneralSettingsWithDefaultsRef = AutoDisposeProviderRef; String _$generalSettingsRepositoryHash() => - r'e311760a7773109a90c28275262883fcca348bbb'; + r'07eeaf811fac4b9c787cce7c29379a7329910ae5'; /// See also [GeneralSettingsRepository]. @ProviderFor(GeneralSettingsRepository) diff --git a/app/lib/features/user/domain/repositories/tor_settings.dart b/app/lib/features/user/domain/repositories/tor_settings.dart new file mode 100644 index 00000000..3b17764c --- /dev/null +++ b/app/lib/features/user/domain/repositories/tor_settings.dart @@ -0,0 +1,80 @@ +import 'package:drift/drift.dart'; +import 'package:riverpod/riverpod.dart'; +import 'package:riverpod_annotation/riverpod_annotation.dart'; +import 'package:weblibre/features/user/data/models/tor_settings.dart'; +import 'package:weblibre/features/user/data/providers.dart'; + +part 'tor_settings.g.dart'; + +typedef UpdateTorSettingsFunc = + TorSettings Function(TorSettings currentSettings); + +@Riverpod(keepAlive: true) +class TorSettingsRepository extends _$TorSettingsRepository { + final _partitionKey = 'tor'; + + TorSettings _deserializeSettings(List> entries) { + final settings = Map.fromEntries(entries); + + final db = ref.read(userDatabaseProvider); + + return TorSettings.fromJson({ + 'proxyPrivateTabsTor': settings['proxyPrivateTabsTor']?.readAs( + DriftSqlType.bool, + db.typeMapping, + ), + 'autoConfig': settings['autoConfig']?.readAs( + DriftSqlType.bool, + db.typeMapping, + ), + }); + } + + //Eager fetch, when up to date settings are required + Future fetchSettings() { + return ref + .read(userDatabaseProvider) + .settingDao + .getAllSettingsOfPartitionKey(_partitionKey) + .get() + .then(_deserializeSettings); + } + + Future updateSettings(UpdateTorSettingsFunc updateWithCurrent) async { + final current = await fetchSettings(); + + final oldJson = current.toJson(); + final newJson = updateWithCurrent(current).toJson(); + + final db = ref.read(userDatabaseProvider); + + return db.transaction(() async { + for (final MapEntry(:key, :value) in newJson.entries) { + if (oldJson[key] != value) { + await db.settingDao.updateSetting(key, _partitionKey, value); + } + } + }); + } + + @override + Stream build() { + final db = ref.watch(userDatabaseProvider); + + return db.settingDao + .getAllSettingsOfPartitionKey(_partitionKey) + .watch() + .map((event) { + return _deserializeSettings(event); + }); + } +} + +@Riverpod() +TorSettings torSettingsWithDefaults(Ref ref) { + return ref.watch( + torSettingsRepositoryProvider.select( + (value) => value.valueOrNull ?? TorSettings.withDefaults(), + ), + ); +} diff --git a/app/lib/features/user/domain/repositories/tor_settings.g.dart b/app/lib/features/user/domain/repositories/tor_settings.g.dart new file mode 100644 index 00000000..843caba1 --- /dev/null +++ b/app/lib/features/user/domain/repositories/tor_settings.g.dart @@ -0,0 +1,46 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'tor_settings.dart'; + +// ************************************************************************** +// RiverpodGenerator +// ************************************************************************** + +String _$torSettingsWithDefaultsHash() => + r'b355678ae49e038f7e1b60f2d5da3f806349cba8'; + +/// See also [torSettingsWithDefaults]. +@ProviderFor(torSettingsWithDefaults) +final torSettingsWithDefaultsProvider = + AutoDisposeProvider.internal( + torSettingsWithDefaults, + name: r'torSettingsWithDefaultsProvider', + debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product') + ? null + : _$torSettingsWithDefaultsHash, + dependencies: null, + allTransitiveDependencies: null, + ); + +@Deprecated('Will be removed in 3.0. Use Ref instead') +// ignore: unused_element +typedef TorSettingsWithDefaultsRef = AutoDisposeProviderRef; +String _$torSettingsRepositoryHash() => + r'686e8576453f33a0d2d0eb2869e29ca88e00bc37'; + +/// See also [TorSettingsRepository]. +@ProviderFor(TorSettingsRepository) +final torSettingsRepositoryProvider = + StreamNotifierProvider.internal( + TorSettingsRepository.new, + name: r'torSettingsRepositoryProvider', + debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product') + ? null + : _$torSettingsRepositoryHash, + dependencies: null, + allTransitiveDependencies: null, + ); + +typedef _$TorSettingsRepository = StreamNotifier; +// 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