optimize permission section
This commit is contained in:
@@ -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),
|
||||
};
|
||||
}
|
||||
+43
-93
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user