184 lines
5.2 KiB
TypeScript
184 lines
5.2 KiB
TypeScript
import React, { useState } from 'react';
|
|
import { ScrollView, StyleSheet, View } from 'react-native';
|
|
import {
|
|
Button,
|
|
List,
|
|
Portal,
|
|
SegmentedButtons,
|
|
Snackbar,
|
|
Switch,
|
|
Text,
|
|
useTheme,
|
|
} from 'react-native-paper';
|
|
import { useDispatch, useSelector } from 'react-redux';
|
|
import type {} from 'redux-thunk/extend-redux';
|
|
import {
|
|
RootState,
|
|
setGridColumns,
|
|
setMasonryColumns,
|
|
setNoMedia,
|
|
} from '../state';
|
|
import StorageLocationChangeDialog from '../components/storageLocationChangeDialog';
|
|
import { useRealm } from '@realm/react';
|
|
import { FileSystem, FileStat } from 'react-native-file-access';
|
|
import { Meme } from '../database';
|
|
|
|
const settingsStyles = StyleSheet.create({
|
|
scrollView: {
|
|
paddingHorizontal: '4%',
|
|
},
|
|
snackbar: {
|
|
marginBottom: 90,
|
|
},
|
|
marginBottom: {
|
|
marginBottom: 15,
|
|
},
|
|
columnSegmentedButtons: {
|
|
marginBottom: 15,
|
|
paddingHorizontal: '2%',
|
|
},
|
|
hideMediaSwitch: {
|
|
flexDirection: 'row',
|
|
justifyContent: 'space-between',
|
|
paddingHorizontal: '2%',
|
|
},
|
|
});
|
|
|
|
const Settings = () => {
|
|
const { colors } = useTheme();
|
|
const noMedia = useSelector((state: RootState) => state.settings.noMedia);
|
|
const masonryColumns = useSelector(
|
|
(state: RootState) => state.settings.masonryColumns,
|
|
);
|
|
const gridColumns = useSelector(
|
|
(state: RootState) => state.settings.gridColumns,
|
|
);
|
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
const storageUri = useSelector(
|
|
(state: RootState) => state.settings.storageUri,
|
|
)!;
|
|
const dispatch = useDispatch();
|
|
const realm = useRealm();
|
|
|
|
const [snackbarMessage, setSnackbarMessage] = useState<string>();
|
|
|
|
const [
|
|
storageLocationChangeDialogVisible,
|
|
setStorageLocationChangeDialogVisible,
|
|
] = useState(false);
|
|
|
|
const refreshMemeMetadata = async () => {
|
|
const stat = await FileSystem.statDir(storageUri);
|
|
|
|
const statMap = new Map<string, FileStat>();
|
|
stat.forEach(s => statMap.set(s.filename, s));
|
|
|
|
const memes = realm.objects<Meme>(Meme.schema.name);
|
|
|
|
realm.write(() => {
|
|
memes.forEach(meme => {
|
|
const fileStat = statMap.get(meme.filename);
|
|
meme.size = fileStat?.size ?? 0;
|
|
});
|
|
});
|
|
|
|
setSnackbarMessage('Meme metadata refreshed.');
|
|
};
|
|
|
|
return (
|
|
<>
|
|
<ScrollView
|
|
contentContainerStyle={[
|
|
settingsStyles.scrollView,
|
|
{ backgroundColor: colors.background },
|
|
]}>
|
|
<List.Section>
|
|
<List.Subheader>Views</List.Subheader>
|
|
<Text style={settingsStyles.columnSegmentedButtons}>
|
|
Masonry Columns
|
|
</Text>
|
|
<SegmentedButtons
|
|
value={masonryColumns.toString()}
|
|
onValueChange={value => {
|
|
void dispatch(
|
|
setMasonryColumns(Number.parseInt(value) as 1 | 2 | 3 | 4),
|
|
);
|
|
}}
|
|
buttons={[
|
|
{ label: '1', value: '1' },
|
|
{ label: '2', value: '2' },
|
|
{ label: '3', value: '3' },
|
|
{ label: '4', value: '4' },
|
|
]}
|
|
style={settingsStyles.marginBottom}
|
|
/>
|
|
<Text style={settingsStyles.columnSegmentedButtons}>
|
|
Grid Columns
|
|
</Text>
|
|
<SegmentedButtons
|
|
value={gridColumns.toString()}
|
|
onValueChange={value => {
|
|
void dispatch(
|
|
setGridColumns(Number.parseInt(value) as 1 | 2 | 3 | 4),
|
|
);
|
|
}}
|
|
buttons={[
|
|
{ label: '1', value: '1' },
|
|
{ label: '2', value: '2' },
|
|
{ label: '3', value: '3' },
|
|
{ label: '4', value: '4' },
|
|
]}
|
|
/>
|
|
</List.Section>
|
|
<List.Section>
|
|
<List.Subheader>Storage</List.Subheader>
|
|
<Button
|
|
mode="elevated"
|
|
style={settingsStyles.marginBottom}
|
|
onPress={() => setStorageLocationChangeDialogVisible(true)}>
|
|
Change Storage Location
|
|
</Button>
|
|
<Button
|
|
mode="elevated"
|
|
style={settingsStyles.marginBottom}
|
|
onPress={refreshMemeMetadata}>
|
|
Refresh Meme Metadata
|
|
</Button>
|
|
<View style={settingsStyles.hideMediaSwitch}>
|
|
<Text>Hide media from gallery</Text>
|
|
<Switch
|
|
value={noMedia}
|
|
onValueChange={value => {
|
|
void dispatch(setNoMedia(value));
|
|
}}
|
|
/>
|
|
</View>
|
|
</List.Section>
|
|
</ScrollView>
|
|
<Portal>
|
|
<Portal>
|
|
<StorageLocationChangeDialog
|
|
visible={storageLocationChangeDialogVisible}
|
|
setVisible={setStorageLocationChangeDialogVisible}
|
|
setSnackbarMessage={setSnackbarMessage}
|
|
/>
|
|
</Portal>
|
|
<Snackbar
|
|
visible={!!snackbarMessage}
|
|
// eslint-disable-next-line unicorn/no-useless-undefined
|
|
onDismiss={() => setSnackbarMessage(undefined)}
|
|
style={settingsStyles.snackbar}
|
|
action={{
|
|
label: 'Dismiss',
|
|
// eslint-disable-next-line unicorn/no-useless-undefined
|
|
onPress: () => setSnackbarMessage(undefined),
|
|
}}>
|
|
{snackbarMessage}
|
|
</Snackbar>
|
|
</Portal>
|
|
</>
|
|
);
|
|
};
|
|
|
|
export default Settings;
|