cleanup code

This commit is contained in:
Fabian Freund
2026-01-19 10:11:37 +01:00
parent 2c00504b42
commit 3111de9d44
9 changed files with 528 additions and 315 deletions
@@ -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);
}
}
@@ -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),
);
}
}
@@ -51,7 +51,7 @@ final class TrackingProtectionRepositoryProvider
}
String _$trackingProtectionRepositoryHash() =>
r'6d4407034b2c67317d0a0e106002f1785fd86a34';
r'f4b09ed513da6bd5a9f4d01833a2dbba990f59de';
/// Repository for managing per-site Enhanced Tracking Protection exceptions
///
@@ -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)
@@ -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 }
@@ -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) {
@@ -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)