proofmode 0.9.0

Capture, share, and preserve verifiable photos and videos
Documentation
import Foundation
import UIKit
import AVFoundation
import Photos
import CoreLocation

@MainActor
class PermissionService: ObservableObject {
    @Published var cameraPermissionStatus: AVAuthorizationStatus = .notDetermined
    @Published var photoLibraryPermissionStatus: PHAuthorizationStatus = .notDetermined
    @Published var locationPermissionStatus: CLAuthorizationStatus = .notDetermined
    
    private let locationManager = CLLocationManager()
    
    init() {
        checkPermissions()
    }
    
    func checkPermissions() {
        checkCameraPermission()
        checkPhotoLibraryPermission()
        checkLocationPermission()
    }
    
    // MARK: - Camera Permission
    
    func checkCameraPermission() {
        cameraPermissionStatus = AVCaptureDevice.authorizationStatus(for: .video)
    }
    
    func requestCameraPermission(completion: @escaping (Bool) -> Void) {
        switch cameraPermissionStatus {
        case .authorized:
            completion(true)
        case .notDetermined:
            AVCaptureDevice.requestAccess(for: .video) { granted in
                DispatchQueue.main.async {
                    self.cameraPermissionStatus = granted ? .authorized : .denied
                    completion(granted)
                }
            }
        case .denied, .restricted:
            showPermissionAlert(for: "Camera")
            completion(false)
        @unknown default:
            completion(false)
        }
    }
    
    // MARK: - Photo Library Permission
    
    func checkPhotoLibraryPermission() {
        photoLibraryPermissionStatus = PHPhotoLibrary.authorizationStatus()
    }
    
    func requestPhotoLibraryPermission(completion: @escaping (Bool) -> Void) {
        switch photoLibraryPermissionStatus {
        case .authorized, .limited:
            completion(true)
        case .notDetermined:
            PHPhotoLibrary.requestAuthorization { status in
                DispatchQueue.main.async {
                    self.photoLibraryPermissionStatus = status
                    completion(status == .authorized || status == .limited)
                }
            }
        case .denied, .restricted:
            showPermissionAlert(for: "Photo Library")
            completion(false)
        @unknown default:
            completion(false)
        }
    }
    
    // MARK: - Location Permission
    
    func checkLocationPermission() {
        locationPermissionStatus = locationManager.authorizationStatus
    }
    
    func requestLocationPermission(completion: @escaping (Bool) -> Void) {
        switch locationPermissionStatus {
        case .authorizedWhenInUse, .authorizedAlways:
            completion(true)
        case .notDetermined:
            locationManager.requestWhenInUseAuthorization()
            // Completion will be called via delegate
            completion(false)
        case .denied, .restricted:
            showPermissionAlert(for: "Location")
            completion(false)
        @unknown default:
            completion(false)
        }
    }
    
    // MARK: - Helper Methods
    
    private func showPermissionAlert(for feature: String) {
        guard let settingsUrl = URL(string: UIApplication.openSettingsURLString),
              UIApplication.shared.canOpenURL(settingsUrl) else { return }
        
        DispatchQueue.main.async {
            let alert = UIAlertController(
                title: "\(feature) Access Required",
                message: "Please enable \(feature) access in Settings to use this feature.",
                preferredStyle: .alert
            )
            
            alert.addAction(UIAlertAction(title: "Cancel", style: .cancel))
            alert.addAction(UIAlertAction(title: "Settings", style: .default) { _ in
                UIApplication.shared.open(settingsUrl)
            })
            
            if let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene,
               let rootViewController = windowScene.windows.first?.rootViewController {
                rootViewController.present(alert, animated: true)
            }
        }
    }
}