feat(iOS): Add subTypes field (#495)

Allow to know PHAssetMediaSubtype on iOS.
So for example if a node is a LivePhoto or a Panorama.
This commit is contained in:
Théo Poizat
2023-05-31 09:33:11 +02:00
committed by GitHub
parent 08ba91db78
commit 1f6499be0a
7 changed files with 59 additions and 0 deletions
+1
View File
@@ -113,6 +113,7 @@ export default class CameraRollExample extends React.Component<Props, State> {
<Text>{asset.node.group_name}</Text>
<Text>{new Date(asset.node.timestamp * 1000).toString()}</Text>
<Text>{new Date(asset.node.modificationTimestamp * 1000).toString()}</Text>
<Text>Subtypes: {asset.node.subTypes.join(' ')}</Text>
</View>
</View>
</TouchableOpacity>
+1
View File
@@ -248,6 +248,7 @@ Returns a Promise which when resolved will be of the following shape:
* `edges` : {Array<node>} An array of node objects
* `node`: {object} An object with the following shape:
* `type`: {string}
* `subTypes`: {Array<string>} : An array of subtype strings (see `SubTypes` type). Always [] on Android.
* `group_name`: {string}
* `image`: {object} : An object with the following shape:
* `uri`: {string}
@@ -40,6 +40,7 @@ import com.facebook.react.bridge.WritableArray;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.bridge.WritableNativeArray;
import com.facebook.react.bridge.WritableNativeMap;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.common.ReactConstants;
import com.facebook.react.module.annotations.ReactModule;
@@ -615,6 +616,8 @@ public class CameraRollModule extends NativeCameraRollModuleSpec {
int dateAddedIndex,
int dateModifiedIndex) {
node.putString("type", media.getString(mimeTypeIndex));
WritableArray subTypes = Arguments.createArray();
node.putArray("subTypes", subTypes);
node.putString("group_name", media.getString(groupNameIndex));
long dateTaken = media.getLong(dateTakenIndex);
if (dateTaken == 0L) {
+1
View File
@@ -113,6 +113,7 @@ export default class CameraRollExample extends React.Component<Props, State> {
<Text>{asset.node.group_name}</Text>
<Text>{new Date(asset.node.timestamp * 1000).toString()}</Text>
<Text>{new Date(asset.node.modificationTimestamp * 1000).toString()}</Text>
<Text>Subtypes: {asset.node.subTypes.join(' ')}</Text>
</View>
</View>
</TouchableOpacity>
+39
View File
@@ -422,6 +422,8 @@ RCT_EXPORT_METHOD(getPhotos:(NSDictionary *)params
? @"audio"
: @"unknown")));
NSArray<NSString*> *const assetMediaSubtypesLabel = [self mediaSubTypeLabelsForAsset:asset];
if (includeFileExtension) {
NSString *name = [asset valueForKey:@"filename"];
NSString *extension = [name pathExtension];
@@ -433,6 +435,7 @@ RCT_EXPORT_METHOD(getPhotos:(NSDictionary *)params
[assets addObject:@{
@"node": @{
@"type": assetMediaTypeLabel, // TODO: switch to mimeType?
@"subTypes":assetMediaSubtypesLabel,
@"group_name": currentCollectionName,
@"image": @{
@"uri": uri,
@@ -559,6 +562,8 @@ RCT_EXPORT_METHOD(getPhotoByInternalID:(NSString *)internalId
__block NSString *filePath = @"";
NSArray<NSString*> *const assetMediaSubtypesLabel = [self mediaSubTypeLabelsForAsset:asset];
// check if HEIC extension asset
if (convertHeic && asset.mediaType == PHAssetMediaTypeImage && [uniformMimeType isEqual: @"public.heic"]) {
// convert to JPEG
@@ -589,6 +594,7 @@ RCT_EXPORT_METHOD(getPhotoByInternalID:(NSString *)internalId
resolve(@{
@"node": @{
@"type": assetMediaTypeLabel,
@"subTypes":assetMediaSubtypesLabel,
@"image": @{
@"filepath": fullPath,
@"filename": originalFilename,
@@ -631,6 +637,7 @@ RCT_EXPORT_METHOD(getPhotoByInternalID:(NSString *)internalId
resolve(@{
@"node": @{
@"type": assetMediaTypeLabel,
@"subTypes":assetMediaSubtypesLabel,
@"image": @{
@"filepath": filePath,
@"filename": originalFilename,
@@ -670,6 +677,38 @@ RCT_EXPORT_METHOD(getPhotoByInternalID:(NSString *)internalId
}, false);
}
- (NSArray<NSString *> *) mediaSubTypeLabelsForAsset:(PHAsset *)asset {
PHAssetMediaSubtype subtype = asset.mediaSubtypes;
NSMutableArray<NSString*> *mediaSubTypeLabels = [NSMutableArray array];
if (subtype & PHAssetMediaSubtypePhotoPanorama) {
[mediaSubTypeLabels addObject:@"PhotoPanorama"];
}
if (subtype & PHAssetMediaSubtypePhotoHDR) {
[mediaSubTypeLabels addObject:@"PhotoHDR"];
}
if (subtype & PHAssetMediaSubtypePhotoScreenshot) {
[mediaSubTypeLabels addObject:@"PhotoScreenshot"];
}
if (subtype & PHAssetMediaSubtypePhotoLive) {
[mediaSubTypeLabels addObject:@"PhotoLive"];
}
if (subtype & PHAssetMediaSubtypePhotoDepthEffect) {
[mediaSubTypeLabels addObject:@"PhotoDepthEffect"];
}
if (subtype & PHAssetMediaSubtypeVideoStreamed) {
[mediaSubTypeLabels addObject:@"VideoStreamed"];
}
if (subtype & PHAssetMediaSubtypeVideoHighFrameRate) {
[mediaSubTypeLabels addObject:@"VideoHighFrameRate"];
}
if (subtype & PHAssetMediaSubtypeVideoTimelapse) {
[mediaSubTypeLabels addObject:@"VideoTimelapse"];
}
return mediaSubTypeLabels;
}
static void checkPhotoLibraryConfig()
{
#if RCT_DEV
+11
View File
@@ -32,6 +32,16 @@ export type GroupTypes =
| 'PhotoStream'
| 'SavedPhotos';
export type SubTypes =
| 'PhotoPanorama'
| 'PhotoHDR'
| 'PhotoScreenshot'
| 'PhotoLive'
| 'PhotoDepthEffect'
| 'VideoStreamed'
| 'VideoHighFrameRate'
| 'VideoTimelapse';
export type Include =
| 'filename'
| 'fileSize'
@@ -100,6 +110,7 @@ export type GetPhotosParams = {
export type PhotoIdentifier = {
node: {
type: string;
subTypes: SubTypes;
group_name: string;
image: {
filename: string | null;
+3
View File
@@ -3,6 +3,8 @@
// and we want to stay compatible with those
import {TurboModuleRegistry, TurboModule} from 'react-native';
import type {SubTypes} from './CameraRoll';
type Album = {
title: string;
count: number;
@@ -11,6 +13,7 @@ type Album = {
type PhotoIdentifier = {
node: {
type: string;
subTypes: SubTypes;
group_name: string;
image: {
filename: string | null;