import * as React from 'react'; import {useEffect, useState} from 'react'; import { CardActions, CardContent, FormControl, Select, Stack, Table, TableBody, TableCell, TableHead, TableRow, useMediaQuery } from "@mui/material"; import Typography from "@mui/material/Typography"; import prefs from "../app/Prefs"; import {Paragraph} from "./styles"; import EditIcon from '@mui/icons-material/Edit'; import CloseIcon from "@mui/icons-material/Close"; import IconButton from "@mui/material/IconButton"; import PlayArrowIcon from '@mui/icons-material/PlayArrow'; import Container from "@mui/material/Container"; import TextField from "@mui/material/TextField"; import MenuItem from "@mui/material/MenuItem"; import Card from "@mui/material/Card"; import Button from "@mui/material/Button"; import {useLiveQuery} from "dexie-react-hooks"; import theme from "./theme"; import Dialog from "@mui/material/Dialog"; import DialogTitle from "@mui/material/DialogTitle"; import DialogContent from "@mui/material/DialogContent"; import DialogActions from "@mui/material/DialogActions"; import userManager from "../app/UserManager"; import {playSound, shuffle, sounds, validUrl} from "../app/utils"; import {useTranslation} from "react-i18next"; const Preferences = () => { return ( ); }; const Notifications = () => { const { t } = useTranslation(); return ( {t("prefs_notifications_title")} ); }; const Sound = () => { const { t } = useTranslation(); const labelId = "prefSound"; const sound = useLiveQuery(async () => prefs.sound()); const handleChange = async (ev) => { await prefs.setSound(ev.target.value); } if (!sound) { return null; // While loading } let description; if (sound === "none") { description = t("prefs_notifications_sound_description_none"); } else { description = t("prefs_notifications_sound_description_some", { sound: sounds[sound].label }); } return (
playSound(sound)} disabled={sound === "none"} aria-label={t("prefs_notifications_sound_play")}>
) }; const MinPriority = () => { const { t } = useTranslation(); const labelId = "prefMinPriority"; const minPriority = useLiveQuery(async () => prefs.minPriority()); const handleChange = async (ev) => { await prefs.setMinPriority(ev.target.value); } if (!minPriority) { return null; // While loading } const priorities = { 1: t("priority_min"), 2: t("priority_low"), 3: t("priority_default"), 4: t("priority_high"), 5: t("priority_max") } let description; if (minPriority === 1) { description = t("prefs_notifications_min_priority_description_any"); } else if (minPriority === 5) { description = t("prefs_notifications_min_priority_description_max"); } else { description = t("prefs_notifications_min_priority_description_x_or_higher", { number: minPriority, name: priorities[minPriority] }); } return ( ) }; const DeleteAfter = () => { const { t } = useTranslation(); const labelId = "prefDeleteAfter"; const deleteAfter = useLiveQuery(async () => prefs.deleteAfter()); const handleChange = async (ev) => { await prefs.setDeleteAfter(ev.target.value); } if (deleteAfter === null || deleteAfter === undefined) { // !deleteAfter will not work with "0" return null; // While loading } const description = (() => { switch (deleteAfter) { case 0: return t("prefs_notifications_delete_after_never_description"); case 10800: return t("prefs_notifications_delete_after_three_hours_description"); case 86400: return t("prefs_notifications_delete_after_one_day_description"); case 604800: return t("prefs_notifications_delete_after_one_week_description"); case 2592000: return t("prefs_notifications_delete_after_one_month_description"); } })(); return ( ) }; const PrefGroup = (props) => { return (
{props.children}
) }; const Pref = (props) => { return (
{props.title}
{props.description &&
{props.description}
}
{props.children}
); }; const Users = () => { const { t } = useTranslation(); const [dialogKey, setDialogKey] = useState(0); const [dialogOpen, setDialogOpen] = useState(false); const users = useLiveQuery(() => userManager.all()); const handleAddClick = () => { setDialogKey(prev => prev+1); setDialogOpen(true); }; const handleDialogCancel = () => { setDialogOpen(false); }; const handleDialogSubmit = async (user) => { setDialogOpen(false); try { await userManager.save(user); console.debug(`[Preferences] User ${user.username} for ${user.baseUrl} added`); } catch (e) { console.log(`[Preferences] Error adding user.`, e); } }; return ( {t("prefs_users_title")} {t("prefs_users_description")} {users?.length > 0 && } ); }; const UserTable = (props) => { const { t } = useTranslation(); const [dialogKey, setDialogKey] = useState(0); const [dialogOpen, setDialogOpen] = useState(false); const [dialogUser, setDialogUser] = useState(null); const handleEditClick = (user) => { setDialogKey(prev => prev+1); setDialogUser(user); setDialogOpen(true); }; const handleDialogCancel = () => { setDialogOpen(false); }; const handleDialogSubmit = async (user) => { setDialogOpen(false); try { await userManager.save(user); console.debug(`[Preferences] User ${user.username} for ${user.baseUrl} updated`); } catch (e) { console.log(`[Preferences] Error updating user.`, e); } }; const handleDeleteClick = async (user) => { try { await userManager.delete(user.baseUrl); console.debug(`[Preferences] User ${user.username} for ${user.baseUrl} deleted`); } catch (e) { console.error(`[Preferences] Error deleting user for ${user.baseUrl}`, e); } }; return ( {t("prefs_users_table_user_header")} {t("prefs_users_table_base_url_header")} {props.users?.map(user => ( {user.username} {user.baseUrl} handleEditClick(user)} aria-label={t("prefs_users_edit_button")}> handleDeleteClick(user)} aria-label={t("prefs_users_delete_button")}> ))}
); }; const UserDialog = (props) => { const { t } = useTranslation(); const [baseUrl, setBaseUrl] = useState(""); const [username, setUsername] = useState(""); const [password, setPassword] = useState(""); const fullScreen = useMediaQuery(theme.breakpoints.down('sm')); const editMode = props.user !== null; const addButtonEnabled = (() => { if (editMode) { return username.length > 0 && password.length > 0; } const baseUrlValid = validUrl(baseUrl); const baseUrlExists = props.users?.map(user => user.baseUrl).includes(baseUrl); return baseUrlValid && !baseUrlExists && username.length > 0 && password.length > 0; })(); const handleSubmit = async () => { props.onSubmit({ baseUrl: baseUrl, username: username, password: password }) }; useEffect(() => { if (editMode) { setBaseUrl(props.user.baseUrl); setUsername(props.user.username); setPassword(props.user.password); } }, [editMode, props.user]); return ( {editMode ? t("prefs_users_dialog_title_edit") : t("prefs_users_dialog_title_add")} {!editMode && setBaseUrl(ev.target.value)} type="url" fullWidth variant="standard" />} setUsername(ev.target.value)} type="text" fullWidth variant="standard" /> setPassword(ev.target.value)} fullWidth variant="standard" /> ); }; const Appearance = () => { const { t } = useTranslation(); return ( {t("prefs_appearance_title")} ); }; const Language = () => { const { t, i18n } = useTranslation(); const labelId = "prefLanguage"; const randomFlags = shuffle(["🇬🇧", "🇺🇸", "🇪🇸", "🇫🇷", "🇧🇬", "🇨🇿", "🇩🇪", "🇵🇱", "🇺🇦", "🇨🇳", "🇮🇹", "🇭🇺", "🇧🇷", "🇳🇱", "🇮🇩", "🇯🇵", "🇷🇺", "🇹🇷"]).slice(0, 3); const title = t("prefs_appearance_language_title") + " " + randomFlags.join(" "); const lang = i18n.language ?? "en"; // Remember: Flags are not languages. Don't put flags next to the language in the list. // Languages names from: https://www.omniglot.com/language/names.htm // Better: Sidebar in Wikipedia: https://en.wikipedia.org/wiki/Bokm%C3%A5l return ( ) }; export default Preferences;