diff --git a/css/_font.scss b/css/_font.scss index f1a214d4ad..9c1a3c3004 100644 --- a/css/_font.scss +++ b/css/_font.scss @@ -36,6 +36,9 @@ .icon-navigate_before:before { content: "\e408"; } +.icon-navigate_next:before { + content: "\e409"; +} .icon-public:before { content: "\e80b"; } diff --git a/fonts/jitsi.eot b/fonts/jitsi.eot index a5ac411602..7984214cd1 100755 Binary files a/fonts/jitsi.eot and b/fonts/jitsi.eot differ diff --git a/fonts/jitsi.svg b/fonts/jitsi.svg index 2a52c1eed2..28a2a67e4d 100755 --- a/fonts/jitsi.svg +++ b/fonts/jitsi.svg @@ -12,6 +12,7 @@ + diff --git a/fonts/jitsi.ttf b/fonts/jitsi.ttf index 7c0742d18d..bd462b4cd8 100755 Binary files a/fonts/jitsi.ttf and b/fonts/jitsi.ttf differ diff --git a/fonts/jitsi.woff b/fonts/jitsi.woff index 4cea331333..fbcd0f7068 100755 Binary files a/fonts/jitsi.woff and b/fonts/jitsi.woff differ diff --git a/fonts/selection.json b/fonts/selection.json index 814ceacf47..4b0c9e5073 100755 --- a/fonts/selection.json +++ b/fonts/selection.json @@ -1,6 +1,33 @@ { "IcoMoonType": "selection", "icons": [ + { + "icon": { + "paths": [ + "M426 256l256 256-256 256-60-60 196-196-196-196z" + ], + "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, + "tags": [ + "navigate_next" + ], + "defaultCode": 58377, + "grid": 24 + }, + "attrs": [], + "properties": { + "ligatures": "chevron_right, navigate_next", + "id": 153, + "order": 927, + "prevSize": 24, + "code": 58377, + "name": "navigate_next" + }, + "setIdx": 0, + "setId": 2, + "iconIdx": 153 + }, { "icon": { "paths": [ @@ -24,9 +51,9 @@ "code": 58834, "name": "menu" }, - "setIdx": 0, - "setId": 2, - "iconIdx": 489 + "setIdx": 1, + "setId": 1, + "iconIdx": 0 }, { "icon": { @@ -53,7 +80,7 @@ }, "setIdx": 1, "setId": 1, - "iconIdx": 0 + "iconIdx": 1 }, { "icon": { @@ -80,7 +107,7 @@ }, "setIdx": 1, "setId": 1, - "iconIdx": 1 + "iconIdx": 2 }, { "icon": { @@ -107,7 +134,7 @@ }, "setIdx": 1, "setId": 1, - "iconIdx": 2 + "iconIdx": 3 }, { "icon": { @@ -134,7 +161,7 @@ }, "setIdx": 1, "setId": 1, - "iconIdx": 3 + "iconIdx": 4 }, { "icon": { @@ -161,7 +188,7 @@ }, "setIdx": 1, "setId": 1, - "iconIdx": 4 + "iconIdx": 5 }, { "icon": { @@ -188,7 +215,7 @@ }, "setIdx": 1, "setId": 1, - "iconIdx": 5 + "iconIdx": 6 }, { "icon": { @@ -215,7 +242,7 @@ }, "setIdx": 1, "setId": 1, - "iconIdx": 6 + "iconIdx": 7 }, { "icon": { @@ -242,7 +269,7 @@ }, "setIdx": 1, "setId": 1, - "iconIdx": 7 + "iconIdx": 8 }, { "icon": { @@ -269,7 +296,7 @@ }, "setIdx": 1, "setId": 1, - "iconIdx": 8 + "iconIdx": 9 }, { "icon": { @@ -298,7 +325,7 @@ }, "setIdx": 1, "setId": 1, - "iconIdx": 9 + "iconIdx": 10 }, { "icon": { @@ -325,7 +352,7 @@ }, "setIdx": 1, "setId": 1, - "iconIdx": 10 + "iconIdx": 11 }, { "icon": { @@ -352,7 +379,7 @@ }, "setIdx": 1, "setId": 1, - "iconIdx": 11 + "iconIdx": 12 }, { "icon": { @@ -381,7 +408,7 @@ }, "setIdx": 1, "setId": 1, - "iconIdx": 12 + "iconIdx": 13 }, { "icon": { @@ -410,7 +437,7 @@ }, "setIdx": 1, "setId": 1, - "iconIdx": 13 + "iconIdx": 14 }, { "icon": { @@ -439,7 +466,7 @@ }, "setIdx": 1, "setId": 1, - "iconIdx": 14 + "iconIdx": 15 }, { "icon": { @@ -468,7 +495,7 @@ }, "setIdx": 1, "setId": 1, - "iconIdx": 15 + "iconIdx": 16 }, { "icon": { @@ -497,7 +524,7 @@ }, "setIdx": 1, "setId": 1, - "iconIdx": 16 + "iconIdx": 17 }, { "icon": { @@ -523,7 +550,7 @@ }, "setIdx": 1, "setId": 1, - "iconIdx": 17 + "iconIdx": 18 }, { "icon": { @@ -549,7 +576,7 @@ }, "setIdx": 1, "setId": 1, - "iconIdx": 18 + "iconIdx": 19 }, { "icon": { @@ -575,7 +602,7 @@ }, "setIdx": 1, "setId": 1, - "iconIdx": 19 + "iconIdx": 20 }, { "icon": { @@ -601,7 +628,7 @@ }, "setIdx": 1, "setId": 1, - "iconIdx": 20 + "iconIdx": 21 }, { "icon": { @@ -627,7 +654,7 @@ }, "setIdx": 1, "setId": 1, - "iconIdx": 21 + "iconIdx": 22 }, { "icon": { @@ -653,7 +680,7 @@ }, "setIdx": 1, "setId": 1, - "iconIdx": 22 + "iconIdx": 23 }, { "icon": { @@ -679,7 +706,7 @@ }, "setIdx": 1, "setId": 1, - "iconIdx": 23 + "iconIdx": 24 }, { "icon": { @@ -705,7 +732,7 @@ }, "setIdx": 1, "setId": 1, - "iconIdx": 24 + "iconIdx": 25 }, { "icon": { @@ -731,7 +758,7 @@ }, "setIdx": 1, "setId": 1, - "iconIdx": 25 + "iconIdx": 26 }, { "icon": { @@ -757,7 +784,7 @@ }, "setIdx": 1, "setId": 1, - "iconIdx": 26 + "iconIdx": 27 }, { "icon": { @@ -783,7 +810,7 @@ }, "setIdx": 1, "setId": 1, - "iconIdx": 27 + "iconIdx": 28 }, { "icon": { @@ -809,7 +836,7 @@ }, "setIdx": 1, "setId": 1, - "iconIdx": 28 + "iconIdx": 29 }, { "icon": { @@ -835,7 +862,7 @@ }, "setIdx": 1, "setId": 1, - "iconIdx": 29 + "iconIdx": 30 }, { "icon": { @@ -861,7 +888,7 @@ }, "setIdx": 1, "setId": 1, - "iconIdx": 30 + "iconIdx": 31 }, { "icon": { @@ -887,7 +914,7 @@ }, "setIdx": 1, "setId": 1, - "iconIdx": 31 + "iconIdx": 32 }, { "icon": { @@ -913,7 +940,7 @@ }, "setIdx": 1, "setId": 1, - "iconIdx": 32 + "iconIdx": 33 }, { "icon": { @@ -939,7 +966,7 @@ }, "setIdx": 1, "setId": 1, - "iconIdx": 33 + "iconIdx": 34 }, { "icon": { @@ -965,7 +992,7 @@ }, "setIdx": 1, "setId": 1, - "iconIdx": 34 + "iconIdx": 35 }, { "icon": { @@ -991,7 +1018,7 @@ }, "setIdx": 1, "setId": 1, - "iconIdx": 35 + "iconIdx": 36 }, { "icon": { @@ -1017,7 +1044,7 @@ }, "setIdx": 1, "setId": 1, - "iconIdx": 36 + "iconIdx": 37 }, { "icon": { @@ -1043,7 +1070,7 @@ }, "setIdx": 1, "setId": 1, - "iconIdx": 37 + "iconIdx": 38 }, { "icon": { @@ -1069,7 +1096,7 @@ }, "setIdx": 1, "setId": 1, - "iconIdx": 38 + "iconIdx": 39 }, { "icon": { @@ -1095,7 +1122,7 @@ }, "setIdx": 1, "setId": 1, - "iconIdx": 39 + "iconIdx": 40 }, { "icon": { @@ -1121,7 +1148,7 @@ }, "setIdx": 1, "setId": 1, - "iconIdx": 40 + "iconIdx": 41 }, { "icon": { @@ -1147,7 +1174,7 @@ }, "setIdx": 1, "setId": 1, - "iconIdx": 41 + "iconIdx": 42 }, { "icon": { @@ -1173,7 +1200,7 @@ }, "setIdx": 1, "setId": 1, - "iconIdx": 42 + "iconIdx": 43 }, { "icon": { @@ -1199,7 +1226,7 @@ }, "setIdx": 1, "setId": 1, - "iconIdx": 43 + "iconIdx": 44 }, { "icon": { @@ -1225,7 +1252,7 @@ }, "setIdx": 1, "setId": 1, - "iconIdx": 44 + "iconIdx": 45 }, { "icon": { @@ -1251,7 +1278,7 @@ }, "setIdx": 1, "setId": 1, - "iconIdx": 45 + "iconIdx": 46 }, { "icon": { @@ -1280,7 +1307,7 @@ }, "setIdx": 1, "setId": 1, - "iconIdx": 46 + "iconIdx": 47 }, { "icon": { @@ -1310,7 +1337,7 @@ }, "setIdx": 1, "setId": 1, - "iconIdx": 47 + "iconIdx": 48 }, { "icon": { @@ -1340,7 +1367,7 @@ }, "setIdx": 1, "setId": 1, - "iconIdx": 48 + "iconIdx": 49 }, { "icon": { @@ -1366,7 +1393,7 @@ }, "setIdx": 1, "setId": 1, - "iconIdx": 49 + "iconIdx": 50 }, { "icon": { @@ -1392,7 +1419,7 @@ }, "setIdx": 1, "setId": 1, - "iconIdx": 50 + "iconIdx": 51 }, { "icon": { @@ -1418,7 +1445,7 @@ }, "setIdx": 1, "setId": 1, - "iconIdx": 51 + "iconIdx": 52 } ], "height": 1024, diff --git a/lang/main.json b/lang/main.json index 41991d30be..134d457605 100644 --- a/lang/main.json +++ b/lang/main.json @@ -531,6 +531,7 @@ "calendarSync": { "later": "Later", "next": "Upcoming", + "nextMeeting": "next meeting", "now": "Now" } } diff --git a/react/features/base/font-icons/jitsi.json b/react/features/base/font-icons/jitsi.json index 814ceacf47..4b0c9e5073 100755 --- a/react/features/base/font-icons/jitsi.json +++ b/react/features/base/font-icons/jitsi.json @@ -1,6 +1,33 @@ { "IcoMoonType": "selection", "icons": [ + { + "icon": { + "paths": [ + "M426 256l256 256-256 256-60-60 196-196-196-196z" + ], + "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, + "tags": [ + "navigate_next" + ], + "defaultCode": 58377, + "grid": 24 + }, + "attrs": [], + "properties": { + "ligatures": "chevron_right, navigate_next", + "id": 153, + "order": 927, + "prevSize": 24, + "code": 58377, + "name": "navigate_next" + }, + "setIdx": 0, + "setId": 2, + "iconIdx": 153 + }, { "icon": { "paths": [ @@ -24,9 +51,9 @@ "code": 58834, "name": "menu" }, - "setIdx": 0, - "setId": 2, - "iconIdx": 489 + "setIdx": 1, + "setId": 1, + "iconIdx": 0 }, { "icon": { @@ -53,7 +80,7 @@ }, "setIdx": 1, "setId": 1, - "iconIdx": 0 + "iconIdx": 1 }, { "icon": { @@ -80,7 +107,7 @@ }, "setIdx": 1, "setId": 1, - "iconIdx": 1 + "iconIdx": 2 }, { "icon": { @@ -107,7 +134,7 @@ }, "setIdx": 1, "setId": 1, - "iconIdx": 2 + "iconIdx": 3 }, { "icon": { @@ -134,7 +161,7 @@ }, "setIdx": 1, "setId": 1, - "iconIdx": 3 + "iconIdx": 4 }, { "icon": { @@ -161,7 +188,7 @@ }, "setIdx": 1, "setId": 1, - "iconIdx": 4 + "iconIdx": 5 }, { "icon": { @@ -188,7 +215,7 @@ }, "setIdx": 1, "setId": 1, - "iconIdx": 5 + "iconIdx": 6 }, { "icon": { @@ -215,7 +242,7 @@ }, "setIdx": 1, "setId": 1, - "iconIdx": 6 + "iconIdx": 7 }, { "icon": { @@ -242,7 +269,7 @@ }, "setIdx": 1, "setId": 1, - "iconIdx": 7 + "iconIdx": 8 }, { "icon": { @@ -269,7 +296,7 @@ }, "setIdx": 1, "setId": 1, - "iconIdx": 8 + "iconIdx": 9 }, { "icon": { @@ -298,7 +325,7 @@ }, "setIdx": 1, "setId": 1, - "iconIdx": 9 + "iconIdx": 10 }, { "icon": { @@ -325,7 +352,7 @@ }, "setIdx": 1, "setId": 1, - "iconIdx": 10 + "iconIdx": 11 }, { "icon": { @@ -352,7 +379,7 @@ }, "setIdx": 1, "setId": 1, - "iconIdx": 11 + "iconIdx": 12 }, { "icon": { @@ -381,7 +408,7 @@ }, "setIdx": 1, "setId": 1, - "iconIdx": 12 + "iconIdx": 13 }, { "icon": { @@ -410,7 +437,7 @@ }, "setIdx": 1, "setId": 1, - "iconIdx": 13 + "iconIdx": 14 }, { "icon": { @@ -439,7 +466,7 @@ }, "setIdx": 1, "setId": 1, - "iconIdx": 14 + "iconIdx": 15 }, { "icon": { @@ -468,7 +495,7 @@ }, "setIdx": 1, "setId": 1, - "iconIdx": 15 + "iconIdx": 16 }, { "icon": { @@ -497,7 +524,7 @@ }, "setIdx": 1, "setId": 1, - "iconIdx": 16 + "iconIdx": 17 }, { "icon": { @@ -523,7 +550,7 @@ }, "setIdx": 1, "setId": 1, - "iconIdx": 17 + "iconIdx": 18 }, { "icon": { @@ -549,7 +576,7 @@ }, "setIdx": 1, "setId": 1, - "iconIdx": 18 + "iconIdx": 19 }, { "icon": { @@ -575,7 +602,7 @@ }, "setIdx": 1, "setId": 1, - "iconIdx": 19 + "iconIdx": 20 }, { "icon": { @@ -601,7 +628,7 @@ }, "setIdx": 1, "setId": 1, - "iconIdx": 20 + "iconIdx": 21 }, { "icon": { @@ -627,7 +654,7 @@ }, "setIdx": 1, "setId": 1, - "iconIdx": 21 + "iconIdx": 22 }, { "icon": { @@ -653,7 +680,7 @@ }, "setIdx": 1, "setId": 1, - "iconIdx": 22 + "iconIdx": 23 }, { "icon": { @@ -679,7 +706,7 @@ }, "setIdx": 1, "setId": 1, - "iconIdx": 23 + "iconIdx": 24 }, { "icon": { @@ -705,7 +732,7 @@ }, "setIdx": 1, "setId": 1, - "iconIdx": 24 + "iconIdx": 25 }, { "icon": { @@ -731,7 +758,7 @@ }, "setIdx": 1, "setId": 1, - "iconIdx": 25 + "iconIdx": 26 }, { "icon": { @@ -757,7 +784,7 @@ }, "setIdx": 1, "setId": 1, - "iconIdx": 26 + "iconIdx": 27 }, { "icon": { @@ -783,7 +810,7 @@ }, "setIdx": 1, "setId": 1, - "iconIdx": 27 + "iconIdx": 28 }, { "icon": { @@ -809,7 +836,7 @@ }, "setIdx": 1, "setId": 1, - "iconIdx": 28 + "iconIdx": 29 }, { "icon": { @@ -835,7 +862,7 @@ }, "setIdx": 1, "setId": 1, - "iconIdx": 29 + "iconIdx": 30 }, { "icon": { @@ -861,7 +888,7 @@ }, "setIdx": 1, "setId": 1, - "iconIdx": 30 + "iconIdx": 31 }, { "icon": { @@ -887,7 +914,7 @@ }, "setIdx": 1, "setId": 1, - "iconIdx": 31 + "iconIdx": 32 }, { "icon": { @@ -913,7 +940,7 @@ }, "setIdx": 1, "setId": 1, - "iconIdx": 32 + "iconIdx": 33 }, { "icon": { @@ -939,7 +966,7 @@ }, "setIdx": 1, "setId": 1, - "iconIdx": 33 + "iconIdx": 34 }, { "icon": { @@ -965,7 +992,7 @@ }, "setIdx": 1, "setId": 1, - "iconIdx": 34 + "iconIdx": 35 }, { "icon": { @@ -991,7 +1018,7 @@ }, "setIdx": 1, "setId": 1, - "iconIdx": 35 + "iconIdx": 36 }, { "icon": { @@ -1017,7 +1044,7 @@ }, "setIdx": 1, "setId": 1, - "iconIdx": 36 + "iconIdx": 37 }, { "icon": { @@ -1043,7 +1070,7 @@ }, "setIdx": 1, "setId": 1, - "iconIdx": 37 + "iconIdx": 38 }, { "icon": { @@ -1069,7 +1096,7 @@ }, "setIdx": 1, "setId": 1, - "iconIdx": 38 + "iconIdx": 39 }, { "icon": { @@ -1095,7 +1122,7 @@ }, "setIdx": 1, "setId": 1, - "iconIdx": 39 + "iconIdx": 40 }, { "icon": { @@ -1121,7 +1148,7 @@ }, "setIdx": 1, "setId": 1, - "iconIdx": 40 + "iconIdx": 41 }, { "icon": { @@ -1147,7 +1174,7 @@ }, "setIdx": 1, "setId": 1, - "iconIdx": 41 + "iconIdx": 42 }, { "icon": { @@ -1173,7 +1200,7 @@ }, "setIdx": 1, "setId": 1, - "iconIdx": 42 + "iconIdx": 43 }, { "icon": { @@ -1199,7 +1226,7 @@ }, "setIdx": 1, "setId": 1, - "iconIdx": 43 + "iconIdx": 44 }, { "icon": { @@ -1225,7 +1252,7 @@ }, "setIdx": 1, "setId": 1, - "iconIdx": 44 + "iconIdx": 45 }, { "icon": { @@ -1251,7 +1278,7 @@ }, "setIdx": 1, "setId": 1, - "iconIdx": 45 + "iconIdx": 46 }, { "icon": { @@ -1280,7 +1307,7 @@ }, "setIdx": 1, "setId": 1, - "iconIdx": 46 + "iconIdx": 47 }, { "icon": { @@ -1310,7 +1337,7 @@ }, "setIdx": 1, "setId": 1, - "iconIdx": 47 + "iconIdx": 48 }, { "icon": { @@ -1340,7 +1367,7 @@ }, "setIdx": 1, "setId": 1, - "iconIdx": 48 + "iconIdx": 49 }, { "icon": { @@ -1366,7 +1393,7 @@ }, "setIdx": 1, "setId": 1, - "iconIdx": 49 + "iconIdx": 50 }, { "icon": { @@ -1392,7 +1419,7 @@ }, "setIdx": 1, "setId": 1, - "iconIdx": 50 + "iconIdx": 51 }, { "icon": { @@ -1418,7 +1445,7 @@ }, "setIdx": 1, "setId": 1, - "iconIdx": 51 + "iconIdx": 52 } ], "height": 1024, diff --git a/react/features/calendar-sync/components/ConferenceNotification.native.js b/react/features/calendar-sync/components/ConferenceNotification.native.js new file mode 100644 index 0000000000..c3515d135f --- /dev/null +++ b/react/features/calendar-sync/components/ConferenceNotification.native.js @@ -0,0 +1,284 @@ +// @flow +import React, { Component } from 'react'; +import { + Text, + TouchableOpacity, + View +} from 'react-native'; +import { connect } from 'react-redux'; + +import { appNavigate } from '../../app'; +import { getURLWithoutParams } from '../../base/connection'; +import { translate } from '../../base/i18n'; +import { Icon } from '../../base/font-icons'; +import { ASPECT_RATIO_NARROW } from '../../base/responsive-ui'; +import { getLocalizedDateFormatter } from '../../base/util'; + +import styles from './styles'; + +const ALERT_MILLISECONDS = 5 * 60 * 1000; + +type Props = { + + /** + * The Redux dispatch function. + */ + dispatch: Function, + + /** + * The current aspect ratio of the screen. + */ + _aspectRatio: Symbol, + + /** + * The URL of the current conference without params. + */ + _currentConferenceURL: string, + + /** + * The calendar event list. + */ + _eventList: Array, + + /** + * The translate function. + */ + t: Function +}; + +type State = { + + /** + * The event object to display the notification for. + */ + event?: Object +}; + +/** + * Component to display a permanent badge-like notification on the + * conference screen when another meeting is about to start. + */ +class ConferenceNotification extends Component { + updateIntervalId: number; + + /** + * Constructor of the ConferenceNotification component. + * + * @inheritdoc + */ + constructor(props) { + super(props); + + this.state = { + event: undefined + }; + + this._getNotificationContentStyle + = this._getNotificationContentStyle.bind(this); + this._getNotificationPosition + = this._getNotificationPosition.bind(this); + this._maybeDisplayNotification + = this._maybeDisplayNotification.bind(this); + this._onGoToNext = this._onGoToNext.bind(this); + } + + /** + * Implements React Component's componentDidMount. + * + * @inheritdoc + */ + componentDidMount() { + this.updateIntervalId = setInterval( + this._maybeDisplayNotification, + 10 * 1000 + ); + } + + /** + * Implements React Component's componentWillUnmount. + * + * @inheritdoc + */ + componentWillUnmount() { + clearTimeout(this.updateIntervalId); + } + + /** + * Implements the React Components's render method. + * + * @inheritdoc + */ + render() { + const { event } = this.state; + const { t } = this.props; + + if (event) { + return ( + + + + + + + { t('calendarSync.nextMeeting') } + + + { + getLocalizedDateFormatter( + event.startDate + ).fromNow() + } + + + + + + + + + + ); + } + + return null; + } + + _getNotificationContentStyle: () => Array + + /** + * Decides the color of the notification and some additional + * styles based on notificationPosition. + * + * @private + * @returns {Array} + */ + _getNotificationContentStyle() { + const { event } = this.state; + const { _aspectRatio } = this.props; + const now = Date.now(); + const style = [ + styles.notificationContent + ]; + + if (event && event.startDate < now && event.endDate > now) { + style.push(styles.notificationContentPast); + } else { + style.push(styles.notificationContentNext); + } + + if (_aspectRatio === ASPECT_RATIO_NARROW) { + style.push(styles.notificationContentSide); + } else { + style.push(styles.notificationContentTop); + } + + return style; + } + + _getNotificationPosition: () => Object; + + /** + * Decides the position of the notification. + * + * @private + * @returns {Object} + */ + _getNotificationPosition() { + const { _aspectRatio } = this.props; + + if (_aspectRatio === ASPECT_RATIO_NARROW) { + return styles.notificationContainerSide; + } + + return styles.notificationContainerTop; + } + + _maybeDisplayNotification: () => void; + + /** + * Periodically checks if there is an event in the calendar for which we + * need to show a notification. + * + * @private + * @returns {void} + */ + _maybeDisplayNotification() { + const { _currentConferenceURL, _eventList } = this.props; + let eventToShow; + + if (_eventList && _eventList.length) { + const now = Date.now(); + + for (const event of _eventList) { + if (event.url !== _currentConferenceURL) { + if ((!eventToShow + && event.startDate > now + && event.startDate < now + ALERT_MILLISECONDS) + || (event.startDate < now && event.endDate > now) + ) { + eventToShow = event; + } + } + } + } + + this.setState({ + event: eventToShow + }); + } + + _onGoToNext: () => void; + + /** + * Opens the meeting URL that the notification shows. + * + * @private + * @param {string} url - The URL to open. + * @returns {void} + */ + _onGoToNext() { + const { event } = this.state; + + if (event && event.url) { + this.props.dispatch(appNavigate(event.url)); + } + } + +} + +/** + * Maps redux state to component props. + * + * @param {Object} state - The redux state. + * @returns {{ + * _aspectRatio: Symbol, + * _currentConferenceURL: string, + * _eventList: Array + * }} + */ +export function _mapStateToProps(state: Object) { + const { locationURL } = state['features/base/connection']; + + return { + _aspectRatio: state['features/base/responsive-ui'].aspectRatio, + _currentConferenceURL: + locationURL ? getURLWithoutParams(locationURL)._url : '', + _eventList: state['features/calendar-sync'].events + }; +} + +export default translate(connect(_mapStateToProps)(ConferenceNotification)); diff --git a/react/features/calendar-sync/components/index.js b/react/features/calendar-sync/components/index.js index a1e8409ca9..6f467d016d 100644 --- a/react/features/calendar-sync/components/index.js +++ b/react/features/calendar-sync/components/index.js @@ -1 +1,2 @@ export { default as MeetingList } from './MeetingList'; +export { default as ConferenceNotification } from './ConferenceNotification'; diff --git a/react/features/calendar-sync/components/styles.js b/react/features/calendar-sync/components/styles.js index 0df69074b7..09dc07dfce 100644 --- a/react/features/calendar-sync/components/styles.js +++ b/react/features/calendar-sync/components/styles.js @@ -1,9 +1,8 @@ import { createStyleSheet } from '../../base/styles'; const AVATAR_OPACITY = 0.4; - const AVATAR_SIZE = 65; - +const NOTIFICATION_SIZE = 55; const OVERLAY_FONT_COLOR = 'rgba(255, 255, 255, 0.6)'; export const UNDERLAY_COLOR = 'rgba(255, 255, 255, 0.2)'; @@ -50,6 +49,105 @@ export default createStyleSheet({ textAlign: 'center' }, + /** + * Style for the actual notification content. + */ + notificationContainer: { + flexDirection: 'row', + justifyContent: 'center', + overflow: 'hidden', + position: 'absolute' + }, + + /** + * Additional style for the container when the notification is displayed + * on the side (narrow view). + */ + notificationContainerSide: { + top: 100 + }, + + /** + * Additional style for the container when the notification is displayed + * on the top (wide view). + */ + notificationContainerTop: { + justifyContent: 'center', + left: 0, + right: 0, + top: 0 + }, + + /** + * The top level container of the notification. + */ + notificationContent: { + alignSelf: 'flex-start', + flexDirection: 'row', + height: NOTIFICATION_SIZE, + justifyContent: 'center', + paddingHorizontal: 10 + }, + + /** + * Color for upcoming meeting notification. + */ + notificationContentNext: { + backgroundColor: '#eeb231' + }, + + /** + * Color for already ongoing meeting notifications. + */ + notificationContentPast: { + backgroundColor: 'red' + }, + + /** + * Additional style for the content when the notification is displayed + * on the side (narrow view). + */ + notificationContentSide: { + borderBottomRightRadius: NOTIFICATION_SIZE, + borderTopRightRadius: NOTIFICATION_SIZE + }, + + /** + * Additional style for the content when the notification is displayed + * on the top (wide view). + */ + notificationContentTop: { + borderBottomLeftRadius: NOTIFICATION_SIZE / 2, + borderBottomRightRadius: NOTIFICATION_SIZE / 2, + paddingHorizontal: 20 + }, + + /** + * The icon of the notification. + */ + notificationIcon: { + color: 'white', + fontSize: 25 + }, + + notificationIconContainer: { + alignItems: 'center', + flexDirection: 'row', + height: NOTIFICATION_SIZE, + justifyContent: 'center' + }, + + notificationText: { + color: 'white', + fontSize: 13 + }, + + notificationTextContainer: { + flexDirection: 'column', + height: NOTIFICATION_SIZE, + justifyContent: 'center' + }, + /** * The top level container style of the list. */ @@ -105,5 +203,9 @@ export default createStyleSheet({ color: OVERLAY_FONT_COLOR, fontSize: 14, fontWeight: 'normal' + }, + + touchableView: { + flexDirection: 'row' } }); diff --git a/react/features/calendar-sync/middleware.js b/react/features/calendar-sync/middleware.js index e11ddcd467..82b3452747 100644 --- a/react/features/calendar-sync/middleware.js +++ b/react/features/calendar-sync/middleware.js @@ -117,6 +117,24 @@ function _fetchCalendarEntries(store) { } } + // TEST events to check notification popup. + // TODO: Remove this before a PR. + eventList.push({ + endDate: Date.now() + (60 * 60 * 1000), + id: -1, + startDate: Date.now() + (80 * 1000), + title: 'ShipIt 41', + url: 'https://meet.jit.si/shipit41' + }); + + eventList.push({ + endDate: Date.now() + (2 * 60 * 60 * 1000), + id: -2, + startDate: Date.now() + (60 * 60 * 1000), + title: 'ShipIt 41 demo', + url: 'https://meet.jit.si/shipit41' + }); + store.dispatch(updateCalendarEntryList(eventList.sort((a, b) => a.startDate - b.startDate ).slice(0, MAX_LIST_LENGTH))); diff --git a/react/features/conference/components/Conference.native.js b/react/features/conference/components/Conference.native.js index c900669fb3..be26ee8bcb 100644 --- a/react/features/conference/components/Conference.native.js +++ b/react/features/conference/components/Conference.native.js @@ -12,6 +12,7 @@ import { DialogContainer } from '../../base/dialog'; import { CalleeInfoContainer } from '../../base/jwt'; import { Container, LoadingIndicator, TintedView } from '../../base/react'; import { createDesiredLocalTracks } from '../../base/tracks'; +import { ConferenceNotification } from '../../calendar-sync'; import { Filmstrip } from '../../filmstrip'; import { LargeVideo } from '../../large-video'; import { setToolboxVisible, Toolbox } from '../../toolbox'; @@ -233,6 +234,8 @@ class Conference extends Component { + + {/* * The dialogs are in the topmost stacking layers. */ diff --git a/react/features/recent-list/components/AbstractRecentList.js b/react/features/recent-list/components/AbstractRecentList.js index e33eeb0a86..bd8972c780 100644 --- a/react/features/recent-list/components/AbstractRecentList.js +++ b/react/features/recent-list/components/AbstractRecentList.js @@ -13,14 +13,14 @@ type Props = { _recentList: Array, /** - * The redux store's {@code dispatch} function. + * Indicates if the list is disabled or not. */ - dispatch: Dispatch<*>, + disabled: boolean, /** - * Whether {@code AbstractRecentList} is enabled. + * The redux store's {@code dispatch} function. */ - enabled: boolean + dispatch: Dispatch<*> }; /** @@ -40,9 +40,9 @@ export default class AbstractRecentList extends Component { * @returns {void} */ _onJoin(room) { - const { dispatch, enabled } = this.props; + const { dispatch, disabled } = this.props; - enabled && room && dispatch(appNavigate(room)); + !disabled && room && dispatch(appNavigate(room)); } /** diff --git a/react/features/recent-list/components/RecentList.native.js b/react/features/recent-list/components/RecentList.native.js index 856700b8a6..a568adf9e3 100644 --- a/react/features/recent-list/components/RecentList.native.js +++ b/react/features/recent-list/components/RecentList.native.js @@ -53,7 +53,7 @@ class RecentList extends AbstractRecentList { * @returns {ReactElement} */ render() { - const { enabled, _recentList } = this.props; + const { disabled, _recentList } = this.props; if (!_recentList) { return null; @@ -66,7 +66,7 @@ class RecentList extends AbstractRecentList {