Compare commits

...

123 Commits

Author SHA1 Message Date
xenia 4bd73cc368 jiti modifications >:3 2023-03-08 22:19:23 -08:00
Boris Grozev e12999d44f chore(deps) lib-jitsi-meet@latest
https://github.com/jitsi/lib-jitsi-meet/compare/v1588.0.0+04e906cc...v1589.0.0+d43c349d
2023-03-08 11:16:05 -05:00
Robert Pintilii 8982f17ce1
feat(virtual-background) Move dialog to SettingsDialog tab (#13005)
Implement redesign
2023-03-08 13:15:07 +02:00
Robert Pintilii c8f1690057
ref(feedback-dialog) Update design (#12926)
Convert file to TS
Move styles from SCSS to JSS
2023-03-08 12:46:10 +02:00
Robert Pintilii aa57309057
ref(more-tab) Update design on SettingsDialog More tab (#13006) 2023-03-08 10:40:40 +02:00
damencho fb81619fc5 fix: Fixes muc rate limit to fire occupant-pre-join.
If any handler returns a value (that isn't nil) then processing will halt and that value will be returned.
2023-03-07 18:54:06 -06:00
Hristo Terezov 5a5656020b fix(e2ee): enabled/supported flags calculation. 2023-03-07 15:36:47 -06:00
Hristo Terezov 0ff44a2f22 fix(participants-reducer):old particpant selection 2023-03-07 15:36:47 -06:00
Hristo Terezov 4d04ea325e fix(everyoneIsModerator): Optimize. 2023-03-07 15:36:47 -06:00
Hristo Terezov 42ce6dcc58 fix(e2ee): Optimize. 2023-03-07 15:36:47 -06:00
Hristo Terezov b033d0268a fix(speaker-stats): dispatch action only on change 2023-03-07 15:36:47 -06:00
Hristo Terezov 4aea40d34f fix: Batch actions. 2023-03-07 15:36:47 -06:00
Hristo Terezov e5a170fb28 fix(Filmstrip): Use id for localScreenShare. 2023-03-07 15:36:47 -06:00
Hristo Terezov d1cf5578fc fix(avatar): Remove unnecessary code. 2023-03-07 15:36:47 -06:00
Hristo Terezov 4b29af6b5f fix(lastN): Update only if neccessary. 2023-03-07 15:36:47 -06:00
bgrozev f3481576ff
doc: Document new bridgeChannel options. (#13010) 2023-03-07 14:21:41 -06:00
bgrozev 455a91a5c6
chore(deps) lib-jitsi-meet@latest (#13009)
https://github.com/jitsi/lib-jitsi-meet/compare/v1586.0.0+df2c3096...v1588.0.0+04e906cc
2023-03-07 13:44:42 -06:00
Gabriel Borlea 297ab194a8
fix(dialog-portal): set z-index to high value (#13004) 2023-03-07 16:39:27 +02:00
Christoph Settgast 077a88a803
lang: update German translation (#13000) 2023-03-07 08:17:41 +01:00
Gabriel Borlea 02c232440e
fix(av-moderation): buttons for participants pane (#12977)
* fix(av): buttons for participants pane

* fix tests

* fix lint

* rename cliked from participant pane
2023-03-06 11:05:26 -06:00
Emmanuel Pelletier f727b9295f
Use tabs ARIA design pattern when using tabbed UI (#12994)
feat(a11y): use tabs ARIA design pattern when using tabbed UI
2023-03-06 17:13:29 +02:00
Robert Pintilii 0d0bec3aad
feat(device-selection) Separate Devices into Audio and Video in Settings (#12987)
Create separate tabs for Audio and Video in the Settings Dialog
Move some settings from the More tab to Audio/ Video tab
Implement redesign
Convert some files to TS
Move some styles from SCSS to JSS
Enable device selection on welcome page
2023-03-06 15:14:52 +02:00
Emmanuel Pelletier cfb8589bef
Use focus-visible for some focus styles to fix a11y issues (#12968)
feat(a11y): fix-focus-styles
2023-03-06 12:39:46 +02:00
japm48 65730e256e fix(lang) update Spanish translation 2023-03-04 15:41:39 +01:00
Robert Pintilii 7b8b911fee
feat(shortcuts) Update dialog (#12993)
Create Shortcuts tab in Settings Dialog
Move keyboard shortcut option from More to this tab
Move shortcuts info from KeyboardShortcuts dialog to this tab
Remove KeyboardShortcuts dialog
2023-03-03 13:48:17 +02:00
Robert Pintilii 036286a1d6
feat(notification-settings) Update Sounds tab in Settings Dialog (#12990)
Rename from Sounds to Notifications
Move Notifications settings from More tab to this tab
2023-03-03 12:53:39 +02:00
Robert Pintilii d550254f31
ref(moderator-settings) Update Moderator tab in Settings Dialog (#12991)
Update design
2023-03-03 11:48:00 +02:00
Robert Pintilii b1a71d55d7
feat(profile-tab) Update Profile tab in Settings Dialog (#12992)
Implement redesign
Move some options from More to this tab
2023-03-03 10:42:59 +02:00
George Politis 17ed45799c feat: Sends the statisticsDisplayName to rtcstats. 2023-03-02 19:34:25 +01:00
Jaya Allamsetty e5681382b0 chore(deps) lib-jitsi-meet@latest
https://github.com/jitsi/lib-jitsi-meet/compare/v1585.0.0+362d1b2c...v1586.0.0+df2c3096
2023-03-01 20:58:55 -05:00
Robert Pintilii c27cb25afe
chore(deps) Upgrade eslint (#12981) 2023-03-01 13:30:43 +02:00
Avram Tudor baf5aa14e8
feat(devices) scroll overflow devices texts on hover (#12974) 2023-03-01 09:38:26 +02:00
Horatiu Muresan 29b6ce7721 fix(numbers-list) Re-add sip svg 2023-02-28 11:53:26 -06:00
Mihaela Dumitru 4f95c45e50
fix(ui) change streaming icon background + add tooltip (#12973) 2023-02-28 16:52:33 +02:00
Emmanuel Pelletier 72dd609247
feat(a11y) add headings across the app for easier screen reader nav (#12427)
feat(a11y): added headings across the app for easier screen reader nav
2023-02-28 16:52:06 +02:00
Horatiu Muresan fed74afffe
fix(sound-settings) Disable checkbox for disabled sounds (#12976) 2023-02-28 16:47:00 +02:00
Mihaela Dumitru 204f34cccb
fix(pinning) Fix whiteboard pinning behavior when stage filmstrip is enabled (#12966) 2023-02-28 14:44:37 +02:00
Emmanuel Pelletier c81777a475
Make (most) UI elements reachable via keyboard (#12657)
feat(a11y): make (most) UI elements reachable via keyboard
2023-02-28 12:21:15 +02:00
Horatiu Muresan 778bca3031
fix(always-on-top) Show participant`s avatar (#12967) 2023-02-27 16:20:40 +02:00
Avram Tudor 336fa304ce
feat(notifications) trigger iframe api event when a notification occurs (#12952)
* feat(notifications) trigger iframe api event when a notification occurs

* remove useless comment

* fix typo
2023-02-27 15:31:54 +02:00
damencho f14b69166c fix: Fixes visitors count when the data is missing. 2023-02-24 11:44:31 -06:00
Calin-Teodor e405595a11 feat(notifications): moved notifications to the bottom of the screen 2023-02-24 17:22:55 +02:00
zobadaniel cabe48d66a
lang: Add lower sorbian translation (#12947)
* add lower sorbian translation

* adjustments after using update-translation.js

* adjustments after running lint

* add translation into language list
2023-02-24 09:04:06 -06:00
Duduman Bogdan Vlad 8d7f46024b
feat(webhid) - add integration webhid telephony device (#12904) 2023-02-24 16:37:30 +02:00
damencho d7f6c2bbf0 feat: Introduces iAmVisitor mode. 2023-02-24 07:51:47 -06:00
damencho 3c69645169 feat(mobile): Adds visitors count. 2023-02-24 07:51:47 -06:00
damencho abe2fa4dd4 feat: Adds visitors count in conference info. 2023-02-24 07:51:47 -06:00
damencho 863fd12488 feat: Hide self-view and buttons in visitors mode. 2023-02-24 07:51:47 -06:00
damencho 50c4748d40 feat: Adds visitors count in participants pane. 2023-02-24 07:51:47 -06:00
damencho f83840a3bc feat: Adds initial impl of visitors feature. 2023-02-24 07:51:47 -06:00
damencho 1466d7d149 fix: Always normalizes bosh config. 2023-02-24 07:51:47 -06:00
Calinteodor d0fe034db5
feat(base/dialog): visibility control for PageReloadDialog (#12961)
* feat(base/dialog): visibility control for  PageReloadDialog
2023-02-24 13:51:27 +02:00
Дамян Минков 8225f5e363
feat: Drops external connect optimization. (#12958)
* feat: Drops external connect optimization.

A bosh only optimization which is no longer used and does not bring any significant value when measured.

* squash: Updates ljm.
2023-02-24 08:59:00 +01:00
Saúl Ibarra Corretgé c641835d0f fix(virtual-background) don't disable uploads
Even when images are provided via dyamic branding.

Fixes: https://github.com/jitsi/jitsi-meet/issues/12941
2023-02-23 16:41:27 +01:00
Horatiu Muresan 35ee92869f
feat(deeplinking) Refactor deeplinking (#12950)
- redesign deeplinking mobile page, desktop page and dial in number page
- now dial in number page is an entry point in app.bundle.
2023-02-23 17:01:55 +02:00
Stefan Plücken 9b7a5ffdd1 fix(reservations): fixes errors not being displayed when reservation system returns error. removed translations applied twice. (#11144) 2023-02-23 08:52:54 -06:00
Calin-Teodor 581c2e621c feat(notifications): fix width for notifications on all devices 2023-02-23 16:39:19 +02:00
Mihaela Dumitru f3117f3037
fix(video-layout) get pinned participant from payload to determine pinning behavior (#12951) 2023-02-23 14:41:29 +02:00
Saúl Ibarra Corretgé 877ef58dfb deps(rn) react-native-webrtc@106.0.6
Fixes to SDP negotiation and transceiver lifetime.
2023-02-23 13:08:49 +01:00
Calinteodor 19e61747b8
feat(notifications): small ui updates (#12943)
* feat(notifications): small ui updates
2023-02-23 11:49:26 +02:00
Calinteodor b4bf363237
feat(lobby): deleted knocking participant api event (#12940)
feat(lobby): make sure that that the knocking participant event is always fired
2023-02-21 13:55:03 +02:00
Calinteodor f8af9c4fae
feat(notifications): native UI updates (#12798)
* feat(notifications): native notifications UI updates
2023-02-21 11:26:04 +02:00
Nitish Kumar 9fa426d97f
fix(ParticipantsCounter)fixup badge style 2023-02-21 10:17:22 +01:00
Yash-Ambekar e3c95e376a
fix(toolbar) Removed width from toolbar (#12935) 2023-02-20 20:29:57 +02:00
Calinteodor 00ed794c50
feat(mobile/navigation): reload now navigates to conference (#12919)
* feat(mobile/navigation): navigate back to same room when reload now is initiated
2023-02-17 17:40:01 +02:00
Saúl Ibarra Corretgé b52d5629e2 chore(deps) remove unused dependencies 2023-02-17 15:03:55 +01:00
Horatiu Muresan 9d8e646d4e
fix(lobby) Fix lobby inputs (#12930) 2023-02-17 15:34:45 +02:00
Horatiu Muresan 850c0b97e4
chore(recording-notif) Show sticky notif for copy recording link (#12928) 2023-02-17 14:24:39 +02:00
Robert Pintilii 87035d0812
ref(deps) Remove atlaskit/tabs (#12927) 2023-02-17 13:36:00 +02:00
Robert Pintilii ef0168c9ff
ref(dialog) Remove atlaskit dialog (#12925) 2023-02-17 12:53:14 +02:00
Robert Pintilii df1a5a25d4
ref(desktop-picker) Replace atlaskit tabs with our component (#12910)
Fixes wrong focus on desktop picker dialog
2023-02-17 11:34:47 +02:00
Robert Pintilii c424884201
ref(settings-dialog) Update to use new Dialog component (#12912)
* ref(settings-dialog) Update to use new Dialog component

Created new DialogWithTabs component
Refactored Dialog into Dialog and BaseDialog
Updated dialog functionality on mobile
2023-02-17 11:34:30 +02:00
Дамян Минков 0a464a5223
feat: Avoids joining participants before jicofo is in the room. (#12923)
* feat: Avoids joining participants before jicofo is in the room.

* squash: Move away from global hook to be able to use it per muc component.
2023-02-16 18:16:43 -06:00
Horatiu Muresan 8cd62bc132
fix(external-api) Unpin all participants when participant id is null (#12921) 2023-02-16 18:14:10 +02:00
Jaya Allamsetty 123a74b38b fix(video-quality) Add pinned participants to selectedSources.
When mulltiple videos are pinned to the stage filmstrip, the expectation is that the bridge will forward all the videos even if they are of lower quality. For this, the video sources need to be added to selectedSources instead of onStageSources.
2023-02-16 10:36:22 -05:00
Christoph Settgast dbeca806bb lang: update German translation 2023-02-15 14:03:20 -06:00
Jaya Allamsetty f790d3e3ed chore(deps) lib-jitsi-meet@latest
https://github.com/jitsi/lib-jitsi-meet/compare/v1582.0.0+829f5ac0...v1583.0.0+931ca368
2023-02-15 13:59:05 -05:00
Horatiu Muresan a12f7fc4d2
fix(follow-me-pinning) Fix pin/unpin when follow-me (#12911) 2023-02-15 19:08:08 +02:00
Gabriel Borlea 456ce38a10 fix(context-menu): set height for context menu when it does not have enough space at top 2023-02-15 19:06:57 +02:00
Gabriel Borlea 72ef1668f2 fix(video-background): set dialog add button margin to right size 2023-02-15 19:06:57 +02:00
Jaya Allamsetty fce8f52574 chore(deps) lib-jitsi-meet@latest
https://github.com/jitsi/lib-jitsi-meet/compare/v1578.0.0+5855ca72...v1582.0.0+829f5ac0
2023-02-15 09:15:01 -05:00
Titus Moldovan 8fcfd7a308 fix(rn) makes the preferedCode vp8 and enabled p2p 2023-02-14 16:40:38 +01:00
Saúl Ibarra Corretgé 04a41395c8 fix(notifications) remove dead code 2023-02-14 11:51:47 +01:00
Robert Pintilii 18e8201167
fix(participants-counter) Style fix (#12907) 2023-02-14 12:40:29 +02:00
Robert Pintilii 27b8794d8c
feat(video-picker) Redesign (#12902)
Convert some files to TS
Implement redesign
Add Virtual background and Flip video to picker menu
2023-02-14 12:15:37 +02:00
Calinteodor 3cb0df579c
feat(overlay): native page reload dialog (#12667)
feat(overlay): native feature removal + replaced PageReloadOverlay with PageReloadDialog
2023-02-14 11:50:46 +02:00
Robert Pintilii 22ded30b61
feat(audio-menu) Redesign audio picker menu (#12899)
Convert some files to TS
Remove unnecessary files
Implement redesign
Add noise suppression to picker menu
Fix Popover placement on browser resize
2023-02-13 16:01:08 +02:00
Robert Pintilii 533deea5fd
ref(password-required) Update component to use new Dialog (#12900)
Convert component to TS
2023-02-13 15:47:42 +02:00
Saúl Ibarra Corretgé 46c6d1057d fix(ios) avoid getting duplicated SDK events
UIView has 2 designated initializers: initWithFrame and initWithCoder,
which means either of them is going to be called, whatever the
constructor.

THus overriding init will cause creating new (and unnecessary)
observers.

Ref: https://community.jitsi.org/t/duplicate-delegate-calls/121051/6
Fixes: https://github.com/jitsi/jitsi-meet/issues/12892
2023-02-13 14:20:44 +01:00
Titus Moldovan 45aa53b1a6 chore(rn) updates react-native-gesture-handler 2023-02-13 15:11:31 +02:00
damencho 7d65123495 fix: Drop unused dependency. 2023-02-13 06:48:53 +01:00
Maria Mironova e1ac000cd1
fix(chat) keep avatar width inside flex container (#12891)
Co-authored-by: Maria Mironova <maria@example.com>
2023-02-10 14:31:11 +02:00
Saúl Ibarra Corretgé f98036efa1 fixup! 2023-02-09 16:38:03 +01:00
Saúl Ibarra Corretgé 23aeafcc93 fixup! 2023-02-09 16:38:03 +01:00
Saúl Ibarra Corretgé 0ffe2c2c87 fixup! 2023-02-09 16:38:03 +01:00
Saúl Ibarra Corretgé dec58afe46 feat(icons) add new moderator icon 2023-02-09 16:38:03 +01:00
Mihaela Dumitru 2aa770e532
feat(config) add flag to disable lobby password & group lobby config flags (#12793) 2023-02-09 14:46:25 +02:00
Gabriel Borlea 1a113ba733
feat: add custom buttons for participant menu and toolbar via config (#12832)
* add custom remote menu button

* add config for custom buttons

* whitelist custom buttons flag

* add toolbox custom button

* fix notify toolbox buttons

* whitelist toolbar custom buttons

* rename and fix notify

* rename participant remote menu

* revert some flag wrong changes

* fix some formatings

* add undefined type to custom buttons toolbox

* code review

* code review 2

* fix linting issue
2023-02-09 13:12:00 +02:00
dependabot[bot] 3a5833829c chore(deps): bump @sideway/formula from 3.0.0 to 3.0.1
Bumps [@sideway/formula](https://github.com/sideway/formula) from 3.0.0 to 3.0.1.
- [Release notes](https://github.com/sideway/formula/releases)
- [Commits](https://github.com/sideway/formula/compare/v3.0.0...v3.0.1)

---
updated-dependencies:
- dependency-name: "@sideway/formula"
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-09 10:36:48 +01:00
Priyanshu Sharma e6d1f039d2
fix(participant-count) Fix mobile style (#12880) 2023-02-09 10:10:16 +02:00
Horatiu Muresan fef78152e1
fix(remote-control) Add some missing key codes for numpad (#12879) 2023-02-07 17:00:59 +02:00
Mihaela Dumitru 84221c5c13
feat(dialout) check appId for permission to call outbound destination (#12871) 2023-02-07 16:18:27 +02:00
Calinteodor 3e59359563
feat(base/icon): removed burger icon (#12876)
* feat(base/icons): removed unused icon
2023-02-07 13:02:15 +02:00
Calin-Teodor e69db9b878 feat(participants-pane): removed unused action 2023-02-07 12:40:35 +02:00
Robert Pintilii ae7e441e21
fix(context-menu) Minor style fixes (#12874) 2023-02-07 12:05:46 +02:00
Robert Pintilii 6b8afbcceb
fix(filmstrip) Minor style fixes (#12870) 2023-02-07 10:10:28 +02:00
José Luís Andrade d712a565f8
lang: Update Portuguese translation (#12647)
* Update Portuguese translation

* Small fix in the translation

* Add new update

* feat(audioOnly) translation

* chore(welcome-page) translation

* translate "noMicPermission"
2023-02-03 11:41:11 -06:00
Saúl Ibarra Corretgé 36bfbeb81d fix(etherpad) avoid using deprecated property 2023-02-03 15:52:26 +01:00
Saúl Ibarra Corretgé e7b16b0daf fix(etherpad) fix CORS issues
Avoid modifying the iframe. We don't really need to bubble up mouse
events anymore since the Etherpad frame won't overlap with the toolbar
or filmstrip, so when the user moves over those areas it will just show
up.
2023-02-03 15:52:26 +01:00
Saúl Ibarra Corretgé 92a891e7d3 chore(rn,deps) react-native-webrtc@latest
Brings back Metal rendering and other SDP negotiation improvements.
2023-02-03 13:34:10 +01:00
Robert Pintilii 09e4696c60
feat(title-bar) Update design (#12851)
Convert some files to TS
Move some styles from SCSS to JSS
Update design
2023-02-03 13:31:00 +02:00
Robert Pintilii a594aac078
fix(toolbar) Fix styles (#12863) 2023-02-03 13:30:38 +02:00
Saúl Ibarra Corretgé 9409e64066 fix(deps) remove nunused dependencies 2023-02-03 11:57:22 +02:00
Robert Pintilii 12318db4c7
fix(local-rec) Handle no mic permission (#12862) 2023-02-03 11:34:07 +02:00
Shawn 749c26b74c fix(toolbox): consistent color of hangup buttons 2023-02-02 15:55:17 +01:00
Robert10B babe62eb6d
fix(lang) updated Dutch translation 2023-02-02 13:50:25 +01:00
Robert Pintilii fbc0a502e7
ref(TS) Improve TS (#12656) 2023-02-02 13:12:31 +02:00
Shawn ab262ec8b1 fix(toolbox): do not show hangup menu for non-moderators 2023-02-02 10:50:15 +01:00
Maciej Zakrzewski cced41665d
fix(local-recording) after IFrame sandboxing
Fix local recording saving not working after IFrame sanbox introduciton. The allow-downloads flag was missing.
2023-02-02 10:45:48 +01:00
Mihaela Dumitru f95e167779 feat(giphy) add sample resource for giphy-proxy 2023-02-02 10:30:40 +01:00
damencho bf1b7cc856 fix: Fixes follow-me on the side that is screen sharing. 2023-02-01 07:12:15 -06:00
damencho 091e3f69dc fix: Fixes follow-me when there is a screenshare. 2023-01-31 08:40:56 -06:00
Horatiu Muresan 42868c9ec2
fix(context-menu) Fit the overflow menu on small heights (#12848) 2023-01-31 15:19:01 +02:00
426 changed files with 11850 additions and 8904 deletions

View File

@ -44,12 +44,8 @@ deploy-appbundle:
cp \
$(BUILD_DIR)/app.bundle.min.js \
$(BUILD_DIR)/app.bundle.min.js.map \
$(BUILD_DIR)/do_external_connect.min.js \
$(BUILD_DIR)/do_external_connect.min.js.map \
$(BUILD_DIR)/external_api.min.js \
$(BUILD_DIR)/external_api.min.js.map \
$(BUILD_DIR)/dial_in_info_bundle.min.js \
$(BUILD_DIR)/dial_in_info_bundle.min.js.map \
$(BUILD_DIR)/alwaysontop.min.js \
$(BUILD_DIR)/alwaysontop.min.js.map \
$(OUTPUT_DIR)/analytics-ga.js \
@ -70,7 +66,6 @@ deploy-lib-jitsi-meet:
$(LIBJITSIMEET_DIR)/dist/umd/lib-jitsi-meet.min.js \
$(LIBJITSIMEET_DIR)/dist/umd/lib-jitsi-meet.min.map \
$(LIBJITSIMEET_DIR)/dist/umd/lib-jitsi-meet.e2ee-worker.js \
$(LIBJITSIMEET_DIR)/connection_optimization/external_connect.js \
$(LIBJITSIMEET_DIR)/modules/browser/capabilities.json \
$(DEPLOY_DIR)
@ -131,7 +126,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 connection_optimization favicon.ico fonts images libs static sounds LICENSE lang source_package/jitsi-meet && \
cp -r *.js *.html resources/*.txt favicon.ico 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

@ -76,7 +76,6 @@ dependencies {
implementation project(':react-native-get-random-values')
implementation project(':react-native-immersive')
implementation project(':react-native-keep-awake')
implementation project(':react-native-masked-view_masked-view')
implementation project(':react-native-orientation-locker')
implementation project(':react-native-pager-view')
implementation project(':react-native-performance')

View File

@ -119,7 +119,6 @@ class ReactInstanceManagerHolder {
new com.oblador.performance.PerformancePackage(),
new com.reactnativecommunity.slider.ReactSliderPackage(),
new com.brentvatne.react.ReactVideoPackage(),
new org.reactnative.maskedview.RNCMaskedViewPackage(),
new com.reactnativecommunity.webview.RNCWebViewPackage(),
new com.kevinresol.react_native_default_preference.RNDefaultPreferencePackage(),
new com.learnium.RNDeviceInfo.RNDeviceInfo(),

View File

@ -31,8 +31,6 @@ include ':react-native-immersive'
project(':react-native-immersive').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-immersive/android')
include ':react-native-keep-awake'
project(':react-native-keep-awake').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-keep-awake/android')
include ':react-native-masked-view_masked-view'
project(':react-native-masked-view_masked-view').projectDir = new File(rootProject.projectDir, '../node_modules/@react-native-masked-view/masked-view/android')
include ':react-native-orientation-locker'
project(':react-native-orientation-locker').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-orientation-locker/android')
include ':react-native-pager-view'

11
app.js
View File

@ -33,17 +33,6 @@ window.APP = {
API,
conference,
// Used by do_external_connect.js if we receive the attach data after
// connect was already executed. status property can be 'initialized',
// 'ready', or 'connecting'. We are interested in 'ready' status only which
// means that connect was executed but we have to wait for the attach data.
// In status 'ready' handler property will be set to a function that will
// finish the connect process when the attach data or error is received.
connect: {
handler: null,
status: 'initialized'
},
// Used for automated performance tests.
connectionTimes: {
'index.loaded': window.indexLoadedTime

View File

@ -141,7 +141,7 @@ import {
showNotification,
showWarningNotification
} from './react/features/notifications';
import { mediaPermissionPromptVisibilityChanged } from './react/features/overlay';
import { mediaPermissionPromptVisibilityChanged } from './react/features/overlay/actions';
import { suspendDetected } from './react/features/power-monitor';
import { initPrejoin, makePrecallTest, setJoiningInProgress } from './react/features/prejoin/actions';
import { isPrejoinPageVisible } from './react/features/prejoin/functions';
@ -153,6 +153,7 @@ import { createRnnoiseProcessor } from './react/features/stream-effects/rnnoise'
import { endpointMessageReceived } from './react/features/subtitles';
import { handleToggleVideoMuted } from './react/features/toolbox/actions.any';
import { muteLocal } from './react/features/video-menu/actions.any';
import { setIAmVisitor } from './react/features/visitors/actions';
import UIEvents from './service/UI/UIEvents';
const logger = Logger.getLogger(__filename);
@ -342,6 +343,8 @@ class ConferenceConnector {
case JitsiConferenceErrors.REDIRECTED: {
generateVisitorConfig(APP.store.getState(), params);
APP.store.dispatch(setIAmVisitor(true));
connection.disconnect().then(() => {
connect(this._conference.roomName).then(con => {
const localTracks = getLocalTracks(APP.store.getState()['features/base/tracks']);

View File

@ -46,9 +46,9 @@ var config = {
},
// BOSH URL. FIXME: use XEP-0156 to discover it.
bosh: '//jitsi-meet.example.com/' + subdir + 'http-bind',
bosh: 'https://jitsi-meet.example.com/' + subdir + 'http-bind',
// Websocket URL
// Websocket URL (XMPP)
// websocket: 'wss://jitsi-meet.example.com/' + subdir + 'xmpp-websocket',
// The real JID of focus participant - can be overridden here
@ -56,6 +56,19 @@ var config = {
// https://github.com/jitsi/jitsi-meet/issues/7376
// focusUserJid: 'focus@auth.jitsi-meet.example.com',
// Options related to the bridge (colibri) data channel
bridgeChannel: {
// If the backend advertises multiple colibri websockets, this options allows
// to filter some of them out based on the domain name. We use the first URL
// which does not match ignoreDomain, falling back to the first one that matches
// ignoreDomain. Has no effect if undefined.
// ignoreDomain: 'example.com',
// Prefer SCTP (WebRTC data channels over the media path) over a colibri websocket.
// If SCTP is available in the backend it will be used instead of a WS. Defaults to
// false (SCTP is used only if available and no WS are available).
// preferSctp: false
},
// Testing / experimental features.
//
@ -542,12 +555,15 @@ var config = {
// Disables responsive tiles.
// disableResponsiveTiles: false,
// Hides lobby button
// DEPRECATED. Please use `securityUi?.hideLobbyButton` instead.
// Hides lobby button.
// hideLobbyButton: false,
// DEPRECATED. Please use `lobby?.autoKnock` instead.
// If Lobby is enabled starts knocking automatically.
// autoKnockLobby: false,
// DEPRECATED. Please use `lobby?.enableChat` instead.
// Enable lobby chat.
// enableLobbyChat: true,
@ -572,6 +588,22 @@ var config = {
// customUrl: ''
// },
// Configs for the lobby screen.
// lobby {
// // If Lobby is enabled, it starts knocking automatically. Replaces `autoKnockLobby`.
// autoKnock: false,
// // Enables the lobby chat. Replaces `enableLobbyChat`.
// enableChat: true,
// },
// Configs for the security related UI elements.
// securityUi: {
// // Hides the lobby button. Replaces `hideLobbyButton`.
// hideLobbyButton: false,
// // Hides the possibility to set and enter a lobby password.
// disableLobbyPassword: false,
// },
// Disable app shortcuts that are registered upon joining a conference
// disableShortcuts: false,
@ -799,6 +831,14 @@ var config = {
// 'microphone', 'camera', 'select-background', 'invite', 'settings'
// hiddenPremeetingButtons: [],
// An array with custom option buttons for the participant context menu
// type: Array<{ icon: string; id: string; text: string; }>
// customParticipantMenuButtons: [],
// An array with custom option buttons for the toolbar
// type: Array<{ icon: string; id: string; text: string; }>
// customToolbarButtons: [],
// Stats
//
@ -1119,6 +1159,13 @@ var config = {
// }
// },
// // The terms, privacy and help centre URL's.
// legalUrls: {
// helpCentre: 'https://web-cdn.jitsi.net/faq/meet-faq.html',
// privacy: 'https://jitsi.org/meet/privacy',
// terms: 'https://jitsi.org/meet/terms'
// },
// A property to disable the right click context menu for localVideo
// the menu has option to flip the locally seen video for local presentations
// disableLocalVideoFlip: false,
@ -1335,9 +1382,9 @@ var config = {
deploymentInfo
dialOutAuthUrl
dialOutCodesUrl
dialOutRegionUrl
disableRemoteControl
displayJids
externalConnectUrl
e2eeLabels
firefox_fake_device
googleApiApplicationClientID

View File

@ -32,54 +32,6 @@ const logger = Logger.getLogger(__filename);
*/
export const DISCO_JIBRI_FEATURE = 'http://jitsi.org/protocol/jibri';
/**
* Checks if we have data to use attach instead of connect. If we have the data
* executes attach otherwise check if we have to wait for the data. If we have
* to wait for the attach data we are setting handler to APP.connect.handler
* which is going to be called when the attach data is received otherwise
* executes connect.
*
* @param {string} [id] user id
* @param {string} [password] password
* @param {string} [roomName] the name of the conference.
*/
function checkForAttachParametersAndConnect(id, password, connection) {
if (window.XMPPAttachInfo) {
APP.connect.status = 'connecting';
// When connection optimization is not deployed or enabled the default
// value will be window.XMPPAttachInfo.status = "error"
// If the connection optimization is deployed and enabled and there is
// a failure the value will be window.XMPPAttachInfo.status = "error"
if (window.XMPPAttachInfo.status === 'error') {
connection.connect({
id,
password
});
return;
}
const attachOptions = window.XMPPAttachInfo.data;
if (attachOptions) {
connection.attach(attachOptions);
delete window.XMPPAttachInfo.data;
} else {
connection.connect({
id,
password
});
}
} else {
APP.connect.status = 'ready';
APP.connect.handler
= checkForAttachParametersAndConnect.bind(
null,
id, password, connection);
}
}
/**
* Try to open connection using provided credentials.
* @param {string} [id]
@ -182,7 +134,10 @@ export async function connect(id, password) {
APP.store.dispatch(setPrejoinDisplayNameRequired());
}
checkForAttachParametersAndConnect(id, password, connection);
connection.connect({
id,
password
});
});
}

View File

@ -1,3 +0,0 @@
module.exports = {
'extends': '../react/.eslintrc.js'
};

View File

@ -1,86 +0,0 @@
/* global config, createConnectionExternally */
import getRoomName from '../react/features/base/config/getRoomName';
import { parseURLParams } from '../react/features/base/util/parseURLParams';
/**
* Implements external connect using createConnectionExternally function defined
* in external_connect.js for Jitsi Meet. Parses the room name and JSON Web
* Token (JWT) from the URL and executes createConnectionExternally.
*
* NOTE: If you are using lib-jitsi-meet without Jitsi Meet, you should use this
* file as reference only because the implementation is Jitsi Meet-specific.
*
* NOTE: For optimal results this file should be included right after
* external_connect.js.
*/
if (typeof createConnectionExternally === 'function') {
// URL params have higher priority than config params.
// Do not use external connect if websocket is enabled.
let url
= parseURLParams(window.location, true, 'hash')[
'config.externalConnectUrl']
|| config.websocket ? undefined : config.externalConnectUrl;
const isRecorder
= parseURLParams(window.location, true, 'hash')['config.iAmRecorder'];
let roomName;
if (url && (roomName = getRoomName()) && !isRecorder) {
url += `?room=${roomName}`;
const token = parseURLParams(window.location, true, 'search').jwt;
if (token) {
url += `&token=${token}`;
}
createConnectionExternally(
url,
connectionInfo => {
// Sets that global variable to be used later by connect method
// in connection.js.
window.XMPPAttachInfo = {
status: 'success',
data: connectionInfo
};
checkForConnectHandlerAndConnect();
},
errorCallback);
} else {
errorCallback();
}
} else {
errorCallback();
}
/**
* Check if connect from connection.js was executed and executes the handler
* that is going to finish the connect work.
*
* @returns {void}
*/
function checkForConnectHandlerAndConnect() {
window.APP
&& window.APP.connect.status === 'ready'
&& window.APP.connect.handler();
}
/**
* Implements a callback to be invoked if anything goes wrong.
*
* @param {Error} error - The specifics of what went wrong.
* @returns {void}
*/
function errorCallback(error) {
// The value of error is undefined if external connect is disabled.
error && console.warn(error);
// Sets that global variable to be used later by connect method in
// connection.js.
window.XMPPAttachInfo = {
status: 'error'
};
checkForConnectHandlerAndConnect();
}

View File

@ -2,13 +2,13 @@
display: inline-block;
&-content {
background: $menuBG;
border-radius: 3px;
font-size: 14px;
line-height: 24px;
position: relative;
right: auto;
margin-bottom: 4px;
max-height: 456px;
overflow: auto;
width: 300px;
&-ul {
margin:0;
padding:0;
@ -16,90 +16,33 @@
}
}
&-header {
color: #fff;
align-items: center;
display: flex;
margin-top: 8px;
padding: 8px 16px;
&-icon {
display: inline-block;
svg {
fill: #fff;
}
}
&--bordered {
border-bottom: 1px solid #4C4D50;
}
&-text {
margin-left: 12px;
}
&-header:hover {
background-color: initial;
cursor: initial;
}
&-entry {
align-items: center;
color: #fff;
cursor: pointer;
display: flex;
padding: 8px 0;
margin-left: 48px;
&-entry-text {
max-width: 213px;
&--selected {
background: #131519;
cursor: initial;
margin-left: 0;
padding-left: 18px;
}
&-text {
color: #fff;
display: inline-block;
line-height: 24px;
text-overflow: ellipsis;
max-width: 213px;
overflow: hidden;
white-space: nowrap;
&.left-margin {
margin-left: 36px;
}
}
&-speaker {
position: relative;
&-ul {
margin:0;
padding:0;
list-style-type: none;
}
&:hover, &:focus-within, &:focus {
.audio-preview-entry {
background: #36383C;
margin-left: 0;
padding-left: 48px;
&--selected {
padding-left: 18px;
background: $newToolbarBackgroundColor;
}
}
.audio-preview-test-button {
display: inline-block;
}
.audio-preview-entry-text {
max-width: 178px;
margin-right: 0;
}
}
&:last-child {
padding-bottom: 8px;
}
.audio-preview-entry-text {
max-width: 238px;
}
@ -108,19 +51,6 @@
&-microphone {
position: relative;
&:hover {
.audio-preview-entry {
background: #36383C;
margin-left: 0;
padding-left: 48px;
&--selected {
background: $newToolbarBackgroundColor;
padding-left: 18px;
}
}
}
&--nometer {
.audio-preview-entry-text {
max-width: 238px;
@ -140,42 +70,21 @@
display: inline-block;
width: 14px;
& svg {
fill: #1C2025;
}
&--check {
background: #31B76A;
margin-right: 16px;
}
&--exclamation {
margin-left: 6px;
& svg {
fill: #E54B4B;
}
}
}
&-hr {
border-top: 1px solid #4C4D50;
border-bottom: 0;
}
&-test-button {
display: none;
background: #FFF;
border: 1px solid #D1DBE8;
border-radius: 3px;
color: #1C2025;
cursor: pointer;
font-weight: 600;
font-size: 0.8rem;
line-height: 24px;
padding: 2px 8px;
padding: 4px 10px;
position: absolute;
right: 16px;
top: 5px;
top: 6px;
}
&-meter-mic {
@ -184,9 +93,7 @@
top: 14px;
}
// Override @atlaskit/InlineDialog container which is made with styled components
& > div:nth-child(2) {
outline: none;
padding: 0;
&-checkbox-container {
padding: 10px 16px;
}
}

67
css/_jiti.scss Normal file
View File

@ -0,0 +1,67 @@
@keyframes rotateAroundY {
from { transform: rotateY(0deg); }
to { transform: rotateY(360deg); }
}
@keyframes rainbowRoad {
to {
background-position: 400% 0 !important;
}
}
body {
font-family: "Comic Sans MS", "Comic Sans", sans-serif !important;
}
a {
background: linear-gradient(90deg, rgba(255,0,0,1) 0%, rgba(255,154,0,1) 10%, rgba(208,222,33,1) 20%, rgba(79,220,74,1) 30%, rgba(63,218,216,1) 40%, rgba(47,201,226,1) 50%, rgba(28,127,238,1) 60%, rgba(95,21,242,1) 70%, rgba(186,12,248,1) 80%, rgba(251,7,217,1) 90%, rgba(255,0,0,1) 100%) !important;
-webkit-background-clip: text !important;
-webkit-text-fill-color: transparent !important;
-moz-background-clip: text !important;
-moz-text-fill-color: transparent !important;
animation: rainbowRoad 8s linear infinite !important;
}
a:hover {
}
.dominant-speaker {
box-shadow: inset 0px 0px 0px 4px rgba(255,0,255,0.33) !important;
}
.display-avatar-only {
background-image: url("");
}
.videocontainer:nth-child(odd) {
transform: rotate(1.5deg);
}
.videocontainer:nth-child(even) {
transform: rotate(-1.3deg);
}
#largeVideoContainer.videocontainer {
transform: none;
}
.sideToolbarContainer {
transform: rotate(-1.1deg);
}
.displayname:before {
content: "♡︎ ";
}
.displayname:after {
content: " ♡︎";
}
.avatar, .userAvatar {
transform: rotateY(0deg);
}
.avatar:hover, .userAvatar:hover {
animation: rotateAroundY 3.6s linear infinite;
}

View File

@ -82,6 +82,7 @@
}
.left-column {
order: -1;
display: flex;
flex-direction: column;
flex-grow: 0;
@ -92,6 +93,7 @@
.right-column {
display: flex;
flex-direction: column;
align-items: flex-start;
flex-grow: 1;
padding-left: 16px;
padding-top: 13px;
@ -99,11 +101,11 @@
}
.title {
font-size: 12px;
font-weight: 600;
line-height: 16px;
padding-bottom: 4px;
}
font-size: 12px;
font-weight: 600;
line-height: 16px;
margin-bottom: 4px;
}
.subtitle {
color: #5E6D7A;
@ -125,8 +127,7 @@
cursor: pointer;
}
&.with-click-handler:hover,
&.with-click-handler:focus {
&.with-click-handler:hover {
background-color: #c7ddff;
}

View File

@ -3,28 +3,28 @@
display: inline-block;
& > svg {
fill: #4E5E6C;
fill: #525252;
width: 38px;
}
}
&.metr--disabled {
& > svg {
fill: #4E5E6C;
fill: #525252;
}
}
}
.metr-l-0 {
rect:first-child {
fill: #31B76A;
fill: #1EC26A;
}
}
@for $i from 1 through 7 {
.metr-l-#{$i} {
rect:nth-child(-n+#{$i+1}) {
fill: #31B76A;
fill: #1EC26A;
}
}
}

View File

@ -1,3 +1,3 @@
#polls-panel {
.polls-panel {
height: calc(100% - 119px);
}

View File

@ -5,15 +5,15 @@
.popupmenu__contents {
.popupmenu__volume-slider {
&::-webkit-slider-runnable-track {
background-color: $popupSliderColor;
background-color: #246FE5;
}
&::-moz-range-track {
background-color: $popupSliderColor;
background-color: #246FE5;
}
&::-ms-fill-lower {
background-color: $popupSliderColor;
background-color: #246FE5;
}
}
}

View File

@ -30,24 +30,24 @@
right: -4px;
top: -3px;
&:hover {
&:hover {
background: #F2F3F4;
box-shadow: 0px 4px 4px rgba(0, 0, 0, 0.25), 0px 0px 0px 1px rgba(0, 0, 0, 0.1);
&> svg {
fill: #000;
& > svg {
fill: #040404;
}
&.settings-button-small-icon--disabled {
background: #36383C;
&> svg {
fill: #929292;
}
fill: #929292;
}
}
}
&> svg {
& > svg {
fill: #fff;
}

View File

@ -12,7 +12,6 @@
&#autoHide.with-always-on {
overflow: hidden;
animation: hideSubject forwards .6s ease-out;
margin-left: 4px;
& > .subject-info-container {
justify-content: flex-start;
@ -43,43 +42,6 @@
height: 28px;
}
.subject-text {
background: rgba(0, 0, 0, 0.6);
border-radius: 3px 0px 0px 3px;
box-sizing: border-box;
font-size: 14px;
line-height: 28px;
padding: 0 16px;
height: 28px;
max-width: 324px;
@media (max-width: 300px) {
display: none;
}
&--content {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
}
.subject-timer {
background: rgba(0, 0, 0, 0.8);
border-radius: 0px 3px 3px 0px;
box-sizing: border-box;
font-size: 12px;
line-height: 28px;
min-width: 34px;
padding: 0 8px;
height: 28px;
font-variant-numeric: tabular-nums;
@media (max-width: 300px) {
display: none;
}
}
.details-container {
width: 100%;
display: flex;

View File

@ -120,12 +120,16 @@
margin: 8px 0;
}
.hangup-button {
background-color: $hangupColor;
div.hangup-button {
background-color: #CB2233;
@media (hover: hover) and (pointer: fine) {
&:hover {
background-color: $hangupHoverColor;
background-color: #E04757;
}
&:active {
background-color: #A21B29;
}
}
@ -134,12 +138,16 @@
}
}
.hangup-menu-button {
background-color: $hangupMenuButtonColor;
div.hangup-menu-button {
background-color: #CB2233;
@media (hover: hover) and (pointer: fine) {
&:hover {
background-color: $hangupMenuButtonHoverColor;
background-color: #E04757;
}
&:active {
background-color: #A21B29;
}
}

View File

@ -4,10 +4,6 @@
* Style variables
*/
$baseFontFamily: -apple-system, BlinkMacSystemFont, 'open_sanslight', 'Helvetica Neue', Helvetica, Arial, sans-serif;
$hangupColor:#DD3849;
$hangupHoverColor: #F25363;
$hangupMenuButtonColor:#0056E0;;
$hangupMenuButtonHoverColor: #246FE5;
/**
* Size variables.
@ -205,11 +201,6 @@ $deepLinkingDialInConferenceIdPadding: inherit;
$deepLinkingDialInConferenceIdBackgroundColor: inherit;
$deepLinkingDialInConferenceIdBorderRadius: inherit;
$deepLinkingDialInConferenceNameFontSize: inherit;
$deepLinkingDialInConferenceNameLineHeight: inherit;
$deepLinkingDialInConferenceNameMarginBottom: none;
$deepLinkingDialInConferenceNameFontWeight: inherit;
$deepLinkingDialInConferenceDescriptionFontSize: 0.8em;
$deepLinkingDialInConferenceDescriptionLineHeight: inherit;
$deepLinkingDialInConferenceDescriptionMarginBottom: none;

View File

@ -3,49 +3,38 @@
display: inline-block;
&-container {
max-height: 344px;
background: $menuBG;
border-radius: 3px;
max-height: 456px;
overflow: auto;
padding: 8px;
margin-bottom: 8px;
margin-bottom: 4px;
position: relative;
right: auto;
}
&-entry {
cursor: pointer;
height: 168px;
margin-bottom: 8px;
height: 138px;
width: 244px;
position: relative;
width: 284px;
margin: 0 7px 4px;
border-radius: 6px;
box-sizing: border-box;
overflow: hidden;
&:last-child {
margin-bottom: 0;
}
&--selected {
border: 3px solid #31B76A;
border-radius: 3px;
cursor: default;
height: 162px;
width: 278px;
border: 2px solid #4687ED;
}
}
&-video {
border-radius: 3px;
height: 100%;
object-fit: cover;
width: 100%;
}
&-overlay {
background: rgba(42, 58, 75, 0.6);
height: 100%;
position: absolute;
width: 100%;
z-index: 1;
}
&-error {
align-items: center;
display: flex;
@ -56,23 +45,22 @@
}
&-label {
bottom: 8px;
color: #fff;
position: absolute;
width: 100%;
bottom: 0;
left: 0;
right: 0;
max-width: 100%;
padding: 8px;
z-index: 2;
&-container {
margin: 0 16px;
}
&-text {
background-color: #131519;
border-radius: 3px;
padding: 2px 8px;
font-size: 13px;
line-height: 20px;
margin: 0 auto;
background-color: rgba(0, 0, 0, 0.7);
border-radius: 4px;
padding: 4px 8px;
color: #fff;
font-size: 12px;
line-height: 16px;
font-weight: 600;
max-width: calc(100% - 16px);
overflow: hidden;
text-overflow: ellipsis;
@ -80,8 +68,8 @@
white-space: nowrap;
}
}
// Override @atlaskit/InlineDialog container which is made with styled components
& > div:nth-child(2) {
padding: 0;
&-checkbox-container {
padding: 10px 14px;
}
}

View File

@ -90,7 +90,7 @@ body.welcome-page {
font-size: 14px;
padding-left: 10px;
&:focus {
&.focus-visible {
outline: auto 2px #005fcc;
}
}
@ -167,7 +167,7 @@ body.welcome-page {
margin: 4px;
display: $welcomePageTabButtonsDisplay;
.tab {
[role="tab"] {
background-color: #c7ddff;
border-radius: 7px;
cursor: pointer;
@ -176,8 +176,10 @@ body.welcome-page {
margin: 2px;
padding: 7px 0;
text-align: center;
color: inherit;
border: 0;
&.selected {
&[aria-selected="true"] {
background-color: #FFF;
}
}

View File

@ -67,6 +67,13 @@
font-size: 1em;
}
.dial-in-conference-id {
text-align: center;
min-width: 200px;
margin-top: 40px;
}
.dial-in-conference-id {
margin: $deepLinkingDialInConferenceIdMargin;
padding: $deepLinkingDialInConferenceIdPadding;
@ -74,24 +81,12 @@
border-radius: $deepLinkingDialInConferenceIdBorderRadius;
}
.dial-in-conference-name {
font-size: $deepLinkingDialInConferenceNameFontSize;
line-height: $deepLinkingDialInConferenceNameLineHeight;
margin-bottom: $deepLinkingDialInConferenceNameMarginBottom;
font-weight: $deepLinkingDialInConferenceNameFontWeight;
}
.dial-in-conference-description {
font-size: $deepLinkingDialInConferenceDescriptionFontSize;
line-height: $deepLinkingDialInConferenceDescriptionLineHeight;
margin-bottom: $deepLinkingDialInConferenceDescriptionMarginBottom;
}
.dial-in-conference-pin {
font-size: $deepLinkingDialInConferencePinFontSize;
line-height: $deepLinkingDialInConferencePinLineHeight;
}
.toll-free-list {
min-width: 80px;
}

View File

@ -33,7 +33,6 @@ $flagsImagePath: "../images/";
@import 'reload_overlay/reload_overlay';
@import 'mini_toolbox';
@import 'modals/desktop-picker/desktop-picker';
@import 'modals/device-selection/device-selection';
@import 'modals/dialog';
@import 'modals/embed-meeting/embed-meeting';
@import 'modals/feedback/feedback';
@ -95,3 +94,9 @@ $flagsImagePath: "../images/";
@import 'notifications';
/* Modules END */
/* Jeet crew BEGIN */
@import 'jiti';
/* Jeet crew END */

View File

@ -63,3 +63,8 @@
.desktop-source-preview-image-container {
padding: 10px;
}
.desktop-picker-tabs-container {
width: 65%;
margin-top: 3px;
}

View File

@ -1,148 +0,0 @@
.device-selection {
.device-selectors {
font-size: 14px;
> div {
display: block;
margin-bottom: 4px;
}
.device-selector-icon {
align-self: center;
color: inherit;
font-size: 20px;
margin-left: 3px;
}
.device-selector-label {
margin-bottom: 1px;
}
/* device-selector-trigger stylings attempt to mimic AtlasKit button */
.device-selector-trigger {
background-color: #0E1624;
border: 1px solid #455166;
border-radius: 5px;
display: flex;
height: 2.3em;
justify-content: space-between;
line-height: 2.3em;
overflow: hidden;
padding: 0 8px;
}
.device-selector-trigger-disabled {
.device-selector-trigger {
color: #a5adba;
cursor: default;
}
}
.device-selector-trigger-text {
overflow: hidden;
text-align: center;
text-overflow: ellipsis;
white-space: nowrap;
width: 100%;
}
}
.device-selection-column {
box-sizing: border-box;
display: inline-block;
vertical-align: top;
&.column-selectors {
margin-left: 15px;
width: 45%;
}
&.column-video {
width: 50%;
}
}
.device-selection-video-container {
border-radius: 3px;
margin-bottom: 5px;
.video-input-preview {
margin-top: 2px;
position: relative;
> video {
border-radius: 3px;
}
.video-input-preview-error {
color: $participantNameColor;
display: none;
left: 0;
position: absolute;
right: 0;
text-align: center;
top: 50%;
}
&.video-preview-has-error {
background: black;
.video-input-preview-error {
display: block;
}
}
.video-input-preview-display {
height: auto;
overflow: hidden;
width: 100%;
}
}
}
.audio-output-preview {
font-size: 14px;
a {
color: #6FB1EA;
cursor: pointer;
text-decoration: none;
}
a:hover {
color: #B3D4FF;
}
}
.audio-input-preview {
background: #1B2638;
border-radius: 5px;
height: 8px;
.audio-input-preview-level {
background: #75B1FF;
border-radius: 5px;
height: 100%;
-webkit-transition: width .1s ease-in-out;
-moz-transition: width .1s ease-in-out;
-o-transition: width .1s ease-in-out;
transition: width .1s ease-in-out;
}
}
}
.device-selection.video-hidden {
display: flex;
flex-direction: column;
width: 100%;
.column-selectors {
width: 100%;
margin-left: 0;
}
.column-video {
order: 1;
width: 100%;
margin-top: 8px;
}
}

View File

@ -44,61 +44,3 @@
-webkit-animation-timing-function: ease-in-out;
animation-timing-function: ease-in-out
}
.feedback-dialog {
margin-bottom: 5px;
.details {
textarea {
min-height: 100px;
}
}
.input-control {
background-color: $feedbackInputBg;
color: $feedbackInputTextColor;
&::-webkit-input-placeholder {
color: $feedbackInputPlaceholderColor;
}
&::-moz-placeholder { /* Firefox 19+ */
color: $feedbackInputPlaceholderColor;
}
&:-ms-input-placeholder {
color: $feedbackInputPlaceholderColor;
}
}
.rating {
line-height: 1.2;
margin-top: 10px;
text-align: center;
.star-label {
font-size: 14px;
height: 16px;
}
.star-btn {
color: inherit;
cursor: pointer;
display: inline-block;
font-size: 34px;
outline: none;
position: relative;
text-decoration: none;
@include transition(all .2s ease);
&.active,
&:hover,
&.starHover {
color: #36B37E;
};
}
.star-btn:focus,
.star-btn:active {
outline: 1px solid #B8C7E0;
}
}
}

View File

@ -50,6 +50,8 @@
}
.dial-in-numbers-list {
max-width: 334px;
width: 100%;
margin-top: 20px;
font-size: 12px;
line-height: 24px;
@ -59,10 +61,6 @@
text-align: left;
}
tr {
border-bottom: 1px solid #d1dbe8;
}
.flag-cell {
vertical-align: top;
width: 30px;
@ -91,6 +89,7 @@
font-weight: bold;
list-style: none;
vertical-align: top;
text-align: right;
}
li.toll-free:empty:before {
@ -119,11 +118,6 @@
margin-top: 40px;
}
.dial-in-conference-name,
.dial-in-conference-pin {
font-size: 18px;
}
.dial-in-conference-description {
margin: 12px;
}

View File

@ -60,6 +60,7 @@
.prejoin-input {
margin-bottom: 16px;
width: 100%;
& input {
text-align: center;

View File

@ -103,10 +103,6 @@
padding: 11px 16px;
}
}
input::placeholder {
color: #040404;
}
}
#preview {

View File

@ -65,7 +65,6 @@ $errorColor: #c61600;
// Popover colors
$popoverFontColor: #ffffff !important;
$popupSliderColor: #0376da;
// Toolbar
$toolbarBackground: rgba(0, 0, 0, 0.5);

View File

@ -8,7 +8,6 @@ sounds /usr/share/jitsi-meet/
fonts /usr/share/jitsi-meet/
images /usr/share/jitsi-meet/
lang /usr/share/jitsi-meet/
connection_optimization /usr/share/jitsi-meet/
resources/robots.txt /usr/share/jitsi-meet/
resources/*.sh /usr/share/jitsi-meet/scripts/
pwa-worker.js /usr/share/jitsi-meet/

View File

@ -93,7 +93,7 @@ server {
}
# ensure all static content can always be found first
location ~ ^/(libs|css|static|images|fonts|lang|sounds|connection_optimization|.well-known)/(.*)$
location ~ ^/(libs|css|static|images|fonts|lang|sounds|.well-known)/(.*)$
{
add_header 'Access-Control-Allow-Origin' '*';
alias /usr/share/jitsi-meet/$1/$2;

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 6.3 KiB

View File

@ -182,8 +182,6 @@
'error', loadErrHandler, true /* capture phase type of listener */);
</script>
<script><!--#include virtual="/config.js" --></script><!-- adapt to your needs, i.e. set hosts and bosh path -->
<!--#include virtual="connection_optimization/connection_optimization.html" -->
<script src="libs/do_external_connect.min.js?v=1"></script>
<script><!--#include virtual="/interface_config.js" --></script>
<script src="libs/lib-jitsi-meet.min.js?v=139"></script>
<script src="libs/app.bundle.min.js?v=139"></script>

View File

@ -9,7 +9,7 @@
*/
var interfaceConfig = {
APP_NAME: 'Jitsi Meet',
APP_NAME: 'JitSea 🏴‍☠️',
AUDIO_LEVEL_PRIMARY_COLOR: 'rgba(255,255,255,0.4)',
AUDIO_LEVEL_SECONDARY_COLOR: 'rgba(255,255,255,0.2)',

View File

@ -389,7 +389,7 @@ PODS:
- react-native-video/Video (6.0.0-alpha.1):
- PromisesSwift
- React-Core
- react-native-webrtc (106.0.4):
- react-native-webrtc (106.0.6):
- JitsiWebRTC (~> 106.0.0)
- React-Core
- react-native-webview (11.15.1):
@ -465,13 +465,11 @@ PODS:
- React-Core
- RNCClipboard (1.5.1):
- React-Core
- RNCMaskedView (0.2.6):
- React-Core
- RNDefaultPreference (1.4.4):
- React-Core
- RNDeviceInfo (8.4.8):
- React-Core
- RNGestureHandler (2.8.0):
- RNGestureHandler (2.9.0):
- React-Core
- RNGoogleSignin (7.0.4):
- GoogleSignIn (~> 6.0.0)
@ -547,7 +545,6 @@ DEPENDENCIES:
- RNCalendarEvents (from `../node_modules/react-native-calendar-events`)
- "RNCAsyncStorage (from `../node_modules/@react-native-async-storage/async-storage`)"
- "RNCClipboard (from `../node_modules/@react-native-community/clipboard`)"
- "RNCMaskedView (from `../node_modules/@react-native-masked-view/masked-view`)"
- RNDefaultPreference (from `../node_modules/react-native-default-preference`)
- RNDeviceInfo (from `../node_modules/react-native-device-info`)
- RNGestureHandler (from `../node_modules/react-native-gesture-handler`)
@ -682,8 +679,6 @@ EXTERNAL SOURCES:
:path: "../node_modules/@react-native-async-storage/async-storage"
RNCClipboard:
:path: "../node_modules/@react-native-community/clipboard"
RNCMaskedView:
:path: "../node_modules/@react-native-masked-view/masked-view"
RNDefaultPreference:
:path: "../node_modules/react-native-default-preference"
RNDeviceInfo:
@ -759,7 +754,7 @@ SPEC CHECKSUMS:
react-native-slider: 6e9b86e76cce4b9e35b3403193a6432ed07e0c81
react-native-splash-screen: 4312f786b13a81b5169ef346d76d33bc0c6dc457
react-native-video: bb6f12a7198db53b261fefb5d609dc77417acc8b
react-native-webrtc: 4522d420ead45fff83c4ecc7e5a706797857a185
react-native-webrtc: 22ac6c64a1e38552bb173dde81ffea6979a58ef3
react-native-webview: ea4899a1056c782afa96dd082179a66cbebf5504
React-perflogger: 0458a87ea9a7342079e7a31b0d32b3734fb8415f
React-RCTActionSheet: 22538001ea2926dea001111dd2846c13a0730bc9
@ -776,10 +771,9 @@ SPEC CHECKSUMS:
RNCalendarEvents: 7e65eb4a94f53c1744d1e275f7fafcfaa619f7a3
RNCAsyncStorage: 005c0e2f09575360f142d0d1f1f15e4ec575b1af
RNCClipboard: 41d8d918092ae8e676f18adada19104fa3e68495
RNCMaskedView: c298b644a10c0c142055b3ae24d83879ecb13ccd
RNDefaultPreference: 08bdb06cfa9188d5da97d4642dac745218d7fb31
RNDeviceInfo: 0400a6d0c94186d1120c3cbd97b23abc022187a9
RNGestureHandler: 62232ba8f562f7dea5ba1b3383494eb5bf97a4d3
RNGestureHandler: 071d7a9ad81e8b83fe7663b303d132406a7d8f39
RNGoogleSignin: c4381751eefd73c552b923ba347a9bfc6f18771c
RNScreens: 40a2cb40a02a609938137a1e0acfbf8fc9eebf19
RNSound: 27e8268bdb0a1f191f219a33267f7e0445e8d62f

View File

@ -40,19 +40,10 @@ static NSString *const PiPEnabledFeatureFlag = @"pip.enabled";
#pragma mark Initializers
- (instancetype)init {
self = [super init];
if (self) {
[self initWithXXX];
}
return self;
}
- (instancetype)initWithCoder:(NSCoder *)coder {
self = [super initWithCoder:coder];
if (self) {
[self initWithXXX];
[self doInitialize];
}
return self;
@ -61,7 +52,7 @@ static NSString *const PiPEnabledFeatureFlag = @"pip.enabled";
- (instancetype)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
[self initWithXXX];
[self doInitialize];
}
return self;
@ -71,9 +62,9 @@ static NSString *const PiPEnabledFeatureFlag = @"pip.enabled";
* Internal initialization:
*
* - sets the background color
* - initializes the external API scope
* - registers necessary observers
*/
- (void)initWithXXX {
- (void)doInitialize {
// Set a background color which is in accord with the JavaScript and Android
// parts of the application and causes less perceived visual flicker than
// the default background color.

View File

@ -7,6 +7,7 @@
"cs": "Čeština",
"da": "Dansk",
"de": "Deutsch",
"dsb": "Dolnoserbšćina",
"el": "Ελληνικά",
"en": "English",
"enGB": "English (United Kingdom)",

View File

@ -184,13 +184,21 @@
"deepLinking": {
"appNotInstalled": "Sie benötigen die „{{app}}“-App, um der Konferenz auf dem Smartphone beizutreten.",
"description": "Nichts passiert? Wir haben versucht, die Konferenz in {{app}} zu öffnen. Versuchen Sie es erneut oder treten Sie der Konferenz in {{app}} im Web bei.",
"descriptionNew": "Nichts passiert? Wir haben versucht, die Konferenz in {{app}} zu öffnen. <br /><br /> Versuchen Sie es erneut oder treten Sie der Konferenz im Web bei.",
"descriptionWithoutWeb": "Ist nichts passiert? Wir haben versucht, Ihre Besprechung in der „{{app}}“-Desktop-App zu starten.",
"downloadApp": "App herunterladen",
"downloadMobileApp": "Aus dem App Store herunterladen",
"ifDoNotHaveApp": "Wenn Sie die App noch nicht haben:",
"ifHaveApp": "Wenn Sie die App bereits haben:",
"joinInApp": "Mit der App am Meeting teilnehmen",
"joinInAppNew": "Mit der App",
"joinInBrowser": "Im Browser",
"launchMeetingLabel": "Wie möchten Sie an der Konferenz teilnehmen?",
"launchWebButton": "Im Web öffnen",
"noMobileApp": "Sie haben die App noch nicht installiert?",
"termsAndConditions": "Indem Sie fortfahren, stimmen Sie underen<a href='{{termsAndConditionsLink}}' rel='noopener noreferrer' target='_blank'>Nutzungsbedingungen</a> zu.",
"title": "Die Konferenz wird in {{app}} geöffnet …",
"titleNew": "Konferenz starten ...",
"tryAgainButton": "Erneut mit der nativen Applikation versuchen",
"unsupportedBrowser": "Sie verwenden einen Browser, der noch nicht unterstützt wird."
},
@ -203,6 +211,12 @@
"microphonePermission": "Fehler beim Bezug der Mikrofon-Zugriffsberechtigungen"
},
"deviceSelection": {
"hid": {
"callControl": "Anrufsteuerung",
"connectedDevices": "Verbundene Geräte:",
"deleteDevice": "Gerät löschen",
"pairDevice": "Gerät verbinden"
},
"noPermission": "Berechtigungen nicht erteilt",
"previewUnavailable": "Keine Vorschau verfügbar",
"selectADevice": "Ein Gerät wählen",
@ -226,7 +240,9 @@
"WaitingForHostTitle": "Warten auf den Beginn der Konferenz …",
"Yes": "Ja",
"accessibilityLabel": {
"liveStreaming": "Livestream"
"close": "Popup schließen",
"liveStreaming": "Livestream",
"sharingTabs": "Optionen zum Teilen"
},
"add": "Hinzufügen",
"addMeetingNote": "Notiz zu dieser Konferenz hinzufügen",
@ -438,6 +454,11 @@
"veryBad": "Sehr schlecht",
"veryGood": "Sehr gut"
},
"filmstrip": {
"accessibilityLabel": {
"heading": "Videominiaturen"
}
},
"giphy": {
"noResults": "Keine Ergebnisse :(",
"search": "GIPHY durchsuchen"
@ -751,6 +772,7 @@
"headings": {
"lobby": "Lobby ({{count}})",
"participantsList": "Anwesende ({{count}})",
"visitors": "Gäste ({{count}})",
"waitingLobby": "In der Lobby ({{count}})"
},
"search": "Suche Anwesende",
@ -758,6 +780,7 @@
},
"passwordDigitsOnly": "Bis zu {{number}} Ziffern",
"passwordSetRemotely": "von einer anderen Person gesetzt",
"pinParticipant": "{{participantName}} - anheften",
"pinnedParticipant": "Die Person ist angeheftet",
"polls": {
"answer": {
@ -916,6 +939,7 @@
"localRecordingVideoWarning": "Um Ihr eigenes Kamerabild aufzuzeichnen, müssen Sie Ihre Kamera beim Start der Aufnahme einschalten",
"localRecordingWarning": "Bitte prüfen Sie, dass das aktuelle Tab auswählen, um Bild und Ton aufzuzeichnen. Die Länge der Aufzeichnung ist aktuell auf 1GB beschränkt, was ungefähr 100 Minuten entspricht.",
"loggedIn": "Als {{userName}} angemeldet",
"noMicPermission": "Zugriff auf Mikrofon fehlgeschlagen. Bitte erlauben Sie den Zugriff auf das Mikrofon.",
"noStreams": "Kein Ton oder Video erkannt.",
"off": "Aufnahme gestoppt",
"offBy": "{{name}} stoppte die Aufnahme",
@ -949,6 +973,7 @@
"title": "Sicherheitsoptionen"
},
"settings": {
"audio": "Audio",
"buttonLabel": "Einstellungen",
"calendar": {
"about": "Die Kalenderintegration von {{appName}} wird verwendet, um ein sicheres Zugreifen auf Ihren Kalender und Auslesen der bevorstehenden Termine zu ermöglichen.",
@ -969,9 +994,11 @@
"maxStageParticipants": "Maximale Anzahl an Personen, die zur Hauptansicht angeheftet werden können",
"microphones": "Mikrofon",
"moderator": "Moderation",
"moderatorOptions": "Moderationseinstellungen",
"more": "Mehr",
"name": "Name",
"noDevice": "Kein",
"notifications": "Benachrichtigungen",
"participantJoined": "Neue Person nimmt teil",
"participantKnocking": "Person hat Lobby betreten",
"participantLeft": "Person verlässt die Konferenz",
@ -982,13 +1009,14 @@
"selectCamera": "Kamera",
"selectMic": "Mikrofon",
"selfView": "Eigene Ansicht",
"sounds": "Hinweistöne",
"shortcuts": "Tastaturkürzel",
"speakers": "Lautsprecher",
"startAudioMuted": "Alle Personen treten stummgeschaltet bei",
"startReactionsMuted": "Interaktionstöne für alle deaktivieren",
"startVideoMuted": "Alle Personen treten ohne Video bei",
"talkWhileMuted": "Wenn bei Stummschaltung gesprochen wird",
"title": "Einstellungen"
"title": "Einstellungen",
"video": "Kamera"
},
"settingsView": {
"advanced": "Erweitert",
@ -1080,6 +1108,7 @@
"giphy": "GIPHY ein-/ausschalten",
"grantModerator": "Moderationsrechte vergeben",
"hangup": "Konferenz verlassen",
"heading": "Toolbar",
"help": "Hilfe",
"invite": "Person einladen",
"kick": "Person entfernen",
@ -1146,6 +1175,7 @@
"download": "Unsere Apps herunterladen",
"e2ee": "Ende-zu-Ende-Verschlüsselung",
"embedMeeting": "Konferenz einbetten",
"enableNoiseSuppression": "Rauschunterdrückung einschalten",
"endConference": "Konferenz für alle beenden",
"enterFullScreen": "Vollbildmodus",
"enterTileView": "Kachelansicht einschalten",
@ -1233,6 +1263,7 @@
"subtitlesOff": "Ausschalten",
"tr": "TR"
},
"unpinParticipant": "{{participantName}} - Nicht mehr anheften",
"userMedia": {
"androidGrantPermissions": "Wählen Sie <b><i>Zulassen</i></b>, wenn der Browser um Berechtigungen bittet.",
"chromeGrantPermissions": "Wählen Sie <b><i>Zulassen</i></b>, wenn der Browser um Berechtigungen bittet.",
@ -1271,9 +1302,11 @@
"ldTooltip": "Video wird in niedriger Auflösung angezeigt",
"lowDefinition": "Niedrige Auflösung",
"performanceSettings": "Qualitätseinstellungen",
"recording": "Aufnahme läuft",
"sd": "SD",
"sdTooltip": "Video wird in Standardauflösung angezeigt",
"standardDefinition": "Standardauflösung"
"standardDefinition": "Standardauflösung",
"streaming": "Streaming läuft"
},
"videothumbnail": {
"connectionInfo": "Verbindungsinformationen",
@ -1285,6 +1318,7 @@
"grantModerator": "Moderationsrechte vergeben",
"hideSelfView": "Eigene Ansicht ausblenden",
"kick": "Hinauswerfen",
"mirrorVideo": "Mein Video spiegeln",
"moderator": "Moderation",
"mute": "Person ist stumm geschaltet",
"muted": "Stummgeschaltet",
@ -1322,6 +1356,7 @@
"webAssemblyWarning": "WebAssembly wird nicht unterstützt",
"webAssemblyWarningDescription": "WebAssembly ist deaktiviert oder wird in diesem Browser nicht unterstützt"
},
"visitorsLabel": "Anzahl Gäste: {{count}}",
"volumeSlider": "Lautstärkeregler",
"welcomepage": {
"accessibilityLabel": {
@ -1354,6 +1389,7 @@
"microsoftLogo": "Microsoft Logo",
"policyLogo": "Richtlinienlogo"
},
"meetingsAccessibilityLabel": "Konferenzen",
"mobileDownLoadLinkAndroid": "Android App Download",
"mobileDownLoadLinkFDroid": "F-Droid App Download",
"mobileDownLoadLinkIos": "iOS App Download",
@ -1373,5 +1409,10 @@
"terms": "AGB",
"title": "Sichere, voll funktionale und komplett kostenlose Videokonferenzen",
"upcomingMeetings": "Ihre zukünftigen Konferenzen"
},
"whiteboard": {
"accessibilityLabel": {
"heading": "Whiteboard"
}
}
}

1379
lang/main-dsb.json Normal file

File diff suppressed because it is too large Load Diff

View File

@ -838,7 +838,7 @@
"selectCamera": "Cámara",
"selectMic": "Micrófono",
"sounds": "Sonidos",
"speakers": "Parlantes",
"speakers": "Altavoces",
"startAudioMuted": "Todos inician silenciados",
"startVideoMuted": "Todos inician con cámara desactivada",
"talkWhileMuted": "Hablar en silencio",

View File

@ -882,6 +882,7 @@
"document": "Gedeeld document in- of uitschakelen",
"download": "Download onze apps",
"embedMeeting": "Vergadering embedden",
"endConference": "Vergadering voor iedereen beëindigen",
"feedback": "Feedback achterlaten",
"fullScreen": "Volledig scherm in- of uitschakelen",
"grantModerator": "Moderatorrechten verlenen",
@ -889,6 +890,7 @@
"help": "Hulp",
"invite": "Personen uitnodigen",
"kick": "Deelnemer verwijderen",
"leaveConference": "Vergadering verlaten",
"lobbyButton": "Lobby-modus in- of uitschakelen",
"localRecording": "Besturingselementen voor lokale opname in- of uitschakelen",
"lockRoom": "Wachtwoord voor vergadering in- of uitschakelen",
@ -938,6 +940,7 @@
"download": "Download onze apps",
"e2ee": "Eind-tot-eind-versleuteling",
"embedMeeting": "Vergadering embedden",
"endConference": "Vergadering voor iedereen beëindigen",
"enterFullScreen": "Volledig scherm weergeven",
"enterTileView": "Tegelweergave openen",
"exitFullScreen": "Volledig scherm sluiten",
@ -948,6 +951,7 @@
"invite": "Personen uitnodigen",
"joinBreakoutRoom": "Deelnemen aan aparte vergaderruimte",
"leaveBreakoutRoom": "Aparte vergaderruimte verlaten",
"leaveConference": "Vergadering verlaten",
"lobbyButtonDisable": "Schakel lobby-modus uit",
"lobbyButtonEnable": "Schakel lobby-modus in",
"login": "Aanmelden",

View File

@ -89,7 +89,7 @@
"chat": {
"enter": "Entrar na sala",
"error": "Erro: a sua mensagem não foi enviada. Motivo: {{error}}",
"fieldPlaceHolder": "Escreva aqui a sua mensagem",
"fieldPlaceHolder": "Aa",
"lobbyChatMessageTo": "Mensagem de chat na sala de espera para {{recipient}}",
"message": "Mensagem",
"messageAccessibleTitle": "{{user}} disse:",
@ -147,6 +147,7 @@
"bridgeCount": "Servidores: ",
"codecs": "Codecs (A/V): ",
"connectedTo": "Ligado a:",
"e2eeVerified": "E2EE verificada:",
"framerate": "Taxa de frames:",
"less": "Mostrar menos",
"localaddress": "Endereço local:",
@ -266,7 +267,7 @@
"e2eeWarning": "AVISO: Nem todos os participantes neste encontro parecem ter apoio para a encriptação de ponta a ponta. Se o permitir, eles não o poderão ver nem ouvir.",
"e2eeWillDisableDueToMaxModeDescription": "AVISO: A encriptação de ponta a ponta será automaticamente desativada se mais participantes aderirem à conferência.",
"embedMeeting": "Embutir reunião",
"enterDisplayName": "Digite o seu nome aqui",
"enterDisplayName": "Digite o seu nome",
"error": "Erro",
"gracefulShutdown": "O nosso serviço está atualmente em manutenção. Por favor, tente novamente mais tarde.",
"grantModeratorDialog": "Tem a certeza que quer conceder direitos de moderador a {{participantName}}?",
@ -408,6 +409,10 @@
"user": "Utilizador",
"userIdentifier": "Identificador do utilizador",
"userPassword": "Palavra-passe do utilizador",
"verifyParticipantConfirm": "Coincidem",
"verifyParticipantDismiss": "Não coincidem",
"verifyParticipantQuestion": "EXPERIMENTAL: Perguntar ao participante {{participantName}} se vêem o mesmo conteúdo, na mesma ordem.",
"verifyParticipantTitle": "Verificação pelo utilizador",
"videoLink": "Link do vídeo",
"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.",
@ -437,9 +442,6 @@
"noResults": "Não foram encontrados resultados :(",
"search": "Procurar no GIPHY"
},
"helpView": {
"title": "Centro de ajuda"
},
"incomingCall": {
"answer": "Responder",
"audioCallTitle": "Chamada recebida",
@ -563,7 +565,6 @@
"lobby": {
"admit": "Aceitar",
"admitAll": "Aceitar todos",
"allow": "Permitir",
"backToKnockModeButton": "Peça para aderir",
"chat": "Chat",
"dialogTitle": "Modo sala de espera",
@ -649,6 +650,8 @@
"connectedOneMember": "{{name}} entrou na reunião",
"connectedThreePlusMembers": "{{name}} e muitos outros entraram na reunião",
"connectedTwoMembers": "{{first}} e {{second}} entraram na reunião",
"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.",
"disconnected": "desconectado",
"displayNotifications": "Mostrar notificações para",
"focus": "Foco da conferência",
@ -709,6 +712,8 @@
"reactionSoundsForAll": "Desativar sons para todos",
"screenShareNoAudio": "A caixa de compartilhar áudio não foi marcada no ecrã de seleção da janela.",
"screenShareNoAudioTitle": "Não foi possível partilhar o áudio do sistema!",
"screenSharingAudioOnlyDescription": "Note por favor que ao partilhar o seu ecrã está a afectar o modo \"Melhor desempenho\" e irá utilizar mais largura de banda.",
"screenSharingAudioOnlyTitle": "Modo \"Melhor desempenho\"",
"selfViewTitle": "Pode sempre reexibir a autovisualização a partir das definições",
"somebody": "Alguém",
"startSilentDescription": "Volte à reunião para habilitar o áudio",
@ -858,9 +863,6 @@
"rejected": "Rejeitado",
"ringing": "Tocando..."
},
"privacyView": {
"title": "Privacidade"
},
"profile": {
"avatar": "avatar",
"setDisplayNameLabel": "Definir seu nome de exibição",
@ -914,6 +916,7 @@
"localRecordingVideoWarning": "Para gravar o seu vídeo deve tê-lo ligado quando iniciar a gravação",
"localRecordingWarning": "Certifique-se de selecionar o separador actual a fim de utilizar o vídeo e áudio corretos. A gravação está actualmente limitada a 1 GB, o que é cerca de 100 minutos.",
"loggedIn": "Conectado como {{userName}}",
"noMicPermission": "Não foi possível criar a faixa de microfone. Por favor, conceda permissão para utilizar o microfone.",
"noStreams": "Não foi detetado nenhum sinal áudio ou vídeo.",
"off": "Gravação parada",
"offBy": "{{name}} parou a gravação",
@ -964,7 +967,7 @@
"incomingMessage": "Receber uma mensagem",
"language": "Idioma",
"loggedIn": "Sessão iniciada como {{name}}",
"maxStageParticipants": "Número máximo de participantes que podem ser afixados",
"maxStageParticipants": "Número máximo de participantes que podem ser afixados (EXPERIMENTAL)",
"microphones": "Microfones",
"moderator": "Moderador",
"more": "Mais",
@ -983,7 +986,7 @@
"sounds": "Sons",
"speakers": "Participantes",
"startAudioMuted": "Todos começam com microfone desligado",
"startReactionsMuted": "Sons de reação silenciados para todos",
"startReactionsMuted": "Todos começam com os sons de reação desativados",
"startVideoMuted": "Todos começam com câmara desligada",
"talkWhileMuted": "Falar com o microfone desligado",
"title": "Definições"
@ -1003,6 +1006,7 @@
"displayName": "Nome de exibição",
"displayNamePlaceholderText": "Ex: João Dias",
"email": "Email",
"emailPlaceholderText": "email@example.com",
"goTo": "Ir para",
"header": "Configurações",
"help": "Ajuda",
@ -1291,6 +1295,7 @@
"show": "Mostrar no palco",
"showSelfView": "Mostrar autovisualização",
"unpinFromStage": "Desafixar",
"verify": "Verificar participante",
"videoMuted": "Câmara desativada",
"videomute": "Participante parou a câmara"
},
@ -1358,6 +1363,7 @@
"recentList": "Recente",
"recentListDelete": "Remover",
"recentListEmpty": "A sua lista recente está atualmente vazia. Converse com a sua equipa e encontrará aqui todas as suas reuniões recentes.",
"recentMeetings": "As suas reuniões recentes",
"reducedUIText": "Bem-vindo ao {{app}}!",
"roomNameAllowedChars": "Nome da reunião não deve conter qualquer um destes caracteres: ?. &, :, ', \", %, #.",
"roomname": "Digite o nome da sala",
@ -1366,6 +1372,7 @@
"settings": "Definições",
"startMeeting": "Iniciar reunião",
"terms": "Termos",
"title": "Videoconferências mais seguras, flexíveis e totalmente gratuitas"
"title": "Videoconferências mais seguras, flexíveis e totalmente gratuitas",
"upcomingMeetings": "As suas próximas reuniões"
}
}

View File

@ -184,13 +184,21 @@
"deepLinking": {
"appNotInstalled": "You need the {{app}} mobile app to join this meeting on your phone.",
"description": "Nothing happened? We tried launching your meeting in the {{app}} desktop app. Try again or launch it in the {{app}} web app.",
"descriptionNew": "Nothing happened? We tried launching your meeting in the {{app}} desktop app. <br /><br /> You can try again or launch it on web.",
"descriptionWithoutWeb": "Nothing happened? We tried launching your meeting in the {{app}} desktop app.",
"downloadApp": "Download the app",
"downloadMobileApp": "Download from App Store",
"ifDoNotHaveApp": "If you don't have the app yet:",
"ifHaveApp": "If you already have the app:",
"joinInApp": "Join this meeting using the app",
"joinInAppNew": "Join in app",
"joinInBrowser": "Join in browser",
"launchMeetingLabel": "How do you want to join this meeting?",
"launchWebButton": "Launch in web",
"noMobileApp": "You dont have the app?",
"termsAndConditions": "By continuing you agree to our <a href='{{termsAndConditionsLink}}' rel='noopener noreferrer' target='_blank'>terms & conditions.</a>",
"title": "Launching your meeting in {{app}}...",
"titleNew": "Launching your meeting ...",
"tryAgainButton": "Try again in desktop",
"unsupportedBrowser": "It looks like you're using a browser we don't support."
},
@ -203,10 +211,16 @@
"microphonePermission": "Error obtaining microphone permission"
},
"deviceSelection": {
"hid": {
"callControl": "Call control",
"connectedDevices": "Connected devices:",
"deleteDevice": "Delete device",
"pairDevice": "Pair device"
},
"noPermission": "Permission not granted",
"previewUnavailable": "Preview unavailable",
"selectADevice": "Select a device",
"testAudio": "Play a test sound"
"testAudio": "Test"
},
"dialIn": {
"screenTitle": "Dial-in summary"
@ -226,7 +240,9 @@
"WaitingForHostTitle": "Waiting for the host ...",
"Yes": "Yes",
"accessibilityLabel": {
"liveStreaming": "Live Stream"
"close": "Close dialog",
"liveStreaming": "Live Stream",
"sharingTabs": "Sharing options"
},
"add": "Add",
"addMeetingNote": "Add a note about this meeting",
@ -438,6 +454,11 @@
"veryBad": "Very Bad",
"veryGood": "Very Good"
},
"filmstrip": {
"accessibilityLabel": {
"heading": "Video thumbnails"
}
},
"giphy": {
"noResults": "No results found :(",
"search": "Search GIPHY"
@ -751,6 +772,7 @@
"headings": {
"lobby": "Lobby ({{count}})",
"participantsList": "Meeting participants ({{count}})",
"visitors": "Visitors ({{count}})",
"waitingLobby": "Waiting in lobby ({{count}})"
},
"search": "Search participants",
@ -758,6 +780,7 @@
},
"passwordDigitsOnly": "Up to {{number}} digits",
"passwordSetRemotely": "Set by another participant",
"pinParticipant": "{{participantName}} - Pin",
"pinnedParticipant": "The participant is pinned",
"polls": {
"answer": {
@ -865,9 +888,9 @@
},
"profile": {
"avatar": "avatar",
"setDisplayNameLabel": "Set your display name",
"setDisplayNameLabel": "Name",
"setEmailInput": "Enter email",
"setEmailLabel": "Set your gravatar email",
"setEmailLabel": "Gravatar email",
"title": "Profile"
},
"raisedHand": "Would like to speak",
@ -916,6 +939,7 @@
"localRecordingVideoWarning": "To record your video you must have it on when starting the recording",
"localRecordingWarning": "Make sure you select the current tab in order to use the right video and audio. The recording is currently limited to 1GB, which is around 100 minutes.",
"loggedIn": "Logged in as {{userName}}",
"noMicPermission": "Microphone track could not be created. Please grant permission to use the microphone.",
"noStreams": "No audio or video stream detected.",
"off": "Recording stopped",
"offBy": "{{name}} stopped the recording",
@ -949,6 +973,7 @@
"title": "Security Options"
},
"settings": {
"audio": "Audio",
"buttonLabel": "Settings",
"calendar": {
"about": "The {{appName}} calendar integration is used to securely access your calendar so it can read upcoming events.",
@ -969,9 +994,11 @@
"maxStageParticipants": "Maximum number of participants who can be pinned to the main stage (EXPERIMENTAL)",
"microphones": "Microphones",
"moderator": "Moderator",
"more": "More",
"moderatorOptions": "Moderator options",
"more": "General",
"name": "Name",
"noDevice": "None",
"notifications": "Notifications",
"participantJoined": "Participant Joined",
"participantKnocking": "Participant entered lobby",
"participantLeft": "Participant Left",
@ -982,13 +1009,14 @@
"selectCamera": "Camera",
"selectMic": "Microphone",
"selfView": "Self view",
"sounds": "Sounds",
"shortcuts": "Shortcuts",
"speakers": "Speakers",
"startAudioMuted": "Everyone starts muted",
"startReactionsMuted": "Mute reaction sounds for everyone",
"startVideoMuted": "Everyone starts hidden",
"talkWhileMuted": "Talk while muted",
"title": "Settings"
"title": "Settings",
"video": "Video"
},
"settingsView": {
"advanced": "Advanced",
@ -1080,6 +1108,7 @@
"giphy": "Toggle GIPHY menu",
"grantModerator": "Grant Moderator Rights",
"hangup": "Leave the meeting",
"heading": "Toolbar",
"help": "Help",
"invite": "Invite people",
"kick": "Kick participant",
@ -1146,6 +1175,7 @@
"download": "Download our apps",
"e2ee": "End-to-End Encryption",
"embedMeeting": "Embed meeting",
"enableNoiseSuppression": "Enable noise suppression",
"endConference": "End meeting for all",
"enterFullScreen": "View full screen",
"enterTileView": "Enter tile view",
@ -1233,6 +1263,7 @@
"subtitlesOff": "Off",
"tr": "TR"
},
"unpinParticipant": "{{participantName}} - Unpin",
"userMedia": {
"androidGrantPermissions": "Select <b><i>Allow</i></b> when your browser asks for permissions.",
"chromeGrantPermissions": "Select <b><i>Allow</i></b> when your browser asks for permissions.",
@ -1271,9 +1302,11 @@
"ldTooltip": "Viewing low definition video",
"lowDefinition": "Low definition",
"performanceSettings": "Performance settings",
"recording": "Recording in progress",
"sd": "SD",
"sdTooltip": "Viewing standard definition video",
"standardDefinition": "Standard definition"
"standardDefinition": "Standard definition",
"streaming": "Streaming in progress"
},
"videothumbnail": {
"connectionInfo": "Connection Info",
@ -1285,6 +1318,7 @@
"grantModerator": "Grant Moderator Rights",
"hideSelfView": "Hide self view",
"kick": "Kick out",
"mirrorVideo": "Mirror my video",
"moderator": "Moderator",
"mute": "Participant is muted",
"muted": "Muted",
@ -1316,12 +1350,13 @@
"none": "None",
"pleaseWait": "Please wait...",
"removeBackground": "Remove background",
"slightBlur": "Slight Blur",
"slightBlur": "Half Blur",
"title": "Virtual backgrounds",
"uploadedImage": "Uploaded image {{index}}",
"webAssemblyWarning": "WebAssembly not supported",
"webAssemblyWarningDescription": "WebAssembly disabled or not supported by this browser"
},
"visitorsLabel": "Number of visitors: {{count}}",
"volumeSlider": "Volume slider",
"welcomepage": {
"accessibilityLabel": {
@ -1354,6 +1389,7 @@
"microsoftLogo": "Microsoft logo",
"policyLogo": "Policy logo"
},
"meetingsAccessibilityLabel": "Meetings",
"mobileDownLoadLinkAndroid": "Download mobile app for Android",
"mobileDownLoadLinkFDroid": "Download mobile app for F-Droid",
"mobileDownLoadLinkIos": "Download mobile app for iOS",
@ -1373,5 +1409,10 @@
"terms": "Terms",
"title": "Secure, fully featured, and completely free video conferencing",
"upcomingMeetings": "Your upcoming meetings"
},
"whiteboard": {
"accessibilityLabel": {
"heading": "Whiteboard"
}
}
}

View File

@ -71,8 +71,13 @@ import {
import { appendSuffix } from '../../react/features/display-name';
import { isEnabled as isDropboxEnabled } from '../../react/features/dropbox';
import { setMediaEncryptionKey, toggleE2EE } from '../../react/features/e2ee/actions';
import { addStageParticipant, resizeFilmStrip, setVolume } from '../../react/features/filmstrip/actions.web';
import { isStageFilmstripAvailable } from '../../react/features/filmstrip/functions.web';
import {
addStageParticipant,
resizeFilmStrip,
setVolume,
togglePinStageParticipant
} from '../../react/features/filmstrip/actions.web';
import { getPinnedActiveParticipants, isStageFilmstripAvailable } from '../../react/features/filmstrip/functions.web';
import { invite } from '../../react/features/invite';
import {
selectParticipantInLargeVideo
@ -101,6 +106,8 @@ import { startAudioScreenShareFlow, startScreenShareFlow } from '../../react/fea
import { isScreenAudioSupported } from '../../react/features/screen-share/functions';
import { toggleScreenshotCaptureSummary } from '../../react/features/screenshot-capture';
import { isScreenshotCaptureEnabled } from '../../react/features/screenshot-capture/functions';
import SettingsDialog from '../../react/features/settings/components/web/SettingsDialog';
import { SETTINGS_TABS } from '../../react/features/settings/constants';
import { playSharedVideo, stopSharedVideo } from '../../react/features/shared-video/actions.any';
import { extractYoutubeIdOrURL } from '../../react/features/shared-video/functions';
import { setRequestingSubtitles, toggleRequestingSubtitles } from '../../react/features/subtitles/actions';
@ -108,7 +115,6 @@ import { isAudioMuteButtonDisabled } from '../../react/features/toolbox/function
import { setTileView, toggleTileView } from '../../react/features/video-layout';
import { muteAllParticipants } from '../../react/features/video-menu/actions';
import { setVideoQuality } from '../../react/features/video-quality';
import VirtualBackgroundDialog from '../../react/features/virtual-background/components/VirtualBackgroundDialog';
import { getJitsiMeetTransport } from '../transport';
import { API_ID, ENDPOINT_TEXT_MESSAGE_NAME } from './constants';
@ -241,6 +247,22 @@ function initCommands() {
logger.debug('Pin participant command received');
const state = APP.store.getState();
// if id not provided, unpin everybody.
if (!id) {
if (isStageFilmstripAvailable(state)) {
const pinnedParticipants = getPinnedActiveParticipants(state);
pinnedParticipants?.forEach(p => {
APP.store.dispatch(togglePinStageParticipant(p.participantId));
});
} else {
APP.store.dispatch(pinParticipant());
}
return;
}
const participant = videoType === VIDEO_TYPE.DESKTOP
? getVirtualScreenshareParticipantByOwnerId(state, id) : getParticipantById(state, id);
@ -254,7 +276,7 @@ function initCommands() {
const participantId = participant.id;
if (isStageFilmstripAvailable(APP.store.getState())) {
if (isStageFilmstripAvailable(state)) {
APP.store.dispatch(addStageParticipant(participantId, true));
} else {
APP.store.dispatch(pinParticipant(participantId));
@ -777,7 +799,8 @@ function initCommands() {
APP.store.dispatch(overwriteConfig(whitelistedConfig));
},
'toggle-virtual-background': () => {
APP.store.dispatch(toggleDialog(VirtualBackgroundDialog));
APP.store.dispatch(toggleDialog(SettingsDialog, {
defaultTab: SETTINGS_TABS.VIRTUAL_BACKGROUND }));
},
'end-conference': () => {
APP.store.dispatch(endConference());
@ -1208,6 +1231,22 @@ class API {
});
}
/**
* Notify the external app that a notification has been triggered.
*
* @param {string} title - The notification title.
* @param {string} description - The notification description.
*
* @returns {void}
*/
notifyNotificationTriggered(title: string, description: string) {
this._sendEvent({
description,
name: 'notification-triggered',
title
});
}
/**
* Notify external application that the video quality setting has changed.
*
@ -1941,6 +1980,21 @@ class API {
});
}
/**
* Notify external application ( if API is enabled) that a participant menu button was clicked.
*
* @param {string} key - The key of the participant menu button.
* @param {string} participantId - The ID of the participant for with the participant menu button was clicked.
* @returns {void}
*/
notifyParticipantMenuButtonClicked(key, participantId) {
this._sendEvent({
name: 'participant-menu-button-clicked',
key,
participantId
});
}
/**
* Disposes the allocated resources.
*

View File

@ -127,6 +127,7 @@ const events = {
'mouse-enter': 'mouseEnter',
'mouse-leave': 'mouseLeave',
'mouse-move': 'mouseMove',
'notification-triggered': 'notificationTriggered',
'outgoing-message': 'outgoingMessage',
'participant-joined': 'participantJoined',
'participant-kicked-out': 'participantKickedOut',
@ -140,6 +141,7 @@ const events = {
'raise-hand-updated': 'raiseHandUpdated',
'recording-link-available': 'recordingLinkAvailable',
'recording-status-changed': 'recordingStatusChanged',
'participant-menu-button-clicked': 'participantMenuButtonClick',
'video-ready-to-close': 'readyToClose',
'video-conference-joined': 'videoConferenceJoined',
'video-conference-left': 'videoConferenceLeft',
@ -391,7 +393,7 @@ export default class JitsiMeetExternalAPI extends EventEmitter {
this._frame.name = frameName;
this._frame.id = frameName;
this._setSize(height, width);
this._frame.sandbox = 'allow-scripts allow-same-origin allow-popups allow-forms';
this._frame.sandbox = 'allow-scripts allow-same-origin allow-popups allow-forms allow-downloads';
this._frame.setAttribute('allowFullScreen', 'true');
this._frame.style.border = 0;

View File

@ -292,17 +292,6 @@ UI.showToolbar = timeout => APP.store.dispatch(showToolbox(timeout));
// Used by torture.
UI.dockToolbar = dock => APP.store.dispatch(dockToolbox(dock));
/**
* Updates the displayed avatar for participant.
*
* @param {string} id - User id whose avatar should be updated.
* @param {string} avatarURL - The URL to avatar image to display.
* @returns {void}
*/
UI.refreshAvatarDisplay = function(id) {
VideoLayout.changeUserAvatar(id);
};
/**
* Notify user that connection failed.
* @param {string} stropheErrorMsg raw Strophe error message

View File

@ -8,39 +8,6 @@ import Filmstrip from '../videolayout/Filmstrip';
import LargeContainer from '../videolayout/LargeContainer';
import VideoLayout from '../videolayout/VideoLayout';
/**
*
*/
function bubbleIframeMouseMove(iframe) {
const existingOnMouseMove = iframe.contentWindow.onmousemove;
iframe.contentWindow.onmousemove = function(e) {
if (existingOnMouseMove) {
existingOnMouseMove(e);
}
const evt = document.createEvent('MouseEvents');
const boundingClientRect = iframe.getBoundingClientRect();
evt.initMouseEvent(
'mousemove',
true, // bubbles
false, // not cancelable
window,
e.detail,
e.screenX,
e.screenY,
e.clientX + boundingClientRect.left,
e.clientY + boundingClientRect.top,
e.ctrlKey,
e.altKey,
e.shiftKey,
e.metaKey,
e.button,
null // no related element
);
iframe.dispatchEvent(evt);
};
}
/**
* Default Etherpad frame width.
@ -68,7 +35,7 @@ class Etherpad extends LargeContainer {
iframe.id = 'etherpadIFrame';
iframe.src = url;
iframe.frameBorder = 0;
iframe.style.border = 0;
iframe.scrolling = 'no';
iframe.width = DEFAULT_WIDTH;
iframe.height = DEFAULT_HEIGHT;
@ -76,26 +43,6 @@ class Etherpad extends LargeContainer {
this.container.appendChild(iframe);
iframe.onload = function() {
// eslint-disable-next-line no-self-assign
document.domain = document.domain;
bubbleIframeMouseMove(iframe);
setTimeout(() => {
const doc = iframe.contentDocument;
// the iframes inside of the etherpad are
// not yet loaded when the etherpad iframe is loaded
const outer = doc.getElementsByName('ace_outer')[0];
bubbleIframeMouseMove(outer);
const inner = doc.getElementsByName('ace_inner')[0];
bubbleIframeMouseMove(inner);
}, 2000);
};
this.iframe = iframe;
}

View File

@ -139,12 +139,6 @@ const VideoLayout = {
}
},
changeUserAvatar(id, avatarUrl) {
if (this.isCurrentlyOnLarge(id)) {
largeVideo.updateAvatar(avatarUrl);
}
},
isLargeVideoVisible() {
return this.isLargeContainerTypeVisible(VIDEO_CONTAINER_TYPE);
},

View File

@ -8,10 +8,9 @@ import {
createShortcutEvent,
sendAnalytics
} from '../../react/features/analytics';
import { toggleDialog } from '../../react/features/base/dialog';
import { clickOnVideo } from '../../react/features/filmstrip/actions';
import { KeyboardShortcutsDialog }
from '../../react/features/keyboard-shortcuts';
import { openSettingsDialog } from '../../react/features/settings/actions';
import { SETTINGS_TABS } from '../../react/features/settings/constants';
const logger = Logger.getLogger(__filename);
@ -120,15 +119,17 @@ const KeyboardShortcut = {
return jitsiLocalStorage.getItem(_enableShortcutsKey) === 'false' ? false : true;
},
getShortcutsDescriptions() {
return _shortcutsHelp;
},
/**
* Opens the {@KeyboardShortcutsDialog} dialog.
* Opens the {@SettingsDialog} dialog on the Shortcuts page.
*
* @returns {void}
*/
openDialog() {
APP.store.dispatch(toggleDialog(KeyboardShortcutsDialog, {
shortcutDescriptions: _shortcutsHelp
}));
APP.store.dispatch(openSettingsDialog(SETTINGS_TABS.SHORTCUTS, false));
},
/**

619
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -20,10 +20,8 @@
"@atlaskit/icon": "21.2.0",
"@atlaskit/inline-dialog": "13.0.9",
"@atlaskit/inline-message": "11.0.8",
"@atlaskit/modal-dialog": "11.2.4",
"@atlaskit/multi-select": "15.0.5",
"@atlaskit/spinner": "15.0.6",
"@atlaskit/tabs": "12.1.2",
"@atlaskit/theme": "11.0.2",
"@atlaskit/tooltip": "17.1.2",
"@emotion/react": "11.10.0",
@ -46,7 +44,6 @@
"@react-native-community/netinfo": "7.1.7",
"@react-native-community/slider": "4.1.12",
"@react-native-google-signin/google-signin": "7.0.4",
"@react-native-masked-view/masked-view": "0.2.6",
"@react-navigation/bottom-tabs": "6.5.3",
"@react-navigation/elements": "1.3.13",
"@react-navigation/material-top-tabs": "6.5.2",
@ -58,6 +55,7 @@
"@types/amplitude-js": "8.16.2",
"@types/audioworklet": "0.0.29",
"@types/w3c-image-capture": "1.0.6",
"@types/w3c-web-hid": "1.0.3",
"@vladmandic/human": "2.6.5",
"@vladmandic/human-models": "2.5.9",
"@xmldom/xmldom": "0.7.9",
@ -79,7 +77,7 @@
"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/v1578.0.0+5855ca72/lib-jitsi-meet.tgz",
"lib-jitsi-meet": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1589.0.0+d43c349d/lib-jitsi-meet.tgz",
"lodash": "4.17.21",
"moment": "2.29.4",
"moment-duration-format": "2.2.2",
@ -97,11 +95,10 @@
"react-native-background-timer": "2.4.1",
"react-native-calendar-events": "2.2.0",
"react-native-callstats": "3.73.7",
"react-native-collapsible": "1.6.0",
"react-native-default-preference": "1.4.4",
"react-native-device-info": "8.4.8",
"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-gesture-handler": "2.8.0",
"react-native-gesture-handler": "2.9.0",
"react-native-get-random-values": "1.7.2",
"react-native-immersive": "2.0.0",
"react-native-keep-awake": "4.0.0",
@ -119,7 +116,7 @@
"react-native-url-polyfill": "1.3.0",
"react-native-video": "https://git@github.com/react-native-video/react-native-video#7c48ae7c8544b2b537fb60194e9620b9fcceae52",
"react-native-watch-connectivity": "1.0.11",
"react-native-webrtc": "106.0.4",
"react-native-webrtc": "106.0.6",
"react-native-webview": "11.15.1",
"react-native-youtube-iframe": "2.2.1",
"react-redux": "7.1.0",
@ -147,11 +144,11 @@
"@babel/preset-env": "7.16.0",
"@babel/preset-flow": "7.16.0",
"@babel/preset-react": "7.16.0",
"@babel/runtime": "7.16.0",
"@jitsi/eslint-config": "4.1.5",
"@types/js-md5": "0.4.3",
"@types/lodash": "4.14.182",
"@types/react": "17.0.14",
"@types/react-dom": "17.0.14",
"@types/react-linkify": "1.0.1",
"@types/react-native": "0.68.9",
"@types/react-redux": "7.1.24",
@ -166,20 +163,18 @@
"circular-dependency-plugin": "5.2.0",
"clean-css-cli": "4.3.0",
"css-loader": "3.6.0",
"eslint": "8.25.0",
"eslint": "8.35.0",
"eslint-plugin-flowtype": "8.0.3",
"eslint-plugin-import": "2.25.2",
"eslint-plugin-jsdoc": "37.0.3",
"eslint-plugin-react": "7.26.1",
"eslint-plugin-react-native": "3.11.0",
"eslint-plugin-typescript-sort-keys": "2.1.0",
"imports-loader": "0.7.1",
"jetifier": "1.6.4",
"metro-react-native-babel-preset": "0.67.0",
"patch-package": "6.4.7",
"process": "0.11.10",
"sass": "1.26.8",
"string-replace-loader": "3.0.3",
"style-loader": "3.3.1",
"traverse": "0.6.6",
"ts-loader": "9.4.1",

View File

@ -199,7 +199,7 @@ export default class AlwaysOnTop extends Component<*, State> {
color = { getAvatarColor(displayName, customAvatarBackgrounds) }
id = 'avatar'
initials = { getInitials(displayName) }
url = { displayName ? null : avatarURL } />)
url = { avatarURL } />)
</div>
<div
className = 'displayname'

View File

@ -30,12 +30,10 @@ import {
// @ts-ignore
import { screen } from '../mobile/navigation/routes';
import { clearNotifications } from '../notifications/actions';
// @ts-ignore
import { setFatalError } from '../overlay';
import { addTrackStateToURL, getDefaultURL } from './functions.native';
import logger from './logger';
import { IStore } from './types';
import { IReloadNowOptions, IStore } from './types';
export * from './actions.any';
@ -46,9 +44,10 @@ export * from './actions.any';
* @param {string|undefined} uri - The URI to which to navigate. It may be a
* full URL with an HTTP(S) scheme, a full or partial URI with the app-specific
* scheme, or a mere room name.
* @param {Object} [options] - Options.
* @returns {Function}
*/
export function appNavigate(uri?: string) {
export function appNavigate(uri?: string, options: IReloadNowOptions = {}) {
logger.info(`appNavigate to ${uri}`);
return async (dispatch: IStore['dispatch'], getState: IStore['getState']) => {
@ -144,7 +143,10 @@ export function appNavigate(uri?: string) {
dispatch(createDesiredLocalTracks());
dispatch(clearNotifications());
if (isPrejoinPageEnabled(getState())) {
// @ts-ignore
const { hidePrejoin } = options;
if (!hidePrejoin && isPrejoinPageEnabled(getState())) {
navigateRoot(screen.preJoin);
} else {
dispatch(connect());
@ -177,7 +179,6 @@ export function maybeRedirectToWelcomePage(options: any) { // eslint-disable-lin
*/
export function reloadNow() {
return (dispatch: IStore['dispatch'], getState: IStore['getState']) => {
dispatch(setFatalError(undefined));
const state = getState();
const { locationURL } = state['features/base/connection'];
@ -188,6 +189,8 @@ export function reloadNow() {
logger.info(`Reloading the conference using URL: ${locationURL}`);
dispatch(appNavigate(toURLString(newURL)));
dispatch(appNavigate(toURLString(newURL), {
hidePrejoin: true
}));
};
}

View File

@ -20,7 +20,6 @@ import {
import { isVpaasMeeting } from '../jaas/functions';
import { clearNotifications, showNotification } from '../notifications/actions';
import { NOTIFICATION_TIMEOUT_TYPE } from '../notifications/constants';
import { setFatalError } from '../overlay/actions';
import { isWelcomePageEnabled } from '../welcome/functions';
import {
@ -222,7 +221,6 @@ export function maybeRedirectToWelcomePage(options: { feedbackSubmitted?: boolea
*/
export function reloadNow() {
return (dispatch: IStore['dispatch'], getState: IStore['getState']) => {
dispatch(setFatalError(undefined));
const state = getState();
const { locationURL } = state['features/base/connection'];

View File

@ -1,10 +1,7 @@
// @flow
import React, { Fragment } from 'react';
import React from 'react';
import { BaseApp } from '../../base/app';
import { toURLString } from '../../base/util';
import { OverlayContainer } from '../../overlay';
import { appNavigate } from '../actions';
import { getDefaultURL } from '../functions';
@ -73,23 +70,7 @@ export class AbstractApp extends BaseApp<Props, *> {
}
}
/**
* Creates an extra {@link ReactElement}s to be added (unconditionally)
* alongside the main element.
*
* @abstract
* @protected
* @returns {ReactElement}
*/
_createExtraElement() {
return (
<Fragment>
<OverlayContainer />
</Fragment>
);
}
_createMainElement: (React$Element<*>, Object) => ?React$Element<*>;
_createMainElement: (React.ReactElement, Object) => ?React.ReactElement;
/**
* Gets the default URL to be opened when this {@code App} mounts.

View File

@ -1,12 +1,11 @@
// @flow
import { AtlasKitThemeProvider } from '@atlaskit/theme';
import React from 'react';
import React, { Fragment } from 'react';
import GlobalStyles from '../../base/ui/components/GlobalStyles.web';
import JitsiThemeProvider from '../../base/ui/components/JitsiThemeProvider.web';
import DialogContainer from '../../base/ui/components/web/DialogContainer';
import { ChromeExtensionBanner } from '../../chrome-extension-banner';
import OverlayContainer from '../../overlay/components/web/OverlayContainer';
import { AbstractApp } from './AbstractApp';
@ -14,12 +13,30 @@ import { AbstractApp } from './AbstractApp';
import '../middlewares';
import '../reducers';
/**
* Root app {@code Component} on Web/React.
*
* @augments AbstractApp
*/
export class App extends AbstractApp {
/**
* Creates an extra {@link ReactElement}s to be added (unconditionally)
* alongside the main element.
*
* @abstract
* @protected
* @returns {ReactElement}
*/
_createExtraElement() {
return (
<Fragment>
<OverlayContainer />
</Fragment>
);
}
/**
* Overrides the parent method to inject {@link AtlasKitThemeProvider} as
* the top most component.

View File

@ -48,5 +48,6 @@ import '../transcribing/middleware';
import '../video-layout/middleware';
import '../video-quality/middleware';
import '../videosipgw/middleware';
import '../visitors/middleware';
import './middleware';

View File

@ -5,7 +5,6 @@ import '../base/media/middleware';
import '../dynamic-branding/middleware';
import '../e2ee/middleware';
import '../external-api/middleware';
import '../keyboard-shortcuts/middleware';
import '../no-audio-signal/middleware';
import '../notifications/middleware';
import '../noise-detection/middleware';
@ -15,12 +14,12 @@ import '../prejoin/middleware';
import '../remote-control/middleware';
import '../screen-share/middleware';
import '../shared-video/middleware';
import '../web-hid/middleware';
import '../settings/middleware';
import '../talk-while-muted/middleware';
import '../toolbox/middleware';
import '../face-landmarks/middleware';
import '../gifs/middleware';
import '../whiteboard/middleware';
import '../base/dialog/middleware';
import './middlewares.any';

View File

@ -56,3 +56,4 @@ import '../transcribing/reducer';
import '../video-layout/reducer';
import '../video-quality/reducer';
import '../videosipgw/reducer';
import '../visitors/reducer';

View File

@ -16,5 +16,6 @@ import '../screenshot-capture/reducer';
import '../talk-while-muted/reducer';
import '../virtual-background/reducer';
import '../whiteboard/reducer';
import '../web-hid/reducer';
import './reducers.any';

View File

@ -76,6 +76,8 @@ import { IVideoLayoutState } from '../video-layout/reducer';
import { IVideoQualityPersistedState, IVideoQualityState } from '../video-quality/reducer';
import { IVideoSipGW } from '../videosipgw/reducer';
import { IVirtualBackground } from '../virtual-background/reducer';
import { IVisitorsState } from '../visitors/reducer';
import { IWebHid } from '../web-hid/reducer';
import { IWhiteboardState } from '../whiteboard/reducer';
export interface IStore {
@ -90,6 +92,7 @@ export interface IReduxState {
'features/background': IBackgroundState;
'features/base/app': IAppState;
'features/base/audio-only': IAudioOnlyState;
'features/base/color-scheme': any;
'features/base/conference': IConferenceState;
'features/base/config': IConfigState;
'features/base/connection': IConnectionState;
@ -162,5 +165,11 @@ export interface IReduxState {
'features/video-quality-persistent-storage': IVideoQualityPersistedState;
'features/videosipgw': IVideoSipGW;
'features/virtual-background': IVirtualBackground;
'features/visitors': IVisitorsState;
'features/web-hid': IWebHid;
'features/whiteboard': IWhiteboardState;
}
export interface IReloadNowOptions {
hidePrejoin?: boolean;
}

View File

@ -98,7 +98,7 @@ function _upgradeRoleFinished(
name: authenticationError || connectionError,
...other
};
progress = authenticationError ? 0.5 : 0;
progress = 0;
}
return {

View File

@ -207,7 +207,7 @@ class LoginDialog extends Component<IProps, IState> {
let messageKey;
if (progress && progress < 1) {
messageKey = t('connection.FETCH_SESSION_ID');
messageKey = 'connection.FETCH_SESSION_ID';
} else if (error) {
const { name } = error;
@ -218,14 +218,14 @@ class LoginDialog extends Component<IProps, IState> {
&& credentials.jid === toJid(username, configHosts ?? { authdomain: '',
domain: '' })
&& credentials.password === password) {
messageKey = t('dialog.incorrectPassword');
messageKey = 'dialog.incorrectPassword';
}
} else if (name) {
messageKey = t('dialog.connectErrorWithMsg');
messageKey = 'dialog.connectErrorWithMsg';
messageOptions.msg = `${name} ${error.message}`;
}
} else if (connecting) {
messageKey = t('connection.CONNECTING');
messageKey = 'connection.CONNECTING';
}
if (messageKey) {

View File

@ -24,9 +24,8 @@ import {
openWaitForOwnerDialog,
stopWaitForOwner
} from './actions.web';
// eslint-disable-next-line lines-around-comment
// @ts-ignore
import { LoginDialog, WaitForOwnerDialog } from './components';
import LoginDialog from './components/web/LoginDialog';
import WaitForOwnerDialog from './components/web/WaitForOwnerDialog';
/**
* Middleware that captures connection or conference failed errors and controls

View File

@ -1,7 +1,5 @@
// @flow
import { toState } from '../redux';
import { StyleType } from '../styles';
import { toState } from '../redux/functions';
import { StyleType } from '../styles/functions.any';
import defaultScheme from './defaultScheme';
@ -90,7 +88,7 @@ class ColorSchemeRegistry {
stateful: Object | Function,
componentName: string,
style: StyleType): StyleType {
let schemedStyle;
let schemedStyle: any;
if (Array.isArray(style)) {
// The style is an array of styles, we apply the same transformation
@ -116,7 +114,7 @@ class ColorSchemeRegistry {
// The value is another style object, we apply the same
// transformation recursively.
schemedStyle[styleName]
= this._applyColorScheme(
= this._applyColorScheme( // @ts-ignore
stateful, componentName, styleValue);
} else if (typeof styleValue === 'function') {
// The value is a function, which indicates that it's a
@ -149,11 +147,14 @@ class ColorSchemeRegistry {
stateful: Object | Function,
componentName: string,
colorDefinition: string): string {
// @ts-ignore
const colorScheme = toState(stateful)['features/base/color-scheme'] || {};
return {
...defaultScheme._defaultTheme,
...colorScheme._defaultTheme,
// @ts-ignore
...defaultScheme[componentName],
...colorScheme[componentName]
}[colorDefinition];

View File

@ -1,4 +1,5 @@
import { ColorPalette, getRGBAFormat } from '../styles';
import { ColorPalette } from '../styles/components/styles/ColorPalette';
import { getRGBAFormat } from '../styles/functions.any';
/**
* The default color scheme of the application.

View File

@ -1,5 +1,3 @@
// @flow
/**
* A special function to be used in the {@code createColorSchemedStyle} call,
* that denotes that the color is a dynamic color.

View File

@ -88,7 +88,7 @@ const useStyles = makeStyles()(theme => {
boxShadow: 'inset 0px -1px 0px rgba(255, 255, 255, 0.15)',
minHeight: '40px',
'&:hover': {
'&:hover, &:focus-within': {
backgroundColor: theme.palette.ui02,
'& .indicators': {
@ -97,6 +97,8 @@ const useStyles = makeStyles()(theme => {
'& .actions': {
display: 'flex',
position: 'relative',
top: 'auto',
boxShadow: `-15px 0px 10px -5px ${theme.palette.ui02}`,
backgroundColor: theme.palette.ui02
}
@ -154,7 +156,8 @@ const useStyles = makeStyles()(theme => {
},
actionsContainer: {
display: 'none',
position: 'absolute',
top: '-1000px',
boxShadow: `-15px 0px 10px -5px ${theme.palette.ui02}`,
backgroundColor: theme.palette.ui02
},

View File

@ -98,7 +98,7 @@ export function overwriteConfig(config: Object) {
* base/config.
* @returns {Function}
*/
export function setConfig(config: Object = {}) {
export function setConfig(config: IConfig = {}) {
return (dispatch: IStore['dispatch'], getState: IStore['getState']) => {
const { locationURL } = getState()['features/base/connection'];
@ -119,6 +119,26 @@ export function setConfig(config: Object = {}) {
window.interfaceConfig,
locationURL);
let { bosh } = config;
if (bosh) {
// Normalize the BOSH URL.
if (bosh.startsWith('//')) {
// By default our config.js doesn't include the protocol.
bosh = `${locationURL?.protocol}${bosh}`;
} else if (bosh.startsWith('/')) {
// Handle relative URLs, which won't work on mobile.
const {
protocol,
host,
contextRoot
} = parseURIString(locationURL?.href);
bosh = `${protocol}//${host}${contextRoot || '/'}${bosh.substr(1)}`;
}
config.bosh = bosh;
}
dispatch({
type: SET_CONFIG,
config

View File

@ -206,6 +206,8 @@ export interface IConfig {
};
};
corsAvatarURLs?: Array<string>;
customParticipantMenuButtons?: Array<{ icon: string; id: string; text: string; }>;
customToolbarButtons?: Array<{ icon: string; id: string; text: string; }>;
deeplinking?: IDeeplinkingConfig;
defaultLanguage?: string;
defaultLocalDisplayName?: string;
@ -386,6 +388,11 @@ export interface IConfig {
lastNLimits?: {
[key: number]: number;
};
legalUrls?: {
helpCentre: string;
privacy: string;
terms: string;
};
liveStreaming?: {
dataPrivacyLink?: string;
enabled?: boolean;
@ -394,6 +401,10 @@ export interface IConfig {
validatorRegExpString?: string;
};
liveStreamingEnabled?: boolean;
lobby?: {
autoKnock?: boolean;
enableChat?: boolean;
};
localRecording?: {
disable?: boolean;
disableSelfRecording?: boolean;
@ -464,6 +475,10 @@ export interface IConfig {
enabled?: boolean;
mode?: 'always' | 'recording';
};
securityUi?: {
disableLobbyPassword?: boolean;
hideLobbyButton?: boolean;
};
serviceUrl?: string;
sipInviteUrl?: string;
speakerStats?: {

View File

@ -185,6 +185,7 @@ export default [
'inviteAppName',
'liveStreaming',
'liveStreamingEnabled',
'lobby',
'localRecording',
'localSubject',
'logging',
@ -209,6 +210,7 @@ export default [
'resolution',
'salesforceUrl',
'screenshotCapture',
'securityUi',
'speakerStats',
'startAudioMuted',
'startAudioOnly',

View File

@ -61,6 +61,11 @@ export const PREMEETING_BUTTONS = [ 'microphone', 'camera', 'select-background',
*/
export const THIRD_PARTY_PREJOIN_BUTTONS = [ 'microphone', 'camera', 'select-background' ];
/**
* The toolbar buttons to show when in visitors mode.
*/
export const VISITORS_MODE_BUTTONS = [ 'hangup', 'tileview' ];
/**
* The set of feature flags.
*
@ -70,3 +75,18 @@ export const THIRD_PARTY_PREJOIN_BUTTONS = [ 'microphone', 'camera', 'select-bac
export const FEATURE_FLAGS = {
SSRC_REWRITING: 'ssrcRewritingEnabled'
};
/**
* The URL at which the terms (of service/use) are available to the user.
*/
export const DEFAULT_TERMS_URL = 'https://jitsi.org/meet/terms';
/**
* The URL at which the privacy policy is available to the user.
*/
export const DEFAULT_PRIVACY_URL = 'https://jitsi.org/meet/privacy';
/**
* The URL at which the help centre is available to the user.
*/
export const DEFAULT_HELP_CENTRE_URL = 'https://web-cdn.jitsi.net/faq/meet-faq.html';

View File

@ -11,7 +11,13 @@ import { parseURLParams } from '../util/parseURLParams';
import { IConfig } from './configType';
import CONFIG_WHITELIST from './configWhitelist';
import { FEATURE_FLAGS, _CONFIG_STORE_PREFIX } from './constants';
import {
DEFAULT_HELP_CENTRE_URL,
DEFAULT_PRIVACY_URL,
DEFAULT_TERMS_URL,
FEATURE_FLAGS,
_CONFIG_STORE_PREFIX
} from './constants';
import INTERFACE_CONFIG_WHITELIST from './interfaceConfigWhitelist';
import logger from './logger';
@ -316,3 +322,34 @@ export function getDialOutStatusUrl(state: IReduxState) {
export function getDialOutUrl(state: IReduxState) {
return state['features/base/config'].guestDialOutUrl;
}
/**
* Selector to return the security UI config.
*
* @param {IReduxState} state - State object.
* @returns {Object}
*/
export function getSecurityUiConfig(state: IReduxState) {
return state['features/base/config']?.securityUi || {};
}
/**
* Returns the terms, privacy and help centre URL's.
*
* @param {IReduxState} state - The state of the application.
* @returns {{
* privacy: string,
* helpCentre: string,
* terms: string
* }}
*/
export function getLegalUrls(state: IReduxState) {
const helpCentreURL = state['features/base/config']?.helpCentreURL;
const configLegalUrls = state['features/base/config']?.legalUrls;
return {
privacy: configLegalUrls?.privacy || DEFAULT_PRIVACY_URL,
helpCentre: helpCentreURL || configLegalUrls?.helpCentre || DEFAULT_HELP_CENTRE_URL,
terms: configLegalUrls?.terms || DEFAULT_TERMS_URL
};
}

View File

@ -32,9 +32,16 @@ export function getReplaceParticipant(state: IReduxState): string | undefined {
* @returns {Array<string>} - The list of enabled toolbar buttons.
*/
export function getToolbarButtons(state: IReduxState): Array<string> {
const { toolbarButtons } = state['features/base/config'];
const { toolbarButtons, customToolbarButtons } = state['features/base/config'];
const customButtons = customToolbarButtons?.map(({ id }) => id);
return Array.isArray(toolbarButtons) ? toolbarButtons : TOOLBAR_BUTTONS;
const buttons = Array.isArray(toolbarButtons) ? toolbarButtons : TOOLBAR_BUTTONS;
if (customButtons) {
buttons.push(...customButtons);
}
return buttons;
}
/**
@ -101,3 +108,30 @@ export function _setDeeplinkingDefaults(deeplinking: IDeeplinkingConfig) {
android.dynamicLink.isi = android.dynamicLink.isi || '1165103905';
}
}
/**
* Returns the list of buttons that have that notify the api when clicked.
*
* @param {Object} state - The redux state.
* @returns {Array} - The list of buttons.
*/
export function getButtonsWithNotifyClick(state: IReduxState): Array<{ key: string; preventExecution: boolean; }> {
const { buttonsWithNotifyClick, customToolbarButtons } = state['features/base/config'];
const customButtons = customToolbarButtons?.map(({ id }) => {
return {
key: id,
preventExecution: false
};
});
const buttons = Array.isArray(buttonsWithNotifyClick)
? buttonsWithNotifyClick as Array<{ key: string; preventExecution: boolean; }>
: [];
if (customButtons) {
buttons.push(...customButtons);
}
return buttons;
}

View File

@ -52,9 +52,7 @@ function _setConfig({ dispatch, getState }: IStore, next: Function, action: AnyA
const settings = state['features/base/settings'];
const config: IConfig = {};
// FIXME: P2P is currently temporality disabled on mobile.
// eslint-disable-next-line no-constant-condition
if (false && typeof settings.disableP2P !== 'undefined') {
if (typeof settings.disableP2P !== 'undefined') {
config.p2p = { enabled: !settings.disableP2P };
}

View File

@ -57,10 +57,8 @@ const INITIAL_RN_STATE: IConfig = {
// than requiring this override here...
p2p: {
// Temporarily disable P2P on mobile while we sort out some (codec?) issues.
enabled: false,
disabledCodec: 'vp9',
preferredCodec: 'h264'
preferredCodec: 'vp8'
},
videoQuality: {
@ -535,6 +533,30 @@ function _translateLegacyConfig(oldValue: IConfig) {
};
}
if (oldValue.autoKnockLobby !== undefined
&& newValue.lobby?.autoKnock === undefined) {
newValue.lobby = {
...newValue.lobby || {},
autoKnock: oldValue.autoKnockLobby
};
}
if (oldValue.enableLobbyChat !== undefined
&& newValue.lobby?.enableChat === undefined) {
newValue.lobby = {
...newValue.lobby || {},
enableChat: oldValue.enableLobbyChat
};
}
if (oldValue.hideLobbyButton !== undefined
&& newValue.securityUi?.hideLobbyButton === undefined) {
newValue.securityUi = {
...newValue.securityUi || {},
hideLobbyButton: oldValue.hideLobbyButton
};
}
_setDeeplinkingDefaults(newValue.deeplinking as IDeeplinkingConfig);
return newValue;

View File

@ -3,8 +3,7 @@ import _ from 'lodash';
import { IReduxState } from '../../app/types';
import {
appendURLParam,
getBackendSafeRoomName,
parseURIString
getBackendSafeRoomName
} from '../util/uri';
import {
@ -145,7 +144,8 @@ export function constructOptions(state: IReduxState) {
// redux store.
const options = _.cloneDeep(state['features/base/config']);
let { bosh, websocket } = options;
const { bosh } = options;
let { websocket } = options;
// TESTING: Only enable WebSocket for some percentage of users.
if (websocket && navigator.product === 'ReactNative') {
@ -154,25 +154,6 @@ export function constructOptions(state: IReduxState) {
}
}
// Normalize the BOSH URL.
if (bosh && !websocket) {
const { locationURL } = state['features/base/connection'];
if (bosh.startsWith('//')) {
// By default our config.js doesn't include the protocol.
bosh = `${locationURL?.protocol}${bosh}`;
} else if (bosh.startsWith('/')) {
// Handle relative URLs, which won't work on mobile.
const {
protocol,
host,
contextRoot
} = parseURIString(locationURL?.href);
bosh = `${protocol}//${host}${contextRoot || '/'}${bosh.substr(1)}`;
}
}
// WebSocket is preferred over BOSH.
const serviceUrl = websocket || bosh;

View File

@ -1,43 +0,0 @@
// @flow
import React, { Component } from 'react';
import { Container, Text } from '../../react';
import { type StyleType } from '../../styles';
import styles from './styles';
type Props = {
/**
* Children of the component.
*/
children: string | React$Node,
style: ?StyleType
};
/**
* Generic dialog content container to provide the same styling for all custom
* dialogs.
*/
export default class DialogContent extends Component<Props> {
/**
* Implements {@code Component#render}.
*
* @inheritdoc
*/
render() {
const { children, style } = this.props;
const childrenComponent = typeof children === 'string'
? <Text style = { style }>{ children }</Text>
: children;
return (
<Container style = { styles.dialogContainer }>
{ childrenComponent }
</Container>
);
}
}

View File

@ -1,5 +1,3 @@
// @flow
export * from './_';
export { default as DialogContent } from './DialogContent';

View File

@ -48,7 +48,7 @@ type Props = {
/**
* Dialog title.
*/
title?: string,
title?: string
};
/**

View File

@ -0,0 +1,231 @@
/* eslint-disable lines-around-comment */
// @ts-ignore
import { randomInt } from '@jitsi/js-utils/random';
import React, { Component } from 'react';
import { WithTranslation } from 'react-i18next';
import type { Dispatch } from 'redux';
import { appNavigate, reloadNow } from '../../../../app/actions.native';
import { IReduxState } from '../../../../app/types';
import { translate } from '../../../i18n/functions';
import { isFatalJitsiConnectionError } from '../../../lib-jitsi-meet/functions.native';
import { connect } from '../../../redux/functions';
import { hideDialog } from '../../actions';
// @ts-ignore
import logger from '../../logger';
// @ts-ignore
import ConfirmDialog from './ConfirmDialog';
/**
* The type of the React {@code Component} props of
* {@link PageReloadDialog}.
*/
interface IPageReloadDialogProps extends WithTranslation {
dispatch: Dispatch<any>;
isNetworkFailure: boolean;
reason: string;
}
/**
* The type of the React {@code Component} state of
* {@link PageReloadDialog}.
*/
interface IPageReloadDialogState {
timeLeft: number;
}
/**
* Implements a React Component that is shown before the
* conference is reloaded.
* Shows a warning message and counts down towards the re-load.
*/
class PageReloadDialog extends Component<IPageReloadDialogProps, IPageReloadDialogState> {
// @ts-ignore
_interval: IntervalID;
_timeoutSeconds: number;
/**
* Initializes a new PageReloadOverlay instance.
*
* @param {Object} props - The read-only properties with which the new
* instance is to be initialized.
* @public
*/
constructor(props: IPageReloadDialogProps) {
super(props);
this._timeoutSeconds = 10 + randomInt(0, 20);
this.state = {
timeLeft: this._timeoutSeconds
};
this._onCancel = this._onCancel.bind(this);
this._onReloadNow = this._onReloadNow.bind(this);
this._onReconnecting = this._onReconnecting.bind(this);
}
/**
* React Component method that executes once component is mounted.
*
* @inheritdoc
* @returns {void}
*/
componentDidMount() {
const { timeLeft } = this.state;
logger.info(
`The conference will be reloaded after ${timeLeft} seconds.`
);
this._interval = setInterval(() =>
this._onReconnecting(), 1000);
}
/**
* Clears the timer interval.
*
* @inheritdoc
* @returns {void}
*/
componentWillUnmount() {
if (this._interval) {
clearInterval(this._interval);
this._interval = undefined;
}
}
/**
* Handle clicking of the "Cancel" button. It will navigate back to the
* welcome page.
*
* @private
* @returns {boolean}
*/
_onCancel() {
const { dispatch } = this.props;
clearInterval(this._interval);
dispatch(appNavigate(undefined));
return true;
}
/**
* Handles automatic reconnection.
*
* @private
* @returns {void}
*/
_onReconnecting() {
const { dispatch } = this.props;
const { timeLeft } = this.state;
if (timeLeft === 0) {
if (this._interval) {
dispatch(hideDialog());
this._onReloadNow();
this._interval = undefined;
}
}
this.setState({
timeLeft: timeLeft - 1
});
}
/**
* Handle clicking on the "Reload Now" button. It will navigate to the same
* conference URL as before immediately, without waiting for the timer to
* kick in.
*
* @private
* @returns {boolean}
*/
_onReloadNow() {
const { dispatch } = this.props;
clearInterval(this._interval);
dispatch(reloadNow());
return true;
}
/**
* Implements React's {@link Component#render()}.
*
* @inheritdoc
* @returns {ReactElement}
*/
render() {
const { isNetworkFailure, t } = this.props;
const { timeLeft } = this.state;
let message, title;
if (isNetworkFailure) {
title = 'dialog.conferenceDisconnectTitle';
message = 'dialog.conferenceDisconnectMsg';
} else {
title = 'dialog.conferenceReloadTitle';
message = 'dialog.conferenceReloadMsg';
}
return (
<ConfirmDialog
cancelLabel = 'dialog.Cancel'
confirmLabel = 'dialog.rejoinNow'
descriptionKey = { `${t(message, { seconds: timeLeft })}` }
onCancel = { this._onCancel }
onSubmit = { this._onReloadNow }
title = { title } />
);
}
}
/**
* Maps (parts of) the redux state to the associated component's props.
*
* @param {Object} state - The redux state.
* @protected
* @returns {{
* isNetworkFailure: boolean,
* reason: string
* }}
*/
function mapStateToProps(state: IReduxState) {
const { error: conferenceError } = state['features/base/conference'];
const { error: configError } = state['features/base/config'];
const { error: connectionError } = state['features/base/connection'];
const { fatalError } = state['features/overlay'];
const fatalConnectionError
// @ts-ignore
= connectionError && isFatalJitsiConnectionError(connectionError);
const fatalConfigError = fatalError === configError;
const isNetworkFailure = fatalConfigError || fatalConnectionError;
let reason;
if (conferenceError) {
reason = `error.conference.${conferenceError.name}`;
} else if (connectionError) {
reason = `error.conference.${connectionError.name}`;
} else if (configError) {
reason = `error.config.${configError.name}`;
} else {
logger.error('No reload reason defined!');
}
return {
isNetworkFailure,
reason
};
}
export default translate(connect(mapStateToProps)(PageReloadDialog));

View File

@ -5,6 +5,7 @@ export { default as ConfirmDialog } from './ConfirmDialog';
export { default as DialogContainer } from './DialogContainer';
export { default as AlertDialog } from './AlertDialog';
export { default as InputDialog } from './InputDialog';
export { default as PageReloadDialog } from './PageReloadDialog';
// NOTE: Some dialogs reuse the style of these base classes for consistency
// and as we're in a /native namespace, it's safe to export the styles.

View File

@ -1,14 +0,0 @@
import { BoxModel, createStyleSheet } from '../../styles';
/**
* The React {@code Component} styles of {@code Dialog}.
*/
export default createStyleSheet({
/**
* Unified container for a consistent Dialog style.
*/
dialogContainer: {
paddingHorizontal: BoxModel.padding,
paddingVertical: 1.5 * BoxModel.padding
}
});

View File

@ -1,5 +0,0 @@
/**
* Placeholder styles for web to be able to use cross platform components
* unmodified such as {@code DialogContent}.
*/
export default {};

View File

@ -5,11 +5,6 @@ import { Component } from 'react';
*/
export interface IProps {
/**
* Function that closes the dialog.
*/
closeDialog: Function;
/**
* Callback to invoke on change.
*/

View File

@ -1,93 +0,0 @@
// @flow
import React from 'react';
import { connect } from '../../../redux';
import AbstractDialog from '../AbstractDialog';
import type { Props as AbstractDialogProps, State } from '../AbstractDialog';
import StatelessDialog from './StatelessDialog';
/**
* The type of the React {@code Component} props of {@link Dialog}.
*/
type Props = AbstractDialogProps & {
/**
* True if listening for the Enter key should be disabled.
*/
disableEnter: boolean,
/**
* Whether the dialog is modal. This means clicking on the blanket will
* leave the dialog open. No cancel button.
*/
isModal: boolean,
/**
* Disables rendering of the submit button.
*/
submitDisabled: boolean,
/**
* Width of the dialog, can be:
* - 'small' (400px), 'medium' (600px), 'large' (800px),
* 'x-large' (968px)
* - integer value for pixel width
* - string value for percentage.
*/
width: string
};
/**
* Web dialog that uses atlaskit modal-dialog to display dialogs.
*/
class Dialog extends AbstractDialog<Props, State> {
/**
* Initializes a new Dialog instance.
*
* @param {Object} props - The read-only properties with which the new
* instance is to be initialized.
*/
constructor(props: Props) {
super(props);
// Bind event handlers so they are only bound once per instance.
this._onCancel = this._onCancel.bind(this);
this._onSubmit = this._onSubmit.bind(this);
}
/**
* Implements React's {@link Component#render()}.
*
* @inheritdoc
* @returns {ReactElement}
*/
render() {
const props = {
...this.props,
onCancel: this._onCancel,
onSubmit: this._onSubmit
};
// $FlowExpectedError
delete props.dispatch;
return <StatelessDialog { ...props } />;
}
_onCancel: () => void;
/**
* Dispatches action to hide the dialog.
*
* @returns {void}
*/
_onCancel() {
this.props.isModal || super._onCancel();
}
_onSubmit: (?string) => void;
}
export default connect()(Dialog);

View File

@ -1,256 +0,0 @@
// @flow
import Tabs from '@atlaskit/tabs';
import React, { Component } from 'react';
import { translate } from '../../../i18n/functions';
import logger from '../../logger';
import StatelessDialog from './StatelessDialog';
/**
* The type of the React {@code Component} props of {@link DialogWithTabs}.
*/
export type Props = {
/**
* Function that closes the dialog.
*/
closeDialog: Function,
/**
* Css class name that will be added to the dialog.
*/
cssClassName: string,
/**
* Which settings tab should be initially displayed. If not defined then
* the first tab will be displayed.
*/
defaultTab: number,
/**
* Disables dismissing the dialog when the blanket is clicked. Enabled
* by default.
*/
disableBlanketClickDismiss: boolean,
/**
* Callback invoked when the Save button has been pressed.
*/
onSubmit: Function,
/**
* Invoked to obtain translated strings.
*/
t: Function,
/**
* Information about the tabs that will be rendered.
*/
tabs: Array<Object>,
/**
* Key to use for showing a title.
*/
titleKey: string
};
/**
* The type of the React {@code Component} state of {@link DialogWithTabs}.
*/
type State = {
/**
* The index of the tab that should be displayed.
*/
selectedTab: number,
/**
* An array of the states of the tabs.
*/
tabStates: Array<Object>
};
/**
* A React {@code Component} for displaying a dialog with tabs.
*
* @augments Component
*/
class DialogWithTabs extends Component<Props, State> {
/**
* Initializes a new {@code DialogWithTabs} instance.
*
* @param {Object} props - The read-only React {@code Component} props with
* which the new instance is to be initialized.
*/
constructor(props: Props) {
super(props);
this.state = {
selectedTab: this.props.defaultTab || 0,
tabStates: this.props.tabs.map(tab => tab.props)
};
this._onSubmit = this._onSubmit.bind(this);
this._onTabSelected = this._onTabSelected.bind(this);
this._onTabStateChange = this._onTabStateChange.bind(this);
}
/**
* Implements React's {@link Component#render()}.
*
* @inheritdoc
* @returns {ReactElement}
*/
render() {
const onCancel = this.props.closeDialog;
return (
<StatelessDialog
disableBlanketClickDismiss
= { this.props.disableBlanketClickDismiss }
onCancel = { onCancel }
onSubmit = { this._onSubmit }
titleKey = { this.props.titleKey } >
<div className = { this.props.cssClassName } >
{ this._renderTabs() }
</div>
</StatelessDialog>
);
}
/**
* Gets the props to pass into the tab component.
*
* @param {number} tabId - The index of the tab configuration within
* {@link this.state.tabStates}.
* @returns {Object}
*/
_getTabProps(tabId) {
const { tabs } = this.props;
const { tabStates } = this.state;
const tabConfiguration = tabs[tabId];
const currentTabState = tabStates[tabId];
if (tabConfiguration.propsUpdateFunction) {
return tabConfiguration.propsUpdateFunction(
currentTabState,
tabConfiguration.props);
}
return { ...currentTabState };
}
_onTabSelected: (Object, number) => void;
/**
* Callback invoked when the desired tab to display should be changed.
*
* @param {Object} tab - The configuration passed into atlaskit tabs to
* describe how to display the selected tab.
* @param {number} tabIndex - The index of the tab within the array of
* displayed tabs.
* @private
* @returns {void}
*/
_onTabSelected(tab, tabIndex) { // eslint-disable-line no-unused-vars
this.setState({ selectedTab: tabIndex });
}
/**
* Renders the tabs from the tab information passed on props.
*
* @returns {void}
*/
_renderTabs() {
const { t, tabs } = this.props;
if (tabs.length === 1) {
return this._renderTab({
...tabs[0],
tabId: 0
});
}
if (tabs.length > 1) {
return (
<Tabs
onSelect = { this._onTabSelected }
selected = { this.state.selectedTab }
tabs = {
tabs.map(({ component, label, styles }, idx) => {
return {
content: this._renderTab({
component,
styles,
tabId: idx
}),
label: t(label)
};
})
} />);
}
logger.warn('No settings tabs configured to display.');
return null;
}
/**
* Renders a tab from the tab information passed as parameters.
*
* @param {Object} tabInfo - Information about the tab.
* @returns {Component} - The tab.
*/
_renderTab({ component, styles, tabId }) {
const { closeDialog } = this.props;
const TabComponent = component;
return (
<div className = { styles }>
<TabComponent
closeDialog = { closeDialog }
mountCallback = { this.props.tabs[tabId].onMount }
onTabStateChange
= { this._onTabStateChange }
tabId = { tabId }
{ ...this._getTabProps(tabId) } />
</div>);
}
_onTabStateChange: (number, Object) => void;
/**
* Changes the state for a tab.
*
* @param {number} tabId - The id of the tab which state will be changed.
* @param {Object} state - The new state.
* @returns {void}
*/
_onTabStateChange(tabId, state) {
const tabStates = [ ...this.state.tabStates ];
tabStates[tabId] = state;
this.setState({ tabStates });
}
_onSubmit: () => void;
/**
* Submits the information filled in the dialog.
*
* @returns {void}
*/
_onSubmit() {
const { onSubmit, tabs } = this.props;
tabs.forEach(({ submit }, idx) => {
submit && submit(this.state.tabStates[idx]);
});
onSubmit();
}
}
export default translate(DialogWithTabs);

View File

@ -1,172 +0,0 @@
/* eslint-disable lines-around-comment */
/* eslint-disable react/no-multi-comp */
import ErrorIcon from '@atlaskit/icon/glyph/error';
import WarningIcon from '@atlaskit/icon/glyph/warning';
import {
Header,
Title,
TitleText,
titleIconWrapperStyles
// @ts-ignore
} from '@atlaskit/modal-dialog/dist/es2019/styled/Content';
import { Theme } from '@mui/material';
import { withStyles } from '@mui/styles';
import React from 'react';
import { WithTranslation } from 'react-i18next';
import { translate } from '../../../i18n/functions';
import { IconCloseLarge } from '../../../icons/svg';
import { withPixelLineHeight } from '../../../styles/functions.web';
import Button from '../../../ui/components/web/Button';
import { BUTTON_TYPES } from '../../../ui/constants.web';
const TitleIcon = ({ appearance }: { appearance?: 'danger' | 'warning'; }) => {
if (!appearance) {
return null;
}
const IconSymbol = appearance === 'danger' ? ErrorIcon : WarningIcon;
return (
<span css = { titleIconWrapperStyles(appearance) }>
<IconSymbol label = { `${appearance} icon` } />
</span>
);
};
interface IProps extends WithTranslation {
appearance?: 'danger' | 'warning';
classes: any;
heading: string;
hideCloseIconButton: boolean;
id?: string;
isHeadingMultiline: boolean;
onClose: (e?: any) => void;
showKeyline: boolean;
testId?: string;
}
/**
* Creates the styles for the component.
*
* @param {Object} theme - The current UI theme.
*
* @returns {Object}
*/
const styles = (theme: Theme) => {
return {
closeButton: {
borderRadius: theme.shape.borderRadius,
cursor: 'pointer',
padding: 13,
[theme.breakpoints.down(480)]: {
background: theme.palette.action02
},
'&:hover': {
background: theme.palette.ui04
}
},
header: {
boxShadow: 'none',
'& h4': {
...withPixelLineHeight(theme.typography.heading5),
color: theme.palette.text01
}
}
};
};
/**
* A default header for modal-dialog components.
*
* @class ModalHeader
* @augments {React.Component<IProps>}
*/
class ModalHeader extends React.Component<IProps> {
static defaultProps = {
isHeadingMultiline: true
};
/**
* Initializes a new {@code ModalHeader} instance.
*
* @param {*} props - The read-only properties with which the new instance
* is to be initialized.
*/
constructor(props: IProps) {
super(props);
// Bind event handler so it is only bound once for every instance.
this._onKeyPress = this._onKeyPress.bind(this);
}
/**
* KeyPress handler for accessibility.
*
* @param {Object} e - The key event to handle.
*
* @returns {void}
*/
_onKeyPress(e: React.KeyboardEvent) {
if (this.props.onClose && (e.key === ' ' || e.key === 'Enter')) {
e.preventDefault();
this.props.onClose();
}
}
/**
* Implements React's {@link Component#render()}.
*
* @inheritdoc
* @returns {ReactElement}
*/
render() {
const {
id,
appearance,
classes,
heading,
hideCloseIconButton,
onClose,
showKeyline,
isHeadingMultiline,
testId,
t
} = this.props;
if (!heading) {
return null;
}
return (
<Header
className = { classes.header }
showKeyline = { showKeyline }>
<Title>
<TitleIcon appearance = { appearance } />
<TitleText
data-testid = { testId && `${testId}-heading` }
id = { id }
isHeadingMultiline = { isHeadingMultiline }>
{heading}
</TitleText>
</Title>
{
!hideCloseIconButton && <Button
accessibilityLabel = { t('dialog.close') }
icon = { IconCloseLarge }
id = 'modal-header-close-button'
onClick = { onClose }
size = 'large'
type = { BUTTON_TYPES.TERTIARY } />
}
</Header>
);
}
}
export default translate(withStyles(styles)(ModalHeader));

View File

@ -1,377 +0,0 @@
/* eslint-disable lines-around-comment */
import Modal, { ModalFooter } from '@atlaskit/modal-dialog';
import { Theme } from '@mui/material';
import { withStyles } from '@mui/styles';
import React, { Component, ReactElement } from 'react';
import { WithTranslation } from 'react-i18next';
import { translate } from '../../../i18n/functions';
import Button from '../../../ui/components/web/Button';
import { BUTTON_TYPES } from '../../../ui/constants.web';
import type { DialogProps } from '../../constants';
import ModalHeader from './ModalHeader';
/**
* The ID to be used for the cancel button if enabled.
*
* @type {string}
*/
const CANCEL_BUTTON_ID = 'modal-dialog-cancel-button';
/**
* The ID to be used for the ok button if enabled.
*
* @type {string}
*/
const OK_BUTTON_ID = 'modal-dialog-ok-button';
/**
* The type of the React {@code Component} props of {@link StatelessDialog}.
*
* @static
*/
interface IProps extends DialogProps, WithTranslation {
/**
* An object containing the CSS classes.
*/
classes: any;
/**
* Custom dialog header that replaces the standard heading.
*/
customHeader?: ReactElement<any> | Function;
/**
* Disables dismissing the dialog when the blanket is clicked. Enabled
* by default.
*/
disableBlanketClickDismiss: boolean;
/*
* True if listening for the Enter key should be disabled.
*/
disableEnter: boolean;
/**
* If true, no footer will be displayed.
*/
disableFooter?: boolean;
/**
* If true, the cancel button will not display but cancel actions, like
* clicking the blanket, will cancel.
*/
hideCancelButton: boolean;
/**
* If true, the close icon button will not be displayed.
*/
hideCloseIconButton: boolean;
/**
* Whether the dialog is modal. This means clicking on the blanket will
* leave the dialog open. No cancel button.
*/
isModal: boolean;
/**
* The handler for the event when clicking the 'confirmNo' button.
* Defaults to onCancel if absent.
*/
onDecline?: () => void;
/**
* Callback invoked when setting the ref of the Dialog.
*/
onDialogRef?: Function;
/**
* Disables rendering of the submit button.
*/
submitDisabled: boolean;
/**
* Width of the dialog, can be:
* - 'small' (400px), 'medium' (600px), 'large' (800px),
* 'x-large' (968px)
* - integer value for pixel width
* - string value for percentage.
*/
width: string;
}
/**
* Creates the styles for the component.
*
* @param {Object} theme - The theme.
* @returns {Object}
*/
const styles = (theme: Theme) => {
return {
footer: {
boxShadow: 'none'
},
buttonContainer: {
display: 'flex',
'& > button:first-child': {
marginRight: theme.spacing(2)
}
}
};
};
/**
* Web dialog that uses atlaskit modal-dialog to display dialogs.
*/
class StatelessDialog extends Component<IProps> {
static defaultProps = {
hideCloseIconButton: false
};
/**
* Initializes a new {@code StatelessDialog} instance.
*
* @param {Object} props - The read-only properties with which the new
* instance is to be initialized.
*/
constructor(props: IProps) {
super(props);
// Bind event handlers so they are only bound once for every instance.
this._onCancel = this._onCancel.bind(this);
this._onDialogDismissed = this._onDialogDismissed.bind(this);
this._onKeyPress = this._onKeyPress.bind(this);
this._onSubmit = this._onSubmit.bind(this);
this._renderFooter = this._renderFooter.bind(this);
this._onDialogRef = this._onDialogRef.bind(this);
}
/**
* Implements React's {@link Component#render()}.
*
* @inheritdoc
* @returns {ReactElement}
*/
render() {
const {
customHeader,
children,
hideCloseIconButton,
t,
titleString,
titleKey,
width
} = this.props;
return (
<Modal
autoFocus = { true }
components = {{
// @ts-ignore
Header: customHeader ? customHeader : props => (
// @ts-ignore
<ModalHeader
{ ...props }
heading = { titleString || t(titleKey ?? '') }
hideCloseIconButton = { hideCloseIconButton } />
)
}}
footer = { this._renderFooter }
i18n = { this.props.i18n }
onClose = { this._onDialogDismissed }
onDialogDismissed = { this._onDialogDismissed }
shouldCloseOnEscapePress = { true }
width = { width || 'medium' }>
<div
onKeyPress = { this._onKeyPress }
ref = { this._onDialogRef }>
<form
className = 'modal-dialog-form'
id = 'modal-dialog-form'
onSubmit = { this._onSubmit }>
{ children }
</form>
</div>
</Modal>
);
}
/**
* Returns a ReactElement to display buttons for closing the modal.
*
* @param {Object} propsFromModalFooter - The props passed in from the
* {@link ModalFooter} component.
* @private
* @returns {ReactElement}
*/
_renderFooter(propsFromModalFooter: any) {
// Filter out falsy (null) values because {@code ButtonGroup} will error
// if passed in anything but buttons with valid type props.
const buttons = [
this._renderCancelButton(),
this._renderOKButton()
].filter(Boolean);
if (this.props.disableFooter) {
return null;
}
return (
<ModalFooter
className = { this.props.classes.footer }
showKeyline = { propsFromModalFooter.showKeyline } >
{
/**
* Atlaskit has this empty span (JustifySim) so...
*/
}
<span />
<div className = { this.props.classes.buttonContainer }>
{ buttons }
</div>
</ModalFooter>
);
}
/**
* Dispatches action to hide the dialog.
*
* @returns {void}
*/
_onCancel() {
if (!this.props.isModal) {
const { onCancel } = this.props;
onCancel?.();
}
}
/**
* Handles click on the blanket area.
*
* @returns {void}
*/
_onDialogDismissed() {
if (!this.props.disableBlanketClickDismiss) {
this._onCancel();
}
}
/**
* Dispatches the action when submitting the dialog.
*
* @private
* @param {string} value - The submitted value if any.
* @returns {void}
*/
_onSubmit(value?: any) {
const { onSubmit } = this.props;
onSubmit?.(value);
}
/**
* Renders Cancel button.
*
* @private
* @returns {ReactElement|null} The Cancel button if enabled and dialog is
* not modal.
*/
_renderCancelButton() {
if (this.props.cancelDisabled
|| this.props.isModal
|| this.props.hideCancelButton) {
return null;
}
const {
t,
onDecline
} = this.props;
return (
<Button
accessibilityLabel = { t(this.props.cancelKey || 'dialog.Cancel') }
id = { CANCEL_BUTTON_ID }
key = { CANCEL_BUTTON_ID }
label = { t(this.props.cancelKey || 'dialog.Cancel') }
onClick = { onDecline || this._onCancel }
size = 'small'
type = { BUTTON_TYPES.TERTIARY } />
);
}
/**
* Renders OK button.
*
* @private
* @returns {ReactElement|null} The OK button if enabled.
*/
_renderOKButton() {
const {
submitDisabled,
t
} = this.props;
if (submitDisabled) {
return null;
}
return (
<Button
accessibilityLabel = { t(this.props.okKey || 'dialog.Ok') }
disabled = { this.props.okDisabled }
id = { OK_BUTTON_ID }
key = { OK_BUTTON_ID }
label = { t(this.props.okKey || 'dialog.Ok') }
onClick = { this._onSubmit }
size = 'small' />
);
}
/**
* Callback invoked when setting the ref of the dialog's child passing the Modal ref.
* It is done this way because we cannot directly access the ref of the Modal component.
*
* @param {HTMLElement} element - The DOM element for the dialog.
* @private
* @returns {void}
*/
_onDialogRef(element?: any) {
this.props.onDialogRef?.(element?.parentNode);
}
/**
* Handles 'Enter' key in the dialog to submit/hide dialog depending on
* the available buttons and their disabled state.
*
* @param {Object} event - The key event.
* @private
* @returns {void}
*/
_onKeyPress(event: React.KeyboardEvent) {
// If the event coming to the dialog has been subject to preventDefault
// we don't handle it here.
if (event.defaultPrevented) {
return;
}
if (event.key === 'Enter' && !this.props.disableEnter) {
event.preventDefault();
event.stopPropagation();
if (this.props.submitDisabled && !this.props.cancelDisabled) {
this._onCancel();
} else if (!this.props.okDisabled) {
this._onSubmit();
}
}
}
}
export default translate(withStyles(styles)(StatelessDialog));

View File

@ -1,31 +0,0 @@
// @flow
import {
Dialog,
FillScreen,
PositionerAbsolute,
PositionerRelative,
dialogHeight,
dialogWidth
} from '@atlaskit/modal-dialog/dist/es2019/styled/Modal.js';
import { DN50, N0 } from '@atlaskit/theme/colors';
import { themed } from '@atlaskit/theme/components';
import React from 'react';
type Props = {
isChromeless: boolean
}
const ThemedDialog = (props: Props) => {
const style = { backgroundColor: props.isChromeless ? 'transparent' : themed({ light: N0,
dark: DN50 })({ theme: { mode: 'dark' } }) };
return (<Dialog
{ ...props }
aria-modal = { true }
style = { style }
theme = {{ mode: 'dark' }} />);
};
export { ThemedDialog as Dialog, FillScreen, dialogWidth, dialogHeight, PositionerAbsolute, PositionerRelative };

View File

@ -2,7 +2,4 @@
export { default as AbstractDialogTab } from './AbstractDialogTab';
export type { Props as AbstractDialogTabProps } from './AbstractDialogTab';
export { default as Dialog } from './Dialog-old';
export { default as DialogWithTabs } from './DialogWithTabs';
export { default as StatelessDialog } from './StatelessDialog';
export { default as DialogContainer } from '../../../ui/components/web/DialogContainer';

View File

@ -2,9 +2,7 @@ import { ComponentType } from 'react';
import { IReduxState } from '../../app/types';
import { IStateful } from '../app/types';
// eslint-disable-next-line lines-around-comment
// @ts-ignore
import { ColorSchemeRegistry } from '../color-scheme';
import ColorSchemeRegistry from '../color-scheme/ColorSchemeRegistry';
import { toState } from '../redux/functions';
/**
@ -28,7 +26,7 @@ export function isAnyDialogOpen(stateful: IStateful) {
* {@code Dialog} to be checked.
* @returns {boolean}
*/
export function isDialogOpen(stateful: IStateful, component: ComponentType) {
export function isDialogOpen(stateful: IStateful, component: ComponentType<any>) {
return toState(stateful)['features/base/dialog'].component === component;
}

View File

@ -1,72 +0,0 @@
/* eslint-disable lines-around-comment */
import LoginDialog from '../../authentication/components/web/LoginDialog';
import WaitForOwnerDialog from '../../authentication/components/web/WaitForOwnerDialog';
import ChatPrivacyDialog from '../../chat/components/web/ChatPrivacyDialog';
import DesktopPicker from '../../desktop-picker/components/DesktopPicker';
import DisplayNamePrompt from '../../display-name/components/web/DisplayNamePrompt';
import ParticipantVerificationDialog from '../../e2ee/components/ParticipantVerificationDialog';
import EmbedMeetingDialog from '../../embed-meeting/components/EmbedMeetingDialog';
// @ts-ignore
import FeedbackDialog from '../../feedback/components/FeedbackDialog.web';
import AddPeopleDialog from '../../invite/components/add-people-dialog/web/AddPeopleDialog';
import PremiumFeatureDialog from '../../jaas/components/web/PremiumFeatureDialog';
import KeyboardShortcutsDialog from '../../keyboard-shortcuts/components/web/KeyboardShortcutsDialog';
// @ts-ignore
import StartLiveStreamDialog from '../../recording/components/LiveStream/web/StartLiveStreamDialog';
// @ts-ignore
import StopLiveStreamDialog from '../../recording/components/LiveStream/web/StopLiveStreamDialog';
// @ts-ignore
import StartRecordingDialog from '../../recording/components/Recording/web/StartRecordingDialog';
// @ts-ignore
import StopRecordingDialog from '../../recording/components/Recording/web/StopRecordingDialog';
// @ts-ignore
import RemoteControlAuthorizationDialog from '../../remote-control/components/RemoteControlAuthorizationDialog';
import SalesforceLinkDialog from '../../salesforce/components/web/SalesforceLinkDialog';
import ShareAudioDialog from '../../screen-share/components/web/ShareAudioDialog';
import ShareScreenWarningDialog from '../../screen-share/components/web/ShareScreenWarningDialog';
import SecurityDialog from '../../security/components/security-dialog/web/SecurityDialog';
import LogoutDialog from '../../settings/components/web/LogoutDialog';
import SharedVideoDialog from '../../shared-video/components/web/SharedVideoDialog';
import SpeakerStats from '../../speaker-stats/components/web/SpeakerStats';
import LanguageSelectorDialog from '../../subtitles/components/LanguageSelectorDialog.web';
import GrantModeratorDialog from '../../video-menu/components/web/GrantModeratorDialog';
import KickRemoteParticipantDialog from '../../video-menu/components/web/KickRemoteParticipantDialog';
import MuteEveryoneDialog from '../../video-menu/components/web/MuteEveryoneDialog';
import MuteEveryonesVideoDialog from '../../video-menu/components/web/MuteEveryonesVideoDialog';
import MuteRemoteParticipantsVideoDialog from '../../video-menu/components/web/MuteRemoteParticipantsVideoDialog';
// @ts-ignore
import VideoQualityDialog from '../../video-quality/components/VideoQualityDialog.web';
import VirtualBackgroundDialog from '../../virtual-background/components/VirtualBackgroundDialog';
import MiddlewareRegistry from '../redux/MiddlewareRegistry';
import { OPEN_DIALOG } from './actionTypes';
// ! IMPORTANT - This whole middleware is only needed for the transition from from @atlaskit dialog to our component.
// ! It should be removed when the transition is over.
const NEW_DIALOG_LIST = [ KeyboardShortcutsDialog, ChatPrivacyDialog, DisplayNamePrompt, EmbedMeetingDialog,
FeedbackDialog, AddPeopleDialog, PremiumFeatureDialog, StartLiveStreamDialog, StopLiveStreamDialog,
StartRecordingDialog, StopRecordingDialog, ShareAudioDialog, ShareScreenWarningDialog, SecurityDialog,
SharedVideoDialog, SpeakerStats, LanguageSelectorDialog, MuteEveryoneDialog, MuteEveryonesVideoDialog,
GrantModeratorDialog, KickRemoteParticipantDialog, MuteRemoteParticipantsVideoDialog, VideoQualityDialog,
VirtualBackgroundDialog, LoginDialog, WaitForOwnerDialog, DesktopPicker, RemoteControlAuthorizationDialog,
LogoutDialog, SalesforceLinkDialog, ParticipantVerificationDialog ];
// This function is necessary while the transition from @atlaskit dialog to our component is ongoing.
const isNewDialog = (component: any) => NEW_DIALOG_LIST.some(comp => comp === component);
/**
* Implements the entry point of the middleware of the feature base/media.
*
* @param {IStore} store - The redux store.
* @returns {Function}
*/
MiddlewareRegistry.register(() => (next: Function) => (action: any) => {
switch (action.type) {
case OPEN_DIALOG: {
action.isNewDialog = isNewDialog(action.component);
}
}
return next(action);
});

View File

@ -13,7 +13,6 @@ import {
export interface IDialogState {
component?: ComponentType;
componentProps?: Object;
isNewDialog?: boolean;
sheet?: ComponentType;
sheetProps?: Object;
}
@ -44,8 +43,7 @@ ReducerRegistry.register<IDialogState>('features/base/dialog', (state = {}, acti
case OPEN_DIALOG:
return assign(state, {
component: action.component,
componentProps: action.componentProps,
isNewDialog: action.isNewDialog
componentProps: action.componentProps
});
case HIDE_SHEET:

View File

@ -2,9 +2,7 @@ import React, { useCallback } from 'react';
// @ts-ignore
import { Container } from '../../react/base';
// eslint-disable-next-line lines-around-comment
// @ts-ignore
import { styleTypeToObject } from '../../styles';
import { styleTypeToObject } from '../../styles/functions';
interface IProps {
@ -141,6 +139,8 @@ export default function Icon(props: IProps) {
color: styleColor,
fontSize: styleSize,
...restStyle
// @ts-ignore
} = styleTypeToObject(style ?? {});
const calculatedColor = color ?? styleColor ?? DEFAULT_COLOR;
const calculatedSize = size ?? styleSize ?? DEFAULT_SIZE;

View File

@ -0,0 +1,3 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M12 1.5C11.5858 1.5 11.25 1.83579 11.25 2.25V3C11.25 3.01239 11.2503 3.0247 11.2509 3.03694C7.46047 3.41282 4.5 6.61068 4.5 10.5V12.0949C4.5 12.9852 4.10453 13.8296 3.42055 14.3995L3.07702 14.6858C2.55299 15.1225 2.25 15.7694 2.25 16.4515C2.25 17.7209 3.27906 18.75 4.54846 18.75H8.25C8.25 20.8211 9.92893 22.5 12 22.5C14.0711 22.5 15.75 20.8211 15.75 18.75H19.3635C20.6815 18.75 21.75 17.6815 21.75 16.3635C21.75 15.7306 21.4986 15.1236 21.051 14.676L20.3787 14.0037C19.8161 13.4411 19.5 12.678 19.5 11.8824V10.5C19.5 6.61068 16.5395 3.41282 12.7491 3.03694C12.7497 3.0247 12.75 3.01239 12.75 3V2.25C12.75 1.83579 12.4142 1.5 12 1.5ZM18 10.5C18 7.18629 15.3137 4.5 12 4.5C8.68629 4.5 6 7.18629 6 10.5V12.7974C6 13.6878 5.60453 14.5321 4.92055 15.1021L4.0373 15.8381C3.85526 15.9898 3.75 16.2146 3.75 16.4515C3.75 16.8925 4.10748 17.25 4.54846 17.25H19.3635C19.8531 17.25 20.25 16.8531 20.25 16.3635C20.25 16.1284 20.1566 15.9029 19.9904 15.7367L18.8787 14.625C18.3161 14.0624 18 13.2993 18 12.5037V10.5ZM14.25 18.75H9.75C9.75 19.9926 10.7574 21 12 21C13.2426 21 14.25 19.9926 14.25 18.75Z" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

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