From a3299c19f7e58efd4de9d863bd19b75019075867 Mon Sep 17 00:00:00 2001 From: Arnaud Vergnet Date: Wed, 5 Aug 2020 13:51:14 +0200 Subject: [PATCH] Improve Settings screen components to match linter --- src/managers/AsyncStorageManager.js | 15 +- src/screens/Other/FeedbackScreen.js | 217 ++++---- src/screens/Other/Settings/SettingsScreen.js | 530 ++++++++++--------- 3 files changed, 425 insertions(+), 337 deletions(-) diff --git a/src/managers/AsyncStorageManager.js b/src/managers/AsyncStorageManager.js index 3b85edb..fc38060 100644 --- a/src/managers/AsyncStorageManager.js +++ b/src/managers/AsyncStorageManager.js @@ -131,7 +131,11 @@ export default class AsyncStorageManager { * @param key * @param value */ - static set(key: string, value: number | string | boolean | {...} | []) { + static set( + key: string, + // eslint-disable-next-line flowtype/no-weak-types + value: number | string | boolean | {...} | Array, + ) { AsyncStorageManager.getInstance().setPreference(key, value); } @@ -142,7 +146,8 @@ export default class AsyncStorageManager { * @returns {string} */ static getString(key: string): string { - return AsyncStorageManager.getInstance().getPreference(key); + const value = AsyncStorageManager.getInstance().getPreference(key); + return value != null ? value : ''; } /** @@ -207,7 +212,11 @@ export default class AsyncStorageManager { * @param key * @param value */ - setPreference(key: string, value: number | string | boolean | {...} | []) { + setPreference( + key: string, + // eslint-disable-next-line flowtype/no-weak-types + value: number | string | boolean | {...} | Array, + ) { if (AsyncStorageManager.PREFERENCES[key] != null) { let convertedValue; if (typeof value === 'string') convertedValue = value; diff --git a/src/screens/Other/FeedbackScreen.js b/src/screens/Other/FeedbackScreen.js index 71d9307..7bf0662 100644 --- a/src/screens/Other/FeedbackScreen.js +++ b/src/screens/Other/FeedbackScreen.js @@ -1,116 +1,139 @@ // @flow import * as React from 'react'; -import {Avatar, Button, Card, Paragraph, withTheme} from "react-native-paper"; -import i18n from "i18n-js"; -import {Linking} from "react-native"; -import type {CustomTheme} from "../../managers/ThemeManager"; -import CollapsibleScrollView from "../../components/Collapsible/CollapsibleScrollView"; +import {Avatar, Button, Card, Paragraph, withTheme} from 'react-native-paper'; +import i18n from 'i18n-js'; +import {Linking} from 'react-native'; +import type {CustomThemeType} from '../../managers/ThemeManager'; +import CollapsibleScrollView from '../../components/Collapsible/CollapsibleScrollView'; -type Props = { - theme: CustomTheme +type PropsType = { + theme: CustomThemeType, }; const links = { - bugsMail: `mailto:app@amicale-insat.fr?subject=[BUG] Application CAMPUS + bugsMail: `mailto:app@amicale-insat.fr?subject=[BUG] Application CAMPUS &body=Coucou Arnaud ça bug c'est nul,\n\n Informations sur ton système si tu sais (iOS ou Android, modèle du tel, version):\n\n\n Nature du problème :\n\n\n Étapes pour reproduire ce pb :\n\n\n\n Stp corrige le pb, bien cordialement.`, - bugsGit: 'https://git.etud.insa-toulouse.fr/vergnet/application-amicale/issues/new', - facebook: "https://www.facebook.com/campus.insat", - feedbackMail: `mailto:app@amicale-insat.fr?subject=[FEEDBACK] Application CAMPUS + bugsGit: + 'https://git.etud.insa-toulouse.fr/vergnet/application-amicale/issues/new', + facebook: 'https://www.facebook.com/campus.insat', + feedbackMail: `mailto:app@amicale-insat.fr?subject=[FEEDBACK] Application CAMPUS &body=Coucou Arnaud j'ai du feedback\n\n\n\nBien cordialement.`, - feedbackGit: "https://git.etud.insa-toulouse.fr/vergnet/application-amicale/issues/new", -} + feedbackGit: + 'https://git.etud.insa-toulouse.fr/vergnet/application-amicale/issues/new', +}; -class FeedbackScreen extends React.Component { +class FeedbackScreen extends React.Component { + /** + * Gets link buttons + * + * @param isBug True if buttons should redirect to bug report methods + * @returns {*} + */ + static getButtons(isBug: boolean): React.Node { + return ( + + + + + + ); + } - /** - * Gets link buttons - * - * @param isBug True if buttons should redirect to bug report methods - * @returns {*} - */ - getButtons(isBug: boolean) { - return ( - - - - - - ); - } + render(): React.Node { + const {theme} = this.props; + return ( + + + ( + + )} + /> + + {i18n.t('screens.feedback.bugsDescription')} + + {i18n.t('screens.feedback.contactMeans')} + + + {FeedbackScreen.getButtons(true)} + - render() { - return ( - - - } - /> - - - {i18n.t('screens.feedback.bugsDescription')} - - - {i18n.t('screens.feedback.contactMeans')} - - - {this.getButtons(true)} - - - - } - /> - - - {i18n.t('screens.feedback.feedbackDescription')} - - - {this.getButtons(false)} - - - ); - } + + ( + + )} + /> + + + {i18n.t('screens.feedback.feedbackDescription')} + + + {FeedbackScreen.getButtons(false)} + + + ); + } } export default withTheme(FeedbackScreen); diff --git a/src/screens/Other/Settings/SettingsScreen.js b/src/screens/Other/Settings/SettingsScreen.js index c9f4ce1..c0b3d2f 100644 --- a/src/screens/Other/Settings/SettingsScreen.js +++ b/src/screens/Other/Settings/SettingsScreen.js @@ -1,267 +1,323 @@ // @flow import * as React from 'react'; -import {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 {View} from 'react-native'; +import i18n from 'i18n-js'; import {Card, List, Switch, ToggleButton, withTheme} from 'react-native-paper'; -import {Appearance} from "react-native-appearance"; -import CustomSlider from "../../../components/Overrides/CustomSlider"; -import {StackNavigationProp} from "@react-navigation/stack"; -import CollapsibleScrollView from "../../../components/Collapsible/CollapsibleScrollView"; +import {Appearance} from 'react-native-appearance'; +import {StackNavigationProp} from '@react-navigation/stack'; +import type {CustomThemeType} from '../../../managers/ThemeManager'; +import ThemeManager from '../../../managers/ThemeManager'; +import AsyncStorageManager from '../../../managers/AsyncStorageManager'; +import CustomSlider from '../../../components/Overrides/CustomSlider'; +import CollapsibleScrollView from '../../../components/Collapsible/CollapsibleScrollView'; -type Props = { - navigation: StackNavigationProp, - theme: CustomTheme, +type PropsType = { + navigation: StackNavigationProp, + theme: CustomThemeType, }; -type State = { - nightMode: boolean, - nightModeFollowSystem: boolean, - notificationReminderSelected: number, - startScreenPickerSelected: string, - isDebugUnlocked: boolean, +type StateType = { + nightMode: boolean, + nightModeFollowSystem: boolean, + startScreenPickerSelected: string, + isDebugUnlocked: boolean, }; /** * Class defining the Settings screen. This screen shows controls to modify app preferences. */ -class SettingsScreen extends React.Component { +class SettingsScreen extends React.Component { + savedNotificationReminder: number; - savedNotificationReminder: number; + /** + * Loads user preferences into state + */ + constructor() { + super(); + const notifReminder = AsyncStorageManager.getString( + AsyncStorageManager.PREFERENCES.proxiwashNotifications.key, + ); + this.savedNotificationReminder = parseInt(notifReminder, 10); + if (Number.isNaN(this.savedNotificationReminder)) + this.savedNotificationReminder = 0; - /** - * Loads user preferences into state - */ - constructor() { - super(); - let notifReminder = AsyncStorageManager.getString(AsyncStorageManager.PREFERENCES.proxiwashNotifications.key); - this.savedNotificationReminder = parseInt(notifReminder); - if (isNaN(this.savedNotificationReminder)) - this.savedNotificationReminder = 0; - - this.state = { - nightMode: ThemeManager.getNightMode(), - nightModeFollowSystem: AsyncStorageManager.getBool(AsyncStorageManager.PREFERENCES.nightModeFollowSystem.key) - && Appearance.getColorScheme() !== 'no-preference', - notificationReminderSelected: this.savedNotificationReminder, - startScreenPickerSelected: AsyncStorageManager.getString(AsyncStorageManager.PREFERENCES.defaultStartScreen.key), - isDebugUnlocked: AsyncStorageManager.getBool(AsyncStorageManager.PREFERENCES.debugUnlocked.key) - }; - } - - /** - * Unlocks debug mode and saves its state to user preferences - */ - unlockDebugMode = () => { - this.setState({isDebugUnlocked: true}); - AsyncStorageManager.set(AsyncStorageManager.PREFERENCES.debugUnlocked.key, true); - } - - /** - * Saves the value for the proxiwash reminder notification time - * - * @param value The value to store - */ - onProxiwashNotifPickerValueChange = (value: number) => { - this.setState({notificationReminderSelected: value}); - AsyncStorageManager.set(AsyncStorageManager.PREFERENCES.proxiwashNotifications.key, value); + this.state = { + nightMode: ThemeManager.getNightMode(), + nightModeFollowSystem: + AsyncStorageManager.getBool( + AsyncStorageManager.PREFERENCES.nightModeFollowSystem.key, + ) && Appearance.getColorScheme() !== 'no-preference', + startScreenPickerSelected: AsyncStorageManager.getString( + AsyncStorageManager.PREFERENCES.defaultStartScreen.key, + ), + isDebugUnlocked: AsyncStorageManager.getBool( + AsyncStorageManager.PREFERENCES.debugUnlocked.key, + ), }; + } - /** - * Saves the value for the proxiwash reminder notification time - * - * @param value The value to store - */ - onStartScreenPickerValueChange = (value: string) => { - if (value != null) { - this.setState({startScreenPickerSelected: value}); - AsyncStorageManager.set(AsyncStorageManager.PREFERENCES.defaultStartScreen.key, value); - } - }; + /** + * Saves the value for the proxiwash reminder notification time + * + * @param value The value to store + */ + onProxiwashNotifPickerValueChange = (value: number) => { + AsyncStorageManager.set( + AsyncStorageManager.PREFERENCES.proxiwashNotifications.key, + value, + ); + }; - /** - * Returns a picker allowing the user to select the proxiwash reminder notification time - * - * @returns {React.Node} - */ - getProxiwashNotifPicker() { - return ( - - ); + /** + * Saves the value for the proxiwash reminder notification time + * + * @param value The value to store + */ + onStartScreenPickerValueChange = (value: string) => { + if (value != null) { + this.setState({startScreenPickerSelected: value}); + AsyncStorageManager.set( + AsyncStorageManager.PREFERENCES.defaultStartScreen.key, + value, + ); } + }; - /** - * Returns a picker allowing the user to select the start screen - * - * @returns {React.Node} - */ - getStartScreenPicker() { - return ( - - - - - - - - ); + /** + * Returns a picker allowing the user to select the proxiwash reminder notification time + * + * @returns {React.Node} + */ + getProxiwashNotifPicker(): React.Node { + const {theme} = this.props; + return ( + + ); + } + + /** + * Returns a picker allowing the user to select the start screen + * + * @returns {React.Node} + */ + getStartScreenPicker(): React.Node { + const {startScreenPickerSelected} = this.state; + return ( + + + + + + + + ); + } + + /** + * Toggles night mode and saves it to preferences + */ + onToggleNightMode = () => { + const {nightMode} = this.state; + ThemeManager.getInstance().setNightMode(!nightMode); + this.setState({nightMode: !nightMode}); + }; + + onToggleNightModeFollowSystem = () => { + const {nightModeFollowSystem} = this.state; + const value = !nightModeFollowSystem; + this.setState({nightModeFollowSystem: value}); + AsyncStorageManager.set( + AsyncStorageManager.PREFERENCES.nightModeFollowSystem.key, + value, + ); + if (value) { + const nightMode = Appearance.getColorScheme() === 'dark'; + ThemeManager.getInstance().setNightMode(nightMode); + this.setState({nightMode}); } + }; - /** - * Toggles night mode and saves it to preferences - */ - onToggleNightMode = () => { - ThemeManager.getInstance().setNightMode(!this.state.nightMode); - this.setState({nightMode: !this.state.nightMode}); - }; + /** + * Gets a list item using a checkbox control + * + * @param onPressCallback The callback when the checkbox state changes + * @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} + */ + static getToggleItem( + onPressCallback: () => void, + icon: string, + title: string, + subtitle: string, + state: boolean, + ): React.Node { + return ( + ( + + )} + right={(): React.Node => ( + + )} + /> + ); + } - onToggleNightModeFollowSystem = () => { - const value = !this.state.nightModeFollowSystem; - this.setState({nightModeFollowSystem: value}); - AsyncStorageManager.set(AsyncStorageManager.PREFERENCES.nightModeFollowSystem.key, value); - if (value) { - const nightMode = Appearance.getColorScheme() === 'dark'; - ThemeManager.getInstance().setNightMode(nightMode); - this.setState({nightMode: nightMode}); - } - }; + getNavigateItem( + route: string, + icon: string, + title: string, + subtitle: string, + onLongPress?: () => void, + ): React.Node { + const {navigation} = this.props; + return ( + { + navigation.navigate(route); + }} + left={({size, color}: {size: number, color: number}): React.Node => ( + + )} + right={({size, color}: {size: number, color: number}): React.Node => ( + + )} + onLongPress={onLongPress} + /> + ); + } - /** - * Gets a list item using a checkbox control - * - * @param onPressCallback The callback when the checkbox state changes - * @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) { - return ( + /** + * Unlocks debug mode and saves its state to user preferences + */ + unlockDebugMode = () => { + this.setState({isDebugUnlocked: true}); + AsyncStorageManager.set( + AsyncStorageManager.PREFERENCES.debugUnlocked.key, + true, + ); + }; + + render(): React.Node { + const {nightModeFollowSystem, nightMode, isDebugUnlocked} = this.state; + return ( + + + + + {Appearance.getColorScheme() !== 'no-preference' + ? SettingsScreen.getToggleItem( + this.onToggleNightModeFollowSystem, + 'theme-light-dark', + i18n.t('screens.settings.nightModeAuto'), + i18n.t('screens.settings.nightModeAutoSub'), + nightModeFollowSystem, + ) + : null} + {Appearance.getColorScheme() === 'no-preference' || + !nightModeFollowSystem + ? SettingsScreen.getToggleItem( + this.onToggleNightMode, + 'theme-light-dark', + i18n.t('screens.settings.nightMode'), + nightMode + ? i18n.t('screens.settings.nightModeSubOn') + : i18n.t('screens.settings.nightModeSubOff'), + nightMode, + ) + : null} } - right={() => - } + title={i18n.t('screens.settings.startScreen')} + description={i18n.t('screens.settings.startScreenSub')} + left={({ + size, + color, + }: { + size: number, + color: number, + }): React.Node => ( + + )} /> - ); - } - - getNavigateItem(route: string, icon: string, title: string, subtitle: string, onLongPress?: () => void) { - return ( + {this.getStartScreenPicker()} + {this.getNavigateItem( + 'dashboard-edit', + 'view-dashboard', + i18n.t('screens.settings.dashboard'), + i18n.t('screens.settings.dashboardSub'), + )} + + + + + this.props.navigation.navigate(route)} - left={props => } - right={props => } - onLongPress={onLongPress} + title={i18n.t('screens.settings.proxiwashNotifReminder')} + description={i18n.t('screens.settings.proxiwashNotifReminderSub')} + left={({ + size, + color, + }: { + size: number, + color: number, + }): React.Node => ( + + )} /> - ); - } - - render() { - return ( - - - - - {Appearance.getColorScheme() !== 'no-preference' ? this.getToggleItem( - this.onToggleNightModeFollowSystem, - 'theme-light-dark', - i18n.t('screens.settings.nightModeAuto'), - i18n.t('screens.settings.nightModeAutoSub'), - this.state.nightModeFollowSystem - ) : null} - { - Appearance.getColorScheme() === 'no-preference' || !this.state.nightModeFollowSystem ? - this.getToggleItem( - this.onToggleNightMode, - 'theme-light-dark', - i18n.t('screens.settings.nightMode'), - this.state.nightMode ? - i18n.t('screens.settings.nightModeSubOn') : - i18n.t('screens.settings.nightModeSubOff'), - this.state.nightMode - ) : null - } - } - /> - {this.getStartScreenPicker()} - {this.getNavigateItem( - "dashboard-edit", - "view-dashboard", - i18n.t('screens.settings.dashboard'), - i18n.t('screens.settings.dashboardSub') - )} - - - - - - } - opened={true} - /> - - {this.getProxiwashNotifPicker()} - - - - - - - {this.state.isDebugUnlocked - ? this.getNavigateItem( - "debug", - "bug-check", - i18n.t('screens.debug.title'), - "" - ) - : null} - {this.getNavigateItem( - "about", - "information", - i18n.t('screens.about.title'), - i18n.t('screens.about.buttonDesc'), - this.unlockDebugMode, - )} - {this.getNavigateItem( - "feedback", - "comment-quote", - i18n.t('screens.feedback.homeButtonTitle'), - i18n.t('screens.feedback.homeButtonSubtitle'), - )} - - - - ); - } + + {this.getProxiwashNotifPicker()} + + + + + + + {isDebugUnlocked + ? this.getNavigateItem( + 'debug', + 'bug-check', + i18n.t('screens.debug.title'), + '', + ) + : null} + {this.getNavigateItem( + 'about', + 'information', + i18n.t('screens.about.title'), + i18n.t('screens.about.buttonDesc'), + this.unlockDebugMode, + )} + {this.getNavigateItem( + 'feedback', + 'comment-quote', + i18n.t('screens.feedback.homeButtonTitle'), + i18n.t('screens.feedback.homeButtonSubtitle'), + )} + + + + ); + } } export default withTheme(SettingsScreen);