Update setting hooks

Signed-off-by: Nikolaos Karaolidis <nick@karaolidis.com>
This commit is contained in:
2023-07-11 14:38:05 +03:00
parent 7ed62507c7
commit ca67493302
5 changed files with 69 additions and 72 deletions

View File

@@ -1 +1 @@
export { SettingsProvider, useSettings } from './settings'; export { SettingsProvider, useStorageUri, useNoMedia } from './settings';

View File

@@ -14,14 +14,15 @@ import {
createFile, createFile,
deleteFile, deleteFile,
} from 'react-native-scoped-storage'; } from 'react-native-scoped-storage';
import { Settings } from '../types';
import { LoadingView } from '../components'; import { LoadingView } from '../components';
import { Welcome } from '../screens'; import { Welcome } from '../screens';
import { clearPermissions, isPermissionForPath } from '../utilities'; import { clearPermissions, isPermissionForPath } from '../utilities';
interface SettingsContextType { interface SettingsContextType {
settings: Settings; storageUri: string;
setSettings: (newSettings: Partial<Settings>) => void; noMedia: boolean;
setStorageUri: (newStorageUri: string) => Promise<void>;
setNoMedia: (newNoMedia: boolean) => Promise<void>;
} }
const SettingsContext = createContext<SettingsContextType | undefined>( const SettingsContext = createContext<SettingsContextType | undefined>(
@@ -29,80 +30,70 @@ const SettingsContext = createContext<SettingsContextType | undefined>(
); );
function SettingsProvider({ children }: { children: ReactNode }) { function SettingsProvider({ children }: { children: ReactNode }) {
const [settings, setSettings] = useState<Settings>({ const [storageUri, setStorageUri] = useState('');
storageUri: '', const [noMedia, setNoMedia] = useState(false);
noMedia: false,
});
const [hasLoaded, setHasLoaded] = useState(false); const [hasLoaded, setHasLoaded] = useState(false);
const updateSettings = (newSettings: Partial<Settings>) => { const updateStorageUri = async (newStorageUri: string): Promise<void> => {
const updatedSettings = { ...settings, ...newSettings }; 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<void> => {
setNoMedia(newNoMedia);
void FileSystem.exists( const noMediaExists = await FileSystem.exists(
AndroidScoped.appendPath(updatedSettings.storageUri, '.nomedia'), AndroidScoped.appendPath(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'),
); );
if (newNoMedia && !noMediaExists) {
await createFile(storageUri, '.nomedia', 'text/x-unknown');
} else if (!newNoMedia && noMediaExists) {
await deleteFile(AndroidScoped.appendPath(storageUri, '.nomedia'));
} }
});
setSettings(updatedSettings); void AsyncStorage.setItem('noMedia', newNoMedia.toString());
}; };
useEffect(() => { useEffect(() => {
const loadSettings = async () => { const loadSettings = async () => {
const storageUriValue = await AsyncStorage.getItem('storageUri'); let storageUriValue = (await AsyncStorage.getItem('storageUri')) ?? '';
const noMediaValue = await AsyncStorage.getItem('noMedia'); let noMediaValue = (await AsyncStorage.getItem('noMedia')) === 'true';
let storageUri = storageUriValue ?? ''; if (storageUriValue !== '') {
let noMedia = noMediaValue === 'true';
if (storageUri !== '') {
const permissions = await getPersistedUriPermissions(); const permissions = await getPersistedUriPermissions();
if ( if (
!permissions.some(permission => !permissions.some(permission =>
isPermissionForPath(permission, storageUri), isPermissionForPath(permission, storageUriValue),
) )
) { ) {
storageUri = ''; storageUriValue = '';
} }
try { try {
const exists = await FileSystem.exists(storageUri); const exists = await FileSystem.exists(storageUriValue);
if (!exists) { if (!exists) {
throw new Error('Storage URI does not exist'); throw new Error('Storage URI does not exist');
} }
const isDirectory = await FileSystem.isDir(storageUri); const isDirectory = await FileSystem.isDir(storageUriValue);
if (!isDirectory) { if (!isDirectory) {
throw new Error('Storage URI is not a directory'); throw new Error('Storage URI is not a directory');
} }
} catch { } catch {
storageUri = ''; storageUriValue = '';
} }
noMedia = await FileSystem.exists( noMediaValue = await FileSystem.exists(
AndroidScoped.appendPath(storageUri, '.nomedia'), AndroidScoped.appendPath(storageUriValue, '.nomedia'),
); );
} }
setSettings({ setStorageUri(storageUriValue);
storageUri, setNoMedia(noMediaValue);
noMedia,
});
setHasLoaded(true); setHasLoaded(true);
}; };
@@ -114,14 +105,19 @@ function SettingsProvider({ children }: { children: ReactNode }) {
}, []); }, []);
return ( return (
<SettingsContext.Provider value={{ settings, setSettings: updateSettings }}> <SettingsContext.Provider
value={{
storageUri,
noMedia,
setStorageUri: updateStorageUri,
setNoMedia: updateNoMedia,
}}>
{hasLoaded ? ( {hasLoaded ? (
settings.storageUri === '' ? ( storageUri === '' ? (
<Welcome <Welcome
selectStorageLocation={() => { selectStorageLocation={async () => {
void openDocumentTree(true).then(uri => { const { uri } = await openDocumentTree(true);
updateSettings({ storageUri: uri.uri }); await updateStorageUri(uri);
});
}} }}
/> />
) : ( ) : (
@@ -134,12 +130,20 @@ function SettingsProvider({ children }: { children: ReactNode }) {
); );
} }
const useSettings = (): SettingsContextType => { function useStorageUri(): [string, (newStorageUri: string) => Promise<void>] {
const context = useContext(SettingsContext); const context = useContext(SettingsContext);
if (!context) { 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<void>] {
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 };

View File

@@ -6,7 +6,7 @@ import { openDocumentTree } from 'react-native-scoped-storage';
import { PaddedView } from '../components'; import { PaddedView } from '../components';
import styles from '../styles'; import styles from '../styles';
import { Meme } from '../database'; import { Meme } from '../database';
import { useSettings } from '../contexts'; import { useStorageUri, useNoMedia } from '../contexts';
const SettingsScreen = () => { const SettingsScreen = () => {
const [optimizingDatabase, setOptimizingDatabase] = useState(false); const [optimizingDatabase, setOptimizingDatabase] = useState(false);
@@ -14,7 +14,8 @@ const SettingsScreen = () => {
const [snackbarVisible, setSnackbarVisible] = useState(false); const [snackbarVisible, setSnackbarVisible] = useState(false);
const [snackbarMessage, setSnackbarMessage] = useState(''); const [snackbarMessage, setSnackbarMessage] = useState('');
const { settings, setSettings } = useSettings(); const [, setStorageUri] = useStorageUri();
const [noMedia, setNoMedia] = useNoMedia();
const realm = useRealm(); const realm = useRealm();
@@ -59,10 +60,9 @@ const SettingsScreen = () => {
<Button <Button
mode="elevated" mode="elevated"
style={styles.marginBottom} style={styles.marginBottom}
onPress={() => { onPress={async () => {
void openDocumentTree(true).then(uri => { const { uri } = await openDocumentTree(true);
setSettings({ storageUri: uri.uri }); void setStorageUri(uri);
});
}}> }}>
Change External Storage Path Change External Storage Path
</Button> </Button>
@@ -74,9 +74,9 @@ const SettingsScreen = () => {
]}> ]}>
<Text>Hide media from gallery</Text> <Text>Hide media from gallery</Text>
<Switch <Switch
value={settings.noMedia} value={noMedia}
onValueChange={value => { onValueChange={value => {
setSettings({ noMedia: value }); void setNoMedia(value);
}} }}
/> />
</View> </View>

View File

@@ -1 +0,0 @@
export type { default as Settings } from './settings';

View File

@@ -1,6 +0,0 @@
interface Settings {
storageUri: string;
noMedia: boolean;
}
export default Settings;