Files
smart-city-digital-twin-mar…/smart-app-city/frontend/node_modules/expo-image-picker/ios/ImagePickerPermissionRequesters.swift
Eric FELIXINE e30ae8ed09 feat(smart-app): implement complete mobile app MVP
- App.tsx: full navigation (Auth stack + Main tabs with 5 screens)
- Auth: LoginScreen, RegisterScreen, ForgotPasswordScreen
- HomeScreen: dashboard with IoT metrics, weather widget, alerts, quick actions, sensors
- MapScreen: interactive map with layer toggles (6 layers)
- MarketplaceScreen: categories (6), products (5), search
- ChatScreen: AI chat with quick prompts (4), bot responses
- ProfileScreen: user info, stats, menu (9 items), logout
- AlertsScreen: alert list with severity, acknowledge
- SensorsScreen: sensor list with type filters (6 types), search
- ZonesScreen: zone cards with stats
- SettingsScreen: language picker (FR/EN/ES/DE), privacy, about
- Stores: iotStore (sensors, zones, alerts), notificationStore, uiStore + i18n
- Hooks: useSensors, useAlerts, useNotifications, useLocation
- Components: Card, Button, LoadingSpinner, ErrorBoundary, Header
- Services: iotService, notificationService (with axios API client)
- Utils: formatters (temp, AQI, noise, dates), validators (email, password, IBAN)
- Theme: colors.ts with full design system (Blue Ocean palette)
- Ditto: fixed MongoDB connection, new JWT secrets, official gateway image
2026-06-01 18:00:35 -04:00

137 lines
4.5 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"
}
@available(iOS 14, *)
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) {
let authorizationHandler = { [weak self] (_: PHAuthorizationStatus) in
resolve(self?.getPermissions())
}
if #available(iOS 14.0, *) {
PHPhotoLibrary.requestAuthorization(for: self.accessLevel(), handler: authorizationHandler)
} else {
PHPhotoLibrary.requestAuthorization(authorizationHandler)
}
}
@objc
public func getPermissions() -> [AnyHashable: Any] {
var authorizationStatus: PHAuthorizationStatus
if #available(iOS 14.0, *) {
authorizationStatus = PHPhotoLibrary.authorizationStatus(for: self.accessLevel())
} else {
authorizationStatus = PHPhotoLibrary.authorizationStatus()
}
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
]
}
@available(iOS 14, *)
@objc
internal func accessLevel() -> PHAccessLevel {
return PHAccessLevel.readWrite
}
}