Properly gate calendar feature on-off
This commit is contained in:
parent
09482f053b
commit
374e3ccf2c
|
@ -267,7 +267,7 @@ class ConferenceNotification extends Component<Props, State> {
|
||||||
* _eventList: Array
|
* _eventList: Array
|
||||||
* }}
|
* }}
|
||||||
*/
|
*/
|
||||||
export function _mapStateToProps(state: Object) {
|
function _mapStateToProps(state: Object) {
|
||||||
const { locationURL } = state['features/base/connection'];
|
const { locationURL } = state['features/base/connection'];
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -10,6 +10,7 @@ import { NavigateSectionList } from '../../base/react';
|
||||||
import { openSettings } from '../../mobile/permissions';
|
import { openSettings } from '../../mobile/permissions';
|
||||||
|
|
||||||
import { refreshCalendar } from '../actions';
|
import { refreshCalendar } from '../actions';
|
||||||
|
import { CALENDAR_ENABLED } from '../constants';
|
||||||
import styles from './styles';
|
import styles from './styles';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
|
@ -59,6 +60,23 @@ class MeetingList extends Component<Props> {
|
||||||
_eventList: []
|
_eventList: []
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Public API method for {@code Component}s rendered in
|
||||||
|
* {@link AbstractPagedList}. When invoked, refreshes the calendar entries
|
||||||
|
* in the app.
|
||||||
|
*
|
||||||
|
* Note: It is a static method as the {@code Component} may not be
|
||||||
|
* initialized yet when the UI invokes refresh (e.g. {@link TabBarIOS} tab
|
||||||
|
* change).
|
||||||
|
*
|
||||||
|
* @param {Function} dispatch - The Redux dispatch function.
|
||||||
|
* @public
|
||||||
|
* @returns {void}
|
||||||
|
*/
|
||||||
|
static refresh(dispatch) {
|
||||||
|
dispatch(refreshCalendar());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor of the MeetingList component.
|
* Constructor of the MeetingList component.
|
||||||
*
|
*
|
||||||
|
@ -82,21 +100,6 @@ class MeetingList extends Component<Props> {
|
||||||
this._toDateString = this._toDateString.bind(this);
|
this._toDateString = this._toDateString.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Implements React Component's componentWillReceiveProps.
|
|
||||||
*
|
|
||||||
* @inheritdoc
|
|
||||||
*/
|
|
||||||
componentWillReceiveProps(newProps) {
|
|
||||||
const { displayed } = this.props;
|
|
||||||
|
|
||||||
if (newProps.displayed && !displayed) {
|
|
||||||
const { dispatch } = this.props;
|
|
||||||
|
|
||||||
dispatch(refreshCalendar());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implements the React Components's render.
|
* Implements the React Components's render.
|
||||||
*
|
*
|
||||||
|
@ -266,7 +269,7 @@ class MeetingList extends Component<Props> {
|
||||||
* _eventList: Array
|
* _eventList: Array
|
||||||
* }}
|
* }}
|
||||||
*/
|
*/
|
||||||
export function _mapStateToProps(state: Object) {
|
function _mapStateToProps(state: Object) {
|
||||||
const calendarSyncState = state['features/calendar-sync'];
|
const calendarSyncState = state['features/calendar-sync'];
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
@ -275,4 +278,6 @@ export function _mapStateToProps(state: Object) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export default translate(connect(_mapStateToProps)(MeetingList));
|
export default CALENDAR_ENABLED
|
||||||
|
? translate(connect(_mapStateToProps)(MeetingList))
|
||||||
|
: undefined;
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
// @flow
|
||||||
|
|
||||||
|
import { NativeModules } from 'react-native';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The indicator which determines whether the calendar feature is enabled by the
|
||||||
|
* app.
|
||||||
|
*
|
||||||
|
* @type {boolean}
|
||||||
|
*/
|
||||||
|
export const CALENDAR_ENABLED = _isCalendarEnabled();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines whether the calendar feature is enabled by the app. For
|
||||||
|
* example, Apple through its App Store requires
|
||||||
|
* {@code NSCalendarsUsageDescription} in the app's Info.plist or App Store
|
||||||
|
* rejects the app.
|
||||||
|
*
|
||||||
|
* @returns {boolean} If the app has enabled the calendar feature, {@code true};
|
||||||
|
* otherwise, {@code false}.
|
||||||
|
*/
|
||||||
|
function _isCalendarEnabled() {
|
||||||
|
const { calendarEnabled } = NativeModules.AppInfo;
|
||||||
|
|
||||||
|
return typeof calendarEnabled === 'undefined' ? true : calendarEnabled;
|
||||||
|
}
|
|
@ -1,4 +1,3 @@
|
||||||
export * from './actions';
|
|
||||||
export * from './components';
|
export * from './components';
|
||||||
|
|
||||||
import './middleware';
|
import './middleware';
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
// @flow
|
// @flow
|
||||||
|
|
||||||
import { NativeModules } from 'react-native';
|
|
||||||
import RNCalendarEvents from 'react-native-calendar-events';
|
import RNCalendarEvents from 'react-native-calendar-events';
|
||||||
|
|
||||||
import { APP_WILL_MOUNT } from '../app';
|
import { APP_WILL_MOUNT } from '../app';
|
||||||
|
@ -15,6 +14,7 @@ import {
|
||||||
setCalendarEvents
|
setCalendarEvents
|
||||||
} from './actions';
|
} from './actions';
|
||||||
import { REFRESH_CALENDAR } from './actionTypes';
|
import { REFRESH_CALENDAR } from './actionTypes';
|
||||||
|
import { CALENDAR_ENABLED } from './constants';
|
||||||
|
|
||||||
const logger = require('jitsi-meet-logger').getLogger(__filename);
|
const logger = require('jitsi-meet-logger').getLogger(__filename);
|
||||||
|
|
||||||
|
@ -22,30 +22,31 @@ const FETCH_END_DAYS = 10;
|
||||||
const FETCH_START_DAYS = -1;
|
const FETCH_START_DAYS = -1;
|
||||||
const MAX_LIST_LENGTH = 10;
|
const MAX_LIST_LENGTH = 10;
|
||||||
|
|
||||||
MiddlewareRegistry.register(store => next => action => {
|
CALENDAR_ENABLED
|
||||||
const result = next(action);
|
&& MiddlewareRegistry.register(store => next => action => {
|
||||||
|
const result = next(action);
|
||||||
|
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
case APP_STATE_CHANGED:
|
case APP_STATE_CHANGED:
|
||||||
_maybeClearAccessStatus(store, action);
|
_maybeClearAccessStatus(store, action);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case APP_WILL_MOUNT:
|
case APP_WILL_MOUNT:
|
||||||
_ensureDefaultServer(store);
|
_ensureDefaultServer(store);
|
||||||
_fetchCalendarEntries(store, false, false);
|
_fetchCalendarEntries(store, false, false);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case REFRESH_CALENDAR:
|
case REFRESH_CALENDAR:
|
||||||
_fetchCalendarEntries(store, true, action.forcePermission);
|
_fetchCalendarEntries(store, true, action.forcePermission);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SET_ROOM:
|
case SET_ROOM:
|
||||||
_parseAndAddKnownDomain(store);
|
_parseAndAddKnownDomain(store);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clears the calendar access status when the app comes back from the
|
* Clears the calendar access status when the app comes back from the
|
||||||
|
@ -123,11 +124,6 @@ function _fetchCalendarEntries(
|
||||||
{ dispatch, getState },
|
{ dispatch, getState },
|
||||||
maybePromptForPermission,
|
maybePromptForPermission,
|
||||||
forcePermission) {
|
forcePermission) {
|
||||||
if (!_isCalendarEnabled()) {
|
|
||||||
// The calendar feature is not enabled.
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const state = getState()['features/calendar-sync'];
|
const state = getState()['features/calendar-sync'];
|
||||||
const promptForPermission
|
const promptForPermission
|
||||||
= (maybePromptForPermission && !state.authorization)
|
= (maybePromptForPermission && !state.authorization)
|
||||||
|
@ -203,20 +199,6 @@ function _getURLFromEvent(event, knownDomains) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Determines whether the calendar feature is enabled by the app. For
|
|
||||||
* example, Apple through its App Store requires NSCalendarsUsageDescription in
|
|
||||||
* the app's Info.plist or App Store rejects the app.
|
|
||||||
*
|
|
||||||
* @returns {boolean} If the app has enabled the calendar feature, {@code true};
|
|
||||||
* otherwise, {@code false}.
|
|
||||||
*/
|
|
||||||
export function _isCalendarEnabled() {
|
|
||||||
const { calendarEnabled } = NativeModules.AppInfo;
|
|
||||||
|
|
||||||
return typeof calendarEnabled === 'undefined' ? true : calendarEnabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves the domain name of a room upon join and stores it in the known
|
* Retrieves the domain name of a room upon join and stores it in the known
|
||||||
* domain list, if not present yet.
|
* domain list, if not present yet.
|
||||||
|
|
|
@ -8,6 +8,7 @@ import {
|
||||||
SET_CALENDAR_AUTHORIZATION,
|
SET_CALENDAR_AUTHORIZATION,
|
||||||
SET_CALENDAR_EVENTS
|
SET_CALENDAR_EVENTS
|
||||||
} from './actionTypes';
|
} from './actionTypes';
|
||||||
|
import { CALENDAR_ENABLED } from './constants';
|
||||||
|
|
||||||
const DEFAULT_STATE = {
|
const DEFAULT_STATE = {
|
||||||
/**
|
/**
|
||||||
|
@ -24,31 +25,33 @@ const MAX_DOMAIN_LIST_SIZE = 10;
|
||||||
|
|
||||||
const STORE_NAME = 'features/calendar-sync';
|
const STORE_NAME = 'features/calendar-sync';
|
||||||
|
|
||||||
PersistenceRegistry.register(STORE_NAME, {
|
CALENDAR_ENABLED
|
||||||
knownDomains: true
|
&& PersistenceRegistry.register(STORE_NAME, {
|
||||||
});
|
knownDomains: true
|
||||||
|
});
|
||||||
|
|
||||||
ReducerRegistry.register(STORE_NAME, (state = DEFAULT_STATE, action) => {
|
CALENDAR_ENABLED
|
||||||
switch (action.type) {
|
&& ReducerRegistry.register(STORE_NAME, (state = DEFAULT_STATE, action) => {
|
||||||
case ADD_KNOWN_DOMAIN:
|
switch (action.type) {
|
||||||
return _addKnownDomain(state, action);
|
case ADD_KNOWN_DOMAIN:
|
||||||
|
return _addKnownDomain(state, action);
|
||||||
|
|
||||||
case SET_CALENDAR_AUTHORIZATION:
|
case SET_CALENDAR_AUTHORIZATION:
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
authorization: action.status
|
authorization: action.status
|
||||||
};
|
};
|
||||||
|
|
||||||
case SET_CALENDAR_EVENTS:
|
case SET_CALENDAR_EVENTS:
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
events: action.events
|
events: action.events
|
||||||
};
|
};
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds a new domain to the known domain list if not present yet.
|
* Adds a new domain to the known domain list if not present yet.
|
||||||
|
|
|
@ -1,53 +0,0 @@
|
||||||
// @flow
|
|
||||||
|
|
||||||
import { Component } from 'react';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The page to be displayed on render.
|
|
||||||
*/
|
|
||||||
export const DEFAULT_PAGE = 0;
|
|
||||||
|
|
||||||
type Props = {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Indicates if the list is disabled or not.
|
|
||||||
*/
|
|
||||||
disabled: boolean,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The Redux dispatch function.
|
|
||||||
*/
|
|
||||||
dispatch: Function,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The i18n translate function
|
|
||||||
*/
|
|
||||||
t: Function
|
|
||||||
}
|
|
||||||
|
|
||||||
type State = {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The currently selected page.
|
|
||||||
*/
|
|
||||||
pageIndex: number
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Abstract class for the platform specific paged lists.
|
|
||||||
*/
|
|
||||||
export default class AbstractPagedList extends Component<Props, State> {
|
|
||||||
/**
|
|
||||||
* Constructor of the component.
|
|
||||||
*
|
|
||||||
* @inheritdoc
|
|
||||||
*/
|
|
||||||
constructor(props: Props) {
|
|
||||||
super(props);
|
|
||||||
|
|
||||||
this.state = {
|
|
||||||
pageIndex: DEFAULT_PAGE
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -0,0 +1,91 @@
|
||||||
|
// @flow
|
||||||
|
|
||||||
|
import React, { Component } from 'react';
|
||||||
|
import { View } from 'react-native';
|
||||||
|
import { isCalendarEnabled } from '../../calendar-sync';
|
||||||
|
import { RecentList } from '../../recent-list';
|
||||||
|
|
||||||
|
import styles from './styles';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The page to be displayed on render.
|
||||||
|
*/
|
||||||
|
export const DEFAULT_PAGE = 0;
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates if the list is disabled or not.
|
||||||
|
*/
|
||||||
|
disabled: boolean,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The Redux dispatch function.
|
||||||
|
*/
|
||||||
|
dispatch: Function,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The i18n translate function
|
||||||
|
*/
|
||||||
|
t: Function
|
||||||
|
}
|
||||||
|
|
||||||
|
type State = {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The currently selected page.
|
||||||
|
*/
|
||||||
|
pageIndex: number
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Abstract class for the platform specific paged lists.
|
||||||
|
*/
|
||||||
|
export default class AbstractPagedList extends Component<Props, State> {
|
||||||
|
/**
|
||||||
|
* True if the calendar feature is enabled on the platform, false otherwise.
|
||||||
|
*/
|
||||||
|
_calendarEnabled: boolean
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor of the component.
|
||||||
|
*
|
||||||
|
* @inheritdoc
|
||||||
|
*/
|
||||||
|
constructor(props: Props) {
|
||||||
|
super(props);
|
||||||
|
|
||||||
|
this._calendarEnabled = isCalendarEnabled();
|
||||||
|
|
||||||
|
this.state = {
|
||||||
|
pageIndex: DEFAULT_PAGE
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Renders the component.
|
||||||
|
*
|
||||||
|
* @inheritdoc
|
||||||
|
*/
|
||||||
|
render() {
|
||||||
|
const { disabled } = this.props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<View
|
||||||
|
style = { [
|
||||||
|
styles.pagedListContainer,
|
||||||
|
disabled ? styles.pagedListContainerDisabled : null
|
||||||
|
] }>
|
||||||
|
{
|
||||||
|
(this._calendarEnabled && this._renderPagedList(disabled))
|
||||||
|
|| <RecentList
|
||||||
|
disabled = { disabled }
|
||||||
|
style = { styles.pagedList } />
|
||||||
|
}
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
_renderPagedList: boolean => Object
|
||||||
|
|
||||||
|
}
|
|
@ -35,20 +35,17 @@ export default class PagedList extends AbstractPagedList {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Renders the paged list.
|
* Renders the entire paged list if calendar is enabled.
|
||||||
*
|
*
|
||||||
* @inheritdoc
|
* @param {boolean} disabled - True if the rendered lists should be
|
||||||
|
* disabled.
|
||||||
|
* @returns {ReactElement}
|
||||||
*/
|
*/
|
||||||
render() {
|
_renderPagedList(disabled) {
|
||||||
const { disabled } = this.props;
|
|
||||||
const { pageIndex } = this.state;
|
const { pageIndex } = this.state;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View
|
<View style = { styles.pagedListContainer }>
|
||||||
style = { [
|
|
||||||
styles.pagedListContainer,
|
|
||||||
disabled ? styles.pagedListContainerDisabled : null
|
|
||||||
] }>
|
|
||||||
<ViewPagerAndroid
|
<ViewPagerAndroid
|
||||||
initialPage = { DEFAULT_PAGE }
|
initialPage = { DEFAULT_PAGE }
|
||||||
onPageSelected = { this._onPageSelected }
|
onPageSelected = { this._onPageSelected }
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
// @flow
|
// @flow
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { View, TabBarIOS } from 'react-native';
|
import { TabBarIOS } from 'react-native';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
|
|
||||||
import { translate } from '../../base/i18n';
|
import { translate } from '../../base/i18n';
|
||||||
|
@ -31,39 +31,35 @@ class PagedList extends AbstractPagedList {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Renders the paged list.
|
* Renders the entire paged list if calendar is enabled.
|
||||||
*
|
*
|
||||||
* @inheritdoc
|
* @param {boolean} disabled - True if the rendered lists should be
|
||||||
|
* disabled.
|
||||||
|
* @returns {ReactElement}
|
||||||
*/
|
*/
|
||||||
render() {
|
_renderPagedList(disabled) {
|
||||||
const { pageIndex } = this.state;
|
const { pageIndex } = this.state;
|
||||||
const { disabled, t } = this.props;
|
const { t } = this.props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View
|
<TabBarIOS
|
||||||
style = { [
|
itemPositioning = 'fill'
|
||||||
styles.pagedListContainer,
|
style = { styles.pagedList }>
|
||||||
disabled ? styles.pagedListContainerDisabled : null
|
<TabBarIOS.Item
|
||||||
] }>
|
onPress = { this._onTabSelected(0) }
|
||||||
<TabBarIOS
|
selected = { pageIndex === 0 }
|
||||||
itemPositioning = 'fill'
|
systemIcon = 'history' >
|
||||||
style = { styles.pagedList }>
|
<RecentList disabled = { disabled } />
|
||||||
<TabBarIOS.Item
|
</TabBarIOS.Item>
|
||||||
onPress = { this._onTabSelected(0) }
|
<TabBarIOS.Item
|
||||||
selected = { pageIndex === 0 }
|
icon = { CALENDAR_ICON }
|
||||||
systemIcon = 'history' >
|
onPress = { this._onTabSelected(1) }
|
||||||
<RecentList disabled = { disabled } />
|
selected = { pageIndex === 1 }
|
||||||
</TabBarIOS.Item>
|
title = { t('welcomepage.calendar') } >
|
||||||
<TabBarIOS.Item
|
<MeetingList
|
||||||
icon = { CALENDAR_ICON }
|
disabled = { disabled } />
|
||||||
onPress = { this._onTabSelected(1) }
|
</TabBarIOS.Item>
|
||||||
selected = { pageIndex === 1 }
|
</TabBarIOS>
|
||||||
title = { t('welcomepage.calendar') } >
|
|
||||||
<MeetingList
|
|
||||||
disabled = { disabled } />
|
|
||||||
</TabBarIOS.Item>
|
|
||||||
</TabBarIOS>
|
|
||||||
</View>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue