diff --git a/App.js b/App.js index 42fcfe4..5de5714 100644 --- a/App.js +++ b/App.js @@ -1,10 +1,9 @@ // @flow import * as React from 'react'; -import {StatusBar, Platform} from 'react-native'; +import {Platform, StatusBar} from 'react-native'; import {Root, StyleProvider} from 'native-base'; import {createAppContainerWithInitialRoute} from './navigation/AppNavigator'; -import ThemeManager from './utils/ThemeManager'; import LocaleManager from './utils/LocaleManager'; import * as Font from 'expo-font'; import {clearThemeCache} from 'native-base-shoutem-theme'; @@ -12,6 +11,7 @@ import AsyncStorageManager from "./utils/AsyncStorageManager"; import CustomIntroSlider from "./components/CustomIntroSlider"; import {AppLoading} from 'expo'; import NotificationsManager from "./utils/NotificationsManager"; +import ThemeManager from './utils/ThemeManager'; type Props = {}; @@ -49,12 +49,9 @@ export default class App extends React.Component { setupStatusBar() { if (Platform.OS === 'ios') { - console.log(ThemeManager.getNightMode()); if (ThemeManager.getNightMode()) { - console.log('setting light mode'); StatusBar.setBarStyle('light-content', true); } else { - console.log('setting dark mode'); StatusBar.setBarStyle('dark-content', true); } } @@ -73,7 +70,6 @@ export default class App extends React.Component { } async loadAssetsAsync() { - console.log('Starting loading assets...'); // Wait for custom fonts to be loaded before showing the app await Font.loadAsync({ 'Roboto': require('native-base/Fonts/Roboto.ttf'), @@ -83,18 +79,15 @@ export default class App extends React.Component { await AsyncStorageManager.getInstance().loadPreferences(); ThemeManager.getInstance().setUpdateThemeCallback(() => this.updateTheme()); await NotificationsManager.initExpoToken(); - // console.log(AsyncStorageManager.getInstance().preferences.expoToken.current); } onLoadFinished() { // Only show intro if this is the first time starting the app - console.log('Finished loading'); this.setState({ isLoading: false, currentTheme: ThemeManager.getCurrentTheme(), showIntro: AsyncStorageManager.getInstance().preferences.showIntro.current === '1', showUpdate: AsyncStorageManager.getInstance().preferences.showUpdate5.current === '1' - // showIntro: true }); // Status bar goes dark if set too fast setTimeout(this.setupStatusBar, diff --git a/Changelog.md b/Changelog.md index 6e15d2c..71fce28 100644 --- a/Changelog.md +++ b/Changelog.md @@ -2,6 +2,15 @@ Pensez à garder l'appli à jour pour profiter des dernières fonctionnalités ! + - **v1.5.0** - _05/02/2020_ + - Amélioration des performances de l'application + - Amélioration du menu gauche + - Ajout d'animations au changement d'écran + - Affichage de l'événement de l'accueil directement au clic, au lieu de juste amener sur la liste + - _Notes de développement :_ + - Passage de React Navigation 3 à 4 + - Mise à jour d'autres librairies + - **v1.4.0** - _01/02/2020_ - Correction d'un crash lors du rafraichissement de planex - Correction de bugs divers diff --git a/app.json b/app.json index 24144dd..ceaf9ed 100644 --- a/app.json +++ b/app.json @@ -10,7 +10,7 @@ "android", "web" ], - "version": "1.4.0", + "version": "1.5.0", "orientation": "portrait", "primaryColor": "#be1522", "icon": "./assets/android.icon.png", @@ -36,7 +36,7 @@ }, "android": { "package": "fr.amicaleinsat.application", - "versionCode": 12, + "versionCode": 13, "icon": "./assets/android.icon.png", "adaptiveIcon": { "foregroundImage": "./assets/android.adaptive-icon.png", diff --git a/babel.config.js b/babel.config.js index 2900afe..5a71250 100644 --- a/babel.config.js +++ b/babel.config.js @@ -2,5 +2,10 @@ module.exports = function(api) { api.cache(true); return { presets: ['babel-preset-expo'], + env: { + production: { + plugins: ['react-native-paper/babel'], + }, + }, }; }; diff --git a/components/BaseContainer.js b/components/BaseContainer.js index 7c97a98..1e4fa85 100644 --- a/components/BaseContainer.js +++ b/components/BaseContainer.js @@ -3,7 +3,6 @@ import * as React from 'react'; import {Container} from "native-base"; import CustomHeader from "./CustomHeader"; -import CustomSideMenu from "./CustomSideMenu"; import CustomMaterialIcon from "./CustomMaterialIcon"; import {Platform, StatusBar, View} from "react-native"; import ThemeManager from "../utils/ThemeManager"; @@ -15,6 +14,7 @@ import {NavigationActions} from "react-navigation"; type Props = { navigation: Object, headerTitle: string, + headerSubtitle: string, headerRightButton: React.Node, children: React.Node, hasTabs: boolean, @@ -25,7 +25,6 @@ type Props = { } type State = { - isOpen: boolean, isHeaderVisible: boolean } @@ -39,24 +38,17 @@ export default class BaseContainer extends React.Component { hasSideMenu: true, enableRotation: false, hideHeaderOnLandscape: false, + headerSubtitle: '', }; willBlurSubscription: function; willFocusSubscription: function; state = { - isOpen: false, isHeaderVisible: true, }; toggle() { - this.setState({ - isOpen: !this.state.isOpen, - }); + this.props.navigation.toggleDrawer(); } - - updateMenuState(isOpen: boolean) { - this.setState({isOpen}); - } - /** * Register for blur event to close side menu on screen change */ @@ -87,7 +79,6 @@ export default class BaseContainer extends React.Component { () => { if (this.props.enableRotation) ScreenOrientation.lockAsync(ScreenOrientation.Orientation.PORTRAIT); - this.setState({isOpen: false}); } ); } @@ -107,7 +98,9 @@ export default class BaseContainer extends React.Component { {this.state.isHeaderVisible ? { render() { - return ( - - {this.props.hasSideMenu ? - this.updateMenuState(isOpen)}> - {this.getMainContainer()} - : - this.getMainContainer()} - - ); + return (this.getMainContainer()); } } diff --git a/components/CustomHeader.js b/components/CustomHeader.js index 091f6f3..0290c89 100644 --- a/components/CustomHeader.js +++ b/components/CustomHeader.js @@ -1,13 +1,14 @@ // @flow import * as React from "react"; -import {Body, Header, Input, Item, Left, Right, Title} from "native-base"; +import {Body, Header, Input, Item, Left, Right, Subtitle, Title} from "native-base"; import {Platform, StyleSheet, View} from "react-native"; import {getStatusBarHeight} from "react-native-status-bar-height"; import Touchable from 'react-native-platform-touchable'; import ThemeManager from "../utils/ThemeManager"; import CustomMaterialIcon from "./CustomMaterialIcon"; import i18n from "i18n-js"; +import {NavigationActions} from 'react-navigation'; type Props = { hasBackButton: boolean, @@ -17,6 +18,7 @@ type Props = { leftButton: React.Node, rightButton: React.Node, title: string, + subtitle: string, navigation: Object, hasTabs: boolean, }; @@ -37,6 +39,7 @@ export default class CustomHeader extends React.Component { searchCallback: () => null, shouldFocusSearchBar: false, title: '', + subtitle: '', leftButton: , rightButton: , hasTabs: false, @@ -51,23 +54,39 @@ export default class CustomHeader extends React.Component { getSearchBar() { return ( - - - this.props.searchCallback(text)}/> - + + + + this.props.searchCallback(text)}/> + + ); } + getHeaderTitle() { + return ( + + + {this.props.title} + + {this.props.subtitle !== '' ? {this.props.subtitle} : null} + + ); + } + + render() { let button; // Does the app have a back button or a burger menu ? @@ -75,10 +94,13 @@ export default class CustomHeader extends React.Component { button = this.props.navigation.goBack()}> + onPress={() => { + const backAction = NavigationActions.back(); + this.props.navigation.dispatch(backAction); + }}> + icon={Platform.OS === 'ios' ? 'chevron-left' : "arrow-left"}/> ; else button = this.props.leftButton; @@ -89,14 +111,9 @@ export default class CustomHeader extends React.Component { {button} - - {this.props.hasSearchField ? - this.getSearchBar() : - {this.props.title}} - + {this.props.hasSearchField ? + this.getSearchBar() : + this.getHeaderTitle()} {this.props.rightButton} @@ -104,7 +121,6 @@ export default class CustomHeader extends React.Component { } }; - // Fix header in status bar on Android const styles = StyleSheet.create({ header: { diff --git a/components/CustomSideMenu.js b/components/CustomSideMenu.js deleted file mode 100644 index 8ebc159..0000000 --- a/components/CustomSideMenu.js +++ /dev/null @@ -1,48 +0,0 @@ -// @flow - -import * as React from 'react'; -import SideMenu from "react-native-side-menu"; -import SideBar from "./Sidebar"; -import {View} from "react-native"; - - -type Props = { - navigation: Object, - children: React.Node, - isOpen: boolean, - onChange: Function, -} - -type State = { - shouldShowMenu: boolean, // Prevent menu from showing in transitions between tabs -} - -export default class CustomSideMenu extends React.Component { - - state = { - shouldShowMenu: this.props.isOpen, - }; - - // Stop the side menu from being shown while tab transition is playing - // => Hide the menu when behind the actual screen - onMenuMove(percent: number) { - if (percent <= 0) - this.setState({shouldShowMenu: false}); - else if (this.state.shouldShowMenu === false) - this.setState({shouldShowMenu: true}); - } - - render() { - return ( - - : } - isOpen={this.props.isOpen} - onChange={this.props.onChange} - onSliding={(percent) => this.onMenuMove(percent)}> - {this.props.children} - - ); - } -} diff --git a/navigation/AppNavigator.js b/navigation/AppNavigator.js index c3d2426..e43a316 100644 --- a/navigation/AppNavigator.js +++ b/navigation/AppNavigator.js @@ -1,56 +1,14 @@ // @flow -import {createAppContainer, createStackNavigator} from 'react-navigation'; -import {createMaterialBottomTabNavigatorWithInitialRoute} from './MainTabNavigator'; -import SettingsScreen from '../screens/SettingsScreen'; -import AboutScreen from '../screens/About/AboutScreen'; -import ProximoListScreen from '../screens/Proximo/ProximoListScreen'; -import AboutDependenciesScreen from '../screens/About/AboutDependenciesScreen'; -import ProxiwashAboutScreen from '../screens/Proxiwash/ProxiwashAboutScreen'; -import ProximoAboutScreen from '../screens/Proximo/ProximoAboutScreen'; -import SelfMenuScreen from '../screens/SelfMenuScreen'; -import TutorInsaScreen from "../screens/Websites/TutorInsaScreen"; -import AmicaleScreen from "../screens/Websites/AmicaleScreen"; -import WiketudScreen from "../screens/Websites/WiketudScreen"; -import ElusEtudScreen from "../screens/Websites/ElusEtudScreen"; -import BlueMindScreen from "../screens/Websites/BlueMindScreen"; -import EntScreen from "../screens/Websites/EntScreen"; -import AvailableRoomScreen from "../screens/Websites/AvailableRoomScreen"; -import DebugScreen from '../screens/DebugScreen'; -import {fromRight} from "react-navigation-transitions"; +import {createAppContainer} from 'react-navigation'; +import {createDrawerNavigatorWithInitialRoute} from './DrawerNavigator'; /** * Create a stack navigator using the drawer to handle navigation between screens */ function createAppContainerWithInitialRoute(initialRoute: string) { - return createAppContainer( - createStackNavigator({ - Main: createMaterialBottomTabNavigatorWithInitialRoute(initialRoute), - // Drawer: MainDrawerNavigator, - ProximoListScreen: {screen: ProximoListScreen}, - SettingsScreen: {screen: SettingsScreen}, - AboutScreen: {screen: AboutScreen}, - AboutDependenciesScreen: {screen: AboutDependenciesScreen}, - SelfMenuScreen: {screen: SelfMenuScreen}, - TutorInsaScreen: {screen: TutorInsaScreen}, - AmicaleScreen: {screen: AmicaleScreen}, - WiketudScreen: {screen: WiketudScreen}, - ElusEtudScreen: {screen: ElusEtudScreen}, - BlueMindScreen: {screen: BlueMindScreen}, - EntScreen: {screen: EntScreen}, - AvailableRoomScreen: {screen: AvailableRoomScreen}, - ProxiwashAboutScreen: {screen: ProxiwashAboutScreen}, - ProximoAboutScreen: {screen: ProximoAboutScreen}, - DebugScreen: {screen: DebugScreen}, - }, - { - initialRouteName: "Main", - mode: 'card', - headerMode: "none", - transitionConfig: () => fromRight(), - }) - ); + return createAppContainer(createDrawerNavigatorWithInitialRoute(initialRoute)); } export {createAppContainerWithInitialRoute}; diff --git a/navigation/DrawerNavigator.js b/navigation/DrawerNavigator.js new file mode 100644 index 0000000..ba16eef --- /dev/null +++ b/navigation/DrawerNavigator.js @@ -0,0 +1,79 @@ +// @flow + +import { createDrawerNavigator } from 'react-navigation-drawer'; +import {createMaterialBottomTabNavigatorWithInitialRoute} from './MainTabNavigator'; +import SettingsScreen from '../screens/SettingsScreen'; +import AboutScreen from '../screens/About/AboutScreen'; +import AboutDependenciesScreen from '../screens/About/AboutDependenciesScreen'; +import SelfMenuScreen from '../screens/SelfMenuScreen'; +import TutorInsaScreen from "../screens/Websites/TutorInsaScreen"; +import AmicaleScreen from "../screens/Websites/AmicaleScreen"; +import WiketudScreen from "../screens/Websites/WiketudScreen"; +import ElusEtudScreen from "../screens/Websites/ElusEtudScreen"; +import BlueMindScreen from "../screens/Websites/BlueMindScreen"; +import EntScreen from "../screens/Websites/EntScreen"; +import AvailableRoomScreen from "../screens/Websites/AvailableRoomScreen"; +import DebugScreen from '../screens/DebugScreen'; +import Sidebar from "../components/Sidebar"; +import {createStackNavigator, TransitionPresets} from "react-navigation-stack"; + +const AboutStack = createStackNavigator({ + AboutScreen: {screen: AboutScreen}, + AboutDependenciesScreen: {screen: AboutDependenciesScreen}, + DebugScreen: {screen: DebugScreen}, + }, + { + initialRouteName: "AboutScreen", + mode: 'card', + headerMode: "none", + defaultNavigationOptions: { + gestureEnabled: true, + cardOverlayEnabled: true, + ...TransitionPresets.SlideFromRightIOS, + }, + }); + + +// Create a stack to use animations +function createDrawerStackWithInitialRoute(initialRoute: string) { + return createStackNavigator({ + Main: createMaterialBottomTabNavigatorWithInitialRoute(initialRoute), + SettingsScreen: {screen: SettingsScreen}, + AboutScreen: AboutStack, + SelfMenuScreen: {screen: SelfMenuScreen}, + TutorInsaScreen: {screen: TutorInsaScreen}, + AmicaleScreen: {screen: AmicaleScreen}, + WiketudScreen: {screen: WiketudScreen}, + ElusEtudScreen: {screen: ElusEtudScreen}, + BlueMindScreen: {screen: BlueMindScreen}, + EntScreen: {screen: EntScreen}, + AvailableRoomScreen: {screen: AvailableRoomScreen}, + }, + { + initialRouteName: "Main", + mode: 'card', + headerMode: "none", + defaultNavigationOptions: { + gestureEnabled: true, + cardOverlayEnabled: true, + ...TransitionPresets.SlideFromRightIOS, + }, + }); +} + +/** + * Creates the drawer navigation stack + */ +function createDrawerNavigatorWithInitialRoute(initialRoute: string) { + return createDrawerNavigator({ + Main: createDrawerStackWithInitialRoute(initialRoute), + }, { + contentComponent: Sidebar, + initialRouteName: 'Main', + backBehavior: 'initialRoute', + drawerType: 'front', + useNativeAnimations: true, + }); +} + +export {createDrawerNavigatorWithInitialRoute}; diff --git a/navigation/MainTabNavigator.js b/navigation/MainTabNavigator.js index cb0348c..1d0e556 100644 --- a/navigation/MainTabNavigator.js +++ b/navigation/MainTabNavigator.js @@ -1,10 +1,15 @@ import * as React from 'react'; +import {createStackNavigator, TransitionPresets} from 'react-navigation-stack'; import {createMaterialBottomTabNavigator} from "react-navigation-material-bottom-tabs"; import HomeScreen from '../screens/HomeScreen'; import PlanningScreen from '../screens/PlanningScreen'; +import PlanningDisplayScreen from '../screens/PlanningDisplayScreen'; import ProxiwashScreen from '../screens/Proxiwash/ProxiwashScreen'; +import ProxiwashAboutScreen from '../screens/Proxiwash/ProxiwashAboutScreen'; import ProximoMainScreen from '../screens/Proximo/ProximoMainScreen'; +import ProximoListScreen from "../screens/Proximo/ProximoListScreen"; +import ProximoAboutScreen from "../screens/Proximo/ProximoAboutScreen"; import PlanexScreen from '../screens/Websites/PlanexScreen'; import CustomMaterialIcon from "../components/CustomMaterialIcon"; import ThemeManager from "../utils/ThemeManager"; @@ -17,12 +22,78 @@ const TAB_ICONS = { Planex: 'timetable', }; +const ProximoStack = createStackNavigator({ + ProximoMainScreen: {screen: ProximoMainScreen}, + ProximoListScreen: {screen: ProximoListScreen}, + ProximoAboutScreen: { + screen: ProximoAboutScreen, + navigationOptions: () => ({ + ...TransitionPresets.ModalSlideFromBottomIOS, + }), + }, + }, + { + initialRouteName: "ProximoMainScreen", + mode: 'card', + headerMode: "none", + defaultNavigationOptions: { + gestureEnabled: true, + cardOverlayEnabled: true, + ...TransitionPresets.SlideFromRightIOS, + }, + }); + +const ProxiwashStack = createStackNavigator({ + ProxiwashScreen: {screen: ProxiwashScreen}, + ProxiwashAboutScreen: {screen: ProxiwashAboutScreen}, + }, + { + initialRouteName: "ProxiwashScreen", + mode: 'card', + headerMode: "none", + defaultNavigationOptions: { + gestureEnabled: true, + cardOverlayEnabled: true, + ...TransitionPresets.ModalSlideFromBottomIOS, + }, + }); + +const PlanningStack = createStackNavigator({ + PlanningScreen: {screen: PlanningScreen}, + PlanningDisplayScreen: {screen: PlanningDisplayScreen}, + }, + { + initialRouteName: "PlanningScreen", + mode: 'card', + headerMode: "none", + defaultNavigationOptions: { + gestureEnabled: true, + cardOverlayEnabled: true, + ...TransitionPresets.ModalSlideFromBottomIOS, + }, + }); + +const HomeStack = createStackNavigator({ + HomeScreen: {screen: HomeScreen}, + PlanningDisplayScreen: {screen: PlanningDisplayScreen}, + }, + { + initialRouteName: "HomeScreen", + mode: 'card', + headerMode: "none", + defaultNavigationOptions: { + gestureEnabled: true, + cardOverlayEnabled: true, + ...TransitionPresets.ModalSlideFromBottomIOS, + }, + }); + function createMaterialBottomTabNavigatorWithInitialRoute(initialRoute: string) { return createMaterialBottomTabNavigator({ - Home: {screen: HomeScreen}, - Planning: {screen: PlanningScreen,}, - Proxiwash: {screen: ProxiwashScreen,}, - Proximo: {screen: ProximoMainScreen,}, + Home: HomeStack, + Planning: PlanningStack, + Proxiwash: ProxiwashStack, + Proximo: ProximoStack, Planex: { screen: PlanexScreen, navigationOptions: ({navigation}) => { diff --git a/package.json b/package.json index ddfdff3..7919241 100644 --- a/package.json +++ b/package.json @@ -8,6 +8,7 @@ "eject": "expo eject" }, "dependencies": { + "@react-native-community/masked-view": "0.1.5", "expo": "^36.0.0", "expo-font": "~8.0.0", "expo-linear-gradient": "~8.0.0", @@ -21,19 +22,22 @@ "react-native": "https://github.com/expo/react-native/archive/sdk-36.0.1.tar.gz", "react-native-app-intro-slider": "^3.0.0", "react-native-autolink": "^1.8.1", - "react-native-calendars": "^1.212.0", + "react-native-calendars": "^1.260.0", "react-native-gesture-handler": "~1.5.0", - "react-native-material-menu": "^0.6.7", + "react-native-material-menu": "^1.0.0", "react-native-modalize": "^1.3.6", "react-native-paper": "^3.5.1", "react-native-platform-touchable": "^1.1.1", + "react-native-reanimated": "~1.4.0", "react-native-render-html": "^4.1.2", + "react-native-safe-area-context": "0.6.0", "react-native-screens": "2.0.0-alpha.12", - "react-native-side-menu": "^1.1.3", "react-native-status-bar-height": "^2.3.1", "react-native-webview": "7.4.3", - "react-navigation": "^3.13.0", - "react-navigation-material-bottom-tabs": "^1.1.1", + "react-navigation": "^4.1.0", + "react-navigation-drawer": "^2.3.3", + "react-navigation-material-bottom-tabs": "^2.1.5", + "react-navigation-stack": "^2.1.0", "react-navigation-transitions": "^1.0.12" }, "devDependencies": { diff --git a/screens/About/AboutScreen.js b/screens/About/AboutScreen.js index 5cecf0e..c4bc463 100644 --- a/screens/About/AboutScreen.js +++ b/screens/About/AboutScreen.js @@ -319,14 +319,12 @@ export default class AboutScreen extends React.Component { tryUnlockDebugMode() { this.debugTapCounter = this.debugTapCounter + 1; - console.log(this.debugTapCounter); if (this.debugTapCounter >= 4) { this.unlockDebugMode(); } } unlockDebugMode() { - console.log('unlocked'); this.setState({isDebugUnlocked: true}); let key = AsyncStorageManager.getInstance().preferences.debugUnlocked.key; AsyncStorageManager.getInstance().savePref(key, '1'); diff --git a/screens/DebugScreen.js b/screens/DebugScreen.js index fd7c391..ea2b33e 100644 --- a/screens/DebugScreen.js +++ b/screens/DebugScreen.js @@ -83,7 +83,6 @@ export default class DebugScreen extends React.Component { alertCurrentExpoToken() { let token = AsyncStorageManager.getInstance().preferences.expoToken.current; - console.log(token); Alert.alert( 'Expo Token', token, diff --git a/screens/HomeScreen.js b/screens/HomeScreen.js index 5fead20..6a2ef12 100644 --- a/screens/HomeScreen.js +++ b/screens/HomeScreen.js @@ -310,7 +310,12 @@ export default class HomeScreen extends FetchedDataSectionList { ; } else subtitle = i18n.t('homeScreen.dashboard.todayEventsSubtitleNA'); - let clickAction = () => this.props.navigation.navigate('Planning'); + let clickAction = () => { + if (isAvailable) + this.props.navigation.navigate('PlanningDisplayScreen', {data: displayEvent}); + else + this.props.navigation.navigate('PlanningScreen'); + }; let displayEvent = this.getDisplayEvent(futureEvents); diff --git a/screens/PlanningDisplayScreen.js b/screens/PlanningDisplayScreen.js new file mode 100644 index 0000000..be07370 --- /dev/null +++ b/screens/PlanningDisplayScreen.js @@ -0,0 +1,69 @@ +// @flow + +import * as React from 'react'; +import {Image} from 'react-native'; +import {Container, Content, H1, H3, View} from 'native-base'; +import CustomHeader from "../components/CustomHeader"; +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) { + Linking.openURL(link).catch((err) => console.error('Error opening link', err)); +} + +/** + * 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 { + + render() { + const nav = this.props.navigation; + const displayData = nav.getParam('data', []); + return ( + + + +

+ {displayData.title} +

+

+ {PlanningEventManager.getFormattedTime(displayData)} +

+ {displayData.logo !== null ? + + + + : } + + {displayData.description !== null ? + // Surround description with div to allow text styling if the description is not html + " + displayData.description + ""} + tagsStyles={{ + p: { + color: ThemeManager.getCurrentThemeVariables().textColor, + fontSize: ThemeManager.getCurrentThemeVariables().fontSizeBase + }, + div: {color: ThemeManager.getCurrentThemeVariables().textColor} + }} + onLinkPress={(event, link) => openWebLink(link)}/> + : } +
+
+ ); + } +} diff --git a/screens/PlanningScreen.js b/screens/PlanningScreen.js index 1fe69ac..d683cd8 100644 --- a/screens/PlanningScreen.js +++ b/screens/PlanningScreen.js @@ -1,18 +1,16 @@ // @flow import * as React from 'react'; -import {BackHandler, Image, View} from 'react-native'; -import {Button, Content, H1, H3, Text} from 'native-base'; +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 HTML from 'react-native-render-html'; import Touchable from 'react-native-platform-touchable'; -import {Modalize} from 'react-native-modalize'; import WebDataManager from "../utils/WebDataManager"; -import CustomMaterialIcon from "../components/CustomMaterialIcon"; +import PlanningEventManager from '../utils/PlanningEventManager'; LocaleConfig.locales['fr'] = { monthNames: ['Janvier', 'Février', 'Mars', 'Avril', 'Mai', 'Juin', 'Juillet', 'Août', 'Septembre', 'Octobre', 'Novembre', 'Décembre'], @@ -28,7 +26,6 @@ type Props = { } type State = { - modalCurrentDisplayItem: Object, refreshing: boolean, agendaItems: Object, calendarShowing: boolean, @@ -51,7 +48,6 @@ function openWebLink(link) { */ export default class PlanningScreen extends React.Component { - modalRef: Modalize; agendaRef: Agenda; webDataManager: WebDataManager; @@ -61,7 +57,6 @@ export default class PlanningScreen extends React.Component { didFocusSubscription: Function; willBlurSubscription: Function; state = { - modalCurrentDisplayItem: {}, refreshing: false, agendaItems: {}, calendarShowing: false, @@ -69,7 +64,6 @@ export default class PlanningScreen extends React.Component { constructor(props: any) { super(props); - this.modalRef = React.createRef(); this.webDataManager = new WebDataManager(FETCH_URL); this.didFocusSubscription = props.navigation.addListener( 'didFocus', @@ -131,72 +125,11 @@ export default class PlanningScreen extends React.Component { return daysOfYear; } - getModalHeader() { - return ( - - - - ); - } - - getModalContent() { - return ( - -

- {this.state.modalCurrentDisplayItem.title} -

-

- {this.getFormattedTime(this.state.modalCurrentDisplayItem)} -

- - {this.state.modalCurrentDisplayItem.logo !== null ? - - - - : } - - {this.state.modalCurrentDisplayItem.description !== null ? - // Surround description with div to allow text styling if the description is not html - " + this.state.modalCurrentDisplayItem.description + ""} - tagsStyles={{ - p: { - color: ThemeManager.getCurrentThemeVariables().textColor, - fontSize: ThemeManager.getCurrentThemeVariables().fontSizeBase - }, - div: {color: ThemeManager.getCurrentThemeVariables().textColor} - }} - onLinkPress={(event, link) => openWebLink(link)}/> - : } - -
- ); - } - - showItemDetails(item: Object) { - this.setState({ - modalCurrentDisplayItem: item, - }); - if (this.modalRef.current) { - this.modalRef.current.open(); - } - } - getRenderItem(item: Object) { + let navData = { + data: item + }; + const nav = this.props.navigation; return ( { marginRight: 10, marginTop: 17, }} - onPress={() => this.showItemDetails(item)}> + onPress={() => nav.navigate('PlanningDisplayScreen', navData)}> { marginTop: 5, marginBottom: 10 }}> - {this.getFormattedTime(item)} + {PlanningEventManager.getFormattedTime(item)}

{item.title}

@@ -296,8 +229,8 @@ export default class PlanningScreen extends React.Component { generateEventAgenda(eventList: Array) { let agendaItems = this.generateEmptyCalendar(); for (let i = 0; i < eventList.length; i++) { - if (agendaItems[this.getEventStartDate(eventList[i])] !== undefined) { - this.pushEventInOrder(agendaItems, eventList[i], this.getEventStartDate(eventList[i])); + if (agendaItems[PlanningEventManager.getEventStartDate(eventList[i])] !== undefined) { + this.pushEventInOrder(agendaItems, eventList[i], PlanningEventManager.getEventStartDate(eventList[i])); } } this.setState({agendaItems: agendaItems}) @@ -308,7 +241,7 @@ export default class PlanningScreen extends React.Component { agendaItems[startDate].push(event); else { for (let i = 0; i < agendaItems[startDate].length; i++) { - if (this.isEventBefore(event, agendaItems[startDate][i])) { + if (PlanningEventManager.isEventBefore(event, agendaItems[startDate][i])) { agendaItems[startDate].splice(i, 0, event); break; } else if (i === agendaItems[startDate].length - 1) { @@ -319,65 +252,10 @@ export default class PlanningScreen extends React.Component { } } - isEventBefore(event1: Object, event2: Object) { - let date1 = new Date(); - let date2 = new Date(); - let timeArray = this.getEventStartTime(event1).split(":"); - date1.setHours(parseInt(timeArray[0]), parseInt(timeArray[1])); - timeArray = this.getEventStartTime(event2).split(":"); - date2.setHours(parseInt(timeArray[0]), parseInt(timeArray[1])); - return date1 < date2; - } - - getEventStartDate(event: Object) { - return event.date_begin.split(" ")[0]; - } - - getEventStartTime(event: Object) { - if (event !== undefined && Object.keys(event).length > 0 && event.date_begin !== null) - return this.formatTime(event.date_begin.split(" ")[1]); - else - return ""; - } - - getEventEndTime(event: Object) { - if (event !== undefined && Object.keys(event).length > 0 && event.date_end !== null) - return this.formatTime(event.date_end.split(" ")[1]); - else - return ""; - } - - getFormattedTime(event: Object) { - if (this.getEventEndTime(event) !== "") - return this.getEventStartTime(event) + " - " + this.getEventEndTime(event); - else - return this.getEventStartTime(event); - } - - formatTime(time: string) { - let array = time.split(':'); - return array[0] + ':' + array[1]; - } - - onModalClosed() { - this.setState({ - modalCurrentDisplayItem: {}, - }); - } - render() { const nav = this.props.navigation; return ( - this.getModalHeader()} - onClosed={() => this.onModalClosed()}> - {this.getModalContent()} - { agendaDayNumColor: ThemeManager.getCurrentThemeVariables().listNoteColor, agendaTodayColor: ThemeManager.getCurrentThemeVariables().brandPrimary, agendaKnobColor: ThemeManager.getCurrentThemeVariables().brandPrimary, - // Fix for days hiding behind knob - 'stylesheet.calendar.header': { - week: { - marginTop: 0, - flexDirection: 'row', - justifyContent: 'space-between' - } - } }} /> diff --git a/translations/en.json b/translations/en.json index 3cd8800..852f257 100644 --- a/translations/en.json +++ b/translations/en.json @@ -2,6 +2,7 @@ "screens": { "home": "Home", "planning": "Planning", + "planningDisplayScreen": "Event Details", "proxiwash": "Proxiwash", "proximo": "Proximo", "menuSelf": "RU Menu", diff --git a/translations/fr.json b/translations/fr.json index d2c78a1..8d506a8 100644 --- a/translations/fr.json +++ b/translations/fr.json @@ -2,6 +2,7 @@ "screens": { "home": "Accueil", "planning": "Planning", + "planningDisplayScreen": "Détails", "proxiwash": "Proxiwash", "proximo": "Proximo", "menuSelf": "Menu du RU", diff --git a/utils/PlanningEventManager.js b/utils/PlanningEventManager.js new file mode 100644 index 0000000..a853057 --- /dev/null +++ b/utils/PlanningEventManager.js @@ -0,0 +1,42 @@ + +export default class PlanningEventManager { + static isEventBefore(event1: Object, event2: Object) { + let date1 = new Date(); + let date2 = new Date(); + let timeArray = this.getEventStartTime(event1).split(":"); + date1.setHours(parseInt(timeArray[0]), parseInt(timeArray[1])); + timeArray = this.getEventStartTime(event2).split(":"); + date2.setHours(parseInt(timeArray[0]), parseInt(timeArray[1])); + return date1 < date2; + } + + static getEventStartDate(event: Object) { + return event.date_begin.split(" ")[0]; + } + + static getEventStartTime(event: Object) { + if (event !== undefined && Object.keys(event).length > 0 && event.date_begin !== null) + return this.formatTime(event.date_begin.split(" ")[1]); + else + return ""; + } + + static getEventEndTime(event: Object) { + if (event !== undefined && Object.keys(event).length > 0 && event.date_end !== null) + return this.formatTime(event.date_end.split(" ")[1]); + else + return ""; + } + + static getFormattedTime(event: Object) { + if (this.getEventEndTime(event) !== "") + return this.getEventStartTime(event) + " - " + this.getEventEndTime(event); + else + return this.getEventStartTime(event); + } + + static formatTime(time: string) { + let array = time.split(':'); + return array[0] + ':' + array[1]; + } +}