// @flow import * as React from 'react'; import {Alert, Platform, View} from 'react-native'; import {Body, Card, CardItem, Left, Right, Text} from 'native-base'; import ThemeManager from '../../utils/ThemeManager'; import i18n from "i18n-js"; import CustomMaterialIcon from "../../components/CustomMaterialIcon"; import FetchedDataSectionList from "../../components/FetchedDataSectionList"; import NotificationsManager from "../../utils/NotificationsManager"; import PlatformTouchable from "react-native-platform-touchable"; import Touchable from "react-native-platform-touchable"; import AsyncStorageManager from "../../utils/AsyncStorageManager"; import * as Expo from "expo"; const DATA_URL = "https://srv-falcon.etud.insa-toulouse.fr/~amicale_app/washinsa/washinsa.json"; const MACHINE_STATES = { "TERMINE": "0", "DISPONIBLE": "1", "EN COURS": "2", "HS": "3", "ERREUR": "4" }; let stateStrings = {}; let modalStateStrings = {}; let stateIcons = {}; let stateColors = {}; const REFRESH_TIME = 1000 * 10; // Refresh every 10 seconds /** * Class defining the app's proxiwash screen. This screen shows information about washing machines and * dryers, taken from a scrapper reading proxiwash website */ export default class ProxiwashScreen extends FetchedDataSectionList { /** * Creates machine state parameters using current theme and translations */ constructor() { super(DATA_URL, REFRESH_TIME); let colors = ThemeManager.getCurrentThemeVariables(); stateColors[MACHINE_STATES.TERMINE] = colors.proxiwashFinishedColor; stateColors[MACHINE_STATES.DISPONIBLE] = colors.proxiwashReadyColor; stateColors[MACHINE_STATES["EN COURS"]] = colors.proxiwashRunningColor; stateColors[MACHINE_STATES.HS] = colors.proxiwashBrokenColor; stateColors[MACHINE_STATES.ERREUR] = colors.proxiwashErrorColor; stateStrings[MACHINE_STATES.TERMINE] = i18n.t('proxiwashScreen.states.finished'); stateStrings[MACHINE_STATES.DISPONIBLE] = i18n.t('proxiwashScreen.states.ready'); stateStrings[MACHINE_STATES["EN COURS"]] = i18n.t('proxiwashScreen.states.running'); stateStrings[MACHINE_STATES.HS] = i18n.t('proxiwashScreen.states.broken'); stateStrings[MACHINE_STATES.ERREUR] = i18n.t('proxiwashScreen.states.error'); modalStateStrings[MACHINE_STATES.TERMINE] = i18n.t('proxiwashScreen.modal.finished'); modalStateStrings[MACHINE_STATES.DISPONIBLE] = i18n.t('proxiwashScreen.modal.ready'); modalStateStrings[MACHINE_STATES["EN COURS"]] = i18n.t('proxiwashScreen.modal.running'); modalStateStrings[MACHINE_STATES.HS] = i18n.t('proxiwashScreen.modal.broken'); modalStateStrings[MACHINE_STATES.ERREUR] = i18n.t('proxiwashScreen.modal.error'); stateIcons[MACHINE_STATES.TERMINE] = 'check-circle'; stateIcons[MACHINE_STATES.DISPONIBLE] = 'radiobox-blank'; stateIcons[MACHINE_STATES["EN COURS"]] = 'progress-check'; stateIcons[MACHINE_STATES.HS] = 'alert-octagram-outline'; stateIcons[MACHINE_STATES.ERREUR] = 'alert'; // let dataString = AsyncStorageManager.getInstance().preferences.proxiwashWatchedMachines.current; this.state = { refreshing: false, firstLoading: true, fetchedData: {}, // machinesWatched: JSON.parse(dataString), machinesWatched: [], }; this.setMinTimeRefresh(30); this.navigateToAboutScreen = this.navigateToAboutScreen.bind(this); } /** * Setup notification channel for android and add listeners to detect notifications fired */ componentDidMount() { super.componentDidMount(); if (AsyncStorageManager.getInstance().preferences.expoToken.current !== '') { // Get latest watchlist from server NotificationsManager.getMachineNotificationWatchlist((fetchedList) => { this.setState({machinesWatched: fetchedList}) }); // Get updated watchlist after received notification Expo.Notifications.addListener(() => { NotificationsManager.getMachineNotificationWatchlist((fetchedList) => { this.setState({machinesWatched: fetchedList}) }); }); if (Platform.OS === 'android') { Expo.Notifications.createChannelAndroidAsync('reminders', { name: 'Reminders', priority: 'max', vibrate: [0, 250, 250, 250], }); } } } getHeaderTranslation() { return i18n.t("screens.proxiwash"); } getUpdateToastTranslations() { return [i18n.t("proxiwashScreen.listUpdated"), i18n.t("proxiwashScreen.listUpdateFail")]; } getDryersKeyExtractor(item: Object) { return item !== undefined ? "dryer" + item.number : undefined; } getWashersKeyExtractor(item: Object) { return item !== undefined ? "washer" + item.number : undefined; } /** * Setup notifications for the machine with the given ID. * One notification will be sent at the end of the program. * Another will be send a few minutes before the end, based on the value of reminderNotifTime * * @param machineId The machine's ID * @returns {Promise} */ setupNotifications(machineId: string) { if (AsyncStorageManager.getInstance().preferences.expoToken.current !== '') { if (!this.isMachineWatched(machineId)) { NotificationsManager.setupMachineNotification(machineId, true); this.saveNotificationToState(machineId); } else this.disableNotification(machineId); } else { this.showNotificationsDisabledWarning(); } } showNotificationsDisabledWarning() { Alert.alert( i18n.t("proxiwashScreen.modal.notificationErrorTitle"), i18n.t("proxiwashScreen.modal.notificationErrorDescription"), ); } /** * Stop scheduled notifications for the machine of the given ID. * This will also remove the notification if it was already shown. * * @param machineId The machine's ID */ disableNotification(machineId: string) { let data = this.state.machinesWatched; if (data.length > 0) { let arrayIndex = data.indexOf(machineId); if (arrayIndex !== -1) { NotificationsManager.setupMachineNotification(machineId, false); this.removeNotificationFroState(arrayIndex); } } } /** * Add the given notifications associated to a machine ID to the watchlist, and save the array to the preferences * * @param machineId */ saveNotificationToState(machineId: string) { let data = this.state.machinesWatched; data.push(machineId); this.updateNotificationState(data); } /** * remove the given index from the watchlist array and save it to preferences * * @param index */ removeNotificationFroState(index: number) { let data = this.state.machinesWatched; data.splice(index, 1); this.updateNotificationState(data); } /** * Set the given data as the watchlist and save it to preferences * * @param data */ updateNotificationState(data: Array) { this.setState({machinesWatched: data}); // let prefKey = AsyncStorageManager.getInstance().preferences.proxiwashWatchedMachines.key; // AsyncStorageManager.getInstance().savePref(prefKey, JSON.stringify(data)); } /** * Checks whether the machine of the given ID has scheduled notifications * * @param machineID The machine's ID * @returns {boolean} */ isMachineWatched(machineID: string) { return this.state.machinesWatched.indexOf(machineID) !== -1; } createDataset(fetchedData: Object) { return [ { title: i18n.t('proxiwashScreen.washers'), icon: 'washing-machine', data: fetchedData.washers === undefined ? [] : fetchedData.washers, extraData: super.state, keyExtractor: this.getWashersKeyExtractor }, { title: i18n.t('proxiwashScreen.dryers'), icon: 'tumble-dryer', data: fetchedData.dryers === undefined ? [] : fetchedData.dryers, extraData: super.state, keyExtractor: this.getDryersKeyExtractor }, ]; } hasTabs(): boolean { return true; } /** * Show an alert fo a machine, allowing to enable/disable notifications if running * * @param title * @param item * @param isDryer */ showAlert(title: string, item: Object, isDryer: boolean) { let buttons = [{text: i18n.t("proxiwashScreen.modal.ok")}]; let message = modalStateStrings[MACHINE_STATES[item.state]]; if (MACHINE_STATES[item.state] === MACHINE_STATES["EN COURS"]) { buttons = [ { text: this.isMachineWatched(item.number) ? i18n.t("proxiwashScreen.modal.disableNotifications") : i18n.t("proxiwashScreen.modal.enableNotifications"), onPress: () => this.setupNotifications(item.number) }, { text: i18n.t("proxiwashScreen.modal.cancel") } ]; message = i18n.t('proxiwashScreen.modal.running', { start: item.startTime, end: item.endTime, remaining: item.remainingTime }); } else if (MACHINE_STATES[item.state] === MACHINE_STATES.DISPONIBLE) { if (isDryer) message += '\n' + i18n.t('proxiwashScreen.dryersTariff'); else message += '\n' + i18n.t('proxiwashScreen.washersTariff'); } Alert.alert( title, message, buttons ); } navigateToAboutScreen() { this.props.navigation.navigate('ProxiwashAboutScreen'); } getRightButton(): * { return ( ); } /** * Get list item to be rendered * * @param item The object containing the item's FetchedData * @param section The object describing the current SectionList section * @returns {React.Node} */ getRenderItem(item: Object, section: Object) { let isMachineRunning = MACHINE_STATES[item.state] === MACHINE_STATES["EN COURS"]; let machineName = (section.title === i18n.t('proxiwashScreen.dryers') ? i18n.t('proxiwashScreen.dryer') : i18n.t('proxiwashScreen.washer')) + ' n°' + item.number; let isDryer = section.title === i18n.t('proxiwashScreen.dryers'); return ( this.showAlert(machineName, item, isDryer)} style={{ height: 64, position: 'absolute', zIndex: 10, // Make sure the button is above the text right: 0, width: '100%' }} > {machineName + ' '} {this.isMachineWatched(item.number) ? : ''} {isMachineRunning ? item.startTime + '/' + item.endTime : ''} {stateStrings[MACHINE_STATES[item.state]]} ); } }