From 63c165ee8b6025223a611beb37cef7f37b7b4c14 Mon Sep 17 00:00:00 2001 From: zbettenbuk Date: Mon, 16 Apr 2018 20:07:38 +0200 Subject: [PATCH] More generic way to refresh lists on the welcome screen --- .../components/MeetingList.native.js | 14 -- .../components/AbstractPagedList.native.js | 57 ++++++-- .../welcome/components/PagedList.android.js | 132 +++++++++--------- .../welcome/components/PagedList.ios.js | 52 +++---- 4 files changed, 131 insertions(+), 124 deletions(-) diff --git a/react/features/calendar-sync/components/MeetingList.native.js b/react/features/calendar-sync/components/MeetingList.native.js index 516600b65..b312341c7 100644 --- a/react/features/calendar-sync/components/MeetingList.native.js +++ b/react/features/calendar-sync/components/MeetingList.native.js @@ -35,14 +35,6 @@ type Props = { */ dispatch: Function, - /** - * Tells the component if it's being displayed at the moment, or not. Note: - * as an example, on Android it can happen that the component is rendered - * but not displayed, because components like ViewPagerAndroid render their - * children even if they are not visible at the moment. - */ - displayed: boolean, - /** * The translate function. */ @@ -85,12 +77,6 @@ class MeetingList extends Component { constructor(props) { super(props); - const { dispatch, displayed } = props; - - if (displayed) { - dispatch(refreshCalendar()); - } - this._getRenderListEmptyComponent = this._getRenderListEmptyComponent.bind(this); this._onPress = this._onPress.bind(this); diff --git a/react/features/welcome/components/AbstractPagedList.native.js b/react/features/welcome/components/AbstractPagedList.native.js index d07b9ee08..e7ad0c707 100644 --- a/react/features/welcome/components/AbstractPagedList.native.js +++ b/react/features/welcome/components/AbstractPagedList.native.js @@ -2,7 +2,8 @@ import React, { Component } from 'react'; import { View } from 'react-native'; -import { isCalendarEnabled } from '../../calendar-sync'; + +import { MeetingList } from '../../calendar-sync'; import { RecentList } from '../../recent-list'; import styles from './styles'; @@ -28,7 +29,7 @@ type Props = { * The i18n translate function */ t: Function -} +}; type State = { @@ -36,16 +37,16 @@ type State = { * The currently selected page. */ pageIndex: number -} +}; /** * Abstract class for the platform specific paged lists. */ export default class AbstractPagedList extends Component { /** - * True if the calendar feature is enabled on the platform, false otherwise. + * The list of pages displayed in the component, referenced by page index. */ - _calendarEnabled: boolean + _pages: Array; /** * Constructor of the component. @@ -55,7 +56,13 @@ export default class AbstractPagedList extends Component { constructor(props: Props) { super(props); - this._calendarEnabled = isCalendarEnabled(); + this._pages = []; + for (const component of [ RecentList, MeetingList ]) { + // XXX Certain pages may be contributed by optional features. For + // example, MeetingList is contributed by the calendar feature and + // apps i.e. SDK consumers may not enable the calendar feature. + component && this._pages.push(component); + } this.state = { pageIndex: DEFAULT_PAGE @@ -77,15 +84,43 @@ export default class AbstractPagedList extends Component { disabled ? styles.pagedListContainerDisabled : null ] }> { - (this._calendarEnabled && this._renderPagedList(disabled)) - || + this._pages.length > 1 + ? this._renderPagedList(disabled) + : React.createElement( + /* type */ this._pages[0], + /* props */ { + disabled, + style: styles.pagedList + }) } ); } - _renderPagedList: boolean => Object + _renderPagedList: boolean => React$Node; + _selectPage: number => void; + + /** + * Sets the selected page. + * + * @param {number} pageIndex - The index of the active page. + * @protected + * @returns {void} + */ + _selectPage(pageIndex: number) { + this.setState({ + pageIndex + }); + + // The page's Component may have a refresh(dispatch) function which we + // invoke when the page is selected. + const selectedPageComponent = this._pages[pageIndex]; + + if (selectedPageComponent) { + const { refresh } = selectedPageComponent; + + typeof refresh === 'function' && refresh(this.props.dispatch); + } + } } diff --git a/react/features/welcome/components/PagedList.android.js b/react/features/welcome/components/PagedList.android.js index 4a1ee28b5..f6a83d9a5 100644 --- a/react/features/welcome/components/PagedList.android.js +++ b/react/features/welcome/components/PagedList.android.js @@ -1,6 +1,8 @@ // @flow + import React from 'react'; import { Text, TouchableOpacity, View, ViewPagerAndroid } from 'react-native'; +import { connect } from 'react-redux'; import { Icon } from '../../base/font-icons'; import { MeetingList } from '../../calendar-sync'; @@ -14,24 +16,74 @@ import styles from './styles'; * * @extends PagedList */ -export default class PagedList extends AbstractPagedList { +class PagedList extends AbstractPagedList { /** * A reference to the viewpager. */ _viewPager: Object; /** - * Constructor of the PagedList Component. + * Initializes a new {@code PagedList} instance. * * @inheritdoc */ constructor(props) { super(props); + // Bind event handlers so they are only bound once per instance. this._getIndicatorStyle = this._getIndicatorStyle.bind(this); this._onPageSelected = this._onPageSelected.bind(this); this._onSelectPage = this._onSelectPage.bind(this); - this._setPagerReference = this._setPagerReference.bind(this); + this._setViewPager = this._setViewPager.bind(this); + } + + _getIndicatorStyle: number => Object; + + /** + * Constructs the style of an indicator. + * + * @param {number} indicatorIndex - The index of the indicator. + * @private + * @returns {Object} + */ + _getIndicatorStyle(indicatorIndex) { + if (this.state.pageIndex === indicatorIndex) { + return styles.pageIndicatorTextActive; + } + + return null; + } + + _onPageSelected: Object => void; + + /** + * Updates the index of the currently selected page. + * + * @param {Object} event - The native event of the callback. + * @private + * @returns {void} + */ + _onPageSelected({ nativeEvent: { position } }) { + if (this.state.pageIndex !== position) { + this._selectPage(position); + } + } + + _onSelectPage: number => Function; + + /** + * Constructs a function to be used as a callback for the tab bar. + * + * @param {number} pageIndex - The index of the page to activate via the + * callback. + * @private + * @returns {Function} + */ + _onSelectPage(pageIndex) { + return () => { + this._viewPager.setPage(pageIndex); + this._selectPage(pageIndex); + }; } /** @@ -42,23 +94,19 @@ export default class PagedList extends AbstractPagedList { * @returns {ReactElement} */ _renderPagedList(disabled) { - const { pageIndex } = this.state; - return ( - + @@ -107,69 +155,19 @@ export default class PagedList extends AbstractPagedList { ); } - _getIndicatorStyle: number => Object; + _setViewPager: Object => void; /** - * Constructs the style of an indicator. + * Sets the {@link ViewPagerAndroid} instance. * + * @param {ViewPagerAndroid} viewPager - The {@code ViewPagerAndroid} + * instance. * @private - * @param {number} indicatorIndex - The index of the indicator. - * @returns {Object} - */ - _getIndicatorStyle(indicatorIndex) { - if (this.state.pageIndex === indicatorIndex) { - return styles.pageIndicatorTextActive; - } - - return null; - } - - _onPageSelected: Object => void; - - /** - * Updates the index of the currently selected page. - * - * @private - * @param {Object} event - The native event of the callback. * @returns {void} */ - _onPageSelected({ nativeEvent: { position } }) { - if (this.state.pageIndex !== position) { - this.setState({ - pageIndex: position - }); - } - } - - _onSelectPage: number => Function - - /** - * Constructs a function to be used as a callback for the tab bar. - * - * @private - * @param {number} pageIndex - The index of the page to activate via the - * callback. - * @returns {Function} - */ - _onSelectPage(pageIndex) { - return () => { - this._viewPager.setPage(pageIndex); - this.setState({ - pageIndex - }); - }; - } - - _setPagerReference: Object => void - - /** - * Sets the pager's reference for direct modification. - * - * @private - * @param {React@Node} component - The pager component. - * @returns {void} - */ - _setPagerReference(component) { - this._viewPager = component; + _setViewPager(viewPager) { + this._viewPager = viewPager; } } + +export default connect()(PagedList); diff --git a/react/features/welcome/components/PagedList.ios.js b/react/features/welcome/components/PagedList.ios.js index 558f3e234..e13af3707 100644 --- a/react/features/welcome/components/PagedList.ios.js +++ b/react/features/welcome/components/PagedList.ios.js @@ -5,7 +5,7 @@ import { TabBarIOS } from 'react-native'; import { connect } from 'react-redux'; import { translate } from '../../base/i18n'; -import { MeetingList, refreshCalendar } from '../../calendar-sync'; +import { MeetingList } from '../../calendar-sync'; import { RecentList } from '../../recent-list'; import AbstractPagedList from './AbstractPagedList'; @@ -21,15 +21,30 @@ const CALENDAR_ICON = require('../../../../images/calendar.png'); class PagedList extends AbstractPagedList { /** - * Constructor of the PagedList Component. + * Initializes a new {@code PagedList} instance. * * @inheritdoc */ constructor(props) { super(props); + + // Bind event handlers so they are only bound once per instance. this._onTabSelected = this._onTabSelected.bind(this); } + _onTabSelected: number => Function; + + /** + * Constructs a callback to update the selected tab. + * + * @param {number} tabIndex - The selected tab. + * @private + * @returns {Function} + */ + _onTabSelected(tabIndex) { + return () => super._selectPage(tabIndex); + } + /** * Renders the entire paged list if calendar is enabled. * @@ -48,46 +63,19 @@ class PagedList extends AbstractPagedList { + systemIcon = 'history'> - + title = { t('welcomepage.calendar') }> + ); } - - _onTabSelected: number => Function; - - /** - * Constructs a callback to update the selected tab. - * - * @private - * @param {number} tabIndex - The selected tab. - * @returns {Function} - */ - _onTabSelected(tabIndex) { - return () => { - this.setState({ - pageIndex: tabIndex - }); - - if (tabIndex === 1) { - /** - * This is a workaround as TabBarIOS doesn't invoke - * componentWillReciveProps on prop change of the MeetingList - * component. - */ - this.props.dispatch(refreshCalendar()); - } - }; - } } export default translate(connect()(PagedList));