feat(settings): New preferences wrapper

Co-authored-by: David Ralph <me@davidcralph.co.uk>
This commit is contained in:
alexsparkes 2024-02-07 20:47:20 +00:00
parent 21184c6c03
commit 85b0e9826c
7 changed files with 289 additions and 263 deletions

View File

@ -1,7 +1,7 @@
import variables from 'modules/variables';
import { PureComponent } from 'react';
import { MdErrorOutline } from 'react-icons/md';
import { MdErrorOutline, MdRefresh } from 'react-icons/md';
import { captureException } from '@sentry/react';
class ErrorBoundary extends PureComponent {
@ -49,16 +49,18 @@ class ErrorBoundary extends PureComponent {
</span>
<div className="buttonsRow">
{this.state.showReport ? (
<button onClick={() => this.reportError()}>
<button className="sideload" onClick={() => this.reportError()}>
{variables.getMessage('modals.main.error_boundary.report_error')}
<MdErrorOutline />
</button>
) : (
<span className="subtitle">
{variables.getMessage('modals.main.error_boundary.sent')}
</span>
)}
<button className="refresh" onClick={() => window.location.reload()}>
<button className="sideload" onClick={() => window.location.reload()}>
{variables.getMessage('modals.main.error_boundary.refresh')}
<MdRefresh />
</button>
</div>
</div>

View File

@ -27,9 +27,11 @@ class Header extends PureComponent {
if (localStorage.getItem(this.props.setting) === 'true') {
localStorage.setItem(this.props.setting, false);
this.setState({ [this.props.setting]: false });
EventBus.emit('toggle', this.props.setting);
} else {
localStorage.setItem(this.props.setting, true);
this.setState({ [this.props.setting]: true });
EventBus.emit('toggle', this.props.setting);
}
variables.stats.postEvent(
@ -91,24 +93,6 @@ class Header extends PureComponent {
</button>
</div>
</div>
{this.props.zoomSetting && (
<SettingsItem
title={variables.getMessage(
'modals.main.settings.sections.appearance.accessibility.widget_zoom',
)}
subtitle={variables.getMessage('modals.main.settings.sections.header.size')}
>
<Slider
name={this.props.zoomSetting}
min="10"
max="400"
default="100"
display="%"
marks={values('zoom')}
category={this.props.zoomCategory || this.props.category}
/>
</SettingsItem>
)}
</>
);
}

View File

@ -0,0 +1,43 @@
import React, { useState } from 'react';
import SettingsItem from './SettingsItem';
import variables from 'modules/variables';
import Slider from './Slider';
import { values } from 'modules/helpers/settings/modals';
import EventBus from 'modules/helpers/eventbus';
const PreferencesWrapper = ({ children, ...props }) => {
const [shown, setShown] = useState(localStorage.getItem(props.setting) === 'true');
EventBus.on('toggle', (setting) => {
if (setting === props.setting) {
setShown(!shown);
}
});
return (
<div className={shown ? '' : 'inactiveSetting'}>
{props.zoomSetting && (
<SettingsItem
title={variables.getMessage(
'modals.main.settings.sections.appearance.accessibility.widget_zoom',
)}
subtitle={variables.getMessage('modals.main.settings.sections.header.size')}
>
<Slider
name={props.zoomSetting}
min="10"
max="400"
default="100"
display="%"
marks={values('zoom')}
category={props.zoomCategory || props.category}
/>
</SettingsItem>
)}
{children}
</div>
);
};
export default PreferencesWrapper;

View File

@ -1,5 +1,5 @@
import variables from 'modules/variables';
import { PureComponent } from 'react';
import { useState } from 'react';
import Modal from 'react-modal';
import { MenuItem } from '@mui/material';
import {
@ -19,115 +19,103 @@ import SettingsItem from '../SettingsItem';
import time_zones from 'components/widgets/time/timezones.json';
export default class AdvancedSettings extends PureComponent {
constructor() {
super();
this.state = {
resetModal: false,
};
}
export default function AdvancedSettings() {
const [resetModal, setResetModal] = useState(false);
const ADVANCED_SECTION = 'modals.main.settings.sections.advanced';
render() {
return (
<>
<span className="mainTitle">
{variables.getMessage('modals.main.settings.sections.advanced.title')}
</span>
<SettingsItem
title={variables.getMessage('modals.main.settings.sections.advanced.offline_mode')}
subtitle={variables.getMessage('modals.main.settings.sections.advanced.offline_subtitle')}
>
<Switch name="offlineMode" element=".other" />
</SettingsItem>
{localStorage.getItem('welcomePreview') !== 'true' && (
<div className="settingsRow">
<div className="content">
<span className="title">
{variables.getMessage('modals.main.settings.sections.advanced.data')}
</span>
<span className="subtitle">
{variables.getMessage('modals.main.settings.sections.advanced.data_subtitle')}
</span>
</div>
<div className="action activityButtons">
<button onClick={() => this.setState({ resetModal: true })}>
{variables.getMessage('modals.main.settings.buttons.reset')}
<ResetIcon />
</button>
<button onClick={() => exportSettings()}>
{variables.getMessage('modals.main.settings.buttons.export')}
<ExportIcon />
</button>
<button onClick={() => document.getElementById('file-input').click()}>
{variables.getMessage('modals.main.settings.buttons.import')}
<ImportIcon />
</button>
</div>
return (
<>
<span className="mainTitle">{variables.getMessage(`${ADVANCED_SECTION}.title`)}</span>
<SettingsItem
title={variables.getMessage('modals.main.settings.sections.advanced.offline_mode')}
subtitle={variables.getMessage('modals.main.settings.sections.advanced.offline_subtitle')}
>
<Switch name="offlineMode" element=".other" />
</SettingsItem>
{localStorage.getItem('welcomePreview') !== 'true' && (
<div className="settingsRow">
<div className="content">
<span className="title">
{variables.getMessage('modals.main.settings.sections.advanced.data')}
</span>
<span className="subtitle">
{variables.getMessage('modals.main.settings.sections.advanced.data_subtitle')}
</span>
</div>
)}
<SettingsItem
title={variables.getMessage('modals.main.settings.sections.advanced.timezone.title')}
subtitle={variables.getMessage(
'modals.main.settings.sections.advanced.timezone.subtitle',
)}
>
<Dropdown name="timezone" category="timezone" manual={true}>
<MenuItem value="auto">
{variables.getMessage('modals.main.settings.sections.advanced.timezone.automatic')}
<div className="action activityButtons">
<button onClick={() => setResetModal(true)}>
{variables.getMessage('modals.main.settings.buttons.reset')}
<ResetIcon />
</button>
<button onClick={() => exportSettings()}>
{variables.getMessage('modals.main.settings.buttons.export')}
<ExportIcon />
</button>
<button onClick={() => document.getElementById('file-input').click()}>
{variables.getMessage('modals.main.settings.buttons.import')}
<ImportIcon />
</button>
</div>
</div>
)}
<SettingsItem
title={variables.getMessage('modals.main.settings.sections.advanced.timezone.title')}
subtitle={variables.getMessage('modals.main.settings.sections.advanced.timezone.subtitle')}
>
<Dropdown name="timezone" category="timezone" manual={true}>
<MenuItem value="auto">
{variables.getMessage('modals.main.settings.sections.advanced.timezone.automatic')}
</MenuItem>
{time_zones.map((timezone) => (
<MenuItem value={timezone} key={timezone}>
{timezone}
</MenuItem>
{time_zones.map((timezone) => (
<MenuItem value={timezone} key={timezone}>
{timezone}
</MenuItem>
))}
</Dropdown>
</SettingsItem>
<SettingsItem
title={variables.getMessage('modals.main.settings.sections.advanced.tab_name')}
subtitle={variables.getMessage(
'modals.main.settings.sections.advanced.tab_name_subtitle',
)}
>
<Text name="tabName" default={variables.getMessage('tabname')} category="other" />
</SettingsItem>
<FileUpload
id="file-input"
accept="application/json"
type="settings"
loadFunction={(e) => importSettings(e)}
))}
</Dropdown>
</SettingsItem>
<SettingsItem
title={variables.getMessage('modals.main.settings.sections.advanced.tab_name')}
subtitle={variables.getMessage('modals.main.settings.sections.advanced.tab_name_subtitle')}
>
<Text name="tabName" default={variables.getMessage('tabname')} category="other" />
</SettingsItem>
<FileUpload
id="file-input"
accept="application/json"
type="settings"
loadFunction={(e) => importSettings(e)}
/>
<SettingsItem
title={variables.getMessage('modals.main.settings.sections.advanced.custom_css')}
subtitle={variables.getMessage(
'modals.main.settings.sections.advanced.custom_css_subtitle',
)}
>
<Text name="customcss" textarea={true} category="other" customcss={true} />
</SettingsItem>
<SettingsItem
title={variables.getMessage('modals.main.settings.sections.experimental.title')}
subtitle={variables.getMessage(
'modals.main.settings.sections.advanced.experimental_warning',
)}
final={true}
>
<Switch
name="experimental"
text={variables.getMessage('modals.main.settings.enabled')}
element=".other"
/>
<SettingsItem
title={variables.getMessage('modals.main.settings.sections.advanced.custom_css')}
subtitle={variables.getMessage(
'modals.main.settings.sections.advanced.custom_css_subtitle',
)}
>
<Text name="customcss" textarea={true} category="other" customcss={true} />
</SettingsItem>
<SettingsItem
title={variables.getMessage('modals.main.settings.sections.experimental.title')}
subtitle={variables.getMessage(
'modals.main.settings.sections.advanced.experimental_warning',
)}
final={true}
>
<Switch
name="experimental"
text={variables.getMessage('modals.main.settings.enabled')}
element=".other"
/>
</SettingsItem>
<Modal
closeTimeoutMS={100}
onRequestClose={() => this.setState({ resetModal: false })}
isOpen={this.state.resetModal}
className="Modal resetmodal mainModal"
overlayClassName="Overlay resetoverlay"
ariaHideApp={false}
>
<ResetModal modalClose={() => this.setState({ resetModal: false })} />
</Modal>
</>
);
}
</SettingsItem>
<Modal
closeTimeoutMS={100}
onRequestClose={() => setResetModal(false)}
isOpen={resetModal}
className="Modal resetmodal mainModal"
overlayClassName="Overlay resetoverlay"
ariaHideApp={false}
>
<ResetModal modalClose={() => setResetModal(false)} />
</Modal>
</>
);
}

View File

@ -1,126 +1,121 @@
import variables from 'modules/variables';
import { PureComponent } from 'react';
import { useState } from 'react';
import Header from '../Header';
import Checkbox from '../Checkbox';
import Dropdown from '../Dropdown';
import SettingsItem from '../SettingsItem';
export default class DateSettings extends PureComponent {
constructor() {
super();
this.state = {
dateType: localStorage.getItem('dateType') || 'long',
};
}
export default function Date() {
const [dateType, setDateType] = useState(localStorage.getItem('dateType') || 'long');
const longSettings = (
<>
<Dropdown
label={variables.getMessage('modals.main.settings.sections.date.long_format')}
name="longFormat"
category="date"
>
<option value="DMY">DMY</option>
<option value="MDY">MDY</option>
<option value="YMD">YMD</option>
</Dropdown>
<Checkbox
name="dayofweek"
text={variables.getMessage('modals.main.settings.sections.date.day_of_week')}
category="date"
/>
<Checkbox
name="datenth"
text={variables.getMessage('modals.main.settings.sections.date.datenth')}
category="date"
/>
</>
);
render() {
const longSettings = (
<>
const shortSettings = (
<>
<Dropdown
label={variables.getMessage('modals.main.settings.sections.date.short_format')}
name="dateFormat"
category="date"
>
<option value="DMY">DMY</option>
<option value="MDY">MDY</option>
<option value="YMD">YMD</option>
</Dropdown>
<Dropdown
label={variables.getMessage('modals.main.settings.sections.date.short_separator.title')}
name="shortFormat"
category="date"
>
<option value="dash">
{variables.getMessage('modals.main.settings.sections.date.short_separator.dash')}
</option>
<option value="dots">
{variables.getMessage('modals.main.settings.sections.date.short_separator.dots')}
</option>
<option value="gaps">
{variables.getMessage('modals.main.settings.sections.date.short_separator.gaps')}
</option>
<option value="slashes">
{variables.getMessage('modals.main.settings.sections.date.short_separator.slashes')}
</option>
</Dropdown>
</>
);
return (
<>
<Header
title={variables.getMessage('modals.main.settings.sections.date.title')}
setting="date"
category="date"
element=".date"
zoomSetting="zoomDate"
switch={true}
/>
<SettingsItem
title={variables.getMessage('modals.main.settings.sections.time.type')}
subtitle={variables.getMessage('modals.main.settings.sections.date.type.subtitle')}
>
<Dropdown
label={variables.getMessage('modals.main.settings.sections.date.long_format')}
name="longFormat"
name="dateType"
onChange={(value) => {
setDateType(value);
localStorage.setItem('dateType', value);
}}
category="date"
>
<option value="DMY">DMY</option>
<option value="MDY">MDY</option>
<option value="YMD">YMD</option>
<option value="long">
{variables.getMessage('modals.main.settings.sections.date.type.long')}
</option>
<option value="short">
{variables.getMessage('modals.main.settings.sections.date.type.short')}
</option>
</Dropdown>
</SettingsItem>
<SettingsItem
title={
dateType === 'long'
? variables.getMessage('modals.main.settings.sections.date.type.long')
: variables.getMessage('modals.main.settings.sections.date.type.short')
}
subtitle={variables.getMessage('modals.main.settings.sections.date.type_settings')}
final={true}
>
{dateType === 'long' ? longSettings : shortSettings}
<Checkbox
name="dayofweek"
text={variables.getMessage('modals.main.settings.sections.date.day_of_week')}
name="weeknumber"
text={variables.getMessage('modals.main.settings.sections.date.week_number')}
category="date"
/>
<Checkbox
name="datenth"
text={variables.getMessage('modals.main.settings.sections.date.datenth')}
name="datezero"
text={variables.getMessage('modals.main.settings.sections.time.digital.zero')}
category="date"
/>
</>
);
const shortSettings = (
<>
<Dropdown
label={variables.getMessage('modals.main.settings.sections.date.short_format')}
name="dateFormat"
category="date"
>
<option value="DMY">DMY</option>
<option value="MDY">MDY</option>
<option value="YMD">YMD</option>
</Dropdown>
<Dropdown
label={variables.getMessage('modals.main.settings.sections.date.short_separator.title')}
name="shortFormat"
category="date"
>
<option value="dash">
{variables.getMessage('modals.main.settings.sections.date.short_separator.dash')}
</option>
<option value="dots">
{variables.getMessage('modals.main.settings.sections.date.short_separator.dots')}
</option>
<option value="gaps">
{variables.getMessage('modals.main.settings.sections.date.short_separator.gaps')}
</option>
<option value="slashes">
{variables.getMessage('modals.main.settings.sections.date.short_separator.slashes')}
</option>
</Dropdown>
</>
);
return (
<>
<Header
title={variables.getMessage('modals.main.settings.sections.date.title')}
setting="date"
category="date"
element=".date"
zoomSetting="zoomDate"
switch={true}
/>
<SettingsItem
title={variables.getMessage('modals.main.settings.sections.time.type')}
subtitle={variables.getMessage('modals.main.settings.sections.date.type.subtitle')}
>
<Dropdown
name="dateType"
onChange={(value) => this.setState({ dateType: value })}
category="date"
>
<option value="long">
{variables.getMessage('modals.main.settings.sections.date.type.long')}
</option>
<option value="short">
{variables.getMessage('modals.main.settings.sections.date.type.short')}
</option>
</Dropdown>
</SettingsItem>
<SettingsItem
title={
this.state.dateType === 'long'
? variables.getMessage('modals.main.settings.sections.date.type.long')
: variables.getMessage('modals.main.settings.sections.date.type.short')
}
subtitle={variables.getMessage('modals.main.settings.sections.date.type_settings')}
final={true}
>
{this.state.dateType === 'long' ? longSettings : shortSettings}
<Checkbox
name="weeknumber"
text={variables.getMessage('modals.main.settings.sections.date.week_number')}
category="date"
/>
<Checkbox
name="datezero"
text={variables.getMessage('modals.main.settings.sections.time.digital.zero')}
category="date"
/>
</SettingsItem>
</>
);
}
</SettingsItem>
</>
);
}

View File

@ -28,6 +28,33 @@ export default class TimeSettings extends PureComponent {
const TIME_SECTION = 'modals.main.settings.sections.time';
const WidgetType = () => {
return (
<SettingsItem
title={variables.getMessage(`${TIME_SECTION}.type`)}
subtitle={variables.getMessage(`${TIME_SECTION}.type_subtitle`)}
final={this.state.timeType === 'percentageComplete'}
>
<Dropdown
name="timeType"
onChange={(value) => this.setState({ timeType: value })}
category="clock"
>
<option value="digital">{variables.getMessage(`${TIME_SECTION}.digital.title`)}</option>
<option value="analogue">
{variables.getMessage(`${TIME_SECTION}.analogue.title`)}
</option>
<option value="percentageComplete">
{variables.getMessage(`${TIME_SECTION}.percentage_complete`)}
</option>
<option value="verticalClock">
{variables.getMessage(`${TIME_SECTION}.vertical_clock.title`)}
</option>
</Dropdown>
</SettingsItem>
);
};
const digitalSettings = (
<SettingsItem
title={variables.getMessage(`${TIME_SECTION}.digital.title`)}
@ -173,28 +200,7 @@ export default class TimeSettings extends PureComponent {
zoomSetting="zoomClock"
switch={true}
/>
<SettingsItem
title={variables.getMessage(`${TIME_SECTION}.type`)}
subtitle={variables.getMessage(`${TIME_SECTION}.type_subtitle`)}
final={this.state.timeType === 'percentageComplete'}
>
<Dropdown
name="timeType"
onChange={(value) => this.setState({ timeType: value })}
category="clock"
>
<option value="digital">{variables.getMessage(`${TIME_SECTION}.digital.title`)}</option>
<option value="analogue">
{variables.getMessage(`${TIME_SECTION}.analogue.title`)}
</option>
<option value="percentageComplete">
{variables.getMessage(`${TIME_SECTION}.percentage_complete`)}
</option>
<option value="verticalClock">
{variables.getMessage(`${TIME_SECTION}.vertical_clock.title`)}
</option>
</Dropdown>
</SettingsItem>
<WidgetType />
{timeSettings}
</>
);

View File

@ -9,6 +9,7 @@ import Dropdown from '../Dropdown';
import Checkbox from '../Checkbox';
import { TextField } from '@mui/material';
import SettingsItem from '../SettingsItem';
import PreferencesWrapper from '../PreferencesWrapper';
export default class TimeSettings extends PureComponent {
constructor() {
@ -194,11 +195,18 @@ export default class TimeSettings extends PureComponent {
zoomCategory="weather"
switch={true}
/>
<WidgetType />
{/* https://stackoverflow.com/a/65328486 when using inputs it may defocus so we do the {} instead of <> */}
{LocationSetting()}
<TemperatureFormat />
{weatherType === '4' && <CustomOptions />}
<PreferencesWrapper
setting="weatherEnabled"
zoomSetting="zoomWeather"
zoomCategory="weather"
switch={true}
>
<WidgetType />
{/* https://stackoverflow.com/a/65328486 when using inputs it may defocus so we do the {} instead of <> */}
{LocationSetting()}
<TemperatureFormat />
{weatherType === '4' && <CustomOptions />}
</PreferencesWrapper>
</>
);
}