From 3f61d09be252494e6d63bc677699ef479baba840 Mon Sep 17 00:00:00 2001 From: Santhosh Vaiyapuri Date: Wed, 8 Nov 2023 14:24:13 +0100 Subject: [PATCH] feat: support refreshing photo selection on iOS --- .../expo-package/src/handlers/getPhotos.ts | 5 ++-- .../handlers/iOS14RefreshGallerySelection.ts | 29 +++++++++++++++++++ .../native-package/src/handlers/getPhotos.ts | 3 +- .../handlers/iOS14RefreshGallerySelection.ts | 14 +++++++++ package/native-package/src/handlers/index.ts | 1 + package/native-package/src/index.js | 2 ++ .../AttachmentPicker/AttachmentPicker.tsx | 23 +++++++++++++-- package/src/i18n/en.json | 1 + package/src/i18n/fr.json | 1 + package/src/i18n/he.json | 1 + package/src/i18n/hi.json | 1 + package/src/i18n/it.json | 1 + package/src/i18n/ja.json | 1 + package/src/i18n/ko.json | 1 + package/src/i18n/nl.json | 1 + package/src/i18n/ru.json | 1 + package/src/i18n/tr.json | 1 + package/src/native.ts | 9 ++++++ 18 files changed, 91 insertions(+), 5 deletions(-) create mode 100644 package/expo-package/src/handlers/iOS14RefreshGallerySelection.ts create mode 100644 package/native-package/src/handlers/iOS14RefreshGallerySelection.ts diff --git a/package/expo-package/src/handlers/getPhotos.ts b/package/expo-package/src/handlers/getPhotos.ts index f0f65c3962..dc6cc41755 100644 --- a/package/expo-package/src/handlers/getPhotos.ts +++ b/package/expo-package/src/handlers/getPhotos.ts @@ -5,6 +5,7 @@ type ReturnType = { assets: Array & { source: 'picker' }>; endCursor: string | undefined; hasNextPage: boolean; + iOSLimited: boolean; }; export const getPhotos = async ({ @@ -16,7 +17,7 @@ export const getPhotos = async ({ // should always check first before requesting permission // because always requesting permission will cause // the app to go to background even if it was granted - const { status } = await MediaLibrary.getPermissionsAsync(); + const { accessPrivileges, status } = await MediaLibrary.getPermissionsAsync(); if (status !== 'granted') { const { status: newStatus } = await MediaLibrary.requestPermissionsAsync(); if (newStatus !== 'granted') { @@ -42,7 +43,7 @@ export const getPhotos = async ({ const hasNextPage = results.hasNextPage; const endCursor = results.endCursor; - return { assets, endCursor, hasNextPage }; + return { assets, endCursor, hasNextPage, iOSLimited: accessPrivileges === 'limited' }; } catch { throw new Error('getPhotos Error'); } diff --git a/package/expo-package/src/handlers/iOS14RefreshGallerySelection.ts b/package/expo-package/src/handlers/iOS14RefreshGallerySelection.ts new file mode 100644 index 0000000000..ce890b7d91 --- /dev/null +++ b/package/expo-package/src/handlers/iOS14RefreshGallerySelection.ts @@ -0,0 +1,29 @@ +import { Platform } from 'react-native'; + +import * as MediaLibrary from 'expo-media-library'; + +const isAboveIOS14 = Platform.OS === 'ios' && parseInt(Platform.Version as string, 10) >= 14; + +export function oniOS14GalleryLibrarySelectionChange(callback: () => void): { + unsubscribe: () => void; +} { + if (isAboveIOS14) { + const subscription = MediaLibrary.addListener(callback); + return { + unsubscribe: () => { + subscription.remove(); + }, + }; + } + return { + // eslint-disable-next-line @typescript-eslint/no-empty-function + unsubscribe: () => {}, + }; +} + +export const iOS14RefreshGallerySelection = (): Promise => { + if (isAboveIOS14) { + return MediaLibrary.presentPermissionsPickerAsync(); + } + return Promise.resolve(); +}; diff --git a/package/native-package/src/handlers/getPhotos.ts b/package/native-package/src/handlers/getPhotos.ts index a1b8bb43e3..e263200447 100644 --- a/package/native-package/src/handlers/getPhotos.ts +++ b/package/native-package/src/handlers/getPhotos.ts @@ -7,6 +7,7 @@ type ReturnType = { assets: Array & { source: 'picker' }>; endCursor: string | undefined; hasNextPage: boolean; + iOSLimited: boolean; }; const verifyAndroidPermissions = async () => { @@ -84,7 +85,7 @@ export const getPhotos = async ({ })); const hasNextPage = results.page_info.has_next_page; const endCursor = results.page_info.end_cursor; - return { assets, endCursor, hasNextPage }; + return { assets, endCursor, hasNextPage, iOSLimited: !!results.limited }; } catch (_error) { throw new Error('getPhotos Error'); } diff --git a/package/native-package/src/handlers/iOS14RefreshGallerySelection.ts b/package/native-package/src/handlers/iOS14RefreshGallerySelection.ts new file mode 100644 index 0000000000..7fc833fa47 --- /dev/null +++ b/package/native-package/src/handlers/iOS14RefreshGallerySelection.ts @@ -0,0 +1,14 @@ +import { Platform } from 'react-native'; + +import { iosRefreshGallerySelection } from '@react-native-camera-roll/camera-roll'; + +const isAboveIOS14 = Platform.OS === 'ios' && parseInt(Platform.Version as string, 10) >= 14; + +export const iOS14RefreshGallerySelection = (): Promise => { + if (isAboveIOS14) { + return iosRefreshGallerySelection().then(() => { + //do nothing + }); + } + return Promise.resolve(); +}; diff --git a/package/native-package/src/handlers/index.ts b/package/native-package/src/handlers/index.ts index b6a29d72c6..9c0e249db7 100644 --- a/package/native-package/src/handlers/index.ts +++ b/package/native-package/src/handlers/index.ts @@ -8,3 +8,4 @@ export * from './takePhoto'; export * from './Sound'; export * from './Video'; export * from './oniOS14GalleryLibrarySelectionChange'; +export * from './iOS14RefreshGallerySelection'; diff --git a/package/native-package/src/index.js b/package/native-package/src/index.js index e11e71d1cd..7187ae049f 100644 --- a/package/native-package/src/index.js +++ b/package/native-package/src/index.js @@ -8,6 +8,7 @@ import { deleteFile, getLocalAssetUri, getPhotos, + iOS14RefreshGallerySelection, NetInfo, oniOS14GalleryLibrarySelectionChange, saveFile, @@ -29,6 +30,7 @@ registerNativeHandlers({ FlatList, getLocalAssetUri, getPhotos, + iOS14RefreshGallerySelection, NetInfo, oniOS14GalleryLibrarySelectionChange, pickDocument, diff --git a/package/src/components/AttachmentPicker/AttachmentPicker.tsx b/package/src/components/AttachmentPicker/AttachmentPicker.tsx index f89f62a784..7bbc35926e 100644 --- a/package/src/components/AttachmentPicker/AttachmentPicker.tsx +++ b/package/src/components/AttachmentPicker/AttachmentPicker.tsx @@ -1,5 +1,13 @@ import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'; -import { BackHandler, Dimensions, Keyboard, Platform, StatusBar, StyleSheet } from 'react-native'; +import { + BackHandler, + Button, + Dimensions, + Keyboard, + Platform, + StatusBar, + StyleSheet, +} from 'react-native'; import BottomSheet, { BottomSheetFlatList, BottomSheetHandleProps } from '@gorhom/bottom-sheet'; import dayjs from 'dayjs'; @@ -11,7 +19,12 @@ import { renderAttachmentPickerItem } from './components/AttachmentPickerItem'; import { useAttachmentPickerContext } from '../../contexts/attachmentPickerContext/AttachmentPickerContext'; import { useTheme } from '../../contexts/themeContext/ThemeContext'; -import { getPhotos, oniOS14GalleryLibrarySelectionChange } from '../../native'; +import { useTranslationContext } from '../../contexts/translationContext/TranslationContext'; +import { + getPhotos, + iOS14RefreshGallerySelection, + oniOS14GalleryLibrarySelectionChange, +} from '../../native'; import type { Asset } from '../../types/types'; import { vh } from '../../utils/utils'; @@ -97,10 +110,12 @@ export const AttachmentPicker = React.forwardRef( const [currentIndex, setCurrentIndex] = useState(-1); const endCursorRef = useRef(); const [photoError, setPhotoError] = useState(false); + const [iOSLimited, setIosLimited] = useState(false); const hasNextPageRef = useRef(true); const [loadingPhotos, setLoadingPhotos] = useState(false); const [photos, setPhotos] = useState([]); const attemptedToLoadPhotosOnOpenRef = useRef(false); + const { t } = useTranslationContext(); const getMorePhotos = useCallback(async () => { if ( @@ -121,6 +136,7 @@ export const AttachmentPicker = React.forwardRef( setPhotos((prevPhotos) => endCursor ? [...prevPhotos, ...results.assets] : results.assets, ); + setIosLimited(results.iOSLimited); hasNextPageRef.current = !!results.hasNextPage; } catch (error) { setPhotoError(true); @@ -299,6 +315,9 @@ export const AttachmentPicker = React.forwardRef( ref={ref} snapPoints={snapPoints} > + {iOSLimited && ( +