124 lines
4.1 KiB
Swift
124 lines
4.1 KiB
Swift
// Copyright 2022-present 650 Industries. All rights reserved.
|
|
|
|
import Photos
|
|
import ExpoModulesCore
|
|
|
|
public class CameraPermissionRequester: NSObject, EXPermissionsRequester {
|
|
static public func permissionType() -> String {
|
|
return "camera"
|
|
}
|
|
|
|
public func requestPermissions(resolver resolve: @escaping EXPromiseResolveBlock, rejecter reject: EXPromiseRejectBlock) {
|
|
AVCaptureDevice.requestAccess(for: AVMediaType.video) { [weak self] _ in
|
|
resolve(self?.getPermissions())
|
|
}
|
|
}
|
|
|
|
public func getPermissions() -> [AnyHashable: Any] {
|
|
var systemStatus: AVAuthorizationStatus
|
|
var status: EXPermissionStatus
|
|
let cameraUsageDescription = Bundle.main.object(forInfoDictionaryKey: "NSCameraUsageDescription")
|
|
if cameraUsageDescription == nil {
|
|
EXFatal(EXErrorWithMessage("""
|
|
This app is missing 'NSCameraUsageDescription', video services will fail. \
|
|
Ensure this key exists in the app's Info.plist
|
|
"""))
|
|
systemStatus = AVAuthorizationStatus.denied
|
|
} else {
|
|
systemStatus = AVCaptureDevice.authorizationStatus(for: AVMediaType.video)
|
|
}
|
|
|
|
switch systemStatus {
|
|
case .authorized:
|
|
status = EXPermissionStatusGranted
|
|
case .restricted,
|
|
.denied:
|
|
status = EXPermissionStatusDenied
|
|
case .notDetermined:
|
|
fallthrough
|
|
@unknown default:
|
|
status = EXPermissionStatusUndetermined
|
|
}
|
|
|
|
return [
|
|
"status": status.rawValue
|
|
]
|
|
}
|
|
}
|
|
|
|
public class MediaLibraryPermissionRequester: DefaultMediaLibraryPermissionRequester,
|
|
EXPermissionsRequester {
|
|
public static func permissionType() -> String {
|
|
return "mediaLibrary"
|
|
}
|
|
}
|
|
|
|
public class MediaLibraryWriteOnlyPermissionRequester: DefaultMediaLibraryPermissionRequester,
|
|
EXPermissionsRequester {
|
|
public static func permissionType() -> String {
|
|
return "mediaLibraryWriteOnly"
|
|
}
|
|
|
|
override internal func accessLevel() -> PHAccessLevel {
|
|
return PHAccessLevel.addOnly
|
|
}
|
|
}
|
|
|
|
// MARK: - Permission requesters shared implementation extracted to an extension (mixin pattern)
|
|
|
|
/**
|
|
* Dummy class just to prevent extending NSObject publicly/globally.
|
|
*/
|
|
public class DefaultMediaLibraryPermissionRequester: NSObject {}
|
|
|
|
/**
|
|
* This extension is adding default implmentation for EXPermissionsRequester that can be shared by many classe.
|
|
* In Swift language you cannot override static methods in subclasses, so you cannot subclass any already implemented
|
|
* PermissionRequester as instances of this class are registered by the unique name coming from `static func permissionType()`.
|
|
* To prevent repeating the similar code for every MediaLibrary PermissionRequester (the only differences so far are
|
|
* aforementioned permissionType and accessLevel, while the latter can be easily overritten) I've extracted the code
|
|
* to this extension. I'm using as a mixin that implements major part of EXPermissionsRequester protocol.
|
|
*/
|
|
extension DefaultMediaLibraryPermissionRequester {
|
|
@objc
|
|
public func requestPermissions(resolver resolve: @escaping EXPromiseResolveBlock, rejecter reject: EXPromiseRejectBlock) {
|
|
PHPhotoLibrary.requestAuthorization(for: self.accessLevel()) { [weak self] (_: PHAuthorizationStatus) in
|
|
resolve(self?.getPermissions())
|
|
}
|
|
}
|
|
|
|
@objc
|
|
public func getPermissions() -> [AnyHashable: Any] {
|
|
let authorizationStatus = PHPhotoLibrary.authorizationStatus(for: self.accessLevel())
|
|
var status: EXPermissionStatus
|
|
var scope: String
|
|
|
|
switch authorizationStatus {
|
|
case .authorized:
|
|
status = EXPermissionStatusGranted
|
|
scope = "all"
|
|
case .limited:
|
|
status = EXPermissionStatusGranted
|
|
scope = "limited"
|
|
case .denied, .restricted:
|
|
status = EXPermissionStatusDenied
|
|
scope = "none"
|
|
case .notDetermined:
|
|
fallthrough
|
|
@unknown default:
|
|
status = EXPermissionStatusUndetermined
|
|
scope = "none"
|
|
}
|
|
|
|
return [
|
|
"status": status.rawValue,
|
|
"accessPrivileges": scope
|
|
]
|
|
}
|
|
|
|
@objc
|
|
internal func accessLevel() -> PHAccessLevel {
|
|
return PHAccessLevel.readWrite
|
|
}
|
|
}
|