2022-07-03 01:50:01 +00:00
|
|
|
import AsyncStorage from '@react-native-async-storage/async-storage';
|
2022-07-09 07:39:11 +00:00
|
|
|
import React, {useCallback, useContext, useEffect, useState} from 'react';
|
|
|
|
import {
|
|
|
|
NativeModules,
|
|
|
|
PermissionsAndroid,
|
|
|
|
StyleSheet,
|
|
|
|
Text,
|
|
|
|
View,
|
|
|
|
} from 'react-native';
|
|
|
|
import {Dirs, FileSystem} from 'react-native-file-access';
|
2022-07-06 04:27:36 +00:00
|
|
|
import {Button, Snackbar, Switch, TextInput} from 'react-native-paper';
|
2022-07-07 02:18:38 +00:00
|
|
|
import {DatabaseContext} from './App';
|
2022-07-06 09:03:56 +00:00
|
|
|
import BatteryDialog from './BatteryDialog';
|
2022-07-09 07:39:11 +00:00
|
|
|
import Set from './set';
|
|
|
|
import DocumentPicker from 'react-native-document-picker';
|
2022-07-03 01:50:01 +00:00
|
|
|
|
2022-07-08 03:45:24 +00:00
|
|
|
const {getItem, setItem} = AsyncStorage;
|
|
|
|
|
2022-07-08 03:20:03 +00:00
|
|
|
export default function SettingsPage() {
|
2022-07-03 01:50:01 +00:00
|
|
|
const [minutes, setMinutes] = useState<string>('');
|
|
|
|
const [seconds, setSeconds] = useState<string>('');
|
2022-07-07 07:01:31 +00:00
|
|
|
const [alarmEnabled, setAlarmEnabled] = useState<boolean>(false);
|
2022-07-06 04:27:36 +00:00
|
|
|
const [snackbar, setSnackbar] = useState('');
|
2022-07-06 09:03:56 +00:00
|
|
|
const [showBattery, setShowBattery] = useState(false);
|
2022-07-07 00:45:45 +00:00
|
|
|
const [ignoring, setIgnoring] = useState(false);
|
2022-07-09 07:39:11 +00:00
|
|
|
const [timeoutId, setTimeoutId] = useState(0);
|
2022-07-07 02:18:38 +00:00
|
|
|
const db = useContext(DatabaseContext);
|
2022-07-03 01:50:01 +00:00
|
|
|
|
2022-07-09 07:39:11 +00:00
|
|
|
const refresh = useCallback(async () => {
|
2022-07-08 03:51:10 +00:00
|
|
|
setMinutes((await getItem('minutes')) || '');
|
2022-07-08 03:45:24 +00:00
|
|
|
setSeconds((await getItem('seconds')) || '');
|
|
|
|
setAlarmEnabled((await getItem('alarmEnabled')) === 'true');
|
2022-07-07 00:45:45 +00:00
|
|
|
NativeModules.AlarmModule.ignoringBatteryOptimizations(setIgnoring);
|
2022-07-09 07:39:11 +00:00
|
|
|
}, [setIgnoring]);
|
2022-07-07 00:45:45 +00:00
|
|
|
|
2022-07-07 03:13:44 +00:00
|
|
|
useEffect(() => {
|
2022-07-07 00:45:45 +00:00
|
|
|
refresh();
|
2022-07-09 07:39:11 +00:00
|
|
|
}, [refresh]);
|
2022-07-03 01:50:01 +00:00
|
|
|
|
2022-07-09 07:39:11 +00:00
|
|
|
const toast = useCallback(
|
|
|
|
(message: string) => {
|
|
|
|
setSnackbar(message);
|
|
|
|
clearTimeout(timeoutId);
|
|
|
|
setTimeoutId(setTimeout(() => setSnackbar(''), 3000));
|
|
|
|
},
|
|
|
|
[setSnackbar, timeoutId, setTimeoutId],
|
|
|
|
);
|
|
|
|
|
|
|
|
const clear = useCallback(async () => {
|
2022-07-03 01:50:01 +00:00
|
|
|
await db.executeSql(`DELETE FROM sets`);
|
2022-07-09 07:39:11 +00:00
|
|
|
toast('All data has been deleted!');
|
|
|
|
}, [db, toast]);
|
|
|
|
|
|
|
|
const exportSets = useCallback(async () => {
|
|
|
|
const fileName = 'sets.csv';
|
|
|
|
const filePath = `${Dirs.DocumentDir}/${fileName}`;
|
|
|
|
const [result] = await db.executeSql('SELECT * FROM sets');
|
|
|
|
if (result.rows.length === 0) return;
|
|
|
|
const sets: Set[] = result.rows.raw();
|
|
|
|
const data = ['id,name,reps,weight,created,unit']
|
|
|
|
.concat(
|
|
|
|
sets.map(
|
|
|
|
set =>
|
|
|
|
`${set.id},${set.name},${set.reps},${set.weight},${set.created},${set.unit}`,
|
|
|
|
),
|
|
|
|
)
|
|
|
|
.join('\n');
|
|
|
|
console.log('SettingsPage.exportSets', {length: sets.length});
|
|
|
|
const permission = async () => {
|
|
|
|
const granted = await PermissionsAndroid.request(
|
|
|
|
PermissionsAndroid.PERMISSIONS.WRITE_EXTERNAL_STORAGE,
|
|
|
|
);
|
|
|
|
return granted === PermissionsAndroid.RESULTS.GRANTED;
|
|
|
|
};
|
2022-07-03 01:50:01 +00:00
|
|
|
|
2022-07-09 07:39:11 +00:00
|
|
|
const granted = await permission();
|
|
|
|
if (granted) {
|
|
|
|
await FileSystem.writeFile(filePath, data);
|
|
|
|
if (!FileSystem.exists(filePath)) return;
|
|
|
|
await FileSystem.cpExternal(filePath, fileName, 'downloads');
|
|
|
|
}
|
|
|
|
toast('Exported data. Check your downloads folder.');
|
|
|
|
}, [db, toast]);
|
2022-07-05 12:06:16 +00:00
|
|
|
|
2022-07-09 07:39:11 +00:00
|
|
|
const importSets = useCallback(async () => {
|
|
|
|
const result = await DocumentPicker.pickSingle();
|
|
|
|
const file = await FileSystem.readFile(result.uri);
|
|
|
|
console.log(`${SettingsPage.name}.${importSets.name}:`, file.length);
|
|
|
|
const values = file
|
|
|
|
.split('\n')
|
|
|
|
.slice(1)
|
|
|
|
.map(set => {
|
|
|
|
const cells = set.split(',');
|
|
|
|
return `('${cells[1]}',${cells[2]},${cells[3]},'${cells[4]}','${cells[5]}')`;
|
|
|
|
})
|
|
|
|
.join(',');
|
|
|
|
await db.executeSql(
|
|
|
|
`INSERT INTO sets(name,reps,weight,created,unit) VALUES ${values}`,
|
|
|
|
);
|
|
|
|
toast('Data imported.');
|
|
|
|
}, [db, toast]);
|
2022-07-06 04:27:36 +00:00
|
|
|
|
2022-07-09 07:39:11 +00:00
|
|
|
const changeAlarmEnabled = useCallback(
|
|
|
|
(enabled: boolean) => {
|
|
|
|
setAlarmEnabled(enabled);
|
|
|
|
if (enabled && !ignoring) setShowBattery(true);
|
|
|
|
setItem('alarmEnabled', enabled ? 'true' : 'false');
|
|
|
|
},
|
2022-07-09 07:42:10 +00:00
|
|
|
[alarmEnabled, setShowBattery, ignoring],
|
2022-07-09 07:39:11 +00:00
|
|
|
);
|
2022-07-06 09:03:56 +00:00
|
|
|
|
2022-07-03 01:50:01 +00:00
|
|
|
return (
|
|
|
|
<View style={styles.container}>
|
|
|
|
<TextInput
|
2022-07-04 04:03:48 +00:00
|
|
|
label="Rest minutes"
|
2022-07-03 01:50:01 +00:00
|
|
|
value={minutes}
|
|
|
|
keyboardType="numeric"
|
|
|
|
placeholder="3"
|
2022-07-08 03:46:48 +00:00
|
|
|
onChangeText={text => {
|
2022-07-08 03:45:24 +00:00
|
|
|
setMinutes(text);
|
2022-07-08 03:46:48 +00:00
|
|
|
setItem('minutes', text);
|
2022-07-08 03:45:24 +00:00
|
|
|
}}
|
2022-07-04 04:17:29 +00:00
|
|
|
style={styles.text}
|
2022-07-03 01:50:01 +00:00
|
|
|
/>
|
|
|
|
<TextInput
|
2022-07-04 04:03:48 +00:00
|
|
|
label="Rest seconds"
|
2022-07-03 01:50:01 +00:00
|
|
|
value={seconds}
|
|
|
|
keyboardType="numeric"
|
|
|
|
placeholder="30"
|
2022-07-09 01:27:19 +00:00
|
|
|
onChangeText={s => {
|
|
|
|
setSeconds(s);
|
|
|
|
setItem('seconds', s);
|
2022-07-08 03:45:24 +00:00
|
|
|
}}
|
2022-07-04 04:17:29 +00:00
|
|
|
style={styles.text}
|
2022-07-03 01:50:01 +00:00
|
|
|
/>
|
2022-07-06 10:02:43 +00:00
|
|
|
<Text style={styles.text}>Rest timers</Text>
|
2022-07-03 01:50:01 +00:00
|
|
|
<Switch
|
2022-07-04 04:17:29 +00:00
|
|
|
style={[styles.text, {alignSelf: 'flex-start'}]}
|
2022-07-03 01:50:01 +00:00
|
|
|
value={alarmEnabled}
|
2022-07-06 09:03:56 +00:00
|
|
|
onValueChange={changeAlarmEnabled}
|
2022-07-03 01:50:01 +00:00
|
|
|
/>
|
2022-07-05 12:06:16 +00:00
|
|
|
<Button
|
|
|
|
style={{alignSelf: 'flex-start'}}
|
|
|
|
icon="arrow-down"
|
|
|
|
onPress={exportSets}>
|
2022-07-06 04:27:36 +00:00
|
|
|
Export
|
|
|
|
</Button>
|
|
|
|
<Button
|
|
|
|
style={{alignSelf: 'flex-start'}}
|
|
|
|
icon="arrow-up"
|
|
|
|
onPress={importSets}>
|
|
|
|
Import
|
2022-07-05 12:06:16 +00:00
|
|
|
</Button>
|
2022-07-05 03:33:42 +00:00
|
|
|
<Button
|
|
|
|
style={{alignSelf: 'flex-start', marginTop: 'auto'}}
|
|
|
|
icon="trash"
|
|
|
|
onPress={clear}>
|
|
|
|
Delete all data
|
2022-07-03 01:50:01 +00:00
|
|
|
</Button>
|
2022-07-06 04:27:36 +00:00
|
|
|
|
2022-07-06 09:03:56 +00:00
|
|
|
<BatteryDialog show={showBattery} setShow={setShowBattery} />
|
|
|
|
|
2022-07-06 04:27:36 +00:00
|
|
|
<Snackbar
|
|
|
|
visible={!!snackbar}
|
|
|
|
onDismiss={() => setSnackbar('')}
|
|
|
|
action={{label: 'Close', onPress: () => setSnackbar('')}}>
|
|
|
|
{snackbar}
|
|
|
|
</Snackbar>
|
2022-07-03 01:50:01 +00:00
|
|
|
</View>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
const styles = StyleSheet.create({
|
|
|
|
container: {
|
|
|
|
padding: 10,
|
2022-07-05 03:33:42 +00:00
|
|
|
flex: 1,
|
2022-07-03 01:50:01 +00:00
|
|
|
},
|
2022-07-04 04:17:29 +00:00
|
|
|
text: {
|
|
|
|
marginBottom: 10,
|
|
|
|
},
|
2022-07-03 01:50:01 +00:00
|
|
|
});
|