diff --git a/package.json b/package.json index 02dbe91..54040bc 100644 --- a/package.json +++ b/package.json @@ -51,6 +51,7 @@ "react-native-safe-area-context": "0.7.3", "react-native-screens": "~2.2.0", "react-native-webview": "8.1.1", + "react-navigation-collapsible": "^5.4.0", "react-navigation-header-buttons": "^3.0.5" }, "devDependencies": { diff --git a/src/components/Custom/BasicLoadingScreen.js b/src/components/Custom/BasicLoadingScreen.js index 5e3a027..01ad378 100644 --- a/src/components/Custom/BasicLoadingScreen.js +++ b/src/components/Custom/BasicLoadingScreen.js @@ -1,8 +1,8 @@ // @flow import * as React from 'react'; +import {View} from 'react-native'; import {ActivityIndicator, withTheme} from 'react-native-paper'; -import {View} from "react-native"; /** * Component used to display a header button @@ -12,17 +12,19 @@ import {View} from "react-native"; */ function BasicLoadingScreen(props) { const {colors} = props.theme; + let position = undefined; + if (props.isAbsolute !== undefined && props.isAbsolute) + position = 'absolute'; + return ( { +class WebSectionList extends React.PureComponent { static defaultProps = { renderSectionHeader: null, @@ -171,11 +174,16 @@ export default class WebSectionList extends React.PureComponent { index }); + onListScroll= (event) => { + + }; + render() { let dataset = []; if (this.state.fetchedData !== undefined) dataset = this.props.createDataset(this.state.fetchedData); const shouldRenderHeader = this.props.renderSectionHeader !== null; + const {containerPaddingTop, scrollIndicatorInsetTop, onScrollWithListener} = this.props.collapsibleStack; return ( {/*$FlowFixMe*/} @@ -184,6 +192,7 @@ export default class WebSectionList extends React.PureComponent { extraData={this.props.updateData} refreshControl={ @@ -193,7 +202,6 @@ export default class WebSectionList extends React.PureComponent { //$FlowFixMe renderItem={this.props.renderItem} stickySectionHeadersEnabled={this.props.stickyHeader} - contentContainerStyle={{minHeight: '100%'}} style={{minHeight: '100%'}} ListEmptyComponent={this.state.refreshing ? @@ -204,7 +212,12 @@ export default class WebSectionList extends React.PureComponent { } getItemLayout={this.props.itemHeight !== null ? this.itemLayout : undefined} // Animations - onScroll={this.props.onScroll} + onScroll={onScrollWithListener(this.props.onScroll)} + contentContainerStyle={{ + paddingTop: containerPaddingTop, + minHeight: '100%' + }} + scrollIndicatorInsets={{top: scrollIndicatorInsetTop}} /> { ); } } + +export default withCollapsible(WebSectionList); diff --git a/src/components/Screens/WebViewScreen.js b/src/components/Screens/WebViewScreen.js index f57dc27..4e99d73 100644 --- a/src/components/Screens/WebViewScreen.js +++ b/src/components/Screens/WebViewScreen.js @@ -9,14 +9,18 @@ import MaterialHeaderButtons, {Item} from '../Custom/HeaderButton'; import {HiddenItem} from "react-navigation-header-buttons"; import {Linking} from "expo"; import i18n from 'i18n-js'; -import {BackHandler} from "react-native"; +import {Animated, BackHandler} from "react-native"; +import {withCollapsible} from "../../utils/withCollapsible"; type Props = { navigation: Object, url: string, customJS: string, + collapsibleStack: Object, } +const AnimatedWebView = Animated.createAnimatedComponent(WebView); + /** * Class defining a webview screen. */ @@ -63,7 +67,7 @@ class WebViewScreen extends React.PureComponent { } onBackButtonPressAndroid = () => { - if (this.canGoBack){ + if (this.canGoBack) { this.onGoBackClicked(); return true; } @@ -112,15 +116,48 @@ class WebViewScreen extends React.PureComponent { * * @return {*} */ - getRenderLoading = () => ; + getRenderLoading = () => ; + +// document.getElementsByTagName('body')[0].style.paddingTop = '100px'; + +// $( 'body *' ).filter(function(){ +// var position = $(this).css('position'); +// var top = $(this).css('top'); +// if((position === 'fixed') && top !== 'auto'){ +// console.log(top); +// $(this).css('top', 'calc(' + top + ' + 100px)'); +// console.log($(this).css('top')); +// }; +// }); + +// document.querySelectorAll('body *').forEach(function(node){ +// var style = window.getComputedStyle(node); +// var position = style.getPropertyValue('position'); +// var top = style.getPropertyValue('top'); +// if((position === 'fixed') && top !== 'auto'){ +// console.log(top); +// node.style.top = 'calc(' + top + ' + 100px)'; +// console.log(node.style.top); +// console.log(node); +// }; +// }); + + getJavascriptPadding(padding: number) { + return ( + "document.getElementsByTagName('body')[0].style.paddingTop = '" + padding + "px';\n" + + "true;" + ); + } render() { + const {containerPaddingTop, onScroll} = this.props.collapsibleStack; + const customJS = this.getJavascriptPadding(containerPaddingTop); return ( - { onNavigationStateChange={navState => { this.canGoBack = navState.canGoBack; }} + // Animations + onScroll={onScroll} /> ); } } -export default WebViewScreen; +export default withCollapsible(WebViewScreen); diff --git a/src/navigation/DrawerNavigator.js b/src/navigation/DrawerNavigator.js index 810cd0c..a85e949 100644 --- a/src/navigation/DrawerNavigator.js +++ b/src/navigation/DrawerNavigator.js @@ -26,6 +26,8 @@ import {AmicaleWebsiteScreen} from "../screens/Websites/AmicaleWebsiteScreen"; import {TutorInsaWebsiteScreen} from "../screens/Websites/TutorInsaWebsiteScreen"; import {WiketudWebsiteScreen} from "../screens/Websites/WiketudWebsiteScreen"; import {ElusEtudiantsWebsiteScreen} from "../screens/Websites/ElusEtudiantsWebsiteScreen"; +import {createCollapsibleStack} from "react-navigation-collapsible"; +import {useTheme} from "react-native-paper"; const defaultScreenOptions = { gestureEnabled: true, @@ -106,23 +108,33 @@ function SettingsStackComponent() { const SelfMenuStack = createStackNavigator(); function SelfMenuStackComponent() { + const {colors} = useTheme(); return ( - { - const openDrawer = getDrawerButton.bind(this, navigation); - return { - title: i18n.t('screens.menuSelf'), - headerLeft: openDrawer - }; - }} - /> + {createCollapsibleStack( + { + const openDrawer = getDrawerButton.bind(this, navigation); + return { + title: i18n.t('screens.menuSelf'), + headerLeft: openDrawer, + headerStyle: { + backgroundColor: colors.surface, + }, + }; + }} + />, + { + collapsedColor: 'transparent', + useNativeDriver: true, + } + )} ); } @@ -130,23 +142,33 @@ function SelfMenuStackComponent() { const AvailableRoomStack = createStackNavigator(); function AvailableRoomStackComponent() { + const {colors} = useTheme(); return ( - { - const openDrawer = getDrawerButton.bind(this, navigation); - return { - title: i18n.t('screens.availableRooms'), - headerLeft: openDrawer - }; - }} - /> + {createCollapsibleStack( + { + const openDrawer = getDrawerButton.bind(this, navigation); + return { + title: i18n.t('screens.availableRooms'), + headerLeft: openDrawer, + headerStyle: { + backgroundColor: colors.surface, + }, + }; + }} + />, + { + collapsedColor: 'transparent', + useNativeDriver: false, // native driver does not work with webview + } + )} ); } @@ -154,23 +176,33 @@ function AvailableRoomStackComponent() { const BibStack = createStackNavigator(); function BibStackComponent() { + const {colors} = useTheme(); return ( - { - const openDrawer = getDrawerButton.bind(this, navigation); - return { - title: i18n.t('screens.bib'), - headerLeft: openDrawer - }; - }} - /> + {createCollapsibleStack( + { + const openDrawer = getDrawerButton.bind(this, navigation); + return { + title: i18n.t('screens.bib'), + headerLeft: openDrawer, + headerStyle: { + backgroundColor: colors.surface, + }, + }; + }} + />, + { + collapsedColor: 'transparent', + useNativeDriver: false, // native driver does not work with webview + } + )} ); } @@ -178,23 +210,33 @@ function BibStackComponent() { const AmicaleWebsiteStack = createStackNavigator(); function AmicaleWebsiteStackComponent() { + const {colors} = useTheme(); return ( - { - const openDrawer = getDrawerButton.bind(this, navigation); - return { - title: "Amicale", - headerLeft: openDrawer - }; - }} - /> + {createCollapsibleStack( + { + const openDrawer = getDrawerButton.bind(this, navigation); + return { + title: "Amicale", + headerLeft: openDrawer, + headerStyle: { + backgroundColor: colors.surface, + }, + }; + }} + />, + { + collapsedColor: 'transparent', + useNativeDriver: false, // native driver does not work with webview + } + )} ); } @@ -202,23 +244,33 @@ function AmicaleWebsiteStackComponent() { const ElusEtudiantsStack = createStackNavigator(); function ElusEtudiantsStackComponent() { + const {colors} = useTheme(); return ( - { - const openDrawer = getDrawerButton.bind(this, navigation); - return { - title: "Élus Étudiants", - headerLeft: openDrawer - }; - }} - /> + {createCollapsibleStack( + { + const openDrawer = getDrawerButton.bind(this, navigation); + return { + title: "Élus Étudiants", + headerLeft: openDrawer, + headerStyle: { + backgroundColor: colors.surface, + }, + }; + }} + />, + { + collapsedColor: 'transparent', + useNativeDriver: false, // native driver does not work with webview + } + )} ); } @@ -226,23 +278,33 @@ function ElusEtudiantsStackComponent() { const WiketudStack = createStackNavigator(); function WiketudStackComponent() { + const {colors} = useTheme(); return ( - { - const openDrawer = getDrawerButton.bind(this, navigation); - return { - title: "Wiketud", - headerLeft: openDrawer - }; - }} - /> + {createCollapsibleStack( + { + const openDrawer = getDrawerButton.bind(this, navigation); + return { + title: "Wiketud", + headerLeft: openDrawer, + headerStyle: { + backgroundColor: colors.surface, + }, + }; + }} + />, + { + collapsedColor: 'transparent', + useNativeDriver: false, // native driver does not work with webview + } + )} ); } @@ -250,29 +312,38 @@ function WiketudStackComponent() { const TutorInsaStack = createStackNavigator(); function TutorInsaStackComponent() { + const {colors} = useTheme(); return ( - { - const openDrawer = getDrawerButton.bind(this, navigation); - return { - title: "Tutor'INSA", - headerLeft: openDrawer - }; - }} - /> + {createCollapsibleStack( + { + const openDrawer = getDrawerButton.bind(this, navigation); + return { + title: "Tutor'INSA", + headerLeft: openDrawer, + headerStyle: { + backgroundColor: colors.surface, + }, + }; + }} + />, + { + collapsedColor: 'transparent', + useNativeDriver: false, // native driver does not work with webview + } + )} ); } - const TetrisStack = createStackNavigator(); function TetrisStackComponent() { @@ -408,23 +479,33 @@ function AmicaleContactStackComponent() { const ClubStack = createStackNavigator(); function ClubStackComponent() { + const {colors} = useTheme(); return ( - { - const openDrawer = getDrawerButton.bind(this, navigation); - return { - title: i18n.t('clubs.clubList'), - headerLeft: openDrawer - }; - }} - /> + {createCollapsibleStack( + { + const openDrawer = getDrawerButton.bind(this, navigation); + return { + title: i18n.t('clubs.clubList'), + headerLeft: openDrawer, + headerStyle: { + backgroundColor: colors.surface, + }, + }; + }} + />, + { + collapsedColor: 'transparent', + useNativeDriver: true, + } + )} - { - const openDrawer = getDrawerButton.bind(this, navigation); - return { - title: 'Proximo', - headerLeft: openDrawer - }; - }} - component={ProximoMainScreen} - /> - + {createCollapsibleStack( + { + const openDrawer = getDrawerButton.bind(this, navigation); + return { + title: 'Proximo', + headerLeft: openDrawer, + headerStyle: { + backgroundColor: colors.surface, + }, + }; + }} + component={ProximoMainScreen} + />, + { + collapsedColor: 'transparent', + useNativeDriver: true, + } + )} + {createCollapsibleStack( + , + { + collapsedColor: 'transparent', + useNativeDriver: true, + } + )} - { - const openDrawer = getDrawerButton.bind(this, navigation); - return { - title: i18n.t('screens.proxiwash'), - headerLeft: openDrawer - }; - }} - /> + {createCollapsibleStack( + { + const openDrawer = getDrawerButton.bind(this, navigation); + return { + title: i18n.t('screens.proxiwash'), + headerLeft: openDrawer, + headerStyle: { + backgroundColor: colors.surface, + }, + }; + }} + />, + { + collapsedColor: 'transparent', + useNativeDriver: true, + } + )} - { - const openDrawer = getDrawerButton.bind(this, navigation); - return { - title: i18n.t('screens.home'), - headerLeft: openDrawer - }; - }} - initialParams={data} - /> + {createCollapsibleStack( + { + const openDrawer = getDrawerButton.bind(this, navigation); + return { + title: i18n.t('screens.home'), + headerLeft: openDrawer, + headerStyle: { + backgroundColor: colors.surface, + }, + }; + }} + initialParams={data} + />, + { + collapsedColor: 'transparent', + useNativeDriver: true, + } + )} - { - const openDrawer = getDrawerButton.bind(this, navigation); - return { - title: 'Planex', - headerLeft: openDrawer - }; - }} - /> + {createCollapsibleStack( + { + const openDrawer = getDrawerButton.bind(this, navigation); + return { + title: 'Planex', + headerLeft: openDrawer, + headerStyle: { + backgroundColor: colors.surface, + }, + }; + }} + />, + { + collapsedColor: 'transparent', + useNativeDriver: false, // native driver does not work with webview + } + )} ); } diff --git a/src/screens/Amicale/Clubs/ClubListScreen.js b/src/screens/Amicale/Clubs/ClubListScreen.js index d2cf1d2..04a30fb 100644 --- a/src/screens/Amicale/Clubs/ClubListScreen.js +++ b/src/screens/Amicale/Clubs/ClubListScreen.js @@ -1,7 +1,7 @@ // @flow import * as React from 'react'; -import {FlatList, Platform} from "react-native"; +import {Animated, Platform} from "react-native"; import {Chip, Searchbar, withTheme} from 'react-native-paper'; import AuthenticatedScreen from "../../../components/Amicale/AuthenticatedScreen"; import i18n from "i18n-js"; @@ -9,10 +9,12 @@ import ClubListItem from "../../../components/Lists/ClubListItem"; import {isItemInCategoryFilter, stringMatchQuery} from "../../../utils/Search"; import ClubListHeader from "../../../components/Lists/ClubListHeader"; import MaterialHeaderButtons, {Item} from "../../../components/Custom/HeaderButton"; +import {withCollapsible} from "../../../utils/withCollapsible"; type Props = { navigation: Object, theme: Object, + collapsibleStack: Object, } type State = { @@ -94,9 +96,10 @@ class ClubListScreen extends React.Component { getScreen = (data: Object) => { this.categories = data[0].categories; + const {containerPaddingTop, scrollIndicatorInsetTop, onScroll} = this.props.collapsibleStack; return ( //$FlowFixMe - { // Performance props, see https://reactnative.dev/docs/optimizing-flatlist-configuration removeClippedSubviews={true} getItemLayout={this.itemLayout} + // Animations + onScroll={onScroll} + contentContainerStyle={{paddingTop: containerPaddingTop}} + scrollIndicatorInsets={{top: scrollIndicatorInsetTop}} /> ) }; @@ -208,4 +215,4 @@ class ClubListScreen extends React.Component { } } -export default withTheme(ClubListScreen); +export default withCollapsible(withTheme(ClubListScreen)); diff --git a/src/screens/Proximo/ProximoListScreen.js b/src/screens/Proximo/ProximoListScreen.js index 90b54b0..8139cb9 100644 --- a/src/screens/Proximo/ProximoListScreen.js +++ b/src/screens/Proximo/ProximoListScreen.js @@ -1,13 +1,14 @@ // @flow import * as React from 'react'; -import {FlatList, Image, Platform, ScrollView, View} from "react-native"; +import {Animated, Image, Platform, ScrollView, View} from "react-native"; import i18n from "i18n-js"; import CustomModal from "../../components/Custom/CustomModal"; import {RadioButton, Searchbar, Subheading, Text, Title, withTheme} from "react-native-paper"; import {stringMatchQuery} from "../../utils/Search"; import ProximoListItem from "../../components/Lists/ProximoListItem"; import MaterialHeaderButtons, {Item} from "../../components/Custom/HeaderButton"; +import {withCollapsible} from "../../utils/withCollapsible"; function sortPrice(a, b) { return a.price - b.price; @@ -39,6 +40,7 @@ type Props = { navigation: Object, route: Object, theme: Object, + collapsibleStack: Object, } type State = { @@ -295,6 +297,7 @@ class ProximoListScreen extends React.Component { itemLayout = (data, index) => ({length: LIST_ITEM_HEIGHT, offset: LIST_ITEM_HEIGHT * index, index}); render() { + const {containerPaddingTop, scrollIndicatorInsetTop, onScroll} = this.props.collapsibleStack; return ( { {this.state.modalCurrentDisplayItem} {/*$FlowFixMe*/} - { removeClippedSubviews={true} getItemLayout={this.itemLayout} initialNumToRender={10} + // Animations + onScroll={onScroll} + contentContainerStyle={{paddingTop: containerPaddingTop}} + scrollIndicatorInsets={{top: scrollIndicatorInsetTop}} /> ); } } -export default withTheme(ProximoListScreen); +export default withCollapsible(withTheme(ProximoListScreen)); diff --git a/src/utils/withCollapsible.js b/src/utils/withCollapsible.js new file mode 100644 index 0000000..0cb5cad --- /dev/null +++ b/src/utils/withCollapsible.js @@ -0,0 +1,8 @@ +import React from 'react'; +import {useCollapsibleStack} from "react-navigation-collapsible"; + +export const withCollapsible = (Component: any) => { + return (props: any) => { + return ; + }; +};