- 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
229 lines
4.9 KiB
Swift
229 lines
4.9 KiB
Swift
// Copyright 2022-present 650 Industries. All rights reserved.
|
|
|
|
import ExpoModulesCore
|
|
import MobileCoreServices
|
|
import PhotosUI
|
|
|
|
internal let DEFAULT_QUALITY = 0.2
|
|
internal let MAXIMUM_QUALITY = 1.0
|
|
|
|
internal let UNLIMITED_SELECTION = 0
|
|
internal let SINGLE_SELECTION = 1
|
|
|
|
internal struct ImagePickerOptions: Record {
|
|
@Field
|
|
var allowsEditing: Bool = false
|
|
|
|
@Field
|
|
var aspect: [Double]
|
|
|
|
@Field
|
|
var quality: Double?
|
|
|
|
@Field
|
|
var mediaTypes: MediaType = .images
|
|
|
|
@Field
|
|
var exif: Bool
|
|
|
|
@Field
|
|
var base64: Bool = false
|
|
|
|
@Field
|
|
var videoExportPreset: VideoExportPreset = .passthrough
|
|
|
|
@Field
|
|
var videoQuality: VideoQuality = .typeHigh
|
|
|
|
@Field
|
|
var videoMaxDuration: Double = 0
|
|
|
|
@Field
|
|
var presentationStyle: PresentationStyle = .automatic
|
|
|
|
@Field
|
|
var preferredAssetRepresentationMode: PreferredAssetRepresentationMode = .automatic
|
|
|
|
@Field
|
|
var cameraType: CameraType = .back
|
|
|
|
@Field
|
|
var allowsMultipleSelection: Bool = false
|
|
|
|
@Field
|
|
var selectionLimit: Int = UNLIMITED_SELECTION
|
|
|
|
@Field
|
|
var orderedSelection: Bool = false
|
|
}
|
|
|
|
internal enum PresentationStyle: String, EnumArgument {
|
|
case fullScreen
|
|
case pageSheet
|
|
case formSheet
|
|
case currentContext
|
|
case overFullScreen
|
|
case overCurrentContext
|
|
case popover
|
|
case none
|
|
case automatic
|
|
|
|
func toPresentationStyle() -> UIModalPresentationStyle {
|
|
switch self {
|
|
case .fullScreen:
|
|
return .fullScreen
|
|
case .pageSheet:
|
|
return .pageSheet
|
|
case .formSheet:
|
|
return .formSheet
|
|
case .currentContext:
|
|
return .currentContext
|
|
case .overFullScreen:
|
|
return .overFullScreen
|
|
case .overCurrentContext:
|
|
return .overCurrentContext
|
|
case .popover:
|
|
return .popover
|
|
case .none:
|
|
return .none
|
|
case .automatic:
|
|
if #available(iOS 13.0, *) {
|
|
return .automatic
|
|
}
|
|
// default prior iOS 13
|
|
return .fullScreen
|
|
}
|
|
}
|
|
}
|
|
|
|
internal enum PreferredAssetRepresentationMode: String, EnumArgument {
|
|
case automatic
|
|
case compatible
|
|
case current
|
|
|
|
@available(iOS 14.0, *)
|
|
func toAssetRepresentationMode() -> PHPickerConfiguration.AssetRepresentationMode {
|
|
switch self {
|
|
case .automatic:
|
|
return .automatic
|
|
case .compatible:
|
|
return .compatible
|
|
case .current:
|
|
return .current
|
|
}
|
|
}
|
|
}
|
|
|
|
internal enum VideoQuality: Int, EnumArgument {
|
|
case typeHigh = 0
|
|
case typeMedium = 1
|
|
case typeLow = 2
|
|
case type640x480 = 3
|
|
case typeIFrame1280x720 = 4
|
|
case typeIFrame960x540 = 5
|
|
|
|
func toQualityType() -> UIImagePickerController.QualityType {
|
|
switch self {
|
|
case .typeHigh:
|
|
return .typeHigh
|
|
case .typeMedium:
|
|
return .typeMedium
|
|
case .typeLow:
|
|
return .typeLow
|
|
case .type640x480:
|
|
return .type640x480
|
|
case .typeIFrame1280x720:
|
|
return .typeIFrame1280x720
|
|
case .typeIFrame960x540:
|
|
return .typeIFrame960x540
|
|
}
|
|
}
|
|
}
|
|
|
|
internal enum MediaType: String, EnumArgument {
|
|
case all = "All"
|
|
case videos = "Videos"
|
|
case images = "Images"
|
|
|
|
func toArray() -> [String] {
|
|
switch self {
|
|
case .images:
|
|
return [kUTTypeImage as String]
|
|
case .videos:
|
|
return [kUTTypeMovie as String]
|
|
case .all:
|
|
return [kUTTypeImage as String, kUTTypeMovie as String]
|
|
}
|
|
}
|
|
|
|
func requiresMicrophonePermission() -> Bool {
|
|
switch self {
|
|
case .images:
|
|
return false
|
|
case .videos:
|
|
return true
|
|
case .all:
|
|
return true
|
|
}
|
|
}
|
|
|
|
@available(iOS 14, *)
|
|
func toPickerFilter() -> PHPickerFilter {
|
|
// TODO: (barthap) Maybe add support for live photos
|
|
switch self {
|
|
case .images:
|
|
return .images
|
|
case .videos:
|
|
return .videos
|
|
case .all:
|
|
return .any(of: [.images, .videos])
|
|
}
|
|
}
|
|
}
|
|
|
|
internal enum VideoExportPreset: Int, EnumArgument {
|
|
case passthrough = 0
|
|
case lowQuality = 1
|
|
case mediumQuality = 2
|
|
case highestQuality = 3
|
|
case h264_640x480 = 4
|
|
case h264_960x540 = 5
|
|
case h264_1280x720 = 6
|
|
case h264_1920x1080 = 7
|
|
case h264_3840x2160 = 8
|
|
case hevc_1920x1080 = 9
|
|
case hevc_3840_2160 = 10
|
|
|
|
func toAVAssetExportPreset() -> String {
|
|
switch self {
|
|
case .passthrough:
|
|
return AVAssetExportPresetPassthrough
|
|
case .lowQuality:
|
|
return AVAssetExportPresetLowQuality
|
|
case .mediumQuality:
|
|
return AVAssetExportPresetMediumQuality
|
|
case .highestQuality:
|
|
return AVAssetExportPresetHighestQuality
|
|
case .h264_640x480:
|
|
return AVAssetExportPreset640x480
|
|
case .h264_960x540:
|
|
return AVAssetExportPreset960x540
|
|
case .h264_1280x720:
|
|
return AVAssetExportPreset1280x720
|
|
case .h264_1920x1080:
|
|
return AVAssetExportPreset1920x1080
|
|
case .h264_3840x2160:
|
|
return AVAssetExportPreset3840x2160
|
|
case .hevc_1920x1080:
|
|
return AVAssetExportPresetHEVC1920x1080
|
|
case .hevc_3840_2160:
|
|
return AVAssetExportPresetHEVC3840x2160
|
|
}
|
|
}
|
|
}
|
|
|
|
internal enum CameraType: String, EnumArgument {
|
|
case back
|
|
case front
|
|
}
|