forked from vergnet/application-amicale
Reworked section list to use react native design
This commit is contained in:
parent
f5702297f5
commit
b562357a95
10 changed files with 484 additions and 604 deletions
2
App.js
2
App.js
|
@ -14,6 +14,7 @@ import ThemeManager from './utils/ThemeManager';
|
||||||
import { NavigationContainer } from '@react-navigation/native';
|
import { NavigationContainer } from '@react-navigation/native';
|
||||||
import { createStackNavigator } from '@react-navigation/stack';
|
import { createStackNavigator } from '@react-navigation/stack';
|
||||||
import DrawerNavigator from './navigation/DrawerNavigator';
|
import DrawerNavigator from './navigation/DrawerNavigator';
|
||||||
|
import { enableScreens } from 'react-native-screens';
|
||||||
|
|
||||||
type Props = {};
|
type Props = {};
|
||||||
|
|
||||||
|
@ -38,6 +39,7 @@ export default class App extends React.Component<Props, State> {
|
||||||
constructor(props: Object) {
|
constructor(props: Object) {
|
||||||
super(props);
|
super(props);
|
||||||
LocaleManager.initTranslations();
|
LocaleManager.initTranslations();
|
||||||
|
enableScreens();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -8,7 +8,6 @@ import Touchable from 'react-native-platform-touchable';
|
||||||
import ThemeManager from "../utils/ThemeManager";
|
import ThemeManager from "../utils/ThemeManager";
|
||||||
import CustomMaterialIcon from "./CustomMaterialIcon";
|
import CustomMaterialIcon from "./CustomMaterialIcon";
|
||||||
import i18n from "i18n-js";
|
import i18n from "i18n-js";
|
||||||
import {NavigationActions} from 'react-navigation';
|
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
hasBackButton: boolean,
|
hasBackButton: boolean,
|
||||||
|
@ -105,8 +104,7 @@ export default class CustomHeader extends React.Component<Props> {
|
||||||
|
|
||||||
|
|
||||||
onPressBack() {
|
onPressBack() {
|
||||||
const backAction = NavigationActions.back();
|
this.props.navigation.goBack();
|
||||||
this.props.navigation.dispatch(backAction);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
|
|
@ -1,399 +0,0 @@
|
||||||
// @flow
|
|
||||||
|
|
||||||
import * as React from 'react';
|
|
||||||
import WebDataManager from "../utils/WebDataManager";
|
|
||||||
import {H3, Spinner, Tab, TabHeading, Tabs, Text} from "native-base";
|
|
||||||
import {RefreshControl, SectionList, View} from "react-native";
|
|
||||||
import CustomMaterialIcon from "./CustomMaterialIcon";
|
|
||||||
import i18n from 'i18n-js';
|
|
||||||
import ThemeManager from "../utils/ThemeManager";
|
|
||||||
import BaseContainer from "./BaseContainer";
|
|
||||||
|
|
||||||
type Props = {
|
|
||||||
navigation: Object,
|
|
||||||
}
|
|
||||||
|
|
||||||
type State = {
|
|
||||||
refreshing: boolean,
|
|
||||||
firstLoading: boolean,
|
|
||||||
fetchedData: Object,
|
|
||||||
machinesWatched: Array<string>,
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Class used to create a basic list view using online json data.
|
|
||||||
* Used by inheriting from it and redefining getters.
|
|
||||||
*/
|
|
||||||
export default class FetchedDataSectionList extends React.Component<Props, State> {
|
|
||||||
webDataManager: WebDataManager;
|
|
||||||
|
|
||||||
willFocusSubscription: function;
|
|
||||||
willBlurSubscription: function;
|
|
||||||
refreshInterval: IntervalID;
|
|
||||||
refreshTime: number;
|
|
||||||
lastRefresh: Date;
|
|
||||||
|
|
||||||
minTimeBetweenRefresh = 60;
|
|
||||||
state = {
|
|
||||||
refreshing: false,
|
|
||||||
firstLoading: true,
|
|
||||||
fetchedData: {},
|
|
||||||
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}
|
|
||||||
*/
|
|
||||||
getHeaderTranslation(): string {
|
|
||||||
return "Header";
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the translation for the toasts in the current language
|
|
||||||
* @return {string}
|
|
||||||
*/
|
|
||||||
getUpdateToastTranslations(): Array<string> {
|
|
||||||
return ["whoa", "nah"];
|
|
||||||
}
|
|
||||||
|
|
||||||
setMinTimeRefresh(value: number) {
|
|
||||||
this.minTimeBetweenRefresh = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Register react navigation events on first screen load.
|
|
||||||
* Allows to detect when the screen is focused
|
|
||||||
*/
|
|
||||||
componentDidMount() {
|
|
||||||
this.willFocusSubscription = this.props.navigation.addListener(
|
|
||||||
'willFocus', this.onScreenFocus.bind(this));
|
|
||||||
this.willBlurSubscription = this.props.navigation.addListener(
|
|
||||||
'willBlur', this.onScreenBlur.bind(this));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Refresh data when focusing the screen and setup a refresh interval if asked to
|
|
||||||
*/
|
|
||||||
onScreenFocus() {
|
|
||||||
this.onRefresh();
|
|
||||||
if (this.refreshTime > 0)
|
|
||||||
this.refreshInterval = setInterval(this.onRefresh.bind(this), this.refreshTime)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove any interval on un-focus
|
|
||||||
*/
|
|
||||||
onScreenBlur() {
|
|
||||||
clearInterval(this.refreshInterval);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Unregister from event when un-mounting components
|
|
||||||
*/
|
|
||||||
componentWillUnmount() {
|
|
||||||
if (this.willBlurSubscription !== undefined)
|
|
||||||
this.willBlurSubscription.remove();
|
|
||||||
if (this.willFocusSubscription !== undefined)
|
|
||||||
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() {
|
|
||||||
let canRefresh;
|
|
||||||
if (this.lastRefresh !== undefined)
|
|
||||||
canRefresh = (new Date().getTime() - this.lastRefresh.getTime()) / 1000 > this.minTimeBetweenRefresh;
|
|
||||||
else
|
|
||||||
canRefresh = true;
|
|
||||||
|
|
||||||
if (canRefresh) {
|
|
||||||
this.setState({refreshing: true});
|
|
||||||
this.webDataManager.readData()
|
|
||||||
.then(this.onFetchSuccess)
|
|
||||||
.catch(this.onFetchError);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the render item to be used for display in the list.
|
|
||||||
* Must be overridden by inheriting class.
|
|
||||||
*
|
|
||||||
* @param item
|
|
||||||
* @param section
|
|
||||||
* @return {*}
|
|
||||||
*/
|
|
||||||
getRenderItem(item: Object, section: Object) {
|
|
||||||
return <View/>;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the render item to be used for the section title in the list.
|
|
||||||
* Must be overridden by inheriting class.
|
|
||||||
*
|
|
||||||
* @param title
|
|
||||||
* @return {*}
|
|
||||||
*/
|
|
||||||
getRenderSectionHeader(title: string) {
|
|
||||||
return <View/>;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the render item to be used when the list is empty.
|
|
||||||
* No need to be overridden, has good defaults.
|
|
||||||
*
|
|
||||||
* @param text
|
|
||||||
* @param isSpinner
|
|
||||||
* @param icon
|
|
||||||
* @return {*}
|
|
||||||
*/
|
|
||||||
getEmptyRenderItem(text: string, isSpinner: boolean, icon: string) {
|
|
||||||
return (
|
|
||||||
<View>
|
|
||||||
<View style={{
|
|
||||||
justifyContent: 'center',
|
|
||||||
alignItems: 'center',
|
|
||||||
width: '100%',
|
|
||||||
height: 100,
|
|
||||||
marginBottom: 20
|
|
||||||
}}>
|
|
||||||
{isSpinner ?
|
|
||||||
<Spinner/>
|
|
||||||
:
|
|
||||||
<CustomMaterialIcon
|
|
||||||
icon={icon}
|
|
||||||
fontSize={100}
|
|
||||||
width={100}
|
|
||||||
color={ThemeManager.getCurrentThemeVariables().fetchedDataSectionListErrorText}/>}
|
|
||||||
</View>
|
|
||||||
|
|
||||||
<H3 style={{
|
|
||||||
textAlign: 'center',
|
|
||||||
marginRight: 20,
|
|
||||||
marginLeft: 20,
|
|
||||||
color: ThemeManager.getCurrentThemeVariables().fetchedDataSectionListErrorText
|
|
||||||
}}>
|
|
||||||
{text}
|
|
||||||
</H3>
|
|
||||||
</View>);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create the dataset to be used in the list from the data fetched.
|
|
||||||
* Must be overridden.
|
|
||||||
*
|
|
||||||
* @param fetchedData {Object}
|
|
||||||
* @return {Array}
|
|
||||||
*/
|
|
||||||
createDataset(fetchedData: Object): Array<Object> {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
datasetKeyExtractor(item: Object) {
|
|
||||||
return item.text
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create the dataset when no fetched data is available.
|
|
||||||
* No need to be overridden, has good defaults.
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
createEmptyDataset() {
|
|
||||||
return [
|
|
||||||
{
|
|
||||||
title: '',
|
|
||||||
data: [
|
|
||||||
{
|
|
||||||
text: this.state.refreshing ?
|
|
||||||
i18n.t('general.loading') :
|
|
||||||
i18n.t('general.networkError'),
|
|
||||||
isSpinner: this.state.refreshing,
|
|
||||||
icon: this.state.refreshing ?
|
|
||||||
'refresh' :
|
|
||||||
'access-point-network-off'
|
|
||||||
}
|
|
||||||
],
|
|
||||||
keyExtractor: this.datasetKeyExtractor,
|
|
||||||
}
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Should the app use a tab layout instead of a section list ?
|
|
||||||
* If yes, each section will be rendered in a new tab.
|
|
||||||
* Can be overridden.
|
|
||||||
*
|
|
||||||
* @return {boolean}
|
|
||||||
*/
|
|
||||||
hasTabs() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
hasBackButton() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
getRightButton() {
|
|
||||||
return <View/>
|
|
||||||
}
|
|
||||||
|
|
||||||
hasStickyHeader() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
hasSideMenu() {
|
|
||||||
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
|
|
||||||
*
|
|
||||||
* @param dataset
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
getSectionList(dataset: Array<Object>) {
|
|
||||||
let isEmpty = dataset[0].data.length === 0;
|
|
||||||
if (isEmpty)
|
|
||||||
dataset = this.createEmptyDataset();
|
|
||||||
return (
|
|
||||||
<SectionList
|
|
||||||
sections={dataset}
|
|
||||||
stickySectionHeadersEnabled={this.hasStickyHeader()}
|
|
||||||
refreshControl={
|
|
||||||
<RefreshControl
|
|
||||||
refreshing={this.state.refreshing}
|
|
||||||
onRefresh={this.onRefresh}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
renderSectionHeader={isEmpty ? this.renderSectionHeaderEmpty : this.renderSectionHeaderNotEmpty}
|
|
||||||
renderItem={isEmpty ? this.renderItemEmpty : this.renderItemNotEmpty}
|
|
||||||
style={{minHeight: 300, width: '100%'}}
|
|
||||||
contentContainerStyle={
|
|
||||||
isEmpty ?
|
|
||||||
{flexGrow: 1, justifyContent: 'center', alignItems: 'center'} : {}
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Generate the tabs containing the lists
|
|
||||||
*
|
|
||||||
* @param dataset
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
getTabbedView(dataset: Array<Object>) {
|
|
||||||
let tabbedView = [];
|
|
||||||
for (let i = 0; i < dataset.length; i++) {
|
|
||||||
tabbedView.push(
|
|
||||||
<Tab heading={
|
|
||||||
<TabHeading>
|
|
||||||
<CustomMaterialIcon
|
|
||||||
icon={dataset[i].icon}
|
|
||||||
color={ThemeManager.getCurrentThemeVariables().tabIconColor}
|
|
||||||
fontSize={20}
|
|
||||||
/>
|
|
||||||
<Text>{dataset[i].title}</Text>
|
|
||||||
</TabHeading>}
|
|
||||||
key={dataset[i].title}
|
|
||||||
style={{backgroundColor: ThemeManager.getCurrentThemeVariables().containerBgColor}}>
|
|
||||||
{this.getSectionList(
|
|
||||||
[
|
|
||||||
{
|
|
||||||
title: dataset[i].title,
|
|
||||||
data: dataset[i].data,
|
|
||||||
extraData: dataset[i].extraData,
|
|
||||||
keyExtractor: dataset[i].keyExtractor
|
|
||||||
}
|
|
||||||
]
|
|
||||||
)}
|
|
||||||
</Tab>);
|
|
||||||
}
|
|
||||||
return tabbedView;
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
// console.log("rendering FetchedDataSectionList");
|
|
||||||
const dataset = this.createDataset(this.state.fetchedData);
|
|
||||||
return (
|
|
||||||
<BaseContainer
|
|
||||||
navigation={this.props.navigation}
|
|
||||||
headerTitle={this.getHeaderTranslation()}
|
|
||||||
headerRightButton={this.getRightButton()}
|
|
||||||
hasTabs={this.hasTabs()}
|
|
||||||
hasBackButton={this.hasBackButton()}
|
|
||||||
hasSideMenu={this.hasSideMenu()}
|
|
||||||
>
|
|
||||||
{this.hasTabs() ?
|
|
||||||
<Tabs
|
|
||||||
tabContainerStyle={{
|
|
||||||
elevation: 0, // Fix for android shadow
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{this.getTabbedView(dataset)}
|
|
||||||
</Tabs>
|
|
||||||
:
|
|
||||||
this.getSectionList(dataset)
|
|
||||||
}
|
|
||||||
</BaseContainer>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
221
components/WebSectionList.js
Normal file
221
components/WebSectionList.js
Normal file
|
@ -0,0 +1,221 @@
|
||||||
|
// @flow
|
||||||
|
|
||||||
|
import * as React from 'react';
|
||||||
|
import {H3, Spinner, View} from "native-base";
|
||||||
|
import ThemeManager from '../utils/ThemeManager';
|
||||||
|
import WebDataManager from "../utils/WebDataManager";
|
||||||
|
import CustomMaterialIcon from "./CustomMaterialIcon";
|
||||||
|
import i18n from "i18n-js";
|
||||||
|
import {RefreshControl, SectionList} from "react-native";
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
navigation: Object,
|
||||||
|
fetchUrl: string,
|
||||||
|
refreshTime: number,
|
||||||
|
renderItem: React.Node,
|
||||||
|
renderSectionHeader: React.Node,
|
||||||
|
stickyHeader: boolean,
|
||||||
|
createDataset: Function,
|
||||||
|
updateErrorText: string,
|
||||||
|
}
|
||||||
|
|
||||||
|
type State = {
|
||||||
|
refreshing: boolean,
|
||||||
|
firstLoading: boolean,
|
||||||
|
fetchedData: Object,
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Custom component defining a material icon using native base
|
||||||
|
*
|
||||||
|
* @prop active {boolean} Whether to set the icon color to active
|
||||||
|
* @prop icon {string} The icon string to use from MaterialCommunityIcons
|
||||||
|
* @prop color {string} The icon color. Use default theme color if unspecified
|
||||||
|
* @prop fontSize {number} The icon size. Use 26 if unspecified
|
||||||
|
* @prop width {number} The icon width. Use 30 if unspecified
|
||||||
|
*/
|
||||||
|
export default class WebSectionList extends React.Component<Props, State> {
|
||||||
|
|
||||||
|
static defaultProps = {
|
||||||
|
renderSectionHeader: undefined,
|
||||||
|
stickyHeader: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
webDataManager: WebDataManager;
|
||||||
|
|
||||||
|
refreshInterval: IntervalID;
|
||||||
|
lastRefresh: Date;
|
||||||
|
|
||||||
|
state = {
|
||||||
|
refreshing: false,
|
||||||
|
firstLoading: true,
|
||||||
|
fetchedData: {},
|
||||||
|
};
|
||||||
|
|
||||||
|
onRefresh: Function;
|
||||||
|
onFetchSuccess: Function;
|
||||||
|
onFetchError: Function;
|
||||||
|
getEmptyRenderItem: Function;
|
||||||
|
getEmptySectionHeader: Function;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
// 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.getEmptyRenderItem = this.getEmptyRenderItem.bind(this);
|
||||||
|
this.getEmptySectionHeader = this.getEmptySectionHeader.bind(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register react navigation events on first screen load.
|
||||||
|
* Allows to detect when the screen is focused
|
||||||
|
*/
|
||||||
|
componentDidMount() {
|
||||||
|
this.webDataManager = new WebDataManager(this.props.fetchUrl);
|
||||||
|
const onScreenFocus = this.onScreenFocus.bind(this);
|
||||||
|
const onScreenBlur = this.onScreenBlur.bind(this);
|
||||||
|
this.props.navigation.addListener('focus', onScreenFocus);
|
||||||
|
this.props.navigation.addListener('blur', onScreenBlur);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Refresh data when focusing the screen and setup a refresh interval if asked to
|
||||||
|
*/
|
||||||
|
onScreenFocus() {
|
||||||
|
this.onRefresh();
|
||||||
|
if (this.props.refreshTime > 0)
|
||||||
|
this.refreshInterval = setInterval(this.onRefresh, this.props.refreshTime)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove any interval on un-focus
|
||||||
|
*/
|
||||||
|
onScreenBlur() {
|
||||||
|
clearInterval(this.refreshInterval);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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.props.updateErrorText);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Refresh data and show a toast if any error occurred
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
onRefresh() {
|
||||||
|
let canRefresh;
|
||||||
|
if (this.lastRefresh !== undefined)
|
||||||
|
canRefresh = (new Date().getTime() - this.lastRefresh.getTime()) > this.props.refreshTime;
|
||||||
|
else
|
||||||
|
canRefresh = true;
|
||||||
|
if (canRefresh) {
|
||||||
|
this.setState({refreshing: true});
|
||||||
|
this.webDataManager.readData()
|
||||||
|
.then(this.onFetchSuccess)
|
||||||
|
.catch(this.onFetchError);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getEmptySectionHeader({section}: Object) {
|
||||||
|
return <View/>;
|
||||||
|
}
|
||||||
|
|
||||||
|
getEmptyRenderItem({item}: Object) {
|
||||||
|
return (
|
||||||
|
<View>
|
||||||
|
<View style={{
|
||||||
|
justifyContent: 'center',
|
||||||
|
alignItems: 'center',
|
||||||
|
width: '100%',
|
||||||
|
height: 100,
|
||||||
|
marginBottom: 20
|
||||||
|
}}>
|
||||||
|
{this.state.refreshing ?
|
||||||
|
<Spinner/>
|
||||||
|
:
|
||||||
|
<CustomMaterialIcon
|
||||||
|
icon={item.icon}
|
||||||
|
fontSize={100}
|
||||||
|
width={100}
|
||||||
|
color={ThemeManager.getCurrentThemeVariables().fetchedDataSectionListErrorText}/>}
|
||||||
|
</View>
|
||||||
|
|
||||||
|
<H3 style={{
|
||||||
|
textAlign: 'center',
|
||||||
|
marginRight: 20,
|
||||||
|
marginLeft: 20,
|
||||||
|
color: ThemeManager.getCurrentThemeVariables().fetchedDataSectionListErrorText
|
||||||
|
}}>
|
||||||
|
{item.text}
|
||||||
|
</H3>
|
||||||
|
</View>);
|
||||||
|
}
|
||||||
|
|
||||||
|
createEmptyDataset() {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
title: '',
|
||||||
|
data: [
|
||||||
|
{
|
||||||
|
text: this.state.refreshing ?
|
||||||
|
i18n.t('general.loading') :
|
||||||
|
i18n.t('general.networkError'),
|
||||||
|
isSpinner: this.state.refreshing,
|
||||||
|
icon: this.state.refreshing ?
|
||||||
|
'refresh' :
|
||||||
|
'access-point-network-off'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
keyExtractor: this.datasetKeyExtractor,
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
datasetKeyExtractor(item: Object) {
|
||||||
|
return item.text
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
let dataset = this.props.createDataset(this.state.fetchedData);
|
||||||
|
const isEmpty = dataset[0].data.length === 0;
|
||||||
|
const shouldRenderHeader = isEmpty || (this.props.renderSectionHeader !== undefined);
|
||||||
|
if (isEmpty)
|
||||||
|
dataset = this.createEmptyDataset();
|
||||||
|
return (
|
||||||
|
<SectionList
|
||||||
|
sections={dataset}
|
||||||
|
refreshControl={
|
||||||
|
<RefreshControl
|
||||||
|
refreshing={this.state.refreshing}
|
||||||
|
onRefresh={this.onRefresh}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
renderSectionHeader={shouldRenderHeader ? this.getEmptySectionHeader : this.props.renderSectionHeader}
|
||||||
|
renderItem={isEmpty ? this.getEmptyRenderItem : this.props.renderItem}
|
||||||
|
style={{minHeight: 300, width: '100%'}}
|
||||||
|
stickySectionHeadersEnabled={this.props.stickyHeader}
|
||||||
|
contentContainerStyle={
|
||||||
|
isEmpty ?
|
||||||
|
{flexGrow: 1, justifyContent: 'center', alignItems: 'center'} : {}
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,14 +1,16 @@
|
||||||
// @flow
|
// @flow
|
||||||
|
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import {Image, Linking, TouchableOpacity, View} from 'react-native';
|
import {Image, TouchableOpacity, View} from 'react-native';
|
||||||
import {Body, Button, Card, CardItem, H1, Left, Text, Thumbnail} from 'native-base';
|
import {Body, Button, Card, CardItem, Left, Text, Thumbnail} from 'native-base';
|
||||||
import i18n from "i18n-js";
|
import i18n from "i18n-js";
|
||||||
import CustomMaterialIcon from '../components/CustomMaterialIcon';
|
import CustomMaterialIcon from '../components/CustomMaterialIcon';
|
||||||
import FetchedDataSectionList from "../components/FetchedDataSectionList";
|
|
||||||
import Autolink from 'react-native-autolink';
|
import Autolink from 'react-native-autolink';
|
||||||
import ThemeManager from "../utils/ThemeManager";
|
import ThemeManager from "../utils/ThemeManager";
|
||||||
import DashboardItem from "../components/DashboardItem";
|
import DashboardItem from "../components/DashboardItem";
|
||||||
|
import * as WebBrowser from 'expo-web-browser';
|
||||||
|
import BaseContainer from "../components/BaseContainer";
|
||||||
|
import WebSectionList from "../components/WebSectionList";
|
||||||
// import DATA from "../dashboard_data.json";
|
// import DATA from "../dashboard_data.json";
|
||||||
|
|
||||||
|
|
||||||
|
@ -25,46 +27,30 @@ const REFRESH_TIME = 1000 * 20; // Refresh every 20 seconds
|
||||||
|
|
||||||
const CARD_BORDER_RADIUS = 10;
|
const CARD_BORDER_RADIUS = 10;
|
||||||
|
|
||||||
/**
|
type Props = {
|
||||||
* Opens a link in the device's browser
|
navigation: Object,
|
||||||
* @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 home screen
|
* Class defining the app's home screen
|
||||||
*/
|
*/
|
||||||
export default class HomeScreen extends FetchedDataSectionList {
|
export default class HomeScreen extends React.Component<Props> {
|
||||||
|
|
||||||
onProxiwashClick: Function;
|
onProxiwashClick: Function;
|
||||||
onTutorInsaClick: Function;
|
onTutorInsaClick: Function;
|
||||||
onMenuClick: Function;
|
onMenuClick: Function;
|
||||||
onProximoClick: Function;
|
onProximoClick: Function;
|
||||||
|
getRenderItem: Function;
|
||||||
|
createDataset: Function;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super(DATA_URL, REFRESH_TIME);
|
super();
|
||||||
this.onProxiwashClick = this.onProxiwashClick.bind(this);
|
this.onProxiwashClick = this.onProxiwashClick.bind(this);
|
||||||
this.onTutorInsaClick = this.onTutorInsaClick.bind(this);
|
this.onTutorInsaClick = this.onTutorInsaClick.bind(this);
|
||||||
this.onMenuClick = this.onMenuClick.bind(this);
|
this.onMenuClick = this.onMenuClick.bind(this);
|
||||||
this.onProximoClick = this.onProximoClick.bind(this);
|
this.onProximoClick = this.onProximoClick.bind(this);
|
||||||
}
|
this.getRenderItem = this.getRenderItem.bind(this);
|
||||||
|
this.createDataset = this.createDataset.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');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -77,12 +63,20 @@ export default class HomeScreen extends FetchedDataSectionList {
|
||||||
return date.toLocaleString();
|
return date.toLocaleString();
|
||||||
}
|
}
|
||||||
|
|
||||||
getHeaderTranslation() {
|
onProxiwashClick() {
|
||||||
return i18n.t("screens.home");
|
this.props.navigation.navigate('Proxiwash');
|
||||||
}
|
}
|
||||||
|
|
||||||
getUpdateToastTranslations() {
|
onTutorInsaClick() {
|
||||||
return [i18n.t("homeScreen.listUpdated"), i18n.t("homeScreen.listUpdateFail")];
|
WebBrowser.openBrowserAsync("https://www.etud.insa-toulouse.fr/~tutorinsa/");
|
||||||
|
}
|
||||||
|
|
||||||
|
onProximoClick() {
|
||||||
|
this.props.navigation.navigate('Proximo');
|
||||||
|
}
|
||||||
|
|
||||||
|
onMenuClick() {
|
||||||
|
this.props.navigation.navigate('SelfMenuScreen');
|
||||||
}
|
}
|
||||||
|
|
||||||
getKeyExtractor(item: Object) {
|
getKeyExtractor(item: Object) {
|
||||||
|
@ -154,25 +148,6 @@ export default class HomeScreen extends FetchedDataSectionList {
|
||||||
return dataset
|
return dataset
|
||||||
}
|
}
|
||||||
|
|
||||||
getRenderSectionHeader(title: string) {
|
|
||||||
if (title === '') {
|
|
||||||
return <View/>;
|
|
||||||
} else {
|
|
||||||
return (
|
|
||||||
<View style={{
|
|
||||||
backgroundColor: ThemeManager.getCurrentThemeVariables().containerBgColor
|
|
||||||
}}>
|
|
||||||
<H1 style={{
|
|
||||||
marginLeft: 'auto',
|
|
||||||
marginRight: 'auto',
|
|
||||||
marginTop: 10,
|
|
||||||
marginBottom: 10
|
|
||||||
}}>{title}</H1>
|
|
||||||
</View>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
getDashboardItem(item: Object) {
|
getDashboardItem(item: Object) {
|
||||||
let content = item['content'];
|
let content = item['content'];
|
||||||
if (item['id'] === 'event')
|
if (item['id'] === 'event')
|
||||||
|
@ -318,7 +293,7 @@ export default class HomeScreen extends FetchedDataSectionList {
|
||||||
if (isAvailable)
|
if (isAvailable)
|
||||||
this.props.navigation.navigate('PlanningDisplayScreen', {data: displayEvent});
|
this.props.navigation.navigate('PlanningDisplayScreen', {data: displayEvent});
|
||||||
else
|
else
|
||||||
this.props.navigation.navigate('PlanningScreen');
|
this.props.navigation.navigate('Planning');
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -345,13 +320,13 @@ export default class HomeScreen extends FetchedDataSectionList {
|
||||||
subtitle = i18n.t('homeScreen.dashboard.todayEventsSubtitleNA');
|
subtitle = i18n.t('homeScreen.dashboard.todayEventsSubtitleNA');
|
||||||
|
|
||||||
let displayEvent = this.getDisplayEvent(futureEvents);
|
let displayEvent = this.getDisplayEvent(futureEvents);
|
||||||
|
const clickAction = this.clickAction.bind(this, isAvailable, displayEvent);
|
||||||
return (
|
return (
|
||||||
<DashboardItem
|
<DashboardItem
|
||||||
subtitle={subtitle}
|
subtitle={subtitle}
|
||||||
color={color}
|
color={color}
|
||||||
icon={icon}
|
icon={icon}
|
||||||
clickAction={this.clickAction.bind(this, isAvailable, displayEvent)}
|
clickAction={clickAction}
|
||||||
title={title}
|
title={title}
|
||||||
isAvailable={isAvailable}
|
isAvailable={isAvailable}
|
||||||
displayEvent={displayEvent}
|
displayEvent={displayEvent}
|
||||||
|
@ -523,64 +498,90 @@ export default class HomeScreen extends FetchedDataSectionList {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
openLink(link: string) {
|
||||||
|
WebBrowser.openBrowserAsync(link);
|
||||||
|
}
|
||||||
|
|
||||||
getRenderItem(item: Object, section: Object) {
|
getFeedItem(item: Object) {
|
||||||
|
const onImagePress = this.openLink.bind(this, item.full_picture);
|
||||||
|
const onOutLinkPress = this.openLink.bind(this, item.permalink_url);
|
||||||
return (
|
return (
|
||||||
section['id'] === SECTIONS_ID[0] ? this.getDashboardItem(item) :
|
<Card style={{
|
||||||
<Card style={{
|
flex: 0,
|
||||||
flex: 0,
|
marginLeft: 10,
|
||||||
marginLeft: 10,
|
marginRight: 10,
|
||||||
marginRight: 10,
|
borderRadius: CARD_BORDER_RADIUS,
|
||||||
borderRadius: CARD_BORDER_RADIUS,
|
}}>
|
||||||
|
<CardItem style={{
|
||||||
|
backgroundColor: 'transparent'
|
||||||
}}>
|
}}>
|
||||||
<CardItem style={{
|
<Left>
|
||||||
backgroundColor: 'transparent'
|
<Thumbnail source={ICON_AMICALE} square/>
|
||||||
}}>
|
|
||||||
<Left>
|
|
||||||
<Thumbnail source={ICON_AMICALE} square/>
|
|
||||||
<Body>
|
|
||||||
<Text>{NAME_AMICALE}</Text>
|
|
||||||
<Text note>{HomeScreen.getFormattedDate(item.created_time)}</Text>
|
|
||||||
</Body>
|
|
||||||
</Left>
|
|
||||||
</CardItem>
|
|
||||||
<CardItem style={{
|
|
||||||
backgroundColor: 'transparent'
|
|
||||||
}}>
|
|
||||||
<Body>
|
<Body>
|
||||||
{item.full_picture !== '' && item.full_picture !== undefined ?
|
<Text>{NAME_AMICALE}</Text>
|
||||||
<TouchableOpacity onPress={openWebLink.bind(null, item.full_picture)}
|
<Text note>{HomeScreen.getFormattedDate(item.created_time)}</Text>
|
||||||
style={{width: '100%', height: 250, marginBottom: 5}}>
|
|
||||||
<Image source={{uri: item.full_picture}}
|
|
||||||
style={{flex: 1, resizeMode: "contain"}}
|
|
||||||
resizeMode="contain"
|
|
||||||
/>
|
|
||||||
</TouchableOpacity>
|
|
||||||
: <View/>}
|
|
||||||
{item.message !== undefined ?
|
|
||||||
<Autolink
|
|
||||||
text={item.message}
|
|
||||||
hashtag="facebook"
|
|
||||||
style={{color: ThemeManager.getCurrentThemeVariables().textColor}}
|
|
||||||
/> : <View/>
|
|
||||||
}
|
|
||||||
</Body>
|
</Body>
|
||||||
</CardItem>
|
</Left>
|
||||||
<CardItem style={{
|
</CardItem>
|
||||||
backgroundColor: 'transparent'
|
<CardItem style={{
|
||||||
}}>
|
backgroundColor: 'transparent'
|
||||||
<Left>
|
}}>
|
||||||
<Button transparent
|
<Body>
|
||||||
onPress={openWebLink.bind(null, item.permalink_url)}>
|
{item.full_picture !== '' && item.full_picture !== undefined ?
|
||||||
<CustomMaterialIcon
|
<TouchableOpacity onPress={onImagePress}
|
||||||
icon="facebook"
|
style={{width: '100%', height: 250, marginBottom: 5}}>
|
||||||
color="#57aeff"
|
<Image source={{uri: item.full_picture}}
|
||||||
width={20}/>
|
style={{flex: 1, resizeMode: "contain"}}
|
||||||
<Text>En savoir plus</Text>
|
resizeMode="contain"
|
||||||
</Button>
|
/>
|
||||||
</Left>
|
</TouchableOpacity>
|
||||||
</CardItem>
|
: <View/>}
|
||||||
</Card>
|
{item.message !== undefined ?
|
||||||
|
<Autolink
|
||||||
|
text={item.message}
|
||||||
|
hashtag="facebook"
|
||||||
|
style={{color: ThemeManager.getCurrentThemeVariables().textColor}}
|
||||||
|
/> : <View/>
|
||||||
|
}
|
||||||
|
</Body>
|
||||||
|
</CardItem>
|
||||||
|
<CardItem style={{
|
||||||
|
backgroundColor: 'transparent'
|
||||||
|
}}>
|
||||||
|
<Left>
|
||||||
|
<Button transparent
|
||||||
|
onPress={onOutLinkPress}>
|
||||||
|
<CustomMaterialIcon
|
||||||
|
icon="facebook"
|
||||||
|
color="#57aeff"
|
||||||
|
width={20}/>
|
||||||
|
<Text>En savoir plus</Text>
|
||||||
|
</Button>
|
||||||
|
</Left>
|
||||||
|
</CardItem>
|
||||||
|
</Card>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
getRenderItem({item, section}: Object) {
|
||||||
|
return (section['id'] === SECTIONS_ID[0] ?
|
||||||
|
this.getDashboardItem(item) : this.getFeedItem(item));
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const nav = this.props.navigation;
|
||||||
|
return (
|
||||||
|
<BaseContainer
|
||||||
|
navigation={nav}
|
||||||
|
headerTitle={i18n.t('screens.home')}>
|
||||||
|
<WebSectionList
|
||||||
|
createDataset={this.createDataset}
|
||||||
|
navigation={nav}
|
||||||
|
refreshTime={REFRESH_TIME}
|
||||||
|
fetchUrl={DATA_URL}
|
||||||
|
renderItem={this.getRenderItem}
|
||||||
|
updateErrorText={i18n.t("homeScreen.listUpdateFail")}/>
|
||||||
|
</BaseContainer>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,7 +41,8 @@ function sortNameReverse(a, b) {
|
||||||
}
|
}
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
navigation: Object
|
navigation: Object,
|
||||||
|
route: Object,
|
||||||
}
|
}
|
||||||
|
|
||||||
type State = {
|
type State = {
|
||||||
|
@ -60,16 +61,8 @@ export default class ProximoListScreen extends React.Component<Props, State> {
|
||||||
|
|
||||||
modalRef: { current: null | Modalize };
|
modalRef: { current: null | Modalize };
|
||||||
originalData: Array<Object>;
|
originalData: Array<Object>;
|
||||||
navData = this.props.navigation.getParam('data', []);
|
shouldFocusSearchBar: boolean;
|
||||||
shouldFocusSearchBar = this.props.navigation.getParam('shouldFocusSearchBar', false);
|
|
||||||
state = {
|
|
||||||
currentlyDisplayedData: this.navData['data'].sort(sortPrice),
|
|
||||||
currentSortMode: sortMode.price,
|
|
||||||
isSortReversed: false,
|
|
||||||
sortPriceIcon: '',
|
|
||||||
sortNameIcon: '',
|
|
||||||
modalCurrentDisplayItem: {},
|
|
||||||
};
|
|
||||||
sortMenuRef: Menu;
|
sortMenuRef: Menu;
|
||||||
|
|
||||||
onMenuRef: Function;
|
onMenuRef: Function;
|
||||||
|
@ -82,7 +75,16 @@ export default class ProximoListScreen extends React.Component<Props, State> {
|
||||||
constructor(props: any) {
|
constructor(props: any) {
|
||||||
super(props);
|
super(props);
|
||||||
this.modalRef = React.createRef();
|
this.modalRef = React.createRef();
|
||||||
this.originalData = this.navData['data'];
|
this.originalData = this.props.route.params['data']['data'];
|
||||||
|
this.shouldFocusSearchBar = this.props.route.params['shouldFocusSearchBar'];
|
||||||
|
this.state = {
|
||||||
|
currentlyDisplayedData: this.originalData,
|
||||||
|
currentSortMode: sortMode.price,
|
||||||
|
isSortReversed: false,
|
||||||
|
sortPriceIcon: '',
|
||||||
|
sortNameIcon: '',
|
||||||
|
modalCurrentDisplayItem: {},
|
||||||
|
};
|
||||||
|
|
||||||
this.onMenuRef = this.onMenuRef.bind(this);
|
this.onMenuRef = this.onMenuRef.bind(this);
|
||||||
this.onSearchStringChange = this.onSearchStringChange.bind(this);
|
this.onSearchStringChange = this.onSearchStringChange.bind(this);
|
||||||
|
@ -365,7 +367,6 @@ export default class ProximoListScreen extends React.Component<Props, State> {
|
||||||
shouldFocusSearchBar={this.shouldFocusSearchBar}
|
shouldFocusSearchBar={this.shouldFocusSearchBar}
|
||||||
rightButton={this.getSortMenu()}
|
rightButton={this.getSortMenu()}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<FlatList
|
<FlatList
|
||||||
data={this.state.currentlyDisplayedData}
|
data={this.state.currentlyDisplayedData}
|
||||||
extraData={this.state.currentlyDisplayedData}
|
extraData={this.state.currentlyDisplayedData}
|
||||||
|
|
|
@ -5,26 +5,40 @@ import {Platform, View} from 'react-native'
|
||||||
import {Body, Left, ListItem, Right, Text} from 'native-base';
|
import {Body, Left, ListItem, Right, Text} from 'native-base';
|
||||||
import i18n from "i18n-js";
|
import i18n from "i18n-js";
|
||||||
import CustomMaterialIcon from "../../components/CustomMaterialIcon";
|
import CustomMaterialIcon from "../../components/CustomMaterialIcon";
|
||||||
import FetchedDataSectionList from "../../components/FetchedDataSectionList";
|
|
||||||
import ThemeManager from "../../utils/ThemeManager";
|
import ThemeManager from "../../utils/ThemeManager";
|
||||||
import Touchable from "react-native-platform-touchable";
|
import Touchable from "react-native-platform-touchable";
|
||||||
|
import BaseContainer from "../../components/BaseContainer";
|
||||||
|
import WebSectionList from "../../components/WebSectionList";
|
||||||
|
|
||||||
const DATA_URL = "https://etud.insa-toulouse.fr/~proximo/data/stock-v2.json";
|
const DATA_URL = "https://etud.insa-toulouse.fr/~proximo/data/stock-v2.json";
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
navigation: Object,
|
||||||
|
}
|
||||||
|
|
||||||
|
type State = {
|
||||||
|
fetchedData: Object,
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class defining the main proximo screen. This screen shows the different categories of articles
|
* Class defining the main proximo screen. This screen shows the different categories of articles
|
||||||
* offered by proximo.
|
* offered by proximo.
|
||||||
*/
|
*/
|
||||||
export default class ProximoMainScreen extends FetchedDataSectionList {
|
export default class ProximoMainScreen extends React.Component<Props, State> {
|
||||||
|
|
||||||
|
articles: Object;
|
||||||
|
|
||||||
onPressSearchBtn: Function;
|
onPressSearchBtn: Function;
|
||||||
onPressAboutBtn: Function;
|
onPressAboutBtn: Function;
|
||||||
|
getRenderItem: Function;
|
||||||
|
createDataset: Function;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super(DATA_URL, 0);
|
super();
|
||||||
this.onPressSearchBtn = this.onPressSearchBtn.bind(this);
|
this.onPressSearchBtn = this.onPressSearchBtn.bind(this);
|
||||||
this.onPressAboutBtn = this.onPressAboutBtn.bind(this);
|
this.onPressAboutBtn = this.onPressAboutBtn.bind(this);
|
||||||
|
this.getRenderItem = this.getRenderItem.bind(this);
|
||||||
|
this.createDataset = this.createDataset.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
static sortFinalData(a: Object, b: Object) {
|
static sortFinalData(a: Object, b: Object) {
|
||||||
|
@ -45,14 +59,6 @@ export default class ProximoMainScreen extends FetchedDataSectionList {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
getHeaderTranslation() {
|
|
||||||
return i18n.t("screens.proximo");
|
|
||||||
}
|
|
||||||
|
|
||||||
getUpdateToastTranslations() {
|
|
||||||
return [i18n.t("proximoScreen.listUpdated"), i18n.t("proximoScreen.listUpdateFail")];
|
|
||||||
}
|
|
||||||
|
|
||||||
getKeyExtractor(item: Object) {
|
getKeyExtractor(item: Object) {
|
||||||
return item !== undefined ? item.type['id'] : undefined;
|
return item !== undefined ? item.type['id'] : undefined;
|
||||||
}
|
}
|
||||||
|
@ -62,7 +68,7 @@ export default class ProximoMainScreen extends FetchedDataSectionList {
|
||||||
{
|
{
|
||||||
title: '',
|
title: '',
|
||||||
data: this.generateData(fetchedData),
|
data: this.generateData(fetchedData),
|
||||||
extraData: super.state,
|
extraData: this.state,
|
||||||
keyExtractor: this.getKeyExtractor
|
keyExtractor: this.getKeyExtractor
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
@ -77,21 +83,22 @@ export default class ProximoMainScreen extends FetchedDataSectionList {
|
||||||
*/
|
*/
|
||||||
generateData(fetchedData: Object) {
|
generateData(fetchedData: Object) {
|
||||||
let finalData = [];
|
let finalData = [];
|
||||||
|
this.articles = undefined;
|
||||||
if (fetchedData.types !== undefined && fetchedData.articles !== undefined) {
|
if (fetchedData.types !== undefined && fetchedData.articles !== undefined) {
|
||||||
let types = fetchedData.types;
|
let types = fetchedData.types;
|
||||||
let articles = fetchedData.articles;
|
this.articles = fetchedData.articles;
|
||||||
finalData.push({
|
finalData.push({
|
||||||
type: {
|
type: {
|
||||||
id: -1,
|
id: -1,
|
||||||
name: i18n.t('proximoScreen.all'),
|
name: i18n.t('proximoScreen.all'),
|
||||||
icon: 'star'
|
icon: 'star'
|
||||||
},
|
},
|
||||||
data: this.getAvailableArticles(articles, undefined)
|
data: this.getAvailableArticles(this.articles, undefined)
|
||||||
});
|
});
|
||||||
for (let i = 0; i < types.length; i++) {
|
for (let i = 0; i < types.length; i++) {
|
||||||
finalData.push({
|
finalData.push({
|
||||||
type: types[i],
|
type: types[i],
|
||||||
data: this.getAvailableArticles(articles, types[i])
|
data: this.getAvailableArticles(this.articles, types[i])
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -128,8 +135,8 @@ export default class ProximoMainScreen extends FetchedDataSectionList {
|
||||||
name: i18n.t('proximoScreen.all'),
|
name: i18n.t('proximoScreen.all'),
|
||||||
icon: 'star'
|
icon: 'star'
|
||||||
},
|
},
|
||||||
data: this.state.fetchedData.articles !== undefined ?
|
data: this.articles !== undefined ?
|
||||||
this.getAvailableArticles(this.state.fetchedData.articles, undefined) : []
|
this.getAvailableArticles(this.articles, undefined) : []
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
this.props.navigation.navigate('ProximoListScreen', searchScreenData);
|
this.props.navigation.navigate('ProximoListScreen', searchScreenData);
|
||||||
|
@ -163,7 +170,7 @@ export default class ProximoMainScreen extends FetchedDataSectionList {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
getRenderItem(item: Object, section: Object) {
|
getRenderItem({item}: Object) {
|
||||||
let dataToSend = {
|
let dataToSend = {
|
||||||
shouldFocusSearchBar: false,
|
shouldFocusSearchBar: false,
|
||||||
data: item,
|
data: item,
|
||||||
|
@ -196,10 +203,26 @@ export default class ProximoMainScreen extends FetchedDataSectionList {
|
||||||
</Right>
|
</Right>
|
||||||
</ListItem>
|
</ListItem>
|
||||||
);
|
);
|
||||||
} else {
|
} else
|
||||||
return <View/>;
|
return <View/>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const nav = this.props.navigation;
|
||||||
|
return (
|
||||||
|
<BaseContainer
|
||||||
|
navigation={nav}
|
||||||
|
headerTitle={i18n.t('screens.proximo')}
|
||||||
|
headerRightButton={this.getRightButton()}>
|
||||||
|
<WebSectionList
|
||||||
|
createDataset={this.createDataset}
|
||||||
|
navigation={nav}
|
||||||
|
refreshTime={0}
|
||||||
|
fetchUrl={DATA_URL}
|
||||||
|
renderItem={this.getRenderItem}
|
||||||
|
updateErrorText={i18n.t("homeScreen.listUpdateFail")}/>
|
||||||
|
</BaseContainer>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,12 +6,13 @@ import {Body, Card, CardItem, Left, Right, Text} from 'native-base';
|
||||||
import ThemeManager from '../../utils/ThemeManager';
|
import ThemeManager from '../../utils/ThemeManager';
|
||||||
import i18n from "i18n-js";
|
import i18n from "i18n-js";
|
||||||
import CustomMaterialIcon from "../../components/CustomMaterialIcon";
|
import CustomMaterialIcon from "../../components/CustomMaterialIcon";
|
||||||
import FetchedDataSectionList from "../../components/FetchedDataSectionList";
|
import WebSectionList from "../../components/WebSectionList";
|
||||||
import NotificationsManager from "../../utils/NotificationsManager";
|
import NotificationsManager from "../../utils/NotificationsManager";
|
||||||
import PlatformTouchable from "react-native-platform-touchable";
|
import PlatformTouchable from "react-native-platform-touchable";
|
||||||
import Touchable from "react-native-platform-touchable";
|
import Touchable from "react-native-platform-touchable";
|
||||||
import AsyncStorageManager from "../../utils/AsyncStorageManager";
|
import AsyncStorageManager from "../../utils/AsyncStorageManager";
|
||||||
import * as Expo from "expo";
|
import * as Expo from "expo";
|
||||||
|
import BaseContainer from "../../components/BaseContainer";
|
||||||
|
|
||||||
const DATA_URL = "https://etud.insa-toulouse.fr/~amicale_app/washinsa/washinsa.json";
|
const DATA_URL = "https://etud.insa-toulouse.fr/~amicale_app/washinsa/washinsa.json";
|
||||||
|
|
||||||
|
@ -30,19 +31,41 @@ let stateColors = {};
|
||||||
|
|
||||||
const REFRESH_TIME = 1000 * 10; // Refresh every 10 seconds
|
const REFRESH_TIME = 1000 * 10; // Refresh every 10 seconds
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
navigation: Object,
|
||||||
|
}
|
||||||
|
|
||||||
|
type State = {
|
||||||
|
refreshing: boolean,
|
||||||
|
firstLoading: boolean,
|
||||||
|
fetchedData: Object,
|
||||||
|
machinesWatched: Array<string>,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class defining the app's proxiwash screen. This screen shows information about washing machines and
|
* Class defining the app's proxiwash screen. This screen shows information about washing machines and
|
||||||
* dryers, taken from a scrapper reading proxiwash website
|
* dryers, taken from a scrapper reading proxiwash website
|
||||||
*/
|
*/
|
||||||
export default class ProxiwashScreen extends FetchedDataSectionList {
|
export default class ProxiwashScreen extends React.Component<Props, State> {
|
||||||
|
|
||||||
onAboutPress: Function;
|
onAboutPress: Function;
|
||||||
|
getRenderItem: Function;
|
||||||
|
createDataset: Function;
|
||||||
|
|
||||||
|
state = {
|
||||||
|
refreshing: false,
|
||||||
|
firstLoading: true,
|
||||||
|
fetchedData: {},
|
||||||
|
// machinesWatched: JSON.parse(dataString),
|
||||||
|
machinesWatched: [],
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates machine state parameters using current theme and translations
|
* Creates machine state parameters using current theme and translations
|
||||||
*/
|
*/
|
||||||
constructor() {
|
constructor() {
|
||||||
super(DATA_URL, REFRESH_TIME);
|
super();
|
||||||
let colors = ThemeManager.getCurrentThemeVariables();
|
let colors = ThemeManager.getCurrentThemeVariables();
|
||||||
stateColors[MACHINE_STATES.TERMINE] = colors.proxiwashFinishedColor;
|
stateColors[MACHINE_STATES.TERMINE] = colors.proxiwashFinishedColor;
|
||||||
stateColors[MACHINE_STATES.DISPONIBLE] = colors.proxiwashReadyColor;
|
stateColors[MACHINE_STATES.DISPONIBLE] = colors.proxiwashReadyColor;
|
||||||
|
@ -69,23 +92,16 @@ export default class ProxiwashScreen extends FetchedDataSectionList {
|
||||||
stateIcons[MACHINE_STATES.ERREUR] = 'alert';
|
stateIcons[MACHINE_STATES.ERREUR] = 'alert';
|
||||||
|
|
||||||
// let dataString = AsyncStorageManager.getInstance().preferences.proxiwashWatchedMachines.current;
|
// let dataString = AsyncStorageManager.getInstance().preferences.proxiwashWatchedMachines.current;
|
||||||
this.state = {
|
// this.setMinTimeRefresh(30);
|
||||||
refreshing: false,
|
|
||||||
firstLoading: true,
|
|
||||||
fetchedData: {},
|
|
||||||
// machinesWatched: JSON.parse(dataString),
|
|
||||||
machinesWatched: [],
|
|
||||||
};
|
|
||||||
this.setMinTimeRefresh(30);
|
|
||||||
|
|
||||||
this.onAboutPress = this.onAboutPress.bind(this);
|
this.onAboutPress = this.onAboutPress.bind(this);
|
||||||
|
this.getRenderItem = this.getRenderItem.bind(this);
|
||||||
|
this.createDataset = this.createDataset.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Setup notification channel for android and add listeners to detect notifications fired
|
* Setup notification channel for android and add listeners to detect notifications fired
|
||||||
*/
|
*/
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
super.componentDidMount();
|
|
||||||
if (AsyncStorageManager.getInstance().preferences.expoToken.current !== '') {
|
if (AsyncStorageManager.getInstance().preferences.expoToken.current !== '') {
|
||||||
// Get latest watchlist from server
|
// Get latest watchlist from server
|
||||||
NotificationsManager.getMachineNotificationWatchlist((fetchedList) => {
|
NotificationsManager.getMachineNotificationWatchlist((fetchedList) => {
|
||||||
|
@ -107,14 +123,6 @@ export default class ProxiwashScreen extends FetchedDataSectionList {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
getHeaderTranslation() {
|
|
||||||
return i18n.t("screens.proxiwash");
|
|
||||||
}
|
|
||||||
|
|
||||||
getUpdateToastTranslations() {
|
|
||||||
return [i18n.t("proxiwashScreen.listUpdated"), i18n.t("proxiwashScreen.listUpdateFail")];
|
|
||||||
}
|
|
||||||
|
|
||||||
getDryersKeyExtractor(item: Object) {
|
getDryersKeyExtractor(item: Object) {
|
||||||
return item !== undefined ? "dryer" + item.number : undefined;
|
return item !== undefined ? "dryer" + item.number : undefined;
|
||||||
}
|
}
|
||||||
|
@ -212,28 +220,23 @@ export default class ProxiwashScreen extends FetchedDataSectionList {
|
||||||
|
|
||||||
createDataset(fetchedData: Object) {
|
createDataset(fetchedData: Object) {
|
||||||
return [
|
return [
|
||||||
{
|
|
||||||
title: i18n.t('proxiwashScreen.washers'),
|
|
||||||
icon: 'washing-machine',
|
|
||||||
data: fetchedData.washers === undefined ? [] : fetchedData.washers,
|
|
||||||
extraData: super.state,
|
|
||||||
keyExtractor: this.getWashersKeyExtractor
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
title: i18n.t('proxiwashScreen.dryers'),
|
title: i18n.t('proxiwashScreen.dryers'),
|
||||||
icon: 'tumble-dryer',
|
icon: 'tumble-dryer',
|
||||||
data: fetchedData.dryers === undefined ? [] : fetchedData.dryers,
|
data: fetchedData.dryers === undefined ? [] : fetchedData.dryers,
|
||||||
extraData: super.state,
|
extraData: this.state,
|
||||||
keyExtractor: this.getDryersKeyExtractor
|
keyExtractor: this.getDryersKeyExtractor
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
title: i18n.t('proxiwashScreen.washers'),
|
||||||
|
icon: 'washing-machine',
|
||||||
|
data: fetchedData.washers === undefined ? [] : fetchedData.washers,
|
||||||
|
extraData: this.state,
|
||||||
|
keyExtractor: this.getWashersKeyExtractor
|
||||||
|
},
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
hasTabs(): boolean {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Show an alert fo a machine, allowing to enable/disable notifications if running
|
* Show an alert fo a machine, allowing to enable/disable notifications if running
|
||||||
*
|
*
|
||||||
|
@ -292,6 +295,24 @@ export default class ProxiwashScreen extends FetchedDataSectionList {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const nav = this.props.navigation;
|
||||||
|
return (
|
||||||
|
<BaseContainer
|
||||||
|
navigation={nav}
|
||||||
|
headerTitle={i18n.t('screens.proxiwash')}
|
||||||
|
headerRightButton={this.getRightButton()}>
|
||||||
|
<WebSectionList
|
||||||
|
createDataset={this.createDataset}
|
||||||
|
navigation={nav}
|
||||||
|
refreshTime={REFRESH_TIME}
|
||||||
|
fetchUrl={DATA_URL}
|
||||||
|
renderItem={this.getRenderItem}
|
||||||
|
updateErrorText={i18n.t("proxiwashScreen.listUpdateFail")}/>
|
||||||
|
</BaseContainer>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get list item to be rendered
|
* Get list item to be rendered
|
||||||
*
|
*
|
||||||
|
@ -299,7 +320,7 @@ export default class ProxiwashScreen extends FetchedDataSectionList {
|
||||||
* @param section The object describing the current SectionList section
|
* @param section The object describing the current SectionList section
|
||||||
* @returns {React.Node}
|
* @returns {React.Node}
|
||||||
*/
|
*/
|
||||||
getRenderItem(item: Object, section: Object) {
|
getRenderItem({item, 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');
|
||||||
|
|
|
@ -5,22 +5,31 @@ import {View} from 'react-native';
|
||||||
import {Card, CardItem, H2, H3, Text} from 'native-base';
|
import {Card, CardItem, H2, H3, Text} from 'native-base';
|
||||||
import ThemeManager from "../utils/ThemeManager";
|
import ThemeManager from "../utils/ThemeManager";
|
||||||
import i18n from "i18n-js";
|
import i18n from "i18n-js";
|
||||||
import FetchedDataSectionList from "../components/FetchedDataSectionList";
|
import BaseContainer from "../components/BaseContainer";
|
||||||
|
import WebSectionList from "../components/WebSectionList";
|
||||||
|
|
||||||
const DATA_URL = "https://etud.insa-toulouse.fr/~amicale_app/menu/menu_data.json";
|
const DATA_URL = "https://etud.insa-toulouse.fr/~amicale_app/menu/menu_data.json";
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
navigation: Object,
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class defining the app's menu screen.
|
* Class defining the app's menu screen.
|
||||||
* This screen fetches data from etud to render the RU menu
|
* This screen fetches data from etud to render the RU menu
|
||||||
*/
|
*/
|
||||||
export default class SelfMenuScreen extends FetchedDataSectionList {
|
export default class SelfMenuScreen extends React.Component<Props> {
|
||||||
|
|
||||||
// Hard code strings as toLocaleDateString does not work on current android JS engine
|
// Hard code strings as toLocaleDateString does not work on current android JS engine
|
||||||
daysOfWeek = [];
|
daysOfWeek = [];
|
||||||
monthsOfYear = [];
|
monthsOfYear = [];
|
||||||
|
|
||||||
|
getRenderItem: Function;
|
||||||
|
getRenderSectionHeader: Function;
|
||||||
|
createDataset: Function;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super(DATA_URL, 0);
|
super();
|
||||||
this.daysOfWeek.push(i18n.t("date.daysOfWeek.monday"));
|
this.daysOfWeek.push(i18n.t("date.daysOfWeek.monday"));
|
||||||
this.daysOfWeek.push(i18n.t("date.daysOfWeek.tuesday"));
|
this.daysOfWeek.push(i18n.t("date.daysOfWeek.tuesday"));
|
||||||
this.daysOfWeek.push(i18n.t("date.daysOfWeek.wednesday"));
|
this.daysOfWeek.push(i18n.t("date.daysOfWeek.wednesday"));
|
||||||
|
@ -41,32 +50,16 @@ export default class SelfMenuScreen extends FetchedDataSectionList {
|
||||||
this.monthsOfYear.push(i18n.t("date.monthsOfYear.october"));
|
this.monthsOfYear.push(i18n.t("date.monthsOfYear.october"));
|
||||||
this.monthsOfYear.push(i18n.t("date.monthsOfYear.november"));
|
this.monthsOfYear.push(i18n.t("date.monthsOfYear.november"));
|
||||||
this.monthsOfYear.push(i18n.t("date.monthsOfYear.december"));
|
this.monthsOfYear.push(i18n.t("date.monthsOfYear.december"));
|
||||||
}
|
|
||||||
|
|
||||||
getHeaderTranslation() {
|
this.getRenderItem = this.getRenderItem.bind(this);
|
||||||
return i18n.t("screens.menuSelf");
|
this.getRenderSectionHeader = this.getRenderSectionHeader.bind(this);
|
||||||
}
|
this.createDataset = this.createDataset.bind(this);
|
||||||
|
|
||||||
getUpdateToastTranslations() {
|
|
||||||
return [i18n.t("homeScreen.listUpdated"), i18n.t("homeScreen.listUpdateFail")];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getKeyExtractor(item: Object) {
|
getKeyExtractor(item: Object) {
|
||||||
return item !== undefined ? item['name'] : undefined;
|
return item !== undefined ? item['name'] : undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
hasBackButton() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
hasStickyHeader(): boolean {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
hasSideMenu(): boolean {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
createDataset(fetchedData: Object) {
|
createDataset(fetchedData: Object) {
|
||||||
let result = [];
|
let result = [];
|
||||||
// Prevent crash by giving a default value when fetchedData is empty (not yet available)
|
// Prevent crash by giving a default value when fetchedData is empty (not yet available)
|
||||||
|
@ -101,7 +94,8 @@ export default class SelfMenuScreen extends FetchedDataSectionList {
|
||||||
return this.daysOfWeek[date.getDay() - 1] + " " + date.getDate() + " " + this.monthsOfYear[date.getMonth()] + " " + date.getFullYear();
|
return this.daysOfWeek[date.getDay() - 1] + " " + date.getDate() + " " + this.monthsOfYear[date.getMonth()] + " " + date.getFullYear();
|
||||||
}
|
}
|
||||||
|
|
||||||
getRenderSectionHeader(title: string) {
|
getRenderSectionHeader({section}: Object) {
|
||||||
|
let title = "";
|
||||||
return (
|
return (
|
||||||
<Card style={{
|
<Card style={{
|
||||||
marginLeft: 10,
|
marginLeft: 10,
|
||||||
|
@ -114,12 +108,12 @@ export default class SelfMenuScreen extends FetchedDataSectionList {
|
||||||
textAlign: 'center',
|
textAlign: 'center',
|
||||||
marginTop: 10,
|
marginTop: 10,
|
||||||
marginBottom: 10
|
marginBottom: 10
|
||||||
}}>{title}</H2>
|
}}>{section.title}</H2>
|
||||||
</Card>
|
</Card>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
getRenderItem(item: Object, section: Object) {
|
getRenderItem({item}: Object) {
|
||||||
return (
|
return (
|
||||||
<Card style={{
|
<Card style={{
|
||||||
flex: 0,
|
flex: 0,
|
||||||
|
@ -167,5 +161,24 @@ export default class SelfMenuScreen extends FetchedDataSectionList {
|
||||||
return name.charAt(0) + name.substr(1).toLowerCase();
|
return name.charAt(0) + name.substr(1).toLowerCase();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const nav = this.props.navigation;
|
||||||
|
return (
|
||||||
|
<BaseContainer
|
||||||
|
navigation={nav}
|
||||||
|
headerTitle={i18n.t('screens.menuSelf')}
|
||||||
|
hasBackButton={true}>
|
||||||
|
<WebSectionList
|
||||||
|
createDataset={this.createDataset}
|
||||||
|
navigation={nav}
|
||||||
|
refreshTime={0}
|
||||||
|
fetchUrl={DATA_URL}
|
||||||
|
renderItem={this.getRenderItem}
|
||||||
|
renderSectionHeader={this.getRenderSectionHeader}
|
||||||
|
updateErrorText={i18n.t("homeScreen.listUpdateFail")}
|
||||||
|
stickyHeader={true}/>
|
||||||
|
</BaseContainer>
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -45,14 +45,13 @@ export default class WebDataManager {
|
||||||
/**
|
/**
|
||||||
* Show a toast message depending on the validity of the fetched data
|
* Show a toast message depending on the validity of the fetched data
|
||||||
*
|
*
|
||||||
* @param successString
|
|
||||||
* @param errorString
|
* @param errorString
|
||||||
*/
|
*/
|
||||||
showUpdateToast(successString, errorString) {
|
showUpdateToast(errorString) {
|
||||||
let isSuccess = this.isDataObjectValid();
|
let isSuccess = this.isDataObjectValid();
|
||||||
if (!isSuccess) {
|
if (!isSuccess) {
|
||||||
Toast.show({
|
Toast.show({
|
||||||
text: isSuccess ? successString : errorString,
|
text: errorString,
|
||||||
buttonText: 'OK',
|
buttonText: 'OK',
|
||||||
type: isSuccess ? "success" : "danger",
|
type: isSuccess ? "success" : "danger",
|
||||||
duration: 2000
|
duration: 2000
|
||||||
|
|
Loading…
Reference in a new issue