Compare commits
17 commits
7fb4de3c5b
...
ddfac76f4e
| Author | SHA1 | Date | |
|---|---|---|---|
| ddfac76f4e | |||
| 097ea5379a | |||
| e96f55d142 | |||
| 2dab27de22 | |||
| 3d0e03cb9d | |||
| 854e03e893 | |||
| 885bf239d8 | |||
| 9e4e340302 | |||
| ea16a1f50f | |||
| 0b7191887d | |||
| 517e75f4b9 | |||
| cb522466c7 | |||
| eda9edd21c | |||
| b83b142942 | |||
| 65eb4dd77b | |||
| aa2fad344a | |||
| 1835fcadf9 |
23 changed files with 414 additions and 170 deletions
142
__tests__/utils/Proxiwash.test.js
Normal file
142
__tests__/utils/Proxiwash.test.js
Normal file
|
|
@ -0,0 +1,142 @@
|
|||
import React from 'react';
|
||||
import {getCleanedMachineWatched, getMachineEndDate, getMachineOfId, isMachineWatched} from "../../src/utils/Proxiwash";
|
||||
|
||||
test('getMachineEndDate', () => {
|
||||
jest.spyOn(Date, 'now')
|
||||
.mockImplementation(() =>
|
||||
new Date('2020-01-14T15:00:00.000Z').getTime()
|
||||
);
|
||||
let expectDate = new Date('2020-01-14T15:00:00.000Z');
|
||||
expectDate.setHours(23);
|
||||
expectDate.setMinutes(10);
|
||||
expect(getMachineEndDate({endTime: "23:10"}).getTime()).toBe(expectDate.getTime());
|
||||
|
||||
expectDate.setHours(16);
|
||||
expectDate.setMinutes(30);
|
||||
expect(getMachineEndDate({endTime: "16:30"}).getTime()).toBe(expectDate.getTime());
|
||||
|
||||
expect(getMachineEndDate({endTime: "15:30"})).toBeNull();
|
||||
|
||||
expect(getMachineEndDate({endTime: "13:10"})).toBeNull();
|
||||
|
||||
jest.spyOn(Date, 'now')
|
||||
.mockImplementation(() =>
|
||||
new Date('2020-01-14T23:00:00.000Z').getTime()
|
||||
);
|
||||
expectDate = new Date('2020-01-14T23:00:00.000Z');
|
||||
expectDate.setHours(0);
|
||||
expectDate.setMinutes(30);
|
||||
expect(getMachineEndDate({endTime: "00:30"}).getTime()).toBe(expectDate.getTime());
|
||||
});
|
||||
|
||||
test('isMachineWatched', () => {
|
||||
let machineList = [
|
||||
{
|
||||
number: "0",
|
||||
endTime: "23:30",
|
||||
},
|
||||
{
|
||||
number: "1",
|
||||
endTime: "20:30",
|
||||
},
|
||||
];
|
||||
expect(isMachineWatched({number: "0", endTime: "23:30"}, machineList)).toBeTrue();
|
||||
expect(isMachineWatched({number: "1", endTime: "20:30"}, machineList)).toBeTrue();
|
||||
expect(isMachineWatched({number: "3", endTime: "20:30"}, machineList)).toBeFalse();
|
||||
expect(isMachineWatched({number: "1", endTime: "23:30"}, machineList)).toBeFalse();
|
||||
});
|
||||
|
||||
test('getMachineOfId', () => {
|
||||
let machineList = [
|
||||
{
|
||||
number: "0",
|
||||
},
|
||||
{
|
||||
number: "1",
|
||||
},
|
||||
];
|
||||
expect(getMachineOfId("0", machineList)).toStrictEqual({number: "0"});
|
||||
expect(getMachineOfId("1", machineList)).toStrictEqual({number: "1"});
|
||||
expect(getMachineOfId("3", machineList)).toBeNull();
|
||||
});
|
||||
|
||||
test('getCleanedMachineWatched', () => {
|
||||
let machineList = [
|
||||
{
|
||||
number: "0",
|
||||
endTime: "23:30",
|
||||
},
|
||||
{
|
||||
number: "1",
|
||||
endTime: "20:30",
|
||||
},
|
||||
{
|
||||
number: "2",
|
||||
endTime: "",
|
||||
},
|
||||
];
|
||||
let watchList = [
|
||||
{
|
||||
number: "0",
|
||||
endTime: "23:30",
|
||||
},
|
||||
{
|
||||
number: "1",
|
||||
endTime: "20:30",
|
||||
},
|
||||
{
|
||||
number: "2",
|
||||
endTime: "",
|
||||
},
|
||||
];
|
||||
let cleanedList = watchList;
|
||||
expect(getCleanedMachineWatched(watchList, machineList)).toStrictEqual(cleanedList);
|
||||
|
||||
watchList = [
|
||||
{
|
||||
number: "0",
|
||||
endTime: "23:30",
|
||||
},
|
||||
{
|
||||
number: "1",
|
||||
endTime: "20:30",
|
||||
},
|
||||
{
|
||||
number: "2",
|
||||
endTime: "15:30",
|
||||
},
|
||||
];
|
||||
cleanedList = [
|
||||
{
|
||||
number: "0",
|
||||
endTime: "23:30",
|
||||
},
|
||||
{
|
||||
number: "1",
|
||||
endTime: "20:30",
|
||||
},
|
||||
];
|
||||
expect(getCleanedMachineWatched(watchList, machineList)).toStrictEqual(cleanedList);
|
||||
|
||||
watchList = [
|
||||
{
|
||||
number: "0",
|
||||
endTime: "23:30",
|
||||
},
|
||||
{
|
||||
number: "1",
|
||||
endTime: "20:31",
|
||||
},
|
||||
{
|
||||
number: "3",
|
||||
endTime: "15:30",
|
||||
},
|
||||
];
|
||||
cleanedList = [
|
||||
{
|
||||
number: "0",
|
||||
endTime: "23:30",
|
||||
},
|
||||
];
|
||||
expect(getCleanedMachineWatched(watchList, machineList)).toStrictEqual(cleanedList);
|
||||
});
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<resources>
|
||||
<color name="activityBackground">#ffffff</color>
|
||||
<color name="activityBackground">#be1522</color>
|
||||
<color name="navigationBarColor">#121212</color>
|
||||
<color name="colorPrimaryDark">#be1522</color>
|
||||
<color name="colorPrimary">#be1522</color>
|
||||
|
|
|
|||
Binary file not shown.
|
Before Width: | Height: | Size: 35 KiB After Width: | Height: | Size: 35 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 26 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 87 KiB |
41
package.json
41
package.json
|
|
@ -20,12 +20,13 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"@nartc/react-native-barcode-mask": "^1.1.9",
|
||||
"@react-native-community/masked-view": "0.1.6",
|
||||
"@react-native-community/async-storage": "^1.9.0",
|
||||
"@react-native-community/masked-view": "^0.1.10",
|
||||
"@react-native-community/push-notification-ios": "^1.1.1",
|
||||
"@react-navigation/bottom-tabs": "^5.1.1",
|
||||
"@react-navigation/drawer": "^5.1.1",
|
||||
"@react-navigation/native": "^5.0.9",
|
||||
"@react-navigation/stack": "^5.1.1",
|
||||
"@react-native-community/slider": "^2.0.9",
|
||||
"@react-navigation/bottom-tabs": "^5.3.2",
|
||||
"@react-navigation/native": "^5.2.2",
|
||||
"@react-navigation/stack": "^5.2.17",
|
||||
"i18n-js": "^3.3.0",
|
||||
"react": "~16.9.0",
|
||||
"react-dom": "16.9.0",
|
||||
|
|
@ -43,29 +44,29 @@
|
|||
"react-native-linear-gradient": "^2.5.6",
|
||||
"react-native-localize": "^1.4.0",
|
||||
"react-native-modalize": "^1.3.6",
|
||||
"react-native-paper": "^3.8.0",
|
||||
"react-native-permissions": "^2.1.3",
|
||||
"react-native-push-notification": "^3.3.0",
|
||||
"react-native-reanimated": "~1.7.0",
|
||||
"react-native-paper": "^3.9.0",
|
||||
"react-native-permissions": "^2.1.4",
|
||||
"react-native-push-notification": "^3.3.1",
|
||||
"react-native-reanimated": "^1.8.0",
|
||||
"react-native-render-html": "^4.1.2",
|
||||
"react-native-safe-area-context": "0.7.3",
|
||||
"react-native-screens": "~2.2.0",
|
||||
"react-native-screens": "^2.7.0",
|
||||
"react-native-splash-screen": "^3.2.0",
|
||||
"react-native-vector-icons": "^6.6.0",
|
||||
"react-native-web": "~0.11.7",
|
||||
"react-native-webview": "8.1.1",
|
||||
"react-native-webview": "^9.4.0",
|
||||
"react-navigation-collapsible": "^5.5.0",
|
||||
"react-navigation-header-buttons": "^3.0.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.6.2",
|
||||
"@babel/runtime": "^7.6.2",
|
||||
"@react-native-community/eslint-config": "^0.0.5",
|
||||
"babel-jest": "^24.9.0",
|
||||
"@babel/core": "^7.9.6",
|
||||
"@babel/runtime": "^7.9.6",
|
||||
"@react-native-community/eslint-config": "^1.1.0",
|
||||
"babel-jest": "^25.5.1",
|
||||
"eslint": "^6.5.1",
|
||||
"jest": "^24.9.0",
|
||||
"metro-react-native-babel-preset": "^0.58.0",
|
||||
"react-test-renderer": "16.9.0",
|
||||
"flow-bin": "^0.122.0"
|
||||
"flow-bin": "^0.123.0",
|
||||
"jest": "^25.5.3",
|
||||
"jest-extended": "^0.11.5",
|
||||
"metro-react-native-babel-preset": "^0.59.0",
|
||||
"react-test-renderer": "16.9.0"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,13 +12,13 @@ type Props = {
|
|||
title: string,
|
||||
subtitle?: string,
|
||||
left?: (props: { [keys: string]: any }) => React.Node,
|
||||
opened: boolean,
|
||||
opened?: boolean,
|
||||
unmountWhenCollapsed: boolean,
|
||||
children?: React.Node,
|
||||
}
|
||||
|
||||
type State = {
|
||||
expanded: boolean
|
||||
expanded: boolean,
|
||||
}
|
||||
|
||||
const AnimatedListIcon = Animatable.createAnimatableComponent(List.Icon);
|
||||
|
|
@ -26,7 +26,6 @@ const AnimatedListIcon = Animatable.createAnimatableComponent(List.Icon);
|
|||
class AnimatedAccordion extends React.Component<Props, State> {
|
||||
|
||||
static defaultProps = {
|
||||
opened: false,
|
||||
unmountWhenCollapsed: false,
|
||||
}
|
||||
chevronRef: { current: null | AnimatedListIcon };
|
||||
|
|
@ -35,7 +34,7 @@ class AnimatedAccordion extends React.Component<Props, State> {
|
|||
animEnd: string;
|
||||
|
||||
state = {
|
||||
expanded: this.props.opened,
|
||||
expanded: this.props.opened != null ? this.props.opened : false,
|
||||
}
|
||||
|
||||
constructor(props) {
|
||||
|
|
@ -57,14 +56,15 @@ class AnimatedAccordion extends React.Component<Props, State> {
|
|||
}
|
||||
|
||||
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) {
|
||||
this.state.expanded = nextProps.opened;
|
||||
this.setupChevron();
|
||||
shouldComponentUpdate(nextProps: Props, nextState: State): boolean {
|
||||
if (nextProps.opened != null && nextProps.opened !== this.props.opened)
|
||||
this.state.expanded = nextProps.opened;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,14 +3,14 @@
|
|||
import * as React from 'react';
|
||||
import {Avatar, Card, List, withTheme} from 'react-native-paper';
|
||||
import {StyleSheet, View} from "react-native";
|
||||
import {DrawerNavigationProp} from "@react-navigation/drawer";
|
||||
import type {CustomTheme} from "../../managers/ThemeManager";
|
||||
import i18n from 'i18n-js';
|
||||
import {StackNavigationProp} from "@react-navigation/stack";
|
||||
|
||||
const ICON_AMICALE = require("../../../assets/amicale.png");
|
||||
|
||||
type Props = {
|
||||
navigation: DrawerNavigationProp,
|
||||
navigation: StackNavigationProp,
|
||||
theme: CustomTheme,
|
||||
isLoggedIn: boolean,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,10 +23,6 @@ const LIST_ITEM_HEIGHT = 64;
|
|||
|
||||
class GroupListAccordion extends React.Component<Props> {
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
shouldComponentUpdate(nextProps: Props) {
|
||||
return (nextProps.currentSearchString !== this.props.currentSearchString)
|
||||
|| (nextProps.favoriteNumber !== this.props.favoriteNumber)
|
||||
|
|
@ -35,21 +31,31 @@ class GroupListAccordion extends React.Component<Props> {
|
|||
|
||||
keyExtractor = (item: group) => item.id.toString();
|
||||
|
||||
renderItem = ({item}: {item: group}) => {
|
||||
if (stringMatchQuery(item.name, this.props.currentSearchString)) {
|
||||
const onPress = () => this.props.onGroupPress(item);
|
||||
const onStarPress = () => this.props.onFavoritePress(item);
|
||||
return (
|
||||
<GroupListItem
|
||||
height={LIST_ITEM_HEIGHT}
|
||||
item={item}
|
||||
onPress={onPress}
|
||||
onStarPress={onStarPress}/>
|
||||
);
|
||||
} else
|
||||
return null;
|
||||
renderItem = ({item}: { item: group }) => {
|
||||
const onPress = () => this.props.onGroupPress(item);
|
||||
const onStarPress = () => this.props.onFavoritePress(item);
|
||||
return (
|
||||
<GroupListItem
|
||||
height={LIST_ITEM_HEIGHT}
|
||||
item={item}
|
||||
onPress={onPress}
|
||||
onStarPress={onStarPress}/>
|
||||
);
|
||||
}
|
||||
|
||||
getData() {
|
||||
const originalData = this.props.item.content;
|
||||
let displayData = [];
|
||||
for (let i = 0; i < originalData.length; i++) {
|
||||
if (stringMatchQuery(originalData[i].name, this.props.currentSearchString))
|
||||
displayData.push(originalData[i]);
|
||||
}
|
||||
return displayData;
|
||||
}
|
||||
|
||||
itemLayout = (data, index) => ({length: LIST_ITEM_HEIGHT, offset: LIST_ITEM_HEIGHT * index, index});
|
||||
|
||||
|
||||
render() {
|
||||
const item = this.props.item;
|
||||
return (
|
||||
|
|
@ -73,14 +79,14 @@ class GroupListAccordion extends React.Component<Props> {
|
|||
>
|
||||
{/*$FlowFixMe*/}
|
||||
<FlatList
|
||||
data={item.content}
|
||||
data={this.getData()}
|
||||
extraData={this.props.currentSearchString}
|
||||
renderItem={this.renderItem}
|
||||
keyExtractor={this.keyExtractor}
|
||||
listKey={item.id.toString()}
|
||||
// Performance props, see https://reactnative.dev/docs/optimizing-flatlist-configuration
|
||||
// getItemLayout={this.itemLayout} // Broken with search
|
||||
// removeClippedSubviews={true}
|
||||
getItemLayout={this.itemLayout}
|
||||
removeClippedSubviews={true}
|
||||
/>
|
||||
</AnimatedAccordion>
|
||||
</View>
|
||||
|
|
|
|||
58
src/components/Overrides/CustomSlider.js
Normal file
58
src/components/Overrides/CustomSlider.js
Normal file
|
|
@ -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<Props, State> {
|
||||
|
||||
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 (
|
||||
<View style={{flex: 1, flexDirection: 'row'}}>
|
||||
<Text style={{marginHorizontal: 10, marginTop: 'auto', marginBottom: 'auto'}}>
|
||||
{this.state.currentValue}min
|
||||
</Text>
|
||||
<Slider
|
||||
{...this.props}
|
||||
onValueChange={this.onValueChange}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default withTheme(CustomSlider);
|
||||
|
||||
|
|
@ -31,26 +31,16 @@ class CustomTabBar extends React.Component<Props, State> {
|
|||
|
||||
static TAB_BAR_HEIGHT = 48;
|
||||
|
||||
activeColor: string;
|
||||
inactiveColor: string;
|
||||
|
||||
state = {
|
||||
translateY: new Animated.Value(0),
|
||||
barSynced: false,// Is the bar synced with the header for animations?
|
||||
}
|
||||
|
||||
// shouldComponentUpdate(nextProps: Props): boolean {
|
||||
// return (nextProps.theme.dark !== this.props.theme.dark)
|
||||
// || (nextProps.state.index !== this.props.state.index);
|
||||
// }
|
||||
|
||||
tabRef: Object;
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.tabRef = React.createRef();
|
||||
this.activeColor = props.theme.colors.primary;
|
||||
this.inactiveColor = props.theme.colors.tabIcon;
|
||||
}
|
||||
|
||||
onItemPress(route: Object, currentIndex: number, destIndex: number) {
|
||||
|
|
@ -119,7 +109,7 @@ class CustomTabBar extends React.Component<Props, State> {
|
|||
}
|
||||
}
|
||||
|
||||
const color = isFocused ? this.activeColor : this.inactiveColor;
|
||||
const color = isFocused ? this.props.theme.colors.primary : this.props.theme.colors.tabIcon;
|
||||
if (route.name !== "home") {
|
||||
return <TabIcon
|
||||
onPress={onPress}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
// @flow
|
||||
|
||||
import {AsyncStorage} from "react-native";
|
||||
import AsyncStorage from '@react-native-community/async-storage';
|
||||
|
||||
/**
|
||||
* Singleton used to manage preferences.
|
||||
|
|
|
|||
|
|
@ -25,7 +25,6 @@ const links = {
|
|||
"Coucou !\n\n",
|
||||
yohanLinkedin: 'https://www.linkedin.com/in/yohan-simard',
|
||||
react: 'https://facebook.github.io/react-native/',
|
||||
expo: 'https://expo.io/',
|
||||
};
|
||||
|
||||
type Props = {
|
||||
|
|
@ -153,12 +152,6 @@ class AboutScreen extends React.Component<Props, State> {
|
|||
text: i18n.t('aboutScreen.reactNative'),
|
||||
showChevron: true
|
||||
},
|
||||
{
|
||||
onPressCallback: () => openWebLink(links.react),
|
||||
icon: 'language-javascript',
|
||||
text: i18n.t('aboutScreen.expo'),
|
||||
showChevron: true
|
||||
},
|
||||
{
|
||||
onPressCallback: () => this.props.navigation.navigate('dependencies'),
|
||||
icon: 'developer-board',
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ class FeedItemScreen extends React.Component<Props> {
|
|||
|
||||
getHeaderButton = () => {
|
||||
return <MaterialHeaderButtons>
|
||||
<Item title="main" iconName={'facebook'} onPress={this.onOutLinkPress}/>
|
||||
<Item title="main" iconName={'facebook'} color={"#2e88fe"} onPress={this.onOutLinkPress}/>
|
||||
</MaterialHeaderButtons>;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -17,7 +17,6 @@ import AnimatedFAB from "../../components/Animations/AnimatedFAB";
|
|||
import {StackNavigationProp} from "@react-navigation/stack";
|
||||
import type {CustomTheme} from "../../managers/ThemeManager";
|
||||
import {View} from "react-native-animatable";
|
||||
import {HiddenItem} from "react-navigation-header-buttons";
|
||||
import ConnectionManager from "../../managers/ConnectionManager";
|
||||
import LogoutDialog from "../../components/Amicale/LogoutDialog";
|
||||
// import DATA from "../dashboard_data.json";
|
||||
|
|
@ -178,8 +177,8 @@ class HomeScreen extends React.Component<Props, State> {
|
|||
const onPressAbout = () => this.props.navigation.navigate("about");
|
||||
return <MaterialHeaderButtons>
|
||||
<Item title="log" iconName={logIcon} color={logColor} onPress={onPressLog}/>
|
||||
<HiddenItem title={i18n.t("screens.settings")} iconName={"settings"} onPress={onPressSettings}/>
|
||||
<HiddenItem title={i18n.t("screens.about")} iconName={"information"} onPress={onPressAbout}/>
|
||||
<Item title={i18n.t("screens.settings")} iconName={"settings"} onPress={onPressSettings}/>
|
||||
<Item title={i18n.t("screens.about")} iconName={"information"} onPress={onPressAbout}/>
|
||||
</MaterialHeaderButtons>;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ class FeedbackScreen extends React.Component<Props> {
|
|||
}}>
|
||||
<Button
|
||||
icon="email"
|
||||
mode={"contained"}
|
||||
style={{
|
||||
marginLeft: 'auto',
|
||||
marginTop: 5,
|
||||
|
|
@ -45,6 +46,8 @@ class FeedbackScreen extends React.Component<Props> {
|
|||
</Button>
|
||||
<Button
|
||||
icon="git"
|
||||
mode={"contained"}
|
||||
color={"#609927"}
|
||||
style={{
|
||||
marginLeft: 'auto',
|
||||
marginTop: 5,
|
||||
|
|
@ -54,6 +57,8 @@ class FeedbackScreen extends React.Component<Props> {
|
|||
</Button>
|
||||
<Button
|
||||
icon="facebook"
|
||||
mode={"contained"}
|
||||
color={"#2e88fe"}
|
||||
style={{
|
||||
marginLeft: 'auto',
|
||||
marginTop: 5,
|
||||
|
|
|
|||
|
|
@ -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<Props, State> {
|
||||
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<Props, State> {
|
||||
|
||||
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<Props, State> {
|
|||
*
|
||||
* @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<Props, State> {
|
|||
*/
|
||||
getProxiwashNotifPicker() {
|
||||
return (
|
||||
<ToggleButton.Row
|
||||
<CustomSlider
|
||||
style={{flex: 1, marginHorizontal: 10, height: 50}}
|
||||
minimumValue={0}
|
||||
maximumValue={10}
|
||||
step={1}
|
||||
value={this.savedNotificationReminder}
|
||||
onValueChange={this.onProxiwashNotifPickerValueChange}
|
||||
value={this.state.proxiwashNotifPickerSelected}
|
||||
style={{marginLeft: 'auto', marginRight: 'auto'}}
|
||||
>
|
||||
<ToggleButton icon="close" value="never"/>
|
||||
<ToggleButton icon="numeric-2" value="2"/>
|
||||
<ToggleButton icon="numeric-5" value="5"/>
|
||||
</ToggleButton.Row>
|
||||
thumbTintColor={this.props.theme.colors.primary}
|
||||
minimumTrackTintColor={this.props.theme.colors.primary}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -133,6 +138,7 @@ export default class SettingsScreen extends React.Component<Props, State> {
|
|||
* @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<Props, State> {
|
|||
title={title}
|
||||
description={subtitle}
|
||||
left={props => <List.Icon {...props} icon={icon}/>}
|
||||
right={props =>
|
||||
right={() =>
|
||||
<Switch
|
||||
value={state}
|
||||
onValueChange={onPressCallback}
|
||||
|
|
@ -177,28 +183,31 @@ export default class SettingsScreen extends React.Component<Props, State> {
|
|||
this.state.nightMode
|
||||
) : null
|
||||
}
|
||||
<AnimatedAccordion
|
||||
<List.Item
|
||||
title={i18n.t('settingsScreen.startScreen')}
|
||||
subtitle={i18n.t('settingsScreen.startScreenSub')}
|
||||
left={props => <List.Icon {...props} icon="power"/>}
|
||||
>
|
||||
{this.getStartScreenPicker()}
|
||||
</AnimatedAccordion>
|
||||
/>
|
||||
{this.getStartScreenPicker()}
|
||||
</List.Section>
|
||||
</Card>
|
||||
<Card style={{margin: 5}}>
|
||||
<Card.Title title="Proxiwash"/>
|
||||
<List.Section>
|
||||
<AnimatedAccordion
|
||||
<List.Item
|
||||
title={i18n.t('settingsScreen.proxiwashNotifReminder')}
|
||||
description={i18n.t('settingsScreen.proxiwashNotifReminderSub')}
|
||||
left={props => <List.Icon {...props} icon="washing-machine"/>}
|
||||
>
|
||||
opened={true}
|
||||
/>
|
||||
<View style={{marginLeft: 30}}>
|
||||
{this.getProxiwashNotifPicker()}
|
||||
</AnimatedAccordion>
|
||||
</View>
|
||||
</List.Section>
|
||||
</Card>
|
||||
</ScrollView>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default withTheme(SettingsScreen);
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ type Props = {
|
|||
navigation: Object,
|
||||
};
|
||||
|
||||
const LOGO = "https://etud.insa-toulouse.fr/~amicale_app/images/proxiwash-logo.png";
|
||||
const LOGO = "https://etud.insa-toulouse.fr/~amicale_app/images/Proxiwash.png";
|
||||
|
||||
/**
|
||||
* Class defining the proxiwash about screen.
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ import type {CustomTheme} from "../../managers/ThemeManager";
|
|||
import {Collapsible} from "react-navigation-collapsible";
|
||||
import {StackNavigationProp} from "@react-navigation/stack";
|
||||
import {getCleanedMachineWatched, getMachineEndDate, isMachineWatched} from "../../utils/Proxiwash";
|
||||
import {Modalize} from "react-native-modalize";
|
||||
|
||||
const DATA_URL = "https://etud.insa-toulouse.fr/~amicale_app/washinsa/washinsa.json";
|
||||
|
||||
|
|
@ -55,9 +56,12 @@ type State = {
|
|||
*/
|
||||
class ProxiwashScreen extends React.Component<Props, State> {
|
||||
|
||||
modalRef: Object;
|
||||
modalRef: null | Modalize;
|
||||
|
||||
fetchedData: Object;
|
||||
fetchedData: {
|
||||
dryers: Array<Machine>,
|
||||
washers: Array<Machine>,
|
||||
};
|
||||
|
||||
state = {
|
||||
refreshing: false,
|
||||
|
|
@ -95,7 +99,10 @@ class ProxiwashScreen extends React.Component<Props, State> {
|
|||
*/
|
||||
componentDidMount() {
|
||||
this.props.navigation.setOptions({
|
||||
headerRight: this.getAboutButton,
|
||||
headerRight: () =>
|
||||
<MaterialHeaderButtons>
|
||||
<Item title="information" iconName="information" onPress={this.onAboutPress}/>
|
||||
</MaterialHeaderButtons>,
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -105,16 +112,6 @@ class ProxiwashScreen extends React.Component<Props, State> {
|
|||
*/
|
||||
onAboutPress = () => this.props.navigation.navigate('proxiwash-about');
|
||||
|
||||
/**
|
||||
* Gets the about header button
|
||||
*
|
||||
* @return {*}
|
||||
*/
|
||||
getAboutButton = () =>
|
||||
<MaterialHeaderButtons>
|
||||
<Item title="information" iconName="information" onPress={this.onAboutPress}/>
|
||||
</MaterialHeaderButtons>;
|
||||
|
||||
/**
|
||||
* Extracts the key for the given item
|
||||
*
|
||||
|
|
@ -123,7 +120,6 @@ class ProxiwashScreen extends React.Component<Props, State> {
|
|||
*/
|
||||
getKeyExtractor = (item: Machine) => item.number;
|
||||
|
||||
|
||||
/**
|
||||
* Setups notifications for the machine with the given ID.
|
||||
* One notification will be sent at the end of the program.
|
||||
|
|
@ -141,7 +137,7 @@ class ProxiwashScreen extends React.Component<Props, State> {
|
|||
this.showNotificationsDisabledWarning();
|
||||
});
|
||||
} else {
|
||||
Notifications.setupMachineNotification(machine.number, false)
|
||||
Notifications.setupMachineNotification(machine.number, false, null)
|
||||
.then(() => {
|
||||
this.removeNotificationFromState(machine);
|
||||
});
|
||||
|
|
@ -271,6 +267,10 @@ class ProxiwashScreen extends React.Component<Props, State> {
|
|||
let message = modalStateStrings[ProxiwashConstants.machineStates[item.state]];
|
||||
const onPress = this.onSetupNotificationsPress.bind(this, item);
|
||||
if (ProxiwashConstants.machineStates[item.state] === ProxiwashConstants.machineStates["EN COURS"]) {
|
||||
let remainingTime = parseInt(item.remainingTime)
|
||||
if (remainingTime < 0)
|
||||
remainingTime = 0;
|
||||
|
||||
button =
|
||||
{
|
||||
text: isMachineWatched(item, this.state.machinesWatched) ?
|
||||
|
|
@ -284,7 +284,7 @@ class ProxiwashScreen extends React.Component<Props, State> {
|
|||
{
|
||||
start: item.startTime,
|
||||
end: item.endTime,
|
||||
remaining: item.remainingTime
|
||||
remaining: remainingTime
|
||||
});
|
||||
} else if (ProxiwashConstants.machineStates[item.state] === ProxiwashConstants.machineStates.DISPONIBLE) {
|
||||
if (isDryer)
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ type Props = {
|
|||
navigation: Object,
|
||||
};
|
||||
|
||||
const LOGO = "https://etud.insa-toulouse.fr/~amicale_app/images/proximo-logo.png";
|
||||
const LOGO = "https://etud.insa-toulouse.fr/~amicale_app/images/Proximo.png";
|
||||
|
||||
/**
|
||||
* Class defining the proximo about screen.
|
||||
|
|
|
|||
|
|
@ -20,17 +20,22 @@ type Props = {
|
|||
collapsibleStack: Collapsible,
|
||||
theme: CustomTheme,
|
||||
}
|
||||
const BIB_IMAGE = "https://scontent-cdg2-1.xx.fbcdn.net/v/t1.0-9/50695561_2124263197597162_2325349608210825216_n.jpg?_nc_cat=109&_nc_sid=8bfeb9&_nc_ohc=tmcV6FWO7_kAX9vfWHU&_nc_ht=scontent-cdg2-1.xx&oh=3b81c76e46b49f7c3a033ea3b07ec212&oe=5EC59B4D";
|
||||
const RU_IMAGE = "https://scontent-cdg2-1.xx.fbcdn.net/v/t1.0-9/47123773_2041883702501779_5289372776166064128_o.jpg?_nc_cat=100&_nc_sid=cdbe9c&_nc_ohc=dpuBGlIIy_EAX8CyC0l&_nc_ht=scontent-cdg2-1.xx&oh=5c5bb4f0c7f12b554246f7c9b620a5f3&oe=5EC4DB31";
|
||||
const ROOM_IMAGE = "https://scontent-cdt1-1.xx.fbcdn.net/v/t1.0-9/47041013_2043521689004647_316124496522117120_n.jpg?_nc_cat=103&_nc_sid=8bfeb9&_nc_ohc=bIp8OVJvvSEAX8mKnDZ&_nc_ht=scontent-cdt1-1.xx&oh=b4fef72a645804a849ad30e9e20fca12&oe=5EC29309";
|
||||
const EMAIL_IMAGE = "https://etud-mel.insa-toulouse.fr/webmail/images/logo-bluemind.png";
|
||||
const ENT_IMAGE = "https://ent.insa-toulouse.fr/media/org/jasig/portal/layout/tab-column/xhtml-theme/insa/institutional/LogoInsa.png";
|
||||
|
||||
const PROXIMO_IMAGE = "https://etud.insa-toulouse.fr/~amicale_app/images/proximo-logo.png"
|
||||
const WIKETUD_LINK = "https://wiki.etud.insa-toulouse.fr/resources/assets/wiketud.png?ff051";
|
||||
const CLUBS_IMAGE = "https://etud.insa-toulouse.fr/~amicale_app/images/Clubs.png";
|
||||
const PROFILE_IMAGE = "https://etud.insa-toulouse.fr/~amicale_app/images/ProfilAmicaliste.png";
|
||||
const VOTE_IMAGE = "https://etud.insa-toulouse.fr/~amicale_app/images/";
|
||||
const AMICALE_IMAGE = require("../../../assets/amicale.png");
|
||||
const EE_IMAGE = "https://etud.insa-toulouse.fr/~eeinsat/wp-content/uploads/2019/09/logo-blanc.png";
|
||||
const TUTORINSA_IMAGE = "https://www.etud.insa-toulouse.fr/~tutorinsa/public/images/logo-gray.png";
|
||||
|
||||
const PROXIMO_IMAGE = "https://etud.insa-toulouse.fr/~amicale_app/images/Proximo.png"
|
||||
const WIKETUD_IMAGE = "https://etud.insa-toulouse.fr/~amicale_app/images/Wiketud.png";
|
||||
const EE_IMAGE = "https://etud.insa-toulouse.fr/~amicale_app/images/EEC.png";
|
||||
const TUTORINSA_IMAGE = "https://etud.insa-toulouse.fr/~amicale_app/images/TutorINSA.png";
|
||||
|
||||
const BIB_IMAGE = "https://etud.insa-toulouse.fr/~amicale_app/images/Bib.png";
|
||||
const RU_IMAGE = "https://etud.insa-toulouse.fr/~amicale_app/images/RU.png";
|
||||
const ROOM_IMAGE = "https://etud.insa-toulouse.fr/~amicale_app/images/Salles.png";
|
||||
const EMAIL_IMAGE = "https://etud.insa-toulouse.fr/~amicale_app/images/Bluemind.png";
|
||||
const ENT_IMAGE = "https://etud.insa-toulouse.fr/~amicale_app/images/ENT.png";
|
||||
|
||||
export type listItem = {
|
||||
title: string,
|
||||
|
|
@ -59,19 +64,25 @@ class ServicesScreen extends React.Component<Props, State> {
|
|||
{
|
||||
title: i18n.t('screens.clubsAbout'),
|
||||
subtitle: "CLUB LIST",
|
||||
image: AMICALE_IMAGE,
|
||||
image: CLUBS_IMAGE,
|
||||
onPress: () => nav.navigate("club-list"),
|
||||
},
|
||||
{
|
||||
title: i18n.t('screens.profile'),
|
||||
subtitle: "PROFIL",
|
||||
image: AMICALE_IMAGE,
|
||||
image: PROFILE_IMAGE,
|
||||
onPress: () => nav.navigate("profile"),
|
||||
},
|
||||
{
|
||||
title: i18n.t('screens.amicaleWebsite'),
|
||||
subtitle: "AMICALE",
|
||||
image: AMICALE_IMAGE,
|
||||
onPress: () => nav.navigate("amicale-website"),
|
||||
},
|
||||
{
|
||||
title: i18n.t('screens.vote'),
|
||||
subtitle: "ELECTIONS",
|
||||
image: AMICALE_IMAGE,
|
||||
image: VOTE_IMAGE,
|
||||
onPress: () => nav.navigate("vote"),
|
||||
},
|
||||
];
|
||||
|
|
@ -82,16 +93,10 @@ class ServicesScreen extends React.Component<Props, State> {
|
|||
image: PROXIMO_IMAGE,
|
||||
onPress: () => nav.navigate("proximo"),
|
||||
},
|
||||
{
|
||||
title: i18n.t('screens.amicaleWebsite'),
|
||||
subtitle: "AMICALE",
|
||||
image: AMICALE_IMAGE,
|
||||
onPress: () => nav.navigate("amicale-website"),
|
||||
},
|
||||
{
|
||||
title: "Wiketud",
|
||||
subtitle: "wiketud",
|
||||
image: WIKETUD_LINK,
|
||||
image: WIKETUD_IMAGE,
|
||||
onPress: () => nav.navigate("wiketud"),
|
||||
},
|
||||
{
|
||||
|
|
@ -201,7 +206,7 @@ class ServicesScreen extends React.Component<Props, State> {
|
|||
return <Avatar.Image
|
||||
{...props}
|
||||
size={48}
|
||||
source={AMICALE_IMAGE}
|
||||
source={source}
|
||||
style={{backgroundColor: 'transparent'}}
|
||||
/>
|
||||
else
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
import {checkNotifications, requestNotifications, RESULTS} from 'react-native-permissions';
|
||||
import AsyncStorageManager from "../managers/AsyncStorageManager";
|
||||
import i18n from "i18n-js";
|
||||
|
||||
const PushNotification = require("react-native-push-notification");
|
||||
|
||||
|
|
@ -38,8 +39,8 @@ function createNotifications(machineID: string, date: Date) {
|
|||
let reminderDate = new Date(date);
|
||||
reminderDate.setMinutes(reminderDate.getMinutes() - reminder);
|
||||
PushNotification.localNotificationSchedule({
|
||||
title: "Title",
|
||||
message: "Message",
|
||||
title: i18n.t("proxiwashScreen.notifications.machineRunningTitle", {time: reminder}),
|
||||
message: i18n.t("proxiwashScreen.notifications.machineRunningBody", {number: machineID}),
|
||||
id: id.toString(),
|
||||
date: reminderDate,
|
||||
});
|
||||
|
|
@ -48,8 +49,8 @@ function createNotifications(machineID: string, date: Date) {
|
|||
console.log("Setting up notifications for ", date);
|
||||
|
||||
PushNotification.localNotificationSchedule({
|
||||
title: "Title",
|
||||
message: "Message",
|
||||
title: i18n.t("proxiwashScreen.notifications.machineFinishedTitle"),
|
||||
message: i18n.t("proxiwashScreen.notifications.machineFinishedBody", {number: machineID}),
|
||||
id: machineID,
|
||||
date: date,
|
||||
});
|
||||
|
|
@ -62,7 +63,7 @@ function createNotifications(machineID: string, date: Date) {
|
|||
* @param isEnabled True to enable notifications, false to disable
|
||||
* @param endDate
|
||||
*/
|
||||
export async function setupMachineNotification(machineID: string, isEnabled: boolean, endDate?: Date) {
|
||||
export async function setupMachineNotification(machineID: string, isEnabled: boolean, endDate: Date | null) {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (isEnabled && endDate != null) {
|
||||
askPermissions()
|
||||
|
|
|
|||
|
|
@ -1,22 +1,41 @@
|
|||
// @flow
|
||||
|
||||
import type {Machine} from "../screens/Proxiwash/ProxiwashScreen";
|
||||
import ProxiwashConstants from "../constants/ProxiwashConstants";
|
||||
|
||||
export function getMachineEndDate(machine: Machine) {
|
||||
/**
|
||||
* Gets the machine end Date object.
|
||||
* If the end time is at least 12 hours before the current time,
|
||||
* it will be considered as happening the day after.
|
||||
* If it is before but less than 12 hours, it will be considered invalid (to fix proxiwash delay)
|
||||
*
|
||||
* @param machine The machine to get the date from
|
||||
* @returns {Date} The date object representing the end time.
|
||||
*/
|
||||
export function getMachineEndDate(machine: Machine): Date | null {
|
||||
const array = machine.endTime.split(":");
|
||||
let date = new Date();
|
||||
date.setHours(parseInt(array[0]), parseInt(array[1]));
|
||||
if (date < new Date())
|
||||
date.setDate(date.getDate() + 1);
|
||||
return date;
|
||||
let endDate = new Date(Date.now());
|
||||
endDate.setHours(parseInt(array[0]), parseInt(array[1]));
|
||||
|
||||
let limit = new Date(Date.now());
|
||||
if (endDate < limit) {
|
||||
if (limit.getHours() > 12) {
|
||||
limit.setHours(limit.getHours() - 12);
|
||||
if (endDate < limit)
|
||||
endDate.setDate(endDate.getDate() + 1);
|
||||
else
|
||||
endDate = null;
|
||||
} else
|
||||
endDate = null;
|
||||
}
|
||||
|
||||
return endDate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the machine of the given ID has scheduled notifications
|
||||
*
|
||||
* @param machine
|
||||
* @param machineList
|
||||
* @param machine The machine to check
|
||||
* @param machineList The machine list
|
||||
* @returns {boolean}
|
||||
*/
|
||||
export function isMachineWatched(machine: Machine, machineList: Array<Machine>) {
|
||||
|
|
@ -30,7 +49,14 @@ export function isMachineWatched(machine: Machine, machineList: Array<Machine>)
|
|||
return watched;
|
||||
}
|
||||
|
||||
function getMachineOfId(id: string, allMachines: Array<Machine>) {
|
||||
/**
|
||||
* Gets the machine of the given id
|
||||
*
|
||||
* @param id The machine's ID
|
||||
* @param allMachines The machine list
|
||||
* @returns {null|Machine} The machine or null if not found
|
||||
*/
|
||||
export function getMachineOfId(id: string, allMachines: Array<Machine>) {
|
||||
for (let i = 0; i < allMachines.length; i++) {
|
||||
if (allMachines[i].number === id)
|
||||
return allMachines[i];
|
||||
|
|
@ -38,13 +64,22 @@ function getMachineOfId(id: string, allMachines: Array<Machine>) {
|
|||
return null;
|
||||
}
|
||||
|
||||
export function getCleanedMachineWatched(machineList: Array<Machine>, allMachines: Array<Machine>) {
|
||||
/**
|
||||
* Gets a cleaned machine watched list by removing invalid entries.
|
||||
* An entry is considered invalid if the end time in the watched list
|
||||
* and in the full list does not match (a new machine cycle started)
|
||||
*
|
||||
* @param machineWatchedList The current machine watch list
|
||||
* @param allMachines The current full machine list
|
||||
* @returns {Array<Machine>}
|
||||
*/
|
||||
export function getCleanedMachineWatched(machineWatchedList: Array<Machine>, allMachines: Array<Machine>) {
|
||||
let newList = [];
|
||||
for (let i = 0; i < machineList.length; i++) {
|
||||
let machine = getMachineOfId(machineList[i].number, allMachines);
|
||||
for (let i = 0; i < machineWatchedList.length; i++) {
|
||||
let machine = getMachineOfId(machineWatchedList[i].number, allMachines);
|
||||
if (machine !== null
|
||||
&& machineList[i].number === machine.number && machineList[i].endTime === machine.endTime
|
||||
&& ProxiwashConstants.machineStates[machineList[i].state] === ProxiwashConstants.machineStates["EN COURS"]) {
|
||||
&& machineWatchedList[i].number === machine.number
|
||||
&& machineWatchedList[i].endTime === machine.endTime) {
|
||||
newList.push(machine);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue