Compare commits

...

163 Commits

Author SHA1 Message Date
Hristo Terezov
a403a221ae fix(analytics): prejoin property. 2023-12-08 15:37:19 -06:00
Jaya Allamsetty
3a836eba63 chore(deps) lib-jitsi-meet@latest
https://github.com/jitsi/lib-jitsi-meet/compare/v1733.0.0+c5dd1faa...v1734.0.0+34ceebd2
2023-12-08 12:43:01 -05:00
Calin-Teodor
55a16f31c2 feat(settings/native): hide login/logout for 8x8.vc on profile screen 2023-12-08 17:41:46 +02:00
Hristo Terezov
7de88f4e47 chore(deps) lib-jitsi-meet@latest
https://github.com/jitsi/lib-jitsi-meet/compare/v1732.0.0+7841a38e...v1733.0.0+c5dd1faa
2023-12-06 15:11:17 -06:00
Hristo Terezov
d71b827d1a feat(analytics): add visitor,prejoin,lobby props 2023-12-06 14:37:49 -06:00
Дамян Минков
3811caa8a0 fix(auth): Skip authStatusChanged for jaas meetings. (#14128)
It is showing Login/Logout buttons which does nothing in this case.
2023-12-05 10:59:21 -06:00
Calinteodor
32f6bc376b feat(rn): 0.70.14 update (#14123)
* feat(rn): update to 0.70.14 and removed libray_search_paths variables from ios project
2023-12-01 22:29:08 +02:00
Calin-Teodor
8b4ebe4fa3 feat(mobile): fixed undefined is not an object (evaluating action.conference.callUUID) 2023-12-01 18:59:18 +02:00
damencho
45415ef8da fix: When host is loaded muc module maybe still be nil in rayo filter.
This can prevent outgoing calls due to error.
2023-11-30 18:09:17 -06:00
Shawn
99bba14628 fix(breakout-rooms, persistent-lobby): support for using both these modules together 2023-11-30 00:25:05 +01:00
bgrozev
8b8b2568e2 feat: Log all API commands. (#14118)
* feat: Log all API commands.
2023-11-29 14:37:48 -08:00
Hristo Terezov
ca144e127c chore(deps) lib-jitsi-meet@latest
https://github.com/jitsi/lib-jitsi-meet/compare/v1729.0.0+ba526ee8...v1732.0.0+7841a38e
2023-11-28 11:59:26 -06:00
Saúl Ibarra Corretgé
965760df41 feat(ci) test debian packages build 2023-11-28 16:30:01 +01:00
bgrozev
6ab25f7bc0 Remove callstats (#14076)
* ref: Remove precall test.
* ref: Remove callstats.
* Remove the dependency on react-native-callstats.
2023-11-28 07:28:05 -08:00
Дамян Минков
701ae5b2b1 fix(debian): No svg available in root folder.
We reference the favicon from index as svg directly from the images folder.
2023-11-28 08:01:42 -06:00
Horatiu Muresan
b2d6ee06df fix(ci) Fix favicon (#14108) 2023-11-28 12:15:22 +02:00
Javier García
18f5bdeaf8 fix(lang) update spanish translation 2023-11-27 23:46:59 +01:00
Saúl Ibarra Corretgé
dd6ce33296 feat(deps,rn) update react-native-webrtc to 118 2023-11-27 13:29:23 +01:00
brlarini
5a7a6bf59c fix(lang) update Brazilian Portuguese translation 2023-11-24 22:39:15 +01:00
shane215
20d8a403f3 fix(favicon) make favicon visible in dark-themed browser
Fixes: #6182
2023-11-24 17:48:28 +01:00
Gabriel Borlea
0bce8e185d fix(devices): device type to settings key mapping for video 2023-11-24 18:06:04 +02:00
Horatiu Muresan
7f21075613 fix(media-devices) Fix configuring media devices on init (#14097)
- on 3rd party prejoin, we did not setup the initial devices, resulting in always creating tracks for default device for camera and mic regardless of settings, and for both meeting and 3rd party prejoin to not set the audio output device at all
2023-11-24 17:48:43 +02:00
Gabriel Borlea
e833860fcb fix(devices): return user selected device id if there is no device id 2023-11-24 15:32:17 +02:00
Saúl Ibarra Corretgé
376b17e011 fix(compute-pressure) disable when in an iframe
Permission delegation doesn't work for 3rd party iframes on this origin
trial, wait until Google solves it: https://bugs.chromium.org/p/chromium/issues/detail?id=1504167
2023-11-24 13:56:35 +01:00
Gabriel Borlea
87541a63d3 ref(settings): listen to TRACK_ADDED to set the input devices id (#14093)
This fixes the issue when starting the conference with video muted, after unmuting it the cameraDeviceId would stay undefined.
2023-11-24 14:16:08 +02:00
Calinteodor
109b83d6f1 fix(sdk): custom server url is overwritten by sdk default url option value (#14092)
* fix(sdk): custom server url is overwritten by sdk default url option value
2023-11-22 17:13:02 +02:00
Andrei Gavrilescu
3a1fc363ed feat(rtcstats): fetch conference creator id and send to rtcstats (#14060)
* fetch conference creator id and send to rtcstats

* fix lint

* fix lint again
2023-11-22 12:39:08 +02:00
Calin-Teodor
71658a5de6 feat(react-native-sdk): null error fix for ios 2023-11-22 12:34:13 +02:00
Calinteodor
40ac57a5d4 feat(settings): make settings screen functional component (#14084)
* feat(settings): convert component to functional component
2023-11-22 09:47:15 +02:00
Edgars Voroboks
a20bf845ea fix(lang) update Latvian translation
* Update Latvian lang. Make Meeting term consistent.

* Better express Meeting end message
2023-11-21 23:55:19 +01:00
damencho
95943b725c fix(i18n): Fixes retrieving correct countries i18n file. 2023-11-21 13:53:21 -06:00
Gabriel Borlea
0813ae0f3c fix(electron-screensharing): get the right current selected source 2023-11-21 12:13:59 -06:00
Jaya Allamsetty
a33e34c309 chore(deps) lib-jitsi-meet@latest
https://github.com/jitsi/lib-jitsi-meet/compare/v1728.0.0+456e45ee...v1729.0.0+ba526ee8
2023-11-21 12:51:56 -05:00
Calin-Teodor
821cc11364 sdk(react-native-sdk/android): replaced activityContext with currentActivity 2023-11-21 17:11:32 +02:00
Calin-Teodor
caf7df4a82 chore(rn-orientation-locker, version): bump to latest 2023-11-21 17:04:19 +02:00
Thomas Egebrand Gram
bda39ef876 feat(watermark) move static styles into stylesheet file & refactor a tiny bit 2023-11-21 16:03:20 +01:00
Horatiu Muresan
9e2ed855eb feat(recording) Allow extra metadata for file recordings (#14081) 2023-11-21 12:06:14 +02:00
Edgars Voroboks
3be453e76a fix(lang) update Latvian language translation (#14075) 2023-11-21 09:03:40 +01:00
damencho
dec54692c1 chore(deps) lib-jitsi-meet@latest
https://github.com/jitsi/lib-jitsi-meet/compare/v1727.0.0+bd98ecd0...v1728.0.0+456e45ee
2023-11-20 16:30:10 -05:00
Calinteodor
e77d19b128 sdk(react-native-sdk): update script for rnsdk dependencies (#14069)
* sdk(react-native-sdk): update script for rnsdk dependencies
Some of our peer dependencies use github urls that need to be taken in consideration.
2023-11-20 21:20:24 +02:00
bgrozev
a83bf98625 Whitelist config.bridgeChannel. (#13775) 2023-11-20 10:35:00 -08:00
Jaya Allamsetty
3307365885 chore(deps) lib-jitsi-meet@latest
https://github.com/jitsi/lib-jitsi-meet/compare/v1724.0.0+1b38128d...v1727.0.0+bd98ecd0
2023-11-18 08:25:26 -05:00
Jaya Allamsetty
341fc774a6 fix(config): Add the new codec settings 2023-11-17 12:40:47 -05:00
maheichyk
56673f14b5 fix(context-menu) fix double click behaviour if closed with ESC
Signed-off-by: Mikhail Aheichyk <mikhail.aheichyk@nordeck.net>
Co-authored-by: Mikhail Aheichyk <mikhail.aheichyk@nordeck.net>
2023-11-17 15:08:50 +01:00
Abbas Al-Mansoori
ab08eb2f99 refactor(rnsdk): remove redundant audio and video actions (#14066)
* refactor(rnsdk): remove redundant audio and video actions
2023-11-17 12:09:31 +02:00
Mihaela Dumitru
000458697d fix(salesforce) reduce notification duration (#14068) 2023-11-17 11:59:57 +02:00
Дамян Минков
b0c56d8963 fix: Fixes login button in profile settings. 2023-11-16 12:09:23 -06:00
Gabriel Borlea
0ecd65777e fix(screenshot-captue): get the right worker url 2023-11-16 17:44:24 +02:00
Abbas Al-Mansoori
6d02f50d09 feat(rnsdk): add audio and video muted state changed 2023-11-16 12:54:36 +02:00
Philipp Fruck
a71143891e fix(native app): Display poll creator name
In the jitsi web app, the poll creator is displayed
for all published votes whereas in the native app
the current username of the participant has been
displayed for all polls regardless of the creator
2023-11-16 11:53:36 +02:00
Jaya Allamsetty
6fda5924a3 chore(deps) lib-jitsi-meet@latest
https://github.com/jitsi/lib-jitsi-meet/compare/v1723.0.0+e9af2b98...v1724.0.0+1b38128d
2023-11-15 13:03:15 -05:00
Calin-Teodor
b09574f62f feat(authentication): group config options inside an object param 2023-11-15 16:30:42 +02:00
Calin-Teodor
8cdde88049 feat(authentication): used config for control over joining audio/video mute/unmute 2023-11-15 12:42:24 +02:00
Jaya Allamsetty
9cd42b988d fix(config) Remove deprecated config option. 2023-11-14 15:29:45 -05:00
Jaya Allamsetty
8b559ad4f2 fix(config): Add the optional screenshare settings. 2023-11-14 15:29:45 -05:00
Jaya Allamsetty
192fce8740 fix(iFrame): Add 'speaker-selection' to the allow list.
This is needed for Firefox 116 and above for setSinkId to succeed.
2023-11-14 11:44:04 -05:00
Jaya Allamsetty
235016d7cf chore(deps) lib-jitsi-meet@latest
https://github.com/jitsi/lib-jitsi-meet/compare/v1722.0.0+4588cc78...v1723.0.0+e9af2b98
2023-11-14 11:25:34 -05:00
Calinteodor
27792b0be4 ref(authentication): handle joining in low bandwidth mode (#14032)
ref(authentication): handle joining in low bandwidth mode
2023-11-14 11:31:55 +02:00
Calin-Teodor
765fd7d766 ref(@react-native-): updated related deps to latest 2023-11-14 11:26:20 +02:00
Hristo Terezov
d49a5097f0 chore(deps) lib-jitsi-meet@latest
https://github.com/jitsi/lib-jitsi-meet/compare/v1720.0.0+b3173832...v1722.0.0+4588cc78
2023-11-13 15:44:03 -06:00
Hristo Terezov
cfcc3fdbbe fix(FeedbackButoon): display for JaaS meetings. 2023-11-13 13:56:36 -05:00
Mihaela Dumitru
fdbceb0e42 chore(deps) update excalidraw with disabled image pasting (#14046) 2023-11-13 20:17:55 +02:00
nurjin jafar
89197cbdb2 fix(a11y) resolve contrast issues in userAvatar and in performance settings slider
Signed-off-by: nurjinn jafar <nurjin.jafar@nordeck.net>
2023-11-13 10:51:35 +01:00
Hristo Terezov
f067f07d64 fix(pr-test): For LJM 2023-11-12 22:24:29 -05:00
Hristo Terezov
4594a978e0 feat(feedback): show even if callstats is disabled 2023-11-10 09:56:03 -05:00
Calin-Teodor
fcddccf018 feat(base/ui): removed unneeded lineHeight value 2023-11-09 12:11:09 +02:00
nurjin jafar
7a9285b326 feat(a11y) make instructions in share audio accessible and provide equivilant translation 2023-11-09 10:41:43 +01:00
Gabriel Borlea
11f0ab9226 ref(screenshot-capture): move screenshot processing on a web worker (#14015)
Improvement for the screenshot capture feature by using a web worker to process the differences between the screenshots, and some code adjustments.
2023-11-09 10:01:02 +02:00
Hristo Terezov
0b6705610c chore(package.jsom): Update LJM 2023-11-08 10:26:55 -05:00
Hristo Terezov
9d9199ba3b fix(conference-hangup): Leave room in parallel.
Currently we are waiting for the user to submit feedback dialog in
order to leave the room. Now the leave and showing the dialog are
executed in parallel.
2023-11-08 09:16:58 -05:00
AHMAD KADRI
ff656a0625 ref(accessibility): add an aria-expended attribute if the the button open menu (#14023)
ref(accessibility): add an aria-expended attribute if the the button open menu
2023-11-08 15:59:05 +02:00
emrah
148fc103e3 fix(token): add jitsi_meet_context_room into the param list 2023-11-08 06:06:22 -06:00
Calinteodor
77abbee308 feat(base/modal): changed hasTabNavigator to hasExtraHeaderHeight (#14033)
* feat(base/modal): changed hasTabNavigator to hasExtraHeaderHeight
2023-11-08 11:44:10 +02:00
Calinteodor
83c4ce98b4 feat(filmstrip): fixed indicators container dissapear when not in tile view (#14031)
* feat(filmstrip): fixed indicators container dissapear when not in tile view
2023-11-07 23:33:28 +02:00
Calin-Teodor
898741e40d feat(filmstrip): fixed indicators container ui 2023-11-07 18:39:02 +02:00
Calin-Teodor
0c3e7395e7 feat(participants-pane): fixed visitors label position 2023-11-07 18:39:02 +02:00
Saúl Ibarra Corretgé
c530bdd107 feat(external_api) add event with transcription chunks 2023-11-07 13:10:00 +01:00
Horatiu Muresan
29dbcb309d fix(drawer-menu) Make drawer menu accessible on small height (#14026) 2023-11-07 13:06:03 +02:00
Calinteodor
8a4990d9ae sdk(react-native-sdk): rnsdk screenshare android fix (#13884)
sdk(react-native-sdk): rnsdk screenshare android fix
2023-11-07 12:22:02 +02:00
Дамян Минков
0e55cbbda6 Clean up prosody modules with some extra checks (#14020)
* fix: Adds check for jitsi_meet_room not being string.

Oct 20 12:22:50 mod_bosh        error   Traceback[bosh]: /usr/share/jitsi-meet/prosody-plugins/token/util.lib.lua:336: bad argument #1 to 'lower' (string expected, got userdata)
        stack traceback:
        [C]: in function 'lower'
        /usr/share/jitsi-meet/prosody-plugins/token/util.lib.lua:336: in function 'verify_room'
        ...re/jitsi-meet/prosody-plugins/mod_token_verification.lua:78: in function 'verify_user'

* fix: Adds check for missing speaker stats for occupant.

error   Traceback[c2s]: ...itsi-meet/prosody-plugins/mod_speakerstats_component.lua:124: attempt to index field '?' (a nil value)
        stack traceback:
        ...itsi-meet/prosody-plugins/mod_speakerstats_component.lua:124: in function '?'

* fix: Nil check for breakout_rooms.

c2saaaad95a16c0 error   Traceback[c2s]: ...re/jitsi-meet/prosody-plugins/mod_muc_breakout_rooms.lua:345: attempt to index local 'main_room' (a nil value)
        stack traceback:
        ...re/jitsi-meet/prosody-plugins/mod_muc_breakout_rooms.lua:345: in function '?'
        /usr/share/lua/5.2/prosody/util/events.lua:81: in function </usr/share/lua/5.2/prosody/util/events.lua:77>
        (...tail calls...)
        /usr/lib/prosody/modules/muc/muc.lib.lua:496: in function </usr/lib/prosody/modules/muc/muc.lib.lua:492>

* fix: Adds nil check in allowners.

c2saaaae3024810 error   Traceback[c2s]: /usr/share/jitsi-meet/prosody-plugins/mod_muc_allowners.lua:171: attempt to index local 'room' (a nil value)
        stack traceback:
        /usr/share/jitsi-meet/prosody-plugins/mod_muc_allowners.lua:171: in function '?'
        /usr/share/lua/5.2/prosody/util/events.lua:81: in function </usr/share/lua/5.2/prosody/util/events.lua:77>

* fix: Adds nil check in lobby.

mod_bosh        error   Traceback[bosh]: ...share/jitsi-meet/prosody-plugins/mod_muc_lobby_rooms.lua:168: attempt to index local 'lobby_room' (a nil value)
        stack traceback:
        ...share/jitsi-meet/prosody-plugins/mod_muc_lobby_rooms.lua:168: in function '?'
        /usr/share/lua/5.2/prosody/util/filters.lua:25: in function 'filter'
        /usr/lib/prosody/modules/mod_bosh.lua:361: in function 'send'
        /usr/lib/prosody/modules/muc/mod_muc.lua:495: in function '?'

* fix: Fixes nil error in fmuc.

s2sinaaaaf2817260       error   Traceback[s2s]: /usr/share/jitsi-meet/prosody-plugins/mod_fmuc.lua:295: attempt to index local 'occupant' (a nil value)
        stack traceback:
        /usr/share/jitsi-meet/prosody-plugins/mod_fmuc.lua:295: in function '?'
        /usr/share/lua/5.2/prosody/util/events.lua:81: in function </usr/share/lua/5.2/prosody/util/events.lua:77>
        (...tail calls...)
        /usr/lib/prosody/modules/muc/muc.lib.lua:1201: in function </usr/lib/prosody/modules/muc/muc.lib.lua:1194>

* fix: Fixes nil occupant.

c2s55f4d5411dd0 error   Traceback[c2s]: /usr/share/jitsi-meet/prosody-plugins/mod_muc_flip.lua:120: attempt to index local 'kicked_occupant' (a nil value)
        stack traceback:
        /usr/share/jitsi-meet/prosody-plugins/mod_muc_flip.lua:120: in function '?'
        /usr/share/lua/5.2/prosody/util/events.lua:81: in function </usr/share/lua/5.2/prosody/util/events.lua:77>
        (...tail calls...)
        /usr/lib/prosody/modules/muc/muc.lib.lua:791: in function </usr/lib/prosody/modules/muc/muc.lib.lua:616>

* fix: Fixes caching main room.

Objects should not be set in room._data as this field is being serialized and we see errors like.

error   Traceback[c2s]: /usr/share/lua/5.2/prosody/util/serialization.lua:34: Can't serialize userdata
        stack traceback:
        [C]: in function 'error'
        /usr/share/lua/5.2/prosody/util/serialization.lua:34: in function </usr/share/lua/5.2/prosody/util/serialization.lua:33>
        (...tail calls...)
        /usr/share/lua/5.2/prosody/util/serialization.lua:199: in function 'serialize_table'
        /usr/share/lua/5.2/prosody/util/serialization.lua:197: in function 'serialize_table'
        /usr/share/lua/5.2/prosody/util/serialization.lua:197: in function 'serialize_table'
        /usr/share/lua/5.2/prosody/util/serialization.lua:219: in function </usr/share/lua/5.2/prosody/util/serialization.lua:217>
        (...tail calls...)
        /usr/lib/prosody/modules/mod_storage_memory.lua:42: in function </usr/lib/prosody/modules/mod_storage_memory.lua:40>
        (...tail calls...)
        ...re/jitsi-meet/prosody-plugins/mod_muc_breakout_rooms.lua:207: in function 'create_breakout_room'

* fix: Fixes calling save_occupant after changing its role.

* squash: Fixed passed value to type.
2023-11-06 15:31:59 -06:00
damencho
6da94aecf2 chore(deps) lib-jitsi-meet@latest
https://github.com/jitsi/lib-jitsi-meet/compare/v1718.0.0+30be4f6f...v1719.0.0+f8a18cf0
2023-11-06 09:40:48 -06:00
Calinteodor
2a3c962e88 feat(recent-list): fix undefined error that breaks visitor joining (#14024)
* feat(recent-list): fix undefined error that breaks visitor joining

* feat(recent-list): revert variable name change

* feat(recent-list): fixed linter
2023-11-06 09:40:28 -06:00
AHMAD KADRI
34f1eb60f4 Accessibility: add validation warning on room name (#14009)
feat(accessibility): add validation warning on room name
2023-11-06 10:59:51 +02:00
Jaya Allamsetty
4115ebe856 chore(deps) lib-jitsi-meet@latest
https://github.com/jitsi/lib-jitsi-meet/compare/v1717.0.0+7b6ce949...v1718.0.0+30be4f6f
2023-11-02 15:36:11 -04:00
Horatiu Muresan
d7dadfc157 feat(facing-mode) add config for initial camera facing mode (#14013) 2023-11-02 16:20:38 +02:00
Erin Yuki Schlarb
2851eeeab3 fix: Make room_metadata Prosody module depend on the required jitsi_session module
Without this room_metadata will silently discard all room metadata client requests assuming that they didn’t come from Jitsi meet clients.

Fixes #14001
2023-11-01 17:06:26 -05:00
Muhammed Ajmal M
84d75f2ae8 fix(screen-sharing) Self view of SC sized correctly initially (#13992) 2023-11-01 18:32:34 +02:00
damencho
73b3309adf feat: Adds leave rate limit to muc_rate_limit. 2023-10-31 15:59:23 -05:00
Jaya Allamsetty
e2de06f60d chore(deps) lib-jitsi-meet@latest
https://github.com/jitsi/lib-jitsi-meet/compare/v1716.0.0+93c167d3...v1717.0.0+7b6ce949
2023-10-31 14:35:31 -04:00
damencho
cdc7962d11 feat: Adds region parameter to dial out authorize requests. 2023-10-31 11:45:06 -05:00
Saúl Ibarra Corretgé
59242e1217 feat(external-api) introduce a "ready" event
It's fired when the API is ready, and it signals the embedder that they
can reveal the meeting from behind an overlay, for example.

The astute reader might notice we are currently sending a
'browser-support' event roughly at the same time. The reason for this
new event is plain simply semantics.

In addition the 'onload' handler is faked by calling it when the new
ready event fires. The original onload event is unreliable. It will be
called even when nothing was ever loaded (try loading a page without
internet and be amused).
2023-10-31 16:27:12 +01:00
Saúl Ibarra Corretgé
631e39d4fd feat(external-api) allow vh and vw values as parameters 2023-10-31 16:27:12 +01:00
Julian LADJANI
4290cdf53d fix(breakout-rooms, feature-flags): handle breakout button feature flag on participant pane footer component (#14003)
* fix(breakout-rooms, feature-flags): handle breakout button feature flag on participant pane footer component
2023-10-31 13:53:41 +02:00
damencho
84c1e20216 fix(moderated): Fixes moderators in moderated rooms without tenant. 2023-10-30 17:26:42 -05:00
Saúl Ibarra Corretgé
e6caeb86b0 chore(deps,rn) react-native-webrtc@111.0.6 2023-10-30 15:46:14 +01:00
Saúl Ibarra Corretgé
5854e38a09 fix(rn) allow default server URL to be set from native
On Android we support RestrictionManager, but that already sets it, so
make sure we always save it on the settings.

Editing will be restricted in the Settings dialog if changing it is
restricted anyway.

Fixes: https://github.com/jitsi/jitsi-meet/issues/13994
2023-10-30 15:12:05 +01:00
Saúl Ibarra Corretgé
3e9ee9451f fix(android) fix crash on Android 14
Fixes: https://github.com/jitsi/jitsi-meet/issues/13998
2023-10-30 15:11:19 +01:00
Calinteodor
29d02f0a2b feat(chat/native): fixed keyboard overlapping chat input bar (#13984)
* feat(chat/native): fixed keyboard overlapping chat input bar
2023-10-30 12:59:05 +02:00
David Hall
c780f9bbba Update main-sv.json
Fix typos.
2023-10-29 20:53:01 +01:00
Jaya Allamsetty
d5a0bac0a3 chore(deps) lib-jitsi-meet@latest
https://github.com/jitsi/lib-jitsi-meet/compare/v1713.0.0+a1d7b0ea...v1716.0.0+93c167d3
2023-10-28 14:45:24 -04:00
5idereal
f0187cc0f8 lang: update zhTW translation (#13986)
* update zhTW translation

* Update main.json
2023-10-26 10:47:22 -05:00
damencho
4708d894cc fix: Adds a nil check in visitors module.
Sep 22 22:06:01 mod_bosh        error   Traceback[bosh]: /usr/share/jitsi-meet/prosody-plugins/mod_visitors.lua:305: attempt to index field '?' (a nil value)
        stack traceback:
        /usr/share/jitsi-meet/prosody-plugins/mod_visitors.lua:305: in function '?'
        /usr/share/lua/5.2/prosody/util/events.lua:81: in function </usr/share/lua/5.2/prosody/util/events.lua:77>
2023-10-26 09:38:23 -05:00
damencho
f38d120406 fix(visitors): Bumps queue size for waiting for jicofo.
500 is the maximum meeting participants we test and support.
2023-10-24 18:27:16 -05:00
damencho
53960baf76 fix(visitors): Fixes filtering initial msgs to main participants.
Filters initial msg for <subject/>.
2023-10-24 18:27:16 -05:00
Jaya Allamsetty
a0f061aa6f chore(deps): Update lib-jitsi-meet. 2023-10-23 17:42:32 -04:00
Jaya Allamsetty
f2fb525d0a ref(config) Drop forceJVB121Ratio from config.js 2023-10-23 17:42:32 -04:00
Jaya Allamsetty
5a59bee597 chore(deps) lib-jitsi-meet@latest
https://github.com/jitsi/lib-jitsi-meet/compare/v1711.0.0+8ec3b736...v1712.0.0+540aed1e
2023-10-23 16:10:10 -04:00
Дамян Минков
07b903d887 feat(visitors): Adds an option to request to be visitor based on jwt. (#13977)
* feat(visitors): Adds an option to request to be visitor based on jwt.

* squash: Updates ljm.
2023-10-23 12:07:03 -05:00
Mihaela Dumitru
1a39315001 feat(whiteboard) expose the excalidraw api (#13974) 2023-10-23 09:22:42 +03:00
Gabriel Borlea
97e5f00dae fix(electron-screensharing): simplify the proccess (#13967)
* fix(electron-screensharing): simplify the proccess
2023-10-20 19:55:06 +03:00
Дамян Минков
bae77f21f8 feat: Adds event for parsed jwt and check for required token.context (#13973)
* squash: Remove tabs.

* feat: Adds a check for context required in jwt.

* feat: Adds an event to notify for parsed jwt.
2023-10-20 08:50:38 -05:00
José Luís Andrade
24d788f333 Update Portuguese translation 2023-10-20 06:50:20 -05:00
damencho
c4d553c605 feat: Filter iq rayo respects the actor of grant moderation. 2023-10-18 14:00:21 -05:00
Mehmet
fa64e2e67c fix(visitors): informs visitor nodes when a participant is kicked. (#13951)
* fix(visitors): informs visitor nodes when a participant is kicked.

* remove hooking muc-broadcast-presence event and create a stanza in muc-occupant-left event.
2023-10-17 07:54:02 -05:00
Damien Fetis
94c29180e4 fix(whiteboard) fix room id generation
Fixes: https://github.com/jitsi/jitsi-meet/issues/13921
2023-10-17 11:09:34 +02:00
dependabot[bot]
b864d91572 chore(deps): bump @babel/traverse in /react-native-sdk
Bumps [@babel/traverse](https://github.com/babel/babel/tree/HEAD/packages/babel-traverse) from 7.22.15 to 7.23.2.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.23.2/packages/babel-traverse)

---
updated-dependencies:
- dependency-name: "@babel/traverse"
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-10-16 17:57:49 +02:00
Saúl Ibarra Corretgé
2006182a2a fix(deps) run npm audit fix 2023-10-16 17:57:25 +02:00
Saúl Ibarra Corretgé
8fc3de416c feat(config) add ability to prefer BOSH over WebSocket
There might be cases where we'd want to enforce it.
2023-10-16 17:56:34 +02:00
Jaya Allamsetty
4c5787511e chore(deps) lib-jitsi-meet@latest
https://github.com/jitsi/lib-jitsi-meet/compare/v1698.0.0+03cb3ce8...v1704.0.0+d3efd197
2023-10-16 11:12:19 -04:00
Duduman Bogdan Vlad
8a2e4bc628 feat(screenshare) - add web security fix for electron (#13096)
use send the share screen sources using the external api

---------

Co-authored-by: Gabriel Borlea <gabriel.borlea@8x8.com>
2023-10-16 14:59:55 +03:00
Calinteodor
f78ebbb9a9 feat(settings/native/android): Fixed scroll inside conference settings screen (#13956)
* feat(settings/native/android): fixed scroll inside conference settings screen.
2023-10-16 14:10:52 +03:00
Calin-Teodor
4cc4c25691 feat(prejoin/native): fix display name input on prejoin 2023-10-16 13:13:30 +03:00
Avram Tudor
d02c7dc3a7 i18n: change iframe disabled message based on current hostname (#13950)
* i18n: change iframe disabled message based on current hostname

This will allow us to remove translation overrides from branded repo

* fix linter
2023-10-13 15:05:24 +03:00
Mihaela Dumitru
8741ee771e fix(language/config) deprecate defaultLanguage (#13949) 2023-10-13 14:06:59 +03:00
Mihaela Dumitru
006e8463cd feat(whiteboard) add user limit (#13870) 2023-10-13 13:41:31 +03:00
Saúl Ibarra Corretgé
86e295e9bc fix(conference) clear raised hands when conference changes
Fixes: https://github.com/jitsi/jitsi-meet-sdk-samples/issues/175
2023-10-12 15:03:59 +02:00
keremoge
07bade2557 feat(deps,rn) update React Native to version 0.69.12 2023-10-12 13:18:40 +03:00
Hristo Terezov
0becc890d8 feat(track-state): Log on add/remove/mute/owner. 2023-10-11 16:39:06 -05:00
Hristo Terezov
a1ce6f1ce5 fed(UI): remove UI.setAudioMuted 2023-10-11 16:39:06 -05:00
otbutz
43a7d00c63 web: enable http2 support 2023-10-11 18:22:12 +02:00
Calinteodor
9c04ba767c feat(breakout-rooms/native): separate breakout rooms from participants (#13920)
feat(breakout-rooms/native): separate breakout rooms from participants
2023-10-11 17:34:49 +03:00
Calinteodor
7e1d10fb4d sdk(react-native-sdk): update readme 2023-10-10 12:03:43 +02:00
Saúl Ibarra Corretgé
4ce2280e31 fix(rnsdk,build) run npm install after syncing deps 2023-10-09 15:21:32 +02:00
Saúl Ibarra Corretgé
2918a89d35 fix(rnsdk,build) don't commit the result after bumping version
Just like the other version bumping scripts
2023-10-09 15:21:32 +02:00
malik tekin
8f1c83edfd fix(lang) update Turkish translation
The Turkish translation of the "adjust for" is "ayarla". It was misspelled as "ayala".
2023-10-09 11:01:24 +02:00
eemehmet
106452d857 fix(visitors): Fixes duplicated messages sent from guest domain. 2023-10-06 10:33:23 -05:00
Horatiu Muresan
a4d3fb6c70 fix(notifications) Fix case when description is react component instance (#13919) 2023-10-06 15:20:56 +03:00
Saúl Ibarra Corretgé
a7af01b9e3 fix(screen-sharing) remove stop screen sharing icon 2023-10-06 10:31:47 +02:00
emrah
f7f434ab55 fix(config): add missing notification keys into the list 2023-10-06 10:31:23 +02:00
Esra Hatice YILMAZ
09c0854779 fix(breakout-rooms) fix race condition in timer handling 2023-10-05 22:56:53 +02:00
Horatiu Muresan
b4d12d74f7 fix(aot) remove dependency to store (#13910) 2023-10-05 13:05:15 +03:00
Gabriel Borlea
50b064907a fix(environment): optimal browsers list 2023-10-05 11:14:50 +03:00
dependabot[bot]
b9d6a0f269 chore(deps): bump postcss and css-loader
Bumps [postcss](https://github.com/postcss/postcss) to 8.4.31 and updates ancestor dependency [css-loader](https://github.com/webpack-contrib/css-loader). These dependencies need to be updated together.


Updates `postcss` from 7.0.39 to 8.4.31
- [Release notes](https://github.com/postcss/postcss/releases)
- [Changelog](https://github.com/postcss/postcss/blob/main/CHANGELOG.md)
- [Commits](https://github.com/postcss/postcss/compare/7.0.39...8.4.31)

Updates `css-loader` from 3.6.0 to 6.8.1
- [Release notes](https://github.com/webpack-contrib/css-loader/releases)
- [Changelog](https://github.com/webpack-contrib/css-loader/blob/master/CHANGELOG.md)
- [Commits](https://github.com/webpack-contrib/css-loader/compare/v3.6.0...v6.8.1)

---
updated-dependencies:
- dependency-name: postcss
  dependency-type: indirect
- dependency-name: css-loader
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-10-05 10:04:58 +02:00
Calinteodor
2414e57260 feat(shared-video/native): use local logger (#13886)
* feat(shared-video/native): use local logger
2023-10-04 13:13:54 +03:00
Horatiu Muresan
6c41ddb622 fix(aot) fix icons creating deps to store (#13901) 2023-10-03 17:31:04 +03:00
damencho
55e75d56fd fix: Fixes skipping the lobby for two times in a row for jibri.
An issue where a livestreaming is started for a second time in a meeting with lobby turned on.
2023-10-02 11:22:27 -05:00
Calinteodor
32ac299422 feat(authentication/native): hide login button for 8x8.vc (#13881)
* feat(authentication): hide login button for 8x8.vc
2023-10-02 18:03:57 +03:00
Christoph Settgast
cb7146f954 lang: update German translation 2023-09-29 12:28:22 -05:00
damencho
144c1ce4f4 fix: Fixes passing the hash params in state for token auth URL. 2023-09-29 12:11:52 -05:00
Gabriel Borlea
2102d6eda1 chore(deps): update js-utils to 2.2.1 2023-09-29 18:45:36 +03:00
damencho
1f8e3fe26f fix: Fixes wait for host to respect moderated tenants.
The correct place to check for tenant value is jitsi_meet_domain and not jitsi_meet_context_group.
2023-09-29 09:54:02 -05:00
Andrei Gavrilescu
8b0285a9d7 chore(deps) lib-jitsi-meet@latest (#13891)
https://github.com/jitsi/lib-jitsi-meet/compare/v1695.0.0+51c2187b...v1698.0.0+03cb3ce8
2023-09-29 17:02:31 +03:00
Mihaela Dumitru
b546d01c2d fix(prejoin) improve display name handling relative to configs (#13865) 2023-09-29 16:17:35 +03:00
Saúl Ibarra Corretgé
7bf3e7df1d fix(rn,polyfills) remove no longer needed polyfill
Fixes: https://github.com/jitsi/jitsi-meet/issues/13807
2023-09-28 12:23:09 +02:00
damencho
f9ac965e18 feat: Updates for jwt when room claim is not required.
This allows mod_token_verification to be used with token missing room claim (firebase) and jitsi tokens with the claim.
2023-09-27 19:29:16 -05:00
Gabriel Borlea
d70412166c chore(deps) lib-jitsi-meet@latest
https://github.com/jitsi/lib-jitsi-meet/compare/v1694.0.0+a0145343...v1695.0.0+51c2187b
2023-09-27 16:20:19 +03:00
Дамян Минков
a843406cb0 feat: Check jwt expiration and redirects to auth url if any. (#13879)
* feat: Check jwt expiration and redirects to auth url if any.

It may happen that the jwt had expired while being in the meeting and there is a network issue requiring to reload.

* squash: Fixes lint error.

* squash: Fixes comments.
2023-09-27 07:40:07 -05:00
AHMAD KADRI
58115477a2 Improve accessibility in breakout rooms list (#13669)
Improve accessibility in breakout rooms list
2023-09-27 12:13:03 +03:00
Hristo Terezov
e1dc573c3c fix(GUM):set deviceId only when the device exists 2023-09-26 12:53:08 -05:00
Hristo Terezov
c025102511 feat(devices): Filter MS Teams Audio device 2023-09-26 12:53:08 -05:00
Gabriel Borlea
54d052de73 chore: update js-utils with new ua-parser (#13877)
* chore: update js-utils with new ua-parser

* chore(deps) lib-jitsi-meet@latest
2023-09-26 19:31:26 +03:00
Javier García
7e633f0136 fix: Also check single quote on jitsi-meet-tokens install (#13869)
Fixes #13768.
2023-09-26 11:25:38 -05:00
Gabriel Borlea
4b4bc1c823 chore(deps) lib-jitsi-meet@latest (#13871)
https://github.com/jitsi/lib-jitsi-meet/compare/v1691.0.0+255d8f49...v1693.0.0+c3a086f8
2023-09-25 18:21:58 +03:00
253 changed files with 7003 additions and 7331 deletions

View File

@@ -74,3 +74,17 @@ jobs:
cache: 'npm'
- run: npm install
- run: npx react-native bundle --entry-file react/index.native.js --platform ios --bundle-output /tmp/ios.bundle --reset-cache
debian-build:
name: Test Debian packages build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: 16
cache: 'npm'
- run: npm install
- run: make
- run: sudo apt-get install -y debhelper
- run: dpkg-buildpackage -A -rfakeroot -us -uc -d
- run: make source-package

4
.gitignore vendored
View File

@@ -99,6 +99,10 @@ tsconfig.json
#
react-native-sdk/*.tgz
react-native-sdk/android/src
!react-native-sdk/android/src/main/java/org/jitsi/meet/sdk/JitsiMeetOngoingConferenceService.java
!react-native-sdk/android/src/main/java/org/jitsi/meet/sdk/JitsiMeetReactNativePackage.java
!react-native-sdk/android/src/main/java/org/jitsi/meet/sdk/JMOngoingConferenceModule.java
!react-native-sdk/android/src/main/java/org/jitsi/meet/sdk/RNOngoingNotification.java
react-native-sdk/images
react-native-sdk/ios
react-native-sdk/lang

View File

@@ -55,6 +55,8 @@ deploy-appbundle:
$(BUILD_DIR)/face-landmarks-worker.min.js.map \
$(BUILD_DIR)/noise-suppressor-worklet.min.js \
$(BUILD_DIR)/noise-suppressor-worklet.min.js.map \
$(BUILD_DIR)/screenshot-capture-worker.min.js \
$(BUILD_DIR)/screenshot-capture-worker.min.js.map \
$(DEPLOY_DIR)
cp \
$(BUILD_DIR)/close3.min.js \
@@ -123,7 +125,7 @@ dev: deploy-init deploy-css deploy-rnnoise-binary deploy-tflite deploy-meet-mode
source-package:
mkdir -p source_package/jitsi-meet/css && \
cp -r *.js *.html resources/*.txt favicon.ico fonts images libs static sounds LICENSE lang source_package/jitsi-meet && \
cp -r *.js *.html resources/*.txt fonts images libs static sounds LICENSE lang source_package/jitsi-meet && \
cp css/all.css source_package/jitsi-meet/css && \
(cd source_package ; tar cjf ../jitsi-meet.tar.bz2 jitsi-meet) && \
rm -rf source_package

View File

@@ -1,11 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<restrictions xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Server URL configuration -->
<restriction
android:defaultValue="https://meet.jit.si"
android:description="@string/restriction_server_url_description"
android:key="SERVER_URL"
android:restrictionType="string"
android:title="@string/restriction_server_url_title"/>
</restrictions>
<?xml version="1.0" encoding="utf-8"?>
<restrictions xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Server URL configuration -->
<restriction
android:description="@string/restriction_server_url_description"
android:key="SERVER_URL"
android:restrictionType="string"
android:title="@string/restriction_server_url_title"/>
</restrictions>

6
app.js
View File

@@ -31,12 +31,6 @@ if (window.Olm) {
window.APP = {
API,
conference,
// Used for automated performance tests.
connectionTimes: {
'index.loaded': window.indexLoadedTime
},
translation,
UI
};

View File

@@ -65,7 +65,11 @@ import {
updateDeviceList
} from './react/features/base/devices/actions.web';
import {
areDevicesDifferent,
filterIgnoredDevices,
flattenAvailableDevices,
getDefaultDeviceId,
logDevices,
setAudioOutputDeviceId
} from './react/features/base/devices/functions.web';
import {
@@ -150,7 +154,7 @@ import {
import { isModerationNotificationDisplayed } from './react/features/notifications/functions';
import { mediaPermissionPromptVisibilityChanged } from './react/features/overlay/actions';
import { suspendDetected } from './react/features/power-monitor/actions';
import { initPrejoin, makePrecallTest } from './react/features/prejoin/actions';
import { initPrejoin } from './react/features/prejoin/actions';
import { isPrejoinPageVisible } from './react/features/prejoin/functions';
import { disableReceiver, stopReceiver } from './react/features/remote-control/actions';
import { setScreenAudioShareState } from './react/features/screen-share/actions.web';
@@ -632,7 +636,7 @@ export default {
// so that the user can try unmute later on and add audio/video
// to the conference
if (!tracks.find(t => t.isAudioTrack())) {
this.setAudioMuteStatus(true);
this.updateAudioIconEnabled();
}
if (!tracks.find(t => t.isVideoTrack())) {
@@ -714,8 +718,6 @@ export default {
};
if (isPrejoinPageVisible(state)) {
APP.store.dispatch(makePrecallTest(this._getConferenceOptions()));
const { tryCreateLocalTracks, errors } = this.createInitialLocalTracks(initialOptions);
const localTracks = await tryCreateLocalTracks;
@@ -841,7 +843,7 @@ export default {
// This will only modify base/media.audio.muted which is then synced
// up with the track at the end of local tracks initialization.
muteLocalAudio(mute);
this.setAudioMuteStatus(mute);
this.updateAudioIconEnabled();
return;
} else if (this.isLocalAudioMuted() === mute) {
@@ -1035,17 +1037,6 @@ export default {
.filter(p => !p.isHidden() || !(config.iAmRecorder && p.isHiddenFromRecorder())).length + 1;
},
/**
* Returns true if the callstats integration is enabled, otherwise returns
* false.
*
* @returns true if the callstats integration is enabled, otherwise returns
* false.
*/
isCallstatsEnabled() {
return room && room.isCallstatsEnabled();
},
/**
* Get speaker stats that track total dominant speaker time.
*
@@ -1057,13 +1048,6 @@ export default {
return room.getSpeakerStats();
},
/**
* Returns the connection times stored in the library.
*/
getConnectionTimes() {
return room.getConnectionTimes();
},
// used by torture currently
isJoined() {
return room && room.isJoined();
@@ -1390,7 +1374,7 @@ export default {
APP.store.dispatch(
replaceLocalTrack(oldTrack, newTrack, room))
.then(() => {
this.setAudioMuteStatus(this.isLocalAudioMuted());
this.updateAudioIconEnabled();
})
.then(resolve)
.catch(reject)
@@ -2045,10 +2029,6 @@ export default {
return this.useVideoStream(stream);
})
.then(() => {
logger.info(`Switched local video device to ${cameraDeviceId}.`);
this._updateVideoDeviceId();
})
.catch(error => {
logger.error(`Failed to switch to selected camera:${cameraDeviceId}, error:${error}`);
@@ -2103,8 +2083,6 @@ export default {
// above mentioned chrome bug.
localAudio._realDeviceId = localAudio.deviceId = 'default';
}
logger.info(`switched local audio input device to: ${selectedDeviceId}`);
this._updateAudioDeviceId();
})
.catch(err => {
logger.error(`Failed to switch to selected audio input device ${selectedDeviceId}, error=${err}`);
@@ -2189,13 +2167,6 @@ export default {
return dispatch(getAvailableDevices())
.then(devices => {
// Ugly way to synchronize real device IDs with local
// storage and settings menu. This is a workaround until
// getConstraints() method will be implemented in browsers.
this._updateAudioDeviceId();
this._updateVideoDeviceId();
APP.UI.onAvailableDevicesChanged(devices);
});
}
@@ -2203,36 +2174,6 @@ export default {
return Promise.resolve();
},
/**
* Updates the settings for the currently used video device, extracting
* the device id from the used track.
* @private
*/
_updateVideoDeviceId() {
const localVideo = getLocalJitsiVideoTrack(APP.store.getState());
if (localVideo && localVideo.videoType === 'camera') {
APP.store.dispatch(updateSettings({
cameraDeviceId: localVideo.getDeviceId()
}));
}
},
/**
* Updates the settings for the currently used audio device, extracting
* the device id from the used track.
* @private
*/
_updateAudioDeviceId() {
const localAudio = getLocalJitsiAudioTrack(APP.store.getState());
if (localAudio) {
APP.store.dispatch(updateSettings({
micDeviceId: localAudio.getDeviceId()
}));
}
},
/**
* Event listener for JitsiMediaDevicesEvents.DEVICE_LIST_CHANGED to
* handle change of available media devices.
@@ -2241,19 +2182,28 @@ export default {
* @returns {Promise}
*/
async _onDeviceListChanged(devices) {
const oldDevices = APP.store.getState()['features/base/devices'].availableDevices;
const localAudio = getLocalJitsiAudioTrack(APP.store.getState());
const localVideo = getLocalJitsiVideoTrack(APP.store.getState());
const state = APP.store.getState();
const { filteredDevices, ignoredDevices } = filterIgnoredDevices(devices);
const oldDevices = state['features/base/devices'].availableDevices;
APP.store.dispatch(updateDeviceList(devices));
if (!areDevicesDifferent(flattenAvailableDevices(oldDevices), filteredDevices)) {
return Promise.resolve();
}
logDevices(ignoredDevices, 'Ignored devices on device list changed:');
const localAudio = getLocalJitsiAudioTrack(state);
const localVideo = getLocalJitsiVideoTrack(state);
APP.store.dispatch(updateDeviceList(filteredDevices));
// Firefox users can choose their preferred device in the gUM prompt. In that case
// we should respect that and not attempt to switch to the preferred device from
// our settings.
const newLabelsOnly = mediaDeviceHelper.newDeviceListAddedLabelsOnly(oldDevices, devices);
const newLabelsOnly = mediaDeviceHelper.newDeviceListAddedLabelsOnly(oldDevices, filteredDevices);
const newDevices
= mediaDeviceHelper.getNewMediaDevicesAfterDeviceListChanged(
devices,
filteredDevices,
localVideo,
localAudio,
newLabelsOnly);
@@ -2372,21 +2322,17 @@ export default {
this.useAudioStream(track)
.then(() => {
hasDefaultMicChanged && (track._realDeviceId = track.deviceId = 'default');
this._updateAudioDeviceId();
}));
} else {
promises.push(
this.useVideoStream(track)
.then(() => {
this._updateVideoDeviceId();
}));
this.useVideoStream(track));
}
}
}
return Promise.all(promises)
.then(() => {
APP.UI.onAvailableDevicesChanged(devices);
APP.UI.onAvailableDevicesChanged(filteredDevices);
});
},
@@ -2432,7 +2378,7 @@ export default {
* @param {string} [hangupReason] the reason for leaving the meeting
* requested
*/
async hangup(requestFeedback = false, hangupReason) {
hangup(requestFeedback = false, hangupReason) {
APP.store.dispatch(disableReceiver());
this._stopProxyConnection();
@@ -2449,33 +2395,42 @@ export default {
APP.UI.removeAllListeners();
let feedbackResult = {};
let feedbackResultPromise = Promise.resolve({});
if (requestFeedback) {
try {
feedbackResult = await APP.store.dispatch(maybeOpenFeedbackDialog(room, hangupReason));
} catch (err) { // eslint-disable-line no-empty
const feedbackDialogClosed = (feedbackResult = {}) => {
if (!feedbackResult.wasDialogShown && hangupReason) {
return APP.store.dispatch(
openLeaveReasonDialog(hangupReason)).then(() => feedbackResult);
}
return Promise.resolve(feedbackResult);
};
feedbackResultPromise
= APP.store.dispatch(maybeOpenFeedbackDialog(room, hangupReason))
.then(feedbackDialogClosed, feedbackDialogClosed);
}
const leavePromise = this.leaveRoom().catch(() => Promise.resolve());
Promise.allSettled([ feedbackResultPromise, leavePromise ]).then(([ feedback, _ ]) => {
this._room = undefined;
room = undefined;
/**
* Don't call {@code notifyReadyToClose} if the promotional page flag is set
* and let the page take care of sending the message, since there will be
* a redirect to the page anyway.
*/
if (!interfaceConfig.SHOW_PROMOTIONAL_CLOSE_PAGE) {
APP.API.notifyReadyToClose();
}
}
if (!feedbackResult.wasDialogShown && hangupReason) {
await APP.store.dispatch(openLeaveReasonDialog(hangupReason));
}
APP.store.dispatch(maybeRedirectToWelcomePage(feedback.value ?? {}));
});
await this.leaveRoom();
this._room = undefined;
room = undefined;
/**
* Don't call {@code notifyReadyToClose} if the promotional page flag is set
* and let the page take care of sending the message, since there will be
* a redirect to the page anyway.
*/
if (!interfaceConfig.SHOW_PROMOTIONAL_CLOSE_PAGE) {
APP.API.notifyReadyToClose();
}
APP.store.dispatch(maybeRedirectToWelcomePage(feedbackResult));
},
/**
@@ -2485,7 +2440,7 @@ export default {
* @param {string} reason - reason for leaving the room.
* @returns {Promise}
*/
async leaveRoom(doDisconnect = true, reason = '') {
leaveRoom(doDisconnect = true, reason = '') {
APP.store.dispatch(conferenceWillLeave(room));
const maybeDisconnect = () => {
@@ -2662,15 +2617,6 @@ export default {
APP.UI.setVideoMuted(this.getMyUserId());
},
/**
* Sets the audio muted status.
*
* @param {boolean} muted - New muted status.
*/
setAudioMuteStatus(muted) {
APP.UI.setAudioMuted(this.getMyUserId(), muted);
},
/**
* Dispatches the passed in feedback for submission. The submitted score
* should be a number inclusively between 1 through 5, or -1 for no score.

149
config.js
View File

@@ -51,6 +51,9 @@ var config = {
// Websocket URL (XMPP)
// websocket: 'wss://jitsi-meet.example.com/' + subdir + 'xmpp-websocket',
// Whether BOSH should be preferred over WebSocket if both are configured.
// preferBosh: false,
// The real JID of focus participant - can be overridden here
// Do not change username - FIXME: Make focus username configurable
// https://github.com/jitsi/jitsi-meet/issues/7376
@@ -94,11 +97,6 @@ var config = {
// Disables the auto-play behavior of *all* newly created video element.
// This is useful when the client runs on a host with limited resources.
// noAutoPlayVideo: false,
// Enable callstats only for a percentage of users.
// This takes a value between 0 and 100 which determines the probability for
// the callstats to be enabled.
// callStatsThreshold: 5, // enable callstats for 5% of the users.
},
// Disables moderator indicators.
@@ -215,6 +213,9 @@ var config = {
// Video
// Sets the default camera facing mode.
// cameraFacingMode: 'user',
// Sets the preferred resolution (height) for local video. Defaults to 720.
// resolution: 720,
@@ -288,12 +289,19 @@ var config = {
// max: 5,
// },
// This option has been deprecated since it is no longer supported as per the w3c spec.
// https://w3c.github.io/mediacapture-screen-share/#dom-mediadevices-getdisplaymedia. If the user has not
// interacted with the webpage before the getDisplayMedia call, the promise will be rejected by the browser. This
// has already been implemented in Firefox and Safari and will be implemented in Chrome soon.
// https://bugs.chromium.org/p/chromium/issues/detail?id=1198918
// startScreenSharing: false,
// Optional screenshare settings that give more control over screen capture in the browser.
// screenShareSettings: {
// // Show users the current tab is the preferred capture source, default: false.
// desktopPreferCurrentTab: false,
// // Allow users to select system audio, default: include.
// desktopSystemAudio: 'include',
// // Allow users to seamlessly switch which tab they are sharing without having to select the tab again.
// desktopSurfaceSwitching: 'include',
// // Allow a user to be shown a preference for what screen is to be captured, default: unset.
// desktopDisplaySurface: undefined,
// // Allow users to select the current tab as a capture source, default: exclude.
// desktopSelfBrowserSurface: 'exclude'
// },
// Recording
@@ -431,6 +439,49 @@ var config = {
// // Provides a way to set the codec preference on desktop based endpoints.
// codecPreferenceOrder: [ 'VP9', 'VP8', 'H264' ],
//
// // Codec specific settings for scalability modes and max bitrates.
// av1: {
// maxBitratesVideo: {
// low: 100000,
// standard: 300000,
// high: 1000000,
// ssHigh: 2500000
// },
// scalabilityModeEnabled: true,
// useSimulcast: false,
// useKSVC: true
// },
// h264: {
// maxBitratesVideo: {
// low: 200000,
// standard: 500000,
// high: 1500000,
// ssHigh: 2500000
// },
// scalabilityModeEnabled: true
// },
// vp8: {
// maxBitratesVideo: {
// low: 200000,
// standard: 500000,
// high: 1500000,
// ssHigh: 2500000
// },
// scalabilityModeEnabled: false
// },
// vp9: {
// maxBitratesVideo: {
// low: 100000,
// standard: 300000,
// high: 1200000,
// ssHigh: 2500000
// },
// scalabilityModeEnabled: true,
// useSimulcast: false,
// useKSVC: true
// }
//
// DEPRECATED! Use `codec specific settings` instead.
// // Provides a way to configure the maximum bitrates that will be enforced on the simulcast streams for
// // video tracks. The keys in the object represent the type of the stream (LD, SD or HD) and the values
// // are the max.bitrates to be set on that particular type of stream. The actual send may vary based on
@@ -632,6 +683,7 @@ var config = {
// hideDominantSpeakerBadge: false,
// Default language for the user interface. Cannot be overwritten.
// DEPRECATED! Use the `lang` iframe option directly instead.
// defaultLanguage: 'en',
// Disables profile and the edit of all fields from the profile settings (display name and email)
@@ -886,38 +938,10 @@ var config = {
// The interval at which PeerConnection.getStats() is called. Defaults to 10000
// pcStatsInterval: 10000,
// To enable sending statistics to callstats.io you must provide the
// Application ID and Secret.
// callStatsID: '',
// callStatsSecret: '',
// callStatsApplicationLogsDisabled: false,
// The callstats initialize config params as described in the API:
// https://docs.callstats.io/docs/javascript#callstatsinitialize-with-app-secret
// callStatsConfigParams: {
// disableBeforeUnloadHandler: true, // disables callstats.js's window.onbeforeunload parameter.
// applicationVersion: "app_version", // Application version specified by the developer.
// disablePrecalltest: true, // disables the pre-call test, it is enabled by default.
// siteID: "siteID", // The name/ID of the site/campus from where the call/pre-call test is made.
// additionalIDs: { // additionalIDs object, contains application related IDs.
// customerID: "Customer Identifier. Example, walmart.",
// tenantID: "Tenant Identifier. Example, monster.",
// productName: "Product Name. Example, Jitsi.",
// meetingsName: "Meeting Name. Example, Jitsi loves callstats.",
// serverName: "Server/MiddleBox Name. Example, jvb-prod-us-east-mlkncws12.",
// pbxID: "PBX Identifier. Example, walmart.",
// pbxExtensionID: "PBX Extension Identifier. Example, 5625.",
// fqExtensionID: "Fully qualified Extension Identifier. Example, +71 (US) +5625.",
// sessionID: "Session Identifier. Example, session-12-34",
// },
// collectLegacyStats: true, //enables the collection of legacy stats in chrome browser
// collectIP: true, //enables the collection localIP address
// },
// Enables sending participants' display names to callstats
// Enables sending participants' display names to stats
// enableDisplayNameInStats: false,
// Enables sending participants' emails (if available) to callstats and other analytics
// Enables sending participants' emails (if available) to stats and other analytics
// enableEmailInStats: false,
// faceLandmarks: {
@@ -940,7 +964,7 @@ var config = {
// captureInterval: 1000,
// },
// Controls the percentage of automatic feedback shown to participants when callstats is enabled.
// Controls the percentage of automatic feedback shown to participants.
// The default value is 100%. If set to 0, no automatic feedback will be requested
// feedbackPercentage: 100,
@@ -948,7 +972,7 @@ var config = {
//
// If third party requests are disabled, no other server will be contacted.
// This means avatars will be locally generated and callstats integration
// This means avatars will be locally generated and external stats integration
// will not function.
// disableThirdPartyRequests: false,
@@ -1499,8 +1523,6 @@ var config = {
_peerConnStatusOutOfLastNTimeout
_peerConnStatusRtcMuteTimeout
avgRtpStatsN
callStatsConfIDNamespace
callStatsCustomScriptUrl
desktopSharingSources
disableAEC
disableAGC
@@ -1509,7 +1531,6 @@ var config = {
disableLocalStats
disableNS
enableTalkWhileMuted
forceJVB121Ratio
forceTurnRelay
hiddenDomain
hiddenFromRecorderFeatureEnabled
@@ -1533,6 +1554,7 @@ var config = {
*/
// notifications: [
// 'connection.CONNFAIL', // shown when the connection fails,
// 'dialog.cameraConstraintFailedError', // shown when the camera failed
// 'dialog.cameraNotSendingData', // shown when there's no feed from user's camera
// 'dialog.kickTitle', // shown when user has been kicked
// 'dialog.liveStreaming', // livestreaming notifications (pending, on, off, limits)
@@ -1543,6 +1565,7 @@ var config = {
// 'dialog.recording', // recording notifications (pending, on, off, limits)
// 'dialog.remoteControlTitle', // remote control notifications (allowed, denied, start, stop, error)
// 'dialog.reservationError',
// 'dialog.screenSharingFailedTitle', // shown when the screen sharing failed
// 'dialog.serviceUnavailable', // shown when server is not reachable
// 'dialog.sessTerminated', // shown when there is a failed conference session
// 'dialog.sessionRestarted', // show when a client reload is initiated because of bridge migration
@@ -1555,37 +1578,45 @@ var config = {
// 'liveStreaming.unavailableTitle', // shown when livestreaming service is not reachable
// 'lobby.joinRejectedMessage', // shown when while in a lobby, user's request to join is rejected
// 'lobby.notificationTitle', // shown when lobby is toggled and when join requests are allowed / denied
// 'notify.audioUnmuteBlockedTitle', // shown when mic unmute blocked
// 'notify.chatMessages', // shown when receiving chat messages while the chat window is closed
// 'notify.disconnected', // shown when a participant has left
// 'notify.connectedOneMember', // show when a participant joined
// 'notify.connectedTwoMembers', // show when two participants joined simultaneously
// 'notify.connectedThreePlusMembers', // show when more than 2 participants joined simultaneously
// 'notify.leftOneMember', // show when a participant left
// 'notify.leftTwoMembers', // show when two participants left simultaneously
// 'notify.leftThreePlusMembers', // show when more than 2 participants left simultaneously
// 'notify.grantedTo', // shown when moderator rights were granted to a participant
// 'notify.connectedTwoMembers', // show when two participants joined simultaneously
// 'notify.dataChannelClosed', // shown when the bridge channel has been disconnected
// 'notify.hostAskedUnmute', // shown to participant when host asks them to unmute
// 'notify.invitedOneMember', // shown when 1 participant has been invited
// 'notify.invitedThreePlusMembers', // shown when 3+ participants have been invited
// 'notify.invitedTwoMembers', // shown when 2 participants have been invited
// 'notify.kickParticipant', // shown when a participant is kicked
// 'notify.leftOneMember', // show when a participant left
// 'notify.leftThreePlusMembers', // show when more than 2 participants left simultaneously
// 'notify.leftTwoMembers', // show when two participants left simultaneously
// 'notify.linkToSalesforce', // shown when joining a meeting with salesforce integration
// 'notify.moderationStartedTitle', // shown when AV moderation is activated
// 'notify.moderationStoppedTitle', // shown when AV moderation is deactivated
// 'notify.localRecordingStarted', // shown when the local recording has been started
// 'notify.localRecordingStopped', // shown when the local recording has been stopped
// 'notify.moderationInEffectCSTitle', // shown when user attempts to share content during AV moderation
// 'notify.moderationInEffectTitle', // shown when user attempts to unmute audio during AV moderation
// 'notify.moderationInEffectVideoTitle', // shown when user attempts to enable video during AV moderation
// 'notify.moderationInEffectCSTitle', // shown when user attempts to share content during AV moderation
// 'notify.moderator', // shown when user gets moderator privilege
// 'notify.mutedRemotelyTitle', // shown when user is muted by a remote party
// 'notify.mutedTitle', // shown when user has been muted upon joining,
// 'notify.newDeviceAudioTitle', // prompts the user to use a newly detected audio device
// 'notify.newDeviceCameraTitle', // prompts the user to use a newly detected camera
// 'notify.noiseSuppressionFailedTitle', // shown when failed to start noise suppression
// 'notify.participantWantsToJoin', // shown when lobby is enabled and participant requests to join meeting
// 'notify.participantsWantToJoin', // shown when lobby is enabled and participants request to join meeting
// 'notify.passwordRemovedRemotely', // shown when a password has been removed remotely
// 'notify.passwordSetRemotely', // shown when a password has been set remotely
// 'notify.raisedHand', // shown when a partcipant used raise hand,
// 'notify.screenShareNoAudio', // shown when the audio could not be shared for the selected screen
// 'notify.screenSharingAudioOnlyTitle', // shown when the best performance has been affected by screen sharing
// 'notify.selfViewTitle', // show "You can always un-hide the self-view from settings"
// 'notify.startSilentTitle', // shown when user joined with no audio
// 'notify.suboptimalExperienceTitle', // show the browser warning
// 'notify.unmute', // shown to moderator when user raises hand during AV moderation
// 'notify.videoMutedRemotelyTitle', // shown when user's video is muted by a remote party,
// 'notify.videoUnmuteBlockedTitle', // shown when camera unmute and desktop sharing are blocked
// 'prejoin.errorDialOut',
// 'prejoin.errorDialOutDisconnected',
// 'prejoin.errorDialOutFailed',
@@ -1665,13 +1696,12 @@ var config = {
// logging: {
// // Default log level for the app and lib-jitsi-meet.
// defaultLogLevel: 'trace',
// // Option to disable LogCollector (which stores the logs on CallStats).
// // Option to disable LogCollector.
// //disableLogCollector: true,
// // Individual loggers are customizable.
// loggers: {
// // The following are too verbose in their logging with the default level.
// 'modules/RTC/TraceablePeerConnection.js': 'info',
// 'modules/statistics/CallStats.js': 'info',
// 'modules/xmpp/strophe.util.js': 'log',
// },
@@ -1685,6 +1715,11 @@ var config = {
// // The server used to support whiteboard collaboration.
// // https://github.com/jitsi/excalidraw-backend
// collabServerBaseUrl: 'https://excalidraw-backend.example.com',
// // The user access limit to the whiteboard, introduced as a means
// // to control the performance.
// userLimit: 25,
// // The url for more info about the whiteboard and its usage limitations.
// limitUrl: 'https://example.com/blog/whiteboard-limits,
// },
// The watchRTC initialize config params as described :

View File

@@ -115,17 +115,18 @@ form {
}
.leftwatermark {
max-width: 140px;
max-height:70px;
left: 32px;
top: 32px;
background-position: center left;
background-repeat: no-repeat;
background-size: contain;
}
.leftwatermarknomargin {
background-position: center left;
background-repeat: no-repeat;
background-size: contain;
&.no-margin {
left:0;
top:0;
}
}
.rightwatermark {

View File

@@ -61,6 +61,35 @@ body.welcome-page {
}
.not-allow-title-character-div {
color: #f03e3e;
background-color: #fff;
font-size: 12px;
font-weight: 600;
margin: 10px 0px 5px 0px;
text-align: $welcomePageHeaderTextAlign;
border-radius: 5px;
padding: 5px;
.not-allow-title-character-text {
float: right;
line-height: 1.9;
};
.jitsi-icon {
margin-right: 9px;
float: left;
svg {
fill:#f03e3e;
& > *:first-child {
fill: none !important;
}
}
}
}
.insecure-room-name-warning {
align-items: center;
color: rgb(215, 121, 118);
@@ -231,11 +260,6 @@ body.welcome-page {
width: $welcomePageWatermarkWidth;
height: $welcomePageWatermarkHeight;
}
.watermark.leftwatermarknomargin {
width: $welcomePageWatermarkWidth;
height: $welcomePageWatermarkHeight;
}
}
&.without-content {

View File

@@ -39,7 +39,7 @@ case "$1" in
echo "Application secret is mandatory"
fi
# Not allowed unix special characters in secret: /, \, ", ', `
if echo "$RET" | grep -q '[/\\\"\`]' ; then
if echo "$RET" | grep -q "[/\\\"\`\']" ; then
echo "Application secret contains invalid characters: /, \\, \", ', \`"
exit 1
fi

View File

@@ -1,6 +1,5 @@
interface_config.js /usr/share/jitsi-meet/
*.html /usr/share/jitsi-meet/
*.ico /usr/share/jitsi-meet/
libs /usr/share/jitsi-meet/
static /usr/share/jitsi-meet/
css/all.css /usr/share/jitsi-meet/css/

View File

@@ -43,8 +43,8 @@ server {
}
}
server {
listen 443 ssl;
listen [::]:443 ssl;
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name jitsi-meet.example.com;
# Mozilla Guideline v5.4, nginx 1.17.7, OpenSSL 1.1.1d, intermediate configuration

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

13
images/favicon.svg Normal file

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 8.5 KiB

View File

@@ -107,8 +107,8 @@ var interfaceConfig = {
// Names of browsers which should show a warning stating the current browser
// has a suboptimal experience. Browsers which are not listed as optimal or
// unsupported are considered suboptimal. Valid values are:
// chrome, chromium, edge, electron, firefox, nwjs, opera, safari
OPTIMAL_BROWSERS: [ 'chrome', 'chromium', 'firefox', 'nwjs', 'electron', 'safari' ],
// chrome, chromium, electron, firefox , safari, webkit
OPTIMAL_BROWSERS: [ 'chrome', 'chromium', 'firefox', 'electron', 'safari', 'webkit' ],
POLICY_LOGO: null,
PROVIDER_NAME: 'Jitsi',

View File

@@ -6,8 +6,6 @@ workspace 'jitsi-meet'
install! 'cocoapods', :deterministic_uuids => false
production = ENV["PRODUCTION"] == "1"
target 'JitsiMeet' do
project 'app/app.xcodeproj'
@@ -26,7 +24,6 @@ target 'JitsiMeetSDK' do
flags = get_default_flags()
use_react_native!(
:path => config[:reactNativePath],
:production => production,
:hermes_enabled => false,
:fabric_enabled => false,
# An absolute path to your application root.
@@ -56,24 +53,24 @@ target 'JitsiMeetSDKLite' do
# React Native and its dependencies
#
config = use_native_modules!
use_react_native!(
:path => config["reactNativePath"],
:path => config[:reactNativePath],
:hermes_enabled => false,
:fabric_enabled => false,
# An absolute path to your application root.
:app_path => "#{Pod::Config.instance.installation_root}/.."
)
# Native pod dependencies
#
pod 'CocoaLumberjack', '3.7.2'
end
post_install do |installer|
react_native_post_install(installer)
react_native_post_install(installer, :mac_catalyst_enabled => false)
__apply_Xcode_12_5_M1_post_install_workaround(installer)
installer.pods_project.targets.each do |target|
# https://github.com/CocoaPods/CocoaPods/issues/11402

View File

@@ -14,14 +14,14 @@ PODS:
- CocoaLumberjack/Core (= 3.7.2)
- CocoaLumberjack/Core (3.7.2)
- DoubleConversion (1.1.6)
- FBLazyVector (0.69.11)
- FBReactNativeSpec (0.69.11):
- RCT-Folly (= 2021.06.28.00-v2)
- RCTRequired (= 0.69.11)
- RCTTypeSafety (= 0.69.11)
- React-Core (= 0.69.11)
- React-jsi (= 0.69.11)
- ReactCommon/turbomodule/core (= 0.69.11)
- FBLazyVector (0.70.14)
- FBReactNativeSpec (0.70.14):
- RCT-Folly (= 2021.07.22.00)
- RCTRequired (= 0.70.14)
- RCTTypeSafety (= 0.70.14)
- React-Core (= 0.70.14)
- React-jsi (= 0.70.14)
- ReactCommon/turbomodule/core (= 0.70.14)
- Firebase/Analytics (8.15.0):
- Firebase/Core
- Firebase/Core (8.15.0):
@@ -103,7 +103,7 @@ PODS:
- GoogleUtilities/Network (~> 7.7)
- "GoogleUtilities/NSData+zlib (~> 7.7)"
- nanopb (~> 2.30908.0)
- GoogleDataTransport (9.2.5):
- GoogleDataTransport (9.3.0):
- GoogleUtilities/Environment (~> 7.7)
- nanopb (< 2.30910.0, >= 2.30908.0)
- PromisesObjC (< 3.0, >= 1.2)
@@ -111,41 +111,41 @@ PODS:
- AppAuth (~> 1.5)
- GTMAppAuth (< 3.0, >= 1.3)
- GTMSessionFetcher/Core (< 4.0, >= 1.1)
- GoogleUtilities/AppDelegateSwizzler (7.11.5):
- GoogleUtilities/AppDelegateSwizzler (7.12.0):
- GoogleUtilities/Environment
- GoogleUtilities/Logger
- GoogleUtilities/Network
- GoogleUtilities/Environment (7.11.5):
- GoogleUtilities/Environment (7.12.0):
- PromisesObjC (< 3.0, >= 1.2)
- GoogleUtilities/Logger (7.11.5):
- GoogleUtilities/Logger (7.12.0):
- GoogleUtilities/Environment
- GoogleUtilities/MethodSwizzler (7.11.5):
- GoogleUtilities/MethodSwizzler (7.12.0):
- GoogleUtilities/Logger
- GoogleUtilities/Network (7.11.5):
- GoogleUtilities/Network (7.12.0):
- GoogleUtilities/Logger
- "GoogleUtilities/NSData+zlib"
- GoogleUtilities/Reachability
- "GoogleUtilities/NSData+zlib (7.11.5)"
- GoogleUtilities/Reachability (7.11.5):
- "GoogleUtilities/NSData+zlib (7.12.0)"
- GoogleUtilities/Reachability (7.12.0):
- GoogleUtilities/Logger
- GoogleUtilities/UserDefaults (7.11.5):
- GoogleUtilities/UserDefaults (7.12.0):
- GoogleUtilities/Logger
- GTMAppAuth (2.0.0):
- AppAuth/Core (~> 1.6)
- GTMSessionFetcher/Core (< 4.0, >= 1.5)
- GTMSessionFetcher/Core (3.1.1)
- JitsiWebRTC (111.0.2)
- libwebp (1.3.1):
- libwebp/demux (= 1.3.1)
- libwebp/mux (= 1.3.1)
- libwebp/sharpyuv (= 1.3.1)
- libwebp/webp (= 1.3.1)
- libwebp/demux (1.3.1):
- GTMSessionFetcher/Core (3.2.0)
- JitsiWebRTC (118.0.0)
- libwebp (1.3.2):
- libwebp/demux (= 1.3.2)
- libwebp/mux (= 1.3.2)
- libwebp/sharpyuv (= 1.3.2)
- libwebp/webp (= 1.3.2)
- libwebp/demux (1.3.2):
- libwebp/webp
- libwebp/mux (1.3.1):
- libwebp/mux (1.3.2):
- libwebp/demux
- libwebp/sharpyuv (1.3.1)
- libwebp/webp (1.3.1):
- libwebp/sharpyuv (1.3.2)
- libwebp/webp (1.3.2):
- libwebp/sharpyuv
- nanopb (2.30908.0):
- nanopb/decode (= 2.30908.0)
@@ -156,214 +156,214 @@ PODS:
- PromisesObjC (2.3.1)
- PromisesSwift (2.3.1):
- PromisesObjC (= 2.3.1)
- RCT-Folly (2021.06.28.00-v2):
- RCT-Folly (2021.07.22.00):
- boost
- DoubleConversion
- fmt (~> 6.2.1)
- glog
- RCT-Folly/Default (= 2021.06.28.00-v2)
- RCT-Folly/Default (2021.06.28.00-v2):
- RCT-Folly/Default (= 2021.07.22.00)
- RCT-Folly/Default (2021.07.22.00):
- boost
- DoubleConversion
- fmt (~> 6.2.1)
- glog
- RCTRequired (0.69.11)
- RCTTypeSafety (0.69.11):
- FBLazyVector (= 0.69.11)
- RCTRequired (= 0.69.11)
- React-Core (= 0.69.11)
- React (0.69.11):
- React-Core (= 0.69.11)
- React-Core/DevSupport (= 0.69.11)
- React-Core/RCTWebSocket (= 0.69.11)
- React-RCTActionSheet (= 0.69.11)
- React-RCTAnimation (= 0.69.11)
- React-RCTBlob (= 0.69.11)
- React-RCTImage (= 0.69.11)
- React-RCTLinking (= 0.69.11)
- React-RCTNetwork (= 0.69.11)
- React-RCTSettings (= 0.69.11)
- React-RCTText (= 0.69.11)
- React-RCTVibration (= 0.69.11)
- React-bridging (0.69.11):
- RCT-Folly (= 2021.06.28.00-v2)
- React-jsi (= 0.69.11)
- React-callinvoker (0.69.11)
- React-Codegen (0.69.11):
- FBReactNativeSpec (= 0.69.11)
- RCT-Folly (= 2021.06.28.00-v2)
- RCTRequired (= 0.69.11)
- RCTTypeSafety (= 0.69.11)
- React-Core (= 0.69.11)
- React-jsi (= 0.69.11)
- React-jsiexecutor (= 0.69.11)
- ReactCommon/turbomodule/core (= 0.69.11)
- React-Core (0.69.11):
- RCTRequired (0.70.14)
- RCTTypeSafety (0.70.14):
- FBLazyVector (= 0.70.14)
- RCTRequired (= 0.70.14)
- React-Core (= 0.70.14)
- React (0.70.14):
- React-Core (= 0.70.14)
- React-Core/DevSupport (= 0.70.14)
- React-Core/RCTWebSocket (= 0.70.14)
- React-RCTActionSheet (= 0.70.14)
- React-RCTAnimation (= 0.70.14)
- React-RCTBlob (= 0.70.14)
- React-RCTImage (= 0.70.14)
- React-RCTLinking (= 0.70.14)
- React-RCTNetwork (= 0.70.14)
- React-RCTSettings (= 0.70.14)
- React-RCTText (= 0.70.14)
- React-RCTVibration (= 0.70.14)
- React-bridging (0.70.14):
- RCT-Folly (= 2021.07.22.00)
- React-jsi (= 0.70.14)
- React-callinvoker (0.70.14)
- React-Codegen (0.70.14):
- FBReactNativeSpec (= 0.70.14)
- RCT-Folly (= 2021.07.22.00)
- RCTRequired (= 0.70.14)
- RCTTypeSafety (= 0.70.14)
- React-Core (= 0.70.14)
- React-jsi (= 0.70.14)
- React-jsiexecutor (= 0.70.14)
- ReactCommon/turbomodule/core (= 0.70.14)
- React-Core (0.70.14):
- glog
- RCT-Folly (= 2021.06.28.00-v2)
- React-Core/Default (= 0.69.11)
- React-cxxreact (= 0.69.11)
- React-jsi (= 0.69.11)
- React-jsiexecutor (= 0.69.11)
- React-perflogger (= 0.69.11)
- RCT-Folly (= 2021.07.22.00)
- React-Core/Default (= 0.70.14)
- React-cxxreact (= 0.70.14)
- React-jsi (= 0.70.14)
- React-jsiexecutor (= 0.70.14)
- React-perflogger (= 0.70.14)
- Yoga
- React-Core/CoreModulesHeaders (0.69.11):
- React-Core/CoreModulesHeaders (0.70.14):
- glog
- RCT-Folly (= 2021.06.28.00-v2)
- RCT-Folly (= 2021.07.22.00)
- React-Core/Default
- React-cxxreact (= 0.69.11)
- React-jsi (= 0.69.11)
- React-jsiexecutor (= 0.69.11)
- React-perflogger (= 0.69.11)
- React-cxxreact (= 0.70.14)
- React-jsi (= 0.70.14)
- React-jsiexecutor (= 0.70.14)
- React-perflogger (= 0.70.14)
- Yoga
- React-Core/Default (0.69.11):
- React-Core/Default (0.70.14):
- glog
- RCT-Folly (= 2021.06.28.00-v2)
- React-cxxreact (= 0.69.11)
- React-jsi (= 0.69.11)
- React-jsiexecutor (= 0.69.11)
- React-perflogger (= 0.69.11)
- RCT-Folly (= 2021.07.22.00)
- React-cxxreact (= 0.70.14)
- React-jsi (= 0.70.14)
- React-jsiexecutor (= 0.70.14)
- React-perflogger (= 0.70.14)
- Yoga
- React-Core/DevSupport (0.69.11):
- React-Core/DevSupport (0.70.14):
- glog
- RCT-Folly (= 2021.06.28.00-v2)
- React-Core/Default (= 0.69.11)
- React-Core/RCTWebSocket (= 0.69.11)
- React-cxxreact (= 0.69.11)
- React-jsi (= 0.69.11)
- React-jsiexecutor (= 0.69.11)
- React-jsinspector (= 0.69.11)
- React-perflogger (= 0.69.11)
- RCT-Folly (= 2021.07.22.00)
- React-Core/Default (= 0.70.14)
- React-Core/RCTWebSocket (= 0.70.14)
- React-cxxreact (= 0.70.14)
- React-jsi (= 0.70.14)
- React-jsiexecutor (= 0.70.14)
- React-jsinspector (= 0.70.14)
- React-perflogger (= 0.70.14)
- Yoga
- React-Core/RCTActionSheetHeaders (0.69.11):
- React-Core/RCTActionSheetHeaders (0.70.14):
- glog
- RCT-Folly (= 2021.06.28.00-v2)
- RCT-Folly (= 2021.07.22.00)
- React-Core/Default
- React-cxxreact (= 0.69.11)
- React-jsi (= 0.69.11)
- React-jsiexecutor (= 0.69.11)
- React-perflogger (= 0.69.11)
- React-cxxreact (= 0.70.14)
- React-jsi (= 0.70.14)
- React-jsiexecutor (= 0.70.14)
- React-perflogger (= 0.70.14)
- Yoga
- React-Core/RCTAnimationHeaders (0.69.11):
- React-Core/RCTAnimationHeaders (0.70.14):
- glog
- RCT-Folly (= 2021.06.28.00-v2)
- RCT-Folly (= 2021.07.22.00)
- React-Core/Default
- React-cxxreact (= 0.69.11)
- React-jsi (= 0.69.11)
- React-jsiexecutor (= 0.69.11)
- React-perflogger (= 0.69.11)
- React-cxxreact (= 0.70.14)
- React-jsi (= 0.70.14)
- React-jsiexecutor (= 0.70.14)
- React-perflogger (= 0.70.14)
- Yoga
- React-Core/RCTBlobHeaders (0.69.11):
- React-Core/RCTBlobHeaders (0.70.14):
- glog
- RCT-Folly (= 2021.06.28.00-v2)
- RCT-Folly (= 2021.07.22.00)
- React-Core/Default
- React-cxxreact (= 0.69.11)
- React-jsi (= 0.69.11)
- React-jsiexecutor (= 0.69.11)
- React-perflogger (= 0.69.11)
- React-cxxreact (= 0.70.14)
- React-jsi (= 0.70.14)
- React-jsiexecutor (= 0.70.14)
- React-perflogger (= 0.70.14)
- Yoga
- React-Core/RCTImageHeaders (0.69.11):
- React-Core/RCTImageHeaders (0.70.14):
- glog
- RCT-Folly (= 2021.06.28.00-v2)
- RCT-Folly (= 2021.07.22.00)
- React-Core/Default
- React-cxxreact (= 0.69.11)
- React-jsi (= 0.69.11)
- React-jsiexecutor (= 0.69.11)
- React-perflogger (= 0.69.11)
- React-cxxreact (= 0.70.14)
- React-jsi (= 0.70.14)
- React-jsiexecutor (= 0.70.14)
- React-perflogger (= 0.70.14)
- Yoga
- React-Core/RCTLinkingHeaders (0.69.11):
- React-Core/RCTLinkingHeaders (0.70.14):
- glog
- RCT-Folly (= 2021.06.28.00-v2)
- RCT-Folly (= 2021.07.22.00)
- React-Core/Default
- React-cxxreact (= 0.69.11)
- React-jsi (= 0.69.11)
- React-jsiexecutor (= 0.69.11)
- React-perflogger (= 0.69.11)
- React-cxxreact (= 0.70.14)
- React-jsi (= 0.70.14)
- React-jsiexecutor (= 0.70.14)
- React-perflogger (= 0.70.14)
- Yoga
- React-Core/RCTNetworkHeaders (0.69.11):
- React-Core/RCTNetworkHeaders (0.70.14):
- glog
- RCT-Folly (= 2021.06.28.00-v2)
- RCT-Folly (= 2021.07.22.00)
- React-Core/Default
- React-cxxreact (= 0.69.11)
- React-jsi (= 0.69.11)
- React-jsiexecutor (= 0.69.11)
- React-perflogger (= 0.69.11)
- React-cxxreact (= 0.70.14)
- React-jsi (= 0.70.14)
- React-jsiexecutor (= 0.70.14)
- React-perflogger (= 0.70.14)
- Yoga
- React-Core/RCTSettingsHeaders (0.69.11):
- React-Core/RCTSettingsHeaders (0.70.14):
- glog
- RCT-Folly (= 2021.06.28.00-v2)
- RCT-Folly (= 2021.07.22.00)
- React-Core/Default
- React-cxxreact (= 0.69.11)
- React-jsi (= 0.69.11)
- React-jsiexecutor (= 0.69.11)
- React-perflogger (= 0.69.11)
- React-cxxreact (= 0.70.14)
- React-jsi (= 0.70.14)
- React-jsiexecutor (= 0.70.14)
- React-perflogger (= 0.70.14)
- Yoga
- React-Core/RCTTextHeaders (0.69.11):
- React-Core/RCTTextHeaders (0.70.14):
- glog
- RCT-Folly (= 2021.06.28.00-v2)
- RCT-Folly (= 2021.07.22.00)
- React-Core/Default
- React-cxxreact (= 0.69.11)
- React-jsi (= 0.69.11)
- React-jsiexecutor (= 0.69.11)
- React-perflogger (= 0.69.11)
- React-cxxreact (= 0.70.14)
- React-jsi (= 0.70.14)
- React-jsiexecutor (= 0.70.14)
- React-perflogger (= 0.70.14)
- Yoga
- React-Core/RCTVibrationHeaders (0.69.11):
- React-Core/RCTVibrationHeaders (0.70.14):
- glog
- RCT-Folly (= 2021.06.28.00-v2)
- RCT-Folly (= 2021.07.22.00)
- React-Core/Default
- React-cxxreact (= 0.69.11)
- React-jsi (= 0.69.11)
- React-jsiexecutor (= 0.69.11)
- React-perflogger (= 0.69.11)
- React-cxxreact (= 0.70.14)
- React-jsi (= 0.70.14)
- React-jsiexecutor (= 0.70.14)
- React-perflogger (= 0.70.14)
- Yoga
- React-Core/RCTWebSocket (0.69.11):
- React-Core/RCTWebSocket (0.70.14):
- glog
- RCT-Folly (= 2021.06.28.00-v2)
- React-Core/Default (= 0.69.11)
- React-cxxreact (= 0.69.11)
- React-jsi (= 0.69.11)
- React-jsiexecutor (= 0.69.11)
- React-perflogger (= 0.69.11)
- RCT-Folly (= 2021.07.22.00)
- React-Core/Default (= 0.70.14)
- React-cxxreact (= 0.70.14)
- React-jsi (= 0.70.14)
- React-jsiexecutor (= 0.70.14)
- React-perflogger (= 0.70.14)
- Yoga
- React-CoreModules (0.69.11):
- RCT-Folly (= 2021.06.28.00-v2)
- RCTTypeSafety (= 0.69.11)
- React-Codegen (= 0.69.11)
- React-Core/CoreModulesHeaders (= 0.69.11)
- React-jsi (= 0.69.11)
- React-RCTImage (= 0.69.11)
- ReactCommon/turbomodule/core (= 0.69.11)
- React-cxxreact (0.69.11):
- React-CoreModules (0.70.14):
- RCT-Folly (= 2021.07.22.00)
- RCTTypeSafety (= 0.70.14)
- React-Codegen (= 0.70.14)
- React-Core/CoreModulesHeaders (= 0.70.14)
- React-jsi (= 0.70.14)
- React-RCTImage (= 0.70.14)
- ReactCommon/turbomodule/core (= 0.70.14)
- React-cxxreact (0.70.14):
- boost (= 1.76.0)
- DoubleConversion
- glog
- RCT-Folly (= 2021.06.28.00-v2)
- React-callinvoker (= 0.69.11)
- React-jsi (= 0.69.11)
- React-jsinspector (= 0.69.11)
- React-logger (= 0.69.11)
- React-perflogger (= 0.69.11)
- React-runtimeexecutor (= 0.69.11)
- React-jsi (0.69.11):
- RCT-Folly (= 2021.07.22.00)
- React-callinvoker (= 0.70.14)
- React-jsi (= 0.70.14)
- React-jsinspector (= 0.70.14)
- React-logger (= 0.70.14)
- React-perflogger (= 0.70.14)
- React-runtimeexecutor (= 0.70.14)
- React-jsi (0.70.14):
- boost (= 1.76.0)
- DoubleConversion
- glog
- RCT-Folly (= 2021.06.28.00-v2)
- React-jsi/Default (= 0.69.11)
- React-jsi/Default (0.69.11):
- RCT-Folly (= 2021.07.22.00)
- React-jsi/Default (= 0.70.14)
- React-jsi/Default (0.70.14):
- boost (= 1.76.0)
- DoubleConversion
- glog
- RCT-Folly (= 2021.06.28.00-v2)
- React-jsiexecutor (0.69.11):
- RCT-Folly (= 2021.07.22.00)
- React-jsiexecutor (0.70.14):
- DoubleConversion
- glog
- RCT-Folly (= 2021.06.28.00-v2)
- React-cxxreact (= 0.69.11)
- React-jsi (= 0.69.11)
- React-perflogger (= 0.69.11)
- React-jsinspector (0.69.11)
- React-logger (0.69.11):
- RCT-Folly (= 2021.07.22.00)
- React-cxxreact (= 0.70.14)
- React-jsi (= 0.70.14)
- React-perflogger (= 0.70.14)
- React-jsinspector (0.70.14)
- React-logger (0.70.14):
- glog
- react-native-background-timer (2.4.1):
- React-Core
@@ -371,9 +371,9 @@ PODS:
- React-Core
- react-native-keep-awake (4.0.0):
- React
- react-native-netinfo (9.4.1):
- react-native-netinfo (11.1.0):
- React-Core
- react-native-orientation-locker (1.5.0):
- react-native-orientation-locker (1.6.0):
- React-Core
- react-native-pager-view (6.2.0):
- React-Core
@@ -391,80 +391,80 @@ PODS:
- react-native-video/Video (6.0.0-alpha.7):
- PromisesSwift
- React-Core
- react-native-webrtc (111.0.3):
- JitsiWebRTC (~> 111.0.0)
- react-native-webrtc (118.0.0):
- JitsiWebRTC (~> 118.0.0)
- React-Core
- react-native-webview (13.5.1):
- React-Core
- React-perflogger (0.69.11)
- React-RCTActionSheet (0.69.11):
- React-Core/RCTActionSheetHeaders (= 0.69.11)
- React-RCTAnimation (0.69.11):
- RCT-Folly (= 2021.06.28.00-v2)
- RCTTypeSafety (= 0.69.11)
- React-Codegen (= 0.69.11)
- React-Core/RCTAnimationHeaders (= 0.69.11)
- React-jsi (= 0.69.11)
- ReactCommon/turbomodule/core (= 0.69.11)
- React-RCTBlob (0.69.11):
- RCT-Folly (= 2021.06.28.00-v2)
- React-Codegen (= 0.69.11)
- React-Core/RCTBlobHeaders (= 0.69.11)
- React-Core/RCTWebSocket (= 0.69.11)
- React-jsi (= 0.69.11)
- React-RCTNetwork (= 0.69.11)
- ReactCommon/turbomodule/core (= 0.69.11)
- React-RCTImage (0.69.11):
- RCT-Folly (= 2021.06.28.00-v2)
- RCTTypeSafety (= 0.69.11)
- React-Codegen (= 0.69.11)
- React-Core/RCTImageHeaders (= 0.69.11)
- React-jsi (= 0.69.11)
- React-RCTNetwork (= 0.69.11)
- ReactCommon/turbomodule/core (= 0.69.11)
- React-RCTLinking (0.69.11):
- React-Codegen (= 0.69.11)
- React-Core/RCTLinkingHeaders (= 0.69.11)
- React-jsi (= 0.69.11)
- ReactCommon/turbomodule/core (= 0.69.11)
- React-RCTNetwork (0.69.11):
- RCT-Folly (= 2021.06.28.00-v2)
- RCTTypeSafety (= 0.69.11)
- React-Codegen (= 0.69.11)
- React-Core/RCTNetworkHeaders (= 0.69.11)
- React-jsi (= 0.69.11)
- ReactCommon/turbomodule/core (= 0.69.11)
- React-RCTSettings (0.69.11):
- RCT-Folly (= 2021.06.28.00-v2)
- RCTTypeSafety (= 0.69.11)
- React-Codegen (= 0.69.11)
- React-Core/RCTSettingsHeaders (= 0.69.11)
- React-jsi (= 0.69.11)
- ReactCommon/turbomodule/core (= 0.69.11)
- React-RCTText (0.69.11):
- React-Core/RCTTextHeaders (= 0.69.11)
- React-RCTVibration (0.69.11):
- RCT-Folly (= 2021.06.28.00-v2)
- React-Codegen (= 0.69.11)
- React-Core/RCTVibrationHeaders (= 0.69.11)
- React-jsi (= 0.69.11)
- ReactCommon/turbomodule/core (= 0.69.11)
- React-runtimeexecutor (0.69.11):
- React-jsi (= 0.69.11)
- ReactCommon/turbomodule/core (0.69.11):
- React-perflogger (0.70.14)
- React-RCTActionSheet (0.70.14):
- React-Core/RCTActionSheetHeaders (= 0.70.14)
- React-RCTAnimation (0.70.14):
- RCT-Folly (= 2021.07.22.00)
- RCTTypeSafety (= 0.70.14)
- React-Codegen (= 0.70.14)
- React-Core/RCTAnimationHeaders (= 0.70.14)
- React-jsi (= 0.70.14)
- ReactCommon/turbomodule/core (= 0.70.14)
- React-RCTBlob (0.70.14):
- RCT-Folly (= 2021.07.22.00)
- React-Codegen (= 0.70.14)
- React-Core/RCTBlobHeaders (= 0.70.14)
- React-Core/RCTWebSocket (= 0.70.14)
- React-jsi (= 0.70.14)
- React-RCTNetwork (= 0.70.14)
- ReactCommon/turbomodule/core (= 0.70.14)
- React-RCTImage (0.70.14):
- RCT-Folly (= 2021.07.22.00)
- RCTTypeSafety (= 0.70.14)
- React-Codegen (= 0.70.14)
- React-Core/RCTImageHeaders (= 0.70.14)
- React-jsi (= 0.70.14)
- React-RCTNetwork (= 0.70.14)
- ReactCommon/turbomodule/core (= 0.70.14)
- React-RCTLinking (0.70.14):
- React-Codegen (= 0.70.14)
- React-Core/RCTLinkingHeaders (= 0.70.14)
- React-jsi (= 0.70.14)
- ReactCommon/turbomodule/core (= 0.70.14)
- React-RCTNetwork (0.70.14):
- RCT-Folly (= 2021.07.22.00)
- RCTTypeSafety (= 0.70.14)
- React-Codegen (= 0.70.14)
- React-Core/RCTNetworkHeaders (= 0.70.14)
- React-jsi (= 0.70.14)
- ReactCommon/turbomodule/core (= 0.70.14)
- React-RCTSettings (0.70.14):
- RCT-Folly (= 2021.07.22.00)
- RCTTypeSafety (= 0.70.14)
- React-Codegen (= 0.70.14)
- React-Core/RCTSettingsHeaders (= 0.70.14)
- React-jsi (= 0.70.14)
- ReactCommon/turbomodule/core (= 0.70.14)
- React-RCTText (0.70.14):
- React-Core/RCTTextHeaders (= 0.70.14)
- React-RCTVibration (0.70.14):
- RCT-Folly (= 2021.07.22.00)
- React-Codegen (= 0.70.14)
- React-Core/RCTVibrationHeaders (= 0.70.14)
- React-jsi (= 0.70.14)
- ReactCommon/turbomodule/core (= 0.70.14)
- React-runtimeexecutor (0.70.14):
- React-jsi (= 0.70.14)
- ReactCommon/turbomodule/core (0.70.14):
- DoubleConversion
- glog
- RCT-Folly (= 2021.06.28.00-v2)
- React-bridging (= 0.69.11)
- React-callinvoker (= 0.69.11)
- React-Core (= 0.69.11)
- React-cxxreact (= 0.69.11)
- React-jsi (= 0.69.11)
- React-logger (= 0.69.11)
- React-perflogger (= 0.69.11)
- RCT-Folly (= 2021.07.22.00)
- React-bridging (= 0.70.14)
- React-callinvoker (= 0.70.14)
- React-Core (= 0.70.14)
- React-cxxreact (= 0.70.14)
- React-jsi (= 0.70.14)
- React-logger (= 0.70.14)
- React-perflogger (= 0.70.14)
- RNCalendarEvents (2.2.0):
- React
- RNCAsyncStorage (1.19.3):
- RNCAsyncStorage (1.19.4):
- React-Core
- RNCClipboard (1.5.1):
- React-Core
@@ -474,7 +474,7 @@ PODS:
- React-Core
- RNGestureHandler (2.9.0):
- React-Core
- RNGoogleSignin (10.0.1):
- RNGoogleSignin (10.1.0):
- GoogleSignIn (~> 7.0)
- React-Core
- RNScreens (3.24.0):
@@ -709,8 +709,8 @@ SPEC CHECKSUMS:
boost: a7c83b31436843459a1961bfd74b96033dc77234
CocoaLumberjack: b7e05132ff94f6ae4dfa9d5bce9141893a21d9da
DoubleConversion: 5189b271737e1565bdce30deb4a08d647e3f5f54
FBLazyVector: 5c0975e66853436589eae7542f4b956c7e2ef465
FBReactNativeSpec: bb062293e84c33200005312d1807d8cb94a0d66a
FBLazyVector: efad4471d02263013cfcb7a2f75de6ac7565692f
FBReactNativeSpec: 9cd9542bfdcc64e07bc649f809dd621876f78619
Firebase: 5f8193dff4b5b7c5d5ef72ae54bb76c08e2b841d
FirebaseAnalytics: 7761cbadb00a717d8d0939363eb46041526474fa
FirebaseCore: 5743c5785c074a794d35f2fff7ecc254a91e08b1
@@ -721,71 +721,71 @@ SPEC CHECKSUMS:
fmt: ff9d55029c625d3757ed641535fd4a75fedc7ce9
Giphy: 6b5f6986c8df4f71e01a8ef86595f426b3439fb5
giphy-react-native-sdk: fcda9639f8ca2cc47e0517b6ef11c19359db5f5a
glog: 3d02b25ca00c2d456734d0bcff864cbc62f6ae1a
glog: 04b94705f318337d7ead9e6d17c019bd9b1f6b1b
GoogleAppMeasurement: 4c19f031220c72464d460c9daa1fb5d1acce958e
GoogleDataTransport: 54dee9d48d14580407f8f5fbf2f496e92437a2f2
GoogleDataTransport: 57c22343ab29bc686febbf7cbb13bad167c2d8fe
GoogleSignIn: b232380cf495a429b8095d3178a8d5855b42e842
GoogleUtilities: 13e2c67ede716b8741c7989e26893d151b2b2084
GoogleUtilities: 0759d1a57ebb953965c2dfe0ba4c82e95ccc2e34
GTMAppAuth: 99fb010047ba3973b7026e45393f51f27ab965ae
GTMSessionFetcher: e8647203b65cee28c5f73d0f473d096653945e72
JitsiWebRTC: 80f62908fcf2a1160e0d14b584323fb6e6be630b
libwebp: 33dc822fbbf4503668d09f7885bbfedc76c45e96
GTMSessionFetcher: 41b9ef0b4c08a6db4b7eb51a21ae5183ec99a2c8
JitsiWebRTC: 3a41671ef65a51d7204323814b055a2690b921c7
libwebp: 1786c9f4ff8a279e4dac1e8f385004d5fc253009
nanopb: a0ba3315591a9ae0a16a309ee504766e90db0c96
ObjectiveDropboxOfficial: fe206ce8c0bc49976c249d472db7fdbc53ebbd53
PromisesObjC: c50d2056b5253dadbd6c2bea79b0674bd5a52fa4
PromisesSwift: 28dca69a9c40779916ac2d6985a0192a5cb4a265
RCT-Folly: b9d9fe1fc70114b751c076104e52f3b1b5e5a95a
RCTRequired: 8e9a57dddc8f8e9e816c67c2d2537271a997137a
RCTTypeSafety: 2b19e268e2036a2c2f6db6deb1ac03e28b1d607a
React: f9478e6390f177ee6b67b87a3c6afea42b39523e
React-bridging: d405ecd3ff80e1d0a4059a11063eaa9ed7a00c58
React-callinvoker: c8ffa61f3f06f486ba6647769fc98f19e25d165a
React-Codegen: 73acfdac1495b91ad5efdd3ab005568263c5def6
React-Core: 7b7c75af4b73fe0ed4e5c3cdb7d79979e81148dc
React-CoreModules: cd6e7efb38162884f08c7afa16fffaf15ff28ae4
React-cxxreact: 51157cc600c9f436a7e623913a03b775305ef86c
React-jsi: 3eeb345c4828d7b132fd38064a305f31b46d4ec3
React-jsiexecutor: 5813455a4a908fb7284aa13307a9e0386e93b0bb
React-jsinspector: 9ca5bf73ed0a195397e45fdbcd507cf7d503c428
React-logger: 700340e325f21ba2a2d6413a61ef14268c7360aa
RCT-Folly: 0080d0a6ebf2577475bda044aa59e2ca1f909cda
RCTRequired: 6f42727926c2ef4836fc23169586f3d8d7f5a6e4
RCTTypeSafety: de9b538a8f20ae8c780bf38935f37f303b083fc8
React: 6604c02c25295898e9332c5dbe5d6f140be1e246
React-bridging: 55de000607b776d7c9b1333f38d1991ef25bf915
React-callinvoker: aa42aaefd72dbe9218c112fd503eff7ab782bd11
React-Codegen: 9e13e901ac4d4c46349c2db28b8774fa4274ec18
React-Core: b046bbaddd981014eaac20cef83de953a0405c1b
React-CoreModules: 4f0b29e5924b06a868983952265f77fed219f349
React-cxxreact: 818c9b06607f7972e95eeacb326389429c6a2d38
React-jsi: 0bf359879bc4c2c908204b1cd789b0a727a7a568
React-jsiexecutor: 03144eeee729e6a6cb8d7ff2d5653b67315f8f31
React-jsinspector: 6538dfb58970d1fb9d89c9c34e87713ece6c3cf0
React-logger: 4e9c3f888b4b5bb72a3ac7f1be7929e776181016
react-native-background-timer: 17ea5e06803401a379ebf1f20505b793ac44d0fe
react-native-get-random-values: dee677497c6a740b71e5612e8dbd83e7539ed5bb
react-native-keep-awake: afad8a51dfef9fe9655a6344771be32c8596d774
react-native-netinfo: fefd4e98d75cbdd6e85fc530f7111a8afdf2b0c5
react-native-orientation-locker: 851f6510d8046ea2f14aa169b1e01fcd309a94ba
react-native-netinfo: 3aa5637c18834966e0c932de8ae1ae56fea20a97
react-native-orientation-locker: 4409c5b12b65f942e75449872b4f078b6f27af81
react-native-pager-view: 0ccb8bf60e2ebd38b1f3669fa3650ecce81db2df
react-native-performance: 47ac22ebf2aa24f324a96a5825581f6ce18c09e8
react-native-safe-area-context: 9697629f7b2cda43cf52169bb7e0767d330648c2
react-native-slider: 1cdd6ba29675df21f30544253bf7351d3c2d68c4
react-native-splash-screen: 4312f786b13a81b5169ef346d76d33bc0c6dc457
react-native-video: 967eead48aaa42c25a9e1d65c3b1ab30762a88df
react-native-webrtc: 4d1669c2ed29767fe70b0169428b4466589ecf8b
react-native-webrtc: c8d9ad3c152105b2720ca2851d04b49659551992
react-native-webview: 8baa0f5c6d336d6ba488e942bcadea5bf51f050a
React-perflogger: fdee2a0c512167ae4c19c4e230ccf6aa66a6aff0
React-RCTActionSheet: 1cf5fef4e372f1c877969710a51bea4bb25e78fe
React-RCTAnimation: 73816e3acd1f5e3f00166fc7eedb34f6b112f734
React-RCTBlob: 6976c838fb14a1daf75d7c8bb23bae9cbbf726bb
React-RCTImage: ab8a7498f215117f32271698591e4bd932dcf812
React-RCTLinking: e8e78aed2744ab9946cc8ba5716b4938c2efb1e0
React-RCTNetwork: 796f5aed4d932655d292bdc6b40f9502dcdb9542
React-RCTSettings: 7e1cd2a384b45c90caf67464572abe3833b9da3b
React-RCTText: fd6162890828f0761e03c59058fa23c3a21b2e10
React-RCTVibration: 302cfd5cc33669d7abdb7ec6790123baba66e62e
React-runtimeexecutor: 59407514818b2afbb1d7507e4e1ac834d24b0fbd
ReactCommon: b8487da74723562d7368dab27135fd182f00a91c
React-perflogger: 74b2d33200b8c26440c2c39b87a4177d8404655f
React-RCTActionSheet: 3fdf6b3a85f2ea4b365b267efd9c82aaeb20fe33
React-RCTAnimation: 9659d5ed57ccbd129516486b2cce38e536841337
React-RCTBlob: 49ac98cfd9476af046814a2c9126fca1bf0cbe75
React-RCTImage: b4d2d7d14ad9389bd645bc2daa706ccaead3fc44
React-RCTLinking: ebf051ed2532652e5290e4fb7c017c42e4e1f0d2
React-RCTNetwork: 1636df1f91d4c5ad8815ef93f695931af1c0a842
React-RCTSettings: f6306171fd5d3cd8c5fa0b1803da599784ead5c5
React-RCTText: 53c106b5fb9e263c2f1e5d6b0733049989d6c428
React-RCTVibration: d293c50100c0927379e6a80fab86a219e08792ae
React-runtimeexecutor: 0d01d03375f996484fcc231ccca3fe604a4a5652
ReactCommon: dce64235f8548b6e4758647310145f5356c8d0cb
RNCalendarEvents: 7e65eb4a94f53c1744d1e275f7fafcfaa619f7a3
RNCAsyncStorage: c913ede1fa163a71cea118ed4670bbaaa4b511bb
RNCAsyncStorage: 3a8f7145d17cdd9f88e7b77666c94a09e4f759c8
RNCClipboard: 41d8d918092ae8e676f18adada19104fa3e68495
RNDefaultPreference: 08bdb06cfa9188d5da97d4642dac745218d7fb31
RNDeviceInfo: 02ea8b23e2280fa18e00a06d7e62804d74028579
RNGestureHandler: 071d7a9ad81e8b83fe7663b303d132406a7d8f39
RNGoogleSignin: ccaa4a81582cf713eea562c5dd9dc1961a715fd0
RNGoogleSignin: a6a612cce56a45ab701c5c5c6e36f5390522d100
RNScreens: b21dc57dfa2b710c30ec600786a3fc223b1b92e7
RNSound: 6c156f925295bdc83e8e422e7d8b38d33bc71852
RNSVG: ed492aaf3af9ca01bc945f7a149d76d62e73ec82
RNWatch: fd30ca40a5b5ef58dcbc195638e68219bc455236
Yoga: 7f5ad94937ba3fc58c151ad1b7bbada2c275b28e
Yoga: 56413d530d1808044600320ced5baa883acedc44
PODFILE CHECKSUM: 90720aee51cf2cab2e12611a28dbf55a688e969c
PODFILE CHECKSUM: c5053669414ca81c03ca4548249b11fe53a13060
COCOAPODS: 1.12.1
COCOAPODS: 1.14.3

View File

@@ -3,7 +3,7 @@
archiveVersion = 1;
classes = {
};
objectVersion = 52;
objectVersion = 54;
objects = {
/* Begin PBXBuildFile section */
@@ -862,7 +862,6 @@
"$(inherited)",
"@executable_path/Frameworks",
);
LIBRARY_SEARCH_PATHS = "$(inherited)";
OTHER_LDFLAGS = (
"$(inherited)",
"-ObjC",
@@ -892,7 +891,6 @@
"$(inherited)",
"@executable_path/Frameworks",
);
LIBRARY_SEARCH_PATHS = "$(inherited)";
OTHER_LDFLAGS = (
"$(inherited)",
"-ObjC",
@@ -978,7 +976,7 @@
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LANGUAGE_STANDARD = "c++17";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
@@ -1013,6 +1011,7 @@
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
_LIBCPP_ENABLE_CXX17_REMOVED_UNARY_BINARY_FUNCTION,
);
GCC_SYMBOLS_PRIVATE_EXTERN = NO;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
@@ -1028,6 +1027,10 @@
IPHONEOS_DEPLOYMENT_TARGET = 12.4;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
OTHER_LDFLAGS = (
"$(inherited)",
" ",
);
REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native";
SDKROOT = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2";
@@ -1039,7 +1042,7 @@
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LANGUAGE_STANDARD = "c++17";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
@@ -1069,6 +1072,10 @@
"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = "";
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_NO_COMMON_BLOCKS = YES;
GCC_PREPROCESSOR_DEFINITIONS = (
"$(inherited)",
_LIBCPP_ENABLE_CXX17_REMOVED_UNARY_BINARY_FUNCTION,
);
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
@@ -1081,6 +1088,10 @@
);
IPHONEOS_DEPLOYMENT_TARGET = 12.4;
MTL_ENABLE_DEBUG_INFO = NO;
OTHER_LDFLAGS = (
"$(inherited)",
" ",
);
REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native";
SDKROOT = iphoneos;
SWIFT_COMPILATION_MODE = wholemodule;

View File

@@ -38,7 +38,6 @@
[builder setFeatureFlag:@"resolution" withValue:@(360)];
[builder setFeatureFlag:@"ios.screensharing.enabled" withBoolean:YES];
[builder setFeatureFlag:@"ios.recording.enabled" withBoolean:YES];
builder.serverURL = [NSURL URLWithString:@"https://meet.jit.si"];
}];
[jitsiMeet application:application didFinishLaunchingWithOptions:launchOptions];
@@ -126,7 +125,7 @@
- (UIInterfaceOrientationMask)application:(UIApplication *)application
supportedInterfaceOrientationsForWindow:(UIWindow *)window {
return [[JitsiMeet sharedInstance] application:application
return [[JitsiMeet sharedInstance] application:application
supportedInterfaceOrientationsForWindow:window];
}

View File

@@ -728,7 +728,7 @@
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LANGUAGE_STANDARD = "c++17";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
@@ -766,6 +766,7 @@
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
_LIBCPP_ENABLE_CXX17_REMOVED_UNARY_BINARY_FUNCTION,
);
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
@@ -776,6 +777,10 @@
IPHONEOS_DEPLOYMENT_TARGET = 12.4;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
OTHER_LDFLAGS = (
"$(inherited)",
" ",
);
REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native";
SDKROOT = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2";
@@ -791,7 +796,7 @@
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LANGUAGE_STANDARD = "c++17";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
@@ -824,6 +829,10 @@
"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = "";
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_NO_COMMON_BLOCKS = YES;
GCC_PREPROCESSOR_DEFINITIONS = (
"$(inherited)",
_LIBCPP_ENABLE_CXX17_REMOVED_UNARY_BINARY_FUNCTION,
);
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
@@ -832,6 +841,10 @@
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 12.4;
MTL_ENABLE_DEBUG_INFO = NO;
OTHER_LDFLAGS = (
"$(inherited)",
" ",
);
REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native";
SDKROOT = iphoneos;
SWIFT_COMPILATION_MODE = wholemodule;

View File

@@ -67,13 +67,16 @@
"renameBreakoutRoom": "Breakout-Raum umbenennen",
"sendToBreakoutRoom": "Anwesende in Breakout-Raum verschieben:"
},
"breakoutList": "Breakout-Liste",
"defaultName": "Breakout-Raum #{{index}}",
"hideParticipantList": "Teilnehmerliste ausblenden",
"mainRoom": "Hauptraum",
"notifications": {
"joined": "Breakout-Raum \"{{name}}\" betreten",
"joinedMainRoom": "Hauptraum betreten",
"joinedTitle": "Breakout-Räume"
}
},
"showParticipantList": "Teilnehmerliste anzeigen"
},
"calendarSync": {
"addMeetingURL": "Konferenzlink hinzufügen",
@@ -256,6 +259,7 @@
"Share": "Teilen",
"Submit": "OK",
"WaitForHostMsg": "Die Konferenz wurde noch nicht gestartet. Falls Sie die Konferenz leiten, authentifizieren Sie sich bitte. Warten Sie andernfalls, bis die Konferenz gestartet wird.",
"WaitingForHostButton": "Auf Moderation warten",
"WaitingForHostTitle": "Warten auf den Beginn der Konferenz …",
"Yes": "Ja",
"accessibilityLabel": {
@@ -269,6 +273,8 @@
"addMeetingNote": "Notiz zu dieser Konferenz hinzufügen",
"addOptionalNote": "Notiz hinzufügen (optional):",
"allow": "Erlauben",
"allowToggleCameraDialog": "Wollen Sie {{initiatorName}} erlauben, Ihre Kameraauswahl zu ändern?",
"allowToggleCameraTitle": "Änderung der Kamera zulassen?",
"alreadySharedVideoMsg": "Eine andere Person gibt bereits ein Video weiter. Bei dieser Konferenz ist jeweils nur ein geteiltes Video möglich.",
"alreadySharedVideoTitle": "Nur ein geteiltes Video gleichzeitig",
"applicationWindow": "Anwendungsfenster",
@@ -329,6 +335,7 @@
"lockRoom": "Konferenz$t(lockRoomPassword) hinzufügen",
"lockTitle": "Sperren fehlgeschlagen",
"login": "Anmelden",
"loginQuestion": "Sind Sie sicher, dass sie sich anmelden und die Konferenz verlassen möchten?",
"logoutQuestion": "Sind Sie sicher, dass Sie sich abmelden und die Konferenz verlassen möchten?",
"logoutTitle": "Abmelden",
"maxUsersLimitReached": "Das Limit für die maximale Personenzahl ist erreicht. Die Konferenz ist voll. Bitte wenden Sie sich an die Konferenzleitung oder versuchen Sie es später noch einmal!",
@@ -409,8 +416,10 @@
"sendPrivateMessageTitle": "Privat antworten?",
"serviceUnavailable": "Dienst nicht verfügbar",
"sessTerminated": "Konferenz beendet",
"sessTerminatedReason": "Die Konferenz wurde beendet",
"sessionRestarted": "Konferenz neugestartet",
"shareAudio": "Fortfahren",
"shareAudioAltText": "Um den gewünschten Inhalt zu teilen: Navigiere zu \"Browser tab\", wähle den Inhalt, aktiviere \"Audio teilen\" Kästchen Und klicke den “Teilen” schaltfläche",
"shareAudioTitle": "Wie kann Audio geteilt werden",
"shareAudioWarningD1": "müssen Sie Ihre Bildschirmfreigabe stoppen, bevor Sie Audio teilen können.",
"shareAudioWarningD2": "müssen Sie Ihre Bildschirmfreigabe neustarten und die Option \"Audio freigeben\" auswählen.",
@@ -440,7 +449,24 @@
"thankYou": "Danke für die Verwendung von {{appName}}!",
"token": "Token",
"tokenAuthFailed": "Sie sind nicht berechtigt, dieser Konferenz beizutreten.",
"tokenAuthFailedReason": {
"audInvalid": "Ungültiger `aud`-Wert. Erwartet wird `jitsi`.",
"contextNotFound": "Das `context`-Objekt fehlt.",
"expInvalid": "Ungültiger `exp`-Wert.",
"featureInvalid": "Ungültiges Feature: {{feature}}, noch nicht implementiert.",
"featureValueInvalid": "Ungültiger Wert für Feature: {{feature}}.",
"featuresNotFound": "Das `features`-Objekt fehlt.",
"headerNotFound": "Header fehlt.",
"issInvalid": "Ungültiger `iss`-Wert. Erwartet wird `chat`.",
"kidMismatch": "Die Key-ID (kid) passt nicht zum sub.",
"kidNotFound": "Fehlende Key-ID (kid).",
"nbfFuture": "Der `nbf`-Wert liegt in der Zukunft.",
"nbfInvalid": "Ungültiger `nbf`-Wert.",
"payloadNotFound": "Fehlende Payload.",
"tokenExpired": "Das Token ist abgelaufen."
},
"tokenAuthFailedTitle": "Authentifizierung fehlgeschlagen",
"tokenAuthFailedWithReasons": "Teilnahme an der Konferenz fehlgeschlagen. Möglicher Grund: {{reason}}",
"tokenAuthUnsupported": "Token-Authentifizierung wird nicht unterstützt.",
"transcribing": "Wird transkribiert",
"unlockRoom": "Konferenz$t(lockRoomPassword) entfernen",
@@ -530,6 +556,7 @@
"password": "$t(lockRoomPasswordUppercase):",
"reachedLimit": "Sie haben die Grenzen Ihres Tarifs erreicht.",
"sip": "SIP-Adresse",
"sipAudioOnly": "SIP-Adresse (nur Ton)",
"title": "Teilen",
"tooltip": "Freigabe-Link und Einwahlinformationen für dieses Meeting",
"upgradeOptions": "Bitte prüfen Sie Ihre Upgrade-Optionen auf"
@@ -636,13 +663,13 @@
"knockingParticipantList": "Liste anklopfender Personen",
"lobbyChatStartedNotification": "{{moderator}} hat einen Lobby-Chat mit {{attendee}} gestartet",
"lobbyChatStartedTitle": "{{moderator}} hat einen Lobby-Chat mit Ihnen gestartet.",
"lobbyClosed": "Die Lobby wurde geschlossen.",
"nameField": "Geben Sie Ihren Namen ein",
"notificationLobbyAccessDenied": "{{targetParticipantName}} wurde von {{originParticipantName}} der Zutritt verwehrt",
"notificationLobbyAccessGranted": "{{targetParticipantName}} wurde von {{originParticipantName}} der Zutritt gestattet",
"notificationLobbyDisabled": "{{originParticipantName}} hat die Lobby deaktiviert",
"notificationLobbyEnabled": "{{originParticipantName}} hat die Lobby aktiviert",
"notificationTitle": "Lobby",
"passwordField": "Konferenzpasswort eingeben",
"passwordJoinButton": "Beitreten",
"reject": "Ablehnen",
"rejectAll": "Alle ablehnen",
@@ -677,6 +704,8 @@
"sessionToken": "Sitzungs-Token",
"start": "Aufnahme starten",
"stop": "Aufnahme stoppen",
"stopping": "Aufnahme wird gestoppt",
"wait": "Bitte warten Sie während wir Ihre Aufnahme speichern",
"yes": "Ja"
},
"lockRoomPassword": "Passwort",
@@ -1059,6 +1088,7 @@
"alertOk": "OK",
"alertTitle": "Warnung",
"alertURLText": "Die angegebene Server-URL ist ungültig",
"apply": "Übernehmen",
"buildInfoSection": "Build-Informationen",
"conferenceSection": "Konferenz",
"disableCallIntegration": "Native Anrufintegration deaktivieren",
@@ -1069,6 +1099,7 @@
"displayNamePlaceholderText": "z.B. Erika Musterfrau",
"email": "E-Mail",
"emailPlaceholderText": "email@beispiel.de",
"gavatarMessage": "Wenn Sie ein Gravatar-Konto mit Ihrer Emailadresse haben, wird dieses als Ihr Profilfoto verwendet.",
"goTo": "Gehe zu",
"header": "Einstellungen",
"help": "Hilfe",

View File

@@ -778,7 +778,7 @@
"moreModerationControls": "Más controles de moderación",
"moreParticipantOptions": "Más opciones de participantes",
"mute": "Silenciar",
"muteAll": "Silenciar a todos los demás",
"muteAll": "Silenciar a todos",
"muteEveryoneElse": "Silenciar al resto",
"stopEveryonesVideo": "Detener el vídeo de todos",
"stopVideo": "Detener el vídeo",
@@ -1361,7 +1361,7 @@
"videothumbnail": {
"connectionInfo": "Información de conexión",
"domute": "Silenciar",
"domuteOthers": "Silenciar a todos",
"domuteOthers": "Silenciar a todos los demás",
"domuteVideo": "Desactivar la cámara",
"domuteVideoOfOthers": "Desactivar la cámara de todos los demás",
"flip": "Voltear",

File diff suppressed because it is too large Load Diff

View File

@@ -67,13 +67,18 @@
"renameBreakoutRoom": "Renomear sala",
"sendToBreakoutRoom": "Enviar participante para:"
},
"breakoutList": "lista de salas",
"buttonLabel": "Salas simultâneas",
"defaultName": "Sala #{{index}}",
"hideParticipantList": "Ocultar lista de participantes",
"mainRoom": "Sala principal",
"notifications": {
"joined": "Entrada na sala \"{{name}}\"",
"joinedMainRoom": "Entrada na sala principal",
"joinedTitle": "Salas simultâneas"
}
},
"showParticipantList": "Mostrar lista de participantes",
"title": "Salas simultâneas"
},
"calendarSync": {
"addMeetingURL": "Adicionar um link da reunião",
@@ -477,6 +482,10 @@
"viewUpgradeOptions": "Ver opções de actualização",
"viewUpgradeOptionsContent": "Para obter acesso ilimitado a funcionalidades premium como gravação, transcrições, RTMP Streaming & mais, terá de actualizar o seu plano.",
"viewUpgradeOptionsTitle": "Descobriu uma característica premium!",
"whiteboardLimitContent": "Lamentamos, mas o limite de utilizadores do quadro branco foi atingido.",
"whiteboardLimitReference": "Para mais informações consultar",
"whiteboardLimitReferenceUrl": "o nosso sítio Web",
"whiteboardLimitTitle": "Restrição da utilização do quadro branco",
"yourEntireScreen": "O seu ecrã inteiro"
},
"documentSharing": {
@@ -724,6 +733,7 @@
"dataChannelClosed": "Deficiência na qualidade do vídeo",
"dataChannelClosedDescription": "O canal de ponte foi desconectado e, portanto, a qualidade do vídeo está limitada à sua configuração mais baixa.",
"disabledIframe": "A incorporação destina-se apenas a fins de demonstração, pelo que esta chamada será desligada em {{timeout}} minutos.",
"disabledIframeSecondary": "A incorporação de {{domain}} destina-se apenas a fins de demonstração, pelo que esta chamada será desligada em {{timeout}} minutos. Por favor, use <a href='{{jaasDomain}}' rel='noopener noreferrer' target='_blank'>Jitsi as a Service</a> para incorporação em produção!",
"disconnected": "desconectado",
"displayNotifications": "Mostrar notificações para",
"dontRemindMe": "Não me lembre",
@@ -799,7 +809,9 @@
"videoUnmuteBlockedDescription": "A operação de ligar a câmara e partilhar o ambiente de trabalho foi temporariamente bloqueada devido aos limites do sistema.",
"videoUnmuteBlockedTitle": "Está bloqueado ligar a câmara e partilhar o ambiente de trabalho!",
"viewLobby": "Ver sala de espera",
"waitingParticipants": "{{waitingParticipants}} pessoas"
"waitingParticipants": "{{waitingParticipants}} pessoas",
"whiteboardLimitDescription": "Guarde o seu progresso, pois o limite de utilizadores será atingido em breve e o quadro branco será encerrado.",
"whiteboardLimitTitle": "Utilização do quadro branco"
},
"participantsPane": {
"actions": {
@@ -808,6 +820,7 @@
"askUnmute": "Pedir para ligar o som",
"audioModeration": "Ligar o microfone deles",
"blockEveryoneMicCamera": "Bloquear o microfone e a câmara de todos",
"breakoutRooms": "Salas simultâneas",
"invite": "Convidar alguém",
"moreModerationActions": "Mais opções de moderação",
"moreModerationControls": "Mais controlos de moderação",
@@ -1154,7 +1167,7 @@
"audioOnly": "Mudar para apenas áudio",
"audioRoute": "Selecionar o dispositivo de som",
"boo": "Vaia",
"breakoutRoom": "Entrar/Sair da sala",
"breakoutRooms": "Salas simultâneas",
"callQuality": "Gerir a qualidade do vídeo",
"carmode": "Modo de condução",
"cc": "Mudar legendas",

View File

@@ -1,5 +1,8 @@
{
"addPeople": {
"accessibilityLabel": {
"meetingLink": "Link da reunião: {{url}}"
},
"add": "Convidar",
"addContacts": "Convide seus contatos",
"contacts": "contatos",
@@ -39,6 +42,18 @@
"audioOnly": {
"audioOnly": "Largura de banda baixa"
},
"bandwidthSettings": {
"assumedBandwidthBps": "Ex. 10000000 para 10 Mbps",
"assumedBandwidthBpsWarning": "Valores mais altos podem causar erros de rede.",
"customValue": "valor personalizado",
"customValueEffect": "para definir o valor de bps real",
"leaveEmpty": "deixar vazio",
"leaveEmptyEffect": "para permitir que estimativas assumam",
"possibleValues": "Valores possíveis",
"setAssumedBandwidthBps": "Banda presumida (bps)",
"title": "Configurações de banda",
"zeroEffect": "para desabilitar o vídeo"
},
"breakoutRooms": {
"actions": {
"add": "Adicionar sala de apoio",
@@ -48,15 +63,22 @@
"leaveBreakoutRoom": "Sair da sala de apoio",
"more": "Mais",
"remove": "Remover",
"rename": "Renomear",
"renameBreakoutRoom": "Renomear sala de apoio",
"sendToBreakoutRoom": "Enviar participante para:"
},
"breakoutList": "Lista de apoio",
"buttonLabel": "Salas de apoio",
"defaultName": "Sala de apoio #{{index}}",
"hideParticipantList": "Ocultar lista de participantes",
"mainRoom": "Sala principal",
"notifications": {
"joined": "Entrando na sala de apoio \"{{name}}\"",
"joinedMainRoom": "Entrando na sala principal",
"joinedTitle": "Salas de apoio"
}
},
"showParticipantList": "Exibir lista de participantes",
"title": "Salas de apoio"
},
"calendarSync": {
"addMeetingURL": "Adicionar um link da reunião",
@@ -239,9 +261,12 @@
"Share": "Compartilhar",
"Submit": "Enviar",
"WaitForHostMsg": "A conferência ainda não começou. Se você é o anfitrião, faça a autenticação. Do contrário, aguarde a chegada do anfitrião.",
"WaitingForHostButton": "Aguardar por anfitrião",
"WaitingForHostTitle": "Esperando o anfitrião...",
"Yes": "Sim",
"accessibilityLabel": {
"Cancel": "Cancelar (fechar janela)",
"Ok": "OK (salvar e fechar janela)",
"close": "Fechar janela",
"liveStreaming": "Transmissão ao vivo",
"sharingTabs": "Opções de compartilhamento"
@@ -250,6 +275,8 @@
"addMeetingNote": "Adicionar uma anotação para esta reunião",
"addOptionalNote": "Adicionar uma anotação (opcional):",
"allow": "Permitir",
"allowToggleCameraDialog": "Você permite que {{initiatorName}} possa alternar entre suas câmeras?",
"allowToggleCameraTitle": "Permitir alternar câmera?",
"alreadySharedVideoMsg": "Outro participante já está compartilhando um vídeo. Esta conferência permite apenas um vídeo compartilhado por vez.",
"alreadySharedVideoTitle": "Somente um vídeo compartilhado é permitido por vez",
"applicationWindow": "Janela de aplicativo",
@@ -310,6 +337,7 @@
"lockRoom": "Adicionar reunião $t(lockRoomPasswordUppercase)",
"lockTitle": "Bloqueio falhou",
"login": "Entrar",
"loginQuestion": "Deseja iniciar a sessão e finalizar a conferência?",
"logoutQuestion": "Deseja encerrar a sessão e finalizar a conferência?",
"logoutTitle": "Encerrar sessão",
"maxUsersLimitReached": "O limite para o número máximo de participantes foi atingido. A conferência está cheia. Entre em contato com o proprietário da reunião ou tente novamente mais tarde!",
@@ -353,8 +381,6 @@
"permissionCameraRequiredError": "É necessário permitir acesso à câmera para participar de reuniões com vídeo. Ative a permissão nas configurações",
"permissionErrorTitle": "Permissão necessária",
"permissionMicRequiredError": "É necessário permitir acesso ao microfone para participar de reuniões com áudio. Ative a permissão nas configurações",
"popupError": "Seu navegador está bloqueando janelas popup deste site. Habilite os popups nas configurações de segurança no seu navegador e tente novamente.",
"popupErrorTitle": "Popup bloqueado",
"readMore": "mais...",
"recentlyUsedObjects": "Seus objetos usados recentemente",
"recording": "Gravando",
@@ -371,6 +397,8 @@
"removePassword": "Remover $t(lockRoomPassword)",
"removeSharedVideoMsg": "Deseja remover seu vídeo compartilhado?",
"removeSharedVideoTitle": "Remover vídeo compartilhado",
"renameBreakoutRoomLabel": "Nome da sala",
"renameBreakoutRoomTitle": "Renomear sala de apoio",
"reservationError": "Erro de sistema de reserva",
"reservationErrorMsg": "Código do erro: {{code}}, mensagem: {{msg}}",
"retry": "Tentar novamente",
@@ -389,9 +417,11 @@
"sendPrivateMessageOk": "Enviar em privado",
"sendPrivateMessageTitle": "Enviar em privado?",
"serviceUnavailable": "Serviço indisponível",
"sessTerminated": "Chamada terminada",
"sessionRestarted": "Chamada reiniciada pelo bridge",
"sessTerminated": "Chamada encerrada",
"sessTerminatedReason": "A chamada foi encerrada",
"sessionRestarted": "Chamada reiniciada devido a um erro de conexão.",
"shareAudio": "Continuar",
"shareAudioAltText": "para compartilhar o conteúdo desejado, acesse \"Aba de navegador\", selecione o conteúdo, ative a caixa de \"compartilhar áudio\" e então clique no botão \"compartilhar\"",
"shareAudioTitle": "Como compartilhar áudio",
"shareAudioWarningD1": "você precisa parar o compartilhamento de tela antes de compartilhar seu áudio.",
"shareAudioWarningD2": "você precisa reiniciar o compartilhamento de tela e selecionar a opção \"compartilhar áudio\".",
@@ -421,7 +451,25 @@
"thankYou": "Obrigado por usar o {{appName}}!",
"token": "token",
"tokenAuthFailed": "Desculpe, você não está autorizado a entrar nesta chamada.",
"tokenAuthFailedReason": {
"audInvalid": "Valor `aud` inválido. Deveria ser `jitsi`.",
"contextNotFound": "O objeto `context` está faltando na carga.",
"expInvalid": "Valor `exp`inválido.",
"featureInvalid": "Recurso inválido: {{feature}}, possivelmente ainda não implementado.",
"featureValueInvalid": "Valor inválido para recurso: {{feature}}.",
"featuresNotFound": "O objeto `features` está faltando na carga.",
"headerNotFound": "Cabeçalho está faltando.",
"issInvalid": "Valor `iss` inválido. Deveria ser `chat`.",
"kidMismatch": "Key ID (kid) não coincide com o sub.",
"kidNotFound": "Key ID (kid) faltando.",
"nbfFuture": "O valor `nbf` está no futuro.",
"nbfInvalid": "Valor `nbf` inválido.",
"payloadNotFound": "Carga faltando.",
"tokenExpired": "O token está expirado."
},
"tokenAuthFailedTitle": "Falha de autenticação",
"tokenAuthFailedWithReasons": "Desculpe, você não pode ingressar nesta chamada. Razões possíveis: {{reason}}",
"tokenAuthUnsupported": "Token da URL não é suportada.",
"transcribing": "Transcrevendo",
"unlockRoom": "Remove a reunião $t(lockRoomPassword)",
"user": "Usuário",
@@ -435,6 +483,10 @@
"viewUpgradeOptions": "Ver opções de atualização",
"viewUpgradeOptionsContent": "Para obter acesso ilimitado a recursos premium tais como gravação, transcrição, streaming RTMP e muito mais, você precisa atualizar seu plano.",
"viewUpgradeOptionsTitle": "Você descobriu um recurso premium!",
"whiteboardLimitContent": "Desculpe, o limite de usuários de quadro-branco simultâneos foi atingido.",
"whiteboardLimitReference": "Para mais informações por favor visite",
"whiteboardLimitReferenceUrl": "nosso website",
"whiteboardLimitTitle": "Restrição no uso do quadro-branco",
"yourEntireScreen": "Toda sua tela"
},
"documentSharing": {
@@ -447,6 +499,9 @@
"title": "Reunião em formato compacto"
},
"feedback": {
"accessibilityLabel": {
"yourChoice": "Sua escolha: {{rating}}"
},
"average": "Média",
"bad": "Ruim",
"detailsLabel": "Nos conte mais sobre isso.",
@@ -507,6 +562,7 @@
"password": "$t(lockRoomPasswordUppercase):",
"reachedLimit": "Você atingiu o limite do seu plano.",
"sip": "endereço SIP",
"sipAudioOnly": "Endereço apenas para áudio SIP",
"title": "Compartilhar",
"tooltip": "Compartilhar link e discagem para esta reunião",
"upgradeOptions": "Por favor, verifique as opções de upgrade em"
@@ -613,13 +669,13 @@
"knockingParticipantList": "Remover lista de participantes",
"lobbyChatStartedNotification": "{{moderator}} iniciou uma conversa na sala de espera com {{attendee}}",
"lobbyChatStartedTitle": "{{moderator}} iniciou uma conversa na sala de espera com você.",
"lobbyClosed": "A sala de espera foi fechada.",
"nameField": "Informe seu nome",
"notificationLobbyAccessDenied": "{{targetParticipantName}} foi rejeitado por {{originParticipantName}}",
"notificationLobbyAccessGranted": "{{targetParticipantName}} foi aceito por {{originParticipantName}}",
"notificationLobbyDisabled": "Sala de espera foi desabilitada por {{originParticipantName}}",
"notificationLobbyEnabled": "Sala de espera foi habilitada por {{originParticipantName}}",
"notificationTitle": "Sala de espera",
"passwordField": "Informe a senha da conferência",
"passwordJoinButton": "Solicitar",
"reject": "Rejeitar",
"rejectAll": "Rejeitar todos",
@@ -651,9 +707,11 @@
"participant": "Participante",
"participantStats": "Estatísticas dos Participantes",
"selectTabTitle": "🎥 Por favor selecione esta aba para gravar",
"sessionToken": "Token de Sessão",
"sessionToken": "Token de sessão",
"start": "Iniciar gravação",
"stop": "Parar a Gravação",
"stop": "Parar a gravação",
"stopping": "Parando a gravação",
"wait": "Por favor aguarde enquanto salvamos sua gravação",
"yes": "Sim"
},
"lockRoomPassword": "senha",
@@ -676,6 +734,7 @@
"dataChannelClosed": "Qualidade do vídeo prejudicada",
"dataChannelClosedDescription": "O canal da ponte foi desconectado, assim a qualidade do vídeo foi limitada a sua configuração mais baixa.",
"disabledIframe": "Incorporação destina-se apenas a fins de demonstração, assim esta chamada será desconectada em {{timeout}} minutos.",
"disabledIframeSecondary": "Incorporação de {{domain}} é apenas destinado para fins de demonstração, então esta chamada será desconectada em {{timeout}} minutos. Por favor use o <a href='{{jaasDomain}}' rel='noopener noreferrer' target='_blank'>Jitsi as a Service</a> para incorporação em produção!",
"disconnected": "desconectado",
"displayNotifications": "Exibir notificações para",
"dontRemindMe": "Não me lembrar",
@@ -722,7 +781,6 @@
"newDeviceCameraTitle": "Nova câmera detectada",
"noiseSuppressionDesktopAudioDescription": "A supressão de ruído não pode ser habilitada enquanto compartilha o áudio da área de trabalho. Por favor desabilite e tente novamente.",
"noiseSuppressionFailedTitle": "Falha ao iniciar a supressão de ruído",
"noiseSuppressionNoTrackDescription": "Por favor ative o microfone antes.",
"noiseSuppressionStereoDescription": "Supressão de ruído de áudio estéreo não é suportado no momento.",
"oldElectronClientDescription1": "Você está usando um versão antiga do cliente Jitsi Meet que possui uma conhecida vulnerabilidade de segurança. Por favor tenha certeza de atulizar para a nossa ",
"oldElectronClientDescription2": "última versão",
@@ -752,7 +810,9 @@
"videoUnmuteBlockedDescription": "A liberação da câmera e compartilhamento de tela foram temporariamente bloqueados devido a limites do sistema.",
"videoUnmuteBlockedTitle": "Câmera e compartilhamento de tela bloqueados!",
"viewLobby": "Ver sala de espera",
"waitingParticipants": "{{waitingParticipants}} pessoas"
"waitingParticipants": "{{waitingParticipants}} pessoas",
"whiteboardLimitDescription": "Por favor, salve seu progresso pois o limite de usuários logo será atingido e o quadro-branco será fechado.",
"whiteboardLimitTitle": "Uso do quadro-branco"
},
"participantsPane": {
"actions": {
@@ -761,6 +821,7 @@
"askUnmute": "Pedir para ativar som",
"audioModeration": "Reativarem seus sons",
"blockEveryoneMicCamera": "Bloquear microfone e câmera de todos",
"breakoutRooms": "Salas de apoio",
"invite": "Convidar alguém",
"moreModerationActions": "Mais opções de moderação",
"moreModerationControls": "Mais controles de moderação",
@@ -937,7 +998,7 @@
"limitNotificationDescriptionNative": "Devido a demanda, sua gravação ficará limitada a {{limit}} minutos. Para gravação ilimitada tente <3>{{app}}</3>.",
"limitNotificationDescriptionWeb": "Devido a demanda, sua gravação ficará limitada a {{limit}} minutos. Para gravação ilimitada tente <a href={{url}} rel='noopener noreferrer' target='_blank'>{{app}}</a>.",
"linkGenerated": "Geramos um link para sua gravação.",
"live": "AOVIVO",
"live": "AO VIVO",
"localRecordingNoNotificationWarning": "A gravação não será anunciada aos outros participantes. Você precisará avisá-los que a reunião está sendo gravada.",
"localRecordingNoVideo": "O vídeo não está sendo gravado",
"localRecordingStartWarning": "Por favor, certifique-se de ter parado a gravação antes de sair da reunião para garantir que será salva.",
@@ -1037,6 +1098,7 @@
"alertOk": "OK",
"alertTitle": "Atenção",
"alertURLText": "A URL digitada do servidor é inválida",
"apply": "Aplicar",
"buildInfoSection": "Informações de compilação",
"conferenceSection": "Conferência",
"disableCallIntegration": "Desativar integração de chamada nativa",
@@ -1047,12 +1109,14 @@
"displayNamePlaceholderText": "Ex: João Silva",
"email": "Email",
"emailPlaceholderText": "email@exemplo.com.br",
"gavatarMessage": "Se seu email está associado com uma conta Gravatar, o usaremos para exibir sua foto de perfil.",
"goTo": "Ir para",
"header": "Configurações",
"help": "Ajuda",
"links": "Links",
"privacy": "Privacidade",
"profileSection": "Perfil",
"sdkVersion": "Versão do SDK",
"serverURL": "URL do servidor",
"showAdvanced": "Mostrar configurações avançadas",
"startCarModeInLowBandwidthMode": "Iniciar modo carro em modo de banda baixa",
@@ -1104,7 +1168,7 @@
"audioOnly": "Alternar para apenas áudio",
"audioRoute": "Selecionar o dispositivo de som",
"boo": "Vaia",
"breakoutRoom": "Entrar/sair da sala de apoio",
"breakoutRooms": "Entrar/sair da sala de apoio",
"callQuality": "Gerenciar qualidade do vídeo",
"carmode": "Modo carro",
"cc": "Alternar legendas",
@@ -1132,7 +1196,7 @@
"hangup": "Sair da chamada",
"heading": "Barra de ferramentas",
"help": "Ajuda",
"hideWhiteboard": "Ocultar quadro branco",
"hideWhiteboard": "Ocultar quadro-branco",
"invite": "Convidar pessoas",
"kick": "Remover participante",
"laugh": "Risada",
@@ -1173,7 +1237,7 @@
"sharedvideo": "Alternar compartilhamento de vídeo",
"shortcuts": "Alternar atalhos",
"show": "Mostrar no palco",
"showWhiteboard": "Exibir quadro branco",
"showWhiteboard": "Exibir quadro-branco",
"silence": "Silenciar",
"speakerStats": "Alternar estatísticas do apresentador",
"stopScreenSharing": "Parar de compartilhar sua tela",
@@ -1218,7 +1282,7 @@
"giphy": "Alternar menu do GIPHY",
"hangup": "Sair",
"help": "Ajuda",
"hideWhiteboard": "Ocultar quadro branco",
"hideWhiteboard": "Ocultar quadro-branco",
"invite": "Convidar pessoas",
"joinBreakoutRoom": "Ingressar na sala de apoio",
"laugh": "Risada",
@@ -1266,7 +1330,7 @@
"shareaudio": "Compartilhar áudio",
"sharedvideo": "Compartilhar um vídeo",
"shortcuts": "Ver atalhos",
"showWhiteboard": "Exibir quadro branco",
"showWhiteboard": "Exibir quadro-branco",
"silence": "Silêncio",
"speakerStats": "Estatísticas do Apresentador",
"startScreenSharing": "Iniciar compart. de tela",
@@ -1371,6 +1435,10 @@
"videomute": "O participante parou a câmera"
},
"virtualBackground": {
"accessibilityLabel": {
"currentBackground": "Fundo atual: {{background}}",
"selectBackground": "Selecionar um fundo"
},
"addBackground": "Adicionar novo fundo",
"apply": "Aplicar",
"backgroundEffectError": "Falha ao aplicar efeito de fundo.",
@@ -1457,7 +1525,7 @@
},
"whiteboard": {
"accessibilityLabel": {
"heading": "Quadro branco"
"heading": "Quadro-branco"
}
}
}

View File

@@ -391,7 +391,7 @@
"serviceUnavailable": "Tjänsten otillgänglig",
"sessTerminated": "Konferensen avslutades",
"sessionRestarted": "Samtal återstartat av bryggan",
"shareAudio": "Forstätt",
"shareAudio": "Fortsätt",
"shareAudioTitle": "Hur man delar ljud",
"shareAudioWarningD1": "Du måste avsluta din skärmdelning innan du kan dela ditt ljud",
"shareAudioWarningD2": "Du måste starta om din skärmdelning och därefter klicka på \"ljuddelning\"",
@@ -427,13 +427,13 @@
"user": "Användare",
"userIdentifier": "Användar-ID",
"userPassword": "Lösenord",
"verifyParticipantConfirm": "Dem matchar",
"verifyParticipantDismiss": "Dem matchar inte",
"verifyParticipantConfirm": "De matchar",
"verifyParticipantDismiss": "De matchar inte",
"verifyParticipantQuestion": "EXPERIMENTELLT: Fråga deltagaren; {{participantName}} om han/hon kan se samma innehåll, i samma ordning.",
"verifyParticipantTitle": "Användarverifikation",
"videoLink": "Videolänk",
"viewUpgradeOptions": "Se uppgraderings alternativ",
"viewUpgradeOptionsContent": "För att få obegränsad tillgång till premiumfunktioner som inspelning, transkriptioner, RTMP -streaming och mer måste du uppgradera din plan.",
"viewUpgradeOptionsContent": "För att få obegränsad tillgång till premiumfunktioner som inspelning, transkriptioner, RTMP-streaming och mer måste du uppgradera din plan.",
"viewUpgradeOptionsTitle": "Du upptäckte en premiumfunktion!",
"yourEntireScreen": "Helskärm"
},
@@ -458,7 +458,7 @@
},
"filmstrip": {
"accessibilityLabel": {
"heading": "Videomineatyrer"
"heading": "Videominiatyrer"
}
},
"giphy": {
@@ -1278,7 +1278,7 @@
"tileViewToggle": "Öppna eller stäng panelvyn",
"toggleCamera": "Byta kamera",
"unmute": "Slå på ljud",
"videoSettings": "Video inställningar",
"videoSettings": "Videoinställningar",
"videomute": "Inaktivera kameran",
"videounmute": "Aktivera kameran"
},
@@ -1346,9 +1346,9 @@
"videothumbnail": {
"connectionInfo": "Anslutningsinformation",
"domute": "Tysta",
"domuteOthers": "Inkativerad ljud för alla andra",
"domuteOthers": "Inaktivera ljud för alla andra",
"domuteVideo": "Inaktivera kamera",
"domuteVideoOfOthers": "Inkativera kamera för alla andra",
"domuteVideoOfOthers": "Inaktivera kamera för alla andra",
"flip": "Vänd",
"grantModerator": "Godkänn moderator",
"hideSelfView": "Dölj självvyn",

View File

@@ -1251,7 +1251,7 @@
"pending": "{{displayName}} davet edildi"
},
"videoStatus": {
"adjustFor": "Ayala:",
"adjustFor": "Ayarla:",
"audioOnly": "SES",
"audioOnlyExpanded": "Yalnızca ses modundasınız. Bu mod bant genişliğinden tasarruf sağlar, ancak başkalarının videolarını göremezsiniz.",
"bestPerformance": "En iyi performans",

View File

@@ -1,7 +1,7 @@
{
"addPeople": {
"accessibilityLabel": {
"meetingLink": "會議連結: {{url}}"
"meetingLink": "會議連結{{url}}"
},
"add": "邀請",
"addContacts": "邀請您的聯絡人",
@@ -16,7 +16,7 @@
"failedToAdd": "加入與會者失敗",
"googleEmail": "Google Email",
"inviteMoreHeader": "目前只有您一個人在會議中",
"inviteMoreMailSubject": "加入{{appName}}會議",
"inviteMoreMailSubject": "加入 {{appName}} 會議",
"inviteMorePrompt": "邀請更多人",
"linkCopied": "已將連結複製至剪貼簿",
"noResults": "沒有符合的搜尋結果",
@@ -29,7 +29,7 @@
"sipAddresses": "SIP 位址",
"telephone": "電話號碼:{{number}}",
"title": "邀請他人至會議",
"yahooEmail": "Yahoo! Email"
"yahooEmail": "Yahoo Email"
},
"audioDevices": {
"bluetooth": "藍牙",
@@ -56,24 +56,29 @@
},
"breakoutRooms": {
"actions": {
"add": "新增討論室",
"autoAssign": "自動分配至討論室",
"add": "新增分組討論室",
"autoAssign": "自動分配至分組討論室",
"close": "關閉",
"join": "加入",
"leaveBreakoutRoom": "離開討論室",
"leaveBreakoutRoom": "離開分組討論室",
"more": "更多",
"remove": "移除",
"rename": "重新命名",
"renameBreakoutRoom": "重新命名討論室",
"renameBreakoutRoom": "重新命名分組討論室",
"sendToBreakoutRoom": "將與會者移至:"
},
"breakoutList": "分組討論室列表",
"buttonLabel": "分組討論室",
"defaultName": "分組討論室 #{{index}}",
"hideParticipantList": "隱藏與會者列表",
"mainRoom": "主會議室",
"notifications": {
"joined": "正在加入「{{name}}」分組討論室",
"joinedMainRoom": "正在加入主會議室",
"joinedTitle": "分組討論室"
}
},
"showParticipantList": "顯示與會者列表",
"title": "分組討論室"
},
"calendarSync": {
"addMeetingURL": "增加會議連結",
@@ -107,11 +112,11 @@
"enter": "加入聊天室",
"error": "錯誤:您的訊息未被傳送。原因:{{error}}",
"fieldPlaceHolder": "在此輸入您的訊息",
"lobbyChatMessageTo": "大廳聊天訊息傳送至{{recipient}}",
"lobbyChatMessageTo": "大廳聊天訊息傳送至 {{recipient}}",
"message": "訊息",
"messageAccessibleTitle": "{{user}}",
"messageAccessibleTitleMe": "",
"messageTo": "傳送私人訊息至{{recipient}}",
"messageAccessibleTitleMe": "",
"messageTo": "傳送私人訊息至 {{recipient}}",
"messagebox": "輸入訊息",
"newMessages": "新訊息",
"nickname": {
@@ -120,7 +125,7 @@
"titleWithPolls": "輸入名稱來使用聊天與投票"
},
"noMessagesMessage": "此會議尚無訊息,在此開始對話聊天!",
"privateNotice": "傳送私人訊息至{{recipient}}",
"privateNotice": "傳送私人訊息至 {{recipient}}",
"sendButton": "傳送",
"smileysPanel": "Emoji 面板",
"tabs": {
@@ -133,7 +138,7 @@
},
"chromeExtensionBanner": {
"buttonText": "安裝 Chrome 擴充功能",
"buttonTextEdge": "安裝 Edge 外掛程式",
"buttonTextEdge": "安裝 Edge 擴充功能",
"close": "關閉",
"dontShowAgain": "不要再問了",
"installExtensionText": "安裝適用於 Google 行事曆及 Office 365 整合的擴充功能"
@@ -151,14 +156,14 @@
"DISCONNECTED": "已斷線",
"DISCONNECTING": "中斷連接中",
"ERROR": "錯誤",
"FETCH_SESSION_ID": "正在取得工作階段ID...",
"GET_SESSION_ID_ERROR": "取得工作階段ID時發生錯誤{{code}}",
"GOT_SESSION_ID": "正在取得工作階段ID...完成",
"LOW_BANDWIDTH": "已關閉{{displayName}}的視訊以節省流量"
"FETCH_SESSION_ID": "正在取得工作階段 ID...",
"GET_SESSION_ID_ERROR": "取得工作階段 ID 時發生錯誤:{{code}}",
"GOT_SESSION_ID": "正在取得工作階段 ID... 完成",
"LOW_BANDWIDTH": "已關閉 {{displayName}} 的視訊以節省頻寬"
},
"connectionindicator": {
"address": "位址:",
"audio_ssrc": "音訊SSRC",
"audio_ssrc": "音訊 SSRC",
"bandwidth": "預估頻寬:",
"bitrate": "連線速率:",
"bridgeCount": "伺服器數量:",
@@ -175,7 +180,7 @@
"more": "顯示更多",
"no": "否",
"packetloss": "封包遺失率:",
"participant_id": "與會者ID",
"participant_id": "與會者 ID",
"quality": {
"good": "良好",
"inactive": "閒置",
@@ -192,7 +197,7 @@
"status": "連線狀態:",
"transport": "傳輸協定:",
"transport_plural": "傳輸:",
"video_ssrc": "視訊SSRC",
"video_ssrc": "視訊 SSRC",
"yes": "是"
},
"dateUtils": {
@@ -201,33 +206,33 @@
"yesterday": "昨天"
},
"deepLinking": {
"appNotInstalled": "您需要在手機上安裝{{app}}行動應用程式才能加入這場會議。",
"description": "什麼事情都沒發生?我們已嘗試在您的{{app}}桌面應用程式開啟會議。請再試一次,或是在{{app}}網路應用程式開啟會議。",
"descriptionNew": "什麼事情都沒發生?我們已嘗試在您的{{app}}桌面應用程式開啟會議。<br /><br />您可以再試一次,或在網頁上啟動。",
"descriptionWithoutWeb": "什麼事情都沒發生?我們已試著將您的會議在桌面應用程式{{app}}中啟動。",
"downloadApp": "下載App",
"downloadMobileApp": "從App Store下載",
"ifDoNotHaveApp": "如果您尚未安裝App",
"ifHaveApp": "如果您已經安裝此App",
"joinInApp": "使用App加入會議",
"joinInAppNew": "在APP中加入",
"appNotInstalled": "您需要在手機上安裝 {{app}} 應用程式才能加入這場會議。",
"description": "什麼事情都沒發生?我們已嘗試在您的 {{app}} 桌面應用程式開啟會議。請再試一次,或是在 {{app}} 網頁應用程式開啟會議。",
"descriptionNew": "什麼事情都沒發生?我們已嘗試在您的 {{app}} 桌面應用程式開啟會議。<br /><br />您可以再試一次,或在網頁上啟動。",
"descriptionWithoutWeb": "什麼事情都沒發生?我們已試著將您的會議在桌面應用程式 {{app}} 中啟動。",
"downloadApp": "下載應用程式",
"downloadMobileApp": "從 App Store 下載",
"ifDoNotHaveApp": "如果您尚未安裝應用程式",
"ifHaveApp": "如果您已經安裝應用程式",
"joinInApp": "使用應用程式加入會議",
"joinInAppNew": "在應用程式中加入",
"joinInBrowser": "在瀏覽器中加入",
"launchMeetingLabel": "您想如何加入此會議?",
"launchWebButton": "在瀏覽器開啟",
"noMobileApp": "您尚未安裝該APP",
"noMobileApp": "您尚未安裝該應用程式",
"termsAndConditions": "繼續操作即表示您同意我們的<a href='{{termsAndConditionsLink}}' rel='noopener noreferrer' target='_blank'>條款與條件。</a>",
"title": "正在{{app}}發起您的會議...",
"titleNew": "正在啟您的會議...",
"title": "正在 {{app}} 開啟您的會議...",
"titleNew": "正在啟您的會議...",
"tryAgainButton": "在桌面上再試一次",
"unsupportedBrowser": "您似乎正在使用我們不支援的瀏覽器"
"unsupportedBrowser": "您似乎正在使用我們不支援的瀏覽器"
},
"defaultLink": "例如{{url}}",
"defaultNickname": "例如:Jane Pink",
"defaultLink": "例如 {{url}}",
"defaultNickname": "例如:王小明",
"deviceError": {
"cameraError": "無法存取您的網路攝影機",
"cameraPermission": "取網路攝影機權限時發生錯誤",
"cameraPermission": "取網路攝影機權限時發生錯誤",
"microphoneError": "無法存取您的麥克風",
"microphonePermission": "取麥克風權限時發生錯誤"
"microphonePermission": "取麥克風權限時發生錯誤"
},
"deviceSelection": {
"hid": {
@@ -239,13 +244,13 @@
"noPermission": "未取得權限",
"previewUnavailable": "無法預覽",
"selectADevice": "選擇裝置",
"testAudio": "播放測試聲音"
"testAudio": "測試"
},
"dialIn": {
"screenTitle": "通話記錄"
},
"dialOut": {
"statusMessage": "現在狀態為{{status}}"
"statusMessage": "現在狀態為 {{status}}"
},
"dialog": {
"Back": "返回",
@@ -256,6 +261,7 @@
"Share": "分享",
"Submit": "送出",
"WaitForHostMsg": "此會議尚未開始,如果您是會議主持人,請進行認證並以主持人身分開始會議。",
"WaitingForHostButton": "等待主持人",
"WaitingForHostTitle": "正在等候主持人加入...",
"Yes": "是",
"accessibilityLabel": {
@@ -269,6 +275,8 @@
"addMeetingNote": "新增此會議的備註",
"addOptionalNote": "新增備註(選填):",
"allow": "允許",
"allowToggleCameraDialog": "您要允許 {{initiatorName}} 切換您的鏡頭朝向嗎?",
"allowToggleCameraTitle": "要允許切換鏡頭嗎?",
"alreadySharedVideoMsg": "其他與會者正在分享影像,同一時間只有一個與會者可以分享影像螢幕。",
"alreadySharedVideoTitle": "同一時間只允許一位影像分享",
"applicationWindow": "應用程式視窗",
@@ -277,14 +285,14 @@
"cameraNotFoundError": "找不到網路攝影機。",
"cameraNotSendingData": "我們無法存取您的網路攝影機,請檢查是否有其他應用程式正在使用這個裝置,並從裝置選單裡選擇其他設備或者重新載入。",
"cameraNotSendingDataTitle": "無法存取網路攝影機",
"cameraPermissionDeniedError": "未取得網路攝影機的存取權,您仍可參加會議,但其他人無法看到。按一下網址列中的「攝影機」圖示 ,然後選取「一律允許」選項。",
"cameraPermissionDeniedError": "未取得網路攝影機的存取權,您仍可參加會議,但其他人無法看到。按一下網址列中的「攝影機」圖示 ,然後選取「一律允許」選項。",
"cameraTimeoutError": "無法啟動視訊裝置,連線逾時!",
"cameraUnknownError": "由於不明原因,無法存取網路攝影機。",
"cameraUnsupportedResolutionError": "您的網路攝影機不支援所需的影像解析度。",
"close": "關閉",
"conferenceDisconnectMsg": "請檢查一下網路連線,將在{{seconds}}秒後重新連接...",
"conferenceDisconnectMsg": "請檢查一下網路連線,將在 {{seconds}} 秒後重新連接...",
"conferenceDisconnectTitle": "您已經被中斷連接。",
"conferenceReloadMsg": "我們正試著修復狀況,將在{{seconds}}秒後重新連接...",
"conferenceReloadMsg": "我們正試著修復狀況,將在 {{seconds}} 秒後重新連接...",
"conferenceReloadTitle": "喔哦!好像有東西壞掉囉。",
"confirm": "確認",
"confirmNo": "否",
@@ -298,7 +306,7 @@
"dismiss": "取消",
"displayNameRequired": "嗨!請問大名?",
"done": "完成",
"e2eeDescription": "請注意端對端加密目前是實驗性功能啟用端對端加密將停用部分伺服器端提供的服務例如透過電話加入會議。另外透過網頁版加入會議還需要使用支援Insertable Streams的瀏覽器。",
"e2eeDescription": "請注意,端對端加密目前是實驗性功能,啟用端對端加密將停用部分伺服器端提供的服務,例如:透過電話加入會議。另外,透過網頁版加入會議還需要使用支援 Insertable Streams 的瀏覽器。",
"e2eeDisabledDueToMaxModeDescription": "由於會議中的人數過多,故無法啟用端對端加密。",
"e2eeLabel": "啟用端對端加密",
"e2eeWarning": "警告:看來此會議中不是每位與會者都啟用了端對端加密,如果您啟用了,他們可能無法看或聽到您。",
@@ -307,7 +315,7 @@
"enterDisplayName": "請在此輸入您自己的名字",
"error": "錯誤",
"gracefulShutdown": "服務目前正在維護中,請稍後再試。",
"grantModeratorDialog": "您確定要授予{{participantName}}主持人權限嗎?",
"grantModeratorDialog": "您確定要授予 {{participantName}} 主持人權限嗎?",
"grantModeratorTitle": "授予主持人權限",
"hide": "隱藏",
"hideShareAudioHelper": "不再顯示",
@@ -315,16 +323,16 @@
"incorrectRoomLockPassword": "密碼不符",
"internalError": "喔哦!出現了點問題,發生錯誤:{{error}}",
"internalErrorTitle": "內部錯誤",
"kickMessage": "您可以聯絡{{participantDisplayName}}取得更詳細資訊。",
"kickMessage": "您可以聯絡 {{participantDisplayName}} 取得更詳細資訊。",
"kickParticipantButton": "移除",
"kickParticipantDialog": "您確定要將這位與會者移除嗎?",
"kickParticipantTitle": "移除這位與會者?",
"kickTitle": "噢!{{participantDisplayName}}將您從會議中移除",
"kickTitle": "噢!{{participantDisplayName}} 將您從會議中移除",
"linkMeeting": "連結會議",
"linkMeetingTitle": "將會議連結至 Salesforce",
"liveStreaming": "直播串流中",
"liveStreamingDisabledBecauseOfActiveRecordingTooltip": "正在錄製,無法使用",
"localUserControls": "本使用者控制",
"localUserControls": "本使用者控制",
"lockMessage": "無法鎖定會議。",
"lockRoom": "新增會議 $t(lockRoomPasswordUppercase)",
"lockTitle": "鎖定失敗",
@@ -346,9 +354,9 @@
"muteEveryoneDialog": "與會者可以隨時解除自己的靜音狀態。",
"muteEveryoneDialogModerationOn": "與會者可以隨時請求發言。",
"muteEveryoneElseDialog": "靜音後,您就不能再解除對方的靜音,但對方可以隨時解除自己的靜音狀態。",
"muteEveryoneElseTitle": "是否要讓除了{{whom}}以外的人靜音?",
"muteEveryoneElseTitle": "是否要讓除了 {{whom}} 以外的人靜音?",
"muteEveryoneElsesVideoDialog": "一旦停用,您就不能再重新開啟對方的網路攝影機,但對方隨時能重新開啟自己的網路攝影機。",
"muteEveryoneElsesVideoTitle": "是否要關閉除了{{whom}}以外的人的網路攝影機?",
"muteEveryoneElsesVideoTitle": "是否要關閉除了 {{whom}} 以外的人的網路攝影機?",
"muteEveryoneSelf": "您自己",
"muteEveryoneStartMuted": "現在所有人皆已靜音",
"muteEveryoneTitle": "要將所有人靜音嗎?",
@@ -364,12 +372,12 @@
"muteParticipantsVideoDialog": "確定要停用這位與會者的網路攝影機?您不能再重新開啟對方的網路攝影機,但他們隨時能重新開啟。",
"muteParticipantsVideoDialogModerationOn": "您確定要關閉此與會者的網路攝影機嗎?您和他都無法再將視訊重新開啟。",
"muteParticipantsVideoTitle": "要關閉此與會者的網路攝影機嗎?",
"noDropboxToken": "沒有有效的 Dropbox token",
"noDropboxToken": "沒有有效的 Dropbox 權杖",
"password": "密碼",
"passwordLabel": "會議已被一位與會者鎖定,請輸入$t(lockRoomPassword)以加入。",
"passwordNotSupported": "尚未支援設定會議$t(lockRoomPassword)。",
"passwordNotSupportedTitle": "尚未支援$t(lockRoomPasswordUppercase)",
"passwordRequired": "需要$t(lockRoomPasswordUppercase)",
"passwordLabel": "會議已被一位與會者鎖定,請輸入 $t(lockRoomPassword) 以加入。",
"passwordNotSupported": "尚未支援設定會議 $t(lockRoomPassword)。",
"passwordNotSupportedTitle": "尚未支援 $t(lockRoomPasswordUppercase)",
"passwordRequired": "需要 $t(lockRoomPasswordUppercase)",
"permissionCameraRequiredError": "參與視訊會議需要存取網路攝影機,請在設定中啟用權限",
"permissionErrorTitle": "需要權限",
"permissionMicRequiredError": "參與音訊會議需要存取麥克風,請在設定中啟用權限",
@@ -378,19 +386,19 @@
"recording": "錄製中",
"recordingDisabledBecauseOfActiveLiveStreamingTooltip": "正在直播時無法使用",
"rejoinNow": "立即重新加入",
"remoteControlAllowedMessage": "{{user}}接受您進行遠端控制的請求!",
"remoteControlDeniedMessage": "{{user}}拒絕您進行遠端控制的請求!",
"remoteControlErrorMessage": "在嘗試向{{user}}請求遠端控制權限時發生錯誤!",
"remoteControlRequestMessage": "您要允許{{user}}遠端控制您的桌面嗎?",
"remoteControlAllowedMessage": "{{user}} 接受您進行遠端控制的請求!",
"remoteControlDeniedMessage": "{{user}} 拒絕您進行遠端控制的請求!",
"remoteControlErrorMessage": "在嘗試向 {{user}} 請求遠端控制權限時發生錯誤!",
"remoteControlRequestMessage": "您要允許 {{user}} 遠端控制您的桌面嗎?",
"remoteControlShareScreenWarning": "請注意:如果按下「允許」您將會分享自己的螢幕!",
"remoteControlStopMessage": "遠端控制會話已結束!",
"remoteControlTitle": "遠端桌面控制",
"remoteUserControls": "{{username}}的遠端使用者控制",
"remoteUserControls": "{{username}} 的遠端使用者控制",
"removePassword": "移除 $t(lockRoomPassword)",
"removeSharedVideoMsg": "您確定要移除您分享的影像嗎?",
"removeSharedVideoTitle": "移除分享的影像",
"renameBreakoutRoomLabel": "討論室名稱",
"renameBreakoutRoomTitle": "重新命名討論室",
"renameBreakoutRoomLabel": "分組討論室名稱",
"renameBreakoutRoomTitle": "重新命名分組討論室",
"reservationError": "預約系統錯誤",
"reservationErrorMsg": "錯誤代碼:{{code}},訊息:{{msg}}",
"retry": "重試",
@@ -410,6 +418,7 @@
"sendPrivateMessageTitle": "私人回覆?",
"serviceUnavailable": "服務無法使用",
"sessTerminated": "通話已經終止",
"sessTerminatedReason": "會議已經終止",
"sessionRestarted": "通話因連線問題重新啟動。",
"shareAudio": "繼續",
"shareAudioTitle": "如何分享音訊",
@@ -438,7 +447,7 @@
"stopRecordingWarning": "確定要停用錄製嗎?",
"stopStreamingWarning": "確定要停止直播串流嗎?",
"streamKey": "直播串流金鑰",
"thankYou": "感謝您使用{{appName}}",
"thankYou": "感謝您使用 {{appName}}",
"token": "token",
"tokenAuthFailed": "抱歉,您未被允許加入這個通話。",
"tokenAuthFailedReason": {
@@ -450,29 +459,33 @@
"featuresNotFound": "`context` 未在負載中找到。",
"headerNotFound": "標頭缺失。",
"issInvalid": "無效的`iss`值,應為`chat`。",
"kidMismatch": "金鑰IDkid與子項不符。",
"kidNotFound": "缺少金鑰IDkid。",
"kidMismatch": "金鑰 IDkid與子項不符。",
"kidNotFound": "缺少金鑰 IDkid。",
"nbfFuture": "`nbf`值在未來。",
"nbfInvalid": "無效的`nbf`值。",
"payloadNotFound": "未找到負載。",
"tokenExpired": "Token已過期。"
"payloadNotFound": "負載缺失。",
"tokenExpired": "權杖已過期。"
},
"tokenAuthFailedTitle": "驗證失敗",
"tokenAuthFailedWithReasons": "抱歉,您無法參加這個通話,可能原因:{{reason}}",
"tokenAuthUnsupported": "不支援的令牌位址。",
"tokenAuthUnsupported": "不支援權杖網址。",
"transcribing": "轉錄中",
"unlockRoom": "移除會議 $t(lockRoomPassword)",
"user": "使用者",
"userIdentifier": "使用者ID",
"userIdentifier": "使用者 ID",
"userPassword": "使用者密碼",
"verifyParticipantConfirm": "符合",
"verifyParticipantDismiss": "不符合",
"verifyParticipantQuestion": "實驗性功能:詢問與會者{{participantName}}是否以相同順序看到相同內容。",
"verifyParticipantQuestion": "實驗性功能:詢問與會者 {{participantName}} 是否以相同順序看到相同內容。",
"verifyParticipantTitle": "使用者驗證",
"videoLink": "影片連結",
"viewUpgradeOptions": "查看升級方案",
"viewUpgradeOptionsContent": "若要不受限制地使用錄製、逐字稿、RTMP 串流等進階版功能,您需要升級您的方案。",
"viewUpgradeOptionsTitle": "您找到了進階版功能!",
"whiteboardLimitContent": "抱歉,已達到白板使用者限制。",
"whiteboardLimitReference": "若要了解詳情,請前往",
"whiteboardLimitReferenceUrl": "我們的網站",
"whiteboardLimitTitle": "白板使用受限",
"yourEntireScreen": "您的整個螢幕"
},
"documentSharing": {
@@ -521,7 +534,7 @@
"copyNumber": "複製號碼",
"country": "國家",
"dialANumber": "若要參加您的會議,請撥打以下其中一支號碼,然後輸入 PIN 碼。",
"dialInConferenceID": "PIN碼",
"dialInConferenceID": "PIN 碼:",
"dialInNotSupported": "抱歉,目前不支援電話撥入。",
"dialInNumber": "撥入:",
"dialInSummaryError": "目前解析撥入資訊錯誤,請稍後再試一次。",
@@ -536,7 +549,7 @@
"inviteTextiOSPersonal": "{{name}}邀請您加入會議。",
"inviteTextiOSPhone": "若要透過電話加入,請使用此號碼:{{number}},,{{conferenceID}}#。如果您需要其他號碼,點擊此連結以檢視完整列表:{{didUrl}}。",
"inviteURLFirstPartGeneral": "您受邀參加會議。",
"inviteURLFirstPartPersonal": "{{name}}正在邀請您加入會議。\n",
"inviteURLFirstPartPersonal": "{{name}} 正在邀請您加入會議。\n",
"inviteURLSecondPart": "\n加入會議\n{{url}}\n",
"label": "撥入資訊",
"liveStreamURL": "直播串流:",
@@ -547,7 +560,8 @@
"numbers": "撥入號碼",
"password": "$t(lockRoomPasswordUppercase)",
"reachedLimit": "您已達到您的方案上限",
"sip": "SIP位址",
"sip": "SIP 位址",
"sipAudioOnly": "SIP 僅音訊位址",
"title": "分享",
"tooltip": "顯示此會議的連結及電話撥入號碼",
"upgradeOptions": "請查看升級選項於"
@@ -566,7 +580,7 @@
"searchPlaceholder": "與會者或電話號碼",
"send": "傳送"
},
"jitsiHome": "{{logo}}商標,首頁連結",
"jitsiHome": "{{logo}} 商標,首頁連結",
"keyboardShortcuts": {
"focusLocal": "聚焦於自己的影像",
"focusRemote": "聚焦於另一人的影像",
@@ -594,11 +608,11 @@
"busyTitle": "全部直播設備正在忙碌",
"changeSignIn": "切換帳號",
"choose": "選擇直播串流",
"chooseCTA": "請選擇直播串流選項,您目前是以{{email}}身份登入。",
"chooseCTA": "請選擇直播串流選項,您目前是以 {{email}} 身份登入。",
"enterStreamKey": "在此輸入您的 YouTube 直播串流金鑰。",
"error": "直播串流失敗,請重試。",
"errorAPI": "在存取您的 YouTube 直播時發生問題,請重新登入。",
"errorLiveStreamNotEnabled": "直播在{{email}}尚未啟用,請開啟直播串流或登入有啟用直播串流的帳號。",
"errorLiveStreamNotEnabled": "直播在 {{email}} 尚未啟用,請開啟直播串流或登入有啟用直播串流的帳號。",
"expandedOff": "直播已停用",
"expandedOn": "會議目前正在 YouTube 上直播。",
"expandedPending": "直播串流正被啟動...",
@@ -607,12 +621,12 @@
"googlePrivacyPolicy": "Google 隱私權政策",
"inProgress": "正在錄製或直播",
"invalidStreamKey": "直播串流金鑰可能不正確。",
"limitNotificationDescriptionNative": "您的最大直播長度將被限制在{{limit}}分鐘,若要不受限的直播,請使用{{app}}。",
"limitNotificationDescriptionWeb": "由於目前流量過大,您的最大直播長度將被限制在{{limit}}分鐘。若要不受限的直播,請使用<a href={{url}} rel='noopener noreferrer' target='_blank'>{{app}}</a>。",
"limitNotificationDescriptionNative": "您的最大直播長度將被限制在 {{limit}} 分鐘,若要不受限的直播,請使用 {{app}}。",
"limitNotificationDescriptionWeb": "由於目前流量過大,您的最大直播長度將被限制在 {{limit}} 分鐘。若要不受限的直播,請使用 <a href={{url}} rel='noopener noreferrer' target='_blank'>{{app}}</a>。",
"off": "直播串流已停用",
"offBy": "{{name}}停用了直播串流",
"offBy": "{{name}} 停用了直播串流",
"on": "直播串流已啟動",
"onBy": "{{name}}啟動了直播串流",
"onBy": "{{name}} 啟動了直播串流",
"pending": "啟動直播串流...",
"serviceName": "直播串流服務",
"sessionAlreadyActive": "已在錄製或直播此工作階段。",
@@ -652,13 +666,13 @@
"knockButton": "請求加入",
"knockTitle": "有人想要加入會議",
"knockingParticipantList": "請求加入的與會者名單",
"lobbyChatStartedNotification": "{{moderator}}{{attendee}}開始在大廳中聊天",
"lobbyChatStartedTitle": "{{moderator}}與您開始在大廳中聊天。",
"lobbyChatStartedNotification": "{{moderator}}{{attendee}} 開始在大廳中聊天",
"lobbyChatStartedTitle": "{{moderator}} 與您開始在大廳中聊天。",
"nameField": "輸入您的名字",
"notificationLobbyAccessDenied": "{{originParticipantName}}拒絕了{{targetParticipantName}}的加入請求",
"notificationLobbyAccessGranted": "{{originParticipantName}}同意了{{targetParticipantName}}的加入請求",
"notificationLobbyDisabled": "{{originParticipantName}}已停用大廳模式",
"notificationLobbyEnabled": "{{originParticipantName}}已啟用大廳模式",
"notificationLobbyAccessDenied": "{{originParticipantName}} 拒絕了 {{targetParticipantName}} 的加入請求",
"notificationLobbyAccessGranted": "{{originParticipantName}} 同意了 {{targetParticipantName}} 的加入請求",
"notificationLobbyDisabled": "{{originParticipantName}} 已停用大廳模式",
"notificationLobbyEnabled": "{{originParticipantName}} 已啟用大廳模式",
"notificationTitle": "大廳",
"passwordField": "輸入會議密碼",
"passwordJoinButton": "加入",
@@ -673,19 +687,19 @@
"on": "開啟",
"unknown": "未知"
},
"dialogTitle": "本錄製控制",
"dialogTitle": "本錄製控制",
"duration": "時長",
"durationNA": "不適用",
"encoding": "編碼中",
"label": "本錄製",
"labelToolTip": "本錄製已啟用",
"localRecording": "本錄製中",
"label": "本錄製",
"labelToolTip": "本錄製已啟用",
"localRecording": "本錄製中",
"me": "我",
"messages": {
"engaged": "已啟用本錄製。",
"engaged": "已啟用本錄製。",
"finished": "錄製會話 {{token}} 已結束,請將傳送錄製檔案至主持人。",
"finishedModerator": "錄製階段{{token}}已完成,本錄製追蹤已存檔,請要求各與會者提供其錄製檔案。",
"notModerator": "您不是主持人,無法開始或停止本錄製。"
"finishedModerator": "錄製階段{{token}} 已完成,本錄製追蹤已存檔,請要求各與會者提供其錄製檔案。",
"notModerator": "您不是主持人,無法開始或停止本錄製。"
},
"moderator": "主持人",
"no": "否",
@@ -713,36 +727,37 @@
"audioUnmuteBlockedDescription": "麥克風解除靜音操作由於系統限制而被暫時封鎖。",
"audioUnmuteBlockedTitle": "麥克風解除靜音遭封鎖!",
"chatMessages": "聊天訊息",
"connectedOneMember": "{{name}}加入了會議",
"connectedThreePlusMembers": "{{name}}與其他人加入了會議",
"connectedTwoMembers": "{{first}}與{{second}}加入了會議",
"connectedOneMember": "{{name}} 加入了會議",
"connectedThreePlusMembers": "{{name}} 與其他人加入了會議",
"connectedTwoMembers": "{{first}} 與{{second}} 加入了會議",
"dataChannelClosed": "視訊品質受限",
"dataChannelClosedDescription": "橋接通道已斷開,視訊品質降至最低設定。",
"disabledIframe": "嵌入僅供示範使用,此通話將於 {{timeout}} 分鐘後中斷連線。",
"disabledIframeSecondary": "內嵌 {{domain}} 僅為展示用途,此通話將在 {{timeout}} 分鐘後中斷連線。請使用在正式環境使用 <a href='{{jaasDomain}}' rel='noopener noreferrer' target='_blank'>Jitsi 服務</a>來內嵌!",
"disconnected": "已經中斷連接",
"displayNotifications": "顯示通知給",
"dontRemindMe": "不要再提醒我",
"focus": "會議焦點",
"focusFail": "{{component}}無法使用 - {{ms}}秒後重試",
"focusFail": "{{component}} 無法使用 - {{ms}} 秒後重試",
"gifsMenu": "GIPHY",
"groupTitle": "通知",
"hostAskedUnmute": "主持人希望發言",
"invitedOneMember": "{{name}}已受邀請",
"invitedThreePlusMembers": "{{name}}{{count}}位人員已受邀請",
"invitedTwoMembers": "{{first}}{{second}}已受邀請",
"hostAskedUnmute": "主持人希望發言",
"invitedOneMember": "{{name}} 已受邀請",
"invitedThreePlusMembers": "{{name}}{{count}} 位人員已受邀請",
"invitedTwoMembers": "{{first}}{{second}} 已受邀請",
"joinMeeting": "加入",
"kickParticipant": "{{kicked}}已被{{kicker}}移除會議",
"leftOneMember": "{{name}}已離開會議",
"leftThreePlusMembers": "{{name}}與其他人已離開會議",
"leftTwoMembers": "{{first}}{{second}}已離開會議",
"kickParticipant": "{{kicked}} 已被 {{kicker}} 移除會議",
"leftOneMember": "{{name}} 已離開會議",
"leftThreePlusMembers": "{{name}} 與其他人已離開會議",
"leftTwoMembers": "{{first}}{{second}} 已離開會議",
"linkToSalesforce": "連結至 Salesforce",
"linkToSalesforceDescription": "您可以將會議摘要連結至 Salesforce 物件。",
"linkToSalesforceError": "無法將會議連結至 Salesforce",
"linkToSalesforceKey": "連結此會議",
"linkToSalesforceProgress": "正在將會議連結至 Salesforce...",
"linkToSalesforceSuccess": "會議已連結至 Salesforce",
"localRecordingStarted": "{{name}}已啟用本錄製",
"localRecordingStopped": "{{name}}已停用本錄製",
"localRecordingStarted": "{{name}} 已啟用本錄製",
"localRecordingStopped": "{{name}} 已停用本錄製",
"me": "我",
"moderationInEffectCSDescription": "若要分享您的螢幕,請舉手",
"moderationInEffectCSTitle": "分享螢幕已被主持人停用",
@@ -754,11 +769,11 @@
"moderationRequestFromParticipant": "想要發言",
"moderationStartedTitle": "開始主持",
"moderationStoppedTitle": "停止主持",
"moderationToggleDescription": "由{{participantDisplayName}}",
"moderationToggleDescription": "由 {{participantDisplayName}}",
"moderator": "主持人權限已經取得!",
"muted": "您已經啟動通話,處於靜音。",
"mutedRemotelyDescription": "當您準備好要發言,隨時可以取消靜音。當您結束之後再回復成靜音,保持會議安靜。",
"mutedRemotelyTitle": "您已經被{{participantDisplayName}}設為靜音!",
"mutedRemotelyTitle": "您已經被 {{participantDisplayName}} 設為靜音!",
"mutedTitle": "您目前處於靜音!",
"newDeviceAction": "使用",
"newDeviceAudioTitle": "偵測到新的音效裝置",
@@ -771,11 +786,11 @@
"oldElectronClientDescription3": "",
"participantWantsToJoin": "希望加入會議",
"participantsWantToJoin": "希望加入會議",
"passwordRemovedRemotely": "$t(lockRoomPasswordUppercase)已被其他與會者移除",
"passwordSetRemotely": "$t(lockRoomPasswordUppercase)由其他與會者設定",
"passwordRemovedRemotely": "$t(lockRoomPasswordUppercase) 已被其他與會者移除",
"passwordSetRemotely": "$t(lockRoomPasswordUppercase) 由其他與會者設定",
"raiseHandAction": "舉手發言",
"raisedHand": "{{name}}想要發言。",
"raisedHands": "{{participantName}}與其他{{raisedHands}}人",
"raisedHands": "{{participantName}} 與其他 {{raisedHands}} 人",
"reactionSounds": "停用音效",
"reactionSoundsForAll": "停用所有音效",
"screenShareNoAudio": "您未在選擇視窗時勾選分享音訊",
@@ -790,11 +805,13 @@
"suboptimalExperienceTitle": "瀏覽器警告",
"unmute": "取消靜音",
"videoMutedRemotelyDescription": "您隨時可以再次啟用。",
"videoMutedRemotelyTitle": "您的視訊已被{{participantDisplayName}}停用",
"videoMutedRemotelyTitle": "您的視訊已被 {{participantDisplayName}} 停用",
"videoUnmuteBlockedDescription": "啟用網路攝影機與分享螢幕由於系統限制而被暫時封鎖。",
"videoUnmuteBlockedTitle": "啟用網路攝影機與分享螢幕遭封鎖!",
"viewLobby": "檢視大廳",
"waitingParticipants": "{{waitingParticipants}}人"
"waitingParticipants": "{{waitingParticipants}} 人",
"whiteboardLimitDescription": "由於即將超出使用者限制,白板將關閉,請儲存您的進度。",
"whiteboardLimitTitle": "白板使用情況"
},
"participantsPane": {
"actions": {
@@ -803,6 +820,7 @@
"askUnmute": "要求解除靜音",
"audioModeration": "自我解除靜音",
"blockEveryoneMicCamera": "停用所有人的麥克風和網路攝影機",
"breakoutRooms": "分組討論室",
"invite": "邀請他人",
"moreModerationActions": "更多主持人選項",
"moreModerationControls": "更多主持人操作",
@@ -817,15 +835,15 @@
},
"close": "關閉",
"headings": {
"lobby": "大廳({{count}}人)",
"participantsList": "會議與會者({{count}}人)",
"visitors": "訪客({{count}}人)",
"waitingLobby": "於大廳等候({{count}}人)"
"lobby": "大廳({{count}} 人)",
"participantsList": "會議與會者({{count}} 人)",
"visitors": "訪客({{count}} 人)",
"waitingLobby": "於大廳等候({{count}} 人)"
},
"search": "搜尋與會者",
"title": "與會者"
},
"passwordDigitsOnly": "上限為{{number}}位數",
"passwordDigitsOnly": "上限為 {{number}} 位數",
"passwordSetRemotely": "由其他與會者設定",
"pinParticipant": "{{participantName}} - 釘選",
"pinnedParticipant": "與會者被釘選",
@@ -834,13 +852,13 @@
"skip": "跳過",
"submit": "送出"
},
"by": "由{{ name }}",
"by": "由 {{ name }}",
"create": {
"addOption": "新增選項",
"answerPlaceholder": "選項{{index}}",
"answerPlaceholder": "選項 {{index}}",
"cancel": "取消",
"create": "建立投票",
"pollOption": "選項{{index}}",
"pollOption": "選項 {{index}}",
"pollQuestion": "投票問題",
"questionPlaceholder": "詢問問題",
"removeOption": "移除選項",
@@ -879,7 +897,7 @@
"audioHighQuality": "您的音訊品質極佳。",
"audioLowNoVideo": "您的音訊品質較差,且無視訊功能。",
"goodQuality": "太好了!您的媒體品質良好。",
"noMediaConnectivity": "我們無法為此測試建立媒體連線通常是防火牆或NAT的問題。",
"noMediaConnectivity": "我們無法為此測試建立媒體連線,通常是防火牆或 NAT 的問題。",
"noVideo": "您的視訊畫質將會很糟糕。",
"undetectable": "如果您仍無法在瀏覽器中進行通話,我們建議您檢查喇叭、麥克風、及網路攝影機的設置,確認是否允許瀏覽器存取麥克風及網路攝影機,並將瀏覽器更新到最新版本。如果以上步驟無法解決問題,請聯絡網頁程式的開發者。",
"veryPoorConnection": "您的通話品質將會非常糟糕。",
@@ -958,8 +976,8 @@
},
"recording": {
"authDropboxText": "上傳至 Dropbox",
"availableSpace": "可用空間:{{spaceLeft}}MB錄製時間大約{{duration}}分鐘)",
"beta": "BETA",
"availableSpace": "可用空間:{{spaceLeft}} MB錄製時間大約 {{duration}} 分鐘)",
"beta": "測試版",
"busy": "我們正在釋放錄製資源,請過幾分鐘後再試。",
"busyTitle": "全部錄製目前忙碌",
"copyLink": "複製連結",
@@ -976,15 +994,15 @@
"highlightMomentSuccess": "已精選的時刻",
"highlightMomentSucessDescription": "您的精選時刻將新增至會議摘要。",
"inProgress": "正在錄製或直播",
"limitNotificationDescriptionNative": "由於目前流量過大,您的錄製時間被限制在{{limit}}分鐘。若要無限制的錄製,請試試 <3>{{app}}</3>。",
"limitNotificationDescriptionWeb": "由於目前流量過大,您的錄製時間被限制在{{limit}}分鐘。若要無限制的錄製,請試試 <a href={{url}}rel='noopener noreferrer' target='_blank'>{{app}}</a>。",
"limitNotificationDescriptionNative": "由於目前流量過大,您的錄製時間被限制在 {{limit}} 分鐘。若要無限制的錄製,請試試 <3>{{app}}</3>。",
"limitNotificationDescriptionWeb": "由於目前流量過大,您的錄製時間被限制在 {{limit}} 分鐘。若要無限制的錄製,請試試 <a href={{url}}rel='noopener noreferrer' target='_blank'>{{app}}</a>。",
"linkGenerated": "我們建立了您的錄製檔案的連結。",
"live": "直播",
"localRecordingNoNotificationWarning": "系統不會主動知會與會者錄製已開啟,主持人需另行通知。",
"localRecordingNoVideo": "沒有錄製的視訊",
"localRecordingStartWarning": "請確保在退出會議之前停用錄製以便保存。",
"localRecordingStartWarningTitle": "停用錄製以保存",
"localRecordingVideoStop": "關閉您的視訊也將停止本錄製,確定繼續嗎?",
"localRecordingVideoStop": "關閉您的視訊也將停止本錄製,確定繼續嗎?",
"localRecordingVideoWarning": "錄製視訊必須在開始時啟用",
"localRecordingWarning": "確保選擇目前的分頁以錄製正確的視訊和音訊。錄製目前限制為1GB約可錄製100分鐘。",
"loggedIn": "以 {{userName}} 登入",
@@ -997,7 +1015,7 @@
"onlyRecordSelf": "僅錄製我的音訊和影片串流",
"pending": "正在準備錄製會議...",
"rec": "錄製中",
"saveLocalRecording": "將錄製檔案保存在本BETA",
"saveLocalRecording": "將錄製檔案保存在本機(測試版",
"serviceDescription": "您的錄製會由錄製服務儲存",
"serviceDescriptionCloud": "雲端錄製",
"serviceDescriptionCloudInfo": "已錄製的會議將在 24 小時後自動清除。",
@@ -1007,19 +1025,19 @@
"signOut": "登出",
"surfaceError": "請選擇目前分頁",
"title": "錄製中",
"unavailable": "喔哦!{{serviceName}}目前無法使用,我們正在解決此問題,請稍後再試。",
"unavailable": "喔哦!{{serviceName}} 目前無法使用,我們正在解決此問題,請稍後再試。",
"unavailableTitle": "錄製無法使用",
"uploadToCloud": "上傳至雲端"
},
"screenshareDisplayName": "{{name}}的螢幕",
"screenshareDisplayName": "{{name}} 的螢幕",
"sectionList": {
"pullToRefresh": "下拉以重新整理"
},
"security": {
"about": "您可以新增$t(lockRoomPassword)至您的會議,與會者在加入會議前必須先輸入$t(lockRoomPassword)。",
"aboutReadOnly": "主持人可以新增$t(lockRoomPassword)至會議,與會者在加入會議前必須先輸入$t(lockRoomPassword)。",
"insecureRoomNameWarningNative": "房間名稱不安全,任何人都可能會加入您的會議。{{recommendAction}} 了解有關保護您的會議的更多信息。",
"insecureRoomNameWarningWeb": "房間名稱不安全,任何人都可能會加入您的會議。{{recommendAction}} 在此處了解有關保護您的會議的更多信息 <a href=\"{{securityUrl}}\" rel=\"security\" target=\"_blank\">這裡</a>。",
"about": "您可以新增 $t(lockRoomPassword) 至您的會議,與會者在加入會議前必須先輸入$t(lockRoomPassword)。",
"aboutReadOnly": "主持人可以新增 $t(lockRoomPassword) 至會議,與會者在加入會議前必須先輸入$t(lockRoomPassword)。",
"insecureRoomNameWarningNative": "房間名稱不安全,任何人都可能會加入您的會議。{{recommendAction}} 了解有關保護您的會議的更多資訊。",
"insecureRoomNameWarningWeb": "房間名稱不安全,任何人都可能會加入您的會議。{{recommendAction}} 在此處了解有關保護您的會議的更多資訊 <a href=\"{{securityUrl}}\" rel=\"security\" target=\"_blank\">這裡</a>。",
"title": "安全性選項",
"unsafeRoomActions": {
"meeting": "請考慮使用安全按鈕保護您的會議。",
@@ -1031,10 +1049,10 @@
"audio": "音訊",
"buttonLabel": "設定",
"calendar": {
"about": "{{appName}}行事曆整合功能可安全地存取您行事曆中即將舉行的活動。",
"about": "{{appName}} 行事曆整合功能可安全地存取您行事曆中即將舉行的活動。",
"disconnect": "中斷連接",
"microsoftSignIn": "使用Microsoft帳號登入",
"signedIn": "目前正在存取{{email}}的行事曆事件,點按下方中斷連接可以停用存取行事曆事件。",
"microsoftSignIn": "使用 Microsoft 帳號登入",
"signedIn": "目前正在存取 {{email}} 的行事曆事件,點按下方中斷連接可以停用存取行事曆事件。",
"title": "行事曆"
},
"desktopShareFramerate": "桌面螢幕分享影格率",
@@ -1079,6 +1097,7 @@
"alertOk": "確定",
"alertTitle": "警告",
"alertURLText": "輸入的伺服器網址無效",
"apply": "套用",
"buildInfoSection": "組建資訊",
"conferenceSection": "會議",
"disableCallIntegration": "停用原生通話整合",
@@ -1086,23 +1105,24 @@
"disableCrashReportingWarning": "您確定要停用錯誤回報功能嗎?變更將在重啟應用程式後生效。",
"disableP2P": "停用點對點模式",
"displayName": "顯示名稱",
"displayNamePlaceholderText": "例如:John Doe",
"displayNamePlaceholderText": "例如:王小明",
"email": "電子郵件",
"emailPlaceholderText": "email@example.com",
"gavatarMessage": "如果您的電子郵件地址與 Gravatar 帳號相關聯,我們會使用 Gravatar 上的個人檔案大頭貼。",
"goTo": "前往",
"header": "設定",
"help": "協助",
"links": "連結",
"privacy": "隱私權",
"profileSection": "簡介",
"sdkVersion": "SDK版本",
"sdkVersion": "SDK 版本",
"serverURL": "伺服器網址",
"showAdvanced": "顯示進階設定",
"startCarModeInLowBandwidthMode": "同時啟用行車模式與低頻寬模式",
"startWithAudioMuted": "啟動並靜音",
"startWithVideoMuted": "啟動並關閉影像",
"terms": "條款",
"version": "APP版本"
"version": "應用程式版本"
},
"share": {
"dialInfoText": "\n\n=====\n\n只想要透過手機撥打加入嗎\n\n撥打{{defaultDialInNumber}}或點此連結來查看此會議的電話撥入號碼\n{{dialInfoPageUrl}}",
@@ -1146,7 +1166,7 @@
"Settings": "切換設定",
"audioOnly": "切換僅音訊",
"audioRoute": "選擇音訊裝置",
"boo": "倒彩",
"boo": "倒彩",
"breakoutRoom": "進入/離開分組討論室",
"callQuality": "管理視訊品質",
"carmode": "行車模式",
@@ -1160,7 +1180,7 @@
"document": "切換檔案分享",
"documentClose": "關閉檔案分享",
"documentOpen": "打開檔案分享",
"download": "下載我們的APP",
"download": "下載我們的應用程式",
"embedMeeting": "嵌入會議",
"endConference": "結束會議(所有人)",
"enterFullScreen": "進入全螢幕",
@@ -1183,7 +1203,7 @@
"like": "比讚",
"linkToSalesforce": "連結至 Salesforce",
"lobbyButton": "啟用/停用大廳模式",
"localRecording": "切換本錄製控制",
"localRecording": "切換本錄製控制",
"lockRoom": "切換會議密碼",
"lowerHand": "放下手",
"moreActions": "更多動作",
@@ -1199,7 +1219,7 @@
"openChat": "打開聊天",
"participants": "打開與會者窗格",
"pip": "切換子母螢幕模式",
"privateMessage": "送私人訊息",
"privateMessage": "送私人訊息",
"profile": "編輯您的個人檔案",
"raiseHand": "舉手",
"reactions": "反應",
@@ -1237,7 +1257,7 @@
"audioRoute": "選擇音訊裝置",
"audioSettings": "音訊設定",
"authenticate": "驗證",
"boo": "倒彩",
"boo": "倒彩",
"callQuality": "管理影像品質",
"chat": "開啟/關閉聊天欄",
"clap": "鼓掌",
@@ -1248,7 +1268,7 @@
"disableReactionSounds": "您可以停用此會議的反應音效",
"documentClose": "關閉分享檔案欄",
"documentOpen": "開啟分享檔案欄",
"download": "下載我們的APP",
"download": "下載我們的應用程式",
"e2ee": "端對端加密",
"embedMeeting": "嵌入會議",
"enableNoiseSuppression": "開啟雜訊抑制",
@@ -1273,7 +1293,7 @@
"lobbyButtonEnable": "啟用大廳模式",
"login": "登入",
"logout": "登出",
"lowerYourHand": "放下的手",
"lowerYourHand": "放下的手",
"moreActions": "更多動作",
"moreOptions": "更多選項",
"mute": "靜音/解除靜音",
@@ -1294,9 +1314,9 @@
"pip": "進入子母螢幕模式",
"privateMessage": "傳送私人訊息",
"profile": "編輯您的個人資料",
"raiseHand": "舉起/放下的手",
"raiseHand": "舉起/放下的手",
"raiseYourHand": "舉手",
"reactionBoo": "傳送倒彩反應",
"reactionBoo": "傳送倒彩反應",
"reactionClap": "傳送鼓掌反應",
"reactionLaugh": "傳送大笑反應",
"reactionLike": "傳送比讚反應",
@@ -1336,7 +1356,7 @@
"labelToolTip": "此會議正在轉錄",
"off": "轉錄已停用",
"pending": "準備轉錄會議...",
"sourceLanguageDesc": "會議語言目前設定為<b>{{sourceLanguage}}</b><br/>您可以在這裡",
"sourceLanguageDesc": "會議語言目前設定為 <b>{{sourceLanguage}}</b><br/> 您可以在這裡",
"sourceLanguageHere": "修改",
"start": "開始顯示字幕",
"stop": "停用顯示字幕",
@@ -1360,12 +1380,12 @@
"videoSIPGW": {
"busy": "我們正在釋放資源,請過幾分鐘後再試。",
"busyTitle": "會議室服務目前忙碌中",
"errorAlreadyInvited": "{{displayName}}已經受邀",
"errorAlreadyInvited": "{{displayName}} 已經受邀",
"errorInvite": "會議尚未開始,請稍候再試。",
"errorInviteFailed": "我們正在努力解決這個問題,請稍後再試。",
"errorInviteFailedTitle": "邀請{{displayName}}失敗",
"errorInviteFailedTitle": "邀請 {{displayName}} 失敗",
"errorInviteTitle": "會議室邀請錯誤",
"pending": "已向{{displayName}}送邀請"
"pending": "已向 {{displayName}}送邀請"
},
"videoStatus": {
"adjustFor": "調整為:",
@@ -1415,7 +1435,7 @@
},
"virtualBackground": {
"accessibilityLabel": {
"currentBackground": "前背景:{{background}}",
"currentBackground": "前背景:{{background}}",
"selectBackground": "選擇背景"
},
"addBackground": "新增背景",
@@ -1438,8 +1458,8 @@
"slightBlur": "輕微模糊",
"title": "虛擬背景",
"uploadedImage": "已上傳的圖片 {{index}}",
"webAssemblyWarning": "不支援WebAssembly",
"webAssemblyWarningDescription": "WebAssembly已停用或不受此瀏覽器支援"
"webAssemblyWarning": "不支援 WebAssembly",
"webAssemblyWarningDescription": "WebAssembly 已停用或不受此瀏覽器支援"
},
"visitors": {
"chatIndicator": "(訪客)",
@@ -1456,14 +1476,14 @@
"roomname": "輸入會議室名稱"
},
"addMeetingName": "新增會議名稱",
"appDescription": "來吧,和您的整個團隊進行視訊會議。不,邀請所有您認識的人進行視訊會議。{{app}}是一套完全加密、100% 開放始碼的視訊會議解決方案。無需註冊帳號,無時無刻不分日夜均可免費使用。",
"appDescription": "來吧,和您的整個團隊進行視訊會議。不,邀請所有您認識的人進行視訊會議。{{app}} 是一套完全加密、100% 開放始碼的視訊會議解決方案。無需註冊帳號,無時無刻不分日夜均可免費使用。",
"audioVideoSwitch": {
"audio": "音訊",
"video": "視訊"
},
"calendar": "行事曆",
"connectCalendarButton": "連接您的行事曆",
"connectCalendarText": "連接您的行事曆來查看在{{app}}中的會議。此外,增加{{provider}}的會議至自己的行事曆,只要點按一下即可啟動。",
"connectCalendarText": "連接您的行事曆來查看在 {{app}} 中的會議。此外,增加 {{provider}} 的會議至自己的行事曆,只要點按一下即可啟動。",
"enterRoomTitle": "啟動新的會議",
"getHelp": "取得協助",
"go": "開始",
@@ -1482,25 +1502,25 @@
"policyLogo": "政策圖示"
},
"meetingsAccessibilityLabel": "會議",
"mobileDownLoadLinkAndroid": "下載 Android 版本的手機應用程式",
"mobileDownLoadLinkFDroid": "前往 F-Droid 下載 Android 版本的手機應用程式",
"mobileDownLoadLinkIos": "下載 iOS 版本的手機應用程式",
"mobileDownLoadLinkAndroid": "下載 Android 版本的應用程式",
"mobileDownLoadLinkFDroid": "前往 F-Droid 下載 Android 版本的應用程式",
"mobileDownLoadLinkIos": "下載 iOS 版本的應用程式",
"moderatedMessage": "或以主持人身份<a href=\"{{url}}\" rel=\"noopener noreferrer\" target=\"_blank\">預先建立會議</a>。",
"privacy": "隱私權",
"recentList": "最近使用",
"recentList": "近期",
"recentListDelete": "刪除",
"recentListEmpty": "目前最近使用是空白的,與您的團隊成員聊天,即在此處找到最近使用過的會議。",
"recentMeetings": "您的最近會議",
"recentListEmpty": "您的近期列表目前是空白的,與您的團隊成員聊天,即在此處找到最近參與過的會議。",
"recentMeetings": "您近期的會議",
"reducedUIText": "歡迎使用{{app}}",
"roomNameAllowedChars": "會議室名稱不應包含以下字元:? & : ' \" % #",
"roomNameAllowedChars": "會議室名稱不應包含以下字元:?、&、:、'、\"、%、#。",
"roomname": "輸入會議室名稱",
"roomnameHint": "請輸入您想加入的會議室名稱或網址,您可以用一個名稱來建立會議室,只要其他人輸入相同的名稱就能加入會議室。",
"roomnameHint": "請輸入您想加入的會議室名稱或網址,您可以用一個名稱來建立會議室,只要其他人輸入相同的名稱就能加入會議室。",
"sendFeedback": "傳送回饋",
"settings": "設定",
"startMeeting": "開始會議",
"terms": "條款",
"title": "安全、功能齊全、完全免費的視訊會議",
"upcomingMeetings": "您即將的會議"
"upcomingMeetings": "您即將開始的會議"
},
"whiteboard": {
"accessibilityLabel": {

View File

@@ -67,13 +67,18 @@
"renameBreakoutRoom": "Rename breakout room",
"sendToBreakoutRoom": "Send participant to:"
},
"breakoutList": "Breakout list",
"buttonLabel": "Breakout rooms",
"defaultName": "Breakout room #{{index}}",
"hideParticipantList": "Hide participant list",
"mainRoom": "Main room",
"notifications": {
"joined": "Joining the \"{{name}}\" breakout room",
"joinedMainRoom": "Joining the main room",
"joinedTitle": "Breakout Rooms"
}
},
"showParticipantList": "Show participant list",
"title": "Breakout Rooms"
},
"calendarSync": {
"addMeetingURL": "Add a meeting link",
@@ -416,6 +421,7 @@
"sessTerminatedReason": "The meeting has been terminated",
"sessionRestarted": "Call restarted because of a connection issue.",
"shareAudio": "Continue",
"shareAudioAltText": "to share the desired content, navigate to \"Browser Tab\", select the content, activate the \"share audio\" check mark and then click \"share\" button",
"shareAudioTitle": "How to share audio",
"shareAudioWarningD1": "you need to stop screen sharing before sharing your audio.",
"shareAudioWarningD2": "you need to restart your screen sharing and check the \"share audio\" option.",
@@ -477,6 +483,10 @@
"viewUpgradeOptions": "View upgrade options",
"viewUpgradeOptionsContent": "To get unlimited access to premium features like recording, transcriptions, RTMP Streaming & more, you'll need to upgrade your plan.",
"viewUpgradeOptionsTitle": "You discovered a premium feature!",
"whiteboardLimitContent": "Sorry, the limit of conccurent whiteboard users has been reached.",
"whiteboardLimitReference": "For more information please visit",
"whiteboardLimitReferenceUrl": "our website",
"whiteboardLimitTitle": "Whiteboard usage restricted",
"yourEntireScreen": "Your entire screen"
},
"documentSharing": {
@@ -724,6 +734,7 @@
"dataChannelClosed": "Video quality impaired",
"dataChannelClosedDescription": "The bridge channel has been disconnected and thus video quality is limited to its lowest setting.",
"disabledIframe": "Embedding is only meant for demo purposes, so this call will disconnect in {{timeout}} minutes.",
"disabledIframeSecondary": "Embedding {{domain}} is only meant for demo purposes, so this call will disconnect in {{timeout}} minutes. Please use <a href='{{jaasDomain}}' rel='noopener noreferrer' target='_blank'>Jitsi as a Service</a> for production embedding!",
"disconnected": "disconnected",
"displayNotifications": "Display notifications for",
"dontRemindMe": "Do not remind me",
@@ -799,7 +810,9 @@
"videoUnmuteBlockedDescription": "Camera unmute and desktop sharing operation have been temporarily blocked because of system limits.",
"videoUnmuteBlockedTitle": "Camera unmute and desktop sharing blocked!",
"viewLobby": "View lobby",
"waitingParticipants": "{{waitingParticipants}} people"
"waitingParticipants": "{{waitingParticipants}} people",
"whiteboardLimitDescription": "Please save your progress, as the user limit will soon be reached and the whiteboard will close.",
"whiteboardLimitTitle": "Whiteboard usage"
},
"participantsPane": {
"actions": {
@@ -808,6 +821,7 @@
"askUnmute": "Ask to unmute",
"audioModeration": "Unmute themselves",
"blockEveryoneMicCamera": "Block everyone's mic and camera",
"breakoutRooms": "Breakout rooms",
"invite": "Invite Someone",
"moreModerationActions": "More moderation options",
"moreModerationControls": "More moderation controls",
@@ -1154,7 +1168,7 @@
"audioOnly": "Toggle audio only",
"audioRoute": "Select the sound device",
"boo": "Boo",
"breakoutRoom": "Join/leave breakout room",
"breakoutRooms": "Breakout rooms",
"callQuality": "Manage video quality",
"carmode": "Car Mode",
"cc": "Toggle subtitles",

View File

@@ -244,8 +244,6 @@ function initCommands() {
}
},
'pin-participant': (id, videoType) => {
logger.debug('Pin participant command received');
const state = APP.store.getState();
// if id not provided, unpin everybody.
@@ -303,7 +301,6 @@ function initCommands() {
APP.store.dispatch(removeBreakoutRoom(breakoutRoomJid));
},
'resize-large-video': (width, height) => {
logger.debug('Resize large video command received');
sendAnalytics(createApiEvent('largevideo.resized'));
APP.store.dispatch(resizeLargeVideo(width, height));
},
@@ -324,7 +321,6 @@ function initCommands() {
APP.store.dispatch(setAssumedBandwidthBps(value));
},
'set-follow-me': value => {
logger.debug('Set follow me command received');
if (value) {
sendAnalytics(createApiEvent('follow.me.set'));
@@ -335,7 +331,6 @@ function initCommands() {
APP.store.dispatch(setFollowMe(value));
},
'set-large-video-participant': (participantId, videoType) => {
logger.debug('Set large video participant command received');
const { getState, dispatch } = APP.store;
if (!participantId) {
@@ -373,12 +368,10 @@ function initCommands() {
},
'toggle-audio': () => {
sendAnalytics(createApiEvent('toggle-audio'));
logger.log('Audio toggle: API command received');
APP.conference.toggleAudioMuted(false /* no UI */);
},
'toggle-video': () => {
sendAnalytics(createApiEvent('toggle-video'));
logger.log('Video toggle: API command received');
APP.conference.toggleVideoMuted(false /* no UI */, true /* ensure track */);
},
'toggle-film-strip': () => {
@@ -497,7 +490,6 @@ function initCommands() {
APP.conference.changeLocalAvatarUrl(avatarUrl);
},
'send-chat-message': (message, to, ignorePrivacy = false) => {
logger.debug('Send chat message command received');
if (to) {
const participant = getParticipantById(APP.store.getState(), to);
@@ -515,7 +507,6 @@ function initCommands() {
APP.store.dispatch(sendMessage(message, ignorePrivacy));
},
'send-endpoint-text-message': (to, text) => {
logger.debug('Send endpoint message command received');
try {
APP.conference.sendEndpointMessage(to, {
name: ENDPOINT_TEXT_MESSAGE_NAME,
@@ -538,25 +529,19 @@ function initCommands() {
});
},
'overwrite-names': participantList => {
logger.debug('Overwrite names command received');
APP.store.dispatch(overwriteParticipantsNames(participantList));
},
'toggle-e2ee': enabled => {
logger.debug('Toggle E2EE key command received');
APP.store.dispatch(toggleE2EE(enabled));
},
'set-media-encryption-key': keyInfo => {
APP.store.dispatch(setMediaEncryptionKey(JSON.parse(keyInfo)));
},
'set-video-quality': frameHeight => {
logger.debug('Set video quality command received');
sendAnalytics(createApiEvent('set.video.quality'));
APP.store.dispatch(setVideoQuality(frameHeight));
},
'start-share-video': url => {
logger.debug('Share video command received');
sendAnalytics(createApiEvent('share.video.start'));
const id = extractYoutubeIdOrURL(url);
@@ -564,9 +549,7 @@ function initCommands() {
APP.store.dispatch(playSharedVideo(id));
}
},
'stop-share-video': () => {
logger.debug('Share video command received');
sendAnalytics(createApiEvent('share.video.stop'));
APP.store.dispatch(stopSharedVideo());
},
@@ -641,6 +624,7 @@ function initCommands() {
* Only applies to certain jitsi meet deploys.
* @param { string } arg.youtubeStreamKey - The youtube stream key.
* @param { string } arg.youtubeBroadcastID - The youtube broadcast ID.
* @param { Object } arg.extraMetadata - Any extra metadata params for file recording.
* @returns {void}
*/
'start-recording': ({
@@ -651,7 +635,8 @@ function initCommands() {
rtmpStreamKey,
rtmpBroadcastID,
youtubeStreamKey,
youtubeBroadcastID
youtubeBroadcastID,
extraMetadata = {}
}) => {
const state = APP.store.getState();
const conference = getCurrentConference(state);
@@ -701,6 +686,7 @@ function initCommands() {
mode: JitsiRecordingConstants.mode.FILE,
appData: JSON.stringify({
'file_recording_metadata': {
...extraMetadata,
'upload_credentials': {
'service_name': RECORDING_TYPES.DROPBOX,
'token': dropboxToken
@@ -713,6 +699,7 @@ function initCommands() {
mode: JitsiRecordingConstants.mode.FILE,
appData: JSON.stringify({
'file_recording_metadata': {
...extraMetadata,
'share': shouldShare
}
})
@@ -842,11 +829,14 @@ function initCommands() {
};
transport.on('event', ({ data, name }) => {
if (name && commands[name]) {
logger.info(`API command received: ${name}`);
commands[name](...data);
return true;
}
logger.warn(`Unknown API command received: ${name}`);
return false;
});
transport.on('request', (request, callback) => {
@@ -993,7 +983,13 @@ function initCommands() {
callback(isP2pActive(APP.store.getState()));
break;
}
case '_new_electron_screensharing_supported': {
callback(true);
break;
}
default:
callback({ error: new Error('UnknownRequestError') });
return false;
}
@@ -1101,7 +1097,11 @@ class API {
this._enabled = true;
initCommands();
this.notifyBrowserSupport(isSupportedBrowser());
// Let the embedder know we are ready.
this._sendEvent({ name: 'ready' });
}
/**
@@ -1279,6 +1279,19 @@ class API {
});
}
/**
* Notify request desktop sources.
*
* @param {Object} options - Object with the options for desktop sources.
* @returns {void}
*/
requestDesktopSources(options) {
return transport.sendRequest({
name: '_request-desktop-sources',
options
});
}
/**
* Notify external application that the video quality setting has changed.
*
@@ -1964,6 +1977,20 @@ class API {
});
}
/**
* Notify external application (if API is enabled) that the user received
* a transcription chunk.
*
* @param {Object} data - The event data.
* @returns {void}
*/
notifyTranscriptionChunkReceived(data) {
this._sendEvent({
name: 'transcription-chunk-received',
data
});
}
/**
* Notify external application (if API is enabled) whether the used browser is supported or not.
*

View File

@@ -145,6 +145,7 @@ const events = {
'prejoin-screen-loaded': 'prejoinScreenLoaded',
'proxy-connection-event': 'proxyConnectionEvent',
'raise-hand-updated': 'raiseHandUpdated',
'ready': 'ready',
'recording-link-available': 'recordingLinkAvailable',
'recording-status-changed': 'recordingStatusChanged',
'participant-menu-button-clicked': 'participantMenuButtonClick',
@@ -159,9 +160,14 @@ const events = {
'suspend-detected': 'suspendDetected',
'tile-view-changed': 'tileViewChanged',
'toolbar-button-clicked': 'toolbarButtonClicked',
'transcription-chunk-received': 'transcriptionChunkReceived',
'whiteboard-status-changed': 'whiteboardStatusChanged'
};
const requests = {
'_request-desktop-sources': '_requestDesktopSources'
};
/**
* Last id of api object.
*
@@ -269,10 +275,10 @@ function parseArguments(args) {
function parseSizeParam(value) {
let parsedValue;
// This regex parses values of the form 100px, 100em, 100pt or 100%.
// This regex parses values of the form 100px, 100em, 100pt, 100vh, 100vw or 100%.
// Values like 100 or 100px are handled outside of the regex, and
// invalid values will be ignored and the minimum will be used.
const re = /([0-9]*\.?[0-9]+)(em|pt|px|%)$/;
const re = /([0-9]*\.?[0-9]+)(em|pt|px|((d|l|s)?v)(h|w)|%)$/;
if (typeof value === 'string' && String(value).match(re) !== null) {
parsedValue = value;
@@ -361,7 +367,9 @@ export default class JitsiMeetExternalAPI extends EventEmitter {
},
release
});
this._createIFrame(height, width, onload, sandbox);
this._createIFrame(height, width, sandbox);
this._transport = new Transport({
backend: new PostMessageTransportBackend({
postisOptions: {
@@ -371,9 +379,12 @@ export default class JitsiMeetExternalAPI extends EventEmitter {
}
})
});
if (Array.isArray(invitees) && invitees.length > 0) {
this.invite(invitees);
}
this._onload = onload;
this._tmpE2EEKey = e2eeKey;
this._isLargeVideoVisible = false;
this._isPrejoinVideoVisible = false;
@@ -392,14 +403,12 @@ export default class JitsiMeetExternalAPI extends EventEmitter {
* parseSizeParam for format details.
* @param {number|string} width - The with of the iframe. Check
* parseSizeParam for format details.
* @param {Function} onload - The function that will listen
* for onload event.
* @param {string} sandbox - Sandbox directive for the created iframe, if desired.
* @returns {void}
*
* @private
*/
_createIFrame(height, width, onload, sandbox) {
_createIFrame(height, width, sandbox) {
const frameName = `jitsiConferenceFrame${id}`;
this._frame = document.createElement('iframe');
@@ -411,7 +420,8 @@ export default class JitsiMeetExternalAPI extends EventEmitter {
'display-capture',
'hid',
'microphone',
'screen-wake-lock'
'screen-wake-lock',
'speaker-selection'
].join('; ');
this._frame.name = frameName;
this._frame.id = frameName;
@@ -423,11 +433,6 @@ export default class JitsiMeetExternalAPI extends EventEmitter {
this._frame.sandbox = sandbox;
}
if (onload) {
// waits for iframe resources to load
// and fires event when it is done
this._frame.onload = onload;
}
this._frame.src = this._url;
this._frame = this._parentNode.appendChild(this._frame);
@@ -576,6 +581,12 @@ export default class JitsiMeetExternalAPI extends EventEmitter {
const userID = data.id;
switch (name) {
case 'ready': {
// Fake the iframe onload event because it's not reliable.
this._onload?.();
break;
}
case 'video-conference-joined': {
if (typeof this._tmpE2EEKey !== 'undefined') {
@@ -687,6 +698,18 @@ export default class JitsiMeetExternalAPI extends EventEmitter {
return false;
});
this._transport.on('request', (request, callback) => {
const requestName = requests[request.name];
const data = {
...request,
name: requestName
};
if (requestName) {
this.emit(requestName, data, callback);
}
});
}
/**
@@ -1258,6 +1281,17 @@ export default class JitsiMeetExternalAPI extends EventEmitter {
});
}
/**
* Returns the state of availability electron share screen via external api.
*
* @returns {Promise}
*/
_isNewElectronScreensharingSupported() {
return this._transport.sendRequest({
name: '_new_electron_screensharing_supported'
});
}
/**
* Pins a participant's video on to the stage view.
*
@@ -1398,6 +1432,7 @@ export default class JitsiMeetExternalAPI extends EventEmitter {
* @param { string } options.rtmpBroadcastID - The RTMP broadcast ID.
* @param { string } options.youtubeStreamKey - The youtube stream key.
* @param { string } options.youtubeBroadcastID - The youtube broadcast ID.
* @param {Object } options.extraMetadata - Any extra metadata params for file recording.
* @returns {void}
*/
startRecording(options) {

View File

@@ -203,16 +203,6 @@ UI.toggleFilmstrip = function() {
APP.store.dispatch(setFilmstripVisible(!visible));
};
/**
* Sets muted audio state for participant
*/
UI.setAudioMuted = function(id) {
// FIXME: Maybe this can be removed!
if (APP.conference.isLocalId(id)) {
APP.conference.updateAudioIconEnabled();
}
};
/**
* Sets muted video state for participant
*/

View File

@@ -5,6 +5,7 @@ import {
notifyMicError
} from '../../react/features/base/devices/actions.web';
import {
flattenAvailableDevices,
getAudioOutputDeviceId
} from '../../react/features/base/devices/functions.web';
import { updateSettings } from '../../react/features/base/settings/actions';
@@ -186,7 +187,7 @@ export default {
* @returns {boolean}
*/
newDeviceListAddedLabelsOnly(oldDevices, newDevices) {
const oldDevicesFlattend = oldDevices.audioInput.concat(oldDevices.audioOutput).concat(oldDevices.videoInput);
const oldDevicesFlattend = flattenAvailableDevices(oldDevices);
if (oldDevicesFlattend.length !== newDevices.length) {
return false;

5783
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -22,8 +22,8 @@
"@giphy/js-fetch-api": "4.7.1",
"@giphy/react-components": "6.8.1",
"@giphy/react-native-sdk": "2.3.0",
"@jitsi/excalidraw": "https://github.com/jitsi/excalidraw/releases/download/v0.0.14/jitsi-excalidraw-0.0.14.tgz",
"@jitsi/js-utils": "2.1.3",
"@jitsi/excalidraw": "https://github.com/jitsi/excalidraw/releases/download/v0.0.16/jitsi-excalidraw-0.0.16.tgz",
"@jitsi/js-utils": "2.2.1",
"@jitsi/logger": "2.0.2",
"@jitsi/rnnoise-wasm": "0.1.0",
"@jitsi/rtcstats": "9.5.1",
@@ -31,11 +31,11 @@
"@microsoft/microsoft-graph-client": "3.0.1",
"@mui/material": "5.12.1",
"@mui/styles": "5.12.0",
"@react-native-async-storage/async-storage": "1.19.3",
"@react-native-async-storage/async-storage": "1.19.4",
"@react-native-community/clipboard": "1.5.1",
"@react-native-community/netinfo": "9.4.1",
"@react-native-community/netinfo": "11.1.0",
"@react-native-community/slider": "4.4.3",
"@react-native-google-signin/google-signin": "10.0.1",
"@react-native-google-signin/google-signin": "10.1.0",
"@react-navigation/bottom-tabs": "6.5.8",
"@react-navigation/elements": "1.3.18",
"@react-navigation/material-top-tabs": "6.6.3",
@@ -65,12 +65,13 @@
"js-md5": "0.6.1",
"js-sha512": "0.8.0",
"jwt-decode": "2.2.0",
"lib-jitsi-meet": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1691.0.0+255d8f49/lib-jitsi-meet.tgz",
"lib-jitsi-meet": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1734.0.0+34ceebd2/lib-jitsi-meet.tgz",
"lodash": "4.17.21",
"moment": "2.29.4",
"moment-duration-format": "2.2.2",
"null-loader": "4.0.1",
"optional-require": "1.0.3",
"pixelmatch": "5.3.0",
"promise.allsettled": "1.0.4",
"punycode": "2.3.0",
"react": "18.2.0",
@@ -79,10 +80,9 @@
"react-focus-on": "3.8.1",
"react-i18next": "10.11.4",
"react-linkify": "1.0.0-alpha",
"react-native": "0.69.11",
"react-native": "0.70.14",
"react-native-background-timer": "2.4.1",
"react-native-calendar-events": "2.2.0",
"react-native-callstats": "3.73.22",
"react-native-default-preference": "1.4.4",
"react-native-device-info": "10.9.0",
"react-native-dialog": "https://github.com/jitsi/react-native-dialog/releases/download/v9.2.2-jitsi.1/react-native-dialog-9.2.2.tgz",
@@ -90,7 +90,7 @@
"react-native-get-random-values": "1.9.0",
"react-native-immersive-mode": "2.0.1",
"react-native-keep-awake": "4.0.0",
"react-native-orientation-locker": "1.5.0",
"react-native-orientation-locker": "1.6.0",
"react-native-pager-view": "6.2.0",
"react-native-paper": "5.10.3",
"react-native-performance": "5.0.0",
@@ -104,7 +104,7 @@
"react-native-url-polyfill": "2.0.0",
"react-native-video": "6.0.0-alpha.7",
"react-native-watch-connectivity": "1.1.0",
"react-native-webrtc": "111.0.3",
"react-native-webrtc": "118.0.0",
"react-native-webview": "13.5.1",
"react-native-youtube-iframe": "2.3.0",
"react-redux": "7.2.9",
@@ -113,7 +113,6 @@
"react-youtube": "10.1.0",
"redux": "4.0.4",
"redux-thunk": "2.4.1",
"resemblejs": "4.0.0",
"seamless-scroll-polyfill": "2.1.8",
"semver": "7.5.4",
"tss-react": "4.4.4",
@@ -136,16 +135,17 @@
"@types/dom-screen-wake-lock": "1.0.1",
"@types/js-md5": "0.4.3",
"@types/lodash": "4.14.182",
"@types/offscreencanvas": "2019.7.2",
"@types/pixelmatch": "5.2.5",
"@types/punycode": "2.1.0",
"@types/react": "17.0.14",
"@types/react-dom": "17.0.14",
"@types/react-linkify": "1.0.1",
"@types/react-native": "0.69.20",
"@types/react-native": "0.69.22",
"@types/react-native-keep-awake": "2.0.3",
"@types/react-native-video": "5.0.14",
"@types/react-redux": "7.1.24",
"@types/react-window": "1.8.5",
"@types/resemblejs": "^4.1.0",
"@types/unorm": "1.3.28",
"@types/uuid": "8.3.4",
"@types/w3c-image-capture": "1.0.6",
@@ -157,7 +157,7 @@
"babel-plugin-optional-require": "0.3.1",
"circular-dependency-plugin": "5.2.0",
"clean-css-cli": "4.3.0",
"css-loader": "3.6.0",
"css-loader": "6.8.1",
"eslint": "8.40.0",
"eslint-plugin-import": "2.27.5",
"eslint-plugin-jsdoc": "37.0.3",

View File

@@ -2,7 +2,7 @@ diff --git a/node_modules/react-native/React/CoreModules/RCTTiming.mm b/node_mod
index 13d0d57..00e5d4c 100644
--- a/node_modules/react-native/React/CoreModules/RCTTiming.mm
+++ b/node_modules/react-native/React/CoreModules/RCTTiming.mm
@@ -127,7 +127,15 @@ - (void)setup
@@ -127,7 +127,15 @@ RCT_EXPORT_MODULE()
{
_paused = YES;
_timers = [NSMutableDictionary new];
@@ -19,7 +19,7 @@ index 13d0d57..00e5d4c 100644
for (NSString *name in @[
UIApplicationWillResignActiveNotification,
@@ -146,6 +154,11 @@ - (void)setup
@@ -146,6 +154,11 @@ RCT_EXPORT_MODULE()
name:name
object:nil];
}
@@ -31,7 +31,7 @@ index 13d0d57..00e5d4c 100644
}
- (void)dealloc
@@ -182,6 +195,16 @@ - (void)appDidMoveToForeground
@@ -182,6 +195,16 @@ RCT_EXPORT_MODULE()
[self startTimers];
}

View File

@@ -73,6 +73,13 @@ cd ios && pod install && cd ..
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.CAMERA" />
```
- In `android/app/src/main/AndroidManifest.xml`, under the `</application>` tag, include
```xml
<service
android:name="org.jitsi.meet.sdk.JitsiMeetOngoingConferenceService"
android:foregroundServiceType="mediaProjection" />
```
This will take care of the screen share feature.
If you want to test all the steps before applying them to your app, you can check our React Native SDK sample app here:
https://github.com/jitsi/jitsi-meet-sdk-samples/tree/master/react-native
@@ -87,3 +94,6 @@ https://github.com/jitsi/jitsi-meet-sdk-samples/tree/master/react-native
serverURL={'https://meet.jit.si/'}
token={'dkhalhfajhflahlfaahalhfahfsl'} />
```
For more details on how you can use React Native SDK with React Native app, you can follow this link:
https://jitsi.github.io/handbook/docs/dev-guide/dev-guide-react-native-sdk

View File

@@ -0,0 +1,44 @@
package org.jitsi.meet.sdk;
import android.app.Activity;
import android.content.Context;
import androidx.annotation.NonNull;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.module.annotations.ReactModule;
@ReactModule(name = JMOngoingConferenceModule.NAME)
class JMOngoingConferenceModule
extends ReactContextBaseJavaModule {
public static final String NAME = "JMOngoingConference";
public JMOngoingConferenceModule(ReactApplicationContext reactContext) {
super(reactContext);
}
@ReactMethod
public void launch() {
Context context = getReactApplicationContext();
Activity currentActivity = getCurrentActivity();
JitsiMeetOngoingConferenceService.launch(context, currentActivity);
}
@ReactMethod
public void abort() {
Context context = getReactApplicationContext();
JitsiMeetOngoingConferenceService.abort(context);
}
@NonNull
@Override
public String getName() {
return NAME;
}
}

View File

@@ -0,0 +1,101 @@
/*
* Copyright @ 2019-present 8x8, Inc.
*
* 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.Notification;
import android.app.NotificationManager;
import android.app.Service;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Build;
import android.os.Bundle;
import android.os.IBinder;
import org.jitsi.meet.sdk.log.JitsiMeetLogger;
import java.util.HashMap;
/**
* This class implements an Android {@link Service}, a foreground one specifically, and it's
* responsible for presenting an ongoing notification when a conference is in progress.
* The service will help keep the app running while in the background.
*
* See: https://developer.android.com/guide/components/services
*/
public class JitsiMeetOngoingConferenceService extends Service {
private static final String TAG = JitsiMeetOngoingConferenceService.class.getSimpleName();
public static void launch(Context context, Activity currentActivity) {
RNOngoingNotification.createOngoingConferenceNotificationChannel(currentActivity);
Intent intent = new Intent(context, JitsiMeetOngoingConferenceService.class);
ComponentName componentName;
try {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
componentName = context.startForegroundService(intent);
} else {
componentName = context.startService(intent);
}
} catch (RuntimeException e) {
// Avoid crashing due to ForegroundServiceStartNotAllowedException (API level 31).
// See: https://developer.android.com/guide/components/foreground-services#background-start-restrictions
JitsiMeetLogger.w(TAG + " Ongoing conference service not started", e);
return;
}
if (componentName == null) {
JitsiMeetLogger.w(TAG + " Ongoing conference service not started");
}
}
public static void abort(Context context) {
Intent intent = new Intent(context, JitsiMeetOngoingConferenceService.class);
context.stopService(intent);
}
@Override
public void onCreate() {
super.onCreate();
Notification notification = RNOngoingNotification.buildOngoingConferenceNotification(this);
if (notification == null) {
stopSelf();
JitsiMeetLogger.w(TAG + " Couldn't start service, notification is null");
} else {
startForeground(RNOngoingNotification.NOTIFICATION_ID, notification);
JitsiMeetLogger.i(TAG + " Service started");
}
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
return START_NOT_STICKY;
}
}

View File

@@ -21,6 +21,7 @@ public class JitsiMeetReactNativePackage implements ReactPackage {
new AndroidSettingsModule(reactContext),
new AppInfoModule(reactContext),
new AudioModeModule(reactContext),
new JMOngoingConferenceModule(reactContext),
new JavaScriptSandboxModule(reactContext),
new LocaleDetector(reactContext),
new LogBridgeModule(reactContext),

View File

@@ -0,0 +1,98 @@
/*
* Copyright @ 2019-present 8x8, Inc.
*
* 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.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import androidx.annotation.StringRes;
import androidx.core.app.NotificationCompat;
import org.jitsi.meet.sdk.log.JitsiMeetLogger;
import java.util.Random;
/**
* Helper class for creating the ongoing notification which is used with
* {@link JitsiMeetOngoingConferenceService}. It allows the user to easily get back to the app
* and to hangup from within the notification itself.
*/
class RNOngoingNotification {
private static final String TAG = RNOngoingNotification.class.getSimpleName();
static final int NOTIFICATION_ID = new Random().nextInt(99999) + 10000;
static void createOngoingConferenceNotificationChannel(Activity currentActivity) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
return;
}
if (currentActivity == null) {
JitsiMeetLogger.w(TAG + " Cannot create notification channel: no current context");
return;
}
NotificationManager notificationManager
= (NotificationManager) currentActivity.getSystemService(Context.NOTIFICATION_SERVICE);
NotificationChannel channel
= notificationManager.getNotificationChannel("JitsiOngoingConferenceChannel");
if (channel != null) {
// The channel was already created, no need to do it again.
return;
}
channel = new NotificationChannel("JitsiOngoingConferenceChannel", currentActivity.getString(R.string.ongoing_notification_channel_name), NotificationManager.IMPORTANCE_DEFAULT);
channel.enableLights(false);
channel.enableVibration(false);
channel.setShowBadge(false);
notificationManager.createNotificationChannel(channel);
}
static Notification buildOngoingConferenceNotification(Context context) {
if (context == null) {
JitsiMeetLogger.w(TAG + " Cannot create notification: no current context");
return null;
}
NotificationCompat.Builder builder = new NotificationCompat.Builder(context, "JitsiOngoingConferenceChannel");
builder
.setCategory(NotificationCompat.CATEGORY_CALL)
.setContentTitle(context.getString(R.string.ongoing_notification_title))
.setContentText(context.getString(R.string.ongoing_notification_text))
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
.setOngoing(true)
.setWhen(System.currentTimeMillis())
.setUsesChronometer(true)
.setAutoCancel(false)
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
.setOnlyAlertOnce(true)
.setSmallIcon(context.getResources().getIdentifier("ic_notification", "drawable", context.getPackageName()));
return builder.build();
}
}

View File

@@ -19,6 +19,8 @@ import { setAudioMuted, setVideoMuted } from './react/features/base/media/action
interface IEventListeners {
onAudioMutedChanged?: Function;
onVideoMutedChanged?: Function;
onConferenceBlurred?: Function;
onConferenceFocused?: Function;
onConferenceJoined?: Function;
@@ -107,6 +109,8 @@ export const JitsiMeeting = forwardRef((props: IAppProps, ref) => {
setAppProps({
'flags': flags,
'rnSdkHandlers': {
onAudioMutedChanged: eventListeners?.onAudioMutedChanged,
onVideoMutedChanged: eventListeners?.onVideoMutedChanged,
onConferenceBlurred: eventListeners?.onConferenceBlurred,
onConferenceFocused: eventListeners?.onConferenceFocused,
onConferenceJoined: eventListeners?.onConferenceJoined,

View File

@@ -154,11 +154,11 @@
}
},
"node_modules/@babel/generator": {
"version": "7.22.15",
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.22.15.tgz",
"integrity": "sha512-Zu9oWARBqeVOW0dZOjXc3JObrzuqothQ3y/n1kUtrjCoCPLkXUwMvOo/F/TCfoHMbWIFlWwpZtkZVb9ga4U2pA==",
"version": "7.23.0",
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.0.tgz",
"integrity": "sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g==",
"dependencies": {
"@babel/types": "^7.22.15",
"@babel/types": "^7.23.0",
"@jridgewell/gen-mapping": "^0.3.2",
"@jridgewell/trace-mapping": "^0.3.17",
"jsesc": "^2.5.1"
@@ -191,20 +191,20 @@
}
},
"node_modules/@babel/helper-environment-visitor": {
"version": "7.22.5",
"resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.5.tgz",
"integrity": "sha512-XGmhECfVA/5sAt+H+xpSg0mfrHq6FzNr9Oxh7PSEBBRUb/mL7Kz3NICXb194rCqAEdxkhPT1a88teizAFyvk8Q==",
"version": "7.22.20",
"resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz",
"integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==",
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/helper-function-name": {
"version": "7.22.5",
"resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.22.5.tgz",
"integrity": "sha512-wtHSq6jMRE3uF2otvfuD3DIvVhOsSNshQl0Qrd7qC9oQJzHvOL4qQXlQn2916+CXGywIjpGuIkoyZRRxHPiNQQ==",
"version": "7.23.0",
"resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz",
"integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==",
"dependencies": {
"@babel/template": "^7.22.5",
"@babel/types": "^7.22.5"
"@babel/template": "^7.22.15",
"@babel/types": "^7.23.0"
},
"engines": {
"node": ">=6.9.0"
@@ -281,9 +281,9 @@
}
},
"node_modules/@babel/helper-validator-identifier": {
"version": "7.22.15",
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.15.tgz",
"integrity": "sha512-4E/F9IIEi8WR94324mbDUMo074YTheJmd7eZF5vITTeYchqAi6sYXRLHUVsmkdmY4QjfKTcB2jB7dVP3NaBElQ==",
"version": "7.22.20",
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz",
"integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==",
"engines": {
"node": ">=6.9.0"
}
@@ -323,9 +323,9 @@
}
},
"node_modules/@babel/parser": {
"version": "7.22.15",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.22.15.tgz",
"integrity": "sha512-RWmQ/sklUN9BvGGpCDgSubhHWfAx24XDTDObup4ffvxaYsptOg2P3KG0j+1eWKLxpkX0j0uHxmpq2Z1SP/VhxA==",
"version": "7.23.0",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.0.tgz",
"integrity": "sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==",
"bin": {
"parser": "bin/babel-parser.js"
},
@@ -358,18 +358,18 @@
}
},
"node_modules/@babel/traverse": {
"version": "7.22.15",
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.22.15.tgz",
"integrity": "sha512-DdHPwvJY0sEeN4xJU5uRLmZjgMMDIvMPniLuYzUVXj/GGzysPl0/fwt44JBkyUIzGJPV8QgHMcQdQ34XFuKTYQ==",
"version": "7.23.2",
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.2.tgz",
"integrity": "sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==",
"dependencies": {
"@babel/code-frame": "^7.22.13",
"@babel/generator": "^7.22.15",
"@babel/helper-environment-visitor": "^7.22.5",
"@babel/helper-function-name": "^7.22.5",
"@babel/generator": "^7.23.0",
"@babel/helper-environment-visitor": "^7.22.20",
"@babel/helper-function-name": "^7.23.0",
"@babel/helper-hoist-variables": "^7.22.5",
"@babel/helper-split-export-declaration": "^7.22.6",
"@babel/parser": "^7.22.15",
"@babel/types": "^7.22.15",
"@babel/parser": "^7.23.0",
"@babel/types": "^7.23.0",
"debug": "^4.1.0",
"globals": "^11.1.0"
},
@@ -378,12 +378,12 @@
}
},
"node_modules/@babel/types": {
"version": "7.22.15",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.22.15.tgz",
"integrity": "sha512-X+NLXr0N8XXmN5ZsaQdm9U2SSC3UbIYq/doL++sueHOTisgZHoKaQtZxGuV2cUPQHMfjKEfg/g6oy7Hm6SKFtA==",
"version": "7.23.0",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz",
"integrity": "sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==",
"dependencies": {
"@babel/helper-string-parser": "^7.22.5",
"@babel/helper-validator-identifier": "^7.22.15",
"@babel/helper-validator-identifier": "^7.22.20",
"to-fast-properties": "^2.0.0"
},
"engines": {
@@ -3866,11 +3866,11 @@
}
},
"@babel/generator": {
"version": "7.22.15",
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.22.15.tgz",
"integrity": "sha512-Zu9oWARBqeVOW0dZOjXc3JObrzuqothQ3y/n1kUtrjCoCPLkXUwMvOo/F/TCfoHMbWIFlWwpZtkZVb9ga4U2pA==",
"version": "7.23.0",
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.0.tgz",
"integrity": "sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g==",
"requires": {
"@babel/types": "^7.22.15",
"@babel/types": "^7.23.0",
"@jridgewell/gen-mapping": "^0.3.2",
"@jridgewell/trace-mapping": "^0.3.17",
"jsesc": "^2.5.1"
@@ -3896,17 +3896,17 @@
}
},
"@babel/helper-environment-visitor": {
"version": "7.22.5",
"resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.5.tgz",
"integrity": "sha512-XGmhECfVA/5sAt+H+xpSg0mfrHq6FzNr9Oxh7PSEBBRUb/mL7Kz3NICXb194rCqAEdxkhPT1a88teizAFyvk8Q=="
"version": "7.22.20",
"resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz",
"integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA=="
},
"@babel/helper-function-name": {
"version": "7.22.5",
"resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.22.5.tgz",
"integrity": "sha512-wtHSq6jMRE3uF2otvfuD3DIvVhOsSNshQl0Qrd7qC9oQJzHvOL4qQXlQn2916+CXGywIjpGuIkoyZRRxHPiNQQ==",
"version": "7.23.0",
"resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz",
"integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==",
"requires": {
"@babel/template": "^7.22.5",
"@babel/types": "^7.22.5"
"@babel/template": "^7.22.15",
"@babel/types": "^7.23.0"
}
},
"@babel/helper-hoist-variables": {
@@ -3959,9 +3959,9 @@
"integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw=="
},
"@babel/helper-validator-identifier": {
"version": "7.22.15",
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.15.tgz",
"integrity": "sha512-4E/F9IIEi8WR94324mbDUMo074YTheJmd7eZF5vITTeYchqAi6sYXRLHUVsmkdmY4QjfKTcB2jB7dVP3NaBElQ=="
"version": "7.22.20",
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz",
"integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A=="
},
"@babel/helper-validator-option": {
"version": "7.22.15",
@@ -3989,9 +3989,9 @@
}
},
"@babel/parser": {
"version": "7.22.15",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.22.15.tgz",
"integrity": "sha512-RWmQ/sklUN9BvGGpCDgSubhHWfAx24XDTDObup4ffvxaYsptOg2P3KG0j+1eWKLxpkX0j0uHxmpq2Z1SP/VhxA=="
"version": "7.23.0",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.0.tgz",
"integrity": "sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw=="
},
"@babel/runtime": {
"version": "7.22.5",
@@ -4012,29 +4012,29 @@
}
},
"@babel/traverse": {
"version": "7.22.15",
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.22.15.tgz",
"integrity": "sha512-DdHPwvJY0sEeN4xJU5uRLmZjgMMDIvMPniLuYzUVXj/GGzysPl0/fwt44JBkyUIzGJPV8QgHMcQdQ34XFuKTYQ==",
"version": "7.23.2",
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.2.tgz",
"integrity": "sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==",
"requires": {
"@babel/code-frame": "^7.22.13",
"@babel/generator": "^7.22.15",
"@babel/helper-environment-visitor": "^7.22.5",
"@babel/helper-function-name": "^7.22.5",
"@babel/generator": "^7.23.0",
"@babel/helper-environment-visitor": "^7.22.20",
"@babel/helper-function-name": "^7.23.0",
"@babel/helper-hoist-variables": "^7.22.5",
"@babel/helper-split-export-declaration": "^7.22.6",
"@babel/parser": "^7.22.15",
"@babel/types": "^7.22.15",
"@babel/parser": "^7.23.0",
"@babel/types": "^7.23.0",
"debug": "^4.1.0",
"globals": "^11.1.0"
}
},
"@babel/types": {
"version": "7.22.15",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.22.15.tgz",
"integrity": "sha512-X+NLXr0N8XXmN5ZsaQdm9U2SSC3UbIYq/doL++sueHOTisgZHoKaQtZxGuV2cUPQHMfjKEfg/g6oy7Hm6SKFtA==",
"version": "7.23.0",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz",
"integrity": "sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==",
"requires": {
"@babel/helper-string-parser": "^7.22.5",
"@babel/helper-validator-identifier": "^7.22.15",
"@babel/helper-validator-identifier": "^7.22.20",
"to-fast-properties": "^2.0.0"
}
},

View File

@@ -38,7 +38,6 @@
"react-emoji-render": "1.2.4",
"react-i18next": "10.11.4",
"react-linkify": "1.0.0-alpha",
"react-native-callstats": "3.73.22",
"react-native-dialog": "https://github.com/jitsi/react-native-dialog/releases/download/v9.2.2-jitsi.1/react-native-dialog-9.2.2.tgz",
"react-native-svg-transformer": "1.1.0",
"react-native-tab-view": "3.5.2",
@@ -97,4 +96,4 @@
"keywords": [
"react-native"
]
}
}

View File

@@ -6,7 +6,9 @@ const packageJSON = require('../package.json');
const SDKPackageJSON = require('./package.json');
const androidSourcePath = '../android/sdk/src/main/java/org/jitsi/meet/sdk';
const androidMainSourcePath = '../android/sdk/src/main/res';
const androidTargetPath = './android/src/main/java/org/jitsi/meet/sdk';
const androidMainTargetPath = './android/src/main/res';
const iosSrcPath = '../ios/sdk/src';
const iosDestPath = './ios/src';
@@ -169,6 +171,30 @@ copyFolderRecursiveSync(
`${androidSourcePath}/log`,
`${androidTargetPath}/log`
);
copyFolderRecursiveSync(
`${androidMainSourcePath}/values`,
`${androidMainTargetPath}`
);
copyFolderRecursiveSync(
`${androidMainSourcePath}/drawable-hdpi`,
`${androidMainTargetPath}`
);
copyFolderRecursiveSync(
`${androidMainSourcePath}/drawable-mdpi`,
`${androidMainTargetPath}`
);
copyFolderRecursiveSync(
`${androidMainSourcePath}/drawable-xhdpi`,
`${androidMainTargetPath}`
);
copyFolderRecursiveSync(
`${androidMainSourcePath}/drawable-xxhdpi`,
`${androidMainTargetPath}`
);
copyFolderRecursiveSync(
`${androidMainSourcePath}/drawable-xxxhdpi`,
`${androidMainTargetPath}`
);
copyFolderRecursiveSync(
`${androidSourcePath}/net`,
`${androidTargetPath}/log`

View File

@@ -25,7 +25,8 @@ function updateDependencies() {
updated = true;
}
if (!semver.valid(packageJSON.dependencies[key])) {
if (!semver.valid(packageJSON.dependencies[key])
&& packageJSON.dependencies[key] !== RNSDKpackageJSON.peerDependencies[key]) {
packageJSON.dependencies[key] = RNSDKpackageJSON.peerDependencies[key];
updated = true;
@@ -46,6 +47,18 @@ function updateDependencies() {
console.log(`${key} is now set to ${RNSDKpackageJSON.peerDependencies[key]}`);
}
if (!semver.valid(RNSDKpackageJSON.peerDependencies[key])
&& RNSDKpackageJSON.peerDependencies[key].includes('github')
&& packageJSON.dependencies[key] !== RNSDKpackageJSON.peerDependencies[key]) {
packageJSON.dependencies[key] = RNSDKpackageJSON.peerDependencies[key];
updated = true;
console.log(
`A fix for ${key} is available on ${RNSDKpackageJSON.peerDependencies[key]}.
This is now set on your end.`
);
}
}
packageJSON.overrides = packageJSON.overrides || {};

View File

@@ -4,6 +4,7 @@ import React, { Component } from 'react';
// in this environment (e.g. JitsiMeetJS or interfaceConfig)
import StatelessAvatar from '../base/avatar/components/web/StatelessAvatar';
import { getAvatarColor, getInitials } from '../base/avatar/functions';
import { DEFAULT_ICON } from '../base/icons/svg/constants';
import Toolbar from './Toolbar';
@@ -184,6 +185,7 @@ export default class AlwaysOnTop extends Component<any, IState> {
<div id = 'avatarContainer'>
<StatelessAvatar
color = { getAvatarColor(displayName, customAvatarBackgrounds) }
iconUser = { DEFAULT_ICON.IconUser }
id = 'avatar'
initials = { getInitials(displayName) }
url = { avatarURL } />)

View File

@@ -2,7 +2,8 @@ import React, { Component } from 'react';
// We need to reference these files directly to avoid loading things that are not available
// in this environment (e.g. JitsiMeetJS or interfaceConfig)
import { IconMic, IconMicSlash } from '../base/icons/svg';
import { DEFAULT_ICON } from '../base/icons/svg/constants';
import { IProps } from '../base/toolbox/components/AbstractButton';
import ToolbarButton from './ToolbarButton';
@@ -31,8 +32,8 @@ type Props = Partial<IProps>;
* Stateless "mute/unmute audio" button for the Always-on-Top windows.
*/
export default class AudioMuteButton extends Component<Props, IState> {
icon = IconMic;
toggledIcon = IconMicSlash;
icon = DEFAULT_ICON.IconMic;
toggledIcon = DEFAULT_ICON.IconMicSlash;
accessibilityLabel = 'Audio mute';
/**

View File

@@ -2,7 +2,7 @@ import React, { Component } from 'react';
// We need to reference these files directly to avoid loading things that are not available
// in this environment (e.g. JitsiMeetJS or interfaceConfig)
import { IconHangup } from '../base/icons/svg';
import { DEFAULT_ICON } from '../base/icons/svg/constants';
import { IProps } from '../base/toolbox/components/AbstractButton';
import ToolbarButton from './ToolbarButton';
@@ -17,7 +17,7 @@ type Props = Partial<IProps>;
export default class HangupButton extends Component<Props> {
accessibilityLabel = 'Hangup';
icon = IconHangup;
icon = DEFAULT_ICON.IconHangup;
/**
* Initializes a new {@code HangupButton} instance.

View File

@@ -2,7 +2,7 @@ import React, { Component } from 'react';
// We need to reference these files directly to avoid loading things that are not available
// in this environment (e.g. JitsiMeetJS or interfaceConfig)
import { IconVideo, IconVideoOff } from '../base/icons/svg';
import { DEFAULT_ICON } from '../base/icons/svg/constants';
import { IProps } from '../base/toolbox/components/AbstractButton';
import ToolbarButton from './ToolbarButton';
@@ -32,8 +32,8 @@ type State = {
*/
export default class VideoMuteButton extends Component<Props, State> {
icon = IconVideo;
toggledIcon = IconVideoOff;
icon = DEFAULT_ICON.IconVideo;
toggledIcon = DEFAULT_ICON.IconVideoOff;
accessibilityLabel = 'Video mute';
/**

View File

@@ -934,3 +934,27 @@ export function createGifSentEvent() {
action: 'gif.sent'
};
}
/**
* Creates an event which indicates the whiteboard was opened.
*
* @returns {Object} The event in a format suitable for sending via
* sendAnalytics.
*/
export function createOpenWhiteboardEvent() {
return {
action: 'whiteboard.open'
};
}
/**
* Creates an event which indicates the whiteboard limit was enforced.
*
* @returns {Object} The event in a format suitable for sending via
* sendAnalytics.
*/
export function createRestrictWhiteboardEvent() {
return {
action: 'whiteboard.restrict'
};
}

View File

@@ -16,6 +16,7 @@ import { getJitsiMeetGlobalNS } from '../base/util/helpers';
import { inIframe } from '../base/util/iframeUtils';
import { loadScript } from '../base/util/loadScript';
import { parseURIString } from '../base/util/uri';
import { isPrejoinPageVisible } from '../prejoin/functions';
import AmplitudeHandler from './handlers/AmplitudeHandler';
import MatomoHandler from './handlers/MatomoHandler';
@@ -158,9 +159,10 @@ export async function createHandlers({ getState }: IStore) {
*
* @param {Store} store - The redux store in which the specified {@code action} is being dispatched.
* @param {Array<Object>} handlers - The analytics handlers.
* @param {boolean|undefined} willShowPrejoin -
* @returns {void}
*/
export function initAnalytics(store: IStore, handlers: Array<Object>) {
export function initAnalytics(store: IStore, handlers: Array<Object>, willShowPrejoin?: boolean) {
const { getState, dispatch } = store;
if (!isAnalyticsEnabled(getState) || handlers.length === 0) {
@@ -180,8 +182,12 @@ export function initAnalytics(store: IStore, handlers: Array<Object>) {
externalApi?: boolean;
group?: string;
inIframe?: boolean;
isPromotedFromVisitor?: boolean;
isVisitor?: boolean;
server?: string;
tenant?: string;
wasLobbyVisible?: boolean;
wasPrejoinDisplayed?: boolean;
websocket?: boolean;
} & typeof deploymentInfo = {};
@@ -207,6 +213,15 @@ export function initAnalytics(store: IStore, handlers: Array<Object>) {
// Report the tenant from the URL.
permanentProperties.tenant = tenant || '/';
permanentProperties.wasPrejoinDisplayed = willShowPrejoin ?? isPrejoinPageVisible(state);
// Currently we don't know if there will be lobby. We will update it to true if we go through lobby.
permanentProperties.wasLobbyVisible = false;
// Setting visitor properties to false by default. We will update them later if it turns out we are visitor.
permanentProperties.isVisitor = false;
permanentProperties.isPromotedFromVisitor = false;
// Optionally, include local deployment information based on the
// contents of window.config.deploymentInfo.
if (deploymentInfo) {
@@ -224,7 +239,7 @@ export function initAnalytics(store: IStore, handlers: Array<Object>) {
// Set the handlers last, since this triggers emptying of the cache
analytics.setAnalyticsHandlers(handlers);
if (!isMobileBrowser() && browser.isChrome()) {
if (!isMobileBrowser() && browser.isChromiumBased()) {
const bannerCfg = state['features/base/config'].chromeExtensionBanner;
checkChromeExtensionsInstalled(bannerCfg).then(extensionsInstalled => {

View File

@@ -5,6 +5,7 @@ import {
SET_ROOM
} from '../base/conference/actionTypes';
import { SET_CONFIG } from '../base/config/actionTypes';
import { analytics } from '../base/lib-jitsi-meet';
import { SET_NETWORK_INFO } from '../base/net-info/actionTypes';
import MiddlewareRegistry from '../base/redux/MiddlewareRegistry';
import {
@@ -16,6 +17,10 @@ import {
getLocalAudioTrack,
getLocalVideoTrack
} from '../base/tracks/functions';
import { SET_LOBBY_VISIBILITY } from '../lobby/actionTypes';
import { getIsLobbyVisible } from '../lobby/functions';
import { I_AM_VISITOR_MODE } from '../visitors/actionTypes';
import { iAmVisitor } from '../visitors/functions';
import { createLocalTracksDurationEvent, createNetworkInfoEvent } from './AnalyticsEvents';
import { UPDATE_LOCAL_TRACKS_DURATION } from './actionTypes';
@@ -81,6 +86,18 @@ function calculateLocalTrackDuration(state: IReduxState) {
*/
MiddlewareRegistry.register(store => next => action => {
switch (action.type) {
case I_AM_VISITOR_MODE: {
const oldIAmVisitor = iAmVisitor(store.getState());
const result = next(action);
const newIAmVisitor = iAmVisitor(store.getState());
analytics.addPermanentProperties({
isVisitor: newIAmVisitor,
isPromotedFromVisitor: oldIAmVisitor && !newIAmVisitor
});
return result;
}
case SET_CONFIG:
if (navigator.product === 'ReactNative') {
// Resetting the analytics is currently not needed for web because
@@ -97,7 +114,7 @@ MiddlewareRegistry.register(store => next => action => {
const result = next(action);
createHandlersPromise.then(handlers => {
initAnalytics(store, handlers);
initAnalytics(store, handlers, action.willShowPrejoin);
});
return result;
@@ -144,6 +161,14 @@ MiddlewareRegistry.register(store => next => action => {
});
break;
}
case SET_LOBBY_VISIBILITY:
if (getIsLobbyVisible(store.getState())) {
analytics.addPermanentProperties({
wasLobbyVisible: true
});
}
break;
case SET_NETWORK_INFO:
sendAnalytics(
createNetworkInfoEvent({

View File

@@ -1,8 +1,19 @@
import { getLocationContextRoot } from '../base/util/uri';
// @ts-ignore
// eslint-disable-next-line
import { openTokenAuthUrl } from '../authentication/actions';
// @ts-ignore
import { getTokenAuthUrl, isTokenAuthEnabled } from '../authentication/functions';
import { getJwtExpirationDate } from '../base/jwt/functions';
import { MEDIA_TYPE } from '../base/media/constants';
import { isLocalTrackMuted } from '../base/tracks/functions.any';
import { getLocationContextRoot, parseURIString } from '../base/util/uri';
import { addTrackStateToURL } from './functions.any';
import logger from './logger';
import { IStore } from './types';
/**
* Redirects to another page generated by replacing the path in the original URL
* with the given path.
@@ -83,4 +94,68 @@ export function reloadWithStoredParams() {
};
}
/**
* Checks whether tokenAuthUrl is set, we have a jwt token that will expire soon
* and redirect to the auth url to obtain new token if this is the case.
*
* @param {Dispatch} dispatch - The Redux dispatch function.
* @param {Function} getState - The Redux state.
* @param {Function} failureCallback - The callback on failure to obtain auth url.
* @returns {boolean} Whether we will redirect or not.
*/
export function maybeRedirectToTokenAuthUrl(
dispatch: IStore['dispatch'], getState: IStore['getState'], failureCallback: Function) {
const state = getState();
const config = state['features/base/config'];
const { enabled: audioOnlyEnabled } = state['features/base/audio-only'];
const { startAudioOnly } = config;
const { locationURL = { href: '' } as URL } = state['features/base/connection'];
const audioMuted = isLocalTrackMuted(state['features/base/tracks'], MEDIA_TYPE.AUDIO);
const videoMuted = isLocalTrackMuted(state['features/base/tracks'], MEDIA_TYPE.VIDEO);
if (!isTokenAuthEnabled(config)) {
return false;
}
// if tokenAuthUrl check jwt if is about to expire go through the url to get new token
const jwt = state['features/base/jwt'].jwt;
const expirationDate = getJwtExpirationDate(jwt);
// if there is jwt and its expiration time is less than 3 minutes away
// let's obtain new token
if (expirationDate && expirationDate.getTime() - Date.now() < 3 * 60 * 1000) {
const room = state['features/base/conference'].room;
const { tenant } = parseURIString(locationURL.href) || {};
getTokenAuthUrl(
config,
locationURL,
{
audioMuted,
audioOnlyEnabled: audioOnlyEnabled || startAudioOnly,
skipPrejoin: true,
videoMuted
},
room,
tenant
)
.then((tokenAuthServiceUrl: string | undefined) => {
if (!tokenAuthServiceUrl) {
logger.warn('Cannot handle login, token service URL is not set');
return Promise.reject();
}
return dispatch(openTokenAuthUrl(tokenAuthServiceUrl));
})
.catch(() => {
failureCallback();
});
return true;
}
return false;
}

View File

@@ -31,11 +31,11 @@ import { screen } from '../mobile/navigation/routes';
import { clearNotifications } from '../notifications/actions';
import { isUnsafeRoomWarningEnabled } from '../prejoin/functions';
import { maybeRedirectToTokenAuthUrl } from './actions.any';
import { addTrackStateToURL, getDefaultURL } from './functions.native';
import logger from './logger';
import { IReloadNowOptions, IStore } from './types';
export * from './actions.any';
/**
@@ -150,9 +150,20 @@ export function appNavigate(uri?: string, options: IReloadNowOptions = {}) {
return;
}
let willShowPrejoin = false;
let willShowUnsafeRoomWarning = false;
if (!options.hidePrejoin && isPrejoinPageEnabled(getState()) && room) {
if (isUnsafeRoomWarningEnabled(getState()) && isInsecureRoomName(room)) {
willShowUnsafeRoomWarning = true;
} else {
willShowPrejoin = true;
}
}
dispatch(setLocationURL(locationURL));
dispatch(setConfig(config));
dispatch(setRoom(room));
dispatch(setRoom(room, willShowPrejoin));
if (!room) {
goBackToRoot(getState(), dispatch);
@@ -163,12 +174,10 @@ export function appNavigate(uri?: string, options: IReloadNowOptions = {}) {
dispatch(createDesiredLocalTracks());
dispatch(clearNotifications());
if (!options.hidePrejoin && isPrejoinPageEnabled(getState())) {
if (isUnsafeRoomWarningEnabled(getState()) && isInsecureRoomName(room)) {
navigateRoot(screen.unsafeRoomWarning);
} else {
navigateRoot(screen.preJoin);
}
if (willShowUnsafeRoomWarning) {
navigateRoot(screen.unsafeRoomWarning);
} else if (willShowPrejoin) {
navigateRoot(screen.preJoin);
} else {
dispatch(connect());
navigateRoot(screen.conference.root);
@@ -205,10 +214,18 @@ export function reloadNow() {
// @ts-ignore
const newURL = addTrackStateToURL(locationURL, state);
logger.info(`Reloading the conference using URL: ${locationURL}`);
const reloadAction = () => {
logger.info(`Reloading the conference using URL: ${locationURL}`);
dispatch(appNavigate(toURLString(newURL), {
hidePrejoin: true
}));
dispatch(appNavigate(toURLString(newURL), {
hidePrejoin: true
}));
};
if (maybeRedirectToTokenAuthUrl(dispatch, getState, reloadAction)) {
return;
}
reloadAction();
};
}

View File

@@ -15,6 +15,7 @@ import { NOTIFICATION_TIMEOUT_TYPE } from '../notifications/constants';
import { isWelcomePageEnabled } from '../welcome/functions';
import {
maybeRedirectToTokenAuthUrl,
redirectToStaticPage,
redirectWithStoredParams,
reloadWithStoredParams
@@ -170,8 +171,16 @@ export function reloadNow() {
const state = getState();
const { locationURL } = state['features/base/connection'];
logger.info(`Reloading the conference using URL: ${locationURL}`);
const reloadAction = () => {
logger.info(`Reloading the conference using URL: ${locationURL}`);
dispatch(reloadWithStoredParams());
dispatch(reloadWithStoredParams());
};
if (maybeRedirectToTokenAuthUrl(dispatch, getState, reloadAction)) {
return;
}
reloadAction();
};
}

View File

@@ -7,8 +7,7 @@ import SplashScreen from 'react-native-splash-screen';
import BottomSheetContainer from '../../base/dialog/components/native/BottomSheetContainer';
import DialogContainer from '../../base/dialog/components/native/DialogContainer';
import { updateFlags } from '../../base/flags/actions';
import { CALL_INTEGRATION_ENABLED, SERVER_URL_CHANGE_ENABLED } from '../../base/flags/constants';
import { getFeatureFlag } from '../../base/flags/functions';
import { CALL_INTEGRATION_ENABLED } from '../../base/flags/constants';
import { clientResized, setSafeAreaInsets } from '../../base/responsive-ui/actions';
import DimensionsDetector from '../../base/responsive-ui/components/DimensionsDetector.native';
import { updateSettings } from '../../base/settings/actions';
@@ -22,6 +21,7 @@ import { AbstractApp, IProps as AbstractAppProps } from './AbstractApp';
import '../middlewares.native';
import '../reducers.native';
declare let __DEV__: any;
const { AppInfo } = NativeModules;
@@ -111,7 +111,7 @@ export class App extends AbstractApp<IProps> {
*/
async _extraInit() {
const { dispatch, getState } = this.state.store ?? {};
const { flags = {} } = this.props;
const { flags = {}, url, userInfo } = this.props;
let callIntegrationEnabled = flags[CALL_INTEGRATION_ENABLED as keyof typeof flags];
// CallKit does not work on the simulator, make sure we disable it.
@@ -153,22 +153,19 @@ export class App extends AbstractApp<IProps> {
await rootNavigationReady;
// Check if serverURL is configured externally and not allowed to change.
const serverURLChangeEnabled = getState && getFeatureFlag(getState(), SERVER_URL_CHANGE_ENABLED, true);
// Update specified server URL.
if (typeof url !== 'undefined') {
if (!serverURLChangeEnabled) {
// As serverURL is provided externally, so we push it to settings.
if (typeof this.props.url !== 'undefined') {
// @ts-ignore
const { serverURL } = this.props.url;
// @ts-ignore
const { serverURL } = url;
if (typeof serverURL !== 'undefined') {
dispatch?.(updateSettings({ serverURL }));
}
if (typeof serverURL !== 'undefined') {
dispatch?.(updateSettings({ serverURL }));
}
}
dispatch?.(updateSettings(this.props.userInfo || {}));
// @ts-ignore
dispatch?.(updateSettings(userInfo || {}));
// Update settings with feature-flag.
if (typeof callIntegrationEnabled !== 'undefined') {

View File

@@ -53,10 +53,22 @@ function _getWebConferenceRoute(state: IReduxState) {
if (!browser.isElectron() && config.tokenAuthUrl && config.tokenAuthUrlAutoRedirect
&& state['features/authentication'].tokenAuthUrlSuccessful
&& !state['features/base/jwt'].jwt && room) {
const { locationURL = { href: '' } } = state['features/base/connection'];
const { locationURL = { href: '' } as URL } = state['features/base/connection'];
const { tenant } = parseURIString(locationURL.href) || {};
const { startAudioOnly } = config;
return getTokenAuthUrl(config, room, tenant)
return getTokenAuthUrl(
config,
locationURL,
{
audioMuted: false,
audioOnlyEnabled: startAudioOnly,
skipPrejoin: false,
videoMuted: false
},
room,
tenant
)
.then((url: string | undefined) => {
route.href = url;

View File

@@ -1,7 +1,6 @@
import '../analytics/middleware';
import '../authentication/middleware';
import '../av-moderation/middleware';
import '../base/app/middleware';
import '../base/conference/middleware';
import '../base/config/middleware';
import '../base/jwt/middleware';

View File

@@ -1,3 +1,4 @@
import '../base/app/middleware';
import '../base/connection/middleware';
import '../base/i18n/middleware';
import '../base/devices/middleware';

View File

@@ -68,7 +68,7 @@ export function openTokenAuthUrl(tokenAuthServiceUrl: string): any {
dispatch(openDialog(LoginQuestionDialog, {
handler: () => {
// Give time for the dialog to close.
setTimeout(() => redirect, 500);
setTimeout(() => redirect(), 500);
}
}));
} else {

View File

@@ -17,6 +17,11 @@ interface IProps {
*/
_alternativeCancelText?: boolean;
/**
* Is confirm button hidden?
*/
_isConfirmHidden?: boolean;
/**
* Redux store dispatch function.
*/
@@ -56,11 +61,14 @@ class WaitForOwnerDialog extends Component<IProps> {
* @returns {ReactElement}
*/
render() {
const { _isConfirmHidden } = this.props;
return (
<ConfirmDialog
cancelLabel = { this.props._alternativeCancelText ? 'dialog.WaitingForHostButton' : 'dialog.Cancel' }
confirmLabel = 'dialog.IamHost'
descriptionKey = 'dialog.WaitForHostMsg'
isConfirmHidden = { _isConfirmHidden }
onCancel = { this._onCancel }
onSubmit = { this._onLogin } />
);
@@ -97,9 +105,11 @@ class WaitForOwnerDialog extends Component<IProps> {
*/
function mapStateToProps(state: IReduxState) {
const { membersOnly, lobbyWaitingForHost } = state['features/base/conference'];
const { locationURL } = state['features/base/connection'];
return {
_alternativeCancelText: membersOnly && lobbyWaitingForHost
_alternativeCancelText: membersOnly && lobbyWaitingForHost,
_isConfirmHidden: locationURL?.hostname?.includes('8x8.vc')
};
}

View File

@@ -13,28 +13,66 @@ export const isTokenAuthEnabled = (config: IConfig): boolean =>
/**
* Returns the state that we can add as a parameter to the tokenAuthUrl.
*
* @param {URL} locationURL - The location URL.
* @param {Object} options: - Config options {
* audioMuted: boolean | undefined
* audioOnlyEnabled: boolean | undefined,
* skipPrejoin: boolean | undefined,
* videoMuted: boolean | undefined
* }.
* @param {string?} roomName - The room name.
* @param {string?} tenant - The tenant name if any.
* @param {boolean} skipPrejoin - Whether to skip pre-join page.
*
* @returns {Object} The state object.
*/
export const _getTokenAuthState = (
locationURL: URL,
options: {
audioMuted: boolean | undefined;
audioOnlyEnabled: boolean | undefined;
skipPrejoin: boolean | undefined;
videoMuted: boolean | undefined;
},
roomName: string | undefined,
tenant: string | undefined,
skipPrejoin: boolean | undefined = false): object => {
tenant: string | undefined): object => {
const state = {
room: roomName,
roomSafe: getBackendSafeRoomName(roomName),
tenant
};
const {
audioMuted = false,
audioOnlyEnabled = false,
skipPrejoin = false,
videoMuted = false
} = options;
if (audioMuted) {
// @ts-ignore
state['config.startWithAudioMuted'] = true;
}
if (audioOnlyEnabled) {
// @ts-ignore
state['config.startAudioOnly'] = true;
}
if (skipPrejoin) {
// We have already shown the prejoin screen, no need to show it again after obtaining the token.
// @ts-ignore
state['config.prejoinConfig.enabled'] = false;
}
const params = new URLSearchParams(window.location.search);
if (videoMuted) {
// @ts-ignore
state['config.startWithVideoMuted'] = true;
}
const params = new URLSearchParams(locationURL.hash);
for (const [ key, value ] of params) {
// we allow only config and interfaceConfig overrides in the state

View File

@@ -14,9 +14,15 @@ export * from './functions.any';
* argument to this method.
*
* @param {Object} config - Configuration state object from store. A URL pattern pointing to the login service.
* @param {string} roomName - The name of the conference room for which the user will be authenticated.
* @param {string} tenant - The name of the conference tenant.
* @param {string} skipPrejoin - The name of the conference room for which the user will be authenticated.
* @param {URL} locationURL - The location URL.
* @param {Object} options: - Config options {
* audioMuted: boolean | undefined
* audioOnlyEnabled: boolean | undefined,
* skipPrejoin: boolean | undefined,
* videoMuted: boolean | undefined
* }.
* @param {string?} roomName - The room name.
* @param {string?} tenant - The tenant name if any.
*
* @returns {Promise<string|undefined>} - The URL pointing to JWT login service or
* <tt>undefined</tt> if the pattern stored in config is not a string and the URL can not be
@@ -24,9 +30,23 @@ export * from './functions.any';
*/
export const getTokenAuthUrl = (
config: IConfig,
locationURL: URL,
options: {
audioMuted: boolean | undefined;
audioOnlyEnabled: boolean | undefined;
skipPrejoin: boolean | undefined;
videoMuted: boolean | undefined;
},
roomName: string | undefined,
tenant: string | undefined,
skipPrejoin: boolean | undefined = false): Promise<string | undefined> => {
// eslint-disable-next-line max-params
tenant: string | undefined): Promise<string | undefined> => {
const {
audioMuted = false,
audioOnlyEnabled = false,
skipPrejoin = false,
videoMuted = false
} = options;
let url = config.tokenAuthUrl;
@@ -35,7 +55,17 @@ export const getTokenAuthUrl = (
}
if (url.indexOf('{state}')) {
const state = _getTokenAuthState(roomName, tenant, skipPrejoin);
const state = _getTokenAuthState(
locationURL,
{
audioMuted,
audioOnlyEnabled,
skipPrejoin,
videoMuted
},
roomName,
tenant
);
// Append ios=true or android=true to the token URL.
// @ts-ignore

View File

@@ -32,9 +32,15 @@ function _cryptoRandom() {
* argument to this method.
*
* @param {Object} config - Configuration state object from store. A URL pattern pointing to the login service.
* @param {string} roomName - The name of the conference room for which the user will be authenticated.
* @param {string} tenant - The name of the conference tenant.
* @param {string} skipPrejoin - The name of the conference room for which the user will be authenticated.
* @param {URL} locationURL - The location URL.
* @param {Object} options: - Config options {
* audioMuted: boolean | undefined
* audioOnlyEnabled: boolean | undefined,
* skipPrejoin: boolean | undefined,
* videoMuted: boolean | undefined
* }.
* @param {string?} roomName - The room name.
* @param {string?} tenant - The tenant name if any.
*
* @returns {Promise<string|undefined>} - The URL pointing to JWT login service or
* <tt>undefined</tt> if the pattern stored in config is not a string and the URL can not be
@@ -42,9 +48,23 @@ function _cryptoRandom() {
*/
export const getTokenAuthUrl = (
config: IConfig,
locationURL: URL,
options: {
audioMuted: boolean | undefined;
audioOnlyEnabled: boolean | undefined;
skipPrejoin: boolean | undefined;
videoMuted: boolean | undefined;
},
roomName: string | undefined,
tenant: string | undefined,
skipPrejoin: boolean | undefined = false): Promise<string | undefined> => {
// eslint-disable-next-line max-params
tenant: string | undefined): Promise<string | undefined> => {
const {
audioMuted = false,
audioOnlyEnabled = false,
skipPrejoin = false,
videoMuted = false
} = options;
let url = config.tokenAuthUrl;
@@ -53,7 +73,17 @@ export const getTokenAuthUrl = (
}
if (url.indexOf('{state}')) {
const state = _getTokenAuthState(roomName, tenant, skipPrejoin);
const state = _getTokenAuthState(
locationURL,
{
audioMuted,
audioOnlyEnabled,
skipPrejoin,
videoMuted
},
roomName,
tenant
);
if (browser.isElectron()) {
// @ts-ignore

View File

@@ -13,7 +13,9 @@ import {
JitsiConferenceErrors,
JitsiConnectionErrors
} from '../base/lib-jitsi-meet';
import { MEDIA_TYPE } from '../base/media/constants';
import MiddlewareRegistry from '../base/redux/MiddlewareRegistry';
import { isLocalTrackMuted } from '../base/tracks/functions.any';
import { parseURIString } from '../base/util/uri';
import { openLogoutDialog } from '../settings/actions';
@@ -255,8 +257,11 @@ function _handleLogin({ dispatch, getState }: IStore) {
const state = getState();
const config = state['features/base/config'];
const room = state['features/base/conference'].room;
const { locationURL = { href: '' } } = state['features/base/connection'];
const { locationURL = { href: '' } as URL } = state['features/base/connection'];
const { tenant } = parseURIString(locationURL.href) || {};
const { enabled: audioOnlyEnabled } = state['features/base/audio-only'];
const audioMuted = isLocalTrackMuted(state['features/base/tracks'], MEDIA_TYPE.AUDIO);
const videoMuted = isLocalTrackMuted(state['features/base/tracks'], MEDIA_TYPE.VIDEO);
if (!room) {
logger.warn('Cannot handle login, room is undefined!');
@@ -270,7 +275,18 @@ function _handleLogin({ dispatch, getState }: IStore) {
return;
}
getTokenAuthUrl(config, room, tenant, true)
getTokenAuthUrl(
config,
locationURL,
{
audioMuted,
audioOnlyEnabled,
skipPrejoin: true,
videoMuted
},
room,
tenant
)
.then((tokenAuthServiceUrl: string | undefined) => {
if (!tokenAuthServiceUrl) {
logger.warn('Cannot handle login, token service URL is not set');

View File

@@ -1,6 +1,7 @@
import { AnyAction } from 'redux';
import MiddlewareRegistry from '../../base/redux/MiddlewareRegistry';
import MiddlewareRegistry from '../redux/MiddlewareRegistry';
import { inIframe } from '../util/iframeUtils';
import { APP_WILL_MOUNT, APP_WILL_UNMOUNT } from './actionTypes';
import logger from './logger';
@@ -21,7 +22,9 @@ MiddlewareRegistry.register(() => (next: Function) => async (action: AnyAction)
switch (action.type) {
case APP_WILL_MOUNT: {
if ('PressureObserver' in globalThis) {
// Disable it inside an iframe until Google fixes the origin trial for 3rd party sources:
// https://bugs.chromium.org/p/chromium/issues/detail?id=1504167
if (!inIframe() && 'PressureObserver' in globalThis) {
pressureObserver = new window.PressureObserver(
(records: typeof window.PressureRecord) => {
logger.info('Compute pressure state changed:', JSON.stringify(records));

View File

@@ -2,6 +2,7 @@ import React, { PureComponent } from 'react';
import { connect } from 'react-redux';
import { IReduxState } from '../../../app/types';
import { IconUser } from '../../icons/svg';
import { getParticipantById } from '../../participants/functions';
import { IParticipant } from '../../participants/types';
import { getAvatarColor, getInitials, isCORSAvatarURL } from '../functions';
@@ -182,6 +183,7 @@ class Avatar<P extends IProps> extends PureComponent<P, IState> {
const avatarProps: AbstractProps & {
className?: string;
iconUser?: any;
id?: string;
status?: string;
testId?: string;
@@ -226,6 +228,10 @@ class Avatar<P extends IProps> extends PureComponent<P, IState> {
avatarProps.initials = initials;
}
if (navigator.product !== 'ReactNative') {
avatarProps.iconUser = IconUser;
}
return (
<StatelessAvatar
{ ...avatarProps } />

View File

@@ -2,7 +2,6 @@ import React, { useCallback } from 'react';
import { makeStyles } from 'tss-react/mui';
import Icon from '../../../icons/components/Icon';
import { IconUser } from '../../../icons/svg';
import { withPixelLineHeight } from '../../../styles/functions.web';
import { isIcon } from '../../functions';
import { IAvatarProps } from '../../types';
@@ -122,6 +121,7 @@ const useStyles = makeStyles()(theme => {
const StatelessAvatar = ({
className,
color,
iconUser,
id,
initials,
onAvatarLoadError,
@@ -212,7 +212,7 @@ const StatelessAvatar = ({
style = { _getAvatarStyle() }>
<Icon
size = { '50%' }
src = { IconUser } />
src = { iconUser } />
</div>
);
};

View File

@@ -9,7 +9,7 @@ const AVATAR_COLORS = [
'#B23683',
'#F96E57',
'#4380E2',
'#2AA076',
'#238561',
'#00A8B3'
];
const wordSplitRegex = (/\s+|\.+|_+|;+|-+|,+|\|+|\/+|\\+|"+|'+|\(+|\)+|#+|&+/);

View File

@@ -5,6 +5,11 @@ export interface IAvatarProps {
*/
color?: string;
/**
* The user icon(browser only).
*/
iconUser?: any;
/**
* Initials to be used to render the initials based avatars.
*/

View File

@@ -510,15 +510,18 @@ export function conferenceWillJoin(conference?: IJitsiConference) {
*
* @param {JitsiConference} conference - The JitsiConference instance which will
* be left by the local participant.
* @param {boolean} isRedirect - Indicates if the action has been dispatched as part of visitor promotion.
* @returns {{
* type: CONFERENCE_LEFT,
* conference: JitsiConference
* conference: JitsiConference,
* isRedirect: boolean
* }}
*/
export function conferenceWillLeave(conference?: IJitsiConference) {
export function conferenceWillLeave(conference?: IJitsiConference, isRedirect?: boolean) {
return {
type: CONFERENCE_WILL_LEAVE,
conference
conference,
isRedirect
};
}
@@ -897,15 +900,20 @@ export function setObfuscatedRoom(obfuscatedRoom: string, obfuscatedRoomSource:
*
* @param {(string|undefined)} room - The name of the room of the conference to
* be joined.
* @param {boolean|undefined} willShowPrejoin - Whether the prejoin should be hidden or not.
* NOTE: This argument is used only for mobile currently!
*
* @returns {{
* type: SET_ROOM,
* room: string
* room: string,
* willShowPrejoin: boolean
* }}
*/
export function setRoom(room?: string) {
export function setRoom(room?: string, willShowPrejoin?: boolean) {
return {
type: SET_ROOM,
room
room,
willShowPrejoin
};
}
@@ -1008,7 +1016,7 @@ export function redirect(vnode: string, focusJid: string, username: string) {
}
dispatch(overwriteConfig(newConfig)) // @ts-ignore
.then(() => dispatch(conferenceWillLeave(conference || joining)))
.then(() => dispatch(conferenceWillLeave(conference || joining, true)))
.then(() => dispatch(disconnect()))
.then(() => dispatch(setIAmVisitor(Boolean(vnode))))

View File

@@ -246,8 +246,6 @@ export function getConferenceOptions(stateful: IStateful) {
delete config.analytics?.scriptURLs;
delete config.analytics?.amplitudeAPPKey;
delete config.analytics?.googleAnalyticsTrackingId;
delete options.callStatsID;
delete options.callStatsSecret;
}
return options;

View File

@@ -14,8 +14,10 @@ import { reloadNow } from '../../app/actions';
import { IStore } from '../../app/types';
import { removeLobbyChatParticipant } from '../../chat/actions.any';
import { openDisplayNamePrompt } from '../../display-name/actions';
import { isVpaasMeeting } from '../../jaas/functions';
import { showErrorNotification } from '../../notifications/actions';
import { NOTIFICATION_TIMEOUT_TYPE } from '../../notifications/constants';
import { hasDisplayName } from '../../prejoin/utils';
import { stopLocalVideoRecording } from '../../recording/actions.any';
import LocalRecordingManager from '../../recording/components/Recording/LocalRecordingManager';
import { iAmVisitor } from '../../visitors/functions';
@@ -276,7 +278,9 @@ function _conferenceJoined({ dispatch, getState }: IStore, next: Function, actio
if (requireDisplayName
&& !getLocalParticipant(getState)?.name
&& !conference.isHidden()) {
dispatch(openDisplayNamePrompt(undefined));
dispatch(openDisplayNamePrompt({
validateInput: hasDisplayName
}));
}
return result;
@@ -303,7 +307,7 @@ async function _connectionEstablished({ dispatch, getState }: IStore, next: Func
// if there is token auth URL defined and local participant is using jwt
// this means it is logged in when connection is established, so we can change the state
if (tokenAuthUrl) {
if (tokenAuthUrl && !isVpaasMeeting(getState())) {
let email;
if (getState()['features/base/jwt'].jwt) {

View File

@@ -73,7 +73,6 @@ export interface IJitsiConference {
getSsrcByTrack: Function;
grantOwner: Function;
isAVModerationSupported: Function;
isCallstatsEnabled: Function;
isE2EEEnabled: Function;
isE2EESupported: Function;
isEndConferenceSupported: Function;

View File

@@ -157,6 +157,13 @@ export interface INoiseSuppressionConfig {
};
}
export interface IWhiteboardConfig {
collabServerBaseUrl?: string;
enabled?: boolean;
limitUrl?: string;
userLimit?: number;
}
export interface IWatchRTCConfiguration {
allowBrowserLogCollection?: boolean;
collectionInterval?: number;
@@ -224,28 +231,8 @@ export interface IConfig {
callDisplayName?: string;
callFlowsEnabled?: boolean;
callHandle?: string;
callStatsConfigParams?: {
additionalIDs?: {
customerID?: string;
fqExtensionID?: string;
meetingsName?: string;
pbxExtensionID?: string;
pbxID?: string;
productName?: string;
serverName?: string;
sessionID?: string;
tenantID?: string;
};
applicationVersion?: string;
collectIP?: boolean;
collectLegacyStats?: boolean;
disableBeforeUnloadHandler?: boolean;
disablePrecalltest?: boolean;
siteID?: string;
};
callStatsID?: string;
callStatsSecret?: string;
callUUID?: string;
cameraFacingMode?: string;
channelLastN?: number;
chromeExtensionBanner?: {
chromeExtensionsInfo?: Array<{ id: string; path: string; }>;
@@ -452,6 +439,7 @@ export interface IConfig {
inviteServiceCallFlowsUrl?: string;
inviteServiceUrl?: string;
jaasActuatorUrl?: string;
jaasConferenceCreatorUrl?: string;
jaasFeedbackMetadataURL?: string;
jaasTokenUrl?: string;
legalUrls?: {
@@ -513,6 +501,7 @@ export interface IConfig {
pcStatsInterval?: number;
peopleSearchQueryTypes?: string[];
peopleSearchUrl?: string;
preferBosh?: boolean;
preferredTranscribeLanguage?: string;
prejoinConfig?: {
enabled?: boolean;
@@ -571,7 +560,6 @@ export interface IConfig {
subject?: string;
testing?: {
assumeBandwidth?: boolean;
callStatsThreshold?: number;
disableE2EE?: boolean;
mobileXmppWsThreshold?: number;
noAutoPlayVideo?: boolean;
@@ -630,8 +618,5 @@ export interface IConfig {
customUrl?: string;
disabled?: boolean;
};
whiteboard?: {
collabServerBaseUrl?: string;
enabled?: boolean;
};
whiteboard?: IWhiteboardConfig;
}

View File

@@ -23,6 +23,7 @@ export default [
'avgRtpStatsN',
'backgroundAlpha',
'breakoutRooms',
'bridgeChannel',
'buttonsWithNotifyClick',
/**
@@ -54,10 +55,6 @@ export default [
* @type string
*/
'callHandle',
'callStatsConfIDNamespace',
'callStatsConfigParams',
'callStatsID',
'callStatsSecret',
/**
* The UUID of the CallKit call representing the conference/meeting
@@ -74,6 +71,7 @@ export default [
*/
'callUUID',
'cameraFacingMode',
'conferenceInfo',
'channelLastN',
'connectionIndicators',
@@ -158,7 +156,6 @@ export default [
'filmstrip',
'firefox_fake_device',
'flags',
'forceJVB121Ratio',
'forceTurnRelay',
'gatherStats',
'giphy',
@@ -197,6 +194,7 @@ export default [
'participantMenuButtonsWithNotifyClick',
'participantsPane',
'pcStatsInterval',
'preferBosh',
'prejoinConfig',
'prejoinPageEnabled',
'recordingService',

View File

@@ -28,8 +28,6 @@ export function _cleanupConfig(config: IConfig) {
delete config.analytics?.rtcstatsUseLegacy;
delete config.analytics?.obfuscateRoomName;
delete config.analytics?.watchRTCEnabled;
delete config.callStatsID;
delete config.callStatsSecret;
delete config.watchRTCConfigParams;
config.giphy = { enabled: false };
}

View File

@@ -27,6 +27,7 @@ import { ConnectionFailedError, IIceServers } from './types';
*/
interface IOptions extends IConfigState {
iceServersOverride?: IIceServers;
preferVisitor?: boolean;
}
/**
@@ -112,7 +113,7 @@ export function constructOptions(state: IReduxState) {
// redux store.
const options: IOptions = _.cloneDeep(state['features/base/config']);
const { locationURL } = state['features/base/connection'];
const { locationURL, preferVisitor } = state['features/base/connection'];
const params = parseURLParams(locationURL || '');
const iceServersOverride = params['iceServers.replace'];
@@ -120,7 +121,7 @@ export function constructOptions(state: IReduxState) {
options.iceServersOverride = iceServersOverride;
}
const { bosh } = options;
const { bosh, preferBosh } = options;
let { websocket } = options;
// TESTING: Only enable WebSocket for some percentage of users.
@@ -130,6 +131,10 @@ export function constructOptions(state: IReduxState) {
}
}
if (preferBosh) {
websocket = undefined;
}
// WebSocket is preferred over BOSH.
const serviceUrl = websocket || bosh;
@@ -151,6 +156,10 @@ export function constructOptions(state: IReduxState) {
}
}
if (preferVisitor) {
options.preferVisitor = true;
}
return options;
}

View File

@@ -1,4 +1,5 @@
import { SET_ROOM } from '../conference/actionTypes';
import { SET_JWT } from '../jwt/actionTypes';
import { JitsiConnectionErrors } from '../lib-jitsi-meet';
import ReducerRegistry from '../redux/ReducerRegistry';
import { assign, set } from '../redux/functions';
@@ -26,6 +27,7 @@ export interface IConnectionState {
error?: ConnectionFailedError;
locationURL?: URL;
passwordRequired?: Object;
preferVisitor?: boolean;
showConnectionInfo?: boolean;
timeEstablished?: number;
}
@@ -49,6 +51,9 @@ ReducerRegistry.register<IConnectionState>(
case CONNECTION_WILL_CONNECT:
return _connectionWillConnect(state, action);
case SET_JWT:
return _setJWT(state, action);
case SET_LOCATION_URL:
return _setLocationURL(state, action);
@@ -84,6 +89,7 @@ function _connectionDisconnected(
return assign(state, {
connecting: undefined,
connection: undefined,
preferVisitor: undefined,
timeEstablished: undefined
});
}
@@ -141,7 +147,8 @@ function _connectionFailed(
error,
passwordRequired:
error.name === JitsiConnectionErrors.PASSWORD_REQUIRED
? connection : undefined
? connection : undefined,
preferVisitor: undefined
});
}
@@ -184,6 +191,22 @@ function _getCurrentConnection(baseConnectionState: IConnectionState): IConnecti
return baseConnectionState.connection || baseConnectionState.connecting;
}
/**
* Reduces a specific redux action {@link SET_JWT} of the feature
* base/connection.
*
* @param {IConnectionState} state - The redux state of the feature base/connection.
* @param {Action} action - The Redux action SET_JWT to reduce.
* @private
* @returns {Object} The new state of the feature base/connection after the
* reduction of the specified action.
*/
function _setJWT(state: IConnectionState, { preferVisitor }: { preferVisitor: boolean; }) {
return assign(state, {
preferVisitor
});
}
/**
* Reduces a specific redux action {@link SET_LOCATION_URL} of the feature
* base/connection.

View File

@@ -16,9 +16,13 @@ import {
} from './actionTypes';
import {
areDeviceLabelsInitialized,
areDevicesDifferent,
filterIgnoredDevices,
flattenAvailableDevices,
getDeviceIdByLabel,
getDeviceLabelById,
getDevicesFromURL,
logDevices,
setAudioOutputDeviceId
} from './functions';
import logger from './logger';
@@ -39,7 +43,7 @@ const DEVICE_TYPE_TO_SETTINGS_KEYS = {
userSelectedDeviceLabel: 'userSelectedAudioOutputDeviceLabel'
},
videoInput: {
currentDeviceId: 'audioOutputDeviceId',
currentDeviceId: 'cameraDeviceId',
userSelectedDeviceId: 'userSelectedCameraDeviceId',
userSelectedDeviceLabel: 'userSelectedCameraDeviceLabel'
}
@@ -137,15 +141,21 @@ export function configureInitialDevices() {
* @returns {Function}
*/
export function getAvailableDevices() {
return (dispatch: IStore['dispatch']) => new Promise(resolve => {
return (dispatch: IStore['dispatch'], getState: IStore['getState']) => new Promise(resolve => {
const { mediaDevices } = JitsiMeetJS;
if (mediaDevices.isDeviceListAvailable()
&& mediaDevices.isDeviceChangeAvailable()) {
mediaDevices.enumerateDevices((devices: MediaDeviceInfo[]) => {
dispatch(updateDeviceList(devices));
const { filteredDevices, ignoredDevices } = filterIgnoredDevices(devices);
const oldDevices = flattenAvailableDevices(getState()['features/base/devices'].availableDevices);
resolve(devices);
if (areDevicesDifferent(oldDevices, filteredDevices)) {
logDevices(ignoredDevices, 'Ignored devices on device list changed:');
dispatch(updateDeviceList(filteredDevices));
}
resolve(filteredDevices);
});
} else {
resolve([]);

View File

@@ -0,0 +1,8 @@
/**
* Prefixes of devices that will be filtered from the device list.
*
* NOTE: Currently we filter only 'Microsoft Teams Audio Device' virtual device. It seems that it can't be set
* as default device on the OS level and this use case is not handled in the code. If we add more device prefixes that
* can be default devices we should make sure to handle the default device use case.
*/
export const DEVICE_LABEL_PREFIXES_TO_IGNORE = [ 'Microsoft Teams Audio Device' ];

View File

@@ -5,6 +5,7 @@ import { ISettingsState } from '../settings/reducer';
import { setNewAudioOutputDevice } from '../sounds/functions.web';
import { parseURLParams } from '../util/parseURLParams';
import { DEVICE_LABEL_PREFIXES_TO_IGNORE } from './constants';
import logger from './logger';
import { IDevicesState } from './types';
@@ -176,6 +177,74 @@ export function filterAudioDevices(devices: MediaDeviceInfo[]) {
return devices.filter(device => device.kind === 'audioinput');
}
/**
* Filters the devices that start with one of the prefixes from DEVICE_LABEL_PREFIXES_TO_IGNORE.
*
* @param {MediaDeviceInfo[]} devices - The devices to be filtered.
* @returns {MediaDeviceInfo[]} - The filtered devices.
*/
export function filterIgnoredDevices(devices: MediaDeviceInfo[] = []) {
const ignoredDevices: MediaDeviceInfo[] = [];
const filteredDevices = devices.filter(device => {
if (!device.label) {
return true;
}
if (DEVICE_LABEL_PREFIXES_TO_IGNORE.find(prefix => device.label?.startsWith(prefix))) {
ignoredDevices.push(device);
return false;
}
return true;
});
return {
filteredDevices,
ignoredDevices
};
}
/**
* Check if the passed device arrays are different.
*
* @param {MediaDeviceInfo[]} devices1 - Array with devices to be compared.
* @param {MediaDeviceInfo[]} devices2 - Array with devices to be compared.
* @returns {boolean} - True if the device arrays are different and false otherwise.
*/
export function areDevicesDifferent(devices1: MediaDeviceInfo[] = [], devices2: MediaDeviceInfo[] = []) {
if (devices1.length !== devices2.length) {
return true;
}
for (let i = 0; i < devices1.length; i++) {
const device1 = devices1[i];
const found = devices2.find(({ deviceId, groupId, kind, label }) =>
device1.deviceId === deviceId
&& device1.groupId === groupId
&& device1.kind === kind
&& device1.label === label
);
if (!found) {
return true;
}
}
return false;
}
/**
* Flattens the availableDevices from redux.
*
* @param {IDevicesState.availableDevices} devices - The available devices from redux.
* @returns {MediaDeviceInfo[]} - The flattened array of devices.
*/
export function flattenAvailableDevices(
{ audioInput = [], audioOutput = [], videoInput = [] }: IDevicesState['availableDevices']) {
return audioInput.concat(audioOutput).concat(videoInput);
}
/**
* We want to strip any device details that are not very user friendly, like usb ids put in brackets at the end.
*
@@ -240,6 +309,35 @@ export function getVideoDeviceIds(state: IReduxState) {
return state['features/base/devices'].availableDevices.videoInput?.map(({ deviceId }) => deviceId);
}
/**
* Converts an array of device info objects into string.
*
* @param {MediaDeviceInfo[]} devices - The devices.
* @returns {string}
*/
function devicesToStr(devices?: MediaDeviceInfo[]) {
return devices?.map(device => `\t\t${device.label}[${device.deviceId}]`).join('\n');
}
/**
* Logs an array of devices.
*
* @param {MediaDeviceInfo[]} devices - The array of devices.
* @param {string} title - The title that will be printed in the log.
* @returns {void}
*/
export function logDevices(devices: MediaDeviceInfo[], title = '') {
const deviceList = groupDevicesByKind(devices);
const audioInputs = devicesToStr(deviceList.audioInput);
const audioOutputs = devicesToStr(deviceList.audioOutput);
const videoInputs = devicesToStr(deviceList.videoInput);
logger.debug(`${title}:\n`
+ `audioInput:\n${audioInputs}\n`
+ `audioOutput:\n${audioOutputs}\n`
+ `videoInput:\n${videoInputs}`);
}
/**
* Set device id of the audio output device which is currently in use.
* Empty string stands for default device.

View File

@@ -33,11 +33,10 @@ import {
import {
areDeviceLabelsInitialized,
formatDeviceLabel,
groupDevicesByKind,
logDevices,
setAudioOutputDeviceId
} from './functions';
import logger from './logger';
import { IDevicesState } from './types';
const JITSI_TRACK_ERROR_TO_MESSAGE_KEY_MAP = {
microphone: {
@@ -62,25 +61,6 @@ const JITSI_TRACK_ERROR_TO_MESSAGE_KEY_MAP = {
*/
let permissionsListener: Function | undefined;
/**
* Logs the current device list.
*
* @param {Object} deviceList - Whatever is returned by {@link groupDevicesByKind}.
* @returns {string}
*/
function logDeviceList(deviceList: IDevicesState['availableDevices']) {
const devicesToStr = (list?: MediaDeviceInfo[]) =>
list?.map(device => `\t\t${device.label}[${device.deviceId}]`).join('\n');
const audioInputs = devicesToStr(deviceList.audioInput);
const audioOutputs = devicesToStr(deviceList.audioOutput);
const videoInputs = devicesToStr(deviceList.videoInput);
logger.debug('Device list updated:\n'
+ `audioInput:\n${audioInputs}\n`
+ `audioOutput:\n${audioOutputs}\n`
+ `videoInput:\n${videoInputs}`);
}
/**
* Implements the middleware of the feature base/devices.
*
@@ -199,7 +179,7 @@ MiddlewareRegistry.register(store => next => action => {
break;
}
case UPDATE_DEVICE_LIST:
logDeviceList(groupDevicesByKind(action.devices));
logDevices(action.devices, 'Device list updated');
if (areDeviceLabelsInitialized(store.getState())) {
return _processPendingRequests(store, next, action);
}

View File

@@ -41,6 +41,11 @@ interface IProps extends AbstractProps, WithTranslation {
*/
isConfirmDestructive?: Boolean;
/**
* Whether or not the confirm button is hidden.
*/
isConfirmHidden?: Boolean;
/**
* Dialog title.
*/
@@ -60,7 +65,8 @@ class ConfirmDialog extends AbstractDialog<IProps> {
* @static
*/
static defaultProps = {
isConfirmDestructive: false
isConfirmDestructive: false,
isConfirmHidden: false
};
/**
@@ -95,6 +101,7 @@ class ConfirmDialog extends AbstractDialog<IProps> {
children,
confirmLabel,
isConfirmDestructive,
isConfirmHidden,
t,
title
} = this.props;
@@ -118,10 +125,12 @@ class ConfirmDialog extends AbstractDialog<IProps> {
label = { t(cancelLabel || 'dialog.confirmNo') }
onPress = { this._onCancel }
style = { styles.dialogButton } />
<Dialog.Button
label = { t(confirmLabel || 'dialog.confirmYes') }
onPress = { this._onSubmit }
style = { dialogButtonStyle } />
{
!isConfirmHidden && <Dialog.Button
label = { t(confirmLabel || 'dialog.confirmYes') }
onPress = { this._onSubmit }
style = { dialogButtonStyle } />
}
</Dialog.Container>
);
}

View File

@@ -20,6 +20,11 @@ interface IProps extends AbstractProps, WithTranslation {
*/
descriptionKey?: string;
/**
* Whether to display the cancel button.
*/
disableCancel?: boolean;
/**
* An optional initial value to initiate the field with.
*/
@@ -52,6 +57,11 @@ interface IState extends AbstractState {
* The current value of the field.
*/
fieldValue?: string;
/**
* The result of the input validation.
*/
isValid: boolean;
}
/**
@@ -68,6 +78,7 @@ class InputDialog extends AbstractDialog<IProps, IState> {
this.state = {
fieldValue: props.initialValue,
isValid: props.validateInput ? props.validateInput(props.initialValue) : true,
submitting: false
};
@@ -115,10 +126,11 @@ class InputDialog extends AbstractDialog<IProps, IState> {
</Dialog.Description>
)
}
<Dialog.Button
{!this.props.disableCancel && <Dialog.Button
label = { t('dialog.Cancel') }
onPress = { this._onCancel } />
onPress = { this._onCancel } />}
<Dialog.Button
disabled = { !this.state.isValid }
label = { t('dialog.Ok') }
onPress = { this._onSubmitValue } />
</Dialog.Container>
@@ -132,10 +144,14 @@ class InputDialog extends AbstractDialog<IProps, IState> {
* @returns {void}
*/
_onChangeText(fieldValue: string) {
if (this.props.validateInput && !this.props.validateInput(fieldValue)) {
if (this.props.validateInput) {
this.setState({
isValid: this.props.validateInput(fieldValue),
fieldValue
});
return;
}
this.setState({
fieldValue
});

View File

@@ -7,10 +7,11 @@ const { browser } = JitsiMeetJS.util;
const DEFAULT_OPTIMAL_BROWSERS = [
'chrome',
'chromium',
'electron',
'firefox',
'nwjs',
'safari'
'safari',
'webkit'
];
const DEFAULT_UNSUPPORTED_BROWSERS: string[] = [];
@@ -20,9 +21,8 @@ const browserNameToCheck = {
chromium: browser.isChromiumBased.bind(browser),
electron: browser.isElectron.bind(browser),
firefox: browser.isFirefox.bind(browser),
nwjs: browser.isNWJS.bind(browser),
opera: browser.isOpera.bind(browser),
safari: browser.isSafari.bind(browser)
safari: browser.isSafari.bind(browser),
webkit: browser.isWebKitBased.bind(browser)
};
/**

View File

@@ -23,6 +23,12 @@ export const AUDIO_MUTE_BUTTON_ENABLED = 'audio-mute.enabled';
*/
export const AUDIO_ONLY_BUTTON_ENABLED = 'audio-only.enabled';
/**
* Flag indicating that the Breakout Rooms button in the overflow menu is enabled.
* Default: enabled (true).
*/
export const BREAKOUT_ROOMS_BUTTON_ENABLED = 'breakout-rooms.enabled';
/**
* Flag indicating if calendar integration should be enabled.
* Default: enabled (true) on Android, auto-detected on iOS.

View File

@@ -65,9 +65,15 @@ export const DEFAULT_LANGUAGE = 'en';
*/
const options: i18next.InitOptions = {
backend: <HttpBackendOptions>{
loadPath: (lng: string[], ns: string[]) =>
// eslint-disable-next-line no-extra-parens
(ns[0] === 'main' ? 'lang/{{ns}}-{{lng}}.json' : 'lang/{{ns}}.json')
loadPath: (lng: string[], ns: string[]) => {
switch (ns[0]) {
case 'countries':
case 'main':
return 'lang/{{ns}}-{{lng}}.json';
default:
return 'lang/{{ns}}.json';
}
}
},
defaultNS: 'main',
fallbackLng: DEFAULT_LANGUAGE,

View File

@@ -85,7 +85,6 @@ import { default as IconSip } from './sip.svg';
import { default as IconSites } from './sites.svg';
import { default as IconRemoteControlStart } from './start-remote-control.svg';
import { default as IconRemoteControlStop } from './stop-remote-control.svg';
import { default as IconStopScreenshare } from './stop-screenshare.svg';
import { default as IconStop } from './stop.svg';
import { default as IconSubtitles } from './subtitles.svg';
import { default as IconTileView } from './tile-view.svg';
@@ -202,7 +201,6 @@ export const DEFAULT_ICON: Record<string, any> = {
IconSip,
IconSites,
IconStop,
IconStopScreenshare,
IconSubtitles,
IconTileView,
IconTrash,

View File

@@ -93,7 +93,6 @@ const {
IconSip,
IconSites,
IconStop,
IconStopScreenshare,
IconSubtitles,
IconTileView,
IconTrash,
@@ -213,7 +212,6 @@ export {
IconSip,
IconSites,
IconStop,
IconStopScreenshare,
IconSubtitles,
IconTileView,
IconTrash,

View File

@@ -1,5 +0,0 @@
<svg width="24" height="24" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M22.2803 2.78033C22.5732 2.48744 22.5732 2.01256 22.2803 1.71967C21.9874 1.42678 21.5126 1.42678 21.2197 1.71967L19.9114 3.02797C19.7769 3.00953 19.6396 3 19.5 3H4.5C2.84315 3 1.5 4.34315 1.5 6V17.25C1.5 18.3842 2.12941 19.3714 3.05799 19.8813L1.71967 21.2197C1.42678 21.5126 1.42678 21.9874 1.71967 22.2803C2.01256 22.5732 2.48744 22.5732 2.78033 22.2803L22.2803 2.78033ZM4.21616 18.7232L5.54187 17.3975C5.40631 17.4169 5.2687 17.4055 5.14194 17.3656C4.78878 17.2544 4.48676 16.9074 4.52225 16.4471C4.8467 12.239 8.62852 8.92199 13.327 8.60046V6.87396C13.327 6.08352 14.2729 5.67701 14.8464 6.22103L15.807 7.13235L18.4393 4.5H4.5C3.67157 4.5 3 5.17157 3 6V17.25C3 17.9814 3.52345 18.5905 4.21616 18.7232ZM12.7759 10.1634C10.0327 10.5417 7.82609 12.097 6.73783 14.1317C8.14978 12.9079 9.68868 12.2376 11.0531 11.8862L12.7759 10.1634Z" fill="white" />
<path d="M21 6.1607L22.283 4.87768C22.423 5.22437 22.5 5.60319 22.5 6V17.25C22.5 18.9069 21.1569 20.25 19.5 20.25H18.75C19.1642 20.25 19.5 20.5858 19.5 21C19.5 21.4142 19.1642 21.75 18.75 21.75H5.4107L8.4107 18.75H19.5C20.3284 18.75 21 18.0784 21 17.25V6.1607Z" fill="white" />
<path d="M13.327 13.8337V15.2002C13.327 15.9986 14.2893 16.4017 14.8583 15.8416L19.1656 11.6016C19.5284 11.2444 19.523 10.6577 19.1536 10.3073L17.9732 9.18747L16.9122 10.2485L17.6708 10.9682L14.827 13.7676V12.3337L13.327 13.8337Z" fill="white" />
</svg>

Before

Width:  |  Height:  |  Size: 1.5 KiB

View File

@@ -4,7 +4,6 @@
export const MEET_FEATURES = {
BRANDING: 'branding',
CALENDAR: 'calendar',
CALLSTATS: 'callstats',
FLIP: 'flip',
INBOUND_CALL: 'inbound-call',
LIVESTREAMING: 'livestreaming',

View File

@@ -186,3 +186,23 @@ export function validateJwt(jwt: string) {
return errors;
}
/**
* Extracts and returns the expiration date of jwt.
*
* @param {string|undefined} jwt - The jwt to check.
* @returns {Date} The expiration date of the jwt.
*/
export function getJwtExpirationDate(jwt: string | undefined) {
if (!jwt) {
return;
}
const payload = jwtDecode(jwt);
if (payload) {
const { exp } = payload;
return new Date(exp * 1000);
}
}

View File

@@ -153,6 +153,11 @@ function _setJWT(store: IStore, next: Function, action: AnyAction) {
_overwriteLocalParticipant(
store, { ...newUser,
features: context.features });
// eslint-disable-next-line max-depth
if (context.user && context.user.role === 'visitor') {
action.preferVisitor = true;
}
} else if (jwtPayload.name || jwtPayload.picture || jwtPayload.email) {
// there are some tokens (firebase) having picture and name on the main level.
_overwriteLocalParticipant(store, {

View File

@@ -1,11 +1,9 @@
import { IStore } from '../../app/types';
import RTCStats from '../../rtcstats/RTCStats';
import { isRTCStatsEnabled } from '../../rtcstats/functions';
import { getCurrentConference } from '../conference/functions';
/**
* Implements log storage interface from the @jitsi/logger lib. Captured
* logs are sent to CallStats.
* Implements log storage interface from the @jitsi/logger lib.
*/
export default class JitsiMeetLogStorage {
counter: number;
@@ -33,8 +31,7 @@ export default class JitsiMeetLogStorage {
}
/**
* The JitsiMeetLogStorage is ready when the CallStats are started and
* before refactoring the code it was after the conference has been joined.
* The JitsiMeetLogStorage is ready when the conference has been joined.
* A conference is considered joined when the 'conference' field is defined
* in the base/conference state.
*
@@ -73,54 +70,8 @@ export default class JitsiMeetLogStorage {
*/
storeLogs(logEntries: Array<string | any>) {
// XXX the config.callStatsApplicationLogsDisabled controls whether or not the logs will be sent to callstats.
// this is done in LJM
this.storeLogsCallstats(logEntries);
if (this.canStoreLogsRtcstats()) {
RTCStats.sendLogs(logEntries);
}
}
/**
* Store the console logs in callstats (if callstats is enabled).
*
* @param {Array<string|any>} logEntries - The log entries to send to the rtcstats server.
* @returns {void}
*/
storeLogsCallstats(logEntries: Array<string | any>) {
const conference = getCurrentConference(this.getState());
if (!conference?.isCallstatsEnabled()) {
// Discard the logs if CallStats is not enabled.
return;
}
let logMessage = `{"log${this.counter}":"\n`;
for (let i = 0, len = logEntries.length; i < len; i++) {
const logEntry = logEntries[i];
if (logEntry.timestamp) {
logMessage += `${logEntry.timestamp} `;
}
if (logEntry.count > 1) {
logMessage += `(${logEntry.count}) `;
}
logMessage += `${logEntry.text}\n`;
}
logMessage += '"}';
this.counter += 1;
// Try catch was used, because there are many variables
// on the way that could be uninitialized if the storeLogs
// attempt would be made very early (which is unlikely)
try {
conference.sendApplicationLog(logMessage);
} catch (error) {
// NOTE console is intentional here
console.error(`Failed to store the logs, msg length: ${logMessage.length} error:`, error);
}
}
}

View File

@@ -1,6 +1,6 @@
/**
* The type of redux action which stores the log collector that will be
* submitting the logs to CallStats.
* submitting the logs to a service
*
* {
* type: SET_LOG_COLLECTOR,

View File

@@ -1,8 +1,7 @@
import { SET_LOGGING_CONFIG, SET_LOG_COLLECTOR } from './actionTypes';
/**
* Stores a {@code Logger.LogCollector} instance which will be uploading logs
* to CallStats.
* Stores a {@code Logger.LogCollector} instance which will be uploading logs.
*
* @param {Logger.LogCollector} logCollector - The log collector instance to be
* stored in the Redux state of base/logging feature.

View File

@@ -106,7 +106,7 @@ function _conferenceJoined({ getState }: IStore, next: Function, action: AnyActi
logCollector.flush();
// This event listener will flush the logs, before the statistics module
// (CallStats) is stopped.
// is stopped.
//
// NOTE The LogCollector is not stopped, because this event can be
// triggered multiple times during single conference (whenever

Some files were not shown because too many files have changed in this diff Show More