Application Android et IOS pour l'amicale des élèves
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.

ProxiwashScreen.js 13KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356
  1. // @flow
  2. import * as React from 'react';
  3. import {Alert, Platform, View} from 'react-native';
  4. import {Body, Card, CardItem, Left, Right, Text} from 'native-base';
  5. import ThemeManager from '../utils/ThemeManager';
  6. import i18n from "i18n-js";
  7. import CustomMaterialIcon from "../components/CustomMaterialIcon";
  8. import FetchedDataSectionList from "../components/FetchedDataSectionList";
  9. import NotificationsManager from "../utils/NotificationsManager";
  10. import PlatformTouchable from "react-native-platform-touchable";
  11. import Touchable from "react-native-platform-touchable";
  12. import AsyncStorageManager from "../utils/AsyncStorageManager";
  13. import * as Expo from "expo";
  14. const DATA_URL = "https://srv-falcon.etud.insa-toulouse.fr/~amicale_app/washinsa/washinsa.json";
  15. const MACHINE_STATES = {
  16. "TERMINE": "0",
  17. "DISPONIBLE": "1",
  18. "EN COURS": "2",
  19. "HS": "3",
  20. "ERREUR": "4"
  21. };
  22. let stateStrings = {};
  23. let modalStateStrings = {};
  24. let stateIcons = {};
  25. let stateColors = {};
  26. /**
  27. * Class defining the app's proxiwash screen. This screen shows information about washing machines and
  28. * dryers, taken from a scrapper reading proxiwash website
  29. */
  30. export default class ProxiwashScreen extends FetchedDataSectionList {
  31. refreshInterval: IntervalID;
  32. /**
  33. * Creates machine state parameters using current theme and translations
  34. */
  35. constructor() {
  36. super(DATA_URL, 1000 * 30); // Refresh every half minute
  37. let colors = ThemeManager.getCurrentThemeVariables();
  38. stateColors[MACHINE_STATES.TERMINE] = colors.proxiwashFinishedColor;
  39. stateColors[MACHINE_STATES.DISPONIBLE] = colors.proxiwashReadyColor;
  40. stateColors[MACHINE_STATES["EN COURS"]] = colors.proxiwashRunningColor;
  41. stateColors[MACHINE_STATES.HS] = colors.proxiwashBrokenColor;
  42. stateColors[MACHINE_STATES.ERREUR] = colors.proxiwashErrorColor;
  43. stateStrings[MACHINE_STATES.TERMINE] = i18n.t('proxiwashScreen.states.finished');
  44. stateStrings[MACHINE_STATES.DISPONIBLE] = i18n.t('proxiwashScreen.states.ready');
  45. stateStrings[MACHINE_STATES["EN COURS"]] = i18n.t('proxiwashScreen.states.running');
  46. stateStrings[MACHINE_STATES.HS] = i18n.t('proxiwashScreen.states.broken');
  47. stateStrings[MACHINE_STATES.ERREUR] = i18n.t('proxiwashScreen.states.error');
  48. modalStateStrings[MACHINE_STATES.TERMINE] = i18n.t('proxiwashScreen.modal.finished');
  49. modalStateStrings[MACHINE_STATES.DISPONIBLE] = i18n.t('proxiwashScreen.modal.ready');
  50. modalStateStrings[MACHINE_STATES["EN COURS"]] = i18n.t('proxiwashScreen.modal.running');
  51. modalStateStrings[MACHINE_STATES.HS] = i18n.t('proxiwashScreen.modal.broken');
  52. modalStateStrings[MACHINE_STATES.ERREUR] = i18n.t('proxiwashScreen.modal.error');
  53. stateIcons[MACHINE_STATES.TERMINE] = 'check-circle';
  54. stateIcons[MACHINE_STATES.DISPONIBLE] = 'radiobox-blank';
  55. stateIcons[MACHINE_STATES["EN COURS"]] = 'progress-check';
  56. stateIcons[MACHINE_STATES.HS] = 'alert-octagram-outline';
  57. stateIcons[MACHINE_STATES.ERREUR] = 'alert';
  58. // let dataString = AsyncStorageManager.getInstance().preferences.proxiwashWatchedMachines.current;
  59. this.state = {
  60. refreshing: false,
  61. firstLoading: true,
  62. fetchedData: {},
  63. // machinesWatched: JSON.parse(dataString),
  64. machinesWatched: [],
  65. };
  66. this.setMinTimeRefresh(30);
  67. }
  68. /**
  69. * Setup notification channel for android and add listeners to detect notifications fired
  70. */
  71. componentDidMount() {
  72. super.componentDidMount();
  73. // Get latest watchlist from server
  74. NotificationsManager.getMachineNotificationWatchlist((fetchedList) => {
  75. this.setState({machinesWatched: fetchedList})
  76. });
  77. // Get updated watchlist after received notification
  78. Expo.Notifications.addListener((notification) => {
  79. NotificationsManager.getMachineNotificationWatchlist((fetchedList) => {
  80. this.setState({machinesWatched: fetchedList})
  81. });
  82. });
  83. if (Platform.OS === 'android') {
  84. Expo.Notifications.createChannelAndroidAsync('reminders', {
  85. name: 'Reminders',
  86. priority: 'max',
  87. vibrate: [0, 250, 250, 250],
  88. });
  89. }
  90. }
  91. getHeaderTranslation() {
  92. return i18n.t("screens.proxiwash");
  93. }
  94. getUpdateToastTranslations() {
  95. return [i18n.t("proxiwashScreen.listUpdated"), i18n.t("proxiwashScreen.listUpdateFail")];
  96. }
  97. getDryersKeyExtractor(item: Object) {
  98. return item !== undefined ? "dryer" + item.number : undefined;
  99. }
  100. getWashersKeyExtractor(item: Object) {
  101. return item !== undefined ? "washer" + item.number : undefined;
  102. }
  103. /**
  104. * Setup notifications for the machine with the given ID.
  105. * One notification will be sent at the end of the program.
  106. * Another will be send a few minutes before the end, based on the value of reminderNotifTime
  107. *
  108. * @param machineId The machine's ID
  109. * @returns {Promise<void>}
  110. */
  111. setupNotifications(machineId: string) {
  112. if (!this.isMachineWatched(machineId)) {
  113. NotificationsManager.setupMachineNotification(machineId, true);
  114. this.saveNotificationToState(machineId);
  115. } else
  116. this.disableNotification(machineId);
  117. }
  118. /**
  119. * Stop scheduled notifications for the machine of the given ID.
  120. * This will also remove the notification if it was already shown.
  121. *
  122. * @param machineId The machine's ID
  123. */
  124. disableNotification(machineId: string) {
  125. let data = this.state.machinesWatched;
  126. if (data.length > 0) {
  127. let arrayIndex = data.indexOf(machineId);
  128. if (arrayIndex !== -1) {
  129. NotificationsManager.setupMachineNotification(machineId, false);
  130. this.removeNotificationFroState(arrayIndex);
  131. }
  132. }
  133. }
  134. /**
  135. * Add the given notifications associated to a machine ID to the watchlist, and save the array to the preferences
  136. *
  137. * @param machineId
  138. */
  139. saveNotificationToState(machineId: string) {
  140. let data = this.state.machinesWatched;
  141. data.push(machineId);
  142. this.updateNotificationState(data);
  143. }
  144. /**
  145. * remove the given index from the watchlist array and save it to preferences
  146. *
  147. * @param index
  148. */
  149. removeNotificationFroState(index: number) {
  150. let data = this.state.machinesWatched;
  151. data.splice(index, 1);
  152. this.updateNotificationState(data);
  153. }
  154. /**
  155. * Set the given data as the watchlist and save it to preferences
  156. *
  157. * @param data
  158. */
  159. updateNotificationState(data: Array<Object>) {
  160. this.setState({machinesWatched: data});
  161. // let prefKey = AsyncStorageManager.getInstance().preferences.proxiwashWatchedMachines.key;
  162. // AsyncStorageManager.getInstance().savePref(prefKey, JSON.stringify(data));
  163. }
  164. /**
  165. * Checks whether the machine of the given ID has scheduled notifications
  166. *
  167. * @param machineID The machine's ID
  168. * @returns {boolean}
  169. */
  170. isMachineWatched(machineID: string) {
  171. return this.state.machinesWatched.indexOf(machineID) !== -1;
  172. }
  173. createDataset(fetchedData: Object) {
  174. return [
  175. {
  176. title: i18n.t('proxiwashScreen.washers'),
  177. icon: 'washing-machine',
  178. data: fetchedData.washers === undefined ? [] : fetchedData.washers,
  179. extraData: super.state,
  180. keyExtractor: this.getWashersKeyExtractor
  181. },
  182. {
  183. title: i18n.t('proxiwashScreen.dryers'),
  184. icon: 'tumble-dryer',
  185. data: fetchedData.dryers === undefined ? [] : fetchedData.dryers,
  186. extraData: super.state,
  187. keyExtractor: this.getDryersKeyExtractor
  188. },
  189. ];
  190. }
  191. hasTabs(): boolean {
  192. return true;
  193. }
  194. /**
  195. * Show an alert fo a machine, allowing to enable/disable notifications if running
  196. *
  197. * @param title
  198. * @param item
  199. * @param isDryer
  200. */
  201. showAlert(title: string, item: Object, isDryer: boolean) {
  202. let buttons = [{text: i18n.t("proxiwashScreen.modal.ok")}];
  203. let message = modalStateStrings[MACHINE_STATES[item.state]];
  204. if (MACHINE_STATES[item.state] === MACHINE_STATES["EN COURS"]) {
  205. buttons = [
  206. {
  207. text: this.isMachineWatched(item.number) ?
  208. i18n.t("proxiwashScreen.modal.disableNotifications") :
  209. i18n.t("proxiwashScreen.modal.enableNotifications"),
  210. onPress: () => this.setupNotifications(item.number)
  211. },
  212. {
  213. text: i18n.t("proxiwashScreen.modal.cancel")
  214. }
  215. ];
  216. message = i18n.t('proxiwashScreen.modal.running',
  217. {
  218. start: item.startTime,
  219. end: item.endTime,
  220. remaining: item.remainingTime
  221. });
  222. } else if (MACHINE_STATES[item.state] === MACHINE_STATES.DISPONIBLE) {
  223. if (isDryer)
  224. message += '\n' + i18n.t('proxiwashScreen.dryersTariff');
  225. else
  226. message += '\n' + i18n.t('proxiwashScreen.washersTariff');
  227. }
  228. Alert.alert(
  229. title,
  230. message,
  231. buttons
  232. );
  233. }
  234. getRightButton(): * {
  235. return (
  236. <Touchable
  237. style={{padding: 6}}
  238. onPress={() => this.props.navigation.navigate('ProxiwashAboutScreen')}>
  239. <CustomMaterialIcon
  240. color={Platform.OS === 'ios' ? ThemeManager.getCurrentThemeVariables().brandPrimary : "#fff"}
  241. icon="information"/>
  242. </Touchable>
  243. );
  244. }
  245. /**
  246. * Get list item to be rendered
  247. *
  248. * @param item The object containing the item's FetchedData
  249. * @param section The object describing the current SectionList section
  250. * @param data The full FetchedData used by the SectionList
  251. * @returns {React.Node}
  252. */
  253. getRenderItem(item: Object, section: Object, data: Object) {
  254. let isMachineRunning = MACHINE_STATES[item.state] === MACHINE_STATES["EN COURS"];
  255. let machineName = (section.title === i18n.t('proxiwashScreen.dryers') ? i18n.t('proxiwashScreen.dryer') : i18n.t('proxiwashScreen.washer')) + ' n°' + item.number;
  256. let isDryer = section.title === i18n.t('proxiwashScreen.dryers');
  257. return (
  258. <Card style={{
  259. flex: 0,
  260. height: 64,
  261. marginLeft: 10,
  262. marginRight: 10
  263. }}>
  264. <CardItem
  265. style={{
  266. backgroundColor: stateColors[MACHINE_STATES[item.state]],
  267. paddingRight: 0,
  268. paddingLeft: 0,
  269. height: '100%',
  270. }}
  271. >
  272. <View style={{
  273. height: 64,
  274. position: 'absolute',
  275. right: 0,
  276. width: item.donePercent !== '' ? (100 - parseInt(item.donePercent)).toString() + '%' : 0,
  277. backgroundColor: ThemeManager.getCurrentThemeVariables().containerBgColor
  278. }}/>
  279. <PlatformTouchable
  280. onPress={() => this.showAlert(machineName, item, isDryer)}
  281. style={{
  282. height: 64,
  283. position: 'absolute',
  284. zIndex: 10, // Make sure the button is above the text
  285. right: 0,
  286. width: '100%'
  287. }}
  288. >
  289. <View/>
  290. </PlatformTouchable>
  291. <Left style={{marginLeft: 10}}>
  292. <CustomMaterialIcon
  293. icon={isDryer ? 'tumble-dryer' : 'washing-machine'}
  294. fontSize={30}
  295. />
  296. <Body>
  297. <Text>
  298. {machineName + ' '}
  299. {this.isMachineWatched(item.number) ?
  300. <CustomMaterialIcon
  301. icon='bell-ring'
  302. color={ThemeManager.getCurrentThemeVariables().brandPrimary}
  303. fontSize={20}
  304. /> : ''}
  305. </Text>
  306. <Text note>
  307. {isMachineRunning ? item.startTime + '/' + item.endTime : ''}
  308. </Text>
  309. </Body>
  310. </Left>
  311. <Right style={{marginRight: 10}}>
  312. <Text style={MACHINE_STATES[item.state] === MACHINE_STATES.TERMINE ?
  313. {fontWeight: 'bold'} : {}}
  314. >
  315. {stateStrings[MACHINE_STATES[item.state]]}
  316. </Text>
  317. <CustomMaterialIcon icon={stateIcons[MACHINE_STATES[item.state]]}
  318. fontSize={25}
  319. />
  320. </Right>
  321. </CardItem>
  322. </Card>);
  323. }
  324. }