cleanup code
This commit is contained in:
@@ -0,0 +1,41 @@
|
||||
import 'package:copy_with_extension/copy_with_extension.dart';
|
||||
import 'package:flutter_mozilla_components/flutter_mozilla_components.dart';
|
||||
|
||||
part 'site_permissions.g.dart';
|
||||
|
||||
@CopyWith()
|
||||
class SitePermissionsWrapper extends SitePermissions {
|
||||
SitePermissionsWrapper({
|
||||
required super.origin,
|
||||
super.camera,
|
||||
super.microphone,
|
||||
super.location,
|
||||
super.notification,
|
||||
super.persistentStorage,
|
||||
super.crossOriginStorageAccess,
|
||||
super.mediaKeySystemAccess,
|
||||
super.localDeviceAccess,
|
||||
super.localNetworkAccess,
|
||||
super.autoplayAudible,
|
||||
super.autoplayInaudible,
|
||||
required super.savedAt,
|
||||
});
|
||||
|
||||
factory SitePermissionsWrapper.fromPermission(SitePermissions permissions) {
|
||||
return SitePermissionsWrapper(
|
||||
origin: permissions.origin,
|
||||
camera: permissions.camera,
|
||||
microphone: permissions.microphone,
|
||||
location: permissions.location,
|
||||
notification: permissions.notification,
|
||||
persistentStorage: permissions.persistentStorage,
|
||||
crossOriginStorageAccess: permissions.crossOriginStorageAccess,
|
||||
mediaKeySystemAccess: permissions.mediaKeySystemAccess,
|
||||
localDeviceAccess: permissions.localDeviceAccess,
|
||||
localNetworkAccess: permissions.localNetworkAccess,
|
||||
autoplayAudible: permissions.autoplayAudible,
|
||||
autoplayInaudible: permissions.autoplayInaudible,
|
||||
savedAt: permissions.savedAt,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,220 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'site_permissions.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// CopyWithGenerator
|
||||
// **************************************************************************
|
||||
|
||||
abstract class _$SitePermissionsWrapperCWProxy {
|
||||
SitePermissionsWrapper origin(String origin);
|
||||
|
||||
SitePermissionsWrapper camera(SitePermissionStatus? camera);
|
||||
|
||||
SitePermissionsWrapper microphone(SitePermissionStatus? microphone);
|
||||
|
||||
SitePermissionsWrapper location(SitePermissionStatus? location);
|
||||
|
||||
SitePermissionsWrapper notification(SitePermissionStatus? notification);
|
||||
|
||||
SitePermissionsWrapper persistentStorage(
|
||||
SitePermissionStatus? persistentStorage,
|
||||
);
|
||||
|
||||
SitePermissionsWrapper crossOriginStorageAccess(
|
||||
SitePermissionStatus? crossOriginStorageAccess,
|
||||
);
|
||||
|
||||
SitePermissionsWrapper mediaKeySystemAccess(
|
||||
SitePermissionStatus? mediaKeySystemAccess,
|
||||
);
|
||||
|
||||
SitePermissionsWrapper localDeviceAccess(
|
||||
SitePermissionStatus? localDeviceAccess,
|
||||
);
|
||||
|
||||
SitePermissionsWrapper localNetworkAccess(
|
||||
SitePermissionStatus? localNetworkAccess,
|
||||
);
|
||||
|
||||
SitePermissionsWrapper autoplayAudible(AutoplayStatus? autoplayAudible);
|
||||
|
||||
SitePermissionsWrapper autoplayInaudible(AutoplayStatus? autoplayInaudible);
|
||||
|
||||
SitePermissionsWrapper savedAt(int savedAt);
|
||||
|
||||
/// Creates a new instance with the provided field values.
|
||||
/// Passing `null` to a nullable field nullifies it, while `null` for a non-nullable field is ignored. To update a single field use `SitePermissionsWrapper(...).copyWith.fieldName(value)`.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// SitePermissionsWrapper(...).copyWith(id: 12, name: "My name")
|
||||
/// ```
|
||||
SitePermissionsWrapper call({
|
||||
String origin,
|
||||
SitePermissionStatus? camera,
|
||||
SitePermissionStatus? microphone,
|
||||
SitePermissionStatus? location,
|
||||
SitePermissionStatus? notification,
|
||||
SitePermissionStatus? persistentStorage,
|
||||
SitePermissionStatus? crossOriginStorageAccess,
|
||||
SitePermissionStatus? mediaKeySystemAccess,
|
||||
SitePermissionStatus? localDeviceAccess,
|
||||
SitePermissionStatus? localNetworkAccess,
|
||||
AutoplayStatus? autoplayAudible,
|
||||
AutoplayStatus? autoplayInaudible,
|
||||
int savedAt,
|
||||
});
|
||||
}
|
||||
|
||||
/// Callable proxy for `copyWith` functionality.
|
||||
/// Use as `instanceOfSitePermissionsWrapper.copyWith(...)` or call `instanceOfSitePermissionsWrapper.copyWith.fieldName(value)` for a single field.
|
||||
class _$SitePermissionsWrapperCWProxyImpl
|
||||
implements _$SitePermissionsWrapperCWProxy {
|
||||
const _$SitePermissionsWrapperCWProxyImpl(this._value);
|
||||
|
||||
final SitePermissionsWrapper _value;
|
||||
|
||||
@override
|
||||
SitePermissionsWrapper origin(String origin) => call(origin: origin);
|
||||
|
||||
@override
|
||||
SitePermissionsWrapper camera(SitePermissionStatus? camera) =>
|
||||
call(camera: camera);
|
||||
|
||||
@override
|
||||
SitePermissionsWrapper microphone(SitePermissionStatus? microphone) =>
|
||||
call(microphone: microphone);
|
||||
|
||||
@override
|
||||
SitePermissionsWrapper location(SitePermissionStatus? location) =>
|
||||
call(location: location);
|
||||
|
||||
@override
|
||||
SitePermissionsWrapper notification(SitePermissionStatus? notification) =>
|
||||
call(notification: notification);
|
||||
|
||||
@override
|
||||
SitePermissionsWrapper persistentStorage(
|
||||
SitePermissionStatus? persistentStorage,
|
||||
) => call(persistentStorage: persistentStorage);
|
||||
|
||||
@override
|
||||
SitePermissionsWrapper crossOriginStorageAccess(
|
||||
SitePermissionStatus? crossOriginStorageAccess,
|
||||
) => call(crossOriginStorageAccess: crossOriginStorageAccess);
|
||||
|
||||
@override
|
||||
SitePermissionsWrapper mediaKeySystemAccess(
|
||||
SitePermissionStatus? mediaKeySystemAccess,
|
||||
) => call(mediaKeySystemAccess: mediaKeySystemAccess);
|
||||
|
||||
@override
|
||||
SitePermissionsWrapper localDeviceAccess(
|
||||
SitePermissionStatus? localDeviceAccess,
|
||||
) => call(localDeviceAccess: localDeviceAccess);
|
||||
|
||||
@override
|
||||
SitePermissionsWrapper localNetworkAccess(
|
||||
SitePermissionStatus? localNetworkAccess,
|
||||
) => call(localNetworkAccess: localNetworkAccess);
|
||||
|
||||
@override
|
||||
SitePermissionsWrapper autoplayAudible(AutoplayStatus? autoplayAudible) =>
|
||||
call(autoplayAudible: autoplayAudible);
|
||||
|
||||
@override
|
||||
SitePermissionsWrapper autoplayInaudible(AutoplayStatus? autoplayInaudible) =>
|
||||
call(autoplayInaudible: autoplayInaudible);
|
||||
|
||||
@override
|
||||
SitePermissionsWrapper savedAt(int savedAt) => call(savedAt: savedAt);
|
||||
|
||||
@override
|
||||
/// Creates a new instance with the provided field values.
|
||||
/// Passing `null` to a nullable field nullifies it, while `null` for a non-nullable field is ignored. To update a single field use `SitePermissionsWrapper(...).copyWith.fieldName(value)`.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// SitePermissionsWrapper(...).copyWith(id: 12, name: "My name")
|
||||
/// ```
|
||||
SitePermissionsWrapper call({
|
||||
Object? origin = const $CopyWithPlaceholder(),
|
||||
Object? camera = const $CopyWithPlaceholder(),
|
||||
Object? microphone = const $CopyWithPlaceholder(),
|
||||
Object? location = const $CopyWithPlaceholder(),
|
||||
Object? notification = const $CopyWithPlaceholder(),
|
||||
Object? persistentStorage = const $CopyWithPlaceholder(),
|
||||
Object? crossOriginStorageAccess = const $CopyWithPlaceholder(),
|
||||
Object? mediaKeySystemAccess = const $CopyWithPlaceholder(),
|
||||
Object? localDeviceAccess = const $CopyWithPlaceholder(),
|
||||
Object? localNetworkAccess = const $CopyWithPlaceholder(),
|
||||
Object? autoplayAudible = const $CopyWithPlaceholder(),
|
||||
Object? autoplayInaudible = const $CopyWithPlaceholder(),
|
||||
Object? savedAt = const $CopyWithPlaceholder(),
|
||||
}) {
|
||||
return SitePermissionsWrapper(
|
||||
origin: origin == const $CopyWithPlaceholder() || origin == null
|
||||
? _value.origin
|
||||
// ignore: cast_nullable_to_non_nullable
|
||||
: origin as String,
|
||||
camera: camera == const $CopyWithPlaceholder()
|
||||
? _value.camera
|
||||
// ignore: cast_nullable_to_non_nullable
|
||||
: camera as SitePermissionStatus?,
|
||||
microphone: microphone == const $CopyWithPlaceholder()
|
||||
? _value.microphone
|
||||
// ignore: cast_nullable_to_non_nullable
|
||||
: microphone as SitePermissionStatus?,
|
||||
location: location == const $CopyWithPlaceholder()
|
||||
? _value.location
|
||||
// ignore: cast_nullable_to_non_nullable
|
||||
: location as SitePermissionStatus?,
|
||||
notification: notification == const $CopyWithPlaceholder()
|
||||
? _value.notification
|
||||
// ignore: cast_nullable_to_non_nullable
|
||||
: notification as SitePermissionStatus?,
|
||||
persistentStorage: persistentStorage == const $CopyWithPlaceholder()
|
||||
? _value.persistentStorage
|
||||
// ignore: cast_nullable_to_non_nullable
|
||||
: persistentStorage as SitePermissionStatus?,
|
||||
crossOriginStorageAccess:
|
||||
crossOriginStorageAccess == const $CopyWithPlaceholder()
|
||||
? _value.crossOriginStorageAccess
|
||||
// ignore: cast_nullable_to_non_nullable
|
||||
: crossOriginStorageAccess as SitePermissionStatus?,
|
||||
mediaKeySystemAccess: mediaKeySystemAccess == const $CopyWithPlaceholder()
|
||||
? _value.mediaKeySystemAccess
|
||||
// ignore: cast_nullable_to_non_nullable
|
||||
: mediaKeySystemAccess as SitePermissionStatus?,
|
||||
localDeviceAccess: localDeviceAccess == const $CopyWithPlaceholder()
|
||||
? _value.localDeviceAccess
|
||||
// ignore: cast_nullable_to_non_nullable
|
||||
: localDeviceAccess as SitePermissionStatus?,
|
||||
localNetworkAccess: localNetworkAccess == const $CopyWithPlaceholder()
|
||||
? _value.localNetworkAccess
|
||||
// ignore: cast_nullable_to_non_nullable
|
||||
: localNetworkAccess as SitePermissionStatus?,
|
||||
autoplayAudible: autoplayAudible == const $CopyWithPlaceholder()
|
||||
? _value.autoplayAudible
|
||||
// ignore: cast_nullable_to_non_nullable
|
||||
: autoplayAudible as AutoplayStatus?,
|
||||
autoplayInaudible: autoplayInaudible == const $CopyWithPlaceholder()
|
||||
? _value.autoplayInaudible
|
||||
// ignore: cast_nullable_to_non_nullable
|
||||
: autoplayInaudible as AutoplayStatus?,
|
||||
savedAt: savedAt == const $CopyWithPlaceholder() || savedAt == null
|
||||
? _value.savedAt
|
||||
// ignore: cast_nullable_to_non_nullable
|
||||
: savedAt as int,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
extension $SitePermissionsWrapperCopyWith on SitePermissionsWrapper {
|
||||
/// Returns a callable class used to build a new instance with modified fields.
|
||||
/// Example: `instanceOfSitePermissionsWrapper.copyWith(...)` or `instanceOfSitePermissionsWrapper.copyWith.fieldName(...)`.
|
||||
// ignore: library_private_types_in_public_api
|
||||
_$SitePermissionsWrapperCWProxy get copyWith =>
|
||||
_$SitePermissionsWrapperCWProxyImpl(this);
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
import 'package:flutter_mozilla_components/flutter_mozilla_components.dart';
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
import 'package:weblibre/features/geckoview/features/browser/domain/entities/site_permissions.dart';
|
||||
|
||||
part 'site_permissions.g.dart';
|
||||
|
||||
@Riverpod(keepAlive: true)
|
||||
class SitePermissionsRepository extends _$SitePermissionsRepository {
|
||||
final _api = GeckoSitePermissionsApi();
|
||||
|
||||
Future<SitePermissions?> getPermissions() async {
|
||||
final permissions = await _api.getSitePermissions(origin, isPrivate);
|
||||
state = AsyncValue.data(permissions);
|
||||
|
||||
return permissions;
|
||||
}
|
||||
|
||||
Future<void> updatePermission(
|
||||
SitePermissions Function(SitePermissionsWrapper) updater,
|
||||
) async {
|
||||
final currentPermissions =
|
||||
await getPermissions() ??
|
||||
SitePermissions(
|
||||
origin: origin,
|
||||
savedAt: DateTime.now().millisecondsSinceEpoch,
|
||||
);
|
||||
|
||||
await setPermissions(
|
||||
updater(SitePermissionsWrapper.fromPermission(currentPermissions)),
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> setPermissions(SitePermissions permissions) async {
|
||||
if (permissions.origin != origin) {
|
||||
throw Exception('Origin does not match');
|
||||
}
|
||||
|
||||
await _api.setSitePermissions(permissions, isPrivate);
|
||||
ref.invalidateSelf();
|
||||
}
|
||||
|
||||
Future<void> deletePermissions() async {
|
||||
await _api.deleteSitePermissions(origin, isPrivate);
|
||||
ref.invalidateSelf();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<SitePermissions?> build({
|
||||
required String origin,
|
||||
required bool isPrivate,
|
||||
}) {
|
||||
return _api.getSitePermissions(origin, isPrivate);
|
||||
}
|
||||
}
|
||||
+116
@@ -0,0 +1,116 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'site_permissions.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
// ignore_for_file: type=lint, type=warning
|
||||
|
||||
@ProviderFor(SitePermissionsRepository)
|
||||
final sitePermissionsRepositoryProvider = SitePermissionsRepositoryFamily._();
|
||||
|
||||
final class SitePermissionsRepositoryProvider
|
||||
extends
|
||||
$AsyncNotifierProvider<SitePermissionsRepository, SitePermissions?> {
|
||||
SitePermissionsRepositoryProvider._({
|
||||
required SitePermissionsRepositoryFamily super.from,
|
||||
required ({String origin, bool isPrivate}) super.argument,
|
||||
}) : super(
|
||||
retry: null,
|
||||
name: r'sitePermissionsRepositoryProvider',
|
||||
isAutoDispose: false,
|
||||
dependencies: null,
|
||||
$allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
@override
|
||||
String debugGetCreateSourceHash() => _$sitePermissionsRepositoryHash();
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return r'sitePermissionsRepositoryProvider'
|
||||
''
|
||||
'$argument';
|
||||
}
|
||||
|
||||
@$internal
|
||||
@override
|
||||
SitePermissionsRepository create() => SitePermissionsRepository();
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return other is SitePermissionsRepositoryProvider &&
|
||||
other.argument == argument;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode {
|
||||
return argument.hashCode;
|
||||
}
|
||||
}
|
||||
|
||||
String _$sitePermissionsRepositoryHash() =>
|
||||
r'83033a26cd7c9473a7ac9a23f91787af8ed4ce86';
|
||||
|
||||
final class SitePermissionsRepositoryFamily extends $Family
|
||||
with
|
||||
$ClassFamilyOverride<
|
||||
SitePermissionsRepository,
|
||||
AsyncValue<SitePermissions?>,
|
||||
SitePermissions?,
|
||||
FutureOr<SitePermissions?>,
|
||||
({String origin, bool isPrivate})
|
||||
> {
|
||||
SitePermissionsRepositoryFamily._()
|
||||
: super(
|
||||
retry: null,
|
||||
name: r'sitePermissionsRepositoryProvider',
|
||||
dependencies: null,
|
||||
$allTransitiveDependencies: null,
|
||||
isAutoDispose: false,
|
||||
);
|
||||
|
||||
SitePermissionsRepositoryProvider call({
|
||||
required String origin,
|
||||
required bool isPrivate,
|
||||
}) => SitePermissionsRepositoryProvider._(
|
||||
argument: (origin: origin, isPrivate: isPrivate),
|
||||
from: this,
|
||||
);
|
||||
|
||||
@override
|
||||
String toString() => r'sitePermissionsRepositoryProvider';
|
||||
}
|
||||
|
||||
abstract class _$SitePermissionsRepository
|
||||
extends $AsyncNotifier<SitePermissions?> {
|
||||
late final _$args = ref.$arg as ({String origin, bool isPrivate});
|
||||
String get origin => _$args.origin;
|
||||
bool get isPrivate => _$args.isPrivate;
|
||||
|
||||
FutureOr<SitePermissions?> build({
|
||||
required String origin,
|
||||
required bool isPrivate,
|
||||
});
|
||||
@$mustCallSuper
|
||||
@override
|
||||
void runBuild() {
|
||||
final ref =
|
||||
this.ref as $Ref<AsyncValue<SitePermissions?>, SitePermissions?>;
|
||||
final element =
|
||||
ref.element
|
||||
as $ClassProviderElement<
|
||||
AnyNotifier<AsyncValue<SitePermissions?>, SitePermissions?>,
|
||||
AsyncValue<SitePermissions?>,
|
||||
Object?,
|
||||
Object?
|
||||
>;
|
||||
element.handleCreate(
|
||||
ref,
|
||||
() => build(origin: _$args.origin, isPrivate: _$args.isPrivate),
|
||||
);
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -51,7 +51,7 @@ final class TrackingProtectionRepositoryProvider
|
||||
}
|
||||
|
||||
String _$trackingProtectionRepositoryHash() =>
|
||||
r'6d4407034b2c67317d0a0e106002f1785fd86a34';
|
||||
r'f4b09ed513da6bd5a9f4d01833a2dbba990f59de';
|
||||
|
||||
/// Repository for managing per-site Enhanced Tracking Protection exceptions
|
||||
///
|
||||
|
||||
+25
-19
@@ -23,15 +23,13 @@ import 'package:flutter_mozilla_components/flutter_mozilla_components.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:weblibre/features/geckoview/domain/providers/tab_session.dart';
|
||||
import 'package:weblibre/features/geckoview/features/browser/presentation/widgets/sheets/site_permissions_provider.dart';
|
||||
import 'package:weblibre/utils/ui_helper.dart';
|
||||
|
||||
/// Section widget for clearing site data
|
||||
class ClearSiteDataSection extends HookConsumerWidget {
|
||||
final Uri url;
|
||||
|
||||
const ClearSiteDataSection({
|
||||
required this.url,
|
||||
super.key,
|
||||
});
|
||||
const ClearSiteDataSection({required this.url, super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
@@ -63,7 +61,9 @@ class ClearSiteDataSection extends HookConsumerWidget {
|
||||
type: ClearDataType.cookies,
|
||||
isSelected: selectedTypes.contains(ClearDataType.cookies),
|
||||
onChanged: (selected) {
|
||||
ref.read(selectedClearDataTypesProvider.notifier).toggle(ClearDataType.cookies);
|
||||
ref
|
||||
.read(selectedClearDataTypesProvider.notifier)
|
||||
.toggle(ClearDataType.cookies);
|
||||
},
|
||||
),
|
||||
_DataTypeCheckbox(
|
||||
@@ -72,7 +72,9 @@ class ClearSiteDataSection extends HookConsumerWidget {
|
||||
type: ClearDataType.allCaches,
|
||||
isSelected: selectedTypes.contains(ClearDataType.allCaches),
|
||||
onChanged: (selected) {
|
||||
ref.read(selectedClearDataTypesProvider.notifier).toggle(ClearDataType.allCaches);
|
||||
ref
|
||||
.read(selectedClearDataTypesProvider.notifier)
|
||||
.toggle(ClearDataType.allCaches);
|
||||
},
|
||||
),
|
||||
_DataTypeCheckbox(
|
||||
@@ -81,7 +83,9 @@ class ClearSiteDataSection extends HookConsumerWidget {
|
||||
type: ClearDataType.allSiteData,
|
||||
isSelected: selectedTypes.contains(ClearDataType.allSiteData),
|
||||
onChanged: (selected) {
|
||||
ref.read(selectedClearDataTypesProvider.notifier).toggle(ClearDataType.allSiteData);
|
||||
ref
|
||||
.read(selectedClearDataTypesProvider.notifier)
|
||||
.toggle(ClearDataType.allSiteData);
|
||||
},
|
||||
),
|
||||
_DataTypeCheckbox(
|
||||
@@ -90,11 +94,16 @@ class ClearSiteDataSection extends HookConsumerWidget {
|
||||
type: ClearDataType.authSessions,
|
||||
isSelected: selectedTypes.contains(ClearDataType.authSessions),
|
||||
onChanged: (selected) {
|
||||
ref.read(selectedClearDataTypesProvider.notifier).toggle(ClearDataType.authSessions);
|
||||
ref
|
||||
.read(selectedClearDataTypesProvider.notifier)
|
||||
.toggle(ClearDataType.authSessions);
|
||||
},
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0),
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 16.0,
|
||||
vertical: 8.0,
|
||||
),
|
||||
child: SizedBox(
|
||||
width: double.infinity,
|
||||
child: FilledButton.icon(
|
||||
@@ -124,9 +133,7 @@ class ClearSiteDataSection extends HookConsumerWidget {
|
||||
) async {
|
||||
final selectedTypes = ref.read(selectedClearDataTypesProvider);
|
||||
if (selectedTypes.isEmpty) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(content: Text('Select at least one data type')),
|
||||
);
|
||||
showErrorMessage(context, 'Select at least one data type');
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -157,15 +164,11 @@ class ClearSiteDataSection extends HookConsumerWidget {
|
||||
try {
|
||||
await _clearData(ref, selectedTypes);
|
||||
if (context.mounted) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(content: Text('Site data cleared')),
|
||||
);
|
||||
showInfoMessage(context, 'Site data cleared');
|
||||
}
|
||||
} catch (e) {
|
||||
if (context.mounted) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(content: Text('Failed to clear site data: $e')),
|
||||
);
|
||||
showErrorMessage(context, 'Failed to clear site data: $e');
|
||||
}
|
||||
} finally {
|
||||
isClearing.value = false;
|
||||
@@ -192,7 +195,10 @@ class ClearSiteDataSection extends HookConsumerWidget {
|
||||
return '${labels.sublist(0, labels.length - 1).join(', ')}, and ${labels.last}';
|
||||
}
|
||||
|
||||
Future<void> _clearData(WidgetRef ref, Set<ClearDataType> selectedTypes) async {
|
||||
Future<void> _clearData(
|
||||
WidgetRef ref,
|
||||
Set<ClearDataType> selectedTypes,
|
||||
) async {
|
||||
final host = url.host;
|
||||
|
||||
// Get base domain using PSL API (falls back to host on error)
|
||||
|
||||
+71
-200
@@ -22,7 +22,8 @@ import 'package:flutter_hooks/flutter_hooks.dart';
|
||||
import 'package:flutter_mozilla_components/flutter_mozilla_components.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:weblibre/features/geckoview/domain/providers/tab_session.dart';
|
||||
import 'package:weblibre/features/geckoview/features/browser/presentation/widgets/sheets/site_permissions_provider.dart';
|
||||
import 'package:weblibre/features/geckoview/features/browser/domain/entities/site_permissions.dart';
|
||||
import 'package:weblibre/features/geckoview/features/browser/domain/repositories/site_permissions.dart';
|
||||
|
||||
/// Section widget displaying site permissions with toggles
|
||||
class PermissionsSection extends HookConsumerWidget {
|
||||
@@ -38,7 +39,7 @@ class PermissionsSection extends HookConsumerWidget {
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final permissionsAsync = ref.watch(
|
||||
sitePermissionsProvider(origin, isPrivate),
|
||||
sitePermissionsRepositoryProvider(origin: origin, isPrivate: isPrivate),
|
||||
);
|
||||
|
||||
return permissionsAsync.when(
|
||||
@@ -80,50 +81,75 @@ class _PermissionsList extends HookConsumerWidget {
|
||||
icon: Icons.videocam,
|
||||
label: 'Camera',
|
||||
status: permissions?.camera,
|
||||
onChanged: (status) => _updatePermission(ref, (p) => _copyWithCamera(p, status)),
|
||||
onChanged: (status) => _updatePermission(
|
||||
ref,
|
||||
(permissions) => permissions.copyWith.camera(status),
|
||||
),
|
||||
),
|
||||
_PermissionEntry(
|
||||
icon: Icons.mic,
|
||||
label: 'Microphone',
|
||||
status: permissions?.microphone,
|
||||
onChanged: (status) => _updatePermission(ref, (p) => _copyWithMicrophone(p, status)),
|
||||
onChanged: (status) => _updatePermission(
|
||||
ref,
|
||||
(permissions) => permissions.copyWith.microphone(status),
|
||||
),
|
||||
),
|
||||
_PermissionEntry(
|
||||
icon: Icons.location_on,
|
||||
label: 'Location',
|
||||
status: permissions?.location,
|
||||
onChanged: (status) => _updatePermission(ref, (p) => _copyWithLocation(p, status)),
|
||||
onChanged: (status) => _updatePermission(
|
||||
ref,
|
||||
(permissions) => permissions.copyWith.location(status),
|
||||
),
|
||||
),
|
||||
_PermissionEntry(
|
||||
icon: Icons.notifications,
|
||||
label: 'Notifications',
|
||||
status: permissions?.notification,
|
||||
onChanged: (status) => _updatePermission(ref, (p) => _copyWithNotification(p, status)),
|
||||
onChanged: (status) => _updatePermission(
|
||||
ref,
|
||||
(permissions) => permissions.copyWith.notification(status),
|
||||
),
|
||||
),
|
||||
_PermissionEntry(
|
||||
icon: Icons.storage,
|
||||
label: 'Persistent Storage',
|
||||
status: permissions?.persistentStorage,
|
||||
onChanged: (status) => _updatePermission(ref, (p) => _copyWithPersistentStorage(p, status)),
|
||||
onChanged: (status) => _updatePermission(
|
||||
ref,
|
||||
(permissions) => permissions.copyWith.persistentStorage(status),
|
||||
),
|
||||
),
|
||||
_PermissionEntry(
|
||||
icon: Icons.cookie,
|
||||
label: 'Cross-Origin Storage',
|
||||
status: permissions?.crossOriginStorageAccess,
|
||||
onChanged: (status) => _updatePermission(ref, (p) => _copyWithCrossOriginStorage(p, status)),
|
||||
onChanged: (status) => _updatePermission(
|
||||
ref,
|
||||
(permissions) =>
|
||||
permissions.copyWith.crossOriginStorageAccess(status),
|
||||
),
|
||||
),
|
||||
_PermissionEntry(
|
||||
icon: Icons.key,
|
||||
label: 'Media Key System (DRM)',
|
||||
status: permissions?.mediaKeySystemAccess,
|
||||
onChanged: (status) => _updatePermission(ref, (p) => _copyWithMediaKeySystem(p, status)),
|
||||
onChanged: (status) => _updatePermission(
|
||||
ref,
|
||||
(permissions) => permissions.copyWith.mediaKeySystemAccess(status),
|
||||
),
|
||||
),
|
||||
];
|
||||
|
||||
// Filter to only show permissions that have been explicitly set (not noDecision)
|
||||
final setPermissions = allPermissions.where(
|
||||
(p) => p.status != null && p.status != SitePermissionStatus.noDecision,
|
||||
).toList();
|
||||
final setPermissions = allPermissions
|
||||
.where(
|
||||
(p) =>
|
||||
p.status != null && p.status != SitePermissionStatus.noDecision,
|
||||
)
|
||||
.toList();
|
||||
|
||||
final permissionsToShow = showAll.value ? allPermissions : setPermissions;
|
||||
final hiddenCount = allPermissions.length - setPermissions.length;
|
||||
@@ -151,15 +177,20 @@ class _PermissionsList extends HookConsumerWidget {
|
||||
],
|
||||
),
|
||||
),
|
||||
...permissionsToShow.map((entry) => _PermissionTile(
|
||||
icon: entry.icon,
|
||||
label: entry.label,
|
||||
status: entry.status,
|
||||
onChanged: entry.onChanged,
|
||||
)),
|
||||
...permissionsToShow.map(
|
||||
(entry) => _PermissionTile(
|
||||
icon: entry.icon,
|
||||
label: entry.label,
|
||||
status: entry.status,
|
||||
onChanged: entry.onChanged,
|
||||
),
|
||||
),
|
||||
if (permissionsToShow.isEmpty && !showAll.value)
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0),
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 16.0,
|
||||
vertical: 8.0,
|
||||
),
|
||||
child: Text(
|
||||
'No permissions set for this site',
|
||||
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
|
||||
@@ -171,7 +202,13 @@ class _PermissionsList extends HookConsumerWidget {
|
||||
_AutoplayTile(
|
||||
audibleStatus: permissions?.autoplayAudible,
|
||||
inaudibleStatus: permissions?.autoplayInaudible,
|
||||
onChanged: (audible, inaudible) => _updateAutoplay(ref, audible, inaudible),
|
||||
onChanged: (audible, inaudible) => _updatePermission(
|
||||
ref,
|
||||
(permissions) => permissions.copyWith(
|
||||
autoplayAudible: audible,
|
||||
autoplayInaudible: inaudible,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
@@ -179,184 +216,20 @@ class _PermissionsList extends HookConsumerWidget {
|
||||
|
||||
Future<void> _updatePermission(
|
||||
WidgetRef ref,
|
||||
SitePermissions Function(SitePermissions) updater,
|
||||
SitePermissions Function(SitePermissionsWrapper) updater,
|
||||
) async {
|
||||
final currentPermissions = permissions ?? SitePermissions(
|
||||
origin: origin,
|
||||
savedAt: DateTime.now().millisecondsSinceEpoch,
|
||||
);
|
||||
|
||||
final updatedPermissions = updater(currentPermissions);
|
||||
|
||||
final api = GeckoSitePermissionsApi();
|
||||
await api.setSitePermissions(updatedPermissions, isPrivate);
|
||||
|
||||
// Invalidate the provider to refetch
|
||||
ref.invalidate(sitePermissionsProvider(origin, isPrivate));
|
||||
await ref
|
||||
.read(
|
||||
sitePermissionsRepositoryProvider(
|
||||
origin: origin,
|
||||
isPrivate: isPrivate,
|
||||
).notifier,
|
||||
)
|
||||
.updatePermission(updater);
|
||||
|
||||
// Reload the tab to apply changes
|
||||
await ref.read(selectedTabSessionProvider).reload();
|
||||
}
|
||||
|
||||
Future<void> _updateAutoplay(
|
||||
WidgetRef ref,
|
||||
AutoplayStatus? audible,
|
||||
AutoplayStatus? inaudible,
|
||||
) async {
|
||||
final currentPermissions = permissions ?? SitePermissions(
|
||||
origin: origin,
|
||||
savedAt: DateTime.now().millisecondsSinceEpoch,
|
||||
);
|
||||
|
||||
final updatedPermissions = SitePermissions(
|
||||
origin: currentPermissions.origin,
|
||||
camera: currentPermissions.camera,
|
||||
microphone: currentPermissions.microphone,
|
||||
location: currentPermissions.location,
|
||||
notification: currentPermissions.notification,
|
||||
persistentStorage: currentPermissions.persistentStorage,
|
||||
crossOriginStorageAccess: currentPermissions.crossOriginStorageAccess,
|
||||
mediaKeySystemAccess: currentPermissions.mediaKeySystemAccess,
|
||||
localDeviceAccess: currentPermissions.localDeviceAccess,
|
||||
localNetworkAccess: currentPermissions.localNetworkAccess,
|
||||
autoplayAudible: audible ?? currentPermissions.autoplayAudible,
|
||||
autoplayInaudible: inaudible ?? currentPermissions.autoplayInaudible,
|
||||
savedAt: currentPermissions.savedAt,
|
||||
);
|
||||
|
||||
final api = GeckoSitePermissionsApi();
|
||||
await api.setSitePermissions(updatedPermissions, isPrivate);
|
||||
|
||||
ref.invalidate(sitePermissionsProvider(origin, isPrivate));
|
||||
await ref.read(selectedTabSessionProvider).reload();
|
||||
}
|
||||
|
||||
// Copy helper methods since Pigeon doesn't generate copyWith
|
||||
SitePermissions _copyWithCamera(SitePermissions p, SitePermissionStatus status) {
|
||||
return SitePermissions(
|
||||
origin: p.origin,
|
||||
camera: status,
|
||||
microphone: p.microphone,
|
||||
location: p.location,
|
||||
notification: p.notification,
|
||||
persistentStorage: p.persistentStorage,
|
||||
crossOriginStorageAccess: p.crossOriginStorageAccess,
|
||||
mediaKeySystemAccess: p.mediaKeySystemAccess,
|
||||
localDeviceAccess: p.localDeviceAccess,
|
||||
localNetworkAccess: p.localNetworkAccess,
|
||||
autoplayAudible: p.autoplayAudible,
|
||||
autoplayInaudible: p.autoplayInaudible,
|
||||
savedAt: p.savedAt,
|
||||
);
|
||||
}
|
||||
|
||||
SitePermissions _copyWithMicrophone(SitePermissions p, SitePermissionStatus status) {
|
||||
return SitePermissions(
|
||||
origin: p.origin,
|
||||
camera: p.camera,
|
||||
microphone: status,
|
||||
location: p.location,
|
||||
notification: p.notification,
|
||||
persistentStorage: p.persistentStorage,
|
||||
crossOriginStorageAccess: p.crossOriginStorageAccess,
|
||||
mediaKeySystemAccess: p.mediaKeySystemAccess,
|
||||
localDeviceAccess: p.localDeviceAccess,
|
||||
localNetworkAccess: p.localNetworkAccess,
|
||||
autoplayAudible: p.autoplayAudible,
|
||||
autoplayInaudible: p.autoplayInaudible,
|
||||
savedAt: p.savedAt,
|
||||
);
|
||||
}
|
||||
|
||||
SitePermissions _copyWithLocation(SitePermissions p, SitePermissionStatus status) {
|
||||
return SitePermissions(
|
||||
origin: p.origin,
|
||||
camera: p.camera,
|
||||
microphone: p.microphone,
|
||||
location: status,
|
||||
notification: p.notification,
|
||||
persistentStorage: p.persistentStorage,
|
||||
crossOriginStorageAccess: p.crossOriginStorageAccess,
|
||||
mediaKeySystemAccess: p.mediaKeySystemAccess,
|
||||
localDeviceAccess: p.localDeviceAccess,
|
||||
localNetworkAccess: p.localNetworkAccess,
|
||||
autoplayAudible: p.autoplayAudible,
|
||||
autoplayInaudible: p.autoplayInaudible,
|
||||
savedAt: p.savedAt,
|
||||
);
|
||||
}
|
||||
|
||||
SitePermissions _copyWithNotification(SitePermissions p, SitePermissionStatus status) {
|
||||
return SitePermissions(
|
||||
origin: p.origin,
|
||||
camera: p.camera,
|
||||
microphone: p.microphone,
|
||||
location: p.location,
|
||||
notification: status,
|
||||
persistentStorage: p.persistentStorage,
|
||||
crossOriginStorageAccess: p.crossOriginStorageAccess,
|
||||
mediaKeySystemAccess: p.mediaKeySystemAccess,
|
||||
localDeviceAccess: p.localDeviceAccess,
|
||||
localNetworkAccess: p.localNetworkAccess,
|
||||
autoplayAudible: p.autoplayAudible,
|
||||
autoplayInaudible: p.autoplayInaudible,
|
||||
savedAt: p.savedAt,
|
||||
);
|
||||
}
|
||||
|
||||
SitePermissions _copyWithPersistentStorage(SitePermissions p, SitePermissionStatus status) {
|
||||
return SitePermissions(
|
||||
origin: p.origin,
|
||||
camera: p.camera,
|
||||
microphone: p.microphone,
|
||||
location: p.location,
|
||||
notification: p.notification,
|
||||
persistentStorage: status,
|
||||
crossOriginStorageAccess: p.crossOriginStorageAccess,
|
||||
mediaKeySystemAccess: p.mediaKeySystemAccess,
|
||||
localDeviceAccess: p.localDeviceAccess,
|
||||
localNetworkAccess: p.localNetworkAccess,
|
||||
autoplayAudible: p.autoplayAudible,
|
||||
autoplayInaudible: p.autoplayInaudible,
|
||||
savedAt: p.savedAt,
|
||||
);
|
||||
}
|
||||
|
||||
SitePermissions _copyWithCrossOriginStorage(SitePermissions p, SitePermissionStatus status) {
|
||||
return SitePermissions(
|
||||
origin: p.origin,
|
||||
camera: p.camera,
|
||||
microphone: p.microphone,
|
||||
location: p.location,
|
||||
notification: p.notification,
|
||||
persistentStorage: p.persistentStorage,
|
||||
crossOriginStorageAccess: status,
|
||||
mediaKeySystemAccess: p.mediaKeySystemAccess,
|
||||
localDeviceAccess: p.localDeviceAccess,
|
||||
localNetworkAccess: p.localNetworkAccess,
|
||||
autoplayAudible: p.autoplayAudible,
|
||||
autoplayInaudible: p.autoplayInaudible,
|
||||
savedAt: p.savedAt,
|
||||
);
|
||||
}
|
||||
|
||||
SitePermissions _copyWithMediaKeySystem(SitePermissions p, SitePermissionStatus status) {
|
||||
return SitePermissions(
|
||||
origin: p.origin,
|
||||
camera: p.camera,
|
||||
microphone: p.microphone,
|
||||
location: p.location,
|
||||
notification: p.notification,
|
||||
persistentStorage: p.persistentStorage,
|
||||
crossOriginStorageAccess: p.crossOriginStorageAccess,
|
||||
mediaKeySystemAccess: status,
|
||||
localDeviceAccess: p.localDeviceAccess,
|
||||
localNetworkAccess: p.localNetworkAccess,
|
||||
autoplayAudible: p.autoplayAudible,
|
||||
autoplayInaudible: p.autoplayInaudible,
|
||||
savedAt: p.savedAt,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _PermissionEntry {
|
||||
@@ -475,9 +348,11 @@ class _AutoplayTile extends StatelessWidget {
|
||||
final audible = audibleStatus ?? AutoplayStatus.blocked;
|
||||
final inaudible = inaudibleStatus ?? AutoplayStatus.allowed;
|
||||
|
||||
if (audible == AutoplayStatus.allowed && inaudible == AutoplayStatus.allowed) {
|
||||
if (audible == AutoplayStatus.allowed &&
|
||||
inaudible == AutoplayStatus.allowed) {
|
||||
return _AutoplayCombined.allowAll;
|
||||
} else if (audible == AutoplayStatus.blocked && inaudible == AutoplayStatus.allowed) {
|
||||
} else if (audible == AutoplayStatus.blocked &&
|
||||
inaudible == AutoplayStatus.allowed) {
|
||||
return _AutoplayCombined.blockAudible;
|
||||
} else {
|
||||
return _AutoplayCombined.blockAll;
|
||||
@@ -485,8 +360,4 @@ class _AutoplayTile extends StatelessWidget {
|
||||
}
|
||||
}
|
||||
|
||||
enum _AutoplayCombined {
|
||||
allowAll,
|
||||
blockAudible,
|
||||
blockAll,
|
||||
}
|
||||
enum _AutoplayCombined { allowAll, blockAudible, blockAll }
|
||||
|
||||
-11
@@ -22,17 +22,6 @@ import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
|
||||
part 'site_permissions_provider.g.dart';
|
||||
|
||||
/// Provider to fetch site permissions for a given origin
|
||||
@Riverpod()
|
||||
Future<SitePermissions?> sitePermissions(
|
||||
Ref ref,
|
||||
String origin,
|
||||
bool isPrivate,
|
||||
) {
|
||||
final api = GeckoSitePermissionsApi();
|
||||
return api.getSitePermissions(origin, isPrivate);
|
||||
}
|
||||
|
||||
/// Provider to get the public suffix plus one (eTLD+1) for a host
|
||||
@Riverpod()
|
||||
Future<String> publicSuffixPlusOne(Ref ref, String host) {
|
||||
|
||||
-84
@@ -8,90 +8,6 @@ part of 'site_permissions_provider.dart';
|
||||
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
// ignore_for_file: type=lint, type=warning
|
||||
/// Provider to fetch site permissions for a given origin
|
||||
|
||||
@ProviderFor(sitePermissions)
|
||||
final sitePermissionsProvider = SitePermissionsFamily._();
|
||||
|
||||
/// Provider to fetch site permissions for a given origin
|
||||
|
||||
final class SitePermissionsProvider
|
||||
extends
|
||||
$FunctionalProvider<
|
||||
AsyncValue<SitePermissions?>,
|
||||
SitePermissions?,
|
||||
FutureOr<SitePermissions?>
|
||||
>
|
||||
with $FutureModifier<SitePermissions?>, $FutureProvider<SitePermissions?> {
|
||||
/// Provider to fetch site permissions for a given origin
|
||||
SitePermissionsProvider._({
|
||||
required SitePermissionsFamily super.from,
|
||||
required (String, bool) super.argument,
|
||||
}) : super(
|
||||
retry: null,
|
||||
name: r'sitePermissionsProvider',
|
||||
isAutoDispose: true,
|
||||
dependencies: null,
|
||||
$allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
@override
|
||||
String debugGetCreateSourceHash() => _$sitePermissionsHash();
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return r'sitePermissionsProvider'
|
||||
''
|
||||
'$argument';
|
||||
}
|
||||
|
||||
@$internal
|
||||
@override
|
||||
$FutureProviderElement<SitePermissions?> $createElement(
|
||||
$ProviderPointer pointer,
|
||||
) => $FutureProviderElement(pointer);
|
||||
|
||||
@override
|
||||
FutureOr<SitePermissions?> create(Ref ref) {
|
||||
final argument = this.argument as (String, bool);
|
||||
return sitePermissions(ref, argument.$1, argument.$2);
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return other is SitePermissionsProvider && other.argument == argument;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode {
|
||||
return argument.hashCode;
|
||||
}
|
||||
}
|
||||
|
||||
String _$sitePermissionsHash() => r'785af0f938bfe53799fc8b6ee8be71015afbc86c';
|
||||
|
||||
/// Provider to fetch site permissions for a given origin
|
||||
|
||||
final class SitePermissionsFamily extends $Family
|
||||
with $FunctionalFamilyOverride<FutureOr<SitePermissions?>, (String, bool)> {
|
||||
SitePermissionsFamily._()
|
||||
: super(
|
||||
retry: null,
|
||||
name: r'sitePermissionsProvider',
|
||||
dependencies: null,
|
||||
$allTransitiveDependencies: null,
|
||||
isAutoDispose: true,
|
||||
);
|
||||
|
||||
/// Provider to fetch site permissions for a given origin
|
||||
|
||||
SitePermissionsProvider call(String origin, bool isPrivate) =>
|
||||
SitePermissionsProvider._(argument: (origin, isPrivate), from: this);
|
||||
|
||||
@override
|
||||
String toString() => r'sitePermissionsProvider';
|
||||
}
|
||||
|
||||
/// Provider to get the public suffix plus one (eTLD+1) for a host
|
||||
|
||||
@ProviderFor(publicSuffixPlusOne)
|
||||
|
||||
Reference in New Issue
Block a user