1 // Copyright 2022-present 650 Industries. All rights reserved.
2 
3 import ABI49_0_0ExpoModulesCore
4 import MobileCoreServices
5 import PhotosUI
6 
7 internal let DEFAULT_QUALITY = 0.2
8 internal let MAXIMUM_QUALITY = 1.0
9 
10 internal let UNLIMITED_SELECTION = 0
11 internal let SINGLE_SELECTION = 1
12 
13 internal struct ImagePickerOptions: Record {
14   @Field
15   var allowsEditing: Bool = false
16 
17   @Field
18   var aspect: [Double]
19 
20   @Field
21   var quality: Double?
22 
23   @Field
24   var mediaTypes: MediaType = .images
25 
26   @Field
27   var exif: Bool
28 
29   @Field
30   var base64: Bool = false
31 
32   @Field
33   var videoExportPreset: VideoExportPreset = .passthrough
34 
35   @Field
36   var videoQuality: VideoQuality = .typeHigh
37 
38   @Field
39   var videoMaxDuration: Double = 0
40 
41   @Field
42   var presentationStyle: PresentationStyle = .automatic
43 
44   @Field
45   var preferredAssetRepresentationMode: PreferredAssetRepresentationMode = .automatic
46 
47   @Field
48   var cameraType: CameraType = .back
49 
50   @Field
51   var allowsMultipleSelection: Bool = false
52 
53   @Field
54   var selectionLimit: Int = UNLIMITED_SELECTION
55 
56   @Field
57   var orderedSelection: Bool = false
58 }
59 
60 internal enum PresentationStyle: String, EnumArgument {
61   case fullScreen
62   case pageSheet
63   case formSheet
64   case currentContext
65   case overFullScreen
66   case overCurrentContext
67   case popover
68   case none
69   case automatic
70 
71   func toPresentationStyle() -> UIModalPresentationStyle {
72     switch self {
73     case .fullScreen:
74       return .fullScreen
75     case .pageSheet:
76       return .pageSheet
77     case .formSheet:
78       return .formSheet
79     case .currentContext:
80       return .currentContext
81     case .overFullScreen:
82       return .overFullScreen
83     case .overCurrentContext:
84       return .overCurrentContext
85     case .popover:
86       return .popover
87     case .none:
88       return .none
89     case .automatic:
90       if #available(iOS 13.0, *) {
91         return .automatic
92       }
93       // default prior iOS 13
94       return .fullScreen
95     }
96   }
97 }
98 
99 internal enum PreferredAssetRepresentationMode: String, EnumArgument {
100   case automatic
101   case compatible
102   case current
103 
104   @available(iOS 14.0, *)
105   func toAssetRepresentationMode() -> PHPickerConfiguration.AssetRepresentationMode {
106     switch self {
107     case .automatic:
108       return .automatic
109     case .compatible:
110       return .compatible
111     case .current:
112       return .current
113     }
114   }
115 }
116 
117 internal enum VideoQuality: Int, EnumArgument {
118   case typeHigh = 0
119   case typeMedium = 1
120   case typeLow = 2
121   case type640x480 = 3
122   case typeIFrame1280x720 = 4
123   case typeIFrame960x540 = 5
124 
125   func toQualityType() -> UIImagePickerController.QualityType {
126     switch self {
127     case .typeHigh:
128       return .typeHigh
129     case .typeMedium:
130       return .typeMedium
131     case .typeLow:
132       return .typeLow
133     case .type640x480:
134       return .type640x480
135     case .typeIFrame1280x720:
136       return .typeIFrame1280x720
137     case .typeIFrame960x540:
138       return .typeIFrame960x540
139     }
140   }
141 }
142 
143 internal enum MediaType: String, EnumArgument {
144   case all = "All"
145   case videos = "Videos"
146   case images = "Images"
147 
148   func toArray() -> [String] {
149     switch self {
150     case .images:
151       return [kUTTypeImage as String]
152     case .videos:
153       return [kUTTypeMovie as String]
154     case .all:
155       return [kUTTypeImage as String, kUTTypeMovie as String]
156     }
157   }
158 
159   @available(iOS 14, *)
160   func toPickerFilter() -> PHPickerFilter {
161     // TODO: (barthap) Maybe add support for live photos
162     switch self {
163     case .images:
164       return .images
165     case .videos:
166       return .videos
167     case .all:
168       return .any(of: [.images, .videos])
169     }
170   }
171 }
172 
173 internal enum VideoExportPreset: Int, EnumArgument {
174   case passthrough = 0
175   case lowQuality = 1
176   case mediumQuality = 2
177   case highestQuality = 3
178   case h264_640x480 = 4
179   case h264_960x540 = 5
180   case h264_1280x720 = 6
181   case h264_1920x1080 = 7
182   case h264_3840x2160 = 8
183   case hevc_1920x1080 = 9
184   case hevc_3840_2160 = 10
185 
186   func toAVAssetExportPreset() -> String {
187     switch self {
188     case .passthrough:
189       return AVAssetExportPresetPassthrough
190     case .lowQuality:
191       return AVAssetExportPresetLowQuality
192     case .mediumQuality:
193       return AVAssetExportPresetMediumQuality
194     case .highestQuality:
195       return AVAssetExportPresetHighestQuality
196     case .h264_640x480:
197       return AVAssetExportPreset640x480
198     case .h264_960x540:
199       return AVAssetExportPreset960x540
200     case .h264_1280x720:
201       return AVAssetExportPreset1280x720
202     case .h264_1920x1080:
203       return AVAssetExportPreset1920x1080
204     case .h264_3840x2160:
205       return AVAssetExportPreset3840x2160
206     case .hevc_1920x1080:
207       return AVAssetExportPresetHEVC1920x1080
208     case .hevc_3840_2160:
209       return AVAssetExportPresetHEVC3840x2160
210     }
211   }
212 }
213 
214 internal enum CameraType: String, EnumArgument {
215   case back
216   case front
217 }
218