forked from vergnet/application-amicale
Merge branch 'dev'
This commit is contained in:
commit
e3e5dac314
32 changed files with 539 additions and 343 deletions
13
App.js
13
App.js
|
@ -31,9 +31,16 @@ 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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -102,14 +109,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);
|
||||
|
|
|
@ -13,7 +13,7 @@ Ce dépot contient les sources de cette application, modifiable par les étudian
|
|||
|
||||
Vous voulez influencer le développement ? C'est très simple !
|
||||
|
||||
Pas besoin de connaissance, il est possible d'aider simplement en proposant des améliorations ou en rapportant des bugs par mail (vergnet@etud.insa-toulouse.fr) ou sur [cette page](https://git.srv-falcon.etud.insa-toulouse.fr/vergnet/application-amicale/issues), en vous connectant avec vos login INSA.
|
||||
Pas besoin de connaissance, il est possible d'aider simplement en proposant des améliorations ou en rapportant des bugs par mail (vergnet@etud.insa-toulouse.fr) ou sur [cette page](https://git.etud.insa-toulouse.fr/vergnet/application-amicale/issues), en vous connectant avec vos login INSA.
|
||||
|
||||
Si vous avez assez de connaissances et vous souhaitez proposer des modifications dans le code, installez l'application sur votre machine, réalisez votre modification et créez une 'pull request'.
|
||||
|
||||
|
|
4
app.json
4
app.json
|
@ -10,7 +10,7 @@
|
|||
"android",
|
||||
"web"
|
||||
],
|
||||
"version": "1.5.0",
|
||||
"version": "1.5.1",
|
||||
"orientation": "portrait",
|
||||
"primaryColor": "#be1522",
|
||||
"icon": "./assets/android.icon.png",
|
||||
|
@ -36,7 +36,7 @@
|
|||
},
|
||||
"android": {
|
||||
"package": "fr.amicaleinsat.application",
|
||||
"versionCode": 13,
|
||||
"versionCode": 14,
|
||||
"icon": "./assets/android.icon.png",
|
||||
"adaptiveIcon": {
|
||||
"foregroundImage": "./assets/android.adaptive-icon.png",
|
||||
|
|
BIN
assets/icon.png
BIN
assets/icon.png
Binary file not shown.
Before Width: | Height: | Size: 9.5 KiB |
Binary file not shown.
Before Width: | Height: | Size: 275 B |
|
@ -30,7 +30,6 @@ type State = {
|
|||
|
||||
|
||||
export default class BaseContainer extends React.Component<Props, State> {
|
||||
|
||||
static defaultProps = {
|
||||
headerRightButton: <View/>,
|
||||
hasTabs: false,
|
||||
|
@ -46,19 +45,36 @@ export default class BaseContainer extends React.Component<Props, State> {
|
|||
isHeaderVisible: true,
|
||||
};
|
||||
|
||||
toggle() {
|
||||
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() {
|
||||
this.props.navigation.toggleDrawer();
|
||||
}
|
||||
/**
|
||||
* Register for blur event to close side menu on screen change
|
||||
*/
|
||||
componentDidMount() {
|
||||
this.willFocusSubscription = this.props.navigation.addListener(
|
||||
'willFocus',
|
||||
() => {
|
||||
|
||||
onWillFocus() {
|
||||
if (this.props.enableRotation) {
|
||||
ScreenOrientation.unlockAsync();
|
||||
ScreenOrientation.addOrientationChangeListener((OrientationChangeEvent) => {
|
||||
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 ||
|
||||
|
@ -71,15 +87,19 @@ export default class BaseContainer extends React.Component<Props, State> {
|
|||
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
|
||||
);
|
||||
this.willBlurSubscription = this.props.navigation.addListener(
|
||||
'willBlur',
|
||||
() => {
|
||||
if (this.props.enableRotation)
|
||||
ScreenOrientation.lockAsync(ScreenOrientation.Orientation.PORTRAIT);
|
||||
}
|
||||
this.onWillBlur
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -93,7 +113,9 @@ export default class BaseContainer extends React.Component<Props, State> {
|
|||
this.willFocusSubscription.remove();
|
||||
}
|
||||
|
||||
getMainContainer() {
|
||||
|
||||
render() {
|
||||
// console.log("rendering BaseContainer");
|
||||
return (
|
||||
<Container>
|
||||
{this.state.isHeaderVisible ?
|
||||
|
@ -104,7 +126,7 @@ export default class BaseContainer extends React.Component<Props, State> {
|
|||
leftButton={
|
||||
<Touchable
|
||||
style={{padding: 6}}
|
||||
onPress={() => this.toggle()}>
|
||||
onPress={this.onDrawerPress}>
|
||||
<CustomMaterialIcon
|
||||
color={Platform.OS === 'ios' ? ThemeManager.getCurrentThemeVariables().brandPrimary : "#fff"}
|
||||
icon="menu"/>
|
||||
|
@ -118,9 +140,4 @@ export default class BaseContainer extends React.Component<Props, State> {
|
|||
</Container>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
render() {
|
||||
return (this.getMainContainer());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -32,11 +32,10 @@ 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: '',
|
||||
|
@ -45,10 +44,28 @@ 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 to early for some reason...
|
||||
setTimeout(() => this.refs.searchInput._root.focus(), 500);
|
||||
// does not work if called too early for some reason...
|
||||
setTimeout(this.refs.searchInput._root.focus, 500);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -67,7 +84,7 @@ export default class CustomHeader extends React.Component<Props> {
|
|||
ref="searchInput"
|
||||
placeholder={i18n.t('proximoScreen.search')}
|
||||
placeholderTextColor={ThemeManager.getCurrentThemeVariables().toolbarPlaceholderColor}
|
||||
onChangeText={(text) => this.props.searchCallback(text)}/>
|
||||
onChangeText={this.props.searchCallback}/>
|
||||
</Item>
|
||||
</Body>
|
||||
);
|
||||
|
@ -87,17 +104,20 @@ 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={() => {
|
||||
const backAction = NavigationActions.back();
|
||||
this.props.navigation.dispatch(backAction);
|
||||
}}>
|
||||
onPress={this.onPressBack}>
|
||||
<CustomMaterialIcon
|
||||
color={Platform.OS === 'ios' ? ThemeManager.getCurrentThemeVariables().brandPrimary : "#fff"}
|
||||
icon={Platform.OS === 'ios' ? 'chevron-left' : "arrow-left"}/>
|
||||
|
|
|
@ -117,7 +117,7 @@ export default class CustomIntroSlider extends React.Component<Props> {
|
|||
* @param item
|
||||
* @param dimensions
|
||||
*/
|
||||
static getIntroRenderItem(item: Object, dimensions: Object) {
|
||||
static getIntroRenderItem({item, dimensions}: Object) {
|
||||
|
||||
return (
|
||||
<LinearGradient
|
||||
|
@ -143,9 +143,9 @@ export default class CustomIntroSlider extends React.Component<Props> {
|
|||
render() {
|
||||
return (
|
||||
<AppIntroSlider
|
||||
renderItem={({item, dimensions}) => CustomIntroSlider.getIntroRenderItem(item, dimensions)}
|
||||
renderItem={CustomIntroSlider.getIntroRenderItem}
|
||||
slides={this.props.isUpdate ? this.updateSlides : this.introSlides}
|
||||
onDone={() => this.props.onDone()}
|
||||
onDone={this.props.onDone}
|
||||
bottomButton
|
||||
showSkipButton
|
||||
skipLabel={i18n.t('intro.buttons.skip')}
|
||||
|
|
|
@ -30,7 +30,16 @@ 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
|
||||
|
|
|
@ -25,13 +25,18 @@ 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
|
||||
|
@ -203,6 +208,7 @@ 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)
|
||||
|
|
|
@ -25,7 +25,6 @@ type State = {
|
|||
* Used by inheriting from it and redefining getters.
|
||||
*/
|
||||
export default class FetchedDataSectionList extends React.Component<Props, State> {
|
||||
|
||||
webDataManager: WebDataManager;
|
||||
|
||||
willFocusSubscription: function;
|
||||
|
@ -42,12 +41,29 @@ 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}
|
||||
|
@ -74,26 +90,18 @@ export default class FetchedDataSectionList extends React.Component<Props, State
|
|||
*/
|
||||
componentDidMount() {
|
||||
this.willFocusSubscription = this.props.navigation.addListener(
|
||||
'willFocus',
|
||||
() => {
|
||||
this.onScreenFocus();
|
||||
}
|
||||
);
|
||||
'willFocus', this.onScreenFocus.bind(this));
|
||||
this.willBlurSubscription = this.props.navigation.addListener(
|
||||
'willBlur',
|
||||
() => {
|
||||
this.onScreenBlur();
|
||||
}
|
||||
);
|
||||
'willBlur', this.onScreenBlur.bind(this));
|
||||
}
|
||||
|
||||
/**
|
||||
* 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(), this.refreshTime)
|
||||
this.refreshInterval = setInterval(this.onRefresh.bind(this), this.refreshTime)
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -113,11 +121,29 @@ 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;
|
||||
|
@ -127,25 +153,10 @@ export default class FetchedDataSectionList extends React.Component<Props, State
|
|||
if (canRefresh) {
|
||||
this.setState({refreshing: true});
|
||||
this.webDataManager.readData()
|
||||
.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]);
|
||||
});
|
||||
.then(this.onFetchSuccess)
|
||||
.catch(this.onFetchError);
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the render item to be used for display in the list.
|
||||
|
@ -153,10 +164,9 @@ export default class FetchedDataSectionList extends React.Component<Props, State
|
|||
*
|
||||
* @param item
|
||||
* @param section
|
||||
* @param data
|
||||
* @return {*}
|
||||
*/
|
||||
getRenderItem(item: Object, section: Object, data: Object) {
|
||||
getRenderItem(item: Object, section: Object) {
|
||||
return <View/>;
|
||||
}
|
||||
|
||||
|
@ -222,6 +232,11 @@ 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.
|
||||
|
@ -243,7 +258,7 @@ export default class FetchedDataSectionList extends React.Component<Props, State
|
|||
'access-point-network-off'
|
||||
}
|
||||
],
|
||||
keyExtractor: (item: Object) => item.text,
|
||||
keyExtractor: this.datasetKeyExtractor,
|
||||
}
|
||||
];
|
||||
}
|
||||
|
@ -275,6 +290,19 @@ 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
|
||||
*
|
||||
|
@ -292,19 +320,11 @@ export default class FetchedDataSectionList extends React.Component<Props, State
|
|||
refreshControl={
|
||||
<RefreshControl
|
||||
refreshing={this.state.refreshing}
|
||||
onRefresh={this._onRefresh}
|
||||
onRefresh={this.onRefresh}
|
||||
/>
|
||||
}
|
||||
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)
|
||||
}
|
||||
renderSectionHeader={isEmpty ? this.renderSectionHeaderEmpty : this.renderSectionHeaderNotEmpty}
|
||||
renderItem={isEmpty ? this.renderItemEmpty : this.renderItemNotEmpty}
|
||||
style={{minHeight: 300, width: '100%'}}
|
||||
contentContainerStyle={
|
||||
isEmpty ?
|
||||
|
@ -351,11 +371,12 @@ export default class FetchedDataSectionList extends React.Component<Props, State
|
|||
}
|
||||
|
||||
render() {
|
||||
const nav = this.props.navigation;
|
||||
// console.log("rendering FetchedDataSectionList");
|
||||
const dataset = this.createDataset(this.state.fetchedData);
|
||||
return (
|
||||
<BaseContainer
|
||||
navigation={nav} headerTitle={this.getHeaderTranslation()}
|
||||
navigation={this.props.navigation}
|
||||
headerTitle={this.getHeaderTranslation()}
|
||||
headerRightButton={this.getRightButton()}
|
||||
hasTabs={this.hasTabs()}
|
||||
hasBackButton={this.hasBackButton()}
|
||||
|
@ -375,5 +396,4 @@ export default class FetchedDataSectionList extends React.Component<Props, State
|
|||
</BaseContainer>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -30,6 +30,8 @@ export default class SideBar extends React.Component<Props, State> {
|
|||
active: 'Home',
|
||||
};
|
||||
|
||||
getRenderItem: Function;
|
||||
|
||||
/**
|
||||
* Generate the datasets
|
||||
*
|
||||
|
@ -38,7 +40,6 @@ 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'),
|
||||
|
@ -103,21 +104,34 @@ export default class SideBar extends React.Component<Props, State> {
|
|||
icon: "information",
|
||||
},
|
||||
];
|
||||
this.getRenderItem = this.getRenderItem.bind(this);
|
||||
}
|
||||
|
||||
getRenderItem(item: Object) {
|
||||
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);
|
||||
|
||||
if (item.icon !== undefined) {
|
||||
return (
|
||||
<ListItem
|
||||
button
|
||||
noBorder
|
||||
selected={this.state.active === item.route}
|
||||
onPress={() => {
|
||||
if (item.link !== undefined)
|
||||
Linking.openURL(item.link).catch((err) => console.error('Error opening link', err));
|
||||
else
|
||||
this.navigateToScreen(item.route);
|
||||
}}
|
||||
onPress={onListItemPress}
|
||||
>
|
||||
<Left>
|
||||
<CustomMaterialIcon
|
||||
|
@ -155,15 +169,8 @@ 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,
|
||||
|
@ -172,8 +179,8 @@ export default class SideBar extends React.Component<Props, State> {
|
|||
<FlatList
|
||||
data={this.dataSet}
|
||||
extraData={this.state}
|
||||
keyExtractor={(item) => item.route}
|
||||
renderItem={({item}) => this.getRenderItem(item)}
|
||||
keyExtractor={this.listKeyExtractor}
|
||||
renderItem={this.getRenderItem}
|
||||
/>
|
||||
</Container>
|
||||
);
|
||||
|
|
|
@ -35,6 +35,21 @@ 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));
|
||||
}
|
||||
|
@ -43,7 +58,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}/>
|
||||
|
@ -54,45 +69,42 @@ export default class WebViewScreen extends React.Component<Props> {
|
|||
getRefreshButton() {
|
||||
return (
|
||||
<View style={{flexDirection: 'row'}}>
|
||||
{this.getHeaderButton(() => this.refreshWebview(), 'refresh')}
|
||||
{this.getHeaderButton(this.onRefreshClicked, 'refresh')}
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
refreshWebview() {
|
||||
onRefreshClicked() {
|
||||
for (let view of this.webviewArray) {
|
||||
if (view !== null)
|
||||
view.reload();
|
||||
}
|
||||
}
|
||||
|
||||
goBackWebview() {
|
||||
onGoBackWebview() {
|
||||
for (let view of this.webviewArray) {
|
||||
if (view !== null)
|
||||
view.goBack();
|
||||
}
|
||||
}
|
||||
|
||||
goForwardWebview() {
|
||||
onGoForwardWebview() {
|
||||
for (let view of this.webviewArray) {
|
||||
if (view !== null)
|
||||
view.goForward();
|
||||
}
|
||||
}
|
||||
|
||||
getWebview(obj: Object) {
|
||||
onOpenWebLink() {
|
||||
this.openWebLink(this.props.data[0]['url'])
|
||||
}
|
||||
|
||||
onWebviewRef(ref: WebView) {
|
||||
this.webviewArray.push(ref)
|
||||
}
|
||||
|
||||
getRenderLoading() {
|
||||
return (
|
||||
<WebView
|
||||
ref={ref => (this.webviewArray.push(ref))}
|
||||
source={{uri: obj['url']}}
|
||||
style={{
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
}}
|
||||
startInLoadingState={true}
|
||||
injectedJavaScript={obj['customJS']}
|
||||
javaScriptEnabled={true}
|
||||
renderLoading={() =>
|
||||
<View style={{
|
||||
backgroundColor: ThemeManager.getCurrentThemeVariables().containerBgColor,
|
||||
position: 'absolute',
|
||||
|
@ -106,7 +118,22 @@ export default class WebViewScreen extends React.Component<Props> {
|
|||
}}>
|
||||
<Spinner/>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
getWebview(obj: Object) {
|
||||
return (
|
||||
<WebView
|
||||
ref={this.onWebviewRef}
|
||||
source={{uri: obj['url']}}
|
||||
style={{
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
}}
|
||||
startInLoadingState={true}
|
||||
injectedJavaScript={obj['customJS']}
|
||||
javaScriptEnabled={true}
|
||||
renderLoading={this.getRenderLoading}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
@ -133,6 +160,7 @@ export default class WebViewScreen extends React.Component<Props> {
|
|||
}
|
||||
|
||||
render() {
|
||||
// console.log("rendering WebViewScreen");
|
||||
const nav = this.props.navigation;
|
||||
this.webviewArray = [];
|
||||
return (
|
||||
|
@ -166,7 +194,7 @@ export default class WebViewScreen extends React.Component<Props> {
|
|||
<Left style={{
|
||||
paddingLeft: 6,
|
||||
}}>
|
||||
{this.getHeaderButton(() => this.openWebLink(this.props.data[0]['url']), 'open-in-new')}
|
||||
{this.getHeaderButton(this.onOpenWebLink, 'open-in-new')}
|
||||
</Left>
|
||||
<Body/>
|
||||
<Right style={{
|
||||
|
@ -179,8 +207,8 @@ export default class WebViewScreen extends React.Component<Props> {
|
|||
marginRight: 0,
|
||||
marginLeft: 'auto'
|
||||
}}>
|
||||
{this.getHeaderButton(() => this.goBackWebview(), 'chevron-left')}
|
||||
{this.getHeaderButton(() => this.goForwardWebview(), 'chevron-right')}
|
||||
{this.getHeaderButton(this.onGoBackWebview, 'chevron-left')}
|
||||
{this.getHeaderButton(this.onGoForwardWebview, 'chevron-right')}
|
||||
</View>
|
||||
</Right>
|
||||
</Footer> : <View/>}
|
||||
|
|
|
@ -15,7 +15,7 @@ import ThemeManager from "../../utils/ThemeManager";
|
|||
const links = {
|
||||
appstore: 'https://apps.apple.com/us/app/campus-amicale-insat/id1477722148',
|
||||
playstore: 'https://play.google.com/store/apps/details?id=fr.amicaleinsat.application',
|
||||
git: 'https://git.srv-falcon.etud.insa-toulouse.fr/vergnet/application-amicale/src/branch/master/README.md',
|
||||
git: 'https://git.etud.insa-toulouse.fr/vergnet/application-amicale/src/branch/master/README.md',
|
||||
bugsMail: 'mailto:vergnet@etud.insa-toulouse.fr?' +
|
||||
'subject=' +
|
||||
'[BUG] Application Amicale INSA Toulouse' +
|
||||
|
@ -25,9 +25,9 @@ const links = {
|
|||
'Nature du problème :\n\n\n' +
|
||||
'Étapes pour reproduire ce pb :\n\n\n\n' +
|
||||
'Stp corrige le pb, bien cordialement.',
|
||||
bugsGit: 'https://git.srv-falcon.etud.insa-toulouse.fr/vergnet/application-amicale/issues',
|
||||
changelog: 'https://git.srv-falcon.etud.insa-toulouse.fr/vergnet/application-amicale/src/branch/master/Changelog.md',
|
||||
license: 'https://git.srv-falcon.etud.insa-toulouse.fr/vergnet/application-amicale/src/branch/master/LICENSE',
|
||||
bugsGit: 'https://git.etud.insa-toulouse.fr/vergnet/application-amicale/issues',
|
||||
changelog: 'https://git.etud.insa-toulouse.fr/vergnet/application-amicale/src/branch/master/Changelog.md',
|
||||
license: 'https://git.etud.insa-toulouse.fr/vergnet/application-amicale/src/branch/master/LICENSE',
|
||||
authorMail: "mailto:vergnet@etud.insa-toulouse.fr?" +
|
||||
"subject=" +
|
||||
"Application Amicale INSA Toulouse" +
|
||||
|
@ -187,9 +187,14 @@ 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() {
|
||||
|
@ -197,7 +202,7 @@ export default class AboutScreen extends React.Component<Props, State> {
|
|||
<Card>
|
||||
<CardItem>
|
||||
<Left>
|
||||
<Thumbnail square source={require('../../assets/icon.png')}/>
|
||||
<Thumbnail square source={require('../../assets/android.icon.png')}/>
|
||||
<Body>
|
||||
<H1>{appJson.expo.name}</H1>
|
||||
<Text note>
|
||||
|
@ -210,10 +215,8 @@ export default class AboutScreen extends React.Component<Props, State> {
|
|||
data={this.appData}
|
||||
extraData={this.state}
|
||||
keyExtractor={(item) => item.icon}
|
||||
listKey={(item) => "app"}
|
||||
renderItem={({item}) =>
|
||||
this.getCardItem(item.onPressCallback, item.icon, item.text, item.showChevron, item.showOnlyDebug)
|
||||
}
|
||||
listKey={"app"}
|
||||
renderItem={this.getCardItem}
|
||||
/>
|
||||
</Card>
|
||||
);
|
||||
|
@ -241,10 +244,8 @@ export default class AboutScreen extends React.Component<Props, State> {
|
|||
data={this.authorData}
|
||||
extraData={this.state}
|
||||
keyExtractor={(item) => item.icon}
|
||||
listKey={(item) => "team1"}
|
||||
renderItem={({item}) =>
|
||||
this.getCardItem(item.onPressCallback, item.icon, item.text, item.showChevron, item.showOnlyDebug)
|
||||
}
|
||||
listKey={"team1"}
|
||||
renderItem={this.getCardItem}
|
||||
/>
|
||||
<CardItem header>
|
||||
<Text>{i18n.t('aboutScreen.additionalDev')}</Text>
|
||||
|
@ -253,10 +254,8 @@ export default class AboutScreen extends React.Component<Props, State> {
|
|||
data={this.additionalDevData}
|
||||
extraData={this.state}
|
||||
keyExtractor={(item) => item.icon}
|
||||
listKey={(item) => "team2"}
|
||||
renderItem={({item}) =>
|
||||
this.getCardItem(item.onPressCallback, item.icon, item.text, item.showChevron, item.showOnlyDebug)
|
||||
}
|
||||
listKey={"team2"}
|
||||
renderItem={this.getCardItem}
|
||||
/>
|
||||
</Card>
|
||||
);
|
||||
|
@ -272,10 +271,8 @@ export default class AboutScreen extends React.Component<Props, State> {
|
|||
data={this.technoData}
|
||||
extraData={this.state}
|
||||
keyExtractor={(item) => item.icon}
|
||||
listKey={(item) => "techno"}
|
||||
renderItem={({item}) =>
|
||||
this.getCardItem(item.onPressCallback, item.icon, item.text, item.showChevron, item.showOnlyDebug)
|
||||
}
|
||||
listKey={"techno"}
|
||||
renderItem={this.getCardItem}
|
||||
/>
|
||||
</Card>
|
||||
);
|
||||
|
@ -284,24 +281,19 @@ 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(onPressCallback: Function, icon: string, text: string, showChevron: boolean, showOnlyInDebug: boolean) {
|
||||
let shouldShow = !showOnlyInDebug || (showOnlyInDebug && this.state.isDebugUnlocked);
|
||||
getCardItem({item}: Object) {
|
||||
let shouldShow = !item.showOnlyInDebug || (item.showOnlyInDebug && this.state.isDebugUnlocked);
|
||||
if (shouldShow) {
|
||||
return (
|
||||
<CardItem button
|
||||
onPress={onPressCallback}>
|
||||
onPress={item.onPressCallback}>
|
||||
<Left>
|
||||
<CustomMaterialIcon icon={icon}/>
|
||||
<Text>{text}</Text>
|
||||
<CustomMaterialIcon icon={item.icon}/>
|
||||
<Text>{item.text}</Text>
|
||||
</Left>
|
||||
{showChevron ?
|
||||
{item.showChevron ?
|
||||
<Right>
|
||||
<CustomMaterialIcon icon="chevron-right"
|
||||
fontSize={20}/>
|
||||
|
@ -331,6 +323,8 @@ 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
|
||||
|
@ -349,7 +343,7 @@ export default class AboutScreen extends React.Component<Props, State> {
|
|||
marginLeft: 'auto',
|
||||
marginRight: 'auto',
|
||||
}}
|
||||
onPress={() => openWebLink(links.bugsMail)}>
|
||||
onPress={onPressMail}>
|
||||
<CustomMaterialIcon
|
||||
icon={'email'}
|
||||
color={'#fff'}/>
|
||||
|
@ -361,7 +355,7 @@ export default class AboutScreen extends React.Component<Props, State> {
|
|||
marginLeft: 'auto',
|
||||
marginRight: 'auto',
|
||||
}}
|
||||
onPress={() => openWebLink(links.bugsGit)}>
|
||||
onPress={onPressGit}>
|
||||
<CustomMaterialIcon
|
||||
icon={'git'}
|
||||
color={'#fff'}/>
|
||||
|
@ -378,7 +372,7 @@ export default class AboutScreen extends React.Component<Props, State> {
|
|||
}
|
||||
}
|
||||
|
||||
getMainCard(item: Object) {
|
||||
getMainCard({item}: Object) {
|
||||
switch (item.id) {
|
||||
case 'app':
|
||||
return this.getAppCard();
|
||||
|
@ -401,9 +395,7 @@ export default class AboutScreen extends React.Component<Props, State> {
|
|||
data={this.dataOrder}
|
||||
extraData={this.state}
|
||||
keyExtractor={(item) => item.id}
|
||||
renderItem={({item}) =>
|
||||
this.getMainCard(item)
|
||||
}
|
||||
renderItem={this.getMainCard}
|
||||
/>
|
||||
</Container>
|
||||
);
|
||||
|
|
|
@ -14,7 +14,7 @@ import DashboardItem from "../components/DashboardItem";
|
|||
|
||||
const ICON_AMICALE = require('../assets/amicale.png');
|
||||
const NAME_AMICALE = 'Amicale INSA Toulouse';
|
||||
const DATA_URL = "https://srv-falcon.etud.insa-toulouse.fr/~amicale_app/dashboard/dashboard_data.json";
|
||||
const DATA_URL = "https://etud.insa-toulouse.fr/~amicale_app/dashboard/dashboard_data.json";
|
||||
|
||||
const SECTIONS_ID = [
|
||||
'dashboard',
|
||||
|
@ -38,8 +38,33 @@ 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');
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -289,6 +314,14 @@ 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;
|
||||
|
@ -310,12 +343,6 @@ 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);
|
||||
|
||||
|
@ -324,7 +351,7 @@ export default class HomeScreen extends FetchedDataSectionList {
|
|||
subtitle={subtitle}
|
||||
color={color}
|
||||
icon={icon}
|
||||
clickAction={() => clickAction()}
|
||||
clickAction={this.clickAction.bind(this, isAvailable, displayEvent)}
|
||||
title={title}
|
||||
isAvailable={isAvailable}
|
||||
displayEvent={displayEvent}
|
||||
|
@ -355,7 +382,6 @@ 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';
|
||||
|
@ -367,7 +393,6 @@ 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',
|
||||
|
@ -379,7 +404,7 @@ export default class HomeScreen extends FetchedDataSectionList {
|
|||
subtitle={menuSubtitle}
|
||||
color={menuColor}
|
||||
icon={menuIcon}
|
||||
clickAction={() => menuClickAction()}
|
||||
clickAction={this.onMenuClick}
|
||||
title={menuTitle}
|
||||
isAvailable={isMenuAvailable}
|
||||
isSquareLeft={true}/>
|
||||
|
@ -388,13 +413,14 @@ export default class HomeScreen extends FetchedDataSectionList {
|
|||
subtitle={proximoSubtitle}
|
||||
color={proximoColor}
|
||||
icon={proximoIcon}
|
||||
clickAction={() => proximoClickAction()}
|
||||
clickAction={this.onProximoClick}
|
||||
title={proximoTitle}
|
||||
isAvailable={isProximoAvailable}/>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
getDashboardMiddleItem(content: Array<Object>) {
|
||||
let proxiwashData = content[0]['data'];
|
||||
let tutorinsaData = content[1]['data'];
|
||||
|
@ -449,7 +475,6 @@ 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;
|
||||
|
@ -470,7 +495,6 @@ export default class HomeScreen extends FetchedDataSectionList {
|
|||
</Text>;
|
||||
} else
|
||||
tutorinsaSubtitle = i18n.t('homeScreen.dashboard.tutorinsaSubtitleNA');
|
||||
let tutorinsaClickAction = () => this.props.navigation.navigate('TutorInsaScreen');
|
||||
|
||||
return (
|
||||
<View style={{
|
||||
|
@ -483,7 +507,7 @@ export default class HomeScreen extends FetchedDataSectionList {
|
|||
subtitle={proxiwashSubtitle}
|
||||
color={proxiwashColor}
|
||||
icon={proxiwashIcon}
|
||||
clickAction={() => proxiwashClickAction()}
|
||||
clickAction={this.onProxiwashClick}
|
||||
title={proxiwashTitle}
|
||||
isAvailable={proxiwashIsAvailable}
|
||||
isSquareLeft={true}/>
|
||||
|
@ -492,7 +516,7 @@ export default class HomeScreen extends FetchedDataSectionList {
|
|||
subtitle={tutorinsaSubtitle}
|
||||
color={tutorinsaColor}
|
||||
icon={tutorinsaIcon}
|
||||
clickAction={() => tutorinsaClickAction()}
|
||||
clickAction={this.onTutorInsaClick}
|
||||
title={tutorinsaTitle}
|
||||
isAvailable={tutorinsaIsAvailable}/>
|
||||
</View>
|
||||
|
@ -500,7 +524,7 @@ export default class HomeScreen extends FetchedDataSectionList {
|
|||
}
|
||||
|
||||
|
||||
getRenderItem(item: Object, section: Object, data: Object) {
|
||||
getRenderItem(item: Object, section: Object) {
|
||||
return (
|
||||
section['id'] === SECTIONS_ID[0] ? this.getDashboardItem(item) :
|
||||
<Card style={{
|
||||
|
@ -525,7 +549,7 @@ export default class HomeScreen extends FetchedDataSectionList {
|
|||
}}>
|
||||
<Body>
|
||||
{item.full_picture !== '' && item.full_picture !== undefined ?
|
||||
<TouchableOpacity onPress={() => openWebLink(item.full_picture)}
|
||||
<TouchableOpacity onPress={openWebLink.bind(null, item.full_picture)}
|
||||
style={{width: '100%', height: 250, marginBottom: 5}}>
|
||||
<Image source={{uri: item.full_picture}}
|
||||
style={{flex: 1, resizeMode: "contain"}}
|
||||
|
@ -547,7 +571,7 @@ export default class HomeScreen extends FetchedDataSectionList {
|
|||
}}>
|
||||
<Left>
|
||||
<Button transparent
|
||||
onPress={() => openWebLink(item.permalink_url)}>
|
||||
onPress={openWebLink.bind(null, item.permalink_url)}>
|
||||
<CustomMaterialIcon
|
||||
icon="facebook"
|
||||
color="#57aeff"
|
||||
|
|
|
@ -8,13 +8,12 @@ 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(link) {
|
||||
function openWebLink(event, link) {
|
||||
Linking.openURL(link).catch((err) => console.error('Error opening link', err));
|
||||
}
|
||||
|
||||
|
@ -22,8 +21,8 @@ function openWebLink(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 (
|
||||
|
@ -60,7 +59,7 @@ export default class PlanningDisplayScreen extends React.Component<Props> {
|
|||
},
|
||||
div: {color: ThemeManager.getCurrentThemeVariables().textColor}
|
||||
}}
|
||||
onLinkPress={(event, link) => openWebLink(link)}/>
|
||||
onLinkPress={openWebLink}/>
|
||||
: <View/>}
|
||||
</Content>
|
||||
</Container>
|
||||
|
|
|
@ -5,7 +5,6 @@ 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';
|
||||
|
@ -35,14 +34,6 @@ 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
|
||||
*/
|
||||
|
@ -56,12 +47,21 @@ 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,10 +76,25 @@ 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',
|
||||
() =>
|
||||
|
@ -90,7 +105,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;
|
||||
|
@ -126,10 +141,6 @@ export default class PlanningScreen extends React.Component<Props, State> {
|
|||
}
|
||||
|
||||
getRenderItem(item: Object) {
|
||||
let navData = {
|
||||
data: item
|
||||
};
|
||||
const nav = this.props.navigation;
|
||||
return (
|
||||
<Touchable
|
||||
style={{
|
||||
|
@ -138,7 +149,7 @@ export default class PlanningScreen extends React.Component<Props, State> {
|
|||
marginRight: 10,
|
||||
marginTop: 17,
|
||||
}}
|
||||
onPress={() => nav.navigate('PlanningDisplayScreen', navData)}>
|
||||
onPress={() => this.props.navigation.navigate('PlanningDisplayScreen', {data: item})}>
|
||||
<View style={{
|
||||
padding: 10,
|
||||
flex: 1,
|
||||
|
@ -200,7 +211,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;
|
||||
|
@ -221,7 +232,7 @@ export default class PlanningScreen extends React.Component<Props, State> {
|
|||
this.setState({
|
||||
refreshing: false,
|
||||
});
|
||||
console.log(err);
|
||||
// console.log(err);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
@ -252,38 +263,46 @@ 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() {
|
||||
const nav = this.props.navigation;
|
||||
// console.log("rendering PlanningScreen");
|
||||
return (
|
||||
<BaseContainer navigation={nav} headerTitle={i18n.t('screens.planning')}>
|
||||
<BaseContainer navigation={this.props.navigation} 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.getCurrentDate()}
|
||||
selected={this.currentDate}
|
||||
// Minimum date that can be selected, dates before minDate will be grayed out. Default = undefined
|
||||
minDate={this.getCurrentDate()}
|
||||
minDate={this.currentDate}
|
||||
// Max amount of months allowed to scroll to the past. Default = 50
|
||||
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={(calendarOpened) => {
|
||||
this.setState({calendarShowing: calendarOpened})
|
||||
}}
|
||||
onCalendarToggled={this.onCalendarToggled}
|
||||
// Set this true while waiting for new data from a refresh
|
||||
refreshing={this.state.refreshing}
|
||||
renderItem={(item) => this.getRenderItem(item)}
|
||||
renderEmptyDate={() => this.getRenderEmptyDate()}
|
||||
rowHasChanged={() => this.rowHasChanged()}
|
||||
renderItem={this.getRenderItem}
|
||||
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={(ref) => this.agendaRef = ref}
|
||||
ref={this.onAgendaRef}
|
||||
// agenda theme
|
||||
theme={{
|
||||
backgroundColor: ThemeManager.getCurrentThemeVariables().agendaBackgroundColor,
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
// @flow
|
||||
|
||||
import * as React from 'react';
|
||||
import {Image, Linking, View} from 'react-native';
|
||||
import {Image, 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";
|
||||
|
|
|
@ -70,12 +70,28 @@ export default class ProximoListScreen extends React.Component<Props, State> {
|
|||
sortNameIcon: '',
|
||||
modalCurrentDisplayItem: {},
|
||||
};
|
||||
_menu: Menu;
|
||||
sortMenuRef: Menu;
|
||||
|
||||
onMenuRef: Function;
|
||||
onSearchStringChange: Function;
|
||||
onSelectSortModeName: Function;
|
||||
onSelectSortModePrice: Function;
|
||||
onSortMenuPress: Function;
|
||||
renderItem: Function;
|
||||
onListItemPress: Function;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -83,8 +99,8 @@ export default class ProximoListScreen extends React.Component<Props, State> {
|
|||
*
|
||||
* @param ref The menu reference
|
||||
*/
|
||||
setMenuRef = (ref: Menu) => {
|
||||
this._menu = ref;
|
||||
onMenuRef(ref: Menu) {
|
||||
this.sortMenuRef = ref;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -131,7 +147,7 @@ export default class ProximoListScreen extends React.Component<Props, State> {
|
|||
break;
|
||||
}
|
||||
this.setupSortIcons(mode, isReverse);
|
||||
this._menu.hide();
|
||||
this.sortMenuRef.hide();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -214,7 +230,7 @@ export default class ProximoListScreen extends React.Component<Props, State> {
|
|||
return filteredData;
|
||||
}
|
||||
|
||||
search(str: string) {
|
||||
onSearchStringChange(str: string) {
|
||||
this.setState({
|
||||
currentlyDisplayedData: this.filterData(str)
|
||||
})
|
||||
|
@ -251,7 +267,7 @@ export default class ProximoListScreen extends React.Component<Props, State> {
|
|||
);
|
||||
}
|
||||
|
||||
showItemDetails(item: Object) {
|
||||
onListItemPress(item: Object) {
|
||||
this.setState({
|
||||
modalCurrentDisplayItem: item
|
||||
});
|
||||
|
@ -260,16 +276,27 @@ 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.setMenuRef}
|
||||
ref={this.onMenuRef}
|
||||
button={
|
||||
<Touchable
|
||||
style={{padding: 6}}
|
||||
onPress={() =>
|
||||
this._menu.show()
|
||||
}>
|
||||
onPress={this.onSortMenuPress}>
|
||||
<CustomMaterialIcon
|
||||
color={Platform.OS === 'ios' ? ThemeManager.getCurrentThemeVariables().brandPrimary : "#fff"}
|
||||
icon={'sort'}/>
|
||||
|
@ -277,12 +304,12 @@ export default class ProximoListScreen extends React.Component<Props, State> {
|
|||
}
|
||||
>
|
||||
<MenuItem
|
||||
onPress={() => this.sortModeSelected(sortMode.name)}>
|
||||
onPress={this.onSelectSortModeName}>
|
||||
{this.state.sortNameIcon}
|
||||
{i18n.t('proximoScreen.sortName')}
|
||||
</MenuItem>
|
||||
<MenuItem
|
||||
onPress={() => this.sortModeSelected(sortMode.price)}>
|
||||
onPress={this.onSelectSortModePrice}>
|
||||
{this.state.sortPriceIcon}
|
||||
{i18n.t('proximoScreen.sortPrice')}
|
||||
</MenuItem>
|
||||
|
@ -290,35 +317,10 @@ export default class ProximoListScreen extends React.Component<Props, State> {
|
|||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
const nav = this.props.navigation;
|
||||
return (
|
||||
<Container>
|
||||
<Modalize ref={this.modalRef}
|
||||
adjustToContentHeight
|
||||
modalStyle={{backgroundColor: ThemeManager.getCurrentThemeVariables().containerBgColor}}>
|
||||
{this.getModalContent()}
|
||||
</Modalize>
|
||||
<CustomHeader
|
||||
hasBackButton={true}
|
||||
navigation={nav}
|
||||
hasSearchField={true}
|
||||
searchCallback={(text) => this.search(text)}
|
||||
shouldFocusSearchBar={this.shouldFocusSearchBar}
|
||||
rightButton={this.getSortMenu()}
|
||||
/>
|
||||
|
||||
<FlatList
|
||||
data={this.state.currentlyDisplayedData}
|
||||
extraData={this.state.currentlyDisplayedData}
|
||||
keyExtractor={(item) => item.name + item.code}
|
||||
style={{minHeight: 300, width: '100%'}}
|
||||
renderItem={({item}) =>
|
||||
<ListItem
|
||||
renderItem({item}: Object) {
|
||||
return (<ListItem
|
||||
thumbnail
|
||||
onPress={() => {
|
||||
this.showItemDetails(item);
|
||||
}}
|
||||
onPress={this.onListItemPress}
|
||||
>
|
||||
<Left>
|
||||
<Thumbnail square source={{uri: item.image}}/>
|
||||
|
@ -339,7 +341,38 @@ export default class ProximoListScreen extends React.Component<Props, State> {
|
|||
{item.price}€
|
||||
</Text>
|
||||
</Right>
|
||||
</ListItem>}
|
||||
</ListItem>);
|
||||
}
|
||||
|
||||
keyExtractor(item: Object) {
|
||||
return item.name + item.code;
|
||||
}
|
||||
|
||||
render() {
|
||||
// console.log("rendering ProximoListScreen");
|
||||
const nav = this.props.navigation;
|
||||
return (
|
||||
<Container>
|
||||
<Modalize ref={this.modalRef}
|
||||
adjustToContentHeight
|
||||
modalStyle={{backgroundColor: ThemeManager.getCurrentThemeVariables().containerBgColor}}>
|
||||
{this.getModalContent()}
|
||||
</Modalize>
|
||||
<CustomHeader
|
||||
hasBackButton={true}
|
||||
navigation={nav}
|
||||
hasSearchField={true}
|
||||
searchCallback={this.onSearchStringChange}
|
||||
shouldFocusSearchBar={this.shouldFocusSearchBar}
|
||||
rightButton={this.getSortMenu()}
|
||||
/>
|
||||
|
||||
<FlatList
|
||||
data={this.state.currentlyDisplayedData}
|
||||
extraData={this.state.currentlyDisplayedData}
|
||||
keyExtractor={this.keyExtractor}
|
||||
style={{minHeight: 300, width: '100%'}}
|
||||
renderItem={this.renderItem}
|
||||
/>
|
||||
</Container>
|
||||
);
|
||||
|
|
|
@ -9,7 +9,7 @@ import FetchedDataSectionList from "../../components/FetchedDataSectionList";
|
|||
import ThemeManager from "../../utils/ThemeManager";
|
||||
import Touchable from "react-native-platform-touchable";
|
||||
|
||||
const DATA_URL = "https://srv-falcon.etud.insa-toulouse.fr/~proximo/data/stock-v2.json";
|
||||
const DATA_URL = "https://etud.insa-toulouse.fr/~proximo/data/stock-v2.json";
|
||||
|
||||
|
||||
/**
|
||||
|
@ -18,12 +18,31 @@ const DATA_URL = "https://srv-falcon.etud.insa-toulouse.fr/~proximo/data/stock-v
|
|||
*/
|
||||
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) {
|
||||
return a.type.id - b.type.id;
|
||||
let str1 = a.type.name.toLowerCase();
|
||||
let str2 = b.type.name.toLowerCase();
|
||||
|
||||
// Make 'All' category with id -1 stick to the top
|
||||
if (a.type.id === -1)
|
||||
return -1;
|
||||
if (b.type.id === -1)
|
||||
return 1;
|
||||
|
||||
// Sort others by name ascending
|
||||
if (str1 < str2)
|
||||
return -1;
|
||||
if (str1 > str2)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
getHeaderTranslation() {
|
||||
|
@ -63,7 +82,7 @@ export default class ProximoMainScreen extends FetchedDataSectionList {
|
|||
let articles = fetchedData.articles;
|
||||
finalData.push({
|
||||
type: {
|
||||
id: "0",
|
||||
id: -1,
|
||||
name: i18n.t('proximoScreen.all'),
|
||||
icon: 'star'
|
||||
},
|
||||
|
@ -100,7 +119,7 @@ export default class ProximoMainScreen extends FetchedDataSectionList {
|
|||
return availableArticles;
|
||||
}
|
||||
|
||||
getRightButton() {
|
||||
onPressSearchBtn() {
|
||||
let searchScreenData = {
|
||||
shouldFocusSearchBar: true,
|
||||
data: {
|
||||
|
@ -113,8 +132,14 @@ 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={{
|
||||
|
@ -122,14 +147,14 @@ export default class ProximoMainScreen extends FetchedDataSectionList {
|
|||
}}>
|
||||
<Touchable
|
||||
style={{padding: 6}}
|
||||
onPress={() => this.props.navigation.navigate('ProximoListScreen', searchScreenData)}>
|
||||
onPress={this.onPressSearchBtn}>
|
||||
<CustomMaterialIcon
|
||||
color={Platform.OS === 'ios' ? ThemeManager.getCurrentThemeVariables().brandPrimary : "#fff"}
|
||||
icon="magnify"/>
|
||||
</Touchable>
|
||||
<Touchable
|
||||
style={{padding: 6}}
|
||||
onPress={() => this.props.navigation.navigate('ProximoAboutScreen')}>
|
||||
onPress={this.onPressAboutBtn}>
|
||||
<CustomMaterialIcon
|
||||
color={Platform.OS === 'ios' ? ThemeManager.getCurrentThemeVariables().brandPrimary : "#fff"}
|
||||
icon="information"/>
|
||||
|
@ -138,19 +163,18 @@ export default class ProximoMainScreen extends FetchedDataSectionList {
|
|||
);
|
||||
}
|
||||
|
||||
getRenderItem(item: Object, section: Object, data: Object) {
|
||||
getRenderItem(item: Object, section: 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={() => {
|
||||
this.props.navigation.navigate('ProximoListScreen', dataToSend);
|
||||
}}
|
||||
onPress={onPress}
|
||||
>
|
||||
<Left>
|
||||
<CustomMaterialIcon
|
||||
|
|
|
@ -13,7 +13,7 @@ import Touchable from "react-native-platform-touchable";
|
|||
import AsyncStorageManager from "../../utils/AsyncStorageManager";
|
||||
import * as Expo from "expo";
|
||||
|
||||
const DATA_URL = "https://srv-falcon.etud.insa-toulouse.fr/~amicale_app/washinsa/washinsa.json";
|
||||
const DATA_URL = "https://etud.insa-toulouse.fr/~amicale_app/washinsa/washinsa.json";
|
||||
|
||||
const MACHINE_STATES = {
|
||||
"TERMINE": "0",
|
||||
|
@ -36,6 +36,8 @@ 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
|
||||
*/
|
||||
|
@ -75,6 +77,8 @@ export default class ProxiwashScreen extends FetchedDataSectionList {
|
|||
machinesWatched: [],
|
||||
};
|
||||
this.setMinTimeRefresh(30);
|
||||
|
||||
this.onAboutPress = this.onAboutPress.bind(this);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -82,7 +86,6 @@ export default class ProxiwashScreen extends FetchedDataSectionList {
|
|||
*/
|
||||
componentDidMount() {
|
||||
super.componentDidMount();
|
||||
|
||||
if (AsyncStorageManager.getInstance().preferences.expoToken.current !== '') {
|
||||
// Get latest watchlist from server
|
||||
NotificationsManager.getMachineNotificationWatchlist((fetchedList) => {
|
||||
|
@ -241,13 +244,14 @@ 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: () => this.setupNotifications(item.number)
|
||||
onPress: onPress
|
||||
},
|
||||
{
|
||||
text: i18n.t("proxiwashScreen.modal.cancel")
|
||||
|
@ -272,11 +276,15 @@ export default class ProxiwashScreen extends FetchedDataSectionList {
|
|||
);
|
||||
}
|
||||
|
||||
onAboutPress() {
|
||||
this.props.navigation.navigate('ProxiwashAboutScreen');
|
||||
}
|
||||
|
||||
getRightButton(): * {
|
||||
return (
|
||||
<Touchable
|
||||
style={{padding: 6}}
|
||||
onPress={() => this.props.navigation.navigate('ProxiwashAboutScreen')}>
|
||||
onPress={this.onAboutPress}>
|
||||
<CustomMaterialIcon
|
||||
color={Platform.OS === 'ios' ? ThemeManager.getCurrentThemeVariables().brandPrimary : "#fff"}
|
||||
icon="information"/>
|
||||
|
@ -289,13 +297,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, data: Object) {
|
||||
getRenderItem(item: Object, section: 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,
|
||||
|
@ -320,7 +328,7 @@ export default class ProxiwashScreen extends FetchedDataSectionList {
|
|||
backgroundColor: ThemeManager.getCurrentThemeVariables().containerBgColor
|
||||
}}/>
|
||||
<PlatformTouchable
|
||||
onPress={() => this.showAlert(machineName, item, isDryer)}
|
||||
onPress={onPress}
|
||||
style={{
|
||||
height: 64,
|
||||
position: 'absolute',
|
||||
|
|
|
@ -7,7 +7,7 @@ import ThemeManager from "../utils/ThemeManager";
|
|||
import i18n from "i18n-js";
|
||||
import FetchedDataSectionList from "../components/FetchedDataSectionList";
|
||||
|
||||
const DATA_URL = "https://srv-falcon.etud.insa-toulouse.fr/~amicale_app/menu/menu_data.json";
|
||||
const DATA_URL = "https://etud.insa-toulouse.fr/~amicale_app/menu/menu_data.json";
|
||||
|
||||
/**
|
||||
* Class defining the app's menu screen.
|
||||
|
@ -119,7 +119,7 @@ export default class SelfMenuScreen extends FetchedDataSectionList {
|
|||
);
|
||||
}
|
||||
|
||||
getRenderItem(item: Object, section: Object, data: Object) {
|
||||
getRenderItem(item: Object, section: Object) {
|
||||
return (
|
||||
<Card style={{
|
||||
flex: 0,
|
||||
|
|
|
@ -43,6 +43,17 @@ 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
|
||||
*
|
||||
|
@ -118,7 +129,7 @@ export default class SettingsScreen extends React.Component<Props, State> {
|
|||
mode="dropdown"
|
||||
style={{width: 120}}
|
||||
selectedValue={this.state.proxiwashNotifPickerSelected}
|
||||
onValueChange={(value) => this.onProxiwashNotifPickerValueChange(value)}
|
||||
onValueChange={this.onProxiwashNotifPickerValueChange}
|
||||
>
|
||||
<Picker.Item label={i18n.t('settingsScreen.proxiwashNotifReminderPicker.never')} value="never"/>
|
||||
<Picker.Item label={i18n.t('settingsScreen.proxiwashNotifReminderPicker.5')} value="5"/>
|
||||
|
@ -141,7 +152,7 @@ export default class SettingsScreen extends React.Component<Props, State> {
|
|||
mode="dropdown"
|
||||
style={{width: 120}}
|
||||
selectedValue={this.state.startScreenPickerSelected}
|
||||
onValueChange={(value) => this.onStartScreenPickerValueChange(value)}
|
||||
onValueChange={this.onStartScreenPickerValueChange}
|
||||
>
|
||||
<Picker.Item label={i18n.t('screens.home')} value="Home"/>
|
||||
<Picker.Item label={i18n.t('screens.planning')} value="Planning"/>
|
||||
|
@ -155,7 +166,7 @@ export default class SettingsScreen extends React.Component<Props, State> {
|
|||
/**
|
||||
* Toggle night mode and save it to preferences
|
||||
*/
|
||||
toggleNightMode() {
|
||||
onToggleNightMode() {
|
||||
ThemeManager.getInstance().setNightMode(!this.state.nightMode);
|
||||
this.setState({nightMode: !this.state.nightMode});
|
||||
this.resetStack();
|
||||
|
@ -203,7 +214,7 @@ export default class SettingsScreen extends React.Component<Props, State> {
|
|||
<Right>
|
||||
<CheckBox
|
||||
checked={this.state.nightMode}
|
||||
onPress={() => this.toggleNightMode()}
|
||||
onPress={onPressCallback}
|
||||
style={{marginRight: 20}}/>
|
||||
</Right>
|
||||
</ListItem>
|
||||
|
@ -221,7 +232,7 @@ export default class SettingsScreen extends React.Component<Props, State> {
|
|||
<Text>{i18n.t('settingsScreen.generalCard')}</Text>
|
||||
</CardItem>
|
||||
<List>
|
||||
{this.getToggleItem(() => this.toggleNightMode(), 'theme-light-dark', i18n.t('settingsScreen.nightMode'), i18n.t('settingsScreen.nightModeSub'))}
|
||||
{this.getToggleItem(this.onToggleNightMode, '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>
|
||||
|
|
|
@ -8,7 +8,7 @@ type Props = {
|
|||
}
|
||||
|
||||
|
||||
const URL = 'https://www.etud.insa-toulouse.fr/~amicale';
|
||||
const URL = 'https://amicale-insat.fr/';
|
||||
|
||||
/**
|
||||
* Class defining the app's planex screen.
|
||||
|
|
|
@ -12,8 +12,8 @@ type Props = {
|
|||
const ROOM_URL = 'http://planex.insa-toulouse.fr/salles.php';
|
||||
const PC_URL = 'http://planex.insa-toulouse.fr/sallesInfo.php';
|
||||
const BIB_URL = 'https://bibbox.insa-toulouse.fr/';
|
||||
const CUSTOM_CSS_GENERAL = 'https://srv-falcon.etud.insa-toulouse.fr/~amicale_app/custom_css/rooms/customMobile.css';
|
||||
const CUSTOM_CSS_Bib = 'https://srv-falcon.etud.insa-toulouse.fr/~amicale_app/custom_css/rooms/customBibMobile.css';
|
||||
const CUSTOM_CSS_GENERAL = 'https://etud.insa-toulouse.fr/~amicale_app/custom_css/rooms/customMobile.css';
|
||||
const CUSTOM_CSS_Bib = 'https://etud.insa-toulouse.fr/~amicale_app/custom_css/rooms/customBibMobile.css';
|
||||
|
||||
/**
|
||||
* Class defining the app's planex screen.
|
||||
|
|
|
@ -11,7 +11,7 @@ type Props = {
|
|||
|
||||
const URL = 'https://etud-mel.insa-toulouse.fr/webmail/';
|
||||
|
||||
const CUSTOM_CSS_GENERAL = 'https://srv-falcon.etud.insa-toulouse.fr/~amicale_app/custom_css/bluemind/customMobile.css';
|
||||
const CUSTOM_CSS_GENERAL = 'https://etud.insa-toulouse.fr/~amicale_app/custom_css/bluemind/customMobile.css';
|
||||
|
||||
|
||||
/**
|
||||
|
|
|
@ -8,7 +8,7 @@ type Props = {
|
|||
}
|
||||
|
||||
|
||||
const URL = 'https://srv-falcon.etud.insa-toulouse.fr/~eeinsat/';
|
||||
const URL = 'https://etud.insa-toulouse.fr/~eeinsat/';
|
||||
|
||||
/**
|
||||
* Class defining the app's planex screen.
|
||||
|
|
|
@ -11,12 +11,12 @@ type Props = {
|
|||
|
||||
const URL = 'https://ent.insa-toulouse.fr/';
|
||||
|
||||
const CUSTOM_CSS_GENERAL = 'https://srv-falcon.etud.insa-toulouse.fr/~amicale_app/custom_css/ent/customMobile.css';
|
||||
const CUSTOM_CSS_GENERAL = 'https://etud.insa-toulouse.fr/~amicale_app/custom_css/ent/customMobile.css';
|
||||
|
||||
// let stylesheet = document.createElement('link');
|
||||
// stylesheet.type = 'text/css';
|
||||
// stylesheet.rel = 'stylesheet';
|
||||
// stylesheet.href = 'https://srv-falcon.etud.insa-toulouse.fr/~amicale_app/custom_css/ent/customMobile.css';
|
||||
// stylesheet.href = 'https://etud.insa-toulouse.fr/~amicale_app/custom_css/ent/customMobile.css';
|
||||
// let mobileSpec = document.createElement('meta');
|
||||
// mobileSpec.name = 'viewport';
|
||||
// mobileSpec.content = 'width=device-width, initial-scale=1.0';
|
||||
|
|
|
@ -11,8 +11,8 @@ type Props = {
|
|||
|
||||
const PLANEX_URL = 'http://planex.insa-toulouse.fr/';
|
||||
|
||||
const CUSTOM_CSS_GENERAL = 'https://srv-falcon.etud.insa-toulouse.fr/~amicale_app/custom_css/planex/customMobile3.css';
|
||||
const CUSTOM_CSS_NIGHTMODE = 'https://srv-falcon.etud.insa-toulouse.fr/~amicale_app/custom_css/planex/customDark2.css';
|
||||
const CUSTOM_CSS_GENERAL = 'https://etud.insa-toulouse.fr/~amicale_app/custom_css/planex/customMobile3.css';
|
||||
const CUSTOM_CSS_NIGHTMODE = 'https://etud.insa-toulouse.fr/~amicale_app/custom_css/planex/customDark2.css';
|
||||
|
||||
// // JS + JQuery functions used to remove alpha from events. Copy paste in browser console for quick testing
|
||||
// // Remove alpha from given Jquery node
|
||||
|
|
|
@ -8,7 +8,7 @@ type Props = {
|
|||
}
|
||||
|
||||
|
||||
const URL = 'https://www.etud.insa-toulouse.fr/wiketud';
|
||||
const URL = 'https://wiki.etud.insa-toulouse.fr/';
|
||||
|
||||
/**
|
||||
* Class defining the app's planex screen.
|
||||
|
|
|
@ -6,7 +6,7 @@ import AsyncStorageManager from "./AsyncStorageManager";
|
|||
import LocaleManager from "./LocaleManager";
|
||||
import passwords from "../passwords";
|
||||
|
||||
const EXPO_TOKEN_SERVER = 'https://srv-falcon.etud.insa-toulouse.fr/~amicale_app/expo_notifications/save_token.php';
|
||||
const EXPO_TOKEN_SERVER = 'https://etud.insa-toulouse.fr/~amicale_app/expo_notifications/save_token.php';
|
||||
|
||||
/**
|
||||
* Static class used to manage notifications sent to the user
|
||||
|
@ -123,18 +123,8 @@ 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');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -161,16 +151,7 @@ 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');
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -194,16 +175,7 @@ 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');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue