Compare commits

..

No commits in common. "2598be6e49645a660fa2d78a29431e0186437e6a" and "3f7f9551aa452b6734defb84d0e12dc5a1d411f4" have entirely different histories.

21 changed files with 318 additions and 500 deletions

13
App.js
View file

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

View file

@ -30,6 +30,7 @@ type State = {
export default class BaseContainer extends React.Component<Props, State> {
static defaultProps = {
headerRightButton: <View/>,
hasTabs: false,
@ -45,61 +46,40 @@ export default class BaseContainer extends React.Component<Props, State> {
isHeaderVisible: true,
};
onDrawerPress: Function;
onWillFocus: Function;
onWillBlur: Function;
onChangeOrientation: Function;
constructor() {
super();
this.onDrawerPress = this.onDrawerPress.bind(this);
this.onWillFocus = this.onWillFocus.bind(this);
this.onWillBlur = this.onWillBlur.bind(this);
this.onChangeOrientation = this.onChangeOrientation.bind(this);
}
onDrawerPress() {
toggle() {
this.props.navigation.toggleDrawer();
}
onWillFocus() {
if (this.props.enableRotation) {
ScreenOrientation.unlockAsync();
ScreenOrientation.addOrientationChangeListener(this.onChangeOrientation);
}
}
onWillBlur() {
if (this.props.enableRotation)
ScreenOrientation.lockAsync(ScreenOrientation.Orientation.PORTRAIT);
}
onChangeOrientation(OrientationChangeEvent) {
if (this.props.hideHeaderOnLandscape) {
let isLandscape = OrientationChangeEvent.orientationInfo.orientation === ScreenOrientation.Orientation.LANDSCAPE ||
OrientationChangeEvent.orientationInfo.orientation === ScreenOrientation.Orientation.LANDSCAPE_LEFT ||
OrientationChangeEvent.orientationInfo.orientation === ScreenOrientation.Orientation.LANDSCAPE_RIGHT;
this.setState({isHeaderVisible: !isLandscape});
const setParamsAction = NavigationActions.setParams({
params: {showTabBar: !isLandscape},
key: this.props.navigation.state.key,
});
this.props.navigation.dispatch(setParamsAction);
StatusBar.setHidden(isLandscape);
}
}
/**
* Register for blur event to close side menu on screen change
*/
componentDidMount() {
this.willFocusSubscription = this.props.navigation.addListener(
'willFocus',
this.onWillFocus
);
() => {
if (this.props.enableRotation) {
ScreenOrientation.unlockAsync();
ScreenOrientation.addOrientationChangeListener((OrientationChangeEvent) => {
if (this.props.hideHeaderOnLandscape) {
let isLandscape = OrientationChangeEvent.orientationInfo.orientation === ScreenOrientation.Orientation.LANDSCAPE ||
OrientationChangeEvent.orientationInfo.orientation === ScreenOrientation.Orientation.LANDSCAPE_LEFT ||
OrientationChangeEvent.orientationInfo.orientation === ScreenOrientation.Orientation.LANDSCAPE_RIGHT;
this.setState({isHeaderVisible: !isLandscape});
const setParamsAction = NavigationActions.setParams({
params: {showTabBar: !isLandscape},
key: this.props.navigation.state.key,
});
this.props.navigation.dispatch(setParamsAction);
StatusBar.setHidden(isLandscape);
}
});
}
});
this.willBlurSubscription = this.props.navigation.addListener(
'willBlur',
this.onWillBlur
() => {
if (this.props.enableRotation)
ScreenOrientation.lockAsync(ScreenOrientation.Orientation.PORTRAIT);
}
);
}
@ -113,9 +93,7 @@ export default class BaseContainer extends React.Component<Props, State> {
this.willFocusSubscription.remove();
}
render() {
// console.log("rendering BaseContainer");
getMainContainer() {
return (
<Container>
{this.state.isHeaderVisible ?
@ -126,7 +104,7 @@ export default class BaseContainer extends React.Component<Props, State> {
leftButton={
<Touchable
style={{padding: 6}}
onPress={this.onDrawerPress}>
onPress={() => this.toggle()}>
<CustomMaterialIcon
color={Platform.OS === 'ios' ? ThemeManager.getCurrentThemeVariables().brandPrimary : "#fff"}
icon="menu"/>
@ -140,4 +118,9 @@ export default class BaseContainer extends React.Component<Props, State> {
</Container>
);
}
render() {
return (this.getMainContainer());
}
}

View file

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

View file

@ -117,7 +117,7 @@ export default class CustomIntroSlider extends React.Component<Props> {
* @param item
* @param dimensions
*/
static getIntroRenderItem({item, dimensions}: Object) {
static getIntroRenderItem(item: Object, dimensions: Object) {
return (
<LinearGradient
@ -143,9 +143,9 @@ export default class CustomIntroSlider extends React.Component<Props> {
render() {
return (
<AppIntroSlider
renderItem={CustomIntroSlider.getIntroRenderItem}
renderItem={({item, dimensions}) => CustomIntroSlider.getIntroRenderItem(item, dimensions)}
slides={this.props.isUpdate ? this.updateSlides : this.introSlides}
onDone={this.props.onDone}
onDone={() => this.props.onDone()}
bottomButton
showSkipButton
skipLabel={i18n.t('intro.buttons.skip')}

View file

@ -30,16 +30,7 @@ export default class CustomMaterialIcon extends React.Component<Props> {
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() {
// console.log("rendering icon " + this.props.icon);
return (
<Icon
active

View file

@ -25,18 +25,13 @@ type Props = {
}
export default class DashboardItem extends React.Component<Props> {
static defaultProps = {
isSquare: false,
isSquareLeft: true,
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
* @param dateString
@ -208,7 +203,6 @@ export default class DashboardItem extends React.Component<Props> {
render() {
// console.log("rendering DashboardItem " + this.props.title);
let marginRight = 10;
if (this.props.isSquare) {
if (this.props.isSquareLeft)

View file

@ -25,6 +25,7 @@ type State = {
* Used by inheriting from it and redefining getters.
*/
export default class FetchedDataSectionList extends React.Component<Props, State> {
webDataManager: WebDataManager;
willFocusSubscription: function;
@ -41,29 +42,12 @@ export default class FetchedDataSectionList extends React.Component<Props, State
machinesWatched: [],
};
onRefresh: Function;
onFetchSuccess: Function;
onFetchError: Function;
renderSectionHeaderEmpty: Function;
renderSectionHeaderNotEmpty: Function;
renderItemEmpty: Function;
renderItemNotEmpty: Function;
constructor(fetchUrl: string, refreshTime: number) {
super();
this.webDataManager = new WebDataManager(fetchUrl);
this.refreshTime = refreshTime;
// creating references to functions used in render()
this.onRefresh = this.onRefresh.bind(this);
this.onFetchSuccess = this.onFetchSuccess.bind(this);
this.onFetchError = this.onFetchError.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);
}
/**
* Get the translation for the header in the current language
* @return {string}
@ -90,18 +74,26 @@ export default class FetchedDataSectionList extends React.Component<Props, State
*/
componentDidMount() {
this.willFocusSubscription = this.props.navigation.addListener(
'willFocus', this.onScreenFocus.bind(this));
'willFocus',
() => {
this.onScreenFocus();
}
);
this.willBlurSubscription = this.props.navigation.addListener(
'willBlur', this.onScreenBlur.bind(this));
'willBlur',
() => {
this.onScreenBlur();
}
);
}
/**
* Refresh data when focusing the screen and setup a refresh interval if asked to
*/
onScreenFocus() {
this.onRefresh();
this._onRefresh();
if (this.refreshTime > 0)
this.refreshInterval = setInterval(this.onRefresh.bind(this), this.refreshTime)
this.refreshInterval = setInterval(() => this._onRefresh(), this.refreshTime)
}
/**
@ -121,29 +113,11 @@ export default class FetchedDataSectionList extends React.Component<Props, State
this.willFocusSubscription.remove();
}
onFetchSuccess(fetchedData: Object) {
this.setState({
fetchedData: fetchedData,
refreshing: false,
firstLoading: false
});
this.lastRefresh = new Date();
}
onFetchError() {
this.setState({
fetchedData: {},
refreshing: false,
firstLoading: false
});
this.webDataManager.showUpdateToast(this.getUpdateToastTranslations()[0], this.getUpdateToastTranslations()[1]);
}
/**
* Refresh data and show a toast if any error occurred
* @private
*/
onRefresh() {
_onRefresh = () => {
let canRefresh;
if (this.lastRefresh !== undefined)
canRefresh = (new Date().getTime() - this.lastRefresh.getTime()) / 1000 > this.minTimeBetweenRefresh;
@ -153,10 +127,25 @@ export default class FetchedDataSectionList extends React.Component<Props, State
if (canRefresh) {
this.setState({refreshing: true});
this.webDataManager.readData()
.then(this.onFetchSuccess)
.catch(this.onFetchError);
.then((fetchedData) => {
this.setState({
fetchedData: fetchedData,
refreshing: false,
firstLoading: false
});
this.lastRefresh = new Date();
})
.catch(() => {
this.setState({
fetchedData: {},
refreshing: false,
firstLoading: false
});
this.webDataManager.showUpdateToast(this.getUpdateToastTranslations()[0], this.getUpdateToastTranslations()[1]);
});
}
}
};
/**
* Get the render item to be used for display in the list.
@ -164,9 +153,10 @@ export default class FetchedDataSectionList extends React.Component<Props, State
*
* @param item
* @param section
* @param data
* @return {*}
*/
getRenderItem(item: Object, section: Object) {
getRenderItem(item: Object, section: Object, data: Object) {
return <View/>;
}
@ -232,11 +222,6 @@ export default class FetchedDataSectionList extends React.Component<Props, State
return [];
}
datasetKeyExtractor(item: Object) {
return item.text
}
/**
* Create the dataset when no fetched data is available.
* No need to be overridden, has good defaults.
@ -258,7 +243,7 @@ export default class FetchedDataSectionList extends React.Component<Props, State
'access-point-network-off'
}
],
keyExtractor: this.datasetKeyExtractor,
keyExtractor: (item: Object) => item.text,
}
];
}
@ -290,19 +275,6 @@ export default class FetchedDataSectionList extends React.Component<Props, State
return true;
}
renderSectionHeader(isEmpty: boolean, {section: {title}} : Object) {
return isEmpty ?
<View/> :
this.getRenderSectionHeader(title)
}
renderItem(isEmpty: boolean, {item, section}: Object) {
return isEmpty ?
this.getEmptyRenderItem(item.text, item.isSpinner, item.icon) :
this.getRenderItem(item, section)
}
/**
* Get the section list render using the generated dataset
*
@ -320,11 +292,19 @@ export default class FetchedDataSectionList extends React.Component<Props, State
refreshControl={
<RefreshControl
refreshing={this.state.refreshing}
onRefresh={this.onRefresh}
onRefresh={this._onRefresh}
/>
}
renderSectionHeader={isEmpty ? this.renderSectionHeaderEmpty : this.renderSectionHeaderNotEmpty}
renderItem={isEmpty ? this.renderItemEmpty : this.renderItemNotEmpty}
renderSectionHeader={({section: {title}}) =>
isEmpty ?
<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%'}}
contentContainerStyle={
isEmpty ?
@ -371,12 +351,11 @@ export default class FetchedDataSectionList extends React.Component<Props, State
}
render() {
// console.log("rendering FetchedDataSectionList");
const nav = this.props.navigation;
const dataset = this.createDataset(this.state.fetchedData);
return (
<BaseContainer
navigation={this.props.navigation}
headerTitle={this.getHeaderTranslation()}
navigation={nav} headerTitle={this.getHeaderTranslation()}
headerRightButton={this.getRightButton()}
hasTabs={this.hasTabs()}
hasBackButton={this.hasBackButton()}
@ -396,4 +375,5 @@ export default class FetchedDataSectionList extends React.Component<Props, State
</BaseContainer>
);
}
}

View file

@ -30,8 +30,6 @@ export default class SideBar extends React.Component<Props, State> {
active: 'Home',
};
getRenderItem: Function;
/**
* Generate the datasets
*
@ -40,6 +38,7 @@ export default class SideBar extends React.Component<Props, State> {
constructor(props: Props) {
super(props);
// Dataset used to render the drawer
// If the link field is defined, clicking on the item will open the link
this.dataSet = [
{
name: i18n.t('sidenav.divider1'),
@ -104,34 +103,21 @@ export default class SideBar extends React.Component<Props, State> {
icon: "information",
},
];
this.getRenderItem = this.getRenderItem.bind(this);
}
shouldComponentUpdate(nextProps: Props, nextState: State): boolean {
return nextState.active !== this.state.active;
}
onListItemPress(route: string) {
this.props.navigation.navigate(route);
}
listKeyExtractor(item: Object) {
return item.route;
}
getRenderItem({item}: Object) {
const onListItemPress = this.onListItemPress.bind(this, item.route);
getRenderItem(item: Object) {
if (item.icon !== undefined) {
return (
<ListItem
button
noBorder
selected={this.state.active === item.route}
onPress={onListItemPress}
onPress={() => {
if (item.link !== undefined)
Linking.openURL(item.link).catch((err) => console.error('Error opening link', err));
else
this.navigateToScreen(item.route);
}}
>
<Left>
<CustomMaterialIcon
@ -169,8 +155,15 @@ export default class SideBar extends React.Component<Props, State> {
}
/**
* Navigate to the selected route
* @param route {string} The route name to navigate to
*/
navigateToScreen(route: string) {
this.props.navigation.navigate(route);
};
render() {
// console.log("rendering SideBar");
return (
<Container style={{
backgroundColor: ThemeManager.getCurrentThemeVariables().sideMenuBgColor,
@ -179,8 +172,8 @@ export default class SideBar extends React.Component<Props, State> {
<FlatList
data={this.dataSet}
extraData={this.state}
keyExtractor={this.listKeyExtractor}
renderItem={this.getRenderItem}
keyExtractor={(item) => item.route}
renderItem={({item}) => this.getRenderItem(item)}
/>
</Container>
);

View file

@ -35,21 +35,6 @@ export default class WebViewScreen extends React.Component<Props> {
};
webviewArray: Array<WebView> = [];
onRefreshClicked: Function;
onWebviewRef: Function;
onGoBackWebview: Function;
onGoForwardWebview: Function;
onOpenWebLink: Function;
constructor() {
super();
this.onRefreshClicked = this.onRefreshClicked.bind(this);
this.onWebviewRef = this.onWebviewRef.bind(this);
this.onGoBackWebview = this.onGoBackWebview.bind(this);
this.onGoForwardWebview = this.onGoForwardWebview.bind(this);
this.onOpenWebLink = this.onOpenWebLink.bind(this);
}
openWebLink(url: string) {
Linking.openURL(url).catch((err) => console.error('Error opening link', err));
}
@ -58,7 +43,7 @@ export default class WebViewScreen extends React.Component<Props> {
return (
<Touchable
style={{padding: 6}}
onPress={clickAction}>
onPress={() => clickAction()}>
<CustomMaterialIcon
color={Platform.OS === 'ios' ? ThemeManager.getCurrentThemeVariables().brandPrimary : "#fff"}
icon={icon}/>
@ -69,62 +54,36 @@ export default class WebViewScreen extends React.Component<Props> {
getRefreshButton() {
return (
<View style={{flexDirection: 'row'}}>
{this.getHeaderButton(this.onRefreshClicked, 'refresh')}
{this.getHeaderButton(() => this.refreshWebview(), 'refresh')}
</View>
);
};
onRefreshClicked() {
refreshWebview() {
for (let view of this.webviewArray) {
if (view !== null)
view.reload();
}
}
onGoBackWebview() {
goBackWebview() {
for (let view of this.webviewArray) {
if (view !== null)
view.goBack();
}
}
onGoForwardWebview() {
goForwardWebview() {
for (let view of this.webviewArray) {
if (view !== null)
view.goForward();
}
}
onOpenWebLink() {
this.openWebLink(this.props.data[0]['url'])
}
onWebviewRef(ref: WebView) {
this.webviewArray.push(ref)
}
getRenderLoading() {
return (
<View style={{
backgroundColor: ThemeManager.getCurrentThemeVariables().containerBgColor,
position: 'absolute',
top: 0,
right: 0,
width: '100%',
height: '100%',
flex: 1,
alignItems: 'center',
justifyContent: 'center'
}}>
<Spinner/>
</View>
);
}
getWebview(obj: Object) {
return (
<WebView
ref={this.onWebviewRef}
ref={ref => (this.webviewArray.push(ref))}
source={{uri: obj['url']}}
style={{
width: '100%',
@ -133,7 +92,21 @@ export default class WebViewScreen extends React.Component<Props> {
startInLoadingState={true}
injectedJavaScript={obj['customJS']}
javaScriptEnabled={true}
renderLoading={this.getRenderLoading}
renderLoading={() =>
<View style={{
backgroundColor: ThemeManager.getCurrentThemeVariables().containerBgColor,
position: 'absolute',
top: 0,
right: 0,
width: '100%',
height: '100%',
flex: 1,
alignItems: 'center',
justifyContent: 'center'
}}>
<Spinner/>
</View>
}
/>
);
}
@ -160,7 +133,6 @@ export default class WebViewScreen extends React.Component<Props> {
}
render() {
// console.log("rendering WebViewScreen");
const nav = this.props.navigation;
this.webviewArray = [];
return (
@ -194,7 +166,7 @@ export default class WebViewScreen extends React.Component<Props> {
<Left style={{
paddingLeft: 6,
}}>
{this.getHeaderButton(this.onOpenWebLink, 'open-in-new')}
{this.getHeaderButton(() => this.openWebLink(this.props.data[0]['url']), 'open-in-new')}
</Left>
<Body/>
<Right style={{
@ -207,8 +179,8 @@ export default class WebViewScreen extends React.Component<Props> {
marginRight: 0,
marginLeft: 'auto'
}}>
{this.getHeaderButton(this.onGoBackWebview, 'chevron-left')}
{this.getHeaderButton(this.onGoForwardWebview, 'chevron-right')}
{this.getHeaderButton(() => this.goBackWebview(), 'chevron-left')}
{this.getHeaderButton(() => this.goForwardWebview(), 'chevron-right')}
</View>
</Right>
</Footer> : <View/>}

View file

@ -187,14 +187,9 @@ export default class AboutScreen extends React.Component<Props, State> {
},
];
getCardItem: Function;
getMainCard: Function;
constructor(props: any) {
super(props);
this.modalRef = React.createRef();
this.getCardItem = this.getCardItem.bind(this);
this.getMainCard = this.getMainCard.bind(this);
}
getAppCard() {
@ -215,8 +210,10 @@ export default class AboutScreen extends React.Component<Props, State> {
data={this.appData}
extraData={this.state}
keyExtractor={(item) => item.icon}
listKey={"app"}
renderItem={this.getCardItem}
listKey={(item) => "app"}
renderItem={({item}) =>
this.getCardItem(item.onPressCallback, item.icon, item.text, item.showChevron, item.showOnlyDebug)
}
/>
</Card>
);
@ -244,8 +241,10 @@ export default class AboutScreen extends React.Component<Props, State> {
data={this.authorData}
extraData={this.state}
keyExtractor={(item) => item.icon}
listKey={"team1"}
renderItem={this.getCardItem}
listKey={(item) => "team1"}
renderItem={({item}) =>
this.getCardItem(item.onPressCallback, item.icon, item.text, item.showChevron, item.showOnlyDebug)
}
/>
<CardItem header>
<Text>{i18n.t('aboutScreen.additionalDev')}</Text>
@ -254,8 +253,10 @@ export default class AboutScreen extends React.Component<Props, State> {
data={this.additionalDevData}
extraData={this.state}
keyExtractor={(item) => item.icon}
listKey={"team2"}
renderItem={this.getCardItem}
listKey={(item) => "team2"}
renderItem={({item}) =>
this.getCardItem(item.onPressCallback, item.icon, item.text, item.showChevron, item.showOnlyDebug)
}
/>
</Card>
);
@ -271,8 +272,10 @@ export default class AboutScreen extends React.Component<Props, State> {
data={this.technoData}
extraData={this.state}
keyExtractor={(item) => item.icon}
listKey={"techno"}
renderItem={this.getCardItem}
listKey={(item) => "techno"}
renderItem={({item}) =>
this.getCardItem(item.onPressCallback, item.icon, item.text, item.showChevron, item.showOnlyDebug)
}
/>
</Card>
);
@ -281,19 +284,24 @@ export default class AboutScreen extends React.Component<Props, State> {
/**
* Get a clickable card item to be rendered inside a card.
*
* @param onPressCallback The callback to use when the item is clicked
* @param icon The icon name to use from MaterialCommunityIcons
* @param text The text to show
* @param showChevron Whether to show a chevron indicating this button will change screen
* @param showOnlyInDebug Should we show te current item only in debug mode?
* @returns {React.Node}
*/
getCardItem({item}: Object) {
let shouldShow = !item.showOnlyInDebug || (item.showOnlyInDebug && this.state.isDebugUnlocked);
getCardItem(onPressCallback: Function, icon: string, text: string, showChevron: boolean, showOnlyInDebug: boolean) {
let shouldShow = !showOnlyInDebug || (showOnlyInDebug && this.state.isDebugUnlocked);
if (shouldShow) {
return (
<CardItem button
onPress={item.onPressCallback}>
onPress={onPressCallback}>
<Left>
<CustomMaterialIcon icon={item.icon}/>
<Text>{item.text}</Text>
<CustomMaterialIcon icon={icon}/>
<Text>{text}</Text>
</Left>
{item.showChevron ?
{showChevron ?
<Right>
<CustomMaterialIcon icon="chevron-right"
fontSize={20}/>
@ -323,8 +331,6 @@ export default class AboutScreen extends React.Component<Props, State> {
}
getBugReportModal() {
const onPressMail = openWebLink.bind(this, links.bugsMail);
const onPressGit = openWebLink.bind(this, links.bugsGit);
return (
<Modalize ref={this.modalRef}
adjustToContentHeight
@ -343,7 +349,7 @@ export default class AboutScreen extends React.Component<Props, State> {
marginLeft: 'auto',
marginRight: 'auto',
}}
onPress={onPressMail}>
onPress={() => openWebLink(links.bugsMail)}>
<CustomMaterialIcon
icon={'email'}
color={'#fff'}/>
@ -355,7 +361,7 @@ export default class AboutScreen extends React.Component<Props, State> {
marginLeft: 'auto',
marginRight: 'auto',
}}
onPress={onPressGit}>
onPress={() => openWebLink(links.bugsGit)}>
<CustomMaterialIcon
icon={'git'}
color={'#fff'}/>
@ -372,7 +378,7 @@ export default class AboutScreen extends React.Component<Props, State> {
}
}
getMainCard({item}: Object) {
getMainCard(item: Object) {
switch (item.id) {
case 'app':
return this.getAppCard();
@ -395,7 +401,9 @@ export default class AboutScreen extends React.Component<Props, State> {
data={this.dataOrder}
extraData={this.state}
keyExtractor={(item) => item.id}
renderItem={this.getMainCard}
renderItem={({item}) =>
this.getMainCard(item)
}
/>
</Container>
);

View file

@ -38,33 +38,8 @@ function openWebLink(link) {
*/
export default class HomeScreen extends FetchedDataSectionList {
onProxiwashClick: Function;
onTutorInsaClick: Function;
onMenuClick: Function;
onProximoClick: Function;
constructor() {
super(DATA_URL, REFRESH_TIME);
this.onProxiwashClick = this.onProxiwashClick.bind(this);
this.onTutorInsaClick = this.onTutorInsaClick.bind(this);
this.onMenuClick = this.onMenuClick.bind(this);
this.onProximoClick = this.onProximoClick.bind(this);
}
onProxiwashClick() {
this.props.navigation.navigate('Proxiwash');
}
onTutorInsaClick() {
this.props.navigation.navigate('TutorInsaScreen');
}
onProximoClick() {
this.props.navigation.navigate('Proximo');
}
onMenuClick() {
this.props.navigation.navigate('SelfMenuScreen');
}
/**
@ -314,14 +289,6 @@ export default class HomeScreen extends FetchedDataSectionList {
}
clickAction(isAvailable: boolean, displayEvent: Object) {
if (isAvailable)
this.props.navigation.navigate('PlanningDisplayScreen', {data: displayEvent});
else
this.props.navigation.navigate('PlanningScreen');
};
getDashboardEventItem(content: Array<Object>) {
let icon = 'calendar-range';
let color = ThemeManager.getCurrentThemeVariables().planningColor;
@ -343,6 +310,12 @@ export default class HomeScreen extends FetchedDataSectionList {
</Text>;
} else
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);
@ -351,7 +324,7 @@ export default class HomeScreen extends FetchedDataSectionList {
subtitle={subtitle}
color={color}
icon={icon}
clickAction={this.clickAction.bind(this, isAvailable, displayEvent)}
clickAction={() => clickAction()}
title={title}
isAvailable={isAvailable}
displayEvent={displayEvent}
@ -382,6 +355,7 @@ export default class HomeScreen extends FetchedDataSectionList {
</Text>;
} else
proximoSubtitle = i18n.t('homeScreen.dashboard.proximoSubtitleNA');
let proximoClickAction = () => this.props.navigation.navigate('Proximo');
let menuIcon = 'silverware-fork-knife';
@ -393,6 +367,7 @@ export default class HomeScreen extends FetchedDataSectionList {
menuSubtitle = i18n.t('homeScreen.dashboard.menuSubtitle');
} else
menuSubtitle = i18n.t('homeScreen.dashboard.menuSubtitleNA');
let menuClickAction = () => this.props.navigation.navigate('SelfMenuScreen');
return (
<View style={{
flexDirection: 'row',
@ -404,7 +379,7 @@ export default class HomeScreen extends FetchedDataSectionList {
subtitle={menuSubtitle}
color={menuColor}
icon={menuIcon}
clickAction={this.onMenuClick}
clickAction={() => menuClickAction()}
title={menuTitle}
isAvailable={isMenuAvailable}
isSquareLeft={true}/>
@ -413,14 +388,13 @@ export default class HomeScreen extends FetchedDataSectionList {
subtitle={proximoSubtitle}
color={proximoColor}
icon={proximoIcon}
clickAction={this.onProximoClick}
clickAction={() => proximoClickAction()}
title={proximoTitle}
isAvailable={isProximoAvailable}/>
</View>
);
}
getDashboardMiddleItem(content: Array<Object>) {
let proxiwashData = content[0]['data'];
let tutorinsaData = content[1]['data'];
@ -475,6 +449,7 @@ export default class HomeScreen extends FetchedDataSectionList {
</Text>;
} else
proxiwashSubtitle = i18n.t('homeScreen.dashboard.proxiwashSubtitleNA');
let proxiwashClickAction = () => this.props.navigation.navigate('Proxiwash');
let tutorinsaIcon = 'school';
let tutorinsaColor = ThemeManager.getCurrentThemeVariables().tutorinsaColor;
@ -495,6 +470,7 @@ export default class HomeScreen extends FetchedDataSectionList {
</Text>;
} else
tutorinsaSubtitle = i18n.t('homeScreen.dashboard.tutorinsaSubtitleNA');
let tutorinsaClickAction = () => this.props.navigation.navigate('TutorInsaScreen');
return (
<View style={{
@ -507,7 +483,7 @@ export default class HomeScreen extends FetchedDataSectionList {
subtitle={proxiwashSubtitle}
color={proxiwashColor}
icon={proxiwashIcon}
clickAction={this.onProxiwashClick}
clickAction={() => proxiwashClickAction()}
title={proxiwashTitle}
isAvailable={proxiwashIsAvailable}
isSquareLeft={true}/>
@ -516,7 +492,7 @@ export default class HomeScreen extends FetchedDataSectionList {
subtitle={tutorinsaSubtitle}
color={tutorinsaColor}
icon={tutorinsaIcon}
clickAction={this.onTutorInsaClick}
clickAction={() => tutorinsaClickAction()}
title={tutorinsaTitle}
isAvailable={tutorinsaIsAvailable}/>
</View>
@ -524,7 +500,7 @@ export default class HomeScreen extends FetchedDataSectionList {
}
getRenderItem(item: Object, section: Object) {
getRenderItem(item: Object, section: Object, data: Object) {
return (
section['id'] === SECTIONS_ID[0] ? this.getDashboardItem(item) :
<Card style={{
@ -549,7 +525,7 @@ export default class HomeScreen extends FetchedDataSectionList {
}}>
<Body>
{item.full_picture !== '' && item.full_picture !== undefined ?
<TouchableOpacity onPress={openWebLink.bind(null, item.full_picture)}
<TouchableOpacity onPress={() => openWebLink(item.full_picture)}
style={{width: '100%', height: 250, marginBottom: 5}}>
<Image source={{uri: item.full_picture}}
style={{flex: 1, resizeMode: "contain"}}
@ -571,7 +547,7 @@ export default class HomeScreen extends FetchedDataSectionList {
}}>
<Left>
<Button transparent
onPress={openWebLink.bind(null, item.permalink_url)}>
onPress={() => openWebLink(item.permalink_url)}>
<CustomMaterialIcon
icon="facebook"
color="#57aeff"

View file

@ -8,12 +8,13 @@ import ThemeManager from "../utils/ThemeManager";
import HTML from "react-native-render-html";
import {Linking} from "expo";
import PlanningEventManager from '../utils/PlanningEventManager';
import i18n from 'i18n-js';
type Props = {
navigation: Object,
};
function openWebLink(event, link) {
function openWebLink(link) {
Linking.openURL(link).catch((err) => console.error('Error opening link', err));
}
@ -21,8 +22,8 @@ function openWebLink(event, link) {
* 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> {
render() {
// console.log("rendering planningDisplayScreen");
const nav = this.props.navigation;
const displayData = nav.getParam('data', []);
return (
@ -59,7 +60,7 @@ export default class PlanningDisplayScreen extends React.Component<Props> {
},
div: {color: ThemeManager.getCurrentThemeVariables().textColor}
}}
onLinkPress={openWebLink}/>
onLinkPress={(event, link) => openWebLink(link)}/>
: <View/>}
</Content>
</Container>

View file

@ -5,6 +5,7 @@ import {BackHandler, Image} from 'react-native';
import {H3, Text, View} from 'native-base';
import i18n from "i18n-js";
import ThemeManager from "../utils/ThemeManager";
import {Linking} from "expo";
import BaseContainer from "../components/BaseContainer";
import {Agenda, LocaleConfig} from 'react-native-calendars';
import Touchable from 'react-native-platform-touchable';
@ -34,6 +35,14 @@ const FETCH_URL = "https://amicale-insat.fr/event/json/list";
const AGENDA_MONTH_SPAN = 6;
/**
* Opens a link in the device's browser
* @param link The link to open
*/
function openWebLink(link) {
Linking.openURL(link).catch((err) => console.error('Error opening link', err));
}
/**
* Class defining the app's planning screen
*/
@ -47,21 +56,12 @@ export default class PlanningScreen extends React.Component<Props, State> {
didFocusSubscription: Function;
willBlurSubscription: Function;
state = {
refreshing: false,
agendaItems: {},
calendarShowing: false,
};
onRefresh: Function;
onCalendarToggled: Function;
getRenderItem: Function;
getRenderEmptyDate: Function;
onAgendaRef: Function;
onCalendarToggled: Function;
onBackButtonPressAndroid: Function;
constructor(props: any) {
super(props);
this.webDataManager = new WebDataManager(FETCH_URL);
@ -76,25 +76,10 @@ export default class PlanningScreen extends React.Component<Props, State> {
if (i18n.currentLocale().startsWith("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.onAgendaRef = this.onAgendaRef.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() {
this.onRefresh();
this._onRefresh();
this.willBlurSubscription = this.props.navigation.addListener(
'willBlur',
() =>
@ -105,7 +90,7 @@ export default class PlanningScreen extends React.Component<Props, State> {
);
}
onBackButtonPressAndroid() {
onBackButtonPressAndroid = () => {
if (this.state.calendarShowing) {
this.agendaRef.chooseDay(this.agendaRef.state.selectedDay);
return true;
@ -141,6 +126,10 @@ export default class PlanningScreen extends React.Component<Props, State> {
}
getRenderItem(item: Object) {
let navData = {
data: item
};
const nav = this.props.navigation;
return (
<Touchable
style={{
@ -149,7 +138,7 @@ export default class PlanningScreen extends React.Component<Props, State> {
marginRight: 10,
marginTop: 17,
}}
onPress={() => this.props.navigation.navigate('PlanningDisplayScreen', {data: item})}>
onPress={() => nav.navigate('PlanningDisplayScreen', navData)}>
<View style={{
padding: 10,
flex: 1,
@ -211,7 +200,7 @@ export default class PlanningScreen extends React.Component<Props, State> {
* Refresh data and show a toast if any error occurred
* @private
*/
onRefresh = () => {
_onRefresh = () => {
let canRefresh;
if (this.lastRefresh !== undefined)
canRefresh = (new Date().getTime() - this.lastRefresh.getTime()) / 1000 > this.minTimeBetweenRefresh;
@ -232,7 +221,7 @@ export default class PlanningScreen extends React.Component<Props, State> {
this.setState({
refreshing: false,
});
// console.log(err);
console.log(err);
});
}
};
@ -263,46 +252,38 @@ export default class PlanningScreen extends React.Component<Props, State> {
}
}
onAgendaRef(ref: Agenda) {
this.agendaRef = ref;
}
onCalendarToggled(isCalendarOpened: boolean) {
this.setState({calendarShowing: isCalendarOpened});
}
currentDate = this.getCurrentDate();
render() {
// console.log("rendering PlanningScreen");
const nav = this.props.navigation;
return (
<BaseContainer navigation={this.props.navigation} headerTitle={i18n.t('screens.planning')}>
<BaseContainer navigation={nav} headerTitle={i18n.t('screens.planning')}>
<Agenda
// 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
// considered that the date in question is not yet loaded
items={this.state.agendaItems}
// initially selected day
selected={this.currentDate}
selected={this.getCurrentDate()}
// Minimum date that can be selected, dates before minDate will be grayed out. Default = undefined
minDate={this.currentDate}
minDate={this.getCurrentDate()}
// Max amount of months allowed to scroll to the past. Default = 50
pastScrollRange={1}
// Max amount of months allowed to scroll to the future. Default = 50
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.
onRefresh={this.onRefresh}
onRefresh={() => this._onRefresh()}
// callback that fires when the calendar is opened or closed
onCalendarToggled={this.onCalendarToggled}
onCalendarToggled={(calendarOpened) => {
this.setState({calendarShowing: calendarOpened})
}}
// Set this true while waiting for new data from a refresh
refreshing={this.state.refreshing}
renderItem={this.getRenderItem}
renderEmptyDate={this.getRenderEmptyDate}
rowHasChanged={this.rowHasChanged}
renderItem={(item) => this.getRenderItem(item)}
renderEmptyDate={() => this.getRenderEmptyDate()}
rowHasChanged={() => this.rowHasChanged()}
// If firstDay=1 week starts from Monday. Note that dayNames and dayNamesShort should still start from Sunday.
firstDay={1}
// ref to this agenda in order to handle back button event
ref={this.onAgendaRef}
ref={(ref) => this.agendaRef = ref}
// agenda theme
theme={{
backgroundColor: ThemeManager.getCurrentThemeVariables().agendaBackgroundColor,

View file

@ -1,7 +1,7 @@
// @flow
import * as React from 'react';
import {Image, View} from 'react-native';
import {Image, Linking, View} from 'react-native';
import {Card, CardItem, Container, Content, H2, Left, Text} from 'native-base';
import CustomHeader from "../../components/CustomHeader";
import i18n from "i18n-js";

View file

@ -70,28 +70,12 @@ export default class ProximoListScreen extends React.Component<Props, State> {
sortNameIcon: '',
modalCurrentDisplayItem: {},
};
sortMenuRef: Menu;
onMenuRef: Function;
onSearchStringChange: Function;
onSelectSortModeName: Function;
onSelectSortModePrice: Function;
onSortMenuPress: Function;
renderItem: Function;
onListItemPress: Function;
_menu: Menu;
constructor(props: any) {
super(props);
this.modalRef = React.createRef();
this.originalData = this.navData['data'];
this.onMenuRef = this.onMenuRef.bind(this);
this.onSearchStringChange = this.onSearchStringChange.bind(this);
this.onSelectSortModeName = this.onSelectSortModeName.bind(this);
this.onSelectSortModePrice = this.onSelectSortModePrice.bind(this);
this.onSortMenuPress = this.onSortMenuPress.bind(this);
this.renderItem = this.renderItem.bind(this);
this.onListItemPress = this.onListItemPress.bind(this);
}
/**
@ -99,8 +83,8 @@ export default class ProximoListScreen extends React.Component<Props, State> {
*
* @param ref The menu reference
*/
onMenuRef(ref: Menu) {
this.sortMenuRef = ref;
setMenuRef = (ref: Menu) => {
this._menu = ref;
};
/**
@ -147,7 +131,7 @@ export default class ProximoListScreen extends React.Component<Props, State> {
break;
}
this.setupSortIcons(mode, isReverse);
this.sortMenuRef.hide();
this._menu.hide();
}
/**
@ -230,7 +214,7 @@ export default class ProximoListScreen extends React.Component<Props, State> {
return filteredData;
}
onSearchStringChange(str: string) {
search(str: string) {
this.setState({
currentlyDisplayedData: this.filterData(str)
})
@ -267,7 +251,7 @@ export default class ProximoListScreen extends React.Component<Props, State> {
);
}
onListItemPress(item: Object) {
showItemDetails(item: Object) {
this.setState({
modalCurrentDisplayItem: item
});
@ -276,27 +260,16 @@ export default class ProximoListScreen extends React.Component<Props, State> {
}
}
onSelectSortModeName() {
this.sortModeSelected(sortMode.name);
}
onSelectSortModePrice() {
this.sortModeSelected(sortMode.price);
}
onSortMenuPress() {
this.sortMenuRef.show();
}
getSortMenu() {
return (
<Menu
ref={this.onMenuRef}
ref={this.setMenuRef}
button={
<Touchable
style={{padding: 6}}
onPress={this.onSortMenuPress}>
onPress={() =>
this._menu.show()
}>
<CustomMaterialIcon
color={Platform.OS === 'ios' ? ThemeManager.getCurrentThemeVariables().brandPrimary : "#fff"}
icon={'sort'}/>
@ -304,12 +277,12 @@ export default class ProximoListScreen extends React.Component<Props, State> {
}
>
<MenuItem
onPress={this.onSelectSortModeName}>
onPress={() => this.sortModeSelected(sortMode.name)}>
{this.state.sortNameIcon}
{i18n.t('proximoScreen.sortName')}
</MenuItem>
<MenuItem
onPress={this.onSelectSortModePrice}>
onPress={() => this.sortModeSelected(sortMode.price)}>
{this.state.sortPriceIcon}
{i18n.t('proximoScreen.sortPrice')}
</MenuItem>
@ -317,39 +290,7 @@ export default class ProximoListScreen extends React.Component<Props, State> {
);
}
renderItem({item}: Object) {
return (<ListItem
thumbnail
onPress={this.onListItemPress}
>
<Left>
<Thumbnail square source={{uri: item.image}}/>
</Left>
<Body>
<Text style={{marginLeft: 20}}>
{item.name}
</Text>
<Text note style={{
marginLeft: 20,
color: this.getStockColor(parseInt(item.quantity))
}}>
{item.quantity + ' ' + i18n.t('proximoScreen.inStock')}
</Text>
</Body>
<Right>
<Text style={{fontWeight: "bold"}}>
{item.price}
</Text>
</Right>
</ListItem>);
}
keyExtractor(item: Object) {
return item.name + item.code;
}
render() {
// console.log("rendering ProximoListScreen");
const nav = this.props.navigation;
return (
<Container>
@ -362,7 +303,7 @@ export default class ProximoListScreen extends React.Component<Props, State> {
hasBackButton={true}
navigation={nav}
hasSearchField={true}
searchCallback={this.onSearchStringChange}
searchCallback={(text) => this.search(text)}
shouldFocusSearchBar={this.shouldFocusSearchBar}
rightButton={this.getSortMenu()}
/>
@ -370,9 +311,35 @@ export default class ProximoListScreen extends React.Component<Props, State> {
<FlatList
data={this.state.currentlyDisplayedData}
extraData={this.state.currentlyDisplayedData}
keyExtractor={this.keyExtractor}
keyExtractor={(item) => item.name + item.code}
style={{minHeight: 300, width: '100%'}}
renderItem={this.renderItem}
renderItem={({item}) =>
<ListItem
thumbnail
onPress={() => {
this.showItemDetails(item);
}}
>
<Left>
<Thumbnail square source={{uri: item.image}}/>
</Left>
<Body>
<Text style={{marginLeft: 20}}>
{item.name}
</Text>
<Text note style={{
marginLeft: 20,
color: this.getStockColor(parseInt(item.quantity))
}}>
{item.quantity + ' ' + i18n.t('proximoScreen.inStock')}
</Text>
</Body>
<Right>
<Text style={{fontWeight: "bold"}}>
{item.price}
</Text>
</Right>
</ListItem>}
/>
</Container>
);

View file

@ -18,13 +18,8 @@ const DATA_URL = "https://etud.insa-toulouse.fr/~proximo/data/stock-v2.json";
*/
export default class ProximoMainScreen extends FetchedDataSectionList {
onPressSearchBtn: Function;
onPressAboutBtn: Function;
constructor() {
super(DATA_URL, 0);
this.onPressSearchBtn = this.onPressSearchBtn.bind(this);
this.onPressAboutBtn = this.onPressAboutBtn.bind(this);
}
static sortFinalData(a: Object, b: Object) {
@ -119,7 +114,7 @@ export default class ProximoMainScreen extends FetchedDataSectionList {
return availableArticles;
}
onPressSearchBtn() {
getRightButton() {
let searchScreenData = {
shouldFocusSearchBar: true,
data: {
@ -132,14 +127,8 @@ export default class ProximoMainScreen extends FetchedDataSectionList {
this.getAvailableArticles(this.state.fetchedData.articles, undefined) : []
},
};
this.props.navigation.navigate('ProximoListScreen', searchScreenData);
}
onPressAboutBtn() {
this.props.navigation.navigate('ProximoAboutScreen');
}
getRightButton() {
return (
<View
style={{
@ -147,14 +136,14 @@ export default class ProximoMainScreen extends FetchedDataSectionList {
}}>
<Touchable
style={{padding: 6}}
onPress={this.onPressSearchBtn}>
onPress={() => this.props.navigation.navigate('ProximoListScreen', searchScreenData)}>
<CustomMaterialIcon
color={Platform.OS === 'ios' ? ThemeManager.getCurrentThemeVariables().brandPrimary : "#fff"}
icon="magnify"/>
</Touchable>
<Touchable
style={{padding: 6}}
onPress={this.onPressAboutBtn}>
onPress={() => this.props.navigation.navigate('ProximoAboutScreen')}>
<CustomMaterialIcon
color={Platform.OS === 'ios' ? ThemeManager.getCurrentThemeVariables().brandPrimary : "#fff"}
icon="information"/>
@ -163,18 +152,19 @@ export default class ProximoMainScreen extends FetchedDataSectionList {
);
}
getRenderItem(item: Object, section: Object) {
getRenderItem(item: Object, section: Object, data: Object) {
let dataToSend = {
shouldFocusSearchBar: false,
data: item,
};
const onPress = this.props.navigation.navigate.bind(this, 'ProximoListScreen', dataToSend);
if (item.data.length > 0) {
return (
<ListItem
button
thumbnail
onPress={onPress}
onPress={() => {
this.props.navigation.navigate('ProximoListScreen', dataToSend);
}}
>
<Left>
<CustomMaterialIcon

View file

@ -36,8 +36,6 @@ const REFRESH_TIME = 1000 * 10; // Refresh every 10 seconds
*/
export default class ProxiwashScreen extends FetchedDataSectionList {
onAboutPress: Function;
/**
* Creates machine state parameters using current theme and translations
*/
@ -77,8 +75,6 @@ export default class ProxiwashScreen extends FetchedDataSectionList {
machinesWatched: [],
};
this.setMinTimeRefresh(30);
this.onAboutPress = this.onAboutPress.bind(this);
}
/**
@ -86,6 +82,7 @@ export default class ProxiwashScreen extends FetchedDataSectionList {
*/
componentDidMount() {
super.componentDidMount();
if (AsyncStorageManager.getInstance().preferences.expoToken.current !== '') {
// Get latest watchlist from server
NotificationsManager.getMachineNotificationWatchlist((fetchedList) => {
@ -244,14 +241,13 @@ export default class ProxiwashScreen extends FetchedDataSectionList {
showAlert(title: string, item: Object, isDryer: boolean) {
let buttons = [{text: i18n.t("proxiwashScreen.modal.ok")}];
let message = modalStateStrings[MACHINE_STATES[item.state]];
const onPress = this.setupNotifications.bind(this, item.number);
if (MACHINE_STATES[item.state] === MACHINE_STATES["EN COURS"]) {
buttons = [
{
text: this.isMachineWatched(item.number) ?
i18n.t("proxiwashScreen.modal.disableNotifications") :
i18n.t("proxiwashScreen.modal.enableNotifications"),
onPress: onPress
onPress: () => this.setupNotifications(item.number)
},
{
text: i18n.t("proxiwashScreen.modal.cancel")
@ -276,15 +272,11 @@ export default class ProxiwashScreen extends FetchedDataSectionList {
);
}
onAboutPress() {
this.props.navigation.navigate('ProxiwashAboutScreen');
}
getRightButton(): * {
return (
<Touchable
style={{padding: 6}}
onPress={this.onAboutPress}>
onPress={() => this.props.navigation.navigate('ProxiwashAboutScreen')}>
<CustomMaterialIcon
color={Platform.OS === 'ios' ? ThemeManager.getCurrentThemeVariables().brandPrimary : "#fff"}
icon="information"/>
@ -297,13 +289,13 @@ export default class ProxiwashScreen extends FetchedDataSectionList {
*
* @param item The object containing the item's FetchedData
* @param section The object describing the current SectionList section
* @param data The full FetchedData used by the SectionList
* @returns {React.Node}
*/
getRenderItem(item: Object, section: Object) {
getRenderItem(item: Object, section: Object, data: Object) {
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 isDryer = section.title === i18n.t('proxiwashScreen.dryers');
const onPress = this.showAlert.bind(this, machineName, item, isDryer);
return (
<Card style={{
flex: 0,
@ -328,7 +320,7 @@ export default class ProxiwashScreen extends FetchedDataSectionList {
backgroundColor: ThemeManager.getCurrentThemeVariables().containerBgColor
}}/>
<PlatformTouchable
onPress={onPress}
onPress={() => this.showAlert(machineName, item, isDryer)}
style={{
height: 64,
position: 'absolute',

View file

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

View file

@ -43,17 +43,6 @@ export default class SettingsScreen extends React.Component<Props, State> {
startScreenPickerSelected: AsyncStorageManager.getInstance().preferences.defaultStartScreen.current,
};
onProxiwashNotifPickerValueChange: Function;
onStartScreenPickerValueChange: Function;
onToggleNightMode: Function;
constructor() {
super();
this.onProxiwashNotifPickerValueChange = this.onProxiwashNotifPickerValueChange.bind(this);
this.onStartScreenPickerValueChange = this.onStartScreenPickerValueChange.bind(this);
this.onToggleNightMode = this.onToggleNightMode.bind(this);
}
/**
* Get a list item using the specified control
*
@ -129,7 +118,7 @@ export default class SettingsScreen extends React.Component<Props, State> {
mode="dropdown"
style={{width: 120}}
selectedValue={this.state.proxiwashNotifPickerSelected}
onValueChange={this.onProxiwashNotifPickerValueChange}
onValueChange={(value) => this.onProxiwashNotifPickerValueChange(value)}
>
<Picker.Item label={i18n.t('settingsScreen.proxiwashNotifReminderPicker.never')} value="never"/>
<Picker.Item label={i18n.t('settingsScreen.proxiwashNotifReminderPicker.5')} value="5"/>
@ -152,7 +141,7 @@ export default class SettingsScreen extends React.Component<Props, State> {
mode="dropdown"
style={{width: 120}}
selectedValue={this.state.startScreenPickerSelected}
onValueChange={this.onStartScreenPickerValueChange}
onValueChange={(value) => this.onStartScreenPickerValueChange(value)}
>
<Picker.Item label={i18n.t('screens.home')} value="Home"/>
<Picker.Item label={i18n.t('screens.planning')} value="Planning"/>
@ -166,7 +155,7 @@ export default class SettingsScreen extends React.Component<Props, State> {
/**
* Toggle night mode and save it to preferences
*/
onToggleNightMode() {
toggleNightMode() {
ThemeManager.getInstance().setNightMode(!this.state.nightMode);
this.setState({nightMode: !this.state.nightMode});
this.resetStack();
@ -214,7 +203,7 @@ export default class SettingsScreen extends React.Component<Props, State> {
<Right>
<CheckBox
checked={this.state.nightMode}
onPress={onPressCallback}
onPress={() => this.toggleNightMode()}
style={{marginRight: 20}}/>
</Right>
</ListItem>
@ -232,7 +221,7 @@ export default class SettingsScreen extends React.Component<Props, State> {
<Text>{i18n.t('settingsScreen.generalCard')}</Text>
</CardItem>
<List>
{this.getToggleItem(this.onToggleNightMode, 'theme-light-dark', i18n.t('settingsScreen.nightMode'), i18n.t('settingsScreen.nightModeSub'))}
{this.getToggleItem(() => this.toggleNightMode(), 'theme-light-dark', i18n.t('settingsScreen.nightMode'), i18n.t('settingsScreen.nightModeSub'))}
{SettingsScreen.getGeneralItem(this.getStartScreenPicker(), 'power', i18n.t('settingsScreen.startScreen'), i18n.t('settingsScreen.startScreenSub'))}
</List>
</Card>

View file

@ -123,8 +123,18 @@ export default class NotificationsManager {
'Content-Type': 'application/json',
}),
body: JSON.stringify(data) // <-- Post parameters
});
})
.then((response) => response.json())
.then((responseJson) => {
callback(responseJson);
})
.catch((error) => {
console.log(error);
});
} else {
console.log('Expo token not available');
}
}
/**
@ -151,7 +161,16 @@ export default class NotificationsManager {
'Content-Type': 'application/json',
}),
body: JSON.stringify(data) // <-- Post parameters
});
})
.then((response) => response.text())
.then((responseText) => {
console.log(responseText);
})
.catch((error) => {
console.log(error);
});
} else {
console.log('Expo token not available');
}
}
@ -175,7 +194,16 @@ export default class NotificationsManager {
'Content-Type': 'application/json',
}),
body: JSON.stringify(data) // <-- Post parameters
});
})
.then((response) => response.text())
.then((responseText) => {
console.log(responseText);
})
.catch((error) => {
console.log(error);
});
} else {
console.log('Expo token not available');
}
}
}

View file

@ -25,8 +25,8 @@ export default class WebDataManager {
let response = await fetch(this.FETCH_URL);
fetchedData = await response.json();
} catch (error) {
// console.log('Could not read FetchedData from server');
// console.log(error);
console.log('Could not read FetchedData from server');
console.log(error);
throw new Error('Could not read FetchedData from server');
}
this.lastDataFetched = fetchedData;