Application Android et IOS pour l'amicale des élèves https://play.google.com/store/apps/details?id=fr.amicaleinsat.application
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

SettingsScreen.js 10KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324
  1. // @flow
  2. import * as React from 'react';
  3. import {View} from 'react-native';
  4. import i18n from 'i18n-js';
  5. import {Card, List, Switch, ToggleButton, withTheme} from 'react-native-paper';
  6. import {Appearance} from 'react-native-appearance';
  7. import {StackNavigationProp} from '@react-navigation/stack';
  8. import type {CustomThemeType} from '../../../managers/ThemeManager';
  9. import ThemeManager from '../../../managers/ThemeManager';
  10. import AsyncStorageManager from '../../../managers/AsyncStorageManager';
  11. import CustomSlider from '../../../components/Overrides/CustomSlider';
  12. import CollapsibleScrollView from '../../../components/Collapsible/CollapsibleScrollView';
  13. import type {ListIconPropsType} from '../../../constants/PaperStyles';
  14. type PropsType = {
  15. navigation: StackNavigationProp,
  16. theme: CustomThemeType,
  17. };
  18. type StateType = {
  19. nightMode: boolean,
  20. nightModeFollowSystem: boolean,
  21. startScreenPickerSelected: string,
  22. isDebugUnlocked: boolean,
  23. };
  24. /**
  25. * Class defining the Settings screen. This screen shows controls to modify app preferences.
  26. */
  27. class SettingsScreen extends React.Component<PropsType, StateType> {
  28. savedNotificationReminder: number;
  29. /**
  30. * Loads user preferences into state
  31. */
  32. constructor() {
  33. super();
  34. const notifReminder = AsyncStorageManager.getString(
  35. AsyncStorageManager.PREFERENCES.proxiwashNotifications.key,
  36. );
  37. this.savedNotificationReminder = parseInt(notifReminder, 10);
  38. if (Number.isNaN(this.savedNotificationReminder))
  39. this.savedNotificationReminder = 0;
  40. this.state = {
  41. nightMode: ThemeManager.getNightMode(),
  42. nightModeFollowSystem:
  43. AsyncStorageManager.getBool(
  44. AsyncStorageManager.PREFERENCES.nightModeFollowSystem.key,
  45. ) && Appearance.getColorScheme() !== 'no-preference',
  46. startScreenPickerSelected: AsyncStorageManager.getString(
  47. AsyncStorageManager.PREFERENCES.defaultStartScreen.key,
  48. ),
  49. isDebugUnlocked: AsyncStorageManager.getBool(
  50. AsyncStorageManager.PREFERENCES.debugUnlocked.key,
  51. ),
  52. };
  53. }
  54. /**
  55. * Saves the value for the proxiwash reminder notification time
  56. *
  57. * @param value The value to store
  58. */
  59. onProxiwashNotifPickerValueChange = (value: number) => {
  60. AsyncStorageManager.set(
  61. AsyncStorageManager.PREFERENCES.proxiwashNotifications.key,
  62. value,
  63. );
  64. };
  65. /**
  66. * Saves the value for the proxiwash reminder notification time
  67. *
  68. * @param value The value to store
  69. */
  70. onStartScreenPickerValueChange = (value: string) => {
  71. if (value != null) {
  72. this.setState({startScreenPickerSelected: value});
  73. AsyncStorageManager.set(
  74. AsyncStorageManager.PREFERENCES.defaultStartScreen.key,
  75. value,
  76. );
  77. }
  78. };
  79. /**
  80. * Returns a picker allowing the user to select the proxiwash reminder notification time
  81. *
  82. * @returns {React.Node}
  83. */
  84. getProxiwashNotifPicker(): React.Node {
  85. const {theme} = this.props;
  86. return (
  87. <CustomSlider
  88. style={{flex: 1, marginHorizontal: 10, height: 50}}
  89. minimumValue={0}
  90. maximumValue={10}
  91. step={1}
  92. value={this.savedNotificationReminder}
  93. onValueChange={this.onProxiwashNotifPickerValueChange}
  94. thumbTintColor={theme.colors.primary}
  95. minimumTrackTintColor={theme.colors.primary}
  96. />
  97. );
  98. }
  99. /**
  100. * Returns a picker allowing the user to select the start screen
  101. *
  102. * @returns {React.Node}
  103. */
  104. getStartScreenPicker(): React.Node {
  105. const {startScreenPickerSelected} = this.state;
  106. return (
  107. <ToggleButton.Row
  108. onValueChange={this.onStartScreenPickerValueChange}
  109. value={startScreenPickerSelected}
  110. style={{marginLeft: 'auto', marginRight: 'auto'}}>
  111. <ToggleButton icon="account-circle" value="services" />
  112. <ToggleButton icon="tshirt-crew" value="proxiwash" />
  113. <ToggleButton icon="triangle" value="home" />
  114. <ToggleButton icon="calendar-range" value="planning" />
  115. <ToggleButton icon="clock" value="planex" />
  116. </ToggleButton.Row>
  117. );
  118. }
  119. /**
  120. * Toggles night mode and saves it to preferences
  121. */
  122. onToggleNightMode = () => {
  123. const {nightMode} = this.state;
  124. ThemeManager.getInstance().setNightMode(!nightMode);
  125. this.setState({nightMode: !nightMode});
  126. };
  127. onToggleNightModeFollowSystem = () => {
  128. const {nightModeFollowSystem} = this.state;
  129. const value = !nightModeFollowSystem;
  130. this.setState({nightModeFollowSystem: value});
  131. AsyncStorageManager.set(
  132. AsyncStorageManager.PREFERENCES.nightModeFollowSystem.key,
  133. value,
  134. );
  135. if (value) {
  136. const nightMode = Appearance.getColorScheme() === 'dark';
  137. ThemeManager.getInstance().setNightMode(nightMode);
  138. this.setState({nightMode});
  139. }
  140. };
  141. /**
  142. * Gets a list item using a checkbox control
  143. *
  144. * @param onPressCallback The callback when the checkbox state changes
  145. * @param icon The icon name to display on the list item
  146. * @param title The text to display as this list item title
  147. * @param subtitle The text to display as this list item subtitle
  148. * @param state The current state of the switch
  149. * @returns {React.Node}
  150. */
  151. static getToggleItem(
  152. onPressCallback: () => void,
  153. icon: string,
  154. title: string,
  155. subtitle: string,
  156. state: boolean,
  157. ): React.Node {
  158. return (
  159. <List.Item
  160. title={title}
  161. description={subtitle}
  162. left={(props: ListIconPropsType): React.Node => (
  163. <List.Icon color={props.color} style={props.style} icon={icon} />
  164. )}
  165. right={(): React.Node => (
  166. <Switch value={state} onValueChange={onPressCallback} />
  167. )}
  168. />
  169. );
  170. }
  171. getNavigateItem(
  172. route: string,
  173. icon: string,
  174. title: string,
  175. subtitle: string,
  176. onLongPress?: () => void,
  177. ): React.Node {
  178. const {navigation} = this.props;
  179. return (
  180. <List.Item
  181. title={title}
  182. description={subtitle}
  183. onPress={() => {
  184. navigation.navigate(route);
  185. }}
  186. left={(props: ListIconPropsType): React.Node => (
  187. <List.Icon color={props.color} style={props.style} icon={icon} />
  188. )}
  189. right={(props: ListIconPropsType): React.Node => (
  190. <List.Icon
  191. color={props.color}
  192. style={props.style}
  193. icon="chevron-right"
  194. />
  195. )}
  196. onLongPress={onLongPress}
  197. />
  198. );
  199. }
  200. /**
  201. * Unlocks debug mode and saves its state to user preferences
  202. */
  203. unlockDebugMode = () => {
  204. this.setState({isDebugUnlocked: true});
  205. AsyncStorageManager.set(
  206. AsyncStorageManager.PREFERENCES.debugUnlocked.key,
  207. true,
  208. );
  209. };
  210. render(): React.Node {
  211. const {nightModeFollowSystem, nightMode, isDebugUnlocked} = this.state;
  212. return (
  213. <CollapsibleScrollView>
  214. <Card style={{margin: 5}}>
  215. <Card.Title title={i18n.t('screens.settings.generalCard')} />
  216. <List.Section>
  217. {Appearance.getColorScheme() !== 'no-preference'
  218. ? SettingsScreen.getToggleItem(
  219. this.onToggleNightModeFollowSystem,
  220. 'theme-light-dark',
  221. i18n.t('screens.settings.nightModeAuto'),
  222. i18n.t('screens.settings.nightModeAutoSub'),
  223. nightModeFollowSystem,
  224. )
  225. : null}
  226. {Appearance.getColorScheme() === 'no-preference' ||
  227. !nightModeFollowSystem
  228. ? SettingsScreen.getToggleItem(
  229. this.onToggleNightMode,
  230. 'theme-light-dark',
  231. i18n.t('screens.settings.nightMode'),
  232. nightMode
  233. ? i18n.t('screens.settings.nightModeSubOn')
  234. : i18n.t('screens.settings.nightModeSubOff'),
  235. nightMode,
  236. )
  237. : null}
  238. <List.Item
  239. title={i18n.t('screens.settings.startScreen')}
  240. description={i18n.t('screens.settings.startScreenSub')}
  241. left={(props: ListIconPropsType): React.Node => (
  242. <List.Icon
  243. color={props.color}
  244. style={props.style}
  245. icon="power"
  246. />
  247. )}
  248. />
  249. {this.getStartScreenPicker()}
  250. {this.getNavigateItem(
  251. 'dashboard-edit',
  252. 'view-dashboard',
  253. i18n.t('screens.settings.dashboard'),
  254. i18n.t('screens.settings.dashboardSub'),
  255. )}
  256. </List.Section>
  257. </Card>
  258. <Card style={{margin: 5}}>
  259. <Card.Title title="Proxiwash" />
  260. <List.Section>
  261. <List.Item
  262. title={i18n.t('screens.settings.proxiwashNotifReminder')}
  263. description={i18n.t('screens.settings.proxiwashNotifReminderSub')}
  264. left={(props: ListIconPropsType): React.Node => (
  265. <List.Icon
  266. color={props.color}
  267. style={props.style}
  268. icon="washing-machine"
  269. />
  270. )}
  271. />
  272. <View style={{marginLeft: 30}}>
  273. {this.getProxiwashNotifPicker()}
  274. </View>
  275. </List.Section>
  276. </Card>
  277. <Card style={{margin: 5}}>
  278. <Card.Title title={i18n.t('screens.settings.information')} />
  279. <List.Section>
  280. {isDebugUnlocked
  281. ? this.getNavigateItem(
  282. 'debug',
  283. 'bug-check',
  284. i18n.t('screens.debug.title'),
  285. '',
  286. )
  287. : null}
  288. {this.getNavigateItem(
  289. 'about',
  290. 'information',
  291. i18n.t('screens.about.title'),
  292. i18n.t('screens.about.buttonDesc'),
  293. this.unlockDebugMode,
  294. )}
  295. {this.getNavigateItem(
  296. 'feedback',
  297. 'comment-quote',
  298. i18n.t('screens.feedback.homeButtonTitle'),
  299. i18n.t('screens.feedback.homeButtonSubtitle'),
  300. )}
  301. </List.Section>
  302. </Card>
  303. </CollapsibleScrollView>
  304. );
  305. }
  306. }
  307. export default withTheme(SettingsScreen);