push
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
||||
import 'package:lensai/features/user/data/providers.dart';
|
||||
import 'package:lensai/features/user/domain/repositories/general_settings.dart';
|
||||
import 'package:pocketbase/pocketbase.dart';
|
||||
import 'package:riverpod/riverpod.dart';
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
@@ -47,3 +48,11 @@ PocketBase pocketBase(Ref ref) {
|
||||
|
||||
return PocketBase('http://192.168.2.104:8090', authStore: authStore);
|
||||
}
|
||||
|
||||
@Riverpod()
|
||||
bool incognitoModeEnabled(Ref ref) {
|
||||
return ref.watch(
|
||||
generalSettingsRepositoryProvider
|
||||
.select((value) => value.deleteBrowsingDataOnQuit != null),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -90,5 +90,23 @@ final pocketBaseProvider = Provider<PocketBase>.internal(
|
||||
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
||||
// ignore: unused_element
|
||||
typedef PocketBaseRef = ProviderRef<PocketBase>;
|
||||
String _$incognitoModeEnabledHash() =>
|
||||
r'3968c2d4945be09a0bc08ce0d70b0390187c44e8';
|
||||
|
||||
/// See also [incognitoModeEnabled].
|
||||
@ProviderFor(incognitoModeEnabled)
|
||||
final incognitoModeEnabledProvider = AutoDisposeProvider<bool>.internal(
|
||||
incognitoModeEnabled,
|
||||
name: r'incognitoModeEnabledProvider',
|
||||
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$incognitoModeEnabledHash,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
||||
// ignore: unused_element
|
||||
typedef IncognitoModeEnabledRef = AutoDisposeProviderRef<bool>;
|
||||
// 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
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:lensai/features/geckoview/domain/providers.dart';
|
||||
import 'package:lensai/features/user/data/database/database.dart';
|
||||
import 'package:lensai/features/user/data/providers.dart';
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
|
||||
@@ -9,29 +8,31 @@ part 'cache.g.dart';
|
||||
|
||||
@Riverpod(keepAlive: true)
|
||||
class CacheRepository extends _$CacheRepository {
|
||||
late UserDatabase _db;
|
||||
|
||||
Future<void> clearCache() {
|
||||
return _db.cacheDao.clearIconCache();
|
||||
return ref.read(userDatabaseProvider).cacheDao.clearIconCache();
|
||||
}
|
||||
|
||||
Future<void> cacheIcon(Uri url, Uint8List bytes) {
|
||||
return _db.cacheDao.cacheIcon(url.origin, bytes);
|
||||
return ref.read(userDatabaseProvider).cacheDao.cacheIcon(url.origin, bytes);
|
||||
}
|
||||
|
||||
Future<Uint8List?> getCachedIcon(String origin) {
|
||||
return _db.cacheDao.getCachedIcon(origin).getSingleOrNull();
|
||||
return ref
|
||||
.read(userDatabaseProvider)
|
||||
.cacheDao
|
||||
.getCachedIcon(origin)
|
||||
.getSingleOrNull();
|
||||
}
|
||||
|
||||
@override
|
||||
void build() {
|
||||
final eventService = ref.watch(eventServiceProvider);
|
||||
|
||||
_db = ref.watch(userDatabaseProvider);
|
||||
final db = ref.watch(userDatabaseProvider);
|
||||
|
||||
final sub = eventService.iconUpdateEvents.listen((event) async {
|
||||
if (Uri.tryParse(event.url) case final Uri url) {
|
||||
await _db.cacheDao.cacheIcon(url.origin, event.bytes);
|
||||
await db.cacheDao.cacheIcon(url.origin, event.bytes);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ part of 'cache.dart';
|
||||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
String _$cacheRepositoryHash() => r'37b25ff308b9f25575625984e55cb02f9c0293f0';
|
||||
String _$cacheRepositoryHash() => r'548b7cba9a23c21bba39f0918d7d90acaaf8d8e9';
|
||||
|
||||
/// See also [CacheRepository].
|
||||
@ProviderFor(CacheRepository)
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:drift/drift.dart';
|
||||
import 'package:lensai/features/user/data/database/database.dart';
|
||||
import 'package:lensai/features/user/data/models/engine_settings.dart';
|
||||
import 'package:lensai/features/user/data/providers.dart';
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
|
||||
part 'engine_settings.g.dart';
|
||||
|
||||
typedef UpdateEngineSettingsFunc = EngineSettings Function(
|
||||
EngineSettings currentSettings,
|
||||
);
|
||||
|
||||
@Riverpod(keepAlive: true)
|
||||
class EngineSettingsRepository extends _$EngineSettingsRepository {
|
||||
final _partitionKey = 'engine';
|
||||
|
||||
Future<void> updateSettings(UpdateEngineSettingsFunc updateWithCurrent) {
|
||||
final oldJson = state.toJson();
|
||||
final newJson = updateWithCurrent(state).toJson();
|
||||
|
||||
return ref.read(userDatabaseProvider).transaction(() async {
|
||||
for (final MapEntry(:key, :value) in newJson.entries) {
|
||||
if (oldJson[key] != value) {
|
||||
await ref
|
||||
.read(userDatabaseProvider)
|
||||
.settingDao
|
||||
.updateSetting(key, _partitionKey, value);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
EngineSettings build() {
|
||||
final db = ref.watch(userDatabaseProvider);
|
||||
|
||||
final watchSub = db.settingDao
|
||||
.allSettingsOfPartitionKey(_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),
|
||||
});
|
||||
});
|
||||
|
||||
ref.onDispose(() {
|
||||
unawaited(watchSub.cancel());
|
||||
});
|
||||
|
||||
return EngineSettings.withDefaults();
|
||||
}
|
||||
}
|
||||
+11
-11
@@ -1,27 +1,27 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'settings.dart';
|
||||
part of 'engine_settings.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
String _$settingsRepositoryHash() =>
|
||||
r'7e3e032957f5092aa3d445d2b7b05a882e3cfd20';
|
||||
String _$engineSettingsRepositoryHash() =>
|
||||
r'113617b3a99377bbb83347cfcb6d432abaae6f71';
|
||||
|
||||
/// See also [SettingsRepository].
|
||||
@ProviderFor(SettingsRepository)
|
||||
final settingsRepositoryProvider =
|
||||
NotifierProvider<SettingsRepository, Settings>.internal(
|
||||
SettingsRepository.new,
|
||||
name: r'settingsRepositoryProvider',
|
||||
/// See also [EngineSettingsRepository].
|
||||
@ProviderFor(EngineSettingsRepository)
|
||||
final engineSettingsRepositoryProvider =
|
||||
NotifierProvider<EngineSettingsRepository, EngineSettings>.internal(
|
||||
EngineSettingsRepository.new,
|
||||
name: r'engineSettingsRepositoryProvider',
|
||||
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$settingsRepositoryHash,
|
||||
: _$engineSettingsRepositoryHash,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
typedef _$SettingsRepository = Notifier<Settings>;
|
||||
typedef _$EngineSettingsRepository = Notifier<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
|
||||
@@ -0,0 +1,80 @@
|
||||
import 'dart:async';
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:drift/drift.dart';
|
||||
import 'package:lensai/extensions/nullable.dart';
|
||||
import 'package:lensai/features/user/data/models/general_settings.dart';
|
||||
import 'package:lensai/features/user/data/providers.dart';
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
|
||||
part 'general_settings.g.dart';
|
||||
|
||||
typedef UpdateGeneralSettingsFunc = GeneralSettings Function(
|
||||
GeneralSettings currentSettings,
|
||||
);
|
||||
|
||||
@Riverpod(keepAlive: true)
|
||||
class GeneralSettingsRepository extends _$GeneralSettingsRepository {
|
||||
final _partitionKey = 'general';
|
||||
|
||||
GeneralSettings _deserializeSettings(
|
||||
List<MapEntry<String, DriftAny?>> entries,
|
||||
) {
|
||||
final settings = Map.fromEntries(entries);
|
||||
|
||||
final db = ref.read(userDatabaseProvider);
|
||||
|
||||
return GeneralSettings.fromJson({
|
||||
'themeMode':
|
||||
settings['themeMode']?.readAs(DriftSqlType.string, db.typeMapping),
|
||||
'enableReadability': settings['enableReadability']
|
||||
?.readAs(DriftSqlType.bool, db.typeMapping),
|
||||
'deleteBrowsingDataOnQuit': settings['deleteBrowsingDataOnQuit']
|
||||
?.readAs(DriftSqlType.string, db.typeMapping)
|
||||
.mapNotNull(jsonDecode),
|
||||
});
|
||||
}
|
||||
|
||||
//Eager fetch, when up to date settings are required
|
||||
Future<GeneralSettings> fetch() async {
|
||||
return ref
|
||||
.read(userDatabaseProvider)
|
||||
.settingDao
|
||||
.allSettingsOfPartitionKey(_partitionKey)
|
||||
.get()
|
||||
.then(_deserializeSettings);
|
||||
}
|
||||
|
||||
Future<void> updateSettings(UpdateGeneralSettingsFunc updateWithCurrent) {
|
||||
final oldJson = state.toJson();
|
||||
final newJson = updateWithCurrent(state).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
|
||||
GeneralSettings build() {
|
||||
final db = ref.watch(userDatabaseProvider);
|
||||
|
||||
final watchSub =
|
||||
db.settingDao.allSettingsOfPartitionKey(_partitionKey).watch().listen(
|
||||
(event) {
|
||||
state = _deserializeSettings(event);
|
||||
},
|
||||
);
|
||||
|
||||
ref.onDispose(() {
|
||||
unawaited(watchSub.cancel());
|
||||
});
|
||||
|
||||
return GeneralSettings.withDefaults();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'general_settings.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
String _$generalSettingsRepositoryHash() =>
|
||||
r'd21cee982ed471dff5ba11415e5557073bd2fca3';
|
||||
|
||||
/// See also [GeneralSettingsRepository].
|
||||
@ProviderFor(GeneralSettingsRepository)
|
||||
final generalSettingsRepositoryProvider =
|
||||
NotifierProvider<GeneralSettingsRepository, GeneralSettings>.internal(
|
||||
GeneralSettingsRepository.new,
|
||||
name: r'generalSettingsRepositoryProvider',
|
||||
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$generalSettingsRepositoryHash,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
typedef _$GeneralSettingsRepository = Notifier<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
|
||||
@@ -1,57 +0,0 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:drift/drift.dart';
|
||||
import 'package:lensai/features/user/data/database/database.dart';
|
||||
import 'package:lensai/features/user/data/models/settings.dart';
|
||||
import 'package:lensai/features/user/data/providers.dart';
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
|
||||
part 'settings.g.dart';
|
||||
|
||||
typedef UpdateSettingsFunc = Settings Function(Settings currentSettings);
|
||||
|
||||
@Riverpod(keepAlive: true)
|
||||
class SettingsRepository extends _$SettingsRepository {
|
||||
late UserDatabase _db;
|
||||
|
||||
Future<void> updateSettings(UpdateSettingsFunc updateWithCurrent) {
|
||||
final oldJson = state.toJson();
|
||||
final newJson = updateWithCurrent(state).toJson();
|
||||
|
||||
return _db.transaction(() async {
|
||||
for (final MapEntry(:key, :value) in newJson.entries) {
|
||||
if (oldJson[key] != value) {
|
||||
await _db.settingDao.updateSetting(key, value);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Settings build() {
|
||||
_db = ref.watch(userDatabaseProvider);
|
||||
|
||||
final watchSub = _db.settingDao.allSettings().watch().listen((entries) {
|
||||
final settings = Map.fromEntries(entries);
|
||||
|
||||
state = Settings.fromJson({
|
||||
'incognitoMode': settings['incognitoMode']
|
||||
?.readAs(DriftSqlType.bool, _db.typeMapping),
|
||||
'enableJavascript': settings['enableJavascript']
|
||||
?.readAs(DriftSqlType.bool, _db.typeMapping),
|
||||
'blockHttpProtocol': settings['blockHttpProtocol']
|
||||
?.readAs(DriftSqlType.bool, _db.typeMapping),
|
||||
'themeMode':
|
||||
settings['themeMode']?.readAs(DriftSqlType.string, _db.typeMapping),
|
||||
'enableReadability': settings['enableReadability']
|
||||
?.readAs(DriftSqlType.bool, _db.typeMapping),
|
||||
});
|
||||
});
|
||||
|
||||
ref.onDispose(() {
|
||||
unawaited(watchSub.cancel());
|
||||
});
|
||||
|
||||
return Settings.withDefaults();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:lensai/core/logger.dart';
|
||||
import 'package:lensai/features/geckoview/features/tabs/data/models/container_data.dart';
|
||||
import 'package:local_auth/local_auth.dart';
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
|
||||
part 'local_authentication.g.dart';
|
||||
|
||||
@Riverpod(keepAlive: true)
|
||||
class LocalAuthenticationService extends _$LocalAuthenticationService {
|
||||
final _auth = LocalAuthentication();
|
||||
final _cache = <String, (DateTime, ContainerAuthSettings)>{};
|
||||
|
||||
bool _cacheAuth(String authKey) {
|
||||
final auth = _cache[authKey];
|
||||
if (auth != null && auth.$2.lockTimeout != null) {
|
||||
return DateTime.now().difference(auth.$1) < auth.$2.lockTimeout!;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void evictCacheOnBackground() {
|
||||
_cache.removeWhere(
|
||||
(key, value) => value.$2.lockOnAppBackground,
|
||||
);
|
||||
}
|
||||
|
||||
Future<bool> authenticate({
|
||||
required String authKey,
|
||||
required String localizedReason,
|
||||
ContainerAuthSettings? settings,
|
||||
bool useAuthCache = false,
|
||||
}) async {
|
||||
try {
|
||||
var result = useAuthCache && _cacheAuth(authKey);
|
||||
|
||||
if (!result) {
|
||||
result = await _auth.authenticate(
|
||||
localizedReason: localizedReason,
|
||||
);
|
||||
}
|
||||
|
||||
if (result && settings != null) {
|
||||
_cache[authKey] = (DateTime.now(), settings);
|
||||
}
|
||||
|
||||
return result;
|
||||
} on PlatformException catch (e, s) {
|
||||
logger.e('Could not authenticate', error: e, stackTrace: s);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Future<bool> build() {
|
||||
return _auth.canCheckBiometrics;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'local_authentication.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
String _$localAuthenticationServiceHash() =>
|
||||
r'4893be7a11833d77a575f7aa248a9ba65d6717da';
|
||||
|
||||
/// See also [LocalAuthenticationService].
|
||||
@ProviderFor(LocalAuthenticationService)
|
||||
final localAuthenticationServiceProvider =
|
||||
AsyncNotifierProvider<LocalAuthenticationService, bool>.internal(
|
||||
LocalAuthenticationService.new,
|
||||
name: r'localAuthenticationServiceProvider',
|
||||
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$localAuthenticationServiceHash,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
typedef _$LocalAuthenticationService = AsyncNotifier<bool>;
|
||||
// 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
|
||||
Reference in New Issue
Block a user