From 0b7191887d0907a2b200e2dcea82dd331d0aeb46 Mon Sep 17 00:00:00 2001 From: Arnaud Vergnet Date: Fri, 1 May 2020 15:59:47 +0200 Subject: [PATCH] Improved settings screen elements --- package.json | 1 + .../Animations/AnimatedAccordion.js | 14 ++-- src/components/Overrides/CustomSlider.js | 58 +++++++++++++ src/screens/Other/SettingsScreen.js | 83 ++++++++++--------- 4 files changed, 111 insertions(+), 45 deletions(-) create mode 100644 src/components/Overrides/CustomSlider.js diff --git a/package.json b/package.json index 475eacc..e9098c5 100644 --- a/package.json +++ b/package.json @@ -22,6 +22,7 @@ "@nartc/react-native-barcode-mask": "^1.1.9", "@react-native-community/masked-view": "0.1.6", "@react-native-community/push-notification-ios": "^1.1.1", + "@react-native-community/slider": "^2.0.9", "@react-navigation/bottom-tabs": "^5.1.1", "@react-navigation/drawer": "^5.1.1", "@react-navigation/native": "^5.0.9", diff --git a/src/components/Animations/AnimatedAccordion.js b/src/components/Animations/AnimatedAccordion.js index c113ad1..62c6454 100644 --- a/src/components/Animations/AnimatedAccordion.js +++ b/src/components/Animations/AnimatedAccordion.js @@ -18,7 +18,7 @@ type Props = { } type State = { - expanded: boolean + expanded: boolean, } const AnimatedListIcon = Animatable.createAnimatableComponent(List.Icon); @@ -56,16 +56,14 @@ class AnimatedAccordion extends React.Component { } toggleAccordion = () => { - if (this.chevronRef.current != null) + if (this.chevronRef.current != null) { this.chevronRef.current.transitionTo({rotate: this.state.expanded ? this.animStart : this.animEnd}); - this.setState({expanded: !this.state.expanded}) + this.setState({expanded: !this.state.expanded}) + } }; - shouldComponentUpdate(nextProps: Props) { - if (nextProps.opened != null) - this.state.expanded = nextProps.opened; - this.setupChevron(); - return true; + shouldComponentUpdate(nextProps: Props, nextState: State): boolean { + return nextState.expanded !== this.state.expanded; } render() { diff --git a/src/components/Overrides/CustomSlider.js b/src/components/Overrides/CustomSlider.js new file mode 100644 index 0000000..122ea4a --- /dev/null +++ b/src/components/Overrides/CustomSlider.js @@ -0,0 +1,58 @@ +// @flow + +import * as React from 'react'; +import {Text, withTheme} from 'react-native-paper'; +import {View} from "react-native-animatable"; +import type {CustomTheme} from "../../managers/ThemeManager"; +import Slider, {SliderProps} from "@react-native-community/slider"; + +type Props = { + theme: CustomTheme, + valueSuffix: string, + ...SliderProps +} + +type State = { + currentValue: number, +} + +/** + * Abstraction layer for Modalize component, using custom configuration + * + * @param props Props to pass to the element. Must specify an onRef prop to get an Modalize ref. + * @return {*} + */ +class CustomSlider extends React.Component { + + static defaultProps = { + valueSuffix: "", + } + + state = { + currentValue: this.props.value, + } + + onValueChange = (value: number) => { + this.setState({currentValue: value}); + if (this.props.onValueChange != null) + this.props.onValueChange(value); + } + + render() { + return ( + + + {this.state.currentValue}min + + + + ); + } + +} + +export default withTheme(CustomSlider); + diff --git a/src/screens/Other/SettingsScreen.js b/src/screens/Other/SettingsScreen.js index aca3620..7362d4d 100644 --- a/src/screens/Other/SettingsScreen.js +++ b/src/screens/Other/SettingsScreen.js @@ -1,39 +1,47 @@ // @flow import * as React from 'react'; -import {ScrollView} from "react-native"; +import {ScrollView, View} from "react-native"; +import type {CustomTheme} from "../../managers/ThemeManager"; import ThemeManager from '../../managers/ThemeManager'; import i18n from "i18n-js"; import AsyncStorageManager from "../../managers/AsyncStorageManager"; -import {Card, List, Switch, ToggleButton} from 'react-native-paper'; +import {Card, List, Switch, ToggleButton, withTheme} from 'react-native-paper'; import {Appearance} from "react-native-appearance"; -import AnimatedAccordion from "../../components/Animations/AnimatedAccordion"; +import CustomSlider from "../../components/Overrides/CustomSlider"; type Props = { - navigation: Object, + theme: CustomTheme, }; type State = { nightMode: boolean, nightModeFollowSystem: boolean, - proxiwashNotifPickerSelected: string, + notificationReminderSelected: number, startScreenPickerSelected: string, }; /** * Class defining the Settings screen. This screen shows controls to modify app preferences. */ -export default class SettingsScreen extends React.Component { - state = { - nightMode: ThemeManager.getNightMode(), - nightModeFollowSystem: AsyncStorageManager.getInstance().preferences.nightModeFollowSystem.current === '1' && - Appearance.getColorScheme() !== 'no-preference', - proxiwashNotifPickerSelected: AsyncStorageManager.getInstance().preferences.proxiwashNotifications.current, - startScreenPickerSelected: AsyncStorageManager.getInstance().preferences.defaultStartScreen.current, - }; +class SettingsScreen extends React.Component { + + savedNotificationReminder: number; constructor() { super(); + let notifReminder = AsyncStorageManager.getInstance().preferences.proxiwashNotifications.current; + this.savedNotificationReminder = parseInt(notifReminder); + if (isNaN(this.savedNotificationReminder)) + this.savedNotificationReminder = 0; + + this.state = { + nightMode: ThemeManager.getNightMode(), + nightModeFollowSystem: AsyncStorageManager.getInstance().preferences.nightModeFollowSystem.current === '1' && + Appearance.getColorScheme() !== 'no-preference', + notificationReminderSelected: this.savedNotificationReminder, + startScreenPickerSelected: AsyncStorageManager.getInstance().preferences.defaultStartScreen.current, + }; } /** @@ -41,14 +49,10 @@ export default class SettingsScreen extends React.Component { * * @param value The value to store */ - onProxiwashNotifPickerValueChange = (value: string) => { - if (value != null) { - let key = AsyncStorageManager.getInstance().preferences.proxiwashNotifications.key; - AsyncStorageManager.getInstance().savePref(key, value); - this.setState({ - proxiwashNotifPickerSelected: value - }); - } + onProxiwashNotifPickerValueChange = (value: number) => { + let key = AsyncStorageManager.getInstance().preferences.proxiwashNotifications.key; + AsyncStorageManager.getInstance().savePref(key, value.toString()); + this.setState({notificationReminderSelected: value}) }; /** @@ -73,15 +77,16 @@ export default class SettingsScreen extends React.Component { */ getProxiwashNotifPicker() { return ( - - - - - + thumbTintColor={this.props.theme.colors.primary} + minimumTrackTintColor={this.props.theme.colors.primary} + /> ); } @@ -133,6 +138,7 @@ export default class SettingsScreen extends React.Component { * @param icon The icon name to display on the list item * @param title The text to display as this list item title * @param subtitle The text to display as this list item subtitle + * @param state The current state of the switch * @returns {React.Node} */ getToggleItem(onPressCallback: Function, icon: string, title: string, subtitle: string, state: boolean) { @@ -141,7 +147,7 @@ export default class SettingsScreen extends React.Component { title={title} description={subtitle} left={props => } - right={props => + right={() => { this.state.nightMode ) : null } - } - > - {this.getStartScreenPicker()} - + /> + {this.getStartScreenPicker()} - } - > + opened={true} + /> + {this.getProxiwashNotifPicker()} - + ); } } + +export default withTheme(SettingsScreen);