calling basic workflow complete
parent
d5a21a05ca
commit
012314616a
@ -0,0 +1,264 @@
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue