@hortemo/expo-photos 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/.eslintrc.js ADDED
@@ -0,0 +1,2 @@
1
+ // @generated by expo-module-scripts
2
+ module.exports = require('expo-module-scripts/eslintrc.base.js');
@@ -0,0 +1,24 @@
1
+ require 'json'
2
+
3
+ package = JSON.parse(File.read(File.join(__dir__, 'package.json')))
4
+
5
+ Pod::Spec.new do |s|
6
+ s.name = 'ExpoPhotos'
7
+ s.version = package['version']
8
+ s.summary = package['description']
9
+ s.description = package['description']
10
+ s.license = package['license']
11
+ s.author = package['author']
12
+ s.homepage = package['homepage']
13
+ s.platform = :ios, '15.0'
14
+ s.swift_version = '5.9'
15
+ s.source = { git: package['repository'] || 'https://github.com/hortemo/expo-photos' }
16
+ s.static_framework = true
17
+
18
+ s.dependency 'ExpoModulesCore'
19
+ s.dependency 'React'
20
+ s.dependency 'SDWebImageWebPCoder', '0.15.0'
21
+
22
+ s.source_files = 'ios/**/*.{h,m,swift}'
23
+ s.requires_arc = true
24
+ end
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Henrik Hortemo
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,18 @@
1
+ # @hortemo/expo-photos
2
+
3
+ Lightweight Expo (React Native) wrapper for Apple's [Photos](https://developer.apple.com/documentation/photos) framework.
4
+
5
+ ## Installation
6
+
7
+ ```sh
8
+ npm install @hortemo/expo-photos
9
+ ```
10
+
11
+ ## API Reference
12
+
13
+ - `fetchAssets(options: FetchAssetsOptions): Promise<PHAsset[]>`
14
+ - `requestImage(options: RequestImageOptions): Promise<void>`
15
+ - `requestVideo(options: RequestVideoOptions): Promise<void>`
16
+ - `pickAssets(options: PickAssetsOptions): Promise<PHAsset[]>`
17
+ - `requestAuthorization(accessLevel: PHAccessLevel): Promise<PHAuthorizationStatus>`
18
+ - `presentLimitedLibraryPicker(): Promise<void>`
@@ -0,0 +1,171 @@
1
+ export interface PHAsset {
2
+ localIdentifier: string;
3
+ creationDate: number;
4
+ mediaType: PHAssetMediaType;
5
+ mediaSubtypes: PHAssetMediaSubtype;
6
+ duration: number;
7
+ }
8
+ export declare enum PHAuthorizationStatus {
9
+ notDetermined = 0,
10
+ restricted = 1,
11
+ denied = 2,
12
+ authorized = 3,
13
+ limited = 4
14
+ }
15
+ export declare enum PHAccessLevel {
16
+ addOnly = 1,
17
+ readWrite = 2
18
+ }
19
+ export declare enum PHAssetMediaType {
20
+ Unknown = 0,
21
+ Image = 1,
22
+ Video = 2,
23
+ Audio = 3
24
+ }
25
+ export declare enum PHAssetMediaSubtype {
26
+ None = 0,
27
+ PhotoPanorama = 1,
28
+ PhotoHDR = 2,
29
+ PhotoScreenshot = 4,
30
+ PhotoLive = 8,
31
+ PhotoDepthEffect = 16,
32
+ VideoStreamed = 65536,
33
+ VideoHighFrameRate = 131072,
34
+ VideoTimelapse = 262144,
35
+ VideoCinematic = 524288
36
+ }
37
+ export interface NSSortDescriptor {
38
+ key: string;
39
+ ascending: boolean;
40
+ }
41
+ export interface PHFetchOptions {
42
+ predicate?: string;
43
+ fetchLimit?: number;
44
+ sortDescriptors?: NSSortDescriptor[];
45
+ }
46
+ export type FetchAssetsOptions = PHFetchOptions;
47
+ export interface CGSize {
48
+ width: number;
49
+ height: number;
50
+ }
51
+ export declare enum PHImageRequestOptionsResizeMode {
52
+ None = 0,
53
+ Fast = 1,
54
+ Exact = 2
55
+ }
56
+ export declare enum PHImageRequestOptionsDeliveryMode {
57
+ Opportunistic = 0,
58
+ HighQualityFormat = 1,
59
+ FastFormat = 2
60
+ }
61
+ export declare enum PHImageContentMode {
62
+ aspectFit = 0,
63
+ aspectFill = 1
64
+ }
65
+ export interface PHImageRequestOptions {
66
+ isNetworkAccessAllowed?: boolean;
67
+ resizeMode?: PHImageRequestOptionsResizeMode;
68
+ deliveryMode?: PHImageRequestOptionsDeliveryMode;
69
+ }
70
+ export interface SDImageCoderOptions {
71
+ encodeCompressionQuality?: number;
72
+ encodeMaxFileSize?: number;
73
+ }
74
+ export declare enum PHVideoRequestOptionsDeliveryMode {
75
+ Automatic = 0,
76
+ HighQualityFormat = 1,
77
+ MediumQualityFormat = 2,
78
+ FastFormat = 3
79
+ }
80
+ export interface PHVideoRequestOptions {
81
+ isNetworkAccessAllowed?: boolean;
82
+ deliveryMode?: PHVideoRequestOptionsDeliveryMode;
83
+ }
84
+ export interface CMTimeRange {
85
+ start: number;
86
+ duration: number;
87
+ }
88
+ export declare enum AVFileType {
89
+ ac3 = "public.ac3-audio",
90
+ aifc = "public.aifc-audio",
91
+ aiff = "public.aiff-audio",
92
+ AHAP = "com.apple.itt",
93
+ amr = "org.3gpp.adaptive-multi-rate-audio",
94
+ appleiTT = "com.apple.itt",
95
+ au = "public.au-audio",
96
+ avci = "public.avci",
97
+ caf = "com.apple.coreaudio-format",
98
+ dng = "com.adobe.raw-image",
99
+ eac3 = "public.eac3-audio",
100
+ heic = "public.heic",
101
+ heif = "public.heif",
102
+ jpg = "public.jpeg",
103
+ m4a = "com.apple.m4a-audio",
104
+ m4v = "com.apple.m4v-video",
105
+ mobile3GPP = "public.3gpp",
106
+ mobile3GPP2 = "public.3gpp2",
107
+ mov = "com.apple.quicktime-movie",
108
+ mp3 = "public.mp3",
109
+ mp4 = "public.mpeg-4",
110
+ SCC = "com.scenarist.cc",
111
+ tif = "public.tiff",
112
+ wav = "com.microsoft.waveform-audio"
113
+ }
114
+ export declare enum AVAssetExportPreset {
115
+ LowQuality = "AVAssetExportPresetLowQuality",
116
+ MediumQuality = "AVAssetExportPresetMediumQuality",
117
+ HighestQuality = "AVAssetExportPresetHighestQuality",
118
+ HEVCHighestQuality = "AVAssetExportPresetHEVCHighestQuality",
119
+ HEVCHighestQualityWithAlpha = "AVAssetExportPresetHEVCHighestQualityWithAlpha",
120
+ AVC640x480 = "AVAssetExportPreset640x480",
121
+ AVC960x540 = "AVAssetExportPreset960x540",
122
+ AVC1280x720 = "AVAssetExportPreset1280x720",
123
+ AVC1920x1080 = "AVAssetExportPreset1920x1080",
124
+ AVC3840x2160 = "AVAssetExportPreset3840x2160",
125
+ HEVC1920x1080 = "AVAssetExportPresetHEVC1920x1080",
126
+ HEVC3840x2160 = "AVAssetExportPresetHEVC3840x2160",
127
+ HEVC1920x1080WithAlpha = "AVAssetExportPresetHEVC1920x1080WithAlpha",
128
+ HEVC3840x2160WithAlpha = "AVAssetExportPresetHEVC3840x2160WithAlpha",
129
+ HEVC7680x4320 = "AVAssetExportPresetHEVC7680x4320",
130
+ MVHEVC960x960 = "AVAssetExportPresetMVHEVC960x960",
131
+ MVHEVC1440x1440 = "AVAssetExportPresetMVHEVC1440x1440",
132
+ AppleM4V480pSD = "AVAssetExportPresetAppleM4V480pSD",
133
+ AppleM4V720pHD = "AVAssetExportPresetAppleM4V720pHD",
134
+ AppleM4V1080pHD = "AVAssetExportPresetAppleM4V1080pHD",
135
+ AppleM4ViPod = "AVAssetExportPresetAppleM4ViPod",
136
+ AppleM4VAppleTV = "AVAssetExportPresetAppleM4VAppleTV",
137
+ AppleM4VCellular = "AVAssetExportPresetAppleM4VCellular",
138
+ AppleM4VWiFi = "AVAssetExportPresetAppleM4VWiFi",
139
+ AppleProRes422LPCM = "AVAssetExportPresetAppleProRes422LPCM",
140
+ AppleProRes4444LPCM = "AVAssetExportPresetAppleProRes4444LPCM",
141
+ Passthrough = "AVAssetExportPresetPassthrough",
142
+ AppleM4A = "AVAssetExportPresetAppleM4A"
143
+ }
144
+ export interface AVAssetExportSessionOptions {
145
+ outputURL: string;
146
+ outputFileType?: AVFileType;
147
+ fileLengthLimit?: number;
148
+ timeRange?: CMTimeRange;
149
+ }
150
+ export interface RequestImageOptions extends PHImageRequestOptions, SDImageCoderOptions {
151
+ localIdentifier: string;
152
+ targetSize: CGSize;
153
+ contentMode: PHImageContentMode;
154
+ outputURL: string;
155
+ timeout?: number;
156
+ }
157
+ export interface RequestVideoOptions extends PHVideoRequestOptions, AVAssetExportSessionOptions {
158
+ localIdentifier: string;
159
+ exportPreset: AVAssetExportPreset;
160
+ timeout?: number;
161
+ }
162
+ export declare enum PHPickerFilter {
163
+ images = "images",
164
+ videos = "videos",
165
+ any = "any"
166
+ }
167
+ export interface PickAssetsOptions {
168
+ filter?: PHPickerFilter;
169
+ selectionLimit?: number;
170
+ }
171
+ //# sourceMappingURL=ExpoPhotos.types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ExpoPhotos.types.d.ts","sourceRoot":"","sources":["../src/ExpoPhotos.types.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,122 @@
1
+ export var PHAuthorizationStatus;
2
+ (function (PHAuthorizationStatus) {
3
+ PHAuthorizationStatus[PHAuthorizationStatus["notDetermined"] = 0] = "notDetermined";
4
+ PHAuthorizationStatus[PHAuthorizationStatus["restricted"] = 1] = "restricted";
5
+ PHAuthorizationStatus[PHAuthorizationStatus["denied"] = 2] = "denied";
6
+ PHAuthorizationStatus[PHAuthorizationStatus["authorized"] = 3] = "authorized";
7
+ PHAuthorizationStatus[PHAuthorizationStatus["limited"] = 4] = "limited";
8
+ })(PHAuthorizationStatus || (PHAuthorizationStatus = {}));
9
+ export var PHAccessLevel;
10
+ (function (PHAccessLevel) {
11
+ PHAccessLevel[PHAccessLevel["addOnly"] = 1] = "addOnly";
12
+ PHAccessLevel[PHAccessLevel["readWrite"] = 2] = "readWrite";
13
+ })(PHAccessLevel || (PHAccessLevel = {}));
14
+ export var PHAssetMediaType;
15
+ (function (PHAssetMediaType) {
16
+ PHAssetMediaType[PHAssetMediaType["Unknown"] = 0] = "Unknown";
17
+ PHAssetMediaType[PHAssetMediaType["Image"] = 1] = "Image";
18
+ PHAssetMediaType[PHAssetMediaType["Video"] = 2] = "Video";
19
+ PHAssetMediaType[PHAssetMediaType["Audio"] = 3] = "Audio";
20
+ })(PHAssetMediaType || (PHAssetMediaType = {}));
21
+ export var PHAssetMediaSubtype;
22
+ (function (PHAssetMediaSubtype) {
23
+ PHAssetMediaSubtype[PHAssetMediaSubtype["None"] = 0] = "None";
24
+ PHAssetMediaSubtype[PHAssetMediaSubtype["PhotoPanorama"] = 1] = "PhotoPanorama";
25
+ PHAssetMediaSubtype[PHAssetMediaSubtype["PhotoHDR"] = 2] = "PhotoHDR";
26
+ PHAssetMediaSubtype[PHAssetMediaSubtype["PhotoScreenshot"] = 4] = "PhotoScreenshot";
27
+ PHAssetMediaSubtype[PHAssetMediaSubtype["PhotoLive"] = 8] = "PhotoLive";
28
+ PHAssetMediaSubtype[PHAssetMediaSubtype["PhotoDepthEffect"] = 16] = "PhotoDepthEffect";
29
+ PHAssetMediaSubtype[PHAssetMediaSubtype["VideoStreamed"] = 65536] = "VideoStreamed";
30
+ PHAssetMediaSubtype[PHAssetMediaSubtype["VideoHighFrameRate"] = 131072] = "VideoHighFrameRate";
31
+ PHAssetMediaSubtype[PHAssetMediaSubtype["VideoTimelapse"] = 262144] = "VideoTimelapse";
32
+ PHAssetMediaSubtype[PHAssetMediaSubtype["VideoCinematic"] = 524288] = "VideoCinematic";
33
+ })(PHAssetMediaSubtype || (PHAssetMediaSubtype = {}));
34
+ export var PHImageRequestOptionsResizeMode;
35
+ (function (PHImageRequestOptionsResizeMode) {
36
+ PHImageRequestOptionsResizeMode[PHImageRequestOptionsResizeMode["None"] = 0] = "None";
37
+ PHImageRequestOptionsResizeMode[PHImageRequestOptionsResizeMode["Fast"] = 1] = "Fast";
38
+ PHImageRequestOptionsResizeMode[PHImageRequestOptionsResizeMode["Exact"] = 2] = "Exact";
39
+ })(PHImageRequestOptionsResizeMode || (PHImageRequestOptionsResizeMode = {}));
40
+ export var PHImageRequestOptionsDeliveryMode;
41
+ (function (PHImageRequestOptionsDeliveryMode) {
42
+ PHImageRequestOptionsDeliveryMode[PHImageRequestOptionsDeliveryMode["Opportunistic"] = 0] = "Opportunistic";
43
+ PHImageRequestOptionsDeliveryMode[PHImageRequestOptionsDeliveryMode["HighQualityFormat"] = 1] = "HighQualityFormat";
44
+ PHImageRequestOptionsDeliveryMode[PHImageRequestOptionsDeliveryMode["FastFormat"] = 2] = "FastFormat";
45
+ })(PHImageRequestOptionsDeliveryMode || (PHImageRequestOptionsDeliveryMode = {}));
46
+ export var PHImageContentMode;
47
+ (function (PHImageContentMode) {
48
+ PHImageContentMode[PHImageContentMode["aspectFit"] = 0] = "aspectFit";
49
+ PHImageContentMode[PHImageContentMode["aspectFill"] = 1] = "aspectFill";
50
+ })(PHImageContentMode || (PHImageContentMode = {}));
51
+ export var PHVideoRequestOptionsDeliveryMode;
52
+ (function (PHVideoRequestOptionsDeliveryMode) {
53
+ PHVideoRequestOptionsDeliveryMode[PHVideoRequestOptionsDeliveryMode["Automatic"] = 0] = "Automatic";
54
+ PHVideoRequestOptionsDeliveryMode[PHVideoRequestOptionsDeliveryMode["HighQualityFormat"] = 1] = "HighQualityFormat";
55
+ PHVideoRequestOptionsDeliveryMode[PHVideoRequestOptionsDeliveryMode["MediumQualityFormat"] = 2] = "MediumQualityFormat";
56
+ PHVideoRequestOptionsDeliveryMode[PHVideoRequestOptionsDeliveryMode["FastFormat"] = 3] = "FastFormat";
57
+ })(PHVideoRequestOptionsDeliveryMode || (PHVideoRequestOptionsDeliveryMode = {}));
58
+ export var AVFileType;
59
+ (function (AVFileType) {
60
+ AVFileType["ac3"] = "public.ac3-audio";
61
+ AVFileType["aifc"] = "public.aifc-audio";
62
+ AVFileType["aiff"] = "public.aiff-audio";
63
+ AVFileType["AHAP"] = "com.apple.itt";
64
+ AVFileType["amr"] = "org.3gpp.adaptive-multi-rate-audio";
65
+ AVFileType["appleiTT"] = "com.apple.itt";
66
+ AVFileType["au"] = "public.au-audio";
67
+ AVFileType["avci"] = "public.avci";
68
+ AVFileType["caf"] = "com.apple.coreaudio-format";
69
+ AVFileType["dng"] = "com.adobe.raw-image";
70
+ AVFileType["eac3"] = "public.eac3-audio";
71
+ AVFileType["heic"] = "public.heic";
72
+ AVFileType["heif"] = "public.heif";
73
+ AVFileType["jpg"] = "public.jpeg";
74
+ AVFileType["m4a"] = "com.apple.m4a-audio";
75
+ AVFileType["m4v"] = "com.apple.m4v-video";
76
+ AVFileType["mobile3GPP"] = "public.3gpp";
77
+ AVFileType["mobile3GPP2"] = "public.3gpp2";
78
+ AVFileType["mov"] = "com.apple.quicktime-movie";
79
+ AVFileType["mp3"] = "public.mp3";
80
+ AVFileType["mp4"] = "public.mpeg-4";
81
+ AVFileType["SCC"] = "com.scenarist.cc";
82
+ AVFileType["tif"] = "public.tiff";
83
+ AVFileType["wav"] = "com.microsoft.waveform-audio";
84
+ })(AVFileType || (AVFileType = {}));
85
+ export var AVAssetExportPreset;
86
+ (function (AVAssetExportPreset) {
87
+ AVAssetExportPreset["LowQuality"] = "AVAssetExportPresetLowQuality";
88
+ AVAssetExportPreset["MediumQuality"] = "AVAssetExportPresetMediumQuality";
89
+ AVAssetExportPreset["HighestQuality"] = "AVAssetExportPresetHighestQuality";
90
+ AVAssetExportPreset["HEVCHighestQuality"] = "AVAssetExportPresetHEVCHighestQuality";
91
+ AVAssetExportPreset["HEVCHighestQualityWithAlpha"] = "AVAssetExportPresetHEVCHighestQualityWithAlpha";
92
+ AVAssetExportPreset["AVC640x480"] = "AVAssetExportPreset640x480";
93
+ AVAssetExportPreset["AVC960x540"] = "AVAssetExportPreset960x540";
94
+ AVAssetExportPreset["AVC1280x720"] = "AVAssetExportPreset1280x720";
95
+ AVAssetExportPreset["AVC1920x1080"] = "AVAssetExportPreset1920x1080";
96
+ AVAssetExportPreset["AVC3840x2160"] = "AVAssetExportPreset3840x2160";
97
+ AVAssetExportPreset["HEVC1920x1080"] = "AVAssetExportPresetHEVC1920x1080";
98
+ AVAssetExportPreset["HEVC3840x2160"] = "AVAssetExportPresetHEVC3840x2160";
99
+ AVAssetExportPreset["HEVC1920x1080WithAlpha"] = "AVAssetExportPresetHEVC1920x1080WithAlpha";
100
+ AVAssetExportPreset["HEVC3840x2160WithAlpha"] = "AVAssetExportPresetHEVC3840x2160WithAlpha";
101
+ AVAssetExportPreset["HEVC7680x4320"] = "AVAssetExportPresetHEVC7680x4320";
102
+ AVAssetExportPreset["MVHEVC960x960"] = "AVAssetExportPresetMVHEVC960x960";
103
+ AVAssetExportPreset["MVHEVC1440x1440"] = "AVAssetExportPresetMVHEVC1440x1440";
104
+ AVAssetExportPreset["AppleM4V480pSD"] = "AVAssetExportPresetAppleM4V480pSD";
105
+ AVAssetExportPreset["AppleM4V720pHD"] = "AVAssetExportPresetAppleM4V720pHD";
106
+ AVAssetExportPreset["AppleM4V1080pHD"] = "AVAssetExportPresetAppleM4V1080pHD";
107
+ AVAssetExportPreset["AppleM4ViPod"] = "AVAssetExportPresetAppleM4ViPod";
108
+ AVAssetExportPreset["AppleM4VAppleTV"] = "AVAssetExportPresetAppleM4VAppleTV";
109
+ AVAssetExportPreset["AppleM4VCellular"] = "AVAssetExportPresetAppleM4VCellular";
110
+ AVAssetExportPreset["AppleM4VWiFi"] = "AVAssetExportPresetAppleM4VWiFi";
111
+ AVAssetExportPreset["AppleProRes422LPCM"] = "AVAssetExportPresetAppleProRes422LPCM";
112
+ AVAssetExportPreset["AppleProRes4444LPCM"] = "AVAssetExportPresetAppleProRes4444LPCM";
113
+ AVAssetExportPreset["Passthrough"] = "AVAssetExportPresetPassthrough";
114
+ AVAssetExportPreset["AppleM4A"] = "AVAssetExportPresetAppleM4A";
115
+ })(AVAssetExportPreset || (AVAssetExportPreset = {}));
116
+ export var PHPickerFilter;
117
+ (function (PHPickerFilter) {
118
+ PHPickerFilter["images"] = "images";
119
+ PHPickerFilter["videos"] = "videos";
120
+ PHPickerFilter["any"] = "any";
121
+ })(PHPickerFilter || (PHPickerFilter = {}));
122
+ //# sourceMappingURL=ExpoPhotos.types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ExpoPhotos.types.js","sourceRoot":"","sources":["../src/ExpoPhotos.types.ts"],"names":[],"mappings":"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","sourcesContent":["export interface PHAsset {\n localIdentifier: string;\n creationDate: number;\n mediaType: PHAssetMediaType;\n mediaSubtypes: PHAssetMediaSubtype;\n duration: number;\n}\n\nexport enum PHAuthorizationStatus {\n notDetermined = 0,\n restricted = 1,\n denied = 2,\n authorized = 3,\n limited = 4,\n}\n\nexport enum PHAccessLevel {\n addOnly = 1,\n readWrite = 2,\n}\n\nexport enum PHAssetMediaType {\n Unknown = 0,\n Image = 1,\n Video = 2,\n Audio = 3,\n}\n\nexport enum PHAssetMediaSubtype {\n None = 0,\n PhotoPanorama = 1 << 0,\n PhotoHDR = 1 << 1,\n PhotoScreenshot = 1 << 2,\n PhotoLive = 1 << 3,\n PhotoDepthEffect = 1 << 4,\n VideoStreamed = 1 << 16,\n VideoHighFrameRate = 1 << 17,\n VideoTimelapse = 1 << 18,\n VideoCinematic = 1 << 19,\n}\n\nexport interface NSSortDescriptor {\n key: string;\n ascending: boolean;\n}\n\nexport interface PHFetchOptions {\n predicate?: string;\n fetchLimit?: number;\n sortDescriptors?: NSSortDescriptor[];\n}\n\nexport type FetchAssetsOptions = PHFetchOptions;\n\nexport interface CGSize {\n width: number;\n height: number;\n}\n\nexport enum PHImageRequestOptionsResizeMode {\n None = 0,\n Fast = 1,\n Exact = 2,\n}\n\nexport enum PHImageRequestOptionsDeliveryMode {\n Opportunistic = 0,\n HighQualityFormat = 1,\n FastFormat = 2,\n}\n\nexport enum PHImageContentMode {\n aspectFit = 0,\n aspectFill = 1,\n}\n\nexport interface PHImageRequestOptions {\n isNetworkAccessAllowed?: boolean;\n resizeMode?: PHImageRequestOptionsResizeMode;\n deliveryMode?: PHImageRequestOptionsDeliveryMode;\n}\n\nexport interface SDImageCoderOptions {\n encodeCompressionQuality?: number;\n encodeMaxFileSize?: number;\n}\n\nexport enum PHVideoRequestOptionsDeliveryMode {\n Automatic = 0,\n HighQualityFormat = 1,\n MediumQualityFormat = 2,\n FastFormat = 3,\n}\n\nexport interface PHVideoRequestOptions {\n isNetworkAccessAllowed?: boolean;\n deliveryMode?: PHVideoRequestOptionsDeliveryMode;\n}\n\nexport interface CMTimeRange {\n start: number;\n duration: number;\n}\n\nexport enum AVFileType {\n ac3 = \"public.ac3-audio\",\n aifc = \"public.aifc-audio\",\n aiff = \"public.aiff-audio\",\n AHAP = \"com.apple.itt\",\n amr = \"org.3gpp.adaptive-multi-rate-audio\",\n appleiTT = \"com.apple.itt\",\n au = \"public.au-audio\",\n avci = \"public.avci\",\n caf = \"com.apple.coreaudio-format\",\n dng = \"com.adobe.raw-image\",\n eac3 = \"public.eac3-audio\",\n heic = \"public.heic\",\n heif = \"public.heif\",\n jpg = \"public.jpeg\",\n m4a = \"com.apple.m4a-audio\",\n m4v = \"com.apple.m4v-video\",\n mobile3GPP = \"public.3gpp\",\n mobile3GPP2 = \"public.3gpp2\",\n mov = \"com.apple.quicktime-movie\",\n mp3 = \"public.mp3\",\n mp4 = \"public.mpeg-4\",\n SCC = \"com.scenarist.cc\",\n tif = \"public.tiff\",\n wav = \"com.microsoft.waveform-audio\",\n}\n\nexport enum AVAssetExportPreset {\n LowQuality = \"AVAssetExportPresetLowQuality\",\n MediumQuality = \"AVAssetExportPresetMediumQuality\",\n HighestQuality = \"AVAssetExportPresetHighestQuality\",\n HEVCHighestQuality = \"AVAssetExportPresetHEVCHighestQuality\",\n HEVCHighestQualityWithAlpha = \"AVAssetExportPresetHEVCHighestQualityWithAlpha\",\n AVC640x480 = \"AVAssetExportPreset640x480\",\n AVC960x540 = \"AVAssetExportPreset960x540\",\n AVC1280x720 = \"AVAssetExportPreset1280x720\",\n AVC1920x1080 = \"AVAssetExportPreset1920x1080\",\n AVC3840x2160 = \"AVAssetExportPreset3840x2160\",\n HEVC1920x1080 = \"AVAssetExportPresetHEVC1920x1080\",\n HEVC3840x2160 = \"AVAssetExportPresetHEVC3840x2160\",\n HEVC1920x1080WithAlpha = \"AVAssetExportPresetHEVC1920x1080WithAlpha\",\n HEVC3840x2160WithAlpha = \"AVAssetExportPresetHEVC3840x2160WithAlpha\",\n HEVC7680x4320 = \"AVAssetExportPresetHEVC7680x4320\",\n MVHEVC960x960 = \"AVAssetExportPresetMVHEVC960x960\",\n MVHEVC1440x1440 = \"AVAssetExportPresetMVHEVC1440x1440\",\n AppleM4V480pSD = \"AVAssetExportPresetAppleM4V480pSD\",\n AppleM4V720pHD = \"AVAssetExportPresetAppleM4V720pHD\",\n AppleM4V1080pHD = \"AVAssetExportPresetAppleM4V1080pHD\",\n AppleM4ViPod = \"AVAssetExportPresetAppleM4ViPod\",\n AppleM4VAppleTV = \"AVAssetExportPresetAppleM4VAppleTV\",\n AppleM4VCellular = \"AVAssetExportPresetAppleM4VCellular\",\n AppleM4VWiFi = \"AVAssetExportPresetAppleM4VWiFi\",\n AppleProRes422LPCM = \"AVAssetExportPresetAppleProRes422LPCM\",\n AppleProRes4444LPCM = \"AVAssetExportPresetAppleProRes4444LPCM\",\n Passthrough = \"AVAssetExportPresetPassthrough\",\n AppleM4A = \"AVAssetExportPresetAppleM4A\",\n}\n\nexport interface AVAssetExportSessionOptions {\n outputURL: string;\n outputFileType?: AVFileType;\n fileLengthLimit?: number;\n timeRange?: CMTimeRange;\n}\n\nexport interface RequestImageOptions\n extends PHImageRequestOptions,\n SDImageCoderOptions {\n localIdentifier: string;\n targetSize: CGSize;\n contentMode: PHImageContentMode;\n outputURL: string;\n timeout?: number;\n}\n\nexport interface RequestVideoOptions\n extends PHVideoRequestOptions,\n AVAssetExportSessionOptions {\n localIdentifier: string;\n exportPreset: AVAssetExportPreset;\n timeout?: number;\n}\n\nexport enum PHPickerFilter {\n images = \"images\",\n videos = \"videos\",\n any = \"any\",\n}\n\nexport interface PickAssetsOptions {\n filter?: PHPickerFilter;\n selectionLimit?: number;\n}\n"]}
@@ -0,0 +1,13 @@
1
+ import { NativeModule } from "expo-modules-core";
2
+ import type { FetchAssetsOptions, PHAuthorizationStatus, PHAccessLevel, PHAsset, PickAssetsOptions, RequestImageOptions, RequestVideoOptions } from "./ExpoPhotos.types";
3
+ export declare class ExpoPhotosModule extends NativeModule {
4
+ fetchAssets(options: FetchAssetsOptions): Promise<PHAsset[]>;
5
+ requestImage(options: RequestImageOptions): Promise<void>;
6
+ requestVideo(options: RequestVideoOptions): Promise<void>;
7
+ pickAssets(options: PickAssetsOptions): Promise<PHAsset[]>;
8
+ requestAuthorization(accessLevel: PHAccessLevel): Promise<PHAuthorizationStatus>;
9
+ presentLimitedLibraryPicker(): Promise<void>;
10
+ }
11
+ declare const _default: ExpoPhotosModule;
12
+ export default _default;
13
+ //# sourceMappingURL=ExpoPhotosModule.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ExpoPhotosModule.d.ts","sourceRoot":"","sources":["../src/ExpoPhotosModule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAuB,MAAM,mBAAmB,CAAC;AACtE,OAAO,KAAK,EACV,kBAAkB,EAClB,qBAAqB,EACrB,aAAa,EACb,OAAO,EACP,iBAAiB,EACjB,mBAAmB,EACnB,mBAAmB,EACpB,MAAM,oBAAoB,CAAC;AAE5B,MAAM,CAAC,OAAO,OAAO,gBAAiB,SAAQ,YAAY;IACxD,WAAW,CAAC,OAAO,EAAE,kBAAkB,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC;IAC5D,YAAY,CAAC,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC;IACzD,YAAY,CAAC,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC;IACzD,UAAU,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC;IAC1D,oBAAoB,CAAC,WAAW,EAAE,aAAa,GAAG,OAAO,CAAC,qBAAqB,CAAC;IAChF,2BAA2B,IAAI,OAAO,CAAC,IAAI,CAAC;CAC7C;;AAED,wBAAmE"}
@@ -0,0 +1,3 @@
1
+ import { requireNativeModule } from "expo-modules-core";
2
+ export default requireNativeModule("ExpoPhotos");
3
+ //# sourceMappingURL=ExpoPhotosModule.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ExpoPhotosModule.js","sourceRoot":"","sources":["../src/ExpoPhotosModule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAoBtE,eAAe,mBAAmB,CAAmB,YAAY,CAAC,CAAC","sourcesContent":["import { NativeModule, requireNativeModule } from \"expo-modules-core\";\nimport type {\n FetchAssetsOptions,\n PHAuthorizationStatus,\n PHAccessLevel,\n PHAsset,\n PickAssetsOptions,\n RequestImageOptions,\n RequestVideoOptions,\n} from \"./ExpoPhotos.types\";\n\nexport declare class ExpoPhotosModule extends NativeModule {\n fetchAssets(options: FetchAssetsOptions): Promise<PHAsset[]>;\n requestImage(options: RequestImageOptions): Promise<void>;\n requestVideo(options: RequestVideoOptions): Promise<void>;\n pickAssets(options: PickAssetsOptions): Promise<PHAsset[]>;\n requestAuthorization(accessLevel: PHAccessLevel): Promise<PHAuthorizationStatus>;\n presentLimitedLibraryPicker(): Promise<void>;\n}\n\nexport default requireNativeModule<ExpoPhotosModule>(\"ExpoPhotos\");\n"]}
@@ -0,0 +1,3 @@
1
+ export { default } from "./ExpoPhotosModule";
2
+ export * from "./ExpoPhotos.types";
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAC7C,cAAc,oBAAoB,CAAC"}
package/build/index.js ADDED
@@ -0,0 +1,3 @@
1
+ export { default } from "./ExpoPhotosModule";
2
+ export * from "./ExpoPhotos.types";
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAC7C,cAAc,oBAAoB,CAAC","sourcesContent":["export { default } from \"./ExpoPhotosModule\";\nexport * from \"./ExpoPhotos.types\";\n"]}
@@ -0,0 +1,11 @@
1
+ const { defineConfig } = require('eslint/config');
2
+ const baseConfig = require('expo-module-scripts/eslint.config.base');
3
+
4
+ const normalizedBaseConfig = Array.isArray(baseConfig) ? baseConfig : [baseConfig];
5
+
6
+ module.exports = defineConfig([
7
+ {
8
+ ignores: ['build'],
9
+ },
10
+ ...normalizedBaseConfig,
11
+ ]);
@@ -0,0 +1,7 @@
1
+ {
2
+ "platforms": ["apple"],
3
+ "apple": {
4
+ "modules": ["ExpoPhotos"],
5
+ "podspecPath": "ExpoPhotos.podspec"
6
+ }
7
+ }
@@ -0,0 +1,443 @@
1
+ import ExpoModulesCore
2
+ import Foundation
3
+ import Photos
4
+ import PhotosUI
5
+ import SDWebImageWebPCoder
6
+ import UIKit
7
+
8
+ struct FetchAssetsOptions: Record {
9
+ @Field var predicate: NSPredicate?
10
+ @Field var fetchLimit: Int?
11
+ @Field var sortDescriptors: [NSSortDescriptor]?
12
+ }
13
+
14
+ struct RequestImageOptions: Record {
15
+ @Field var localIdentifier: String?
16
+ @Field var targetSize: CGSize?
17
+ @Field var contentMode: PHImageContentMode?
18
+ @Field var isNetworkAccessAllowed: Bool?
19
+ @Field var deliveryMode: PHImageRequestOptionsDeliveryMode?
20
+ @Field var resizeMode: PHImageRequestOptionsResizeMode?
21
+ @Field var outputURL: URL?
22
+ @Field var encodeCompressionQuality: Double?
23
+ @Field var encodeMaxFileSize: Int?
24
+ @Field var timeout: TimeInterval?
25
+ }
26
+
27
+ protocol AVAssetExportSessionOptions {
28
+ var outputURL: URL? { get }
29
+ var outputFileType: AVFileType? { get }
30
+ var fileLengthLimit: Int64? { get }
31
+ var timeRange: CMTimeRange? { get }
32
+ }
33
+
34
+ struct RequestVideoOptions: Record, AVAssetExportSessionOptions {
35
+ @Field var localIdentifier: String?
36
+ @Field var isNetworkAccessAllowed: Bool?
37
+ @Field var deliveryMode: PHVideoRequestOptionsDeliveryMode?
38
+ @Field var exportPreset: String?
39
+ @Field var outputURL: URL?
40
+ @Field var outputFileType: AVFileType?
41
+ @Field var fileLengthLimit: Int64?
42
+ @Field var timeRange: CMTimeRange?
43
+ @Field var timeout: TimeInterval?
44
+ }
45
+
46
+ struct PickAssetsOptions: Record {
47
+ @Field var filter: PHPickerFilter?
48
+ @Field var selectionLimit: Int?
49
+ }
50
+
51
+ enum ExpoPhotosError: Error {
52
+ case mandatoryFieldMissing
53
+ case couldNotFindAsset
54
+ case couldNotEncodeImage
55
+ case couldNotCreateExportSession
56
+ case noViewController
57
+ case unknown
58
+ }
59
+
60
+ public class ExpoPhotos: Module {
61
+ private var pickAssetsContinuations = [
62
+ ObjectIdentifier: CheckedContinuation<[[String: Any]], Error>
63
+ ]()
64
+
65
+ public func definition() -> ModuleDefinition {
66
+ Name("ExpoPhotos")
67
+
68
+ AsyncFunction("fetchAssets") { (options: FetchAssetsOptions) -> [[String: Any]] in
69
+ let fetchOptions = PHFetchOptions()
70
+
71
+ if let predicate = options.predicate {
72
+ fetchOptions.predicate = predicate
73
+ }
74
+
75
+ if let fetchLimit = options.fetchLimit {
76
+ fetchOptions.fetchLimit = fetchLimit
77
+ }
78
+
79
+ if let sortDescriptors = options.sortDescriptors {
80
+ fetchOptions.sortDescriptors = sortDescriptors
81
+ }
82
+
83
+ var assets: [[String: Any]] = []
84
+ PHAsset.fetchAssets(with: fetchOptions).enumerateObjects { asset, _, _ in
85
+ assets.append(asset.toJS())
86
+ }
87
+ return assets
88
+ }
89
+
90
+ AsyncFunction("requestAuthorization") { (accessLevel: PHAccessLevel) async throws -> Int in
91
+ let status = await PHPhotoLibrary.requestAuthorization(for: accessLevel)
92
+ return status.rawValue
93
+ }
94
+
95
+ AsyncFunction("requestImage") { (options: RequestImageOptions) async throws -> Void in
96
+ guard
97
+ let localIdentifier = options.localIdentifier,
98
+ let targetSize = options.targetSize,
99
+ let contentMode = options.contentMode,
100
+ let outputURL = options.outputURL
101
+ else {
102
+ throw ExpoPhotosError.mandatoryFieldMissing
103
+ }
104
+
105
+ guard let asset = PHAsset.fetchAsset(withLocalIdentifier: localIdentifier) else {
106
+ throw ExpoPhotosError.couldNotFindAsset
107
+ }
108
+
109
+ let imageRequestOptions = PHImageRequestOptions()
110
+
111
+ if let isNetworkAccessAllowed = options.isNetworkAccessAllowed {
112
+ imageRequestOptions.isNetworkAccessAllowed = isNetworkAccessAllowed
113
+ }
114
+
115
+ if let deliveryMode = options.deliveryMode {
116
+ imageRequestOptions.deliveryMode = deliveryMode
117
+ }
118
+
119
+ if let resizeMode = options.resizeMode {
120
+ imageRequestOptions.resizeMode = resizeMode
121
+ }
122
+
123
+ let deadline = options.timeout.map { DispatchTime.now() + $0 }
124
+
125
+ let image = try await withCheckedThrowingContinuation {
126
+ (continuation: CheckedContinuation<UIImage, Error>) in
127
+ let requestId = PHImageManager.default().requestImage(
128
+ for: asset,
129
+ targetSize: targetSize,
130
+ contentMode: contentMode,
131
+ options: imageRequestOptions
132
+ ) { image, info in
133
+ guard let image = image else {
134
+ let error = info?[PHImageErrorKey] as? Error ?? ExpoPhotosError.unknown
135
+ continuation.resume(throwing: error)
136
+ return
137
+ }
138
+ continuation.resume(returning: image)
139
+ }
140
+
141
+ if let deadline = deadline {
142
+ DispatchQueue.global().asyncAfter(deadline: deadline) {
143
+ PHImageManager.default().cancelImageRequest(requestId)
144
+ }
145
+ }
146
+ }
147
+
148
+ var imageCoderOptions: [SDImageCoderOption: Any] = [:]
149
+
150
+ if let encodeCompressionQuality = options.encodeCompressionQuality {
151
+ imageCoderOptions[.encodeCompressionQuality] = encodeCompressionQuality
152
+ }
153
+
154
+ if let encodeMaxFileSize = options.encodeMaxFileSize {
155
+ imageCoderOptions[.encodeMaxFileSize] = encodeMaxFileSize
156
+ }
157
+
158
+ guard
159
+ let data = SDImageWebPCoder.shared.encodedData(
160
+ with: image, format: .webP, options: imageCoderOptions)
161
+ else {
162
+ throw ExpoPhotosError.couldNotEncodeImage
163
+ }
164
+
165
+ try data.write(to: outputURL)
166
+ }
167
+
168
+ AsyncFunction("requestVideo") { (options: RequestVideoOptions) async throws -> Void in
169
+ guard
170
+ let localIdentifier = options.localIdentifier,
171
+ let exportPreset = options.exportPreset,
172
+ options.outputURL != nil
173
+ else {
174
+ throw ExpoPhotosError.mandatoryFieldMissing
175
+ }
176
+
177
+ guard let asset = PHAsset.fetchAsset(withLocalIdentifier: localIdentifier) else {
178
+ throw ExpoPhotosError.couldNotFindAsset
179
+ }
180
+
181
+ let videoRequestOptions = PHVideoRequestOptions()
182
+
183
+ if let isNetworkAccessAllowed = options.isNetworkAccessAllowed {
184
+ videoRequestOptions.isNetworkAccessAllowed = isNetworkAccessAllowed
185
+ }
186
+
187
+ if let deliveryMode = options.deliveryMode {
188
+ videoRequestOptions.deliveryMode = deliveryMode
189
+ }
190
+
191
+ let deadline = options.timeout.map { DispatchTime.now() + $0 }
192
+
193
+ let exportSession = try await withCheckedThrowingContinuation {
194
+ (continuation: CheckedContinuation<AVAssetExportSession, Error>) in
195
+ let requestId = PHImageManager.default().requestExportSession(
196
+ forVideo: asset,
197
+ options: videoRequestOptions,
198
+ exportPreset: exportPreset
199
+ ) { exportSession, info in
200
+ guard let exportSession = exportSession else {
201
+ let error = info?[PHImageErrorKey] as? Error ?? ExpoPhotosError.unknown
202
+ continuation.resume(throwing: error)
203
+ return
204
+ }
205
+ continuation.resume(returning: exportSession)
206
+ }
207
+
208
+ if let deadline = deadline {
209
+ DispatchQueue.global().asyncAfter(deadline: deadline) {
210
+ PHImageManager.default().cancelImageRequest(requestId)
211
+ }
212
+ }
213
+ }
214
+
215
+ if let outputURL = options.outputURL {
216
+ exportSession.outputURL = outputURL
217
+ }
218
+
219
+ if let outputFileType = options.outputFileType {
220
+ exportSession.outputFileType = outputFileType
221
+ }
222
+
223
+ if let fileLengthLimit = options.fileLengthLimit {
224
+ exportSession.fileLengthLimit = fileLengthLimit
225
+ }
226
+
227
+ if let timeRange = options.timeRange {
228
+ exportSession.timeRange = timeRange
229
+ }
230
+
231
+ try await withCheckedThrowingContinuation {
232
+ (continuation: CheckedContinuation<Void, Error>) in
233
+ exportSession.exportAsynchronously {
234
+ switch exportSession.status {
235
+ case .completed:
236
+ continuation.resume()
237
+ default:
238
+ let error = exportSession.error ?? ExpoPhotosError.unknown
239
+ continuation.resume(throwing: error)
240
+ }
241
+ }
242
+
243
+ if let deadline = deadline {
244
+ DispatchQueue.global().asyncAfter(deadline: deadline) {
245
+ exportSession.cancelExport()
246
+ }
247
+ }
248
+ }
249
+ }
250
+
251
+ AsyncFunction("presentLimitedLibraryPicker") { () async throws -> Void in
252
+ guard let viewController = self.appContext?.utilities?.currentViewController() else {
253
+ throw ExpoPhotosError.noViewController
254
+ }
255
+
256
+ await PHPhotoLibrary.shared().presentLimitedLibraryPicker(from: viewController)
257
+ }
258
+
259
+ AsyncFunction("pickAssets") { (options: PickAssetsOptions) async throws -> [[String: Any]] in
260
+ guard let viewController = self.appContext?.utilities?.currentViewController() else {
261
+ throw ExpoPhotosError.noViewController
262
+ }
263
+
264
+ let picker: PHPickerViewController = await MainActor.run {
265
+ var config = PHPickerConfiguration(photoLibrary: .shared())
266
+
267
+ if let selectionLimit = options.selectionLimit {
268
+ config.selectionLimit = selectionLimit
269
+ }
270
+
271
+ if let filter = options.filter {
272
+ config.filter = filter
273
+ }
274
+
275
+ let picker = PHPickerViewController(configuration: config)
276
+ picker.delegate = self
277
+
278
+ return picker
279
+ }
280
+
281
+ return try await withCheckedThrowingContinuation {
282
+ (continuation: CheckedContinuation<[[String: Any]], Error>) in
283
+ self.pickAssetsContinuations[picker.id] = continuation
284
+
285
+ Task {
286
+ await viewController.present(picker, animated: true, completion: nil)
287
+ }
288
+ }
289
+ }
290
+ }
291
+ }
292
+
293
+ extension ExpoPhotos: PHPickerViewControllerDelegate {
294
+ public func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
295
+ picker.dismiss(animated: true, completion: nil)
296
+
297
+ guard let continuation = self.pickAssetsContinuations[picker.id] else {
298
+ return
299
+ }
300
+
301
+ self.pickAssetsContinuations.removeValue(forKey: picker.id)
302
+
303
+ let assetIdentifiers = results.compactMap { $0.assetIdentifier }
304
+ var assets: [[String: Any]] = []
305
+ PHAsset.fetchAssets(withLocalIdentifiers: assetIdentifiers, options: nil).enumerateObjects {
306
+ asset, _, _ in
307
+ assets.append(asset.toJS())
308
+ }
309
+
310
+ continuation.resume(returning: assets)
311
+ }
312
+ }
313
+
314
+ extension PHPickerViewController {
315
+ var id: ObjectIdentifier {
316
+ return ObjectIdentifier(self)
317
+ }
318
+ }
319
+
320
+ extension TimeInterval: @retroactive Convertible {
321
+ public static func convert(from value: Any?, appContext: AppContext) throws -> Self {
322
+ guard let milliseconds = value as? Int else {
323
+ throw Conversions.ConvertingException<Self>(value)
324
+ }
325
+ return Double(milliseconds) / 1000
326
+ }
327
+
328
+ func toJS() -> Int {
329
+ return Int(self * 1000)
330
+ }
331
+ }
332
+
333
+ extension CMTime {
334
+ func toJS() -> Int {
335
+ return Int(self.seconds * 1000)
336
+ }
337
+ }
338
+
339
+ extension PHAsset {
340
+ public static func fetchAsset(withLocalIdentifier identifier: String) -> PHAsset? {
341
+ return PHAsset.fetchAssets(withLocalIdentifiers: [identifier], options: nil).firstObject
342
+ }
343
+
344
+ func toJS() -> [String: Any] {
345
+ return [
346
+ "localIdentifier": localIdentifier,
347
+ "creationDate": creationDate?.timeIntervalSince1970.toJS() ?? NSNull(),
348
+ "mediaType": mediaType.rawValue,
349
+ "mediaSubtypes": mediaSubtypes.rawValue,
350
+ "duration": duration.toJS(),
351
+ ]
352
+ }
353
+ }
354
+
355
+ extension NSSortDescriptor: @retroactive Convertible {
356
+ public static func convert(from value: Any?, appContext: AppContext) throws -> Self {
357
+ guard
358
+ let dict = value as? [String: Any],
359
+ let key = dict["key"] as? String,
360
+ let ascending = dict["ascending"] as? Bool
361
+ else {
362
+ throw Conversions.ConvertingException<NSSortDescriptor>(value)
363
+ }
364
+ return Self(key: key, ascending: ascending)
365
+ }
366
+ }
367
+
368
+ extension NSPredicate: @retroactive Convertible {
369
+ public static func convert(from value: Any?, appContext: AppContext) throws -> Self {
370
+ guard
371
+ let rawValue = value as? String,
372
+ let predicate = NSPredicate(format: rawValue) as? Self
373
+ else {
374
+ throw Conversions.ConvertingException<Self>(value)
375
+ }
376
+ return predicate
377
+ }
378
+ }
379
+
380
+ extension CMTimeRange: @retroactive Convertible {
381
+ public static func convert(from value: Any?, appContext: AppContext) throws -> Self {
382
+ guard let dict = value as? [String: Any],
383
+ let startMs = dict["start"] as? Int,
384
+ let durationMs = dict["duration"] as? Int
385
+ else {
386
+ throw Conversions.ConvertingException<CMTimeRange>(value)
387
+ }
388
+
389
+ return Self(
390
+ start: CMTimeMakeWithSeconds(Double(startMs) / 1000, preferredTimescale: 600),
391
+ duration: CMTimeMakeWithSeconds(Double(durationMs) / 1000, preferredTimescale: 600)
392
+ )
393
+ }
394
+ }
395
+
396
+ extension Convertible where Self: RawRepresentable, Self.RawValue == Int {
397
+ public static func convert(from value: Any?, appContext: AppContext) throws -> Self {
398
+ guard
399
+ let rawValue = value as? Int,
400
+ let enumValue = Self(rawValue: rawValue)
401
+ else {
402
+ throw Conversions.ConvertingException<Self>(value)
403
+ }
404
+ return enumValue
405
+ }
406
+ }
407
+
408
+ extension Convertible where Self: RawRepresentable, Self.RawValue == String {
409
+ public static func convert(from value: Any?, appContext: AppContext) throws -> Self {
410
+ guard
411
+ let rawValue = value as? String,
412
+ let enumValue = Self(rawValue: rawValue)
413
+ else {
414
+ throw Conversions.ConvertingException<Self>(value)
415
+ }
416
+ return enumValue
417
+ }
418
+ }
419
+
420
+ extension PHImageRequestOptionsDeliveryMode: @retroactive Convertible {}
421
+ extension PHImageRequestOptionsResizeMode: @retroactive Convertible {}
422
+ extension PHImageContentMode: @retroactive Convertible {}
423
+ extension PHVideoRequestOptionsDeliveryMode: @retroactive Convertible {}
424
+ extension AVFileType: @retroactive Convertible {}
425
+ extension PHAccessLevel: @retroactive Convertible {}
426
+
427
+ extension PHPickerFilter: @retroactive Convertible {
428
+ public static func convert(from value: Any?, appContext: AppContext) throws -> Self {
429
+ guard let rawValue = value as? String else {
430
+ throw Conversions.ConvertingException<Self>(value)
431
+ }
432
+ switch rawValue {
433
+ case "images":
434
+ return .images
435
+ case "videos":
436
+ return .videos
437
+ case "any":
438
+ return .any(of: [.images, .videos])
439
+ default:
440
+ throw Conversions.ConvertingException<Self>(value)
441
+ }
442
+ }
443
+ }
package/package.json ADDED
@@ -0,0 +1,43 @@
1
+ {
2
+ "name": "@hortemo/expo-photos",
3
+ "version": "1.0.0",
4
+ "description": "Expo module exposing advanced iOS Photos APIs.",
5
+ "main": "build/index.js",
6
+ "types": "build/index.d.ts",
7
+ "scripts": {
8
+ "build": "expo-module build",
9
+ "clean": "expo-module clean",
10
+ "lint": "expo-module lint",
11
+ "test": "./e2e/e2e.sh",
12
+ "prepare": "expo-module prepare",
13
+ "prepublishOnly": "expo-module prepublishOnly",
14
+ "expo-module": "expo-module"
15
+ },
16
+ "keywords": [
17
+ "react-native",
18
+ "expo",
19
+ "photos",
20
+ "ios",
21
+ "@hortemo/expo-photos"
22
+ ],
23
+ "repository": "https://github.com/hortemo/expo-photos",
24
+ "bugs": {
25
+ "url": "https://github.com/hortemo/expo-photos/issues"
26
+ },
27
+ "author": "Henrik Hortemo <henrikhortemo@icloud.com> (https://github.com/hortemo)",
28
+ "license": "MIT",
29
+ "homepage": "https://github.com/hortemo/expo-photos#readme",
30
+ "dependencies": {},
31
+ "devDependencies": {
32
+ "@types/react": "~19.1.0",
33
+ "eslint": "^9.24.0",
34
+ "expo": "^54.0.12",
35
+ "expo-module-scripts": "^5.0.7",
36
+ "react-native": "0.81.4"
37
+ },
38
+ "peerDependencies": {
39
+ "expo": "*",
40
+ "react": "*",
41
+ "react-native": "*"
42
+ }
43
+ }
@@ -0,0 +1,197 @@
1
+ export interface PHAsset {
2
+ localIdentifier: string;
3
+ creationDate: number;
4
+ mediaType: PHAssetMediaType;
5
+ mediaSubtypes: PHAssetMediaSubtype;
6
+ duration: number;
7
+ }
8
+
9
+ export enum PHAuthorizationStatus {
10
+ notDetermined = 0,
11
+ restricted = 1,
12
+ denied = 2,
13
+ authorized = 3,
14
+ limited = 4,
15
+ }
16
+
17
+ export enum PHAccessLevel {
18
+ addOnly = 1,
19
+ readWrite = 2,
20
+ }
21
+
22
+ export enum PHAssetMediaType {
23
+ Unknown = 0,
24
+ Image = 1,
25
+ Video = 2,
26
+ Audio = 3,
27
+ }
28
+
29
+ export enum PHAssetMediaSubtype {
30
+ None = 0,
31
+ PhotoPanorama = 1 << 0,
32
+ PhotoHDR = 1 << 1,
33
+ PhotoScreenshot = 1 << 2,
34
+ PhotoLive = 1 << 3,
35
+ PhotoDepthEffect = 1 << 4,
36
+ VideoStreamed = 1 << 16,
37
+ VideoHighFrameRate = 1 << 17,
38
+ VideoTimelapse = 1 << 18,
39
+ VideoCinematic = 1 << 19,
40
+ }
41
+
42
+ export interface NSSortDescriptor {
43
+ key: string;
44
+ ascending: boolean;
45
+ }
46
+
47
+ export interface PHFetchOptions {
48
+ predicate?: string;
49
+ fetchLimit?: number;
50
+ sortDescriptors?: NSSortDescriptor[];
51
+ }
52
+
53
+ export type FetchAssetsOptions = PHFetchOptions;
54
+
55
+ export interface CGSize {
56
+ width: number;
57
+ height: number;
58
+ }
59
+
60
+ export enum PHImageRequestOptionsResizeMode {
61
+ None = 0,
62
+ Fast = 1,
63
+ Exact = 2,
64
+ }
65
+
66
+ export enum PHImageRequestOptionsDeliveryMode {
67
+ Opportunistic = 0,
68
+ HighQualityFormat = 1,
69
+ FastFormat = 2,
70
+ }
71
+
72
+ export enum PHImageContentMode {
73
+ aspectFit = 0,
74
+ aspectFill = 1,
75
+ }
76
+
77
+ export interface PHImageRequestOptions {
78
+ isNetworkAccessAllowed?: boolean;
79
+ resizeMode?: PHImageRequestOptionsResizeMode;
80
+ deliveryMode?: PHImageRequestOptionsDeliveryMode;
81
+ }
82
+
83
+ export interface SDImageCoderOptions {
84
+ encodeCompressionQuality?: number;
85
+ encodeMaxFileSize?: number;
86
+ }
87
+
88
+ export enum PHVideoRequestOptionsDeliveryMode {
89
+ Automatic = 0,
90
+ HighQualityFormat = 1,
91
+ MediumQualityFormat = 2,
92
+ FastFormat = 3,
93
+ }
94
+
95
+ export interface PHVideoRequestOptions {
96
+ isNetworkAccessAllowed?: boolean;
97
+ deliveryMode?: PHVideoRequestOptionsDeliveryMode;
98
+ }
99
+
100
+ export interface CMTimeRange {
101
+ start: number;
102
+ duration: number;
103
+ }
104
+
105
+ export enum AVFileType {
106
+ ac3 = "public.ac3-audio",
107
+ aifc = "public.aifc-audio",
108
+ aiff = "public.aiff-audio",
109
+ AHAP = "com.apple.itt",
110
+ amr = "org.3gpp.adaptive-multi-rate-audio",
111
+ appleiTT = "com.apple.itt",
112
+ au = "public.au-audio",
113
+ avci = "public.avci",
114
+ caf = "com.apple.coreaudio-format",
115
+ dng = "com.adobe.raw-image",
116
+ eac3 = "public.eac3-audio",
117
+ heic = "public.heic",
118
+ heif = "public.heif",
119
+ jpg = "public.jpeg",
120
+ m4a = "com.apple.m4a-audio",
121
+ m4v = "com.apple.m4v-video",
122
+ mobile3GPP = "public.3gpp",
123
+ mobile3GPP2 = "public.3gpp2",
124
+ mov = "com.apple.quicktime-movie",
125
+ mp3 = "public.mp3",
126
+ mp4 = "public.mpeg-4",
127
+ SCC = "com.scenarist.cc",
128
+ tif = "public.tiff",
129
+ wav = "com.microsoft.waveform-audio",
130
+ }
131
+
132
+ export enum AVAssetExportPreset {
133
+ LowQuality = "AVAssetExportPresetLowQuality",
134
+ MediumQuality = "AVAssetExportPresetMediumQuality",
135
+ HighestQuality = "AVAssetExportPresetHighestQuality",
136
+ HEVCHighestQuality = "AVAssetExportPresetHEVCHighestQuality",
137
+ HEVCHighestQualityWithAlpha = "AVAssetExportPresetHEVCHighestQualityWithAlpha",
138
+ AVC640x480 = "AVAssetExportPreset640x480",
139
+ AVC960x540 = "AVAssetExportPreset960x540",
140
+ AVC1280x720 = "AVAssetExportPreset1280x720",
141
+ AVC1920x1080 = "AVAssetExportPreset1920x1080",
142
+ AVC3840x2160 = "AVAssetExportPreset3840x2160",
143
+ HEVC1920x1080 = "AVAssetExportPresetHEVC1920x1080",
144
+ HEVC3840x2160 = "AVAssetExportPresetHEVC3840x2160",
145
+ HEVC1920x1080WithAlpha = "AVAssetExportPresetHEVC1920x1080WithAlpha",
146
+ HEVC3840x2160WithAlpha = "AVAssetExportPresetHEVC3840x2160WithAlpha",
147
+ HEVC7680x4320 = "AVAssetExportPresetHEVC7680x4320",
148
+ MVHEVC960x960 = "AVAssetExportPresetMVHEVC960x960",
149
+ MVHEVC1440x1440 = "AVAssetExportPresetMVHEVC1440x1440",
150
+ AppleM4V480pSD = "AVAssetExportPresetAppleM4V480pSD",
151
+ AppleM4V720pHD = "AVAssetExportPresetAppleM4V720pHD",
152
+ AppleM4V1080pHD = "AVAssetExportPresetAppleM4V1080pHD",
153
+ AppleM4ViPod = "AVAssetExportPresetAppleM4ViPod",
154
+ AppleM4VAppleTV = "AVAssetExportPresetAppleM4VAppleTV",
155
+ AppleM4VCellular = "AVAssetExportPresetAppleM4VCellular",
156
+ AppleM4VWiFi = "AVAssetExportPresetAppleM4VWiFi",
157
+ AppleProRes422LPCM = "AVAssetExportPresetAppleProRes422LPCM",
158
+ AppleProRes4444LPCM = "AVAssetExportPresetAppleProRes4444LPCM",
159
+ Passthrough = "AVAssetExportPresetPassthrough",
160
+ AppleM4A = "AVAssetExportPresetAppleM4A",
161
+ }
162
+
163
+ export interface AVAssetExportSessionOptions {
164
+ outputURL: string;
165
+ outputFileType?: AVFileType;
166
+ fileLengthLimit?: number;
167
+ timeRange?: CMTimeRange;
168
+ }
169
+
170
+ export interface RequestImageOptions
171
+ extends PHImageRequestOptions,
172
+ SDImageCoderOptions {
173
+ localIdentifier: string;
174
+ targetSize: CGSize;
175
+ contentMode: PHImageContentMode;
176
+ outputURL: string;
177
+ timeout?: number;
178
+ }
179
+
180
+ export interface RequestVideoOptions
181
+ extends PHVideoRequestOptions,
182
+ AVAssetExportSessionOptions {
183
+ localIdentifier: string;
184
+ exportPreset: AVAssetExportPreset;
185
+ timeout?: number;
186
+ }
187
+
188
+ export enum PHPickerFilter {
189
+ images = "images",
190
+ videos = "videos",
191
+ any = "any",
192
+ }
193
+
194
+ export interface PickAssetsOptions {
195
+ filter?: PHPickerFilter;
196
+ selectionLimit?: number;
197
+ }
@@ -0,0 +1,21 @@
1
+ import { NativeModule, requireNativeModule } from "expo-modules-core";
2
+ import type {
3
+ FetchAssetsOptions,
4
+ PHAuthorizationStatus,
5
+ PHAccessLevel,
6
+ PHAsset,
7
+ PickAssetsOptions,
8
+ RequestImageOptions,
9
+ RequestVideoOptions,
10
+ } from "./ExpoPhotos.types";
11
+
12
+ export declare class ExpoPhotosModule extends NativeModule {
13
+ fetchAssets(options: FetchAssetsOptions): Promise<PHAsset[]>;
14
+ requestImage(options: RequestImageOptions): Promise<void>;
15
+ requestVideo(options: RequestVideoOptions): Promise<void>;
16
+ pickAssets(options: PickAssetsOptions): Promise<PHAsset[]>;
17
+ requestAuthorization(accessLevel: PHAccessLevel): Promise<PHAuthorizationStatus>;
18
+ presentLimitedLibraryPicker(): Promise<void>;
19
+ }
20
+
21
+ export default requireNativeModule<ExpoPhotosModule>("ExpoPhotos");
package/src/index.ts ADDED
@@ -0,0 +1,2 @@
1
+ export { default } from "./ExpoPhotosModule";
2
+ export * from "./ExpoPhotos.types";
package/tsconfig.json ADDED
@@ -0,0 +1,9 @@
1
+ // @generated by expo-module-scripts
2
+ {
3
+ "extends": "expo-module-scripts/tsconfig.base",
4
+ "compilerOptions": {
5
+ "outDir": "./build"
6
+ },
7
+ "include": ["./src"],
8
+ "exclude": ["**/__mocks__/*", "**/__tests__/*", "**/__rsc_tests__/*"]
9
+ }