Facelift Welcome screen

This commit is contained in:
zbettenbuk 2018-02-02 15:50:16 +01:00 committed by Lyubo Marinov
parent 9a9890f86c
commit 04690dfc8f
27 changed files with 992 additions and 292 deletions

View File

@ -30,6 +30,9 @@
.icon-event_note:before {
content: "\e616";
}
.icon-menu:before {
content: "\e5d2";
}
.icon-navigate_before:before {
content: "\e408";
}

Binary file not shown.

View File

@ -14,6 +14,7 @@
<glyph unicode="&#xe408;" glyph-name="navigate_before" d="M658 708l-196-196 196-196-60-60-256 256 256 256z" />
<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" />
<glyph unicode="&#xe5d4;" glyph-name="thumb-menu" d="M512 342c46 0 86-40 86-86s-40-86-86-86-86 40-86 86 40 86 86 86zM512 598c46 0 86-40 86-86s-40-86-86-86-86 40-86 86 40 86 86 86zM512 682c-46 0-86 40-86 86s40 86 86 86 86-40 86-86-40-86-86-86z" />
<glyph unicode="&#xe603;" glyph-name="presentation" horiz-adv-x="1088" d="M952.495 1019.065h-818.689c-72.81 0-132.183-60.63-132.183-135.162v-750.719c0-74.473 59.372-135.101 132.183-135.101h818.686c72.936 0 132.314 60.625 132.314 135.101v750.722c0.003 74.532-59.378 135.159-132.311 135.159zM946.346 139.651h-806.14v737.822h806.015l0.126-737.822zM685.753 738.544h216.911v-566.758h-216.911v566.758zM428.672 610.002h216.911v-438.216h-216.911v438.216zM172.339 481.46h216.161v-309.677h-216.161v309.677z" />
<glyph unicode="&#xe613;" glyph-name="recDisable" horiz-adv-x="1140" d="M1123.444 1003.015c-23.593 26.481-64.131 28.989-90.74 5.395l-1008.269-893.436c-26.609-23.468-28.991-64.131-5.46-90.676 12.674-14.306 30.308-21.649 48.126-21.649 15.123 0 30.372 5.401 42.544 16.195l130.045 115.22c90.743-81.844 210.569-132.165 342.473-132.101 282.816 0.061 510.913 227.969 511.287 510.972 0.126 109.934-34.682 211.367-93.499 294.72l118.088 104.625c26.483 23.526 28.997 64.129 5.404 90.735zM944.422 513.818c0.128-200.922-161.896-363.201-362.509-362.952-87.56 0.123-167.573 31.151-230.061 82.569l331.277 293.509v-73.176c1.071-60.993 32.696-92.18 94.944-93.692 61.997 1.512 93.686 32.763 95.131 93.756v41.096h-72.227v-47.499c0.251-4.642-0.564-10.607-2.511-17.949-1.25-3.261-3.448-6.020-6.525-8.093-3.197-2.572-7.845-3.828-13.868-3.828-10.543 0.31-17.132 4.268-19.827 11.921-1.068 3.512-1.947 6.905-2.508 10.163-0.254 2.887-0.377 5.532-0.377 7.786v143.511l42.477 37.634c0.215-0.432 0.452-0.851 0.63-1.303 1.947-6.467 2.762-12.799 2.511-19.076v-36.772h72.227v30.121c-0.246 31.245-9.086 54.699-26.363 70.447l40.711 36.069c35.787-56.055 56.803-122.585 56.867-194.244zM239.795 395.47c-12.613 37.023-19.827 76.557-19.827 117.913-0.19 200.236 161.584 362.009 361.945 362.135 56.853 0 110.313-13.302 158.133-36.398l117.846 104.421c-79.444 50.952-173.758 80.817-275.292 80.948-283.377 0.181-511.354-227.729-511.789-511.675-0.126-79.567 18.636-154.679 51.137-221.882l117.848 104.538zM388.576 690.020h-97.514v-249.057l72.23 64.070v0.689h0.815l117.72 104.418c0 0.564 0.123 0.94 0.123 1.509 0.753 53.898-30.369 80.069-93.374 78.37zM405.959 625.517c1.942-2.767 3.074-6.469 3.323-11.112 0.312-4.452 0.438-9.6 0.438-15.246 0.251-10.916-0.689-19.83-2.949-26.985-2.952-7.594-10.983-11.357-24.159-11.357h-19.325v74.043h15.31c7.842 0 13.865-0.683 18.072-2.19 4.397-1.573 7.468-3.953 9.29-7.153z" />

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": [
"M128 256h768v86h-768v-86zM128 554v-84h768v84h-768zM128 768v-86h768v86h-768z"
],
"attrs": [],
"isMulticolor": false,
"isMulticolor2": false,
"tags": [
"menu"
],
"defaultCode": 58834,
"grid": 24
},
"attrs": [],
"properties": {
"ligatures": "menu",
"id": 489,
"order": 926,
"prevSize": 24,
"code": 58834,
"name": "menu"
},
"setIdx": 0,
"setId": 2,
"iconIdx": 489
},
{
"icon": {
"paths": [
@ -24,9 +51,9 @@
"code": 58820,
"name": "arrow_back"
},
"setIdx": 0,
"setId": 2,
"iconIdx": 45
"setIdx": 1,
"setId": 1,
"iconIdx": 0
},
{
"icon": {
@ -51,9 +78,9 @@
"code": 58376,
"name": "navigate_before"
},
"setIdx": 0,
"setId": 2,
"iconIdx": 152
"setIdx": 1,
"setId": 1,
"iconIdx": 1
},
{
"icon": {
@ -80,7 +107,7 @@
},
"setIdx": 1,
"setId": 1,
"iconIdx": 0
"iconIdx": 2
},
{
"icon": {
@ -107,7 +134,7 @@
},
"setIdx": 1,
"setId": 1,
"iconIdx": 1
"iconIdx": 3
},
{
"icon": {
@ -134,7 +161,7 @@
},
"setIdx": 1,
"setId": 1,
"iconIdx": 2
"iconIdx": 4
},
{
"icon": {
@ -161,7 +188,7 @@
},
"setIdx": 1,
"setId": 1,
"iconIdx": 3
"iconIdx": 5
},
{
"icon": {
@ -188,7 +215,7 @@
},
"setIdx": 1,
"setId": 1,
"iconIdx": 4
"iconIdx": 6
},
{
"icon": {
@ -215,7 +242,7 @@
},
"setIdx": 1,
"setId": 1,
"iconIdx": 5
"iconIdx": 7
},
{
"icon": {
@ -242,7 +269,7 @@
},
"setIdx": 1,
"setId": 1,
"iconIdx": 6
"iconIdx": 8
},
{
"icon": {
@ -271,7 +298,7 @@
},
"setIdx": 1,
"setId": 1,
"iconIdx": 7
"iconIdx": 9
},
{
"icon": {
@ -298,7 +325,7 @@
},
"setIdx": 1,
"setId": 1,
"iconIdx": 8
"iconIdx": 10
},
{
"icon": {
@ -325,7 +352,7 @@
},
"setIdx": 1,
"setId": 1,
"iconIdx": 9
"iconIdx": 11
},
{
"icon": {
@ -354,7 +381,7 @@
},
"setIdx": 1,
"setId": 1,
"iconIdx": 10
"iconIdx": 12
},
{
"icon": {
@ -383,7 +410,7 @@
},
"setIdx": 1,
"setId": 1,
"iconIdx": 11
"iconIdx": 13
},
{
"icon": {
@ -412,7 +439,7 @@
},
"setIdx": 1,
"setId": 1,
"iconIdx": 12
"iconIdx": 14
},
{
"icon": {
@ -441,7 +468,7 @@
},
"setIdx": 1,
"setId": 1,
"iconIdx": 13
"iconIdx": 15
},
{
"icon": {
@ -470,7 +497,7 @@
},
"setIdx": 1,
"setId": 1,
"iconIdx": 14
"iconIdx": 16
},
{
"icon": {
@ -496,7 +523,7 @@
},
"setIdx": 1,
"setId": 1,
"iconIdx": 15
"iconIdx": 17
},
{
"icon": {
@ -522,7 +549,7 @@
},
"setIdx": 1,
"setId": 1,
"iconIdx": 16
"iconIdx": 18
},
{
"icon": {
@ -548,7 +575,7 @@
},
"setIdx": 1,
"setId": 1,
"iconIdx": 17
"iconIdx": 19
},
{
"icon": {
@ -574,7 +601,7 @@
},
"setIdx": 1,
"setId": 1,
"iconIdx": 18
"iconIdx": 20
},
{
"icon": {
@ -600,7 +627,7 @@
},
"setIdx": 1,
"setId": 1,
"iconIdx": 19
"iconIdx": 21
},
{
"icon": {
@ -626,7 +653,7 @@
},
"setIdx": 1,
"setId": 1,
"iconIdx": 20
"iconIdx": 22
},
{
"icon": {
@ -652,7 +679,7 @@
},
"setIdx": 1,
"setId": 1,
"iconIdx": 21
"iconIdx": 23
},
{
"icon": {
@ -678,7 +705,7 @@
},
"setIdx": 1,
"setId": 1,
"iconIdx": 22
"iconIdx": 24
},
{
"icon": {
@ -704,7 +731,7 @@
},
"setIdx": 1,
"setId": 1,
"iconIdx": 23
"iconIdx": 25
},
{
"icon": {
@ -730,7 +757,7 @@
},
"setIdx": 1,
"setId": 1,
"iconIdx": 24
"iconIdx": 26
},
{
"icon": {
@ -756,7 +783,7 @@
},
"setIdx": 1,
"setId": 1,
"iconIdx": 25
"iconIdx": 27
},
{
"icon": {
@ -782,7 +809,7 @@
},
"setIdx": 1,
"setId": 1,
"iconIdx": 26
"iconIdx": 28
},
{
"icon": {
@ -808,7 +835,7 @@
},
"setIdx": 1,
"setId": 1,
"iconIdx": 27
"iconIdx": 29
},
{
"icon": {
@ -834,7 +861,7 @@
},
"setIdx": 1,
"setId": 1,
"iconIdx": 28
"iconIdx": 30
},
{
"icon": {
@ -860,7 +887,7 @@
},
"setIdx": 1,
"setId": 1,
"iconIdx": 29
"iconIdx": 31
},
{
"icon": {
@ -886,7 +913,7 @@
},
"setIdx": 1,
"setId": 1,
"iconIdx": 30
"iconIdx": 32
},
{
"icon": {
@ -912,7 +939,7 @@
},
"setIdx": 1,
"setId": 1,
"iconIdx": 31
"iconIdx": 33
},
{
"icon": {
@ -938,7 +965,7 @@
},
"setIdx": 1,
"setId": 1,
"iconIdx": 32
"iconIdx": 34
},
{
"icon": {
@ -964,7 +991,7 @@
},
"setIdx": 1,
"setId": 1,
"iconIdx": 33
"iconIdx": 35
},
{
"icon": {
@ -990,7 +1017,7 @@
},
"setIdx": 1,
"setId": 1,
"iconIdx": 34
"iconIdx": 36
},
{
"icon": {
@ -1016,7 +1043,7 @@
},
"setIdx": 1,
"setId": 1,
"iconIdx": 35
"iconIdx": 37
},
{
"icon": {
@ -1042,7 +1069,7 @@
},
"setIdx": 1,
"setId": 1,
"iconIdx": 36
"iconIdx": 38
},
{
"icon": {
@ -1068,7 +1095,7 @@
},
"setIdx": 1,
"setId": 1,
"iconIdx": 37
"iconIdx": 39
},
{
"icon": {
@ -1094,7 +1121,7 @@
},
"setIdx": 1,
"setId": 1,
"iconIdx": 38
"iconIdx": 40
},
{
"icon": {
@ -1120,7 +1147,7 @@
},
"setIdx": 1,
"setId": 1,
"iconIdx": 39
"iconIdx": 41
},
{
"icon": {
@ -1146,7 +1173,7 @@
},
"setIdx": 1,
"setId": 1,
"iconIdx": 40
"iconIdx": 42
},
{
"icon": {
@ -1172,7 +1199,7 @@
},
"setIdx": 1,
"setId": 1,
"iconIdx": 41
"iconIdx": 43
},
{
"icon": {
@ -1198,7 +1225,7 @@
},
"setIdx": 1,
"setId": 1,
"iconIdx": 42
"iconIdx": 44
},
{
"icon": {
@ -1224,7 +1251,7 @@
},
"setIdx": 1,
"setId": 1,
"iconIdx": 43
"iconIdx": 45
},
{
"icon": {
@ -1253,7 +1280,7 @@
},
"setIdx": 1,
"setId": 1,
"iconIdx": 44
"iconIdx": 46
},
{
"icon": {
@ -1283,7 +1310,7 @@
},
"setIdx": 1,
"setId": 1,
"iconIdx": 45
"iconIdx": 47
},
{
"icon": {
@ -1313,7 +1340,7 @@
},
"setIdx": 1,
"setId": 1,
"iconIdx": 46
"iconIdx": 48
},
{
"icon": {
@ -1339,7 +1366,7 @@
},
"setIdx": 1,
"setId": 1,
"iconIdx": 47
"iconIdx": 49
},
{
"icon": {
@ -1365,7 +1392,7 @@
},
"setIdx": 1,
"setId": 1,
"iconIdx": 48
"iconIdx": 50
},
{
"icon": {
@ -1391,7 +1418,7 @@
},
"setIdx": 1,
"setId": 1,
"iconIdx": 49
"iconIdx": 51
}
],
"height": 1024,

View File

@ -514,5 +514,8 @@
"serverURL": "Server URL",
"startWithAudioMuted": "Start with audio muted",
"startWithVideoMuted": "Start with video muted"
},
"sideBar": {
"settings": "Settings"
}
}

View File

@ -85,15 +85,15 @@ export const createApiEvent = function(action, attributes = {}) {
};
/**
* Creates an event which indicates that the audio-only mode has been turned
* off.
* Creates an event which indicates that the audio-only mode has been changed.
*
* @param {boolean} enabled - True if audio-only is enabled, false otherwise.
* @returns {Object} The event in a format suitable for sending via
* sendAnalytics.
*/
export const createAudioOnlyDisableEvent = function() {
export const createAudioOnlyChangedEvent = function(enabled) {
return {
action: 'audio.only.disabled'
action: `audio.only.${enabled ? 'enabled' : 'disabled'}`
};
};

View File

@ -3,7 +3,7 @@
import {
ACTION_PINNED,
ACTION_UNPINNED,
createAudioOnlyDisableEvent,
createAudioOnlyChangedEvent,
createPinnedEvent,
sendAnalytics
} from '../../analytics';
@ -125,11 +125,20 @@ function _connectionEstablished({ dispatch }, next, action) {
*/
function _conferenceFailedOrLeft({ dispatch, getState }, next, action) {
const result = next(action);
const state = getState();
const { audioOnly } = state['features/base/conference'];
const { startAudioOnly } = state['features/base/profile'].profile;
if (getState()['features/base/conference'].audioOnly) {
sendAnalytics(createAudioOnlyDisableEvent());
// FIXME: Consider implementing a standalone audio-only feature
// that handles all these state changes.
if (audioOnly && !startAudioOnly) {
sendAnalytics(createAudioOnlyChangedEvent(false));
logger.log('Audio only disabled');
dispatch(setAudioOnly(false));
} else if (!audioOnly && startAudioOnly) {
sendAnalytics(createAudioOnlyChangedEvent(true));
logger.log('Audio only enabled');
dispatch(setAudioOnly(true));
}
return result;

View File

@ -1,6 +1,33 @@
{
"IcoMoonType": "selection",
"icons": [
{
"icon": {
"paths": [
"M128 256h768v86h-768v-86zM128 554v-84h768v84h-768zM128 768v-86h768v86h-768z"
],
"attrs": [],
"isMulticolor": false,
"isMulticolor2": false,
"tags": [
"menu"
],
"defaultCode": 58834,
"grid": 24
},
"attrs": [],
"properties": {
"ligatures": "menu",
"id": 489,
"order": 926,
"prevSize": 24,
"code": 58834,
"name": "menu"
},
"setIdx": 0,
"setId": 2,
"iconIdx": 489
},
{
"icon": {
"paths": [
@ -24,9 +51,9 @@
"code": 58820,
"name": "arrow_back"
},
"setIdx": 0,
"setId": 2,
"iconIdx": 45
"setIdx": 1,
"setId": 1,
"iconIdx": 0
},
{
"icon": {
@ -51,9 +78,9 @@
"code": 58376,
"name": "navigate_before"
},
"setIdx": 0,
"setId": 2,
"iconIdx": 152
"setIdx": 1,
"setId": 1,
"iconIdx": 1
},
{
"icon": {
@ -80,7 +107,7 @@
},
"setIdx": 1,
"setId": 1,
"iconIdx": 0
"iconIdx": 2
},
{
"icon": {
@ -107,7 +134,7 @@
},
"setIdx": 1,
"setId": 1,
"iconIdx": 1
"iconIdx": 3
},
{
"icon": {
@ -134,7 +161,7 @@
},
"setIdx": 1,
"setId": 1,
"iconIdx": 2
"iconIdx": 4
},
{
"icon": {
@ -161,7 +188,7 @@
},
"setIdx": 1,
"setId": 1,
"iconIdx": 3
"iconIdx": 5
},
{
"icon": {
@ -188,7 +215,7 @@
},
"setIdx": 1,
"setId": 1,
"iconIdx": 4
"iconIdx": 6
},
{
"icon": {
@ -215,7 +242,7 @@
},
"setIdx": 1,
"setId": 1,
"iconIdx": 5
"iconIdx": 7
},
{
"icon": {
@ -242,7 +269,7 @@
},
"setIdx": 1,
"setId": 1,
"iconIdx": 6
"iconIdx": 8
},
{
"icon": {
@ -271,7 +298,7 @@
},
"setIdx": 1,
"setId": 1,
"iconIdx": 7
"iconIdx": 9
},
{
"icon": {
@ -298,7 +325,7 @@
},
"setIdx": 1,
"setId": 1,
"iconIdx": 8
"iconIdx": 10
},
{
"icon": {
@ -325,7 +352,7 @@
},
"setIdx": 1,
"setId": 1,
"iconIdx": 9
"iconIdx": 11
},
{
"icon": {
@ -354,7 +381,7 @@
},
"setIdx": 1,
"setId": 1,
"iconIdx": 10
"iconIdx": 12
},
{
"icon": {
@ -383,7 +410,7 @@
},
"setIdx": 1,
"setId": 1,
"iconIdx": 11
"iconIdx": 13
},
{
"icon": {
@ -412,7 +439,7 @@
},
"setIdx": 1,
"setId": 1,
"iconIdx": 12
"iconIdx": 14
},
{
"icon": {
@ -441,7 +468,7 @@
},
"setIdx": 1,
"setId": 1,
"iconIdx": 13
"iconIdx": 15
},
{
"icon": {
@ -470,7 +497,7 @@
},
"setIdx": 1,
"setId": 1,
"iconIdx": 14
"iconIdx": 16
},
{
"icon": {
@ -496,7 +523,7 @@
},
"setIdx": 1,
"setId": 1,
"iconIdx": 15
"iconIdx": 17
},
{
"icon": {
@ -522,7 +549,7 @@
},
"setIdx": 1,
"setId": 1,
"iconIdx": 16
"iconIdx": 18
},
{
"icon": {
@ -548,7 +575,7 @@
},
"setIdx": 1,
"setId": 1,
"iconIdx": 17
"iconIdx": 19
},
{
"icon": {
@ -574,7 +601,7 @@
},
"setIdx": 1,
"setId": 1,
"iconIdx": 18
"iconIdx": 20
},
{
"icon": {
@ -600,7 +627,7 @@
},
"setIdx": 1,
"setId": 1,
"iconIdx": 19
"iconIdx": 21
},
{
"icon": {
@ -626,7 +653,7 @@
},
"setIdx": 1,
"setId": 1,
"iconIdx": 20
"iconIdx": 22
},
{
"icon": {
@ -652,7 +679,7 @@
},
"setIdx": 1,
"setId": 1,
"iconIdx": 21
"iconIdx": 23
},
{
"icon": {
@ -678,7 +705,7 @@
},
"setIdx": 1,
"setId": 1,
"iconIdx": 22
"iconIdx": 24
},
{
"icon": {
@ -704,7 +731,7 @@
},
"setIdx": 1,
"setId": 1,
"iconIdx": 23
"iconIdx": 25
},
{
"icon": {
@ -730,7 +757,7 @@
},
"setIdx": 1,
"setId": 1,
"iconIdx": 24
"iconIdx": 26
},
{
"icon": {
@ -756,7 +783,7 @@
},
"setIdx": 1,
"setId": 1,
"iconIdx": 25
"iconIdx": 27
},
{
"icon": {
@ -782,7 +809,7 @@
},
"setIdx": 1,
"setId": 1,
"iconIdx": 26
"iconIdx": 28
},
{
"icon": {
@ -808,7 +835,7 @@
},
"setIdx": 1,
"setId": 1,
"iconIdx": 27
"iconIdx": 29
},
{
"icon": {
@ -834,7 +861,7 @@
},
"setIdx": 1,
"setId": 1,
"iconIdx": 28
"iconIdx": 30
},
{
"icon": {
@ -860,7 +887,7 @@
},
"setIdx": 1,
"setId": 1,
"iconIdx": 29
"iconIdx": 31
},
{
"icon": {
@ -886,7 +913,7 @@
},
"setIdx": 1,
"setId": 1,
"iconIdx": 30
"iconIdx": 32
},
{
"icon": {
@ -912,7 +939,7 @@
},
"setIdx": 1,
"setId": 1,
"iconIdx": 31
"iconIdx": 33
},
{
"icon": {
@ -938,7 +965,7 @@
},
"setIdx": 1,
"setId": 1,
"iconIdx": 32
"iconIdx": 34
},
{
"icon": {
@ -964,7 +991,7 @@
},
"setIdx": 1,
"setId": 1,
"iconIdx": 33
"iconIdx": 35
},
{
"icon": {
@ -990,7 +1017,7 @@
},
"setIdx": 1,
"setId": 1,
"iconIdx": 34
"iconIdx": 36
},
{
"icon": {
@ -1016,7 +1043,7 @@
},
"setIdx": 1,
"setId": 1,
"iconIdx": 35
"iconIdx": 37
},
{
"icon": {
@ -1042,7 +1069,7 @@
},
"setIdx": 1,
"setId": 1,
"iconIdx": 36
"iconIdx": 38
},
{
"icon": {
@ -1068,7 +1095,7 @@
},
"setIdx": 1,
"setId": 1,
"iconIdx": 37
"iconIdx": 39
},
{
"icon": {
@ -1094,7 +1121,7 @@
},
"setIdx": 1,
"setId": 1,
"iconIdx": 38
"iconIdx": 40
},
{
"icon": {
@ -1120,7 +1147,7 @@
},
"setIdx": 1,
"setId": 1,
"iconIdx": 39
"iconIdx": 41
},
{
"icon": {
@ -1146,7 +1173,7 @@
},
"setIdx": 1,
"setId": 1,
"iconIdx": 40
"iconIdx": 42
},
{
"icon": {
@ -1172,7 +1199,7 @@
},
"setIdx": 1,
"setId": 1,
"iconIdx": 41
"iconIdx": 43
},
{
"icon": {
@ -1198,7 +1225,7 @@
},
"setIdx": 1,
"setId": 1,
"iconIdx": 42
"iconIdx": 44
},
{
"icon": {
@ -1224,7 +1251,7 @@
},
"setIdx": 1,
"setId": 1,
"iconIdx": 43
"iconIdx": 45
},
{
"icon": {
@ -1253,7 +1280,7 @@
},
"setIdx": 1,
"setId": 1,
"iconIdx": 44
"iconIdx": 46
},
{
"icon": {
@ -1283,7 +1310,7 @@
},
"setIdx": 1,
"setId": 1,
"iconIdx": 45
"iconIdx": 47
},
{
"icon": {
@ -1313,7 +1340,7 @@
},
"setIdx": 1,
"setId": 1,
"iconIdx": 46
"iconIdx": 48
},
{
"icon": {
@ -1339,7 +1366,7 @@
},
"setIdx": 1,
"setId": 1,
"iconIdx": 47
"iconIdx": 49
},
{
"icon": {
@ -1365,7 +1392,7 @@
},
"setIdx": 1,
"setId": 1,
"iconIdx": 48
"iconIdx": 50
},
{
"icon": {
@ -1391,7 +1418,7 @@
},
"setIdx": 1,
"setId": 1,
"iconIdx": 49
"iconIdx": 51
}
],
"height": 1024,

View File

@ -19,10 +19,10 @@ export default StyleSheet.create({
*/
videoCover: {
backgroundColor: ColorPalette.black,
height: '100%',
bottom: 0,
left: 0,
position: 'absolute',
top: 0,
width: '100%'
right: 0,
top: 0
}
});

View File

@ -1,5 +1,6 @@
// @flow
import { setAudioOnly } from '../conference';
import { getLocalParticipant, participantUpdated } from '../participants';
import { getProfile } from '../profile';
import { MiddlewareRegistry, toState } from '../redux';
@ -18,11 +19,28 @@ MiddlewareRegistry.register(store => next => action => {
switch (action.type) {
case PROFILE_UPDATED:
_updateLocalParticipant(store);
_maybeUpdateStartAudioOnly(store, action);
}
return result;
});
/**
* Updates startAudioOnly flag if it's updated in the profile.
*
* @private
* @param {Store} store - The redux store.
* @param {Object} action - The redux action.
* @returns {void}
*/
function _maybeUpdateStartAudioOnly(store, action) {
const { profile } = action;
if (typeof profile.startAudioOnly === 'boolean') {
store.dispatch(setAudioOnly(profile.startAudioOnly));
}
}
/**
* Updates the local participant according to profile changes.
*

View File

@ -0,0 +1,204 @@
/* @flow */
import React, { Component } from 'react';
import {
Animated,
Dimensions,
TouchableWithoutFeedback,
View
} from 'react-native';
import styles, { SIDEBAR_WIDTH } from './styles';
/**
* The type of the React {@code Component} props of {@link SideBar}
*/
type Props = {
/**
* The local participant's avatar
*/
_avatar: string,
/**
* The children of the Component
*/
children: React$Node,
/**
* Callback to notify the containing Component that the sidebar is
* closing.
*/
onHide: Function,
/**
* Sets the menu displayed or hidden.
*/
show: boolean
}
type State = {
/**
* Indicates whether the side bar is visible or not.
*/
showSideBar: boolean,
/**
* Indicates whether the side overlay should be rendered or not.
*/
showOverlay: boolean,
/**
* The native animation object.
*/
sliderAnimation: Object
}
/**
* A generic animated side bar to be used for left side menus
*/
export default class SideBar extends Component<Props, State> {
_mounted: boolean;
/**
* Component's contructor.
*
* @inheritdoc
*/
constructor(props: Props) {
super(props);
this.state = {
showSideBar: false,
showOverlay: false,
sliderAnimation: new Animated.Value(-SIDEBAR_WIDTH)
};
this._setShow = this._setShow.bind(this);
this._getContainerStyle = this._getContainerStyle.bind(this);
this._onHideMenu = this._onHideMenu.bind(this);
this._setShow(props.show);
}
/**
* Implements the Component's componentDidMount method.
*
* @inheritdoc
*/
componentDidMount() {
this._mounted = true;
}
/**
* Implements the Component's componentWillReceiveProps method.
*
* @inheritdoc
*/
componentWillReceiveProps(newProps: Props) {
if (newProps.show !== this.props.show) {
this._setShow(newProps.show);
}
}
/**
* Implements React's {@link Component#render()}.
*
* @inheritdoc
*/
render() {
return (
<Animated.View
style = { this._getContainerStyle() } >
<View style = { styles.sideMenuContent }>
{
this.props.children
}
</View>
<TouchableWithoutFeedback
onPress = { this._onHideMenu }
style = { styles.sideMenuShadowTouchable } >
<View style = { styles.sideMenuShadow } />
</TouchableWithoutFeedback>
</Animated.View>
);
}
_getContainerStyle: () => Array<Object>
/**
* Assembles a style array for the container.
*
* @private
* @returns {Array<Object>}
*/
_getContainerStyle() {
const { sliderAnimation } = this.state;
const { height, width } = Dimensions.get('window');
return [
styles.sideMenuContainer,
{
left: sliderAnimation,
width: this.state.showOverlay
? Math.max(height, width) + SIDEBAR_WIDTH : SIDEBAR_WIDTH
}
];
}
_onHideMenu: () => void;
/**
* Hides the menu.
*
* @private
* @returns {void}
*/
_onHideMenu() {
this._setShow(false);
const { onHide } = this.props;
if (typeof onHide === 'function') {
onHide();
}
}
_setShow: (boolean) => void;
/**
* Sets the side menu visible or hidden.
*
* @private
* @param {boolean} show - The new expected visibility value.
* @returns {void}
*/
_setShow(show) {
if (this.state.showSideBar !== show) {
if (show) {
this.setState({
showOverlay: true
});
}
Animated.timing(this.state.sliderAnimation, {
toValue: show ? 0 : -SIDEBAR_WIDTH
}).start(animationState => {
if (animationState.finished && !show) {
this.setState({
showOverlay: false
});
}
});
}
if (this._mounted) {
this.setState({
showSideBar: show
});
}
}
}

View File

@ -2,6 +2,7 @@ export { default as Container } from './Container';
export { default as Link } from './Link';
export { default as LoadingIndicator } from './LoadingIndicator';
export { default as Header } from './Header';
export { default as SideBar } from './SideBar';
export * from './styles';
export { default as TintedView } from './TintedView';
export { default as Text } from './Text';

View File

@ -11,6 +11,7 @@ const HEADER_HEIGHT = 44;
const HEADER_PADDING = BoxModel.padding;
export const STATUSBAR_COLOR = ColorPalette.blueHighlight;
export const SIDEBAR_WIDTH = 250;
/**
* The styles of the React {@code Components} of the generic components
@ -35,5 +36,41 @@ export default createStyleSheet({
height: HEADER_HEIGHT,
justifyContent: 'flex-start',
padding: HEADER_PADDING
},
/**
* The topmost container of the side bar.
*/
sideMenuContainer: {
bottom: 0,
flexDirection: 'row',
left: -SIDEBAR_WIDTH,
position: 'absolute',
top: 0,
width: SIDEBAR_WIDTH
},
/**
* The container of the actual content of the side menu.
*/
sideMenuContent: {
width: SIDEBAR_WIDTH
},
/**
* The opaque area that covers the rest of the scren, when
* the side bar is open.
*/
sideMenuShadow: {
backgroundColor: 'rgba(0, 0, 0, 0.5)',
flex: 1
},
/**
* The touchable area of the rest of the screen that closes the side bar
* when tapped.
*/
sideMenuShadowTouchable: {
flex: 1
}
});

View File

@ -13,8 +13,7 @@ export const PlatformElements = createStyleSheet({
alignSelf: 'center',
color: ColorPalette.white,
fontSize: 26,
paddingRight: 22,
zIndex: 9999
paddingRight: 22
},
/**

View File

@ -192,7 +192,9 @@ class Conference extends Component<Props> {
onClick = { this._onClick }
style = { styles.conference }
touchFeedback = { false }>
<StatusBar translucent = { true } />
<StatusBar
hidden = { true }
translucent = { true } />
{/*
* The LargeVideo is the lowermost stacking layer.

View File

@ -0,0 +1,4 @@
/**
* Action type to signal the need to hide or show the side bar.
*/
export const SET_SIDEBAR_VISIBILITY = Symbol('SET_SIDEBAR_VISIBILITY');

View File

@ -0,0 +1,19 @@
// @flow
import { SET_SIDEBAR_VISIBILITY } from './actionTypes';
/**
* Redux action to hide or show the status bar.
*
* @param {boolean} visible - The new value of the visibility.
* @returns {{
* type: SET_SIDEBAR_VISIBILITY,
* sideBarVisible: boolean
* }}
*/
export function setSideBarVisibility(visible: boolean) {
return {
type: SET_SIDEBAR_VISIBILITY,
sideBarVisible: visible
};
}

View File

@ -3,9 +3,8 @@
import PropTypes from 'prop-types';
import { Component } from 'react';
import { appNavigate } from '../../app';
import { showAppSettings } from '../../app-settings';
import { createWelcomePageEvent, sendAnalytics } from '../../analytics';
import { appNavigate } from '../../app';
import { isRoomValid } from '../../base/conference';
import { generateRoomWithoutSeparator } from '../functions';
@ -14,6 +13,11 @@ import { generateRoomWithoutSeparator } from '../functions';
* {@code AbstractWelcomePage}'s React {@code Component} prop types.
*/
type Props = {
/**
* The user's profile.
*/
_profile: Object,
_room: string,
dispatch: Dispatch<*>
};
@ -72,7 +76,6 @@ export class AbstractWelcomePage extends Component<*, *> {
= this._animateRoomnameChanging.bind(this);
this._onJoin = this._onJoin.bind(this);
this._onRoomChange = this._onRoomChange.bind(this);
this._onSettingsOpen = this._onSettingsOpen.bind(this);
this._updateRoomname = this._updateRoomname.bind(this);
}
@ -205,18 +208,6 @@ export class AbstractWelcomePage extends Component<*, *> {
this.setState({ room: value });
}
_onSettingsOpen: () => void;
/**
* Sets the app settings modal visible.
*
* @protected
* @returns {void}
*/
_onSettingsOpen() {
this.props.dispatch(showAppSettings());
}
_updateRoomname: () => void;
/**
@ -254,6 +245,7 @@ export class AbstractWelcomePage extends Component<*, *> {
*/
export function _mapStateToProps(state: Object) {
return {
_profile: state['features/base/profile'].profile,
_room: state['features/base/conference'].room
};
}

View File

@ -9,7 +9,6 @@ import { NetworkActivityIndicator } from '../../mobile/network-activity';
import { isWelcomePageAppEnabled } from '../functions';
import LocalVideoTrackUnderlay from './LocalVideoTrackUnderlay';
import styles from './styles';
/**
* The React {@code Component} displayed by {@code AbstractApp} when it has no
@ -54,7 +53,7 @@ class BlankPage extends Component<*> {
*/
render() {
return (
<LocalVideoTrackUnderlay style = { styles.blankPage }>
<LocalVideoTrackUnderlay>
<NetworkActivityIndicator />
</LocalVideoTrackUnderlay>
);

View File

@ -0,0 +1,100 @@
// @flow
import React, { Component } from 'react';
import { Linking, Text, TouchableOpacity, View } from 'react-native';
import styles from './styles';
import { Icon } from '../../base/font-icons';
import { translate } from '../../base/i18n';
type Props = {
/**
* The i18n label of the item.
*/
i18Label: string,
/**
* The icon of the item.
*/
icon: string,
/**
* The function to be invoked when the item is pressed
* if the item is a button.
*/
onPress: Function,
/**
* The translate function.
*/
t: Function,
/**
* The URL of the link, if this item is a link.
*/
url: string
};
/**
* A component rendering an item in the system sidebar.
*/
class SideBarItem extends Component<Props> {
/**
* Contructor of the SideBarItem Component.
*
* @inheritdoc
*/
constructor(props: Props) {
super(props);
this._onOpenURL = this._onOpenURL.bind(this);
}
/**
* Implements React's {@link Component#render()}, renders the sidebar item.
*
* @inheritdoc
* @returns {ReactElement}
*/
render() {
const { onPress, t } = this.props;
const onPressCalculated
= typeof onPress === 'function' ? onPress : this._onOpenURL;
return (
<TouchableOpacity
onPress = { onPressCalculated }
style = { styles.sideBarItem }>
<View style = { styles.sideBarItemButtonContainer }>
<Icon
name = { this.props.icon }
style = { styles.sideBarItemIcon } />
<Text style = { styles.sideBarItemText }>
{ t(this.props.i18Label) }
</Text>
</View>
</TouchableOpacity>
);
}
_onOpenURL: () => void;
/**
* Opens the URL if one is provided.
*
* @private
* @returns {void}
*/
_onOpenURL() {
const { url } = this.props;
if (typeof url === 'string') {
Linking.openURL(url);
}
}
}
export default translate(SideBarItem);

View File

@ -1,34 +1,41 @@
import React from 'react';
import { TextInput, TouchableHighlight, View } from 'react-native';
import {
SafeAreaView,
Switch,
TextInput,
TouchableHighlight,
TouchableOpacity,
View
} from 'react-native';
import { connect } from 'react-redux';
import { AppSettings } from '../../app-settings';
import { Icon } from '../../base/font-icons';
import { translate } from '../../base/i18n';
import { Icon } from '../../base/font-icons';
import { MEDIA_TYPE } from '../../base/media';
import { Link, LoadingIndicator, Text } from '../../base/react';
import { ColorPalette } from '../../base/styles';
import { createDesiredLocalTracks } from '../../base/tracks';
import { updateProfile } from '../../base/profile';
import {
LoadingIndicator,
Header,
Text
} from '../../base/react';
import { ColorPalette, PlatformElements } from '../../base/styles';
import {
createDesiredLocalTracks,
destroyLocalTracks
} from '../../base/tracks';
import { RecentList } from '../../recent-list';
import { setSideBarVisibility } from '../actions';
import { AbstractWelcomePage, _mapStateToProps } from './AbstractWelcomePage';
import LocalVideoTrackUnderlay from './LocalVideoTrackUnderlay';
import styles, { PLACEHOLDER_TEXT_COLOR } from './styles';
/**
* The URL at which the privacy policy is available to the user.
*/
const PRIVACY_URL = 'https://jitsi.org/meet/privacy';
/**
* The URL at which the user may send feedback.
*/
const SEND_FEEDBACK_URL = 'mailto:support@jitsi.org';
/**
* The URL at which the terms (of service/use) are available to the user.
*/
const TERMS_URL = 'https://jitsi.org/meet/terms';
import styles, {
PLACEHOLDER_TEXT_COLOR,
SWITCH_THUMB_COLOR,
SWITCH_UNDER_COLOR
} from './styles';
import WelcomePageSideBar from './WelcomePageSideBar';
/**
* The native container rendering the welcome page.
@ -43,6 +50,18 @@ class WelcomePage extends AbstractWelcomePage {
*/
static propTypes = AbstractWelcomePage.propTypes;
/**
* Constructor of the Component.
*
* @inheritdoc
*/
constructor(props) {
super(props);
this._onShowSideBar = this._onShowSideBar.bind(this);
this._onStartAudioOnlyChange = this._onStartAudioOnlyChange.bind(this);
}
/**
* Implements React's {@link Component#componentWillMount()}. Invoked
* immediately before mounting occurs. Creates a local video track if none
@ -54,7 +73,13 @@ class WelcomePage extends AbstractWelcomePage {
componentWillMount() {
super.componentWillMount();
this.props.dispatch(createDesiredLocalTracks(MEDIA_TYPE.VIDEO));
const { dispatch } = this.props;
if (this.props._profile.startAudioOnly) {
dispatch(destroyLocalTracks());
} else {
dispatch(createDesiredLocalTracks(MEDIA_TYPE.VIDEO));
}
}
/**
@ -65,49 +90,85 @@ class WelcomePage extends AbstractWelcomePage {
* @returns {ReactElement}
*/
render() {
const { t } = this.props;
const { t, _profile } = this.props;
return (
<LocalVideoTrackUnderlay style = { styles.welcomePage }>
<View style = { styles.roomContainer }>
<TextInput
accessibilityLabel = { 'Input room name.' }
autoCapitalize = 'none'
autoComplete = { false }
autoCorrect = { false }
autoFocus = { false }
onChangeText = { this._onRoomChange }
onSubmitEditing = { this._onJoin }
placeholder = { t('welcomepage.roomname') }
placeholderTextColor = { PLACEHOLDER_TEXT_COLOR }
returnKeyType = { 'go' }
style = { styles.textInput }
underlineColorAndroid = 'transparent'
value = { this.state.room } />
<View style = { styles.buttonRow }>
<TouchableHighlight
accessibilityLabel = { 'Tap for Settings.' }
onPress = { this._onSettingsOpen }
style = { [ styles.button, styles.settingsButton ] }
underlayColor = { ColorPalette.white }>
<View style = { PlatformElements.page }>
<Header style = { styles.header }>
<TouchableOpacity onPress = { this._onShowSideBar } >
<Icon
name = 'settings'
style = { styles.settingsIcon } />
</TouchableHighlight>
name = 'menu'
style = { PlatformElements.headerButton } />
</TouchableOpacity>
<View style = { styles.audioVideoSwitchContainer }>
<Text style = { PlatformElements.headerText } >
{ t('welcomepage.videoEnabledLabel') }
</Text>
<Switch
onTintColor = { SWITCH_UNDER_COLOR }
onValueChange = { this._onStartAudioOnlyChange }
style = { styles.audioVideoSwitch }
thumbTintColor = { SWITCH_THUMB_COLOR }
value = { _profile.startAudioOnly } />
<Text style = { PlatformElements.headerText } >
{ t('welcomepage.audioOnlyLabel') }
</Text>
</View>
</Header>
<SafeAreaView style = { styles.roomContainer } >
<TextInput
accessibilityLabel = { 'Input room name.' }
autoCapitalize = 'none'
autoComplete = { false }
autoCorrect = { false }
autoFocus = { false }
onChangeText = { this._onRoomChange }
onSubmitEditing = { this._onJoin }
placeholder = { t('welcomepage.roomname') }
placeholderTextColor = { PLACEHOLDER_TEXT_COLOR }
returnKeyType = { 'go' }
style = { styles.textInput }
underlineColorAndroid = 'transparent'
value = { this.state.room } />
{
this._renderJoinButton()
}
</View>
<RecentList />
<RecentList />
</SafeAreaView>
<AppSettings />
</View>
<AppSettings />
{
this._renderLegalese()
}
<WelcomePageSideBar />
</LocalVideoTrackUnderlay>
);
}
/**
* Toggles the side bar.
*
* @private
* @returns {void}
*/
_onShowSideBar() {
this.props.dispatch(setSideBarVisibility(true));
}
/**
* Handles the audio-video switch changes.
*
* @private
* @param {boolean} startAudioOnly - The new startAudioOnly value.
* @returns {void}
*/
_onStartAudioOnlyChange(startAudioOnly) {
const { dispatch } = this.props;
dispatch(updateProfile({
...this.props._profile,
startAudioOnly
}));
}
/**
* Renders the join button.
*
@ -143,7 +204,7 @@ class WelcomePage extends AbstractWelcomePage {
accessibilityLabel = { 'Tap to Join.' }
disabled = { this._isJoinDisabled() }
onPress = { this._onJoin }
style = { [ styles.button, styles.joinButton ] }
style = { styles.button }
underlayColor = { ColorPalette.white }>
{
children
@ -151,37 +212,6 @@ class WelcomePage extends AbstractWelcomePage {
</TouchableHighlight>
);
}
/**
* Renders legal-related content such as Terms of service/use, Privacy
* policy, etc.
*
* @private
* @returns {ReactElement}
*/
_renderLegalese() {
const { t } = this.props;
return (
<View style = { styles.legaleseContainer }>
<Link
style = { styles.legaleseItem }
url = { TERMS_URL }>
{ t('welcomepage.terms') }
</Link>
<Link
style = { styles.legaleseItem }
url = { PRIVACY_URL }>
{ t('welcomepage.privacy') }
</Link>
<Link
style = { styles.legaleseItem }
url = { SEND_FEEDBACK_URL }>
{ t('welcomepage.sendFeedback') }
</Link>
</View>
);
}
}
export default translate(connect(_mapStateToProps)(WelcomePage));

View File

@ -0,0 +1,167 @@
// @flow
import React, { Component } from 'react';
import { SafeAreaView, ScrollView, Text } from 'react-native';
import { connect } from 'react-redux';
import SideBarItem from './SideBarItem';
import styles from './styles';
import { setSideBarVisibility } from '../actions';
import { showAppSettings } from '../../app-settings';
import {
Avatar,
getAvatarURL,
getLocalParticipant,
getParticipantDisplayName
} from '../../base/participants';
import {
Header,
SideBar
} from '../../base/react';
/**
* The URL at which the privacy policy is available to the user.
*/
const PRIVACY_URL = 'https://jitsi.org/meet/privacy';
/**
* The URL at which the user may send feedback.
*/
const SEND_FEEDBACK_URL = 'mailto:support@jitsi.org';
/**
* The URL at which the terms (of service/use) are available to the user.
*/
const TERMS_URL = 'https://jitsi.org/meet/terms';
type Props = {
/**
* Redux dispatch action
*/
dispatch: Function,
/**
* The avatar URL to be rendered.
*/
_avatar: string,
/**
* Display name of the local participant.
*/
_displayName: string,
/**
* Sets the side bar visible or hidden.
*/
_visible: boolean
};
/**
* A component rendering a welcome page sidebar.
*/
class WelcomePageSideBar extends Component<Props> {
/**
* Constructs a new SideBar instance.
*
* @inheritdoc
*/
constructor(props) {
super(props);
this._onHideSideBar = this._onHideSideBar.bind(this);
this._onOpenSettings = this._onOpenSettings.bind(this);
}
/**
* Implements React's {@link Component#render()}, renders the sidebar.
*
* @inheritdoc
* @returns {ReactElement}
*/
render() {
return (
<SideBar
onHide = { this._onHideSideBar }
show = { this.props._visible }>
<Header style = { styles.sideBarHeader }>
<Avatar
style = { styles.avatar }
uri = { this.props._avatar } />
<Text style = { styles.displayName }>
{ this.props._displayName }
</Text>
</Header>
<SafeAreaView style = { styles.sideBarBody }>
<ScrollView
style = { styles.itemContainer }>
<SideBarItem
i18Label = 'settings.title'
icon = 'settings'
onPress = { this._onOpenSettings } />
<SideBarItem
i18Label = 'welcomepage.terms'
icon = 'info'
url = { TERMS_URL } />
<SideBarItem
i18Label = 'welcomepage.privacy'
icon = 'info'
url = { PRIVACY_URL } />
<SideBarItem
i18Label = 'welcomepage.sendFeedback'
icon = 'info'
url = { SEND_FEEDBACK_URL } />
</ScrollView>
</SafeAreaView>
</SideBar>
);
}
_onHideSideBar: () => void;
/**
* Invoked when the sidebar has closed itslef (e.g. overlay pressed).
*
* @private
* @returns {void}
*/
_onHideSideBar() {
this.props.dispatch(setSideBarVisibility(false));
}
_onOpenSettings: () => void;
/**
* Opens the settings screen.
*
* @private
* @returns {void}
*/
_onOpenSettings() {
const { dispatch } = this.props;
dispatch(setSideBarVisibility(false));
dispatch(showAppSettings());
}
}
/**
* Maps (parts of) the redux state to the React {@code Component} props.
*
* @param {Object} state - The redux state.
* @protected
* @returns {Object}
*/
function _mapStateToProps(state: Object) {
const _localParticipant = getLocalParticipant(state);
return {
_avatar: getAvatarURL(_localParticipant),
_displayName: getParticipantDisplayName(state, _localParticipant.id),
_visible: state['features/welcome'].sideBarVisible
};
}
export default connect(_mapStateToProps)(WelcomePageSideBar);

View File

@ -5,7 +5,11 @@ import {
fixAndroidViewClipping
} from '../../base/styles';
const SIDEBAR_HEADER_HEIGHT = 150;
export const PLACEHOLDER_TEXT_COLOR = 'rgba(255, 255, 255, 0.3)';
export const SWITCH_THUMB_COLOR = ColorPalette.blueHighlight;
export const SWITCH_UNDER_COLOR = 'rgba(0, 0, 0, 0.4)';
/**
* The default color of text on the WelcomePage.
@ -17,76 +21,78 @@ const TEXT_COLOR = ColorPalette.white;
* {@code WelcomePage} and {@code BlankPage}.
*/
export default createStyleSheet({
/**
* The style of the top-level container of {@code BlankPage}.
* The audio-video switch itself.
*/
blankPage: {
audioVideoSwitch: {
marginHorizontal: 5
},
/**
* View that contains the audio-video switch and the labels.
*/
audioVideoSwitchContainer: {
flexDirection: 'row'
},
/**
* Style of the avatar in te side bar.
*/
avatar: {
alignSelf: 'center',
borderRadius: 50,
flex: 0,
height: 100,
width: 100
},
/**
* Join button style.
*/
button: {
backgroundColor: ColorPalette.white,
borderColor: ColorPalette.white,
borderRadius: 8,
backgroundColor: ColorPalette.blue,
borderColor: ColorPalette.blue,
borderRadius: 4,
borderWidth: 1,
height: 45,
height: 40,
justifyContent: 'center',
marginBottom: BoxModel.margin,
marginTop: BoxModel.margin
},
/**
* Layout of the button container.
*/
buttonRow: {
flexDirection: 'row'
},
/**
* Join button text style.
*/
buttonText: {
alignSelf: 'center',
color: ColorPalette.blue,
color: ColorPalette.white,
fontSize: 18
},
/**
* Style of the join button.
* The style of the display name label in the side bar.
*/
joinButton: {
flex: 1
displayName: {
color: ColorPalette.white,
fontSize: 16,
margin: BoxModel.margin,
textAlign: 'center'
},
/**
* The style of the legal-related content such as (hyper)links to Privacy
* Policy and Terms of Service displayed on the WelcomePage.
* The welcome screen header style.
*/
legaleseContainer: {
alignItems: 'center',
flex: 0,
flexDirection: 'row',
justifyContent: 'center',
// XXX Lift the legaleseContainer up above the iPhone X home indicator;
// otherwise, the former is partially underneath the latter.
marginBottom: BoxModel.margin
header: {
justifyContent: 'space-between'
},
/**
* The style of a piece of legal-related content such as a (hyper)link to
* Privacy Policy or Terms of Service displayed on the WelcomePage.
* Container for the items in the side bar.
*/
legaleseItem: {
// XXX The backgroundColor must be transparent; otherwise, the
// backgroundColor of a parent may show through. Moreover, the
// legaleseItem is not really expected to have a background of its own.
backgroundColor: 'transparent',
color: TEXT_COLOR,
fontSize: 12,
margin: BoxModel.margin
itemContainer: {
flexDirection: 'column',
paddingTop: 10
},
/**
@ -99,6 +105,14 @@ export default createStyleSheet({
flex: 1
}),
/**
* Top level screen style
*/
page: {
flex: 1,
flexDirection: 'column'
},
/**
* Container for room name input box and 'join' button.
*/
@ -106,39 +120,58 @@ export default createStyleSheet({
alignSelf: 'stretch',
flex: 1,
flexDirection: 'column',
// XXX RecentList will eventually push the room name TextInput and the
// Join button up from the center. I don't like that movement from
// center to top, especially without an animation. Just start with the
// room name TextInput and the Join button at the top.
justifyContent: 'flex-start',
margin: 3 * BoxModel.margin,
// XXX Be consistent with the marginBottom of legaleseContainer!
marginBottom: BoxModel.margin,
// XXX Push the roomContainer down bellow the iPhone X notchl otherwise,
// the former seems glued to the latter. THe amount of visual margin at
// the top is pretty much as the visual margin at the bottom (if you sum
// all bottom and top margins and account for legaleseItem) which brings
// symmetry as well.
marginTop: 5 * BoxModel.margin
margin: BoxModel.margin,
marginTop: BoxModel.margin * 2
},
/**
* Style of the settings button.
* The body of the side bar where the items are.
*/
settingsButton: {
width: 65,
marginRight: BoxModel.margin
sideBarBody: {
backgroundColor: ColorPalette.white,
flex: 1
},
/**
* Style of the settings icon on the settings button.
* The style of the side bar header.
*/
settingsIcon: {
fontSize: 24,
alignSelf: 'center'
sideBarHeader: {
flexDirection: 'column',
height: SIDEBAR_HEADER_HEIGHT,
justifyContent: 'center'
},
/**
* Style of the menu items in the side bar.
*/
sideBarItem: {
padding: 13
},
/**
* The View inside the side bar buttons (icon + text).
*/
sideBarItemButtonContainer: {
alignItems: 'center',
flexDirection: 'row',
justifyContent: 'flex-start'
},
/**
* The icon in the side bar item touchables.
*/
sideBarItemIcon: {
color: ColorPalette.blueHighlight,
fontSize: 20,
marginRight: 15
},
/**
* The label of the side bar item touchables.
*/
sideBarItemText: {
color: ColorPalette.black,
fontWeight: 'bold'
},
/**
@ -147,7 +180,7 @@ export default createStyleSheet({
textInput: {
backgroundColor: 'transparent',
borderColor: ColorPalette.white,
borderRadius: 8,
borderRadius: 4,
borderWidth: 1,
color: TEXT_COLOR,
fontSize: 23,
@ -170,6 +203,7 @@ export default createStyleSheet({
* The style of the top-level container of {@code WelcomePage}.
*/
welcomePage: {
backgroundColor: ColorPalette.blue
backgroundColor: ColorPalette.blue,
overflow: 'hidden'
}
});

View File

@ -1,3 +1,4 @@
import './reducer';
import './route';
export * from './components';

View File

@ -0,0 +1,23 @@
import { ReducerRegistry } from '../base/redux';
import { SET_SIDEBAR_VISIBILITY } from './actionTypes';
const DEFAULT_STATE = {
sideBarVisible: false
};
/**
* Reduces the Redux actions of the feature features/recording.
*/
ReducerRegistry.register('features/welcome',
(state = DEFAULT_STATE, action) => {
switch (action.type) {
case SET_SIDEBAR_VISIBILITY:
return {
...state,
sideBarVisible: action.sideBarVisible
};
default:
return state;
}
});