diff --git a/src/contexts/index.ts b/src/contexts/index.ts index 0d78aa7..a540f75 100644 --- a/src/contexts/index.ts +++ b/src/contexts/index.ts @@ -1 +1 @@ -export { SettingsProvider, useSettings } from './settings'; +export { SettingsProvider, useStorageUri, useNoMedia } from './settings'; diff --git a/src/contexts/settings.tsx b/src/contexts/settings.tsx index 6a916f8..0dd3251 100644 --- a/src/contexts/settings.tsx +++ b/src/contexts/settings.tsx @@ -14,14 +14,15 @@ import { createFile, deleteFile, } from 'react-native-scoped-storage'; -import { Settings } from '../types'; import { LoadingView } from '../components'; import { Welcome } from '../screens'; import { clearPermissions, isPermissionForPath } from '../utilities'; interface SettingsContextType { - settings: Settings; - setSettings: (newSettings: Partial) => void; + storageUri: string; + noMedia: boolean; + setStorageUri: (newStorageUri: string) => Promise; + setNoMedia: (newNoMedia: boolean) => Promise; } const SettingsContext = createContext( @@ -29,80 +30,70 @@ const SettingsContext = createContext( ); function SettingsProvider({ children }: { children: ReactNode }) { - const [settings, setSettings] = useState({ - storageUri: '', - noMedia: false, - }); + const [storageUri, setStorageUri] = useState(''); + const [noMedia, setNoMedia] = useState(false); + const [hasLoaded, setHasLoaded] = useState(false); - const updateSettings = (newSettings: Partial) => { - const updatedSettings = { ...settings, ...newSettings }; + const updateStorageUri = async (newStorageUri: string): Promise => { + setStorageUri(newStorageUri); - void clearPermissions([updatedSettings.storageUri]); + void clearPermissions([newStorageUri]); + void AsyncStorage.setItem('storageUri', newStorageUri); + }; - void AsyncStorage.setItem('storageUri', updatedSettings.storageUri); + const updateNoMedia = async (newNoMedia: boolean): Promise => { + setNoMedia(newNoMedia); - void FileSystem.exists( - AndroidScoped.appendPath(updatedSettings.storageUri, '.nomedia'), - ).then(noMediaExists => { - if (updatedSettings.noMedia && !noMediaExists) { - void createFile( - updatedSettings.storageUri, - '.nomedia', - 'text/x-unknown', - ); - } else if (!updatedSettings.noMedia && noMediaExists) { - void deleteFile( - AndroidScoped.appendPath(updatedSettings.storageUri, '.nomedia'), - ); - } - }); + const noMediaExists = await FileSystem.exists( + AndroidScoped.appendPath(storageUri, '.nomedia'), + ); - setSettings(updatedSettings); + if (newNoMedia && !noMediaExists) { + await createFile(storageUri, '.nomedia', 'text/x-unknown'); + } else if (!newNoMedia && noMediaExists) { + await deleteFile(AndroidScoped.appendPath(storageUri, '.nomedia')); + } + + void AsyncStorage.setItem('noMedia', newNoMedia.toString()); }; useEffect(() => { const loadSettings = async () => { - const storageUriValue = await AsyncStorage.getItem('storageUri'); - const noMediaValue = await AsyncStorage.getItem('noMedia'); + let storageUriValue = (await AsyncStorage.getItem('storageUri')) ?? ''; + let noMediaValue = (await AsyncStorage.getItem('noMedia')) === 'true'; - let storageUri = storageUriValue ?? ''; - let noMedia = noMediaValue === 'true'; - - if (storageUri !== '') { + if (storageUriValue !== '') { const permissions = await getPersistedUriPermissions(); if ( !permissions.some(permission => - isPermissionForPath(permission, storageUri), + isPermissionForPath(permission, storageUriValue), ) ) { - storageUri = ''; + storageUriValue = ''; } try { - const exists = await FileSystem.exists(storageUri); + const exists = await FileSystem.exists(storageUriValue); if (!exists) { throw new Error('Storage URI does not exist'); } - const isDirectory = await FileSystem.isDir(storageUri); + const isDirectory = await FileSystem.isDir(storageUriValue); if (!isDirectory) { throw new Error('Storage URI is not a directory'); } } catch { - storageUri = ''; + storageUriValue = ''; } - noMedia = await FileSystem.exists( - AndroidScoped.appendPath(storageUri, '.nomedia'), + noMediaValue = await FileSystem.exists( + AndroidScoped.appendPath(storageUriValue, '.nomedia'), ); } - setSettings({ - storageUri, - noMedia, - }); - + setStorageUri(storageUriValue); + setNoMedia(noMediaValue); setHasLoaded(true); }; @@ -114,14 +105,19 @@ function SettingsProvider({ children }: { children: ReactNode }) { }, []); return ( - + {hasLoaded ? ( - settings.storageUri === '' ? ( + storageUri === '' ? ( { - void openDocumentTree(true).then(uri => { - updateSettings({ storageUri: uri.uri }); - }); + selectStorageLocation={async () => { + const { uri } = await openDocumentTree(true); + await updateStorageUri(uri); }} /> ) : ( @@ -134,12 +130,20 @@ function SettingsProvider({ children }: { children: ReactNode }) { ); } -const useSettings = (): SettingsContextType => { +function useStorageUri(): [string, (newStorageUri: string) => Promise] { const context = useContext(SettingsContext); if (!context) { - throw new Error('useSettings must be used within a SettingsProvider'); + throw new Error('useStorageUri must be used within a SettingsProvider'); } - return context; -}; + return [context.storageUri, context.setStorageUri]; +} -export { SettingsProvider, useSettings }; +function useNoMedia(): [boolean, (newNoMedia: boolean) => Promise] { + const context = useContext(SettingsContext); + if (!context) { + throw new Error('useNoMedia must be used within a SettingsProvider'); + } + return [context.noMedia, context.setNoMedia]; +} + +export { SettingsProvider, useStorageUri, useNoMedia }; diff --git a/src/screens/settings.tsx b/src/screens/settings.tsx index 23da3a8..6a1931b 100644 --- a/src/screens/settings.tsx +++ b/src/screens/settings.tsx @@ -6,7 +6,7 @@ import { openDocumentTree } from 'react-native-scoped-storage'; import { PaddedView } from '../components'; import styles from '../styles'; import { Meme } from '../database'; -import { useSettings } from '../contexts'; +import { useStorageUri, useNoMedia } from '../contexts'; const SettingsScreen = () => { const [optimizingDatabase, setOptimizingDatabase] = useState(false); @@ -14,7 +14,8 @@ const SettingsScreen = () => { const [snackbarVisible, setSnackbarVisible] = useState(false); const [snackbarMessage, setSnackbarMessage] = useState(''); - const { settings, setSettings } = useSettings(); + const [, setStorageUri] = useStorageUri(); + const [noMedia, setNoMedia] = useNoMedia(); const realm = useRealm(); @@ -59,10 +60,9 @@ const SettingsScreen = () => { @@ -74,9 +74,9 @@ const SettingsScreen = () => { ]}> Hide media from gallery { - setSettings({ noMedia: value }); + void setNoMedia(value); }} /> diff --git a/src/types/index.ts b/src/types/index.ts deleted file mode 100644 index 23038ec..0000000 --- a/src/types/index.ts +++ /dev/null @@ -1 +0,0 @@ -export type { default as Settings } from './settings'; diff --git a/src/types/settings.ts b/src/types/settings.ts deleted file mode 100644 index f495b03..0000000 --- a/src/types/settings.ts +++ /dev/null @@ -1,6 +0,0 @@ -interface Settings { - storageUri: string; - noMedia: boolean; -} - -export default Settings;