better support for iOS 14
Co-Authored-by: Jean-François Puissant <jean-francois.puissant@fleetback.com>
This commit is contained in:
parent
8bb2ea468b
commit
337c5a515e
|
@ -241,6 +241,7 @@ Returns a Promise which when resolved will be of the following shape:
|
||||||
* `has_next_page`: {boolean}
|
* `has_next_page`: {boolean}
|
||||||
* `start_cursor`: {string}
|
* `start_cursor`: {string}
|
||||||
* `end_cursor`: {string}
|
* `end_cursor`: {string}
|
||||||
|
* `limited` : {boolean | undefined} : true if the app can only access a subset of the gallery pictures (authorization is `PHAuthorizationStatusLimited`), false otherwise (iOS only)
|
||||||
|
|
||||||
#### Example
|
#### Example
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,9 @@ const {
|
||||||
Platform,
|
Platform,
|
||||||
StyleSheet,
|
StyleSheet,
|
||||||
View,
|
View,
|
||||||
|
TouchableOpacity,
|
||||||
|
Text,
|
||||||
|
Linking,
|
||||||
} = ReactNative;
|
} = ReactNative;
|
||||||
|
|
||||||
import CameraRoll from '../../js/CameraRoll';
|
import CameraRoll from '../../js/CameraRoll';
|
||||||
|
@ -61,6 +64,7 @@ class CameraRollView extends React.Component {
|
||||||
lastCursor: null,
|
lastCursor: null,
|
||||||
noMore: false,
|
noMore: false,
|
||||||
loadingMore: false,
|
loadingMore: false,
|
||||||
|
isLimited: false,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -148,6 +152,16 @@ class CameraRollView extends React.Component {
|
||||||
if (!this.state.noMore) {
|
if (!this.state.noMore) {
|
||||||
return <ActivityIndicator />;
|
return <ActivityIndicator />;
|
||||||
}
|
}
|
||||||
|
if (this.state.isLimited) {
|
||||||
|
return (
|
||||||
|
<TouchableOpacity onPress={Linking.openSettings}>
|
||||||
|
<Text style={styles.footerText}>
|
||||||
|
Not all pictures are available. Tap here to go to Settings and
|
||||||
|
change which media the app is allowed to access.
|
||||||
|
</Text>
|
||||||
|
</TouchableOpacity>
|
||||||
|
);
|
||||||
|
}
|
||||||
return null;
|
return null;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -162,7 +176,7 @@ class CameraRollView extends React.Component {
|
||||||
|
|
||||||
_appendAssets(data) {
|
_appendAssets(data) {
|
||||||
const assets = data.edges;
|
const assets = data.edges;
|
||||||
const newState = {loadingMore: false};
|
const newState = {loadingMore: false, isLimited: data.limited};
|
||||||
|
|
||||||
if (!data.page_info.has_next_page) {
|
if (!data.page_info.has_next_page) {
|
||||||
newState.noMore = true;
|
newState.noMore = true;
|
||||||
|
@ -210,6 +224,10 @@ const styles = StyleSheet.create({
|
||||||
container: {
|
container: {
|
||||||
flex: 1,
|
flex: 1,
|
||||||
},
|
},
|
||||||
|
footerText: {
|
||||||
|
padding: 20,
|
||||||
|
textAlign: 'center',
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
module.exports = CameraRollView;
|
module.exports = CameraRollView;
|
||||||
|
|
|
@ -96,18 +96,35 @@ static NSString *const kErrorUnableToLoad = @"E_UNABLE_TO_LOAD";
|
||||||
static NSString *const kErrorAuthRestricted = @"E_PHOTO_LIBRARY_AUTH_RESTRICTED";
|
static NSString *const kErrorAuthRestricted = @"E_PHOTO_LIBRARY_AUTH_RESTRICTED";
|
||||||
static NSString *const kErrorAuthDenied = @"E_PHOTO_LIBRARY_AUTH_DENIED";
|
static NSString *const kErrorAuthDenied = @"E_PHOTO_LIBRARY_AUTH_DENIED";
|
||||||
|
|
||||||
typedef void (^PhotosAuthorizedBlock)(void);
|
typedef void (^PhotosAuthorizedBlock)(bool isLimited);
|
||||||
|
|
||||||
static void requestPhotoLibraryAccess(RCTPromiseRejectBlock reject, PhotosAuthorizedBlock authorizedBlock) {
|
static void requestPhotoLibraryAccess(bool addOnly, RCTPromiseRejectBlock reject, PhotosAuthorizedBlock authorizedBlock) {
|
||||||
PHAuthorizationStatus authStatus = [PHPhotoLibrary authorizationStatus];
|
PHAuthorizationStatus authStatus;
|
||||||
|
if (@available(iOS 14, *)) {
|
||||||
|
authStatus = [PHPhotoLibrary authorizationStatusForAccessLevel:(addOnly ? PHAccessLevelAddOnly : PHAccessLevelReadWrite)];
|
||||||
|
} else {
|
||||||
|
authStatus = [PHPhotoLibrary authorizationStatus];
|
||||||
|
}
|
||||||
if (authStatus == PHAuthorizationStatusRestricted) {
|
if (authStatus == PHAuthorizationStatusRestricted) {
|
||||||
reject(kErrorAuthRestricted, @"Access to photo library is restricted", nil);
|
reject(kErrorAuthRestricted, @"Access to photo library is restricted", nil);
|
||||||
} else if (authStatus == PHAuthorizationStatusAuthorized) {
|
} else if (authStatus == PHAuthorizationStatusAuthorized) {
|
||||||
authorizedBlock();
|
authorizedBlock(false);
|
||||||
|
#pragma clang diagnostic push
|
||||||
|
#pragma clang diagnostic ignored "-Wunguarded-availability-new"
|
||||||
|
} else if (authStatus == PHAuthorizationStatusLimited) {
|
||||||
|
#pragma clang diagnostic pop
|
||||||
|
authorizedBlock(true);
|
||||||
} else if (authStatus == PHAuthorizationStatusNotDetermined) {
|
} else if (authStatus == PHAuthorizationStatusNotDetermined) {
|
||||||
[PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus status) {
|
if (@available(iOS 14, *)) {
|
||||||
requestPhotoLibraryAccess(reject, authorizedBlock);
|
[PHPhotoLibrary requestAuthorizationForAccessLevel:(addOnly ? PHAccessLevelAddOnly : PHAccessLevelReadWrite)
|
||||||
|
handler:^(PHAuthorizationStatus status) {
|
||||||
|
requestPhotoLibraryAccess(addOnly, reject, authorizedBlock);
|
||||||
}];
|
}];
|
||||||
|
} else {
|
||||||
|
[PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus status) {
|
||||||
|
requestPhotoLibraryAccess(addOnly, reject, authorizedBlock);
|
||||||
|
}];
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
reject(kErrorAuthDenied, @"Access to photo library was denied", nil);
|
reject(kErrorAuthDenied, @"Access to photo library was denied", nil);
|
||||||
}
|
}
|
||||||
|
@ -188,12 +205,12 @@ RCT_EXPORT_METHOD(saveToCameraRoll:(NSURLRequest *)request
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
void (^loadBlock)(void) = ^void() {
|
void (^loadBlock)(bool isLimited) = ^void(bool isLimited) {
|
||||||
inputURI = request.URL;
|
inputURI = request.URL;
|
||||||
saveWithOptions();
|
saveWithOptions();
|
||||||
};
|
};
|
||||||
|
|
||||||
requestPhotoLibraryAccess(reject, loadBlock);
|
requestPhotoLibraryAccess(true, reject, loadBlock);
|
||||||
}
|
}
|
||||||
|
|
||||||
RCT_EXPORT_METHOD(getAlbums:(NSDictionary *)params
|
RCT_EXPORT_METHOD(getAlbums:(NSDictionary *)params
|
||||||
|
@ -220,14 +237,16 @@ RCT_EXPORT_METHOD(getAlbums:(NSDictionary *)params
|
||||||
|
|
||||||
static void RCTResolvePromise(RCTPromiseResolveBlock resolve,
|
static void RCTResolvePromise(RCTPromiseResolveBlock resolve,
|
||||||
NSArray<NSDictionary<NSString *, id> *> *assets,
|
NSArray<NSDictionary<NSString *, id> *> *assets,
|
||||||
BOOL hasNextPage)
|
BOOL hasNextPage,
|
||||||
|
bool isLimited)
|
||||||
{
|
{
|
||||||
if (!assets.count) {
|
if (!assets.count) {
|
||||||
resolve(@{
|
resolve(@{
|
||||||
@"edges": assets,
|
@"edges": assets,
|
||||||
@"page_info": @{
|
@"page_info": @{
|
||||||
@"has_next_page": @NO,
|
@"has_next_page": @NO,
|
||||||
}
|
},
|
||||||
|
@"limited": @(isLimited)
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -237,7 +256,8 @@ static void RCTResolvePromise(RCTPromiseResolveBlock resolve,
|
||||||
@"start_cursor": assets[0][@"node"][@"image"][@"uri"],
|
@"start_cursor": assets[0][@"node"][@"image"][@"uri"],
|
||||||
@"end_cursor": assets[assets.count - 1][@"node"][@"image"][@"uri"],
|
@"end_cursor": assets[assets.count - 1][@"node"][@"image"][@"uri"],
|
||||||
@"has_next_page": @(hasNextPage),
|
@"has_next_page": @(hasNextPage),
|
||||||
}
|
},
|
||||||
|
@"limited": @(isLimited)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -301,7 +321,7 @@ RCT_EXPORT_METHOD(getPhotos:(NSDictionary *)params
|
||||||
BOOL __block stopCollections_;
|
BOOL __block stopCollections_;
|
||||||
NSString __block *currentCollectionName;
|
NSString __block *currentCollectionName;
|
||||||
|
|
||||||
requestPhotoLibraryAccess(reject, ^{
|
requestPhotoLibraryAccess(false, reject, ^(bool isLimited){
|
||||||
void (^collectAsset)(PHAsset*, NSUInteger, BOOL*) = ^(PHAsset * _Nonnull asset, NSUInteger assetIdx, BOOL * _Nonnull stopAssets) {
|
void (^collectAsset)(PHAsset*, NSUInteger, BOOL*) = ^(PHAsset * _Nonnull asset, NSUInteger assetIdx, BOOL * _Nonnull stopAssets) {
|
||||||
NSString *const uri = [NSString stringWithFormat:@"ph://%@", [asset localIdentifier]];
|
NSString *const uri = [NSString stringWithFormat:@"ph://%@", [asset localIdentifier]];
|
||||||
NSString *_Nullable originalFilename = NULL;
|
NSString *_Nullable originalFilename = NULL;
|
||||||
|
@ -354,7 +374,7 @@ RCT_EXPORT_METHOD(getPhotos:(NSDictionary *)params
|
||||||
stopCollections_ = YES;
|
stopCollections_ = YES;
|
||||||
hasNextPage = YES;
|
hasNextPage = YES;
|
||||||
RCTAssert(resolvedPromise == NO, @"Resolved the promise before we finished processing the results.");
|
RCTAssert(resolvedPromise == NO, @"Resolved the promise before we finished processing the results.");
|
||||||
RCTResolvePromise(resolve, assets, hasNextPage);
|
RCTResolvePromise(resolve, assets, hasNextPage, isLimited);
|
||||||
resolvedPromise = YES;
|
resolvedPromise = YES;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -412,7 +432,7 @@ RCT_EXPORT_METHOD(getPhotos:(NSDictionary *)params
|
||||||
// If we get this far and haven't resolved the promise yet, we reached the end of the list of photos
|
// If we get this far and haven't resolved the promise yet, we reached the end of the list of photos
|
||||||
if (!resolvedPromise) {
|
if (!resolvedPromise) {
|
||||||
hasNextPage = NO;
|
hasNextPage = NO;
|
||||||
RCTResolvePromise(resolve, assets, hasNextPage);
|
RCTResolvePromise(resolve, assets, hasNextPage, isLimited);
|
||||||
resolvedPromise = YES;
|
resolvedPromise = YES;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -122,7 +122,9 @@ export type PhotoIdentifiersPage = {
|
||||||
start_cursor?: string,
|
start_cursor?: string,
|
||||||
end_cursor?: string,
|
end_cursor?: string,
|
||||||
},
|
},
|
||||||
|
limited?: boolean,
|
||||||
};
|
};
|
||||||
|
|
||||||
export type SaveToCameraRollOptions = {
|
export type SaveToCameraRollOptions = {
|
||||||
type?: 'photo' | 'video' | 'auto',
|
type?: 'photo' | 'video' | 'auto',
|
||||||
album?: string,
|
album?: string,
|
||||||
|
|
Loading…
Reference in New Issue