optimize permission section

This commit is contained in:
Fabian Freund
2026-01-19 11:12:39 +01:00
parent 8c7fe372df
commit 1dc609f4e4
2 changed files with 90 additions and 93 deletions
@@ -0,0 +1,47 @@
import 'package:flutter/material.dart';
import 'package:flutter_mozilla_components/flutter_mozilla_components.dart';
import 'package:weblibre/features/geckoview/features/browser/domain/entities/site_permissions.dart';
/// Permission types with their display configuration
enum PermissionType {
camera(Icons.videocam, 'Camera'),
microphone(Icons.mic, 'Microphone'),
location(Icons.location_on, 'Location'),
notification(Icons.notifications, 'Notifications'),
persistentStorage(Icons.storage, 'Persistent Storage'),
crossOriginStorage(Icons.cookie, 'Cross-Origin Storage'),
mediaKeySystem(Icons.key, 'Media Key System (DRM)');
const PermissionType(this.icon, this.label);
final IconData icon;
final String label;
}
extension SitePermissionsGetter on SitePermissions? {
SitePermissionStatus? getStatus(PermissionType type) => switch (type) {
PermissionType.camera => this?.camera,
PermissionType.microphone => this?.microphone,
PermissionType.location => this?.location,
PermissionType.notification => this?.notification,
PermissionType.persistentStorage => this?.persistentStorage,
PermissionType.crossOriginStorage => this?.crossOriginStorageAccess,
PermissionType.mediaKeySystem => this?.mediaKeySystemAccess,
};
}
extension SitePermissionsUpdater on SitePermissionsWrapper {
SitePermissions withStatus(
PermissionType type,
SitePermissionStatus status,
) => switch (type) {
PermissionType.camera => copyWith.camera(status),
PermissionType.microphone => copyWith.microphone(status),
PermissionType.location => copyWith.location(status),
PermissionType.notification => copyWith.notification(status),
PermissionType.persistentStorage => copyWith.persistentStorage(status),
PermissionType.crossOriginStorage => copyWith.crossOriginStorageAccess(
status,
),
PermissionType.mediaKeySystem => copyWith.mediaKeySystemAccess(status),
};
}
@@ -22,6 +22,7 @@ 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/domain/entities/permission_type.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';
@@ -75,81 +76,48 @@ class _PermissionsList extends HookConsumerWidget {
Widget build(BuildContext context, WidgetRef ref) {
final showAll = useState(false);
// Build list of permission entries with their current status
final allPermissions = [
_PermissionEntry(
icon: Icons.videocam,
label: 'Camera',
status: permissions?.camera,
onChanged: (status) => _updatePermission(
ref,
(permissions) => permissions.copyWith.camera(status),
),
),
_PermissionEntry(
icon: Icons.mic,
label: 'Microphone',
status: permissions?.microphone,
onChanged: (status) => _updatePermission(
ref,
(permissions) => permissions.copyWith.microphone(status),
),
),
_PermissionEntry(
icon: Icons.location_on,
label: 'Location',
status: permissions?.location,
onChanged: (status) => _updatePermission(
ref,
(permissions) => permissions.copyWith.location(status),
),
),
_PermissionEntry(
icon: Icons.notifications,
label: 'Notifications',
status: permissions?.notification,
onChanged: (status) => _updatePermission(
ref,
(permissions) => permissions.copyWith.notification(status),
),
),
_PermissionEntry(
icon: Icons.storage,
label: 'Persistent Storage',
status: permissions?.persistentStorage,
onChanged: (status) => _updatePermission(
ref,
(permissions) => permissions.copyWith.persistentStorage(status),
),
),
_PermissionEntry(
icon: Icons.cookie,
label: 'Cross-Origin Storage',
status: permissions?.crossOriginStorageAccess,
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,
(permissions) => permissions.copyWith.mediaKeySystemAccess(status),
),
),
];
// Memoize the update callback to avoid recreating closures
final updatePermission = useCallback((
SitePermissions Function(SitePermissionsWrapper) updater,
) async {
await ref
.read(
sitePermissionsRepositoryProvider(
origin: origin,
isPrivate: isPrivate,
).notifier,
)
.updatePermission(updater);
await ref.read(selectedTabSessionProvider).reload();
}, [origin, isPrivate]);
// Build permission entries - only recalculates when permissions change
final allPermissions = useMemoized(
() => PermissionType.values
.map(
(type) => _PermissionEntry(
icon: type.icon,
label: type.label,
status: permissions.getStatus(type),
onChanged: (status) =>
updatePermission((w) => w.withStatus(type, status)),
),
)
.toList(),
[permissions, updatePermission],
);
// 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();
// Only recalculates when allPermissions changes
final setPermissions = useMemoized(
() => allPermissions
.where(
(p) =>
p.status != null && p.status != SitePermissionStatus.noDecision,
)
.toList(),
[allPermissions],
);
final permissionsToShow = showAll.value ? allPermissions : setPermissions;
final hiddenCount = allPermissions.length - setPermissions.length;
@@ -202,9 +170,8 @@ class _PermissionsList extends HookConsumerWidget {
_AutoplayTile(
audibleStatus: permissions?.autoplayAudible,
inaudibleStatus: permissions?.autoplayInaudible,
onChanged: (audible, inaudible) => _updatePermission(
ref,
(permissions) => permissions.copyWith(
onChanged: (audible, inaudible) => updatePermission(
(p) => p.copyWith(
autoplayAudible: audible,
autoplayInaudible: inaudible,
),
@@ -213,23 +180,6 @@ class _PermissionsList extends HookConsumerWidget {
],
);
}
Future<void> _updatePermission(
WidgetRef ref,
SitePermissions Function(SitePermissionsWrapper) updater,
) async {
await ref
.read(
sitePermissionsRepositoryProvider(
origin: origin,
isPrivate: isPrivate,
).notifier,
)
.updatePermission(updater);
// Reload the tab to apply changes
await ref.read(selectedTabSessionProvider).reload();
}
}
class _PermissionEntry {