117 lines
3.0 KiB
TypeScript
117 lines
3.0 KiB
TypeScript
import { createSlice, PayloadAction, createAsyncThunk } from '@reduxjs/toolkit';
|
|
import {
|
|
createFile,
|
|
deleteFile,
|
|
getPersistedUriPermissions,
|
|
} from 'react-native-scoped-storage';
|
|
import { FileSystem, AndroidScoped } from 'react-native-file-access';
|
|
import { clearPermissions, isPermissionForPath } from '../utilities';
|
|
import { RootState } from '.';
|
|
|
|
interface SettingsState {
|
|
storageUri: string | undefined;
|
|
noMedia: boolean;
|
|
}
|
|
|
|
const initialState: SettingsState = {
|
|
storageUri: undefined,
|
|
noMedia: false,
|
|
};
|
|
|
|
const settingsSlice = createSlice({
|
|
name: 'settings',
|
|
initialState,
|
|
reducers: {
|
|
setStorageUri: (state, action: PayloadAction<string | undefined>) => {
|
|
state.storageUri = action.payload;
|
|
},
|
|
setNoMedia: (state, action: PayloadAction<boolean>) => {
|
|
state.noMedia = action.payload;
|
|
},
|
|
},
|
|
});
|
|
|
|
const { setStorageUri, setNoMedia } = settingsSlice.actions;
|
|
|
|
const updateStorageUri = createAsyncThunk(
|
|
'settings/updateStorageUri',
|
|
async (newStorageUri: string, { dispatch }) => {
|
|
await clearPermissions([newStorageUri]);
|
|
dispatch(setStorageUri(newStorageUri));
|
|
},
|
|
);
|
|
|
|
const updateNoMedia = createAsyncThunk(
|
|
'settings/updateNoMedia',
|
|
async (newNoMedia: boolean, { dispatch, getState }) => {
|
|
dispatch(setNoMedia(newNoMedia));
|
|
|
|
const state = getState() as RootState;
|
|
const { storageUri } = state.settings;
|
|
if (!storageUri) return;
|
|
|
|
const noMediaExists = await FileSystem.exists(
|
|
AndroidScoped.appendPath(storageUri, '.nomedia'),
|
|
);
|
|
|
|
if (newNoMedia && !noMediaExists) {
|
|
await createFile(storageUri, '.nomedia', 'text/x-unknown');
|
|
} else if (!newNoMedia && noMediaExists) {
|
|
await deleteFile(AndroidScoped.appendPath(storageUri, '.nomedia'));
|
|
}
|
|
},
|
|
);
|
|
|
|
const validateSettings = createAsyncThunk(
|
|
'settings/validateSettings',
|
|
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
async (_, { dispatch, getState }) => {
|
|
const state = getState() as RootState;
|
|
const { storageUri, noMedia } = state.settings;
|
|
|
|
if (!storageUri) {
|
|
return;
|
|
}
|
|
|
|
const permissions = await getPersistedUriPermissions();
|
|
if (
|
|
!permissions.some(permission =>
|
|
isPermissionForPath(permission, storageUri),
|
|
)
|
|
) {
|
|
dispatch(setStorageUri());
|
|
return;
|
|
}
|
|
|
|
try {
|
|
const exists = await FileSystem.exists(storageUri);
|
|
if (!exists) {
|
|
throw new Error('Storage URI does not exist');
|
|
}
|
|
|
|
const isDirectory = await FileSystem.isDir(storageUri);
|
|
if (!isDirectory) {
|
|
throw new Error('Storage URI is not a directory');
|
|
}
|
|
} catch {
|
|
dispatch(setStorageUri());
|
|
return;
|
|
}
|
|
|
|
const isNoMedia = await FileSystem.exists(
|
|
AndroidScoped.appendPath(storageUri, '.nomedia'),
|
|
);
|
|
if (noMedia !== isNoMedia) {
|
|
dispatch(setNoMedia(isNoMedia));
|
|
}
|
|
},
|
|
);
|
|
|
|
export {
|
|
type SettingsState,
|
|
updateStorageUri as setStorageUri,
|
|
updateNoMedia as setNoMedia,
|
|
validateSettings,
|
|
};
|
|
export default settingsSlice.reducer;
|