Tried to improve performance...

This commit is contained in:
Yohan Simard 2020-02-11 01:05:24 +01:00
parent 878ff1b308
commit 01f8a7c558
15 changed files with 284 additions and 140 deletions

9
App.js
View file

@ -34,6 +34,9 @@ export default class App extends React.Component<Props, State> {
constructor(props: Object) { constructor(props: Object) {
super(props); super(props);
LocaleManager.initTranslations(); LocaleManager.initTranslations();
this.onIntroDone = this.onIntroDone.bind(this);
this.loadAssetsAsync = this.loadAssetsAsync.bind(this);
this.onLoadFinished = this.onLoadFinished.bind(this);
} }
/** /**
@ -102,14 +105,14 @@ export default class App extends React.Component<Props, State> {
if (this.state.isLoading) { if (this.state.isLoading) {
return ( return (
<AppLoading <AppLoading
startAsync={() => this.loadAssetsAsync()} startAsync={this.loadAssetsAsync}
onFinish={() => this.onLoadFinished()} onFinish={this.onLoadFinished}
onError={console.warn} onError={console.warn}
/> />
); );
} }
if (this.state.showIntro || this.state.showUpdate) { if (this.state.showIntro || this.state.showUpdate) {
return <CustomIntroSlider onDone={() => this.onIntroDone()} return <CustomIntroSlider onDone={this.onIntroDone}
isUpdate={this.state.showUpdate && !this.state.showIntro}/>; isUpdate={this.state.showUpdate && !this.state.showIntro}/>;
} else { } else {
const AppNavigator = createAppContainerWithInitialRoute(AsyncStorageManager.getInstance().preferences.defaultStartScreen.current); const AppNavigator = createAppContainerWithInitialRoute(AsyncStorageManager.getInstance().preferences.defaultStartScreen.current);

View file

@ -30,7 +30,6 @@ type State = {
export default class BaseContainer extends React.Component<Props, State> { export default class BaseContainer extends React.Component<Props, State> {
static defaultProps = { static defaultProps = {
headerRightButton: <View/>, headerRightButton: <View/>,
hasTabs: false, hasTabs: false,
@ -46,9 +45,15 @@ export default class BaseContainer extends React.Component<Props, State> {
isHeaderVisible: true, isHeaderVisible: true,
}; };
constructor() {
super();
this.toggle = this.toggle.bind(this);
}
toggle() { toggle() {
this.props.navigation.toggleDrawer(); this.props.navigation.toggleDrawer();
} }
/** /**
* Register for blur event to close side menu on screen change * Register for blur event to close side menu on screen change
*/ */
@ -93,7 +98,9 @@ export default class BaseContainer extends React.Component<Props, State> {
this.willFocusSubscription.remove(); this.willFocusSubscription.remove();
} }
getMainContainer() {
render() {
// console.log("rendering BaseContainer");
return ( return (
<Container> <Container>
{this.state.isHeaderVisible ? {this.state.isHeaderVisible ?
@ -104,7 +111,7 @@ export default class BaseContainer extends React.Component<Props, State> {
leftButton={ leftButton={
<Touchable <Touchable
style={{padding: 6}} style={{padding: 6}}
onPress={() => this.toggle()}> onPress={this.toggle}>
<CustomMaterialIcon <CustomMaterialIcon
color={Platform.OS === 'ios' ? ThemeManager.getCurrentThemeVariables().brandPrimary : "#fff"} color={Platform.OS === 'ios' ? ThemeManager.getCurrentThemeVariables().brandPrimary : "#fff"}
icon="menu"/> icon="menu"/>
@ -118,9 +125,4 @@ export default class BaseContainer extends React.Component<Props, State> {
</Container> </Container>
); );
} }
render() {
return (this.getMainContainer());
}
} }

View file

@ -32,7 +32,6 @@ type Props = {
* @prop navigation {Object} The navigation object from react navigation * @prop navigation {Object} The navigation object from react navigation
*/ */
export default class CustomHeader extends React.Component<Props> { export default class CustomHeader extends React.Component<Props> {
static defaultProps = { static defaultProps = {
hasBackButton: false, hasBackButton: false,
hasSearchField: false, hasSearchField: false,
@ -45,9 +44,25 @@ export default class CustomHeader extends React.Component<Props> {
hasTabs: false, hasTabs: false,
}; };
constructor() {
super();
this.onPressBack = this.onPressBack.bind(this);
}
shouldComponentUpdate(nextProps: Props): boolean {
return nextProps.title !== this.props.title ||
nextProps.subtitle !== this.props.subtitle ||
nextProps.hasBackButton !== this.props.hasBackButton ||
nextProps.hasSearchField !== this.props.hasSearchField ||
nextProps.shouldFocusSearchBar !== this.props.shouldFocusSearchBar ||
nextProps.hasTabs !== this.props.hasTabs ||
nextProps.rightButton !== this.props.rightButton ||
nextProps.leftButton !== this.props.leftButton;
}
componentDidMount() { componentDidMount() {
if (this.refs.searchInput !== undefined && this.refs.searchInput._root !== undefined && this.props.shouldFocusSearchBar) { if (this.refs.searchInput !== undefined && this.refs.searchInput._root !== undefined && this.props.shouldFocusSearchBar) {
// does not work if called to early for some reason... // does not work if called too early for some reason...
setTimeout(() => this.refs.searchInput._root.focus(), 500); setTimeout(() => this.refs.searchInput._root.focus(), 500);
} }
} }
@ -67,7 +82,7 @@ export default class CustomHeader extends React.Component<Props> {
ref="searchInput" ref="searchInput"
placeholder={i18n.t('proximoScreen.search')} placeholder={i18n.t('proximoScreen.search')}
placeholderTextColor={ThemeManager.getCurrentThemeVariables().toolbarPlaceholderColor} placeholderTextColor={ThemeManager.getCurrentThemeVariables().toolbarPlaceholderColor}
onChangeText={(text) => this.props.searchCallback(text)}/> onChangeText={this.props.searchCallback}/>
</Item> </Item>
</Body> </Body>
); );
@ -87,17 +102,20 @@ export default class CustomHeader extends React.Component<Props> {
} }
onPressBack() {
const backAction = NavigationActions.back();
this.props.navigation.dispatch(backAction);
}
render() { render() {
console.log("rendering CustomHeader");
let button; let button;
// Does the app have a back button or a burger menu ? // Does the app have a back button or a burger menu ?
if (this.props.hasBackButton) if (this.props.hasBackButton)
button = button =
<Touchable <Touchable
style={{padding: 6}} style={{padding: 6}}
onPress={() => { onPress={this.onPressBack}>
const backAction = NavigationActions.back();
this.props.navigation.dispatch(backAction);
}}>
<CustomMaterialIcon <CustomMaterialIcon
color={Platform.OS === 'ios' ? ThemeManager.getCurrentThemeVariables().brandPrimary : "#fff"} color={Platform.OS === 'ios' ? ThemeManager.getCurrentThemeVariables().brandPrimary : "#fff"}
icon={Platform.OS === 'ios' ? 'chevron-left' : "arrow-left"}/> icon={Platform.OS === 'ios' ? 'chevron-left' : "arrow-left"}/>

View file

@ -30,7 +30,16 @@ export default class CustomMaterialIcon extends React.Component<Props> {
width: 30, width: 30,
}; };
shouldComponentUpdate(nextProps: Props): boolean {
return nextProps.icon !== this.props.icon ||
nextProps.active !== this.props.active ||
nextProps.width !== this.props.width ||
nextProps.fontSize !== this.props.fontSize ||
nextProps.color !== this.props.color;
}
render() { render() {
// console.log("rendering icon " + this.props.icon);
return ( return (
<Icon <Icon
active active

View file

@ -25,13 +25,18 @@ type Props = {
} }
export default class DashboardItem extends React.Component<Props> { export default class DashboardItem extends React.Component<Props> {
static defaultProps = { static defaultProps = {
isSquare: false, isSquare: false,
isSquareLeft: true, isSquareLeft: true,
displayEvent: undefined, displayEvent: undefined,
}; };
shouldComponentUpdate(nextProps: Props): boolean {
return nextProps.isAvailable !== this.props.isAvailable ||
nextProps.subtitle !== this.props.subtitle;
}
/** /**
* Convert the date string given by in the event list json to a date object * Convert the date string given by in the event list json to a date object
* @param dateString * @param dateString
@ -203,6 +208,7 @@ export default class DashboardItem extends React.Component<Props> {
render() { render() {
// console.log("rendering DashboardItem " + this.props.title);
let marginRight = 10; let marginRight = 10;
if (this.props.isSquare) { if (this.props.isSquare) {
if (this.props.isSquareLeft) if (this.props.isSquareLeft)

View file

@ -25,7 +25,6 @@ type State = {
* Used by inheriting from it and redefining getters. * Used by inheriting from it and redefining getters.
*/ */
export default class FetchedDataSectionList extends React.Component<Props, State> { export default class FetchedDataSectionList extends React.Component<Props, State> {
webDataManager: WebDataManager; webDataManager: WebDataManager;
willFocusSubscription: function; willFocusSubscription: function;
@ -46,8 +45,22 @@ export default class FetchedDataSectionList extends React.Component<Props, State
super(); super();
this.webDataManager = new WebDataManager(fetchUrl); this.webDataManager = new WebDataManager(fetchUrl);
this.refreshTime = refreshTime; this.refreshTime = refreshTime;
// creating references to functions used in render()
this._onRefresh = this._onRefresh.bind(this);
this.renderSectionHeaderEmpty = this.renderSectionHeader.bind(this, true);
this.renderSectionHeaderNotEmpty = this.renderSectionHeader.bind(this, false);
this.renderItemEmpty = this.renderItem.bind(this, true);
this.renderItemNotEmpty = this.renderItem.bind(this, false);
} }
shouldComponentUpdate(nextProps: Props, nextState: State): boolean {
return this.state.refreshing !== nextState.refreshing ||
nextState.firstLoading !== this.state.firstLoading ||
nextState.machinesWatched.length !== this.state.machinesWatched.length ||
nextState.fetchedData.len !== this.state.fetchedData.len;
}
/** /**
* Get the translation for the header in the current language * Get the translation for the header in the current language
* @return {string} * @return {string}
@ -74,17 +87,9 @@ export default class FetchedDataSectionList extends React.Component<Props, State
*/ */
componentDidMount() { componentDidMount() {
this.willFocusSubscription = this.props.navigation.addListener( this.willFocusSubscription = this.props.navigation.addListener(
'willFocus', 'willFocus', this.onScreenFocus.bind(this));
() => {
this.onScreenFocus();
}
);
this.willBlurSubscription = this.props.navigation.addListener( this.willBlurSubscription = this.props.navigation.addListener(
'willBlur', 'willBlur', this.onScreenBlur.bind(this));
() => {
this.onScreenBlur();
}
);
} }
/** /**
@ -93,7 +98,7 @@ export default class FetchedDataSectionList extends React.Component<Props, State
onScreenFocus() { onScreenFocus() {
this._onRefresh(); this._onRefresh();
if (this.refreshTime > 0) if (this.refreshTime > 0)
this.refreshInterval = setInterval(() => this._onRefresh(), this.refreshTime) this.refreshInterval = setInterval(this._onRefresh.bind(this), this.refreshTime)
} }
/** /**
@ -117,7 +122,7 @@ export default class FetchedDataSectionList extends React.Component<Props, State
* Refresh data and show a toast if any error occurred * Refresh data and show a toast if any error occurred
* @private * @private
*/ */
_onRefresh = () => { _onRefresh() {
let canRefresh; let canRefresh;
if (this.lastRefresh !== undefined) if (this.lastRefresh !== undefined)
canRefresh = (new Date().getTime() - this.lastRefresh.getTime()) / 1000 > this.minTimeBetweenRefresh; canRefresh = (new Date().getTime() - this.lastRefresh.getTime()) / 1000 > this.minTimeBetweenRefresh;
@ -144,8 +149,7 @@ export default class FetchedDataSectionList extends React.Component<Props, State
this.webDataManager.showUpdateToast(this.getUpdateToastTranslations()[0], this.getUpdateToastTranslations()[1]); this.webDataManager.showUpdateToast(this.getUpdateToastTranslations()[0], this.getUpdateToastTranslations()[1]);
}); });
} }
}
};
/** /**
* Get the render item to be used for display in the list. * Get the render item to be used for display in the list.
@ -153,10 +157,9 @@ export default class FetchedDataSectionList extends React.Component<Props, State
* *
* @param item * @param item
* @param section * @param section
* @param data
* @return {*} * @return {*}
*/ */
getRenderItem(item: Object, section: Object, data: Object) { getRenderItem(item: Object, section: Object) {
return <View/>; return <View/>;
} }
@ -222,6 +225,11 @@ export default class FetchedDataSectionList extends React.Component<Props, State
return []; return [];
} }
datasetKeyExtractor(item: Object) {
return item.text
}
/** /**
* Create the dataset when no fetched data is available. * Create the dataset when no fetched data is available.
* No need to be overridden, has good defaults. * No need to be overridden, has good defaults.
@ -243,7 +251,7 @@ export default class FetchedDataSectionList extends React.Component<Props, State
'access-point-network-off' 'access-point-network-off'
} }
], ],
keyExtractor: (item: Object) => item.text, keyExtractor: this.datasetKeyExtractor,
} }
]; ];
} }
@ -275,6 +283,19 @@ export default class FetchedDataSectionList extends React.Component<Props, State
return true; return true;
} }
renderSectionHeader(isEmpty, {section: {title}}) {
return isEmpty ?
<View/> :
this.getRenderSectionHeader(title)
}
renderItem(isEmpty, {item, section}) {
return isEmpty ?
this.getEmptyRenderItem(item.text, item.isSpinner, item.icon) :
this.getRenderItem(item, section)
}
/** /**
* Get the section list render using the generated dataset * Get the section list render using the generated dataset
* *
@ -295,16 +316,8 @@ export default class FetchedDataSectionList extends React.Component<Props, State
onRefresh={this._onRefresh} onRefresh={this._onRefresh}
/> />
} }
renderSectionHeader={({section: {title}}) => renderSectionHeader={isEmpty ? this.renderSectionHeaderEmpty : this.renderSectionHeaderNotEmpty}
isEmpty ? renderItem={isEmpty ? this.renderItemEmpty : this.renderItemNotEmpty}
<View/> :
this.getRenderSectionHeader(title)
}
renderItem={({item, section}) =>
isEmpty ?
this.getEmptyRenderItem(item.text, item.isSpinner, item.icon) :
this.getRenderItem(item, section, dataset)
}
style={{minHeight: 300, width: '100%'}} style={{minHeight: 300, width: '100%'}}
contentContainerStyle={ contentContainerStyle={
isEmpty ? isEmpty ?
@ -351,11 +364,12 @@ export default class FetchedDataSectionList extends React.Component<Props, State
} }
render() { render() {
const nav = this.props.navigation; // console.log("rendering FetchedDataSectionList");
const dataset = this.createDataset(this.state.fetchedData); const dataset = this.createDataset(this.state.fetchedData);
return ( return (
<BaseContainer <BaseContainer
navigation={nav} headerTitle={this.getHeaderTranslation()} navigation={this.props.navigation}
headerTitle={this.getHeaderTranslation()}
headerRightButton={this.getRightButton()} headerRightButton={this.getRightButton()}
hasTabs={this.hasTabs()} hasTabs={this.hasTabs()}
hasBackButton={this.hasBackButton()} hasBackButton={this.hasBackButton()}
@ -375,5 +389,4 @@ export default class FetchedDataSectionList extends React.Component<Props, State
</BaseContainer> </BaseContainer>
); );
} }
} }

View file

@ -103,21 +103,35 @@ export default class SideBar extends React.Component<Props, State> {
icon: "information", icon: "information",
}, },
]; ];
this.getRenderItem = this.getRenderItem.bind(this);
} }
getRenderItem(item: Object) { shouldComponentUpdate(nextProps: Props, nextState: State): boolean {
return nextState.active !== this.state.active;
}
onListItemPress(item) {
if (item.link !== undefined)
Linking.openURL(item.link).catch((err) => console.error('Error opening link', err));
else
this.navigateToScreen(item.route);
}
listKeyExtractor(item) {
return item.route;
}
getRenderItem({item}: Object) {
if (item.icon !== undefined) { if (item.icon !== undefined) {
return ( return (
<ListItem <ListItem
button button
noBorder noBorder
selected={this.state.active === item.route} selected={this.state.active === item.route}
onPress={() => { onPress={this.onListItemPress.bind(this, item)}
if (item.link !== undefined)
Linking.openURL(item.link).catch((err) => console.error('Error opening link', err));
else
this.navigateToScreen(item.route);
}}
> >
<Left> <Left>
<CustomMaterialIcon <CustomMaterialIcon
@ -164,6 +178,7 @@ export default class SideBar extends React.Component<Props, State> {
}; };
render() { render() {
// console.log("rendering SideBar");
return ( return (
<Container style={{ <Container style={{
backgroundColor: ThemeManager.getCurrentThemeVariables().sideMenuBgColor, backgroundColor: ThemeManager.getCurrentThemeVariables().sideMenuBgColor,
@ -172,8 +187,8 @@ export default class SideBar extends React.Component<Props, State> {
<FlatList <FlatList
data={this.dataSet} data={this.dataSet}
extraData={this.state} extraData={this.state}
keyExtractor={(item) => item.route} keyExtractor={this.listKeyExtractor}
renderItem={({item}) => this.getRenderItem(item)} renderItem={this.getRenderItem}
/> />
</Container> </Container>
); );

View file

@ -133,6 +133,7 @@ export default class WebViewScreen extends React.Component<Props> {
} }
render() { render() {
// console.log("rendering WebViewScreen");
const nav = this.props.navigation; const nav = this.props.navigation;
this.webviewArray = []; this.webviewArray = [];
return ( return (

View file

@ -40,6 +40,10 @@ export default class HomeScreen extends FetchedDataSectionList {
constructor() { constructor() {
super(DATA_URL, REFRESH_TIME); super(DATA_URL, REFRESH_TIME);
this.proxiwashClickAction = this.proxiwashClickAction.bind(this);
this.tutorinsaClickAction = this.tutorinsaClickAction.bind(this);
this.menuClickAction = this.menuClickAction.bind(this);
this.proximoClickAction = this.proximoClickAction.bind(this);
} }
/** /**
@ -289,6 +293,14 @@ export default class HomeScreen extends FetchedDataSectionList {
} }
clickAction(isAvailable, displayEvent) {
if (isAvailable)
this.props.navigation.navigate('PlanningDisplayScreen', {data: displayEvent});
else
this.props.navigation.navigate('PlanningScreen');
};
getDashboardEventItem(content: Array<Object>) { getDashboardEventItem(content: Array<Object>) {
let icon = 'calendar-range'; let icon = 'calendar-range';
let color = ThemeManager.getCurrentThemeVariables().planningColor; let color = ThemeManager.getCurrentThemeVariables().planningColor;
@ -310,12 +322,6 @@ export default class HomeScreen extends FetchedDataSectionList {
</Text>; </Text>;
} else } else
subtitle = i18n.t('homeScreen.dashboard.todayEventsSubtitleNA'); subtitle = i18n.t('homeScreen.dashboard.todayEventsSubtitleNA');
let clickAction = () => {
if (isAvailable)
this.props.navigation.navigate('PlanningDisplayScreen', {data: displayEvent});
else
this.props.navigation.navigate('PlanningScreen');
};
let displayEvent = this.getDisplayEvent(futureEvents); let displayEvent = this.getDisplayEvent(futureEvents);
@ -324,7 +330,7 @@ export default class HomeScreen extends FetchedDataSectionList {
subtitle={subtitle} subtitle={subtitle}
color={color} color={color}
icon={icon} icon={icon}
clickAction={() => clickAction()} clickAction={this.clickAction.bind(this, isAvailable, displayEvent)}
title={title} title={title}
isAvailable={isAvailable} isAvailable={isAvailable}
displayEvent={displayEvent} displayEvent={displayEvent}
@ -332,6 +338,14 @@ export default class HomeScreen extends FetchedDataSectionList {
); );
} }
proximoClickAction() {
this.props.navigation.navigate('Proximo');
}
menuClickAction() {
this.props.navigation.navigate('SelfMenuScreen');
}
getDashboardBottomItem(content: Array<Object>) { getDashboardBottomItem(content: Array<Object>) {
let proximoData = content[0]['data']; let proximoData = content[0]['data'];
@ -355,7 +369,6 @@ export default class HomeScreen extends FetchedDataSectionList {
</Text>; </Text>;
} else } else
proximoSubtitle = i18n.t('homeScreen.dashboard.proximoSubtitleNA'); proximoSubtitle = i18n.t('homeScreen.dashboard.proximoSubtitleNA');
let proximoClickAction = () => this.props.navigation.navigate('Proximo');
let menuIcon = 'silverware-fork-knife'; let menuIcon = 'silverware-fork-knife';
@ -367,7 +380,6 @@ export default class HomeScreen extends FetchedDataSectionList {
menuSubtitle = i18n.t('homeScreen.dashboard.menuSubtitle'); menuSubtitle = i18n.t('homeScreen.dashboard.menuSubtitle');
} else } else
menuSubtitle = i18n.t('homeScreen.dashboard.menuSubtitleNA'); menuSubtitle = i18n.t('homeScreen.dashboard.menuSubtitleNA');
let menuClickAction = () => this.props.navigation.navigate('SelfMenuScreen');
return ( return (
<View style={{ <View style={{
flexDirection: 'row', flexDirection: 'row',
@ -379,7 +391,7 @@ export default class HomeScreen extends FetchedDataSectionList {
subtitle={menuSubtitle} subtitle={menuSubtitle}
color={menuColor} color={menuColor}
icon={menuIcon} icon={menuIcon}
clickAction={() => menuClickAction()} clickAction={this.menuClickAction}
title={menuTitle} title={menuTitle}
isAvailable={isMenuAvailable} isAvailable={isMenuAvailable}
isSquareLeft={true}/> isSquareLeft={true}/>
@ -388,13 +400,22 @@ export default class HomeScreen extends FetchedDataSectionList {
subtitle={proximoSubtitle} subtitle={proximoSubtitle}
color={proximoColor} color={proximoColor}
icon={proximoIcon} icon={proximoIcon}
clickAction={() => proximoClickAction()} clickAction={this.proximoClickAction}
title={proximoTitle} title={proximoTitle}
isAvailable={isProximoAvailable}/> isAvailable={isProximoAvailable}/>
</View> </View>
); );
} }
proxiwashClickAction() {
this.props.navigation.navigate('Proxiwash');
}
tutorinsaClickAction() {
this.props.navigation.navigate('TutorInsaScreen');
}
getDashboardMiddleItem(content: Array<Object>) { getDashboardMiddleItem(content: Array<Object>) {
let proxiwashData = content[0]['data']; let proxiwashData = content[0]['data'];
let tutorinsaData = content[1]['data']; let tutorinsaData = content[1]['data'];
@ -449,7 +470,6 @@ export default class HomeScreen extends FetchedDataSectionList {
</Text>; </Text>;
} else } else
proxiwashSubtitle = i18n.t('homeScreen.dashboard.proxiwashSubtitleNA'); proxiwashSubtitle = i18n.t('homeScreen.dashboard.proxiwashSubtitleNA');
let proxiwashClickAction = () => this.props.navigation.navigate('Proxiwash');
let tutorinsaIcon = 'school'; let tutorinsaIcon = 'school';
let tutorinsaColor = ThemeManager.getCurrentThemeVariables().tutorinsaColor; let tutorinsaColor = ThemeManager.getCurrentThemeVariables().tutorinsaColor;
@ -470,7 +490,6 @@ export default class HomeScreen extends FetchedDataSectionList {
</Text>; </Text>;
} else } else
tutorinsaSubtitle = i18n.t('homeScreen.dashboard.tutorinsaSubtitleNA'); tutorinsaSubtitle = i18n.t('homeScreen.dashboard.tutorinsaSubtitleNA');
let tutorinsaClickAction = () => this.props.navigation.navigate('TutorInsaScreen');
return ( return (
<View style={{ <View style={{
@ -483,7 +502,7 @@ export default class HomeScreen extends FetchedDataSectionList {
subtitle={proxiwashSubtitle} subtitle={proxiwashSubtitle}
color={proxiwashColor} color={proxiwashColor}
icon={proxiwashIcon} icon={proxiwashIcon}
clickAction={() => proxiwashClickAction()} clickAction={this.proxiwashClickAction}
title={proxiwashTitle} title={proxiwashTitle}
isAvailable={proxiwashIsAvailable} isAvailable={proxiwashIsAvailable}
isSquareLeft={true}/> isSquareLeft={true}/>
@ -492,7 +511,7 @@ export default class HomeScreen extends FetchedDataSectionList {
subtitle={tutorinsaSubtitle} subtitle={tutorinsaSubtitle}
color={tutorinsaColor} color={tutorinsaColor}
icon={tutorinsaIcon} icon={tutorinsaIcon}
clickAction={() => tutorinsaClickAction()} clickAction={this.tutorinsaClickAction}
title={tutorinsaTitle} title={tutorinsaTitle}
isAvailable={tutorinsaIsAvailable}/> isAvailable={tutorinsaIsAvailable}/>
</View> </View>
@ -500,7 +519,7 @@ export default class HomeScreen extends FetchedDataSectionList {
} }
getRenderItem(item: Object, section: Object, data: Object) { getRenderItem(item: Object, section: Object) {
return ( return (
section['id'] === SECTIONS_ID[0] ? this.getDashboardItem(item) : section['id'] === SECTIONS_ID[0] ? this.getDashboardItem(item) :
<Card style={{ <Card style={{
@ -525,7 +544,7 @@ export default class HomeScreen extends FetchedDataSectionList {
}}> }}>
<Body> <Body>
{item.full_picture !== '' && item.full_picture !== undefined ? {item.full_picture !== '' && item.full_picture !== undefined ?
<TouchableOpacity onPress={() => openWebLink(item.full_picture)} <TouchableOpacity onPress={openWebLink.bind(null, item.full_picture)}
style={{width: '100%', height: 250, marginBottom: 5}}> style={{width: '100%', height: 250, marginBottom: 5}}>
<Image source={{uri: item.full_picture}} <Image source={{uri: item.full_picture}}
style={{flex: 1, resizeMode: "contain"}} style={{flex: 1, resizeMode: "contain"}}
@ -547,7 +566,7 @@ export default class HomeScreen extends FetchedDataSectionList {
}}> }}>
<Left> <Left>
<Button transparent <Button transparent
onPress={() => openWebLink(item.permalink_url)}> onPress={openWebLink.bind(null, item.permalink_url)}>
<CustomMaterialIcon <CustomMaterialIcon
icon="facebook" icon="facebook"
color="#57aeff" color="#57aeff"

View file

@ -14,7 +14,7 @@ type Props = {
navigation: Object, navigation: Object,
}; };
function openWebLink(link) { function openWebLink(event, link) {
Linking.openURL(link).catch((err) => console.error('Error opening link', err)); Linking.openURL(link).catch((err) => console.error('Error opening link', err));
} }
@ -22,8 +22,8 @@ function openWebLink(link) {
* Class defining an about screen. This screen shows the user information about the app and it's author. * Class defining an about screen. This screen shows the user information about the app and it's author.
*/ */
export default class PlanningDisplayScreen extends React.Component<Props> { export default class PlanningDisplayScreen extends React.Component<Props> {
render() { render() {
// console.log("rendering planningDisplayScreen");
const nav = this.props.navigation; const nav = this.props.navigation;
const displayData = nav.getParam('data', []); const displayData = nav.getParam('data', []);
return ( return (
@ -60,7 +60,7 @@ export default class PlanningDisplayScreen extends React.Component<Props> {
}, },
div: {color: ThemeManager.getCurrentThemeVariables().textColor} div: {color: ThemeManager.getCurrentThemeVariables().textColor}
}} }}
onLinkPress={(event, link) => openWebLink(link)}/> onLinkPress={openWebLink}/>
: <View/>} : <View/>}
</Content> </Content>
</Container> </Container>

View file

@ -56,6 +56,7 @@ export default class PlanningScreen extends React.Component<Props, State> {
didFocusSubscription: Function; didFocusSubscription: Function;
willBlurSubscription: Function; willBlurSubscription: Function;
state = { state = {
refreshing: false, refreshing: false,
agendaItems: {}, agendaItems: {},
@ -76,6 +77,22 @@ export default class PlanningScreen extends React.Component<Props, State> {
if (i18n.currentLocale().startsWith("fr")) { if (i18n.currentLocale().startsWith("fr")) {
LocaleConfig.defaultLocale = 'fr'; LocaleConfig.defaultLocale = 'fr';
} }
// Create references for functions required in the render function
this._onRefresh = this._onRefresh.bind(this);
this.onCalendarToggled = this.onCalendarToggled.bind(this);
this.getRenderItem = this.getRenderItem.bind(this);
this.getRenderEmptyDate = this.getRenderEmptyDate.bind(this);
this.setAgendaRef = this.setAgendaRef.bind(this);
this.onCalendarToggled = this.onCalendarToggled.bind(this);
this.onCalendarToggled = this.onCalendarToggled.bind(this);
this.onBackButtonPressAndroid = this.onBackButtonPressAndroid.bind(this);
}
shouldComponentUpdate(nextProps: Props, nextState: State): boolean {
return nextState.refreshing === false && this.state.refreshing === true ||
nextState.agendaItems !== this.state.agendaItems ||
nextState.calendarShowing !== this.state.calendarShowing;
} }
componentDidMount() { componentDidMount() {
@ -90,7 +107,7 @@ export default class PlanningScreen extends React.Component<Props, State> {
); );
} }
onBackButtonPressAndroid = () => { onBackButtonPressAndroid() {
if (this.state.calendarShowing) { if (this.state.calendarShowing) {
this.agendaRef.chooseDay(this.agendaRef.state.selectedDay); this.agendaRef.chooseDay(this.agendaRef.state.selectedDay);
return true; return true;
@ -126,10 +143,6 @@ export default class PlanningScreen extends React.Component<Props, State> {
} }
getRenderItem(item: Object) { getRenderItem(item: Object) {
let navData = {
data: item
};
const nav = this.props.navigation;
return ( return (
<Touchable <Touchable
style={{ style={{
@ -138,7 +151,7 @@ export default class PlanningScreen extends React.Component<Props, State> {
marginRight: 10, marginRight: 10,
marginTop: 17, marginTop: 17,
}} }}
onPress={() => nav.navigate('PlanningDisplayScreen', navData)}> onPress={() => this.props.navigation.navigate('PlanningDisplayScreen', {data: item})}>
<View style={{ <View style={{
padding: 10, padding: 10,
flex: 1, flex: 1,
@ -252,38 +265,46 @@ export default class PlanningScreen extends React.Component<Props, State> {
} }
} }
setAgendaRef(ref) {
this.agendaRef = ref;
}
onCalendarToggled(calendarOpened) {
this.setState({calendarShowing: calendarOpened});
}
currentDate = this.getCurrentDate();
render() { render() {
const nav = this.props.navigation; // console.log("rendering PlanningScreen");
return ( return (
<BaseContainer navigation={nav} headerTitle={i18n.t('screens.planning')}> <BaseContainer navigation={this.props.navigation} headerTitle={i18n.t('screens.planning')}>
<Agenda <Agenda
// the list of items that have to be displayed in agenda. If you want to render item as empty date // the list of items that have to be displayed in agenda. If you want to render item as empty date
// the value of date key kas to be an empty array []. If there exists no value for date key it is // the value of date key kas to be an empty array []. If there exists no value for date key it is
// considered that the date in question is not yet loaded // considered that the date in question is not yet loaded
items={this.state.agendaItems} items={this.state.agendaItems}
// initially selected day // initially selected day
selected={this.getCurrentDate()} selected={this.currentDate}
// Minimum date that can be selected, dates before minDate will be grayed out. Default = undefined // Minimum date that can be selected, dates before minDate will be grayed out. Default = undefined
minDate={this.getCurrentDate()} minDate={this.currentDate}
// Max amount of months allowed to scroll to the past. Default = 50 // Max amount of months allowed to scroll to the past. Default = 50
pastScrollRange={1} pastScrollRange={1}
// Max amount of months allowed to scroll to the future. Default = 50 // Max amount of months allowed to scroll to the future. Default = 50
futureScrollRange={AGENDA_MONTH_SPAN} futureScrollRange={AGENDA_MONTH_SPAN}
// If provided, a standard RefreshControl will be added for "Pull to Refresh" functionality. Make sure to also set the refreshing prop correctly. // If provided, a standard RefreshControl will be added for "Pull to Refresh" functionality. Make sure to also set the refreshing prop correctly.
onRefresh={() => this._onRefresh()} onRefresh={this._onRefresh}
// callback that fires when the calendar is opened or closed // callback that fires when the calendar is opened or closed
onCalendarToggled={(calendarOpened) => { onCalendarToggled={this.onCalendarToggled}
this.setState({calendarShowing: calendarOpened})
}}
// Set this true while waiting for new data from a refresh // Set this true while waiting for new data from a refresh
refreshing={this.state.refreshing} refreshing={this.state.refreshing}
renderItem={(item) => this.getRenderItem(item)} renderItem={this.getRenderItem}
renderEmptyDate={() => this.getRenderEmptyDate()} renderEmptyDate={this.getRenderEmptyDate}
rowHasChanged={() => this.rowHasChanged()} rowHasChanged={this.rowHasChanged}
// If firstDay=1 week starts from Monday. Note that dayNames and dayNamesShort should still start from Sunday. // If firstDay=1 week starts from Monday. Note that dayNames and dayNamesShort should still start from Sunday.
firstDay={1} firstDay={1}
// ref to this agenda in order to handle back button event // ref to this agenda in order to handle back button event
ref={(ref) => this.agendaRef = ref} ref={this.setAgendaRef}
// agenda theme // agenda theme
theme={{ theme={{
backgroundColor: ThemeManager.getCurrentThemeVariables().agendaBackgroundColor, backgroundColor: ThemeManager.getCurrentThemeVariables().agendaBackgroundColor,

View file

@ -76,6 +76,11 @@ export default class ProximoListScreen extends React.Component<Props, State> {
super(props); super(props);
this.modalRef = React.createRef(); this.modalRef = React.createRef();
this.originalData = this.navData['data']; this.originalData = this.navData['data'];
this.search = this.search.bind(this);
this.selectSortModeName = this.selectSortModeName.bind(this);
this.selectSortModePrice = this.selectSortModePrice.bind(this);
this.showMenu = this.showMenu.bind(this);
this.renderItem = this.renderItem.bind(this);
} }
/** /**
@ -260,6 +265,19 @@ export default class ProximoListScreen extends React.Component<Props, State> {
} }
} }
selectSortModeName() {
this.sortModeSelected(sortMode.name);
}
selectSortModePrice() {
this.sortModeSelected(sortMode.price);
}
showMenu() {
this._menu.show();
}
getSortMenu() { getSortMenu() {
return ( return (
<Menu <Menu
@ -267,9 +285,7 @@ export default class ProximoListScreen extends React.Component<Props, State> {
button={ button={
<Touchable <Touchable
style={{padding: 6}} style={{padding: 6}}
onPress={() => onPress={this.showMenu}>
this._menu.show()
}>
<CustomMaterialIcon <CustomMaterialIcon
color={Platform.OS === 'ios' ? ThemeManager.getCurrentThemeVariables().brandPrimary : "#fff"} color={Platform.OS === 'ios' ? ThemeManager.getCurrentThemeVariables().brandPrimary : "#fff"}
icon={'sort'}/> icon={'sort'}/>
@ -277,12 +293,12 @@ export default class ProximoListScreen extends React.Component<Props, State> {
} }
> >
<MenuItem <MenuItem
onPress={() => this.sortModeSelected(sortMode.name)}> onPress={this.selectSortModeName}>
{this.state.sortNameIcon} {this.state.sortNameIcon}
{i18n.t('proximoScreen.sortName')} {i18n.t('proximoScreen.sortName')}
</MenuItem> </MenuItem>
<MenuItem <MenuItem
onPress={() => this.sortModeSelected(sortMode.price)}> onPress={this.selectSortModePrice}>
{this.state.sortPriceIcon} {this.state.sortPriceIcon}
{i18n.t('proximoScreen.sortPrice')} {i18n.t('proximoScreen.sortPrice')}
</MenuItem> </MenuItem>
@ -290,31 +306,8 @@ export default class ProximoListScreen extends React.Component<Props, State> {
); );
} }
render() { renderItem({item}) {
const nav = this.props.navigation; return (<ListItem
return (
<Container>
<Modalize ref={this.modalRef}
adjustToContentHeight
modalStyle={{backgroundColor: ThemeManager.getCurrentThemeVariables().containerBgColor}}>
{this.getModalContent()}
</Modalize>
<CustomHeader
hasBackButton={true}
navigation={nav}
hasSearchField={true}
searchCallback={(text) => this.search(text)}
shouldFocusSearchBar={this.shouldFocusSearchBar}
rightButton={this.getSortMenu()}
/>
<FlatList
data={this.state.currentlyDisplayedData}
extraData={this.state.currentlyDisplayedData}
keyExtractor={(item) => item.name + item.code}
style={{minHeight: 300, width: '100%'}}
renderItem={({item}) =>
<ListItem
thumbnail thumbnail
onPress={() => { onPress={() => {
this.showItemDetails(item); this.showItemDetails(item);
@ -339,7 +332,38 @@ export default class ProximoListScreen extends React.Component<Props, State> {
{item.price} {item.price}
</Text> </Text>
</Right> </Right>
</ListItem>} </ListItem>);
}
keyExtractor(item) {
return item.name + item.code;
}
render() {
// console.log("rendering ProximoListScreen");
const nav = this.props.navigation;
return (
<Container>
<Modalize ref={this.modalRef}
adjustToContentHeight
modalStyle={{backgroundColor: ThemeManager.getCurrentThemeVariables().containerBgColor}}>
{this.getModalContent()}
</Modalize>
<CustomHeader
hasBackButton={true}
navigation={nav}
hasSearchField={true}
searchCallback={this.search}
shouldFocusSearchBar={this.shouldFocusSearchBar}
rightButton={this.getSortMenu()}
/>
<FlatList
data={this.state.currentlyDisplayedData}
extraData={this.state.currentlyDisplayedData}
keyExtractor={this.keyExtractor}
style={{minHeight: 300, width: '100%'}}
renderItem={this.renderItem}
/> />
</Container> </Container>
); );

View file

@ -20,6 +20,8 @@ export default class ProximoMainScreen extends FetchedDataSectionList {
constructor() { constructor() {
super(DATA_URL, 0); super(DATA_URL, 0);
this.onPressSearchBtn = this.onPressSearchBtn.bind(this);
this.onPressAboutBtn = this.onPressAboutBtn.bind(this);
} }
static sortFinalData(a: Object, b: Object) { static sortFinalData(a: Object, b: Object) {
@ -100,7 +102,7 @@ export default class ProximoMainScreen extends FetchedDataSectionList {
return availableArticles; return availableArticles;
} }
getRightButton() { onPressSearchBtn() {
let searchScreenData = { let searchScreenData = {
shouldFocusSearchBar: true, shouldFocusSearchBar: true,
data: { data: {
@ -113,8 +115,14 @@ export default class ProximoMainScreen extends FetchedDataSectionList {
this.getAvailableArticles(this.state.fetchedData.articles, undefined) : [] this.getAvailableArticles(this.state.fetchedData.articles, undefined) : []
}, },
}; };
this.props.navigation.navigate('ProximoListScreen', searchScreenData);
}
onPressAboutBtn() {
this.props.navigation.navigate('ProximoAboutScreen');
}
getRightButton() {
return ( return (
<View <View
style={{ style={{
@ -122,14 +130,14 @@ export default class ProximoMainScreen extends FetchedDataSectionList {
}}> }}>
<Touchable <Touchable
style={{padding: 6}} style={{padding: 6}}
onPress={() => this.props.navigation.navigate('ProximoListScreen', searchScreenData)}> onPress={this.onPressSearchBtn}>
<CustomMaterialIcon <CustomMaterialIcon
color={Platform.OS === 'ios' ? ThemeManager.getCurrentThemeVariables().brandPrimary : "#fff"} color={Platform.OS === 'ios' ? ThemeManager.getCurrentThemeVariables().brandPrimary : "#fff"}
icon="magnify"/> icon="magnify"/>
</Touchable> </Touchable>
<Touchable <Touchable
style={{padding: 6}} style={{padding: 6}}
onPress={() => this.props.navigation.navigate('ProximoAboutScreen')}> onPress={this.onPressAboutBtn}>
<CustomMaterialIcon <CustomMaterialIcon
color={Platform.OS === 'ios' ? ThemeManager.getCurrentThemeVariables().brandPrimary : "#fff"} color={Platform.OS === 'ios' ? ThemeManager.getCurrentThemeVariables().brandPrimary : "#fff"}
icon="information"/> icon="information"/>
@ -138,7 +146,7 @@ export default class ProximoMainScreen extends FetchedDataSectionList {
); );
} }
getRenderItem(item: Object, section: Object, data: Object) { getRenderItem(item: Object, section: Object) {
let dataToSend = { let dataToSend = {
shouldFocusSearchBar: false, shouldFocusSearchBar: false,
data: item, data: item,

View file

@ -75,6 +75,8 @@ export default class ProxiwashScreen extends FetchedDataSectionList {
machinesWatched: [], machinesWatched: [],
}; };
this.setMinTimeRefresh(30); this.setMinTimeRefresh(30);
this.navigateToAboutScreen = this.navigateToAboutScreen.bind(this);
} }
/** /**
@ -272,11 +274,15 @@ export default class ProxiwashScreen extends FetchedDataSectionList {
); );
} }
navigateToAboutScreen() {
this.props.navigation.navigate('ProxiwashAboutScreen');
}
getRightButton(): * { getRightButton(): * {
return ( return (
<Touchable <Touchable
style={{padding: 6}} style={{padding: 6}}
onPress={() => this.props.navigation.navigate('ProxiwashAboutScreen')}> onPress={this.navigateToAboutScreen}>
<CustomMaterialIcon <CustomMaterialIcon
color={Platform.OS === 'ios' ? ThemeManager.getCurrentThemeVariables().brandPrimary : "#fff"} color={Platform.OS === 'ios' ? ThemeManager.getCurrentThemeVariables().brandPrimary : "#fff"}
icon="information"/> icon="information"/>
@ -289,10 +295,9 @@ export default class ProxiwashScreen extends FetchedDataSectionList {
* *
* @param item The object containing the item's FetchedData * @param item The object containing the item's FetchedData
* @param section The object describing the current SectionList section * @param section The object describing the current SectionList section
* @param data The full FetchedData used by the SectionList
* @returns {React.Node} * @returns {React.Node}
*/ */
getRenderItem(item: Object, section: Object, data: Object) { getRenderItem(item: Object, section: Object) {
let isMachineRunning = MACHINE_STATES[item.state] === MACHINE_STATES["EN COURS"]; let isMachineRunning = MACHINE_STATES[item.state] === MACHINE_STATES["EN COURS"];
let machineName = (section.title === i18n.t('proxiwashScreen.dryers') ? i18n.t('proxiwashScreen.dryer') : i18n.t('proxiwashScreen.washer')) + ' n°' + item.number; let machineName = (section.title === i18n.t('proxiwashScreen.dryers') ? i18n.t('proxiwashScreen.dryer') : i18n.t('proxiwashScreen.washer')) + ' n°' + item.number;
let isDryer = section.title === i18n.t('proxiwashScreen.dryers'); let isDryer = section.title === i18n.t('proxiwashScreen.dryers');

View file

@ -119,7 +119,7 @@ export default class SelfMenuScreen extends FetchedDataSectionList {
); );
} }
getRenderItem(item: Object, section: Object, data: Object) { getRenderItem(item: Object, section: Object) {
return ( return (
<Card style={{ <Card style={{
flex: 0, flex: 0,