You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
cloudsolutions-atoms/lib/modules/cx_module/chat/call/utils/permission_helper.dart

265 lines
10 KiB
Dart

import 'dart:async';
import 'dart:developer';
import 'package:flutter/material.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:test_sa/modules/cx_module/chat/call/call_error_handler.dart';
/// Production-ready permission helper for audio/video calls
/// Handles all permission requests with proper error handling and user feedback
class CallPermissionHelper {
CallPermissionHelper._();
/// Check and request microphone permission for audio calls
/// Returns true if permission is granted, false otherwise
static Future<bool> requestMicrophonePermission(BuildContext context) async {
try {
log('🎤 [PERMISSION] Checking microphone permission...', name: 'CallPermissionHelper');
// Check current status
final status = await Permission.microphone.status;
log(' Current status: ${status.name}', name: 'CallPermissionHelper');
if (status.isGranted) {
log('✅ [PERMISSION] Microphone already granted', name: 'CallPermissionHelper');
return true;
}
// If denied permanently, show settings dialog
if (status.isPermanentlyDenied) {
log('⚠️ [PERMISSION] Microphone permanently denied - showing settings dialog', name: 'CallPermissionHelper');
if (context.mounted) {
await _showPermissionDeniedDialog(
context,
'Microphone Permission Required',
'This app needs microphone access to make calls. Please enable it in settings.',
Permission.microphone,
);
}
return false;
}
// Request permission
log('📤 [PERMISSION] Requesting microphone permission...', name: 'CallPermissionHelper');
final result = await Permission.microphone.request();
log(' Result: ${result.name}', name: 'CallPermissionHelper');
if (result.isGranted) {
log('✅ [PERMISSION] Microphone permission granted', name: 'CallPermissionHelper');
return true;
}
if (result.isPermanentlyDenied) {
log('❌ [PERMISSION] Microphone permanently denied', name: 'CallPermissionHelper');
if (context.mounted) {
await _showPermissionDeniedDialog(
context,
'Microphone Permission Required',
'This app needs microphone access to make calls. Please enable it in settings.',
Permission.microphone,
);
}
return false;
}
// User denied
log('❌ [PERMISSION] Microphone permission denied by user', name: 'CallPermissionHelper');
if (context.mounted) {
CallErrorHandler.showMicrophonePermissionDenied(context);
}
return false;
} catch (e, stackTrace) {
log('❌ [PERMISSION] Error requesting microphone permission: $e\nStack: $stackTrace',
name: 'CallPermissionHelper');
if (context.mounted) {
CallErrorHandler.showGenericError(context, 'Failed to request microphone permission');
}
return false;
}
}
/// Check and request camera permission for video calls
/// Returns true if permission is granted, false otherwise
static Future<bool> requestCameraPermission(BuildContext context) async {
try {
log('📹 [PERMISSION] Checking camera permission...', name: 'CallPermissionHelper');
// Check current status
final status = await Permission.camera.status;
log(' Current status: ${status.name}', name: 'CallPermissionHelper');
if (status.isGranted) {
log('✅ [PERMISSION] Camera already granted', name: 'CallPermissionHelper');
return true;
}
// If denied permanently, show settings dialog
if (status.isPermanentlyDenied) {
log('⚠️ [PERMISSION] Camera permanently denied - showing settings dialog', name: 'CallPermissionHelper');
if (context.mounted) {
await _showPermissionDeniedDialog(
context,
'Camera Permission Required',
'This app needs camera access for video calls. Please enable it in settings.',
Permission.camera,
);
}
return false;
}
// Request permission
log('📤 [PERMISSION] Requesting camera permission...', name: 'CallPermissionHelper');
final result = await Permission.camera.request();
log(' Result: ${result.name}', name: 'CallPermissionHelper');
if (result.isGranted) {
log('✅ [PERMISSION] Camera permission granted', name: 'CallPermissionHelper');
return true;
}
if (result.isPermanentlyDenied) {
log('❌ [PERMISSION] Camera permanently denied', name: 'CallPermissionHelper');
if (context.mounted) {
await _showPermissionDeniedDialog(
context,
'Camera Permission Required',
'This app needs camera access for video calls. Please enable it in settings.',
Permission.camera,
);
}
return false;
}
// User denied
log('❌ [PERMISSION] Camera permission denied by user', name: 'CallPermissionHelper');
if (context.mounted) {
CallErrorHandler.showCameraPermissionDenied(context);
}
return false;
} catch (e, stackTrace) {
log('❌ [PERMISSION] Error requesting camera permission: $e\nStack: $stackTrace',
name: 'CallPermissionHelper');
if (context.mounted) {
CallErrorHandler.showGenericError(context, 'Failed to request camera permission');
}
return false;
}
}
/// Request all permissions required for audio calls (microphone only)
/// Returns true if all permissions are granted, false otherwise
static Future<bool> requestAudioCallPermissions(BuildContext context) async {
log('═══════════════════════════════════════════', name: 'CallPermissionHelper');
log('🎵 [PERMISSION] Requesting audio call permissions...', name: 'CallPermissionHelper');
final micGranted = await requestMicrophonePermission(context);
if (!micGranted) {
log('❌ [PERMISSION] Audio call permissions denied', name: 'CallPermissionHelper');
log('═══════════════════════════════════════════', name: 'CallPermissionHelper');
return false;
}
log('✅ [PERMISSION] All audio call permissions granted', name: 'CallPermissionHelper');
log('═══════════════════════════════════════════', name: 'CallPermissionHelper');
return true;
}
/// Request all permissions required for video calls (microphone + camera)
/// Returns true if all permissions are granted, false otherwise
static Future<bool> requestVideoCallPermissions(BuildContext context) async {
log('═══════════════════════════════════════════', name: 'CallPermissionHelper');
log('📹 [PERMISSION] Requesting video call permissions...', name: 'CallPermissionHelper');
// Request both permissions
final micGranted = await requestMicrophonePermission(context);
if (!micGranted) {
log('❌ [PERMISSION] Video call permissions denied (microphone)', name: 'CallPermissionHelper');
log('═══════════════════════════════════════════', name: 'CallPermissionHelper');
return false;
}
final cameraGranted = await requestCameraPermission(context);
if (!cameraGranted) {
log('❌ [PERMISSION] Video call permissions denied (camera)', name: 'CallPermissionHelper');
log('═══════════════════════════════════════════', name: 'CallPermissionHelper');
return false;
}
log('✅ [PERMISSION] All video call permissions granted', name: 'CallPermissionHelper');
log('═══════════════════════════════════════════', name: 'CallPermissionHelper');
return true;
}
/// Check if microphone permission is granted (without requesting)
static Future<bool> isMicrophoneGranted() async {
final status = await Permission.microphone.status;
return status.isGranted;
}
/// Check if camera permission is granted (without requesting)
static Future<bool> isCameraGranted() async {
final status = await Permission.camera.status;
return status.isGranted;
}
/// Show dialog when permission is permanently denied, with option to open settings
static Future<void> _showPermissionDeniedDialog(
BuildContext context,
String title,
String message,
Permission permission,
) async {
if (!context.mounted) return;
return showDialog(
context: context,
barrierDismissible: false,
builder: (BuildContext context) {
return AlertDialog(
title: Text(title),
content: Text(message),
actions: [
TextButton(
onPressed: () => Navigator.of(context).pop(),
child: const Text('Cancel'),
),
TextButton(
onPressed: () async {
Navigator.of(context).pop();
await openAppSettings();
},
child: const Text('Open Settings'),
),
],
);
},
);
}
/// Handle permission denial during an active call
/// Shows error and optionally ends the call
static Future<void> handlePermissionDeniedDuringCall(
BuildContext context,
String permissionName, {
required Function() onEndCall,
int delaySeconds = 2,
}) async {
if (!context.mounted) return;
log('❌ [PERMISSION] $permissionName denied during active call', name: 'CallPermissionHelper');
log(' Showing error and ending call in ${delaySeconds}s...', name: 'CallPermissionHelper');
CallErrorHandler.showGenericError(
context,
'$permissionName permission is required for this call.',
);
// Give user time to see the error
await Future.delayed(Duration(seconds: delaySeconds));
if (context.mounted) {
onEndCall();
}
}
}