diff --git a/SettingsPage.tsx b/SettingsPage.tsx index 662fb95..f0dba58 100644 --- a/SettingsPage.tsx +++ b/SettingsPage.tsx @@ -2,24 +2,23 @@ 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"; -import { NativeModules, ScrollView } from "react-native"; +import { FlatList, NativeModules } from "react-native"; import DocumentPicker from "react-native-document-picker"; import { Dirs, FileSystem } from "react-native-file-access"; import { Button } from "react-native-paper"; -import { check, PERMISSIONS, request, RESULTS } from "react-native-permissions"; +import { PERMISSIONS, RESULTS, check, request } from "react-native-permissions"; import AppInput from "./AppInput"; import ConfirmDialog from "./ConfirmDialog"; -import { MARGIN } from "./constants"; +import DrawerHeader from "./DrawerHeader"; +import Page from "./Page"; +import Select from "./Select"; +import Switch from "./Switch"; +import { PADDING } from "./constants"; import { AppDataSource } from "./data-source"; import { setRepo, settingsRepo } from "./db"; import { DrawerParams } from "./drawer-param-list"; -import DrawerHeader from "./DrawerHeader"; -import Input from "./input"; import { darkOptions, lightOptions, themeOptions } from "./options"; -import Page from "./Page"; -import Select from "./Select"; import Settings from "./settings"; -import Switch from "./Switch"; import { toast } from "./toast"; import { useTheme } from "./use-theme"; @@ -42,6 +41,11 @@ const twentyFours = [ "yyyy.MM.d", ]; +interface Item { + name: string; + renderItem: (name: string) => React.JSX.Element; +} + export default function SettingsPage() { const [ignoring, setIgnoring] = useState(false); const [term, setTerm] = useState(""); @@ -88,229 +92,6 @@ export default function SettingsPage() { return split.pop(); }, [settings.sound]); - const changeSound = useCallback(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."); - }, [setValue, update]); - - const switches: Input[] = useMemo( - () => [ - { name: "Rest timers", value: settings.alarm, key: "alarm" }, - { name: "Vibrate", value: settings.vibrate, key: "vibrate" }, - { name: "Disable sound", value: settings.noSound, key: "noSound" }, - { name: "Notifications", value: settings.notify, key: "notify" }, - { name: "Show images", value: settings.images, key: "images" }, - { name: "Show unit", value: settings.showUnit, key: "showUnit" }, - { name: "Show steps", value: settings.steps, key: "steps" }, - { name: "Show date", value: settings.showDate, key: "showDate" }, - { name: "Automatic backup", value: settings.backup, key: "backup" }, - ], - [settings] - ); - - const filter = useCallback( - ({ name }) => name.toLowerCase().includes(term.toLowerCase()), - [term] - ); - - const changeBoolean = useCallback( - async (key: keyof Settings, value: boolean) => { - setValue(key, value); - await update(key, value); - switch (key) { - case "alarm": - if (value) toast("Timers will now run after each set."); - else toast("Stopped timers running after each set."); - const canNotify = await check(PERMISSIONS.ANDROID.POST_NOTIFICATIONS); - if (canNotify === RESULTS.DENIED || canNotify === RESULTS.BLOCKED) - await request(PERMISSIONS.ANDROID.POST_NOTIFICATIONS); - if (value && !ignoring) NativeModules.SettingsModule.ignoreBattery(); - return; - case "vibrate": - if (value) toast("Alarms will now vibrate."); - else toast("Alarms will no longer vibrate."); - return; - case "notify": - if (value) toast("Show notifications for new records."); - else toast("Stopped notifications for new records."); - return; - case "images": - if (value) toast("Show images for sets."); - else toast("Hid images for sets."); - return; - case "showUnit": - if (value) toast("Show option to select unit for sets."); - else toast("Hid unit option for sets."); - return; - case "steps": - if (value) toast("Show steps for exercises."); - else toast("Hid steps for exercises."); - return; - case "showDate": - if (value) toast("Show date for sets."); - else toast("Hid date on sets."); - return; - case "noSound": - if (value) toast("Alarms will no longer make a sound."); - else toast("Enabled sound for alarms."); - return; - case "backup": - if (value) { - const result = await DocumentPicker.pickDirectory(); - toast("Backup database daily."); - NativeModules.BackupModule.start(result.uri); - } else { - toast("Stopped backing up daily"); - NativeModules.BackupModule.stop(); - } - return; - } - }, - [ignoring, setValue, update] - ); - - const renderSwitch = useCallback( - (item: Input) => ( - changeBoolean(item.key, value)} - title={item.name} - /> - ), - [changeBoolean] - ); - - const switchesMarkup = useMemo( - () => switches.filter(filter).map((s) => renderSwitch(s)), - [filter, switches, renderSwitch] - ); - - const changeString = useCallback( - async (key: keyof Settings, value: string) => { - setValue(key, value); - await update(key, value); - switch (key) { - case "date": - return toast("Changed date format"); - case "darkColor": - setDarkColor(value); - return toast("Set primary color for dark mode."); - case "lightColor": - setLightColor(value); - return toast("Set primary color for light mode."); - case "vibrate": - return toast("Set primary color for light mode."); - case "sound": - return toast("Sound will play after rest timers."); - case "theme": - setTheme(value as string); - 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."); - return; - } - }, - [update, setTheme, setDarkColor, setLightColor, setValue] - ); - - const changeNumber = useCallback( - async (key: keyof Settings, value: number) => { - setValue(key, value); - await update(key, value); - switch (key) { - case "duration": - return toast("Changed duration of alarm vibrations."); - } - }, - [update, setValue] - ); - - const numberInputs: Input[] = useMemo( - () => [ - { - name: "Vibration duration (ms)", - value: settings.duration, - key: "duration", - }, - ], - [settings] - ); - - const renderNumber = useCallback( - (item: Input) => ( - changeString(item.key, value)} - onSubmitEditing={(e) => - changeNumber(item.key, Number(e.nativeEvent.text)) - } - keyboardType="numeric" - blurOnSubmit - /> - ), - [changeString, changeNumber] - ); - - const numbersMarkup = useMemo( - () => numberInputs.filter(filter).map((s) => renderNumber(s)), - [numberInputs, filter, renderNumber] - ); - - const selects: Input[] = useMemo(() => { - const today = new Date(); - return [ - { name: "Theme", value: theme, items: themeOptions, key: "theme" }, - { - name: "Dark color", - value: darkColor, - items: lightOptions, - key: "darkColor", - }, - { - name: "Light color", - value: lightColor, - items: darkOptions, - key: "lightColor", - }, - { - name: "Date format", - value: settings.date, - items: formatOptions.map((option) => ({ - label: format(today, option), - value: option, - })), - key: "date", - }, - ]; - }, [settings, darkColor, formatOptions, theme, lightColor]); - - const renderSelect = useCallback( - (input: Input) => ( - { + 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) => ( + { + setValue("lightColor", value); + setLightColor(value); + await update("lightColor", value); + toast("Set primary color for light mode."); + }} + /> + ), + }, + { + name: "Date format", + renderItem: (name: string) => ( +