Add conference notification

This commit is contained in:
zbettenbuk 2018-02-12 09:53:23 -06:00 committed by Lyubo Marinov
parent bba480f329
commit ae0bf876a8
15 changed files with 587 additions and 120 deletions

View File

@ -36,6 +36,9 @@
.icon-navigate_before:before {
content: "\e408";
}
.icon-navigate_next:before {
content: "\e409";
}
.icon-public:before {
content: "\e80b";
}

Binary file not shown.

View File

@ -12,6 +12,7 @@
<glyph unicode="&#xe1aa;" glyph-name="bluetooth" d="M550 328l-80 82v-162zM470 776v-162l80 82zM670 696l-184-184 184-184-244-242h-42v324l-196-196-60 60 238 238-238 238 60 60 196-196v324h42zM834 738c40-64 62-142 62-222 0-84-24-160-66-226l-50 50c26 52 42 110 42 172s-16 120-42 172zM608 512l98 98c12-30 20-64 20-98s-8-70-20-100z" />
<glyph unicode="&#xe310;" glyph-name="headset" d="M512 982c212 0 384-172 384-384v-300c0-70-58-128-128-128h-128v342h170v86c0 166-132 298-298 298s-298-132-298-298v-86h170v-342h-128c-70 0-128 58-128 128v300c0 212 172 384 384 384z" />
<glyph unicode="&#xe408;" glyph-name="navigate_before" d="M658 708l-196-196 196-196-60-60-256 256 256 256z" />
<glyph unicode="&#xe409;" glyph-name="navigate_next" d="M426 768l256-256-256-256-60 60 196 196-196 196z" />
<glyph unicode="&#xe425;" glyph-name="timer" d="M512 170c166 0 298 134 298 300s-132 298-298 298-298-132-298-298 132-300 298-300zM812 708c52-66 84-148 84-238 0-212-172-384-384-384s-384 172-384 384 172 384 384 384c90 0 174-34 240-86l60 62c22-18 42-38 60-60zM470 426v256h84v-256h-84zM640 982v-86h-256v86h256z" />
<glyph unicode="&#xe5c4;" glyph-name="arrow_back" d="M854 554v-84h-520l238-240-60-60-342 342 342 342 60-60-238-240h520z" />
<glyph unicode="&#xe5d2;" glyph-name="menu" d="M128 768h768v-86h-768v86zM128 470v84h768v-84h-768zM128 256v86h768v-86h-768z" />

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Binary file not shown.

View File

@ -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,

View File

@ -531,6 +531,7 @@
"calendarSync": {
"later": "Later",
"next": "Upcoming",
"nextMeeting": "next meeting",
"now": "Now"
}
}

View File

@ -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,

View File

@ -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<Object>,
/**
* 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<Props, State> {
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 (
<View
style = { [
styles.notificationContainer,
this._getNotificationPosition()
] } >
<View
style = { this._getNotificationContentStyle() }>
<TouchableOpacity
onPress = { this._onGoToNext } >
<View style = { styles.touchableView }>
<View
style = {
styles.notificationTextContainer
}>
<Text style = { styles.notificationText }>
{ t('calendarSync.nextMeeting') }
</Text>
<Text style = { styles.notificationText }>
{
getLocalizedDateFormatter(
event.startDate
).fromNow()
}
</Text>
</View>
<View
style = {
styles.notificationIconContainer
}>
<Icon
name = 'navigate_next'
style = { styles.notificationIcon } />
</View>
</View>
</TouchableOpacity>
</View>
</View>
);
}
return null;
}
_getNotificationContentStyle: () => Array<Object>
/**
* Decides the color of the notification and some additional
* styles based on notificationPosition.
*
* @private
* @returns {Array<Object>}
*/
_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));

View File

@ -1 +1,2 @@
export { default as MeetingList } from './MeetingList';
export { default as ConferenceNotification } from './ConferenceNotification';

View File

@ -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'
}
});

View File

@ -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)));

View File

@ -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<Props> {
<Filmstrip />
</View>
<ConferenceNotification />
{/*
* The dialogs are in the topmost stacking layers.
*/

View File

@ -13,14 +13,14 @@ type Props = {
_recentList: Array<Object>,
/**
* 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<Props> {
* @returns {void}
*/
_onJoin(room) {
const { dispatch, enabled } = this.props;
const { dispatch, disabled } = this.props;
enabled && room && dispatch(appNavigate(room));
!disabled && room && dispatch(appNavigate(room));
}
/**

View File

@ -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 {
<SafeAreaView
style = { [
styles.container,
enabled ? null : styles.containerDisabled
disabled ? styles.containerDisabled : null
] }>
<ListView
dataSource = { listViewDataSource }