forked from vergnet/application-amicale
Added mascot to every main screen and allow cancel with back button
This commit is contained in:
parent
761132732b
commit
2a9bf5bb6a
5 changed files with 168 additions and 50 deletions
|
@ -4,7 +4,7 @@ import * as React from 'react';
|
|||
import {Avatar, Button, Card, Paragraph, Portal, withTheme} from 'react-native-paper';
|
||||
import Mascot from "./Mascot";
|
||||
import * as Animatable from "react-native-animatable";
|
||||
import {Dimensions, ScrollView, TouchableWithoutFeedback, View} from "react-native";
|
||||
import {BackHandler, Dimensions, ScrollView, TouchableWithoutFeedback, View} from "react-native";
|
||||
import type {CustomTheme} from "../../managers/ThemeManager";
|
||||
|
||||
type Props = {
|
||||
|
@ -62,13 +62,35 @@ class MascotPopup extends React.Component<Props, State> {
|
|||
}
|
||||
|
||||
shouldComponentUpdate(nextProps: Props): boolean {
|
||||
if (nextProps.visible)
|
||||
if (nextProps.visible) {
|
||||
this.state.shouldShowDialog = true;
|
||||
else if (nextProps.visible !== this.props.visible)
|
||||
}else if (nextProps.visible !== this.props.visible) {
|
||||
setTimeout(this.onAnimationEnd, 300);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
componentDidMount(): * {
|
||||
BackHandler.addEventListener(
|
||||
'hardwareBackPress',
|
||||
this.onBackButtonPressAndroid
|
||||
)
|
||||
}
|
||||
|
||||
onBackButtonPressAndroid = () => {
|
||||
if (this.state.shouldShowDialog) {
|
||||
const cancel = this.props.buttons.cancel;
|
||||
const action = this.props.buttons.action;
|
||||
if (cancel != null)
|
||||
cancel.onPress();
|
||||
else
|
||||
action.onPress();
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
getSpeechBubble() {
|
||||
return (
|
||||
<Animatable.View
|
||||
|
|
|
@ -59,8 +59,8 @@ export default class AsyncStorageManager {
|
|||
default: 'home',
|
||||
current: '',
|
||||
},
|
||||
homeShowBanner: {
|
||||
key: 'homeShowBanner',
|
||||
servicesShowBanner: {
|
||||
key: 'servicesShowBanner',
|
||||
default: '1',
|
||||
current: '',
|
||||
},
|
||||
|
@ -69,9 +69,14 @@ export default class AsyncStorageManager {
|
|||
default: '1',
|
||||
current: '',
|
||||
},
|
||||
proxiwashWatchedMachines: {
|
||||
key: 'proxiwashWatchedMachines',
|
||||
default: '[]',
|
||||
homeShowBanner: {
|
||||
key: 'homeShowBanner',
|
||||
default: '1',
|
||||
current: '',
|
||||
},
|
||||
eventsShowBanner: {
|
||||
key: 'eventsShowBanner',
|
||||
default: '1',
|
||||
current: '',
|
||||
},
|
||||
planexShowBanner: {
|
||||
|
@ -79,6 +84,11 @@ export default class AsyncStorageManager {
|
|||
default: '1',
|
||||
current: '',
|
||||
},
|
||||
proxiwashWatchedMachines: {
|
||||
key: 'proxiwashWatchedMachines',
|
||||
default: '[]',
|
||||
current: '',
|
||||
},
|
||||
showAprilFoolsStart: {
|
||||
key: 'showAprilFoolsStart',
|
||||
default: '1',
|
||||
|
|
|
@ -15,6 +15,9 @@ import {
|
|||
import {Avatar, Divider, List} from 'react-native-paper';
|
||||
import CustomAgenda from "../../components/Overrides/CustomAgenda";
|
||||
import {StackNavigationProp} from "@react-navigation/stack";
|
||||
import {MASCOT_STYLE} from "../../components/Mascot/Mascot";
|
||||
import MascotPopup from "../../components/Mascot/MascotPopup";
|
||||
import AsyncStorageManager from "../../managers/AsyncStorageManager";
|
||||
|
||||
LocaleConfig.locales['fr'] = {
|
||||
monthNames: ['Janvier', 'Février', 'Mars', 'Avril', 'Mai', 'Juin', 'Juillet', 'Août', 'Septembre', 'Octobre', 'Novembre', 'Décembre'],
|
||||
|
@ -33,6 +36,7 @@ type State = {
|
|||
refreshing: boolean,
|
||||
agendaItems: Object,
|
||||
calendarShowing: boolean,
|
||||
mascotDialogVisible: boolean,
|
||||
};
|
||||
|
||||
const FETCH_URL = "https://www.amicale-insat.fr/api/event/list";
|
||||
|
@ -52,6 +56,7 @@ class PlanningScreen extends React.Component<Props, State> {
|
|||
refreshing: false,
|
||||
agendaItems: {},
|
||||
calendarShowing: false,
|
||||
mascotDialogVisible: AsyncStorageManager.getInstance().preferences.eventsShowBanner.current === "1"
|
||||
};
|
||||
|
||||
currentDate = getDateOnlyString(getCurrentDateString());
|
||||
|
@ -100,6 +105,18 @@ class PlanningScreen extends React.Component<Props, State> {
|
|||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Callback used when closing the banner.
|
||||
* This hides the banner and saves to preferences to prevent it from reopening
|
||||
*/
|
||||
onHideMascotDialog = () => {
|
||||
this.setState({mascotDialogVisible: false});
|
||||
AsyncStorageManager.getInstance().savePref(
|
||||
AsyncStorageManager.getInstance().preferences.eventsShowBanner.key,
|
||||
'0'
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Function used to check if a row has changed
|
||||
*
|
||||
|
@ -206,34 +223,51 @@ class PlanningScreen extends React.Component<Props, State> {
|
|||
|
||||
render() {
|
||||
return (
|
||||
<CustomAgenda
|
||||
{...this.props}
|
||||
// the list of items that have to be displayed in agenda. If you want to render item as empty date
|
||||
// the value of date key kas to be an empty array []. If there exists no value for date key it is
|
||||
// considered that the date in question is not yet loaded
|
||||
items={this.state.agendaItems}
|
||||
// initially selected day
|
||||
selected={this.currentDate}
|
||||
// Minimum date that can be selected, dates before minDate will be grayed out. Default = undefined
|
||||
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}
|
||||
// callback that fires when the calendar is opened or closed
|
||||
onCalendarToggled={this.onCalendarToggled}
|
||||
// Set this true while waiting for new data from a refresh
|
||||
refreshing={this.state.refreshing}
|
||||
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
|
||||
onRef={this.onAgendaRef}
|
||||
/>
|
||||
<View style={{flex: 1}}>
|
||||
<CustomAgenda
|
||||
{...this.props}
|
||||
// the list of items that have to be displayed in agenda. If you want to render item as empty date
|
||||
// the value of date key kas to be an empty array []. If there exists no value for date key it is
|
||||
// considered that the date in question is not yet loaded
|
||||
items={this.state.agendaItems}
|
||||
// initially selected day
|
||||
selected={this.currentDate}
|
||||
// Minimum date that can be selected, dates before minDate will be grayed out. Default = undefined
|
||||
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}
|
||||
// callback that fires when the calendar is opened or closed
|
||||
onCalendarToggled={this.onCalendarToggled}
|
||||
// Set this true while waiting for new data from a refresh
|
||||
refreshing={this.state.refreshing}
|
||||
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
|
||||
onRef={this.onAgendaRef}
|
||||
/>
|
||||
<MascotPopup
|
||||
visible={this.state.mascotDialogVisible}
|
||||
title={i18n.t("planningScreen.mascotTitle")}
|
||||
message={i18n.t("planningScreen.mascotMessage")}
|
||||
icon={"calendar-range"}
|
||||
buttons={{
|
||||
action: null,
|
||||
cancel: {
|
||||
message: i18n.t("planningScreen.mascotButton"),
|
||||
icon: "check",
|
||||
onPress: this.onHideMascotDialog,
|
||||
}
|
||||
}}
|
||||
emotion={MASCOT_STYLE.HAPPY}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,6 +14,9 @@ import MaterialHeaderButtons, {Item} from "../../components/Overrides/CustomHead
|
|||
import ConnectionManager from "../../managers/ConnectionManager";
|
||||
import {StackNavigationProp} from "@react-navigation/stack";
|
||||
import AvailableWebsites from "../../constants/AvailableWebsites";
|
||||
import {MASCOT_STYLE} from "../../components/Mascot/Mascot";
|
||||
import MascotPopup from "../../components/Mascot/MascotPopup";
|
||||
import AsyncStorageManager from "../../managers/AsyncStorageManager";
|
||||
|
||||
type Props = {
|
||||
navigation: StackNavigationProp,
|
||||
|
@ -21,6 +24,11 @@ type Props = {
|
|||
theme: CustomTheme,
|
||||
}
|
||||
|
||||
type State = {
|
||||
mascotDialogVisible: boolean,
|
||||
}
|
||||
|
||||
|
||||
export type listItem = {
|
||||
title: string,
|
||||
description: string,
|
||||
|
@ -49,7 +57,7 @@ const EMAIL_IMAGE = "https://etud.insa-toulouse.fr/~amicale_app/images/Bluemind.
|
|||
const ENT_IMAGE = "https://etud.insa-toulouse.fr/~amicale_app/images/ENT.png";
|
||||
const ACCOUNT_IMAGE = "https://etud.insa-toulouse.fr/~amicale_app/images/Account.png";
|
||||
|
||||
class ServicesScreen extends React.Component<Props> {
|
||||
class ServicesScreen extends React.Component<Props, State> {
|
||||
|
||||
amicaleDataset: cardList;
|
||||
studentsDataset: cardList;
|
||||
|
@ -57,6 +65,10 @@ class ServicesScreen extends React.Component<Props> {
|
|||
|
||||
finalDataset: Array<listItem>
|
||||
|
||||
state = {
|
||||
mascotDialogVisible: AsyncStorageManager.getInstance().preferences.servicesShowBanner.current === "1"
|
||||
}
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
const nav = props.navigation;
|
||||
|
@ -187,6 +199,19 @@ class ServicesScreen extends React.Component<Props> {
|
|||
});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Callback used when closing the banner.
|
||||
* This hides the banner and saves to preferences to prevent it from reopening
|
||||
*/
|
||||
onHideMascotDialog = () => {
|
||||
this.setState({mascotDialogVisible: false});
|
||||
AsyncStorageManager.getInstance().savePref(
|
||||
AsyncStorageManager.getInstance().preferences.servicesShowBanner.key,
|
||||
'0'
|
||||
);
|
||||
};
|
||||
|
||||
getAboutButton = () =>
|
||||
<MaterialHeaderButtons>
|
||||
<Item title="information" iconName="information" onPress={this.onAboutPress}/>
|
||||
|
@ -271,18 +296,37 @@ class ServicesScreen extends React.Component<Props> {
|
|||
|
||||
render() {
|
||||
const {containerPaddingTop, scrollIndicatorInsetTop, onScroll} = this.props.collapsibleStack;
|
||||
return <Animated.FlatList
|
||||
data={this.finalDataset}
|
||||
renderItem={this.renderItem}
|
||||
keyExtractor={this.keyExtractor}
|
||||
onScroll={onScroll}
|
||||
contentContainerStyle={{
|
||||
paddingTop: containerPaddingTop,
|
||||
paddingBottom: CustomTabBar.TAB_BAR_HEIGHT + 20
|
||||
}}
|
||||
scrollIndicatorInsets={{top: scrollIndicatorInsetTop}}
|
||||
ItemSeparatorComponent={() => <Divider/>}
|
||||
/>
|
||||
return (
|
||||
<View>
|
||||
<Animated.FlatList
|
||||
data={this.finalDataset}
|
||||
renderItem={this.renderItem}
|
||||
keyExtractor={this.keyExtractor}
|
||||
onScroll={onScroll}
|
||||
contentContainerStyle={{
|
||||
paddingTop: containerPaddingTop,
|
||||
paddingBottom: CustomTabBar.TAB_BAR_HEIGHT + 20
|
||||
}}
|
||||
scrollIndicatorInsets={{top: scrollIndicatorInsetTop}}
|
||||
ItemSeparatorComponent={() => <Divider/>}
|
||||
/>
|
||||
<MascotPopup
|
||||
visible={this.state.mascotDialogVisible}
|
||||
title={i18n.t("servicesScreen.mascot.title")}
|
||||
message={i18n.t("servicesScreen.mascot.message")}
|
||||
icon={"calendar-range"}
|
||||
buttons={{
|
||||
action: null,
|
||||
cancel: {
|
||||
message: i18n.t("servicesScreen.mascot.button"),
|
||||
icon: "check",
|
||||
onPress: this.onHideMascotDialog,
|
||||
}
|
||||
}}
|
||||
emotion={MASCOT_STYLE.WINK}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -436,10 +436,18 @@
|
|||
"ent": "See your grades",
|
||||
"insaAccount": "See your information and change your password",
|
||||
"equipment": "Book a BBQ or other equipment"
|
||||
},
|
||||
"mascot": {
|
||||
"title": "So handy!",
|
||||
"message": "There a lot of thing you can do with Campus!\n\nHere is a list of every service provided by the app.",
|
||||
"button": "Thx buddy"
|
||||
}
|
||||
},
|
||||
"planningScreen": {
|
||||
"invalidEvent": "Could not find the event. Please make sure the event you are trying to access is valid."
|
||||
"invalidEvent": "Could not find the event. Please make sure the event you are trying to access is valid.",
|
||||
"mascotTitle": "Let's party!",
|
||||
"mascotMessage": "At the INSA, it's not all about classes!\n\nIf you want to see new people, this page is just for you. Here you will find the list of every event organised by students!",
|
||||
"mascotButton": "Thx!"
|
||||
},
|
||||
"feedbackScreen": {
|
||||
"bugs": "Report Bugs",
|
||||
|
|
Loading…
Reference in a new issue