Improved proximo screen

This commit is contained in:
keplyx 2019-06-27 10:17:51 +02:00
parent dd2cb38c58
commit 893eca287e
14 changed files with 446 additions and 146 deletions

6
App.js
View file

@ -1,6 +1,6 @@
import React from 'react'; import React from 'react';
import {Dimensions, StyleSheet, View, Text} from 'react-native'; import {Dimensions, StyleSheet, View, Text} from 'react-native';
import {StyleProvider} from 'native-base'; import {StyleProvider, Root} from 'native-base';
import AppNavigator from './navigation/AppNavigator'; import AppNavigator from './navigation/AppNavigator';
import ThemeManager from './utils/ThemeManager'; import ThemeManager from './utils/ThemeManager';
import LocaleManager from './utils/LocaleManager'; import LocaleManager from './utils/LocaleManager';
@ -48,7 +48,9 @@ export default class App extends React.Component {
// console.log(this.state.currentTheme.variables.containerBgColor); // console.log(this.state.currentTheme.variables.containerBgColor);
return ( return (
<StyleProvider style={this.state.currentTheme}> <StyleProvider style={this.state.currentTheme}>
<AppNavigator/> <Root>
<AppNavigator/>
</Root>
</StyleProvider>); </StyleProvider>);
} }
} }

View file

@ -2,23 +2,48 @@ import React from "react";
import {Body, Button, Header, Icon, Left, Right, Title} from "native-base"; import {Body, Button, 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';
export default class CustomHeader extends React.Component { export default class CustomHeader extends React.Component {
render() { render() {
let button;
let rightMenu;
if (this.props.backButton !== undefined && this.props.backButton === true)
button =
<Touchable
style={{padding: 6}}
onPress={() => this.props.navigation.goBack()}>
<Icon
style={{color: "#fff"}}
name="arrow-left"
type={'MaterialCommunityIcons'}/>
</Touchable>;
else
button =
<Touchable
style={{padding: 6}}
onPress={() => this.props.navigation.toggleDrawer()}>
<Icon
style={{color: "#fff"}}
name="menu"
type={'MaterialCommunityIcons'}/>
</Touchable>;
if (this.props.rightMenu)
rightMenu = this.props.rightMenu;
else
rightMenu = <Right/>;
return ( return (
<Header style={styles.header}> <Header style={styles.header}>
<Left> <Left>
<Button {button}
transparent
onPress={() => this.props.navigation.toggleDrawer()}
>
<Icon name="menu"/>
</Button>
</Left> </Left>
<Body> <Body>
<Title>{this.props.title}</Title> <Title>{this.props.title}</Title>
</Body> </Body>
<Right/> {rightMenu}
</Header>); </Header>);
} }
}; };
@ -30,4 +55,4 @@ const styles = StyleSheet.create({
paddingTop: getStatusBarHeight(), paddingTop: getStatusBarHeight(),
height: 54 + getStatusBarHeight(), height: 54 + getStatusBarHeight(),
}, },
}); });

View file

@ -1,7 +1,6 @@
import React from 'react'; import React from 'react';
import {Platform, Dimensions, ScrollView, StyleSheet, View, Image, FlatList} from 'react-native'; import {Platform, Dimensions, StyleSheet, Image, FlatList} from 'react-native';
import {Drawer} from 'react-native-paper'; import {Badge, Text, Container, Content, Icon, Left, ListItem, Right} from "native-base";
import {Badge, Text, Container, Content, Icon, Left, List, ListItem, Right} from "native-base";
import i18n from "i18n-js"; import i18n from "i18n-js";
const deviceHeight = Dimensions.get("window").height; const deviceHeight = Dimensions.get("window").height;

View file

@ -1,9 +1,17 @@
import { createAppContainer, createSwitchNavigator } from 'react-navigation'; import {createAppContainer, createStackNavigator} from 'react-navigation';
import MainDrawerNavigator from './MainDrawerNavigator'; import MainDrawerNavigator from './MainDrawerNavigator';
import ProximoListScreen from '../screens/Proximo/ProximoListScreen';
export default createAppContainer( export default createAppContainer(
createSwitchNavigator({ createStackNavigator({
Main: MainDrawerNavigator, Main: MainDrawerNavigator,
}) ProximoListScreen: {screen: ProximoListScreen},
); },
{
initialRouteName: "Main",
mode: 'card',
headerMode: "none"
})
);

View file

@ -4,7 +4,7 @@ import {createDrawerNavigator} from 'react-navigation';
import HomeScreen from '../screens/HomeScreen'; import HomeScreen from '../screens/HomeScreen';
import PlanningScreen from '../screens/PlanningScreen'; import PlanningScreen from '../screens/PlanningScreen';
import ProxiwashScreen from '../screens/ProxiwashScreen'; import ProxiwashScreen from '../screens/ProxiwashScreen';
import ProximoScreen from '../screens/ProximoScreen'; import ProximoMainScreen from '../screens/Proximo/ProximoMainScreen';
import SettingsScreen from '../screens/SettingsScreen'; import SettingsScreen from '../screens/SettingsScreen';
import AboutScreen from '../screens/AboutScreen'; import AboutScreen from '../screens/AboutScreen';
import SideMenu from "../components/SideMenu"; import SideMenu from "../components/SideMenu";
@ -14,11 +14,15 @@ export default createDrawerNavigator({
Home: {screen: HomeScreen}, Home: {screen: HomeScreen},
Planning: {screen: PlanningScreen,}, Planning: {screen: PlanningScreen,},
Proxiwash: {screen: ProxiwashScreen,}, Proxiwash: {screen: ProxiwashScreen,},
Proximo: {screen: ProximoScreen,}, Proximo: {screen: ProximoMainScreen,},
Settings: {screen: SettingsScreen,}, Settings: {screen: SettingsScreen,},
About: {screen: AboutScreen,}, About: {screen: AboutScreen,},
}, { }, {
contentComponent: SideMenu, contentComponent: SideMenu,
initialRouteName: 'Home',
backBehavior: 'initialRoute',
drawerType: 'front',
useNativeAnimations: true,
} }
); );

14
package-lock.json generated
View file

@ -6264,6 +6264,15 @@
"resolved": "https://registry.npmjs.org/react-native-maps/-/react-native-maps-0.24.2.tgz", "resolved": "https://registry.npmjs.org/react-native-maps/-/react-native-maps-0.24.2.tgz",
"integrity": "sha512-1iNIDikp2dkCG+8DguaEviYZiMSYyvwqYT7pO2YTZvuFRDSc/P9jXMhTUnSh4wNDlEeQ47OJ09l0pwWVBZ7wxg==" "integrity": "sha512-1iNIDikp2dkCG+8DguaEviYZiMSYyvwqYT7pO2YTZvuFRDSc/P9jXMhTUnSh4wNDlEeQ47OJ09l0pwWVBZ7wxg=="
}, },
"react-native-material-menu": {
"version": "0.6.2",
"resolved": "https://registry.npmjs.org/react-native-material-menu/-/react-native-material-menu-0.6.2.tgz",
"integrity": "sha512-xrWO1JhfB+9vlq13Y5qwAgxsD6RJvGLammjm1vJzTXHp1drtFwizga2TLwsryy0h/fo224H3INVSAxS4PWc7+A==",
"dev": true,
"requires": {
"prop-types": "^15.6.0"
}
},
"react-native-paper": { "react-native-paper": {
"version": "2.16.0", "version": "2.16.0",
"resolved": "https://registry.npmjs.org/react-native-paper/-/react-native-paper-2.16.0.tgz", "resolved": "https://registry.npmjs.org/react-native-paper/-/react-native-paper-2.16.0.tgz",
@ -6296,6 +6305,11 @@
} }
} }
}, },
"react-native-platform-touchable": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/react-native-platform-touchable/-/react-native-platform-touchable-1.1.1.tgz",
"integrity": "sha1-/eSsxl7qWF0osWTQw3FqQhKaaOQ="
},
"react-native-ratings": { "react-native-ratings": {
"version": "6.3.1", "version": "6.3.1",
"resolved": "https://registry.npmjs.org/react-native-ratings/-/react-native-ratings-6.3.1.tgz", "resolved": "https://registry.npmjs.org/react-native-ratings/-/react-native-ratings-6.3.1.tgz",

View file

@ -25,10 +25,12 @@
"react-native-web": "^0.11.4", "react-native-web": "^0.11.4",
"react-native-week-view": "latest", "react-native-week-view": "latest",
"react-navigation": "latest", "react-navigation": "latest",
"react-navigation-material-bottom-tabs": "latest" "react-navigation-material-bottom-tabs": "latest",
"react-native-platform-touchable": "latest"
}, },
"devDependencies": { "devDependencies": {
"babel-preset-expo": "^5.1.1" "babel-preset-expo": "^5.1.1",
"react-native-material-menu": "^0.6.2"
}, },
"private": true "private": true
} }

View file

@ -53,7 +53,8 @@ export default class AboutScreen extends React.Component {
<Text>{Platform.OS === "ios" ? i18n.t('aboutScreen.appstore') : i18n.t('aboutScreen.playstore')}</Text> <Text>{Platform.OS === "ios" ? i18n.t('aboutScreen.appstore') : i18n.t('aboutScreen.playstore')}</Text>
</Left> </Left>
<Right> <Right>
<Icon name="arrow-forward"/> <Icon name="chevron-right"
type={'MaterialCommunityIcons'}/>
</Right> </Right>
</CardItem> </CardItem>
<CardItem button <CardItem button
@ -66,7 +67,8 @@ export default class AboutScreen extends React.Component {
<Text>Gitlab</Text> <Text>Gitlab</Text>
</Left> </Left>
<Right> <Right>
<Icon name="arrow-forward"/> <Icon name="chevron-right"
type={'MaterialCommunityIcons'}/>
</Right> </Right>
</CardItem> </CardItem>
<CardItem button <CardItem button
@ -79,7 +81,8 @@ export default class AboutScreen extends React.Component {
<Text>{i18n.t('aboutScreen.bugs')}</Text> <Text>{i18n.t('aboutScreen.bugs')}</Text>
</Left> </Left>
<Right> <Right>
<Icon name="arrow-forward"/> <Icon name="chevron-right"
type={'MaterialCommunityIcons'}/>
</Right> </Right>
</CardItem> </CardItem>
<CardItem button <CardItem button
@ -94,7 +97,8 @@ export default class AboutScreen extends React.Component {
</Text> </Text>
</Left> </Left>
<Right> <Right>
<Icon name="arrow-forward"/> <Icon name="chevron-right"
type={'MaterialCommunityIcons'}/>
</Right> </Right>
</CardItem> </CardItem>
<CardItem button <CardItem button
@ -109,7 +113,8 @@ export default class AboutScreen extends React.Component {
</Text> </Text>
</Left> </Left>
<Right> <Right>
<Icon name="arrow-forward"/> <Icon name="chevron-right"
type={'MaterialCommunityIcons'}/>
</Right> </Right>
</CardItem> </CardItem>
</Card> </Card>
@ -140,7 +145,8 @@ export default class AboutScreen extends React.Component {
</Text> </Text>
</Left> </Left>
<Right> <Right>
<Icon name="arrow-forward"/> <Icon name="chevron-right"
type={'MaterialCommunityIcons'}/>
</Right> </Right>
</CardItem> </CardItem>
<CardItem button <CardItem button
@ -155,7 +161,8 @@ export default class AboutScreen extends React.Component {
</Text> </Text>
</Left> </Left>
<Right> <Right>
<Icon name="arrow-forward"/> <Icon name="chevron-right"
type={'MaterialCommunityIcons'}/>
</Right> </Right>
</CardItem> </CardItem>
<CardItem button <CardItem button
@ -170,7 +177,8 @@ export default class AboutScreen extends React.Component {
</Text> </Text>
</Left> </Left>
<Right> <Right>
<Icon name="arrow-forward"/> <Icon name="chevron-right"
type={'MaterialCommunityIcons'}/>
</Right> </Right>
</CardItem> </CardItem>
</Card> </Card>
@ -191,7 +199,8 @@ export default class AboutScreen extends React.Component {
</Text> </Text>
</Left> </Left>
<Right> <Right>
<Icon name="arrow-forward"/> <Icon name="chevron-right"
type={'MaterialCommunityIcons'}/>
</Right> </Right>
</CardItem> </CardItem>
<CardItem button <CardItem button
@ -206,7 +215,8 @@ export default class AboutScreen extends React.Component {
</Text> </Text>
</Left> </Left>
<Right> <Right>
<Icon name="arrow-forward"/> <Icon name="chevron-right"
type={'MaterialCommunityIcons'}/>
</Right> </Right>
</CardItem> </CardItem>
</Card> </Card>

View file

@ -12,7 +12,7 @@ export default class HomeScreen extends React.Component {
return ( return (
<Container> <Container>
<CustomHeader navigation={nav} title={i18n.t('screens.home')}/> <CustomHeader navigation={nav} title={i18n.t('screens.home')}/>
<Content> <Content padder>
<Button> <Button>
<Icon <Icon
active active

View file

@ -0,0 +1,199 @@
import React from 'react';
import {Container, Text, Content, ListItem, Left, Thumbnail, Right, Button, Icon} from 'native-base';
import CustomHeader from "../../components/CustomHeader";
import {AsyncStorage, FlatList, View} from "react-native";
import Touchable from 'react-native-platform-touchable';
import Menu, {MenuItem, MenuDivider} from 'react-native-material-menu';
import i18n from "i18n-js";
const IMG_URL = "https://etud.insa-toulouse.fr/~vergnet/appli-amicale/img/";
const defaultImage = require('../../assets/image-missing.png');
const sortMode = {
price: "0",
name: '1',
};
function sortPrice(a, b) {
return a.price - b.price;
}
function sortPriceReverse(a, b) {
return b.price - a.price;
}
function sortName(a, b) {
if (a.name < b.name)
return -1;
if (a.name > b.name)
return 1;
return 0;
}
function sortNameReverse(a, b) {
if (a.name < b.name)
return 1;
if (a.name > b.name)
return -1;
return 0;
}
export default class ProximoMainScreen extends React.Component {
constructor(props) {
super(props);
this.state = {
navData: this.props.navigation.getParam('data', []).sort(sortPrice),
currentSortMode: sortMode.price,
isSortReversed: false,
sortPriceIcon: '',
sortNameIcon: '',
};
}
setMenuRef = ref => {
this._menu = ref;
};
toggleSortMode(mode) {
let isReverse = this.state.isSortReversed;
if (mode === this.state.currentSortMode) // reverse mode
isReverse = !isReverse; // this.state not updating on this function cycle
else
isReverse = false;
this.setSortMode(mode, isReverse);
}
setSortMode(mode, isReverse) {
this.setState({
currentSortMode: mode,
isSortReversed: isReverse
});
let data = this.state.navData;
switch (mode) {
case sortMode.price:
if (isReverse) {
data.sort(sortPriceReverse);
} else {
data.sort(sortPrice);
}
break;
case sortMode.name:
if (isReverse) {
data.sort(sortNameReverse);
} else {
data.sort(sortName);
}
break;
}
this.setState({
navData: data,
});
this.setupSortIcons(mode, isReverse);
this._menu.hide();
}
componentDidMount() {
this.setSortMode(this.state.currentSortMode, this.state.isSortReversed);
}
setupSortIcons(mode, isReverse) {
const downSortIcon =
<Icon
active
name={'sort-descending'}
type={'MaterialCommunityIcons'}/>;
const upSortIcon =
<Icon
active
name={'sort-ascending'}
type={'MaterialCommunityIcons'}/>;
switch (mode) {
case sortMode.price:
this.setState({sortNameIcon: ''});
if (isReverse) {
this.setState({sortPriceIcon: upSortIcon});
} else {
this.setState({sortPriceIcon: downSortIcon});
}
break;
case sortMode.name:
this.setState({sortPriceIcon: ''});
if (isReverse) {
this.setState({sortNameIcon: upSortIcon});
} else {
this.setState({sortNameIcon: downSortIcon});
}
break;
}
}
render() {
const nav = this.props.navigation;
const navType = nav.getParam('type', 'Empty');
return (
<Container>
<CustomHeader backButton={true} navigation={nav} title={navType} rightMenu={
<Right>
<Menu
ref={this.setMenuRef}
button={
<Touchable
style={{padding: 6}}
onPress={() =>
this._menu.show()
}>
<Icon
style={{color: "#fff"}}
name="sort"
type={'MaterialCommunityIcons'}/>
</Touchable>
}
>
<MenuItem
onPress={() => this.toggleSortMode(sortMode.name)}>
{this.state.sortNameIcon}
{i18n.t('proximoScreen.sortName')}
</MenuItem>
<MenuItem
onPress={() => this.toggleSortMode(sortMode.price)}>
{this.state.sortPriceIcon}
{i18n.t('proximoScreen.sortPrice')}
</MenuItem>
</Menu>
</Right>
}/>
<Content>
<FlatList
data={this.state.navData}
extraData={this.state.navData}
keyExtractor={(item, index) => item.name}
style={{minHeight: 300, width: '100%'}}
renderItem={({item}) =>
<ListItem
thumbnail
onPress={() => {
console.log(IMG_URL + item.name + '.jpg')
}}
>
<Left>
<Thumbnail square source={{uri: IMG_URL + item.name + '.jpg'}}/>
<Text style={{marginLeft: 20}}>
{item.name}
</Text>
</Left>
<Right style={{flex: 1}}>
<Text>
{item.price}
</Text>
</Right>
</ListItem>}
/>
</Content>
</Container>
);
}
}

View file

@ -0,0 +1,134 @@
import React from 'react';
import {StyleSheet, RefreshControl, FlatList} from 'react-native';
import {Container, Text, Content, ListItem, Left, Right, Body, Badge, Icon, Toast} from 'native-base';
import CustomHeader from "../../components/CustomHeader";
import i18n from "i18n-js";
const DATA_URL = "https://etud.insa-toulouse.fr/~vergnet/appli-amicale/dataProximo.json";
const typesIcons = {
Nouveau: "alert-decagram",
Alimentaire: "food",
Boissons: "bottle-wine",
Utilitaires: "notebook",
Default: "information-outline",
};
export default class ProximoMainScreen extends React.Component {
constructor(props) {
super(props);
this.state = {
refreshing: false,
data: {},
};
}
static generateDataset(types, data) {
let finalData = [];
for (let i = 0; i < types.length; i++) {
finalData.push({
type: types[i],
data: []
});
for (let k = 0; k < data.length; k++) {
if (data[k]['type'].includes(types[i])) {
finalData[i].data.push(data[k]);
}
}
}
return finalData;
}
async readData() {
try {
let response = await fetch(DATA_URL);
let responseJson = await response.json();
if (responseJson['articles'].length !== 0 && responseJson['types'].length !== 0) {
let data = ProximoMainScreen.generateDataset(responseJson['types'], responseJson['articles']);
this.setState({
data: data
});
} else
this.setState({data: undefined});
} catch (error) {
console.error(error);
return undefined;
}
}
componentDidMount() {
this._onRefresh();
}
_onRefresh = () => {
this.setState({refreshing: true});
this.readData().then(() => {
this.setState({refreshing: false});
Toast.show({
text: i18n.t('proximoScreen.listUpdated'),
buttonText: 'OK',
type: "success",
duration: 2000
})
});
};
render() {
const nav = this.props.navigation;
return (
<Container>
<CustomHeader navigation={nav} title={'Proximo'}/>
<Content>
<FlatList
data={this.state.data}
extraData={this.state}
keyExtractor={(item, index) => item.type}
refreshControl={
<RefreshControl
refreshing={this.state.refreshing}
onRefresh={this._onRefresh}
/>
}
style={{minHeight: 300, width: '100%'}}
renderItem={({item}) =>
<ListItem
button
thumbnail
onPress={() => {
nav.navigate('ProximoListScreen', item);
}}
>
<Left>
<Icon name={typesIcons[item.type] ? typesIcons[item.type] : typesIcons.Default}
type={'MaterialCommunityIcons'}
style={styles.icon}/>
</Left>
<Body>
<Text>
{item.type}
</Text>
<Badge><Text>
{item.data.length} {item.data.length > 1 ? i18n.t('proximoScreen.articles') : i18n.t('proximoScreen.article')}
</Text></Badge>
</Body>
<Right>
<Icon name="chevron-right"
type={'MaterialCommunityIcons'}/>
</Right>
</ListItem>}
/>
</Content>
</Container>
);
}
}
const styles = StyleSheet.create({
icon: {
fontSize: 30,
width: 30
}
});

View file

@ -1,113 +0,0 @@
import React from 'react';
import {StyleSheet, View, Alert, ScrollView, RefreshControl, FlatList} from 'react-native';
import {Container, Text, Content, ListItem, Left, Thumbnail, Right, Badge} from 'native-base';
import CustomHeader from "../components/CustomHeader";
const DATA_URL = "https://etud.insa-toulouse.fr/~vergnet/appli-amicale/data.txt";
const IMG_URL = "https://etud.insa-toulouse.fr/~vergnet/appli-amicale/img/";
const defaultImage = require('../assets/image-missing.png');
export default class ProximoScreen extends React.Component {
constructor(props) {
super(props);
this.state = {
refreshing: false,
data: undefined
};
}
async readData() {
try {
let response = await fetch(
'https://etud.insa-toulouse.fr/~vergnet/appli-amicale/data.txt',
);
let responseText = await response.text();
let responseArray = responseText.split('\n');
let responseFinal = [];
for (let i = 0; i < responseArray.length; i++) {
if (responseArray[i] !== "") {
let itemArray = responseArray[i]
.replace('[', '')
.replace(']', '')
.split(',')[1]
.split(';');
let object = {
name: itemArray[0],
price: itemArray[1],
image: defaultImage
};
responseFinal.push(object);
}
}
this.setState({data: responseFinal});
} catch (error) {
console.error(error);
return undefined;
}
}
componentDidMount() {
this._onRefresh();
}
_onRefresh = () => {
this.setState({refreshing: true});
this.readData().then(() => {
this.setState({refreshing: false});
// console.log(this.state.data);
});
};
render() {
const nav = this.props.navigation;
return (
<Container>
<CustomHeader navigation={nav} title={'Proximo'}/>
<Content>
<FlatList
data={this.state.data}
extraData={this.state}
keyExtractor={(item, index) => item.name}
refreshControl={
<RefreshControl
refreshing={this.state.refreshing}
onRefresh={this._onRefresh}
/>
}
style={{minHeight: 300, width: '100%'}}
renderItem={({item}) =>
<ListItem
onPress={() => {
console.log(IMG_URL + item.name + '.jpg')
}}
>
<Left>
<Thumbnail square source={{ uri: IMG_URL + item.name + '.jpg' }} />
<Text style={{marginLeft: 20}}>
{item.name}
</Text>
</Left>
<Right style={{ flex: 1 }}>
<Text>
{item.price}
</Text>
</Right>
</ListItem>}
/>
</Content>
</Container>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
});

View file

@ -21,4 +21,12 @@
"reactNative": "Made with React Native", "reactNative": "Made with React Native",
"libs": "Libraries used" "libs": "Libraries used"
}, },
"proximoScreen": {
"emptyList": "Empty List",
"article": "Article",
"articles": "Articles",
"sortName": "Sort by name",
"sortPrice": "Sort by price",
"listUpdated": "Article list updated!"
}
} }

View file

@ -20,5 +20,13 @@
"technologies": "Technologies", "technologies": "Technologies",
"reactNative": "Créé avec React Native", "reactNative": "Créé avec React Native",
"libs": "Librairies utilisées" "libs": "Librairies utilisées"
},
"proximoScreen": {
"emptyList": "Liste Vide",
"article": "Article",
"articles": "Articles",
"sortName": "Trier par nom",
"sortPrice": "Trier par prix",
"listUpdated": "Liste des articles mise à jour !"
} }
} }