2023-08-12 03:22:50 +00:00
|
|
|
import { NavigationProp, useNavigation } from "@react-navigation/native";
|
|
|
|
import { format } from "date-fns";
|
|
|
|
import { useCallback, useEffect, useMemo, useState } from "react";
|
|
|
|
import { useForm } from "react-hook-form";
|
2023-11-12 06:07:58 +00:00
|
|
|
import { FlatList, NativeModules } from "react-native";
|
2023-08-12 03:22:50 +00:00
|
|
|
import DocumentPicker from "react-native-document-picker";
|
|
|
|
import { Dirs, FileSystem } from "react-native-file-access";
|
2023-11-12 03:56:07 +00:00
|
|
|
import { Button } from "react-native-paper";
|
2023-11-12 06:07:58 +00:00
|
|
|
import { PERMISSIONS, RESULTS, check, request } from "react-native-permissions";
|
2023-11-12 03:56:07 +00:00
|
|
|
import AppInput from "./AppInput";
|
2023-08-12 03:22:50 +00:00
|
|
|
import ConfirmDialog from "./ConfirmDialog";
|
2023-11-12 06:07:58 +00:00
|
|
|
import DrawerHeader from "./DrawerHeader";
|
|
|
|
import Page from "./Page";
|
|
|
|
import Select from "./Select";
|
|
|
|
import Switch from "./Switch";
|
|
|
|
import { PADDING } from "./constants";
|
2023-08-12 03:22:50 +00:00
|
|
|
import { AppDataSource } from "./data-source";
|
|
|
|
import { setRepo, settingsRepo } from "./db";
|
2023-10-28 02:59:03 +00:00
|
|
|
import { DrawerParams } from "./drawer-param-list";
|
2023-08-12 03:22:50 +00:00
|
|
|
import { darkOptions, lightOptions, themeOptions } from "./options";
|
2023-11-12 03:56:07 +00:00
|
|
|
import Settings from "./settings";
|
2023-08-12 03:22:50 +00:00
|
|
|
import { toast } from "./toast";
|
|
|
|
import { useTheme } from "./use-theme";
|
2022-07-08 03:45:24 +00:00
|
|
|
|
2023-06-17 23:30:28 +00:00
|
|
|
const twelveHours = [
|
2023-08-12 03:22:50 +00:00
|
|
|
"dd/LL/yyyy",
|
|
|
|
"dd/LL/yyyy, p",
|
|
|
|
"ccc p",
|
|
|
|
"p",
|
|
|
|
"yyyy-MM-d",
|
|
|
|
"yyyy-MM-d, p",
|
|
|
|
"yyyy.MM.d",
|
|
|
|
];
|
2023-06-17 23:30:28 +00:00
|
|
|
const twentyFours = [
|
2023-08-12 03:22:50 +00:00
|
|
|
"dd/LL/yyyy",
|
|
|
|
"dd/LL/yyyy, k:m",
|
|
|
|
"ccc k:m",
|
|
|
|
"k:m",
|
|
|
|
"yyyy-MM-d",
|
|
|
|
"yyyy-MM-d, k:m",
|
|
|
|
"yyyy.MM.d",
|
|
|
|
];
|
2022-11-21 05:15:43 +00:00
|
|
|
|
2023-11-12 06:07:58 +00:00
|
|
|
interface Item {
|
|
|
|
name: string;
|
|
|
|
renderItem: (name: string) => React.JSX.Element;
|
|
|
|
}
|
|
|
|
|
2022-07-08 03:20:03 +00:00
|
|
|
export default function SettingsPage() {
|
2023-08-12 03:22:50 +00:00
|
|
|
const [ignoring, setIgnoring] = useState(false);
|
|
|
|
const [term, setTerm] = useState("");
|
|
|
|
const [formatOptions, setFormatOptions] = useState<string[]>(twelveHours);
|
|
|
|
const [importing, setImporting] = useState(false);
|
|
|
|
const [deleting, setDeleting] = useState(false);
|
2023-10-28 02:59:03 +00:00
|
|
|
const { reset } = useNavigation<NavigationProp<DrawerParams>>();
|
2022-10-18 08:43:46 +00:00
|
|
|
|
2023-06-27 03:16:59 +00:00
|
|
|
const { watch, setValue } = useForm<Settings>({
|
|
|
|
defaultValues: () => settingsRepo.findOne({ where: {} }),
|
2023-08-12 03:22:50 +00:00
|
|
|
});
|
|
|
|
const settings = watch();
|
2022-12-30 02:45:18 +00:00
|
|
|
|
2023-06-27 03:16:59 +00:00
|
|
|
const {
|
|
|
|
theme,
|
|
|
|
setTheme,
|
|
|
|
lightColor,
|
|
|
|
setLightColor,
|
|
|
|
darkColor,
|
|
|
|
setDarkColor,
|
2023-08-12 03:22:50 +00:00
|
|
|
} = useTheme();
|
2022-12-29 04:27:43 +00:00
|
|
|
|
2022-12-29 00:52:38 +00:00
|
|
|
useEffect(() => {
|
2023-08-12 03:22:50 +00:00
|
|
|
NativeModules.SettingsModule.ignoringBattery(setIgnoring);
|
2022-12-29 00:52:38 +00:00
|
|
|
NativeModules.SettingsModule.is24().then((is24: boolean) => {
|
2023-08-12 03:22:50 +00:00
|
|
|
console.log(`${SettingsPage.name}.focus:`, { is24 });
|
|
|
|
if (is24) setFormatOptions(twentyFours);
|
|
|
|
else setFormatOptions(twelveHours);
|
|
|
|
});
|
|
|
|
}, []);
|
2022-07-03 01:50:01 +00:00
|
|
|
|
2023-08-21 23:39:51 +00:00
|
|
|
const update = useCallback(async (key: keyof Settings, value: unknown) => {
|
|
|
|
await settingsRepo
|
2023-01-03 01:59:19 +00:00
|
|
|
.createQueryBuilder()
|
|
|
|
.update()
|
2023-06-27 03:16:59 +00:00
|
|
|
.set({ [key]: value })
|
2023-01-03 01:59:19 +00:00
|
|
|
.printSql()
|
2023-08-12 03:22:50 +00:00
|
|
|
.execute();
|
|
|
|
}, []);
|
2023-01-03 01:59:19 +00:00
|
|
|
|
2023-11-13 02:15:18 +00:00
|
|
|
const backupString = useMemo(() => {
|
|
|
|
if (!settings.backupDir) return null;
|
|
|
|
console.log(settings.backupDir);
|
|
|
|
const split = decodeURIComponent(settings.backupDir).split(":");
|
|
|
|
return split.pop();
|
|
|
|
}, [settings.backupDir]);
|
|
|
|
|
2022-12-28 01:15:02 +00:00
|
|
|
const soundString = useMemo(() => {
|
2023-08-12 03:22:50 +00:00
|
|
|
if (!settings.sound) return null;
|
|
|
|
const split = settings.sound.split("/");
|
|
|
|
return split.pop();
|
|
|
|
}, [settings.sound]);
|
2022-12-28 01:15:02 +00:00
|
|
|
|
2023-07-20 02:55:19 +00:00
|
|
|
const confirmDelete = useCallback(async () => {
|
2023-08-12 03:22:50 +00:00
|
|
|
setDeleting(false);
|
|
|
|
await AppDataSource.dropDatabase();
|
|
|
|
await AppDataSource.destroy();
|
|
|
|
await AppDataSource.initialize();
|
|
|
|
toast("Database deleted.");
|
|
|
|
}, []);
|
2023-06-29 03:31:24 +00:00
|
|
|
|
2022-12-08 00:18:41 +00:00
|
|
|
const confirmImport = useCallback(async () => {
|
2023-08-12 03:22:50 +00:00
|
|
|
setImporting(false);
|
|
|
|
await AppDataSource.destroy();
|
|
|
|
const file = await DocumentPicker.pickSingle();
|
|
|
|
await FileSystem.cp(file.uri, Dirs.DatabaseDir + "/massive.db");
|
|
|
|
await AppDataSource.initialize();
|
|
|
|
await setRepo.createQueryBuilder().update().set({ image: null }).execute();
|
|
|
|
await update("sound", null);
|
2023-11-13 02:15:18 +00:00
|
|
|
await update("backup", false);
|
|
|
|
reset({ index: 0, routes: [{ name: "Settings" }] });
|
2023-08-12 03:22:50 +00:00
|
|
|
}, [reset, update]);
|
2022-12-08 00:18:41 +00:00
|
|
|
|
2023-11-12 06:07:58 +00:00
|
|
|
const today = new Date();
|
2022-12-30 07:29:16 +00:00
|
|
|
|
2023-11-12 06:07:58 +00:00
|
|
|
const data: Item[] = [
|
2023-11-12 10:27:28 +00:00
|
|
|
{
|
|
|
|
name: "Start up page",
|
|
|
|
renderItem: (name: string) => (
|
|
|
|
<Select
|
|
|
|
label={name}
|
|
|
|
items={[
|
2023-11-13 05:29:07 +00:00
|
|
|
{ label: "History", value: "History" },
|
2023-11-12 10:27:28 +00:00
|
|
|
{ label: "Exercises", value: "Exercises" },
|
|
|
|
{ label: "Plans", value: "Plans" },
|
|
|
|
{ label: "Graphs", value: "Graphs" },
|
|
|
|
{ label: "Timer", value: "Timer" },
|
|
|
|
{ label: "Weight", value: "Weight" },
|
|
|
|
{ label: "Insights", value: "Insights" },
|
|
|
|
{ label: "Settings", value: "Settings" },
|
|
|
|
]}
|
|
|
|
value={settings.startup}
|
|
|
|
onChange={async (value) => {
|
|
|
|
setValue("startup", value);
|
|
|
|
await update("startup", value);
|
|
|
|
toast(`App will always start on ${value}`);
|
|
|
|
}}
|
|
|
|
/>
|
|
|
|
),
|
|
|
|
},
|
2023-11-12 06:07:58 +00:00
|
|
|
{
|
|
|
|
name: "Theme",
|
|
|
|
renderItem: (name: string) => (
|
|
|
|
<Select
|
|
|
|
label={name}
|
|
|
|
items={themeOptions}
|
|
|
|
value={theme}
|
|
|
|
onChange={async (value) => {
|
|
|
|
setValue("theme", value);
|
|
|
|
setTheme(value);
|
|
|
|
await update("theme", value);
|
|
|
|
if (value === "dark") toast("Theme will always be dark.");
|
|
|
|
else if (value === "light") toast("Theme will always be light.");
|
|
|
|
else if (value === "system") toast("Theme will follow system.");
|
|
|
|
}}
|
|
|
|
/>
|
|
|
|
),
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "Dark color",
|
|
|
|
renderItem: (name: string) => (
|
|
|
|
<Select
|
|
|
|
label={name}
|
|
|
|
items={lightOptions}
|
|
|
|
value={darkColor}
|
|
|
|
onChange={async (value) => {
|
|
|
|
setValue("darkColor", value);
|
|
|
|
setDarkColor(value);
|
|
|
|
await update("darkColor", value);
|
|
|
|
toast("Set primary color for dark mode.");
|
|
|
|
}}
|
|
|
|
/>
|
|
|
|
),
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "Light color",
|
|
|
|
renderItem: (name: string) => (
|
|
|
|
<Select
|
|
|
|
label={name}
|
|
|
|
items={darkOptions}
|
|
|
|
value={lightColor}
|
|
|
|
onChange={async (value) => {
|
|
|
|
setValue("lightColor", value);
|
|
|
|
setLightColor(value);
|
|
|
|
await update("lightColor", value);
|
|
|
|
toast("Set primary color for light mode.");
|
|
|
|
}}
|
|
|
|
/>
|
|
|
|
),
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "Date format",
|
|
|
|
renderItem: (name: string) => (
|
|
|
|
<Select
|
|
|
|
label={name}
|
|
|
|
items={formatOptions.map((option) => ({
|
|
|
|
label: format(today, option),
|
|
|
|
value: option,
|
|
|
|
}))}
|
|
|
|
value={settings.date}
|
|
|
|
onChange={async (value) => {
|
|
|
|
setValue("date", value);
|
|
|
|
await update("date", value);
|
|
|
|
toast("Changed date format.");
|
|
|
|
}}
|
|
|
|
/>
|
|
|
|
),
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "Vibration duration (ms)",
|
|
|
|
renderItem: (name: string) => (
|
|
|
|
<AppInput
|
|
|
|
value={settings.duration?.toString() ?? "300"}
|
|
|
|
label={name}
|
|
|
|
onChangeText={(value) => setValue("duration", Number(value))}
|
|
|
|
onSubmitEditing={async (e) => {
|
|
|
|
setValue("duration", Number(e.nativeEvent.text));
|
|
|
|
await update("duration", e.nativeEvent.text);
|
|
|
|
toast("Changed duration of alarm vibrations.");
|
|
|
|
}}
|
|
|
|
keyboardType="numeric"
|
|
|
|
blurOnSubmit
|
|
|
|
/>
|
|
|
|
),
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "Rest timers",
|
|
|
|
renderItem: (name: string) => (
|
|
|
|
<Switch
|
|
|
|
value={settings.alarm}
|
|
|
|
onChange={async (value) => {
|
|
|
|
setValue("alarm", value);
|
|
|
|
if (value && !ignoring)
|
|
|
|
NativeModules.SettingsModule.ignoreBattery();
|
|
|
|
await update("alarm", value);
|
|
|
|
if (value) toast("Timers will now run after each set.");
|
|
|
|
else toast("Stopped timers running after each set.");
|
|
|
|
}}
|
|
|
|
title={name}
|
|
|
|
/>
|
|
|
|
),
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "Vibrate",
|
|
|
|
renderItem: (name: string) => (
|
|
|
|
<Switch
|
|
|
|
value={settings.vibrate}
|
|
|
|
onChange={async (value) => {
|
|
|
|
setValue("vibrate", value);
|
|
|
|
await update("vibrate", value);
|
|
|
|
if (value) toast("Timers will now run after each set.");
|
|
|
|
else toast("Stopped timers running after each set.");
|
|
|
|
}}
|
|
|
|
title={name}
|
|
|
|
/>
|
|
|
|
),
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "Disable sound",
|
|
|
|
renderItem: (name: string) => (
|
|
|
|
<Switch
|
|
|
|
value={settings.noSound}
|
|
|
|
onChange={async (value) => {
|
|
|
|
setValue("noSound", value);
|
|
|
|
await update("noSound", value);
|
|
|
|
if (value) toast("Alarms will no longer make a sound.");
|
|
|
|
else toast("Enabled sound for alarms.");
|
|
|
|
}}
|
|
|
|
title={name}
|
|
|
|
/>
|
|
|
|
),
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "Notifications",
|
|
|
|
renderItem: (name: string) => (
|
|
|
|
<Switch
|
|
|
|
value={settings.notify}
|
|
|
|
onChange={async (value) => {
|
|
|
|
setValue("notify", value);
|
|
|
|
await update("notify", value);
|
|
|
|
if (value) toast("Show notifications for new records.");
|
|
|
|
else toast("Stopped notifications for new records.");
|
|
|
|
}}
|
|
|
|
title={name}
|
|
|
|
/>
|
|
|
|
),
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "Show images",
|
|
|
|
renderItem: (name: string) => (
|
|
|
|
<Switch
|
|
|
|
value={settings.images}
|
|
|
|
onChange={async (value) => {
|
|
|
|
setValue("images", value);
|
|
|
|
await update("images", value);
|
|
|
|
if (value) toast("Show images for sets.");
|
|
|
|
else toast("Hid images for sets.");
|
|
|
|
}}
|
|
|
|
title={name}
|
|
|
|
/>
|
|
|
|
),
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "Show unit",
|
|
|
|
renderItem: (name: string) => (
|
|
|
|
<Switch
|
|
|
|
value={settings.showUnit}
|
|
|
|
onChange={async (value) => {
|
|
|
|
setValue("showUnit", value);
|
|
|
|
await update("showUnit", value);
|
|
|
|
if (value) toast("Show option to select unit for sets.");
|
|
|
|
else toast("Hid unit option for sets.");
|
|
|
|
}}
|
|
|
|
title={name}
|
|
|
|
/>
|
|
|
|
),
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "Show steps",
|
|
|
|
renderItem: (name: string) => (
|
|
|
|
<Switch
|
|
|
|
value={settings.steps}
|
|
|
|
onChange={async (value) => {
|
|
|
|
setValue("steps", value);
|
|
|
|
await update("steps", value);
|
|
|
|
if (value) toast("Show steps for exercises.");
|
|
|
|
else toast("Hid steps for exercises.");
|
|
|
|
}}
|
|
|
|
title={name}
|
|
|
|
/>
|
|
|
|
),
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "Show date",
|
|
|
|
renderItem: (name: string) => (
|
|
|
|
<Switch
|
|
|
|
value={settings.showDate}
|
|
|
|
onChange={async (value) => {
|
|
|
|
setValue("showDate", value);
|
|
|
|
await update("showDate", value);
|
|
|
|
if (value) toast("Show date for sets.");
|
|
|
|
else toast("Hid date on sets.");
|
|
|
|
}}
|
|
|
|
title={name}
|
|
|
|
/>
|
|
|
|
),
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "Automatic backup",
|
|
|
|
renderItem: (name: string) => (
|
|
|
|
<Switch
|
|
|
|
value={settings.backup}
|
|
|
|
onChange={async (value) => {
|
|
|
|
setValue("backup", value);
|
|
|
|
await update("backup", value);
|
|
|
|
if (value) {
|
|
|
|
const result = await DocumentPicker.pickDirectory();
|
2023-11-13 02:15:18 +00:00
|
|
|
setValue("backupDir", result.uri);
|
|
|
|
await update("backupDir", result.uri);
|
|
|
|
console.log(`${SettingsPage.name}.backup:`, { result });
|
2023-11-12 06:07:58 +00:00
|
|
|
toast("Backup database daily.");
|
|
|
|
NativeModules.BackupModule.start(result.uri);
|
|
|
|
} else {
|
|
|
|
toast("Stopped backing up daily");
|
|
|
|
NativeModules.BackupModule.stop();
|
|
|
|
}
|
|
|
|
}}
|
|
|
|
title={name}
|
|
|
|
/>
|
|
|
|
),
|
|
|
|
},
|
2023-11-13 02:15:18 +00:00
|
|
|
{
|
|
|
|
name: `Backup directory: ${backupString || "Downloads"}`,
|
|
|
|
renderItem: (name: string) => (
|
|
|
|
<Button
|
|
|
|
style={{ alignSelf: "flex-start" }}
|
|
|
|
onPress={async () => {
|
|
|
|
const result = await DocumentPicker.pickDirectory();
|
|
|
|
setValue("backupDir", result.uri);
|
|
|
|
await update("backupDir", result.uri);
|
|
|
|
toast("Changed backup directory.");
|
|
|
|
if (!settings.backup) return;
|
|
|
|
NativeModules.BackupModule.stop();
|
|
|
|
NativeModules.BackupModule.start(result.uri);
|
|
|
|
}}
|
|
|
|
>
|
|
|
|
{name}
|
|
|
|
</Button>
|
|
|
|
),
|
|
|
|
},
|
2023-11-12 06:07:58 +00:00
|
|
|
{
|
|
|
|
name: `Alarm sound: ${soundString || "Default"}`,
|
|
|
|
renderItem: (name: string) => (
|
2023-11-09 00:14:11 +00:00
|
|
|
<Button
|
|
|
|
style={{ alignSelf: "flex-start" }}
|
2023-11-12 06:07:58 +00:00
|
|
|
onPress={async () => {
|
|
|
|
const { fileCopyUri } = await DocumentPicker.pickSingle({
|
|
|
|
type: DocumentPicker.types.audio,
|
|
|
|
copyTo: "documentDirectory",
|
|
|
|
});
|
|
|
|
if (!fileCopyUri) return;
|
|
|
|
setValue("sound", fileCopyUri);
|
|
|
|
await update("sound", fileCopyUri);
|
|
|
|
toast("Sound will play after rest timers.");
|
|
|
|
}}
|
2023-11-09 00:14:11 +00:00
|
|
|
>
|
2023-11-12 06:07:58 +00:00
|
|
|
{name}
|
2023-11-09 00:14:11 +00:00
|
|
|
</Button>
|
2023-11-12 06:07:58 +00:00
|
|
|
),
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "Export database",
|
|
|
|
renderItem: (name: string) => (
|
|
|
|
<Button
|
|
|
|
style={{ alignSelf: "flex-start" }}
|
|
|
|
onPress={async () => {
|
|
|
|
const result = await check(
|
|
|
|
PERMISSIONS.ANDROID.WRITE_EXTERNAL_STORAGE
|
|
|
|
);
|
|
|
|
if (result === RESULTS.DENIED || result === RESULTS.BLOCKED)
|
|
|
|
await request(PERMISSIONS.ANDROID.WRITE_EXTERNAL_STORAGE);
|
|
|
|
const path = Dirs.DatabaseDir + "/massive.db";
|
|
|
|
await FileSystem.cpExternal(path, "massive.db", "downloads");
|
|
|
|
toast("Database exported. Check downloads.");
|
|
|
|
}}
|
|
|
|
>
|
|
|
|
{name}
|
|
|
|
</Button>
|
|
|
|
),
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "Import database",
|
|
|
|
renderItem: (name: string) => (
|
|
|
|
<Button
|
|
|
|
style={{ alignSelf: "flex-start" }}
|
|
|
|
onPress={() => setImporting(true)}
|
|
|
|
>
|
|
|
|
{name}
|
|
|
|
</Button>
|
|
|
|
),
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "Delete database",
|
|
|
|
renderItem: (name: string) => (
|
|
|
|
<Button
|
|
|
|
style={{ alignSelf: "flex-start" }}
|
|
|
|
onPress={() => setDeleting(true)}
|
|
|
|
>
|
|
|
|
{name}
|
|
|
|
</Button>
|
|
|
|
),
|
|
|
|
},
|
|
|
|
];
|
2022-12-24 00:36:11 +00:00
|
|
|
|
|
|
|
return (
|
|
|
|
<>
|
2023-08-12 03:22:50 +00:00
|
|
|
<DrawerHeader name="Settings" />
|
2022-12-24 00:36:11 +00:00
|
|
|
|
2023-11-12 06:07:58 +00:00
|
|
|
<Page term={term} search={setTerm}>
|
|
|
|
<FlatList
|
|
|
|
data={data.filter((item) =>
|
|
|
|
item.name.toLowerCase().includes(term.toLowerCase())
|
|
|
|
)}
|
|
|
|
renderItem={({ item }) => item.renderItem(item.name)}
|
|
|
|
style={{ flex: 1, paddingTop: PADDING }}
|
|
|
|
/>
|
2022-10-22 23:35:58 +00:00
|
|
|
</Page>
|
2022-12-08 00:18:41 +00:00
|
|
|
|
|
|
|
<ConfirmDialog
|
2023-08-12 03:22:50 +00:00
|
|
|
title="Are you sure?"
|
2022-12-08 00:18:41 +00:00
|
|
|
onOk={confirmImport}
|
|
|
|
setShow={setImporting}
|
2023-06-27 03:16:59 +00:00
|
|
|
show={importing}
|
|
|
|
>
|
2022-12-08 00:18:41 +00:00
|
|
|
Importing a database overwrites your current data. This action cannot be
|
|
|
|
reversed!
|
|
|
|
</ConfirmDialog>
|
2023-06-29 03:31:24 +00:00
|
|
|
|
|
|
|
<ConfirmDialog
|
2023-08-12 03:22:50 +00:00
|
|
|
title="Are you sure?"
|
2023-06-29 03:31:24 +00:00
|
|
|
onOk={confirmDelete}
|
|
|
|
setShow={setDeleting}
|
|
|
|
show={deleting}
|
|
|
|
>
|
|
|
|
Deleting your database wipes your current data. This action cannot be
|
|
|
|
reversed!
|
|
|
|
</ConfirmDialog>
|
2022-10-22 23:35:58 +00:00
|
|
|
</>
|
2023-08-12 03:22:50 +00:00
|
|
|
);
|
2022-07-03 01:50:01 +00:00
|
|
|
}
|