mirror of
https://gitcode.com/GitHub_Trending/ji/jitsi-meet.git
synced 2026-01-06 14:52:28 +00:00
Compare commits
2381 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cb514b90e9 | ||
|
|
e0b73fdd1c | ||
|
|
c2ca345dec | ||
|
|
1834fc63d2 | ||
|
|
5561a9c031 | ||
|
|
8f97da3265 | ||
|
|
1ef3e4b7dc | ||
|
|
86fcfcc535 | ||
|
|
dfebd692f3 | ||
|
|
d280f90676 | ||
|
|
1996ac4e02 | ||
|
|
4bf19d73fd | ||
|
|
b3cef401f2 | ||
|
|
eb1a44f5ba | ||
|
|
29d1d448f2 | ||
|
|
cfe4564ab3 | ||
|
|
802d347574 | ||
|
|
a3441030a3 | ||
|
|
3b5ee2d4c6 | ||
|
|
8d11b3024e | ||
|
|
2e2129fa44 | ||
|
|
9834e8ac7b | ||
|
|
e1222e947b | ||
|
|
341e7e01aa | ||
|
|
964061fa5c | ||
|
|
b8a629ead6 | ||
|
|
b55faab33e | ||
|
|
3fdffa7497 | ||
|
|
d521deecc4 | ||
|
|
d03a815572 | ||
|
|
41c6759a23 | ||
|
|
f62288ae17 | ||
|
|
98aa0b6ad9 | ||
|
|
01031ff0a7 | ||
|
|
eae3bead87 | ||
|
|
483e2ee202 | ||
|
|
e08d240a89 | ||
|
|
f9f194d6fe | ||
|
|
cfd6209a20 | ||
|
|
03d337612b | ||
|
|
46b75e5178 | ||
|
|
266d8f72c5 | ||
|
|
9ae26a087e | ||
|
|
66da77bcf5 | ||
|
|
70de9a683f | ||
|
|
4e0761a46a | ||
|
|
f8b607e92e | ||
|
|
da3e59571e | ||
|
|
c196f8007b | ||
|
|
c5436428e5 | ||
|
|
628dc99bfe | ||
|
|
a12984ed6f | ||
|
|
1ea62215f6 | ||
|
|
6fb5c4bc29 | ||
|
|
b5212bb6cd | ||
|
|
ec58aa9959 | ||
|
|
35dab19b30 | ||
|
|
720ae18194 | ||
|
|
e553e61f04 | ||
|
|
a0a4fbf566 | ||
|
|
ca13a9b914 | ||
|
|
35da39becf | ||
|
|
21d419e517 | ||
|
|
6a1eff917c | ||
|
|
6d62e91ff1 | ||
|
|
241dc3b147 | ||
|
|
141acea194 | ||
|
|
80329e8ffe | ||
|
|
9621ba03f3 | ||
|
|
04a1da2cea | ||
|
|
bd24135d76 | ||
|
|
0c08f96755 | ||
|
|
984085ac54 | ||
|
|
9c47a7e972 | ||
|
|
088fe87e31 | ||
|
|
f3783efc48 | ||
|
|
1e84f993b4 | ||
|
|
03b4a32dd7 | ||
|
|
70fc727b92 | ||
|
|
d0476991a6 | ||
|
|
2496b3ec02 | ||
|
|
bf915fe886 | ||
|
|
46ccefdfe9 | ||
|
|
f86f21beb2 | ||
|
|
fe8f383a41 | ||
|
|
72c9933e73 | ||
|
|
4b2795502c | ||
|
|
082fe711f2 | ||
|
|
ba49c7955a | ||
|
|
354fa36f44 | ||
|
|
2a75d67be9 | ||
|
|
5e6cea63fb | ||
|
|
0d3927fed1 | ||
|
|
9049f52402 | ||
|
|
c2ae7999ef | ||
|
|
5a50932174 | ||
|
|
53e1160a1c | ||
|
|
15ab7a292c | ||
|
|
fce0e4c22c | ||
|
|
4dc78ce458 | ||
|
|
67edaac1c9 | ||
|
|
e830b80b6b | ||
|
|
284e4e543e | ||
|
|
1d8ee9d32f | ||
|
|
6982506acc | ||
|
|
d818436645 | ||
|
|
31729d7949 | ||
|
|
ed53f54628 | ||
|
|
9833965a27 | ||
|
|
8cdd73b987 | ||
|
|
a7ee632f43 | ||
|
|
b304ad5808 | ||
|
|
86e4876df2 | ||
|
|
034518a6a0 | ||
|
|
bf523711df | ||
|
|
bfeaf329e1 | ||
|
|
0e234bfd82 | ||
|
|
8fc095039e | ||
|
|
eca04de348 | ||
|
|
18d1572dab | ||
|
|
45a1ae26ca | ||
|
|
6545a7a1bb | ||
|
|
ec9c05e401 | ||
|
|
bf03e73876 | ||
|
|
6682543691 | ||
|
|
8d81f1d69f | ||
|
|
8436f23e05 | ||
|
|
2ae354530e | ||
|
|
4938d1b6de | ||
|
|
cd3dad956b | ||
|
|
328da08b3a | ||
|
|
a94e38e890 | ||
|
|
b9f2ab7692 | ||
|
|
05f8c69fe6 | ||
|
|
7063f144ef | ||
|
|
af92ba5e86 | ||
|
|
5e4f921e1b | ||
|
|
126f8e6d88 | ||
|
|
7f8e8177d0 | ||
|
|
e33030582f | ||
|
|
d669a6c73c | ||
|
|
8eebfcad72 | ||
|
|
ef1b8fdb77 | ||
|
|
c0f648b1ab | ||
|
|
531b638a8a | ||
|
|
4e3d033ff2 | ||
|
|
77e8c75795 | ||
|
|
9559df1b13 | ||
|
|
f93c1b5748 | ||
|
|
f616b0b71b | ||
|
|
70422f4a47 | ||
|
|
735a596afe | ||
|
|
e04129bf4d | ||
|
|
85f0ad2791 | ||
|
|
c54879d605 | ||
|
|
fdee6dc360 | ||
|
|
5f55b3198c | ||
|
|
5b6d7a3040 | ||
|
|
1ca485f1a8 | ||
|
|
6e37fe175d | ||
|
|
24db52ef0f | ||
|
|
0b8c12de0e | ||
|
|
cb5b93fb6e | ||
|
|
7114614697 | ||
|
|
45b8693a3e | ||
|
|
360283aa34 | ||
|
|
fb556edb9d | ||
|
|
28e5230472 | ||
|
|
73ea42f49f | ||
|
|
255ddbd344 | ||
|
|
df1b2c41cf | ||
|
|
8752cc40e2 | ||
|
|
e42d209401 | ||
|
|
cd31aad2fd | ||
|
|
81d7a3147b | ||
|
|
ac909dce4c | ||
|
|
6a040d2e67 | ||
|
|
3ab9765e6b | ||
|
|
1025ce75bd | ||
|
|
2e0faa8715 | ||
|
|
0f6541c07b | ||
|
|
7466a03a7d | ||
|
|
e781f4f02d | ||
|
|
08d9f28cc4 | ||
|
|
a5b94e5534 | ||
|
|
7cea557416 | ||
|
|
52ee8fd473 | ||
|
|
670d575bcb | ||
|
|
16fbf90a00 | ||
|
|
ec22329408 | ||
|
|
26f0f7f89c | ||
|
|
9bca0e3b3d | ||
|
|
3102ea6818 | ||
|
|
ec7c10c99b | ||
|
|
28b4595561 | ||
|
|
e3361e2f3b | ||
|
|
c3a4a38414 | ||
|
|
38e2443ab7 | ||
|
|
2356238887 | ||
|
|
c42f1704ff | ||
|
|
5358f022ff | ||
|
|
5ef914602f | ||
|
|
2818520c8f | ||
|
|
131e5af01e | ||
|
|
90e7804834 | ||
|
|
c0de88ba8c | ||
|
|
99ce46cfa8 | ||
|
|
e0e3e873b8 | ||
|
|
e4f959e400 | ||
|
|
27deb97c5c | ||
|
|
20379da236 | ||
|
|
378a8d014e | ||
|
|
31dd3da2b6 | ||
|
|
ba61876b13 | ||
|
|
f54e87d975 | ||
|
|
c1fbbc4571 | ||
|
|
3d397a28e6 | ||
|
|
6003b560ae | ||
|
|
207393d98e | ||
|
|
571958cf26 | ||
|
|
4a39a630a4 | ||
|
|
3e3577766d | ||
|
|
5e4d3de8fd | ||
|
|
1b7973a28e | ||
|
|
830ec3d097 | ||
|
|
995a25ee15 | ||
|
|
725d39ddcd | ||
|
|
cd910e3074 | ||
|
|
2e3a5b1c35 | ||
|
|
1b0bffe251 | ||
|
|
1782030936 | ||
|
|
382b328262 | ||
|
|
b81dc4e59b | ||
|
|
53f675fbe0 | ||
|
|
f18b42b286 | ||
|
|
91e75bf7b9 | ||
|
|
fe59084979 | ||
|
|
025f7204d5 | ||
|
|
da9e3fb63e | ||
|
|
d7bccd0c93 | ||
|
|
f1f46e0af5 | ||
|
|
19d9b3f023 | ||
|
|
d8cd3e75b4 | ||
|
|
c1fb1a7def | ||
|
|
ca80839094 | ||
|
|
194b3ac9d3 | ||
|
|
cfe7e30550 | ||
|
|
ff442853a2 | ||
|
|
85a168d51b | ||
|
|
d600504d85 | ||
|
|
bd4766648a | ||
|
|
d200abb8db | ||
|
|
002e48b886 | ||
|
|
1c1604bee7 | ||
|
|
99fd325a51 | ||
|
|
4f6ec920cd | ||
|
|
0d33844d51 | ||
|
|
0836f2cefd | ||
|
|
97832e0eef | ||
|
|
00e058d392 | ||
|
|
504646fff0 | ||
|
|
122ebe48c7 | ||
|
|
fe8ac0fff9 | ||
|
|
cd66a7fcb7 | ||
|
|
74ddae4a6a | ||
|
|
1ad8436cb5 | ||
|
|
6b2a93909b | ||
|
|
c259551d9a | ||
|
|
377be4272a | ||
|
|
737419dbe8 | ||
|
|
1748049322 | ||
|
|
caea02a322 | ||
|
|
d778b716be | ||
|
|
4dcbe5c6a0 | ||
|
|
c04ef05058 | ||
|
|
82117a0aef | ||
|
|
9c6afc2062 | ||
|
|
dcc6ce025f | ||
|
|
40c9f583fa | ||
|
|
3e84d8b3b6 | ||
|
|
0983ef48b5 | ||
|
|
da1c760abf | ||
|
|
e818fa1e9e | ||
|
|
d2e8b13add | ||
|
|
68f4a4ae9f | ||
|
|
bfa5f4c953 | ||
|
|
03b043ca2b | ||
|
|
d00ee3d7b6 | ||
|
|
aaf5dd75fa | ||
|
|
f1c9e57b43 | ||
|
|
e542af28a2 | ||
|
|
9778aabe98 | ||
|
|
1fae0ee780 | ||
|
|
1fb31b6773 | ||
|
|
9871580e6d | ||
|
|
3546cf4915 | ||
|
|
a2c2d3bee1 | ||
|
|
e5e7b59f43 | ||
|
|
980d48e00b | ||
|
|
51934dac1b | ||
|
|
f0ab835b46 | ||
|
|
6c488cc613 | ||
|
|
d3c408ae2e | ||
|
|
e8223bbb4a | ||
|
|
fa86d2ab9e | ||
|
|
122a7f6346 | ||
|
|
24eb37ae1e | ||
|
|
2094b15432 | ||
|
|
157eadc44a | ||
|
|
2525bb2805 | ||
|
|
e08171f602 | ||
|
|
db88c555dc | ||
|
|
96e0c56bde | ||
|
|
b0ffe2e63f | ||
|
|
06234066b6 | ||
|
|
1897c395ec | ||
|
|
6ac23c8086 | ||
|
|
a5f61714bd | ||
|
|
00d3d3c09a | ||
|
|
6493b09565 | ||
|
|
955542f4a5 | ||
|
|
68d40b4fa4 | ||
|
|
c369330054 | ||
|
|
b6efdb533d | ||
|
|
22e9dc9893 | ||
|
|
8047fdf5a2 | ||
|
|
2c873e8c7f | ||
|
|
284b5f94b5 | ||
|
|
6bcb9be364 | ||
|
|
3c084c0082 | ||
|
|
a08ea37005 | ||
|
|
2132cd6736 | ||
|
|
44bbd26c96 | ||
|
|
1d90826098 | ||
|
|
4efbbe14b1 | ||
|
|
0b5431b795 | ||
|
|
e7fc4739c4 | ||
|
|
f40faecfbe | ||
|
|
f72932d125 | ||
|
|
ffc12ccc0e | ||
|
|
03da40b56a | ||
|
|
055df1c12e | ||
|
|
d87b8823e9 | ||
|
|
8225600b61 | ||
|
|
b62b296080 | ||
|
|
a690b9d5e1 | ||
|
|
364ab5431c | ||
|
|
4a9a8eec9a | ||
|
|
308360fbe0 | ||
|
|
c97daff506 | ||
|
|
7361151203 | ||
|
|
8093043d39 | ||
|
|
3fbb022ffb | ||
|
|
e6840981ca | ||
|
|
64bb5563bc | ||
|
|
0cffbdb967 | ||
|
|
72691eb2dc | ||
|
|
0bf9a78e4c | ||
|
|
0c446026d6 | ||
|
|
326ce4217f | ||
|
|
5db605b0cf | ||
|
|
117d3bb110 | ||
|
|
3926d705ad | ||
|
|
5b5470ec66 | ||
|
|
7f041170f7 | ||
|
|
e54744e5ef | ||
|
|
96bfcafc97 | ||
|
|
9a295723cf | ||
|
|
58d06fe7e6 | ||
|
|
cc79b073f0 | ||
|
|
599d84a889 | ||
|
|
2b1e8cdeff | ||
|
|
ea0c333f4b | ||
|
|
4eef52b84e | ||
|
|
3e1dc298c8 | ||
|
|
244de8096f | ||
|
|
7d99c54ec8 | ||
|
|
37328b3995 | ||
|
|
b8d3e82ae7 | ||
|
|
07a0e3d8ff | ||
|
|
70122789e7 | ||
|
|
3736d6ca78 | ||
|
|
07158e8071 | ||
|
|
cc6fcfd982 | ||
|
|
b84e910086 | ||
|
|
10766e6958 | ||
|
|
d752e8b864 | ||
|
|
d335669afe | ||
|
|
7ebd2b2cd4 | ||
|
|
622d4ba89c | ||
|
|
3de6f1cd7f | ||
|
|
7b1639569e | ||
|
|
62613ff02e | ||
|
|
4eacbd9f61 | ||
|
|
884509faee | ||
|
|
2e2b1d47c0 | ||
|
|
fac6c30b1c | ||
|
|
1ad614e812 | ||
|
|
21957c8bf2 | ||
|
|
63377a2f76 | ||
|
|
de2eee2e61 | ||
|
|
badbedf0f5 | ||
|
|
2281b1acd2 | ||
|
|
6655ae5a84 | ||
|
|
c4c100e26a | ||
|
|
a7025c41f6 | ||
|
|
d84ab20a47 | ||
|
|
751f27644f | ||
|
|
4ccd5c6072 | ||
|
|
bae609b296 | ||
|
|
e78c70e53d | ||
|
|
cee523fbf1 | ||
|
|
0481e4cf00 | ||
|
|
fcda36a8e0 | ||
|
|
f5d443d194 | ||
|
|
47b6166d79 | ||
|
|
6fc1a3f45d | ||
|
|
ab7d1553db | ||
|
|
1498245b9e | ||
|
|
dc8198100b | ||
|
|
1a9a8a2098 | ||
|
|
2968f8edf8 | ||
|
|
5c094bf6e0 | ||
|
|
c4232b34ae | ||
|
|
99b856233d | ||
|
|
0f4c785705 | ||
|
|
814d56c25c | ||
|
|
f878f54b4d | ||
|
|
46a87e42ce | ||
|
|
db26aa652b | ||
|
|
8d1d3a9c42 | ||
|
|
d5e89a60b7 | ||
|
|
948d18f954 | ||
|
|
7dbba59dee | ||
|
|
61fd4e4ce4 | ||
|
|
9bd6bbfd95 | ||
|
|
cc9249ba1a | ||
|
|
35fddfa8f4 | ||
|
|
82e10e1a00 | ||
|
|
84ae7df8f1 | ||
|
|
5c199e2195 | ||
|
|
9aaf9a484d | ||
|
|
4e4a9012c2 | ||
|
|
4840db67ca | ||
|
|
b09613b943 | ||
|
|
66eac19058 | ||
|
|
aee5a9ca43 | ||
|
|
129e54e262 | ||
|
|
0d4b77d7b1 | ||
|
|
b0eeb8a207 | ||
|
|
ae67b2b28e | ||
|
|
a97d02e0fd | ||
|
|
88bfa61875 | ||
|
|
4df914194c | ||
|
|
86c867ea71 | ||
|
|
16e972d077 | ||
|
|
152427e01b | ||
|
|
2a3c4cfb82 | ||
|
|
573aa168ea | ||
|
|
0de032ebd7 | ||
|
|
ab81c2b56d | ||
|
|
8a3cec4a9d | ||
|
|
2b0563ad35 | ||
|
|
928181cd7a | ||
|
|
e7a4318e8c | ||
|
|
4e5bc172c9 | ||
|
|
3ea2f00578 | ||
|
|
01ac394e92 | ||
|
|
4ce5888b4c | ||
|
|
35f79dd2b4 | ||
|
|
cdb547dbd1 | ||
|
|
00afc32b6b | ||
|
|
8a01067b62 | ||
|
|
7c2d59033b | ||
|
|
fe4de31e57 | ||
|
|
2a446b8799 | ||
|
|
4a1efed4a8 | ||
|
|
8e4864004b | ||
|
|
486d0802a8 | ||
|
|
c250da59d5 | ||
|
|
0aee5e5b48 | ||
|
|
292c1689ba | ||
|
|
0a1bd5a0c7 | ||
|
|
e0d641a787 | ||
|
|
d117989b55 | ||
|
|
2fa7e777d6 | ||
|
|
be30dd09e9 | ||
|
|
84aa3627b4 | ||
|
|
d7818be067 | ||
|
|
c782d21a36 | ||
|
|
7800e4047f | ||
|
|
61e846c4fd | ||
|
|
957badc792 | ||
|
|
53954285c7 | ||
|
|
5cffe328a5 | ||
|
|
1da49d86a1 | ||
|
|
0d7aea377a | ||
|
|
617df1c69c | ||
|
|
0b75f5a4d0 | ||
|
|
f200b17a33 | ||
|
|
2db574810b | ||
|
|
c9a29153dd | ||
|
|
25ec8ac6a7 | ||
|
|
c8c44d62ed | ||
|
|
4d329b510f | ||
|
|
a30e880876 | ||
|
|
5d1087e464 | ||
|
|
da99f3b939 | ||
|
|
73dd7440d0 | ||
|
|
1a87ee5f93 | ||
|
|
9d953f18c2 | ||
|
|
be3ed0cc25 | ||
|
|
ee3cd30b59 | ||
|
|
ca94563c51 | ||
|
|
9591226be6 | ||
|
|
718de31e04 | ||
|
|
4b2add7aa6 | ||
|
|
10e5e0fdf5 | ||
|
|
5f64ccb97d | ||
|
|
4687c1f465 | ||
|
|
79d51bc379 | ||
|
|
893d08d614 | ||
|
|
a5cd118550 | ||
|
|
a266a71999 | ||
|
|
be8694f93e | ||
|
|
a1a394ad0b | ||
|
|
e5cc8cd32b | ||
|
|
01b397faef | ||
|
|
90466183d6 | ||
|
|
84463d8cf0 | ||
|
|
a075f24000 | ||
|
|
ddea60efe9 | ||
|
|
5a14d1ed6c | ||
|
|
9837181d5d | ||
|
|
f6ccacb7df | ||
|
|
a0054ada08 | ||
|
|
2251a17f96 | ||
|
|
b1100a9c7a | ||
|
|
8e3dfcf0d0 | ||
|
|
bf7415e6b5 | ||
|
|
6072978454 | ||
|
|
5a74080839 | ||
|
|
89862cbea9 | ||
|
|
0451e7c9e7 | ||
|
|
2e08815644 | ||
|
|
96e83989a5 | ||
|
|
2c002c875d | ||
|
|
e38dd0e9d3 | ||
|
|
a2a2a583de | ||
|
|
a3ba28f507 | ||
|
|
6865b03338 | ||
|
|
12d7e61362 | ||
|
|
5c5864e94a | ||
|
|
d437f3db03 | ||
|
|
409255f056 | ||
|
|
d1ea29beeb | ||
|
|
a59e691ba8 | ||
|
|
a4a13bed84 | ||
|
|
ec454d1da0 | ||
|
|
e2afb4c7e7 | ||
|
|
87b488a12b | ||
|
|
4dc658c270 | ||
|
|
a5d8b4a933 | ||
|
|
1d34a50d2f | ||
|
|
d1737745c2 | ||
|
|
ec2e6525ac | ||
|
|
8882d9c3b6 | ||
|
|
6d1a018864 | ||
|
|
320e67baa1 | ||
|
|
69f8cf7836 | ||
|
|
5304660e14 | ||
|
|
538da92eae | ||
|
|
4b487e3c89 | ||
|
|
70e1bfc6b8 | ||
|
|
d65295db8b | ||
|
|
34be638fca | ||
|
|
2a0973a897 | ||
|
|
42b51e3c5c | ||
|
|
ff0e392ca8 | ||
|
|
1da95d2e37 | ||
|
|
b7c4ebba84 | ||
|
|
66ababc6c8 | ||
|
|
e128c03f56 | ||
|
|
d5b40280ab | ||
|
|
346980308b | ||
|
|
abd30e0269 | ||
|
|
cbe395f463 | ||
|
|
59d4523d72 | ||
|
|
27f968e753 | ||
|
|
a2ebc169e4 | ||
|
|
d10cc66036 | ||
|
|
3d0226ccd0 | ||
|
|
acb4d12928 | ||
|
|
600f7bcf7b | ||
|
|
1ff89c5a1c | ||
|
|
56b12bd969 | ||
|
|
2333249b05 | ||
|
|
aabe641047 | ||
|
|
dc5a29a976 | ||
|
|
82ecfac4ee | ||
|
|
23fea490aa | ||
|
|
1d60300016 | ||
|
|
6536f82559 | ||
|
|
4464a11314 | ||
|
|
2855ea1500 | ||
|
|
258dc594dd | ||
|
|
a1476c68f1 | ||
|
|
bf163d221c | ||
|
|
7900b9c294 | ||
|
|
6a17d50423 | ||
|
|
9e7f8d0e16 | ||
|
|
3a99ef512e | ||
|
|
a14886031f | ||
|
|
ec881e0fd0 | ||
|
|
80989147ad | ||
|
|
3c31a60b32 | ||
|
|
db59b45076 | ||
|
|
0f0ff6788c | ||
|
|
47c07c2e76 | ||
|
|
896dcde2b2 | ||
|
|
a88409bbfa | ||
|
|
b8189a31ad | ||
|
|
e90d09a6d9 | ||
|
|
9fb49cb59b | ||
|
|
77ab05823d | ||
|
|
28ff188f96 | ||
|
|
bac191f96c | ||
|
|
e1a9487896 | ||
|
|
9e728e4b25 | ||
|
|
06d2c9fb7b | ||
|
|
63c862d925 | ||
|
|
a96a70869d | ||
|
|
ede5be119f | ||
|
|
b7c57d306a | ||
|
|
816eef1702 | ||
|
|
92eeba5392 | ||
|
|
2f3706bd37 | ||
|
|
e6f6884c36 | ||
|
|
ab5c2e9ded | ||
|
|
4f72225372 | ||
|
|
3af0976a43 | ||
|
|
96b1f0ca74 | ||
|
|
32ea2161eb | ||
|
|
c8ab1b9892 | ||
|
|
61e637a639 | ||
|
|
7d94d3fd1a | ||
|
|
88a58a057e | ||
|
|
4bb51516bb | ||
|
|
0805b9e99e | ||
|
|
82b27b45fe | ||
|
|
166fb1d13f | ||
|
|
ef9f145cb5 | ||
|
|
929bc8b8b9 | ||
|
|
d24d5d95dd | ||
|
|
9ba3a1c4ff | ||
|
|
1bcdbd1d96 | ||
|
|
8ada06cfe3 | ||
|
|
bf0be99366 | ||
|
|
653f1dae4c | ||
|
|
d91340166d | ||
|
|
d694e8df86 | ||
|
|
75a486ff96 | ||
|
|
48626ee71b | ||
|
|
b297aa3f3a | ||
|
|
dfc94ff144 | ||
|
|
1ffa7be4e1 | ||
|
|
d7cccacc12 | ||
|
|
96bde3ff44 | ||
|
|
b49c1c6ba2 | ||
|
|
e9dc9c47a9 | ||
|
|
3e055c1201 | ||
|
|
54388b6a0a | ||
|
|
0dff35c0db | ||
|
|
6c676f8d5f | ||
|
|
4e95dbf0e5 | ||
|
|
00b4176bf8 | ||
|
|
7836fd1990 | ||
|
|
92e765ea21 | ||
|
|
16d9ef5f1c | ||
|
|
bce1610794 | ||
|
|
1f16233afa | ||
|
|
e804548b22 | ||
|
|
dc994173d7 | ||
|
|
283140d16a | ||
|
|
03155c63ae | ||
|
|
17fc28b020 | ||
|
|
607bef8d68 | ||
|
|
55f5ceb85a | ||
|
|
7be8e3e1e9 | ||
|
|
55c3f5ddff | ||
|
|
44b81b20e3 | ||
|
|
4097be1908 | ||
|
|
f6ef727573 | ||
|
|
1045cb56fe | ||
|
|
6c0ad4966e | ||
|
|
5d50792a56 | ||
|
|
0c16842e0d | ||
|
|
d9538845bc | ||
|
|
7f1579d96d | ||
|
|
3674694d12 | ||
|
|
3e518e8040 | ||
|
|
33c92a31bf | ||
|
|
5e2e7902ce | ||
|
|
f9585430bb | ||
|
|
19de32e206 | ||
|
|
a82bc1df64 | ||
|
|
c34e841710 | ||
|
|
a5c78be52c | ||
|
|
edbbaef26f | ||
|
|
bdd133309d | ||
|
|
71da05dc96 | ||
|
|
f1cbafb097 | ||
|
|
3db557e2c9 | ||
|
|
a8b3177e20 | ||
|
|
8e6f043586 | ||
|
|
5163472392 | ||
|
|
965c811025 | ||
|
|
adc2260b63 | ||
|
|
4ef84054dc | ||
|
|
7db1c9b8eb | ||
|
|
ae06a6ce41 | ||
|
|
0316450ee2 | ||
|
|
281305147b | ||
|
|
ef41e32af5 | ||
|
|
4ef8172f8d | ||
|
|
5106f9f958 | ||
|
|
2c61d8d94b | ||
|
|
bc8c8c1bb9 | ||
|
|
cbc08eb96d | ||
|
|
f4de65a647 | ||
|
|
0f42f18100 | ||
|
|
a9d9dc6658 | ||
|
|
07cd6a8b88 | ||
|
|
ab62690b97 | ||
|
|
e7a3ee477d | ||
|
|
1ec06f4bf0 | ||
|
|
849f93375c | ||
|
|
35ba6cef4e | ||
|
|
b0d63dae16 | ||
|
|
14d394aed8 | ||
|
|
50fea44ce2 | ||
|
|
98004c2328 | ||
|
|
eb7dda85a1 | ||
|
|
2f994b1227 | ||
|
|
a9bdde193d | ||
|
|
2ffef3bdda | ||
|
|
77b789e26a | ||
|
|
031f2dfeb8 | ||
|
|
cb0eef9edd | ||
|
|
8be85de6ef | ||
|
|
9cf7f2b83d | ||
|
|
95667ef98e | ||
|
|
b211ce02a8 | ||
|
|
739298c782 | ||
|
|
a1da6bff1a | ||
|
|
18a81d7ca0 | ||
|
|
6f15903019 | ||
|
|
a26f7a1292 | ||
|
|
ae8c5287e4 | ||
|
|
fd10362bef | ||
|
|
3af6cc53d1 | ||
|
|
54bb5f1879 | ||
|
|
13e3375e8a | ||
|
|
37157dc9e2 | ||
|
|
8fe3dce649 | ||
|
|
4ec4c45a90 | ||
|
|
19f46ed4f0 | ||
|
|
0e9509ae9b | ||
|
|
618dedc58e | ||
|
|
623b7a8d6f | ||
|
|
7c76f124bf | ||
|
|
f5973e0eee | ||
|
|
32634356a6 | ||
|
|
6d0a07a4cd | ||
|
|
e0b829f92f | ||
|
|
684572bd05 | ||
|
|
334eb5d423 | ||
|
|
bcbdaaa6ea | ||
|
|
986939e501 | ||
|
|
d416fd8c0f | ||
|
|
78119df2db | ||
|
|
e2e04e3f16 | ||
|
|
d37468975c | ||
|
|
589f77ef0e | ||
|
|
1e2d88cd5d | ||
|
|
da4425b5c0 | ||
|
|
0d7cb63978 | ||
|
|
2248560699 | ||
|
|
3daae94bca | ||
|
|
7299b76faf | ||
|
|
673dc6e873 | ||
|
|
9c544c0a4b | ||
|
|
8502ecc6d2 | ||
|
|
74b5638d99 | ||
|
|
e8de8735e2 | ||
|
|
dbcd19418c | ||
|
|
a10f040df6 | ||
|
|
88a7ff891c | ||
|
|
2b4db6c3bf | ||
|
|
4ddc426966 | ||
|
|
309ce43e05 | ||
|
|
61470c0d24 | ||
|
|
2301732e2d | ||
|
|
24ee8eb16a | ||
|
|
57065bb274 | ||
|
|
4ab4aa04da | ||
|
|
0ed39dad63 | ||
|
|
08531ee675 | ||
|
|
e7140ffec7 | ||
|
|
c58c4b7938 | ||
|
|
4e276471e5 | ||
|
|
c5eac63da1 | ||
|
|
866c6d0cf9 | ||
|
|
165294bfb1 | ||
|
|
2d5f0479bd | ||
|
|
e8068cf5ac | ||
|
|
d0171cf386 | ||
|
|
3ae99ea0b9 | ||
|
|
4e9450f200 | ||
|
|
dc2c49f4a9 | ||
|
|
c461e8b63c | ||
|
|
f47bc1163b | ||
|
|
851be2d76e | ||
|
|
63034e6cba | ||
|
|
84b9c5f5fd | ||
|
|
43c8fc6847 | ||
|
|
bc60bd23b2 | ||
|
|
e29120a9c1 | ||
|
|
d383230532 | ||
|
|
9a46896600 | ||
|
|
fba086134d | ||
|
|
2973364c02 | ||
|
|
542bb7caed | ||
|
|
fb47b6ae21 | ||
|
|
aeb301c8d5 | ||
|
|
704e14f008 | ||
|
|
d1050d6b02 | ||
|
|
afc96808e8 | ||
|
|
dc2bae4ae1 | ||
|
|
1d7da21e48 | ||
|
|
affd965d5d | ||
|
|
989161159d | ||
|
|
59a74153dc | ||
|
|
6690c269ef | ||
|
|
b7fd10b905 | ||
|
|
08e1cf1b7e | ||
|
|
54d891afa7 | ||
|
|
ae41782cd4 | ||
|
|
8591fe00b6 | ||
|
|
92f58cb3c1 | ||
|
|
4ad98ca505 | ||
|
|
b9374bde6b | ||
|
|
1ff29384b3 | ||
|
|
4fc714ff10 | ||
|
|
51f0c8a388 | ||
|
|
d01a65f73d | ||
|
|
65239f9ffe | ||
|
|
e5cefcce70 | ||
|
|
8002b5ec6a | ||
|
|
a575f5cc77 | ||
|
|
ab3a80e076 | ||
|
|
dda3798ba9 | ||
|
|
e6f906b9ca | ||
|
|
d74e43ddcc | ||
|
|
23ddce122b | ||
|
|
814bd26c07 | ||
|
|
2e4b39c19c | ||
|
|
3ee65748bb | ||
|
|
5f387737a1 | ||
|
|
4fa800b87a | ||
|
|
9338b3cf94 | ||
|
|
45e09af692 | ||
|
|
9d32f48ab8 | ||
|
|
290e7baead | ||
|
|
e780ae00d0 | ||
|
|
9ea224412d | ||
|
|
cd8ae07698 | ||
|
|
433a73e13d | ||
|
|
1e558f4da6 | ||
|
|
aef6e33c91 | ||
|
|
acd83ede2f | ||
|
|
bd51613e62 | ||
|
|
246cb39003 | ||
|
|
3b54c527b6 | ||
|
|
18368fefaa | ||
|
|
c361e1e31a | ||
|
|
e3d4152e32 | ||
|
|
d861ba1876 | ||
|
|
c942017b73 | ||
|
|
743d12e326 | ||
|
|
d371a3d5fd | ||
|
|
e1056126e6 | ||
|
|
72c267fbf3 | ||
|
|
0ed85b9d25 | ||
|
|
a8877d82b6 | ||
|
|
8896b0adf3 | ||
|
|
60b14e9b45 | ||
|
|
631e853b40 | ||
|
|
b409c8cc2f | ||
|
|
905212b109 | ||
|
|
05b7df26e6 | ||
|
|
1268afd3f8 | ||
|
|
c1b9b7a623 | ||
|
|
0b9160fb75 | ||
|
|
93c9419392 | ||
|
|
6121bcf171 | ||
|
|
702144180c | ||
|
|
d2b2f98941 | ||
|
|
ec95956e25 | ||
|
|
d6d7ce1b67 | ||
|
|
4cb36b0a5d | ||
|
|
2b3aea76a9 | ||
|
|
f50a31b4e8 | ||
|
|
b226c3aca3 | ||
|
|
4979666a89 | ||
|
|
c9636f85b9 | ||
|
|
436bc87a86 | ||
|
|
e89c2b242d | ||
|
|
02b26a65bb | ||
|
|
6a3e4bb59f | ||
|
|
b01ad360da | ||
|
|
c7f3740099 | ||
|
|
554595acd7 | ||
|
|
ee4ddd5446 | ||
|
|
ebab617a12 | ||
|
|
bc5d92a452 | ||
|
|
2f388dfb6a | ||
|
|
73a0197eb2 | ||
|
|
b6990e9e5d | ||
|
|
26e119bfc2 | ||
|
|
9f866ae608 | ||
|
|
023359b9d2 | ||
|
|
2128d047e1 | ||
|
|
a89349c5b9 | ||
|
|
d109b8beb6 | ||
|
|
9b40572921 | ||
|
|
aaf7a38cce | ||
|
|
1ed0759a50 | ||
|
|
213b73da6e | ||
|
|
5b6985fc5c | ||
|
|
538af01bf5 | ||
|
|
92d0589a37 | ||
|
|
f3269070b2 | ||
|
|
d93bd3eda7 | ||
|
|
0dbbc5d8b6 | ||
|
|
08efd5ecab | ||
|
|
dba1bcb0e3 | ||
|
|
348403abff | ||
|
|
c290cf45b7 | ||
|
|
175c8e6e50 | ||
|
|
f90667b23c | ||
|
|
cf69d591e4 | ||
|
|
e599491583 | ||
|
|
d1520773cf | ||
|
|
573ca97b6c | ||
|
|
0d97f14a1a | ||
|
|
b8f28abfdf | ||
|
|
9ac7c97e67 | ||
|
|
52b3eaacb5 | ||
|
|
9b01ae6db9 | ||
|
|
469487ad36 | ||
|
|
176c3c1601 | ||
|
|
94391234cc | ||
|
|
d84901f196 | ||
|
|
c6b117565d | ||
|
|
2a9124acb5 | ||
|
|
401a783d6a | ||
|
|
39483a30b6 | ||
|
|
0e2a07f8d7 | ||
|
|
36f5b0218d | ||
|
|
a1b3c56de7 | ||
|
|
6d664f133e | ||
|
|
732a433ec1 | ||
|
|
f7dcd1ba2c | ||
|
|
55a8b44224 | ||
|
|
e29db31d91 | ||
|
|
183d3c3ca4 | ||
|
|
c57e713696 | ||
|
|
4519f26adf | ||
|
|
c26f9cc01f | ||
|
|
53e784094a | ||
|
|
0e92e48376 | ||
|
|
4c9943ac38 | ||
|
|
4bd0fd145d | ||
|
|
01ae82eb28 | ||
|
|
e21eae0933 | ||
|
|
2f047c50dc | ||
|
|
e397e1a80c | ||
|
|
b09e86352f | ||
|
|
8687b69167 | ||
|
|
6c5468d904 | ||
|
|
d6b0f8d4c5 | ||
|
|
a8cd4ff12c | ||
|
|
8509efc8af | ||
|
|
23a0053dad | ||
|
|
5849980092 | ||
|
|
e81fc2b254 | ||
|
|
f6f730b994 | ||
|
|
2ad869a036 | ||
|
|
7a8c84e990 | ||
|
|
0de01e93dd | ||
|
|
6fa93e5b44 | ||
|
|
2144ec1e3f | ||
|
|
68d2f60ace | ||
|
|
3d671ae71f | ||
|
|
8ed47f9d99 | ||
|
|
b50f858556 | ||
|
|
5de1a74429 | ||
|
|
2063ad467d | ||
|
|
679acbae16 | ||
|
|
a5b706a99e | ||
|
|
542e61357e | ||
|
|
3743602c67 | ||
|
|
ee651840bf | ||
|
|
0765c60d77 | ||
|
|
7fa17322a1 | ||
|
|
cfa3047330 | ||
|
|
9e033deb7b | ||
|
|
f6c914f6f0 | ||
|
|
06ff02c2a5 | ||
|
|
63fd263890 | ||
|
|
94f3d4b279 | ||
|
|
fdc96044ad | ||
|
|
91487ffc94 | ||
|
|
7a57dcc08a | ||
|
|
913a54713d | ||
|
|
39a8681e8e | ||
|
|
a7015b0d1a | ||
|
|
5305f23332 | ||
|
|
acbf3adab7 | ||
|
|
366b2f1374 | ||
|
|
2189ab7ee6 | ||
|
|
349c04d8d1 | ||
|
|
c7c6249ad7 | ||
|
|
5319227a8f | ||
|
|
3aff812ee2 | ||
|
|
88eabf23f4 | ||
|
|
a70beaf7b6 | ||
|
|
c91bffa73c | ||
|
|
ea163dbbba | ||
|
|
18bc99d6b5 | ||
|
|
bab94a207d | ||
|
|
ef39baab47 | ||
|
|
2edaaac7bf | ||
|
|
113e50c074 | ||
|
|
900a675864 | ||
|
|
49b3b49f3e | ||
|
|
23935d3d39 | ||
|
|
3fd33d0f50 | ||
|
|
8c3317b8e9 | ||
|
|
99a9fc054f | ||
|
|
967dcfc3d2 | ||
|
|
0051b3b79c | ||
|
|
cbcee201f0 | ||
|
|
1fa4a53a48 | ||
|
|
6a0b92638c | ||
|
|
2e81b8493e | ||
|
|
57ba702dda | ||
|
|
62bafcaf63 | ||
|
|
7de5c9c1d2 | ||
|
|
8248b14555 | ||
|
|
23ef0c8d9d | ||
|
|
58a4f59fd8 | ||
|
|
0c851934fb | ||
|
|
8d58dbee38 | ||
|
|
cd5e84e4ef | ||
|
|
09ba14eb04 | ||
|
|
b22f1965aa | ||
|
|
df6f920b44 | ||
|
|
f13b2462c8 | ||
|
|
c0e80c14f8 | ||
|
|
2b1176df53 | ||
|
|
05bfbf5620 | ||
|
|
4af706bd83 | ||
|
|
b62e4d5ee9 | ||
|
|
bd98d661d3 | ||
|
|
1f7c5529e9 | ||
|
|
0453346cf4 | ||
|
|
15090243d0 | ||
|
|
b22e3ee253 | ||
|
|
e693554961 | ||
|
|
0efca9a9a8 | ||
|
|
5d22061c0a | ||
|
|
84be7fd739 | ||
|
|
5d269ad0aa | ||
|
|
a4d5c41b3a | ||
|
|
846fb9abb0 | ||
|
|
0f33e59e4d | ||
|
|
896650d005 | ||
|
|
6d6b5a7917 | ||
|
|
db5010be9d | ||
|
|
be8860080c | ||
|
|
42f124b0f6 | ||
|
|
7249ababb7 | ||
|
|
079be92468 | ||
|
|
dda2a2feba | ||
|
|
ae726cfdc0 | ||
|
|
1a04e5a9af | ||
|
|
cac68dbaba | ||
|
|
3c04634609 | ||
|
|
6c12681b9c | ||
|
|
b1b5f3e6f0 | ||
|
|
5baa167a08 | ||
|
|
343d17d19a | ||
|
|
0370cc47fc | ||
|
|
083fc955dc | ||
|
|
a6e268f784 | ||
|
|
7e0a9bc37c | ||
|
|
f25bc818d7 | ||
|
|
9beae22803 | ||
|
|
920b0af269 | ||
|
|
6c674bef2a | ||
|
|
e74fbbb38b | ||
|
|
fb3f916802 | ||
|
|
c80d47d3dd | ||
|
|
693ee1dcf8 | ||
|
|
640c0faff1 | ||
|
|
207ac47aa7 | ||
|
|
8844f83a59 | ||
|
|
4a5a1cd5f4 | ||
|
|
09d63d38ab | ||
|
|
6bf0f9b2ec | ||
|
|
f6fdd3ce70 | ||
|
|
d1f6679f2d | ||
|
|
b8a6eb4768 | ||
|
|
6efad1348a | ||
|
|
eaed9db1e7 | ||
|
|
4f8b7a934c | ||
|
|
71c04936af | ||
|
|
41da758946 | ||
|
|
acbfe5cb09 | ||
|
|
ba3d65c01f | ||
|
|
856732abab | ||
|
|
5f21e4c5b6 | ||
|
|
28b44cf67c | ||
|
|
674b0e706c | ||
|
|
b96ca538e4 | ||
|
|
3266ace916 | ||
|
|
f7ce8d028d | ||
|
|
85e5b0fc31 | ||
|
|
61f4b52a15 | ||
|
|
d17cc9fa86 | ||
|
|
1f995cffe9 | ||
|
|
0936d54114 | ||
|
|
0912dbf130 | ||
|
|
7dd566a591 | ||
|
|
0f9bc766db | ||
|
|
e71e6c5b79 | ||
|
|
4d5f82633b | ||
|
|
2f01746c55 | ||
|
|
7ec5b34548 | ||
|
|
1604fa6584 | ||
|
|
b67994235e | ||
|
|
ee1358fae3 | ||
|
|
9fae5aa02f | ||
|
|
a887beed3a | ||
|
|
8a30d44042 | ||
|
|
4fef8a3b79 | ||
|
|
ad9bdf4dd2 | ||
|
|
29001c3ab0 | ||
|
|
a5387b054a | ||
|
|
c2757469a5 | ||
|
|
ed1aa700d0 | ||
|
|
58b5e1748f | ||
|
|
a99bbe67ab | ||
|
|
f53fb3d814 | ||
|
|
e716c1738c | ||
|
|
3190bfa058 | ||
|
|
c570b80d7b | ||
|
|
2f9887245a | ||
|
|
6006333ccf | ||
|
|
fd6c91715f | ||
|
|
a40b6a9df8 | ||
|
|
d67b7c7f49 | ||
|
|
616ab0f635 | ||
|
|
930e65da66 | ||
|
|
414a978b10 | ||
|
|
4ebefb17e9 | ||
|
|
c46772015b | ||
|
|
677eef12dd | ||
|
|
cd03b29ece | ||
|
|
63aa60f2d6 | ||
|
|
282defc54c | ||
|
|
593de63d49 | ||
|
|
5bb53ba036 | ||
|
|
3c369a4c67 | ||
|
|
83aeb99b95 | ||
|
|
188d53ef94 | ||
|
|
961cf7edbb | ||
|
|
2c5a5816c4 | ||
|
|
96a6f2dfd6 | ||
|
|
35be17cfc9 | ||
|
|
8d90a7d091 | ||
|
|
4a71c2655a | ||
|
|
043fd6e259 | ||
|
|
7722e14117 | ||
|
|
5e377d3694 | ||
|
|
f512583973 | ||
|
|
5fce7f6ba2 | ||
|
|
dfe1666530 | ||
|
|
41f0069a22 | ||
|
|
9f332ffcec | ||
|
|
891bd7f346 | ||
|
|
4810249301 | ||
|
|
984a6519fc | ||
|
|
986f13ef1a | ||
|
|
83dd56d34c | ||
|
|
b646e8d213 | ||
|
|
2785e76e23 | ||
|
|
c5cacd7955 | ||
|
|
62532b5879 | ||
|
|
7e22f9c57b | ||
|
|
d9017b2665 | ||
|
|
4571a4c048 | ||
|
|
80685395ed | ||
|
|
38b9819b68 | ||
|
|
a4dcf5f8df | ||
|
|
9a49a01713 | ||
|
|
8c3fb54d3d | ||
|
|
7707e384c5 | ||
|
|
a09b8ce56e | ||
|
|
7ecafb1e69 | ||
|
|
9f93ce86be | ||
|
|
a5773f1d0b | ||
|
|
d72813340e | ||
|
|
daf56455a5 | ||
|
|
f58d7fc3cc | ||
|
|
4584d89c43 | ||
|
|
1cc2b388a2 | ||
|
|
51a1a7ed22 | ||
|
|
99c2b60a1d | ||
|
|
de5cd53f85 | ||
|
|
f027a8f74f | ||
|
|
7d81ec4d86 | ||
|
|
a6fed4da65 | ||
|
|
ce42d3ab5d | ||
|
|
d939ae5fb2 | ||
|
|
642fa8d6f8 | ||
|
|
8f02b9249e | ||
|
|
7487684301 | ||
|
|
02e3f6b3a2 | ||
|
|
727df551e6 | ||
|
|
e5dc7058c1 | ||
|
|
c9488d5ee9 | ||
|
|
4720088039 | ||
|
|
96a18ab2d5 | ||
|
|
137aace970 | ||
|
|
4a8eca2020 | ||
|
|
23efa7827c | ||
|
|
fd24595baf | ||
|
|
2331982e33 | ||
|
|
683fc84a28 | ||
|
|
a0f5e5c8f8 | ||
|
|
c9af2b956c | ||
|
|
75b3bc6190 | ||
|
|
6c716bcbb1 | ||
|
|
44beed6216 | ||
|
|
2352811c20 | ||
|
|
c1df375af4 | ||
|
|
e8c631de01 | ||
|
|
bdc67201e2 | ||
|
|
0db33bb45c | ||
|
|
9f26270a98 | ||
|
|
df721cbd2e | ||
|
|
8745efb81f | ||
|
|
e56f1a9ded | ||
|
|
52fbb8f02c | ||
|
|
a1639b67a5 | ||
|
|
3475ad4674 | ||
|
|
685d117a91 | ||
|
|
e51f791ab0 | ||
|
|
0f2ba1cefe | ||
|
|
1f457dfca5 | ||
|
|
841050953f | ||
|
|
c6296821c0 | ||
|
|
7c8ca45d9a | ||
|
|
142f6e4518 | ||
|
|
f72e7ffbc2 | ||
|
|
111b6e1c27 | ||
|
|
4add2d0590 | ||
|
|
cb0f7417b6 | ||
|
|
06eb7c6109 | ||
|
|
4d0701cfda | ||
|
|
86bce1e5f6 | ||
|
|
8da0d3a1f1 | ||
|
|
f32438b219 | ||
|
|
0238a10a4b | ||
|
|
6669a96fd8 | ||
|
|
09406bfbfc | ||
|
|
51da40e90c | ||
|
|
52847bd28d | ||
|
|
835d3c6a25 | ||
|
|
00e6e98a61 | ||
|
|
6d90adcdf6 | ||
|
|
06d2fb0aca | ||
|
|
c3428e8213 | ||
|
|
57b0736ebb | ||
|
|
6211566c0c | ||
|
|
48bb427f71 | ||
|
|
56f15356c7 | ||
|
|
8e6fd0ca95 | ||
|
|
b5dfc2a520 | ||
|
|
4900fe020d | ||
|
|
94bd6bc330 | ||
|
|
36bcc6831b | ||
|
|
76c89845a8 | ||
|
|
b58f1cdd16 | ||
|
|
141c64cd00 | ||
|
|
51b802da84 | ||
|
|
71c27f308c | ||
|
|
75b9adf01b | ||
|
|
a079914603 | ||
|
|
4d3ca4a85a | ||
|
|
afa1d5423c | ||
|
|
766eb94c7d | ||
|
|
ad6e793615 | ||
|
|
d900d3c3fd | ||
|
|
7f315ef105 | ||
|
|
dc0a7e7628 | ||
|
|
6d1f42bf30 | ||
|
|
c26b144f0d | ||
|
|
752f4dd5de | ||
|
|
693ebbea9d | ||
|
|
b24a54aab2 | ||
|
|
00aee89709 | ||
|
|
a5f243e18d | ||
|
|
d05ff9b4ee | ||
|
|
a67087b6de | ||
|
|
e2ea16ea3f | ||
|
|
5098b64666 | ||
|
|
66fbc28385 | ||
|
|
4bcd75f15c | ||
|
|
da6af88910 | ||
|
|
1a91f4953b | ||
|
|
9a0d28720d | ||
|
|
5b6956e25b | ||
|
|
fd51108ae3 | ||
|
|
73a2eca51c | ||
|
|
9bc24e1caa | ||
|
|
3fc02bf6c2 | ||
|
|
3bd4f1d5d8 | ||
|
|
f3dbeea091 | ||
|
|
d2ef94a7eb | ||
|
|
1d1d8defda | ||
|
|
d0127b879d | ||
|
|
cbc6943305 | ||
|
|
9124aa2c87 | ||
|
|
8817f0c53d | ||
|
|
e4f9c17f8a | ||
|
|
686ee1111a | ||
|
|
4b11767ac5 | ||
|
|
5545c0d905 | ||
|
|
611edf7e34 | ||
|
|
7a37d70fb6 | ||
|
|
b2577090bd | ||
|
|
5b0777d4db | ||
|
|
12c1574f07 | ||
|
|
5623a06996 | ||
|
|
148960c6d2 | ||
|
|
ff8c6690ef | ||
|
|
c926e95822 | ||
|
|
0a28dd0cd3 | ||
|
|
8caae4bfde | ||
|
|
a67c5a8dc7 | ||
|
|
cf38fde207 | ||
|
|
4549b766f5 | ||
|
|
45126d4f3d | ||
|
|
82926ef8c6 | ||
|
|
42604971dc | ||
|
|
95fcf5bae5 | ||
|
|
34acadc3b5 | ||
|
|
d3df082e3d | ||
|
|
fe7e9f333f | ||
|
|
92901e09e1 | ||
|
|
128b301a39 | ||
|
|
1b1b9475a4 | ||
|
|
5aff96e3b7 | ||
|
|
fb4e9b3c6d | ||
|
|
a8a6b38c28 | ||
|
|
68ab87cc0d | ||
|
|
986c29ca5d | ||
|
|
d7fc20b607 | ||
|
|
96b280668d | ||
|
|
66b7404961 | ||
|
|
7f3323f7c0 | ||
|
|
e34d86b485 | ||
|
|
34ea330aa3 | ||
|
|
70c3c1a21c | ||
|
|
98d3755859 | ||
|
|
a4a1579c84 | ||
|
|
20c6dba599 | ||
|
|
056fc64f7a | ||
|
|
cb0ec3f702 | ||
|
|
084929f875 | ||
|
|
10f3f01da8 | ||
|
|
1f75683581 | ||
|
|
29b86a7fe3 | ||
|
|
bb80bf4144 | ||
|
|
92df64f706 | ||
|
|
fc3e0147e0 | ||
|
|
b2d2209236 | ||
|
|
f4e6dceaa4 | ||
|
|
f09a9be523 | ||
|
|
2b08950294 | ||
|
|
62713bf87c | ||
|
|
7a2eca3706 | ||
|
|
22b7142159 | ||
|
|
cba5528478 | ||
|
|
5e8c5b3ce4 | ||
|
|
d4df6f2dda | ||
|
|
257bb49c52 | ||
|
|
6740b9edf6 | ||
|
|
cf241effbf | ||
|
|
c0c198098b | ||
|
|
ac0ee771ed | ||
|
|
0ca9389e4b | ||
|
|
9910caf29f | ||
|
|
78dbaa9b21 | ||
|
|
5c956de99e | ||
|
|
91340a5268 | ||
|
|
38e44440d0 | ||
|
|
02495e3b31 | ||
|
|
3360c62392 | ||
|
|
05e9dfca92 | ||
|
|
510c650b7b | ||
|
|
c41c219206 | ||
|
|
4d335e086b | ||
|
|
3fa62c3757 | ||
|
|
d256bc317a | ||
|
|
101c413a3c | ||
|
|
c3e0d7ff56 | ||
|
|
826a7fd220 | ||
|
|
e5607d0371 | ||
|
|
b3b50fe346 | ||
|
|
16a2b0377a | ||
|
|
8ba7a354e5 | ||
|
|
bbbd01b26c | ||
|
|
e7d089c815 | ||
|
|
24169743e7 | ||
|
|
02ae3b3053 | ||
|
|
69e4f49e74 | ||
|
|
1328870a2b | ||
|
|
51d48e18c6 | ||
|
|
4b1dfb9a33 | ||
|
|
9633919e32 | ||
|
|
76e55f1132 | ||
|
|
30e717bd20 | ||
|
|
d703271c96 | ||
|
|
c6c701330a | ||
|
|
f02f050e56 | ||
|
|
f6609524ea | ||
|
|
6eb767ba11 | ||
|
|
c4d0340956 | ||
|
|
10f04575ed | ||
|
|
a9c984e7db | ||
|
|
03fd87476a | ||
|
|
317f0e736c | ||
|
|
9f280e320d | ||
|
|
a1e098680d | ||
|
|
ede4808ec4 | ||
|
|
e86294191a | ||
|
|
0bf372b8ab | ||
|
|
ae7ad8b456 | ||
|
|
16c70fddba | ||
|
|
e679509c56 | ||
|
|
f08e9afc19 | ||
|
|
215d8b1355 | ||
|
|
b1f129a53a | ||
|
|
a6a7e81a0f | ||
|
|
aaca510f8a | ||
|
|
3ad1573130 | ||
|
|
d60146c6a8 | ||
|
|
31d6a41759 | ||
|
|
e731f6c3f3 | ||
|
|
1f200b63a7 | ||
|
|
ae01275729 | ||
|
|
fab93a170e | ||
|
|
f28311a2ce | ||
|
|
7da8db74b0 | ||
|
|
5feeef0122 | ||
|
|
87f7be2182 | ||
|
|
e81a10de4a | ||
|
|
8d9863a635 | ||
|
|
456b3030e3 | ||
|
|
d72695ae0f | ||
|
|
e6748cf153 | ||
|
|
a5e7c86125 | ||
|
|
a7a7f269c3 | ||
|
|
c815b1f25b | ||
|
|
c98ffdc817 | ||
|
|
09016c2182 | ||
|
|
22b2f17234 | ||
|
|
0c1bef927b | ||
|
|
4aa47a7901 | ||
|
|
051db50b3f | ||
|
|
c726a1a879 | ||
|
|
2edb279d22 | ||
|
|
20e7c6d873 | ||
|
|
96479e0474 | ||
|
|
1036768b2a | ||
|
|
77e28a6a45 | ||
|
|
a8b69d5cd8 | ||
|
|
9054e72b7f | ||
|
|
dc93940bbd | ||
|
|
b6a6c99c9d | ||
|
|
544792b9cc | ||
|
|
7e2fe30472 | ||
|
|
5e7e5b317b | ||
|
|
a63bb5d906 | ||
|
|
0354dd2c24 | ||
|
|
647f577332 | ||
|
|
be1ba21166 | ||
|
|
8b2491c7a2 | ||
|
|
f987a53313 | ||
|
|
d875b35b32 | ||
|
|
df76d6990e | ||
|
|
86ffccb95a | ||
|
|
50494eb745 | ||
|
|
28f719b58a | ||
|
|
d384cd77c6 | ||
|
|
bb3384dc7c | ||
|
|
ae9819a45c | ||
|
|
40473a16c7 | ||
|
|
baad364b04 | ||
|
|
d2f52b534a | ||
|
|
532010c916 | ||
|
|
e349cc59ad | ||
|
|
634a18e847 | ||
|
|
01581196f0 | ||
|
|
d7ed0bac69 | ||
|
|
209272f940 | ||
|
|
138ed6a487 | ||
|
|
d84d0b65ca | ||
|
|
2fe69d409b | ||
|
|
9764fe52de | ||
|
|
131d5cc256 | ||
|
|
7fead897ed | ||
|
|
e3d5bd3dfb | ||
|
|
e3edef2999 | ||
|
|
328ff54423 | ||
|
|
2807346bdf | ||
|
|
fec8f4e005 | ||
|
|
3ae299cf2b | ||
|
|
bbf68a97bb | ||
|
|
739e2bd35a | ||
|
|
7acda03024 | ||
|
|
5cead57723 | ||
|
|
1e24be6dd4 | ||
|
|
8d80e13e31 | ||
|
|
69b79b7687 | ||
|
|
698b3caeb8 | ||
|
|
323684c5fe | ||
|
|
09e3fb9917 | ||
|
|
a17a98991c | ||
|
|
3fe43abdea | ||
|
|
64112e00e6 | ||
|
|
61651f7060 | ||
|
|
09c8e14465 | ||
|
|
0bb772d242 | ||
|
|
68b587b110 | ||
|
|
dd4a5f2705 | ||
|
|
79c52e1a77 | ||
|
|
221f6d1d68 | ||
|
|
ea0f0da8a4 | ||
|
|
d2ccd20c78 | ||
|
|
8762aae111 | ||
|
|
05fcaa2554 | ||
|
|
3c6d464b32 | ||
|
|
c95c46edac | ||
|
|
b2a1c9881e | ||
|
|
9f10a059ef | ||
|
|
86f1d287d7 | ||
|
|
6820ec8d23 | ||
|
|
4997ae79e3 | ||
|
|
c76fa50aa5 | ||
|
|
1c218191b0 | ||
|
|
84d71d558e | ||
|
|
659c84d696 | ||
|
|
99d50ade11 | ||
|
|
f271eb4610 | ||
|
|
076f7a82de | ||
|
|
547f96c0c1 | ||
|
|
8a789aa608 | ||
|
|
8fd23771f4 | ||
|
|
15bc3b9ad4 | ||
|
|
3196ffd941 | ||
|
|
84d2b79b4f | ||
|
|
a4e1f939cd | ||
|
|
563ea1244c | ||
|
|
3dca6f2354 | ||
|
|
bf5a1d1f8e | ||
|
|
a615649933 | ||
|
|
3c0c823a37 | ||
|
|
efed4bf13c | ||
|
|
5217bf0bb8 | ||
|
|
98de4c90b5 | ||
|
|
8c426e8bb7 | ||
|
|
5bc727804f | ||
|
|
32bfebc924 | ||
|
|
8f8b1385fa | ||
|
|
d342f93547 | ||
|
|
ecfc56461e | ||
|
|
d09a8b1896 | ||
|
|
88be44b472 | ||
|
|
4b82bc0e33 | ||
|
|
3022754f19 | ||
|
|
f7bfe8d8bf | ||
|
|
210605d8f3 | ||
|
|
52344ff741 | ||
|
|
687b0cad8e | ||
|
|
0053c4df49 | ||
|
|
2a5b4dde31 | ||
|
|
d2690444ac | ||
|
|
c473178dfe | ||
|
|
229a3b4418 | ||
|
|
63dfa5247f | ||
|
|
469dee36ee | ||
|
|
abb1482456 | ||
|
|
e1c5ea11bc | ||
|
|
55b741d11b | ||
|
|
8f57179aa4 | ||
|
|
0fa5aa48af | ||
|
|
a65fca851c | ||
|
|
62af73ea09 | ||
|
|
0e8297ea8d | ||
|
|
70861465e1 | ||
|
|
3bf8b7fbe2 | ||
|
|
436f3b9d9b | ||
|
|
71475038ba | ||
|
|
c9edc0ae15 | ||
|
|
242c1419fd | ||
|
|
8ca0943881 | ||
|
|
58a07355fb | ||
|
|
4acfb033c8 | ||
|
|
572fb20dd4 | ||
|
|
d15413cd18 | ||
|
|
c18caf52d0 | ||
|
|
c09e10a584 | ||
|
|
1ff0bdbcfd | ||
|
|
736b98869f | ||
|
|
91fd16e9b4 | ||
|
|
8118b4aea1 | ||
|
|
f62d7dbdf7 | ||
|
|
1bf2920f3e | ||
|
|
8ecf079a3f | ||
|
|
05ae9134a8 | ||
|
|
040f4a6618 | ||
|
|
a9aa29d0ad | ||
|
|
54cfbaaba0 | ||
|
|
0455c26fb2 | ||
|
|
65f8c9ad97 | ||
|
|
f0ac52614b | ||
|
|
b5f0d30298 | ||
|
|
d97ed17052 | ||
|
|
dc43135980 | ||
|
|
27158752b0 | ||
|
|
5c6f897ce7 | ||
|
|
d415a15e93 | ||
|
|
19709cd3fc | ||
|
|
89e15b6d3d | ||
|
|
dcf2d64067 | ||
|
|
c459e3cffd | ||
|
|
8eb7303bd9 | ||
|
|
de67abd21d | ||
|
|
bb5495b495 | ||
|
|
124303b8b8 | ||
|
|
9078596f3a | ||
|
|
3254bbaabb | ||
|
|
26792625f2 | ||
|
|
c54938374d | ||
|
|
83e7f23d0f | ||
|
|
b7fccf5040 | ||
|
|
a91deca6cd | ||
|
|
cbc7fe5d98 | ||
|
|
cf3ea2b8af | ||
|
|
a4c3348630 | ||
|
|
6bd5d6e4d5 | ||
|
|
442d2fa316 | ||
|
|
3ecc24d85e | ||
|
|
5e3193e087 | ||
|
|
b96743f4de | ||
|
|
2eec52485d | ||
|
|
c2085a5a9d | ||
|
|
f8733b2501 | ||
|
|
5597847190 | ||
|
|
13d187b878 | ||
|
|
43906a4e30 | ||
|
|
9641dbf373 | ||
|
|
ad2fb28f97 | ||
|
|
2f11e85304 | ||
|
|
25aeb184af | ||
|
|
ba778c50ac | ||
|
|
d06aef511f | ||
|
|
d94b50f1e4 | ||
|
|
367c9401eb | ||
|
|
338e1bac00 | ||
|
|
6148b4b229 | ||
|
|
e5f38e34e9 | ||
|
|
60eb76355b | ||
|
|
da86cba7ea | ||
|
|
33c026cc06 | ||
|
|
22a2d85ee2 | ||
|
|
26ff54366b | ||
|
|
762420fcc8 | ||
|
|
856a18fc2a | ||
|
|
9ed6e0e2f9 | ||
|
|
bbe475cb4e | ||
|
|
36fdb3127f | ||
|
|
ee31d24f7c | ||
|
|
7baa473e55 | ||
|
|
688e71cd1b | ||
|
|
ce9fff2a8d | ||
|
|
6202935a27 | ||
|
|
df7a6f0df6 | ||
|
|
4ae0d1b882 | ||
|
|
84fd0531f6 | ||
|
|
71d767f0b4 | ||
|
|
5fe0c62842 | ||
|
|
58b4e0d59a | ||
|
|
94366190a0 | ||
|
|
491ce70e1a | ||
|
|
7f3ff13c18 | ||
|
|
1edebf83ae | ||
|
|
d55e0f70d9 | ||
|
|
429325ca6d | ||
|
|
1238ffbc40 | ||
|
|
e24d5da0ef | ||
|
|
74f31db434 | ||
|
|
a2c71d05e6 | ||
|
|
e5503deadd | ||
|
|
d5541f612f | ||
|
|
8fafd2b4ea | ||
|
|
f66555a88f | ||
|
|
ab895280f4 | ||
|
|
b9705b5eed | ||
|
|
224bbdf8a9 | ||
|
|
b8af817ea3 | ||
|
|
231cd49916 | ||
|
|
35c1a77845 | ||
|
|
125e894624 | ||
|
|
53cb40be4c | ||
|
|
7e26625324 | ||
|
|
0e9835dde2 | ||
|
|
1f66abac4d | ||
|
|
6e4a710df6 | ||
|
|
3f0aa500f7 | ||
|
|
e868984116 | ||
|
|
7f24d14832 | ||
|
|
47d39ed5ca | ||
|
|
924bb3c7f7 | ||
|
|
3c8e704ace | ||
|
|
f2d6ff3426 | ||
|
|
480f0c703a | ||
|
|
a2b076985a | ||
|
|
9babe4a44d | ||
|
|
d2c2936efa | ||
|
|
98bc16801c | ||
|
|
71790b07b7 | ||
|
|
4ffe013165 | ||
|
|
6320ef1caa | ||
|
|
d10158c9fb | ||
|
|
92f1061db8 | ||
|
|
c8f18040f6 | ||
|
|
17b57ea852 | ||
|
|
b2a70b263a | ||
|
|
b3f0620f5b | ||
|
|
c95a8e058c | ||
|
|
ecf44498b8 | ||
|
|
2f92aa9645 | ||
|
|
e894b0db43 | ||
|
|
da65bbaa2d | ||
|
|
032509be15 | ||
|
|
c6f81668de | ||
|
|
43d0582b2f | ||
|
|
818ddad2c3 | ||
|
|
c8f79dbd2d | ||
|
|
1ceb3f0129 | ||
|
|
fe7911b944 | ||
|
|
0dcf8add63 | ||
|
|
ae2ea4f421 | ||
|
|
664d7a4f67 | ||
|
|
6e90b767ef | ||
|
|
268a2ea7ce | ||
|
|
854fef35cb | ||
|
|
b58556b6c3 | ||
|
|
97aaa36f7d | ||
|
|
07f111abbd | ||
|
|
3bb877cc3a | ||
|
|
17bcc9bfcc | ||
|
|
c7cd771de2 | ||
|
|
77e65f727f | ||
|
|
d793cdc797 | ||
|
|
4ec266ef11 | ||
|
|
fcc9532bde | ||
|
|
b4a191e27a | ||
|
|
973d40a877 | ||
|
|
ce3090b8fe | ||
|
|
f6662745d1 | ||
|
|
4289df1681 | ||
|
|
dad3c57fad | ||
|
|
8f4b94f732 | ||
|
|
76f8ca2116 | ||
|
|
94e5cda02d | ||
|
|
066b4f16a0 | ||
|
|
f3381b31ed | ||
|
|
15f4288e4a | ||
|
|
4569970bc4 | ||
|
|
b2e0b49556 | ||
|
|
03152d65ab | ||
|
|
96735d47c4 | ||
|
|
16266e3622 | ||
|
|
87ed7b7989 | ||
|
|
fef95f7cf1 | ||
|
|
36d1f7d06f | ||
|
|
33078a868c | ||
|
|
2a8700bca3 | ||
|
|
1e54111aad | ||
|
|
57003be3a3 | ||
|
|
f10177a352 | ||
|
|
939b87ffed | ||
|
|
6ccc58a060 | ||
|
|
08b2fbe30f | ||
|
|
cbd15f45a4 | ||
|
|
37dcc6c994 | ||
|
|
6249ff89ff | ||
|
|
07441b092c | ||
|
|
1c8535a2d5 | ||
|
|
047a2369b3 | ||
|
|
7585413e7d | ||
|
|
6e0ba1de33 | ||
|
|
661ea2cf45 | ||
|
|
bcee2a207d | ||
|
|
e94bf73cc3 | ||
|
|
03e8331e4f | ||
|
|
bbd5e55e5e | ||
|
|
212798ad19 | ||
|
|
bb0f6e0989 | ||
|
|
42fd3097de | ||
|
|
5952261e87 | ||
|
|
62d2e3e2a4 | ||
|
|
5843c6c569 | ||
|
|
352e784cad | ||
|
|
b8937e0349 | ||
|
|
0aea799b50 | ||
|
|
46766ec239 | ||
|
|
66bbc4d9fd | ||
|
|
40f2c593a2 | ||
|
|
30cb948dcf | ||
|
|
fceb512a03 | ||
|
|
4722054c3e | ||
|
|
9d1364b6fb | ||
|
|
5daceaead7 | ||
|
|
8a43699a89 | ||
|
|
3ef5dd20ef | ||
|
|
e9445866a5 | ||
|
|
cf931f8a9f | ||
|
|
3140257b69 | ||
|
|
b3d6e5876e | ||
|
|
c437f64f35 | ||
|
|
af91fb50b2 | ||
|
|
a35e194a2d | ||
|
|
42d9d0393d | ||
|
|
d319e837f5 | ||
|
|
a054a0d61d | ||
|
|
8e75da8540 | ||
|
|
975b13f868 | ||
|
|
75f80ae877 | ||
|
|
7c824d9da0 | ||
|
|
9aa7f80e82 | ||
|
|
b772c151fc | ||
|
|
d2e42c2a7d | ||
|
|
b54f92b2ae | ||
|
|
5ef241ae66 | ||
|
|
eb2e709749 | ||
|
|
06247266ad | ||
|
|
f9a5b62326 | ||
|
|
644faca306 | ||
|
|
9cb0723f8d | ||
|
|
48c99e796f | ||
|
|
fcf7069b25 | ||
|
|
415619021f | ||
|
|
88a45cf991 | ||
|
|
7eb85fe7aa | ||
|
|
0e5fe88b5e | ||
|
|
b754361268 | ||
|
|
419950ca49 | ||
|
|
11953cbb60 | ||
|
|
ecfc05bcc8 | ||
|
|
b0012b4d63 | ||
|
|
febaf49d07 | ||
|
|
e3f3287f14 | ||
|
|
fbd2879aa3 | ||
|
|
4db8faa526 | ||
|
|
586ea2ae0d | ||
|
|
e39648ce21 | ||
|
|
e0a05c5908 | ||
|
|
2c01fde713 | ||
|
|
82ebfd9945 | ||
|
|
92641c20f3 | ||
|
|
f145d98a12 | ||
|
|
a3d2c95d80 | ||
|
|
a5a9936e25 | ||
|
|
cfeb03740c | ||
|
|
4ab0fca4d7 | ||
|
|
df3b7e2dbc | ||
|
|
302b0cf776 | ||
|
|
e7cbacf9a2 | ||
|
|
f9817b12bf | ||
|
|
bbc7aedb48 | ||
|
|
4fdc11c6fb | ||
|
|
e1cb75fe04 | ||
|
|
0bf6d52eef | ||
|
|
7453198472 | ||
|
|
0c1120c1a8 | ||
|
|
efbc84d18b | ||
|
|
cdca1a46ef | ||
|
|
689f7dc8f3 | ||
|
|
4ca9349de7 | ||
|
|
9d6253455a | ||
|
|
388f868165 | ||
|
|
aacb39a439 | ||
|
|
298338f076 | ||
|
|
2d2915967c | ||
|
|
4572e1d344 | ||
|
|
f8b200f32c | ||
|
|
3d4addd9ef | ||
|
|
2919a60403 | ||
|
|
a07858cc72 | ||
|
|
d1d4674136 | ||
|
|
9b5d4b8ceb | ||
|
|
abe216a0bb | ||
|
|
84983c341e | ||
|
|
075423ee96 | ||
|
|
2ff77676e2 | ||
|
|
2da3373e10 | ||
|
|
1486eac752 | ||
|
|
c5adecb6e1 | ||
|
|
e4c4236386 | ||
|
|
e5e7e043ee | ||
|
|
f8d01b4312 | ||
|
|
f0a898c674 | ||
|
|
8b7bdb4957 | ||
|
|
bd46430434 | ||
|
|
a1635ccc68 | ||
|
|
1853fa6fae | ||
|
|
692f0792e1 | ||
|
|
bc222c60e0 | ||
|
|
96bbf0419c | ||
|
|
531e3d2765 | ||
|
|
02165786f1 | ||
|
|
a449223b40 | ||
|
|
12344ab486 | ||
|
|
b6e18d8a68 | ||
|
|
1a0677cb59 | ||
|
|
c483587853 | ||
|
|
9b25467080 | ||
|
|
f37fd15fca | ||
|
|
5092f52716 | ||
|
|
0013745783 | ||
|
|
ad5fa13339 | ||
|
|
e1fa5ecb34 | ||
|
|
e1512e3776 | ||
|
|
dab5252746 | ||
|
|
d8dd564b06 | ||
|
|
407b082780 | ||
|
|
a671093489 | ||
|
|
3ee61df319 | ||
|
|
c43b1f54c7 | ||
|
|
1a554828e1 | ||
|
|
974a0334df | ||
|
|
e7e7c7d5a0 | ||
|
|
29f0c0b311 | ||
|
|
955680018f | ||
|
|
686e85cd4f | ||
|
|
297d4e65fc | ||
|
|
0e94bf7e0b | ||
|
|
a5bc9625ef | ||
|
|
cbde4f89b2 | ||
|
|
891c108191 | ||
|
|
764d767789 | ||
|
|
7ded10cd8d | ||
|
|
3b05a16b32 | ||
|
|
cf49c8c6ff | ||
|
|
99bf4bc44d | ||
|
|
929639b06b | ||
|
|
c18b80c43f | ||
|
|
9ce83250da | ||
|
|
a9e31a2843 | ||
|
|
45496b7592 | ||
|
|
4075a5f4f7 | ||
|
|
2d4819257b | ||
|
|
406618677b | ||
|
|
4c72833f5a | ||
|
|
e3eaac5bef | ||
|
|
f10b13328f | ||
|
|
c609cd0ace | ||
|
|
0396a05b38 | ||
|
|
4a460e09b9 | ||
|
|
d5d81c1bed | ||
|
|
dc6e8f99d8 | ||
|
|
e02a8c9103 | ||
|
|
7b4941bde9 | ||
|
|
c602839e06 | ||
|
|
2aea6c4120 | ||
|
|
a937e025b5 | ||
|
|
b9fb510006 | ||
|
|
b3f66aea3b | ||
|
|
8491fbbd95 | ||
|
|
c6ec96aca5 | ||
|
|
d250623fde | ||
|
|
c3b4ecbbd8 | ||
|
|
2b84a149fe | ||
|
|
99ca38d13f | ||
|
|
bfc174ffdc | ||
|
|
09f7615a35 | ||
|
|
fdf0e39516 | ||
|
|
775f389e5c | ||
|
|
f811410b45 | ||
|
|
50e803f1a0 | ||
|
|
9a0d8616ed | ||
|
|
b4c9816d9f | ||
|
|
17e28069ab | ||
|
|
8562d3d55d | ||
|
|
d65479abc9 | ||
|
|
ed29db290e | ||
|
|
978c0f2f31 | ||
|
|
62c4ff719e | ||
|
|
e28f646cef | ||
|
|
fb63ed92a8 | ||
|
|
c0097d1e2b | ||
|
|
0683f94edb | ||
|
|
fe710d8de9 | ||
|
|
83546a899f | ||
|
|
2eca459ff6 | ||
|
|
6b23ad54db | ||
|
|
5ef7f38bed | ||
|
|
f86056c4f8 | ||
|
|
f19b364871 | ||
|
|
29f1d96d87 | ||
|
|
2f966b7da4 | ||
|
|
e3f599fbc0 | ||
|
|
76a7c7b426 | ||
|
|
4044e11da2 | ||
|
|
a07c21b2a3 | ||
|
|
109bedba75 | ||
|
|
aced860ba4 | ||
|
|
d33324c198 | ||
|
|
adb1b33441 | ||
|
|
238e1f1bea | ||
|
|
4c9b6ce193 | ||
|
|
5ef547d285 | ||
|
|
aea99b8ffb | ||
|
|
9ec120d7cb | ||
|
|
e2c5439112 | ||
|
|
19362d1904 | ||
|
|
1a69fd8a49 | ||
|
|
224670ed03 | ||
|
|
bb705e32d9 | ||
|
|
3e269978d9 | ||
|
|
9ba62c320b | ||
|
|
8e6d7d3960 | ||
|
|
3138748f57 | ||
|
|
6f10156bf3 | ||
|
|
3852b34397 | ||
|
|
3128628d09 | ||
|
|
d8c4c0627a | ||
|
|
d9559ecf63 | ||
|
|
2b492883ca | ||
|
|
5ab6c551df | ||
|
|
0e27f471f1 | ||
|
|
ba477ad720 | ||
|
|
7858c157c1 | ||
|
|
a5d3cc63c3 | ||
|
|
cac7ccf176 | ||
|
|
9693cba17a | ||
|
|
45e38ae4c9 | ||
|
|
ad68d535b4 | ||
|
|
bb56ea4b33 | ||
|
|
ba822eaeed | ||
|
|
7076ada6f4 | ||
|
|
84834dc4e6 | ||
|
|
f9b3f34593 | ||
|
|
c17576a931 | ||
|
|
570124058c | ||
|
|
3793119209 | ||
|
|
7fb18d1cb3 | ||
|
|
4fc86175e1 | ||
|
|
c951f7f3e9 | ||
|
|
777217bd75 | ||
|
|
2bb637e140 | ||
|
|
b5c1c95a15 | ||
|
|
f2e369cfc0 | ||
|
|
6329271731 | ||
|
|
1428559546 | ||
|
|
5c9a85e928 | ||
|
|
00355caf8d | ||
|
|
feb1d9d8e1 | ||
|
|
7f2fa9597c | ||
|
|
246ab88a3e | ||
|
|
49cc4ae087 | ||
|
|
8d466ad77f | ||
|
|
f824f78db9 | ||
|
|
35f592bb2c | ||
|
|
25a6728acc | ||
|
|
169da33411 | ||
|
|
db70cf4aa9 | ||
|
|
dcfab4401f | ||
|
|
d85a91ae49 | ||
|
|
a3b1a80658 | ||
|
|
db20f145fb | ||
|
|
986bfd02b3 | ||
|
|
57506934f2 | ||
|
|
372a5e2a49 | ||
|
|
726b972223 | ||
|
|
65300b34df | ||
|
|
d7a7733d30 | ||
|
|
7154fd4d39 | ||
|
|
45830c1086 | ||
|
|
202ad0542f | ||
|
|
c59d9e7c8b | ||
|
|
f4f0a7d90e | ||
|
|
ec98e6fdff | ||
|
|
c68bcb8fbc | ||
|
|
c37876a8b7 | ||
|
|
23a805b79c | ||
|
|
157bb1931d | ||
|
|
e59ad67055 | ||
|
|
97b9b67768 | ||
|
|
f899d16a79 | ||
|
|
53288fc997 | ||
|
|
7c89f2b7d1 | ||
|
|
2c39514359 | ||
|
|
536ffb31e0 | ||
|
|
a50a980de4 | ||
|
|
da0898a066 | ||
|
|
541f83cf71 | ||
|
|
fe6588516f | ||
|
|
6651168dd3 | ||
|
|
ced7da405d | ||
|
|
fd836560aa | ||
|
|
5654d34ee8 | ||
|
|
6302e42229 | ||
|
|
34a24ce290 | ||
|
|
71a778b65c | ||
|
|
62fa4dffa8 | ||
|
|
d3dd643a88 | ||
|
|
6116df9411 | ||
|
|
db0c4e95f7 | ||
|
|
9a25db34aa | ||
|
|
c7710bfe1c | ||
|
|
dd7502f8de | ||
|
|
df01358fb8 | ||
|
|
d3cd634bff | ||
|
|
1454a28a69 | ||
|
|
7251c7a641 | ||
|
|
06c636311d | ||
|
|
b457166726 | ||
|
|
562c2e38db | ||
|
|
e2c16c9c11 | ||
|
|
db91040443 | ||
|
|
9f3c209096 | ||
|
|
123b5abb08 | ||
|
|
6cb89891ce | ||
|
|
ff68caaa16 | ||
|
|
a58190a935 | ||
|
|
372278d163 | ||
|
|
a5a7b63abf | ||
|
|
e9b7aaea84 | ||
|
|
132d823f54 | ||
|
|
75eb30b09d | ||
|
|
baa60347fb | ||
|
|
8de3e0ff0b | ||
|
|
443c29f505 | ||
|
|
b309ef25fd | ||
|
|
0ea5175354 | ||
|
|
10517115c3 | ||
|
|
ddb356482f | ||
|
|
6ae35fb21d | ||
|
|
330597182c | ||
|
|
adefa40dcc | ||
|
|
8d162609e0 | ||
|
|
0a51ddd7ef | ||
|
|
c3ae8669e8 | ||
|
|
974ba47e3c | ||
|
|
9d170e4c59 | ||
|
|
ae0e950c16 | ||
|
|
79412f20ab | ||
|
|
7ea047cf1b | ||
|
|
4bf5d69002 | ||
|
|
0e2d8a323a | ||
|
|
9a4cee1818 | ||
|
|
b0957f387e | ||
|
|
1f8dc54368 | ||
|
|
74ece3a775 | ||
|
|
60f7b9ab93 | ||
|
|
f8d555790b | ||
|
|
4ff297730c | ||
|
|
29050ea917 | ||
|
|
c4c0bc1c37 | ||
|
|
0f52f4e5a1 | ||
|
|
cff7a5c2f5 | ||
|
|
626d9a40ed | ||
|
|
b8f26c58e3 | ||
|
|
9dbd9b8405 | ||
|
|
08f200f0eb | ||
|
|
9fa65ccda6 | ||
|
|
d0fa9e7ef1 | ||
|
|
d7c1976a52 | ||
|
|
39e71efb2f | ||
|
|
855bcf8fe3 | ||
|
|
97069f1dc6 | ||
|
|
bc3c6412f6 | ||
|
|
51dcb2befb | ||
|
|
805c9e4eda | ||
|
|
a38e85b39c | ||
|
|
96bd3a54cb | ||
|
|
4fd5fba768 | ||
|
|
06027ea8e5 | ||
|
|
6f38d58954 | ||
|
|
30c964f1e3 | ||
|
|
2a8e0bd866 | ||
|
|
644e12929c | ||
|
|
d625b8e3f3 | ||
|
|
5b884806d2 | ||
|
|
7aa47647f0 | ||
|
|
c779dbe8ad | ||
|
|
64ee01d831 | ||
|
|
52c6bbe731 | ||
|
|
1963972f75 | ||
|
|
85d0c62c1d | ||
|
|
dfa9bab9e1 | ||
|
|
3ed1532f25 | ||
|
|
115420db82 | ||
|
|
d2a6c4a97f | ||
|
|
c04874b087 | ||
|
|
a0b3018ea0 | ||
|
|
e46d45adea | ||
|
|
f977030bd6 | ||
|
|
38fc1c01d4 | ||
|
|
2f202deedf | ||
|
|
08bd40bb26 | ||
|
|
28700173a0 | ||
|
|
66a46fc580 | ||
|
|
de41977c77 | ||
|
|
45c420561a | ||
|
|
e240b15d61 | ||
|
|
486058834e | ||
|
|
3e473ea9d7 | ||
|
|
62dd54ab31 | ||
|
|
b3e02add3d | ||
|
|
7bf9a82f0b | ||
|
|
ce5ff20d5b | ||
|
|
615daa8c9f | ||
|
|
5dffddceec | ||
|
|
d5de49b5cf | ||
|
|
62f7553ba4 | ||
|
|
b7ad6b606a | ||
|
|
60c2ee41e3 | ||
|
|
64475143cf | ||
|
|
c1122eae3a | ||
|
|
1792b1ed85 | ||
|
|
d624f2584d | ||
|
|
f39f8d14fd | ||
|
|
770b003163 | ||
|
|
702b177e06 | ||
|
|
3c0295e294 | ||
|
|
970e8c764c | ||
|
|
1d393f5786 | ||
|
|
f03b228eea | ||
|
|
d149ba6fc5 | ||
|
|
f3dc6f15e4 | ||
|
|
8ca282079a | ||
|
|
769644a63f | ||
|
|
2cefea3677 | ||
|
|
2e802c0f6d | ||
|
|
d29e39c1d2 | ||
|
|
09fb5e5667 | ||
|
|
70e5ce7aec | ||
|
|
1f942aa13d | ||
|
|
b60095df28 | ||
|
|
6715d41f92 | ||
|
|
375b145030 | ||
|
|
9d3b2aee02 | ||
|
|
2d2e27b8d0 | ||
|
|
4b6ac38058 | ||
|
|
21c2469dd6 | ||
|
|
02f176c75a | ||
|
|
8b528b582f | ||
|
|
72d38ad202 | ||
|
|
7a5461e1cb | ||
|
|
1714ede6d4 | ||
|
|
f8ee97a71c | ||
|
|
897a6bfbe6 | ||
|
|
97237470af | ||
|
|
d79971a737 | ||
|
|
334f7bf95a | ||
|
|
661795fd51 | ||
|
|
47fe71c1f1 | ||
|
|
c5eebcda98 | ||
|
|
8deb003ef6 | ||
|
|
10b2746a3e | ||
|
|
62fd07e98e | ||
|
|
ee8a270a36 | ||
|
|
870a4e705b | ||
|
|
9dcb717a51 | ||
|
|
f72e3bf552 | ||
|
|
ef70ff7da0 | ||
|
|
61fa2d8ed1 | ||
|
|
1bda4ca61c | ||
|
|
ba00080462 | ||
|
|
57815cb2fe | ||
|
|
346ff889ea | ||
|
|
165507b83a | ||
|
|
955e01a750 | ||
|
|
ca62f9bec2 | ||
|
|
c82bf2a19c | ||
|
|
98919e0996 | ||
|
|
81437263b4 | ||
|
|
f883199f4f | ||
|
|
207e6e1b7d | ||
|
|
06911c4c75 | ||
|
|
fa1ea94c5c | ||
|
|
6b704f184b | ||
|
|
c2eede2bb5 | ||
|
|
0fec9565e5 | ||
|
|
8114152369 | ||
|
|
968521ef7c | ||
|
|
bdb4d019f8 | ||
|
|
c1a93afeaf | ||
|
|
b8d8ef5cfd | ||
|
|
07c2e91ae2 | ||
|
|
7e4b13fb44 | ||
|
|
69798848c0 | ||
|
|
9e52e65faa | ||
|
|
3d5af92c7a | ||
|
|
ed9fd6c8fd | ||
|
|
6c1349c501 | ||
|
|
6e34e33b0d | ||
|
|
5d9d6b4642 | ||
|
|
8196233ed2 | ||
|
|
c29f9921a1 | ||
|
|
f574dbe056 | ||
|
|
e6385bb95d | ||
|
|
ccdba03888 | ||
|
|
e257a3dfc9 | ||
|
|
448fcf36b6 | ||
|
|
48b219111d | ||
|
|
7f9c4d6480 | ||
|
|
064917886e | ||
|
|
0cf291d796 | ||
|
|
8418fc97f1 | ||
|
|
6170f6c268 | ||
|
|
4dd82b3376 | ||
|
|
9ce5e232bb | ||
|
|
318ab2c9dc | ||
|
|
29f06bbb77 | ||
|
|
c1807c3649 | ||
|
|
b270256a7a | ||
|
|
27586643c3 | ||
|
|
99e6453e09 | ||
|
|
eda11f4657 | ||
|
|
474155ce9d | ||
|
|
49e60a8b4f | ||
|
|
5e027e0a91 | ||
|
|
e2a7a66772 | ||
|
|
76017bcbe3 | ||
|
|
1eb915d312 | ||
|
|
3df47f0d72 | ||
|
|
cc5d563599 | ||
|
|
c5e7ca8a26 | ||
|
|
626b37b4fe | ||
|
|
c3338d3bf2 | ||
|
|
d34adb67dd | ||
|
|
ae543e68d6 | ||
|
|
50f261effc | ||
|
|
0736206722 | ||
|
|
9dc9dc3685 | ||
|
|
2bd600aeaf | ||
|
|
2c0d60a1f4 | ||
|
|
1f98fbb99f | ||
|
|
c9ebecbf10 |
6
.buckconfig
Normal file
6
.buckconfig
Normal file
@@ -0,0 +1,6 @@
|
||||
|
||||
[android]
|
||||
target = Google Inc.:Google APIs:23
|
||||
|
||||
[maven_repositories]
|
||||
central = https://repo1.maven.org/maven2
|
||||
@@ -8,3 +8,6 @@ indent_size = 4
|
||||
indent_style = space
|
||||
max_line_length = 80
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
[Makefile]
|
||||
indent_style = tab
|
||||
|
||||
12
.eslintignore
Normal file
12
.eslintignore
Normal file
@@ -0,0 +1,12 @@
|
||||
# The build artifacts of the jitsi-meet project.
|
||||
build/*
|
||||
|
||||
# Third-party source code which we (1) do not want to modify or (2) try to
|
||||
# modify as little as possible.
|
||||
flow-typed/*
|
||||
libs/*
|
||||
|
||||
# ESLint will by default ignore its own configuration file. However, there does
|
||||
# not seem to be a reason why we will want to risk being inconsistent with our
|
||||
# remaining JavaScript source code.
|
||||
!.eslintrc.js
|
||||
61
.eslintrc.js
Normal file
61
.eslintrc.js
Normal file
@@ -0,0 +1,61 @@
|
||||
module.exports = {
|
||||
'env': {
|
||||
'browser': true,
|
||||
'commonjs': true,
|
||||
'es6': true
|
||||
},
|
||||
'extends': [
|
||||
'eslint:recommended',
|
||||
'plugin:flowtype/recommended'
|
||||
],
|
||||
'globals': {
|
||||
// The globals that (1) are accessed but not defined within many of our
|
||||
// files, (2) are certainly defined, and (3) we would like to use
|
||||
// without explicitly specifying them (using a comment) inside of our
|
||||
// files.
|
||||
'__filename': false
|
||||
},
|
||||
'parser': 'babel-eslint',
|
||||
'parserOptions': {
|
||||
'ecmaFeatures': {
|
||||
'experimentalObjectRestSpread': true
|
||||
},
|
||||
'sourceType': 'module'
|
||||
},
|
||||
'plugins': [
|
||||
'flowtype'
|
||||
],
|
||||
'rules': {
|
||||
'indent': [
|
||||
'error',
|
||||
4,
|
||||
{
|
||||
'CallExpression': {
|
||||
arguments: 'off'
|
||||
},
|
||||
'FunctionDeclaration': {
|
||||
parameters: 2
|
||||
},
|
||||
'FunctionExpression': {
|
||||
parameters: 2
|
||||
},
|
||||
'MemberExpression': 'off',
|
||||
'SwitchCase': 0
|
||||
}
|
||||
],
|
||||
'new-cap': [
|
||||
'error',
|
||||
{
|
||||
'capIsNew': false // Behave like JSHint's newcap.
|
||||
}
|
||||
],
|
||||
// While it is considered a best practice to avoid using methods on
|
||||
// console in JavaScript that is designed to be executed in the browser
|
||||
// and ESLint includes the rule among its set of recommended rules, (1)
|
||||
// the general practice is to strip such calls before pushing to
|
||||
// production and (2) we prefer to utilize console in lib-jitsi-meet
|
||||
// (and jitsi-meet).
|
||||
'no-console': 'off',
|
||||
'semi': 'error'
|
||||
}
|
||||
};
|
||||
74
.flowconfig
Normal file
74
.flowconfig
Normal file
@@ -0,0 +1,74 @@
|
||||
[ignore]
|
||||
; We fork some components by platform
|
||||
.*/*[.]android.js
|
||||
|
||||
; Ignore "BUCK" generated dirs
|
||||
<PROJECT_ROOT>/\.buckd/
|
||||
|
||||
; Ignore unexpected extra "@providesModule"
|
||||
.*/node_modules/.*/node_modules/fbjs/.*
|
||||
|
||||
; Ignore duplicate module providers
|
||||
; For RN Apps installed via npm, "Libraries" folder is inside
|
||||
; "node_modules/react-native" but in the source repo it is in the root
|
||||
.*/Libraries/react-native/React.js
|
||||
.*/Libraries/react-native/ReactNative.js
|
||||
|
||||
; Ignore packages in node_modules which we (i.e. the jitsi-meet project) have
|
||||
; seen to cause errors and we have chosen not to fix.
|
||||
.*/node_modules/babel-.*
|
||||
.*/node_modules/bower/.*
|
||||
.*/node_modules/jsonlint/.*
|
||||
.*/node_modules/promise/index.js.flow
|
||||
.*/node_modules/styled-components/.*
|
||||
|
||||
.*/\.git/.*
|
||||
|
||||
[include]
|
||||
|
||||
[libs]
|
||||
node_modules/react-native/Libraries/react-native/react-native-interface.js
|
||||
node_modules/react-native/flow
|
||||
flow/
|
||||
|
||||
[options]
|
||||
emoji=true
|
||||
|
||||
module.system=haste
|
||||
|
||||
experimental.strict_type_args=true
|
||||
|
||||
; FIXME: munge_underscores should be false but right now there are some errors
|
||||
; if we change the value to false
|
||||
; Treats class properties with underscore as private. Disabled because currently
|
||||
; for us "_" can mean protected too.
|
||||
; munge_underscores=false
|
||||
munge_underscores=true
|
||||
|
||||
module.name_mapper='^[./a-zA-Z0-9$_-]+\.\(bmp\|gif\|jpg\|jpeg\|png\|psd\|svg\|webp\|m4v\|mov\|mp4\|mpeg\|mpg\|webm\|aac\|aiff\|caf\|m4a\|mp3\|wav\|html\|pdf\)$' -> 'RelativeImageStub'
|
||||
|
||||
suppress_type=$FlowIssue
|
||||
suppress_type=$FlowFixMe
|
||||
suppress_type=$FixMe
|
||||
|
||||
suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(>=0\\.\\(3[0-8]\\|[1-2][0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)
|
||||
suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(>=0\\.\\(3[0-8]\\|1[0-9]\\|[1-2][0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)?:? #[0-9]+
|
||||
suppress_comment=\\(.\\|\n\\)*\\$FlowFixedInNextDeploy
|
||||
suppress_comment=\\(.\\|\n\\)*\\$FlowDisableNextLine
|
||||
|
||||
unsafe.enable_getters_and_setters=true
|
||||
|
||||
; We (i.e. the jitsi-meet project) are using the haste module system on Web as
|
||||
; well, not only on React Native. Unfortunately, Flow does not support .web.js
|
||||
; by default. Override Flow's defaults to include .web.js as well. Technically,
|
||||
; we have .native.js as well so the choice of .web.js may lead to errors.
|
||||
; Practically though, it is a potential future problem that we do not have at
|
||||
; the time of this writing.
|
||||
module.file_ext=.web.js
|
||||
; Flow's defaults:
|
||||
module.file_ext=.js
|
||||
module.file_ext=.jsx
|
||||
module.file_ext=.json
|
||||
|
||||
[version]
|
||||
^0.38.0
|
||||
1
.gitattributes
vendored
1
.gitattributes
vendored
@@ -1,2 +1,3 @@
|
||||
*.bundle.js -text -diff
|
||||
*.pbxproj -text
|
||||
lib-jitsi-meet.js -text -diff
|
||||
|
||||
72
.gitignore
vendored
72
.gitignore
vendored
@@ -1,11 +1,71 @@
|
||||
node_modules
|
||||
*.swp
|
||||
.idea/
|
||||
*.iml
|
||||
.*.tmp
|
||||
deploy-local.sh
|
||||
libs/app.bundle.*
|
||||
libs/lib-jitsi-meet*
|
||||
libs/external_connect.js
|
||||
libs/
|
||||
all.css
|
||||
*css.map
|
||||
.remote-sync.json
|
||||
.sync-config.cson
|
||||
|
||||
# The following are automatically generated by the react-native command line
|
||||
# utility (either with the init or upgrade option which pull in the latest
|
||||
# template files recommended by Facebook for React Native).
|
||||
|
||||
# OSX
|
||||
#
|
||||
.DS_Store
|
||||
|
||||
# Xcode
|
||||
#
|
||||
build/
|
||||
*.pbxuser
|
||||
!default.pbxuser
|
||||
*.mode1v3
|
||||
!default.mode1v3
|
||||
*.mode2v3
|
||||
!default.mode2v3
|
||||
*.perspectivev3
|
||||
!default.perspectivev3
|
||||
xcuserdata
|
||||
*.xccheckout
|
||||
*.moved-aside
|
||||
DerivedData
|
||||
*.hmap
|
||||
*.ipa
|
||||
*.xcuserstate
|
||||
project.xcworkspace
|
||||
|
||||
# Android/IntelliJ
|
||||
#
|
||||
build/
|
||||
.idea
|
||||
.gradle
|
||||
local.properties
|
||||
*.iml
|
||||
|
||||
# node.js
|
||||
#
|
||||
node_modules/
|
||||
npm-debug.log
|
||||
yarn-error.log
|
||||
|
||||
# BUCK
|
||||
#
|
||||
buck-out/
|
||||
\.buckd/
|
||||
*.keystore
|
||||
|
||||
# fastlane
|
||||
#
|
||||
# It is recommended to not store the screenshots in the git repo. Instead, use
|
||||
# fastlane to re-generate the screenshots whenever they are needed. For more
|
||||
# information about the recommended setup visit:
|
||||
# https://github.com/fastlane/fastlane/blob/master/fastlane/docs/Gitignore.md
|
||||
#
|
||||
fastlane/report.xml
|
||||
fastlane/Preview.html
|
||||
fastlane/screenshots
|
||||
|
||||
# CocoaPods
|
||||
Pods/
|
||||
Podfile.lock
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
node_modules
|
||||
libs
|
||||
debian
|
||||
analytics.js
|
||||
20
.jshintrc
20
.jshintrc
@@ -1,20 +0,0 @@
|
||||
{
|
||||
// Refer to http://jshint.com/docs/options/ for an exhaustive list of options
|
||||
"asi": false, // true: Tolerate Automatic Semicolon Insertion (no semicolons)
|
||||
"expr": true, // true: Tolerate `ExpressionStatement` as Programs
|
||||
"loopfunc": true, // true: Tolerate functions being defined in loops
|
||||
"curly": false, // true: Require {} for every new block or scope
|
||||
"evil": true, // true: Tolerate use of `eval` and `new Function()`
|
||||
"white": true,
|
||||
"undef": true, // true: Require all non-global variables to be declared (prevents global leaks)
|
||||
"browser": true, // Web Browser (window, document, etc)
|
||||
"node": true, // Node.js
|
||||
"trailing": true,
|
||||
"indent": 4, // {int} Number of spaces to use for indentation
|
||||
"latedef": true, // true: Require variables/functions to be defined before being used
|
||||
"newcap": true, // true: Require capitalization of all constructor functions e.g. `new F()`
|
||||
"maxlen": 80, // {int} Max number of characters per line
|
||||
"latedef": false, //This option prohibits the use of a variable before it was defined
|
||||
"laxbreak": true, //Ignore line breaks around "=", "==", "&&", etc.
|
||||
"esnext": true //support ES2015
|
||||
}
|
||||
1
.watchmanconfig
Normal file
1
.watchmanconfig
Normal file
@@ -0,0 +1 @@
|
||||
{}
|
||||
29
CONTRIBUTING.md
Normal file
29
CONTRIBUTING.md
Normal file
@@ -0,0 +1,29 @@
|
||||
# How to contribute
|
||||
We would love to have your help. Before you start working however, please read
|
||||
and follow this short guide.
|
||||
|
||||
# Reporting Issues
|
||||
Provide as much information as possible. Mention the version of Jitsi Meet,
|
||||
Jicofo and JVB you are using, and explain (as detailed as you can) how the
|
||||
problem can be reproduced.
|
||||
|
||||
# Code contributions
|
||||
Found a bug and know how to fix it? Great! Please read on.
|
||||
|
||||
## Contributor License Agreement
|
||||
While the Jitsi projects are released under the
|
||||
[Apache License 2.0](https://github.com/jitsi/jitsi-meet/blob/master/LICENSE), the copyright
|
||||
holder and principal creator is [Atlassian](https://www.atlassian.com/). To
|
||||
ensure that we can continue making these projects available under an Open Source license,
|
||||
we need you to sign our Apache-based contributor
|
||||
license agreement as either a [corporation](https://jitsi.org/ccla) or an
|
||||
[individual](https://jitsi.org/icla). If you cannot accept the terms laid out
|
||||
in the agreement, unfortunately, we cannot accept your contribution.
|
||||
|
||||
## Creating Pull Requests
|
||||
- Make sure your code passes the linter rules beforehand. The linter is exeuted
|
||||
automatically when committing code.
|
||||
- Perform **one** logical change per pull request.
|
||||
- Maintain a clean list of commits, squash them if necessary.
|
||||
- Rebase your topic branch on top of the master branch before creating the pull
|
||||
request.
|
||||
11
ConferenceEvents.js
Normal file
11
ConferenceEvents.js
Normal file
@@ -0,0 +1,11 @@
|
||||
/**
|
||||
* Notifies interested parties that hangup procedure will start.
|
||||
*/
|
||||
export const BEFORE_HANGUP = "conference.before_hangup";
|
||||
|
||||
/**
|
||||
* Notifies interested parties that desktop sharing enable/disable state is
|
||||
* changed.
|
||||
*/
|
||||
export const DESKTOP_SHARING_ENABLED_CHANGED
|
||||
= "conference.desktop_sharing_enabled_changed";
|
||||
58
Makefile
58
Makefile
@@ -1,24 +1,22 @@
|
||||
NPM = npm
|
||||
BROWSERIFY = ./node_modules/.bin/browserify
|
||||
UGLIFYJS = ./node_modules/.bin/uglifyjs
|
||||
EXORCIST = ./node_modules/.bin/exorcist
|
||||
BUILD_DIR = build
|
||||
CLEANCSS = ./node_modules/.bin/cleancss
|
||||
CSS_FILES = font.css toastr.css main.css videolayout_default.css font-awesome.css jquery-impromptu.css modaldialog.css notice.css popup_menu.css login_menu.css popover.css jitsi_popover.css contact_list.css chat.css welcome_page.css settingsmenu.css feedback.css
|
||||
DEPLOY_DIR = libs
|
||||
BROWSERIFY_FLAGS = -d
|
||||
OUTPUT_DIR = .
|
||||
LIBJITSIMEET_DIR = node_modules/lib-jitsi-meet/
|
||||
NODE_SASS = ./node_modules/.bin/node-sass
|
||||
NPM = npm
|
||||
OUTPUT_DIR = .
|
||||
STYLES_BUNDLE = css/all.bundle.css
|
||||
STYLES_DESTINATION = css/all.css
|
||||
STYLES_MAIN = css/main.scss
|
||||
WEBPACK = ./node_modules/.bin/webpack
|
||||
|
||||
all: update-deps compile uglify deploy clean
|
||||
|
||||
update-deps:
|
||||
$(NPM) update
|
||||
all: compile deploy clean
|
||||
|
||||
compile:
|
||||
$(BROWSERIFY) $(BROWSERIFY_FLAGS) -e app.js -s APP | $(EXORCIST) $(OUTPUT_DIR)/app.bundle.js.map > $(OUTPUT_DIR)/app.bundle.js
|
||||
$(WEBPACK) -p
|
||||
|
||||
clean:
|
||||
rm -f $(OUTPUT_DIR)/app.bundle.*
|
||||
rm -fr $(BUILD_DIR)
|
||||
|
||||
deploy: deploy-init deploy-appbundle deploy-lib-jitsi-meet deploy-css deploy-local
|
||||
|
||||
@@ -26,28 +24,36 @@ deploy-init:
|
||||
mkdir -p $(DEPLOY_DIR)
|
||||
|
||||
deploy-appbundle:
|
||||
cp $(OUTPUT_DIR)/app.bundle.min.js $(OUTPUT_DIR)/app.bundle.min.map \
|
||||
$(DEPLOY_DIR)
|
||||
cp \
|
||||
$(BUILD_DIR)/app.bundle.min.js \
|
||||
$(BUILD_DIR)/app.bundle.min.map \
|
||||
$(BUILD_DIR)/do_external_connect.min.js \
|
||||
$(BUILD_DIR)/do_external_connect.min.map \
|
||||
$(BUILD_DIR)/external_api.min.js \
|
||||
$(BUILD_DIR)/external_api.min.map \
|
||||
$(BUILD_DIR)/device_selection_popup_bundle.min.js \
|
||||
$(BUILD_DIR)/device_selection_popup_bundle.min.map \
|
||||
$(OUTPUT_DIR)/analytics.js \
|
||||
$(DEPLOY_DIR)
|
||||
|
||||
deploy-lib-jitsi-meet:
|
||||
cp $(LIBJITSIMEET_DIR)/lib-jitsi-meet.min.js \
|
||||
$(LIBJITSIMEET_DIR)/lib-jitsi-meet.min.map \
|
||||
$(LIBJITSIMEET_DIR)/connection_optimization/external_connect.js \
|
||||
$(DEPLOY_DIR)
|
||||
cp \
|
||||
$(LIBJITSIMEET_DIR)/lib-jitsi-meet.min.js \
|
||||
$(LIBJITSIMEET_DIR)/lib-jitsi-meet.min.map \
|
||||
$(LIBJITSIMEET_DIR)/connection_optimization/external_connect.js \
|
||||
$(DEPLOY_DIR)
|
||||
|
||||
deploy-css:
|
||||
(cd css; cat $(CSS_FILES)) | $(CLEANCSS) > css/all.css
|
||||
$(NODE_SASS) $(STYLES_MAIN) $(STYLES_BUNDLE) && \
|
||||
$(CLEANCSS) $(STYLES_BUNDLE) > $(STYLES_DESTINATION) ; \
|
||||
rm $(STYLES_BUNDLE)
|
||||
|
||||
deploy-local:
|
||||
([ ! -x deploy-local.sh ] || ./deploy-local.sh)
|
||||
|
||||
uglify:
|
||||
$(UGLIFYJS) -p relative $(OUTPUT_DIR)/app.bundle.js -o $(OUTPUT_DIR)/app.bundle.min.js --source-map $(OUTPUT_DIR)/app.bundle.min.map --in-source-map $(OUTPUT_DIR)/app.bundle.js.map
|
||||
|
||||
|
||||
source-package:
|
||||
mkdir -p source_package/jitsi-meet/css && \
|
||||
cp -r *.js connection_optimization favicon.ico fonts images index.html libs plugin.*html sounds title.html unsupported_browser.html LICENSE lang source_package/jitsi-meet && \
|
||||
cp -r *.js *.html connection_optimization favicon.ico fonts images libs static sounds LICENSE lang source_package/jitsi-meet && \
|
||||
cp css/all.css source_package/jitsi-meet/css && \
|
||||
cp css/unsupported_browser.css source_package/jitsi-meet/css && \
|
||||
(cd source_package ; tar cjf ../jitsi-meet.tar.bz2 jitsi-meet) && \
|
||||
rm -rf source_package
|
||||
|
||||
37
README.md
37
README.md
@@ -1,5 +1,5 @@
|
||||
Jitsi Meet - Secure, Simple and Scalable Video Conferences
|
||||
====
|
||||
# Jitsi Meet - Secure, Simple and Scalable Video Conferences
|
||||
|
||||
Jitsi Meet is an open-source (Apache) WebRTC JavaScript application that uses [Jitsi Videobridge](https://jitsi.org/videobridge) to provide high quality, scalable video conferences. You can see [Jitsi Meet in action](http://youtu.be/7vFUVClsNh0) here at the session #482 of the VoIP Users Conference.
|
||||
|
||||
You can also try it out yourself at https://meet.jit.si .
|
||||
@@ -12,9 +12,23 @@ Installing Jitsi Meet is quite a simple experience. For Debian-based systems, we
|
||||
|
||||
For other systems, or if you wish to install all components manually, see the [detailed manual installation instructions](https://github.com/jitsi/jitsi-meet/blob/master/doc/manual-install.md).
|
||||
|
||||
## Download
|
||||
|
||||
You can download Debian/Ubuntu binaries:
|
||||
* [stable](https://download.jitsi.org/stable/) ([instructions](https://jitsi.org/downloads/ubuntu-debian-installations-instructions/))
|
||||
* [testing](https://download.jitsi.org/testing/) ([instructions](https://jitsi.org/downloads/ubuntu-debian-installations-instructions-for-testing/))
|
||||
* [nightly](https://download.jitsi.org/unstable/) ([instructions](https://jitsi.org/downloads/ubuntu-debian-installations-instructions-nightly/))
|
||||
|
||||
You can download source archives (produced by ```make source-package```):
|
||||
* [source builds](https://download.jitsi.org/jitsi-meet/src/)
|
||||
|
||||
You can get our mobile versions from here:
|
||||
* [Android](https://play.google.com/store/apps/details?id=org.jitsi.meet)
|
||||
* [iOS](https://itunes.apple.com/us/app/jitsi-meet/id1165103905)
|
||||
|
||||
## Building the sources
|
||||
|
||||
Jitsi Meet uses [Browserify](http://browserify.org). If you want to make changes in the code you need to [install Browserify](http://browserify.org/#install). Browserify requires [nodejs](http://nodejs.org).
|
||||
Node.js >= 6 is required.
|
||||
|
||||
On Debian/Ubuntu systems, the required packages can be installed with:
|
||||
```
|
||||
@@ -28,7 +42,7 @@ To build the Jitsi Meet application, just type
|
||||
make
|
||||
```
|
||||
|
||||
## Working with the library sources(lib-jitsi-meet).
|
||||
## Working with the library sources (lib-jitsi-meet)
|
||||
|
||||
By default the library is build from its git repository sources. The default dependency path in package.json is :
|
||||
```json
|
||||
@@ -66,6 +80,7 @@ npm link lib-jitsi-meet
|
||||
```
|
||||
|
||||
So now after changes in local `lib-jitsi-meet` repository you can rebuild it with `npm run install` and your `jitsi-meet` repository will use that modified library.
|
||||
Note: when using node version 4.x, the make file of jitsi-meet do npm update which will delete the link, no longer the case with version 6.x.
|
||||
|
||||
If you do not want to use local repository anymore you should run
|
||||
```bash
|
||||
@@ -74,8 +89,18 @@ npm unlink lib-jitsi-meet
|
||||
npm install
|
||||
```
|
||||
|
||||
## Discuss
|
||||
Please use the [Jitsi dev mailing list](http://lists.jitsi.org/pipermail/dev/) to discuss feature requests before opening an issue on Github.
|
||||
## Contributing
|
||||
|
||||
If you are looking to contribute to Jitsi Meet, first of all, thank you! Please
|
||||
see our [guidelines for contributing](CONTRIBUTING.md).
|
||||
|
||||
## Embedding in external applications
|
||||
|
||||
Jitsi Meet provides a very flexible way of embedding it in external applications by using the [Jitsi Meet API](doc/api.md).
|
||||
|
||||
## Mobile app
|
||||
Jitsi Meet is also available as a React Native app for Android and iOS.
|
||||
Instructions on how to build it can be found [here](doc/mobile.md).
|
||||
|
||||
## Acknowledgements
|
||||
|
||||
|
||||
26
analytics.js
26
analytics.js
@@ -1,5 +1,10 @@
|
||||
/* global ga */
|
||||
/* eslint-disable indent */
|
||||
|
||||
(function (ctx) {
|
||||
function Analytics() {
|
||||
/* eslint-disable semi */
|
||||
|
||||
/**
|
||||
* Google Analytics
|
||||
*/
|
||||
@@ -8,11 +13,26 @@
|
||||
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
|
||||
ga('create', 'UA-319188-14', 'jit.si');
|
||||
ga('send', 'pageview');
|
||||
|
||||
/* eslint-enable semi */
|
||||
}
|
||||
|
||||
Analytics.prototype.sendEvent = function (action, data) {
|
||||
ga('send', 'event', 'jit.si', action);
|
||||
// empty label if missing value for it and add the value,
|
||||
// the value should be integer or null
|
||||
var value = data.value;
|
||||
value = value? Math.round(parseFloat(value)) : null;
|
||||
var label = data.label || "";
|
||||
|
||||
ga('send', 'event', 'jit.si',
|
||||
action + '.' + data.browserName, label, value);
|
||||
};
|
||||
|
||||
ctx.Analytics = Analytics;
|
||||
}(window));
|
||||
if (typeof ctx.JitsiMeetJS === "undefined")
|
||||
ctx.JitsiMeetJS = {};
|
||||
if (typeof ctx.JitsiMeetJS.app === "undefined")
|
||||
ctx.JitsiMeetJS.app = {};
|
||||
if (typeof ctx.JitsiMeetJS.app.analyticsHandlers === "undefined")
|
||||
ctx.JitsiMeetJS.app.analyticsHandlers = [];
|
||||
ctx.JitsiMeetJS.app.analyticsHandlers.push(Analytics);
|
||||
}(window));
|
||||
|
||||
288
android/README.md
Normal file
288
android/README.md
Normal file
@@ -0,0 +1,288 @@
|
||||
# Jitsi Meet SDK for Android
|
||||
|
||||
## Build
|
||||
|
||||
1. Install all required [dependencies](https://github.com/jitsi/jitsi-meet/blob/master/doc/mobile.md).
|
||||
|
||||
2. ```bash
|
||||
cd android/
|
||||
./gradlew :sdk:assembleRelease
|
||||
```
|
||||
|
||||
3. ```bash
|
||||
./gradlew :sdk:publish
|
||||
cd ../
|
||||
```
|
||||
|
||||
## Install
|
||||
|
||||
Add the Maven repository
|
||||
`https://github.com/jitsi/jitsi-maven-repository/raw/master/releases` and the
|
||||
dependency `org.jitsi.react:jitsi-meet-sdk:1.9.0` into your `build.gradle`.
|
||||
|
||||
## API
|
||||
|
||||
Jitsi Meet SDK is an Android library which embodies the whole Jitsi Meet
|
||||
experience and makes it reusable by third-party apps.
|
||||
|
||||
To get started, extends your `android.app.Activity` from
|
||||
`org.jitsi.meet.sdk.JitsiMeetActivity`:
|
||||
|
||||
```java
|
||||
package org.jitsi.example;
|
||||
|
||||
import org.jitsi.meet.sdk.JitsiMeetActivity;
|
||||
|
||||
public class MainActivity extends JitsiMeetActivity {
|
||||
}
|
||||
```
|
||||
|
||||
Alternatively, you can use the `org.jitsi.meet.sdk.JitsiMeetView` class which
|
||||
extends `android.view.View`:
|
||||
|
||||
```java
|
||||
package org.jitsi.example;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
|
||||
import org.jitsi.meet.sdk.JitsiMeetView;
|
||||
|
||||
public class MainActivity extends AppCompatActivity {
|
||||
private JitsiMeetView view;
|
||||
|
||||
@Override
|
||||
public void onBackPressed() {
|
||||
if (!JitsiMeetView.onBackPressed()) {
|
||||
// Invoke the default handler if it wasn't handled by React.
|
||||
super.onBackPressed();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
view = new JitsiMeetView(this);
|
||||
view.loadURL(null);
|
||||
|
||||
setContentView(view);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
super.onDestroy();
|
||||
|
||||
view.dispose();
|
||||
view = null;
|
||||
|
||||
JitsiMeetView.onHostDestroy(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNewIntent(Intent intent) {
|
||||
JitsiMeetView.onNewIntent(intent);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPause() {
|
||||
super.onPause();
|
||||
|
||||
JitsiMeetView.onHostPause(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
|
||||
JitsiMeetView.onHostResume(this);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### JitsiMeetActivity
|
||||
|
||||
This class encapsulates a high level API in the form of an Android `Activity`
|
||||
which displays a single `JitsiMeetView`.
|
||||
|
||||
#### getDefaultURL()
|
||||
|
||||
See JitsiMeetView.getDefaultURL.
|
||||
|
||||
#### getWelcomePageEnabled()
|
||||
|
||||
See JitsiMeetView.getWelcomePageEnabled.
|
||||
|
||||
#### loadURL(URL)
|
||||
|
||||
See JitsiMeetView.loadURL.
|
||||
|
||||
#### setDefaultURL(URL)
|
||||
|
||||
See JitsiMeetView.setDefaultURL.
|
||||
|
||||
#### setWelcomePageEnabled(boolean)
|
||||
|
||||
See JitsiMeetView.setWelcomePageEnabled.
|
||||
|
||||
### JitsiMeetView
|
||||
|
||||
The `JitsiMeetView` class is the core of Jitsi Meet SDK. It's designed to
|
||||
display a Jitsi Meet conference (or a welcome page).
|
||||
|
||||
#### dispose()
|
||||
|
||||
Releases all resources associated with this view. This method MUST be called
|
||||
when the Activity holding this view is going to be destroyed, usually in the
|
||||
`onDestroy()` method.
|
||||
|
||||
#### getDefaultURL()
|
||||
|
||||
Returns the default base URL used to join a conference when a partial URL (e.g.
|
||||
a room name only) is specified to `loadURLString`/`loadURLObject`. If not set or
|
||||
if set to `null`, the default built in JavaScript is used: https://meet.jit.si.
|
||||
|
||||
#### getListener()
|
||||
|
||||
Returns the `JitsiMeetViewListener` instance attached to the view.
|
||||
|
||||
#### getWelcomePageEnabled()
|
||||
|
||||
Returns true if the Welcome page is enabled; otherwise, false. If false, a black
|
||||
empty view will be rendered when not in a conference. Defaults to false.
|
||||
|
||||
#### loadURL(URL)
|
||||
|
||||
Loads a specific URL which may identify a conference to join. If the specified
|
||||
URL is null and the Welcome page is enabled, the Welcome page is displayed
|
||||
instead.
|
||||
|
||||
#### loadURLString(String)
|
||||
|
||||
Loads a specific URL which may identify a conference to join. If the specified
|
||||
URL is null and the Welcome page is enabled, the Welcome page is displayed
|
||||
instead.
|
||||
|
||||
#### loadURLObject(Bundle)
|
||||
|
||||
Loads a specific URL which may identify a conference to join. The URL is
|
||||
specified in the form of a Bundle of properties which (1) internally are
|
||||
sufficient to construct a URL (string) while (2) abstracting the specifics of
|
||||
constructing the URL away from API clients/consumers. If the specified URL is
|
||||
null and the Welcome page is enabled, the Welcome page is displayed instead.
|
||||
|
||||
Example:
|
||||
|
||||
```java
|
||||
Bundle config = new Bundle();
|
||||
config.putBoolean("startWithAudioMuted", true);
|
||||
config.putBoolean("startWithVideoMuted", false);
|
||||
Bundle urlObject = new Bundle();
|
||||
urlObject.putBundle("config", config);
|
||||
urlObject.putString("url", "https://meet.jit.si/Test123");
|
||||
view.loadURLObject(urlObject);
|
||||
```
|
||||
|
||||
#### setDefaultURL(URL)
|
||||
|
||||
Sets the default URL. See `getDefaultURL` for more information.
|
||||
|
||||
NOTE: Must be called before `loadURL`/`loadURLString` for it to take effect.
|
||||
|
||||
#### setListener(listener)
|
||||
|
||||
Sets the given listener (class implementing the `JitsiMeetViewListener`
|
||||
interface) on the view.
|
||||
|
||||
#### setWelcomePageEnabled(boolean)
|
||||
|
||||
Sets whether the Welcome page is enabled. See `getWelcomePageEnabled` for more
|
||||
information.
|
||||
|
||||
NOTE: Must be called before `loadURL`/`loadURLString` for it to take effect.
|
||||
|
||||
#### onBackPressed()
|
||||
|
||||
Helper method which should be called from the activity's `onBackPressed` method.
|
||||
If this function returns `true`, it means the action was handled and thus no
|
||||
extra processing is required; otherwise the app should call the parent's
|
||||
`onBackPressed` method.
|
||||
|
||||
This is a static method.
|
||||
|
||||
#### onHostDestroy(activity)
|
||||
|
||||
Helper method which should be called from the activity's `onDestroy` method.
|
||||
|
||||
This is a static method.
|
||||
|
||||
#### onHostPause(activity)
|
||||
|
||||
Helper method which should be called from the activity's `onPause` method.
|
||||
|
||||
This is a static method.
|
||||
|
||||
#### onHostResume(activity)
|
||||
|
||||
Helper method which should be called from the activity's `onResume` method.
|
||||
|
||||
This is a static method.
|
||||
|
||||
#### onNewIntent(intent)
|
||||
|
||||
Helper method for integrating the *deep linking* functionality. If your app's
|
||||
activity is launched in "singleTask" mode this method should be called from the
|
||||
activity's `onNewIntent` method.
|
||||
|
||||
This is a static method.
|
||||
|
||||
#### JitsiMeetViewListener
|
||||
|
||||
`JitsiMeetViewListener` provides an interface apps can implement to listen to
|
||||
the state of the Jitsi Meet conference displayed in a `JitsiMeetView`.
|
||||
|
||||
### JitsiMeetViewAdapter
|
||||
|
||||
A default implementation of the `JitsiMeetViewListener` interface. Apps may
|
||||
extend the class instead of implementing the interface in order to minimize
|
||||
boilerplate.
|
||||
|
||||
##### onConferenceFailed
|
||||
|
||||
Called when a joining a conference was unsuccessful or when there was an error
|
||||
while in a conference.
|
||||
|
||||
The `data` `Map` contains an "error" key describing the error and a "url" key
|
||||
with the conference URL.
|
||||
|
||||
#### onConferenceJoined
|
||||
|
||||
Called when a conference was joined.
|
||||
|
||||
The `data` `Map` contains a "url" key with the conference URL.
|
||||
|
||||
#### onConferenceLeft
|
||||
|
||||
Called when a conference was left.
|
||||
|
||||
The `data` `Map` contains a "url" key with the conference URL.
|
||||
|
||||
#### onConferenceWillJoin
|
||||
|
||||
Called before a conference is joined.
|
||||
|
||||
The `data` `Map` contains a "url" key with the conference URL.
|
||||
|
||||
#### onConferenceWillLeave
|
||||
|
||||
Called before a conference is left.
|
||||
|
||||
The `data` `Map` contains a "url" key with the conference URL.
|
||||
|
||||
#### onLoadConfigError
|
||||
|
||||
Called when loading the main configuration file from the Jitsi Meet deployment
|
||||
fails.
|
||||
|
||||
The `data` `Map` contains an "error" key with the error and a "url" key with the
|
||||
conference URL which necessitated the loading of the configuration file.
|
||||
40
android/app/build.gradle
Normal file
40
android/app/build.gradle
Normal file
@@ -0,0 +1,40 @@
|
||||
apply plugin: 'com.android.application'
|
||||
|
||||
android {
|
||||
compileSdkVersion rootProject.ext.compileSdkVersion
|
||||
|
||||
defaultConfig {
|
||||
applicationId 'org.jitsi.meet'
|
||||
versionCode Integer.parseInt("${version}")
|
||||
versionName "1.9.${version}"
|
||||
|
||||
minSdkVersion rootProject.ext.minSdkVersion
|
||||
targetSdkVersion rootProject.ext.targetSdkVersion
|
||||
|
||||
ndk {
|
||||
abiFilters 'armeabi-v7a', 'x86'
|
||||
}
|
||||
|
||||
packagingOptions {
|
||||
// The project react-native does not provide 64-bit binaries at the
|
||||
// time of this writing. Unfortunately, packaging any 64-bit
|
||||
// binaries into the .apk will crash the app at runtime on 64-bit
|
||||
// platforms.
|
||||
exclude '/lib/mips64/**'
|
||||
exclude '/lib/arm64-v8a/**'
|
||||
exclude '/lib/x86_64/**'
|
||||
}
|
||||
}
|
||||
buildTypes {
|
||||
release {
|
||||
minifyEnabled false
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compile fileTree(dir: 'libs', include: ['*.jar'])
|
||||
|
||||
implementation project(':sdk')
|
||||
}
|
||||
66
android/app/proguard-rules.pro
vendored
Normal file
66
android/app/proguard-rules.pro
vendored
Normal file
@@ -0,0 +1,66 @@
|
||||
# Add project specific ProGuard rules here.
|
||||
# By default, the flags in this file are appended to flags specified
|
||||
# in /usr/local/Cellar/android-sdk/24.3.3/tools/proguard/proguard-android.txt
|
||||
# You can edit the include path and order by changing the proguardFiles
|
||||
# directive in build.gradle.
|
||||
#
|
||||
# For more details, see
|
||||
# http://developer.android.com/guide/developing/tools/proguard.html
|
||||
|
||||
# Add any project specific keep options here:
|
||||
|
||||
# If your project uses WebView with JS, uncomment the following
|
||||
# and specify the fully qualified class name to the JavaScript interface
|
||||
# class:
|
||||
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
|
||||
# public *;
|
||||
#}
|
||||
|
||||
# Disabling obfuscation is useful if you collect stack traces from production crashes
|
||||
# (unless you are using a system that supports de-obfuscate the stack traces).
|
||||
-dontobfuscate
|
||||
|
||||
# React Native
|
||||
|
||||
# Keep our interfaces so they can be used by other ProGuard rules.
|
||||
# See http://sourceforge.net/p/proguard/bugs/466/
|
||||
-keep,allowobfuscation @interface com.facebook.proguard.annotations.DoNotStrip
|
||||
-keep,allowobfuscation @interface com.facebook.proguard.annotations.KeepGettersAndSetters
|
||||
-keep,allowobfuscation @interface com.facebook.common.internal.DoNotStrip
|
||||
|
||||
# Do not strip any method/class that is annotated with @DoNotStrip
|
||||
-keep @com.facebook.proguard.annotations.DoNotStrip class *
|
||||
-keep @com.facebook.common.internal.DoNotStrip class *
|
||||
-keepclassmembers class * {
|
||||
@com.facebook.proguard.annotations.DoNotStrip *;
|
||||
@com.facebook.common.internal.DoNotStrip *;
|
||||
}
|
||||
|
||||
-keepclassmembers @com.facebook.proguard.annotations.KeepGettersAndSetters class * {
|
||||
void set*(***);
|
||||
*** get*();
|
||||
}
|
||||
|
||||
-keep class * extends com.facebook.react.bridge.JavaScriptModule { *; }
|
||||
-keep class * extends com.facebook.react.bridge.NativeModule { *; }
|
||||
-keepclassmembers,includedescriptorclasses class * { native <methods>; }
|
||||
-keepclassmembers class * { @com.facebook.react.uimanager.UIProp <fields>; }
|
||||
-keepclassmembers class * { @com.facebook.react.uimanager.annotations.ReactProp <methods>; }
|
||||
-keepclassmembers class * { @com.facebook.react.uimanager.annotations.ReactPropGroup <methods>; }
|
||||
|
||||
-dontwarn com.facebook.react.**
|
||||
|
||||
# okhttp
|
||||
|
||||
-keepattributes Signature
|
||||
-keepattributes *Annotation*
|
||||
-keep class okhttp3.** { *; }
|
||||
-keep interface okhttp3.** { *; }
|
||||
-dontwarn okhttp3.**
|
||||
|
||||
# okio
|
||||
|
||||
-keep class sun.misc.Unsafe { *; }
|
||||
-dontwarn java.nio.file.*
|
||||
-dontwarn org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement
|
||||
-dontwarn okio.**
|
||||
38
android/app/src/main/AndroidManifest.xml
Normal file
38
android/app/src/main/AndroidManifest.xml
Normal file
@@ -0,0 +1,38 @@
|
||||
<manifest
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="org.jitsi.meet">
|
||||
<application
|
||||
android:allowBackup="true"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:label="@string/app_name"
|
||||
android:theme="@style/AppTheme">
|
||||
<activity
|
||||
android:configChanges="keyboard|keyboardHidden|orientation|screenSize"
|
||||
android:label="@string/app_name"
|
||||
android:launchMode="singleTask"
|
||||
android:name=".MainActivity"
|
||||
android:windowSoftInputMode="adjustResize">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<data android:host="beta.hipchat.me" android:scheme="https" />
|
||||
<data android:host="beta.meet.jit.si" android:scheme="https" />
|
||||
<data android:host="chaos.hipchat.me" android:scheme="https" />
|
||||
<data android:host="enso.me" android:scheme="https" />
|
||||
<data android:host="hipchat.me" android:scheme="https" />
|
||||
<data android:host="meet.jit.si" android:scheme="https" />
|
||||
</intent-filter>
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<data android:scheme="org.jitsi.meet" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
</application>
|
||||
</manifest>
|
||||
105
android/app/src/main/java/org/jitsi/meet/MainActivity.java
Normal file
105
android/app/src/main/java/org/jitsi/meet/MainActivity.java
Normal file
@@ -0,0 +1,105 @@
|
||||
/*
|
||||
* Copyright @ 2017-present Atlassian Pty Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jitsi.meet;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
|
||||
import org.jitsi.meet.sdk.JitsiMeetActivity;
|
||||
import org.jitsi.meet.sdk.JitsiMeetView;
|
||||
import org.jitsi.meet.sdk.JitsiMeetViewListener;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* The one and only {@link Activity} that the Jitsi Meet app needs. The
|
||||
* {@code Activity} is launched in {@code singleTask} mode, so it will be
|
||||
* created upon application initialization and there will be a single instance
|
||||
* of it. Further attempts at launching the application once it was already
|
||||
* launched will result in {@link Activity#onNewIntent(Intent)} being called.
|
||||
*
|
||||
* This {@code Activity} extends {@link JitsiMeetActivity} to keep the React
|
||||
* Native CLI working, since the latter always tries to launch an
|
||||
* {@code Activity} named {@code MainActivity} when doing
|
||||
* {@code react-native run-android}.
|
||||
*/
|
||||
public class MainActivity extends JitsiMeetActivity {
|
||||
@Override
|
||||
protected JitsiMeetView initializeView() {
|
||||
JitsiMeetView view = super.initializeView();
|
||||
|
||||
// XXX In order to increase (1) awareness of API breakages and (2) API
|
||||
// coverage, utilize JitsiMeetViewListener in the Debug configuration of
|
||||
// the app.
|
||||
if (BuildConfig.DEBUG && view != null) {
|
||||
view.setListener(new JitsiMeetViewListener() {
|
||||
private void on(String name, Map<String, Object> data) {
|
||||
// Log with the tag "ReactNative" in order to have the log
|
||||
// visible in react-native log-android as well.
|
||||
Log.d(
|
||||
"ReactNative",
|
||||
JitsiMeetViewListener.class.getSimpleName() + " "
|
||||
+ name + " "
|
||||
+ data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConferenceFailed(Map<String, Object> data) {
|
||||
on("CONFERENCE_FAILED", data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConferenceJoined(Map<String, Object> data) {
|
||||
on("CONFERENCE_JOINED", data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConferenceLeft(Map<String, Object> data) {
|
||||
on("CONFERENCE_LEFT", data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConferenceWillJoin(Map<String, Object> data) {
|
||||
on("CONFERENCE_WILL_JOIN", data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConferenceWillLeave(Map<String, Object> data) {
|
||||
on("CONFERENCE_WILL_LEAVE", data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoadConfigError(Map<String, Object> data) {
|
||||
on("LOAD_CONFIG_ERROR", data);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
// As this is the Jitsi Meet app (i.e. not the Jitsi Meet SDK), we do
|
||||
// want the Welcome page to be enabled. It defaults to disabled in the
|
||||
// SDK at the time of this writing but it is clearer to be explicit
|
||||
// about what we want anyway.
|
||||
setWelcomePageEnabled(true);
|
||||
|
||||
super.onCreate(savedInstanceState);
|
||||
}
|
||||
}
|
||||
BIN
android/app/src/main/res/mipmap-hdpi/ic_launcher.png
Normal file
BIN
android/app/src/main/res/mipmap-hdpi/ic_launcher.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 8.7 KiB |
BIN
android/app/src/main/res/mipmap-mdpi/ic_launcher.png
Normal file
BIN
android/app/src/main/res/mipmap-mdpi/ic_launcher.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 5.0 KiB |
BIN
android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
Normal file
BIN
android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 13 KiB |
BIN
android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
Normal file
BIN
android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 25 KiB |
BIN
android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
Normal file
BIN
android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 38 KiB |
3
android/app/src/main/res/values/strings.xml
Normal file
3
android/app/src/main/res/values/strings.xml
Normal file
@@ -0,0 +1,3 @@
|
||||
<resources>
|
||||
<string name="app_name">Jitsi Meet</string>
|
||||
</resources>
|
||||
7
android/app/src/main/res/values/styles.xml
Normal file
7
android/app/src/main/res/values/styles.xml
Normal file
@@ -0,0 +1,7 @@
|
||||
<resources>
|
||||
<!-- Base application theme. -->
|
||||
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
|
||||
<!-- Customize your theme here. -->
|
||||
<item name="android:windowTranslucentStatus">true</item>
|
||||
</style>
|
||||
</resources>
|
||||
157
android/build.gradle
Normal file
157
android/build.gradle
Normal file
@@ -0,0 +1,157 @@
|
||||
// Top-level build file where you can add configuration options common to all
|
||||
// sub-projects/modules.
|
||||
|
||||
buildscript {
|
||||
repositories {
|
||||
jcenter()
|
||||
maven { url 'https://maven.google.com' }
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:3.0.0-beta7'
|
||||
|
||||
// NOTE: Do not place your application dependencies here; they belong
|
||||
// in the individual module build.gradle files.
|
||||
}
|
||||
}
|
||||
|
||||
allprojects {
|
||||
repositories {
|
||||
mavenLocal()
|
||||
jcenter()
|
||||
maven { url "https://maven.google.com" } // Required for appcompat.
|
||||
// React Native (JS, Obj-C sources, Android binaries) is installed from
|
||||
// npm.
|
||||
maven { url "$rootDir/../node_modules/react-native/android" }
|
||||
}
|
||||
|
||||
// Third-party react-native modules which Jitsi Meet SDK for Android depends
|
||||
// on and which are not available in third-party Maven repositories need to
|
||||
// be deployed in a Maven repository of ours.
|
||||
//
|
||||
|
||||
if (project.name.startsWith('react-native-')) {
|
||||
apply plugin: 'maven-publish'
|
||||
publishing {
|
||||
publications {}
|
||||
repositories {
|
||||
maven { url "file:${rootProject.projectDir}/../../../jitsi/jitsi-maven-repository/releases" }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
afterEvaluate { project ->
|
||||
if (project.name.startsWith('react-native-')) {
|
||||
def npmManifest = project.file('../package.json')
|
||||
def json = new groovy.json.JsonSlurper().parseText(npmManifest.text)
|
||||
|
||||
// React Native modules have an npm peer dependency on react-native,
|
||||
// they do not have an npm dependency on it. Further below though we
|
||||
// choose a react-native version (range) when we represent them as
|
||||
// Maven artifacts. Effectively, we are forking the projects by not
|
||||
// complying with the full range of their npm peer dependency and,
|
||||
// consequently, we should qualify their version.
|
||||
def versionQualifier = '-jitsi-1'
|
||||
if ('react-native-webrtc'.equals(project.name))
|
||||
versionQualifier = '-jitsi-1'
|
||||
|
||||
project.version = "${json.version}${versionQualifier}"
|
||||
|
||||
project.android {
|
||||
compileSdkVersion rootProject.ext.compileSdkVersion
|
||||
if (rootProject.ext.has('buildToolsVersion')) {
|
||||
buildToolsVersion rootProject.ext.buildToolsVersion
|
||||
}
|
||||
defaultConfig {
|
||||
minSdkVersion rootProject.ext.minSdkVersion
|
||||
targetSdkVersion rootProject.ext.targetSdkVersion
|
||||
}
|
||||
}
|
||||
|
||||
task androidJavadocs(type: Javadoc) {
|
||||
source = android.sourceSets.main.java.source
|
||||
classpath += project.files(android.getBootClasspath().join(File.pathSeparator))
|
||||
failOnError false
|
||||
}
|
||||
task androidJavadocsJar(type: Jar, dependsOn: androidJavadocs) {
|
||||
classifier = 'javadoc'
|
||||
from androidJavadocs.destinationDir
|
||||
}
|
||||
task androidSourcesJar(type: Jar) {
|
||||
classifier = 'sources'
|
||||
from android.sourceSets.main.java.source
|
||||
}
|
||||
|
||||
publishing.publications {
|
||||
aarArchive(MavenPublication) {
|
||||
groupId rootProject.ext.moduleGroupId
|
||||
artifactId project.name
|
||||
version project.version
|
||||
|
||||
artifact("${project.buildDir}/outputs/aar/${project.name}-release.aar") {
|
||||
extension "aar"
|
||||
}
|
||||
artifact(androidSourcesJar)
|
||||
artifact(androidJavadocsJar)
|
||||
pom.withXml {
|
||||
def pomXml = asNode()
|
||||
pomXml.appendNode('name', project.name)
|
||||
pomXml.appendNode('description', json.description)
|
||||
pomXml.appendNode('url', json.homepage)
|
||||
if (json.license) {
|
||||
def license = pomXml.appendNode('licenses').appendNode('license')
|
||||
license.appendNode('name', json.license)
|
||||
license.appendNode('distribution', 'repo')
|
||||
}
|
||||
|
||||
def dependencies = pomXml.appendNode('dependencies')
|
||||
configurations.getByName('releaseCompileClasspath').getResolvedConfiguration().getFirstLevelModuleDependencies().each {
|
||||
def artifactId = it.moduleName
|
||||
def version = it.moduleVersion
|
||||
// React Native signals breaking changes by
|
||||
// increasing the minor version number. So the
|
||||
// (third-party) React Native modules we utilize can
|
||||
// depend not on a specific react-native release but
|
||||
// a wider range.
|
||||
if (artifactId.equals('react-native')) {
|
||||
def versionNumber = VersionNumber.parse(version)
|
||||
version = "${versionNumber.major}.${versionNumber.minor}"
|
||||
}
|
||||
|
||||
def dependency = dependencies.appendNode('dependency')
|
||||
dependency.appendNode('groupId', it.moduleGroup)
|
||||
dependency.appendNode('artifactId', artifactId)
|
||||
dependency.appendNode('version', version)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ext {
|
||||
compileSdkVersion = 25
|
||||
minSdkVersion = 16
|
||||
targetSdkVersion = 25
|
||||
|
||||
// The Maven artifact groupdId of the third-party react-native modules which
|
||||
// Jitsi Meet SDK for Android depends on and which are not available in
|
||||
// third-party Maven repositories so we have to deploy to a Maven repository
|
||||
// of ours.
|
||||
moduleGroupId = 'com.facebook.react'
|
||||
}
|
||||
|
||||
// Force the version of the Android build tools we have chosen on all
|
||||
// subprojects. The forcing was introduced for react-native and the third-party
|
||||
// modules that we utilize such as react-native-background-timer.
|
||||
subprojects { subproject ->
|
||||
afterEvaluate{
|
||||
if ((subproject.plugins.hasPlugin('android')
|
||||
|| subproject.plugins.hasPlugin('android-library'))
|
||||
&& rootProject.ext.has('buildToolsVersion')) {
|
||||
android {
|
||||
buildToolsVersion rootProject.ext.buildToolsVersion
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
21
android/gradle.properties
Normal file
21
android/gradle.properties
Normal file
@@ -0,0 +1,21 @@
|
||||
# Project-wide Gradle settings.
|
||||
|
||||
# IDE (e.g. Android Studio) users:
|
||||
# Gradle settings configured through the IDE *will override*
|
||||
# any settings specified in this file.
|
||||
|
||||
# For more details on how to configure your build environment visit
|
||||
# http://www.gradle.org/docs/current/userguide/build_environment.html
|
||||
|
||||
# Specifies the JVM arguments used for the daemon process.
|
||||
# The setting is particularly useful for tweaking memory settings.
|
||||
# Default value: -Xmx10248m -XX:MaxPermSize=256m
|
||||
# org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
|
||||
|
||||
# When configured, Gradle will run in incubating parallel mode.
|
||||
# This option should only be used with decoupled projects. More details, visit
|
||||
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
|
||||
# org.gradle.parallel=true
|
||||
|
||||
android.useDeprecatedNdk=true
|
||||
version=1
|
||||
BIN
android/gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
BIN
android/gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
Binary file not shown.
6
android/gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
6
android/gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
#Fri Sep 08 10:42:14 CEST 2017
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-all.zip
|
||||
164
android/gradlew
vendored
Executable file
164
android/gradlew
vendored
Executable file
@@ -0,0 +1,164 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
##############################################################################
|
||||
##
|
||||
## Gradle start up script for UN*X
|
||||
##
|
||||
##############################################################################
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS=""
|
||||
|
||||
APP_NAME="Gradle"
|
||||
APP_BASE_NAME=`basename "$0"`
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD="maximum"
|
||||
|
||||
warn ( ) {
|
||||
echo "$*"
|
||||
}
|
||||
|
||||
die ( ) {
|
||||
echo
|
||||
echo "$*"
|
||||
echo
|
||||
exit 1
|
||||
}
|
||||
|
||||
# OS specific support (must be 'true' or 'false').
|
||||
cygwin=false
|
||||
msys=false
|
||||
darwin=false
|
||||
case "`uname`" in
|
||||
CYGWIN* )
|
||||
cygwin=true
|
||||
;;
|
||||
Darwin* )
|
||||
darwin=true
|
||||
;;
|
||||
MINGW* )
|
||||
msys=true
|
||||
;;
|
||||
esac
|
||||
|
||||
# For Cygwin, ensure paths are in UNIX format before anything is touched.
|
||||
if $cygwin ; then
|
||||
[ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
|
||||
fi
|
||||
|
||||
# Attempt to set APP_HOME
|
||||
# Resolve links: $0 may be a link
|
||||
PRG="$0"
|
||||
# Need this for relative symlinks.
|
||||
while [ -h "$PRG" ] ; do
|
||||
ls=`ls -ld "$PRG"`
|
||||
link=`expr "$ls" : '.*-> \(.*\)$'`
|
||||
if expr "$link" : '/.*' > /dev/null; then
|
||||
PRG="$link"
|
||||
else
|
||||
PRG=`dirname "$PRG"`"/$link"
|
||||
fi
|
||||
done
|
||||
SAVED="`pwd`"
|
||||
cd "`dirname \"$PRG\"`/" >&-
|
||||
APP_HOME="`pwd -P`"
|
||||
cd "$SAVED" >&-
|
||||
|
||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||
|
||||
# Determine the Java command to use to start the JVM.
|
||||
if [ -n "$JAVA_HOME" ] ; then
|
||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||
# IBM's JDK on AIX uses strange locations for the executables
|
||||
JAVACMD="$JAVA_HOME/jre/sh/java"
|
||||
else
|
||||
JAVACMD="$JAVA_HOME/bin/java"
|
||||
fi
|
||||
if [ ! -x "$JAVACMD" ] ; then
|
||||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
else
|
||||
JAVACMD="java"
|
||||
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
|
||||
# Increase the maximum file descriptors if we can.
|
||||
if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
|
||||
MAX_FD_LIMIT=`ulimit -H -n`
|
||||
if [ $? -eq 0 ] ; then
|
||||
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
|
||||
MAX_FD="$MAX_FD_LIMIT"
|
||||
fi
|
||||
ulimit -n $MAX_FD
|
||||
if [ $? -ne 0 ] ; then
|
||||
warn "Could not set maximum file descriptor limit: $MAX_FD"
|
||||
fi
|
||||
else
|
||||
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
|
||||
fi
|
||||
fi
|
||||
|
||||
# For Darwin, add options to specify how the application appears in the dock
|
||||
if $darwin; then
|
||||
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
|
||||
fi
|
||||
|
||||
# For Cygwin, switch paths to Windows format before running java
|
||||
if $cygwin ; then
|
||||
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
|
||||
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
|
||||
|
||||
# We build the pattern for arguments to be converted via cygpath
|
||||
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
|
||||
SEP=""
|
||||
for dir in $ROOTDIRSRAW ; do
|
||||
ROOTDIRS="$ROOTDIRS$SEP$dir"
|
||||
SEP="|"
|
||||
done
|
||||
OURCYGPATTERN="(^($ROOTDIRS))"
|
||||
# Add a user-defined pattern to the cygpath arguments
|
||||
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
|
||||
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
|
||||
fi
|
||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||
i=0
|
||||
for arg in "$@" ; do
|
||||
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
|
||||
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
|
||||
|
||||
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
|
||||
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
|
||||
else
|
||||
eval `echo args$i`="\"$arg\""
|
||||
fi
|
||||
i=$((i+1))
|
||||
done
|
||||
case $i in
|
||||
(0) set -- ;;
|
||||
(1) set -- "$args0" ;;
|
||||
(2) set -- "$args0" "$args1" ;;
|
||||
(3) set -- "$args0" "$args1" "$args2" ;;
|
||||
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
|
||||
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
|
||||
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
|
||||
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
|
||||
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
|
||||
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
|
||||
function splitJvmOpts() {
|
||||
JVM_OPTS=("$@")
|
||||
}
|
||||
eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
|
||||
JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
|
||||
|
||||
exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
|
||||
90
android/gradlew.bat
vendored
Normal file
90
android/gradlew.bat
vendored
Normal file
@@ -0,0 +1,90 @@
|
||||
@if "%DEBUG%" == "" @echo off
|
||||
@rem ##########################################################################
|
||||
@rem
|
||||
@rem Gradle startup script for Windows
|
||||
@rem
|
||||
@rem ##########################################################################
|
||||
|
||||
@rem Set local scope for the variables with windows NT shell
|
||||
if "%OS%"=="Windows_NT" setlocal
|
||||
|
||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
set DEFAULT_JVM_OPTS=
|
||||
|
||||
set DIRNAME=%~dp0
|
||||
if "%DIRNAME%" == "" set DIRNAME=.
|
||||
set APP_BASE_NAME=%~n0
|
||||
set APP_HOME=%DIRNAME%
|
||||
|
||||
@rem Find java.exe
|
||||
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||
|
||||
set JAVA_EXE=java.exe
|
||||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if "%ERRORLEVEL%" == "0" goto init
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:findJavaFromJavaHome
|
||||
set JAVA_HOME=%JAVA_HOME:"=%
|
||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||
|
||||
if exist "%JAVA_EXE%" goto init
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:init
|
||||
@rem Get command-line arguments, handling Windowz variants
|
||||
|
||||
if not "%OS%" == "Windows_NT" goto win9xME_args
|
||||
if "%@eval[2+2]" == "4" goto 4NT_args
|
||||
|
||||
:win9xME_args
|
||||
@rem Slurp the command line arguments.
|
||||
set CMD_LINE_ARGS=
|
||||
set _SKIP=2
|
||||
|
||||
:win9xME_args_slurp
|
||||
if "x%~1" == "x" goto execute
|
||||
|
||||
set CMD_LINE_ARGS=%*
|
||||
goto execute
|
||||
|
||||
:4NT_args
|
||||
@rem Get arguments from the 4NT Shell from JP Software
|
||||
set CMD_LINE_ARGS=%$
|
||||
|
||||
:execute
|
||||
@rem Setup the command line
|
||||
|
||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||
|
||||
@rem Execute Gradle
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
if "%ERRORLEVEL%"=="0" goto mainEnd
|
||||
|
||||
:fail
|
||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||
rem the _cmd.exe /c_ return code!
|
||||
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
|
||||
exit /b 1
|
||||
|
||||
:mainEnd
|
||||
if "%OS%"=="Windows_NT" endlocal
|
||||
|
||||
:omega
|
||||
8
android/keystores/BUCK
Normal file
8
android/keystores/BUCK
Normal file
@@ -0,0 +1,8 @@
|
||||
keystore(
|
||||
name = 'debug',
|
||||
store = 'debug.keystore',
|
||||
properties = 'debug.keystore.properties',
|
||||
visibility = [
|
||||
'PUBLIC',
|
||||
],
|
||||
)
|
||||
4
android/keystores/debug.keystore.properties
Normal file
4
android/keystores/debug.keystore.properties
Normal file
@@ -0,0 +1,4 @@
|
||||
key.store=debug.keystore
|
||||
key.alias=androiddebugkey
|
||||
key.store.password=android
|
||||
key.alias.password=android
|
||||
162
android/sdk/build.gradle
Normal file
162
android/sdk/build.gradle
Normal file
@@ -0,0 +1,162 @@
|
||||
apply plugin: 'com.android.library'
|
||||
apply plugin: 'maven-publish'
|
||||
|
||||
android {
|
||||
compileSdkVersion rootProject.ext.compileSdkVersion
|
||||
|
||||
defaultConfig {
|
||||
minSdkVersion rootProject.ext.minSdkVersion
|
||||
targetSdkVersion rootProject.ext.targetSdkVersion
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
debug {}
|
||||
release {
|
||||
minifyEnabled false
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compile fileTree(dir: 'libs', include: ['*.jar'])
|
||||
|
||||
compile 'com.android.support:appcompat-v7:25.4.0'
|
||||
compile 'com.facebook.react:react-native:+'
|
||||
|
||||
compile project(':react-native-background-timer')
|
||||
compile project(':react-native-fetch-blob')
|
||||
compile project(':react-native-immersive')
|
||||
compile project(':react-native-keep-awake')
|
||||
compile project(':react-native-vector-icons')
|
||||
compile project(':react-native-webrtc')
|
||||
}
|
||||
|
||||
// Build process helpers
|
||||
//
|
||||
|
||||
void runBefore(String dependentTaskName, Task task) {
|
||||
Task dependentTask = tasks.findByPath(dependentTaskName);
|
||||
if (dependentTask != null) {
|
||||
dependentTask.dependsOn task
|
||||
}
|
||||
}
|
||||
|
||||
gradle.projectsEvaluated {
|
||||
android.buildTypes.all { buildType ->
|
||||
def buildNameCapitalized = "${buildType.name.capitalize()}"
|
||||
def bundlePath = "${buildDir}/intermediates/bundles/${buildType.name}"
|
||||
|
||||
// Bundle fonts in react-native-vector-icons.
|
||||
//
|
||||
|
||||
def currentFontTask = tasks.create(
|
||||
name: "copy${buildNameCapitalized}Fonts",
|
||||
type: Copy) {
|
||||
from("${projectDir}/../../fonts/jitsi.ttf")
|
||||
from("${projectDir}/../../node_modules/react-native-vector-icons/Fonts/")
|
||||
into("${bundlePath}/assets/fonts")
|
||||
}
|
||||
|
||||
currentFontTask.dependsOn("merge${buildNameCapitalized}Resources")
|
||||
currentFontTask.dependsOn("merge${buildNameCapitalized}Assets")
|
||||
|
||||
runBefore("processArmeabi-v7a${buildNameCapitalized}Resources", currentFontTask)
|
||||
runBefore("processX86${buildNameCapitalized}Resources", currentFontTask)
|
||||
runBefore("processUniversal${buildNameCapitalized}Resources", currentFontTask)
|
||||
runBefore("process${buildNameCapitalized}Resources", currentFontTask)
|
||||
|
||||
// Bundle JavaScript and React resources.
|
||||
// (adapted from react-native/react.gradle)
|
||||
//
|
||||
|
||||
// React JS bundle directories
|
||||
def jsBundleDir = file("${bundlePath}/assets")
|
||||
def resourcesDir = file("${bundlePath}/res/merged")
|
||||
def jsBundleFile = file("${jsBundleDir}/index.android.bundle")
|
||||
|
||||
// Bundle task name for variant.
|
||||
def bundleJsAndAssetsTaskName = "bundle${buildNameCapitalized}JsAndAssets"
|
||||
|
||||
def currentBundleTask = tasks.create(
|
||||
name: bundleJsAndAssetsTaskName,
|
||||
type: Exec) {
|
||||
// Set up inputs and outputs so gradle can cache the result.
|
||||
def reactRoot = file("${projectDir}/../../")
|
||||
inputs.files fileTree(dir: reactRoot, excludes: ['android/**', 'ios/**'])
|
||||
outputs.dir jsBundleDir
|
||||
outputs.dir resourcesDir
|
||||
|
||||
// Set up the call to the react-native cli.
|
||||
workingDir reactRoot
|
||||
|
||||
// Create JS bundle
|
||||
def devEnabled = !buildNameCapitalized.toLowerCase().contains('release')
|
||||
commandLine(
|
||||
'node',
|
||||
'node_modules/react-native/local-cli/cli.js',
|
||||
'bundle',
|
||||
'--assets-dest', resourcesDir,
|
||||
'--bundle-output', jsBundleFile,
|
||||
'--dev', "${devEnabled}",
|
||||
'--entry-file', 'index.android.js',
|
||||
'--platform', 'android',
|
||||
'--reset-cache')
|
||||
|
||||
// Disable bundling on dev builds
|
||||
enabled !devEnabled
|
||||
}
|
||||
|
||||
// Hook bundle${productFlavor}${buildType}JsAndAssets into the android build process
|
||||
currentBundleTask.dependsOn("merge${buildNameCapitalized}Resources")
|
||||
currentBundleTask.dependsOn("merge${buildNameCapitalized}Assets")
|
||||
|
||||
runBefore("processArmeabi-v7a${buildNameCapitalized}Resources", currentBundleTask)
|
||||
runBefore("processX86${buildNameCapitalized}Resources", currentBundleTask)
|
||||
runBefore("processUniversal${buildNameCapitalized}Resources", currentBundleTask)
|
||||
runBefore("process${buildNameCapitalized}Resources", currentBundleTask)
|
||||
}
|
||||
}
|
||||
|
||||
publishing {
|
||||
publications {
|
||||
aarArchive(MavenPublication) {
|
||||
groupId 'org.jitsi.react'
|
||||
artifactId 'jitsi-meet-sdk'
|
||||
version '1.9.0'
|
||||
|
||||
artifact("${project.buildDir}/outputs/aar/${project.name}-release.aar") {
|
||||
extension "aar"
|
||||
}
|
||||
pom.withXml {
|
||||
def pomXml = asNode()
|
||||
pomXml.appendNode('name', 'jitsi-meet-sdk')
|
||||
pomXml.appendNode('description', 'Jitsi Meet SDK for Android')
|
||||
def dependencies = pomXml.appendNode('dependencies')
|
||||
configurations.getByName('releaseCompileClasspath').getResolvedConfiguration().getFirstLevelModuleDependencies().each {
|
||||
// The (third-party) React Native modules that we depend on
|
||||
// are in source code form and do not have groupId. That is
|
||||
// why we have a dedicated groupId for them. But the other
|
||||
// dependencies come through Maven and, consequently, have
|
||||
// groupId.
|
||||
def groupId = it.moduleGroup
|
||||
def artifactId = it.moduleName
|
||||
|
||||
if (artifactId.startsWith('react-native-')
|
||||
&& groupId.equals('jitsi-meet')) {
|
||||
groupId = rootProject.ext.moduleGroupId
|
||||
}
|
||||
|
||||
def dependency = dependencies.appendNode('dependency')
|
||||
dependency.appendNode('groupId', groupId)
|
||||
dependency.appendNode('artifactId', artifactId)
|
||||
dependency.appendNode('version', it.moduleVersion)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
repositories {
|
||||
maven { url "file:${rootProject.projectDir}/../../../jitsi/jitsi-maven-repository/releases" }
|
||||
}
|
||||
}
|
||||
25
android/sdk/proguard-rules.pro
vendored
Normal file
25
android/sdk/proguard-rules.pro
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
# Add project specific ProGuard rules here.
|
||||
# By default, the flags in this file are appended to flags specified
|
||||
# in /Users/scorretge/Library/Android/sdk/tools/proguard/proguard-android.txt
|
||||
# You can edit the include path and order by changing the proguardFiles
|
||||
# directive in build.gradle.
|
||||
#
|
||||
# For more details, see
|
||||
# http://developer.android.com/guide/developing/tools/proguard.html
|
||||
|
||||
# Add any project specific keep options here:
|
||||
|
||||
# If your project uses WebView with JS, uncomment the following
|
||||
# and specify the fully qualified class name to the JavaScript interface
|
||||
# class:
|
||||
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
|
||||
# public *;
|
||||
#}
|
||||
|
||||
# Uncomment this to preserve the line number information for
|
||||
# debugging stack traces.
|
||||
#-keepattributes SourceFile,LineNumberTable
|
||||
|
||||
# If you keep the line number information, uncomment this to
|
||||
# hide the original source file name.
|
||||
#-renamesourcefileattribute SourceFile
|
||||
29
android/sdk/src/main/AndroidManifest.xml
Normal file
29
android/sdk/src/main/AndroidManifest.xml
Normal file
@@ -0,0 +1,29 @@
|
||||
<manifest
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="org.jitsi.meet.sdk">
|
||||
<!-- XXX ACCESS_NETWORK_STATE is required by WebRTC. -->
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||
<uses-permission android:name="android.permission.BLUETOOTH" />
|
||||
<uses-permission android:name="android.permission.CAMERA" />
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
|
||||
<uses-permission android:name="android.permission.RECORD_AUDIO" />
|
||||
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
|
||||
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
||||
|
||||
<uses-feature android:glEsVersion="0x00020000" android:required="true" />
|
||||
<uses-feature
|
||||
android:name="android.hardware.camera"
|
||||
android:required="false" />
|
||||
<uses-feature
|
||||
android:name="android.hardware.camera.autofocus"
|
||||
android:required="false" />
|
||||
|
||||
<application
|
||||
android:allowBackup="true"
|
||||
android:label="@string/app_name"
|
||||
android:supportsRtl="true">
|
||||
<activity
|
||||
android:name="com.facebook.react.devsupport.DevSettingsActivity" />
|
||||
</application>
|
||||
</manifest>
|
||||
@@ -0,0 +1,39 @@
|
||||
/**
|
||||
* Adapted from
|
||||
* {@link https://github.com/Aleksandern/react-native-android-settings-library}.
|
||||
*/
|
||||
|
||||
package org.jitsi.meet.sdk;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.provider.Settings;
|
||||
|
||||
import com.facebook.react.bridge.ReactApplicationContext;
|
||||
import com.facebook.react.bridge.ReactContextBaseJavaModule;
|
||||
import com.facebook.react.bridge.ReactMethod;
|
||||
|
||||
class AndroidSettingsModule extends ReactContextBaseJavaModule {
|
||||
public AndroidSettingsModule(ReactApplicationContext reactContext) {
|
||||
super(reactContext);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "AndroidSettings";
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void open() {
|
||||
Context context = getReactApplicationContext();
|
||||
Intent intent = new Intent();
|
||||
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
|
||||
intent.setData(
|
||||
Uri.fromParts("package", context.getPackageName(), null));
|
||||
|
||||
context.startActivity(intent);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
package org.jitsi.meet.sdk;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
|
||||
import com.facebook.react.bridge.ReactApplicationContext;
|
||||
import com.facebook.react.bridge.ReactContextBaseJavaModule;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
class AppInfoModule extends ReactContextBaseJavaModule {
|
||||
public AppInfoModule(ReactApplicationContext reactContext) {
|
||||
super(reactContext);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a {@code Map} of constants this module exports to JS. Supports JSON
|
||||
* types.
|
||||
*
|
||||
* @return a {@link Map} of constants this module exports to JS
|
||||
*/
|
||||
@Override
|
||||
public Map<String, Object> getConstants() {
|
||||
Context context = getReactApplicationContext();
|
||||
PackageManager packageManager = context.getPackageManager();
|
||||
ApplicationInfo applicationInfo;
|
||||
PackageInfo packageInfo;
|
||||
|
||||
try {
|
||||
String packageName = context.getPackageName();
|
||||
|
||||
applicationInfo
|
||||
= packageManager.getApplicationInfo(packageName, 0);
|
||||
packageInfo = packageManager.getPackageInfo(packageName, 0);
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
applicationInfo = null;
|
||||
packageInfo = null;
|
||||
}
|
||||
|
||||
Map<String, Object> constants = new HashMap<>();
|
||||
|
||||
constants.put(
|
||||
"name",
|
||||
applicationInfo == null
|
||||
? ""
|
||||
: packageManager.getApplicationLabel(applicationInfo));
|
||||
constants.put(
|
||||
"version",
|
||||
packageInfo == null ? "" : packageInfo.versionName);
|
||||
|
||||
return constants;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "AppInfo";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,349 @@
|
||||
/*
|
||||
* Copyright @ 2017-present Atlassian Pty Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jitsi.meet.sdk;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.media.AudioDeviceInfo;
|
||||
import android.media.AudioManager;
|
||||
import android.os.Build;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.util.Log;
|
||||
|
||||
import com.facebook.react.bridge.Promise;
|
||||
import com.facebook.react.bridge.ReactApplicationContext;
|
||||
import com.facebook.react.bridge.ReactContextBaseJavaModule;
|
||||
import com.facebook.react.bridge.ReactMethod;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Module implementing a simple API to select the appropriate audio device for a
|
||||
* conference call.
|
||||
*
|
||||
* Audio calls should use {@code AudioModeModule.AUDIO_CALL}, which uses the
|
||||
* builtin earpiece, wired headset or bluetooth headset. The builtin earpiece is
|
||||
* the default audio device.
|
||||
*
|
||||
* Video calls should should use {@code AudioModeModule.VIDEO_CALL}, which uses
|
||||
* the builtin speaker, earpiece, wired headset or bluetooth headset. The
|
||||
* builtin speaker is the default audio device.
|
||||
*
|
||||
* Before a call has started and after it has ended the
|
||||
* {@code AudioModeModule.DEFAULT} mode should be used.
|
||||
*/
|
||||
class AudioModeModule extends ReactContextBaseJavaModule {
|
||||
/**
|
||||
* Constants representing the audio mode.
|
||||
* - DEFAULT: Used before and after every call. It represents the default
|
||||
* audio routing scheme.
|
||||
* - AUDIO_CALL: Used for audio only calls. It will use the earpiece by
|
||||
* default, unless a wired or Bluetooth headset is connected.
|
||||
* - VIDEO_CALL: Used for video calls. It will use the speaker by default,
|
||||
* unless a wired or Bluetooth headset is connected.
|
||||
*/
|
||||
private static final int DEFAULT = 0;
|
||||
private static final int AUDIO_CALL = 1;
|
||||
private static final int VIDEO_CALL = 2;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final String ACTION_HEADSET_PLUG
|
||||
= (Build.VERSION.SDK_INT >= 21)
|
||||
? AudioManager.ACTION_HEADSET_PLUG
|
||||
: Intent.ACTION_HEADSET_PLUG;
|
||||
|
||||
/**
|
||||
* The name of {@code AudioModeModule} to be used in the React Native
|
||||
* bridge.
|
||||
*/
|
||||
private static final String MODULE_NAME = "AudioMode";
|
||||
|
||||
/**
|
||||
* The {@code Log} tag {@code AudioModeModule} is to log messages with.
|
||||
*/
|
||||
static final String TAG = MODULE_NAME;
|
||||
|
||||
/**
|
||||
* {@link AudioManager} instance used to interact with the Android audio
|
||||
* subsystem.
|
||||
*/
|
||||
private final AudioManager audioManager;
|
||||
|
||||
/**
|
||||
* {@link BluetoothHeadsetMonitor} for detecting Bluetooth device changes in
|
||||
* old (< M) Android versions.
|
||||
*/
|
||||
private BluetoothHeadsetMonitor bluetoothHeadsetMonitor;
|
||||
|
||||
/**
|
||||
* {@link Handler} for running all operations on the main thread.
|
||||
*/
|
||||
private final Handler mainThreadHandler
|
||||
= new Handler(Looper.getMainLooper());
|
||||
|
||||
/**
|
||||
* {@link Runnable} for running update operation on the main thread.
|
||||
*/
|
||||
private final Runnable mainThreadRunner
|
||||
= new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (mode != -1) {
|
||||
updateAudioRoute(mode);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Audio mode currently in use.
|
||||
*/
|
||||
private int mode = -1;
|
||||
|
||||
/**
|
||||
* Initializes a new module instance. There shall be a single instance of
|
||||
* this module throughout the lifetime of the application.
|
||||
*
|
||||
* @param reactContext the {@link ReactApplicationContext} where this module
|
||||
* is created.
|
||||
*/
|
||||
public AudioModeModule(ReactApplicationContext reactContext) {
|
||||
super(reactContext);
|
||||
|
||||
audioManager
|
||||
= (AudioManager)
|
||||
reactContext.getSystemService(Context.AUDIO_SERVICE);
|
||||
|
||||
// Setup runtime device change detection.
|
||||
setupAudioRouteChangeDetection();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a mapping with the constants this module is exporting.
|
||||
*
|
||||
* @return a {@link Map} mapping the constants to be exported with their
|
||||
* values.
|
||||
*/
|
||||
@Override
|
||||
public Map<String, Object> getConstants() {
|
||||
Map<String, Object> constants = new HashMap<>();
|
||||
|
||||
constants.put("AUDIO_CALL", AUDIO_CALL);
|
||||
constants.put("DEFAULT", DEFAULT);
|
||||
constants.put("VIDEO_CALL", VIDEO_CALL);
|
||||
|
||||
return constants;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the name for this module to be used in the React Native bridge.
|
||||
*
|
||||
* @return a string with the module name.
|
||||
*/
|
||||
@Override
|
||||
public String getName() {
|
||||
return MODULE_NAME;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to trigger an audio route update when devices change. It
|
||||
* makes sure the operation is performed on the main thread.
|
||||
*/
|
||||
void onAudioDeviceChange() {
|
||||
mainThreadHandler.post(mainThreadRunner);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to set the output route to a Bluetooth device.
|
||||
*
|
||||
* @param enabled true if Bluetooth should use used, false otherwise.
|
||||
*/
|
||||
private void setBluetoothAudioRoute(boolean enabled) {
|
||||
if (enabled) {
|
||||
audioManager.startBluetoothSco();
|
||||
audioManager.setBluetoothScoOn(true);
|
||||
} else {
|
||||
audioManager.setBluetoothScoOn(false);
|
||||
audioManager.stopBluetoothSco();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Public method to set the current audio mode.
|
||||
*
|
||||
* @param mode the desired audio mode.
|
||||
* @param promise a {@link Promise} which will be resolved if the audio mode
|
||||
* could be updated successfully, and it will be rejected otherwise.
|
||||
*/
|
||||
@ReactMethod
|
||||
public void setMode(final int mode, final Promise promise) {
|
||||
if (mode != DEFAULT && mode != AUDIO_CALL && mode != VIDEO_CALL) {
|
||||
promise.reject("setMode", "Invalid audio mode " + mode);
|
||||
return;
|
||||
}
|
||||
|
||||
Runnable r = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
boolean success;
|
||||
|
||||
try {
|
||||
success = updateAudioRoute(mode);
|
||||
} catch (Throwable e) {
|
||||
success = false;
|
||||
Log.e(
|
||||
TAG,
|
||||
"Failed to update audio route for mode: " + mode,
|
||||
e);
|
||||
}
|
||||
if (success) {
|
||||
AudioModeModule.this.mode = mode;
|
||||
promise.resolve(null);
|
||||
} else {
|
||||
promise.reject(
|
||||
"setMode",
|
||||
"Failed to set audio mode to " + mode);
|
||||
}
|
||||
}
|
||||
};
|
||||
mainThreadHandler.post(r);
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup the audio route change detection mechanism. We use the
|
||||
* {@link android.media.AudioDeviceCallback} API on Android >= 23 only.
|
||||
*/
|
||||
private void setupAudioRouteChangeDetection() {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
setupAudioRouteChangeDetectionM();
|
||||
} else {
|
||||
setupAudioRouteChangeDetectionPreM();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Audio route change detection mechanism for Android API >= 23.
|
||||
*/
|
||||
@TargetApi(Build.VERSION_CODES.M)
|
||||
private void setupAudioRouteChangeDetectionM() {
|
||||
android.media.AudioDeviceCallback audioDeviceCallback =
|
||||
new android.media.AudioDeviceCallback() {
|
||||
@Override
|
||||
public void onAudioDevicesAdded(
|
||||
AudioDeviceInfo[] addedDevices) {
|
||||
Log.d(TAG, "Audio devices added");
|
||||
onAudioDeviceChange();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAudioDevicesRemoved(
|
||||
AudioDeviceInfo[] removedDevices) {
|
||||
Log.d(TAG, "Audio devices removed");
|
||||
onAudioDeviceChange();
|
||||
}
|
||||
};
|
||||
|
||||
audioManager.registerAudioDeviceCallback(audioDeviceCallback, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Audio route change detection mechanism for Android API < 23.
|
||||
*/
|
||||
private void setupAudioRouteChangeDetectionPreM() {
|
||||
Context context = getReactApplicationContext();
|
||||
|
||||
// Detect changes in wired headset connections.
|
||||
IntentFilter wiredHeadSetFilter = new IntentFilter(ACTION_HEADSET_PLUG);
|
||||
BroadcastReceiver wiredHeadsetReceiver = new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
Log.d(TAG, "Wired headset added / removed");
|
||||
onAudioDeviceChange();
|
||||
}
|
||||
};
|
||||
context.registerReceiver(wiredHeadsetReceiver, wiredHeadSetFilter);
|
||||
|
||||
// Detect Bluetooth device changes.
|
||||
bluetoothHeadsetMonitor = new BluetoothHeadsetMonitor(this, context);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the audio route for the given mode.
|
||||
*
|
||||
* @param mode the audio mode to be used when computing the audio route.
|
||||
* @return {@code true} if the audio route was updated successfully;
|
||||
* {@code false}, otherwise.
|
||||
*/
|
||||
private boolean updateAudioRoute(int mode) {
|
||||
Log.d(TAG, "Update audio route for mode: " + mode);
|
||||
|
||||
if (mode == DEFAULT) {
|
||||
audioManager.setMode(AudioManager.MODE_NORMAL);
|
||||
audioManager.abandonAudioFocus(null);
|
||||
audioManager.setSpeakerphoneOn(false);
|
||||
setBluetoothAudioRoute(false);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
audioManager.setMode(AudioManager.MODE_IN_COMMUNICATION);
|
||||
audioManager.setMicrophoneMute(false);
|
||||
|
||||
if (audioManager.requestAudioFocus(
|
||||
null,
|
||||
AudioManager.STREAM_VOICE_CALL,
|
||||
AudioManager.AUDIOFOCUS_GAIN)
|
||||
== AudioManager.AUDIOFOCUS_REQUEST_FAILED) {
|
||||
Log.d(TAG, "Audio focus request failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
boolean useSpeaker = (mode == VIDEO_CALL);
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
// On Android >= M we use the AudioDeviceCallback API, so turn on
|
||||
// Bluetooth SCO from the start.
|
||||
if (audioManager.isBluetoothScoAvailableOffCall()) {
|
||||
audioManager.startBluetoothSco();
|
||||
}
|
||||
} else {
|
||||
// On older Android versions we must set the Bluetooth route
|
||||
// manually. Also disable the speaker in that case.
|
||||
setBluetoothAudioRoute(
|
||||
bluetoothHeadsetMonitor.isHeadsetAvailable());
|
||||
if (bluetoothHeadsetMonitor.isHeadsetAvailable()) {
|
||||
useSpeaker = false;
|
||||
}
|
||||
}
|
||||
|
||||
// XXX: isWiredHeadsetOn is not deprecated when used just for knowing if
|
||||
// there is a wired headset connected, regardless of audio being routed
|
||||
// to it.
|
||||
audioManager.setSpeakerphoneOn(
|
||||
useSpeaker
|
||||
&& !(audioManager.isWiredHeadsetOn()
|
||||
|| audioManager.isBluetoothScoOn()));
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,205 @@
|
||||
/*
|
||||
* Copyright @ 2017-present Atlassian Pty Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jitsi.meet.sdk;
|
||||
|
||||
import android.bluetooth.BluetoothAdapter;
|
||||
import android.bluetooth.BluetoothHeadset;
|
||||
import android.bluetooth.BluetoothProfile;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.media.AudioManager;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.util.Log;
|
||||
|
||||
/**
|
||||
* Helper class to detect and handle Bluetooth device changes. It monitors
|
||||
* Bluetooth headsets being connected / disconnected and notifies the module
|
||||
* about device changes when this occurs.
|
||||
*/
|
||||
class BluetoothHeadsetMonitor {
|
||||
/**
|
||||
* {@link AudioModeModule} where this monitor reports.
|
||||
*/
|
||||
private final AudioModeModule audioModeModule;
|
||||
|
||||
/**
|
||||
* The {@link Context} in which {@link #audioModeModule} executes.
|
||||
*/
|
||||
private final Context context;
|
||||
|
||||
/**
|
||||
* Reference to a proxy object which allows us to query connected devices.
|
||||
*/
|
||||
private BluetoothHeadset headset;
|
||||
|
||||
/**
|
||||
* Flag indicating if there are any Bluetooth headset devices currently
|
||||
* available.
|
||||
*/
|
||||
private boolean headsetAvailable = false;
|
||||
|
||||
/**
|
||||
* {@link Handler} for running all operations on the main thread.
|
||||
*/
|
||||
private final Handler mainThreadHandler
|
||||
= new Handler(Looper.getMainLooper());
|
||||
|
||||
/**
|
||||
* Helper for running Bluetooth operations on the main thread.
|
||||
*/
|
||||
private final Runnable updateDevicesRunnable
|
||||
= new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
headsetAvailable
|
||||
= (headset != null)
|
||||
&& !headset.getConnectedDevices().isEmpty();
|
||||
audioModeModule.onAudioDeviceChange();
|
||||
}
|
||||
};
|
||||
|
||||
public BluetoothHeadsetMonitor(
|
||||
AudioModeModule audioModeModule,
|
||||
Context context) {
|
||||
this.audioModeModule = audioModeModule;
|
||||
this.context = context;
|
||||
|
||||
AudioManager audioManager
|
||||
= (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
|
||||
|
||||
if (!audioManager.isBluetoothScoAvailableOffCall()) {
|
||||
Log.w(AudioModeModule.TAG, "Bluetooth SCO is not available");
|
||||
return;
|
||||
}
|
||||
|
||||
if (getBluetoothHeadsetProfileProxy()) {
|
||||
registerBluetoothReceiver();
|
||||
|
||||
// Initial detection.
|
||||
updateDevices();
|
||||
}
|
||||
}
|
||||
|
||||
private boolean getBluetoothHeadsetProfileProxy() {
|
||||
BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
|
||||
|
||||
if (adapter == null) {
|
||||
Log.w(AudioModeModule.TAG, "Device doesn't support Bluetooth");
|
||||
return false;
|
||||
}
|
||||
|
||||
// XXX: The profile listener listens for system services of the given
|
||||
// type being available to the application. That is, if our Bluetooth
|
||||
// adapter has the "headset" profile.
|
||||
BluetoothProfile.ServiceListener listener
|
||||
= new BluetoothProfile.ServiceListener() {
|
||||
@Override
|
||||
public void onServiceConnected(
|
||||
int profile,
|
||||
BluetoothProfile proxy) {
|
||||
if (profile == BluetoothProfile.HEADSET) {
|
||||
headset = (BluetoothHeadset) proxy;
|
||||
updateDevices();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onServiceDisconnected(int profile) {
|
||||
// The logic is the same as the logic of onServiceConnected.
|
||||
onServiceConnected(profile, /* proxy */ null);
|
||||
}
|
||||
};
|
||||
|
||||
return
|
||||
adapter.getProfileProxy(
|
||||
context,
|
||||
listener,
|
||||
BluetoothProfile.HEADSET);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current headset availability.
|
||||
*
|
||||
* @return {@code true} if there is a Bluetooth headset connected;
|
||||
* {@code false}, otherwise.
|
||||
*/
|
||||
public boolean isHeadsetAvailable() {
|
||||
return headsetAvailable;
|
||||
}
|
||||
|
||||
private void onBluetoothReceiverReceive(Context context, Intent intent) {
|
||||
final String action = intent.getAction();
|
||||
|
||||
if (action.equals(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED)) {
|
||||
// XXX: This action will be fired when a Bluetooth headset is
|
||||
// connected or disconnected to the system. This is not related to
|
||||
// audio routing.
|
||||
int state = intent.getIntExtra(BluetoothHeadset.EXTRA_STATE, -99);
|
||||
|
||||
switch (state) {
|
||||
case BluetoothHeadset.STATE_CONNECTED:
|
||||
case BluetoothHeadset.STATE_DISCONNECTED:
|
||||
Log.d(
|
||||
AudioModeModule.TAG,
|
||||
"BT headset connection state changed: " + state);
|
||||
updateDevices();
|
||||
break;
|
||||
}
|
||||
} else if (action.equals(AudioManager.ACTION_SCO_AUDIO_STATE_UPDATED)) {
|
||||
// XXX: This action will be fired when the connection established
|
||||
// with a Bluetooth headset (called a SCO connection) changes state.
|
||||
// When the SCO connection is active we route audio to it.
|
||||
int state
|
||||
= intent.getIntExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, -99);
|
||||
|
||||
switch (state) {
|
||||
case AudioManager.SCO_AUDIO_STATE_CONNECTED:
|
||||
case AudioManager.SCO_AUDIO_STATE_DISCONNECTED:
|
||||
Log.d(
|
||||
AudioModeModule.TAG,
|
||||
"BT SCO connection state changed: " + state);
|
||||
updateDevices();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void registerBluetoothReceiver() {
|
||||
BroadcastReceiver receiver = new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
onBluetoothReceiverReceive(context, intent);
|
||||
}
|
||||
};
|
||||
IntentFilter filter = new IntentFilter();
|
||||
|
||||
filter.addAction(AudioManager.ACTION_SCO_AUDIO_STATE_UPDATED);
|
||||
filter.addAction(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED);
|
||||
context.registerReceiver(receiver, filter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Detects if there are new devices connected / disconnected and fires the
|
||||
* {@link AudioModeModule#onAudioDeviceChange()} callback.
|
||||
*/
|
||||
private void updateDevices() {
|
||||
mainThreadHandler.post(updateDevicesRunnable);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright @ 2017-present Atlassian Pty Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jitsi.meet.sdk;
|
||||
|
||||
import android.app.Activity;
|
||||
|
||||
import com.facebook.react.modules.core.DefaultHardwareBackBtnHandler;
|
||||
|
||||
/**
|
||||
* Defines the default behavior of {@code JitsiMeetActivity} and
|
||||
* {@code JitsiMeetView} upon invoking the back button if no
|
||||
* {@code JitsiMeetView} handles the invocation. For example, a
|
||||
* {@code JitsiMeetView} may (1) handle the invocation of the back button
|
||||
* during a conference by leaving the conference and (2) not handle the
|
||||
* invocation when not in a conference.
|
||||
*/
|
||||
public class DefaultHardwareBackBtnHandlerImpl
|
||||
implements DefaultHardwareBackBtnHandler {
|
||||
|
||||
/**
|
||||
* The {@code Activity} to which the default handling of the back button
|
||||
* is being provided by this instance.
|
||||
*/
|
||||
private final Activity activity;
|
||||
|
||||
/**
|
||||
* Initializes a new {@code DefaultHardwareBackBtnHandlerImpl} instance to
|
||||
* provide the default handling of the back button to a specific
|
||||
* {@code Activity}.
|
||||
*
|
||||
* @param activity the {@code Activity} to which the new instance is to
|
||||
* provide the default behavior of the back button
|
||||
*/
|
||||
public DefaultHardwareBackBtnHandlerImpl(Activity activity) {
|
||||
this.activity = activity;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* Finishes the associated {@code Activity}.
|
||||
*/
|
||||
@Override
|
||||
public void invokeDefaultOnBackPressed() {
|
||||
// Technically, we'd like to invoke Activity#onBackPressed().
|
||||
// Practically, it's not possible. Fortunately, the documentation of
|
||||
// Activity#onBackPressed() specifies that "[t]he default implementation
|
||||
// simply finishes the current activity,"
|
||||
activity.finish();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,172 @@
|
||||
/*
|
||||
* Copyright @ 2017-present Atlassian Pty Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jitsi.meet.sdk;
|
||||
|
||||
import com.facebook.react.bridge.ReactApplicationContext;
|
||||
import com.facebook.react.bridge.ReactContextBaseJavaModule;
|
||||
import com.facebook.react.bridge.ReactMethod;
|
||||
import com.facebook.react.bridge.ReadableMap;
|
||||
import com.facebook.react.bridge.ReadableMapKeySetIterator;
|
||||
|
||||
import org.jitsi.meet.sdk.JitsiMeetView;
|
||||
import org.jitsi.meet.sdk.JitsiMeetViewListener;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* Module implementing a simple API to enable a proximity sensor-controlled
|
||||
* wake lock. When the lock is held, if the proximity sensor detects a nearby
|
||||
* object it will dim the screen and disable touch controls. The functionality
|
||||
* is used with the conference audio-only mode.
|
||||
*/
|
||||
class ExternalAPIModule extends ReactContextBaseJavaModule {
|
||||
/**
|
||||
* The {@code Method}s of {@code JitsiMeetViewListener} by event name i.e.
|
||||
* redux action types.
|
||||
*/
|
||||
private static final Map<String, Method> JITSI_MEET_VIEW_LISTENER_METHODS
|
||||
= new HashMap<>();
|
||||
|
||||
static {
|
||||
// Figure out the mapping between the JitsiMeetViewListener methods
|
||||
// and the events i.e. redux action types.
|
||||
Pattern onPattern = Pattern.compile("^on[A-Z]+");
|
||||
Pattern camelcasePattern = Pattern.compile("([a-z0-9]+)([A-Z0-9]+)");
|
||||
|
||||
for (Method method : JitsiMeetViewListener.class.getDeclaredMethods()) {
|
||||
// * The method must be public (because it is declared by an
|
||||
// interface).
|
||||
// * The method must be/return void.
|
||||
if (!Modifier.isPublic(method.getModifiers())
|
||||
|| !Void.TYPE.equals(method.getReturnType())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// * The method name must start with "on" followed by a
|
||||
// capital/uppercase letter (in agreement with the camelcase
|
||||
// coding style customary to Java in general and the projects of
|
||||
// the Jitsi community in particular).
|
||||
String name = method.getName();
|
||||
|
||||
if (!onPattern.matcher(name).find()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// * The method must accept/have exactly 1 parameter of a type
|
||||
// assignable from HashMap.
|
||||
Class<?>[] parameterTypes = method.getParameterTypes();
|
||||
|
||||
if (parameterTypes.length != 1
|
||||
|| !parameterTypes[0].isAssignableFrom(HashMap.class)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Convert the method name to an event name.
|
||||
name
|
||||
= camelcasePattern.matcher(name.substring(2))
|
||||
.replaceAll("$1_$2")
|
||||
.toUpperCase(Locale.ROOT);
|
||||
JITSI_MEET_VIEW_LISTENER_METHODS.put(name, method);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes a new module instance. There shall be a single instance of
|
||||
* this module throughout the lifetime of the application.
|
||||
*
|
||||
* @param reactContext the {@link ReactApplicationContext} where this module
|
||||
* is created.
|
||||
*/
|
||||
public ExternalAPIModule(ReactApplicationContext reactContext) {
|
||||
super(reactContext);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the name of this module to be used in the React Native bridge.
|
||||
*
|
||||
* @return The name of this module to be used in the React Native bridge.
|
||||
*/
|
||||
@Override
|
||||
public String getName() {
|
||||
return "ExternalAPI";
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispatches an event that occurred on JavaScript to the view's listener.
|
||||
*
|
||||
* @param name The name of the event.
|
||||
* @param data The details/specifics of the event to send determined
|
||||
* by/associated with the specified {@code name}.
|
||||
* @param scope
|
||||
*/
|
||||
@ReactMethod
|
||||
public void sendEvent(String name, ReadableMap data, String scope) {
|
||||
// The JavaScript App needs to provide uniquely identifying information
|
||||
// to the native ExternalAPI module so that the latter may match the
|
||||
// former to the native JitsiMeetView which hosts it.
|
||||
JitsiMeetView view = JitsiMeetView.findViewByExternalAPIScope(scope);
|
||||
|
||||
if (view == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
JitsiMeetViewListener listener = view.getListener();
|
||||
|
||||
if (listener == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Method method = JITSI_MEET_VIEW_LISTENER_METHODS.get(name);
|
||||
|
||||
if (method != null) {
|
||||
try {
|
||||
method.invoke(listener, toHashMap(data));
|
||||
} catch (IllegalAccessException | InvocationTargetException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes a new {@code HashMap} instance with the key-value
|
||||
* associations of a specific {@code ReadableMap}.
|
||||
*
|
||||
* @param readableMap the {@code ReadableMap} specifying the key-value
|
||||
* associations with which the new {@code HashMap} instance is to be
|
||||
* initialized.
|
||||
* @return a new {@code HashMap} instance initialized with the key-value
|
||||
* associations of the specified {@code readableMap}.
|
||||
*/
|
||||
private HashMap<String, Object> toHashMap(ReadableMap readableMap) {
|
||||
HashMap<String, Object> hashMap = new HashMap<>();
|
||||
|
||||
for (ReadableMapKeySetIterator i = readableMap.keySetIterator();
|
||||
i.hasNextKey();) {
|
||||
String key = i.nextKey();
|
||||
|
||||
hashMap.put(key, readableMap.getString(key));
|
||||
}
|
||||
|
||||
return hashMap;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,246 @@
|
||||
/*
|
||||
* Copyright @ 2017-present Atlassian Pty Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jitsi.meet.sdk;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.provider.Settings;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
|
||||
import java.net.URL;
|
||||
|
||||
import com.facebook.react.modules.core.DefaultHardwareBackBtnHandler;
|
||||
|
||||
/**
|
||||
* Base Activity for applications integrating Jitsi Meet at a higher level. It
|
||||
* contains all the required wiring between the {@code JKConferenceView} and
|
||||
* the Activity lifecycle methods already implemented.
|
||||
*
|
||||
* In this activity we use a single {@code JKConferenceView} instance. This
|
||||
* instance gives us access to a view which displays the welcome page and the
|
||||
* conference itself. All lifetime methods associated with this Activity are
|
||||
* hooked to the React Native subsystem via proxy calls through the
|
||||
* {@code JKConferenceView} static methods.
|
||||
*/
|
||||
public class JitsiMeetActivity
|
||||
extends AppCompatActivity {
|
||||
|
||||
/**
|
||||
* The request code identifying requests for the permission to draw on top
|
||||
* of other apps. The value must be 16-bit and is arbitrarily chosen here.
|
||||
*/
|
||||
private static final int OVERLAY_PERMISSION_REQUEST_CODE
|
||||
= (int) (Math.random() * Short.MAX_VALUE);
|
||||
|
||||
/**
|
||||
* The default behavior of this {@code JitsiMeetActivity} upon invoking the
|
||||
* back button if {@link #view} does not handle the invocation.
|
||||
*/
|
||||
private DefaultHardwareBackBtnHandler defaultBackButtonImpl;
|
||||
|
||||
/**
|
||||
* The default base {@code URL} used to join a conference when a partial URL
|
||||
* (e.g. a room name only) is specified. The value is used only while
|
||||
* {@link #view} equals {@code null}.
|
||||
*/
|
||||
private URL defaultURL;
|
||||
|
||||
/**
|
||||
* Instance of the {@link JitsiMeetView} which this activity will display.
|
||||
*/
|
||||
private JitsiMeetView view;
|
||||
|
||||
/**
|
||||
* Whether the Welcome page is enabled. The value is used only while
|
||||
* {@link #view} equals {@code null}.
|
||||
*/
|
||||
private boolean welcomePageEnabled;
|
||||
|
||||
private boolean canRequestOverlayPermission() {
|
||||
return
|
||||
BuildConfig.DEBUG
|
||||
&& Build.VERSION.SDK_INT >= Build.VERSION_CODES.M
|
||||
&& getApplicationInfo().targetSdkVersion
|
||||
>= Build.VERSION_CODES.M;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @see JitsiMeetView#getDefaultURL()
|
||||
*/
|
||||
public URL getDefaultURL() {
|
||||
return view == null ? defaultURL : view.getDefaultURL();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @see JitsiMeetView#getWelcomePageEnabled()
|
||||
*/
|
||||
public boolean getWelcomePageEnabled() {
|
||||
return view == null ? welcomePageEnabled : view.getWelcomePageEnabled();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the {@link #view} of this {@code JitsiMeetActivity} with a
|
||||
* new {@link JitsiMeetView} instance.
|
||||
*/
|
||||
private void initializeContentView() {
|
||||
JitsiMeetView view = initializeView();
|
||||
|
||||
if (view != null) {
|
||||
this.view = view;
|
||||
setContentView(this.view);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes a new {@link JitsiMeetView} instance.
|
||||
*
|
||||
* @return a new {@code JitsiMeetView} instance.
|
||||
*/
|
||||
protected JitsiMeetView initializeView() {
|
||||
JitsiMeetView view = new JitsiMeetView(this);
|
||||
|
||||
// XXX Before calling JitsiMeetView#loadURL, make sure to call whatever
|
||||
// is documented to need such an order in order to take effect:
|
||||
view.setDefaultURL(defaultURL);
|
||||
view.setWelcomePageEnabled(welcomePageEnabled);
|
||||
|
||||
view.loadURL(null);
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the given URL and displays the conference. If the specified URL is
|
||||
* null, the welcome page is displayed instead.
|
||||
*
|
||||
* @param url The conference URL.
|
||||
*/
|
||||
public void loadURL(@Nullable URL url) {
|
||||
view.loadURL(url);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onActivityResult(
|
||||
int requestCode,
|
||||
int resultCode,
|
||||
Intent data) {
|
||||
if (requestCode == OVERLAY_PERMISSION_REQUEST_CODE
|
||||
&& canRequestOverlayPermission()) {
|
||||
if (Settings.canDrawOverlays(this)) {
|
||||
initializeContentView();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBackPressed() {
|
||||
if (!JitsiMeetView.onBackPressed()) {
|
||||
// JitsiMeetView didn't handle the invocation of the back button.
|
||||
// Generally, an Activity extender would very likely want to invoke
|
||||
// Activity#onBackPressed(). For the sake of consistency with
|
||||
// JitsiMeetView and within the Jitsi Meet SDK for Android though,
|
||||
// JitsiMeetActivity does what JitsiMeetView would've done if it
|
||||
// were able to handle the invocation.
|
||||
if (defaultBackButtonImpl == null) {
|
||||
super.onBackPressed();
|
||||
} else {
|
||||
defaultBackButtonImpl.invokeDefaultOnBackPressed();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
// In Debug builds React needs permission to write over other apps in
|
||||
// order to display the warning and error overlays.
|
||||
if (canRequestOverlayPermission() && !Settings.canDrawOverlays(this)) {
|
||||
Intent intent
|
||||
= new Intent(
|
||||
Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
|
||||
Uri.parse("package:" + getPackageName()));
|
||||
|
||||
startActivityForResult(intent, OVERLAY_PERMISSION_REQUEST_CODE);
|
||||
return;
|
||||
}
|
||||
|
||||
initializeContentView();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
super.onDestroy();
|
||||
|
||||
if (view != null) {
|
||||
view.dispose();
|
||||
view = null;
|
||||
}
|
||||
|
||||
JitsiMeetView.onHostDestroy(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNewIntent(Intent intent) {
|
||||
JitsiMeetView.onNewIntent(intent);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPause() {
|
||||
super.onPause();
|
||||
|
||||
JitsiMeetView.onHostPause(this);
|
||||
defaultBackButtonImpl = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
|
||||
defaultBackButtonImpl = new DefaultHardwareBackBtnHandlerImpl(this);
|
||||
JitsiMeetView.onHostResume(this, defaultBackButtonImpl);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @see JitsiMeetView#setDefaultURL(URL)
|
||||
*/
|
||||
public void setDefaultURL(URL defaultURL) {
|
||||
if (view == null) {
|
||||
this.defaultURL = defaultURL;
|
||||
} else {
|
||||
view.setDefaultURL(defaultURL);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @see JitsiMeetView#setWelcomePageEnabled(boolean)
|
||||
*/
|
||||
public void setWelcomePageEnabled(boolean welcomePageEnabled) {
|
||||
if (view == null) {
|
||||
this.welcomePageEnabled = welcomePageEnabled;
|
||||
} else {
|
||||
view.setWelcomePageEnabled(welcomePageEnabled);
|
||||
}
|
||||
}
|
||||
}
|
||||
437
android/sdk/src/main/java/org/jitsi/meet/sdk/JitsiMeetView.java
Normal file
437
android/sdk/src/main/java/org/jitsi/meet/sdk/JitsiMeetView.java
Normal file
@@ -0,0 +1,437 @@
|
||||
/*
|
||||
* Copyright @ 2017-present Atlassian Pty Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jitsi.meet.sdk;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.Application;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.widget.FrameLayout;
|
||||
|
||||
import com.facebook.react.ReactInstanceManager;
|
||||
import com.facebook.react.ReactRootView;
|
||||
import com.facebook.react.bridge.NativeModule;
|
||||
import com.facebook.react.bridge.ReactApplicationContext;
|
||||
import com.facebook.react.common.LifecycleState;
|
||||
import com.facebook.react.modules.core.DefaultHardwareBackBtnHandler;
|
||||
|
||||
import java.net.URL;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.WeakHashMap;
|
||||
|
||||
public class JitsiMeetView extends FrameLayout {
|
||||
/**
|
||||
* Background color used by {@code JitsiMeetView} and the React Native root
|
||||
* view.
|
||||
*/
|
||||
private static final int BACKGROUND_COLOR = 0xFF111111;
|
||||
|
||||
/**
|
||||
* React Native bridge. The instance manager allows embedding applications
|
||||
* to create multiple root views off the same JavaScript bundle.
|
||||
*/
|
||||
private static ReactInstanceManager reactInstanceManager;
|
||||
|
||||
private static final Set<JitsiMeetView> views
|
||||
= Collections.newSetFromMap(new WeakHashMap<JitsiMeetView, Boolean>());
|
||||
|
||||
private static List<NativeModule> createNativeModules(
|
||||
ReactApplicationContext reactContext) {
|
||||
return Arrays.<NativeModule>asList(
|
||||
new AndroidSettingsModule(reactContext),
|
||||
new AppInfoModule(reactContext),
|
||||
new AudioModeModule(reactContext),
|
||||
new ExternalAPIModule(reactContext),
|
||||
new ProximityModule(reactContext)
|
||||
);
|
||||
}
|
||||
|
||||
public static JitsiMeetView findViewByExternalAPIScope(
|
||||
String externalAPIScope) {
|
||||
synchronized (views) {
|
||||
for (JitsiMeetView view : views) {
|
||||
if (view.externalAPIScope.equals(externalAPIScope)) {
|
||||
return view;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal method to initialize the React Native instance manager. We
|
||||
* create a single instance in order to load the JavaScript bundle a single
|
||||
* time. All {@code ReactRootView} instances will be tied to the one and
|
||||
* only {@code ReactInstanceManager}.
|
||||
*
|
||||
* @param application {@code Application} instance which is running.
|
||||
*/
|
||||
private static void initReactInstanceManager(Application application) {
|
||||
reactInstanceManager
|
||||
= ReactInstanceManager.builder()
|
||||
.setApplication(application)
|
||||
.setBundleAssetName("index.android.bundle")
|
||||
.setJSMainModuleName("index.android")
|
||||
.addPackage(new com.corbt.keepawake.KCKeepAwakePackage())
|
||||
.addPackage(new com.facebook.react.shell.MainReactPackage())
|
||||
.addPackage(new com.oblador.vectoricons.VectorIconsPackage())
|
||||
.addPackage(new com.ocetnik.timer.BackgroundTimerPackage())
|
||||
.addPackage(new com.oney.WebRTCModule.WebRTCModulePackage())
|
||||
.addPackage(new com.RNFetchBlob.RNFetchBlobPackage())
|
||||
.addPackage(new com.rnimmersive.RNImmersivePackage())
|
||||
.addPackage(new ReactPackageAdapter() {
|
||||
@Override
|
||||
public List<NativeModule> createNativeModules(
|
||||
ReactApplicationContext reactContext) {
|
||||
return JitsiMeetView.createNativeModules(reactContext);
|
||||
}
|
||||
})
|
||||
.setUseDeveloperSupport(BuildConfig.DEBUG)
|
||||
.setInitialLifecycleState(LifecycleState.RESUMED)
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads a specific URL {@code String} in all existing
|
||||
* {@code JitsiMeetView}s.
|
||||
*
|
||||
* @param urlString he URL {@code String} to load in all existing
|
||||
* {@code JitsiMeetView}s.
|
||||
* @return If the specified {@code urlString} was submitted for loading in
|
||||
* at least one {@code JitsiMeetView}, then {@code true}; otherwise,
|
||||
* {@code false}.
|
||||
*/
|
||||
private static boolean loadURLStringInViews(String urlString) {
|
||||
synchronized (views) {
|
||||
if (!views.isEmpty()) {
|
||||
for (JitsiMeetView view : views) {
|
||||
view.loadURLString(urlString);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Activity lifecycle method which should be called from
|
||||
* {@code Activity.onBackPressed} so we can do the required internal
|
||||
* processing.
|
||||
*
|
||||
* @return {@code true} if the back-press was processed; {@code false},
|
||||
* otherwise. If {@code false}, the application should call the parent's
|
||||
* implementation.
|
||||
*/
|
||||
public static boolean onBackPressed() {
|
||||
if (reactInstanceManager == null) {
|
||||
return false;
|
||||
} else {
|
||||
reactInstanceManager.onBackPressed();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Activity lifecycle method which should be called from
|
||||
* {@code Activity.onDestroy} so we can do the required internal
|
||||
* processing.
|
||||
*
|
||||
* @param activity {@code Activity} being destroyed.
|
||||
*/
|
||||
public static void onHostDestroy(Activity activity) {
|
||||
if (reactInstanceManager != null) {
|
||||
reactInstanceManager.onHostDestroy(activity);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Activity lifecycle method which should be called from
|
||||
* {@code Activity.onPause} so we can do the required internal processing.
|
||||
*
|
||||
* @param activity {@code Activity} being paused.
|
||||
*/
|
||||
public static void onHostPause(Activity activity) {
|
||||
if (reactInstanceManager != null) {
|
||||
reactInstanceManager.onHostPause(activity);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Activity lifecycle method which should be called from
|
||||
* {@code Activity.onResume} so we can do the required internal processing.
|
||||
*
|
||||
* @param activity {@code Activity} being resumed.
|
||||
*/
|
||||
public static void onHostResume(Activity activity) {
|
||||
onHostResume(activity, new DefaultHardwareBackBtnHandlerImpl(activity));
|
||||
}
|
||||
|
||||
/**
|
||||
* Activity lifecycle method which should be called from
|
||||
* {@code Activity.onResume} so we can do the required internal processing.
|
||||
*
|
||||
* @param activity {@code Activity} being resumed.
|
||||
* @param defaultBackButtonImpl a {@code DefaultHardwareBackBtnHandler} to
|
||||
* handle invoking the back button if no {@code JitsiMeetView} handles it.
|
||||
*/
|
||||
public static void onHostResume(
|
||||
Activity activity,
|
||||
DefaultHardwareBackBtnHandler defaultBackButtonImpl) {
|
||||
if (reactInstanceManager != null) {
|
||||
reactInstanceManager.onHostResume(activity, defaultBackButtonImpl);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Activity lifecycle method which should be called from
|
||||
* {@code Activity.onNewIntent} so we can do the required internal
|
||||
* processing. Note that this is only needed if the activity's "launchMode"
|
||||
* was set to "singleTask". This is required for deep linking to work once
|
||||
* the application is already running.
|
||||
*
|
||||
* @param intent {@code Intent} instance which was received.
|
||||
*/
|
||||
public static void onNewIntent(Intent intent) {
|
||||
// XXX At least twice we received bug reports about malfunctioning
|
||||
// loadURL in the Jitsi Meet SDK while the Jitsi Meet app seemed to
|
||||
// functioning as expected in our testing. But that was to be expected
|
||||
// because the app does not exercise loadURL. In order to increase the
|
||||
// test coverage of loadURL, channel deep linking through loadURL.
|
||||
Uri uri;
|
||||
|
||||
if (Intent.ACTION_VIEW.equals(intent.getAction())
|
||||
&& (uri = intent.getData()) != null
|
||||
&& loadURLStringInViews(uri.toString())) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (reactInstanceManager != null) {
|
||||
reactInstanceManager.onNewIntent(intent);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The default base {@code URL} used to join a conference when a partial URL
|
||||
* (e.g. a room name only) is specified to {@link #loadURLString(String)} or
|
||||
* {@link #loadURLObject(Bundle)}.
|
||||
*/
|
||||
private URL defaultURL;
|
||||
|
||||
/**
|
||||
* The unique identifier of this {@code JitsiMeetView} within the process
|
||||
* for the purposes of {@link ExternalAPI}. The name scope was inspired by
|
||||
* postis which we use on Web for the similar purposes of the iframe-based
|
||||
* external API.
|
||||
*/
|
||||
private final String externalAPIScope;
|
||||
|
||||
/**
|
||||
* {@link JitsiMeetViewListener} instance for reporting events occurring in
|
||||
* Jitsi Meet.
|
||||
*/
|
||||
private JitsiMeetViewListener listener;
|
||||
|
||||
/**
|
||||
* React Native root view.
|
||||
*/
|
||||
private ReactRootView reactRootView;
|
||||
|
||||
/**
|
||||
* Whether the Welcome page is enabled.
|
||||
*/
|
||||
private boolean welcomePageEnabled;
|
||||
|
||||
public JitsiMeetView(@NonNull Context context) {
|
||||
super(context);
|
||||
|
||||
setBackgroundColor(BACKGROUND_COLOR);
|
||||
|
||||
if (reactInstanceManager == null) {
|
||||
initReactInstanceManager(((Activity) context).getApplication());
|
||||
}
|
||||
|
||||
// Hook this JitsiMeetView into ExternalAPI.
|
||||
externalAPIScope = UUID.randomUUID().toString();
|
||||
synchronized (views) {
|
||||
views.add(this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Releases the React resources (specifically the {@link ReactRootView})
|
||||
* associated with this view.
|
||||
*
|
||||
* This method MUST be called when the Activity holding this view is
|
||||
* destroyed, typically in the {@code onDestroy} method.
|
||||
*/
|
||||
public void dispose() {
|
||||
if (reactRootView != null) {
|
||||
removeView(reactRootView);
|
||||
reactRootView.unmountReactApplication();
|
||||
reactRootView = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the default base {@code URL} used to join a conference when a
|
||||
* partial URL (e.g. a room name only) is specified to
|
||||
* {@link #loadURLString(String)} or {@link #loadURLObject(Bundle)}. If not
|
||||
* set or if set to {@code null}, the default built in JavaScript is used:
|
||||
* {@link https://meet.jit.si}
|
||||
*
|
||||
* @return The default base {@code URL} or {@code null}.
|
||||
*/
|
||||
public URL getDefaultURL() {
|
||||
return defaultURL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the {@link JitsiMeetViewListener} set on this {@code JitsiMeetView}.
|
||||
*
|
||||
* @return The {@code JitsiMeetViewListener} set on this
|
||||
* {@code JitsiMeetView}.
|
||||
*/
|
||||
public JitsiMeetViewListener getListener() {
|
||||
return listener;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets whether the Welcome page is enabled. If {@code true}, the Welcome
|
||||
* page is rendered when this {@code JitsiMeetView} is not at a URL
|
||||
* identifying a Jitsi Meet conference/room.
|
||||
*
|
||||
* @return {@code true} if the Welcome page is enabled; otherwise,
|
||||
* {@code false}.
|
||||
*/
|
||||
public boolean getWelcomePageEnabled() {
|
||||
return welcomePageEnabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads a specific {@link URL} which may identify a conference to join. If
|
||||
* the specified {@code URL} is {@code null} and the Welcome page is
|
||||
* enabled, the Welcome page is displayed instead.
|
||||
*
|
||||
* @param url The {@code URL} to load which may identify a conference to
|
||||
* join.
|
||||
*/
|
||||
public void loadURL(@Nullable URL url) {
|
||||
loadURLString(url == null ? null : url.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads a specific URL which may identify a conference to join. The URL is
|
||||
* specified in the form of a {@link Bundle} of properties which (1)
|
||||
* internally are sufficient to construct a URL {@code String} while (2)
|
||||
* abstracting the specifics of constructing the URL away from API
|
||||
* clients/consumers. If the specified URL is {@code null} and the Welcome
|
||||
* page is enabled, the Welcome page is displayed instead.
|
||||
*
|
||||
* @param urlObject The URL to load which may identify a conference to join.
|
||||
*/
|
||||
public void loadURLObject(@Nullable Bundle urlObject) {
|
||||
Bundle props = new Bundle();
|
||||
|
||||
// defaultURL
|
||||
if (defaultURL != null) {
|
||||
props.putString("defaultURL", defaultURL.toString());
|
||||
}
|
||||
// externalAPIScope
|
||||
props.putString("externalAPIScope", externalAPIScope);
|
||||
// url
|
||||
if (urlObject != null) {
|
||||
props.putBundle("url", urlObject);
|
||||
}
|
||||
// welcomePageEnabled
|
||||
props.putBoolean("welcomePageEnabled", welcomePageEnabled);
|
||||
|
||||
// TODO: ReactRootView#setAppProperties is only available on React
|
||||
// Native 0.45, so destroy the current root view and create a new one.
|
||||
dispose();
|
||||
|
||||
reactRootView = new ReactRootView(getContext());
|
||||
reactRootView.startReactApplication(reactInstanceManager, "App", props);
|
||||
reactRootView.setBackgroundColor(BACKGROUND_COLOR);
|
||||
addView(reactRootView);
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads a specific URL {@link String} which may identify a conference to
|
||||
* join. If the specified URL {@code String} is {@code null} and the Welcome
|
||||
* page is enabled, the Welcome page is displayed instead.
|
||||
*
|
||||
* @param urlString The URL {@code String} to load which may identify a
|
||||
* conference to join.
|
||||
*/
|
||||
public void loadURLString(@Nullable String urlString) {
|
||||
Bundle urlObject;
|
||||
|
||||
if (urlString == null) {
|
||||
urlObject = null;
|
||||
} else {
|
||||
urlObject = new Bundle();
|
||||
urlObject.putString("url", urlString);
|
||||
}
|
||||
loadURLObject(urlObject);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the default base {@code URL} used to join a conference when a
|
||||
* partial URL (e.g. a room name only) is specified to
|
||||
* {@link #loadURLString(String)} or {@link #loadURLObject(Bundle)}. Must be
|
||||
* called before {@link #loadURL(URL)} for it to take effect.
|
||||
*
|
||||
* @param defaultURL The {@code URL} to be set as the default base URL.
|
||||
* @see #getDefaultURL()
|
||||
*/
|
||||
public void setDefaultURL(URL defaultURL) {
|
||||
this.defaultURL = defaultURL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a specific {@link JitsiMeetViewListener} on this
|
||||
* {@code JitsiMeetView}.
|
||||
*
|
||||
* @param listener The {@code JitsiMeetViewListener} to set on this
|
||||
* {@code JitsiMeetView}.
|
||||
*/
|
||||
public void setListener(JitsiMeetViewListener listener) {
|
||||
this.listener = listener;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether the Welcome page is enabled. Must be called before
|
||||
* {@link #loadURL(URL)} for it to take effect.
|
||||
*
|
||||
* @param welcomePageEnabled {@code true} to enable the Welcome page;
|
||||
* otherwise, {@code false}.
|
||||
*/
|
||||
public void setWelcomePageEnabled(boolean welcomePageEnabled) {
|
||||
this.welcomePageEnabled = welcomePageEnabled;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright @ 2017-present Atlassian Pty Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jitsi.meet.sdk;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Implements {@link JitsiMeetViewListener} so apps don't have to add stubs for
|
||||
* all methods in the interface if they are only interested in some.
|
||||
*/
|
||||
public abstract class JitsiMeetViewAdapter implements JitsiMeetViewListener {
|
||||
@Override
|
||||
public void onConferenceFailed(Map<String, Object> data) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConferenceJoined(Map<String, Object> data) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConferenceLeft(Map<String, Object> data) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConferenceWillJoin(Map<String, Object> data) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConferenceWillLeave(Map<String, Object> data) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoadConfigError(Map<String, Object> data) {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright @ 2017-present Atlassian Pty Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jitsi.meet.sdk;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Interface for listening to events coming from Jitsi Meet.
|
||||
*/
|
||||
public interface JitsiMeetViewListener {
|
||||
/**
|
||||
* Called when joining a conference fails or an ongoing conference is
|
||||
* interrupted due to a failure.
|
||||
*
|
||||
* @param data Map with an "error" key describing the problem, and a "url"
|
||||
* key with the conference URL.
|
||||
*/
|
||||
void onConferenceFailed(Map<String, Object> data);
|
||||
|
||||
/**
|
||||
* Called when a conference was joined.
|
||||
*
|
||||
* @param data Map with a "url" key with the conference URL.
|
||||
*/
|
||||
void onConferenceJoined(Map<String, Object> data);
|
||||
|
||||
/**
|
||||
* Called when the conference was left, typically after hanging up.
|
||||
*
|
||||
* @param data Map with a "url" key with the conference URL.
|
||||
*/
|
||||
void onConferenceLeft(Map<String, Object> data);
|
||||
|
||||
/**
|
||||
* Called before the conference is joined.
|
||||
*
|
||||
* @param data Map with a "url" key with the conference URL.
|
||||
*/
|
||||
void onConferenceWillJoin(Map<String, Object> data);
|
||||
|
||||
/**
|
||||
* Called before the conference is left.
|
||||
*
|
||||
* @param data Map with a "url" key with the conference URL.
|
||||
*/
|
||||
void onConferenceWillLeave(Map<String, Object> data);
|
||||
|
||||
/**
|
||||
* Called when loading the main configuration file from the Jitsi Meet
|
||||
* deployment fails.
|
||||
*
|
||||
* @param data Map with an "error" key with the error and a "url" key with
|
||||
* the conference URL which necessitated the loading of the configuration
|
||||
* file.
|
||||
*/
|
||||
void onLoadConfigError(Map<String, Object> data);
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
* Copyright @ 2017-present Atlassian Pty Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jitsi.meet.sdk;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.PowerManager;
|
||||
import android.os.PowerManager.WakeLock;
|
||||
|
||||
import com.facebook.react.bridge.ReactApplicationContext;
|
||||
import com.facebook.react.bridge.ReactContextBaseJavaModule;
|
||||
import com.facebook.react.bridge.ReactMethod;
|
||||
import com.facebook.react.bridge.UiThreadUtil;
|
||||
|
||||
/**
|
||||
* Module implementing a simple API to enable a proximity sensor-controlled
|
||||
* wake lock. When the lock is held, if the proximity sensor detects a nearby
|
||||
* object it will dim the screen and disable touch controls. The functionality
|
||||
* is used with the conference audio-only mode.
|
||||
*/
|
||||
class ProximityModule extends ReactContextBaseJavaModule {
|
||||
/**
|
||||
* The name of {@code ProximityModule} to be used in the React Native
|
||||
* bridge.
|
||||
*/
|
||||
private static final String MODULE_NAME = "Proximity";
|
||||
|
||||
/**
|
||||
* This type of wake lock (the one activated by the proximity sensor) has
|
||||
* been available for a while, but the constant was only exported in API
|
||||
* level 21 (Android Marshmallow) so make no assumptions and use its value
|
||||
* directly.
|
||||
*
|
||||
* TODO: Remove when we bump the API level to 21.
|
||||
*/
|
||||
private static final int PROXIMITY_SCREEN_OFF_WAKE_LOCK = 32;
|
||||
|
||||
/**
|
||||
* {@link WakeLock} instance.
|
||||
*/
|
||||
private final WakeLock wakeLock;
|
||||
|
||||
/**
|
||||
* Initializes a new module instance. There shall be a single instance of
|
||||
* this module throughout the lifetime of the application.
|
||||
*
|
||||
* @param reactContext The {@link ReactApplicationContext} where this module
|
||||
* is created.
|
||||
*/
|
||||
public ProximityModule(ReactApplicationContext reactContext) {
|
||||
super(reactContext);
|
||||
|
||||
WakeLock wakeLock;
|
||||
PowerManager powerManager
|
||||
= (PowerManager)
|
||||
reactContext.getSystemService(Context.POWER_SERVICE);
|
||||
|
||||
try {
|
||||
wakeLock
|
||||
= powerManager.newWakeLock(
|
||||
PROXIMITY_SCREEN_OFF_WAKE_LOCK,
|
||||
MODULE_NAME);
|
||||
} catch (Throwable ignored) {
|
||||
wakeLock = null;
|
||||
}
|
||||
|
||||
this.wakeLock = wakeLock;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the name of this module to be used in the React Native bridge.
|
||||
*
|
||||
* @return The name of this module to be used in the React Native bridge.
|
||||
*/
|
||||
@Override
|
||||
public String getName() {
|
||||
return MODULE_NAME;
|
||||
}
|
||||
|
||||
/**
|
||||
* Acquires / releases the proximity sensor wake lock.
|
||||
*
|
||||
* @param enabled {@code true} to enable the proximity sensor; otherwise,
|
||||
* {@code false}.
|
||||
*/
|
||||
@ReactMethod
|
||||
public void setEnabled(final boolean enabled) {
|
||||
if (wakeLock == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
UiThreadUtil.runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (enabled) {
|
||||
if (!wakeLock.isHeld()) {
|
||||
wakeLock.acquire();
|
||||
}
|
||||
} else if (wakeLock.isHeld()) {
|
||||
wakeLock.release();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright @ 2017-present Atlassian Pty Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jitsi.meet.sdk;
|
||||
|
||||
import com.facebook.react.ReactPackage;
|
||||
import com.facebook.react.bridge.JavaScriptModule;
|
||||
import com.facebook.react.bridge.NativeModule;
|
||||
import com.facebook.react.bridge.ReactApplicationContext;
|
||||
import com.facebook.react.uimanager.ViewManager;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class ReactPackageAdapter implements ReactPackage {
|
||||
@Override
|
||||
public List<Class<? extends JavaScriptModule>> createJSModules() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<NativeModule> createNativeModules(
|
||||
ReactApplicationContext reactContext) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ViewManager> createViewManagers(
|
||||
ReactApplicationContext reactContext) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
3
android/sdk/src/main/res/values/strings.xml
Normal file
3
android/sdk/src/main/res/values/strings.xml
Normal file
@@ -0,0 +1,3 @@
|
||||
<resources>
|
||||
<string name="app_name">Jitsi Meet SDK</string>
|
||||
</resources>
|
||||
15
android/settings.gradle
Normal file
15
android/settings.gradle
Normal file
@@ -0,0 +1,15 @@
|
||||
rootProject.name = 'jitsi-meet'
|
||||
|
||||
include ':app', ':sdk'
|
||||
include ':react-native-background-timer'
|
||||
project(':react-native-background-timer').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-background-timer/android')
|
||||
include ':react-native-fetch-blob'
|
||||
project(':react-native-fetch-blob').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-fetch-blob/android')
|
||||
include ':react-native-immersive'
|
||||
project(':react-native-immersive').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-immersive/android')
|
||||
include ':react-native-keep-awake'
|
||||
project(':react-native-keep-awake').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-keep-awake/android')
|
||||
include ':react-native-vector-icons'
|
||||
project(':react-native-vector-icons').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-vector-icons/android')
|
||||
include ':react-native-webrtc'
|
||||
project(':react-native-webrtc').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-webrtc/android')
|
||||
167
app.js
167
app.js
@@ -1,144 +1,57 @@
|
||||
/* global $, JitsiMeetJS, config, getRoomName */
|
||||
/* application specific logic */
|
||||
|
||||
import "babel-polyfill";
|
||||
import "jquery";
|
||||
import "jquery-ui";
|
||||
import "strophe";
|
||||
import "strophe-disco";
|
||||
import "strophe-caps";
|
||||
import "tooltip";
|
||||
import "popover";
|
||||
import "jQuery-Impromptu";
|
||||
import "autosize";
|
||||
window.toastr = require("toastr");
|
||||
import 'jquery';
|
||||
import 'jquery-contextmenu';
|
||||
import 'jquery-ui';
|
||||
import 'strophe';
|
||||
import 'strophe-disco';
|
||||
import 'jQuery-Impromptu';
|
||||
import 'autosize';
|
||||
|
||||
import URLProcessor from "./modules/config/URLProcessor";
|
||||
import RoomnameGenerator from './modules/util/RoomnameGenerator';
|
||||
import 'aui';
|
||||
import 'aui-experimental';
|
||||
import 'aui-css';
|
||||
import 'aui-experimental-css';
|
||||
|
||||
import UI from "./modules/UI/UI";
|
||||
import settings from "./modules/settings/Settings";
|
||||
import conference from './conference';
|
||||
import API from './modules/API/API';
|
||||
import API from './modules/API';
|
||||
import keyboardshortcut from './modules/keyboardshortcut/keyboardshortcut';
|
||||
import remoteControl from './modules/remotecontrol/RemoteControl';
|
||||
import settings from './modules/settings/Settings';
|
||||
import translation from './modules/translation/translation';
|
||||
import UI from './modules/UI/UI';
|
||||
|
||||
import UIEvents from './service/UI/UIEvents';
|
||||
window.APP = {
|
||||
API,
|
||||
conference,
|
||||
|
||||
/**
|
||||
* Builds and returns the room name.
|
||||
*/
|
||||
function buildRoomName () {
|
||||
let roomName = getRoomName();
|
||||
|
||||
if(!roomName) {
|
||||
let word = RoomnameGenerator.generateRoomWithoutSeparator();
|
||||
roomName = word.toLowerCase();
|
||||
window.history.pushState(
|
||||
'VideoChat', `Room: ${word}`, window.location.pathname + word
|
||||
);
|
||||
}
|
||||
|
||||
return roomName;
|
||||
}
|
||||
|
||||
const APP = {
|
||||
// Used by do_external_connect.js if we receive the attach data after
|
||||
// connect was already executed. status property can be "initialized",
|
||||
// "ready" or "connecting". We are interested in "ready" status only which
|
||||
// connect was already executed. status property can be 'initialized',
|
||||
// 'ready', or 'connecting'. We are interested in 'ready' status only which
|
||||
// means that connect was executed but we have to wait for the attach data.
|
||||
// In status "ready" handler property will be set to a function that will
|
||||
// In status 'ready' handler property will be set to a function that will
|
||||
// finish the connect process when the attach data or error is received.
|
||||
connect: {
|
||||
status: "initialized",
|
||||
handler: null
|
||||
handler: null,
|
||||
status: 'initialized'
|
||||
},
|
||||
// Used for automated performance tests
|
||||
|
||||
// Used for automated performance tests.
|
||||
connectionTimes: {
|
||||
"index.loaded": window.indexLoadedTime
|
||||
'index.loaded': window.indexLoadedTime
|
||||
},
|
||||
UI,
|
||||
|
||||
keyboardshortcut,
|
||||
remoteControl,
|
||||
settings,
|
||||
conference,
|
||||
connection: null,
|
||||
API,
|
||||
init () {
|
||||
this.keyboardshortcut =
|
||||
require("./modules/keyboardshortcut/keyboardshortcut");
|
||||
this.translation = require("./modules/translation/translation");
|
||||
this.configFetch = require("./modules/config/HttpConfigFetch");
|
||||
}
|
||||
translation,
|
||||
UI
|
||||
};
|
||||
|
||||
function init() {
|
||||
var isUIReady = APP.UI.start();
|
||||
if (isUIReady) {
|
||||
APP.conference.init({roomName: buildRoomName()}).then(function () {
|
||||
APP.UI.initConference();
|
||||
|
||||
APP.UI.addListener(UIEvents.LANG_CHANGED, function (language) {
|
||||
APP.translation.setLanguage(language);
|
||||
APP.settings.setLanguage(language);
|
||||
});
|
||||
|
||||
APP.keyboardshortcut.init();
|
||||
}).catch(function (err) {
|
||||
console.error(err);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If we have an HTTP endpoint for getting config.json configured we're going to
|
||||
* read it and override properties from config.js and interfaceConfig.js.
|
||||
* If there is no endpoint we'll just continue with initialization.
|
||||
* Keep in mind that if the endpoint has been configured and we fail to obtain
|
||||
* the config for any reason then the conference won't start and error message
|
||||
* will be displayed to the user.
|
||||
*/
|
||||
function obtainConfigAndInit() {
|
||||
let roomName = APP.conference.roomName;
|
||||
|
||||
if (config.configLocation) {
|
||||
APP.configFetch.obtainConfig(
|
||||
config.configLocation, roomName,
|
||||
// Get config result callback
|
||||
function(success, error) {
|
||||
if (success) {
|
||||
var now = APP.connectionTimes["configuration.fetched"] =
|
||||
window.performance.now();
|
||||
console.log("(TIME) configuration fetched:\t", now);
|
||||
init();
|
||||
} else {
|
||||
// Show obtain config error,
|
||||
// pass the error object for report
|
||||
APP.UI.messageHandler.openReportDialog(
|
||||
null, "dialog.connectError", error);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
require("./modules/config/BoshAddressChoice").chooseAddress(
|
||||
config, roomName);
|
||||
|
||||
init();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
$(document).ready(function () {
|
||||
var now = APP.connectionTimes["document.ready"] = window.performance.now();
|
||||
console.log("(TIME) document ready:\t", now);
|
||||
|
||||
URLProcessor.setConfigParametersFromUrl();
|
||||
APP.init();
|
||||
|
||||
APP.translation.init(settings.getLanguage());
|
||||
|
||||
APP.API.init();
|
||||
|
||||
obtainConfigAndInit();
|
||||
});
|
||||
|
||||
$(window).bind('beforeunload', function () {
|
||||
APP.API.dispose();
|
||||
});
|
||||
|
||||
module.exports = APP;
|
||||
// TODO The execution of the mobile app starts from react/index.native.js.
|
||||
// Similarly, the execution of the Web app should start from react/index.web.js
|
||||
// for the sake of consistency and ease of understanding. Temporarily though
|
||||
// because we are at the beginning of introducing React into the Web app, allow
|
||||
// the execution of the Web app to start from app.js in order to reduce the
|
||||
// complexity of the beginning step.
|
||||
import './react';
|
||||
|
||||
2547
conference.js
2547
conference.js
File diff suppressed because it is too large
Load Diff
308
config.js
308
config.js
@@ -1,74 +1,278 @@
|
||||
/* jshint -W101 */
|
||||
var config = {
|
||||
// configLocation: './config.json', // see ./modules/HttpConfigFetch.js
|
||||
hosts: {
|
||||
domain: 'jitsi-meet.example.com',
|
||||
//anonymousdomain: 'guest.example.com',
|
||||
//authdomain: 'jitsi-meet.example.com', // defaults to <domain>
|
||||
muc: 'conference.jitsi-meet.example.com', // FIXME: use XEP-0030
|
||||
bridge: 'jitsi-videobridge.jitsi-meet.example.com', // FIXME: use XEP-0030
|
||||
//jirecon: 'jirecon.jitsi-meet.example.com',
|
||||
//call_control: 'callcontrol.jitsi-meet.example.com',
|
||||
//focus: 'focus.jitsi-meet.example.com', // defaults to 'focus.jitsi-meet.example.com'
|
||||
},
|
||||
// getroomnode: function (path) { return 'someprefixpossiblybasedonpath'; },
|
||||
// useStunTurn: true, // use XEP-0215 to fetch STUN and TURN server
|
||||
// useIPv6: true, // ipv6 support. use at your own risk
|
||||
useNicks: false,
|
||||
bosh: '//jitsi-meet.example.com/http-bind', // FIXME: use xep-0156 for that
|
||||
clientNode: 'http://jitsi.org/jitsimeet', // The name of client node advertised in XEP-0115 'c' stanza
|
||||
//focusUserJid: 'focus@auth.jitsi-meet.example.com', // The real JID of focus participant - can be overridden here
|
||||
//defaultSipNumber: '', // Default SIP number
|
||||
var config = { // eslint-disable-line no-unused-vars
|
||||
// Configuration
|
||||
//
|
||||
|
||||
// Alternative location for the configuration.
|
||||
//configLocation: './config.json',
|
||||
|
||||
// Custom function which given the URL path should return a room name.
|
||||
//getroomnode: function (path) { return 'someprefixpossiblybasedonpath'; },
|
||||
|
||||
|
||||
// Connection
|
||||
//
|
||||
|
||||
hosts: {
|
||||
// XMPP domain.
|
||||
domain: 'jitsi-meet.example.com',
|
||||
|
||||
// XMPP MUC domain. FIXME: use XEP-0030 to discover it.
|
||||
muc: 'conference.jitsi-meet.example.com',
|
||||
|
||||
// When using authentication, domain for guest users.
|
||||
//anonymousdomain: 'guest.example.com',
|
||||
|
||||
// Domain for authenticated users. Defaults to <domain>.
|
||||
//authdomain: 'jitsi-meet.example.com',
|
||||
|
||||
// Jirecon recording component domain.
|
||||
//jirecon: 'jirecon.jitsi-meet.example.com',
|
||||
|
||||
// Call control component (Jigasi).
|
||||
//call_control: 'callcontrol.jitsi-meet.example.com',
|
||||
|
||||
// Focus component domain. Defaults to focus.<domain>.
|
||||
//focus: 'focus.jitsi-meet.example.com',
|
||||
},
|
||||
|
||||
// BOSH URL. FIXME: use XEP-0156 to discover it.
|
||||
bosh: '//jitsi-meet.example.com/http-bind',
|
||||
|
||||
// The name of client node advertised in XEP-0115 'c' stanza
|
||||
clientNode: 'http://jitsi.org/jitsimeet',
|
||||
|
||||
// The real JID of focus participant - can be overridden here
|
||||
//focusUserJid: 'focus@auth.jitsi-meet.example.com',
|
||||
|
||||
|
||||
// Testing / experimental features.
|
||||
//
|
||||
|
||||
testing: {
|
||||
// Enables experimental simulcast support on Firefox.
|
||||
enableFirefoxSimulcast: false,
|
||||
// P2P test mode disables automatic switching to P2P when there are 2
|
||||
// participants in the conference.
|
||||
p2pTestMode: false,
|
||||
},
|
||||
|
||||
// Disables ICE/UDP by filtering out local and remote UDP candidates in
|
||||
// signalling.
|
||||
//webrtcIceUdpDisable: false,
|
||||
|
||||
// Disables ICE/TCP by filtering out local and remote TCP candidates in
|
||||
// signalling.
|
||||
//webrtcIceTcpDisable: false,
|
||||
|
||||
|
||||
// Media
|
||||
//
|
||||
|
||||
// Audio
|
||||
|
||||
// Disable measuring of audio levels.
|
||||
//disableAudioLevels: false,
|
||||
|
||||
// Start the conference in audio only mode (no video is being received nor
|
||||
// sent).
|
||||
//startAudioOnly: false,
|
||||
|
||||
// Every participant after the Nth will start audio muted.
|
||||
//startAudioMuted: 10,
|
||||
|
||||
// Start calls with audio muted. Unlike the option above, this one is only
|
||||
// applied locally. FIXME: having these 2 options is confusing.
|
||||
//startWithAudioMuted: false,
|
||||
|
||||
// Video
|
||||
|
||||
// Sets the preferred resolution (height) for local video. Defaults to 720.
|
||||
//resolution: 720,
|
||||
|
||||
// Enable / disable simulcast support.
|
||||
//disableSimulcast: false,
|
||||
|
||||
// Suspend sending video if bandwidth estimation is too low. This may cause
|
||||
// problems with audio playback. Disabled until these are fixed.
|
||||
disableSuspendVideo: true,
|
||||
|
||||
// Every participant after the Nth will start video muted.
|
||||
//startVideoMuted: 10,
|
||||
|
||||
// Start calls with video muted. Unlike the option above, this one is only
|
||||
// applied locally. FIXME: having these 2 options is confusing.
|
||||
//startWithVideoMuted: false,
|
||||
|
||||
// If set to true, prefer to use the H.264 video codec (if supported).
|
||||
// Note that it's not recommended to do this because simulcast is not
|
||||
// supported when using H.264. For 1-to-1 calls this setting is enabled by
|
||||
// default and can be toggled in the p2p section.
|
||||
//preferH264: true,
|
||||
|
||||
// Desktop sharing
|
||||
|
||||
// Enable / disable desktop sharing
|
||||
//disableDesktopSharing: false,
|
||||
|
||||
// Desktop sharing method. Can be set to 'ext', 'webrtc' or false to disable.
|
||||
desktopSharingChromeMethod: 'ext',
|
||||
// The ID of the jidesha extension for Chrome.
|
||||
desktopSharingChromeExtId: 'diibjkoicjeejcmhdnailmkgecihlobk',
|
||||
desktopSharingChromeExtId: null,
|
||||
|
||||
// Whether desktop sharing should be disabled on Chrome.
|
||||
desktopSharingChromeDisabled: true,
|
||||
|
||||
// The media sources to use when using screen sharing with the Chrome
|
||||
// extension.
|
||||
desktopSharingChromeSources: ['screen', 'window'],
|
||||
desktopSharingChromeSources: ['screen', 'window', 'tab'],
|
||||
|
||||
// Required version of Chrome extension
|
||||
desktopSharingChromeMinExtVersion: '0.1',
|
||||
|
||||
// The ID of the jidesha extension for Firefox. If null, we assume that no
|
||||
// extension is required.
|
||||
desktopSharingFirefoxExtId: null,
|
||||
|
||||
// Whether desktop sharing should be disabled on Firefox.
|
||||
desktopSharingFirefoxDisabled: true,
|
||||
desktopSharingFirefoxDisabled: false,
|
||||
|
||||
// The maximum version of Firefox which requires a jidesha extension.
|
||||
// Example: if set to 41, we will require the extension for Firefox versions
|
||||
// up to and including 41. On Firefox 42 and higher, we will run without the
|
||||
// extension.
|
||||
// If set to -1, an extension will be required for all versions of Firefox.
|
||||
desktopSharingFirefoxMaxVersionExtRequired: -1,
|
||||
desktopSharingFirefoxMaxVersionExtRequired: 51,
|
||||
|
||||
// The URL to the Firefox extension for desktop sharing.
|
||||
desktopSharingFirefoxExtensionURL: null,
|
||||
|
||||
// Disables ICE/UDP by filtering out local and remote UDP candidates in signalling.
|
||||
webrtcIceUdpDisable: false,
|
||||
// Disables ICE/TCP by filtering out local and remote TCP candidates in signalling.
|
||||
webrtcIceTcpDisable: false,
|
||||
// Try to start calls with screen-sharing instead of camera video.
|
||||
//startScreenSharing: false,
|
||||
|
||||
openSctp: true, // Toggle to enable/disable SCTP channels
|
||||
disableStats: false,
|
||||
disableAudioLevels: false,
|
||||
channelLastN: -1, // The default value of the channel attribute last-n.
|
||||
adaptiveLastN: false,
|
||||
//disableAdaptiveSimulcast: false,
|
||||
enableRecording: false,
|
||||
// Recording
|
||||
|
||||
// Whether to enable recording or not.
|
||||
//enableRecording: false,
|
||||
|
||||
// Type for recording: one of jibri or jirecon.
|
||||
//recordingType: 'jibri',
|
||||
|
||||
// Misc
|
||||
|
||||
// Default value for the channel "last N" attribute. -1 for unlimited.
|
||||
channelLastN: -1,
|
||||
|
||||
// Disables or enables RTX (RFC 4588) (defaults to false).
|
||||
//disableRtx: false,
|
||||
|
||||
// Use XEP-0215 to fetch STUN and TURN servers.
|
||||
//useStunTurn: true,
|
||||
|
||||
// Enable IPv6 support.
|
||||
//useIPv6: true,
|
||||
|
||||
// Enables / disables a data communication channel with the Videobridge.
|
||||
// Values can be 'datachannel', 'websocket', true (treat it as
|
||||
// 'datachannel'), undefined (treat it as 'datachannel') and false (don't
|
||||
// open any channel).
|
||||
//openBridgeChannel: true,
|
||||
|
||||
|
||||
// UI
|
||||
//
|
||||
|
||||
// Use display name as XMPP nickname.
|
||||
//useNicks: false,
|
||||
|
||||
// Require users to always specify a display name.
|
||||
//requireDisplayName: true,
|
||||
|
||||
// Whether to use a welcome page or not. In case it's false a random room
|
||||
// will be joined when no room is specified.
|
||||
enableWelcomePage: true,
|
||||
disableSimulcast: false,
|
||||
logStats: false, // Enable logging of PeerConnection stats via the focus
|
||||
// requireDisplayName: true, // Forces the participants that doesn't have display name to enter it when they enter the room.
|
||||
// startAudioMuted: 10, // every participant after the Nth will start audio muted
|
||||
// startVideoMuted: 10, // every participant after the Nth will start video muted
|
||||
// defaultLanguage: "en",
|
||||
// To enable sending statistics to callstats.io you should provide Applicaiton ID and Secret.
|
||||
// callStatsID: "", // Application ID for callstats.io API
|
||||
// callStatsSecret: "", // Secret for callstats.io API
|
||||
/*noticeMessage: 'Service update is scheduled for 16th March 2015. ' +
|
||||
'During that time service will not be available. ' +
|
||||
'Apologise for inconvenience.',*/
|
||||
disableThirdPartyRequests: false,
|
||||
minHDHeight: 540
|
||||
|
||||
// Enabling the close page will ignore the welcome page redirection when
|
||||
// a call is hangup.
|
||||
//enableClosePage: false,
|
||||
|
||||
// Disable hiding of remote thumbnails when in a 1-on-1 conference call.
|
||||
//disable1On1Mode: false,
|
||||
|
||||
// The minimum value a video's height (or width, whichever is smaller) needs
|
||||
// to be in order to be considered high-definition.
|
||||
minHDHeight: 540,
|
||||
|
||||
// Default language for the user interface.
|
||||
//defaultLanguage: 'en',
|
||||
|
||||
// If true all users without a token will be considered guests and all users
|
||||
// with token will be considered non-guests. Only guests will be allowed to
|
||||
// edit their profile.
|
||||
enableUserRolesBasedOnToken: false,
|
||||
|
||||
// Message to show the users. Example: 'The service will be down for
|
||||
// maintenance at 01:00 AM GMT,
|
||||
//noticeMessage: '',
|
||||
|
||||
|
||||
// Stats
|
||||
//
|
||||
|
||||
// Whether to enable stats collection or not.
|
||||
//disableStats: false,
|
||||
|
||||
// To enable sending statistics to callstats.io you must provide the
|
||||
// Application ID and Secret.
|
||||
//callStatsID: '',
|
||||
//callStatsSecret: '',
|
||||
|
||||
|
||||
// Privacy
|
||||
//
|
||||
|
||||
// If third party requests are disabled, no other server will be contacted.
|
||||
// This means avatars will be locally generated and callstats integration
|
||||
// will not function.
|
||||
//disableThirdPartyRequests: false,
|
||||
|
||||
|
||||
// Peer-To-Peer mode: used (if enabled) when there are just 2 participants.
|
||||
//
|
||||
|
||||
p2p: {
|
||||
// Enables peer to peer mode. When enabled the system will try to
|
||||
// establish a direct connection when there are exactly 2 participants
|
||||
// in the room. If that succeeds the conference will stop sending data
|
||||
// through the JVB and use the peer to peer connection instead. When a
|
||||
// 3rd participant joins the conference will be moved back to the JVB
|
||||
// connection.
|
||||
enabled: true,
|
||||
|
||||
// Use XEP-0215 to fetch STUN and TURN servers.
|
||||
//useStunTurn: true,
|
||||
|
||||
// The STUN servers that will be used in the peer to peer connections
|
||||
stunServers: [
|
||||
{ urls: "stun:stun.l.google.com:19302" },
|
||||
{ urls: "stun:stun1.l.google.com:19302" },
|
||||
{ urls: "stun:stun2.l.google.com:19302" }
|
||||
],
|
||||
|
||||
// If set to true, it will prefer to use H.264 for P2P calls (if H.264
|
||||
// is supported).
|
||||
preferH264: true
|
||||
|
||||
// How long we're going to wait, before going back to P2P after the 3rd
|
||||
// participant has left the conference (to filter out page reload).
|
||||
//backToP2PDelay: 5
|
||||
},
|
||||
|
||||
|
||||
// Information about the jitsi-meet instance we are connecting to, including
|
||||
// the user region as seen by the server.
|
||||
//
|
||||
|
||||
deploymentInfo: {
|
||||
//shard: "shard1",
|
||||
//region: "europe",
|
||||
//userRegion: "asia"
|
||||
}
|
||||
};
|
||||
|
||||
110
connection.js
110
connection.js
@@ -1,9 +1,19 @@
|
||||
/* global APP, JitsiMeetJS, config */
|
||||
//FIXME:
|
||||
import LoginDialog from './modules/UI/authentication/LoginDialog';
|
||||
|
||||
import AuthHandler from './modules/UI/authentication/AuthHandler';
|
||||
import jitsiLocalStorage from './modules/util/JitsiLocalStorage';
|
||||
|
||||
import {
|
||||
connectionEstablished,
|
||||
connectionFailed
|
||||
} from './react/features/base/connection';
|
||||
import {
|
||||
isFatalJitsiConnectionError
|
||||
} from './react/features/base/lib-jitsi-meet';
|
||||
|
||||
const ConnectionEvents = JitsiMeetJS.events.connection;
|
||||
const ConnectionErrors = JitsiMeetJS.errors.connection;
|
||||
const logger = require("jitsi-meet-logger").getLogger(__filename);
|
||||
|
||||
/**
|
||||
* Checks if we have data to use attach instead of connect. If we have the data
|
||||
@@ -51,40 +61,57 @@ function checkForAttachParametersAndConnect(id, password, connection) {
|
||||
* everything is ok, else error.
|
||||
*/
|
||||
function connect(id, password, roomName) {
|
||||
|
||||
let connectionConfig = Object.assign({}, config);
|
||||
const connectionConfig = Object.assign({}, config);
|
||||
const { issuer, jwt } = APP.store.getState()['features/jwt'];
|
||||
|
||||
connectionConfig.bosh += '?room=' + roomName;
|
||||
|
||||
let connection
|
||||
= new JitsiMeetJS.JitsiConnection(null, config.token, connectionConfig);
|
||||
= new JitsiMeetJS.JitsiConnection(
|
||||
null,
|
||||
jwt && issuer && issuer !== 'anonymous' ? jwt : undefined,
|
||||
connectionConfig);
|
||||
|
||||
return new Promise(function (resolve, reject) {
|
||||
connection.addEventListener(
|
||||
ConnectionEvents.CONNECTION_ESTABLISHED, handleConnectionEstablished
|
||||
);
|
||||
ConnectionEvents.CONNECTION_ESTABLISHED,
|
||||
handleConnectionEstablished);
|
||||
connection.addEventListener(
|
||||
ConnectionEvents.CONNECTION_FAILED, handleConnectionFailed
|
||||
);
|
||||
ConnectionEvents.CONNECTION_FAILED,
|
||||
handleConnectionFailed);
|
||||
connection.addEventListener(
|
||||
ConnectionEvents.CONNECTION_FAILED,
|
||||
connectionFailedHandler);
|
||||
|
||||
function connectionFailedHandler(error, message, credentials) {
|
||||
APP.store.dispatch(
|
||||
connectionFailed(connection, error, message, credentials));
|
||||
|
||||
if (isFatalJitsiConnectionError(error)) {
|
||||
connection.removeEventListener(
|
||||
ConnectionEvents.CONNECTION_FAILED,
|
||||
connectionFailedHandler);
|
||||
}
|
||||
}
|
||||
|
||||
function unsubscribe() {
|
||||
connection.removeEventListener(
|
||||
ConnectionEvents.CONNECTION_ESTABLISHED,
|
||||
handleConnectionEstablished
|
||||
);
|
||||
handleConnectionEstablished);
|
||||
connection.removeEventListener(
|
||||
ConnectionEvents.CONNECTION_FAILED,
|
||||
handleConnectionFailed
|
||||
);
|
||||
handleConnectionFailed);
|
||||
}
|
||||
|
||||
function handleConnectionEstablished() {
|
||||
APP.store.dispatch(connectionEstablished(connection));
|
||||
unsubscribe();
|
||||
resolve(connection);
|
||||
}
|
||||
|
||||
function handleConnectionFailed(err) {
|
||||
unsubscribe();
|
||||
console.error("CONNECTION FAILED:", err);
|
||||
logger.error("CONNECTION FAILED:", err);
|
||||
reject(err);
|
||||
}
|
||||
|
||||
@@ -92,33 +119,6 @@ function connect(id, password, roomName) {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Show Authentication Dialog and try to connect with new credentials.
|
||||
* If failed to connect because of PASSWORD_REQUIRED error
|
||||
* then ask for password again.
|
||||
* @param {string} [roomName]
|
||||
* @returns {Promise<JitsiConnection>}
|
||||
*/
|
||||
function requestAuth(roomName) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
let authDialog = LoginDialog.showAuthDialog(
|
||||
function (id, password) {
|
||||
connect(id, password, roomName).then(function (connection) {
|
||||
authDialog.close();
|
||||
resolve(connection);
|
||||
}, function (err) {
|
||||
if (err === ConnectionErrors.PASSWORD_REQUIRED) {
|
||||
authDialog.displayError(err);
|
||||
} else {
|
||||
authDialog.close();
|
||||
reject(err);
|
||||
}
|
||||
});
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Open JitsiConnection using provided credentials.
|
||||
* If retry option is true it will show auth dialog on PASSWORD_REQUIRED error.
|
||||
@@ -133,34 +133,28 @@ function requestAuth(roomName) {
|
||||
* @returns {Promise<JitsiConnection>}
|
||||
*/
|
||||
export function openConnection({id, password, retry, roomName}) {
|
||||
|
||||
let usernameOverride
|
||||
= window.localStorage.getItem("xmpp_username_override");
|
||||
= jitsiLocalStorage.getItem("xmpp_username_override");
|
||||
let passwordOverride
|
||||
= window.localStorage.getItem("xmpp_password_override");
|
||||
= jitsiLocalStorage.getItem("xmpp_password_override");
|
||||
|
||||
if (usernameOverride && usernameOverride.length > 0) {
|
||||
id = usernameOverride;
|
||||
}
|
||||
|
||||
if (passwordOverride && passwordOverride.length > 0) {
|
||||
password = passwordOverride;
|
||||
}
|
||||
|
||||
return connect(id, password, roomName).catch(function (err) {
|
||||
if (!retry) {
|
||||
throw err;
|
||||
return connect(id, password, roomName).catch(err => {
|
||||
if (retry) {
|
||||
const { issuer, jwt } = APP.store.getState()['features/jwt'];
|
||||
|
||||
if (err === ConnectionErrors.PASSWORD_REQUIRED
|
||||
&& (!jwt || issuer === 'anonymous')) {
|
||||
return AuthHandler.requestAuth(roomName, connect);
|
||||
}
|
||||
}
|
||||
|
||||
if (err === ConnectionErrors.PASSWORD_REQUIRED) {
|
||||
// do not retry if token is not valid
|
||||
if (config.token) {
|
||||
throw err;
|
||||
} else {
|
||||
return requestAuth(roomName);
|
||||
}
|
||||
} else {
|
||||
throw err;
|
||||
}
|
||||
throw err;
|
||||
});
|
||||
}
|
||||
|
||||
3
connection_optimization/.eslintrc.js
Normal file
3
connection_optimization/.eslintrc.js
Normal file
@@ -0,0 +1,3 @@
|
||||
module.exports = {
|
||||
'extends': '../react/.eslintrc.js'
|
||||
};
|
||||
@@ -1,73 +1,82 @@
|
||||
/* global config, getRoomName, getConfigParamsFromUrl */
|
||||
/* global createConnectionExternally */
|
||||
/* global config, createConnectionExternally */
|
||||
|
||||
import getRoomName from '../react/features/base/config/getRoomName';
|
||||
import parseURLParams from '../react/features/base/config/parseURLParams';
|
||||
|
||||
/**
|
||||
* Implements extrnal connect using createConnectionExtenally function defined
|
||||
* in external_connect.js for Jitsi Meet. Parses the room name and token from
|
||||
* the url and executes createConnectionExtenally.
|
||||
* Implements external connect using createConnectionExternally function defined
|
||||
* in external_connect.js for Jitsi Meet. Parses the room name and JSON Web
|
||||
* Token (JWT) from the URL and executes createConnectionExternally.
|
||||
*
|
||||
* NOTE: If you are using lib-jitsi-meet without Jitsi Meet you should use this
|
||||
* file as reference only because the implementation is Jitsi Meet specific.
|
||||
* NOTE: If you are using lib-jitsi-meet without Jitsi Meet, you should use this
|
||||
* file as reference only because the implementation is Jitsi Meet-specific.
|
||||
*
|
||||
* NOTE: For optimal results this file should be included right after
|
||||
* exrnal_connect.js.
|
||||
* external_connect.js.
|
||||
*/
|
||||
|
||||
if (typeof createConnectionExternally === 'function') {
|
||||
// URL params have higher proirity than config params.
|
||||
let url
|
||||
= parseURLParams(window.location, true, 'hash')[
|
||||
'config.externalConnectUrl']
|
||||
|| config.externalConnectUrl;
|
||||
let roomName;
|
||||
|
||||
if (url && (roomName = getRoomName())) {
|
||||
url += `?room=${roomName}`;
|
||||
|
||||
const token = parseURLParams(window.location, true, 'search').jwt;
|
||||
|
||||
if (token) {
|
||||
url += `&token=${token}`;
|
||||
}
|
||||
|
||||
createConnectionExternally(
|
||||
url,
|
||||
connectionInfo => {
|
||||
// Sets that global variable to be used later by connect method
|
||||
// in connection.js.
|
||||
window.XMPPAttachInfo = {
|
||||
status: 'success',
|
||||
data: connectionInfo
|
||||
};
|
||||
checkForConnectHandlerAndConnect();
|
||||
},
|
||||
errorCallback);
|
||||
} else {
|
||||
errorCallback();
|
||||
}
|
||||
} else {
|
||||
errorCallback();
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes createConnectionExternally function.
|
||||
* Check if connect from connection.js was executed and executes the handler
|
||||
* that is going to finish the connect work.
|
||||
*
|
||||
* @returns {void}
|
||||
*/
|
||||
(function () {
|
||||
var params = getConfigParamsFromUrl();
|
||||
|
||||
//Url params have higher proirity than config params
|
||||
var url = config.externalConnectUrl;
|
||||
if(params.hasOwnProperty('config.externalConnectUrl'))
|
||||
url = params["config.externalConnectUrl"];
|
||||
function checkForConnectHandlerAndConnect() {
|
||||
window.APP
|
||||
&& window.APP.connect.status === 'ready'
|
||||
&& window.APP.connect.handler();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if connect from connection.js was executed and executes the handler
|
||||
* that is going to finish the connect work.
|
||||
*/
|
||||
function checkForConnectHandlerAndConnect() {
|
||||
/**
|
||||
* Implements a callback to be invoked if anything goes wrong.
|
||||
*
|
||||
* @param {Error} error - The specifics of what went wrong.
|
||||
* @returns {void}
|
||||
*/
|
||||
function errorCallback(error) {
|
||||
// The value of error is undefined if external connect is disabled.
|
||||
error && console.warn(error);
|
||||
|
||||
if(window.APP && window.APP.connect.status === "ready") {
|
||||
window.APP.connect.handler();
|
||||
}
|
||||
}
|
||||
|
||||
function error_callback(error){
|
||||
if(error) //error=undefined if external connect is disabled.
|
||||
console.warn(error);
|
||||
// Sets that global variable to be used later by connect method in
|
||||
// connection.js
|
||||
window.XMPPAttachInfo = {
|
||||
status: "error"
|
||||
};
|
||||
checkForConnectHandlerAndConnect();
|
||||
}
|
||||
|
||||
if(!url || !window.createConnectionExternally) {
|
||||
error_callback();
|
||||
return;
|
||||
}
|
||||
var room_name = getRoomName();
|
||||
if(!room_name) {
|
||||
error_callback();
|
||||
return;
|
||||
}
|
||||
|
||||
url += "?room=" + room_name;
|
||||
|
||||
var token = params["config.token"] || config.token;
|
||||
if(token)
|
||||
url += "&token=" + token;
|
||||
|
||||
createConnectionExternally(url, function(connectionInfo) {
|
||||
// Sets that global variable to be used later by connect method in
|
||||
// connection.js
|
||||
window.XMPPAttachInfo = {
|
||||
status: "success",
|
||||
data: connectionInfo
|
||||
};
|
||||
checkForConnectHandlerAndConnect();
|
||||
}, error_callback);
|
||||
})();
|
||||
// Sets that global variable to be used later by connect method in
|
||||
// connection.js.
|
||||
window.XMPPAttachInfo = {
|
||||
status: 'error'
|
||||
};
|
||||
checkForConnectHandlerAndConnect();
|
||||
}
|
||||
|
||||
14
css/404.scss
Normal file
14
css/404.scss
Normal file
@@ -0,0 +1,14 @@
|
||||
.error_page {
|
||||
width: 60%;
|
||||
margin: 20% auto;
|
||||
text-align: center;
|
||||
|
||||
h2 {
|
||||
font-size: 36px;
|
||||
}
|
||||
|
||||
&__message {
|
||||
font-size: 24px;
|
||||
margin-top: 20px;
|
||||
}
|
||||
}
|
||||
69
css/_animations.scss
Normal file
69
css/_animations.scss
Normal file
@@ -0,0 +1,69 @@
|
||||
/**
|
||||
* Project animations
|
||||
**/
|
||||
|
||||
/**
|
||||
* Slide in animation for extended toolbar.
|
||||
*/
|
||||
@include keyframes(slideInX) {
|
||||
0% { transform: translateX(-100%); }
|
||||
100% { transform: translateX(0%); }
|
||||
}
|
||||
|
||||
@include keyframes(slideOutX) {
|
||||
0% { transform: translateX(0%); }
|
||||
100% { transform: translateX(-100%); }
|
||||
}
|
||||
|
||||
@include keyframes(slideInExtX) {
|
||||
0% { transform: translateX(-500%); }
|
||||
100% { transform: translateX(0%); }
|
||||
}
|
||||
|
||||
@include keyframes(slideOutExtX) {
|
||||
0% { transform: translateX(0%); }
|
||||
100% { transform: translateX(-500%); }
|
||||
}
|
||||
|
||||
/**
|
||||
* Slide in / out animation for main toolbar.
|
||||
*/
|
||||
|
||||
@include keyframes(slideInY) {
|
||||
100% { transform: translateY(0%); }
|
||||
}
|
||||
|
||||
@include keyframes(slideOutY) {
|
||||
0% { transform: translateY(0%); }
|
||||
100% { transform: translateY(-100%); }
|
||||
}
|
||||
|
||||
/**
|
||||
* Slide in animation for extended toolbar (inner) panel.
|
||||
*/
|
||||
|
||||
// FIX: Can't use percentage because of breaking animation when width is changed
|
||||
// (100% of 0 is also zero) Extracted this to config variable.
|
||||
@include keyframes(slideInExt) {
|
||||
from { left: -$sidebarWidth; }
|
||||
to { left: 0; }
|
||||
}
|
||||
|
||||
@include keyframes(slideOutExt) {
|
||||
from { left: 0; }
|
||||
to { left: -$sidebarWidth; }
|
||||
}
|
||||
|
||||
/**
|
||||
* Slide in animation for extended toolbar container
|
||||
**/
|
||||
|
||||
@include keyframes(slideOutExtContainer) {
|
||||
from { width: $sidebarWidth; }
|
||||
to { width: 0; }
|
||||
}
|
||||
|
||||
@include keyframes(slideInExtContainer) {
|
||||
from { width: 0; }
|
||||
to { width: $sidebarWidth; }
|
||||
}
|
||||
157
css/_base.scss
Normal file
157
css/_base.scss
Normal file
@@ -0,0 +1,157 @@
|
||||
/**
|
||||
* Safari will limit input in input elements to one character when user-select
|
||||
* none is applied. Other browsers already support selecting within inputs while
|
||||
* user-select is none. As such, disallow user-select except on inputs.
|
||||
*/
|
||||
*:not(input) {
|
||||
-webkit-user-select: none;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0px;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
font-size: 12px;
|
||||
font-weight: 400;
|
||||
overflow: hidden;
|
||||
color: $defaultColor;
|
||||
background: $defaultBackground;
|
||||
&.filmstrip-only {
|
||||
background: transparent;
|
||||
}
|
||||
}
|
||||
|
||||
p {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
body, input, textarea, keygen, select, button {
|
||||
font-family: $baseFontFamily !important;
|
||||
}
|
||||
|
||||
#nowebrtc {
|
||||
display:none;
|
||||
}
|
||||
|
||||
.no-fa-video-camera, .fa-microphone-slash {
|
||||
color: #636363;
|
||||
}
|
||||
|
||||
button, input, select, textarea {
|
||||
margin: 0;
|
||||
vertical-align: baseline;
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
button, select, input[type="button"],
|
||||
input[type="reset"], input[type="submit"] {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
textarea {
|
||||
overflow: hidden;
|
||||
word-wrap: break-word;
|
||||
resize: none;
|
||||
line-height: 1.5em;
|
||||
}
|
||||
|
||||
input[type='text'], input[type='password'], textarea {
|
||||
outline: none; /* removes the default outline */
|
||||
resize: none; /* prevents the user-resizing, adjust to taste */
|
||||
}
|
||||
|
||||
button {
|
||||
color: #FFF;
|
||||
background-color: $buttonBackground;
|
||||
border-radius: $borderRadius;
|
||||
|
||||
&.no-icon {
|
||||
padding: 0 1em;
|
||||
}
|
||||
}
|
||||
|
||||
button,
|
||||
form {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.watermark {
|
||||
display: block;
|
||||
position: absolute;
|
||||
top: 15;
|
||||
width: $watermarkWidth;
|
||||
height: $watermarkHeight;
|
||||
background-size: contain;
|
||||
background-repeat: no-repeat;
|
||||
z-index: $zindex2;
|
||||
}
|
||||
|
||||
.leftwatermark {
|
||||
left: $defaultToolbarSize;
|
||||
margin-left: 10px;
|
||||
background-image: url($defaultWatermarkLink);
|
||||
background-position: center left;
|
||||
}
|
||||
|
||||
.rightwatermark {
|
||||
right: 15;
|
||||
background-position: center right;
|
||||
}
|
||||
|
||||
.poweredby {
|
||||
position: absolute;
|
||||
left: 25;
|
||||
bottom: 7;
|
||||
font-size: 11pt;
|
||||
color: rgba(255,255,255,.50);
|
||||
text-decoration: none;
|
||||
z-index: $poweredByZ;
|
||||
}
|
||||
|
||||
.connected {
|
||||
color: #21B9FC;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.lastN, .disconnected {
|
||||
color: #a3a3a3;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
/**
|
||||
* Dialogs fade
|
||||
*/
|
||||
.aui-blanket {
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
#inviteLinkRef {
|
||||
-webkit-user-select: text;
|
||||
user-select: text;
|
||||
}
|
||||
|
||||
/**
|
||||
* Re-style default OS scrollbar.
|
||||
*/
|
||||
::-webkit-scrollbar {
|
||||
background: transparent;
|
||||
width: 7px;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-button {
|
||||
display: none;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-track {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-track-piece {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb {
|
||||
background: rgba(0, 0, 0, .5);
|
||||
border-radius: 4px;
|
||||
}
|
||||
@@ -1,10 +1,4 @@
|
||||
#chatspace {
|
||||
display: none;
|
||||
background-color: black;
|
||||
border-left: 1px solid #424242;
|
||||
}
|
||||
|
||||
#chatspace * {
|
||||
#chat_container * {
|
||||
-webkit-user-select: text;
|
||||
user-select: text;
|
||||
}
|
||||
@@ -19,11 +13,49 @@
|
||||
font-size: 10pt;
|
||||
width: 100%;
|
||||
height: 90%;
|
||||
overflow-y: scroll;
|
||||
overflow-x: hidden;
|
||||
overflow: auto;
|
||||
word-wrap: break-word;
|
||||
|
||||
a:link {
|
||||
color: rgb(184, 184, 184);
|
||||
}
|
||||
|
||||
a:visited {
|
||||
color: white;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
color: rgb(213, 213, 213);
|
||||
}
|
||||
|
||||
a:active {
|
||||
color: black;
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar {
|
||||
background: #06a5df;
|
||||
width: 7px;
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar-button {
|
||||
display: none;
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar-track {
|
||||
background: black;
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar-track-piece {
|
||||
background: black;
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar-thumb {
|
||||
background: #06a5df;
|
||||
border-radius: 4px;
|
||||
}
|
||||
}
|
||||
#chatspace.is-conversation-mode #chatconversation {
|
||||
|
||||
#chat_container.is-conversation-mode #chatconversation {
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
@@ -65,7 +97,7 @@
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
#chatspace.is-conversation-mode #usermsg {
|
||||
#chat_container.is-conversation-mode #usermsg {
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
@@ -80,7 +112,7 @@
|
||||
width: 95%;
|
||||
}
|
||||
|
||||
#chatspace.is-conversation-mode #nickname {
|
||||
#chat_container.is-conversation-mode #nickname {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
@@ -93,31 +125,23 @@
|
||||
color: #a7a7a7;
|
||||
}
|
||||
|
||||
#unreadMessages {
|
||||
font-size: 8px;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
#bottomUnreadMessages {
|
||||
top: 5px;
|
||||
left: 10px;
|
||||
position: absolute;
|
||||
font-size: 8px;
|
||||
}
|
||||
|
||||
#chatspace .username {
|
||||
#chat_container .username {
|
||||
float: left;
|
||||
padding-left: 5px;
|
||||
font-weight: bold;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
width: 95%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
#chatspace .timestamp {
|
||||
#chat_container .timestamp {
|
||||
float: right;
|
||||
padding-right: 5px;
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
#chatspace .usermessage {
|
||||
#chat_container .usermessage {
|
||||
padding-top: 20px;
|
||||
padding-left: 5px;
|
||||
}
|
||||
@@ -131,7 +155,7 @@
|
||||
.chatmessage {
|
||||
background: #3a3a3a;
|
||||
width: 93%;
|
||||
margin-left: 5%;
|
||||
margin-left: 9px;
|
||||
margin-right: auto;
|
||||
border-radius: 5px;
|
||||
border-top-left-radius: 0px;
|
||||
@@ -178,7 +202,7 @@
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
#chatspace.is-conversation-mode #smileysarea {
|
||||
#chat_container.is-conversation-mode #smileysarea {
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
@@ -210,44 +234,6 @@
|
||||
line-height: 30px;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar {
|
||||
background: #06a5df;
|
||||
width: 7px;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-button {
|
||||
display: none;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-track {
|
||||
background: black;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-track-piece {
|
||||
background: black;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb {
|
||||
background: #06a5df;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
#usermsg::-webkit-scrollbar-track-piece {
|
||||
background: #3a3a3a;
|
||||
}
|
||||
|
||||
a:link {
|
||||
color: rgb(184, 184, 184);
|
||||
}
|
||||
|
||||
a:visited {
|
||||
color: white;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
color: rgb(213, 213, 213);
|
||||
}
|
||||
|
||||
a:active {
|
||||
color: black;
|
||||
}
|
||||
57
css/_connection-info.scss
Normal file
57
css/_connection-info.scss
Normal file
@@ -0,0 +1,57 @@
|
||||
%connection-info {
|
||||
font-size: 12px;
|
||||
font-weight: 400;
|
||||
color: $modalTextColor;
|
||||
|
||||
td {
|
||||
padding: 2px 0;
|
||||
}
|
||||
}
|
||||
|
||||
.connection-info
|
||||
{
|
||||
@extend %connection-info;
|
||||
|
||||
/**
|
||||
* Apply negative margin to reduce the appearance of padding in AtlasKit
|
||||
* InlineDialog.
|
||||
*/
|
||||
margin: -15px;
|
||||
|
||||
> table {
|
||||
white-space: nowrap;
|
||||
@extend %connection-info;
|
||||
}
|
||||
|
||||
td:nth-child(n-1) {
|
||||
padding-left: 5px;
|
||||
}
|
||||
|
||||
&__icon {
|
||||
margin-right: 2px;
|
||||
}
|
||||
|
||||
&__download
|
||||
{
|
||||
@extend .connection-info__icon;
|
||||
color: $downloadConnectionIconColor;
|
||||
}
|
||||
|
||||
&__status
|
||||
{
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
&__upload
|
||||
{
|
||||
@extend .connection-info__icon;
|
||||
color: $uploadConnectionIconColor;
|
||||
}
|
||||
|
||||
.showmore {
|
||||
display: block;
|
||||
margin: 10px auto;
|
||||
text-align: center;
|
||||
width: 90px;
|
||||
}
|
||||
}
|
||||
64
css/_contact_list.scss
Normal file
64
css/_contact_list.scss
Normal file
@@ -0,0 +1,64 @@
|
||||
#contacts_container {
|
||||
cursor: default;
|
||||
|
||||
#contacts {
|
||||
font-size: 12px;
|
||||
bottom: 0px;
|
||||
margin: 0;
|
||||
margin-top: 12px;
|
||||
padding: 0px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.clickable {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.icon-security,
|
||||
.icon-security-locked {
|
||||
font-size: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
#contacts {
|
||||
.contact-list-item {
|
||||
align-items: center;
|
||||
border-radius: 3px;
|
||||
color: $baseLight;
|
||||
display: flex;
|
||||
font-size: 14px;
|
||||
height: 36px;
|
||||
list-style-type: none;
|
||||
padding: 0 10%;
|
||||
text-align: left;
|
||||
white-space: nowrap;
|
||||
|
||||
&:hover,
|
||||
&:active {
|
||||
background: $toolbarSelectBackground;
|
||||
}
|
||||
|
||||
.contact-list-item-name {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.avatar {
|
||||
cursor: pointer;
|
||||
height: 24px;
|
||||
margin: 0 8px 0 4px;
|
||||
width: 24px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.avatar {
|
||||
padding: 0px;
|
||||
margin-right: 10px;
|
||||
vertical-align: middle;
|
||||
font-size: 22pt;
|
||||
border-radius: 20px;
|
||||
max-height: 30px;
|
||||
max-width: 30px;
|
||||
}
|
||||
81
css/_dial-out.scss
Normal file
81
css/_dial-out.scss
Normal file
@@ -0,0 +1,81 @@
|
||||
/**
|
||||
* The dialog content element.
|
||||
*/
|
||||
.dial-out-content {
|
||||
margin-top: 5px;
|
||||
|
||||
/**
|
||||
* Wrap the contents in flex so items can be aligned on the same line.
|
||||
*/
|
||||
.form-control {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
/**
|
||||
* The style of the flag icon.
|
||||
*/
|
||||
.dial-out-flag-icon {
|
||||
position: absolute;
|
||||
left: 5px;
|
||||
top: 50%;
|
||||
transform: translate(0, -50%);
|
||||
}
|
||||
|
||||
/**
|
||||
* The style of the dial code element.
|
||||
*/
|
||||
.dial-out-code {
|
||||
margin-bottom: 0;
|
||||
padding-left: 25px;
|
||||
}
|
||||
|
||||
/**
|
||||
* The dial-out dialog error element.
|
||||
*/
|
||||
.dial-out-error {
|
||||
color: $errorColor;
|
||||
}
|
||||
|
||||
/**
|
||||
* The style of the dial input element.
|
||||
*/
|
||||
.dial-out-input {
|
||||
display: inline-block;
|
||||
flex: 1;
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
/**
|
||||
* Re-styling the default dropdown inside the dial-out-content.
|
||||
*/
|
||||
.dropdown {
|
||||
position: relative;
|
||||
width: 65px;
|
||||
}
|
||||
|
||||
/**
|
||||
* Re-styling the default form-control inside the dial-out-content.
|
||||
*/
|
||||
.form-control {
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.dropdown {
|
||||
position: relative;
|
||||
|
||||
input {
|
||||
padding-left: 16px;
|
||||
|
||||
&:read-only {
|
||||
color: inherit;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.dropdown-trigger-icon {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 50%;
|
||||
transform: translate(0, -50%);
|
||||
}
|
||||
}
|
||||
212
css/_filmstrip.scss
Normal file
212
css/_filmstrip.scss
Normal file
@@ -0,0 +1,212 @@
|
||||
%align-right {
|
||||
@include flex();
|
||||
flex-direction: row-reverse;
|
||||
flex-wrap: nowrap;
|
||||
justify-content: flex-start;
|
||||
}
|
||||
|
||||
.filmstrip {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
padding: 10px 5px;
|
||||
@extend %align-right;
|
||||
z-index: $filmstripVideosZ;
|
||||
|
||||
&__toolbar {
|
||||
@include flex();
|
||||
flex-direction: column-reverse;
|
||||
flex-wrap: nowrap;
|
||||
position: relative;
|
||||
width: $filmstripToggleButtonWidth;
|
||||
|
||||
button {
|
||||
font-size: 14px;
|
||||
line-height: 1.2;
|
||||
text-align: center;
|
||||
background: transparent;
|
||||
opacity: 0.7;
|
||||
height: auto;
|
||||
width: 100%;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
border: none;
|
||||
outline: none;
|
||||
|
||||
-webkit-appearance: none;
|
||||
|
||||
&:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
i {
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&__videos {
|
||||
@extend %align-right;
|
||||
position:relative;
|
||||
padding: 0;
|
||||
/* The filmstrip should not be covered by the left toolbar. */
|
||||
bottom: 0;
|
||||
width:auto;
|
||||
transition: bottom 2s;
|
||||
overflow: visible !important;
|
||||
|
||||
&#remoteVideos {
|
||||
border: $thumbnailsBorder solid transparent;
|
||||
padding-left: $defaultToolbarSize + 5;
|
||||
}
|
||||
|
||||
/**
|
||||
* The local video identifier.
|
||||
*/
|
||||
&#filmstripLocalVideo {
|
||||
bottom: 32px;
|
||||
flex-direction: column;
|
||||
|
||||
/**
|
||||
* The invite button style.
|
||||
*/
|
||||
.filmstrip__invite {
|
||||
padding-bottom: 5px;
|
||||
margin-left: 2px;
|
||||
}
|
||||
|
||||
/**
|
||||
* The invite button group style.
|
||||
* TOFIX: use AtlasKit.ButtonGroup if it starts supporting different
|
||||
* flex grow options for the buttons.
|
||||
*/
|
||||
.invite-button-group {
|
||||
display: inline-flex;
|
||||
justify-content: space-between;
|
||||
width: 100%;
|
||||
|
||||
& button {
|
||||
background: $toolbarBackground;
|
||||
flex-grow: 1;
|
||||
flex-shrink: 1;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
& > * {
|
||||
color: $toolbarButtonColor;
|
||||
flex-grow: 0;
|
||||
flex-shrink: 0;
|
||||
margin-left: 2px;
|
||||
}
|
||||
|
||||
/**
|
||||
* Making sure any svg-s in an invite button group will be
|
||||
* colored the way we want.
|
||||
*/
|
||||
& path {
|
||||
fill: $toolbarButtonColor;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.hidden {
|
||||
bottom: -196px;
|
||||
}
|
||||
|
||||
.remote-videos-container {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.videocontainer {
|
||||
display: none;
|
||||
position: relative;
|
||||
background-size: contain;
|
||||
border: $thumbnailVideoBorder solid transparent;
|
||||
border-radius: $borderRadius;
|
||||
margin: 0 $thumbnailVideoMargin;
|
||||
|
||||
&.videoContainerFocused, &:hover {
|
||||
cursor: hand;
|
||||
}
|
||||
|
||||
/**
|
||||
* Focused video thumbnail.
|
||||
*/
|
||||
&.videoContainerFocused {
|
||||
transition-duration: 0.5s;
|
||||
-webkit-transition-duration: 0.5s;
|
||||
-webkit-animation-name: greyPulse;
|
||||
-webkit-animation-duration: 2s;
|
||||
-webkit-animation-iteration-count: 1;
|
||||
border: $thumbnailVideoBorder solid $videoThumbnailSelected !important;
|
||||
box-shadow: inset 0 0 3px $videoThumbnailSelected,
|
||||
0 0 3px $videoThumbnailSelected !important;
|
||||
}
|
||||
|
||||
.remotevideomenu > .icon-menu {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.presence-label {
|
||||
color: $participantNameColor;
|
||||
font-size: 12px;
|
||||
font-weight: 100;
|
||||
left: 0;
|
||||
margin: 0 auto;
|
||||
overflow: hidden;
|
||||
pointer-events: none;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
text-align: center;
|
||||
text-overflow: ellipsis;
|
||||
top: calc(50% + 30px);
|
||||
white-space: nowrap;
|
||||
width: 100%;
|
||||
z-index: $zindex3;
|
||||
}
|
||||
|
||||
/**
|
||||
* Hovered video thumbnail.
|
||||
*/
|
||||
&:hover {
|
||||
cursor: hand;
|
||||
border: $thumbnailVideoBorder solid $videoThumbnailHovered;
|
||||
box-shadow: inset 0 0 3px $videoThumbnailHovered,
|
||||
0 0 3px $videoThumbnailHovered;
|
||||
|
||||
.remotevideomenu > .icon-menu {
|
||||
display: inline-block;
|
||||
}
|
||||
}
|
||||
|
||||
/* With the TemasysWebRTC plugin <object/> element is used
|
||||
instead of <video/> */
|
||||
& > video,
|
||||
& > object {
|
||||
cursor: hand;
|
||||
border-radius: $borderRadius;
|
||||
object-fit: cover;
|
||||
overflow: hidden;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Style the filmstrip videos in filmstrip-only mode.
|
||||
*/
|
||||
&__videos-filmstripOnly {
|
||||
margin-top: auto;
|
||||
margin-bottom: auto;
|
||||
}
|
||||
|
||||
.remote-videos-container {
|
||||
transition: opacity 1s;
|
||||
}
|
||||
|
||||
&.hide-videos {
|
||||
.remote-videos-container {
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
35
css/_flag-icon.scss
Executable file
35
css/_flag-icon.scss
Executable file
@@ -0,0 +1,35 @@
|
||||
.flag-icon-background {
|
||||
background-size: contain;
|
||||
background-position: 50%;
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
.flag-icon {
|
||||
background-size: contain;
|
||||
background-position: 50%;
|
||||
background-repeat: no-repeat;
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
width: 1.33333333em;
|
||||
line-height: 1em;
|
||||
}
|
||||
.flag-icon:before {
|
||||
content: "\00a0";
|
||||
}
|
||||
.flag-icon-au {
|
||||
background-image: url(../images/countries/au.svg);
|
||||
}
|
||||
.flag-icon-ca {
|
||||
background-image: url(../images/countries/ca.svg);
|
||||
}
|
||||
.flag-icon-de {
|
||||
background-image: url(../images/countries/de.svg);
|
||||
}
|
||||
.flag-icon-gb {
|
||||
background-image: url(../images/countries/gb.svg);
|
||||
}
|
||||
.flag-icon-fr {
|
||||
background-image: url(../images/countries/fr.svg);
|
||||
}
|
||||
.flag-icon-us {
|
||||
background-image: url(../images/countries/us.svg);
|
||||
}
|
||||
@@ -255,9 +255,6 @@
|
||||
.fa-road:before {
|
||||
content: "\f018";
|
||||
}
|
||||
.fa-download:before {
|
||||
content: "\f019";
|
||||
}
|
||||
.fa-arrow-circle-o-down:before {
|
||||
content: "\f01a";
|
||||
}
|
||||
@@ -842,9 +839,6 @@
|
||||
.fa-exchange:before {
|
||||
content: "\f0ec";
|
||||
}
|
||||
.fa-cloud-download:before {
|
||||
content: "\f0ed";
|
||||
}
|
||||
.fa-cloud-upload:before {
|
||||
content: "\f0ee";
|
||||
}
|
||||
159
css/_font.scss
Normal file
159
css/_font.scss
Normal file
@@ -0,0 +1,159 @@
|
||||
@font-face {
|
||||
font-family: 'jitsi';
|
||||
src:url('../fonts/jitsi.eot?94d075');
|
||||
src:url('../fonts/jitsi.eot?#iefix94d075') format('embedded-opentype'),
|
||||
url('../fonts/jitsi.woff?94d075') format('woff'),
|
||||
url('../fonts/jitsi.ttf?94d075') format('truetype'),
|
||||
url('../fonts/jitsi.svg?94d075#jitsi') format('svg');
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
[class^="icon-"], [class*=" icon-"] {
|
||||
font-family: 'jitsi';
|
||||
speak: none;
|
||||
font-style: normal;
|
||||
font-weight: normal;
|
||||
font-variant: normal;
|
||||
text-transform: none;
|
||||
line-height: 1.22em;
|
||||
font-size: 1.22em;
|
||||
cursor: default;
|
||||
|
||||
/* Better Font Rendering =========== */
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
.icon-thumb-menu:before {
|
||||
content: "\e5d4";
|
||||
}
|
||||
.icon-mic-camera-combined:before {
|
||||
content: "\e903";
|
||||
}
|
||||
.icon-feedback:before {
|
||||
content: "\e91d";
|
||||
}
|
||||
.icon-toggle-filmstrip:before {
|
||||
content: "\e91c";
|
||||
}
|
||||
.icon-avatar:before {
|
||||
content: "\e901";
|
||||
}
|
||||
.icon-hangup:before {
|
||||
content: "\e905";
|
||||
}
|
||||
.icon-chat:before {
|
||||
content: "\e906";
|
||||
}
|
||||
.icon-download:before {
|
||||
content: "\e902";
|
||||
}
|
||||
.icon-edit:before {
|
||||
content: "\e907";
|
||||
}
|
||||
.icon-share-doc:before {
|
||||
content: "\e908";
|
||||
}
|
||||
.icon-kick:before {
|
||||
content: "\e904";
|
||||
}
|
||||
.icon-menu-up:before {
|
||||
content: "\e91f";
|
||||
}
|
||||
.icon-menu-down:before {
|
||||
content: "\e920";
|
||||
}
|
||||
.icon-full-screen:before {
|
||||
content: "\e90b";
|
||||
}
|
||||
.icon-exit-full-screen:before {
|
||||
content: "\e90c";
|
||||
}
|
||||
.icon-star-full:before {
|
||||
content: "\e90a";
|
||||
}
|
||||
.icon-security:before {
|
||||
content: "\e90d";
|
||||
}
|
||||
.icon-security-locked:before {
|
||||
content: "\e90e";
|
||||
}
|
||||
.icon-reload:before {
|
||||
content: "\e90f";
|
||||
}
|
||||
.icon-microphone:before {
|
||||
content: "\e910";
|
||||
}
|
||||
.icon-mic-empty:before {
|
||||
content: "\e911";
|
||||
}
|
||||
.icon-mic-disabled:before {
|
||||
content: "\e912";
|
||||
}
|
||||
.icon-ninja:before {
|
||||
content: "\e909";
|
||||
}
|
||||
.icon-raised-hand:before {
|
||||
content: "\e91e";
|
||||
}
|
||||
.icon-contactList:before {
|
||||
content: "\e91b";
|
||||
}
|
||||
.icon-link:before {
|
||||
content: "\e913";
|
||||
}
|
||||
.icon-shared-video:before {
|
||||
content: "\e914";
|
||||
}
|
||||
.icon-settings:before {
|
||||
content: "\e915";
|
||||
}
|
||||
.icon-star:before {
|
||||
content: "\e916";
|
||||
}
|
||||
.icon-switch-camera:before {
|
||||
content: "\e921";
|
||||
}
|
||||
.icon-share-desktop:before {
|
||||
content: "\e917";
|
||||
}
|
||||
.icon-camera:before {
|
||||
content: "\e918";
|
||||
}
|
||||
.icon-camera-disabled:before {
|
||||
content: "\e919";
|
||||
}
|
||||
.icon-volume:before {
|
||||
content: "\e91a";
|
||||
}
|
||||
.icon-recDisable:before {
|
||||
content: "\e613";
|
||||
}
|
||||
.icon-recEnable:before {
|
||||
content: "\e614";
|
||||
}
|
||||
.icon-presentation:before {
|
||||
content: "\e603";
|
||||
}
|
||||
.icon-dialpad:before {
|
||||
content: "\e925";
|
||||
}
|
||||
.icon-visibility:before {
|
||||
content: "\e923";
|
||||
}
|
||||
.icon-visibility-off:before {
|
||||
content: "\e924";
|
||||
}
|
||||
.icon-telephone:before {
|
||||
content: "\e0cd";
|
||||
}
|
||||
.icon-add:before {
|
||||
content: "\e145";
|
||||
}
|
||||
.icon-info:before {
|
||||
content: "\e922";
|
||||
}
|
||||
.icon-gsm-bars:before {
|
||||
content: "\e926";
|
||||
}
|
||||
6
css/_functions.scss
Normal file
6
css/_functions.scss
Normal file
@@ -0,0 +1,6 @@
|
||||
/* Functions */
|
||||
|
||||
/* Pixels to Ems function */
|
||||
@function em($value, $base: 16) {
|
||||
@return #{$value / $base}em;
|
||||
}
|
||||
113
css/_inlay.scss
Normal file
113
css/_inlay.scss
Normal file
@@ -0,0 +1,113 @@
|
||||
.inlay {
|
||||
margin-top: 14%;
|
||||
@include border-radius(4px);
|
||||
padding: 40px 38px 44px;
|
||||
color: #fff;
|
||||
background: $inlayColorBg;
|
||||
text-align: center;
|
||||
|
||||
&__title {
|
||||
margin: 17px 0;
|
||||
padding-bottom: 17px;
|
||||
color: $popoverFontColor;
|
||||
font-size: 21px;
|
||||
letter-spacing: 0.3px;
|
||||
border-bottom: 1px solid $inlayBorderColor;
|
||||
}
|
||||
|
||||
&__text {
|
||||
color: $popoverFontColor;
|
||||
display: block;
|
||||
margin-top: 22px;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
&__icon {
|
||||
margin: 0 10px;
|
||||
font-size: 50px;
|
||||
}
|
||||
|
||||
&-filmstrip-only {
|
||||
background-color: $inlayFilmstripOnlyBg;
|
||||
color: $inlayFilmstripOnlyColor;
|
||||
margin-left: 20px;
|
||||
margin-right: 20px;
|
||||
margin-top: 20px;
|
||||
bottom: 30px;
|
||||
position: absolute;
|
||||
display: flex;
|
||||
max-height: 120px;
|
||||
height: 80%;
|
||||
right: 0px;
|
||||
border-radius: 4px;
|
||||
overflow: hidden;
|
||||
&__content {
|
||||
padding: 20px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
position: relative;
|
||||
> .button-control {
|
||||
align-self: center;
|
||||
}
|
||||
> #reloadProgressBar {
|
||||
position: absolute;
|
||||
left: 0px;
|
||||
bottom: 0px;
|
||||
margin-bottom: 0px;
|
||||
width: 100%;
|
||||
border-radius: 0px;
|
||||
> .aui-progress-indicator-value {
|
||||
border-radius: 0px;
|
||||
}
|
||||
}
|
||||
}
|
||||
&__title {
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
&__container {
|
||||
align-self: center;
|
||||
}
|
||||
|
||||
&__text {
|
||||
margin-top: 10px;
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
&__icon {
|
||||
font-size: 50px;
|
||||
align-self: center;
|
||||
color: $inlayIconColor;
|
||||
opacity: 0.6;
|
||||
}
|
||||
&__icon-container {
|
||||
text-align: center;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
top: 0px;
|
||||
}
|
||||
|
||||
&__avatar-container {
|
||||
height: 100%;
|
||||
position: relative;
|
||||
> img {
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
&__icon-background {
|
||||
background: $inlayIconBg;
|
||||
opacity: 0.6;
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
top: 0px;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -9,7 +9,8 @@
|
||||
}
|
||||
div.jqi{
|
||||
width: 400px;
|
||||
position: absolute;
|
||||
position: absolute;
|
||||
color: #3a3a3a;
|
||||
background-color: #ffffff;
|
||||
font-size: 11px;
|
||||
text-align: left;
|
||||
@@ -55,7 +56,7 @@ div.jqi .jqibuttons{
|
||||
div.jqi .jqibuttons button{
|
||||
margin: 0;
|
||||
padding: 5px 20px;
|
||||
background-color: transparent;
|
||||
background-color: transparent !important;
|
||||
font-weight: normal;
|
||||
border: none;
|
||||
border-left: solid 1px #e4e4e4;
|
||||
206
css/_jquery.contextMenu.scss
Normal file
206
css/_jquery.contextMenu.scss
Normal file
@@ -0,0 +1,206 @@
|
||||
@charset "UTF-8";
|
||||
/*!
|
||||
* jQuery contextMenu - Plugin for simple contextMenu handling
|
||||
*
|
||||
* Version: v2.1.1
|
||||
*
|
||||
* Authors: Björn Brala (SWIS.nl), Rodney Rehm, Addy Osmani (patches for FF)
|
||||
* Web: http://swisnl.github.io/jQuery-contextMenu/
|
||||
*
|
||||
* Copyright (c) 2011-2016 SWIS BV and contributors
|
||||
*
|
||||
* Licensed under
|
||||
* MIT License http://www.opensource.org/licenses/mit-license
|
||||
*
|
||||
* Date: 2016-02-28T09:53:18.890Z
|
||||
*/
|
||||
@font-face {
|
||||
font-family: "context-menu-icons";
|
||||
font-style: normal;
|
||||
font-weight: normal;
|
||||
|
||||
src: url("font/context-menu-icons.eot?2qmzf");
|
||||
src: url("font/context-menu-icons.eot?2qmzf#iefix") format("embedded-opentype"), url("font/context-menu-icons.woff2?2qmzf") format("woff2"), url("font/context-menu-icons.woff?2qmzf") format("woff"), url("font/context-menu-icons.ttf?2qmzf") format("truetype");
|
||||
}
|
||||
|
||||
.context-menu-icon:before {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 0;
|
||||
width: 28px;
|
||||
font-family: "context-menu-icons";
|
||||
font-size: 16px;
|
||||
font-style: normal;
|
||||
font-weight: normal;
|
||||
line-height: 1;
|
||||
color: #2980b9;
|
||||
text-align: center;
|
||||
-webkit-transform: translateY(-50%);
|
||||
-ms-transform: translateY(-50%);
|
||||
-o-transform: translateY(-50%);
|
||||
transform: translateY(-50%);
|
||||
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
.context-menu-icon-add:before {
|
||||
content: "";
|
||||
}
|
||||
|
||||
.context-menu-icon-copy:before {
|
||||
content: "";
|
||||
}
|
||||
|
||||
.context-menu-icon-cut:before {
|
||||
content: "";
|
||||
}
|
||||
|
||||
.context-menu-icon-delete:before {
|
||||
content: "";
|
||||
}
|
||||
|
||||
.context-menu-icon-edit:before {
|
||||
content: "";
|
||||
}
|
||||
|
||||
.context-menu-icon-paste:before {
|
||||
content: "";
|
||||
}
|
||||
|
||||
.context-menu-icon-quit:before {
|
||||
content: "";
|
||||
}
|
||||
|
||||
.context-menu-icon.context-menu-hover:before {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.context-menu-list {
|
||||
position: absolute;
|
||||
display: inline-block;
|
||||
min-width: 180px;
|
||||
max-width: 360px;
|
||||
padding: 4px 0;
|
||||
margin: 5px;
|
||||
font-family: inherit;
|
||||
font-size: inherit;
|
||||
list-style-type: none;
|
||||
background: #fff;
|
||||
border: 1px solid #bebebe;
|
||||
border-radius: $borderRadius;
|
||||
-webkit-box-shadow: 0 2px 5px rgba(0, 0, 0, .5);
|
||||
box-shadow: 0 2px 5px rgba(0, 0, 0, .5);
|
||||
}
|
||||
|
||||
.context-menu-item {
|
||||
position: relative;
|
||||
padding: 3px 28px;
|
||||
color: #2f2f2f;
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.context-menu-separator {
|
||||
padding: 0;
|
||||
margin: 5px 0;
|
||||
border-bottom: 1px solid #e6e6e6;
|
||||
}
|
||||
|
||||
.context-menu-item > label > input,
|
||||
.context-menu-item > label > textarea {
|
||||
-webkit-user-select: text;
|
||||
-moz-user-select: text;
|
||||
-ms-user-select: text;
|
||||
user-select: text;
|
||||
}
|
||||
|
||||
.context-menu-item.context-menu-hover {
|
||||
color: #fff;
|
||||
cursor: pointer;
|
||||
background-color: #2980b9;
|
||||
}
|
||||
|
||||
.context-menu-item.context-menu-disabled {
|
||||
color: #626262;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.context-menu-item.context-menu-disabled {
|
||||
color: #626262;
|
||||
}
|
||||
|
||||
.context-menu-input.context-menu-hover,
|
||||
.context-menu-item.context-menu-disabled.context-menu-hover {
|
||||
cursor: default;
|
||||
background-color: #eee;
|
||||
}
|
||||
|
||||
.context-menu-submenu:after {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
right: 8px;
|
||||
z-index: $zindex1;
|
||||
width: 0;
|
||||
height: 0;
|
||||
content: '';
|
||||
border-color: transparent transparent transparent #2f2f2f;
|
||||
border-style: solid;
|
||||
border-width: 4px 0 4px 4px;
|
||||
-webkit-transform: translateY(-50%);
|
||||
-ms-transform: translateY(-50%);
|
||||
-o-transform: translateY(-50%);
|
||||
transform: translateY(-50%);
|
||||
}
|
||||
|
||||
/**
|
||||
* Inputs
|
||||
*/
|
||||
.context-menu-item.context-menu-input {
|
||||
padding: 5px 10px;
|
||||
}
|
||||
|
||||
/* vertically align inside labels */
|
||||
.context-menu-input > label > * {
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
/* position checkboxes and radios as icons */
|
||||
.context-menu-input > label > input[type="checkbox"],
|
||||
.context-menu-input > label > input[type="radio"] {
|
||||
position: relative;
|
||||
top: 3px;
|
||||
}
|
||||
|
||||
.context-menu-input > label,
|
||||
.context-menu-input > label > input[type="text"],
|
||||
.context-menu-input > label > textarea,
|
||||
.context-menu-input > label > select {
|
||||
display: block;
|
||||
width: 100%;
|
||||
-webkit-box-sizing: border-box;
|
||||
-moz-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.context-menu-input > label > textarea {
|
||||
height: 100px;
|
||||
}
|
||||
|
||||
.context-menu-item > .context-menu-list {
|
||||
top: 5px;
|
||||
/* re-positioned by js */
|
||||
right: -5px;
|
||||
display: none;
|
||||
}
|
||||
|
||||
.context-menu-item.context-menu-visible > .context-menu-list {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.context-menu-accesskey {
|
||||
text-decoration: underline;
|
||||
}
|
||||
25
css/_keyboard-shortcuts.scss
Normal file
25
css/_keyboard-shortcuts.scss
Normal file
@@ -0,0 +1,25 @@
|
||||
#keyboard-shortcuts {
|
||||
display: none;
|
||||
position: absolute;
|
||||
bottom: 20px;
|
||||
left: $defaultToolbarSize;
|
||||
overflow: hidden;
|
||||
padding: 20px;
|
||||
margin-left: 10px;
|
||||
z-index: $zindex10;
|
||||
border-radius: $borderRadius;
|
||||
background-attachment: scroll;
|
||||
background-size: auto auto;
|
||||
color: rgba(255, 255, 255, .8);
|
||||
background-color: rgba(0, 0, 0, .8);
|
||||
}
|
||||
|
||||
#keyboard-shortcuts .item-action {
|
||||
color: #209EFF;
|
||||
font-size: 14pt;
|
||||
padding-right: 5px;
|
||||
}
|
||||
|
||||
#keyboard-shortcuts-list {
|
||||
list-style-type: none;
|
||||
}
|
||||
18
css/_login_menu.scss
Normal file
18
css/_login_menu.scss
Normal file
@@ -0,0 +1,18 @@
|
||||
/*Initialize*/
|
||||
div.loginmenu {
|
||||
position: absolute;
|
||||
margin: 0;
|
||||
padding: 5px;
|
||||
top: 40px;
|
||||
left: 20px;
|
||||
}
|
||||
|
||||
a.disabled {
|
||||
color: gray !important;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.loginmenu.extendedToolbarPopup {
|
||||
top: 20px;
|
||||
left: 40px;
|
||||
}
|
||||
195
css/_mixins.scss
Normal file
195
css/_mixins.scss
Normal file
@@ -0,0 +1,195 @@
|
||||
/**
|
||||
* Animation mixin.
|
||||
*/
|
||||
@mixin animation($animate...) {
|
||||
$max: length($animate);
|
||||
$animations: '';
|
||||
|
||||
@for $i from 1 through $max {
|
||||
$animations: #{$animations + nth($animate, $i)};
|
||||
|
||||
@if $i < $max {
|
||||
$animations: #{$animations + ", "};
|
||||
}
|
||||
}
|
||||
-webkit-animation: $animations;
|
||||
-moz-animation: $animations;
|
||||
-o-animation: $animations;
|
||||
animation: $animations;
|
||||
}
|
||||
|
||||
@mixin flex() {
|
||||
display: -webkit-box;
|
||||
display: -moz-box;
|
||||
display: -ms-flexbox;
|
||||
display: -webkit-flex;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
/**
|
||||
* Keyframes mixin.
|
||||
*/
|
||||
@mixin keyframes($animationName) {
|
||||
@-webkit-keyframes #{$animationName} {
|
||||
@content;
|
||||
}
|
||||
@-moz-keyframes #{$animationName} {
|
||||
@content;
|
||||
}
|
||||
@-o-keyframes #{$animationName} {
|
||||
@content;
|
||||
}
|
||||
@keyframes #{$animationName} {
|
||||
@content;
|
||||
}
|
||||
}
|
||||
|
||||
@mixin circle($diameter) {
|
||||
width: $diameter;
|
||||
height: $diameter;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
/**
|
||||
* Absolute position the element at the top left corner
|
||||
**/
|
||||
@mixin topLeft() {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
@mixin absoluteAligning() {
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
position: absolute;
|
||||
@include transform(translate(-50%, -50%));
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines the maximum width and height
|
||||
**/
|
||||
@mixin maxSize($value) {
|
||||
max-width: $value;
|
||||
max-height: $value;
|
||||
}
|
||||
|
||||
@mixin transform($func) {
|
||||
-moz-transform: $func;
|
||||
-ms-transform: $func;
|
||||
-webkit-transform: $func;
|
||||
-o-transform: $func;
|
||||
transform: $func;
|
||||
}
|
||||
|
||||
@mixin transition($transition...) {
|
||||
-moz-transition: $transition;
|
||||
-o-transition: $transition;
|
||||
-webkit-transition: $transition;
|
||||
transition: $transition;
|
||||
}
|
||||
|
||||
/**
|
||||
* Mixin styling a placeholder.
|
||||
**/
|
||||
@mixin placeholder() {
|
||||
$selectors: (
|
||||
"::-webkit-input-placeholder",
|
||||
"::-moz-placeholder",
|
||||
":-moz-placeholder",
|
||||
":-ms-input-placeholder"
|
||||
);
|
||||
|
||||
@each $selector in $selectors {
|
||||
#{$selector} {
|
||||
@content;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Mixin styling a slider track for different browsers.
|
||||
**/
|
||||
@mixin slider() {
|
||||
$selectors: (
|
||||
"input[type=range]::-webkit-slider-runnable-track",
|
||||
"input[type=range]::-moz-range-track",
|
||||
"input[type=range]::-ms-track"
|
||||
);
|
||||
|
||||
@each $selector in $selectors {
|
||||
#{$selector} {
|
||||
@content;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Mixin styling a slider thumb for different browsers.
|
||||
**/
|
||||
@mixin slider-thumb() {
|
||||
$selectors: (
|
||||
"input[type=range]::-webkit-slider-thumb",
|
||||
"input[type=range]::-moz-range-thumb",
|
||||
"input[type=range]::-ms-thumb"
|
||||
);
|
||||
|
||||
@each $selector in $selectors {
|
||||
#{$selector} {
|
||||
@content;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@mixin box-shadow($h, $y, $blur, $color, $inset: false) {
|
||||
@if $inset {
|
||||
-webkit-box-shadow: inset $h $y $blur $color;
|
||||
-moz-box-shadow: inset $h $y $blur $color;
|
||||
box-shadow: inset $h $y $blur $color;
|
||||
} @else {
|
||||
-webkit-box-shadow: $h $y $blur $color;
|
||||
-moz-box-shadow: $h $y $blur $color;
|
||||
box-shadow: $h $y $blur $color;
|
||||
}
|
||||
}
|
||||
|
||||
@mixin no-box-shadow {
|
||||
-webkit-box-shadow: none;
|
||||
-moz-box-shadow: none;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
@mixin box-sizing($box-model) {
|
||||
-webkit-box-sizing: $box-model; // Safari <= 5
|
||||
-moz-box-sizing: $box-model; // Firefox <= 19
|
||||
box-sizing: $box-model;
|
||||
}
|
||||
|
||||
@mixin border-radius($radius) {
|
||||
-webkit-border-radius: $radius;
|
||||
border-radius: $radius;
|
||||
/* stops bg color from leaking outside the border: */
|
||||
background-clip: padding-box;
|
||||
}
|
||||
|
||||
@mixin opacity($opacity) {
|
||||
opacity: $opacity;
|
||||
$opacity-ie: $opacity * 100;
|
||||
-ms-filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=$opacity-ie);
|
||||
filter: alpha(opacity=$opacity-ie); //IE8
|
||||
}
|
||||
|
||||
@mixin text-truncate {
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a semi-transparent background with the given color and alpha
|
||||
* (opacity) value.
|
||||
*/
|
||||
@mixin transparentBg($color, $alpha) {
|
||||
background-color: rgba(red($color), green($color), blue($color), $alpha);
|
||||
}
|
||||
@@ -19,11 +19,6 @@
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.jqibuttons button {
|
||||
margin-right: 5px;
|
||||
float:right;
|
||||
}
|
||||
|
||||
button.jqidefaultbutton #inviteLinkRef {
|
||||
color: #2c8ad2;
|
||||
}
|
||||
15
css/_notice.scss
Normal file
15
css/_notice.scss
Normal file
@@ -0,0 +1,15 @@
|
||||
.notice {
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
z-index: $zindex3;
|
||||
margin-top: 6px;
|
||||
|
||||
@include transform(translateX(-50%));
|
||||
|
||||
&__message {
|
||||
background-color: #000000;
|
||||
color: white;
|
||||
padding: 3px;
|
||||
border-radius: 5px;
|
||||
}
|
||||
}
|
||||
15
css/_policy.scss
Normal file
15
css/_policy.scss
Normal file
@@ -0,0 +1,15 @@
|
||||
.policy {
|
||||
&__logo {
|
||||
display: block;
|
||||
width: 200px;
|
||||
height: 50px;
|
||||
margin: 30px auto 0;
|
||||
}
|
||||
|
||||
&__text {
|
||||
text-align: center;
|
||||
font-size: 14px;
|
||||
line-height: 21px;
|
||||
font-weight: 300;
|
||||
}
|
||||
}
|
||||
33
css/_popover.scss
Normal file
33
css/_popover.scss
Normal file
@@ -0,0 +1,33 @@
|
||||
/**
|
||||
* Mousemove padding styles are used to add invisible elements to the popover
|
||||
* to allow mouse movement from the popover trigger to the popover itself
|
||||
* without triggering a mouseleave event.
|
||||
*/
|
||||
.popover-mousemove-padding-bottom {
|
||||
bottom: -15px;
|
||||
height: 20px;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
width: 100%;
|
||||
}
|
||||
.popover-mousemove-padding-right {
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
right: -20;
|
||||
top: 0;
|
||||
width: 40px;
|
||||
}
|
||||
|
||||
/**
|
||||
* An invisible element is added to the top of the popover to ensure the mouse
|
||||
* stays over the popover when the popover's height is shrunk, which would then
|
||||
* normally leave the mouse outside of the popover itself and cause a mouseleave
|
||||
* event.
|
||||
*/
|
||||
.popover-mouse-padding-top {
|
||||
height: 30px;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: -25px;
|
||||
width: 100%;
|
||||
}
|
||||
103
css/_popup_menu.scss
Normal file
103
css/_popup_menu.scss
Normal file
@@ -0,0 +1,103 @@
|
||||
/**
|
||||
* Initialize
|
||||
**/
|
||||
|
||||
.popupmenu {
|
||||
text-align: left;
|
||||
padding: 0;
|
||||
white-space: nowrap;
|
||||
|
||||
&__item {
|
||||
list-style-type: none;
|
||||
height: 35px;
|
||||
|
||||
&:hover {
|
||||
background-color: rgba(9, 30, 66, 0.04);
|
||||
}
|
||||
}
|
||||
|
||||
// Link Appearance
|
||||
&__link,
|
||||
&__contents {
|
||||
color: $modalTextColor;
|
||||
display: block;
|
||||
box-sizing: border-box;
|
||||
text-decoration: none;
|
||||
height: 100%;
|
||||
font-size: 9pt;
|
||||
width: 100%;
|
||||
cursor: pointer;
|
||||
padding: 0 5px;
|
||||
|
||||
&.disabled {
|
||||
color: gray !important;
|
||||
pointer-events: none;
|
||||
}
|
||||
}
|
||||
|
||||
&__text {
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
&__link {
|
||||
i {
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
&__contents {
|
||||
display: flex;
|
||||
|
||||
/**
|
||||
* Positioning styles on the slider and its container are used to make
|
||||
* the container fit the popup width, by removing the slider from the
|
||||
* page flow, and then making the slider fit the container.
|
||||
*/
|
||||
.popupmenu__slider_container {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
|
||||
.popupmenu__slider {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
transform: translate(0, -50%);
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&__icon {
|
||||
vertical-align: middle;
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
min-width: 20px;
|
||||
height: 100%;
|
||||
|
||||
> * {
|
||||
@include absoluteAligning();
|
||||
}
|
||||
}
|
||||
|
||||
.icon-kick {
|
||||
font-size: 8pt;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Override reset css styling modifying all lists and set negative margin to
|
||||
* reduce the visibility of padding on AtlasKit
|
||||
* InlineDialogs.
|
||||
*/
|
||||
ul.popupmenu {
|
||||
margin: -15px;
|
||||
}
|
||||
|
||||
span.remotevideomenu:hover ul.popupmenu, ul.popupmenu:hover {
|
||||
display:block !important;
|
||||
}
|
||||
|
||||
.remote-control-spinner {
|
||||
top: 6px;
|
||||
left: 2px;
|
||||
}
|
||||
3
css/_recording.scss
Normal file
3
css/_recording.scss
Normal file
@@ -0,0 +1,3 @@
|
||||
.recordingSpinner {
|
||||
vertical-align: top;
|
||||
}
|
||||
34
css/_redirect_page.scss
Normal file
34
css/_redirect_page.scss
Normal file
@@ -0,0 +1,34 @@
|
||||
.redirectPageMessage {
|
||||
width: 30%;
|
||||
margin: 20% auto;
|
||||
text-align: center;
|
||||
font-size: 24px;
|
||||
|
||||
.thanks-msg {
|
||||
border-bottom: 1px solid $selectBg;
|
||||
padding-left: 30px;
|
||||
padding-right: 30px;
|
||||
p {
|
||||
margin: 30px auto;
|
||||
font-size: 24px;
|
||||
line-height: 24px;
|
||||
}
|
||||
}
|
||||
.hint-msg{
|
||||
p {
|
||||
margin: 26px auto;
|
||||
font-weight: 600;
|
||||
font-size: 16px;
|
||||
line-height: 18px;
|
||||
.hint-msg__holder{
|
||||
font-weight: 200;
|
||||
}
|
||||
}
|
||||
.happy-software{
|
||||
width: 120px;
|
||||
height: 86px;
|
||||
margin: 0 auto;
|
||||
background: $happySoftwareBackground;
|
||||
}
|
||||
}
|
||||
}
|
||||
146
css/_side_toolbar_container.scss
Normal file
146
css/_side_toolbar_container.scss
Normal file
@@ -0,0 +1,146 @@
|
||||
/**
|
||||
* Toolbar side panel main container element.
|
||||
*/
|
||||
#sideToolbarContainer {
|
||||
background-color: $sideToolbarContainerBg;
|
||||
height: 100%;
|
||||
left: $defaultToolbarSize;
|
||||
max-width: $sidebarWidth;
|
||||
overflow: hidden;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
width: 0;
|
||||
z-index: $sideToolbarContainerZ;
|
||||
|
||||
/**
|
||||
* Labels inside the side panel.
|
||||
*/
|
||||
label {
|
||||
color: $baseLight;
|
||||
}
|
||||
|
||||
/**
|
||||
* Form elements and blocks.
|
||||
*/
|
||||
input, select, a,
|
||||
.sideToolbarBlock, .form-control, .button-control {
|
||||
display: block;
|
||||
margin-top: 15px;
|
||||
margin-left: 10%;
|
||||
width: 80%;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify styling of elements inside a block.
|
||||
*/
|
||||
.sideToolbarBlock {
|
||||
input, button, a, select {
|
||||
margin-left: 0;
|
||||
margin-top: 5px;
|
||||
width: 100%;
|
||||
}
|
||||
input[type='checkbox'] {
|
||||
display: inline;
|
||||
width: auto !important;
|
||||
> label {
|
||||
margin-top: 5px;
|
||||
width: 80%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Inner container, for example contact list, settings or profile.
|
||||
*/
|
||||
.sideToolbarContainer__inner {
|
||||
display: none;
|
||||
height: 100%;
|
||||
width: $sidebarWidth;
|
||||
position: absolute;
|
||||
box-sizing: border-box;
|
||||
color: #FFF;
|
||||
|
||||
.input-control {
|
||||
border: 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Titles and subtitles of inner containers.
|
||||
*/
|
||||
div.title, div.subTitle {
|
||||
margin: 24px 0 11px;
|
||||
}
|
||||
|
||||
/**
|
||||
* Main title size.
|
||||
*/
|
||||
div.title {
|
||||
color: $toolbarTitleColor;
|
||||
text-align: center;
|
||||
font-size: $toolbarTitleFontSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Subtitle specific properties.
|
||||
*/
|
||||
div.subTitle {
|
||||
color: $defaultSideBarFontColor !important;
|
||||
font-size: 11px;
|
||||
font-weight: 500;
|
||||
margin-left: 10%;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
/**
|
||||
* First element after a title.
|
||||
*/
|
||||
.first {
|
||||
margin-top: 0 !important;
|
||||
}
|
||||
|
||||
/**
|
||||
* Buttons in the side toolbar container.
|
||||
*/
|
||||
.button-control {
|
||||
margin: 9px 0;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#device_settings {
|
||||
width : auto !important;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#deviceOptionsWrapper {
|
||||
button {
|
||||
float: none;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Profile
|
||||
*/
|
||||
.auth_container {
|
||||
ul {
|
||||
padding: 0;
|
||||
|
||||
li {
|
||||
list-style-type: none;
|
||||
|
||||
a.authButton {
|
||||
width: 160px;
|
||||
margin: 10px 20px;
|
||||
padding: 3px 29px;
|
||||
box-sizing: border-box;
|
||||
background-color: #06a5df;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
color: $defaultColor;
|
||||
text-decoration: none;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
396
css/_toolbars.scss
Normal file
396
css/_toolbars.scss
Normal file
@@ -0,0 +1,396 @@
|
||||
/**
|
||||
* Round badge.
|
||||
*/
|
||||
.badge-round {
|
||||
background-color: $toolbarBadgeBackground;
|
||||
border-radius: 50%;
|
||||
box-sizing: border-box;
|
||||
color: $toolbarBadgeColor;
|
||||
// Do not inherit the font-family from the toolbar button, because it's an
|
||||
// icon style.
|
||||
font-family: $baseFontFamily;
|
||||
font-size: 9px;
|
||||
font-weight: 700;
|
||||
line-height: 13px;
|
||||
min-width: 13px;
|
||||
overflow: hidden;
|
||||
text-align: center;
|
||||
text-overflow: ellipsis;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.toolbar-container {
|
||||
display: block;
|
||||
left:0;
|
||||
min-height: 100px;
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
position: absolute;
|
||||
right:0;
|
||||
text-align: center;
|
||||
top:0;
|
||||
z-index: $toolbarZ;
|
||||
}
|
||||
|
||||
/**
|
||||
* Common toolbar styles.
|
||||
*/
|
||||
.toolbar {
|
||||
color: $modalTextColor;
|
||||
height: 100%;
|
||||
pointer-events: auto;
|
||||
position: relative;
|
||||
z-index: $toolbarZ;
|
||||
|
||||
/**
|
||||
* Ensure nested elements that don't have a button class, maybe because they
|
||||
* are wrapped in a React Element, still display in a line.
|
||||
*/
|
||||
> div {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
/**
|
||||
* Always on top overrides.
|
||||
*/
|
||||
&.always-on-top {
|
||||
/**
|
||||
* Toolbar button styles for always on top.
|
||||
*/
|
||||
> .button {
|
||||
font-size: $alwaysOnTopToolbarFontSize;
|
||||
height: $alwaysOnTopToolbarSize;
|
||||
line-height: $alwaysOnTopToolbarSize;
|
||||
width: $alwaysOnTopToolbarSize;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Toolbar button styles.
|
||||
*/
|
||||
.button {
|
||||
color: $toolbarButtonColor;
|
||||
cursor: pointer;
|
||||
z-index: $zindex1;
|
||||
display: inline-block;
|
||||
font-size: $toolbarFontSize;
|
||||
height: $defaultToolbarSize;
|
||||
line-height: $defaultToolbarSize;
|
||||
position: relative;
|
||||
text-align: center;
|
||||
top:0px;
|
||||
vertical-align: middle;
|
||||
width: $defaultToolbarSize;
|
||||
|
||||
&_hangup {
|
||||
color: $hangupColor;
|
||||
font-size: $hangupFontSize;
|
||||
}
|
||||
|
||||
&[disabled] {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
&:hover, &:active {
|
||||
cursor: pointer;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
&:not(.toggled) {
|
||||
&:hover, &:active {
|
||||
// sum opacity with background layer should give us 0.8
|
||||
background: $toolbarSelectBackground;
|
||||
}
|
||||
}
|
||||
|
||||
&.toggled {
|
||||
background: $toolbarToggleBackground;
|
||||
|
||||
&.icon-camera {
|
||||
@extend .icon-camera-disabled;
|
||||
}
|
||||
|
||||
&.icon-full-screen {
|
||||
@extend .icon-exit-full-screen;
|
||||
}
|
||||
|
||||
&.icon-microphone {
|
||||
@extend .icon-mic-disabled;
|
||||
}
|
||||
}
|
||||
|
||||
&.unclickable {
|
||||
cursor: default;
|
||||
|
||||
&:hover, &:active, &.selected {
|
||||
background: none;
|
||||
cursor: default;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Primary toolbar styles.
|
||||
*/
|
||||
&_primary {
|
||||
background-color: $toolbarBackground;
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
top: 30px;
|
||||
display: inline-block;
|
||||
width: auto;
|
||||
height: $defaultToolbarSize;
|
||||
border-radius: 3px;
|
||||
opacity: 0;
|
||||
|
||||
&.always-on-top {
|
||||
height: $alwaysOnTopToolbarSize;
|
||||
top: 10px;
|
||||
}
|
||||
|
||||
@include transform(translateX(-50%));
|
||||
|
||||
> div:first-child .button {
|
||||
border-bottom-left-radius: 3px;
|
||||
border-top-left-radius: 3px;
|
||||
}
|
||||
> div:last-child .button {
|
||||
border-bottom-right-radius: 3px;
|
||||
border-top-right-radius: 3px;
|
||||
}
|
||||
}
|
||||
|
||||
&_primary a.button:last-child::after {
|
||||
content: none;
|
||||
}
|
||||
|
||||
/**
|
||||
* Secondary toolbar styles.
|
||||
*/
|
||||
&_secondary {
|
||||
background-color: $secondaryToolbarBg;
|
||||
position: absolute;
|
||||
align-items: center;
|
||||
box-sizing: border-box;
|
||||
display: -moz-box;
|
||||
display: -ms-flexbox;
|
||||
display: -webkit-box;
|
||||
display: -webkit-flex;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-wrap: nowrap;
|
||||
height: 100%;
|
||||
justify-content: flex-start;
|
||||
left: 0;
|
||||
padding-top: 24px;
|
||||
top: 0;
|
||||
transform: translateX(-100%);
|
||||
width: $defaultToolbarSize;
|
||||
-webkit-transform: translateX(-100%);
|
||||
|
||||
.button {
|
||||
font-size: $secToolbarFontSize;
|
||||
height: $secToolbarLineHeight;
|
||||
line-height: $secToolbarLineHeight;
|
||||
}
|
||||
|
||||
.button.toggled:not(.icon-raised-hand):not(.button-active) {
|
||||
background: $secondaryToolbarBg;
|
||||
cursor: pointer;
|
||||
text-decoration: none;
|
||||
|
||||
&.unclickable {
|
||||
cursor: default;
|
||||
|
||||
&:hover, &:active, &.selected {
|
||||
background: none;
|
||||
cursor: default;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Styles the toolbar in filmstrip-only mode.
|
||||
*/
|
||||
&_filmstrip-only {
|
||||
background-color: $toolbarBackground;
|
||||
border-radius: 3px;
|
||||
display: inline-block;
|
||||
height: auto;
|
||||
width: $defaultFilmStripOnlyToolbarSize;
|
||||
|
||||
.button {
|
||||
height: 37px;
|
||||
line-height: 37px !important;
|
||||
width: 37px;
|
||||
}
|
||||
|
||||
.button:first-child {
|
||||
border-top-left-radius: 3px;
|
||||
border-top-right-radius: 3px;
|
||||
}
|
||||
.button:last-child {
|
||||
border-bottom-right-radius: 3px;
|
||||
border-bottom-left-radius: 3px;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Toolbar specific round badge.
|
||||
*/
|
||||
.badge-round {
|
||||
bottom: 9px;
|
||||
position: absolute;
|
||||
right: 9px;
|
||||
}
|
||||
}
|
||||
|
||||
.filmstrip-only {
|
||||
.toolbox,
|
||||
.toolbox-toolbars {
|
||||
align-items: center;
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
|
||||
.subject {
|
||||
background: linear-gradient(to bottom, rgba(255,255,255,.85) , rgba(255,255,255,.35));
|
||||
border-bottom-left-radius: 12px;
|
||||
border-bottom-right-radius: 12px;
|
||||
box-shadow: 0 0 2px #000000, 0 0 10px #000000;
|
||||
margin-left: 40%;
|
||||
margin-right: 40%;
|
||||
padding: 5px;
|
||||
position: relative;
|
||||
text-align: center;
|
||||
width: auto;
|
||||
z-index: $zindex3;
|
||||
|
||||
&.subject_slide-in {
|
||||
top: 80px;
|
||||
@include transition(top .3s ease-in);
|
||||
}
|
||||
|
||||
&.subject_slide-out {
|
||||
top: 0;
|
||||
@include transition(top .3s ease-out);
|
||||
}
|
||||
}
|
||||
|
||||
#toolbar_button_profile {
|
||||
height: $toolbarAvatarSize + 2*$toolbarAvatarPadding;
|
||||
}
|
||||
|
||||
a.button>#avatar {
|
||||
border-radius: 50%;
|
||||
padding-bottom: $toolbarAvatarPadding;
|
||||
padding-top: $toolbarAvatarPadding;
|
||||
width: $toolbarAvatarSize;
|
||||
}
|
||||
|
||||
#feedbackButton {
|
||||
margin-top: auto;
|
||||
}
|
||||
|
||||
/**
|
||||
* START of slide in animation for extended toolbar.
|
||||
*/
|
||||
@include keyframes(slideInX) {
|
||||
0% { transform: translateX(-100%); }
|
||||
100% { transform: translateX(0%); }
|
||||
}
|
||||
|
||||
.slideInX {
|
||||
@include animation('slideInX .5s forwards');
|
||||
}
|
||||
|
||||
@include keyframes(slideOutX) {
|
||||
0% { transform: translateX(0%); }
|
||||
100% { transform: translateX(-100%); }
|
||||
}
|
||||
|
||||
.slideOutX {
|
||||
@include animation('slideOutX .5s forwards');
|
||||
}
|
||||
|
||||
@include keyframes(slideInExtX) {
|
||||
0% { transform: translateX(-500%); }
|
||||
100% { transform: translateX(0%); }
|
||||
}
|
||||
|
||||
.slideInExtX {
|
||||
@include animation('slideInExtX .5s forwards');
|
||||
}
|
||||
|
||||
@include keyframes(slideOutExtX) {
|
||||
0% { transform: translateX(0%); }
|
||||
100% { transform: translateX(-500%); }
|
||||
}
|
||||
|
||||
.slideOutExtX {
|
||||
@include animation('slideOutExtX .5s forwards');
|
||||
}
|
||||
|
||||
/**
|
||||
* END of slide out animation for extended toolbar.
|
||||
*/
|
||||
|
||||
/**
|
||||
* START of slide in / out animation for main toolbar.
|
||||
*/
|
||||
@include keyframes(slideInY) {
|
||||
100% { transform: translateY(0%); }
|
||||
}
|
||||
|
||||
.slideInY {
|
||||
@include animation('slideInY .5s forwards');
|
||||
}
|
||||
|
||||
@include keyframes(slideOutY) {
|
||||
0% { transform: translateY(0%); }
|
||||
100% { transform: translateY(-100%); }
|
||||
}
|
||||
|
||||
.slideOutY {
|
||||
@include animation('slideOutY .5s forwards');
|
||||
}
|
||||
/**
|
||||
* END of slide in / out animation for main toolbar.
|
||||
*/
|
||||
|
||||
/**
|
||||
* START of slide in animation for extended toolbar panel.
|
||||
*/
|
||||
@include keyframes(slideInExt) {
|
||||
from { width: 0px; }
|
||||
to { width: $sidebarWidth; } // TO FIX: Make this value a percentage.
|
||||
}
|
||||
|
||||
.slideInExt {
|
||||
@include animation("slideInExt .5s forwards");
|
||||
}
|
||||
|
||||
@include keyframes(slideOutExt) {
|
||||
from { width: $sidebarWidth; } // TO FIX: Make this value a percentage.
|
||||
to { width: 0px; }
|
||||
}
|
||||
|
||||
.slideOutExt {
|
||||
@include animation("slideOutExt .5s forwards");
|
||||
}
|
||||
|
||||
/**
|
||||
* START of fade in animation for main toolbar
|
||||
*/
|
||||
.fadeIn {
|
||||
opacity: 1;
|
||||
|
||||
@include transition(all .3s ease-in);
|
||||
}
|
||||
|
||||
.fadeOut {
|
||||
opacity: 0;
|
||||
|
||||
@include transition(all .3s ease-out);
|
||||
}
|
||||
38
css/_utils.scss
Normal file
38
css/_utils.scss
Normal file
@@ -0,0 +1,38 @@
|
||||
/**
|
||||
* Hides an element.
|
||||
*/
|
||||
.hide {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows an element.
|
||||
*/
|
||||
.show {
|
||||
display: block !important;
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows an inline element.
|
||||
*/
|
||||
.show-inline {
|
||||
display: inline-block !important;
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows as a list item
|
||||
**/
|
||||
.show-list-item {
|
||||
display: list-item !important;
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows a flex element.
|
||||
*/
|
||||
.show-flex {
|
||||
display: -webkit-box !important;
|
||||
display: -moz-box !important;
|
||||
display: -ms-flexbox !important;
|
||||
display: -webkit-flex !important;
|
||||
display: flex !important;
|
||||
}
|
||||
153
css/_variables.scss
Normal file
153
css/_variables.scss
Normal file
@@ -0,0 +1,153 @@
|
||||
@import "themes/light";
|
||||
|
||||
/**
|
||||
* Style variables
|
||||
*/
|
||||
$baseFontFamily: 'open_sanslight', 'Helvetica Neue', Helvetica, Arial, sans-serif;
|
||||
$hangupColor: #bf2117;
|
||||
$hangupFontSize: 2em;
|
||||
|
||||
/**
|
||||
* Size variables.
|
||||
*/
|
||||
|
||||
// Video layout.
|
||||
$thumbnailToolbarHeight: 22px;
|
||||
$thumbnailIndicatorBorder: 2px;
|
||||
$thumbnailIndicatorSize: $thumbnailToolbarHeight;
|
||||
$thumbnailVideoMargin: 2px;
|
||||
$thumbnailsBorder: 2px;
|
||||
$thumbnailVideoBorder: 2px;
|
||||
$filmstripToggleButtonWidth: 17px;
|
||||
|
||||
|
||||
/**
|
||||
* Color variables.
|
||||
*/
|
||||
$defaultColor: #F1F1F1;
|
||||
$defaultSideBarFontColor: #44A5FF;
|
||||
$defaultSemiDarkColor: #ACACAC;
|
||||
$defaultDarkColor: #2b3d5c;
|
||||
|
||||
/**
|
||||
* Toolbar
|
||||
*/
|
||||
$alwaysOnTopToolbarFontSize: 1em;
|
||||
$alwaysOnTopToolbarSize: 30px;
|
||||
$defaultToolbarSize: 50px;
|
||||
$defaultFilmStripOnlyToolbarSize: 37px;
|
||||
$secToolbarFontSize: 1.9em;
|
||||
$secToolbarLineHeight: 45px;
|
||||
$toolbarAvatarPadding: 10px;
|
||||
$toolbarAvatarSize: 40px;
|
||||
$toolbarFontSize: 1.9em;
|
||||
$toolbarTitleFontSize: 19px;
|
||||
|
||||
/**
|
||||
* Main controls
|
||||
* TODO: looks like we don't use it
|
||||
*/
|
||||
$inputSemiBackground: rgba(132, 132, 132, .8);
|
||||
$inputLightBackground: #EBEBEB;
|
||||
|
||||
/**
|
||||
* Video layout
|
||||
*/
|
||||
$videoThumbnailHovered: rgba(22, 94, 204, .4);
|
||||
$videoThumbnailSelected: #165ECC;
|
||||
$participantNameColor: #fff;
|
||||
$thumbnailPictogramColor: #fff;
|
||||
$dominantSpeakerBg: #165ecc;
|
||||
$raiseHandBg: #D6D61E;
|
||||
$audioLevelBg: #44A5FF;
|
||||
$connectionIndicatorBg: #165ecc;
|
||||
$audioLevelShadow: rgba(9, 36, 77, 0.9);
|
||||
$videoStateIndicatorColor: $defaultColor;
|
||||
$videoStateIndicatorBackground: $toolbarBackground;
|
||||
|
||||
/**
|
||||
* Feedback Modal
|
||||
*/
|
||||
$feedbackContentBg: #fff;
|
||||
$feedbackInputBg: #fff;
|
||||
$feedbackTextColor: #000;
|
||||
$feedbackInputTextColor: #333;
|
||||
$feedbackInputPlaceholderColor: #777;
|
||||
$rateStarLabelColor: #333;
|
||||
$rateStarDefault: #ccc;
|
||||
$rateStarActivity: #165ecc;
|
||||
$rateStarSize: 34px;
|
||||
|
||||
/**
|
||||
* Modals
|
||||
*/
|
||||
$modalButtonFontSize: 14px;
|
||||
$modalMockAKInputBackground: #fafbfc;
|
||||
$modalMockAKInputBorder: 1px solid #f4f5f7;
|
||||
$modalTextColor: #333;
|
||||
|
||||
/**
|
||||
* Misc.
|
||||
*/
|
||||
$borderRadius: 4px;
|
||||
$defaultWatermarkLink: '../images/watermark.png';
|
||||
$sidebarWidth: 220px;
|
||||
$popoverMenuPadding: 13px;
|
||||
$happySoftwareBackground: transparent;
|
||||
|
||||
/**
|
||||
* Z-indexes. TODO: Replace this by a function.
|
||||
*/
|
||||
$zindex0: 0;
|
||||
$zindex1: 1;
|
||||
$zindex2: 2;
|
||||
$zindex3: 3;
|
||||
$filmstripVideosZ: 5;
|
||||
$zindex10: 10;
|
||||
$reloadZ: 20;
|
||||
$poweredByZ: 100;
|
||||
$ringingZ: 300;
|
||||
$sideToolbarContainerZ: 300;
|
||||
$toolbarZ: 350;
|
||||
$tooltipsZ: 401;
|
||||
$dropdownMaskZ: 900;
|
||||
$dropdownZ: 901;
|
||||
$centeredVideoLabelZ: 1010;
|
||||
$popoverZ: 1015;
|
||||
$overlayZ: 1016;
|
||||
|
||||
|
||||
/**
|
||||
* Font Colors
|
||||
*/
|
||||
$defaultFontColor: #777;
|
||||
$defaultLightFontColor: #F1F1F1;
|
||||
$defaultDarkFontColor: #000;
|
||||
|
||||
/**
|
||||
* Forms
|
||||
*/
|
||||
//inputs
|
||||
$inputControlEmColor: #f29424;
|
||||
//buttons
|
||||
$linkFontColor: #489afe;
|
||||
$linkHoverFontColor: #287ade;
|
||||
$formPadding: 16px;
|
||||
|
||||
/**
|
||||
* Unsupported browser
|
||||
*/
|
||||
$primaryUnsupportedBrowserButtonBgColor: #17a0db;
|
||||
$unsupportedBrowserButtonBgColor: #ff9a00;
|
||||
$unsupportedBrowserTextColor: #4a4a4a;
|
||||
$unsupportedBrowserTextSmallFontSize: 17px;
|
||||
$unsupportedBrowserTitleColor: #fff;
|
||||
$unsupportedBrowserTitleFontSize: 24px;
|
||||
$unsupportedDesktopBrowserTextColor: rgba(255, 255, 255, 0.7);
|
||||
$unsupportedDesktopBrowserTextFontSize: 21px;
|
||||
|
||||
/**
|
||||
* The size of the default watermark.
|
||||
*/
|
||||
$watermarkWidth: 186px;
|
||||
$watermarkHeight: 74px;
|
||||
221
css/_vertical_filmstrip_overrides.scss
Normal file
221
css/_vertical_filmstrip_overrides.scss
Normal file
@@ -0,0 +1,221 @@
|
||||
/**
|
||||
* Override other styles to support vertical filmstrip mode.
|
||||
*/
|
||||
.vertical-filmstrip {
|
||||
.filmstrip {
|
||||
align-items: flex-end;
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
flex-direction: column-reverse;
|
||||
height: 100%;
|
||||
/**
|
||||
* fixed positioning is necessary for remote menus and tooltips to pop
|
||||
* out of the scrolling filmstrip. AtlasKit dialogs and tooltips use
|
||||
* a library called popper which will position its elements fixed if
|
||||
* any parent is also fixed.
|
||||
*/
|
||||
position: fixed;
|
||||
|
||||
/**
|
||||
* z-index adjusting is needed because the video state indicator has to
|
||||
* display over the filmstrip when no videos are displayed but still be
|
||||
* clickable but its inline dialogs must display over the video state
|
||||
* indicator when videos are displayed.
|
||||
*/
|
||||
z-index: #{$tooltipsZ + 1};
|
||||
|
||||
/**
|
||||
* Hide videos by making them slight to the right.
|
||||
*/
|
||||
.filmstrip__videos {
|
||||
right: 0;
|
||||
transition: right 2s;
|
||||
|
||||
&.hidden {
|
||||
bottom: auto;
|
||||
right: -196px;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove horizontal filmstrip padding used to prevent videos from
|
||||
* overlapping the left-side toolbar. An id selector is used to
|
||||
* match id specificity with filmstrip styles.
|
||||
*/
|
||||
&#remoteVideos {
|
||||
padding-left: 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Re-styles the local Video and invite button to better fit the
|
||||
* vertical filmstrip layout.
|
||||
*/
|
||||
#filmstripLocalVideo {
|
||||
bottom: 5px;
|
||||
flex-direction: column-reverse;
|
||||
height: auto;
|
||||
justify-content: flex-start;
|
||||
|
||||
.filmstrip__invite {
|
||||
padding-bottom: 0px;
|
||||
padding-top: 5px;
|
||||
z-index: $dropdownZ;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove unnecssary padding that is normally used to prevent horizontal
|
||||
* filmstrip from overlapping the left edge of the screen.
|
||||
*/
|
||||
#filmstripLocalVideo,
|
||||
#filmstripRemoteVideos {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#filmstripRemoteVideos {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
flex-direction: column;
|
||||
height: auto;
|
||||
justify-content: flex-end;
|
||||
|
||||
#filmstripRemoteVideosContainer {
|
||||
flex-direction: column-reverse;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Rotate the hide filmstrip icon so it points towards the right edge
|
||||
* of the screen.
|
||||
*/
|
||||
&__toolbar {
|
||||
transform: rotate(-90deg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Move the remote video menu trigger to the bottom left of the
|
||||
* video thumbnail.
|
||||
*/
|
||||
.remotevideomenu,
|
||||
.remote-video-menu-trigger {
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
top: auto;
|
||||
right: auto;
|
||||
}
|
||||
|
||||
.remote-video-menu-trigger {
|
||||
margin-bottom: 7px;
|
||||
}
|
||||
|
||||
#remoteVideos {
|
||||
flex-direction: column;
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.videocontainer {
|
||||
/**
|
||||
* Move status icons to the bottom right of the thumbnail.
|
||||
*/
|
||||
&__toolbar {
|
||||
text-align: right;
|
||||
|
||||
.right {
|
||||
float: none;
|
||||
margin: auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.filmstrip-only {
|
||||
.filmstrip {
|
||||
flex-direction: row-reverse;
|
||||
}
|
||||
.filmstrip__videos-filmstripOnly {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
/**
|
||||
* In filmstrip only mode, the toolbar is normally displayed in the
|
||||
* vertical center of the filmstrip strip. In vertical filmstrip mode,
|
||||
* that alignment makes the toolbar appear floating and detached from
|
||||
* the filmstrip. So, instead anchor the toolbar next to the local
|
||||
* video.
|
||||
*/
|
||||
.toolbar_filmstrip-only {
|
||||
bottom: 0;
|
||||
top: auto;
|
||||
transform: none;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* These styles are for the video labels that display on the top right. The
|
||||
* styles adjust the labels' positioning as the filmstrip itself or
|
||||
* filmstrip's remote videos appear and disappear.
|
||||
*
|
||||
* The class with-filmstrip is for when the filmstrip is visible.
|
||||
* The class without-filmstrip is for when the filmstrip has been toggled to
|
||||
* be hidden.
|
||||
* The class opening is for when the filmstrip is transitioning from hidden
|
||||
* to visible.
|
||||
*/
|
||||
.video-state-indicator.moveToCorner {
|
||||
transition: right 0.5s;
|
||||
|
||||
&.with-filmstrip {
|
||||
&#recordingLabel {
|
||||
right: 200px;
|
||||
}
|
||||
|
||||
&#videoResolutionLabel {
|
||||
right: 150px;
|
||||
}
|
||||
}
|
||||
|
||||
&.with-filmstrip.opening {
|
||||
transition: 0.9s;
|
||||
transition-timing-function: ease-in-out;
|
||||
}
|
||||
|
||||
&.without-filmstrip {
|
||||
transition: 1.2s ease-in-out;
|
||||
transition-delay: 0.1s;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply hardware acceleration to prevent flickering on scroll. The
|
||||
* selectors are specific to icon wrappers to prevent fixed position dialogs
|
||||
* and tooltips from getting a new location context due to translate3d.
|
||||
*/
|
||||
.connection-indicator,
|
||||
.remote-video-menu-trigger,
|
||||
.indicator-icon-container {
|
||||
transform: translate3d(0, 0, 0);
|
||||
}
|
||||
|
||||
.indicator-container {
|
||||
float: none;
|
||||
}
|
||||
|
||||
/**
|
||||
* FIXME: disable pointer to allow any elements moved below to still be
|
||||
* clickable. The real fix would to make sure those moved elements are
|
||||
* actually part of the toolbar instead of positioning being faked.
|
||||
*/
|
||||
.videocontainer__toolbar {
|
||||
pointer-events: none;
|
||||
|
||||
> div {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.toolbar-icon {
|
||||
pointer-events: all;
|
||||
}
|
||||
}
|
||||
}
|
||||
598
css/_videolayout_default.scss
Normal file
598
css/_videolayout_default.scss
Normal file
@@ -0,0 +1,598 @@
|
||||
#videoconference_page {
|
||||
min-height: 100%;
|
||||
}
|
||||
|
||||
#videospace {
|
||||
display: block;
|
||||
min-height: 100%;
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
left: 0px;
|
||||
right: 0px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.video_blurred_container {
|
||||
height: 100%;
|
||||
filter: blur(40px);
|
||||
left: 0;
|
||||
overflow: hidden;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.videocontainer {
|
||||
position: relative;
|
||||
text-align: center;
|
||||
|
||||
&__background {
|
||||
@include topLeft();
|
||||
background-color: black;
|
||||
border-radius: $borderRadius;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
/**
|
||||
* The toolbar of the video thumbnail.
|
||||
*/
|
||||
&__toolbar,
|
||||
&__toptoolbar {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
pointer-events: none;
|
||||
z-index: $zindex10;
|
||||
width: 100%;
|
||||
box-sizing: border-box; // Includes the padding in the 100% width.
|
||||
|
||||
/**
|
||||
* FIXME (lenny): Disabling pointer-events is a pretty big sin that
|
||||
* sidesteps the problems. There are z-index wars occurring within
|
||||
* videocontainer and AtlasKit Tooltips rely on their parent z-indexe
|
||||
* being higher than whatever they need to appear over. So set a higher
|
||||
* z-index for the tooltip containers but make any empty space not block
|
||||
* mouse overs for various mouseover triggers.
|
||||
*/
|
||||
pointer-events: none;
|
||||
|
||||
* {
|
||||
pointer-events: auto;
|
||||
}
|
||||
|
||||
.indicator-container {
|
||||
display: inline-block;
|
||||
float: left;
|
||||
pointer-events: all;
|
||||
}
|
||||
}
|
||||
|
||||
&__toolbar {
|
||||
bottom: 0;
|
||||
height: $thumbnailToolbarHeight;
|
||||
padding: 0 5px 0 5px;
|
||||
}
|
||||
|
||||
&__toptoolbar {
|
||||
$toolbarIconMargin: 5px;
|
||||
top: 0;
|
||||
padding-bottom: 0;
|
||||
/**
|
||||
* Override text-align center as icons need to be left justified.
|
||||
*/
|
||||
text-align: left;
|
||||
|
||||
/**
|
||||
* Intentionally use margin on the icon itself as AtlasKit InlineDialog
|
||||
* positioning depends on the trigger (indicator icon).
|
||||
*/
|
||||
.indicator {
|
||||
margin-left: 5px;
|
||||
margin-top: $toolbarIconMargin;
|
||||
}
|
||||
|
||||
.indicator-container:nth-child(1) .indicator {
|
||||
margin-left: $toolbarIconMargin;
|
||||
}
|
||||
|
||||
.indicator-container {
|
||||
display: inline-block;
|
||||
vertical-align: top;
|
||||
|
||||
.popover-trigger {
|
||||
display: inline-block;
|
||||
}
|
||||
}
|
||||
|
||||
.connection-indicator,
|
||||
.indicator {
|
||||
position: relative;
|
||||
font-size: 8px;
|
||||
text-align: center;
|
||||
line-height: $thumbnailIndicatorSize;
|
||||
padding: 0;
|
||||
@include circle($thumbnailIndicatorSize);
|
||||
box-sizing: border-box;
|
||||
z-index: $zindex3;
|
||||
background: $dominantSpeakerBg;
|
||||
color: $thumbnailPictogramColor;
|
||||
border: $thumbnailIndicatorBorder solid $thumbnailPictogramColor;
|
||||
|
||||
.indicatoricon {
|
||||
@include absoluteAligning();
|
||||
}
|
||||
|
||||
.connection {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
margin: 0 auto;
|
||||
left: 0;
|
||||
@include transform(translate(0, -50%));
|
||||
|
||||
&_empty,
|
||||
&_lost
|
||||
{
|
||||
color: #8B8B8B;/*#FFFFFF*/
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
&_full
|
||||
{
|
||||
@include topLeft();
|
||||
color: #FFFFFF;/*#15A1ED*/
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
&_ninja
|
||||
{
|
||||
font-size: 1.5em;
|
||||
}
|
||||
}
|
||||
|
||||
.icon-gsm-bars {
|
||||
cursor: pointer;
|
||||
font-size: 1em;
|
||||
}
|
||||
}
|
||||
|
||||
.hide-connection-indicator {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
&__hoverOverlay {
|
||||
background: rgba(0,0,0,.6);
|
||||
border-radius: $borderRadius;
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
visibility: hidden;
|
||||
z-index: $zindex2;
|
||||
}
|
||||
|
||||
&.audio-only {
|
||||
.videoThumbnailProblemFilter {
|
||||
filter: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#localVideoWrapper {
|
||||
display:inline-block;
|
||||
}
|
||||
|
||||
.flipVideoX {
|
||||
transform: scale(-1, 1);
|
||||
-moz-transform: scale(-1, 1);
|
||||
-webkit-transform: scale(-1, 1);
|
||||
-o-transform: scale(-1, 1);
|
||||
}
|
||||
|
||||
#localVideoWrapper video,
|
||||
#localVideoWrapper object {
|
||||
border-radius: $borderRadius !important;
|
||||
cursor: hand;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
#largeVideo,
|
||||
#largeVideoWrapper,
|
||||
#largeVideoContainer {
|
||||
overflow: hidden;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#largeVideoWrapper {
|
||||
box-shadow: 0 0 20px -2px #444;
|
||||
}
|
||||
|
||||
#largeVideo,
|
||||
#largeVideoWrapper
|
||||
{
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
#sharedVideo,
|
||||
#etherpad,
|
||||
#localVideoWrapper video,
|
||||
#localVideoWrapper object,
|
||||
#localVideoWrapper,
|
||||
#largeVideoWrapper,
|
||||
#largeVideoWrapper>video,
|
||||
#largeVideoWrapper>object,
|
||||
.videocontainer>video,
|
||||
.videocontainer>object {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
z-index: $zindex1;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
#etherpad {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#etherpad {
|
||||
z-index: $zindex0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Positions video thumbnail display name and editor.
|
||||
*/
|
||||
.videocontainer .displayname,
|
||||
.videocontainer .editdisplayname {
|
||||
display: inline-block;
|
||||
position: absolute;
|
||||
left: 10%;
|
||||
width: 80%;
|
||||
top: 50%;
|
||||
@include transform(translateY(-40%));
|
||||
color: $participantNameColor;
|
||||
text-align: center;
|
||||
text-overflow: ellipsis;
|
||||
font-size: 12px;
|
||||
font-weight: 100;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
line-height: $thumbnailToolbarHeight;
|
||||
z-index: $zindex2;
|
||||
}
|
||||
|
||||
/**
|
||||
* Positions video thumbnail display name editor.
|
||||
*/
|
||||
.videocontainer .editdisplayname {
|
||||
outline: none;
|
||||
border: none;
|
||||
background: none;
|
||||
box-shadow: none;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#localVideoContainer .displayname:hover {
|
||||
cursor: text;
|
||||
}
|
||||
|
||||
.videocontainer .displayname {
|
||||
pointer-events: none;
|
||||
padding: 0 3px 0 3px;
|
||||
}
|
||||
|
||||
.videocontainer .editdisplayname {
|
||||
height: auto;
|
||||
}
|
||||
|
||||
#localDisplayName {
|
||||
pointer-events: auto !important;
|
||||
}
|
||||
|
||||
.videocontainer>a.displayname {
|
||||
display: inline-block;
|
||||
position: absolute;
|
||||
color: #FFFFFF;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
padding: 3px 5px;
|
||||
font-size: 9pt;
|
||||
cursor: pointer;
|
||||
z-index: $zindex2;
|
||||
}
|
||||
|
||||
/**
|
||||
* Video thumbnail toolbar icon.
|
||||
*/
|
||||
.videocontainer .toolbar-icon {
|
||||
font-size: 8pt;
|
||||
text-align: center;
|
||||
text-shadow: 0px 1px 0px rgba(255,255,255,.3), 0px -1px 0px rgba(0,0,0,.7);
|
||||
color: #FFFFFF;
|
||||
width: 12px;
|
||||
line-height: $thumbnailToolbarHeight;
|
||||
height: $thumbnailToolbarHeight;
|
||||
padding: 0;
|
||||
border: 0;
|
||||
margin: 0px 5px 0px 0px;
|
||||
}
|
||||
|
||||
/**
|
||||
* Toolbar icon internal i elements (font icons).
|
||||
*/
|
||||
.toolbar-icon>i {
|
||||
line-height: $thumbnailToolbarHeight;
|
||||
}
|
||||
|
||||
/**
|
||||
* Toolbar icons positioned on the right.
|
||||
*/
|
||||
.moderator-icon {
|
||||
display: inline-block;
|
||||
|
||||
&.right {
|
||||
float: right;
|
||||
margin: 0px 0px 0px 5px;
|
||||
}
|
||||
|
||||
.toolbar-icon {
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.raisehandindicator {
|
||||
background: $raiseHandBg;
|
||||
}
|
||||
|
||||
.connection-indicator {
|
||||
background: $connectionIndicatorBg;
|
||||
|
||||
&.status-high {
|
||||
background: green;
|
||||
}
|
||||
|
||||
&.status-med {
|
||||
background: #FFD740;
|
||||
}
|
||||
|
||||
&.status-lost {
|
||||
background: gray;
|
||||
}
|
||||
|
||||
&.status-low {
|
||||
background: #BF2117;
|
||||
}
|
||||
|
||||
&.status-other {
|
||||
background: $connectionIndicatorBg;
|
||||
}
|
||||
}
|
||||
|
||||
.remote-video-menu-trigger,
|
||||
.remotevideomenu
|
||||
{
|
||||
display: inline-block;
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
right: 0;
|
||||
z-index: $zindex2;
|
||||
width: 18px;
|
||||
height: 13px;
|
||||
color: #FFF;
|
||||
font-size: 10pt;
|
||||
|
||||
>i{
|
||||
cursor: hand;
|
||||
}
|
||||
}
|
||||
.remote-video-menu-trigger {
|
||||
margin-top: 7px;
|
||||
}
|
||||
|
||||
/**
|
||||
* Audio indicator on video thumbnails.
|
||||
*/
|
||||
.videocontainer>span.audioindicator,
|
||||
.videocontainer>.audioindicator-container {
|
||||
position: absolute;
|
||||
display: inline-block;
|
||||
left: 6px;
|
||||
top: 50%;
|
||||
margin-top: -17px;
|
||||
width: 6px;
|
||||
height: 35px;
|
||||
z-index: $zindex2;
|
||||
border: none;
|
||||
|
||||
.audiodot-top,
|
||||
.audiodot-bottom,
|
||||
.audiodot-middle {
|
||||
opacity: 0;
|
||||
display: inline-block;
|
||||
@include circle(5px);
|
||||
background: $audioLevelShadow;
|
||||
margin: 1px 0 1px 0;
|
||||
transition: opacity .25s ease-in-out;
|
||||
-moz-transition: opacity .25s ease-in-out;
|
||||
}
|
||||
|
||||
span.audiodot-top::after,
|
||||
span.audiodot-bottom::after,
|
||||
span.audiodot-middle::after {
|
||||
content: "";
|
||||
display: inline-block;
|
||||
width: 5px;
|
||||
height: 5px;
|
||||
border-radius: 50%;
|
||||
-webkit-filter: blur(0.5px);
|
||||
filter: blur(0.5px);
|
||||
background: $audioLevelBg;
|
||||
}
|
||||
}
|
||||
|
||||
#reloadPresentation {
|
||||
display: none;
|
||||
position: absolute;
|
||||
color: #FFFFFF;
|
||||
top: 0;
|
||||
right:0;
|
||||
padding: 10px 10px;
|
||||
font-size: 11pt;
|
||||
cursor: pointer;
|
||||
background: rgba(0, 0, 0, 0.3);
|
||||
border-radius: 5px;
|
||||
background-clip: padding-box;
|
||||
-webkit-border-radius: 5px;
|
||||
-webkit-background-clip: padding-box;
|
||||
z-index: $reloadZ; /*The reload button should appear on top of the header!*/
|
||||
}
|
||||
|
||||
.audiolevel {
|
||||
display: inline-block;
|
||||
position: absolute;
|
||||
z-index: $zindex0;
|
||||
border-radius:1px;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
#dominantSpeaker {
|
||||
visibility: hidden;
|
||||
width: 300px;
|
||||
height: 300px;
|
||||
margin: auto;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
#mixedstream {
|
||||
display:none !important;
|
||||
}
|
||||
|
||||
#dominantSpeakerAvatar,
|
||||
.dynamic-shadow {
|
||||
width: 200px;
|
||||
height: 200px;
|
||||
}
|
||||
|
||||
#dominantSpeakerAvatar {
|
||||
top: 50px;
|
||||
margin: auto;
|
||||
position: relative;
|
||||
border-radius: 100px;
|
||||
visibility: inherit;
|
||||
background-color: #000000;
|
||||
}
|
||||
|
||||
.dynamic-shadow {
|
||||
border-radius: 50%;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
margin: -100px 0 0 -100px;
|
||||
transition: box-shadow 0.3s ease;
|
||||
}
|
||||
|
||||
.userAvatar {
|
||||
@include maxSize(60px);
|
||||
@include absoluteAligning();
|
||||
border-radius: 50%;
|
||||
height: 50%;
|
||||
width: auto;
|
||||
}
|
||||
|
||||
.sharedVideoAvatar {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.noMic {
|
||||
position: absolute;
|
||||
border-radius: 8px;
|
||||
z-index: $zindex1;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-image: url("../images/noMic.png");
|
||||
background-color: #000;
|
||||
background-repeat: no-repeat;
|
||||
background-position: center;
|
||||
}
|
||||
|
||||
.noVideo {
|
||||
position: absolute;
|
||||
border-radius: 8px;
|
||||
z-index: $zindex1;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-image: url("../images/noVideo.png");
|
||||
background-color: #000;
|
||||
background-repeat: no-repeat;
|
||||
background-position: center;
|
||||
}
|
||||
|
||||
.videoMessageFilter {
|
||||
-webkit-filter: grayscale(.5) opacity(0.8);
|
||||
filter: grayscale(.5) opacity(0.8);
|
||||
}
|
||||
|
||||
.remoteVideoProblemFilter {
|
||||
-webkit-filter: grayscale(100%);
|
||||
filter: grayscale(100%);
|
||||
}
|
||||
|
||||
.videoProblemFilter {
|
||||
-webkit-filter: blur(10px) grayscale(.5) opacity(0.8);
|
||||
filter: blur(10px) grayscale(.5) opacity(0.8);
|
||||
}
|
||||
|
||||
.videoThumbnailProblemFilter {
|
||||
-webkit-filter: grayscale(100%);
|
||||
filter: grayscale(100%);
|
||||
}
|
||||
|
||||
#remotePresenceMessage,
|
||||
#remoteConnectionMessage {
|
||||
position: absolute;
|
||||
width: auto;
|
||||
z-index: $zindex2;
|
||||
font-weight: 600;
|
||||
font-size: 14px;
|
||||
text-align: center;
|
||||
color: #FFF;
|
||||
left: 50%;
|
||||
transform: translate(-50%, 0);
|
||||
}
|
||||
#remotePresenceMessage .presence-label,
|
||||
#remoteConnectionMessage {
|
||||
opacity: .80;
|
||||
text-shadow: 0px 0px 1px rgba(0,0,0,0.3),
|
||||
0px 1px 1px rgba(0,0,0,0.3),
|
||||
1px 0px 1px rgba(0,0,0,0.3),
|
||||
0px 0px 1px rgba(0,0,0,0.3);
|
||||
|
||||
background: rgba(0,0,0,.5);
|
||||
border-radius: 5px;
|
||||
padding: 5px;
|
||||
padding-left: 10px;
|
||||
padding-right: 10px;
|
||||
}
|
||||
#remotePresenceMessage .no-presence,
|
||||
#remoteConnectionMessage {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#localConnectionMessage {
|
||||
display: none;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
top:50%;
|
||||
z-index: $zindex2;
|
||||
font-weight: 600;
|
||||
font-size: 14px;
|
||||
text-align: center;
|
||||
color: #FFF;
|
||||
opacity: .80;
|
||||
text-shadow: 0px 0px 1px rgba(0,0,0,0.3),
|
||||
0px 1px 1px rgba(0,0,0,0.3),
|
||||
1px 0px 1px rgba(0,0,0,0.3),
|
||||
0px 0px 1px rgba(0,0,0,0.3);
|
||||
}
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
#disable_welcome {
|
||||
display:none;
|
||||
}
|
||||
@@ -21,10 +20,9 @@
|
||||
-moz-user-select: none;
|
||||
background-repeat: no-repeat;
|
||||
font-weight: 500;
|
||||
font-family: Helvetica;
|
||||
font-size: 16px;
|
||||
color: #acacac;
|
||||
z-index: 2;
|
||||
z-index: $zindex2;
|
||||
}
|
||||
|
||||
#disable_welcome:checked + label
|
||||
@@ -35,10 +33,9 @@
|
||||
-moz-user-select: none;
|
||||
background-repeat: no-repeat;
|
||||
font-weight: 500;
|
||||
font-family: Helvetica;
|
||||
font-size: 16px;
|
||||
color: #acacac;
|
||||
z-index: 2;
|
||||
z-index: $zindex2;
|
||||
}
|
||||
|
||||
#enter_room_form {
|
||||
@@ -53,48 +50,62 @@
|
||||
float: left;
|
||||
}
|
||||
|
||||
#domain_name
|
||||
.domain-name
|
||||
{
|
||||
float: left;
|
||||
padding: 20px 0px 10px 20px;
|
||||
height: 55px;
|
||||
line-height: 55px;
|
||||
font-size: 18px;
|
||||
font-weight: 500;
|
||||
font-family: Helvetica;
|
||||
padding-left: 20px;
|
||||
color: $defaultDarkColor;
|
||||
}
|
||||
|
||||
#enter_room_field {
|
||||
font-size: 15px;
|
||||
padding: 15px 0px 10px 10px;
|
||||
border: none;
|
||||
-webkit-appearance: none;
|
||||
width: 228px;
|
||||
height: 55px;
|
||||
font-weight: 500;
|
||||
font-family: Helvetica;
|
||||
box-shadow: none;
|
||||
float: left;
|
||||
background-color: #FFFFFF;
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
}
|
||||
.enter-room {
|
||||
&__field {
|
||||
font-size: 15px;
|
||||
border: none;
|
||||
-webkit-appearance: none;
|
||||
width: 228px;
|
||||
height: 55px;
|
||||
line-height: 55px;
|
||||
font-weight: 500;
|
||||
box-shadow: none;
|
||||
float: left;
|
||||
background-color: #FFFFFF;
|
||||
position: relative;
|
||||
z-index: $zindex2;
|
||||
}
|
||||
|
||||
#enter_room_button {
|
||||
width: 73px;
|
||||
height: 45px;
|
||||
background-color: #16a8fe;
|
||||
moz-border-radius: 1px;
|
||||
-webkit-border-radius: 1px;
|
||||
color: #ffffff;
|
||||
font-weight: 600;
|
||||
border: none;
|
||||
margin-top: 5px;
|
||||
font-size: 19px;
|
||||
font-family: Helvetica;
|
||||
padding-top: 6px;
|
||||
outline: none;
|
||||
float:left;
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
&__reload {
|
||||
display: block;
|
||||
width: 30px;
|
||||
color: #acacac;
|
||||
font-size: 1.9em;
|
||||
line-height: 55px;
|
||||
z-index: $zindex3;
|
||||
float: left;
|
||||
cursor: pointer;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
&__button {
|
||||
width: 73px;
|
||||
height: 45px;
|
||||
background-color: #21B9FC;
|
||||
moz-border-radius: 1px;
|
||||
-webkit-border-radius: 1px;
|
||||
color: #ffffff;
|
||||
font-weight: 600;
|
||||
border: none;
|
||||
margin-top: 5px;
|
||||
font-size: 19px;
|
||||
padding-top: 6px;
|
||||
outline: none;
|
||||
float:left;
|
||||
position: relative;
|
||||
z-index: $zindex2;
|
||||
}
|
||||
}
|
||||
|
||||
#enter_room_container {
|
||||
@@ -136,7 +147,6 @@
|
||||
width: 885px;
|
||||
height: 100px;
|
||||
color: #ffffff;
|
||||
font-family: Helvetica;
|
||||
font-size: 24px;
|
||||
text-align: center;
|
||||
margin: 0px auto 0px auto;
|
||||
@@ -171,7 +181,6 @@
|
||||
background-repeat: no-repeat;
|
||||
width: 169px;
|
||||
height: 169px;
|
||||
font-family: Helvetica;
|
||||
color: #ffffff;
|
||||
font-size: 22px;
|
||||
/*font-weight: bold;*/
|
||||
@@ -183,23 +192,9 @@
|
||||
.feature_description
|
||||
{
|
||||
width: 190px;
|
||||
font-family: Helvetica;
|
||||
color: #ffffff;
|
||||
font-size: 16px;
|
||||
padding-top: 30px;
|
||||
line-height: 22px;
|
||||
font-weight: 200;
|
||||
}
|
||||
|
||||
#reload_roomname
|
||||
{
|
||||
width: 30px;
|
||||
height: 19px;
|
||||
color: #acacac;
|
||||
margin-top: 22px;
|
||||
z-index: 3;
|
||||
float: left;
|
||||
cursor: pointer;
|
||||
text-align: center;
|
||||
display: none;
|
||||
}
|
||||
68
css/aui-components/dropdown.scss
Normal file
68
css/aui-components/dropdown.scss
Normal file
@@ -0,0 +1,68 @@
|
||||
.select2-container.aui-select2-container {
|
||||
background-color: transparent !important;
|
||||
margin-top: 2px;
|
||||
|
||||
a.select2-choice {
|
||||
height: 28px !important;
|
||||
line-height: 18px !important;
|
||||
width: 100% !important;
|
||||
background-color: $selectBg !important;
|
||||
border-color: $selectBg !important;
|
||||
color: $selectFontColor !important;
|
||||
text-shadow: none !important;
|
||||
font-size: 12px !important;
|
||||
margin: 0 auto !important;
|
||||
|
||||
&:after {
|
||||
border-top-color: $selectFontColor;
|
||||
}
|
||||
}
|
||||
|
||||
&.select2-dropdown-open{
|
||||
a.select2-choice {
|
||||
background-color: $selectActiveBg !important;
|
||||
border-color: $selectActiveBg !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.select2-drop.aui-select2-drop.aui-style-default {
|
||||
z-index: $dropdownZ;
|
||||
background-color: $selectActiveBg;
|
||||
border-color: $selectActiveBg;
|
||||
|
||||
.select2-results{
|
||||
background-color: $selectActiveBg;
|
||||
border-color: $selectActiveBg;
|
||||
|
||||
&::-webkit-scrollbar {
|
||||
background-color: transparent;
|
||||
}
|
||||
&::-webkit-scrollbar-track {
|
||||
background-color: transparent;
|
||||
}
|
||||
&::-webkit-scrollbar-track-piece {
|
||||
background-color: transparent;
|
||||
}
|
||||
&::-webkit-scrollbar-thumb {
|
||||
background-color: $selectActiveItemBg;
|
||||
}
|
||||
|
||||
.select2-result{
|
||||
&.select2-highlighted{
|
||||
background-color: $selectActiveItemBg;
|
||||
}
|
||||
|
||||
.select2-result-label{
|
||||
font-size: 12px;
|
||||
color: $selectFontColor !important;
|
||||
line-height: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
.select2-drop-mask {
|
||||
z-index: $dropdownMaskZ;
|
||||
}
|
||||
101
css/components/_button-control.scss
Normal file
101
css/components/_button-control.scss
Normal file
@@ -0,0 +1,101 @@
|
||||
.button-control {
|
||||
box-sizing: border-box;
|
||||
display: inline-block;
|
||||
border: 1px solid $buttonBorder;
|
||||
vertical-align: baseline;
|
||||
height: 30px;
|
||||
min-width: 60px;
|
||||
padding: 4px 10px;
|
||||
margin: 0;
|
||||
line-height: 1.5em;
|
||||
outline: none;
|
||||
background-color: transparent;
|
||||
float: right;
|
||||
font-size: 14px;
|
||||
margin-left: 10px;
|
||||
color: $buttonColor;
|
||||
font-weight: $buttonFontWeight;
|
||||
@include transition(background-color .1s ease-out);
|
||||
|
||||
&[disabled] {
|
||||
color: #666;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
&_full-width {
|
||||
margin: 0;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
border: 1px solid $buttonHoverBorder;
|
||||
background-color: $buttonHoverBackground;
|
||||
@include transition(background-color .1s ease-in);
|
||||
}
|
||||
|
||||
&:active {
|
||||
@include box-shadow(0, 0, 1px, $buttonShadowColor, true);
|
||||
}
|
||||
|
||||
&_light {
|
||||
color: $defaultDarkColor;
|
||||
background-color: $buttonLightBackground;
|
||||
border: 1px solid $buttonLightBorder;
|
||||
|
||||
&:hover {
|
||||
border: 1px solid $buttonLightHoverBorder;
|
||||
background-color: $buttonLightHoverBackground;
|
||||
}
|
||||
}
|
||||
|
||||
&_link {
|
||||
color: $buttonLinkColor;
|
||||
background-color: $buttonLinkBackground;
|
||||
|
||||
&:hover {
|
||||
background-color: $buttonLinkBackground;
|
||||
}
|
||||
}
|
||||
|
||||
&_overlay {
|
||||
color: $primaryButtonColor;
|
||||
background-color: $overlayButtonBg;
|
||||
border-radius: 2px;
|
||||
border: none;
|
||||
|
||||
&:hover {
|
||||
background-color: $primaryButtonBackground;
|
||||
border: none;
|
||||
}
|
||||
}
|
||||
|
||||
&_primary {
|
||||
background-color: $primaryButtonBackground;
|
||||
border: 1px solid $primaryButtonBackground;
|
||||
color: $primaryButtonColor !important;
|
||||
font-weight: $primaryButtonFontWeight;
|
||||
|
||||
&:hover {
|
||||
border: 1px solid $primaryButtonHoverBackground;
|
||||
background-color: $primaryButtonHoverBackground;
|
||||
}
|
||||
|
||||
&[disabled] {
|
||||
color: $primaryButtonColor;
|
||||
}
|
||||
}
|
||||
|
||||
&_close {
|
||||
color: $defaultFontColor;
|
||||
}
|
||||
&_submit {
|
||||
color: $linkFontColor;
|
||||
&:hover {
|
||||
color: $linkHoverFontColor;
|
||||
}
|
||||
}
|
||||
|
||||
&_center {
|
||||
float: none !important;
|
||||
}
|
||||
}
|
||||
49
css/components/_form-control.scss
Normal file
49
css/components/_form-control.scss
Normal file
@@ -0,0 +1,49 @@
|
||||
.form-control {
|
||||
padding: $formPadding 0;
|
||||
|
||||
&:first-child {
|
||||
padding-top: 0;
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
&__text {
|
||||
margin: 8px 0;
|
||||
font-size: 1em
|
||||
}
|
||||
|
||||
&__label {
|
||||
font-size: 1em;
|
||||
font-weight: $labelFontWeight;
|
||||
}
|
||||
|
||||
&__em {
|
||||
color: $inputControlEmColor;
|
||||
}
|
||||
|
||||
&__container {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
margin-top: 5px;
|
||||
margin-bottom: 5px;
|
||||
@include flex();
|
||||
|
||||
.button-control {
|
||||
margin: 1px 0 1px 10px;
|
||||
}
|
||||
}
|
||||
|
||||
&__right {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a specific color for read only style.
|
||||
*/
|
||||
input:read-only {
|
||||
color: $readOnlyInputColor;
|
||||
}
|
||||
29
css/components/_input-control.scss
Normal file
29
css/components/_input-control.scss
Normal file
@@ -0,0 +1,29 @@
|
||||
.input-control {
|
||||
@include transition(all .2s ease-in);
|
||||
display: inline-block;
|
||||
width: 100%;
|
||||
padding: 5px 7px;
|
||||
border-radius: $borderRadius;
|
||||
line-height: 32px;
|
||||
height: 32px;
|
||||
text-align: left;
|
||||
margin-bottom: 8px;
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: inherit;
|
||||
}
|
||||
|
||||
&::selection {
|
||||
background-color: $defaultDarkSelectionColor;
|
||||
}
|
||||
|
||||
|
||||
&.error {
|
||||
color: $errorColor;
|
||||
border-color: $errorColor;
|
||||
}
|
||||
}
|
||||
|
||||
@include placeholder {
|
||||
color: $placeHolderColor;
|
||||
}
|
||||
41
css/components/_input-slider.scss
Normal file
41
css/components/_input-slider.scss
Normal file
@@ -0,0 +1,41 @@
|
||||
/**
|
||||
* Disable the default webkit styles for range inputs (sliders).
|
||||
*/
|
||||
input[type=range]{
|
||||
-webkit-appearance: none;
|
||||
background: none;
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable the default focus styles for webkit range inputs (sliders).
|
||||
*/
|
||||
input[type=range]:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
/**
|
||||
* Include the mixin for a range input style.
|
||||
*/
|
||||
@include slider {
|
||||
background: $sliderTrackBackground;
|
||||
border: none;
|
||||
border-radius: 3px;
|
||||
cursor: pointer;
|
||||
height: 6px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/**
|
||||
* Include the mixin for a range input thumb style.
|
||||
*/
|
||||
@include slider-thumb {
|
||||
-webkit-appearance: none;
|
||||
background: white;
|
||||
border: 1px solid $sliderThumbBackground;
|
||||
border-radius: 50%;
|
||||
box-shadow: 0px 0px 1px $sliderThumbBackground;
|
||||
cursor: pointer;
|
||||
height: 14px;
|
||||
margin-top: -4px;
|
||||
width: 14px;
|
||||
}
|
||||
20
css/components/_link.scss
Normal file
20
css/components/_link.scss
Normal file
@@ -0,0 +1,20 @@
|
||||
.link {
|
||||
cursor: pointer;
|
||||
color: $linkFontColor;
|
||||
@include transition(color .1s ease-out);
|
||||
|
||||
&:hover {
|
||||
color: $linkHoverFontColor;
|
||||
text-decoration: underline;
|
||||
@include transition(color .1s ease-in);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper links are links that are meant to open a documentation page or more
|
||||
* detailed info.
|
||||
*/
|
||||
.helper-link {
|
||||
@extend .link;
|
||||
font-size: 12px;
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
#contactlist {
|
||||
display: none;
|
||||
background-color: black;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
#contactlist>div.title {
|
||||
text-align: left;
|
||||
padding: 7px 10px;
|
||||
margin: 2px;
|
||||
color: #00ccff;
|
||||
font-size: 11pt;
|
||||
border-bottom: 1px solid #676767;
|
||||
}
|
||||
|
||||
#contactlist>ul#contacts {
|
||||
position: absolute;
|
||||
top: 31px;
|
||||
bottom: 0px;
|
||||
width: 100%;
|
||||
margin: 0px;
|
||||
padding: 0px;
|
||||
overflow-y: scroll;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
#contacts>li {
|
||||
list-style-type: none;
|
||||
text-align: left;
|
||||
color: #FFF;
|
||||
font-size: 10pt;
|
||||
padding: 7px 10px;
|
||||
margin: 2px;
|
||||
}
|
||||
|
||||
#contacts>li>p {
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
margin: 0px;
|
||||
}
|
||||
|
||||
.avatar {
|
||||
padding: 0px;
|
||||
margin-right: 10px;
|
||||
vertical-align: middle;
|
||||
font-size: 22pt;
|
||||
border-radius: 20px;
|
||||
max-height: 30px;
|
||||
max-width: 30px;
|
||||
}
|
||||
|
||||
#contactlist .clickable {
|
||||
cursor: pointer;
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
/**
|
||||
* The feedback window inner div css.
|
||||
*/
|
||||
.feedback {
|
||||
width: 450px;
|
||||
display: block;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
text-align: center;
|
||||
font-size: 22px;
|
||||
}
|
||||
|
||||
/**
|
||||
* Style of the thank you text inside the feedback window.
|
||||
*/
|
||||
.feedbackTitle {
|
||||
font-size: 22px;
|
||||
color: #087dba;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stars div css.
|
||||
*/
|
||||
#stars {
|
||||
font-size: 30px;
|
||||
}
|
||||
|
||||
/**
|
||||
* Star css.
|
||||
*/
|
||||
#stars>a {
|
||||
padding-right: 4px;
|
||||
}
|
||||
|
||||
/**
|
||||
* Mouse over a star.
|
||||
*/
|
||||
.starHover {
|
||||
color: #087dba;
|
||||
}
|
||||
|
||||
/**
|
||||
* Detailed feedback section text area style.
|
||||
*/
|
||||
.feedbackDetails textarea {
|
||||
resize: vertical;
|
||||
min-height: 100px;
|
||||
}
|
||||
123
css/font.css
123
css/font.css
@@ -1,123 +0,0 @@
|
||||
@font-face {
|
||||
font-family: 'jitsi';
|
||||
src:url('../fonts/jitsi.eot?94d075');
|
||||
src:url('../fonts/jitsi.eot?#iefix94d075') format('embedded-opentype'),
|
||||
url('../fonts/jitsi.woff?94d075') format('woff'),
|
||||
url('../fonts/jitsi.ttf?94d075') format('truetype'),
|
||||
url('../fonts/jitsi.svg?94d075#jitsi') format('svg');
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
[class^="icon-"], [class*=" icon-"] {
|
||||
font-family: 'jitsi';
|
||||
speak: none;
|
||||
font-style: normal;
|
||||
font-weight: normal;
|
||||
font-variant: normal;
|
||||
text-transform: none;
|
||||
line-height: 0.75em;
|
||||
font-size: 1.22em;
|
||||
|
||||
/* Better Font Rendering =========== */
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
.icon-contactList:before {
|
||||
content: "\e615";
|
||||
}
|
||||
.icon-avatar:before {
|
||||
content: "\e616";
|
||||
}
|
||||
.icon-callRetro:before {
|
||||
content: "\e611";
|
||||
}
|
||||
.icon-callModern:before {
|
||||
content: "\e612";
|
||||
}
|
||||
.icon-recDisable:before {
|
||||
content: "\e613";
|
||||
}
|
||||
.icon-recEnable:before {
|
||||
content: "\e614";
|
||||
}
|
||||
.icon-authenticate:before {
|
||||
content: "\e1ae";
|
||||
}
|
||||
.icon-kick1:before {
|
||||
content: "\e60f";
|
||||
}
|
||||
.icon-kick:before {
|
||||
content: "\e610";
|
||||
}
|
||||
.icon-share-desktop:before {
|
||||
content: "\e602";
|
||||
}
|
||||
.icon-chat-simple:before {
|
||||
content: "\e606";
|
||||
}
|
||||
.icon-full-screen:before {
|
||||
content: "\e60d";
|
||||
}
|
||||
.icon-exit-full-screen:before {
|
||||
content: "\e60e";
|
||||
}
|
||||
.icon-link:before {
|
||||
content: "\e600";
|
||||
}
|
||||
.icon-chat:before {
|
||||
content: "\e601";
|
||||
}
|
||||
.icon-presentation:before {
|
||||
content: "\e603";
|
||||
}
|
||||
.icon-security:before {
|
||||
content: "\e604";
|
||||
}
|
||||
.icon-share-doc:before {
|
||||
content: "\e605";
|
||||
}
|
||||
.icon-telephone:before {
|
||||
content: "\e611";
|
||||
}
|
||||
.icon-security-locked:before {
|
||||
content: "\e607";
|
||||
}
|
||||
.icon-camera:before {
|
||||
content: "\e608";
|
||||
}
|
||||
.icon-camera-disabled:before {
|
||||
content: "\e609";
|
||||
}
|
||||
.icon-mic-disabled:before {
|
||||
content: "\e60a";
|
||||
}
|
||||
.icon-microphone:before {
|
||||
content: "\e60b";
|
||||
}
|
||||
|
||||
.icon-hangup:before {
|
||||
content: "\e617";
|
||||
}
|
||||
|
||||
.icon-reload:before {
|
||||
content: "\e618";
|
||||
}
|
||||
|
||||
.icon-filmstrip:before {
|
||||
content: "\e619";
|
||||
}
|
||||
|
||||
.icon-connection:before {
|
||||
line-height: normal;
|
||||
content: "\e61a";
|
||||
}
|
||||
|
||||
.icon-settings:before {
|
||||
content: "\e61b";
|
||||
}
|
||||
|
||||
.icon-dialPad:before {
|
||||
content: "\e61c";
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user