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"?>
|
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||||
<resources>
|
<resources>
|
||||||
<color name="activityBackground">#ffffff</color>
|
<color name="activityBackground">#be1522</color>
|
||||||
<color name="navigationBarColor">#121212</color>
|
<color name="navigationBarColor">#121212</color>
|
||||||
<color name="colorPrimaryDark">#be1522</color>
|
<color name="colorPrimaryDark">#be1522</color>
|
||||||
<color name="colorPrimary">#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": {
|
"dependencies": {
|
||||||
"@nartc/react-native-barcode-mask": "^1.1.9",
|
"@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-native-community/push-notification-ios": "^1.1.1",
|
||||||
"@react-navigation/bottom-tabs": "^5.1.1",
|
"@react-native-community/slider": "^2.0.9",
|
||||||
"@react-navigation/drawer": "^5.1.1",
|
"@react-navigation/bottom-tabs": "^5.3.2",
|
||||||
"@react-navigation/native": "^5.0.9",
|
"@react-navigation/native": "^5.2.2",
|
||||||
"@react-navigation/stack": "^5.1.1",
|
"@react-navigation/stack": "^5.2.17",
|
||||||
"i18n-js": "^3.3.0",
|
"i18n-js": "^3.3.0",
|
||||||
"react": "~16.9.0",
|
"react": "~16.9.0",
|
||||||
"react-dom": "16.9.0",
|
"react-dom": "16.9.0",
|
||||||
|
|
@ -43,29 +44,29 @@
|
||||||
"react-native-linear-gradient": "^2.5.6",
|
"react-native-linear-gradient": "^2.5.6",
|
||||||
"react-native-localize": "^1.4.0",
|
"react-native-localize": "^1.4.0",
|
||||||
"react-native-modalize": "^1.3.6",
|
"react-native-modalize": "^1.3.6",
|
||||||
"react-native-paper": "^3.8.0",
|
"react-native-paper": "^3.9.0",
|
||||||
"react-native-permissions": "^2.1.3",
|
"react-native-permissions": "^2.1.4",
|
||||||
"react-native-push-notification": "^3.3.0",
|
"react-native-push-notification": "^3.3.1",
|
||||||
"react-native-reanimated": "~1.7.0",
|
"react-native-reanimated": "^1.8.0",
|
||||||
"react-native-render-html": "^4.1.2",
|
"react-native-render-html": "^4.1.2",
|
||||||
"react-native-safe-area-context": "0.7.3",
|
"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-splash-screen": "^3.2.0",
|
||||||
"react-native-vector-icons": "^6.6.0",
|
"react-native-vector-icons": "^6.6.0",
|
||||||
"react-native-web": "~0.11.7",
|
"react-native-webview": "^9.4.0",
|
||||||
"react-native-webview": "8.1.1",
|
|
||||||
"react-navigation-collapsible": "^5.5.0",
|
"react-navigation-collapsible": "^5.5.0",
|
||||||
"react-navigation-header-buttons": "^3.0.5"
|
"react-navigation-header-buttons": "^3.0.5"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/core": "^7.6.2",
|
"@babel/core": "^7.9.6",
|
||||||
"@babel/runtime": "^7.6.2",
|
"@babel/runtime": "^7.9.6",
|
||||||
"@react-native-community/eslint-config": "^0.0.5",
|
"@react-native-community/eslint-config": "^1.1.0",
|
||||||
"babel-jest": "^24.9.0",
|
"babel-jest": "^25.5.1",
|
||||||
"eslint": "^6.5.1",
|
"eslint": "^6.5.1",
|
||||||
"jest": "^24.9.0",
|
"flow-bin": "^0.123.0",
|
||||||
"metro-react-native-babel-preset": "^0.58.0",
|
"jest": "^25.5.3",
|
||||||
"react-test-renderer": "16.9.0",
|
"jest-extended": "^0.11.5",
|
||||||
"flow-bin": "^0.122.0"
|
"metro-react-native-babel-preset": "^0.59.0",
|
||||||
|
"react-test-renderer": "16.9.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,13 +12,13 @@ type Props = {
|
||||||
title: string,
|
title: string,
|
||||||
subtitle?: string,
|
subtitle?: string,
|
||||||
left?: (props: { [keys: string]: any }) => React.Node,
|
left?: (props: { [keys: string]: any }) => React.Node,
|
||||||
opened: boolean,
|
opened?: boolean,
|
||||||
unmountWhenCollapsed: boolean,
|
unmountWhenCollapsed: boolean,
|
||||||
children?: React.Node,
|
children?: React.Node,
|
||||||
}
|
}
|
||||||
|
|
||||||
type State = {
|
type State = {
|
||||||
expanded: boolean
|
expanded: boolean,
|
||||||
}
|
}
|
||||||
|
|
||||||
const AnimatedListIcon = Animatable.createAnimatableComponent(List.Icon);
|
const AnimatedListIcon = Animatable.createAnimatableComponent(List.Icon);
|
||||||
|
|
@ -26,7 +26,6 @@ const AnimatedListIcon = Animatable.createAnimatableComponent(List.Icon);
|
||||||
class AnimatedAccordion extends React.Component<Props, State> {
|
class AnimatedAccordion extends React.Component<Props, State> {
|
||||||
|
|
||||||
static defaultProps = {
|
static defaultProps = {
|
||||||
opened: false,
|
|
||||||
unmountWhenCollapsed: false,
|
unmountWhenCollapsed: false,
|
||||||
}
|
}
|
||||||
chevronRef: { current: null | AnimatedListIcon };
|
chevronRef: { current: null | AnimatedListIcon };
|
||||||
|
|
@ -35,7 +34,7 @@ class AnimatedAccordion extends React.Component<Props, State> {
|
||||||
animEnd: string;
|
animEnd: string;
|
||||||
|
|
||||||
state = {
|
state = {
|
||||||
expanded: this.props.opened,
|
expanded: this.props.opened != null ? this.props.opened : false,
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
|
|
@ -57,14 +56,15 @@ class AnimatedAccordion extends React.Component<Props, State> {
|
||||||
}
|
}
|
||||||
|
|
||||||
toggleAccordion = () => {
|
toggleAccordion = () => {
|
||||||
if (this.chevronRef.current != null)
|
if (this.chevronRef.current != null) {
|
||||||
this.chevronRef.current.transitionTo({rotate: this.state.expanded ? this.animStart : this.animEnd});
|
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) {
|
shouldComponentUpdate(nextProps: Props, nextState: State): boolean {
|
||||||
this.state.expanded = nextProps.opened;
|
if (nextProps.opened != null && nextProps.opened !== this.props.opened)
|
||||||
this.setupChevron();
|
this.state.expanded = nextProps.opened;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,14 +3,14 @@
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import {Avatar, Card, List, withTheme} from 'react-native-paper';
|
import {Avatar, Card, List, withTheme} from 'react-native-paper';
|
||||||
import {StyleSheet, View} from "react-native";
|
import {StyleSheet, View} from "react-native";
|
||||||
import {DrawerNavigationProp} from "@react-navigation/drawer";
|
|
||||||
import type {CustomTheme} from "../../managers/ThemeManager";
|
import type {CustomTheme} from "../../managers/ThemeManager";
|
||||||
import i18n from 'i18n-js';
|
import i18n from 'i18n-js';
|
||||||
|
import {StackNavigationProp} from "@react-navigation/stack";
|
||||||
|
|
||||||
const ICON_AMICALE = require("../../../assets/amicale.png");
|
const ICON_AMICALE = require("../../../assets/amicale.png");
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
navigation: DrawerNavigationProp,
|
navigation: StackNavigationProp,
|
||||||
theme: CustomTheme,
|
theme: CustomTheme,
|
||||||
isLoggedIn: boolean,
|
isLoggedIn: boolean,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,10 +23,6 @@ const LIST_ITEM_HEIGHT = 64;
|
||||||
|
|
||||||
class GroupListAccordion extends React.Component<Props> {
|
class GroupListAccordion extends React.Component<Props> {
|
||||||
|
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
|
||||||
}
|
|
||||||
|
|
||||||
shouldComponentUpdate(nextProps: Props) {
|
shouldComponentUpdate(nextProps: Props) {
|
||||||
return (nextProps.currentSearchString !== this.props.currentSearchString)
|
return (nextProps.currentSearchString !== this.props.currentSearchString)
|
||||||
|| (nextProps.favoriteNumber !== this.props.favoriteNumber)
|
|| (nextProps.favoriteNumber !== this.props.favoriteNumber)
|
||||||
|
|
@ -35,21 +31,31 @@ class GroupListAccordion extends React.Component<Props> {
|
||||||
|
|
||||||
keyExtractor = (item: group) => item.id.toString();
|
keyExtractor = (item: group) => item.id.toString();
|
||||||
|
|
||||||
renderItem = ({item}: {item: group}) => {
|
renderItem = ({item}: { item: group }) => {
|
||||||
if (stringMatchQuery(item.name, this.props.currentSearchString)) {
|
const onPress = () => this.props.onGroupPress(item);
|
||||||
const onPress = () => this.props.onGroupPress(item);
|
const onStarPress = () => this.props.onFavoritePress(item);
|
||||||
const onStarPress = () => this.props.onFavoritePress(item);
|
return (
|
||||||
return (
|
<GroupListItem
|
||||||
<GroupListItem
|
height={LIST_ITEM_HEIGHT}
|
||||||
height={LIST_ITEM_HEIGHT}
|
item={item}
|
||||||
item={item}
|
onPress={onPress}
|
||||||
onPress={onPress}
|
onStarPress={onStarPress}/>
|
||||||
onStarPress={onStarPress}/>
|
);
|
||||||
);
|
|
||||||
} else
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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() {
|
render() {
|
||||||
const item = this.props.item;
|
const item = this.props.item;
|
||||||
return (
|
return (
|
||||||
|
|
@ -73,14 +79,14 @@ class GroupListAccordion extends React.Component<Props> {
|
||||||
>
|
>
|
||||||
{/*$FlowFixMe*/}
|
{/*$FlowFixMe*/}
|
||||||
<FlatList
|
<FlatList
|
||||||
data={item.content}
|
data={this.getData()}
|
||||||
extraData={this.props.currentSearchString}
|
extraData={this.props.currentSearchString}
|
||||||
renderItem={this.renderItem}
|
renderItem={this.renderItem}
|
||||||
keyExtractor={this.keyExtractor}
|
keyExtractor={this.keyExtractor}
|
||||||
listKey={item.id.toString()}
|
listKey={item.id.toString()}
|
||||||
// Performance props, see https://reactnative.dev/docs/optimizing-flatlist-configuration
|
// Performance props, see https://reactnative.dev/docs/optimizing-flatlist-configuration
|
||||||
// getItemLayout={this.itemLayout} // Broken with search
|
getItemLayout={this.itemLayout}
|
||||||
// removeClippedSubviews={true}
|
removeClippedSubviews={true}
|
||||||
/>
|
/>
|
||||||
</AnimatedAccordion>
|
</AnimatedAccordion>
|
||||||
</View>
|
</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;
|
static TAB_BAR_HEIGHT = 48;
|
||||||
|
|
||||||
activeColor: string;
|
|
||||||
inactiveColor: string;
|
|
||||||
|
|
||||||
state = {
|
state = {
|
||||||
translateY: new Animated.Value(0),
|
translateY: new Animated.Value(0),
|
||||||
barSynced: false,// Is the bar synced with the header for animations?
|
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;
|
tabRef: Object;
|
||||||
|
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
this.tabRef = React.createRef();
|
this.tabRef = React.createRef();
|
||||||
this.activeColor = props.theme.colors.primary;
|
|
||||||
this.inactiveColor = props.theme.colors.tabIcon;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onItemPress(route: Object, currentIndex: number, destIndex: number) {
|
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") {
|
if (route.name !== "home") {
|
||||||
return <TabIcon
|
return <TabIcon
|
||||||
onPress={onPress}
|
onPress={onPress}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
// @flow
|
// @flow
|
||||||
|
|
||||||
import {AsyncStorage} from "react-native";
|
import AsyncStorage from '@react-native-community/async-storage';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Singleton used to manage preferences.
|
* Singleton used to manage preferences.
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,6 @@ const links = {
|
||||||
"Coucou !\n\n",
|
"Coucou !\n\n",
|
||||||
yohanLinkedin: 'https://www.linkedin.com/in/yohan-simard',
|
yohanLinkedin: 'https://www.linkedin.com/in/yohan-simard',
|
||||||
react: 'https://facebook.github.io/react-native/',
|
react: 'https://facebook.github.io/react-native/',
|
||||||
expo: 'https://expo.io/',
|
|
||||||
};
|
};
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
|
|
@ -153,12 +152,6 @@ class AboutScreen extends React.Component<Props, State> {
|
||||||
text: i18n.t('aboutScreen.reactNative'),
|
text: i18n.t('aboutScreen.reactNative'),
|
||||||
showChevron: true
|
showChevron: true
|
||||||
},
|
},
|
||||||
{
|
|
||||||
onPressCallback: () => openWebLink(links.react),
|
|
||||||
icon: 'language-javascript',
|
|
||||||
text: i18n.t('aboutScreen.expo'),
|
|
||||||
showChevron: true
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
onPressCallback: () => this.props.navigation.navigate('dependencies'),
|
onPressCallback: () => this.props.navigation.navigate('dependencies'),
|
||||||
icon: 'developer-board',
|
icon: 'developer-board',
|
||||||
|
|
|
||||||
|
|
@ -44,7 +44,7 @@ class FeedItemScreen extends React.Component<Props> {
|
||||||
|
|
||||||
getHeaderButton = () => {
|
getHeaderButton = () => {
|
||||||
return <MaterialHeaderButtons>
|
return <MaterialHeaderButtons>
|
||||||
<Item title="main" iconName={'facebook'} onPress={this.onOutLinkPress}/>
|
<Item title="main" iconName={'facebook'} color={"#2e88fe"} onPress={this.onOutLinkPress}/>
|
||||||
</MaterialHeaderButtons>;
|
</MaterialHeaderButtons>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,6 @@ import AnimatedFAB from "../../components/Animations/AnimatedFAB";
|
||||||
import {StackNavigationProp} from "@react-navigation/stack";
|
import {StackNavigationProp} from "@react-navigation/stack";
|
||||||
import type {CustomTheme} from "../../managers/ThemeManager";
|
import type {CustomTheme} from "../../managers/ThemeManager";
|
||||||
import {View} from "react-native-animatable";
|
import {View} from "react-native-animatable";
|
||||||
import {HiddenItem} from "react-navigation-header-buttons";
|
|
||||||
import ConnectionManager from "../../managers/ConnectionManager";
|
import ConnectionManager from "../../managers/ConnectionManager";
|
||||||
import LogoutDialog from "../../components/Amicale/LogoutDialog";
|
import LogoutDialog from "../../components/Amicale/LogoutDialog";
|
||||||
// import DATA from "../dashboard_data.json";
|
// import DATA from "../dashboard_data.json";
|
||||||
|
|
@ -178,8 +177,8 @@ class HomeScreen extends React.Component<Props, State> {
|
||||||
const onPressAbout = () => this.props.navigation.navigate("about");
|
const onPressAbout = () => this.props.navigation.navigate("about");
|
||||||
return <MaterialHeaderButtons>
|
return <MaterialHeaderButtons>
|
||||||
<Item title="log" iconName={logIcon} color={logColor} onPress={onPressLog}/>
|
<Item title="log" iconName={logIcon} color={logColor} onPress={onPressLog}/>
|
||||||
<HiddenItem title={i18n.t("screens.settings")} iconName={"settings"} onPress={onPressSettings}/>
|
<Item title={i18n.t("screens.settings")} iconName={"settings"} onPress={onPressSettings}/>
|
||||||
<HiddenItem title={i18n.t("screens.about")} iconName={"information"} onPress={onPressAbout}/>
|
<Item title={i18n.t("screens.about")} iconName={"information"} onPress={onPressAbout}/>
|
||||||
</MaterialHeaderButtons>;
|
</MaterialHeaderButtons>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -36,6 +36,7 @@ class FeedbackScreen extends React.Component<Props> {
|
||||||
}}>
|
}}>
|
||||||
<Button
|
<Button
|
||||||
icon="email"
|
icon="email"
|
||||||
|
mode={"contained"}
|
||||||
style={{
|
style={{
|
||||||
marginLeft: 'auto',
|
marginLeft: 'auto',
|
||||||
marginTop: 5,
|
marginTop: 5,
|
||||||
|
|
@ -45,6 +46,8 @@ class FeedbackScreen extends React.Component<Props> {
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
icon="git"
|
icon="git"
|
||||||
|
mode={"contained"}
|
||||||
|
color={"#609927"}
|
||||||
style={{
|
style={{
|
||||||
marginLeft: 'auto',
|
marginLeft: 'auto',
|
||||||
marginTop: 5,
|
marginTop: 5,
|
||||||
|
|
@ -54,6 +57,8 @@ class FeedbackScreen extends React.Component<Props> {
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
icon="facebook"
|
icon="facebook"
|
||||||
|
mode={"contained"}
|
||||||
|
color={"#2e88fe"}
|
||||||
style={{
|
style={{
|
||||||
marginLeft: 'auto',
|
marginLeft: 'auto',
|
||||||
marginTop: 5,
|
marginTop: 5,
|
||||||
|
|
|
||||||
|
|
@ -1,39 +1,47 @@
|
||||||
// @flow
|
// @flow
|
||||||
|
|
||||||
import * as React from 'react';
|
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 ThemeManager from '../../managers/ThemeManager';
|
||||||
import i18n from "i18n-js";
|
import i18n from "i18n-js";
|
||||||
import AsyncStorageManager from "../../managers/AsyncStorageManager";
|
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 {Appearance} from "react-native-appearance";
|
||||||
import AnimatedAccordion from "../../components/Animations/AnimatedAccordion";
|
import CustomSlider from "../../components/Overrides/CustomSlider";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
navigation: Object,
|
theme: CustomTheme,
|
||||||
};
|
};
|
||||||
|
|
||||||
type State = {
|
type State = {
|
||||||
nightMode: boolean,
|
nightMode: boolean,
|
||||||
nightModeFollowSystem: boolean,
|
nightModeFollowSystem: boolean,
|
||||||
proxiwashNotifPickerSelected: string,
|
notificationReminderSelected: number,
|
||||||
startScreenPickerSelected: string,
|
startScreenPickerSelected: string,
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class defining the Settings screen. This screen shows controls to modify app preferences.
|
* Class defining the Settings screen. This screen shows controls to modify app preferences.
|
||||||
*/
|
*/
|
||||||
export default class SettingsScreen extends React.Component<Props, State> {
|
class SettingsScreen extends React.Component<Props, State> {
|
||||||
state = {
|
|
||||||
nightMode: ThemeManager.getNightMode(),
|
savedNotificationReminder: number;
|
||||||
nightModeFollowSystem: AsyncStorageManager.getInstance().preferences.nightModeFollowSystem.current === '1' &&
|
|
||||||
Appearance.getColorScheme() !== 'no-preference',
|
|
||||||
proxiwashNotifPickerSelected: AsyncStorageManager.getInstance().preferences.proxiwashNotifications.current,
|
|
||||||
startScreenPickerSelected: AsyncStorageManager.getInstance().preferences.defaultStartScreen.current,
|
|
||||||
};
|
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
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
|
* @param value The value to store
|
||||||
*/
|
*/
|
||||||
onProxiwashNotifPickerValueChange = (value: string) => {
|
onProxiwashNotifPickerValueChange = (value: number) => {
|
||||||
if (value != null) {
|
let key = AsyncStorageManager.getInstance().preferences.proxiwashNotifications.key;
|
||||||
let key = AsyncStorageManager.getInstance().preferences.proxiwashNotifications.key;
|
AsyncStorageManager.getInstance().savePref(key, value.toString());
|
||||||
AsyncStorageManager.getInstance().savePref(key, value);
|
this.setState({notificationReminderSelected: value})
|
||||||
this.setState({
|
|
||||||
proxiwashNotifPickerSelected: value
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -73,15 +77,16 @@ export default class SettingsScreen extends React.Component<Props, State> {
|
||||||
*/
|
*/
|
||||||
getProxiwashNotifPicker() {
|
getProxiwashNotifPicker() {
|
||||||
return (
|
return (
|
||||||
<ToggleButton.Row
|
<CustomSlider
|
||||||
|
style={{flex: 1, marginHorizontal: 10, height: 50}}
|
||||||
|
minimumValue={0}
|
||||||
|
maximumValue={10}
|
||||||
|
step={1}
|
||||||
|
value={this.savedNotificationReminder}
|
||||||
onValueChange={this.onProxiwashNotifPickerValueChange}
|
onValueChange={this.onProxiwashNotifPickerValueChange}
|
||||||
value={this.state.proxiwashNotifPickerSelected}
|
thumbTintColor={this.props.theme.colors.primary}
|
||||||
style={{marginLeft: 'auto', marginRight: 'auto'}}
|
minimumTrackTintColor={this.props.theme.colors.primary}
|
||||||
>
|
/>
|
||||||
<ToggleButton icon="close" value="never"/>
|
|
||||||
<ToggleButton icon="numeric-2" value="2"/>
|
|
||||||
<ToggleButton icon="numeric-5" value="5"/>
|
|
||||||
</ToggleButton.Row>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -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 icon The icon name to display on the list item
|
||||||
* @param title The text to display as this list item title
|
* @param title The text to display as this list item title
|
||||||
* @param subtitle The text to display as this list item subtitle
|
* @param subtitle The text to display as this list item subtitle
|
||||||
|
* @param state The current state of the switch
|
||||||
* @returns {React.Node}
|
* @returns {React.Node}
|
||||||
*/
|
*/
|
||||||
getToggleItem(onPressCallback: Function, icon: string, title: string, subtitle: string, state: boolean) {
|
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}
|
title={title}
|
||||||
description={subtitle}
|
description={subtitle}
|
||||||
left={props => <List.Icon {...props} icon={icon}/>}
|
left={props => <List.Icon {...props} icon={icon}/>}
|
||||||
right={props =>
|
right={() =>
|
||||||
<Switch
|
<Switch
|
||||||
value={state}
|
value={state}
|
||||||
onValueChange={onPressCallback}
|
onValueChange={onPressCallback}
|
||||||
|
|
@ -177,28 +183,31 @@ export default class SettingsScreen extends React.Component<Props, State> {
|
||||||
this.state.nightMode
|
this.state.nightMode
|
||||||
) : null
|
) : null
|
||||||
}
|
}
|
||||||
<AnimatedAccordion
|
<List.Item
|
||||||
title={i18n.t('settingsScreen.startScreen')}
|
title={i18n.t('settingsScreen.startScreen')}
|
||||||
subtitle={i18n.t('settingsScreen.startScreenSub')}
|
subtitle={i18n.t('settingsScreen.startScreenSub')}
|
||||||
left={props => <List.Icon {...props} icon="power"/>}
|
left={props => <List.Icon {...props} icon="power"/>}
|
||||||
>
|
/>
|
||||||
{this.getStartScreenPicker()}
|
{this.getStartScreenPicker()}
|
||||||
</AnimatedAccordion>
|
|
||||||
</List.Section>
|
</List.Section>
|
||||||
</Card>
|
</Card>
|
||||||
<Card style={{margin: 5}}>
|
<Card style={{margin: 5}}>
|
||||||
<Card.Title title="Proxiwash"/>
|
<Card.Title title="Proxiwash"/>
|
||||||
<List.Section>
|
<List.Section>
|
||||||
<AnimatedAccordion
|
<List.Item
|
||||||
title={i18n.t('settingsScreen.proxiwashNotifReminder')}
|
title={i18n.t('settingsScreen.proxiwashNotifReminder')}
|
||||||
description={i18n.t('settingsScreen.proxiwashNotifReminderSub')}
|
description={i18n.t('settingsScreen.proxiwashNotifReminderSub')}
|
||||||
left={props => <List.Icon {...props} icon="washing-machine"/>}
|
left={props => <List.Icon {...props} icon="washing-machine"/>}
|
||||||
>
|
opened={true}
|
||||||
|
/>
|
||||||
|
<View style={{marginLeft: 30}}>
|
||||||
{this.getProxiwashNotifPicker()}
|
{this.getProxiwashNotifPicker()}
|
||||||
</AnimatedAccordion>
|
</View>
|
||||||
</List.Section>
|
</List.Section>
|
||||||
</Card>
|
</Card>
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export default withTheme(SettingsScreen);
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ type Props = {
|
||||||
navigation: Object,
|
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.
|
* Class defining the proxiwash about screen.
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@ import type {CustomTheme} from "../../managers/ThemeManager";
|
||||||
import {Collapsible} from "react-navigation-collapsible";
|
import {Collapsible} from "react-navigation-collapsible";
|
||||||
import {StackNavigationProp} from "@react-navigation/stack";
|
import {StackNavigationProp} from "@react-navigation/stack";
|
||||||
import {getCleanedMachineWatched, getMachineEndDate, isMachineWatched} from "../../utils/Proxiwash";
|
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";
|
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> {
|
class ProxiwashScreen extends React.Component<Props, State> {
|
||||||
|
|
||||||
modalRef: Object;
|
modalRef: null | Modalize;
|
||||||
|
|
||||||
fetchedData: Object;
|
fetchedData: {
|
||||||
|
dryers: Array<Machine>,
|
||||||
|
washers: Array<Machine>,
|
||||||
|
};
|
||||||
|
|
||||||
state = {
|
state = {
|
||||||
refreshing: false,
|
refreshing: false,
|
||||||
|
|
@ -95,7 +99,10 @@ class ProxiwashScreen extends React.Component<Props, State> {
|
||||||
*/
|
*/
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
this.props.navigation.setOptions({
|
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');
|
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
|
* Extracts the key for the given item
|
||||||
*
|
*
|
||||||
|
|
@ -123,7 +120,6 @@ class ProxiwashScreen extends React.Component<Props, State> {
|
||||||
*/
|
*/
|
||||||
getKeyExtractor = (item: Machine) => item.number;
|
getKeyExtractor = (item: Machine) => item.number;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Setups notifications for the machine with the given ID.
|
* Setups notifications for the machine with the given ID.
|
||||||
* One notification will be sent at the end of the program.
|
* One notification will be sent at the end of the program.
|
||||||
|
|
@ -141,7 +137,7 @@ class ProxiwashScreen extends React.Component<Props, State> {
|
||||||
this.showNotificationsDisabledWarning();
|
this.showNotificationsDisabledWarning();
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
Notifications.setupMachineNotification(machine.number, false)
|
Notifications.setupMachineNotification(machine.number, false, null)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
this.removeNotificationFromState(machine);
|
this.removeNotificationFromState(machine);
|
||||||
});
|
});
|
||||||
|
|
@ -271,6 +267,10 @@ class ProxiwashScreen extends React.Component<Props, State> {
|
||||||
let message = modalStateStrings[ProxiwashConstants.machineStates[item.state]];
|
let message = modalStateStrings[ProxiwashConstants.machineStates[item.state]];
|
||||||
const onPress = this.onSetupNotificationsPress.bind(this, item);
|
const onPress = this.onSetupNotificationsPress.bind(this, item);
|
||||||
if (ProxiwashConstants.machineStates[item.state] === ProxiwashConstants.machineStates["EN COURS"]) {
|
if (ProxiwashConstants.machineStates[item.state] === ProxiwashConstants.machineStates["EN COURS"]) {
|
||||||
|
let remainingTime = parseInt(item.remainingTime)
|
||||||
|
if (remainingTime < 0)
|
||||||
|
remainingTime = 0;
|
||||||
|
|
||||||
button =
|
button =
|
||||||
{
|
{
|
||||||
text: isMachineWatched(item, this.state.machinesWatched) ?
|
text: isMachineWatched(item, this.state.machinesWatched) ?
|
||||||
|
|
@ -284,7 +284,7 @@ class ProxiwashScreen extends React.Component<Props, State> {
|
||||||
{
|
{
|
||||||
start: item.startTime,
|
start: item.startTime,
|
||||||
end: item.endTime,
|
end: item.endTime,
|
||||||
remaining: item.remainingTime
|
remaining: remainingTime
|
||||||
});
|
});
|
||||||
} else if (ProxiwashConstants.machineStates[item.state] === ProxiwashConstants.machineStates.DISPONIBLE) {
|
} else if (ProxiwashConstants.machineStates[item.state] === ProxiwashConstants.machineStates.DISPONIBLE) {
|
||||||
if (isDryer)
|
if (isDryer)
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ type Props = {
|
||||||
navigation: Object,
|
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.
|
* Class defining the proximo about screen.
|
||||||
|
|
|
||||||
|
|
@ -20,17 +20,22 @@ type Props = {
|
||||||
collapsibleStack: Collapsible,
|
collapsibleStack: Collapsible,
|
||||||
theme: CustomTheme,
|
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 CLUBS_IMAGE = "https://etud.insa-toulouse.fr/~amicale_app/images/Clubs.png";
|
||||||
const WIKETUD_LINK = "https://wiki.etud.insa-toulouse.fr/resources/assets/wiketud.png?ff051";
|
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 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 = {
|
export type listItem = {
|
||||||
title: string,
|
title: string,
|
||||||
|
|
@ -59,19 +64,25 @@ class ServicesScreen extends React.Component<Props, State> {
|
||||||
{
|
{
|
||||||
title: i18n.t('screens.clubsAbout'),
|
title: i18n.t('screens.clubsAbout'),
|
||||||
subtitle: "CLUB LIST",
|
subtitle: "CLUB LIST",
|
||||||
image: AMICALE_IMAGE,
|
image: CLUBS_IMAGE,
|
||||||
onPress: () => nav.navigate("club-list"),
|
onPress: () => nav.navigate("club-list"),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: i18n.t('screens.profile'),
|
title: i18n.t('screens.profile'),
|
||||||
subtitle: "PROFIL",
|
subtitle: "PROFIL",
|
||||||
image: AMICALE_IMAGE,
|
image: PROFILE_IMAGE,
|
||||||
onPress: () => nav.navigate("profile"),
|
onPress: () => nav.navigate("profile"),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
title: i18n.t('screens.amicaleWebsite'),
|
||||||
|
subtitle: "AMICALE",
|
||||||
|
image: AMICALE_IMAGE,
|
||||||
|
onPress: () => nav.navigate("amicale-website"),
|
||||||
|
},
|
||||||
{
|
{
|
||||||
title: i18n.t('screens.vote'),
|
title: i18n.t('screens.vote'),
|
||||||
subtitle: "ELECTIONS",
|
subtitle: "ELECTIONS",
|
||||||
image: AMICALE_IMAGE,
|
image: VOTE_IMAGE,
|
||||||
onPress: () => nav.navigate("vote"),
|
onPress: () => nav.navigate("vote"),
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
@ -82,16 +93,10 @@ class ServicesScreen extends React.Component<Props, State> {
|
||||||
image: PROXIMO_IMAGE,
|
image: PROXIMO_IMAGE,
|
||||||
onPress: () => nav.navigate("proximo"),
|
onPress: () => nav.navigate("proximo"),
|
||||||
},
|
},
|
||||||
{
|
|
||||||
title: i18n.t('screens.amicaleWebsite'),
|
|
||||||
subtitle: "AMICALE",
|
|
||||||
image: AMICALE_IMAGE,
|
|
||||||
onPress: () => nav.navigate("amicale-website"),
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
title: "Wiketud",
|
title: "Wiketud",
|
||||||
subtitle: "wiketud",
|
subtitle: "wiketud",
|
||||||
image: WIKETUD_LINK,
|
image: WIKETUD_IMAGE,
|
||||||
onPress: () => nav.navigate("wiketud"),
|
onPress: () => nav.navigate("wiketud"),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -201,7 +206,7 @@ class ServicesScreen extends React.Component<Props, State> {
|
||||||
return <Avatar.Image
|
return <Avatar.Image
|
||||||
{...props}
|
{...props}
|
||||||
size={48}
|
size={48}
|
||||||
source={AMICALE_IMAGE}
|
source={source}
|
||||||
style={{backgroundColor: 'transparent'}}
|
style={{backgroundColor: 'transparent'}}
|
||||||
/>
|
/>
|
||||||
else
|
else
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
import {checkNotifications, requestNotifications, RESULTS} from 'react-native-permissions';
|
import {checkNotifications, requestNotifications, RESULTS} from 'react-native-permissions';
|
||||||
import AsyncStorageManager from "../managers/AsyncStorageManager";
|
import AsyncStorageManager from "../managers/AsyncStorageManager";
|
||||||
|
import i18n from "i18n-js";
|
||||||
|
|
||||||
const PushNotification = require("react-native-push-notification");
|
const PushNotification = require("react-native-push-notification");
|
||||||
|
|
||||||
|
|
@ -38,8 +39,8 @@ function createNotifications(machineID: string, date: Date) {
|
||||||
let reminderDate = new Date(date);
|
let reminderDate = new Date(date);
|
||||||
reminderDate.setMinutes(reminderDate.getMinutes() - reminder);
|
reminderDate.setMinutes(reminderDate.getMinutes() - reminder);
|
||||||
PushNotification.localNotificationSchedule({
|
PushNotification.localNotificationSchedule({
|
||||||
title: "Title",
|
title: i18n.t("proxiwashScreen.notifications.machineRunningTitle", {time: reminder}),
|
||||||
message: "Message",
|
message: i18n.t("proxiwashScreen.notifications.machineRunningBody", {number: machineID}),
|
||||||
id: id.toString(),
|
id: id.toString(),
|
||||||
date: reminderDate,
|
date: reminderDate,
|
||||||
});
|
});
|
||||||
|
|
@ -48,8 +49,8 @@ function createNotifications(machineID: string, date: Date) {
|
||||||
console.log("Setting up notifications for ", date);
|
console.log("Setting up notifications for ", date);
|
||||||
|
|
||||||
PushNotification.localNotificationSchedule({
|
PushNotification.localNotificationSchedule({
|
||||||
title: "Title",
|
title: i18n.t("proxiwashScreen.notifications.machineFinishedTitle"),
|
||||||
message: "Message",
|
message: i18n.t("proxiwashScreen.notifications.machineFinishedBody", {number: machineID}),
|
||||||
id: machineID,
|
id: machineID,
|
||||||
date: date,
|
date: date,
|
||||||
});
|
});
|
||||||
|
|
@ -62,7 +63,7 @@ function createNotifications(machineID: string, date: Date) {
|
||||||
* @param isEnabled True to enable notifications, false to disable
|
* @param isEnabled True to enable notifications, false to disable
|
||||||
* @param endDate
|
* @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) => {
|
return new Promise((resolve, reject) => {
|
||||||
if (isEnabled && endDate != null) {
|
if (isEnabled && endDate != null) {
|
||||||
askPermissions()
|
askPermissions()
|
||||||
|
|
|
||||||
|
|
@ -1,22 +1,41 @@
|
||||||
// @flow
|
// @flow
|
||||||
|
|
||||||
import type {Machine} from "../screens/Proxiwash/ProxiwashScreen";
|
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(":");
|
const array = machine.endTime.split(":");
|
||||||
let date = new Date();
|
let endDate = new Date(Date.now());
|
||||||
date.setHours(parseInt(array[0]), parseInt(array[1]));
|
endDate.setHours(parseInt(array[0]), parseInt(array[1]));
|
||||||
if (date < new Date())
|
|
||||||
date.setDate(date.getDate() + 1);
|
let limit = new Date(Date.now());
|
||||||
return date;
|
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
|
* Checks whether the machine of the given ID has scheduled notifications
|
||||||
*
|
*
|
||||||
* @param machine
|
* @param machine The machine to check
|
||||||
* @param machineList
|
* @param machineList The machine list
|
||||||
* @returns {boolean}
|
* @returns {boolean}
|
||||||
*/
|
*/
|
||||||
export function isMachineWatched(machine: Machine, machineList: Array<Machine>) {
|
export function isMachineWatched(machine: Machine, machineList: Array<Machine>) {
|
||||||
|
|
@ -30,7 +49,14 @@ export function isMachineWatched(machine: Machine, machineList: Array<Machine>)
|
||||||
return watched;
|
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++) {
|
for (let i = 0; i < allMachines.length; i++) {
|
||||||
if (allMachines[i].number === id)
|
if (allMachines[i].number === id)
|
||||||
return allMachines[i];
|
return allMachines[i];
|
||||||
|
|
@ -38,13 +64,22 @@ function getMachineOfId(id: string, allMachines: Array<Machine>) {
|
||||||
return null;
|
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 = [];
|
let newList = [];
|
||||||
for (let i = 0; i < machineList.length; i++) {
|
for (let i = 0; i < machineWatchedList.length; i++) {
|
||||||
let machine = getMachineOfId(machineList[i].number, allMachines);
|
let machine = getMachineOfId(machineWatchedList[i].number, allMachines);
|
||||||
if (machine !== null
|
if (machine !== null
|
||||||
&& machineList[i].number === machine.number && machineList[i].endTime === machine.endTime
|
&& machineWatchedList[i].number === machine.number
|
||||||
&& ProxiwashConstants.machineStates[machineList[i].state] === ProxiwashConstants.machineStates["EN COURS"]) {
|
&& machineWatchedList[i].endTime === machine.endTime) {
|
||||||
newList.push(machine);
|
newList.push(machine);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue