Преглед на файлове

Facelift Welcome screen

j8
zbettenbuk преди 7 години
родител
ревизия
04690dfc8f
променени са 27 файла, в които са добавени 989 реда и са изтрити 289 реда
  1. 3
    0
      css/_font.scss
  2. Двоични данни
      fonts/jitsi.eot
  3. 1
    0
      fonts/jitsi.svg
  4. Двоични данни
      fonts/jitsi.ttf
  5. Двоични данни
      fonts/jitsi.woff
  6. 83
    56
      fonts/selection.json
  7. 3
    0
      lang/main.json
  8. 4
    4
      react/features/analytics/AnalyticsEvents.js
  9. 12
    3
      react/features/base/conference/middleware.js
  10. 83
    56
      react/features/base/font-icons/jitsi.json
  11. 3
    3
      react/features/base/media/components/native/styles.js
  12. 18
    0
      react/features/base/profile/middleware.js
  13. 204
    0
      react/features/base/react/components/native/SideBar.js
  14. 1
    0
      react/features/base/react/components/native/index.js
  15. 37
    0
      react/features/base/react/components/native/styles.js
  16. 1
    2
      react/features/base/styles/components/styles/PlatformElements.native.js
  17. 3
    1
      react/features/conference/components/Conference.native.js
  18. 4
    0
      react/features/welcome/actionTypes.js
  19. 19
    0
      react/features/welcome/actions.js
  20. 7
    15
      react/features/welcome/components/AbstractWelcomePage.js
  21. 1
    2
      react/features/welcome/components/BlankPage.native.js
  22. 100
    0
      react/features/welcome/components/SideBarItem.js
  23. 115
    85
      react/features/welcome/components/WelcomePage.native.js
  24. 167
    0
      react/features/welcome/components/WelcomePageSideBar.native.js
  25. 96
    62
      react/features/welcome/components/styles.js
  26. 1
    0
      react/features/welcome/index.js
  27. 23
    0
      react/features/welcome/reducer.js

+ 3
- 0
css/_font.scss Целия файл

@@ -30,6 +30,9 @@
30 30
 .icon-event_note:before {
31 31
     content: "\e616";
32 32
 }
33
+.icon-menu:before {
34
+  content: "\e5d2";
35
+}
33 36
 .icon-navigate_before:before {
34 37
   content: "\e408";
35 38
 }

Двоични данни
fonts/jitsi.eot Целия файл


+ 1
- 0
fonts/jitsi.svg Целия файл

@@ -14,6 +14,7 @@
14 14
 <glyph unicode="&#xe408;" glyph-name="navigate_before" d="M658 708l-196-196 196-196-60-60-256 256 256 256z" />
15 15
 <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" />
16 16
 <glyph unicode="&#xe5c4;" glyph-name="arrow_back" d="M854 554v-84h-520l238-240-60-60-342 342 342 342 60-60-238-240h520z" />
17
+<glyph unicode="&#xe5d2;" glyph-name="menu" d="M128 768h768v-86h-768v86zM128 470v84h768v-84h-768zM128 256v86h768v-86h-768z" />
17 18
 <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" />
18 19
 <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" />
19 20
 <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" />

Двоични данни
fonts/jitsi.ttf Целия файл


Двоични данни
fonts/jitsi.woff Целия файл


+ 83
- 56
fonts/selection.json Целия файл

@@ -1,6 +1,33 @@
1 1
 {
2 2
   "IcoMoonType": "selection",
3 3
   "icons": [
4
+    {
5
+      "icon": {
6
+        "paths": [
7
+          "M128 256h768v86h-768v-86zM128 554v-84h768v84h-768zM128 768v-86h768v86h-768z"
8
+        ],
9
+        "attrs": [],
10
+        "isMulticolor": false,
11
+        "isMulticolor2": false,
12
+        "tags": [
13
+          "menu"
14
+        ],
15
+        "defaultCode": 58834,
16
+        "grid": 24
17
+      },
18
+      "attrs": [],
19
+      "properties": {
20
+        "ligatures": "menu",
21
+        "id": 489,
22
+        "order": 926,
23
+        "prevSize": 24,
24
+        "code": 58834,
25
+        "name": "menu"
26
+      },
27
+      "setIdx": 0,
28
+      "setId": 2,
29
+      "iconIdx": 489
30
+    },
4 31
     {
5 32
       "icon": {
6 33
         "paths": [
@@ -24,9 +51,9 @@
24 51
         "code": 58820,
25 52
         "name": "arrow_back"
26 53
       },
27
-      "setIdx": 0,
28
-      "setId": 2,
29
-      "iconIdx": 45
54
+      "setIdx": 1,
55
+      "setId": 1,
56
+      "iconIdx": 0
30 57
     },
31 58
     {
32 59
       "icon": {
@@ -51,9 +78,9 @@
51 78
         "code": 58376,
52 79
         "name": "navigate_before"
53 80
       },
54
-      "setIdx": 0,
55
-      "setId": 2,
56
-      "iconIdx": 152
81
+      "setIdx": 1,
82
+      "setId": 1,
83
+      "iconIdx": 1
57 84
     },
58 85
     {
59 86
       "icon": {
@@ -80,7 +107,7 @@
80 107
       },
81 108
       "setIdx": 1,
82 109
       "setId": 1,
83
-      "iconIdx": 0
110
+      "iconIdx": 2
84 111
     },
85 112
     {
86 113
       "icon": {
@@ -107,7 +134,7 @@
107 134
       },
108 135
       "setIdx": 1,
109 136
       "setId": 1,
110
-      "iconIdx": 1
137
+      "iconIdx": 3
111 138
     },
112 139
     {
113 140
       "icon": {
@@ -134,7 +161,7 @@
134 161
       },
135 162
       "setIdx": 1,
136 163
       "setId": 1,
137
-      "iconIdx": 2
164
+      "iconIdx": 4
138 165
     },
139 166
     {
140 167
       "icon": {
@@ -161,7 +188,7 @@
161 188
       },
162 189
       "setIdx": 1,
163 190
       "setId": 1,
164
-      "iconIdx": 3
191
+      "iconIdx": 5
165 192
     },
166 193
     {
167 194
       "icon": {
@@ -188,7 +215,7 @@
188 215
       },
189 216
       "setIdx": 1,
190 217
       "setId": 1,
191
-      "iconIdx": 4
218
+      "iconIdx": 6
192 219
     },
193 220
     {
194 221
       "icon": {
@@ -215,7 +242,7 @@
215 242
       },
216 243
       "setIdx": 1,
217 244
       "setId": 1,
218
-      "iconIdx": 5
245
+      "iconIdx": 7
219 246
     },
220 247
     {
221 248
       "icon": {
@@ -242,7 +269,7 @@
242 269
       },
243 270
       "setIdx": 1,
244 271
       "setId": 1,
245
-      "iconIdx": 6
272
+      "iconIdx": 8
246 273
     },
247 274
     {
248 275
       "icon": {
@@ -271,7 +298,7 @@
271 298
       },
272 299
       "setIdx": 1,
273 300
       "setId": 1,
274
-      "iconIdx": 7
301
+      "iconIdx": 9
275 302
     },
276 303
     {
277 304
       "icon": {
@@ -298,7 +325,7 @@
298 325
       },
299 326
       "setIdx": 1,
300 327
       "setId": 1,
301
-      "iconIdx": 8
328
+      "iconIdx": 10
302 329
     },
303 330
     {
304 331
       "icon": {
@@ -325,7 +352,7 @@
325 352
       },
326 353
       "setIdx": 1,
327 354
       "setId": 1,
328
-      "iconIdx": 9
355
+      "iconIdx": 11
329 356
     },
330 357
     {
331 358
       "icon": {
@@ -354,7 +381,7 @@
354 381
       },
355 382
       "setIdx": 1,
356 383
       "setId": 1,
357
-      "iconIdx": 10
384
+      "iconIdx": 12
358 385
     },
359 386
     {
360 387
       "icon": {
@@ -383,7 +410,7 @@
383 410
       },
384 411
       "setIdx": 1,
385 412
       "setId": 1,
386
-      "iconIdx": 11
413
+      "iconIdx": 13
387 414
     },
388 415
     {
389 416
       "icon": {
@@ -412,7 +439,7 @@
412 439
       },
413 440
       "setIdx": 1,
414 441
       "setId": 1,
415
-      "iconIdx": 12
442
+      "iconIdx": 14
416 443
     },
417 444
     {
418 445
       "icon": {
@@ -441,7 +468,7 @@
441 468
       },
442 469
       "setIdx": 1,
443 470
       "setId": 1,
444
-      "iconIdx": 13
471
+      "iconIdx": 15
445 472
     },
446 473
     {
447 474
       "icon": {
@@ -470,7 +497,7 @@
470 497
       },
471 498
       "setIdx": 1,
472 499
       "setId": 1,
473
-      "iconIdx": 14
500
+      "iconIdx": 16
474 501
     },
475 502
     {
476 503
       "icon": {
@@ -496,7 +523,7 @@
496 523
       },
497 524
       "setIdx": 1,
498 525
       "setId": 1,
499
-      "iconIdx": 15
526
+      "iconIdx": 17
500 527
     },
501 528
     {
502 529
       "icon": {
@@ -522,7 +549,7 @@
522 549
       },
523 550
       "setIdx": 1,
524 551
       "setId": 1,
525
-      "iconIdx": 16
552
+      "iconIdx": 18
526 553
     },
527 554
     {
528 555
       "icon": {
@@ -548,7 +575,7 @@
548 575
       },
549 576
       "setIdx": 1,
550 577
       "setId": 1,
551
-      "iconIdx": 17
578
+      "iconIdx": 19
552 579
     },
553 580
     {
554 581
       "icon": {
@@ -574,7 +601,7 @@
574 601
       },
575 602
       "setIdx": 1,
576 603
       "setId": 1,
577
-      "iconIdx": 18
604
+      "iconIdx": 20
578 605
     },
579 606
     {
580 607
       "icon": {
@@ -600,7 +627,7 @@
600 627
       },
601 628
       "setIdx": 1,
602 629
       "setId": 1,
603
-      "iconIdx": 19
630
+      "iconIdx": 21
604 631
     },
605 632
     {
606 633
       "icon": {
@@ -626,7 +653,7 @@
626 653
       },
627 654
       "setIdx": 1,
628 655
       "setId": 1,
629
-      "iconIdx": 20
656
+      "iconIdx": 22
630 657
     },
631 658
     {
632 659
       "icon": {
@@ -652,7 +679,7 @@
652 679
       },
653 680
       "setIdx": 1,
654 681
       "setId": 1,
655
-      "iconIdx": 21
682
+      "iconIdx": 23
656 683
     },
657 684
     {
658 685
       "icon": {
@@ -678,7 +705,7 @@
678 705
       },
679 706
       "setIdx": 1,
680 707
       "setId": 1,
681
-      "iconIdx": 22
708
+      "iconIdx": 24
682 709
     },
683 710
     {
684 711
       "icon": {
@@ -704,7 +731,7 @@
704 731
       },
705 732
       "setIdx": 1,
706 733
       "setId": 1,
707
-      "iconIdx": 23
734
+      "iconIdx": 25
708 735
     },
709 736
     {
710 737
       "icon": {
@@ -730,7 +757,7 @@
730 757
       },
731 758
       "setIdx": 1,
732 759
       "setId": 1,
733
-      "iconIdx": 24
760
+      "iconIdx": 26
734 761
     },
735 762
     {
736 763
       "icon": {
@@ -756,7 +783,7 @@
756 783
       },
757 784
       "setIdx": 1,
758 785
       "setId": 1,
759
-      "iconIdx": 25
786
+      "iconIdx": 27
760 787
     },
761 788
     {
762 789
       "icon": {
@@ -782,7 +809,7 @@
782 809
       },
783 810
       "setIdx": 1,
784 811
       "setId": 1,
785
-      "iconIdx": 26
812
+      "iconIdx": 28
786 813
     },
787 814
     {
788 815
       "icon": {
@@ -808,7 +835,7 @@
808 835
       },
809 836
       "setIdx": 1,
810 837
       "setId": 1,
811
-      "iconIdx": 27
838
+      "iconIdx": 29
812 839
     },
813 840
     {
814 841
       "icon": {
@@ -834,7 +861,7 @@
834 861
       },
835 862
       "setIdx": 1,
836 863
       "setId": 1,
837
-      "iconIdx": 28
864
+      "iconIdx": 30
838 865
     },
839 866
     {
840 867
       "icon": {
@@ -860,7 +887,7 @@
860 887
       },
861 888
       "setIdx": 1,
862 889
       "setId": 1,
863
-      "iconIdx": 29
890
+      "iconIdx": 31
864 891
     },
865 892
     {
866 893
       "icon": {
@@ -886,7 +913,7 @@
886 913
       },
887 914
       "setIdx": 1,
888 915
       "setId": 1,
889
-      "iconIdx": 30
916
+      "iconIdx": 32
890 917
     },
891 918
     {
892 919
       "icon": {
@@ -912,7 +939,7 @@
912 939
       },
913 940
       "setIdx": 1,
914 941
       "setId": 1,
915
-      "iconIdx": 31
942
+      "iconIdx": 33
916 943
     },
917 944
     {
918 945
       "icon": {
@@ -938,7 +965,7 @@
938 965
       },
939 966
       "setIdx": 1,
940 967
       "setId": 1,
941
-      "iconIdx": 32
968
+      "iconIdx": 34
942 969
     },
943 970
     {
944 971
       "icon": {
@@ -964,7 +991,7 @@
964 991
       },
965 992
       "setIdx": 1,
966 993
       "setId": 1,
967
-      "iconIdx": 33
994
+      "iconIdx": 35
968 995
     },
969 996
     {
970 997
       "icon": {
@@ -990,7 +1017,7 @@
990 1017
       },
991 1018
       "setIdx": 1,
992 1019
       "setId": 1,
993
-      "iconIdx": 34
1020
+      "iconIdx": 36
994 1021
     },
995 1022
     {
996 1023
       "icon": {
@@ -1016,7 +1043,7 @@
1016 1043
       },
1017 1044
       "setIdx": 1,
1018 1045
       "setId": 1,
1019
-      "iconIdx": 35
1046
+      "iconIdx": 37
1020 1047
     },
1021 1048
     {
1022 1049
       "icon": {
@@ -1042,7 +1069,7 @@
1042 1069
       },
1043 1070
       "setIdx": 1,
1044 1071
       "setId": 1,
1045
-      "iconIdx": 36
1072
+      "iconIdx": 38
1046 1073
     },
1047 1074
     {
1048 1075
       "icon": {
@@ -1068,7 +1095,7 @@
1068 1095
       },
1069 1096
       "setIdx": 1,
1070 1097
       "setId": 1,
1071
-      "iconIdx": 37
1098
+      "iconIdx": 39
1072 1099
     },
1073 1100
     {
1074 1101
       "icon": {
@@ -1094,7 +1121,7 @@
1094 1121
       },
1095 1122
       "setIdx": 1,
1096 1123
       "setId": 1,
1097
-      "iconIdx": 38
1124
+      "iconIdx": 40
1098 1125
     },
1099 1126
     {
1100 1127
       "icon": {
@@ -1120,7 +1147,7 @@
1120 1147
       },
1121 1148
       "setIdx": 1,
1122 1149
       "setId": 1,
1123
-      "iconIdx": 39
1150
+      "iconIdx": 41
1124 1151
     },
1125 1152
     {
1126 1153
       "icon": {
@@ -1146,7 +1173,7 @@
1146 1173
       },
1147 1174
       "setIdx": 1,
1148 1175
       "setId": 1,
1149
-      "iconIdx": 40
1176
+      "iconIdx": 42
1150 1177
     },
1151 1178
     {
1152 1179
       "icon": {
@@ -1172,7 +1199,7 @@
1172 1199
       },
1173 1200
       "setIdx": 1,
1174 1201
       "setId": 1,
1175
-      "iconIdx": 41
1202
+      "iconIdx": 43
1176 1203
     },
1177 1204
     {
1178 1205
       "icon": {
@@ -1198,7 +1225,7 @@
1198 1225
       },
1199 1226
       "setIdx": 1,
1200 1227
       "setId": 1,
1201
-      "iconIdx": 42
1228
+      "iconIdx": 44
1202 1229
     },
1203 1230
     {
1204 1231
       "icon": {
@@ -1224,7 +1251,7 @@
1224 1251
       },
1225 1252
       "setIdx": 1,
1226 1253
       "setId": 1,
1227
-      "iconIdx": 43
1254
+      "iconIdx": 45
1228 1255
     },
1229 1256
     {
1230 1257
       "icon": {
@@ -1253,7 +1280,7 @@
1253 1280
       },
1254 1281
       "setIdx": 1,
1255 1282
       "setId": 1,
1256
-      "iconIdx": 44
1283
+      "iconIdx": 46
1257 1284
     },
1258 1285
     {
1259 1286
       "icon": {
@@ -1283,7 +1310,7 @@
1283 1310
       },
1284 1311
       "setIdx": 1,
1285 1312
       "setId": 1,
1286
-      "iconIdx": 45
1313
+      "iconIdx": 47
1287 1314
     },
1288 1315
     {
1289 1316
       "icon": {
@@ -1313,7 +1340,7 @@
1313 1340
       },
1314 1341
       "setIdx": 1,
1315 1342
       "setId": 1,
1316
-      "iconIdx": 46
1343
+      "iconIdx": 48
1317 1344
     },
1318 1345
     {
1319 1346
       "icon": {
@@ -1339,7 +1366,7 @@
1339 1366
       },
1340 1367
       "setIdx": 1,
1341 1368
       "setId": 1,
1342
-      "iconIdx": 47
1369
+      "iconIdx": 49
1343 1370
     },
1344 1371
     {
1345 1372
       "icon": {
@@ -1365,7 +1392,7 @@
1365 1392
       },
1366 1393
       "setIdx": 1,
1367 1394
       "setId": 1,
1368
-      "iconIdx": 48
1395
+      "iconIdx": 50
1369 1396
     },
1370 1397
     {
1371 1398
       "icon": {
@@ -1391,7 +1418,7 @@
1391 1418
       },
1392 1419
       "setIdx": 1,
1393 1420
       "setId": 1,
1394
-      "iconIdx": 49
1421
+      "iconIdx": 51
1395 1422
     }
1396 1423
   ],
1397 1424
   "height": 1024,

+ 3
- 0
lang/main.json Целия файл

@@ -514,5 +514,8 @@
514 514
         "serverURL": "Server URL",
515 515
         "startWithAudioMuted": "Start with audio muted",
516 516
         "startWithVideoMuted": "Start with video muted"
517
+    },
518
+    "sideBar": {
519
+        "settings": "Settings"
517 520
     }
518 521
 }

+ 4
- 4
react/features/analytics/AnalyticsEvents.js Целия файл

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

+ 12
- 3
react/features/base/conference/middleware.js Целия файл

@@ -3,7 +3,7 @@
3 3
 import {
4 4
     ACTION_PINNED,
5 5
     ACTION_UNPINNED,
6
-    createAudioOnlyDisableEvent,
6
+    createAudioOnlyChangedEvent,
7 7
     createPinnedEvent,
8 8
     sendAnalytics
9 9
 } from '../../analytics';
@@ -125,11 +125,20 @@ function _connectionEstablished({ dispatch }, next, action) {
125 125
  */
126 126
 function _conferenceFailedOrLeft({ dispatch, getState }, next, action) {
127 127
     const result = next(action);
128
+    const state = getState();
129
+    const { audioOnly } = state['features/base/conference'];
130
+    const { startAudioOnly } = state['features/base/profile'].profile;
128 131
 
129
-    if (getState()['features/base/conference'].audioOnly) {
130
-        sendAnalytics(createAudioOnlyDisableEvent());
132
+    // FIXME: Consider implementing a standalone audio-only feature
133
+    // that handles all these state changes.
134
+    if (audioOnly && !startAudioOnly) {
135
+        sendAnalytics(createAudioOnlyChangedEvent(false));
131 136
         logger.log('Audio only disabled');
132 137
         dispatch(setAudioOnly(false));
138
+    } else if (!audioOnly && startAudioOnly) {
139
+        sendAnalytics(createAudioOnlyChangedEvent(true));
140
+        logger.log('Audio only enabled');
141
+        dispatch(setAudioOnly(true));
133 142
     }
134 143
 
135 144
     return result;

+ 83
- 56
react/features/base/font-icons/jitsi.json Целия файл

@@ -1,6 +1,33 @@
1 1
 {
2 2
   "IcoMoonType": "selection",
3 3
   "icons": [
4
+    {
5
+      "icon": {
6
+        "paths": [
7
+          "M128 256h768v86h-768v-86zM128 554v-84h768v84h-768zM128 768v-86h768v86h-768z"
8
+        ],
9
+        "attrs": [],
10
+        "isMulticolor": false,
11
+        "isMulticolor2": false,
12
+        "tags": [
13
+          "menu"
14
+        ],
15
+        "defaultCode": 58834,
16
+        "grid": 24
17
+      },
18
+      "attrs": [],
19
+      "properties": {
20
+        "ligatures": "menu",
21
+        "id": 489,
22
+        "order": 926,
23
+        "prevSize": 24,
24
+        "code": 58834,
25
+        "name": "menu"
26
+      },
27
+      "setIdx": 0,
28
+      "setId": 2,
29
+      "iconIdx": 489
30
+    },
4 31
     {
5 32
       "icon": {
6 33
         "paths": [
@@ -24,9 +51,9 @@
24 51
         "code": 58820,
25 52
         "name": "arrow_back"
26 53
       },
27
-      "setIdx": 0,
28
-      "setId": 2,
29
-      "iconIdx": 45
54
+      "setIdx": 1,
55
+      "setId": 1,
56
+      "iconIdx": 0
30 57
     },
31 58
     {
32 59
       "icon": {
@@ -51,9 +78,9 @@
51 78
         "code": 58376,
52 79
         "name": "navigate_before"
53 80
       },
54
-      "setIdx": 0,
55
-      "setId": 2,
56
-      "iconIdx": 152
81
+      "setIdx": 1,
82
+      "setId": 1,
83
+      "iconIdx": 1
57 84
     },
58 85
     {
59 86
       "icon": {
@@ -80,7 +107,7 @@
80 107
       },
81 108
       "setIdx": 1,
82 109
       "setId": 1,
83
-      "iconIdx": 0
110
+      "iconIdx": 2
84 111
     },
85 112
     {
86 113
       "icon": {
@@ -107,7 +134,7 @@
107 134
       },
108 135
       "setIdx": 1,
109 136
       "setId": 1,
110
-      "iconIdx": 1
137
+      "iconIdx": 3
111 138
     },
112 139
     {
113 140
       "icon": {
@@ -134,7 +161,7 @@
134 161
       },
135 162
       "setIdx": 1,
136 163
       "setId": 1,
137
-      "iconIdx": 2
164
+      "iconIdx": 4
138 165
     },
139 166
     {
140 167
       "icon": {
@@ -161,7 +188,7 @@
161 188
       },
162 189
       "setIdx": 1,
163 190
       "setId": 1,
164
-      "iconIdx": 3
191
+      "iconIdx": 5
165 192
     },
166 193
     {
167 194
       "icon": {
@@ -188,7 +215,7 @@
188 215
       },
189 216
       "setIdx": 1,
190 217
       "setId": 1,
191
-      "iconIdx": 4
218
+      "iconIdx": 6
192 219
     },
193 220
     {
194 221
       "icon": {
@@ -215,7 +242,7 @@
215 242
       },
216 243
       "setIdx": 1,
217 244
       "setId": 1,
218
-      "iconIdx": 5
245
+      "iconIdx": 7
219 246
     },
220 247
     {
221 248
       "icon": {
@@ -242,7 +269,7 @@
242 269
       },
243 270
       "setIdx": 1,
244 271
       "setId": 1,
245
-      "iconIdx": 6
272
+      "iconIdx": 8
246 273
     },
247 274
     {
248 275
       "icon": {
@@ -271,7 +298,7 @@
271 298
       },
272 299
       "setIdx": 1,
273 300
       "setId": 1,
274
-      "iconIdx": 7
301
+      "iconIdx": 9
275 302
     },
276 303
     {
277 304
       "icon": {
@@ -298,7 +325,7 @@
298 325
       },
299 326
       "setIdx": 1,
300 327
       "setId": 1,
301
-      "iconIdx": 8
328
+      "iconIdx": 10
302 329
     },
303 330
     {
304 331
       "icon": {
@@ -325,7 +352,7 @@
325 352
       },
326 353
       "setIdx": 1,
327 354
       "setId": 1,
328
-      "iconIdx": 9
355
+      "iconIdx": 11
329 356
     },
330 357
     {
331 358
       "icon": {
@@ -354,7 +381,7 @@
354 381
       },
355 382
       "setIdx": 1,
356 383
       "setId": 1,
357
-      "iconIdx": 10
384
+      "iconIdx": 12
358 385
     },
359 386
     {
360 387
       "icon": {
@@ -383,7 +410,7 @@
383 410
       },
384 411
       "setIdx": 1,
385 412
       "setId": 1,
386
-      "iconIdx": 11
413
+      "iconIdx": 13
387 414
     },
388 415
     {
389 416
       "icon": {
@@ -412,7 +439,7 @@
412 439
       },
413 440
       "setIdx": 1,
414 441
       "setId": 1,
415
-      "iconIdx": 12
442
+      "iconIdx": 14
416 443
     },
417 444
     {
418 445
       "icon": {
@@ -441,7 +468,7 @@
441 468
       },
442 469
       "setIdx": 1,
443 470
       "setId": 1,
444
-      "iconIdx": 13
471
+      "iconIdx": 15
445 472
     },
446 473
     {
447 474
       "icon": {
@@ -470,7 +497,7 @@
470 497
       },
471 498
       "setIdx": 1,
472 499
       "setId": 1,
473
-      "iconIdx": 14
500
+      "iconIdx": 16
474 501
     },
475 502
     {
476 503
       "icon": {
@@ -496,7 +523,7 @@
496 523
       },
497 524
       "setIdx": 1,
498 525
       "setId": 1,
499
-      "iconIdx": 15
526
+      "iconIdx": 17
500 527
     },
501 528
     {
502 529
       "icon": {
@@ -522,7 +549,7 @@
522 549
       },
523 550
       "setIdx": 1,
524 551
       "setId": 1,
525
-      "iconIdx": 16
552
+      "iconIdx": 18
526 553
     },
527 554
     {
528 555
       "icon": {
@@ -548,7 +575,7 @@
548 575
       },
549 576
       "setIdx": 1,
550 577
       "setId": 1,
551
-      "iconIdx": 17
578
+      "iconIdx": 19
552 579
     },
553 580
     {
554 581
       "icon": {
@@ -574,7 +601,7 @@
574 601
       },
575 602
       "setIdx": 1,
576 603
       "setId": 1,
577
-      "iconIdx": 18
604
+      "iconIdx": 20
578 605
     },
579 606
     {
580 607
       "icon": {
@@ -600,7 +627,7 @@
600 627
       },
601 628
       "setIdx": 1,
602 629
       "setId": 1,
603
-      "iconIdx": 19
630
+      "iconIdx": 21
604 631
     },
605 632
     {
606 633
       "icon": {
@@ -626,7 +653,7 @@
626 653
       },
627 654
       "setIdx": 1,
628 655
       "setId": 1,
629
-      "iconIdx": 20
656
+      "iconIdx": 22
630 657
     },
631 658
     {
632 659
       "icon": {
@@ -652,7 +679,7 @@
652 679
       },
653 680
       "setIdx": 1,
654 681
       "setId": 1,
655
-      "iconIdx": 21
682
+      "iconIdx": 23
656 683
     },
657 684
     {
658 685
       "icon": {
@@ -678,7 +705,7 @@
678 705
       },
679 706
       "setIdx": 1,
680 707
       "setId": 1,
681
-      "iconIdx": 22
708
+      "iconIdx": 24
682 709
     },
683 710
     {
684 711
       "icon": {
@@ -704,7 +731,7 @@
704 731
       },
705 732
       "setIdx": 1,
706 733
       "setId": 1,
707
-      "iconIdx": 23
734
+      "iconIdx": 25
708 735
     },
709 736
     {
710 737
       "icon": {
@@ -730,7 +757,7 @@
730 757
       },
731 758
       "setIdx": 1,
732 759
       "setId": 1,
733
-      "iconIdx": 24
760
+      "iconIdx": 26
734 761
     },
735 762
     {
736 763
       "icon": {
@@ -756,7 +783,7 @@
756 783
       },
757 784
       "setIdx": 1,
758 785
       "setId": 1,
759
-      "iconIdx": 25
786
+      "iconIdx": 27
760 787
     },
761 788
     {
762 789
       "icon": {
@@ -782,7 +809,7 @@
782 809
       },
783 810
       "setIdx": 1,
784 811
       "setId": 1,
785
-      "iconIdx": 26
812
+      "iconIdx": 28
786 813
     },
787 814
     {
788 815
       "icon": {
@@ -808,7 +835,7 @@
808 835
       },
809 836
       "setIdx": 1,
810 837
       "setId": 1,
811
-      "iconIdx": 27
838
+      "iconIdx": 29
812 839
     },
813 840
     {
814 841
       "icon": {
@@ -834,7 +861,7 @@
834 861
       },
835 862
       "setIdx": 1,
836 863
       "setId": 1,
837
-      "iconIdx": 28
864
+      "iconIdx": 30
838 865
     },
839 866
     {
840 867
       "icon": {
@@ -860,7 +887,7 @@
860 887
       },
861 888
       "setIdx": 1,
862 889
       "setId": 1,
863
-      "iconIdx": 29
890
+      "iconIdx": 31
864 891
     },
865 892
     {
866 893
       "icon": {
@@ -886,7 +913,7 @@
886 913
       },
887 914
       "setIdx": 1,
888 915
       "setId": 1,
889
-      "iconIdx": 30
916
+      "iconIdx": 32
890 917
     },
891 918
     {
892 919
       "icon": {
@@ -912,7 +939,7 @@
912 939
       },
913 940
       "setIdx": 1,
914 941
       "setId": 1,
915
-      "iconIdx": 31
942
+      "iconIdx": 33
916 943
     },
917 944
     {
918 945
       "icon": {
@@ -938,7 +965,7 @@
938 965
       },
939 966
       "setIdx": 1,
940 967
       "setId": 1,
941
-      "iconIdx": 32
968
+      "iconIdx": 34
942 969
     },
943 970
     {
944 971
       "icon": {
@@ -964,7 +991,7 @@
964 991
       },
965 992
       "setIdx": 1,
966 993
       "setId": 1,
967
-      "iconIdx": 33
994
+      "iconIdx": 35
968 995
     },
969 996
     {
970 997
       "icon": {
@@ -990,7 +1017,7 @@
990 1017
       },
991 1018
       "setIdx": 1,
992 1019
       "setId": 1,
993
-      "iconIdx": 34
1020
+      "iconIdx": 36
994 1021
     },
995 1022
     {
996 1023
       "icon": {
@@ -1016,7 +1043,7 @@
1016 1043
       },
1017 1044
       "setIdx": 1,
1018 1045
       "setId": 1,
1019
-      "iconIdx": 35
1046
+      "iconIdx": 37
1020 1047
     },
1021 1048
     {
1022 1049
       "icon": {
@@ -1042,7 +1069,7 @@
1042 1069
       },
1043 1070
       "setIdx": 1,
1044 1071
       "setId": 1,
1045
-      "iconIdx": 36
1072
+      "iconIdx": 38
1046 1073
     },
1047 1074
     {
1048 1075
       "icon": {
@@ -1068,7 +1095,7 @@
1068 1095
       },
1069 1096
       "setIdx": 1,
1070 1097
       "setId": 1,
1071
-      "iconIdx": 37
1098
+      "iconIdx": 39
1072 1099
     },
1073 1100
     {
1074 1101
       "icon": {
@@ -1094,7 +1121,7 @@
1094 1121
       },
1095 1122
       "setIdx": 1,
1096 1123
       "setId": 1,
1097
-      "iconIdx": 38
1124
+      "iconIdx": 40
1098 1125
     },
1099 1126
     {
1100 1127
       "icon": {
@@ -1120,7 +1147,7 @@
1120 1147
       },
1121 1148
       "setIdx": 1,
1122 1149
       "setId": 1,
1123
-      "iconIdx": 39
1150
+      "iconIdx": 41
1124 1151
     },
1125 1152
     {
1126 1153
       "icon": {
@@ -1146,7 +1173,7 @@
1146 1173
       },
1147 1174
       "setIdx": 1,
1148 1175
       "setId": 1,
1149
-      "iconIdx": 40
1176
+      "iconIdx": 42
1150 1177
     },
1151 1178
     {
1152 1179
       "icon": {
@@ -1172,7 +1199,7 @@
1172 1199
       },
1173 1200
       "setIdx": 1,
1174 1201
       "setId": 1,
1175
-      "iconIdx": 41
1202
+      "iconIdx": 43
1176 1203
     },
1177 1204
     {
1178 1205
       "icon": {
@@ -1198,7 +1225,7 @@
1198 1225
       },
1199 1226
       "setIdx": 1,
1200 1227
       "setId": 1,
1201
-      "iconIdx": 42
1228
+      "iconIdx": 44
1202 1229
     },
1203 1230
     {
1204 1231
       "icon": {
@@ -1224,7 +1251,7 @@
1224 1251
       },
1225 1252
       "setIdx": 1,
1226 1253
       "setId": 1,
1227
-      "iconIdx": 43
1254
+      "iconIdx": 45
1228 1255
     },
1229 1256
     {
1230 1257
       "icon": {
@@ -1253,7 +1280,7 @@
1253 1280
       },
1254 1281
       "setIdx": 1,
1255 1282
       "setId": 1,
1256
-      "iconIdx": 44
1283
+      "iconIdx": 46
1257 1284
     },
1258 1285
     {
1259 1286
       "icon": {
@@ -1283,7 +1310,7 @@
1283 1310
       },
1284 1311
       "setIdx": 1,
1285 1312
       "setId": 1,
1286
-      "iconIdx": 45
1313
+      "iconIdx": 47
1287 1314
     },
1288 1315
     {
1289 1316
       "icon": {
@@ -1313,7 +1340,7 @@
1313 1340
       },
1314 1341
       "setIdx": 1,
1315 1342
       "setId": 1,
1316
-      "iconIdx": 46
1343
+      "iconIdx": 48
1317 1344
     },
1318 1345
     {
1319 1346
       "icon": {
@@ -1339,7 +1366,7 @@
1339 1366
       },
1340 1367
       "setIdx": 1,
1341 1368
       "setId": 1,
1342
-      "iconIdx": 47
1369
+      "iconIdx": 49
1343 1370
     },
1344 1371
     {
1345 1372
       "icon": {
@@ -1365,7 +1392,7 @@
1365 1392
       },
1366 1393
       "setIdx": 1,
1367 1394
       "setId": 1,
1368
-      "iconIdx": 48
1395
+      "iconIdx": 50
1369 1396
     },
1370 1397
     {
1371 1398
       "icon": {
@@ -1391,7 +1418,7 @@
1391 1418
       },
1392 1419
       "setIdx": 1,
1393 1420
       "setId": 1,
1394
-      "iconIdx": 49
1421
+      "iconIdx": 51
1395 1422
     }
1396 1423
   ],
1397 1424
   "height": 1024,

+ 3
- 3
react/features/base/media/components/native/styles.js Целия файл

@@ -19,10 +19,10 @@ export default StyleSheet.create({
19 19
      */
20 20
     videoCover: {
21 21
         backgroundColor: ColorPalette.black,
22
-        height: '100%',
22
+        bottom: 0,
23 23
         left: 0,
24 24
         position: 'absolute',
25
-        top: 0,
26
-        width: '100%'
25
+        right: 0,
26
+        top: 0
27 27
     }
28 28
 });

+ 18
- 0
react/features/base/profile/middleware.js Целия файл

@@ -1,5 +1,6 @@
1 1
 // @flow
2 2
 
3
+import { setAudioOnly } from '../conference';
3 4
 import { getLocalParticipant, participantUpdated } from '../participants';
4 5
 import { getProfile } from '../profile';
5 6
 import { MiddlewareRegistry, toState } from '../redux';
@@ -18,11 +19,28 @@ MiddlewareRegistry.register(store => next => action => {
18 19
     switch (action.type) {
19 20
     case PROFILE_UPDATED:
20 21
         _updateLocalParticipant(store);
22
+        _maybeUpdateStartAudioOnly(store, action);
21 23
     }
22 24
 
23 25
     return result;
24 26
 });
25 27
 
28
+/**
29
+ * Updates startAudioOnly flag if it's updated in the profile.
30
+ *
31
+ * @private
32
+ * @param {Store} store - The redux store.
33
+ * @param {Object} action - The redux action.
34
+ * @returns {void}
35
+ */
36
+function _maybeUpdateStartAudioOnly(store, action) {
37
+    const { profile } = action;
38
+
39
+    if (typeof profile.startAudioOnly === 'boolean') {
40
+        store.dispatch(setAudioOnly(profile.startAudioOnly));
41
+    }
42
+}
43
+
26 44
 /**
27 45
  * Updates the local participant according to profile changes.
28 46
  *

+ 204
- 0
react/features/base/react/components/native/SideBar.js Целия файл

@@ -0,0 +1,204 @@
1
+/* @flow */
2
+
3
+import React, { Component } from 'react';
4
+import {
5
+    Animated,
6
+    Dimensions,
7
+    TouchableWithoutFeedback,
8
+    View
9
+} from 'react-native';
10
+
11
+import styles, { SIDEBAR_WIDTH } from './styles';
12
+
13
+
14
+/**
15
+ * The type of the React {@code Component} props of {@link SideBar}
16
+ */
17
+type Props = {
18
+
19
+    /**
20
+     * The local participant's avatar
21
+     */
22
+    _avatar: string,
23
+
24
+    /**
25
+     * The children of the Component
26
+     */
27
+    children: React$Node,
28
+
29
+    /**
30
+     * Callback to notify the containing Component that the sidebar is
31
+     * closing.
32
+     */
33
+    onHide: Function,
34
+
35
+    /**
36
+     * Sets the menu displayed or hidden.
37
+     */
38
+    show: boolean
39
+}
40
+
41
+type State = {
42
+
43
+    /**
44
+     * Indicates whether the side bar is visible or not.
45
+     */
46
+    showSideBar: boolean,
47
+
48
+    /**
49
+     * Indicates whether the side overlay should be rendered or not.
50
+     */
51
+    showOverlay: boolean,
52
+
53
+    /**
54
+     * The native animation object.
55
+     */
56
+    sliderAnimation: Object
57
+}
58
+
59
+/**
60
+ * A generic animated side bar to be used for left side menus
61
+ */
62
+export default class SideBar extends Component<Props, State> {
63
+    _mounted: boolean;
64
+
65
+    /**
66
+     * Component's contructor.
67
+     *
68
+     * @inheritdoc
69
+     */
70
+    constructor(props: Props) {
71
+        super(props);
72
+
73
+        this.state = {
74
+            showSideBar: false,
75
+            showOverlay: false,
76
+            sliderAnimation: new Animated.Value(-SIDEBAR_WIDTH)
77
+        };
78
+
79
+        this._setShow = this._setShow.bind(this);
80
+
81
+        this._getContainerStyle = this._getContainerStyle.bind(this);
82
+        this._onHideMenu = this._onHideMenu.bind(this);
83
+        this._setShow(props.show);
84
+    }
85
+
86
+    /**
87
+     * Implements the Component's componentDidMount method.
88
+     *
89
+     * @inheritdoc
90
+     */
91
+    componentDidMount() {
92
+        this._mounted = true;
93
+    }
94
+
95
+    /**
96
+     * Implements the Component's componentWillReceiveProps method.
97
+     *
98
+     * @inheritdoc
99
+     */
100
+    componentWillReceiveProps(newProps: Props) {
101
+        if (newProps.show !== this.props.show) {
102
+            this._setShow(newProps.show);
103
+        }
104
+    }
105
+
106
+    /**
107
+     * Implements React's {@link Component#render()}.
108
+     *
109
+     * @inheritdoc
110
+     */
111
+    render() {
112
+        return (
113
+            <Animated.View
114
+                style = { this._getContainerStyle() } >
115
+                <View style = { styles.sideMenuContent }>
116
+                    {
117
+                        this.props.children
118
+                    }
119
+                </View>
120
+                <TouchableWithoutFeedback
121
+                    onPress = { this._onHideMenu }
122
+                    style = { styles.sideMenuShadowTouchable } >
123
+                    <View style = { styles.sideMenuShadow } />
124
+                </TouchableWithoutFeedback>
125
+            </Animated.View>
126
+        );
127
+    }
128
+
129
+    _getContainerStyle: () => Array<Object>
130
+
131
+    /**
132
+     * Assembles a style array for the container.
133
+     *
134
+     * @private
135
+     * @returns {Array<Object>}
136
+     */
137
+    _getContainerStyle() {
138
+        const { sliderAnimation } = this.state;
139
+        const { height, width } = Dimensions.get('window');
140
+
141
+        return [
142
+            styles.sideMenuContainer,
143
+            {
144
+                left: sliderAnimation,
145
+                width: this.state.showOverlay
146
+                    ? Math.max(height, width) + SIDEBAR_WIDTH : SIDEBAR_WIDTH
147
+            }
148
+        ];
149
+    }
150
+
151
+    _onHideMenu: () => void;
152
+
153
+    /**
154
+     * Hides the menu.
155
+     *
156
+     * @private
157
+     * @returns {void}
158
+     */
159
+    _onHideMenu() {
160
+        this._setShow(false);
161
+
162
+        const { onHide } = this.props;
163
+
164
+        if (typeof onHide === 'function') {
165
+            onHide();
166
+        }
167
+    }
168
+
169
+    _setShow: (boolean) => void;
170
+
171
+    /**
172
+     * Sets the side menu visible or hidden.
173
+     *
174
+     * @private
175
+     * @param {boolean} show - The new expected visibility value.
176
+     * @returns {void}
177
+     */
178
+    _setShow(show) {
179
+        if (this.state.showSideBar !== show) {
180
+            if (show) {
181
+                this.setState({
182
+                    showOverlay: true
183
+                });
184
+            }
185
+
186
+            Animated.timing(this.state.sliderAnimation, {
187
+                toValue: show ? 0 : -SIDEBAR_WIDTH
188
+            }).start(animationState => {
189
+                if (animationState.finished && !show) {
190
+                    this.setState({
191
+                        showOverlay: false
192
+                    });
193
+                }
194
+            });
195
+        }
196
+
197
+        if (this._mounted) {
198
+            this.setState({
199
+                showSideBar: show
200
+            });
201
+        }
202
+    }
203
+
204
+}

+ 1
- 0
react/features/base/react/components/native/index.js Целия файл

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

+ 37
- 0
react/features/base/react/components/native/styles.js Целия файл

@@ -11,6 +11,7 @@ const HEADER_HEIGHT = 44;
11 11
 const HEADER_PADDING = BoxModel.padding;
12 12
 
13 13
 export const STATUSBAR_COLOR = ColorPalette.blueHighlight;
14
+export const SIDEBAR_WIDTH = 250;
14 15
 
15 16
 /**
16 17
  * The styles of the React {@code Components} of the generic components
@@ -35,5 +36,41 @@ export default createStyleSheet({
35 36
         height: HEADER_HEIGHT,
36 37
         justifyContent: 'flex-start',
37 38
         padding: HEADER_PADDING
39
+    },
40
+
41
+    /**
42
+     * The topmost container of the side bar.
43
+     */
44
+    sideMenuContainer: {
45
+        bottom: 0,
46
+        flexDirection: 'row',
47
+        left: -SIDEBAR_WIDTH,
48
+        position: 'absolute',
49
+        top: 0,
50
+        width: SIDEBAR_WIDTH
51
+    },
52
+
53
+    /**
54
+     * The container of the actual content of the side menu.
55
+     */
56
+    sideMenuContent: {
57
+        width: SIDEBAR_WIDTH
58
+    },
59
+
60
+    /**
61
+     * The opaque area that covers the rest of the scren, when
62
+     * the side bar is open.
63
+     */
64
+    sideMenuShadow: {
65
+        backgroundColor: 'rgba(0, 0, 0, 0.5)',
66
+        flex: 1
67
+    },
68
+
69
+    /**
70
+     * The touchable area of the rest of the screen that closes the side bar
71
+     * when tapped.
72
+     */
73
+    sideMenuShadowTouchable: {
74
+        flex: 1
38 75
     }
39 76
 });

+ 1
- 2
react/features/base/styles/components/styles/PlatformElements.native.js Целия файл

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

+ 3
- 1
react/features/conference/components/Conference.native.js Целия файл

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

+ 4
- 0
react/features/welcome/actionTypes.js Целия файл

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

+ 19
- 0
react/features/welcome/actions.js Целия файл

@@ -0,0 +1,19 @@
1
+// @flow
2
+
3
+import { SET_SIDEBAR_VISIBILITY } from './actionTypes';
4
+
5
+/**
6
+ * Redux action to hide or show the status bar.
7
+ *
8
+ * @param {boolean} visible - The new value of the visibility.
9
+ * @returns {{
10
+ *     type: SET_SIDEBAR_VISIBILITY,
11
+ *     sideBarVisible: boolean
12
+ * }}
13
+ */
14
+export function setSideBarVisibility(visible: boolean) {
15
+    return {
16
+        type: SET_SIDEBAR_VISIBILITY,
17
+        sideBarVisible: visible
18
+    };
19
+}

+ 7
- 15
react/features/welcome/components/AbstractWelcomePage.js Целия файл

@@ -3,9 +3,8 @@
3 3
 import PropTypes from 'prop-types';
4 4
 import { Component } from 'react';
5 5
 
6
-import { appNavigate } from '../../app';
7
-import { showAppSettings } from '../../app-settings';
8 6
 import { createWelcomePageEvent, sendAnalytics } from '../../analytics';
7
+import { appNavigate } from '../../app';
9 8
 import { isRoomValid } from '../../base/conference';
10 9
 
11 10
 import { generateRoomWithoutSeparator } from '../functions';
@@ -14,6 +13,11 @@ import { generateRoomWithoutSeparator } from '../functions';
14 13
  * {@code AbstractWelcomePage}'s React {@code Component} prop types.
15 14
  */
16 15
 type Props = {
16
+
17
+    /**
18
+     * The user's profile.
19
+     */
20
+    _profile: Object,
17 21
     _room: string,
18 22
     dispatch: Dispatch<*>
19 23
 };
@@ -72,7 +76,6 @@ export class AbstractWelcomePage extends Component<*, *> {
72 76
             = this._animateRoomnameChanging.bind(this);
73 77
         this._onJoin = this._onJoin.bind(this);
74 78
         this._onRoomChange = this._onRoomChange.bind(this);
75
-        this._onSettingsOpen = this._onSettingsOpen.bind(this);
76 79
         this._updateRoomname = this._updateRoomname.bind(this);
77 80
     }
78 81
 
@@ -205,18 +208,6 @@ export class AbstractWelcomePage extends Component<*, *> {
205 208
         this.setState({ room: value });
206 209
     }
207 210
 
208
-    _onSettingsOpen: () => void;
209
-
210
-    /**
211
-     * Sets the app settings modal visible.
212
-     *
213
-     * @protected
214
-     * @returns {void}
215
-     */
216
-    _onSettingsOpen() {
217
-        this.props.dispatch(showAppSettings());
218
-    }
219
-
220 211
     _updateRoomname: () => void;
221 212
 
222 213
     /**
@@ -254,6 +245,7 @@ export class AbstractWelcomePage extends Component<*, *> {
254 245
  */
255 246
 export function _mapStateToProps(state: Object) {
256 247
     return {
248
+        _profile: state['features/base/profile'].profile,
257 249
         _room: state['features/base/conference'].room
258 250
     };
259 251
 }

+ 1
- 2
react/features/welcome/components/BlankPage.native.js Целия файл

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

+ 100
- 0
react/features/welcome/components/SideBarItem.js Целия файл

@@ -0,0 +1,100 @@
1
+// @flow
2
+
3
+import React, { Component } from 'react';
4
+import { Linking, Text, TouchableOpacity, View } from 'react-native';
5
+
6
+import styles from './styles';
7
+
8
+import { Icon } from '../../base/font-icons';
9
+import { translate } from '../../base/i18n';
10
+
11
+type Props = {
12
+
13
+    /**
14
+     * The i18n label of the item.
15
+     */
16
+    i18Label: string,
17
+
18
+    /**
19
+     * The icon of the item.
20
+     */
21
+    icon: string,
22
+
23
+    /**
24
+     * The function to be invoked when the item is pressed
25
+     * if the item is a button.
26
+     */
27
+    onPress: Function,
28
+
29
+    /**
30
+     * The translate function.
31
+     */
32
+    t: Function,
33
+
34
+    /**
35
+     * The URL of the link, if this item is a link.
36
+     */
37
+    url: string
38
+};
39
+
40
+/**
41
+ * A component rendering an item in the system sidebar.
42
+ */
43
+class SideBarItem extends Component<Props> {
44
+
45
+    /**
46
+     * Contructor of the SideBarItem Component.
47
+     *
48
+     * @inheritdoc
49
+     */
50
+    constructor(props: Props) {
51
+        super(props);
52
+
53
+        this._onOpenURL = this._onOpenURL.bind(this);
54
+    }
55
+
56
+    /**
57
+     * Implements React's {@link Component#render()}, renders the sidebar item.
58
+     *
59
+     * @inheritdoc
60
+     * @returns {ReactElement}
61
+     */
62
+    render() {
63
+        const { onPress, t } = this.props;
64
+        const onPressCalculated
65
+            = typeof onPress === 'function' ? onPress : this._onOpenURL;
66
+
67
+        return (
68
+            <TouchableOpacity
69
+                onPress = { onPressCalculated }
70
+                style = { styles.sideBarItem }>
71
+                <View style = { styles.sideBarItemButtonContainer }>
72
+                    <Icon
73
+                        name = { this.props.icon }
74
+                        style = { styles.sideBarItemIcon } />
75
+                    <Text style = { styles.sideBarItemText }>
76
+                        { t(this.props.i18Label) }
77
+                    </Text>
78
+                </View>
79
+            </TouchableOpacity>
80
+        );
81
+    }
82
+
83
+    _onOpenURL: () => void;
84
+
85
+    /**
86
+     * Opens the URL if one is provided.
87
+     *
88
+     * @private
89
+     * @returns {void}
90
+     */
91
+    _onOpenURL() {
92
+        const { url } = this.props;
93
+
94
+        if (typeof url === 'string') {
95
+            Linking.openURL(url);
96
+        }
97
+    }
98
+}
99
+
100
+export default translate(SideBarItem);

+ 115
- 85
react/features/welcome/components/WelcomePage.native.js Целия файл

@@ -1,34 +1,41 @@
1 1
 import React from 'react';
2
-import { TextInput, TouchableHighlight, View } from 'react-native';
2
+import {
3
+    SafeAreaView,
4
+    Switch,
5
+    TextInput,
6
+    TouchableHighlight,
7
+    TouchableOpacity,
8
+    View
9
+} from 'react-native';
3 10
 import { connect } from 'react-redux';
4 11
 
5 12
 import { AppSettings } from '../../app-settings';
6
-import { Icon } from '../../base/font-icons';
7 13
 import { translate } from '../../base/i18n';
14
+import { Icon } from '../../base/font-icons';
8 15
 import { MEDIA_TYPE } from '../../base/media';
9
-import { Link, LoadingIndicator, Text } from '../../base/react';
10
-import { ColorPalette } from '../../base/styles';
11
-import { createDesiredLocalTracks } from '../../base/tracks';
16
+import { updateProfile } from '../../base/profile';
17
+import {
18
+    LoadingIndicator,
19
+    Header,
20
+    Text
21
+} from '../../base/react';
22
+import { ColorPalette, PlatformElements } from '../../base/styles';
23
+import {
24
+    createDesiredLocalTracks,
25
+    destroyLocalTracks
26
+} from '../../base/tracks';
12 27
 import { RecentList } from '../../recent-list';
13 28
 
29
+import { setSideBarVisibility } from '../actions';
30
+
14 31
 import { AbstractWelcomePage, _mapStateToProps } from './AbstractWelcomePage';
15 32
 import LocalVideoTrackUnderlay from './LocalVideoTrackUnderlay';
16
-import styles, { PLACEHOLDER_TEXT_COLOR } from './styles';
17
-
18
-/**
19
- * The URL at which the privacy policy is available to the user.
20
- */
21
-const PRIVACY_URL = 'https://jitsi.org/meet/privacy';
22
-
23
-/**
24
- * The URL at which the user may send feedback.
25
- */
26
-const SEND_FEEDBACK_URL = 'mailto:support@jitsi.org';
27
-
28
-/**
29
- * The URL at which the terms (of service/use) are available to the user.
30
- */
31
-const TERMS_URL = 'https://jitsi.org/meet/terms';
33
+import styles, {
34
+    PLACEHOLDER_TEXT_COLOR,
35
+    SWITCH_THUMB_COLOR,
36
+    SWITCH_UNDER_COLOR
37
+} from './styles';
38
+import WelcomePageSideBar from './WelcomePageSideBar';
32 39
 
33 40
 /**
34 41
  * The native container rendering the welcome page.
@@ -43,6 +50,18 @@ class WelcomePage extends AbstractWelcomePage {
43 50
      */
44 51
     static propTypes = AbstractWelcomePage.propTypes;
45 52
 
53
+    /**
54
+     * Constructor of the Component.
55
+     *
56
+     * @inheritdoc
57
+     */
58
+    constructor(props) {
59
+        super(props);
60
+
61
+        this._onShowSideBar = this._onShowSideBar.bind(this);
62
+        this._onStartAudioOnlyChange = this._onStartAudioOnlyChange.bind(this);
63
+    }
64
+
46 65
     /**
47 66
      * Implements React's {@link Component#componentWillMount()}. Invoked
48 67
      * immediately before mounting occurs. Creates a local video track if none
@@ -54,7 +73,13 @@ class WelcomePage extends AbstractWelcomePage {
54 73
     componentWillMount() {
55 74
         super.componentWillMount();
56 75
 
57
-        this.props.dispatch(createDesiredLocalTracks(MEDIA_TYPE.VIDEO));
76
+        const { dispatch } = this.props;
77
+
78
+        if (this.props._profile.startAudioOnly) {
79
+            dispatch(destroyLocalTracks());
80
+        } else {
81
+            dispatch(createDesiredLocalTracks(MEDIA_TYPE.VIDEO));
82
+        }
58 83
     }
59 84
 
60 85
     /**
@@ -65,49 +90,85 @@ class WelcomePage extends AbstractWelcomePage {
65 90
      * @returns {ReactElement}
66 91
      */
67 92
     render() {
68
-        const { t } = this.props;
93
+        const { t, _profile } = this.props;
69 94
 
70 95
         return (
71 96
             <LocalVideoTrackUnderlay style = { styles.welcomePage }>
72
-                <View style = { styles.roomContainer }>
73
-                    <TextInput
74
-                        accessibilityLabel = { 'Input room name.' }
75
-                        autoCapitalize = 'none'
76
-                        autoComplete = { false }
77
-                        autoCorrect = { false }
78
-                        autoFocus = { false }
79
-                        onChangeText = { this._onRoomChange }
80
-                        onSubmitEditing = { this._onJoin }
81
-                        placeholder = { t('welcomepage.roomname') }
82
-                        placeholderTextColor = { PLACEHOLDER_TEXT_COLOR }
83
-                        returnKeyType = { 'go' }
84
-                        style = { styles.textInput }
85
-                        underlineColorAndroid = 'transparent'
86
-                        value = { this.state.room } />
87
-                    <View style = { styles.buttonRow }>
88
-                        <TouchableHighlight
89
-                            accessibilityLabel = { 'Tap for Settings.' }
90
-                            onPress = { this._onSettingsOpen }
91
-                            style = { [ styles.button, styles.settingsButton ] }
92
-                            underlayColor = { ColorPalette.white }>
97
+                <View style = { PlatformElements.page }>
98
+                    <Header style = { styles.header }>
99
+                        <TouchableOpacity onPress = { this._onShowSideBar } >
93 100
                             <Icon
94
-                                name = 'settings'
95
-                                style = { styles.settingsIcon } />
96
-                        </TouchableHighlight>
101
+                                name = 'menu'
102
+                                style = { PlatformElements.headerButton } />
103
+                        </TouchableOpacity>
104
+                        <View style = { styles.audioVideoSwitchContainer }>
105
+                            <Text style = { PlatformElements.headerText } >
106
+                                { t('welcomepage.videoEnabledLabel') }
107
+                            </Text>
108
+                            <Switch
109
+                                onTintColor = { SWITCH_UNDER_COLOR }
110
+                                onValueChange = { this._onStartAudioOnlyChange }
111
+                                style = { styles.audioVideoSwitch }
112
+                                thumbTintColor = { SWITCH_THUMB_COLOR }
113
+                                value = { _profile.startAudioOnly } />
114
+                            <Text style = { PlatformElements.headerText } >
115
+                                { t('welcomepage.audioOnlyLabel') }
116
+                            </Text>
117
+                        </View>
118
+                    </Header>
119
+                    <SafeAreaView style = { styles.roomContainer } >
120
+                        <TextInput
121
+                            accessibilityLabel = { 'Input room name.' }
122
+                            autoCapitalize = 'none'
123
+                            autoComplete = { false }
124
+                            autoCorrect = { false }
125
+                            autoFocus = { false }
126
+                            onChangeText = { this._onRoomChange }
127
+                            onSubmitEditing = { this._onJoin }
128
+                            placeholder = { t('welcomepage.roomname') }
129
+                            placeholderTextColor = { PLACEHOLDER_TEXT_COLOR }
130
+                            returnKeyType = { 'go' }
131
+                            style = { styles.textInput }
132
+                            underlineColorAndroid = 'transparent'
133
+                            value = { this.state.room } />
97 134
                         {
98 135
                             this._renderJoinButton()
99 136
                         }
100
-                    </View>
101
-                    <RecentList />
137
+                        <RecentList />
138
+                    </SafeAreaView>
139
+                    <AppSettings />
102 140
                 </View>
103
-                <AppSettings />
104
-                {
105
-                    this._renderLegalese()
106
-                }
141
+                <WelcomePageSideBar />
107 142
             </LocalVideoTrackUnderlay>
108 143
         );
109 144
     }
110 145
 
146
+    /**
147
+     * Toggles the side bar.
148
+     *
149
+     * @private
150
+     * @returns {void}
151
+     */
152
+    _onShowSideBar() {
153
+        this.props.dispatch(setSideBarVisibility(true));
154
+    }
155
+
156
+    /**
157
+     * Handles the audio-video switch changes.
158
+     *
159
+     * @private
160
+     * @param {boolean} startAudioOnly - The new startAudioOnly value.
161
+     * @returns {void}
162
+     */
163
+    _onStartAudioOnlyChange(startAudioOnly) {
164
+        const { dispatch } = this.props;
165
+
166
+        dispatch(updateProfile({
167
+            ...this.props._profile,
168
+            startAudioOnly
169
+        }));
170
+    }
171
+
111 172
     /**
112 173
      * Renders the join button.
113 174
      *
@@ -143,7 +204,7 @@ class WelcomePage extends AbstractWelcomePage {
143 204
                 accessibilityLabel = { 'Tap to Join.' }
144 205
                 disabled = { this._isJoinDisabled() }
145 206
                 onPress = { this._onJoin }
146
-                style = { [ styles.button, styles.joinButton ] }
207
+                style = { styles.button }
147 208
                 underlayColor = { ColorPalette.white }>
148 209
                 {
149 210
                     children
@@ -151,37 +212,6 @@ class WelcomePage extends AbstractWelcomePage {
151 212
             </TouchableHighlight>
152 213
         );
153 214
     }
154
-
155
-    /**
156
-     * Renders legal-related content such as Terms of service/use, Privacy
157
-     * policy, etc.
158
-     *
159
-     * @private
160
-     * @returns {ReactElement}
161
-     */
162
-    _renderLegalese() {
163
-        const { t } = this.props;
164
-
165
-        return (
166
-            <View style = { styles.legaleseContainer }>
167
-                <Link
168
-                    style = { styles.legaleseItem }
169
-                    url = { TERMS_URL }>
170
-                    { t('welcomepage.terms') }
171
-                </Link>
172
-                <Link
173
-                    style = { styles.legaleseItem }
174
-                    url = { PRIVACY_URL }>
175
-                    { t('welcomepage.privacy') }
176
-                </Link>
177
-                <Link
178
-                    style = { styles.legaleseItem }
179
-                    url = { SEND_FEEDBACK_URL }>
180
-                    { t('welcomepage.sendFeedback') }
181
-                </Link>
182
-            </View>
183
-        );
184
-    }
185 215
 }
186 216
 
187 217
 export default translate(connect(_mapStateToProps)(WelcomePage));

+ 167
- 0
react/features/welcome/components/WelcomePageSideBar.native.js Целия файл

@@ -0,0 +1,167 @@
1
+// @flow
2
+
3
+import React, { Component } from 'react';
4
+import { SafeAreaView, ScrollView, Text } from 'react-native';
5
+import { connect } from 'react-redux';
6
+
7
+import SideBarItem from './SideBarItem';
8
+import styles from './styles';
9
+
10
+import { setSideBarVisibility } from '../actions';
11
+
12
+import { showAppSettings } from '../../app-settings';
13
+import {
14
+    Avatar,
15
+    getAvatarURL,
16
+    getLocalParticipant,
17
+    getParticipantDisplayName
18
+} from '../../base/participants';
19
+import {
20
+    Header,
21
+    SideBar
22
+} from '../../base/react';
23
+
24
+/**
25
+ * The URL at which the privacy policy is available to the user.
26
+ */
27
+const PRIVACY_URL = 'https://jitsi.org/meet/privacy';
28
+
29
+/**
30
+ * The URL at which the user may send feedback.
31
+ */
32
+const SEND_FEEDBACK_URL = 'mailto:support@jitsi.org';
33
+
34
+/**
35
+ * The URL at which the terms (of service/use) are available to the user.
36
+ */
37
+const TERMS_URL = 'https://jitsi.org/meet/terms';
38
+
39
+type Props = {
40
+
41
+    /**
42
+     * Redux dispatch action
43
+     */
44
+    dispatch: Function,
45
+
46
+    /**
47
+     * The avatar URL to be rendered.
48
+     */
49
+    _avatar: string,
50
+
51
+    /**
52
+     * Display name of the local participant.
53
+     */
54
+    _displayName: string,
55
+
56
+    /**
57
+     * Sets the side bar visible or hidden.
58
+     */
59
+    _visible: boolean
60
+};
61
+
62
+/**
63
+ * A component rendering a welcome page sidebar.
64
+ */
65
+class WelcomePageSideBar extends Component<Props> {
66
+    /**
67
+     * Constructs a new SideBar instance.
68
+     *
69
+     * @inheritdoc
70
+     */
71
+    constructor(props) {
72
+        super(props);
73
+
74
+        this._onHideSideBar = this._onHideSideBar.bind(this);
75
+        this._onOpenSettings = this._onOpenSettings.bind(this);
76
+    }
77
+
78
+    /**
79
+     * Implements React's {@link Component#render()}, renders the sidebar.
80
+     *
81
+     * @inheritdoc
82
+     * @returns {ReactElement}
83
+     */
84
+    render() {
85
+        return (
86
+            <SideBar
87
+                onHide = { this._onHideSideBar }
88
+                show = { this.props._visible }>
89
+                <Header style = { styles.sideBarHeader }>
90
+                    <Avatar
91
+                        style = { styles.avatar }
92
+                        uri = { this.props._avatar } />
93
+                    <Text style = { styles.displayName }>
94
+                        { this.props._displayName }
95
+                    </Text>
96
+                </Header>
97
+                <SafeAreaView style = { styles.sideBarBody }>
98
+                    <ScrollView
99
+                        style = { styles.itemContainer }>
100
+                        <SideBarItem
101
+                            i18Label = 'settings.title'
102
+                            icon = 'settings'
103
+                            onPress = { this._onOpenSettings } />
104
+                        <SideBarItem
105
+                            i18Label = 'welcomepage.terms'
106
+                            icon = 'info'
107
+                            url = { TERMS_URL } />
108
+                        <SideBarItem
109
+                            i18Label = 'welcomepage.privacy'
110
+                            icon = 'info'
111
+                            url = { PRIVACY_URL } />
112
+                        <SideBarItem
113
+                            i18Label = 'welcomepage.sendFeedback'
114
+                            icon = 'info'
115
+                            url = { SEND_FEEDBACK_URL } />
116
+                    </ScrollView>
117
+                </SafeAreaView>
118
+            </SideBar>
119
+        );
120
+    }
121
+
122
+    _onHideSideBar: () => void;
123
+
124
+    /**
125
+     * Invoked when the sidebar has closed itslef (e.g. overlay pressed).
126
+     *
127
+     * @private
128
+     * @returns {void}
129
+     */
130
+    _onHideSideBar() {
131
+        this.props.dispatch(setSideBarVisibility(false));
132
+    }
133
+
134
+    _onOpenSettings: () => void;
135
+
136
+    /**
137
+     * Opens the settings screen.
138
+     *
139
+     * @private
140
+     * @returns {void}
141
+     */
142
+    _onOpenSettings() {
143
+        const { dispatch } = this.props;
144
+
145
+        dispatch(setSideBarVisibility(false));
146
+        dispatch(showAppSettings());
147
+    }
148
+}
149
+
150
+/**
151
+ * Maps (parts of) the redux state to the React {@code Component} props.
152
+ *
153
+ * @param {Object} state - The redux state.
154
+ * @protected
155
+ * @returns {Object}
156
+ */
157
+function _mapStateToProps(state: Object) {
158
+    const _localParticipant = getLocalParticipant(state);
159
+
160
+    return {
161
+        _avatar: getAvatarURL(_localParticipant),
162
+        _displayName: getParticipantDisplayName(state, _localParticipant.id),
163
+        _visible: state['features/welcome'].sideBarVisible
164
+    };
165
+}
166
+
167
+export default connect(_mapStateToProps)(WelcomePageSideBar);

+ 96
- 62
react/features/welcome/components/styles.js Целия файл

@@ -5,7 +5,11 @@ import {
5 5
     fixAndroidViewClipping
6 6
 } from '../../base/styles';
7 7
 
8
+const SIDEBAR_HEADER_HEIGHT = 150;
9
+
8 10
 export const PLACEHOLDER_TEXT_COLOR = 'rgba(255, 255, 255, 0.3)';
11
+export const SWITCH_THUMB_COLOR = ColorPalette.blueHighlight;
12
+export const SWITCH_UNDER_COLOR = 'rgba(0, 0, 0, 0.4)';
9 13
 
10 14
 /**
11 15
  * The default color of text on the WelcomePage.
@@ -17,76 +21,78 @@ const TEXT_COLOR = ColorPalette.white;
17 21
  * {@code WelcomePage} and {@code BlankPage}.
18 22
  */
19 23
 export default createStyleSheet({
24
+
25
+    /**
26
+     * The audio-video switch itself.
27
+     */
28
+    audioVideoSwitch: {
29
+        marginHorizontal: 5
30
+    },
31
+
32
+    /**
33
+     * View that contains the audio-video switch and the labels.
34
+     */
35
+    audioVideoSwitchContainer: {
36
+        flexDirection: 'row'
37
+    },
38
+
20 39
     /**
21
-     * The style of the top-level container of {@code BlankPage}.
40
+     * Style of the avatar in te side bar.
22 41
      */
23
-    blankPage: {
42
+    avatar: {
43
+        alignSelf: 'center',
44
+        borderRadius: 50,
45
+        flex: 0,
46
+        height: 100,
47
+        width: 100
24 48
     },
25 49
 
26 50
     /**
27 51
      * Join button style.
28 52
      */
29 53
     button: {
30
-        backgroundColor: ColorPalette.white,
31
-        borderColor: ColorPalette.white,
32
-        borderRadius: 8,
54
+        backgroundColor: ColorPalette.blue,
55
+        borderColor: ColorPalette.blue,
56
+        borderRadius: 4,
33 57
         borderWidth: 1,
34
-        height: 45,
58
+        height: 40,
35 59
         justifyContent: 'center',
36 60
         marginBottom: BoxModel.margin,
37 61
         marginTop: BoxModel.margin
38 62
     },
39 63
 
40
-    /**
41
-     * Layout of the button container.
42
-     */
43
-    buttonRow: {
44
-        flexDirection: 'row'
45
-    },
46
-
47 64
     /**
48 65
      * Join button text style.
49 66
      */
50 67
     buttonText: {
51 68
         alignSelf: 'center',
52
-        color: ColorPalette.blue,
69
+        color: ColorPalette.white,
53 70
         fontSize: 18
54 71
     },
55 72
 
56 73
     /**
57
-     * Style of the join button.
74
+     * The style of the display name label in the side bar.
58 75
      */
59
-    joinButton: {
60
-        flex: 1
76
+    displayName: {
77
+        color: ColorPalette.white,
78
+        fontSize: 16,
79
+        margin: BoxModel.margin,
80
+        textAlign: 'center'
61 81
     },
62 82
 
63 83
     /**
64
-     * The style of the legal-related content such as (hyper)links to Privacy
65
-     * Policy and Terms of Service displayed on the WelcomePage.
84
+     * The welcome screen header style.
66 85
      */
67
-    legaleseContainer: {
68
-        alignItems: 'center',
69
-        flex: 0,
70
-        flexDirection: 'row',
71
-        justifyContent: 'center',
72
-
73
-        // XXX Lift the legaleseContainer up above the iPhone X home indicator;
74
-        // otherwise, the former is partially underneath the latter.
75
-        marginBottom: BoxModel.margin
86
+    header: {
87
+        justifyContent: 'space-between'
76 88
     },
77 89
 
78 90
     /**
79
-     * The style of a piece of legal-related content such as a (hyper)link to
80
-     * Privacy Policy or Terms of Service displayed on the WelcomePage.
91
+     * Container for the items in the side bar.
81 92
      */
82
-    legaleseItem: {
83
-        // XXX The backgroundColor must be transparent; otherwise, the
84
-        // backgroundColor of a parent may show through. Moreover, the
85
-        // legaleseItem is not really expected to have a background of its own.
86
-        backgroundColor: 'transparent',
87
-        color: TEXT_COLOR,
88
-        fontSize: 12,
89
-        margin: BoxModel.margin
93
+    itemContainer: {
94
+        flexDirection: 'column',
95
+        paddingTop: 10
90 96
     },
91 97
 
92 98
     /**
@@ -99,6 +105,14 @@ export default createStyleSheet({
99 105
         flex: 1
100 106
     }),
101 107
 
108
+    /**
109
+     * Top level screen style
110
+     */
111
+    page: {
112
+        flex: 1,
113
+        flexDirection: 'column'
114
+    },
115
+
102 116
     /**
103 117
      * Container for room name input box and 'join' button.
104 118
      */
@@ -106,39 +120,58 @@ export default createStyleSheet({
106 120
         alignSelf: 'stretch',
107 121
         flex: 1,
108 122
         flexDirection: 'column',
123
+        margin: BoxModel.margin,
124
+        marginTop: BoxModel.margin * 2
125
+    },
109 126
 
110
-        // XXX RecentList will eventually push the room name TextInput and the
111
-        // Join button up from the center. I don't like that movement from
112
-        // center to top, especially without an animation. Just start with the
113
-        // room name TextInput and the Join button at the top.
114
-        justifyContent: 'flex-start',
115
-        margin: 3 * BoxModel.margin,
127
+    /**
128
+     * The body of the side bar where the items are.
129
+     */
130
+    sideBarBody: {
131
+        backgroundColor: ColorPalette.white,
132
+        flex: 1
133
+    },
116 134
 
117
-        // XXX Be consistent with the marginBottom of legaleseContainer!
118
-        marginBottom: BoxModel.margin,
135
+    /**
136
+     * The style of the side bar header.
137
+     */
138
+    sideBarHeader: {
139
+        flexDirection: 'column',
140
+        height: SIDEBAR_HEADER_HEIGHT,
141
+        justifyContent: 'center'
142
+    },
119 143
 
120
-        // XXX Push the roomContainer down bellow the iPhone X notchl otherwise,
121
-        // the former seems glued to the latter. THe amount of visual margin at
122
-        // the top is pretty much as the visual margin at the bottom (if you sum
123
-        // all bottom and top margins and account for legaleseItem) which brings
124
-        // symmetry as well.
125
-        marginTop: 5 * BoxModel.margin
144
+    /**
145
+     * Style of the menu items in the side bar.
146
+     */
147
+    sideBarItem: {
148
+        padding: 13
149
+    },
150
+
151
+    /**
152
+     * The View inside the side bar buttons (icon + text).
153
+     */
154
+    sideBarItemButtonContainer: {
155
+        alignItems: 'center',
156
+        flexDirection: 'row',
157
+        justifyContent: 'flex-start'
126 158
     },
127 159
 
128 160
     /**
129
-     * Style of the settings button.
161
+     * The icon in the side bar item touchables.
130 162
      */
131
-    settingsButton: {
132
-        width: 65,
133
-        marginRight: BoxModel.margin
163
+    sideBarItemIcon: {
164
+        color: ColorPalette.blueHighlight,
165
+        fontSize: 20,
166
+        marginRight: 15
134 167
     },
135 168
 
136 169
     /**
137
-     * Style of the settings icon on the settings button.
170
+     * The label of the side bar item touchables.
138 171
      */
139
-    settingsIcon: {
140
-        fontSize: 24,
141
-        alignSelf: 'center'
172
+    sideBarItemText: {
173
+        color: ColorPalette.black,
174
+        fontWeight: 'bold'
142 175
     },
143 176
 
144 177
     /**
@@ -147,7 +180,7 @@ export default createStyleSheet({
147 180
     textInput: {
148 181
         backgroundColor: 'transparent',
149 182
         borderColor: ColorPalette.white,
150
-        borderRadius: 8,
183
+        borderRadius: 4,
151 184
         borderWidth: 1,
152 185
         color: TEXT_COLOR,
153 186
         fontSize: 23,
@@ -170,6 +203,7 @@ export default createStyleSheet({
170 203
      * The style of the top-level container of {@code WelcomePage}.
171 204
      */
172 205
     welcomePage: {
173
-        backgroundColor: ColorPalette.blue
206
+        backgroundColor: ColorPalette.blue,
207
+        overflow: 'hidden'
174 208
     }
175 209
 });

+ 1
- 0
react/features/welcome/index.js Целия файл

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

+ 23
- 0
react/features/welcome/reducer.js Целия файл

@@ -0,0 +1,23 @@
1
+import { ReducerRegistry } from '../base/redux';
2
+import { SET_SIDEBAR_VISIBILITY } from './actionTypes';
3
+
4
+const DEFAULT_STATE = {
5
+    sideBarVisible: false
6
+};
7
+
8
+/**
9
+ * Reduces the Redux actions of the feature features/recording.
10
+ */
11
+ReducerRegistry.register('features/welcome',
12
+    (state = DEFAULT_STATE, action) => {
13
+        switch (action.type) {
14
+        case SET_SIDEBAR_VISIBILITY:
15
+            return {
16
+                ...state,
17
+                sideBarVisible: action.sideBarVisible
18
+            };
19
+
20
+        default:
21
+            return state;
22
+        }
23
+    });

Loading…
Отказ
Запис