diff --git a/ios/app/src/Info.plist b/ios/app/src/Info.plist
index 3fdb58a58..ca7cd2ab8 100644
--- a/ios/app/src/Info.plist
+++ b/ios/app/src/Info.plist
@@ -56,13 +56,13 @@
NSCalendarsUsageDescription
- See your scheduled conferences in the app.
+ See your scheduled meetings in the app.
NSCameraUsageDescription
- Participate in conferences with video.
+ Participate in meetings with video.
NSLocationWhenInUseUsageDescription
NSMicrophoneUsageDescription
- Participate in conferences with voice.
+ Participate in meetings with voice.
UIBackgroundModes
audio
diff --git a/lang/main.json b/lang/main.json
index 3adb24898..414b8981f 100644
--- a/lang/main.json
+++ b/lang/main.json
@@ -608,7 +608,7 @@
"now": "Now",
"ongoingMeeting": "ongoing meeting",
"permissionButton": "Open settings",
- "permissionMessage": "Calendar permission is required to list your meetings in the app."
+ "permissionMessage": "The Calendar permission is required to see your meetings in the app."
},
"recentList": {
"today": "Today",
diff --git a/react/features/base/react/components/native/AbstractPagedList.js b/react/features/base/react/components/native/AbstractPagedList.js
index 0e31df853..eca687487 100644
--- a/react/features/base/react/components/native/AbstractPagedList.js
+++ b/react/features/base/react/components/native/AbstractPagedList.js
@@ -5,11 +5,14 @@ import { View } from 'react-native';
import styles from './styles';
+/**
+ * The type of the React {@code Component} props of {@link AbstractPagedList}.
+ */
type Props = {
/**
- * The index (starting from 0) of the page that should be rendered
- * active as default.
+ * The zero-based index of the page that should be rendered (selected) by
+ * default.
*/
defaultPage: number,
@@ -30,16 +33,20 @@ type Props = {
/**
* The pages of the PagedList component to be rendered.
- * Note: page.component may be undefined and then they don't need to be
- * rendered.
+ *
+ * Note: An element's {@code component} may be {@code undefined} and then it
+ * won't need to be rendered.
*/
pages: Array<{
- component: Object,
+ component: ?Object,
icon: string | number,
title: string
}>
};
+/**
+ * The type of the React {@code Component} state of {@link AbstractPagedList}.
+ */
type State = {
/**
@@ -53,7 +60,7 @@ type State = {
*/
export default class AbstractPagedList extends Component {
/**
- * Constructor of the component.
+ * Initializes a new {@code AbstractPagedList} instance.
*
* @inheritdoc
*/
@@ -63,15 +70,19 @@ export default class AbstractPagedList extends Component {
this.state = {
pageIndex: this._validatePageIndex(props.defaultPage)
};
+
+ // Bind event handlers so they are only bound once per instance.
+ this._maybeRefreshSelectedPage
+ = this._maybeRefreshSelectedPage.bind(this);
}
/**
- * Implements React's {@code Component} componentDidMount.
+ * Implements React's {@link Component#componentDidMount}.
*
* @inheritdoc
*/
componentDidMount() {
- this._maybeRefreshActivePage();
+ this._maybeRefreshSelectedPage();
}
/**
@@ -80,8 +91,8 @@ export default class AbstractPagedList extends Component {
* @inheritdoc
*/
render() {
- const { disabled, pages } = this.props;
- const enabledPages = pages.filter(page => page.component);
+ const { disabled } = this.props;
+ const pages = this.props.pages.filter(({ component }) => component);
return (
{
disabled ? styles.pagedListContainerDisabled : null
] }>
{
- enabledPages.length > 1
+ pages.length > 1
? this._renderPagedList(disabled)
- : enabledPages.length === 1
+ : pages.length === 1
? React.createElement(
- /* type */ enabledPages[0].component,
+
+ // $FlowExpectedError
+ /* type */ pages[0].component,
/* props */ {
disabled,
style: styles.pagedList
- }) : null
+ })
+ : null
}
);
}
- _platformSpecificPageSelect: number => void
-
- /**
- * Method to be overriden by the components implementing this abstract class
- * to handle platform specific actions on page select.
- *
- * @protected
- * @param {number} pageIndex - The selected page index.
- * @returns {void}
- */
- _platformSpecificPageSelect(pageIndex) {
- this._selectPage(pageIndex);
- }
-
- _maybeRefreshActivePage: () => void
+ _maybeRefreshSelectedPage: () => void;
/**
* Components that this PagedList displays may have a refresh function to
@@ -128,13 +128,15 @@ export default class AbstractPagedList extends Component {
* @private
* @returns {void}
*/
- _maybeRefreshActivePage() {
+ _maybeRefreshSelectedPage() {
const selectedPage = this.props.pages[this.state.pageIndex];
+ let component;
- if (selectedPage && selectedPage.component) {
- const { refresh } = selectedPage.component;
+ if (selectedPage && (component = selectedPage.component)) {
+ const { refresh } = component;
- typeof refresh === 'function' && refresh(this.props.dispatch);
+ typeof refresh === 'function'
+ && refresh.call(component, this.props.dispatch);
}
}
@@ -145,25 +147,22 @@ export default class AbstractPagedList extends Component {
/**
* Sets the selected page.
*
- * @param {number} pageIndex - The index of the active page.
+ * @param {number} pageIndex - The index of the selected page.
* @protected
* @returns {void}
*/
_selectPage(pageIndex: number) {
- const validatedPageIndex = this._validatePageIndex(pageIndex);
+ // eslint-disable-next-line no-param-reassign
+ pageIndex = this._validatePageIndex(pageIndex);
const { onSelectPage } = this.props;
- if (typeof onSelectPage === 'function') {
- onSelectPage(validatedPageIndex);
- }
+ typeof onSelectPage === 'function' && onSelectPage(pageIndex);
- this.setState({
- pageIndex: validatedPageIndex
- }, () => this._maybeRefreshActivePage());
+ this.setState({ pageIndex }, this._maybeRefreshSelectedPage);
}
- _validatePageIndex: number => number
+ _validatePageIndex: number => number;
/**
* Validates the requested page index and returns a safe value.
@@ -173,10 +172,10 @@ export default class AbstractPagedList extends Component {
* @returns {number}
*/
_validatePageIndex(pageIndex) {
- // pageIndex may point to a non existing page if some of the pages are
+ // pageIndex may point to a non-existing page if some of the pages are
// disabled (their component property is undefined).
const maxPageIndex
- = this.props.pages.filter(page => page.component).length - 1;
+ = this.props.pages.filter(({ component }) => component).length - 1;
return Math.max(0, Math.min(maxPageIndex, pageIndex));
}
diff --git a/react/features/base/react/components/native/PagedList.android.js b/react/features/base/react/components/native/PagedList.android.js
index c9612e0b0..6563eb708 100644
--- a/react/features/base/react/components/native/PagedList.android.js
+++ b/react/features/base/react/components/native/PagedList.android.js
@@ -86,18 +86,6 @@ class PagedList extends AbstractPagedList {
}
}
- /**
- * Platform specific actions to run on page select.
- *
- * @private
- * @param {number} pageIndex - The selected page index.
- * @returns {void}
- */
- _platformSpecificPageSelect(pageIndex) {
- this._viewPager.setPage(pageIndex);
- this._selectPage(pageIndex);
- }
-
/**
* Renders a single page of the page list.
*
diff --git a/react/features/calendar-sync/actions.js b/react/features/calendar-sync/actions.js
index 3c3950958..cdbbc0357 100644
--- a/react/features/calendar-sync/actions.js
+++ b/react/features/calendar-sync/actions.js
@@ -1,9 +1,9 @@
// @flow
import {
+ REFRESH_CALENDAR,
SET_CALENDAR_AUTHORIZATION,
- SET_CALENDAR_EVENTS,
- REFRESH_CALENDAR
+ SET_CALENDAR_EVENTS
} from './actionTypes';
/**
diff --git a/react/features/calendar-sync/components/MeetingList.native.js b/react/features/calendar-sync/components/MeetingList.native.js
index ea1be7222..db8913766 100644
--- a/react/features/calendar-sync/components/MeetingList.native.js
+++ b/react/features/calendar-sync/components/MeetingList.native.js
@@ -21,7 +21,7 @@ type Props = {
/**
* The current state of the calendar access permission.
*/
- _authorization: string,
+ _authorization: ?string,
/**
* The calendar event list.
@@ -73,7 +73,7 @@ class MeetingList extends Component {
}
/**
- * Constructor of the MeetingList component.
+ * Initializes a new {@code MeetingList} instance.
*
* @inheritdoc
*/
@@ -85,32 +85,26 @@ class MeetingList extends Component {
= this._getRenderListEmptyComponent.bind(this);
this._onPress = this._onPress.bind(this);
this._onRefresh = this._onRefresh.bind(this);
+ this._toDateString = this._toDateString.bind(this);
this._toDisplayableItem = this._toDisplayableItem.bind(this);
this._toDisplayableList = this._toDisplayableList.bind(this);
- this._toDateString = this._toDateString.bind(this);
}
/**
- * Implements the React Components's render.
+ * Implements React's {@link Component#render}.
*
* @inheritdoc
*/
render() {
- const { _authorization, disabled } = this.props;
+ const { disabled } = this.props;
return (
);
}
@@ -122,10 +116,17 @@ class MeetingList extends Component {
* of the default one in the {@link NavigateSectionList}.
*
* @private
- * @returns {Function}
+ * @returns {?React$Component}
*/
_getRenderListEmptyComponent() {
- const { t } = this.props;
+ const { _authorization, t } = this.props;
+
+ // If we don't provide a list specific renderListEmptyComponent, then
+ // the default empty component of the NavigateSectionList will be
+ // rendered, which (atm) is a simple "Pull to refresh" message.
+ if (_authorization !== 'denied') {
+ return undefined;
+ }
return (
@@ -168,6 +169,24 @@ class MeetingList extends Component {
this.props.dispatch(refreshCalendar(true));
}
+ _toDateString: Object => string;
+
+ /**
+ * Generates a date (interval) string for a given event.
+ *
+ * @param {Object} event - The event.
+ * @private
+ * @returns {string}
+ */
+ _toDateString(event) {
+ const startDateTime
+ = getLocalizedDateFormatter(event.startDate).format('lll');
+ const endTime
+ = getLocalizedDateFormatter(event.endDate).format('LT');
+
+ return `${startDateTime} - ${endTime}`;
+ }
+
_toDisplayableItem: Object => Object;
/**
@@ -199,7 +218,9 @@ class MeetingList extends Component {
*/
_toDisplayableList() {
const { _eventList, t } = this.props;
+
const now = Date.now();
+
const { createSection } = NavigateSectionList;
const nowSection = createSection(t('calendarSync.now'), 'now');
const nextSection = createSection(t('calendarSync.next'), 'next');
@@ -227,31 +248,11 @@ class MeetingList extends Component {
nextSection,
laterSection
]) {
- if (section.data.length) {
- sectionList.push(section);
- }
+ section.data.length && sectionList.push(section);
}
return sectionList;
}
-
- _toDateString: Object => string;
-
- /**
- * Generates a date (interval) string for a given event.
- *
- * @param {Object} event - The event.
- * @private
- * @returns {string}
- */
- _toDateString(event) {
- const startDateTime
- = getLocalizedDateFormatter(event.startDate).format('lll');
- const endTime
- = getLocalizedDateFormatter(event.endDate).format('LT');
-
- return `${startDateTime} - ${endTime}`;
- }
}
/**
@@ -259,15 +260,16 @@ class MeetingList extends Component {
*
* @param {Object} state - The redux state.
* @returns {{
- * _eventList: Array
+ * _authorization: ?string,
+ * _eventList: Array