forked from vergnet/application-amicale
Started writing documentation and ported app to use Flow
This commit is contained in:
parent
b16aab8adc
commit
0385bbb882
20 changed files with 351 additions and 243 deletions
11
.flowconfig
Normal file
11
.flowconfig
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
[ignore]
|
||||||
|
|
||||||
|
[include]
|
||||||
|
|
||||||
|
[libs]
|
||||||
|
|
||||||
|
[lints]
|
||||||
|
|
||||||
|
[options]
|
||||||
|
|
||||||
|
[strict]
|
41
App.js
41
App.js
|
@ -1,3 +1,5 @@
|
||||||
|
// @flow
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import {StyleProvider, Root, View} from 'native-base';
|
import {StyleProvider, Root, View} from 'native-base';
|
||||||
import AppNavigator from './navigation/AppNavigator';
|
import AppNavigator from './navigation/AppNavigator';
|
||||||
|
@ -7,26 +9,37 @@ import * as Font from 'expo-font';
|
||||||
// edited native-base-shoutem-theme according to
|
// edited native-base-shoutem-theme according to
|
||||||
// https://github.com/GeekyAnts/theme/pull/5/files/91f67c55ca6e65fe3af779586b506950c9f331be#diff-4cfc2dd4d5dae7954012899f2268a422
|
// https://github.com/GeekyAnts/theme/pull/5/files/91f67c55ca6e65fe3af779586b506950c9f331be#diff-4cfc2dd4d5dae7954012899f2268a422
|
||||||
// to allow for dynamic theme switching
|
// to allow for dynamic theme switching
|
||||||
import { clearThemeCache } from 'native-base-shoutem-theme';
|
import {clearThemeCache} from 'native-base-shoutem-theme';
|
||||||
|
|
||||||
export default class App extends React.Component {
|
type Props = {};
|
||||||
|
|
||||||
constructor(props) {
|
type State = {
|
||||||
|
isLoading: boolean,
|
||||||
|
currentTheme: ?Object,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default class App extends React.Component<Props, State> {
|
||||||
|
|
||||||
|
state = {
|
||||||
|
isLoading: true,
|
||||||
|
currentTheme: null,
|
||||||
|
};
|
||||||
|
|
||||||
|
constructor(props: Object) {
|
||||||
super(props);
|
super(props);
|
||||||
LocaleManager.getInstance().initTranslations();
|
LocaleManager.initTranslations();
|
||||||
this.updateTheme = this.updateTheme.bind(this);
|
|
||||||
this.state = {
|
|
||||||
isLoading: true,
|
|
||||||
currentTheme: undefined,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads data before components are mounted, like fonts and themes
|
||||||
|
* @returns {Promise}
|
||||||
|
*/
|
||||||
async componentWillMount() {
|
async componentWillMount() {
|
||||||
await Font.loadAsync({
|
await Font.loadAsync({
|
||||||
'Roboto': require('native-base/Fonts/Roboto.ttf'),
|
'Roboto': require('native-base/Fonts/Roboto.ttf'),
|
||||||
'Roboto_medium': require('native-base/Fonts/Roboto_medium.ttf'),
|
'Roboto_medium': require('native-base/Fonts/Roboto_medium.ttf'),
|
||||||
});
|
});
|
||||||
ThemeManager.getInstance().setUpdateThemeCallback(this.updateTheme);
|
ThemeManager.getInstance().setUpdateThemeCallback(() => this.updateTheme());
|
||||||
await ThemeManager.getInstance().getDataFromPreferences();
|
await ThemeManager.getInstance().getDataFromPreferences();
|
||||||
this.setState({
|
this.setState({
|
||||||
isLoading: false,
|
isLoading: false,
|
||||||
|
@ -34,6 +47,9 @@ export default class App extends React.Component {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the theme and clears the cache to force reloading the app colors
|
||||||
|
*/
|
||||||
updateTheme() {
|
updateTheme() {
|
||||||
// console.log('update theme called');
|
// console.log('update theme called');
|
||||||
this.setState({
|
this.setState({
|
||||||
|
@ -42,6 +58,11 @@ export default class App extends React.Component {
|
||||||
clearThemeCache();
|
clearThemeCache();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Renders the app based on loading state
|
||||||
|
*
|
||||||
|
* @returns {*}
|
||||||
|
*/
|
||||||
render() {
|
render() {
|
||||||
if (this.state.isLoading) {
|
if (this.state.isLoading) {
|
||||||
return <View/>;
|
return <View/>;
|
||||||
|
|
|
@ -1,15 +1,31 @@
|
||||||
import React from "react";
|
// @flow
|
||||||
import {Body, Button, Header, Icon, Left, Right, Title} from "native-base";
|
|
||||||
|
import * as React from "react";
|
||||||
|
import {Body, Header, Icon, Left, Right, Title} from "native-base";
|
||||||
import {StyleSheet} from "react-native";
|
import {StyleSheet} from "react-native";
|
||||||
import {getStatusBarHeight} from "react-native-status-bar-height";
|
import {getStatusBarHeight} from "react-native-status-bar-height";
|
||||||
import Touchable from 'react-native-platform-touchable';
|
import Touchable from 'react-native-platform-touchable';
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
backButton: boolean,
|
||||||
|
rightMenu: React.Node,
|
||||||
|
title: string,
|
||||||
|
navigation: Object,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
export default class CustomHeader extends React.Component<Props> {
|
||||||
|
|
||||||
|
static defaultProps = {
|
||||||
|
backButton: false,
|
||||||
|
rightMenu: <Right/>,
|
||||||
|
fontSize: 26,
|
||||||
|
width: 30,
|
||||||
|
};
|
||||||
|
|
||||||
export default class CustomHeader extends React.Component {
|
|
||||||
render() {
|
render() {
|
||||||
let button;
|
let button;
|
||||||
let rightMenu;
|
if (this.props.backButton)
|
||||||
if (this.props.backButton !== undefined && this.props.backButton === true)
|
|
||||||
button =
|
button =
|
||||||
<Touchable
|
<Touchable
|
||||||
style={{padding: 6}}
|
style={{padding: 6}}
|
||||||
|
@ -30,11 +46,6 @@ export default class CustomHeader extends React.Component {
|
||||||
type={'MaterialCommunityIcons'}/>
|
type={'MaterialCommunityIcons'}/>
|
||||||
</Touchable>;
|
</Touchable>;
|
||||||
|
|
||||||
if (this.props.rightMenu)
|
|
||||||
rightMenu = this.props.rightMenu;
|
|
||||||
else
|
|
||||||
rightMenu = <Right/>;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Header style={styles.header}>
|
<Header style={styles.header}>
|
||||||
<Left>
|
<Left>
|
||||||
|
@ -43,7 +54,7 @@ export default class CustomHeader extends React.Component {
|
||||||
<Body>
|
<Body>
|
||||||
<Title>{this.props.title}</Title>
|
<Title>{this.props.title}</Title>
|
||||||
</Body>
|
</Body>
|
||||||
{rightMenu}
|
{this.props.rightMenu}
|
||||||
</Header>);
|
</Header>);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,12 +1,25 @@
|
||||||
import React from 'react';
|
// @flow
|
||||||
|
|
||||||
|
import * as React from 'react';
|
||||||
import {Icon} from "native-base";
|
import {Icon} from "native-base";
|
||||||
import ThemeManager from '../utils/ThemeManager';
|
import ThemeManager from '../utils/ThemeManager';
|
||||||
|
|
||||||
export default class CustomMaterialIcon extends React.Component {
|
type Props = {
|
||||||
|
active: boolean,
|
||||||
|
icon: string,
|
||||||
|
color: ?string,
|
||||||
|
fontSize: number,
|
||||||
|
width: number,
|
||||||
|
}
|
||||||
|
|
||||||
constructor(props) {
|
export default class CustomMaterialIcon extends React.Component<Props> {
|
||||||
super(props);
|
|
||||||
}
|
static defaultProps = {
|
||||||
|
active: false,
|
||||||
|
color: undefined,
|
||||||
|
fontSize: 26,
|
||||||
|
width: 30,
|
||||||
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
|
@ -21,8 +34,8 @@ export default class CustomMaterialIcon extends React.Component {
|
||||||
this.props.active ?
|
this.props.active ?
|
||||||
ThemeManager.getInstance().getCurrentThemeVariables().brandPrimary :
|
ThemeManager.getInstance().getCurrentThemeVariables().brandPrimary :
|
||||||
ThemeManager.getInstance().getCurrentThemeVariables().customMaterialIconColor,
|
ThemeManager.getInstance().getCurrentThemeVariables().customMaterialIconColor,
|
||||||
fontSize: this.props.fontSize !== undefined ? this.props.fontSize : 26,
|
fontSize: this.props.fontSize,
|
||||||
width: this.props.width !== undefined ? this.props.width : 30
|
width: this.props.width
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
import React from 'react';
|
// @flow
|
||||||
|
|
||||||
|
import * as React from 'react';
|
||||||
import {Platform, Dimensions, StyleSheet, Image, FlatList, Linking} from 'react-native';
|
import {Platform, Dimensions, StyleSheet, Image, FlatList, Linking} from 'react-native';
|
||||||
import {Badge, Text, Container, Content, Icon, Left, ListItem, Right} from "native-base";
|
import {Badge, Text, Container, Content, Left, ListItem, Right} from "native-base";
|
||||||
import i18n from "i18n-js";
|
import i18n from "i18n-js";
|
||||||
import CustomMaterialIcon from '../components/CustomMaterialIcon';
|
import CustomMaterialIcon from '../components/CustomMaterialIcon';
|
||||||
|
|
||||||
|
@ -10,9 +12,19 @@ const drawerCover = require("../assets/drawer-cover.png");
|
||||||
|
|
||||||
const WIKETUD_LINK = "https://www.etud.insa-toulouse.fr/wiketud/index.php/Accueil";
|
const WIKETUD_LINK = "https://www.etud.insa-toulouse.fr/wiketud/index.php/Accueil";
|
||||||
|
|
||||||
export default class SideBar extends React.Component {
|
type Props = {
|
||||||
|
navigation: Object,
|
||||||
|
};
|
||||||
|
|
||||||
constructor(props) {
|
type State = {
|
||||||
|
active: string,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default class SideBar extends React.Component<Props, State> {
|
||||||
|
|
||||||
|
dataSet: Array<Object>;
|
||||||
|
|
||||||
|
constructor(props: Props) {
|
||||||
super(props);
|
super(props);
|
||||||
this.state = {
|
this.state = {
|
||||||
active: 'Home',
|
active: 'Home',
|
||||||
|
@ -70,7 +82,7 @@ export default class SideBar extends React.Component {
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
navigateToScreen(route) {
|
navigateToScreen(route: string) {
|
||||||
this.props.navigation.navigate(route);
|
this.props.navigation.navigate(route);
|
||||||
this.props.navigation.closeDrawer();
|
this.props.navigation.closeDrawer();
|
||||||
this.setState({active: route});
|
this.setState({active: route});
|
||||||
|
@ -88,7 +100,7 @@ export default class SideBar extends React.Component {
|
||||||
<FlatList
|
<FlatList
|
||||||
data={this.dataSet}
|
data={this.dataSet}
|
||||||
extraData={this.state}
|
extraData={this.state}
|
||||||
keyExtractor={(item, index) => item.route}
|
keyExtractor={(item) => item.route}
|
||||||
renderItem={({item}) =>
|
renderItem={({item}) =>
|
||||||
<ListItem
|
<ListItem
|
||||||
button
|
button
|
||||||
|
|
|
@ -1,16 +0,0 @@
|
||||||
import React from 'react';
|
|
||||||
import {Ionicons} from '@expo/vector-icons/build/Icons';
|
|
||||||
|
|
||||||
export default class TabBarIcon extends React.Component {
|
|
||||||
render() {
|
|
||||||
return (
|
|
||||||
<Ionicons
|
|
||||||
name={this.props.name}
|
|
||||||
size={26}
|
|
||||||
style={{marginBottom: -3}}
|
|
||||||
color={this.props.focused ? Colors.tabIconSelected : Colors.tabIconDefault}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
// @flow
|
||||||
|
|
||||||
import {createAppContainer, createStackNavigator} from 'react-navigation';
|
import {createAppContainer, createStackNavigator} from 'react-navigation';
|
||||||
|
|
||||||
import MainDrawerNavigator from './MainDrawerNavigator';
|
import MainDrawerNavigator from './MainDrawerNavigator';
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
import React from 'react';
|
// @flow
|
||||||
|
|
||||||
|
import * as React from 'react';
|
||||||
import {createDrawerNavigator} from 'react-navigation';
|
import {createDrawerNavigator} from 'react-navigation';
|
||||||
|
|
||||||
import HomeScreen from '../screens/HomeScreen';
|
import HomeScreen from '../screens/HomeScreen';
|
||||||
|
|
|
@ -1,58 +0,0 @@
|
||||||
import React from 'react';
|
|
||||||
import {Platform} from 'react-native';
|
|
||||||
import {createStackNavigator} from 'react-navigation';
|
|
||||||
import {createMaterialBottomTabNavigator} from "react-navigation-material-bottom-tabs";
|
|
||||||
import TabBarIcon from '../components/TabBarIcon';
|
|
||||||
|
|
||||||
import HomeScreen from '../screens/HomeScreen';
|
|
||||||
import PlanningScreen from '../screens/PlanningScreen';
|
|
||||||
|
|
||||||
const HomeStack = createStackNavigator({
|
|
||||||
Home: HomeScreen,
|
|
||||||
});
|
|
||||||
|
|
||||||
HomeStack.navigationOptions = {
|
|
||||||
tabBarLabel: 'Home',
|
|
||||||
tabBarIcon: ({focused}) => (
|
|
||||||
<TabBarIcon
|
|
||||||
focused={focused}
|
|
||||||
name={
|
|
||||||
Platform.OS === 'ios'
|
|
||||||
? 'ios-home'
|
|
||||||
: 'md-home'
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
),
|
|
||||||
};
|
|
||||||
|
|
||||||
const ProfileStack = createStackNavigator({
|
|
||||||
Profile: PlanningScreen,
|
|
||||||
});
|
|
||||||
|
|
||||||
ProfileStack.navigationOptions = {
|
|
||||||
tabBarLabel: 'Profile',
|
|
||||||
tabBarIcon: ({focused}) => (
|
|
||||||
<TabBarIcon
|
|
||||||
focused={focused}
|
|
||||||
name={
|
|
||||||
Platform.OS === 'ios'
|
|
||||||
? 'ios-people'
|
|
||||||
: 'md-people'
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
),
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
export default createMaterialBottomTabNavigator(
|
|
||||||
{
|
|
||||||
Home: HomeStack,
|
|
||||||
Profile: ProfileStack
|
|
||||||
}, {
|
|
||||||
initialRouteName: 'Home',
|
|
||||||
shifting: true,
|
|
||||||
activeColor: Colors.tabIconSelected,
|
|
||||||
inactiveColor: Colors.tabIconDefault,
|
|
||||||
barStyle: {backgroundColor: Colors.mainColor},
|
|
||||||
}
|
|
||||||
);
|
|
|
@ -1,5 +1,7 @@
|
||||||
import React from 'react';
|
// @flow
|
||||||
import {Container, Text, Content, ListItem, Body, Left, Thumbnail, Right, Button, Icon} from 'native-base';
|
|
||||||
|
import * as React from 'react';
|
||||||
|
import {Container, Text, Content, ListItem, Body} from 'native-base';
|
||||||
import CustomHeader from "../../components/CustomHeader";
|
import CustomHeader from "../../components/CustomHeader";
|
||||||
import {FlatList} from "react-native";
|
import {FlatList} from "react-native";
|
||||||
import i18n from "i18n-js";
|
import i18n from "i18n-js";
|
||||||
|
@ -14,8 +16,11 @@ function generateListFromObject(object) {
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
navigation: Object
|
||||||
|
}
|
||||||
|
|
||||||
export default class AboutDependenciesScreen extends React.Component {
|
export default class AboutDependenciesScreen extends React.Component<Props> {
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const nav = this.props.navigation;
|
const nav = this.props.navigation;
|
||||||
|
@ -26,7 +31,7 @@ export default class AboutDependenciesScreen extends React.Component {
|
||||||
<Content>
|
<Content>
|
||||||
<FlatList
|
<FlatList
|
||||||
data={data}
|
data={data}
|
||||||
keyExtractor={(item, index) => item.name}
|
keyExtractor={(item) => item.name}
|
||||||
style={{minHeight: 300, width: '100%'}}
|
style={{minHeight: 300, width: '100%'}}
|
||||||
renderItem={({item}) =>
|
renderItem={({item}) =>
|
||||||
<ListItem>
|
<ListItem>
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
import React from 'react';
|
// @flow
|
||||||
|
|
||||||
|
import * as React from 'react';
|
||||||
import {Platform, StyleSheet, Linking, Alert, FlatList} from 'react-native';
|
import {Platform, StyleSheet, Linking, Alert, FlatList} from 'react-native';
|
||||||
import {Container, Content, Text, Card, CardItem, Body, Icon, Left, Right, Thumbnail, H1, ListItem} from 'native-base';
|
import {Container, Content, Text, Card, CardItem, Body, Left, Right, Thumbnail, H1} from 'native-base';
|
||||||
import CustomHeader from "../../components/CustomHeader";
|
import CustomHeader from "../../components/CustomHeader";
|
||||||
import i18n from "i18n-js";
|
import i18n from "i18n-js";
|
||||||
import appJson from '../../app';
|
import appJson from '../../app';
|
||||||
|
@ -20,13 +22,18 @@ const links = {
|
||||||
react: 'https://facebook.github.io/react-native/',
|
react: 'https://facebook.github.io/react-native/',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
navigation: Object,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
function openWebLink(link) {
|
function openWebLink(link) {
|
||||||
Linking.openURL(link).catch((err) => console.error('Error opening link', err));
|
Linking.openURL(link).catch((err) => console.error('Error opening link', err));
|
||||||
}
|
}
|
||||||
|
|
||||||
export default class AboutScreen extends React.Component {
|
export default class AboutScreen extends React.Component<Props> {
|
||||||
|
|
||||||
appData = [
|
appData: Array<Object> = [
|
||||||
{
|
{
|
||||||
onPressCallback: () => openWebLink(Platform.OS === "ios" ? links.appstore : links.playstore),
|
onPressCallback: () => openWebLink(Platform.OS === "ios" ? links.appstore : links.playstore),
|
||||||
icon: Platform.OS === "ios" ? 'apple' : 'google-play',
|
icon: Platform.OS === "ios" ? 'apple' : 'google-play',
|
||||||
|
@ -59,7 +66,7 @@ export default class AboutScreen extends React.Component {
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
authorData = [
|
authorData: Array<Object> = [
|
||||||
{
|
{
|
||||||
onPressCallback: () => Alert.alert('Coucou', 'Whaou'),
|
onPressCallback: () => Alert.alert('Coucou', 'Whaou'),
|
||||||
icon: 'account-circle',
|
icon: 'account-circle',
|
||||||
|
@ -86,7 +93,7 @@ export default class AboutScreen extends React.Component {
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
technoData = [
|
technoData: Array<Object> = [
|
||||||
{
|
{
|
||||||
onPressCallback: () => openWebLink(links.react),
|
onPressCallback: () => openWebLink(links.react),
|
||||||
icon: 'react',
|
icon: 'react',
|
||||||
|
@ -101,7 +108,7 @@ export default class AboutScreen extends React.Component {
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
getCardItem(onPressCallback, icon, text, showChevron) {
|
getCardItem(onPressCallback: Function, icon: string, text: string, showChevron: boolean) {
|
||||||
return (
|
return (
|
||||||
<CardItem button
|
<CardItem button
|
||||||
onPress={onPressCallback}>
|
onPress={onPressCallback}>
|
||||||
|
@ -178,12 +185,3 @@ export default class AboutScreen extends React.Component {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
|
||||||
container: {
|
|
||||||
flex: 1,
|
|
||||||
backgroundColor: '#fff',
|
|
||||||
alignItems: 'center',
|
|
||||||
justifyContent: 'center',
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
|
@ -1,12 +1,16 @@
|
||||||
import React from 'react';
|
// @flow
|
||||||
|
|
||||||
|
import * as React from 'react';
|
||||||
import {Container, Content, Text, Button, Icon} from 'native-base';
|
import {Container, Content, Text, Button, Icon} from 'native-base';
|
||||||
import CustomHeader from '../components/CustomHeader';
|
import CustomHeader from '../components/CustomHeader';
|
||||||
import i18n from "i18n-js";
|
import i18n from "i18n-js";
|
||||||
import NotificationsManager from '../utils/NotificationsManager'
|
import NotificationsManager from '../utils/NotificationsManager'
|
||||||
import { Notifications } from 'expo';
|
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
navigation: Object,
|
||||||
|
}
|
||||||
|
|
||||||
export default class HomeScreen extends React.Component {
|
export default class HomeScreen extends React.Component<Props> {
|
||||||
render() {
|
render() {
|
||||||
const nav = this.props.navigation;
|
const nav = this.props.navigation;
|
||||||
return (
|
return (
|
||||||
|
@ -19,7 +23,7 @@ export default class HomeScreen extends React.Component {
|
||||||
name={'bell-ring'}
|
name={'bell-ring'}
|
||||||
type={'MaterialCommunityIcons'}
|
type={'MaterialCommunityIcons'}
|
||||||
/>
|
/>
|
||||||
<Text>Notif</Text>
|
<Text>Instant Notification</Text>
|
||||||
</Button>
|
</Button>
|
||||||
</Content>
|
</Content>
|
||||||
</Container>
|
</Container>
|
||||||
|
|
|
@ -1,10 +1,15 @@
|
||||||
import React from 'react';
|
// @flow
|
||||||
import { StyleSheet, View } from 'react-native';
|
|
||||||
|
import * as React from 'react';
|
||||||
import {Container, Text} from 'native-base';
|
import {Container, Text} from 'native-base';
|
||||||
import CustomHeader from "../components/CustomHeader";
|
import CustomHeader from "../components/CustomHeader";
|
||||||
import i18n from "i18n-js";
|
import i18n from "i18n-js";
|
||||||
|
|
||||||
export default class PlanningScreen extends React.Component {
|
type Props = {
|
||||||
|
navigation: Object,
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class PlanningScreen extends React.Component<Props> {
|
||||||
render() {
|
render() {
|
||||||
const nav = this.props.navigation;
|
const nav = this.props.navigation;
|
||||||
return (
|
return (
|
||||||
|
@ -14,11 +19,4 @@ export default class PlanningScreen extends React.Component {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const styles = StyleSheet.create({
|
|
||||||
container: {
|
|
||||||
flex: 1,
|
|
||||||
backgroundColor: '#fff',
|
|
||||||
alignItems: 'center',
|
|
||||||
justifyContent: 'center',
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
import React from 'react';
|
// @flow
|
||||||
|
|
||||||
|
import * as React from 'react';
|
||||||
import {Container, Text, Content, ListItem, Left, Thumbnail, Right, Body, Icon} from 'native-base';
|
import {Container, Text, Content, ListItem, Left, Thumbnail, Right, Body, Icon} from 'native-base';
|
||||||
import CustomHeader from "../../components/CustomHeader";
|
import CustomHeader from "../../components/CustomHeader";
|
||||||
import {AsyncStorage, FlatList, View} from "react-native";
|
import {FlatList} from "react-native";
|
||||||
import Touchable from 'react-native-platform-touchable';
|
import Touchable from 'react-native-platform-touchable';
|
||||||
import Menu, {MenuItem, MenuDivider} from 'react-native-material-menu';
|
import Menu, {MenuItem} from 'react-native-material-menu';
|
||||||
import i18n from "i18n-js";
|
import i18n from "i18n-js";
|
||||||
|
|
||||||
const IMG_URL = "https://etud.insa-toulouse.fr/~vergnet/appli-amicale/img/";
|
const IMG_URL = "https://etud.insa-toulouse.fr/~vergnet/appli-amicale/img/";
|
||||||
|
@ -39,24 +41,35 @@ function sortNameReverse(a, b) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
navigation: Object
|
||||||
|
}
|
||||||
|
|
||||||
export default class ProximoMainScreen extends React.Component {
|
type State = {
|
||||||
constructor(props) {
|
navData: Array<Object>,
|
||||||
super(props);
|
currentSortMode: string,
|
||||||
this.state = {
|
isSortReversed: boolean,
|
||||||
navData: this.props.navigation.getParam('data', []).sort(sortPrice),
|
sortPriceIcon: React.Node,
|
||||||
currentSortMode: sortMode.price,
|
sortNameIcon: React.Node,
|
||||||
isSortReversed: false,
|
};
|
||||||
sortPriceIcon: '',
|
|
||||||
sortNameIcon: '',
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
setMenuRef = ref => {
|
export default class ProximoMainScreen extends React.Component<Props, State> {
|
||||||
|
|
||||||
|
state = {
|
||||||
|
navData: this.props.navigation.getParam('data', []).sort(sortPrice),
|
||||||
|
currentSortMode: sortMode.price,
|
||||||
|
isSortReversed: false,
|
||||||
|
sortPriceIcon: '',
|
||||||
|
sortNameIcon: '',
|
||||||
|
};
|
||||||
|
|
||||||
|
_menu: Menu;
|
||||||
|
|
||||||
|
setMenuRef = (ref: Menu) => {
|
||||||
this._menu = ref;
|
this._menu = ref;
|
||||||
};
|
};
|
||||||
|
|
||||||
toggleSortMode(mode) {
|
toggleSortMode(mode: string) {
|
||||||
let isReverse = this.state.isSortReversed;
|
let isReverse = this.state.isSortReversed;
|
||||||
if (mode === this.state.currentSortMode) // reverse mode
|
if (mode === this.state.currentSortMode) // reverse mode
|
||||||
isReverse = !isReverse; // this.state not updating on this function cycle
|
isReverse = !isReverse; // this.state not updating on this function cycle
|
||||||
|
@ -65,7 +78,7 @@ export default class ProximoMainScreen extends React.Component {
|
||||||
this.setSortMode(mode, isReverse);
|
this.setSortMode(mode, isReverse);
|
||||||
}
|
}
|
||||||
|
|
||||||
setSortMode(mode, isReverse) {
|
setSortMode(mode: string, isReverse: boolean) {
|
||||||
this.setState({
|
this.setState({
|
||||||
currentSortMode: mode,
|
currentSortMode: mode,
|
||||||
isSortReversed: isReverse
|
isSortReversed: isReverse
|
||||||
|
@ -98,7 +111,7 @@ export default class ProximoMainScreen extends React.Component {
|
||||||
this.setSortMode(this.state.currentSortMode, this.state.isSortReversed);
|
this.setSortMode(this.state.currentSortMode, this.state.isSortReversed);
|
||||||
}
|
}
|
||||||
|
|
||||||
setupSortIcons(mode, isReverse) {
|
setupSortIcons(mode: string, isReverse: boolean) {
|
||||||
const downSortIcon =
|
const downSortIcon =
|
||||||
<Icon
|
<Icon
|
||||||
active
|
active
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
import React from 'react';
|
// @flow
|
||||||
|
|
||||||
|
import * as React from 'react';
|
||||||
import {RefreshControl, SectionList} from 'react-native';
|
import {RefreshControl, SectionList} from 'react-native';
|
||||||
import {Container, Text, Content, ListItem, Left, Right, Body, Badge, Icon, Toast, H2} from 'native-base';
|
import {Container, Text, ListItem, Left, Right, Body, Badge, Toast, H2} from 'native-base';
|
||||||
import CustomHeader from "../../components/CustomHeader";
|
import CustomHeader from "../../components/CustomHeader";
|
||||||
import i18n from "i18n-js";
|
import i18n from "i18n-js";
|
||||||
import CustomMaterialIcon from "../../components/CustomMaterialIcon";
|
import CustomMaterialIcon from "../../components/CustomMaterialIcon";
|
||||||
|
@ -15,18 +17,25 @@ const typesIcons = {
|
||||||
Default: "information-outline",
|
Default: "information-outline",
|
||||||
};
|
};
|
||||||
|
|
||||||
export default class ProximoMainScreen extends React.Component {
|
type Props = {
|
||||||
|
navigation: Object
|
||||||
|
}
|
||||||
|
|
||||||
constructor(props) {
|
type State = {
|
||||||
super(props);
|
refreshing: boolean,
|
||||||
this.state = {
|
firstLoading: boolean,
|
||||||
refreshing: false,
|
data: Object,
|
||||||
firstLoading: true,
|
};
|
||||||
data: {},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
static generateDataset(types, data) {
|
export default class ProximoMainScreen extends React.Component<Props, State> {
|
||||||
|
|
||||||
|
state = {
|
||||||
|
refreshing: false,
|
||||||
|
firstLoading: true,
|
||||||
|
data: {},
|
||||||
|
};
|
||||||
|
|
||||||
|
static generateDataset(types: Array<string>, data: Object) {
|
||||||
let finalData = [];
|
let finalData = [];
|
||||||
for (let i = 0; i < types.length; i++) {
|
for (let i = 0; i < types.length; i++) {
|
||||||
finalData.push({
|
finalData.push({
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
import React from 'react';
|
// @flow
|
||||||
|
|
||||||
|
import * as React from 'react';
|
||||||
import {SectionList, RefreshControl, View} from 'react-native';
|
import {SectionList, RefreshControl, View} from 'react-native';
|
||||||
import {Body, Container, Icon, Left, ListItem, Right, Text, Toast, H2, Button} from 'native-base';
|
import {Body, Container, Icon, Left, ListItem, Right, Text, Toast, H2, Button} from 'native-base';
|
||||||
import CustomHeader from "../components/CustomHeader";
|
import CustomHeader from "../components/CustomHeader";
|
||||||
|
@ -25,10 +27,27 @@ let stateStrings = {};
|
||||||
|
|
||||||
let stateColors = {};
|
let stateColors = {};
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
navigation: Object,
|
||||||
|
};
|
||||||
|
|
||||||
export default class ProxiwashScreen extends React.Component {
|
type State = {
|
||||||
|
refreshing: boolean,
|
||||||
|
firstLoading: boolean,
|
||||||
|
data: Object,
|
||||||
|
machinesWatched: Array<Object>
|
||||||
|
};
|
||||||
|
|
||||||
constructor(props) {
|
export default class ProxiwashScreen extends React.Component<Props, State> {
|
||||||
|
|
||||||
|
state = {
|
||||||
|
refreshing: false,
|
||||||
|
firstLoading: true,
|
||||||
|
data: {},
|
||||||
|
machinesWatched: [],
|
||||||
|
};
|
||||||
|
|
||||||
|
constructor(props: Props) {
|
||||||
super(props);
|
super(props);
|
||||||
let colors = ThemeManager.getInstance().getCurrentThemeVariables();
|
let colors = ThemeManager.getInstance().getCurrentThemeVariables();
|
||||||
stateColors[MACHINE_STATES.TERMINE] = colors.proxiwashFinishedColor;
|
stateColors[MACHINE_STATES.TERMINE] = colors.proxiwashFinishedColor;
|
||||||
|
@ -42,24 +61,12 @@ export default class ProxiwashScreen extends React.Component {
|
||||||
stateStrings[MACHINE_STATES.FONCTIONNE] = i18n.t('proxiwashScreen.states.running');
|
stateStrings[MACHINE_STATES.FONCTIONNE] = i18n.t('proxiwashScreen.states.running');
|
||||||
stateStrings[MACHINE_STATES.HS] = i18n.t('proxiwashScreen.states.broken');
|
stateStrings[MACHINE_STATES.HS] = i18n.t('proxiwashScreen.states.broken');
|
||||||
stateStrings[MACHINE_STATES.ERREUR] = i18n.t('proxiwashScreen.states.error');
|
stateStrings[MACHINE_STATES.ERREUR] = i18n.t('proxiwashScreen.states.error');
|
||||||
this.state = {
|
|
||||||
refreshing: false,
|
|
||||||
firstLoading: true,
|
|
||||||
data: {},
|
|
||||||
machinesWatched: [],
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async readData() {
|
async readData() {
|
||||||
try {
|
try {
|
||||||
let response = await fetch(DATA_URL);
|
let response = await fetch(DATA_URL);
|
||||||
let responseJson = await response.json();
|
let responseJson = await response.json();
|
||||||
// This prevents end notifications from showing
|
|
||||||
// let watchList = this.state.machinesWatched;
|
|
||||||
// for (let i = 0; i < watchList.length; i++) {
|
|
||||||
// if (responseJson[MACHINE_STATES[watchList[i].machineNumber.state]] !== MACHINE_STATES.FONCTIONNE)
|
|
||||||
// this.disableNotification(watchList[i].machineNumber);
|
|
||||||
// }
|
|
||||||
this.setState({
|
this.setState({
|
||||||
data: responseJson
|
data: responseJson
|
||||||
});
|
});
|
||||||
|
@ -98,21 +105,23 @@ export default class ProxiwashScreen extends React.Component {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
static getRemainingTime(startString, endString, percentDone) {
|
static getRemainingTime(startString: string, endString: string, percentDone: string): number {
|
||||||
let startArray = startString.split(':');
|
let startArray = startString.split(':');
|
||||||
let endArray = endString.split(':');
|
let endArray = endString.split(':');
|
||||||
let startDate = new Date();
|
let startDate = new Date();
|
||||||
startDate.setHours(parseInt(startArray[0]), parseInt(startArray[1]), 0, 0);
|
startDate.setHours(parseInt(startArray[0]), parseInt(startArray[1]), 0, 0);
|
||||||
let endDate = new Date();
|
let endDate = new Date();
|
||||||
endDate.setHours(parseInt(endArray[0]), parseInt(endArray[1]), 0, 0);
|
endDate.setHours(parseInt(endArray[0]), parseInt(endArray[1]), 0, 0);
|
||||||
return (((100 - percentDone) / 100) * (endDate - startDate) / (60 * 1000)).toFixed(0); // Convert milliseconds into minutes
|
// Convert milliseconds into minutes
|
||||||
|
let time: string = (((100 - parseFloat(percentDone)) / 100) * (endDate - startDate) / (60 * 1000)).toFixed(0);
|
||||||
|
return parseInt(time);
|
||||||
}
|
}
|
||||||
|
|
||||||
async setupNotifications(number, remainingTime) {
|
async setupNotifications(machineId: string, remainingTime: number) {
|
||||||
if (!this.isMachineWatched(number)) {
|
if (!this.isMachineWatched(machineId)) {
|
||||||
let endNotifID = await NotificationsManager.scheduleNotification(
|
let endNotifID = await NotificationsManager.scheduleNotification(
|
||||||
i18n.t('proxiwashScreen.notifications.machineFinishedTitle'),
|
i18n.t('proxiwashScreen.notifications.machineFinishedTitle'),
|
||||||
i18n.t('proxiwashScreen.notifications.machineFinishedBody', {number: number}),
|
i18n.t('proxiwashScreen.notifications.machineFinishedBody', {number: machineId}),
|
||||||
new Date().getTime() + remainingTime * (60 * 1000) // Convert back to milliseconds
|
new Date().getTime() + remainingTime * (60 * 1000) // Convert back to milliseconds
|
||||||
);
|
);
|
||||||
let reminderNotifID = undefined;
|
let reminderNotifID = undefined;
|
||||||
|
@ -127,41 +136,41 @@ export default class ProxiwashScreen extends React.Component {
|
||||||
if (remainingTime > reminderNotifTime && reminderNotifTime > 0) {
|
if (remainingTime > reminderNotifTime && reminderNotifTime > 0) {
|
||||||
reminderNotifID = await NotificationsManager.scheduleNotification(
|
reminderNotifID = await NotificationsManager.scheduleNotification(
|
||||||
i18n.t('proxiwashScreen.notifications.machineRunningTitle', {time: reminderNotifTime}),
|
i18n.t('proxiwashScreen.notifications.machineRunningTitle', {time: reminderNotifTime}),
|
||||||
i18n.t('proxiwashScreen.notifications.machineRunningBody', {number: number}),
|
i18n.t('proxiwashScreen.notifications.machineRunningBody', {number: machineId}),
|
||||||
new Date().getTime() + (remainingTime - reminderNotifTime) * (60 * 1000) // Convert back to milliseconds
|
new Date().getTime() + (remainingTime - reminderNotifTime) * (60 * 1000) // Convert back to milliseconds
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
let data = this.state.machinesWatched;
|
let data = this.state.machinesWatched;
|
||||||
data.push({machineNumber: number, endNotifID: endNotifID, reminderNotifID: reminderNotifID});
|
data.push({machineNumber: machineId, endNotifID: endNotifID, reminderNotifID: reminderNotifID});
|
||||||
this.setState({machinesWatched: data});
|
this.setState({machinesWatched: data});
|
||||||
AsyncStorage.setItem(WATCHED_MACHINES_PREFKEY, JSON.stringify(data));
|
AsyncStorage.setItem(WATCHED_MACHINES_PREFKEY, JSON.stringify(data));
|
||||||
} else
|
} else
|
||||||
this.disableNotification(number);
|
this.disableNotification(machineId);
|
||||||
}
|
}
|
||||||
|
|
||||||
disableNotification(number) {
|
disableNotification(machineId: string) {
|
||||||
let data = this.state.machinesWatched;
|
let data: Object = this.state.machinesWatched;
|
||||||
if (data.length > 0) {
|
if (data.length > 0) {
|
||||||
let elem = this.state.machinesWatched.find(function (elem) {
|
let elem = this.state.machinesWatched.find(function (elem) {
|
||||||
return elem.machineNumber === number
|
return elem.machineNumber === machineId
|
||||||
});
|
});
|
||||||
let arrayIndex = data.indexOf(elem);
|
let arrayIndex = data.indexOf(elem);
|
||||||
NotificationsManager.cancelScheduledNoification(data[arrayIndex].endNotifID);
|
NotificationsManager.cancelScheduledNotification(data[arrayIndex].endNotifID);
|
||||||
if (data[arrayIndex].reminderNotifID !== undefined)
|
if (data[arrayIndex].reminderNotifID !== undefined)
|
||||||
NotificationsManager.cancelScheduledNoification(data[arrayIndex].reminderNotifID);
|
NotificationsManager.cancelScheduledNotification(data[arrayIndex].reminderNotifID);
|
||||||
data.splice(arrayIndex, 1);
|
data.splice(arrayIndex, 1);
|
||||||
this.setState({machinesWatched: data});
|
this.setState({machinesWatched: data});
|
||||||
AsyncStorage.setItem(WATCHED_MACHINES_PREFKEY, JSON.stringify(data));
|
AsyncStorage.setItem(WATCHED_MACHINES_PREFKEY, JSON.stringify(data));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
isMachineWatched(number) {
|
isMachineWatched(number: string) {
|
||||||
return this.state.machinesWatched.find(function (elem) {
|
return this.state.machinesWatched.find(function (elem) {
|
||||||
return elem.machineNumber === number
|
return elem.machineNumber === number
|
||||||
}) !== undefined;
|
}) !== undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
renderItem(item, section, data) {
|
renderItem(item: Object, section: Object, data: Object) {
|
||||||
return (
|
return (
|
||||||
<ListItem
|
<ListItem
|
||||||
thumbnail
|
thumbnail
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
import React from 'react';
|
// @flow
|
||||||
|
|
||||||
|
import * as React from 'react';
|
||||||
import {
|
import {
|
||||||
Container,
|
Container,
|
||||||
Content,
|
Content,
|
||||||
|
@ -22,7 +24,16 @@ import {AsyncStorage} from 'react-native'
|
||||||
|
|
||||||
const proxiwashNotifKey = "proxiwashNotifKey";
|
const proxiwashNotifKey = "proxiwashNotifKey";
|
||||||
|
|
||||||
export default class SettingsScreen extends React.Component {
|
type Props = {
|
||||||
|
navigation: Object,
|
||||||
|
};
|
||||||
|
|
||||||
|
type State = {
|
||||||
|
nightMode: boolean,
|
||||||
|
proxiwashNotifPickerSelected: string,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default class SettingsScreen extends React.Component<Props, State> {
|
||||||
state = {
|
state = {
|
||||||
nightMode: ThemeManager.getInstance().getNightMode(),
|
nightMode: ThemeManager.getInstance().getNightMode(),
|
||||||
proxiwashNotifPickerSelected: "5"
|
proxiwashNotifPickerSelected: "5"
|
||||||
|
@ -38,21 +49,21 @@ export default class SettingsScreen extends React.Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
onProxiwashNotidPickerValueChange(value) {
|
onProxiwashNotifPickerValueChange(value: string) {
|
||||||
AsyncStorage.setItem(proxiwashNotifKey, value);
|
AsyncStorage.setItem(proxiwashNotifKey, value);
|
||||||
this.setState({
|
this.setState({
|
||||||
proxiwashNotifPickerSelected: value
|
proxiwashNotifPickerSelected: value
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
getproxiwashNotifPicker() {
|
getProxiwashNotifPicker() {
|
||||||
return (
|
return (
|
||||||
<Picker
|
<Picker
|
||||||
note
|
note
|
||||||
mode="dropdown"
|
mode="dropdown"
|
||||||
style={{width: 120}}
|
style={{width: 120}}
|
||||||
selectedValue={this.state.proxiwashNotifPickerSelected}
|
selectedValue={this.state.proxiwashNotifPickerSelected}
|
||||||
onValueChange={(value) => this.onProxiwashNotidPickerValueChange(value)}
|
onValueChange={(value) => this.onProxiwashNotifPickerValueChange(value)}
|
||||||
>
|
>
|
||||||
<Picker.Item label={i18n.t('settingsScreen.proxiwashNotifReminderPicker.never')} value="never"/>
|
<Picker.Item label={i18n.t('settingsScreen.proxiwashNotifReminderPicker.never')} value="never"/>
|
||||||
<Picker.Item label={i18n.t('settingsScreen.proxiwashNotifReminderPicker.1')} value="1"/>
|
<Picker.Item label={i18n.t('settingsScreen.proxiwashNotifReminderPicker.1')} value="1"/>
|
||||||
|
@ -67,7 +78,7 @@ export default class SettingsScreen extends React.Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
toggleNightMode() {
|
toggleNightMode() {
|
||||||
ThemeManager.getInstance().setNightmode(!this.state.nightMode);
|
ThemeManager.getInstance().setNightMode(!this.state.nightMode);
|
||||||
this.setState({nightMode: !this.state.nightMode});
|
this.setState({nightMode: !this.state.nightMode});
|
||||||
// Alert.alert(i18n.t('settingsScreen.nightMode'), i18n.t('settingsScreen.restart'));
|
// Alert.alert(i18n.t('settingsScreen.nightMode'), i18n.t('settingsScreen.restart'));
|
||||||
this.resetStack();
|
this.resetStack();
|
||||||
|
@ -83,7 +94,7 @@ export default class SettingsScreen extends React.Component {
|
||||||
this.props.navigation.navigate('Settings');
|
this.props.navigation.navigate('Settings');
|
||||||
}
|
}
|
||||||
|
|
||||||
getToggleItem(onPressCallback, icon, text, subtitle) {
|
getToggleItem(onPressCallback: Function, icon: string, text: string, subtitle: string) {
|
||||||
return (
|
return (
|
||||||
<ListItem
|
<ListItem
|
||||||
button
|
button
|
||||||
|
@ -109,7 +120,7 @@ export default class SettingsScreen extends React.Component {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
getGeneralItem(control, icon, text, subtitle) {
|
static getGeneralItem(control: React.Node, icon: string, text: string, subtitle: string) {
|
||||||
return (
|
return (
|
||||||
<ListItem
|
<ListItem
|
||||||
thumbnail
|
thumbnail
|
||||||
|
@ -152,7 +163,7 @@ export default class SettingsScreen extends React.Component {
|
||||||
<Text>Proxiwash</Text>
|
<Text>Proxiwash</Text>
|
||||||
</CardItem>
|
</CardItem>
|
||||||
<List>
|
<List>
|
||||||
{this.getGeneralItem(this.getproxiwashNotifPicker(), 'washing-machine', i18n.t('settingsScreen.proxiwashNotifReminder'), i18n.t('settingsScreen.proxiwashNotifReminderSub'))}
|
{SettingsScreen.getGeneralItem(this.getProxiwashNotifPicker(), 'washing-machine', i18n.t('settingsScreen.proxiwashNotifReminder'), i18n.t('settingsScreen.proxiwashNotifReminderSub'))}
|
||||||
</List>
|
</List>
|
||||||
</Card>
|
</Card>
|
||||||
</Content>
|
</Content>
|
||||||
|
|
|
@ -1,21 +1,20 @@
|
||||||
|
// @flow
|
||||||
|
|
||||||
import i18n from 'i18n-js';
|
import i18n from 'i18n-js';
|
||||||
import * as Localization from 'expo-localization';
|
import * as Localization from 'expo-localization';
|
||||||
|
|
||||||
import en from '../translations/en';
|
import en from '../translations/en';
|
||||||
import fr from '../translations/fr';
|
import fr from '../translations/fr';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Static class used to manage locales
|
||||||
|
*/
|
||||||
export default class LocaleManager {
|
export default class LocaleManager {
|
||||||
|
|
||||||
static instance = null;
|
/**
|
||||||
|
* Initialize translations using language files
|
||||||
static getInstance() {
|
*/
|
||||||
if (LocaleManager.instance == null) {
|
static initTranslations() {
|
||||||
LocaleManager.instance = new LocaleManager();
|
|
||||||
}
|
|
||||||
return this.instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
initTranslations() {
|
|
||||||
i18n.fallbacks = true;
|
i18n.fallbacks = true;
|
||||||
i18n.translations = {fr, en};
|
i18n.translations = {fr, en};
|
||||||
i18n.locale = Localization.locale;
|
i18n.locale = Localization.locale;
|
||||||
|
|
|
@ -1,8 +1,18 @@
|
||||||
|
// @flow
|
||||||
|
|
||||||
import * as Permissions from 'expo-permissions';
|
import * as Permissions from 'expo-permissions';
|
||||||
import { Notifications } from 'expo';
|
import { Notifications } from 'expo';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Static class used to manage notifications sent to the user
|
||||||
|
*/
|
||||||
export default class NotificationsManager {
|
export default class NotificationsManager {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Async function asking permission to send notifications to the user
|
||||||
|
*
|
||||||
|
* @returns {Promise}
|
||||||
|
*/
|
||||||
static async askPermissions() {
|
static async askPermissions() {
|
||||||
const {status: existingStatus} = await Permissions.getAsync(Permissions.NOTIFICATIONS);
|
const {status: existingStatus} = await Permissions.getAsync(Permissions.NOTIFICATIONS);
|
||||||
let finalStatus = existingStatus;
|
let finalStatus = existingStatus;
|
||||||
|
@ -13,7 +23,14 @@ export default class NotificationsManager {
|
||||||
return finalStatus === 'granted';
|
return finalStatus === 'granted';
|
||||||
}
|
}
|
||||||
|
|
||||||
static async sendNotificationImmediately (title, body) {
|
/**
|
||||||
|
* Async function sending a notification without delay to the user
|
||||||
|
*
|
||||||
|
* @param title {String} Notification title
|
||||||
|
* @param body {String} Notification body text
|
||||||
|
* @returns {Promise<import("react").ReactText>} Notification Id
|
||||||
|
*/
|
||||||
|
static async sendNotificationImmediately (title: string, body: string) {
|
||||||
await NotificationsManager.askPermissions();
|
await NotificationsManager.askPermissions();
|
||||||
return await Notifications.presentLocalNotificationAsync({
|
return await Notifications.presentLocalNotificationAsync({
|
||||||
title: title,
|
title: title,
|
||||||
|
@ -21,7 +38,15 @@ export default class NotificationsManager {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
static async scheduleNotification(title, body, time) {
|
/**
|
||||||
|
* Async function sending notification at the specified time
|
||||||
|
*
|
||||||
|
* @param title Notification title
|
||||||
|
* @param body Notification body text
|
||||||
|
* @param time Time at which we should send the notification
|
||||||
|
* @returns {Promise<import("react").ReactText>} Notification Id
|
||||||
|
*/
|
||||||
|
static async scheduleNotification(title: string, body: string, time: number): Promise<void> {
|
||||||
await NotificationsManager.askPermissions();
|
await NotificationsManager.askPermissions();
|
||||||
return Notifications.scheduleLocalNotificationAsync(
|
return Notifications.scheduleLocalNotificationAsync(
|
||||||
{
|
{
|
||||||
|
@ -34,7 +59,12 @@ export default class NotificationsManager {
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
static async cancelScheduledNoification(notifID) {
|
/**
|
||||||
await Notifications.cancelScheduledNotificationAsync(notifID);
|
* Async function used to cancel the notification of a specific ID
|
||||||
|
* @param notificationID {Number} The notification ID
|
||||||
|
* @returns {Promise}
|
||||||
|
*/
|
||||||
|
static async cancelScheduledNotification(notificationID: number) {
|
||||||
|
await Notifications.cancelScheduledNotificationAsync(notificationID);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
// @flow
|
||||||
|
|
||||||
import {AsyncStorage} from 'react-native'
|
import {AsyncStorage} from 'react-native'
|
||||||
import platform from '../native-base-theme/variables/platform';
|
import platform from '../native-base-theme/variables/platform';
|
||||||
import platformDark from '../native-base-theme/variables/platformDark';
|
import platformDark from '../native-base-theme/variables/platformDark';
|
||||||
|
@ -5,53 +7,85 @@ import getTheme from '../native-base-theme/components';
|
||||||
|
|
||||||
const nightModeKey = 'nightMode';
|
const nightModeKey = 'nightMode';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Singleton class used to manage themes
|
||||||
|
*/
|
||||||
export default class ThemeManager {
|
export default class ThemeManager {
|
||||||
|
|
||||||
static instance = null;
|
static instance: ThemeManager | null = null;
|
||||||
|
nightMode: boolean;
|
||||||
|
updateThemeCallback: Function;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
this.nightMode = false;
|
this.nightMode = false;
|
||||||
this.updateThemeCallback = undefined;
|
this.updateThemeCallback = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
static getInstance() {
|
/**
|
||||||
if (ThemeManager.instance == null) {
|
* Get this class instance or create one if none is found
|
||||||
ThemeManager.instance = new ThemeManager();
|
* @returns {ThemeManager}
|
||||||
}
|
*/
|
||||||
return this.instance;
|
static getInstance(): ThemeManager {
|
||||||
|
return ThemeManager.instance === null ?
|
||||||
|
ThemeManager.instance = new ThemeManager() :
|
||||||
|
ThemeManager.instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
setUpdateThemeCallback(callback) {
|
/**
|
||||||
|
* Set the function to be called when the theme is changed (allows for general reload of the app)
|
||||||
|
* @param callback Function to call after theme change
|
||||||
|
*/
|
||||||
|
setUpdateThemeCallback(callback: ?Function) {
|
||||||
this.updateThemeCallback = callback;
|
this.updateThemeCallback = callback;
|
||||||
}
|
}
|
||||||
|
|
||||||
async getDataFromPreferences() {
|
/**
|
||||||
let result = await AsyncStorage.getItem(nightModeKey);
|
* Read async storage to get preferences
|
||||||
|
* @returns {Promise<void>}
|
||||||
|
*/
|
||||||
|
async getDataFromPreferences(): Promise<void> {
|
||||||
|
let result: string = await AsyncStorage.getItem(nightModeKey);
|
||||||
|
|
||||||
if (result === '1')
|
if (result === '1')
|
||||||
this.nightMode = true;
|
this.nightMode = true;
|
||||||
console.log('nightmode: ' + this.nightMode);
|
// console.log('nightmode: ' + this.nightMode);
|
||||||
}
|
}
|
||||||
|
|
||||||
setNightmode(isNightMode) {
|
/**
|
||||||
|
* Set night mode and save it to preferences
|
||||||
|
*
|
||||||
|
* @param isNightMode Whether to enable night mode
|
||||||
|
*/
|
||||||
|
setNightMode(isNightMode: boolean) {
|
||||||
this.nightMode = isNightMode;
|
this.nightMode = isNightMode;
|
||||||
AsyncStorage.setItem(nightModeKey, isNightMode ? '1' : '0');
|
AsyncStorage.setItem(nightModeKey, isNightMode ? '1' : '0');
|
||||||
if (this.updateThemeCallback !== undefined)
|
if (this.updateThemeCallback !== null)
|
||||||
this.updateThemeCallback();
|
this.updateThemeCallback();
|
||||||
}
|
}
|
||||||
|
|
||||||
getNightMode() {
|
/**
|
||||||
|
* @returns {boolean} Night mode state
|
||||||
|
*/
|
||||||
|
getNightMode(): boolean {
|
||||||
return this.nightMode;
|
return this.nightMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
getCurrentTheme() {
|
/**
|
||||||
|
* Get the current theme based on night mode
|
||||||
|
* @returns {Object}
|
||||||
|
*/
|
||||||
|
getCurrentTheme(): Object {
|
||||||
if (this.nightMode)
|
if (this.nightMode)
|
||||||
return getTheme(platformDark);
|
return getTheme(platformDark);
|
||||||
else
|
else
|
||||||
return getTheme(platform);
|
return getTheme(platform);
|
||||||
}
|
}
|
||||||
|
|
||||||
getCurrentThemeVariables() {
|
/**
|
||||||
|
* Get the variables contained in the current theme
|
||||||
|
* @returns {Object}
|
||||||
|
*/
|
||||||
|
getCurrentThemeVariables(): Object {
|
||||||
return this.getCurrentTheme().variables;
|
return this.getCurrentTheme().variables;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue