mirror of
https://gitcode.com/GitHub_Trending/ji/jitsi-meet.git
synced 2026-02-19 12:20:18 +00:00
Compare commits
90 Commits
8954
...
fix/consol
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
303f81f427 | ||
|
|
23a65fbf2a | ||
|
|
5fee521938 | ||
|
|
9ea9f4c899 | ||
|
|
28c72bfa7f | ||
|
|
24c78cf8ff | ||
|
|
147e64106d | ||
|
|
3d53f2e4c5 | ||
|
|
e60bfc573a | ||
|
|
796a7efa7f | ||
|
|
fb075c376d | ||
|
|
c457ed0d3c | ||
|
|
1efc5e40e1 | ||
|
|
dc84826d9c | ||
|
|
b4a64ebc44 | ||
|
|
dbb3ccc274 | ||
|
|
9a6ed65cb1 | ||
|
|
21ea67b29c | ||
|
|
ab4be2366f | ||
|
|
417c38ab9e | ||
|
|
33a4245a1f | ||
|
|
2eb07cb79f | ||
|
|
63e4c41d92 | ||
|
|
2c6ccd7d6b | ||
|
|
4ce27eeb1a | ||
|
|
11453dcc79 | ||
|
|
3375ee49bd | ||
|
|
e45df58cfb | ||
|
|
7d628960d7 | ||
|
|
cf13b8f0ba | ||
|
|
e106109090 | ||
|
|
fc170891cb | ||
|
|
775cc52f66 | ||
|
|
3baede6ff1 | ||
|
|
9462a9ce36 | ||
|
|
4713062200 | ||
|
|
65eb2a2899 | ||
|
|
f0452d05b9 | ||
|
|
1102f4205a | ||
|
|
447def54c8 | ||
|
|
481b9a6e58 | ||
|
|
fb3bc3c367 | ||
|
|
9fa5489154 | ||
|
|
9499bf29ed | ||
|
|
f605b5c487 | ||
|
|
88fba5acab | ||
|
|
7bc79bc144 | ||
|
|
3e469019b5 | ||
|
|
d324935501 | ||
|
|
cd11cf6f65 | ||
|
|
5db3d529f4 | ||
|
|
c7d2c9c204 | ||
|
|
9832c7a226 | ||
|
|
12ee929499 | ||
|
|
b9ed42613b | ||
|
|
0d572b3bfb | ||
|
|
609eab5f83 | ||
|
|
7bd0f479b9 | ||
|
|
a634b6b2bc | ||
|
|
0e53bd87ce | ||
|
|
9e89c33796 | ||
|
|
eaffd8b8f7 | ||
|
|
b8444d56ff | ||
|
|
42b2dd41c1 | ||
|
|
229d1823fb | ||
|
|
cd6e905b95 | ||
|
|
ddaf7a3180 | ||
|
|
47aa51a58c | ||
|
|
66f7b9de53 | ||
|
|
bab87be9c9 | ||
|
|
6549d47233 | ||
|
|
2063e66b8e | ||
|
|
4dd241712d | ||
|
|
a574d5ec79 | ||
|
|
4b2b85bd12 | ||
|
|
77ab1ea8ed | ||
|
|
05e47ade7c | ||
|
|
6c78ec9099 | ||
|
|
4c5afc0b5e | ||
|
|
2e31ab9dca | ||
|
|
02787b1394 | ||
|
|
2476a06237 | ||
|
|
2d8909911e | ||
|
|
d06b847319 | ||
|
|
b517f614b3 | ||
|
|
10f77f1fbc | ||
|
|
77b89ece4a | ||
|
|
129264c3c9 | ||
|
|
96c5a9abd1 | ||
|
|
93ef2337ae |
2
.github/workflows/ci-lua.yml
vendored
2
.github/workflows/ci-lua.yml
vendored
@@ -7,7 +7,7 @@ jobs:
|
||||
name: Luacheck
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 #v6.0.1
|
||||
|
||||
- name: Install luarocks
|
||||
run: sudo apt-get --install-recommends -y install luarocks
|
||||
|
||||
43
.github/workflows/ci.yml
vendored
43
.github/workflows/ci.yml
vendored
@@ -7,8 +7,8 @@ jobs:
|
||||
name: Lint
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/setup-node@v6
|
||||
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 #v6.0.1
|
||||
- uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f #v6.1.0
|
||||
with:
|
||||
node-version-file: '.nvmrc'
|
||||
cache: 'npm'
|
||||
@@ -42,8 +42,8 @@ jobs:
|
||||
matrix:
|
||||
os: [macos-latest, ubuntu-latest]
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/setup-node@v6
|
||||
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 #v6.0.1
|
||||
- uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f #v6.1.0
|
||||
with:
|
||||
node-version-file: '.nvmrc'
|
||||
cache: 'npm'
|
||||
@@ -59,8 +59,8 @@ jobs:
|
||||
name: Build mobile bundle (Android)
|
||||
runs-on: macos-15
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/setup-node@v6
|
||||
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 #v6.0.1
|
||||
- uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f #v6.1.0
|
||||
with:
|
||||
node-version-file: '.nvmrc'
|
||||
cache: 'npm'
|
||||
@@ -74,8 +74,8 @@ jobs:
|
||||
name: Build mobile bundle (iOS)
|
||||
runs-on: macos-15
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/setup-node@v6
|
||||
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 #v6.0.1
|
||||
- uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f #v6.1.0
|
||||
with:
|
||||
node-version-file: '.nvmrc'
|
||||
cache: 'npm'
|
||||
@@ -103,10 +103,21 @@ jobs:
|
||||
android-sdk-build:
|
||||
name: Build mobile SDK (Android)
|
||||
runs-on: ubuntu-latest
|
||||
container: reactnativecommunity/react-native-android:v15.0
|
||||
container:
|
||||
image: reactnativecommunity/react-native-android:v15.0
|
||||
volumes:
|
||||
- /usr:/host/usr
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/setup-node@v6
|
||||
- name: Make space in image by removing preinstalled, but unused SDKs
|
||||
run: |
|
||||
df -h /
|
||||
rm -rf /host/usr/local/lib/android
|
||||
rm -rf /host/usr/local/.ghcup
|
||||
rm -rf /host/usr/share/dotnet
|
||||
rm -rf /host/usr/share/swift
|
||||
df -h /
|
||||
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 #v6.0.1
|
||||
- uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f #v6.1.0
|
||||
with:
|
||||
node-version-file: '.nvmrc'
|
||||
cache: 'npm'
|
||||
@@ -126,8 +137,8 @@ jobs:
|
||||
name: Build mobile SDK (iOS)
|
||||
runs-on: macos-15
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/setup-node@v6
|
||||
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 #v6.0.1
|
||||
- uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f #v6.1.0
|
||||
with:
|
||||
node-version-file: '.nvmrc'
|
||||
cache: 'npm'
|
||||
@@ -149,7 +160,7 @@ jobs:
|
||||
-workspace ios/jitsi-meet.xcworkspace \
|
||||
-scheme JitsiMeetSDK
|
||||
- name: setup-cocoapods
|
||||
uses: ruby/setup-ruby@v1
|
||||
uses: ruby/setup-ruby@4fc31e1c823882afd7ef55985266a526c589de90 #v1.282.0
|
||||
with:
|
||||
ruby-version: '3.4'
|
||||
bundler-cache: true
|
||||
@@ -176,8 +187,8 @@ jobs:
|
||||
name: Test Debian packages build
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/setup-node@v6
|
||||
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 #v6.0.1
|
||||
- uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f #v6.1.0
|
||||
with:
|
||||
node-version-file: '.nvmrc'
|
||||
cache: 'npm'
|
||||
|
||||
2
.github/workflows/stale.yml
vendored
2
.github/workflows/stale.yml
vendored
@@ -7,7 +7,7 @@ jobs:
|
||||
stale:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/stale@v8
|
||||
- uses: actions/stale@5f858e3efba33a5ca4407a664cc011ad407f2008 #v10.1.0
|
||||
with:
|
||||
stale-issue-message: 'This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.'
|
||||
stale-pr-message: 'This PR has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.'
|
||||
|
||||
@@ -264,4 +264,4 @@ react/features/sample/
|
||||
- [Jitsi Handbook](https://jitsi.github.io/handbook/) - Comprehensive documentation
|
||||
- [Community Forum](https://community.jitsi.org/) - Ask questions and get support
|
||||
- [Architecture Guide](https://jitsi.github.io/handbook/docs/architecture) - System overview
|
||||
- [Contributing Guidelines](https://jitsi.github.io/handbook/docs/dev-guide/contributing) - Detailed contribution process
|
||||
- [Contributing Guidelines](https://jitsi.github.io/handbook/docs/dev-guide/dev-guide-contributing/) - Detailed contribution process
|
||||
|
||||
@@ -30,6 +30,9 @@ import com.facebook.react.ReactRootView;
|
||||
|
||||
import org.jitsi.meet.sdk.log.JitsiMeetLogger;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
|
||||
|
||||
public class JitsiMeetView extends FrameLayout {
|
||||
|
||||
@@ -84,6 +87,10 @@ public class JitsiMeetView extends FrameLayout {
|
||||
result.putInt(key, (int)bValue);
|
||||
} else if (valueType.contentEquals("Bundle")) {
|
||||
result.putBundle(key, mergeProps((Bundle)aValue, (Bundle)bValue));
|
||||
} else if (valueType.contentEquals("String[]")) {
|
||||
// Convert String[] to ArrayList<String> for React Native bridge compatibility
|
||||
String[] stringArray = (String[]) bValue;
|
||||
result.putStringArrayList(key, new ArrayList<>(Arrays.asList(stringArray)));
|
||||
} else {
|
||||
throw new RuntimeException("Unsupported type: " + valueType);
|
||||
}
|
||||
|
||||
14
config.js
14
config.js
@@ -151,6 +151,9 @@ var config = {
|
||||
// Disables self-view settings in UI
|
||||
// disableSelfViewSettings: false,
|
||||
|
||||
// Shows/hides the moderator setting for chat permissions.
|
||||
// showChatPermissionsModeratorSetting: false,
|
||||
|
||||
// screenshotCapture : {
|
||||
// Enables the screensharing capture feature.
|
||||
// enabled: false,
|
||||
@@ -520,9 +523,6 @@ var config = {
|
||||
// // Note: Starting transcriptions from the recording dialog will still work.
|
||||
// disableClosedCaptions: false,
|
||||
|
||||
// // Whether to invite jigasi when backend transcriptions are enabled (asyncTranscription is true in metadata).
|
||||
// // By default, we invite it.
|
||||
// inviteJigasiOnBackendTranscribing: true,
|
||||
// },
|
||||
|
||||
// Misc
|
||||
@@ -927,6 +927,14 @@ var config = {
|
||||
// [ 'microphone', 'camera' ]
|
||||
// ],
|
||||
|
||||
// Enable reduced UI on web.
|
||||
// reducedUIEnabled: true,
|
||||
|
||||
// Overrides the buttons displayed in the main toolbar for reduced UI.
|
||||
// When there isn't an override for a certain configuration the default jitsi-meet configuration will be used.
|
||||
// The order of the buttons in the array is preserved.
|
||||
// reducedUImainToolbarButtons: [ 'microphone', 'camera' ],
|
||||
|
||||
// Toolbar buttons which have their click/tap event exposed through the API on
|
||||
// `toolbarButtonClicked`. Passing a string for the button key will
|
||||
// prevent execution of the click/tap routine; passing an object with `key` and
|
||||
|
||||
@@ -45,7 +45,7 @@ body {
|
||||
|
||||
.jitsi-icon {
|
||||
&-default svg {
|
||||
fill: white;
|
||||
fill: var(--icon-default-color, white);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
.always-on-top-toolbox {
|
||||
background-color: $newToolbarBackgroundColor;
|
||||
background-color: var(--toolbox-background-color, $newToolbarBackgroundColor);
|
||||
border-radius: 3px;
|
||||
display: flex;
|
||||
z-index: $toolbarZ;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* Round badge.
|
||||
*/
|
||||
.badge-round {
|
||||
background-color: #165ECC;
|
||||
background-color: var(--toolbar-badge-background, #165ECC);
|
||||
border-radius: 50%;
|
||||
box-sizing: border-box;
|
||||
color: #FFFFFF;
|
||||
@@ -93,7 +93,7 @@
|
||||
|
||||
.toolbox-content-wrapper::after {
|
||||
content: '';
|
||||
background: $newToolbarBackgroundColor;
|
||||
background: var(--toolbox-background-color, $newToolbarBackgroundColor);
|
||||
padding-bottom: env(safe-area-inset-bottom, 0);
|
||||
}
|
||||
|
||||
|
||||
@@ -60,7 +60,7 @@
|
||||
}
|
||||
|
||||
#notification-participant-list {
|
||||
background-color: $newToolbarBackgroundColor;
|
||||
background-color: var(--toolbox-background-color, $newToolbarBackgroundColor);
|
||||
border: 1px solid rgba(255, 255, 255, .4);
|
||||
border-radius: 8px;
|
||||
left: 0;
|
||||
|
||||
5
custom.d.ts
vendored
5
custom.d.ts
vendored
@@ -2,3 +2,8 @@ declare module '*.svg' {
|
||||
const content: any;
|
||||
export default content;
|
||||
}
|
||||
|
||||
declare module '*.svg?raw' {
|
||||
const content: string;
|
||||
export default content;
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ no-cli
|
||||
no-loopback-peers
|
||||
no-tcp-relay
|
||||
no-tcp
|
||||
no-dtls
|
||||
listening-port=3478
|
||||
tls-listening-port=5349
|
||||
no-tlsv1
|
||||
|
||||
@@ -1407,7 +1407,7 @@ PODS:
|
||||
- Yoga
|
||||
- react-native-performance (5.1.2):
|
||||
- React-Core
|
||||
- react-native-safe-area-context (5.5.2):
|
||||
- react-native-safe-area-context (5.6.1):
|
||||
- React-Core
|
||||
- react-native-slider (4.5.6):
|
||||
- DoubleConversion
|
||||
@@ -2271,7 +2271,7 @@ SPEC CHECKSUMS:
|
||||
react-native-orientation-locker: dbd3f6ddbe9e62389cb0807dc2af63f6c36dec36
|
||||
react-native-pager-view: 11662c698c8f11d39e05891316d2a144fa00adc4
|
||||
react-native-performance: 125a96c145e29918b55b45ce25cbba54f1e24dcd
|
||||
react-native-safe-area-context: 0f7bf11598f9a61b7ceac8dc3f59ef98697e99e1
|
||||
react-native-safe-area-context: 2243039f43d10cb1ea30ec5ac57fc6d1448413f4
|
||||
react-native-slider: 1205801a8d29b28cacc14eef08cb120015cdafcb
|
||||
react-native-video: eb861d67a71dfef1bbf6086a811af5f338b13781
|
||||
react-native-webrtc: e8f0ce746353adc2744a2b933645e1aeb41eaa74
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
"it": "Italiano",
|
||||
"ja": "日本語",
|
||||
"kab": "Taqbaylit",
|
||||
"kk": "Қазақша",
|
||||
"ko": "한국어",
|
||||
"lt": "Lietuvių",
|
||||
"lv": "Latviešu",
|
||||
|
||||
1895
lang/main-da.json
1895
lang/main-da.json
File diff suppressed because it is too large
Load Diff
@@ -109,9 +109,15 @@
|
||||
}
|
||||
},
|
||||
"chat": {
|
||||
"disabled": "Chat-Nachrichten sind deaktiviert.",
|
||||
"enter": "Chat-Raum betreten",
|
||||
"error": "Fehler: Ihre Nachricht wurde nicht versendet. Grund: {{error}}",
|
||||
"everyone": "Alle",
|
||||
"fieldPlaceHolder": "Geben Sie Ihre Nachricht hier ein",
|
||||
"fileAccessibleTitle": "{{user}} hat eine Datei hochgeladen",
|
||||
"fileAccessibleTitleMe": "Ich habe eine Datei hochgeladen",
|
||||
"fileDeleted": "Eine Datei wurde gelöscht",
|
||||
"guestsChatIndicator": "(Gast)",
|
||||
"lobbyChatMessageTo": "Lobby-Nachricht an {{recipient}}",
|
||||
"message": "Nachricht",
|
||||
"messageAccessibleTitle": "{{user}} sagt:",
|
||||
@@ -120,11 +126,20 @@
|
||||
"messagebox": "Nachricht eingeben",
|
||||
"newMessages": "Neue Nachrichten",
|
||||
"nickname": {
|
||||
"featureChat": "Chat",
|
||||
"featureClosedCaptions": "Untertitel",
|
||||
"featureFileSharing": "Dateien",
|
||||
"featurePolls": "Umfragen",
|
||||
"popover": "Wähle einen Alias",
|
||||
"title": "Geben Sie einen Alias zum Chatten ein",
|
||||
"titleWith1Features": "Geben Sie einen Alias ein, um {{feature1}} zu nutzen",
|
||||
"titleWith2Features": "Geben Sie einen Alias ein, um {{feature1}} und {{feature2}} zu nutzen",
|
||||
"titleWith3Features": "Geben Sie einen Alias ein, um {{feature1}}, {{feature2}} und {{feature3}} zu nutzen",
|
||||
"titleWith4Features": "Geben Sie einen Alias ein, um {{feature1}}, {{feature2}}, {{feature3}} und {{feature4}} zu nutzen",
|
||||
"titleWithCC": "Geben Sie einen Alias zum Chatten und für Untertitel ein",
|
||||
"titleWithPolls": "Geben Sie einen Alias zum Chatten und für Umfragen ein",
|
||||
"titleWithPollsAndCC": "Geben Sie einen Alias zum Chatten, für Umfragen und Untertitel ein"
|
||||
"titleWithPollsAndCC": "Geben Sie einen Alias zum Chatten, für Umfragen und Untertitel ein",
|
||||
"titleWithPollsAndCCAndFileSharing": "Geben Sie einen Alias zum Chatten, für Umfragen, Untertitel und Dateien ein"
|
||||
},
|
||||
"noMessagesMessage": "Es gibt noch keine Nachricht in dieser Konferenz. Starten Sie hier eine Unterhaltung!",
|
||||
"privateNotice": "Private Nachricht an {{recipient}}",
|
||||
@@ -132,14 +147,16 @@
|
||||
"smileysPanel": "Emoji-Auswahl",
|
||||
"systemDisplayName": "System",
|
||||
"tabs": {
|
||||
"chat": "Chatten",
|
||||
"chat": "Chat",
|
||||
"closedCaptions": "Untertitel",
|
||||
"fileSharing": "Dateien",
|
||||
"polls": "Umfragen"
|
||||
},
|
||||
"title": "Chatten",
|
||||
"titleWithCC": "Chatten und Untertitel",
|
||||
"titleWithPolls": "Chatten und Umfragen",
|
||||
"titleWithPollsAndCC": "Chatten, Umfragen und Untertitel",
|
||||
"title": "Chat",
|
||||
"titleWithCC": "Untertitel",
|
||||
"titleWithFeatures": "Chat und",
|
||||
"titleWithFileSharing": "Dateien",
|
||||
"titleWithPolls": "Umfragen",
|
||||
"you": "Sie"
|
||||
},
|
||||
"chromeExtensionBanner": {
|
||||
@@ -274,7 +291,6 @@
|
||||
"Submit": "OK",
|
||||
"Understand": "Verstanden, Stummschaltung beibehalten",
|
||||
"UnderstandAndUnmute": "Verstanden, bitte Stummschaltung aufheben",
|
||||
"WaitForHostMsg": "Die Konferenz wurde noch nicht gestartet. Falls Sie die Konferenz leiten, authentifizieren Sie sich bitte. Warten Sie andernfalls, bis die Konferenz gestartet wird.",
|
||||
"WaitForHostNoAuthMsg": "Die Konferenz wurde noch nicht gestartet. Bitte warten Sie, bis die Konferenz gestartet wird.",
|
||||
"WaitingForHostButton": "Auf Moderation warten",
|
||||
"WaitingForHostTitle": "Warten auf den Beginn der Konferenz …",
|
||||
@@ -296,6 +312,12 @@
|
||||
"alreadySharedVideoTitle": "Nur ein geteiltes Video gleichzeitig",
|
||||
"applicationWindow": "Anwendungsfenster",
|
||||
"authenticationRequired": "Authentifizierung benötigt",
|
||||
"cameraCaptureDialog": {
|
||||
"description": "Ein Bild mit Ihrer Kamera aufnehmen und senden",
|
||||
"ok": "Kamera starten",
|
||||
"reject": "Jetzt nicht",
|
||||
"title": "Ein Bild aufnehmen"
|
||||
},
|
||||
"cameraConstraintFailedError": "Ihre Kamera erfüllt die notwendigen Anforderungen nicht.",
|
||||
"cameraNotFoundError": "Kamera nicht gefunden.",
|
||||
"cameraNotSendingData": "Die Kamera ist nicht verfügbar. Bitte prüfen, ob eine andere Applikation die Kamera verwendet, eine andere Kamera vom Einstellungs-Menü auswählen oder die Applikation neu laden.",
|
||||
@@ -371,22 +393,34 @@
|
||||
"micTimeoutError": "Audioquelle konnte nicht gestartet werden. Zeitüberschreitung",
|
||||
"micUnknownError": "Das Mikrofon kann aus einem unbekannten Grund nicht verwendet werden.",
|
||||
"moderationAudioLabel": "Erlaube Anwesenden die Stummschaltung für sich aufzuheben",
|
||||
"moderationDesktopLabel": "Erlaube Anwesenden ihren Bildschirm freizugeben",
|
||||
"moderationVideoLabel": "Erlaube Anwesenden ihre Kamera einzuschalten",
|
||||
"muteEveryoneDialog": "Wollen Sie wirklich alle stummschalten? Sie können deren Stummschaltung nicht mehr beenden, aber sie können ihre Stummschaltung jederzeit selbst beenden.",
|
||||
"muteEveryoneDialogModerationOn": "Die Anwesenden können eine Anfrage zum Sprechen jederzeit senden.",
|
||||
"muteEveryoneElseDialog": "Einmal stummgeschaltet, können Sie deren Stummschaltung nicht mehr beenden, aber sie können ihre Stummschaltung jederzeit selbst beenden.",
|
||||
"muteEveryoneElseTitle": "Alle außer {{whom}} stummschalten?",
|
||||
"muteEveryoneElsesDesktopDialog": "Sobald die Bildschirmfreigaben beendet sind, können Sie diese nicht mehr starten, aber die anderen können sie jederzeit wieder starten.",
|
||||
"muteEveryoneElsesDesktopTitle": "Alle Bildschirmfreigaben außer {{whom}} beenden?",
|
||||
"muteEveryoneElsesVideoDialog": "Sobald die Kamera für alle anderen Personen deaktiviert ist, können Sie diese nicht wieder für alle einschalten, die anderen Personen können ihre Kamera aber jederzeit wieder einschalten.",
|
||||
"muteEveryoneElsesVideoTitle": "Die Kamera von allen außer {{whom}} ausschalten?",
|
||||
"muteEveryoneSelf": "sich selbst",
|
||||
"muteEveryoneStartMuted": "Alle beginnen von jetzt an stummgeschaltet",
|
||||
"muteEveryoneTitle": "Alle stummschalten?",
|
||||
"muteEveryonesDesktopDialog": "Die Anwesenden können ihren Bildschirm jederzeit freigeben.",
|
||||
"muteEveryonesDesktopDialogModerationOn": "Die Anwesenden können jederzeit eine Anfrage zur Bildschirmfreigabe senden.",
|
||||
"muteEveryonesDesktopTitle": "Alle Bildschirmfreigaben beenden?",
|
||||
"muteEveryonesVideoDialog": "Sind Sie sicher, dass Sie die Kamera von allen Personen deaktivieren möchten? Sie können dies nicht wieder rückgängig machen, jede Personen kann ihre Kamera aber jederzeit wieder einschalten.",
|
||||
"muteEveryonesVideoDialogModerationOn": "Die Anwesenden können jederzeit eine Anfrage senden, um ihre Kamera einzuschalten.",
|
||||
"muteEveryonesVideoDialogOk": "deaktivieren",
|
||||
"muteEveryonesVideoTitle": "Die Kamera von allen anderen ausschalten?",
|
||||
"muteParticipantBody": "Sie können die Stummschaltung anderer Personen nicht aufheben, aber eine Person kann ihre eigene Stummschaltung jederzeit beenden.",
|
||||
"muteParticipantButton": "Stummschalten",
|
||||
"muteParticipantsDesktopBody": "Sie können Bildschirmfreigaben von anderen nicht starten, sie können dies aber jederzeit.",
|
||||
"muteParticipantsDesktopBodyModerationOn": "Weder Sie noch andere Anwesende können Bildschirmfreigaben starten.",
|
||||
"muteParticipantsDesktopButton": "Bildschirmfreigabe beenden",
|
||||
"muteParticipantsDesktopDialog": "Sind Sie sicher, dass Sie die Bildschirmfreigabe von dieser Person beenden möchten? Sie können diese nicht mehr starten, die Person aber jederzeit.",
|
||||
"muteParticipantsDesktopDialogModerationOn": "Sind Sie sicher, dass Sie die Bildschirmfreigabe von dieser Person beenden möchten? Weder Sie noch die Person kann die Bildschirmfreigabe wieder starten.",
|
||||
"muteParticipantsDesktopTitle": "Bildschirmfreigabe von dieser Person beenden?",
|
||||
"muteParticipantsVideoBody": "Sie können die Kamera nicht wieder einschalten, die Person kann ihre Kamera aber jederzeit wieder einschalten.",
|
||||
"muteParticipantsVideoBodyModerationOn": "Sie können die Kamera nicht wieder aktivieren und die Person selbst auch nicht.",
|
||||
"muteParticipantsVideoButton": "Kamera ausschalten",
|
||||
@@ -499,6 +533,7 @@
|
||||
"tokenAuthFailedWithReasons": "Teilnahme an der Konferenz fehlgeschlagen. Möglicher Grund: {{reason}}",
|
||||
"tokenAuthUnsupported": "Token-Authentifizierung wird nicht unterstützt.",
|
||||
"transcribing": "Wird transkribiert",
|
||||
"unauthenticatedAccessDisabled": "Zur Teilnahme an dieser Konferenz müssen Sie sich anmelden.",
|
||||
"unlockRoom": "Konferenz$t(lockRoomPassword) entfernen",
|
||||
"user": "Anmeldename",
|
||||
"userIdentifier": "Benutzername",
|
||||
@@ -539,6 +574,25 @@
|
||||
"veryBad": "Sehr schlecht",
|
||||
"veryGood": "Sehr gut"
|
||||
},
|
||||
"fileSharing": {
|
||||
"downloadFailedDescription": "Bitte nochmals versuchen.",
|
||||
"downloadFailedTitle": "Download fehlgeschlagen",
|
||||
"downloadFile": "Download",
|
||||
"downloadStarted": "Download gestartet",
|
||||
"dragAndDrop": "Dateien hier oder irgendwo auf dem Bildschirm loslassen",
|
||||
"fileAlreadyUploaded": "Datei wurde schon zur Konferenz hochgeladen.",
|
||||
"fileRemovedByOther": "Ihre Datei '{{ fileName }}' wurde entfernt",
|
||||
"fileTooLargeDescription": "Bitte stellen Sie sicher, dass Ihre Datei nicht die Maximalgröße von {{ maxFileSize }} überschreitet.",
|
||||
"fileTooLargeTitle": "Die ausgewählte Datei ist zu groß",
|
||||
"fileUploadProgress": "Datei wird hochgeladen",
|
||||
"fileUploadedSuccessfully": "Datei erfolgreich hochgeladen",
|
||||
"newFileNotification": "{{ participantName }} hat Datei '{{ fileName }}' hochgeladen",
|
||||
"removeFile": "Entfernen",
|
||||
"removeFileSuccess": "Datei erfolgreich entfernt",
|
||||
"uploadFailedDescription": "Bitte versuchen Sie es erneut.",
|
||||
"uploadFailedTitle": "Dateiupload fehlgeschlagen",
|
||||
"uploadFile": "Datei hochladen"
|
||||
},
|
||||
"filmstrip": {
|
||||
"accessibilityLabel": {
|
||||
"heading": "Videominiaturen"
|
||||
@@ -707,7 +761,8 @@
|
||||
"notificationTitle": "Lobby",
|
||||
"passwordJoinButton": "Beitreten",
|
||||
"title": "Lobby",
|
||||
"toggleLabel": "Lobby aktivieren"
|
||||
"toggleLabel": "Lobby aktivieren",
|
||||
"waitForModerator": "Die Konferenz wurde noch nicht gestartet, da noch keine Moderation anwesend ist. Wenn Sie zur Moderation gehören, melden Sie sich bitte an, ansonsten warten Sie bitte."
|
||||
},
|
||||
"localRecording": {
|
||||
"clientState": {
|
||||
@@ -750,8 +805,9 @@
|
||||
"me": "ich",
|
||||
"notify": {
|
||||
"OldElectronAPPTitle": "Sicherheitslücke!",
|
||||
"allowAll": "Alles einschalten",
|
||||
"allowAudio": "Mikrofon einschalten",
|
||||
"allowBoth": "Beides",
|
||||
"allowDesktop": "Bildschirmfreigabe einschalten",
|
||||
"allowVideo": "Kamera einschalten",
|
||||
"allowedUnmute": "Sie können die Stummschaltung aufheben, Ihre Kamera einschalten oder Ihren Bildschirm teilen.",
|
||||
"audioUnmuteBlockedDescription": "Díe Stummschaltung kann aus Überlastungsschutzgründen temporär nicht aufgehoben werden.",
|
||||
@@ -765,6 +821,7 @@
|
||||
"dataChannelClosedDescription": "Die Steuerungsverbindung (Bridge Channel) wurde unterbrochen, daher ist die Videoqulität auf die schlechteste Stufe limitiert.",
|
||||
"dataChannelClosedDescriptionWithAudio": "Die Steuerungsverbindung (Bridge Channel) wurde unterbrochen, daher können Video- und Tonprobleme auftreten.",
|
||||
"dataChannelClosedWithAudio": "Ton- und Videoqualität können beeinträchtigt sein",
|
||||
"desktopMutedRemotelyTitle": "Ihre Bildschirmfreigabe wurde von {{participantDisplayName}} gestoppt",
|
||||
"disabledIframe": "Die Einbettung ist nur für Demo-Zwecke vorgesehen. Diese Konferenz wird in {{timeout}} Minuten beendet.",
|
||||
"disabledIframeSecondaryNative": "Die Einbettung von {{domain}} ist nur für Demo-Zwecke vorgesehen. Diese Konferenz wird in {{timeout}} Minuten beendet.",
|
||||
"disabledIframeSecondaryWeb": "Die Einbettung von {{domain}} ist nur für Demo-Zwecke vorgesehen. Diese Konferenz wird in {{timeout}} Minuten beendet. Bitte nutzen Sie <a href='{{jaasDomain}}' rel='noopener noreferrer' target='_blank'>Jitsi as a Service</a> für produktive Zwecke!",
|
||||
@@ -822,6 +879,7 @@
|
||||
"oldElectronClientDescription1": "Sie scheinen eine alte Version des Jitsi-Meet-Clients zu nutzen. Diese hat bekannte Schwachstellen. Bitte aktualisieren Sie auf unsere ",
|
||||
"oldElectronClientDescription2": "aktuelle Version",
|
||||
"oldElectronClientDescription3": "!",
|
||||
"openChat": "Chat öffnen",
|
||||
"participantWantsToJoin": "Möchte an der Konferenz teilnehmen",
|
||||
"participantsWantToJoin": "Möchten an der Konferenz teilnehmen",
|
||||
"passwordRemovedRemotely": "$t(lockRoomPasswordUppercase) von einer anderen Person entfernt",
|
||||
@@ -845,6 +903,7 @@
|
||||
"suggestRecordingDescription": "Möchten Sie eine Aufzeichnung starten?",
|
||||
"suggestRecordingTitle": "Konferenz aufzeichnen",
|
||||
"unmute": "Stummschaltung aufheben",
|
||||
"unmuteScreen": "Bildschirmfreigabe starten",
|
||||
"unmuteVideo": "Kamera einschalten",
|
||||
"videoMutedRemotelyDescription": "Sie können sie jederzeit wieder einschalten.",
|
||||
"videoMutedRemotelyTitle": "Ihre Kamera wurde von {{participantDisplayName}} ausgeschaltet!",
|
||||
@@ -864,11 +923,14 @@
|
||||
"admit": "Zulassen",
|
||||
"admitAll": "Alle zulassen",
|
||||
"allow": "Anwesenden erlauben:",
|
||||
"allowDesktop": "Bildschirm freizugeben",
|
||||
"allowVideo": "Kamera einschalten",
|
||||
"askDesktop": "Anfragen, Bildschirm freizugeben",
|
||||
"askUnmute": "Anfragen, Stummschaltung aufzuheben",
|
||||
"audioModeration": "Für sich selbst die Stummschaltung aufzuheben",
|
||||
"blockEveryoneMicCamera": "Kamera und Mikrofon von allen sperren",
|
||||
"breakoutRooms": "Breakout-Räume",
|
||||
"desktopModeration": "Bildschirmfreigabe",
|
||||
"goLive": "Live gehen",
|
||||
"invite": "Person einladen",
|
||||
"lowerAllHands": "Alle Hände senken",
|
||||
@@ -880,6 +942,8 @@
|
||||
"muteAll": "Alle stummschalten",
|
||||
"muteEveryoneElse": "Alle anderen stummschalten",
|
||||
"reject": "Ablehnen",
|
||||
"stopDesktop": "Bildschirmfreigabe beenden",
|
||||
"stopEveryonesDesktop": "Alle Bildschirmfreigaben beenden",
|
||||
"stopEveryonesVideo": "Alle Kameras ausschalten",
|
||||
"stopVideo": "Kamera ausschalten",
|
||||
"unblockEveryoneMicCamera": "Kamera und Mikrofon von allen entsperren",
|
||||
@@ -889,9 +953,11 @@
|
||||
"headings": {
|
||||
"lobby": "Lobby ({{count}})",
|
||||
"participantsList": "Anwesende ({{count}})",
|
||||
"viewerRequests": "Zuschaueranfragen {{count}}",
|
||||
"visitorInQueue": " (Wartende Gäste {{count}})",
|
||||
"visitorRequests": " (Anfragen {{count}})",
|
||||
"visitors": "Gäste ({{count}})",
|
||||
"visitorsList": "Zuschauer ({{count}})",
|
||||
"waitingLobby": "In der Lobby ({{count}})"
|
||||
},
|
||||
"search": "Suche Anwesende",
|
||||
@@ -912,6 +978,9 @@
|
||||
"by": "Von {{ name }}",
|
||||
"closeButton": "Umfrage schließen",
|
||||
"create": {
|
||||
"accessibilityLabel": {
|
||||
"send": "Umfrage erstellen"
|
||||
},
|
||||
"addOption": "Antwort hinzufügen",
|
||||
"answerPlaceholder": "Antwort {{index}}",
|
||||
"cancel": "Abbrechen",
|
||||
@@ -920,8 +989,7 @@
|
||||
"pollQuestion": "Frage",
|
||||
"questionPlaceholder": "Eine Frage stellen",
|
||||
"removeOption": "Antwort entfernen",
|
||||
"save": "Erstellen",
|
||||
"send": "Senden"
|
||||
"save": "Erstellen"
|
||||
},
|
||||
"errors": {
|
||||
"notUniqueOption": "Optionen müssen einzigartig sein"
|
||||
@@ -1122,7 +1190,7 @@
|
||||
"signedIn": "Momentan wird auf Kalendertermine von {{email}} zugegriffen. Klicken Sie auf die folgende Schaltfläche „Trennen“, um den Zugriff auf die Kalendertermine zu stoppen.",
|
||||
"title": "Kalender"
|
||||
},
|
||||
"chatWithPermissions": "Chat mit Freigaben",
|
||||
"chatWithPermissions": "Chat nur für Moderation erlauben",
|
||||
"desktopShareFramerate": "Framerate für Bildschirmfreigabe",
|
||||
"desktopShareHighFpsWarning": "Eine höhere Framerate könnte sich auf Ihre Datenrate auswirken. Sie müssen die Bildschirmfreigabe neustarten, damit die Einstellung übernommen wird.",
|
||||
"desktopShareWarning": "Sie müssen die Bildschirmfreigabe neustarten, damit die Einstellung übernommen wird.",
|
||||
@@ -1328,6 +1396,20 @@
|
||||
"videounmute": "Kamera einschalten"
|
||||
},
|
||||
"addPeople": "Personen zur Konferenz hinzufügen",
|
||||
"advancedAudioSettings": {
|
||||
"aec": {
|
||||
"label": "Echounterdrückung"
|
||||
},
|
||||
"agc": {
|
||||
"label": "Automatische Mikrofonlautstärke"
|
||||
},
|
||||
"ns": {
|
||||
"label": "Rauschunterdrückung"
|
||||
},
|
||||
"stereo": {
|
||||
"label": "Stereo"
|
||||
}
|
||||
},
|
||||
"audioOnlyOff": "Modus „Nur Audio“ deaktivieren",
|
||||
"audioOnlyOn": "Modus „Nur Audio“ aktivieren",
|
||||
"audioRoute": "Audiogerät auswählen",
|
||||
@@ -1355,6 +1437,7 @@
|
||||
"exitFullScreen": "Vollbildmodus verlassen",
|
||||
"exitTileView": "Kachelansicht ausschalten",
|
||||
"feedback": "Feedback hinterlassen",
|
||||
"fileSharing": "Dateien",
|
||||
"giphy": "GIPHY ein-/ausschalten",
|
||||
"hangup": "Konferenz verlassen",
|
||||
"help": "Hilfe",
|
||||
@@ -1390,6 +1473,7 @@
|
||||
"openReactionsMenu": "Interaktionsmenü öffnen",
|
||||
"participants": "Anwesende",
|
||||
"pip": "Bild-in-Bild-Modus einschalten",
|
||||
"polls": "Umfragen",
|
||||
"privateMessage": "Private Nachricht senden",
|
||||
"profile": "Profil bearbeiten",
|
||||
"raiseHand": "Hand heben",
|
||||
@@ -1399,6 +1483,7 @@
|
||||
"reactionHeart": "Herz senden",
|
||||
"reactionLaugh": "Lachen senden",
|
||||
"reactionLike": "Daumen hoch senden",
|
||||
"reactionLove": "Liebe senden",
|
||||
"reactionSilence": "Stille senden",
|
||||
"reactionSurprised": "Überrascht senden",
|
||||
"reactions": "Interaktionen",
|
||||
@@ -1484,7 +1569,8 @@
|
||||
"connectionInfo": "Verbindungsinformationen",
|
||||
"demote": "Zu Gästen verschieben",
|
||||
"domute": "Stummschalten",
|
||||
"domuteDesktopOfOthers": "Bildschirm freigeben für alle beenden",
|
||||
"domuteDesktop": "Bildschirmfreigabe beenden",
|
||||
"domuteDesktopOfOthers": "Bildschirmfreigabe für alle beenden",
|
||||
"domuteOthers": "Alle anderen stummschalten",
|
||||
"domuteVideo": "Kamera ausschalten",
|
||||
"domuteVideoOfOthers": "Alle anderen Kameras auschalten",
|
||||
@@ -1549,6 +1635,8 @@
|
||||
"noMainParticipantsTitle": "Diese Konferenz wurde noch nicht gestartet.",
|
||||
"noVisitorLobby": "Sie können nicht teilnehmen, solange die Lobby für diese Konferenz aktiviert ist.",
|
||||
"notAllowedPromotion": "Eine Person muss Ihre Anfrage erst erlauben.",
|
||||
"requestToJoin": "Hand gehoben",
|
||||
"requestToJoinDescription": "Ihre Anfrage wurde an die Moderation gesendet, bitte warten Sie.",
|
||||
"title": "Sie sind Gast in der Konferenz"
|
||||
},
|
||||
"waitingMessage": "Sie werden der Konferenz beitreten, sobald sie gestartet ist!"
|
||||
|
||||
@@ -126,8 +126,16 @@
|
||||
"messagebox": "Digita un messaggio",
|
||||
"newMessages": "Nuovi messaggi",
|
||||
"nickname": {
|
||||
"featureChat": "la chat",
|
||||
"featureClosedCaptions": "i sottotitoli",
|
||||
"featureFileSharing": "la condivisione file",
|
||||
"featurePolls": "i sondaggi",
|
||||
"popover": "Scegli un nickname",
|
||||
"title": "Inserisci un nickname per usare la chat",
|
||||
"titleWith1Features": "Inserisci un nickname per usare {{feature1}}",
|
||||
"titleWith2Features": "Inserisci un nickname per usare {{feature1}} e {{feature2}}",
|
||||
"titleWith3Features": "Inserisci un nickname per usare {{feature1}}, {{feature2}} e {{feature3}}",
|
||||
"titleWith4Features": "Inserisci un nickname per usare {{feature1}}, {{feature2}}, {{feature3}} e {{feature4}}",
|
||||
"titleWithCC": "Inserisci un nickname per usare la chat e i sottotitoli",
|
||||
"titleWithPolls": "Inserisci un nickname per usare la chat e i sondaggi",
|
||||
"titleWithPollsAndCC": "Inserisci un nickname per usare la chat, i sondaggi e i sottotitoli",
|
||||
@@ -159,7 +167,7 @@
|
||||
"installExtensionText": "Installa un'estensione per integrare Google Calendar e Office 365"
|
||||
},
|
||||
"closedCaptionsTab": {
|
||||
"emptyState": "Il contenuto dei sottotitoli sarà disponibile una volta che l'organizzatore lo attiverà",
|
||||
"emptyState": "Il contenuto dei sottotitoli sarà disponibile una volta che un moderatore lo attiverà",
|
||||
"startClosedCaptionsButton": "Attiva sottotitoli"
|
||||
},
|
||||
"connectingOverlay": {
|
||||
@@ -283,9 +291,9 @@
|
||||
"Submit": "Invia",
|
||||
"Understand": "Accetto, mantieni microfono e videocamera disattivati per ora",
|
||||
"UnderstandAndUnmute": "Accetto, riattiva microfono e videocamera",
|
||||
"WaitForHostNoAuthMsg": "La riunione non è ancora iniziata perché nessun organizzatore si è ancora collegato. Si prega di attendere.",
|
||||
"WaitingForHostButton": "Attendi l'organizzatore",
|
||||
"WaitingForHostTitle": "In attesa dell'organizzatore…",
|
||||
"WaitForHostNoAuthMsg": "La riunione non è ancora iniziata perché nessun moderatore si è ancora collegato. Si prega di attendere.",
|
||||
"WaitingForHostButton": "Attendi un moderatore",
|
||||
"WaitingForHostTitle": "In attesa di un moderatore…",
|
||||
"Yes": "Sì",
|
||||
"accessibilityLabel": {
|
||||
"Cancel": "Annulla (chiudi dialogo)",
|
||||
@@ -348,8 +356,8 @@
|
||||
"error": "Errore",
|
||||
"errorRoomCreationRestriction": "Hai provato ad accedere alla riunione troppo presto, torna tra un po'.",
|
||||
"gracefulShutdown": "Il nostro servizio è al momento inattivo per manutenzione. Si prega di riprovare più tardi.",
|
||||
"grantModeratorDialog": "Vuoi rendere relatore questo partecipante?",
|
||||
"grantModeratorTitle": "Fai diventare relatore",
|
||||
"grantModeratorDialog": "Desideri di concedere i permessi da moderatore a {{participantName}}?",
|
||||
"grantModeratorTitle": "Concedi permessi da moderatore",
|
||||
"hide": "Nascondi",
|
||||
"hideShareAudioHelper": "Non mostrare più questa finestra",
|
||||
"incorrectPassword": "Nome utente o password errati",
|
||||
@@ -727,12 +735,12 @@
|
||||
"emailField": "Inserisci il tuo indirizzo email",
|
||||
"enableDialogPasswordField": "Imposta password (opzionale)",
|
||||
"enableDialogSubmit": "Attiva",
|
||||
"enableDialogText": "La sala d'attesa ti permette di proteggere la riunione concedendo l'accesso solo alle persone autorizzate da un organizzatore.",
|
||||
"enableDialogText": "La sala d'attesa ti permette di proteggere la riunione concedendo l'accesso solo alle persone autorizzate da un moderatore.",
|
||||
"enterPasswordButton": "Inserisci password riunione",
|
||||
"enterPasswordTitle": "Inserisci la password per entrare nella riunione",
|
||||
"errorMissingPassword": "Inserisci la password della riunione",
|
||||
"invalidPassword": "Password errata",
|
||||
"joinRejectedMessage": "La tua richiesta d'accesso è stata respinta da un organizzatore.",
|
||||
"joinRejectedMessage": "La tua richiesta d'accesso è stata respinta da un moderatore.",
|
||||
"joinRejectedTitle": "Richiesta d'accesso respinta.",
|
||||
"joinTitle": "Entra nella riunione",
|
||||
"joinWithPasswordMessage": "Tentativo di accesso con password in corso, si prega di attendere…",
|
||||
@@ -754,7 +762,7 @@
|
||||
"passwordJoinButton": "Entra",
|
||||
"title": "Sala d'attesa",
|
||||
"toggleLabel": "Attiva sala d'attesa",
|
||||
"waitForModerator": "La riunione non è ancora iniziata, perché non è arrivato alcun organizzatore. Se vuoi diventarlo autenticati, altrimenti attendi."
|
||||
"waitForModerator": "La riunione non è ancora iniziata, perché non è arrivato alcun moderatore. Se vuoi diventarlo autenticati, altrimenti si prega di attendere."
|
||||
},
|
||||
"localRecording": {
|
||||
"clientState": {
|
||||
@@ -772,11 +780,11 @@
|
||||
"me": "Io",
|
||||
"messages": {
|
||||
"engaged": "Registrazione avviata.",
|
||||
"finished": "La registrazione della sessione {{token}} è terminata. Invia il file della registrazione all'organizzatore.",
|
||||
"finishedModerator": "La registrazione della sessione {{token}} è terminata. La registrazione della traccia è stata salvata. Chiedi ai partecipanti di inviare le loro registrazioni.",
|
||||
"notModerator": "Non sei un relatore. Non puoi avviare o interrompere la registrazione."
|
||||
"finished": "La registrazione della sessione {{token}} è terminata. Invia il file della registrazione al moderatore.",
|
||||
"finishedModerator": "La registrazione della sessione {{token}} è terminata. La registrazione della traccia locale è stata salvata. Si prega di chiedere ai partecipanti di inviare le loro registrazioni.",
|
||||
"notModerator": "Non sei un moderatore. Non puoi avviare o interrompere la registrazione."
|
||||
},
|
||||
"moderator": "Relatore",
|
||||
"moderator": "Moderatore",
|
||||
"no": "No",
|
||||
"participant": "Partecipante",
|
||||
"participantStats": "Statistiche partecipante",
|
||||
@@ -824,7 +832,7 @@
|
||||
"focusFail": "{{component}} non disponibile - nuovo tentativo tra {{ms}} sec",
|
||||
"gifsMenu": "GIPHY",
|
||||
"groupTitle": "Notifiche",
|
||||
"hostAskedUnmute": "Il relatore ti chiede di intervenire.",
|
||||
"hostAskedUnmute": "Il moderatore ti chiede di intervenire.",
|
||||
"invalidTenant": "Nome non valido",
|
||||
"invalidTenantHyphenDescription": "Il nome che hai scelto non è valido (inizia o finisce con '-').",
|
||||
"invalidTenantLengthDescription": "Il nome che hai scelto è troppo lungo.",
|
||||
@@ -846,17 +854,17 @@
|
||||
"localRecordingStopped": "{{name}} ha smesso di registrare.",
|
||||
"me": "Io",
|
||||
"moderationInEffectCSDescription": "Alza la mano, se vuoi condividere lo schermo.",
|
||||
"moderationInEffectCSTitle": "La condivisione schermo è stata bloccata dal relatore",
|
||||
"moderationInEffectCSTitle": "La condivisione schermo è stata bloccata dal moderatore",
|
||||
"moderationInEffectDescription": "Alza la mano, se vuoi prendere la parola.",
|
||||
"moderationInEffectTitle": "Il tuo microfono è stato spento dal relatore",
|
||||
"moderationInEffectTitle": "Il tuo microfono è stato spento dal moderatore",
|
||||
"moderationInEffectVideoDescription": "Alza la mano, se vuoi avviare la tua videocamera.",
|
||||
"moderationInEffectVideoTitle": "La tua videocamera è stata spenta dal relatore",
|
||||
"moderationRequestFromModerator": "Il relatore vorrebbe che tu accendessi il microfono",
|
||||
"moderationInEffectVideoTitle": "La tua videocamera è stata spenta dal moderatore",
|
||||
"moderationRequestFromModerator": "L'organizzatore ti chiede di accendere il microfono",
|
||||
"moderationRequestFromParticipant": "Vuole parlare",
|
||||
"moderationStartedTitle": "Moderazione in corso",
|
||||
"moderationStoppedTitle": "Moderazione interrotta",
|
||||
"moderationToggleDescription": "da {{participantDisplayName}}",
|
||||
"moderator": "Ora sei un relatore!",
|
||||
"moderator": "Ora sei un moderatore!",
|
||||
"muted": "Hai iniziato la conversazione con il microfono disattivato.",
|
||||
"mutedRemotelyDescription": "Puoi sempre attivare il microfono quando vuoi parlare. Spegni il microfono quando hai finito, per evitare rumori di fondo nella riunione.",
|
||||
"mutedRemotelyTitle": "{{participantDisplayName}} ti ha spento il microfono",
|
||||
@@ -1162,7 +1170,7 @@
|
||||
},
|
||||
"security": {
|
||||
"about": "Puoi aggiungere una $t(lockRoomPassword) alla riunione. I partecipanti dovranno inserire la $t(lockRoomPassword) per accedere alla riunione.",
|
||||
"aboutReadOnly": "Gli organizzatori possono aggiungere una $t(lockRoomPassword) alla riunione. I partecipanti dovranno inserire la $t(lockRoomPassword) per accedere alla riunione.",
|
||||
"aboutReadOnly": "I moderatori possono aggiungere una $t(lockRoomPassword) alla riunione. I partecipanti dovranno inserire la $t(lockRoomPassword) per accedere alla riunione.",
|
||||
"insecureRoomNameWarningNative": "Il nome della riunione è troppo semplice. Partecipanti non desiderati potrebbero entrare nella riunione. {{recommendAction}} Per saperne di più sulla sicurezza della tua riunione ",
|
||||
"insecureRoomNameWarningWeb": "Il nome della riunione è troppo semplice. Partecipanti non desiderati potrebbero entrare nella riunione. {{recommendAction}} Per saperne di più sulla sicurezza della tua riunione <a href=\"{{securityUrl}}\" rel=\"security\" target=\"_blank\">clicca qui</a>.",
|
||||
"title": "Impostazioni di sicurezza",
|
||||
@@ -1182,7 +1190,7 @@
|
||||
"signedIn": "Accesso agli eventi del calendario per {{email}} in corso. Clicca sul pulsante Disconnetti per interrompere l’accesso agli eventi sul calendario.",
|
||||
"title": "Calendario"
|
||||
},
|
||||
"chatWithPermissions": "La chat richiede il permesso",
|
||||
"chatWithPermissions": "Disattiva la chat per i partecipanti",
|
||||
"desktopShareFramerate": "Frequenza di aggiornamento condivisone schermo",
|
||||
"desktopShareHighFpsWarning": "Una frequenza di aggiornamento della condivisione dello schermo più alta può influire sulla tua connessione. Devi riavviare la condivisione schermo, per applicare le modifiche.",
|
||||
"desktopShareWarning": "Devi riavviare la condivisione schermo, per applicare le modifiche.",
|
||||
@@ -1195,8 +1203,8 @@
|
||||
"loggedIn": "Connesso come {{name}}",
|
||||
"maxStageParticipants": "Numero massimo di partecipanti che possono essere messi in evidenza nella schermata principale",
|
||||
"microphones": "Microfoni",
|
||||
"moderator": "Relatore",
|
||||
"moderatorOptions": "Opzioni relatore",
|
||||
"moderator": "Moderatore",
|
||||
"moderatorOptions": "Opzioni moderatore",
|
||||
"more": "Generali",
|
||||
"name": "Nome",
|
||||
"noDevice": "Nessuno",
|
||||
@@ -1325,7 +1333,7 @@
|
||||
"feedback": "Lascia un feedback",
|
||||
"fullScreen": "Attiva modalità a schermo intero",
|
||||
"giphy": "Mostra menu GIPHY",
|
||||
"grantModerator": "Concedi permessi da relatore",
|
||||
"grantModerator": "Concedi permessi da moderatore",
|
||||
"hangup": "Lascia la riunione",
|
||||
"heading": "Barra degli strumenti",
|
||||
"help": "Aiuto",
|
||||
@@ -1350,7 +1358,7 @@
|
||||
"muteEveryoneElsesVideoStream": "Spegni la videocamera a tutti gli altri",
|
||||
"muteEveryonesVideoStream": "Spegni la videocamera a tutti",
|
||||
"muteGUMPending": "Connessione del microfono in corso",
|
||||
"noiseSuppression": "Cancellazione del rumore (BETA)",
|
||||
"noiseSuppression": "Cancellazione del rumore",
|
||||
"openChat": "Apri chat",
|
||||
"participants": "Apri pannello partecipanti. {{participantsCount}} partecipanti",
|
||||
"pip": "Attiva modalità Picture-in-Picture",
|
||||
@@ -1415,20 +1423,21 @@
|
||||
"closeParticipantsPane": "Chiudi pannello partecipanti",
|
||||
"closeReactionsMenu": "Chiudi menu reazioni",
|
||||
"closedCaptions": "Sottotitoli",
|
||||
"disableNoiseSuppression": "Disattiva cancellazione del rumore (BETA)",
|
||||
"disableNoiseSuppression": "Disattiva cancellazione del rumore",
|
||||
"disableReactionSounds": "Puoi disattivare i suoni delle reazioni in questa riunione",
|
||||
"documentClose": "Chiudi documento condiviso",
|
||||
"documentOpen": "Apri documento condiviso",
|
||||
"download": "Scarica le nostre app",
|
||||
"e2ee": "Crittografia End-to-End",
|
||||
"embedMeeting": "Incorpora riunione",
|
||||
"enableNoiseSuppression": "Attiva cancellazione del rumore (BETA)",
|
||||
"enableNoiseSuppression": "Attiva cancellazione del rumore",
|
||||
"endConference": "Termina la riunione per tutti",
|
||||
"enterFullScreen": "Mostra a schermo intero",
|
||||
"enterTileView": "Mostra vista a mosaico",
|
||||
"exitFullScreen": "Esci dalla modalità a schermo intero",
|
||||
"exitTileView": "Esci dalla vista a mosaico",
|
||||
"feedback": "Lascia un feedback",
|
||||
"fileSharing": "Condivisione file",
|
||||
"giphy": "Menu GIPHY",
|
||||
"hangup": "Lascia la riunione",
|
||||
"help": "Aiuto",
|
||||
@@ -1457,13 +1466,14 @@
|
||||
"noAudioSignalDialInDesc": "Puoi anche chiamare usando:",
|
||||
"noAudioSignalDialInLinkDesc": "Numeri di telefono",
|
||||
"noAudioSignalTitle": "Nessun suono rilevato dal tuo microfono!",
|
||||
"noiseSuppression": "Cancellazione del rumore (BETA)",
|
||||
"noiseSuppression": "Cancellazione del rumore",
|
||||
"noisyAudioInputDesc": "Sembra che il tuo microfono faccia rumore, si prega di spegnerlo o cambiarlo.",
|
||||
"noisyAudioInputTitle": "Il tuo microfono sembra fare rumore!",
|
||||
"openChat": "Apri chat",
|
||||
"openReactionsMenu": "Apri il menu reazioni",
|
||||
"participants": "Partecipanti",
|
||||
"pip": "Abilita modalità Picture-in-Picture",
|
||||
"polls": "Sondaggi",
|
||||
"privateMessage": "Invia un messaggio privato",
|
||||
"profile": "Modifica profilo",
|
||||
"raiseHand": "Alza la mano",
|
||||
@@ -1565,11 +1575,11 @@
|
||||
"domuteVideo": "Disattiva videocamera",
|
||||
"domuteVideoOfOthers": "Disattiva videocamera a tutti gli altri",
|
||||
"flip": "Specchia",
|
||||
"grantModerator": "Concedi permessi da relatore",
|
||||
"grantModerator": "Concedi permessi da moderatore",
|
||||
"hideSelfView": "Nascondi la tua immagine",
|
||||
"kick": "Espelli",
|
||||
"mirrorVideo": "Specchia il tuo video",
|
||||
"moderator": "Relatore",
|
||||
"moderator": "Moderatore",
|
||||
"mute": "Il partecipante ha il microfono spento",
|
||||
"muted": "Microfono spento",
|
||||
"pinToStage": "Metti in primo piano",
|
||||
@@ -1616,7 +1626,7 @@
|
||||
"description": "Adesso sei uno spettatore in questa riunione.",
|
||||
"raiseHand": "Alza la mano",
|
||||
"title": "Ingresso nella riunione in corso",
|
||||
"wishToSpeak": "Se vuoi parlare, si prega di alzare la mano sotto e aspettare l'autorizzazione del relatore."
|
||||
"wishToSpeak": "Per parlare si prega di alzare la mano sotto e aspettare l'autorizzazione del moderatore."
|
||||
},
|
||||
"labelTooltip": "Numero di spettatori: {{count}}",
|
||||
"notification": {
|
||||
@@ -1626,7 +1636,7 @@
|
||||
"noVisitorLobby": "Non puoi partecipare se la sala d'attesa è attiva per la riunione.",
|
||||
"notAllowedPromotion": "Un partecipante deve autorizzare la tua richiesta prima.",
|
||||
"requestToJoin": "Mano alzata",
|
||||
"requestToJoinDescription": "La tua richiesta è stata inviata ai relatori. Tieni duro!",
|
||||
"requestToJoinDescription": "La tua richiesta è stata inviata ai moderatori. Tieni duro!",
|
||||
"title": "Sei uno spettatore nella riunione"
|
||||
},
|
||||
"waitingMessage": "Ti unirai alla riunione quando inizierà!"
|
||||
@@ -1667,7 +1677,7 @@
|
||||
"mobileDownLoadLinkAndroid": "Scarica applicazione per Android",
|
||||
"mobileDownLoadLinkFDroid": "Scarica applicazione da F-Droid",
|
||||
"mobileDownLoadLinkIos": "Scarica applicazione per iOS",
|
||||
"moderatedMessage": "O <a href=\"{{url}}\" rel=\"noopener noreferrer\" target=\"_blank\">prepara un URL di riunione</a> in anticipo, quando sei l'unico organizzatore.",
|
||||
"moderatedMessage": "O <a href=\"{{url}}\" rel=\"noopener noreferrer\" target=\"_blank\">prepara un URL di riunione</a> in anticipo, quando sei l'unico moderatore.",
|
||||
"privacy": "Privacy",
|
||||
"recentList": "Recenti",
|
||||
"recentListDelete": "Cancella",
|
||||
|
||||
1703
lang/main-kk.json
Normal file
1703
lang/main-kk.json
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -114,6 +114,10 @@
|
||||
"error": "Erro: a sua mensagem não foi enviada. Motivo: {{error}}",
|
||||
"everyone": "Todos",
|
||||
"fieldPlaceHolder": "Aa",
|
||||
"fileAccessibleTitle": "{{user}} carregou um ficheiro",
|
||||
"fileAccessibleTitleMe": "carreguei um arquivo",
|
||||
"fileDeleted": "Um ficheiro foi eliminado",
|
||||
"guestsChatIndicator": "(convidado)",
|
||||
"lobbyChatMessageTo": "Mensagem de chat na sala de espera para {{recipient}}",
|
||||
"message": "Mensagem",
|
||||
"messageAccessibleTitle": "{{user}} disse:",
|
||||
@@ -122,8 +126,16 @@
|
||||
"messagebox": "Escreva uma mensagem",
|
||||
"newMessages": "Novas mensagens",
|
||||
"nickname": {
|
||||
"featureChat": "chat",
|
||||
"featureClosedCaptions": "legendas ocultas",
|
||||
"featureFileSharing": "partilha de ficheiros",
|
||||
"featurePolls": "sondagens",
|
||||
"popover": "Escolha um apelido",
|
||||
"title": "Introduza um apelido para usar o chat",
|
||||
"titleWith1Features": "Insira um apelido para usar {{feature1}}",
|
||||
"titleWith2Features": "Insira um apelido para usar {{feature1}} e {{feature2}}",
|
||||
"titleWith3Features": "Insira um apelido para usar {{feature1}}, {{feature2}} e {{feature3}}",
|
||||
"titleWith4Features": "Insira um apelido para usar {{feature1}}, {{feature2}}, {{feature3}} e {{feature4}}",
|
||||
"titleWithCC": "Insira um apelido para usar o chat e as legendas ocultas",
|
||||
"titleWithPolls": "Digite um apelido para usar o chat e as sondagens",
|
||||
"titleWithPollsAndCC": "Insira um apelido para utilizar o chat, as sondagens e as legendas ocultas",
|
||||
@@ -279,7 +291,6 @@
|
||||
"Submit": "Submeter",
|
||||
"Understand": "Entendo, mantenha-me em silêncio por enquanto.",
|
||||
"UnderstandAndUnmute": "Entendo, por favor, desative o silêncio.",
|
||||
"WaitForHostMsg": "A conferência ainda não começou porque ainda não chegaram moderadores. Se quiser ser um moderador, inicie a sessão. Caso contrário, aguarde.",
|
||||
"WaitForHostNoAuthMsg": "A conferência ainda não começou porque ainda não chegaram os moderadores. Por favor, aguarde.",
|
||||
"WaitingForHostButton": "Esperar pelo moderador",
|
||||
"WaitingForHostTitle": "À espera de um moderador…",
|
||||
@@ -522,6 +533,7 @@
|
||||
"tokenAuthFailedWithReasons": "Lamentamos, mas não está autorizado a participar nesta chamada. Razões possíveis: {{reason}}",
|
||||
"tokenAuthUnsupported": "O URL de token não é suportado.",
|
||||
"transcribing": "Transcrição",
|
||||
"unauthenticatedAccessDisabled": "Esta chamada requer autenticação. Por favor, inicie sessão para prosseguir.",
|
||||
"unlockRoom": "Retirar reunião $t(lockRoomPassword)",
|
||||
"user": "Utilizador",
|
||||
"userIdentifier": "Identificador do utilizador",
|
||||
@@ -566,13 +578,17 @@
|
||||
"downloadFailedDescription": "Por favor, tente novamente.",
|
||||
"downloadFailedTitle": "Falha no descarregar",
|
||||
"downloadFile": "Descarregar",
|
||||
"downloadStarted": "O download do ficheiro foi iniciado",
|
||||
"dragAndDrop": "Arraste e solte os ficheiros aqui ou em qualquer lugar do ecrã",
|
||||
"fileAlreadyUploaded": "O ficheiro já foi carregado para esta reunião.",
|
||||
"fileRemovedByOther": "O seu ficheiro '{{ fileName }}' foi removido",
|
||||
"fileTooLargeDescription": "Certifique-se de que o ficheiro não exceda {{ maxFileSize }}.",
|
||||
"fileTooLargeTitle": "O ficheiro selecionado é muito grande",
|
||||
"fileUploadProgress": "Progresso do envio do ficheiro",
|
||||
"fileUploadedSuccessfully": "Ficheiro carregado com sucesso",
|
||||
"newFileNotification": "{{ participantName }} partilhou '{{ fileName }}'",
|
||||
"removeFile": "Remover",
|
||||
"removeFileSuccess": "Ficheiro removido com sucesso",
|
||||
"uploadFailedDescription": "Por favor, tente novamente.",
|
||||
"uploadFailedTitle": "Falha ao carregar",
|
||||
"uploadFile": "Partilhar ficheiro"
|
||||
@@ -745,7 +761,8 @@
|
||||
"notificationTitle": "Sala de espera",
|
||||
"passwordJoinButton": "Solicitar",
|
||||
"title": "Sala de espera",
|
||||
"toggleLabel": "Ativar sala de espera"
|
||||
"toggleLabel": "Ativar sala de espera",
|
||||
"waitForModerator": "A conferência ainda não começou porque não chegou nenhum moderador. Se deseja tornar-se um moderador, faça login. Caso contrário, aguarde."
|
||||
},
|
||||
"localRecording": {
|
||||
"clientState": {
|
||||
@@ -862,6 +879,7 @@
|
||||
"oldElectronClientDescription1": "Parece estar a utilizar uma versão antiga do cliente Jitsi Meet que tem vulnerabilidades de segurança conhecidas. Por favor, certifique-se de que actualiza a nossa ",
|
||||
"oldElectronClientDescription2": "compilação mais recente",
|
||||
"oldElectronClientDescription3": " agora!",
|
||||
"openChat": "Abrir chat",
|
||||
"participantWantsToJoin": "Deseja juntar-se à reunião",
|
||||
"participantsWantToJoin": "Desejam juntar-se à reunião",
|
||||
"passwordRemovedRemotely": "$t(lockRoomPasswordUppercase) removido por outro participante",
|
||||
@@ -960,6 +978,9 @@
|
||||
"by": "Por {{ name }}",
|
||||
"closeButton": "Fechar sondagem",
|
||||
"create": {
|
||||
"accessibilityLabel": {
|
||||
"send": "Enviar sondagem"
|
||||
},
|
||||
"addOption": "Adicionar opção",
|
||||
"answerPlaceholder": "Opção {{index}}",
|
||||
"cancel": "Cancelar",
|
||||
@@ -968,8 +989,7 @@
|
||||
"pollQuestion": "Pergunta de Sondagem",
|
||||
"questionPlaceholder": "Faça uma pergunta",
|
||||
"removeOption": "Remover opção",
|
||||
"save": "Guardar",
|
||||
"send": "Enviar"
|
||||
"save": "Guardar"
|
||||
},
|
||||
"errors": {
|
||||
"notUniqueOption": "As opções devem ser únicas"
|
||||
@@ -1338,7 +1358,7 @@
|
||||
"muteEveryoneElsesVideo": "Parar o vídeo de todos os outros",
|
||||
"muteEveryonesVideo": "Parar o vídeo de todos",
|
||||
"muteGUMPending": "A ligar o seu microfone",
|
||||
"noiseSuppression": "Supressão extra de ruído (BETA)",
|
||||
"noiseSuppression": "Supressão extra de ruído",
|
||||
"openChat": "Abrir chat",
|
||||
"participants": "Abrir painel de participantes. {{participantsCount}} participantes",
|
||||
"pip": "Mudar para o modo Picture-in-Picture",
|
||||
@@ -1376,6 +1396,20 @@
|
||||
"videounmute": "Iniciar câmara"
|
||||
},
|
||||
"addPeople": "Adicione pessoas à sua chamada",
|
||||
"advancedAudioSettings": {
|
||||
"aec": {
|
||||
"label": "Cancelamento de eco acústico"
|
||||
},
|
||||
"agc": {
|
||||
"label": "Controlo automático de ganho"
|
||||
},
|
||||
"ns": {
|
||||
"label": "Supressão de ruído"
|
||||
},
|
||||
"stereo": {
|
||||
"label": "Estéreo"
|
||||
}
|
||||
},
|
||||
"audioOnlyOff": "Desativar modo de largura de banda baixa",
|
||||
"audioOnlyOn": "Ativar modo de largura de banda baixa",
|
||||
"audioRoute": "Selecionar o dispositivo de som",
|
||||
@@ -1389,20 +1423,21 @@
|
||||
"closeParticipantsPane": "Fechar painel de participantes",
|
||||
"closeReactionsMenu": "Fechar menu de reações",
|
||||
"closedCaptions": "Legendas ocultas",
|
||||
"disableNoiseSuppression": "Desativar supressão de ruído extra (BETA)",
|
||||
"disableNoiseSuppression": "Desativar supressão de ruído extra",
|
||||
"disableReactionSounds": "Pode desactivar os sons de reacção para esta reunião",
|
||||
"documentClose": "Fechar documento partilhado",
|
||||
"documentOpen": "Abrir documento partilhado",
|
||||
"download": "Descarregar as nossas aplicações",
|
||||
"e2ee": "Criptografia ponta a ponta",
|
||||
"embedMeeting": "Incorporar reunião",
|
||||
"enableNoiseSuppression": "Ativar supressão extra de ruído (BETA)",
|
||||
"enableNoiseSuppression": "Ativar supressão extra de ruído",
|
||||
"endConference": "Terminar reunião para todos",
|
||||
"enterFullScreen": "Ver em ecrã completo",
|
||||
"enterTileView": "Ver em quadrícula",
|
||||
"exitFullScreen": "Sair de ecrã completo",
|
||||
"exitTileView": "Sair de quadrícula",
|
||||
"feedback": "Deixar comentários",
|
||||
"fileSharing": "Partilha de ficheiros",
|
||||
"giphy": "Ativar/Desativar o menu GIPHY",
|
||||
"hangup": "Sair da reunião",
|
||||
"help": "Ajuda",
|
||||
@@ -1431,13 +1466,14 @@
|
||||
"noAudioSignalDialInDesc": "Também pode marcar usando:",
|
||||
"noAudioSignalDialInLinkDesc": "Números de marcação",
|
||||
"noAudioSignalTitle": "Não há nenhuma entrada vinda do seu microfone!",
|
||||
"noiseSuppression": "Supressão extra de ruído (BETA)",
|
||||
"noiseSuppression": "Supressão extra de ruído",
|
||||
"noisyAudioInputDesc": "Parece que o seu microfone está a fazer barulho, por favor considere silenciar ou mudar de dispositivo.",
|
||||
"noisyAudioInputTitle": "Seu microfone parece estar barulhento!",
|
||||
"openChat": "Abrir chat",
|
||||
"openReactionsMenu": "Abrir menu de reações",
|
||||
"participants": "Participantes",
|
||||
"pip": "Entrar no modo Picture-in-Picture",
|
||||
"polls": "Sondagens",
|
||||
"privateMessage": "Enviar mensagem privada",
|
||||
"profile": "Editar o seu perfil",
|
||||
"raiseHand": "Levantar a mão",
|
||||
@@ -1447,6 +1483,7 @@
|
||||
"reactionHeart": "Enviar reação com coração",
|
||||
"reactionLaugh": "Enviar reação de risos",
|
||||
"reactionLike": "Enviar reação de aprovado",
|
||||
"reactionLove": "Enviar reação de amor",
|
||||
"reactionSilence": "Enviar reação de silêncio",
|
||||
"reactionSurprised": "Enviar reação de surpreendido",
|
||||
"reactions": "Reações",
|
||||
@@ -1598,6 +1635,8 @@
|
||||
"noMainParticipantsTitle": "Esta reunião ainda não começou.",
|
||||
"noVisitorLobby": "Não é possível aderir enquanto houver uma sala de espera activada para a reunião.",
|
||||
"notAllowedPromotion": "É necessário que um participante autorize primeiro o seu pedido.",
|
||||
"requestToJoin": "Mão levantada",
|
||||
"requestToJoinDescription": "A sua solicitação foi enviada aos moderadores. Aguarde um momento!",
|
||||
"title": "É um espectador na reunião"
|
||||
},
|
||||
"waitingMessage": "Participará na reunião assim que esta estiver em direto!"
|
||||
|
||||
@@ -227,6 +227,9 @@
|
||||
"video_ssrc": "Video SSRC:",
|
||||
"yes": "yes"
|
||||
},
|
||||
"customPanel": {
|
||||
"close": "Close"
|
||||
},
|
||||
"dateUtils": {
|
||||
"earlier": "Earlier",
|
||||
"today": "Today",
|
||||
@@ -1190,7 +1193,7 @@
|
||||
"signedIn": "Currently accessing calendar events for {{email}}. Click the Disconnect button below to stop accessing calendar events.",
|
||||
"title": "Calendar"
|
||||
},
|
||||
"chatWithPermissions": "Chat requires permission",
|
||||
"chatWithPermissions": "Disable chat for non-moderators",
|
||||
"desktopShareFramerate": "Desktop sharing frame rate",
|
||||
"desktopShareHighFpsWarning": "A higher frame rate for desktop sharing might affect your bandwidth. You need to restart the screen share for the new settings to take effect.",
|
||||
"desktopShareWarning": "You need to restart the screen share for the new settings to take effect.",
|
||||
@@ -1315,6 +1318,7 @@
|
||||
"chat": "Open / Close chat",
|
||||
"clap": "Clap",
|
||||
"closeChat": "Close chat",
|
||||
"closeCustomPanel": "Close",
|
||||
"closeMoreActions": "Close more actions menu",
|
||||
"closeParticipantsPane": "Close participants pane",
|
||||
"closedCaptions": "Closed captions",
|
||||
@@ -1358,7 +1362,7 @@
|
||||
"muteEveryoneElsesVideoStream": "Stop everyone else's video",
|
||||
"muteEveryonesVideoStream": "Stop everyone's video",
|
||||
"muteGUMPending": "Connecting your microphone",
|
||||
"noiseSuppression": "Extra noise suppression (BETA)",
|
||||
"noiseSuppression": "Extra noise suppression",
|
||||
"openChat": "Open chat",
|
||||
"participants": "Open participants panel. {{participantsCount}} participants",
|
||||
"pip": "Toggle Picture-in-Picture mode",
|
||||
@@ -1420,17 +1424,19 @@
|
||||
"chat": "Open / Close chat",
|
||||
"clap": "Clap",
|
||||
"closeChat": "Close chat",
|
||||
"closeCustomPanel": "Close",
|
||||
"closeParticipantsPane": "Close participants pane",
|
||||
"closeReactionsMenu": "Close reactions menu",
|
||||
"closedCaptions": "Closed captions",
|
||||
"disableNoiseSuppression": "Disable extra noise suppression (BETA)",
|
||||
"copilot": "Copilot",
|
||||
"disableNoiseSuppression": "Disable extra noise suppression",
|
||||
"disableReactionSounds": "You can disable reaction sounds for this meeting",
|
||||
"documentClose": "Close shared document",
|
||||
"documentOpen": "Open shared document",
|
||||
"download": "Download our apps",
|
||||
"e2ee": "End-to-End Encryption",
|
||||
"embedMeeting": "Embed meeting",
|
||||
"enableNoiseSuppression": "Enable extra noise suppression (BETA)",
|
||||
"enableNoiseSuppression": "Enable extra noise suppression",
|
||||
"endConference": "End meeting for all",
|
||||
"enterFullScreen": "View full screen",
|
||||
"enterTileView": "Enter tile view",
|
||||
@@ -1466,7 +1472,7 @@
|
||||
"noAudioSignalDialInDesc": "You can also dial-in using:",
|
||||
"noAudioSignalDialInLinkDesc": "Dial-in numbers",
|
||||
"noAudioSignalTitle": "There is no input coming from your mic!",
|
||||
"noiseSuppression": "Extra noise suppression (BETA)",
|
||||
"noiseSuppression": "Extra noise suppression",
|
||||
"noisyAudioInputDesc": "It sounds like your microphone is making noise, please consider muting or changing the device.",
|
||||
"noisyAudioInputTitle": "Your microphone appears to be noisy!",
|
||||
"openChat": "Open chat",
|
||||
|
||||
@@ -107,9 +107,10 @@ import {
|
||||
open as openParticipantsPane
|
||||
} from '../../react/features/participants-pane/actions';
|
||||
import { getParticipantsPaneOpen } from '../../react/features/participants-pane/functions';
|
||||
import { hidePiP, showPiP } from '../../react/features/pip/actions';
|
||||
import { startLocalVideoRecording, stopLocalVideoRecording } from '../../react/features/recording/actions.any';
|
||||
import { grantRecordingConsent, grantRecordingConsentAndUnmute } from '../../react/features/recording/actions.web';
|
||||
import { RECORDING_METADATA_ID, RECORDING_TYPES } from '../../react/features/recording/constants';
|
||||
import { RECORDING_TYPES } from '../../react/features/recording/constants';
|
||||
import { getActiveSession, supportsLocalRecording } from '../../react/features/recording/functions';
|
||||
import { startAudioScreenShareFlow, startScreenShareFlow } from '../../react/features/screen-share/actions';
|
||||
import { isScreenAudioSupported } from '../../react/features/screen-share/functions';
|
||||
@@ -125,7 +126,7 @@ import { extractYoutubeIdOrURL } from '../../react/features/shared-video/functio
|
||||
import { setRequestingSubtitles, toggleRequestingSubtitles } from '../../react/features/subtitles/actions';
|
||||
import { isAudioMuteButtonDisabled } from '../../react/features/toolbox/functions';
|
||||
import { setTileView, toggleTileView } from '../../react/features/video-layout/actions.any';
|
||||
import { muteAllParticipants } from '../../react/features/video-menu/actions';
|
||||
import { muteAllParticipants, muteRemote } from '../../react/features/video-menu/actions';
|
||||
import { setVideoQuality } from '../../react/features/video-quality/actions';
|
||||
import { toggleBackgroundEffect, toggleBlurredBackgroundEffect } from '../../react/features/virtual-background/actions';
|
||||
import { VIRTUAL_BACKGROUND_TYPE } from '../../react/features/virtual-background/constants';
|
||||
@@ -238,6 +239,31 @@ function initCommands() {
|
||||
|
||||
APP.store.dispatch(muteAllParticipants(exclude, muteMediaType));
|
||||
},
|
||||
'mute-remote-participant': (participantId, mediaType) => {
|
||||
const state = APP.store.getState();
|
||||
const muteMediaType = mediaType ? mediaType : MEDIA_TYPE.AUDIO;
|
||||
const localParticipant = getLocalParticipant(state);
|
||||
|
||||
// Check if targeting the local participant
|
||||
if (participantId === localParticipant?.id) {
|
||||
|
||||
if (muteMediaType === MEDIA_TYPE.AUDIO) {
|
||||
APP.conference.toggleAudioMuted(false);
|
||||
} else if (muteMediaType === MEDIA_TYPE.VIDEO) {
|
||||
APP.conference.toggleVideoMuted(false, true);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isLocalParticipantModerator(state)) {
|
||||
logger.error('Missing moderator rights to mute remote participant');
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
APP.store.dispatch(muteRemote(participantId, muteMediaType));
|
||||
},
|
||||
'toggle-lobby': isLobbyEnabled => {
|
||||
APP.store.dispatch(toggleLobbyMode(isLobbyEnabled));
|
||||
},
|
||||
@@ -779,9 +805,6 @@ function initCommands() {
|
||||
|
||||
if (transcription) {
|
||||
APP.store.dispatch(setRequestingSubtitles(true, false, null, true));
|
||||
conference.getMetadataHandler().setMetadata(RECORDING_METADATA_ID, {
|
||||
isTranscribingEnabled: true
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
@@ -803,10 +826,7 @@ function initCommands() {
|
||||
}
|
||||
|
||||
if (transcription) {
|
||||
APP.store.dispatch(setRequestingSubtitles(false, false, null));
|
||||
conference.getMetadataHandler().setMetadata(RECORDING_METADATA_ID, {
|
||||
isTranscribingEnabled: false
|
||||
});
|
||||
APP.store.dispatch(setRequestingSubtitles(false, false, null, true));
|
||||
}
|
||||
|
||||
if (mode === 'local') {
|
||||
@@ -907,6 +927,12 @@ function initCommands() {
|
||||
backgroundType: VIRTUAL_BACKGROUND_TYPE.IMAGE,
|
||||
virtualSource: backgroundImage
|
||||
}, jitsiTrack));
|
||||
},
|
||||
'show-pip': () => {
|
||||
APP.store.dispatch(showPiP());
|
||||
},
|
||||
'hide-pip': () => {
|
||||
APP.store.dispatch(hidePiP());
|
||||
}
|
||||
};
|
||||
transport.on('event', ({ data, name }) => {
|
||||
@@ -1242,6 +1268,20 @@ class API {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify external application (if API is enabled) that the in-page toolbox
|
||||
* visibility changed.
|
||||
*
|
||||
* @param {boolean} visible - True if the toolbox is visible, false otherwise.
|
||||
* @returns {void}
|
||||
*/
|
||||
notifyToolbarVisibilityChanged(visible) {
|
||||
this._sendEvent({
|
||||
name: 'toolbar-visibility-changed',
|
||||
visible
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Notifies the external application (spot) that the local jitsi-participant
|
||||
* has a status update.
|
||||
@@ -1386,6 +1426,23 @@ class API {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify the external application that a participant's mute status changed.
|
||||
*
|
||||
* @param {string} participantId - The ID of the participant.
|
||||
* @param {boolean} isMuted - True if muted, false if unmuted.
|
||||
* @param {string} mediaType - Media type that was muted ('audio' or 'video').
|
||||
* @returns {void}
|
||||
*/
|
||||
notifyParticipantMuted(participantId, isMuted, mediaType) {
|
||||
this._sendEvent({
|
||||
name: 'participant-muted',
|
||||
id: participantId,
|
||||
isMuted,
|
||||
mediaType
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify the external app that a notification has been triggered.
|
||||
*
|
||||
@@ -2235,6 +2292,40 @@ class API {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify external application (if API is enabled) that Picture-in-Picture was requested.
|
||||
* Used by Electron to handle PiP requests with proper user gesture context.
|
||||
*
|
||||
* @returns {void}
|
||||
*/
|
||||
notifyPictureInPictureRequested() {
|
||||
this._sendEvent({
|
||||
name: '_pip-requested'
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify external application (if API is enabled) that Picture-in-Picture mode was entered.
|
||||
*
|
||||
* @returns {void}
|
||||
*/
|
||||
notifyPictureInPictureEntered() {
|
||||
this._sendEvent({
|
||||
name: 'pip-entered'
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify external application (if API is enabled) that Picture-in-Picture mode was exited.
|
||||
*
|
||||
* @returns {void}
|
||||
*/
|
||||
notifyPictureInPictureLeft() {
|
||||
this._sendEvent({
|
||||
name: 'pip-left'
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify external application ( if API is enabled) that a participant menu button was clicked.
|
||||
*
|
||||
|
||||
119
modules/API/external/external_api.js
vendored
119
modules/API/external/external_api.js
vendored
@@ -2,6 +2,7 @@ import { jitsiLocalStorage } from '@jitsi/js-utils/jitsi-local-storage';
|
||||
import EventEmitter from 'events';
|
||||
|
||||
import { urlObjectToString } from '../../../react/features/base/util/uri';
|
||||
import { isPiPEnabled } from '../../../react/features/pip/external-api.shared';
|
||||
import {
|
||||
PostMessageTransportBackend,
|
||||
Transport
|
||||
@@ -46,6 +47,7 @@ const commands = {
|
||||
localSubject: 'local-subject',
|
||||
kickParticipant: 'kick-participant',
|
||||
muteEveryone: 'mute-everyone',
|
||||
muteRemoteParticipant: 'mute-remote-participant',
|
||||
overwriteConfig: 'overwrite-config',
|
||||
overwriteNames: 'overwrite-names',
|
||||
password: 'password',
|
||||
@@ -94,7 +96,9 @@ const commands = {
|
||||
toggleTileView: 'toggle-tile-view',
|
||||
toggleVirtualBackgroundDialog: 'toggle-virtual-background',
|
||||
toggleVideo: 'toggle-video',
|
||||
toggleWhiteboard: 'toggle-whiteboard'
|
||||
toggleWhiteboard: 'toggle-whiteboard',
|
||||
showPiP: 'show-pip',
|
||||
hidePiP: 'hide-pip'
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -102,6 +106,9 @@ const commands = {
|
||||
* events expected by jitsi-meet.
|
||||
*/
|
||||
const events = {
|
||||
'_pip-requested': '_pipRequested',
|
||||
'pip-entered': 'pipEntered',
|
||||
'pip-left': 'pipLeft',
|
||||
'avatar-changed': 'avatarChanged',
|
||||
'audio-availability-changed': 'audioAvailabilityChanged',
|
||||
'audio-mute-status-changed': 'audioMuteStatusChanged',
|
||||
@@ -144,6 +151,7 @@ const events = {
|
||||
'participant-joined': 'participantJoined',
|
||||
'participant-kicked-out': 'participantKickedOut',
|
||||
'participant-left': 'participantLeft',
|
||||
'participant-muted': 'participantMuted',
|
||||
'participant-role-changed': 'participantRoleChanged',
|
||||
'participants-pane-toggled': 'participantsPaneToggled',
|
||||
'password-required': 'passwordRequired',
|
||||
@@ -167,6 +175,7 @@ const events = {
|
||||
'suspend-detected': 'suspendDetected',
|
||||
'tile-view-changed': 'tileViewChanged',
|
||||
'toolbar-button-clicked': 'toolbarButtonClicked',
|
||||
'toolbar-visibility-changed': 'toolbarVisibilityChanged',
|
||||
'transcribing-status-changed': 'transcribingStatusChanged',
|
||||
'transcription-chunk-received': 'transcriptionChunkReceived',
|
||||
'whiteboard-status-changed': 'whiteboardStatusChanged'
|
||||
@@ -329,6 +338,7 @@ export default class JitsiMeetExternalAPI extends EventEmitter {
|
||||
this._myUserID = undefined;
|
||||
this._onStageParticipant = undefined;
|
||||
this._iAmvisitor = undefined;
|
||||
this._pipConfig = configOverwrite?.pip;
|
||||
this._setupListeners();
|
||||
id++;
|
||||
}
|
||||
@@ -648,6 +658,56 @@ export default class JitsiMeetExternalAPI extends EventEmitter {
|
||||
this.emit(requestName, data, callback);
|
||||
}
|
||||
});
|
||||
|
||||
this._setupIntersectionObserver();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets up IntersectionObserver to monitor iframe visibility.
|
||||
* Calls showPiP/hidePiP based on visibility.
|
||||
*
|
||||
* @private
|
||||
* @returns {void}
|
||||
*/
|
||||
_setupIntersectionObserver() {
|
||||
if (!isPiPEnabled(this._pipConfig)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Don't create duplicate observers.
|
||||
if (this._intersectionObserver) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._isIntersecting = true;
|
||||
|
||||
this._intersectionObserver = new IntersectionObserver(entries => {
|
||||
const entry = entries[entries.length - 1];
|
||||
const wasIntersecting = this._isIntersecting;
|
||||
|
||||
this._isIntersecting = entry.isIntersecting;
|
||||
|
||||
if (!entry.isIntersecting && wasIntersecting) {
|
||||
this.showPiP();
|
||||
} else if (entry.isIntersecting && !wasIntersecting) {
|
||||
this.hidePiP();
|
||||
}
|
||||
});
|
||||
|
||||
this._intersectionObserver.observe(this._frame);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tears down IntersectionObserver.
|
||||
*
|
||||
* @private
|
||||
* @returns {void}
|
||||
*/
|
||||
_teardownIntersectionObserver() {
|
||||
if (this._intersectionObserver) {
|
||||
this._intersectionObserver.disconnect();
|
||||
this._intersectionObserver = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -850,6 +910,8 @@ export default class JitsiMeetExternalAPI extends EventEmitter {
|
||||
this.emit('_willDispose');
|
||||
this._transport.dispose();
|
||||
this.removeAllListeners();
|
||||
this._teardownIntersectionObserver();
|
||||
|
||||
if (this._frame && this._frame.parentNode) {
|
||||
this._frame.parentNode.removeChild(this._frame);
|
||||
}
|
||||
@@ -878,10 +940,47 @@ export default class JitsiMeetExternalAPI extends EventEmitter {
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Handle pip config changes locally.
|
||||
// We update local state, send command to iframe, then handle PiP show/hide
|
||||
// so the iframe config is updated before we try to show PiP.
|
||||
let pipTransition = null;
|
||||
|
||||
if (name === 'overwriteConfig' && args[0]?.pip !== undefined) {
|
||||
const wasEnabled = isPiPEnabled(this._pipConfig);
|
||||
|
||||
this._pipConfig = {
|
||||
...this._pipConfig,
|
||||
...args[0].pip
|
||||
};
|
||||
|
||||
const isEnabled = isPiPEnabled(this._pipConfig);
|
||||
|
||||
if (!wasEnabled && isEnabled) {
|
||||
this._setupIntersectionObserver();
|
||||
pipTransition = 'enabled';
|
||||
} else if (wasEnabled && !isEnabled) {
|
||||
this._teardownIntersectionObserver();
|
||||
pipTransition = 'disabled';
|
||||
}
|
||||
}
|
||||
|
||||
// Send command to iframe first.
|
||||
this._transport.sendEvent({
|
||||
data: args,
|
||||
name: commands[name]
|
||||
});
|
||||
|
||||
// Handle PiP state after command is sent so iframe config is updated.
|
||||
if (pipTransition === 'enabled') {
|
||||
// Show PiP if iframe is currently not visible.
|
||||
if (!this._isIntersecting) {
|
||||
this.showPiP();
|
||||
}
|
||||
} else if (pipTransition === 'disabled') {
|
||||
// Hide any open PiP window.
|
||||
this.hidePiP();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1495,6 +1594,24 @@ export default class JitsiMeetExternalAPI extends EventEmitter {
|
||||
this.executeCommand('setVirtualBackground', enabled, backgroundImage);
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows Picture-in-Picture window.
|
||||
*
|
||||
* @returns {void}
|
||||
*/
|
||||
showPiP() {
|
||||
this.executeCommand('showPiP');
|
||||
}
|
||||
|
||||
/**
|
||||
* Hides Picture-in-Picture window.
|
||||
*
|
||||
* @returns {void}
|
||||
*/
|
||||
hidePiP() {
|
||||
this.executeCommand('hidePiP');
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens the desktop picker. This is invoked by the Electron SDK when gDM is used.
|
||||
*
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
import Logger from '@jitsi/logger';
|
||||
import $ from 'jquery';
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import { createRoot } from 'react-dom/client';
|
||||
import { I18nextProvider } from 'react-i18next';
|
||||
import { Provider } from 'react-redux';
|
||||
|
||||
@@ -166,7 +166,8 @@ export default class LargeVideoManager {
|
||||
|
||||
this.removePresenceLabel();
|
||||
|
||||
ReactDOM.unmountComponentAtNode(this._dominantSpeakerAvatarContainer);
|
||||
this._avatarRoot?.unmount();
|
||||
this._avatarRoot = null;
|
||||
|
||||
this.container.style.display = 'none';
|
||||
}
|
||||
@@ -518,14 +519,16 @@ export default class LargeVideoManager {
|
||||
* Updates the src of the dominant speaker avatar
|
||||
*/
|
||||
updateAvatar() {
|
||||
ReactDOM.render(
|
||||
if (!this._avatarRoot) {
|
||||
this._avatarRoot = createRoot(this._dominantSpeakerAvatarContainer);
|
||||
}
|
||||
this._avatarRoot.render(
|
||||
<Provider store = { APP.store }>
|
||||
<Avatar
|
||||
id = "dominantSpeakerAvatar"
|
||||
participantId = { this.id }
|
||||
size = { 200 } />
|
||||
</Provider>,
|
||||
this._dominantSpeakerAvatarContainer
|
||||
</Provider>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -559,15 +562,18 @@ export default class LargeVideoManager {
|
||||
const presenceLabelContainer = document.getElementById('remotePresenceMessage');
|
||||
|
||||
if (presenceLabelContainer) {
|
||||
ReactDOM.render(
|
||||
if (!this._presenceLabelRoot) {
|
||||
this._presenceLabelRoot = createRoot(presenceLabelContainer);
|
||||
}
|
||||
this._presenceLabelRoot.render(
|
||||
<Provider store = { APP.store }>
|
||||
<I18nextProvider i18n = { i18next }>
|
||||
<PresenceLabel
|
||||
participantID = { id }
|
||||
className = 'presence-label' />
|
||||
</I18nextProvider>
|
||||
</Provider>,
|
||||
presenceLabelContainer);
|
||||
</Provider>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -577,11 +583,8 @@ export default class LargeVideoManager {
|
||||
* @returns {void}
|
||||
*/
|
||||
removePresenceLabel() {
|
||||
const presenceLabelContainer = document.getElementById('remotePresenceMessage');
|
||||
|
||||
if (presenceLabelContainer) {
|
||||
ReactDOM.unmountComponentAtNode(presenceLabelContainer);
|
||||
}
|
||||
this._presenceLabelRoot?.unmount();
|
||||
this._presenceLabelRoot = null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
import Logger from '@jitsi/logger';
|
||||
import $ from 'jquery';
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import { createRoot } from 'react-dom/client';
|
||||
|
||||
import { browser } from '../../../react/features/base/lib-jitsi-meet';
|
||||
import { FILMSTRIP_BREAKPOINT } from '../../../react/features/filmstrip/constants';
|
||||
@@ -659,7 +659,12 @@ export class VideoContainer extends LargeContainer {
|
||||
return;
|
||||
}
|
||||
|
||||
ReactDOM.render(
|
||||
const container = document.getElementById('largeVideoBackgroundContainer');
|
||||
|
||||
if (!this._backgroundRoot) {
|
||||
this._backgroundRoot = createRoot(container);
|
||||
}
|
||||
this._backgroundRoot.render(
|
||||
<LargeVideoBackground
|
||||
hidden = { this._hideBackground || this._isHidden }
|
||||
mirror = {
|
||||
@@ -669,8 +674,7 @@ export class VideoContainer extends LargeContainer {
|
||||
}
|
||||
orientationFit = { this._backgroundOrientation }
|
||||
videoElement = { this.video }
|
||||
videoTrack = { this.stream } />,
|
||||
document.getElementById('largeVideoBackgroundContainer')
|
||||
videoTrack = { this.stream } />
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
5005
package-lock.json
generated
5005
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
20
package.json
20
package.json
@@ -72,7 +72,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/v2115.0.0+cc2f34c2/lib-jitsi-meet.tgz",
|
||||
"lib-jitsi-meet": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v2124.0.0+80df84a1/lib-jitsi-meet.tgz",
|
||||
"lodash-es": "4.17.21",
|
||||
"null-loader": "4.0.1",
|
||||
"optional-require": "1.0.3",
|
||||
@@ -97,7 +97,7 @@
|
||||
"react-native-pager-view": "6.8.1",
|
||||
"react-native-paper": "5.10.3",
|
||||
"react-native-performance": "5.1.2",
|
||||
"react-native-safe-area-context": "5.5.2",
|
||||
"react-native-safe-area-context": "5.6.1",
|
||||
"react-native-screens": "4.11.1",
|
||||
"react-native-sound": "https://github.com/jitsi/react-native-sound.git#ea13c97b5c2a4ff5e0d9bacbd9ff5e4457fe2c3c",
|
||||
"react-native-splash-view": "0.0.18",
|
||||
@@ -164,12 +164,12 @@
|
||||
"@types/w3c-image-capture": "1.0.6",
|
||||
"@types/w3c-web-hid": "1.0.3",
|
||||
"@types/zxcvbn": "4.4.1",
|
||||
"@wdio/allure-reporter": "9.16.0",
|
||||
"@wdio/cli": "9.16.0",
|
||||
"@wdio/globals": "9.16.0",
|
||||
"@wdio/junit-reporter": "9.16.0",
|
||||
"@wdio/local-runner": "9.16.0",
|
||||
"@wdio/mocha-framework": "9.16.0",
|
||||
"@wdio/allure-reporter": "9.23.2",
|
||||
"@wdio/cli": "9.23.2",
|
||||
"@wdio/globals": "9.23.0",
|
||||
"@wdio/junit-reporter": "9.23.2",
|
||||
"@wdio/local-runner": "9.23.2",
|
||||
"@wdio/mocha-framework": "9.23.2",
|
||||
"babel-loader": "9.1.0",
|
||||
"babel-plugin-optional-require": "0.3.1",
|
||||
"circular-dependency-plugin": "5.2.0",
|
||||
@@ -193,8 +193,8 @@
|
||||
"ts-loader": "9.4.2",
|
||||
"typescript": "5.7.2",
|
||||
"unorm": "1.6.0",
|
||||
"webdriverio": "9.16.0",
|
||||
"webpack": "5.95.0",
|
||||
"webdriverio": "9.22.0",
|
||||
"webpack": "5.105.0",
|
||||
"webpack-bundle-analyzer": "4.4.2",
|
||||
"webpack-cli": "5.1.4",
|
||||
"webpack-dev-server": "5.1.0"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { setRoom } from '../base/conference/actions';
|
||||
import { setRoom } from '../base/conference/actions.native';
|
||||
import { getConferenceState } from '../base/conference/functions';
|
||||
import {
|
||||
configWillLoad,
|
||||
@@ -29,7 +29,7 @@ import {
|
||||
} from '../mobile/navigation/rootNavigationContainerRef';
|
||||
import { screen } from '../mobile/navigation/routes';
|
||||
import { clearNotifications } from '../notifications/actions';
|
||||
import { isUnsafeRoomWarningEnabled } from '../prejoin/functions';
|
||||
import { isUnsafeRoomWarningEnabled } from '../prejoin/functions.native';
|
||||
|
||||
import { maybeRedirectToTokenAuthUrl } from './actions.any';
|
||||
import { addTrackStateToURL, getDefaultURL } from './functions.native';
|
||||
|
||||
@@ -5,6 +5,7 @@ import JitsiThemeProvider from '../../base/ui/components/JitsiThemeProvider.web'
|
||||
import DialogContainer from '../../base/ui/components/web/DialogContainer';
|
||||
import ChromeExtensionBanner from '../../chrome-extension-banner/components/ChromeExtensionBanner.web';
|
||||
import OverlayContainer from '../../overlay/components/web/OverlayContainer';
|
||||
import PiP from '../../pip/components/PiP';
|
||||
|
||||
import { AbstractApp } from './AbstractApp';
|
||||
|
||||
@@ -47,6 +48,7 @@ export class App extends AbstractApp {
|
||||
<JitsiThemeProvider>
|
||||
<GlobalStyles />
|
||||
<ChromeExtensionBanner />
|
||||
<PiP />
|
||||
{ super._createMainElement(component, props) }
|
||||
</JitsiThemeProvider>
|
||||
);
|
||||
|
||||
@@ -2,7 +2,6 @@ import '../analytics/middleware';
|
||||
import '../authentication/middleware';
|
||||
import '../av-moderation/middleware';
|
||||
import '../base/conference/middleware';
|
||||
import '../base/config/middleware';
|
||||
import '../base/i18n/middleware';
|
||||
import '../base/jwt/middleware';
|
||||
import '../base/known-domains/middleware';
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import '../base/config/middleware';
|
||||
import '../dynamic-branding/middleware';
|
||||
import '../gifs/middleware';
|
||||
import '../mobile/audio-mode/middleware';
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import '../base/app/middleware';
|
||||
import '../base/config/middleware';
|
||||
import '../base/connection/middleware';
|
||||
import '../base/devices/middleware';
|
||||
import '../base/media/middleware';
|
||||
@@ -11,6 +12,7 @@ import '../no-audio-signal/middleware';
|
||||
import '../notifications/middleware';
|
||||
import '../noise-detection/middleware';
|
||||
import '../old-client-notification/middleware';
|
||||
import '../pip/middleware';
|
||||
import '../power-monitor/middleware';
|
||||
import '../prejoin/middleware';
|
||||
import '../remote-control/middleware';
|
||||
@@ -24,5 +26,6 @@ import '../face-landmarks/middleware';
|
||||
import '../gifs/middleware';
|
||||
import '../whiteboard/middleware.web';
|
||||
import '../file-sharing/middleware.web';
|
||||
import '../custom-panel/middleware.web';
|
||||
|
||||
import './middlewares.any';
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import '../base/devices/reducer';
|
||||
import '../base/premeeting/reducer';
|
||||
import '../custom-panel/reducer';
|
||||
import '../base/tooltip/reducer';
|
||||
import '../e2ee/reducer';
|
||||
import '../face-landmarks/reducer';
|
||||
@@ -8,6 +9,7 @@ import '../keyboard-shortcuts/reducer';
|
||||
import '../no-audio-signal/reducer';
|
||||
import '../noise-detection/reducer';
|
||||
import '../participants-pane/reducer';
|
||||
import '../pip/reducer';
|
||||
import '../power-monitor/reducer';
|
||||
import '../prejoin/reducer';
|
||||
import '../remote-control/reducer';
|
||||
|
||||
@@ -31,6 +31,7 @@ import { IUserInteractionState } from '../base/user-interaction/reducer';
|
||||
import { IBreakoutRoomsState } from '../breakout-rooms/reducer';
|
||||
import { ICalendarSyncState } from '../calendar-sync/reducer';
|
||||
import { IChatState } from '../chat/reducer';
|
||||
import { ICustomPanelState } from '../custom-panel/reducer';
|
||||
import { IDeepLinkingState } from '../deep-linking/reducer';
|
||||
import { IDropboxState } from '../dropbox/reducer';
|
||||
import { IDynamicBrandingState } from '../dynamic-branding/reducer';
|
||||
@@ -57,6 +58,7 @@ import { INoiseDetectionState } from '../noise-detection/reducer';
|
||||
import { INoiseSuppressionState } from '../noise-suppression/reducer';
|
||||
import { INotificationsState } from '../notifications/reducer';
|
||||
import { IParticipantsPaneState } from '../participants-pane/reducer';
|
||||
import { IPipState } from '../pip/reducer';
|
||||
import { IPollsState } from '../polls/reducer';
|
||||
import { IPollsHistoryState } from '../polls-history/reducer';
|
||||
import { IPowerMonitorState } from '../power-monitor/reducer';
|
||||
@@ -120,6 +122,7 @@ export interface IReduxState {
|
||||
'features/calendar-sync': ICalendarSyncState;
|
||||
'features/call-integration': ICallIntegrationState;
|
||||
'features/chat': IChatState;
|
||||
'features/custom-panel': ICustomPanelState;
|
||||
'features/deep-linking': IDeepLinkingState;
|
||||
'features/dropbox': IDropboxState;
|
||||
'features/dynamic-branding': IDynamicBrandingState;
|
||||
@@ -145,6 +148,7 @@ export interface IReduxState {
|
||||
'features/noise-suppression': INoiseSuppressionState;
|
||||
'features/notifications': INotificationsState;
|
||||
'features/participants-pane': IParticipantsPaneState;
|
||||
'features/pip': IPipState;
|
||||
'features/polls': IPollsState;
|
||||
'features/polls-history': IPollsHistoryState;
|
||||
'features/power-monitor': IPowerMonitorState;
|
||||
|
||||
@@ -81,7 +81,6 @@ MiddlewareRegistry.register(({ dispatch, getState }) => next => action => {
|
||||
break;
|
||||
}
|
||||
case LOCAL_PARTICIPANT_MODERATION_NOTIFICATION: {
|
||||
let descriptionKey;
|
||||
let titleKey;
|
||||
let uid = '';
|
||||
const localParticipant = getLocalParticipant(getState);
|
||||
@@ -111,8 +110,6 @@ MiddlewareRegistry.register(({ dispatch, getState }) => next => action => {
|
||||
!raisedHand && dispatch(raiseHand(true));
|
||||
dispatch(hideNotification(uid));
|
||||
}) ],
|
||||
descriptionKey,
|
||||
sticky: true,
|
||||
titleKey,
|
||||
uid
|
||||
}, NOTIFICATION_TIMEOUT_TYPE.MEDIUM));
|
||||
@@ -271,7 +268,6 @@ StateListenerRegistry.register(
|
||||
|
||||
dispatch(showNotification({
|
||||
titleKey: 'notify.hostAskedUnmute',
|
||||
sticky: true,
|
||||
customActionNameKey,
|
||||
customActionHandler,
|
||||
uid: ASKED_TO_UNMUTE_NOTIFICATION_ID
|
||||
|
||||
@@ -5,7 +5,18 @@ import Icon from '../../../icons/components/Icon';
|
||||
import { pixelsToRem } from '../../../ui/functions.any';
|
||||
import { isIcon } from '../../functions';
|
||||
import { IAvatarProps } from '../../types';
|
||||
import { PRESENCE_AVAILABLE_COLOR, PRESENCE_AWAY_COLOR, PRESENCE_BUSY_COLOR, PRESENCE_IDLE_COLOR } from '../styles';
|
||||
import {
|
||||
PRESENCE_AVAILABLE_COLOR,
|
||||
PRESENCE_AWAY_COLOR,
|
||||
PRESENCE_BUSY_COLOR,
|
||||
PRESENCE_IDLE_COLOR
|
||||
} from '../styles';
|
||||
|
||||
import {
|
||||
AVATAR_DEFAULT_BACKGROUND_COLOR,
|
||||
getAvatarFont,
|
||||
getAvatarInitialsColor
|
||||
} from './styles';
|
||||
|
||||
interface IProps extends IAvatarProps {
|
||||
|
||||
@@ -48,10 +59,10 @@ interface IProps extends IAvatarProps {
|
||||
const useStyles = makeStyles()(theme => {
|
||||
return {
|
||||
avatar: {
|
||||
backgroundColor: '#AAA',
|
||||
backgroundColor: AVATAR_DEFAULT_BACKGROUND_COLOR,
|
||||
borderRadius: '50%',
|
||||
color: theme.palette?.text01 || '#fff',
|
||||
...(theme.typography?.heading1 ?? {}),
|
||||
color: getAvatarInitialsColor(theme),
|
||||
...getAvatarFont(theme),
|
||||
fontSize: 'inherit',
|
||||
objectFit: 'cover',
|
||||
textAlign: 'center',
|
||||
|
||||
26
react/features/base/avatar/components/web/styles.ts
Normal file
26
react/features/base/avatar/components/web/styles.ts
Normal file
@@ -0,0 +1,26 @@
|
||||
import { Theme } from '@mui/material/styles';
|
||||
|
||||
// Default avatar background color
|
||||
export const AVATAR_DEFAULT_BACKGROUND_COLOR = '#AAA';
|
||||
|
||||
/**
|
||||
* Returns the avatar font style from the theme.
|
||||
*
|
||||
* @param {Theme} theme - The MUI theme.
|
||||
* @returns {Object} The font style object containing fontFamily, fontWeight, etc.
|
||||
*/
|
||||
export const getAvatarFont = (theme: Theme) => theme.typography?.heading1 ?? {};
|
||||
|
||||
/**
|
||||
* Default text color for avatar initials.
|
||||
*/
|
||||
export const AVATAR_DEFAULT_INITIALS_COLOR = '#FFFFFF';
|
||||
|
||||
/**
|
||||
* Returns the text color for avatar initials from the theme.
|
||||
*
|
||||
* @param {Theme} theme - The MUI theme.
|
||||
* @returns {string} The text color.
|
||||
*/
|
||||
export const getAvatarInitialsColor = (theme: Theme): string =>
|
||||
theme.palette?.text01 || AVATAR_DEFAULT_INITIALS_COLOR;
|
||||
@@ -93,10 +93,17 @@ export function commonUserJoinedHandling(
|
||||
if (!user.isHidden()) {
|
||||
const isReplacing = user?.isReplacing();
|
||||
const isPromoted = conference?.getMetadataHandler().getMetadata()?.visitors?.promoted?.[id];
|
||||
const userIdentity = user.getIdentity()?.user;
|
||||
|
||||
// Map identity from JWT context to userContext for external API
|
||||
const userContext = userIdentity ? {
|
||||
id: userIdentity.id,
|
||||
name: userIdentity.name
|
||||
} : undefined;
|
||||
|
||||
// the identity and avatar come from jwt and never change in the presence
|
||||
dispatch(participantJoined({
|
||||
avatarURL: user.getIdentity()?.user?.avatar,
|
||||
avatarURL: userIdentity?.avatar,
|
||||
botType: user.getBotType(),
|
||||
conference,
|
||||
id,
|
||||
@@ -105,7 +112,8 @@ export function commonUserJoinedHandling(
|
||||
role: user.getRole(),
|
||||
isPromoted,
|
||||
isReplacing,
|
||||
sources: user.getSources()
|
||||
sources: user.getSources(),
|
||||
userContext
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -517,6 +517,10 @@ export interface IConfig {
|
||||
peopleSearchQueryTypes?: string[];
|
||||
peopleSearchTokenLocation?: string;
|
||||
peopleSearchUrl?: string;
|
||||
pip?: {
|
||||
disabled?: boolean;
|
||||
showOnPrejoin?: boolean;
|
||||
};
|
||||
preferBosh?: boolean;
|
||||
preferVisitor?: boolean;
|
||||
preferredTranscribeLanguage?: string;
|
||||
@@ -555,6 +559,8 @@ export interface IConfig {
|
||||
skipConsentInMeeting?: boolean;
|
||||
suggestRecording?: boolean;
|
||||
};
|
||||
reducedUIEnabled?: boolean;
|
||||
reducedUImainToolbarButtons?: Array<string>;
|
||||
remoteVideoMenu?: {
|
||||
disableDemote?: boolean;
|
||||
disableGrantModerator?: boolean;
|
||||
@@ -577,6 +583,7 @@ export interface IConfig {
|
||||
};
|
||||
serviceUrl?: string;
|
||||
sharedVideoAllowedURLDomains?: Array<string>;
|
||||
showChatPermissionsModeratorSetting?: boolean;
|
||||
sipInviteUrl?: string;
|
||||
speakerStats?: {
|
||||
disableSearch?: boolean;
|
||||
@@ -632,7 +639,6 @@ export interface IConfig {
|
||||
autoTranscribeOnRecord?: boolean;
|
||||
disableClosedCaptions?: boolean;
|
||||
enabled?: boolean;
|
||||
inviteJigasiOnBackendTranscribing?: boolean;
|
||||
preferredLanguage?: string;
|
||||
translationLanguages?: Array<string>;
|
||||
translationLanguagesHead?: Array<string>;
|
||||
|
||||
@@ -199,6 +199,7 @@ export default [
|
||||
'participantMenuButtonsWithNotifyClick',
|
||||
'participantsPane',
|
||||
'pcStatsInterval',
|
||||
'pip',
|
||||
'preferBosh',
|
||||
'preferVisitor',
|
||||
'prejoinConfig.enabled',
|
||||
@@ -214,10 +215,13 @@ export default [
|
||||
'recordings.showPrejoinWarning',
|
||||
'recordings.showRecordingLink',
|
||||
'recordings.suggestRecording',
|
||||
'reducedUIEnabled',
|
||||
'reducedUImainToolbarButtons',
|
||||
'replaceParticipant',
|
||||
'resolution',
|
||||
'screenshotCapture',
|
||||
'securityUi',
|
||||
'showChatPermissionsModeratorSetting',
|
||||
'speakerStats',
|
||||
'startAudioMuted',
|
||||
'startAudioOnly',
|
||||
|
||||
@@ -387,7 +387,8 @@ export function setConfigFromURLParams(
|
||||
|
||||
// When not in an iframe, start without media if the pre-join page is not enabled.
|
||||
if (!isEmbedded()
|
||||
&& 'config.prejoinConfig.enabled' in params && config.prejoinConfig?.enabled === false) {
|
||||
&& ('config.prejoinConfig' in params || 'config.prejoinConfig.enabled' in params)
|
||||
&& config.prejoinConfig?.enabled === false) {
|
||||
logger.warn('Using prejoinConfig.enabled config URL overwrite implies starting without media.');
|
||||
config.disableInitialGUM = true;
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ import { AnyAction } from 'redux';
|
||||
|
||||
import { IStore } from '../../app/types';
|
||||
import { SET_DYNAMIC_BRANDING_DATA } from '../../dynamic-branding/actionTypes';
|
||||
import { setUserFilmstripWidth } from '../../filmstrip/actions.web';
|
||||
import { getFeatureFlag } from '../flags/functions';
|
||||
import MiddlewareRegistry from '../redux/MiddlewareRegistry';
|
||||
import { updateSettings } from '../settings/actions';
|
||||
@@ -80,29 +79,8 @@ function _setConfig({ dispatch, getState }: IStore, next: Function, action: AnyA
|
||||
}));
|
||||
}
|
||||
|
||||
const { initialWidth, stageFilmstripParticipants } = action.config.filmstrip || {};
|
||||
|
||||
if (stageFilmstripParticipants !== undefined) {
|
||||
dispatch(updateSettings({
|
||||
maxStageParticipants: stageFilmstripParticipants
|
||||
}));
|
||||
}
|
||||
|
||||
if (initialWidth) {
|
||||
dispatch(setUserFilmstripWidth(initialWidth));
|
||||
}
|
||||
|
||||
dispatch(updateConfig(config));
|
||||
|
||||
// FIXME On Web we rely on the global 'config' variable which gets altered
|
||||
// multiple times, before it makes it to the reducer. At some point it may
|
||||
// not be the global variable which is being modified anymore due to
|
||||
// different merge methods being used along the way. The global variable
|
||||
// must be synchronized with the final state resolved by the reducer.
|
||||
if (typeof window.config !== 'undefined') {
|
||||
window.config = state['features/base/config'];
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
1
react/features/base/config/middleware.native.ts
Normal file
1
react/features/base/config/middleware.native.ts
Normal file
@@ -0,0 +1 @@
|
||||
import './middleware.any';
|
||||
48
react/features/base/config/middleware.web.ts
Normal file
48
react/features/base/config/middleware.web.ts
Normal file
@@ -0,0 +1,48 @@
|
||||
import { setUserFilmstripWidth } from '../../filmstrip/actions.web';
|
||||
import MiddlewareRegistry from '../redux/MiddlewareRegistry';
|
||||
import { updateSettings } from '../settings/actions';
|
||||
|
||||
import { SET_CONFIG } from './actionTypes';
|
||||
import './middleware.any';
|
||||
|
||||
/**
|
||||
* The middleware of the feature {@code base/config}.
|
||||
*
|
||||
* @param {Store} store - The redux store.
|
||||
* @private
|
||||
* @returns {Function}
|
||||
*/
|
||||
MiddlewareRegistry.register(store => next => action => {
|
||||
const result = next(action);
|
||||
|
||||
switch (action.type) {
|
||||
case SET_CONFIG: {
|
||||
const { initialWidth, stageFilmstripParticipants } = action.config.filmstrip || {};
|
||||
const { dispatch, getState } = store;
|
||||
const state = getState();
|
||||
|
||||
if (stageFilmstripParticipants !== undefined) {
|
||||
dispatch(updateSettings({
|
||||
maxStageParticipants: stageFilmstripParticipants
|
||||
}));
|
||||
}
|
||||
|
||||
if (initialWidth) {
|
||||
dispatch(setUserFilmstripWidth(initialWidth));
|
||||
}
|
||||
|
||||
// FIXME On Web we rely on the global 'config' variable which gets altered
|
||||
// multiple times, before it makes it to the reducer. At some point it may
|
||||
// not be the global variable which is being modified anymore due to
|
||||
// different merge methods being used along the way. The global variable
|
||||
// must be synchronized with the final state resolved by the reducer.
|
||||
if (typeof window.config !== 'undefined') {
|
||||
window.config = state['features/base/config'];
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
});
|
||||
@@ -4,6 +4,7 @@ import { getCustomerDetails } from '../../jaas/actions.any';
|
||||
import { getJaasJWT, isVpaasMeeting } from '../../jaas/functions';
|
||||
import { navigateRoot } from '../../mobile/navigation/rootNavigationContainerRef';
|
||||
import { screen } from '../../mobile/navigation/routes';
|
||||
import { conferenceWillLeave } from '../conference/actions.native';
|
||||
import { setJWT } from '../jwt/actions';
|
||||
import { JitsiConnectionErrors } from '../lib-jitsi-meet';
|
||||
|
||||
@@ -58,5 +59,8 @@ export function connect(id?: string, password?: string) {
|
||||
* @returns {Function}
|
||||
*/
|
||||
export function hangup(_requestFeedback = false) {
|
||||
return (dispatch: IStore['dispatch']) => dispatch(appNavigate(undefined));
|
||||
return (dispatch: IStore['dispatch']) => {
|
||||
dispatch(conferenceWillLeave());
|
||||
dispatch(appNavigate(undefined));
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import React, { PureComponent, ReactNode } from 'react';
|
||||
import { SafeAreaView, ScrollView, View, ViewStyle } from 'react-native';
|
||||
import { ScrollView, View, ViewStyle } from 'react-native';
|
||||
import { SafeAreaView } from 'react-native-safe-area-context';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import { IStore } from '../../../../app/types';
|
||||
@@ -122,6 +123,7 @@ class BottomSheet extends PureComponent<Props> {
|
||||
style = { styles.sheetAreaCover } />
|
||||
{ renderHeader?.() }
|
||||
<SafeAreaView
|
||||
edges = { [ 'left', 'right' ] }
|
||||
style = { [
|
||||
styles.sheetItemContainer,
|
||||
renderHeader
|
||||
|
||||
@@ -8,13 +8,14 @@ import i18next from './i18next';
|
||||
*
|
||||
* @param {string} language - The language e.g. 'en', 'fr'.
|
||||
* @param {string} url - The url of the translation bundle.
|
||||
* @param {string} ns - The namespace of the translation bundle.
|
||||
* @returns {void}
|
||||
*/
|
||||
export async function changeLanguageBundle(language: string, url: string) {
|
||||
export async function changeLanguageBundle(language: string, url: string, ns = 'main') {
|
||||
const res = await fetch(url);
|
||||
const bundle = await res.json();
|
||||
|
||||
i18next.addResourceBundle(language, 'main', bundle, true, true);
|
||||
i18next.addResourceBundle(language, ns, bundle, true, true);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -58,6 +58,14 @@ export const DEFAULT_LANGUAGE = 'en';
|
||||
*/
|
||||
export const TRANSLATION_LANGUAGES_HEAD: Array<string> = [ DEFAULT_LANGUAGE ];
|
||||
|
||||
/**
|
||||
* The available/supported i18n namespaces.
|
||||
*
|
||||
* @public
|
||||
* @type {Array<string>}
|
||||
*/
|
||||
export const SUPPORTED_NS = [ 'main', 'languages', 'countries', 'translation-languages' ];
|
||||
|
||||
/**
|
||||
* The options to initialize i18next with.
|
||||
*
|
||||
@@ -81,7 +89,7 @@ const options: i18next.InitOptions = {
|
||||
escapeValue: false // not needed for react as it escapes by default
|
||||
},
|
||||
load: 'all',
|
||||
ns: [ 'main', 'languages', 'countries', 'translation-languages' ],
|
||||
ns: SUPPORTED_NS,
|
||||
react: {
|
||||
// re-render when a new resource bundle is added
|
||||
// @ts-expect-error. Fixed in i18next 19.6.1.
|
||||
|
||||
@@ -4,7 +4,7 @@ import MiddlewareRegistry from '../redux/MiddlewareRegistry';
|
||||
|
||||
import { I18NEXT_INITIALIZED, LANGUAGE_CHANGED } from './actionTypes';
|
||||
import { changeLanguageBundle } from './functions';
|
||||
import i18next from './i18next';
|
||||
import i18next, { SUPPORTED_NS } from './i18next';
|
||||
import logger from './logger';
|
||||
|
||||
/**
|
||||
@@ -19,9 +19,10 @@ MiddlewareRegistry.register(store => next => action => {
|
||||
case LANGUAGE_CHANGED:
|
||||
case SET_DYNAMIC_BRANDING_DATA: {
|
||||
const { language } = i18next;
|
||||
const { labels } = action.type === SET_DYNAMIC_BRANDING_DATA
|
||||
const data = action.type === SET_DYNAMIC_BRANDING_DATA
|
||||
? action.value
|
||||
: store.getState()['features/dynamic-branding'];
|
||||
const labels = data?.labels;
|
||||
|
||||
if (language && labels?.[language]) {
|
||||
changeLanguageBundle(language, labels[language])
|
||||
@@ -30,6 +31,17 @@ MiddlewareRegistry.register(store => next => action => {
|
||||
});
|
||||
}
|
||||
|
||||
SUPPORTED_NS.forEach(ns => {
|
||||
const nsLabels = data?.[`labels-${ns}`];
|
||||
|
||||
if (language && nsLabels?.[language]) {
|
||||
changeLanguageBundle(language, nsLabels[language], ns)
|
||||
.catch(err => {
|
||||
logger.log(`Error setting dynamic language bundle for ${ns}`, err);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Update transcription language, if applicable.
|
||||
if (action.type === SET_DYNAMIC_BRANDING_DATA) {
|
||||
const { defaultTranscriptionLanguage } = action.value;
|
||||
|
||||
1
react/features/base/icons/svg/AI.svg
Normal file
1
react/features/base/icons/svg/AI.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-sparkles-icon lucide-sparkles"><path d="M11.017 2.814a1 1 0 0 1 1.966 0l1.051 5.558a2 2 0 0 0 1.594 1.594l5.558 1.051a1 1 0 0 1 0 1.966l-5.558 1.051a2 2 0 0 0-1.594 1.594l-1.051 5.558a1 1 0 0 1-1.966 0l-1.051-5.558a2 2 0 0 0-1.594-1.594l-5.558-1.051a1 1 0 0 1 0-1.966l5.558-1.051a2 2 0 0 0 1.594-1.594z"/><path d="M20 2v4"/><path d="M22 4h-4"/><circle cx="4" cy="20" r="2"/></svg>
|
||||
|
After Width: | Height: | Size: 582 B |
@@ -1,3 +1,4 @@
|
||||
import { default as IconAI } from './AI.svg';
|
||||
import { default as IconRecordAccount } from './account-record.svg';
|
||||
import { default as IconAddUser } from './add-user.svg';
|
||||
import { default as IconArrowBack } from './arrow-back.svg';
|
||||
@@ -112,6 +113,7 @@ import { default as IconYahoo } from './yahoo.svg';
|
||||
*/
|
||||
export const DEFAULT_ICON: Record<string, any> = {
|
||||
IconAddUser,
|
||||
IconAI,
|
||||
IconArrowBack,
|
||||
IconArrowDown,
|
||||
IconArrowDownLarge,
|
||||
|
||||
@@ -4,6 +4,7 @@ import { DEFAULT_ICON } from './constants';
|
||||
|
||||
const {
|
||||
IconAddUser,
|
||||
IconAI,
|
||||
IconArrowBack,
|
||||
IconArrowDown,
|
||||
IconArrowDownLarge,
|
||||
@@ -123,6 +124,7 @@ const {
|
||||
|
||||
export {
|
||||
IconAddUser,
|
||||
IconAI,
|
||||
IconArrowBack,
|
||||
IconArrowDown,
|
||||
IconArrowDownLarge,
|
||||
|
||||
@@ -10,6 +10,10 @@ import { parseURLParams } from '../util/parseURLParams';
|
||||
import { JWT_VALIDATION_ERRORS, MEET_FEATURES } from './constants';
|
||||
import logger from './logger';
|
||||
|
||||
/**
|
||||
* Note that this is just client-side code and it intentionally does not verify the signature of the JWT.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Retrieves the JSON Web Token (JWT), if any, defined by a specific
|
||||
* {@link URL}.
|
||||
|
||||
@@ -56,9 +56,9 @@ const useStyles = makeStyles()(theme => {
|
||||
label: {
|
||||
...theme.typography.labelRegular,
|
||||
alignItems: 'center',
|
||||
background: theme.palette.ui04,
|
||||
background: theme.palette.labelBackground,
|
||||
borderRadius: '4px',
|
||||
color: theme.palette.text01,
|
||||
color: theme.palette.labelText,
|
||||
display: 'flex',
|
||||
margin: '0 2px',
|
||||
padding: '6px',
|
||||
@@ -72,11 +72,11 @@ const useStyles = makeStyles()(theme => {
|
||||
cursor: 'pointer'
|
||||
},
|
||||
[COLORS.white]: {
|
||||
background: theme.palette.ui09,
|
||||
color: theme.palette.text04,
|
||||
background: theme.palette.labelWhiteBackground,
|
||||
color: theme.palette.labelWhiteText,
|
||||
|
||||
'& svg': {
|
||||
fill: theme.palette.icon04
|
||||
fill: theme.palette.labelWhiteIcon
|
||||
}
|
||||
},
|
||||
[COLORS.green]: {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { IReduxState, IStore } from '../../app/types';
|
||||
import { getLocalParticipant } from '../participants/functions';
|
||||
import StateListenerRegistry from '../redux/StateListenerRegistry';
|
||||
|
||||
/**
|
||||
@@ -13,6 +14,13 @@ StateListenerRegistry.register(
|
||||
|
||||
if (muted !== previousMuted) {
|
||||
APP.API.notifyAudioMutedStatusChanged(muted);
|
||||
|
||||
// Also fire the participantMuted event for consistency
|
||||
const localParticipant = getLocalParticipant(store.getState());
|
||||
|
||||
if (localParticipant) {
|
||||
APP.API.notifyParticipantMuted(localParticipant.id, muted, 'audio');
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
@@ -17,7 +17,7 @@ interface IProps {
|
||||
/**
|
||||
* The children component(s) of the Modal, to be rendered.
|
||||
*/
|
||||
children: React.ReactNode;
|
||||
children?: React.ReactNode;
|
||||
|
||||
/**
|
||||
* Additional style to be appended to the KeyboardAvoidingView content container.
|
||||
@@ -63,7 +63,7 @@ const JitsiScreen = ({
|
||||
footerComponent,
|
||||
hasBottomTextInput = false,
|
||||
hasExtraHeaderHeight = false,
|
||||
safeAreaInsets = [ 'left', 'right' ],
|
||||
safeAreaInsets = [ 'bottom', 'left', 'right' ],
|
||||
style
|
||||
}: IProps) => {
|
||||
const renderContent = () => (
|
||||
@@ -78,8 +78,8 @@ const JitsiScreen = ({
|
||||
edges = { safeAreaInsets }
|
||||
style = { styles.safeArea }>
|
||||
{ children }
|
||||
{ footerComponent?.() }
|
||||
</SafeAreaView>
|
||||
{ footerComponent?.() }
|
||||
</JitsiKeyboardAvoidingView>
|
||||
);
|
||||
|
||||
|
||||
@@ -80,3 +80,8 @@ export const LOWER_HAND_AUDIO_LEVEL = 0.2;
|
||||
* Icon URL for the whiteboard participant.
|
||||
*/
|
||||
export const WHITEBOARD_PARTICIPANT_ICON = IconWhiteboard;
|
||||
|
||||
/**
|
||||
* The ID used for non-participant (system) messages coming from a transcriber.
|
||||
*/
|
||||
export const TRANSCRIBER_ID = 'transcriber';
|
||||
|
||||
@@ -818,7 +818,7 @@ export const addPeopleFeatureControl = (stateful: IStateful) => {
|
||||
* @param {Function} dispatch - The Redux dispatch function.
|
||||
* @returns {Function}
|
||||
*/
|
||||
export const setShareDialogVisiblity = (addPeopleFeatureEnabled: boolean, dispatch: IStore['dispatch']) => {
|
||||
export const setShareDialogVisiblity = (addPeopleFeatureEnabled: boolean | undefined, dispatch: IStore['dispatch']) => {
|
||||
if (addPeopleFeatureEnabled) {
|
||||
dispatch(toggleShareDialog(false));
|
||||
} else {
|
||||
|
||||
@@ -606,13 +606,21 @@ function _e2eeUpdated({ getState, dispatch }: IStore, conference: IJitsiConferen
|
||||
function _localParticipantJoined({ getState, dispatch }: IStore, next: Function, action: AnyAction) {
|
||||
const result = next(action);
|
||||
|
||||
const settings = getState()['features/base/settings'];
|
||||
const state = getState();
|
||||
const settings = state['features/base/settings'];
|
||||
const jwtUser = state['features/base/jwt']?.user;
|
||||
|
||||
const userContext = jwtUser ? {
|
||||
id: jwtUser.id,
|
||||
name: jwtUser.name
|
||||
} : undefined;
|
||||
|
||||
dispatch(localParticipantJoined({
|
||||
avatarURL: settings.avatarURL,
|
||||
email: settings.email,
|
||||
name: settings.displayName,
|
||||
id: ''
|
||||
id: '',
|
||||
userContext
|
||||
}));
|
||||
|
||||
return result;
|
||||
|
||||
@@ -22,17 +22,35 @@ export function preloadImage(
|
||||
return new Promise((resolve, reject) => {
|
||||
const image = document.createElement('img');
|
||||
|
||||
// Cleanup function to release resources and prevent memory leaks
|
||||
const cleanup = () => {
|
||||
// Clear event handlers to break circular references
|
||||
image.onload = null;
|
||||
image.onerror = null;
|
||||
|
||||
// Clear src to stop any pending load and allow GC
|
||||
image.src = '';
|
||||
};
|
||||
|
||||
if (useCORS) {
|
||||
image.setAttribute('crossOrigin', '');
|
||||
}
|
||||
image.onload = () => resolve({
|
||||
src,
|
||||
isUsingCORS: useCORS
|
||||
});
|
||||
|
||||
image.onload = () => {
|
||||
cleanup();
|
||||
resolve({
|
||||
src,
|
||||
isUsingCORS: useCORS
|
||||
});
|
||||
};
|
||||
|
||||
image.onerror = error => {
|
||||
cleanup();
|
||||
|
||||
if (tryOnce) {
|
||||
reject(error);
|
||||
} else {
|
||||
// Retry with different CORS mode
|
||||
preloadImage(src, !useCORS, true)
|
||||
.then(resolve)
|
||||
.catch(reject);
|
||||
|
||||
@@ -627,7 +627,8 @@ function _participantJoined({ participant }: { participant: IParticipant; }) {
|
||||
pinned,
|
||||
presence,
|
||||
role,
|
||||
sources
|
||||
sources,
|
||||
userContext
|
||||
} = participant;
|
||||
let { conference, id } = participant;
|
||||
|
||||
@@ -659,7 +660,8 @@ function _participantJoined({ participant }: { participant: IParticipant; }) {
|
||||
pinned: pinned || false,
|
||||
presence,
|
||||
role: role || PARTICIPANT_ROLE.NONE,
|
||||
sources
|
||||
sources,
|
||||
userContext
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -41,6 +41,12 @@ export interface IParticipant {
|
||||
role?: string;
|
||||
sources?: Map<string, Map<string, ISourceInfo>>;
|
||||
supportsRemoteControl?: boolean;
|
||||
userContext?: IUserContext;
|
||||
}
|
||||
|
||||
export interface IUserContext {
|
||||
id?: string;
|
||||
name?: string;
|
||||
}
|
||||
|
||||
export interface ILocalParticipant extends IParticipant {
|
||||
|
||||
@@ -84,7 +84,7 @@ const useStyles = makeStyles()(theme => {
|
||||
...theme.typography.bodyLongBold,
|
||||
borderRadius: theme.shape.borderRadius,
|
||||
boxSizing: 'border-box',
|
||||
color: theme.palette.text01,
|
||||
color: theme.palette.actionButtonText,
|
||||
cursor: 'pointer',
|
||||
display: 'inline-block',
|
||||
marginBottom: '16px',
|
||||
@@ -95,20 +95,20 @@ const useStyles = makeStyles()(theme => {
|
||||
border: 0,
|
||||
|
||||
'&.primary': {
|
||||
background: theme.palette.action01,
|
||||
color: theme.palette.text01,
|
||||
background: theme.palette.prejoinActionButtonPrimary,
|
||||
color: theme.palette.prejoinActionButtonPrimaryText,
|
||||
|
||||
'&:hover': {
|
||||
backgroundColor: theme.palette.action01Hover
|
||||
backgroundColor: theme.palette.prejoinActionButtonPrimaryHover
|
||||
}
|
||||
},
|
||||
|
||||
'&.secondary': {
|
||||
background: theme.palette.action02,
|
||||
color: theme.palette.text04,
|
||||
background: theme.palette.prejoinActionButtonSecondary,
|
||||
color: theme.palette.prejoinActionButtonSecondaryText,
|
||||
|
||||
'&:hover': {
|
||||
backgroundColor: theme.palette.action02Hover
|
||||
backgroundColor: theme.palette.prejoinActionButtonSecondaryHover
|
||||
}
|
||||
},
|
||||
|
||||
@@ -120,7 +120,7 @@ const useStyles = makeStyles()(theme => {
|
||||
},
|
||||
|
||||
'&.disabled': {
|
||||
background: theme.palette.disabled01,
|
||||
background: theme.palette.prejoinActionButtonDisabled,
|
||||
border: '1px solid #5E6D7A',
|
||||
color: '#AFB6BC',
|
||||
cursor: 'initial',
|
||||
|
||||
@@ -109,7 +109,7 @@ const useStyles = makeStyles()(theme => {
|
||||
position: 'absolute',
|
||||
inset: '0 0 0 0',
|
||||
display: 'flex',
|
||||
backgroundColor: theme.palette.ui01,
|
||||
backgroundColor: theme.palette.preMeetingBackground,
|
||||
zIndex: 252,
|
||||
|
||||
'@media (max-width: 720px)': {
|
||||
@@ -163,7 +163,7 @@ const useStyles = makeStyles()(theme => {
|
||||
},
|
||||
title: {
|
||||
...theme.typography.heading4,
|
||||
color: `${theme.palette.text01}!important`,
|
||||
color: theme.palette.prejoinTitleText,
|
||||
marginBottom: theme.spacing(3),
|
||||
textAlign: 'center',
|
||||
|
||||
@@ -179,7 +179,7 @@ const useStyles = makeStyles()(theme => {
|
||||
|
||||
roomName: {
|
||||
...theme.typography.heading5,
|
||||
color: theme.palette.text01,
|
||||
color: theme.palette.prejoinRoomNameText,
|
||||
display: 'inline-block',
|
||||
overflow: 'hidden',
|
||||
textOverflow: 'ellipsis',
|
||||
|
||||
@@ -6,7 +6,7 @@ const useStyles = makeStyles()(theme => {
|
||||
return {
|
||||
warning: {
|
||||
bottom: 0,
|
||||
color: theme.palette.text03,
|
||||
color: theme.palette.prejoinRecordingWarningText,
|
||||
display: 'flex',
|
||||
justifyContent: 'center',
|
||||
...theme.typography.bodyShortRegular,
|
||||
|
||||
@@ -11,8 +11,8 @@ import { setUnsafeRoomConsent } from '../../actions.web';
|
||||
const useStyles = makeStyles()(theme => {
|
||||
return {
|
||||
warning: {
|
||||
backgroundColor: theme.palette.warning01,
|
||||
color: theme.palette.text04,
|
||||
backgroundColor: theme.palette.prejoinWarningBackground,
|
||||
color: theme.palette.prejoinWarningText,
|
||||
...theme.typography.bodyShortRegular,
|
||||
padding: theme.spacing(3),
|
||||
borderRadius: theme.shape.borderRadius,
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import React, { Component } from 'react';
|
||||
import {
|
||||
SectionList as ReactNativeSectionList,
|
||||
SafeAreaView,
|
||||
SectionListRenderItemInfo,
|
||||
ViewStyle
|
||||
} from 'react-native';
|
||||
import { SafeAreaView } from 'react-native-safe-area-context';
|
||||
|
||||
import { Item, Section } from '../../types';
|
||||
|
||||
@@ -76,6 +76,7 @@ export default class SectionList extends Component<IProps> {
|
||||
override render() {
|
||||
return (
|
||||
<SafeAreaView
|
||||
edges = { [ 'left', 'right' ] }
|
||||
style = { styles.container as ViewStyle } >
|
||||
<ReactNativeSectionList
|
||||
ListEmptyComponent = { this.props.ListEmptyComponent }
|
||||
|
||||
@@ -9,11 +9,11 @@ import { getSupportUrl } from '../../functions';
|
||||
const useStyles = makeStyles()(theme => {
|
||||
return {
|
||||
dialog: {
|
||||
backgroundColor: theme.palette.ui01,
|
||||
border: `1px solid ${theme.palette.ui04}`,
|
||||
backgroundColor: theme.palette.dialogBackground,
|
||||
border: `1px solid ${theme.palette.inlineDialogBorder}`,
|
||||
borderRadius: `${Number(theme.shape.borderRadius)}px`,
|
||||
boxShadow: '0px 1px 2px rgba(41, 41, 41, 0.25)',
|
||||
color: theme.palette.text01,
|
||||
color: theme.palette.dialogText,
|
||||
...theme.typography.bodyShortRegular,
|
||||
padding: `${theme.spacing(3)} 10`,
|
||||
'& .retry-button': {
|
||||
|
||||
@@ -2,6 +2,7 @@ import { batch } from 'react-redux';
|
||||
|
||||
import { IStore } from '../../app/types';
|
||||
import { CHAT_SIZE } from '../../chat/constants';
|
||||
import { getCustomPanelWidth } from '../../custom-panel/functions';
|
||||
import { getParticipantsPaneWidth } from '../../participants-pane/functions';
|
||||
|
||||
import {
|
||||
@@ -24,6 +25,7 @@ import { ASPECT_RATIO_NARROW, ASPECT_RATIO_WIDE } from './constants';
|
||||
* determine whether and how to render it.
|
||||
*/
|
||||
const REDUCED_UI_THRESHOLD = 300;
|
||||
const WEB_REDUCED_UI_THRESHOLD = 320;
|
||||
|
||||
/**
|
||||
* Indicates a resize of the window.
|
||||
@@ -42,6 +44,7 @@ export function clientResized(clientWidth: number, clientHeight: number) {
|
||||
|
||||
if (navigator.product !== 'ReactNative') {
|
||||
const state = getState();
|
||||
const { reducedUIEnabled = true } = state['features/base/config'];
|
||||
const { isOpen: isChatOpen, width } = state['features/chat'];
|
||||
|
||||
if (isChatOpen) {
|
||||
@@ -49,6 +52,9 @@ export function clientResized(clientWidth: number, clientHeight: number) {
|
||||
}
|
||||
|
||||
availableWidth -= getParticipantsPaneWidth(state);
|
||||
availableWidth -= getCustomPanelWidth(state);
|
||||
|
||||
reducedUIEnabled && dispatch(setReducedUI(availableWidth, clientHeight));
|
||||
}
|
||||
|
||||
batch(() => {
|
||||
@@ -106,7 +112,10 @@ export function setAspectRatio(width: number, height: number) {
|
||||
*/
|
||||
export function setReducedUI(width: number, height: number) {
|
||||
return (dispatch: IStore['dispatch'], getState: IStore['getState']) => {
|
||||
const reducedUI = Math.min(width, height) < REDUCED_UI_THRESHOLD;
|
||||
const threshold = navigator.product === 'ReactNative'
|
||||
? REDUCED_UI_THRESHOLD
|
||||
: WEB_REDUCED_UI_THRESHOLD;
|
||||
const reducedUI = Math.max(width, height) < threshold;
|
||||
|
||||
if (reducedUI !== getState()['features/base/responsive-ui'].reducedUI) {
|
||||
return dispatch({
|
||||
|
||||
@@ -22,11 +22,11 @@ interface IProps {
|
||||
const useStyles = makeStyles()(theme => {
|
||||
return {
|
||||
container: {
|
||||
backgroundColor: theme.palette.uiBackground,
|
||||
backgroundColor: theme.palette.tooltipBackground,
|
||||
borderRadius: '3px',
|
||||
padding: theme.spacing(2),
|
||||
...theme.typography.labelRegular,
|
||||
color: theme.palette.text01,
|
||||
color: theme.palette.tooltipText,
|
||||
position: 'relative',
|
||||
|
||||
'&.mounting-animation': {
|
||||
|
||||
@@ -29,6 +29,7 @@ import {
|
||||
TRACK_UPDATED,
|
||||
TRACK_WILL_CREATE
|
||||
} from './actionTypes';
|
||||
import { toggleScreensharing } from './actions';
|
||||
import {
|
||||
createLocalTracksF,
|
||||
getCameraFacingMode,
|
||||
@@ -385,8 +386,22 @@ export function trackAdded(track: any) {
|
||||
const mediaType = track.getVideoType() === VIDEO_TYPE.DESKTOP
|
||||
? MEDIA_TYPE.SCREENSHARE
|
||||
: track.getType();
|
||||
|
||||
let isReceivingData, noDataFromSourceNotificationInfo, participantId;
|
||||
|
||||
// Make screen share toggle off listen to MediaStreamTrack "ended" event
|
||||
// when it's terminated via Android status bar chip.
|
||||
if (navigator.product === 'ReactNative') {
|
||||
const mediaStreamTrack = track?.getTrack?.();
|
||||
|
||||
if (mediaType === MEDIA_TYPE.SCREENSHARE) {
|
||||
const onEnded = () => dispatch(toggleScreensharing(false));
|
||||
|
||||
mediaStreamTrack.addEventListener('ended', onEnded);
|
||||
track._onEnded = onEnded;
|
||||
}
|
||||
}
|
||||
|
||||
if (local) {
|
||||
// Reset the no data from src notification state when we change the track, as it's context is set
|
||||
// on a per device basis.
|
||||
@@ -568,6 +583,16 @@ export function trackRemoved(track: any): {
|
||||
track.removeAllListeners(JitsiTrackEvents.TRACK_VIDEOTYPE_CHANGED);
|
||||
track.removeAllListeners(JitsiTrackEvents.NO_DATA_FROM_SOURCE);
|
||||
|
||||
// Remove MediaStreamTrack "ended" event.
|
||||
if (navigator.product === 'ReactNative') {
|
||||
const mediaStreamTrack = track?.getTrack?.();
|
||||
|
||||
if (track._onEnded) {
|
||||
mediaStreamTrack.removeEventListener('ended', track._onEnded);
|
||||
delete track._onEnded;
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
type: TRACK_REMOVED,
|
||||
track: {
|
||||
|
||||
@@ -33,7 +33,6 @@ import {
|
||||
isUserInteractionRequiredForUnmute,
|
||||
setTrackMuted
|
||||
} from './functions';
|
||||
import './subscriber';
|
||||
|
||||
/**
|
||||
* Middleware that captures LIB_DID_DISPOSE and LIB_DID_INIT actions and,
|
||||
|
||||
@@ -38,6 +38,7 @@ import {
|
||||
import { ITrack, ITrackOptions } from './types';
|
||||
|
||||
import './middleware.any';
|
||||
import './subscriber.web';
|
||||
|
||||
/**
|
||||
* Middleware that captures LIB_DID_DISPOSE and LIB_DID_INIT actions and,
|
||||
@@ -50,7 +51,7 @@ import './middleware.any';
|
||||
MiddlewareRegistry.register(store => next => action => {
|
||||
switch (action.type) {
|
||||
case TRACK_ADDED: {
|
||||
const { local } = action.track;
|
||||
const { local, jitsiTrack } = action.track;
|
||||
|
||||
// The devices list needs to be refreshed when no initial video permissions
|
||||
// were granted and a local video track is added by umuting the video.
|
||||
@@ -64,6 +65,16 @@ MiddlewareRegistry.register(store => next => action => {
|
||||
|
||||
if (participantId) {
|
||||
logTracksForParticipant(store.getState()['features/base/tracks'], participantId, 'Track added');
|
||||
|
||||
// Fire participantMuted event for initial state of remote tracks
|
||||
if (typeof action.track?.muted !== 'undefined' && jitsiTrack) {
|
||||
const isVideoTrack = jitsiTrack.getType() !== MEDIA_TYPE.AUDIO;
|
||||
const mediaType = isVideoTrack
|
||||
? (jitsiTrack.getVideoType() === VIDEO_TYPE.DESKTOP ? 'desktop' : 'video')
|
||||
: 'audio';
|
||||
|
||||
APP.API.notifyParticipantMuted(participantId, action.track.muted, mediaType);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
@@ -118,6 +129,16 @@ MiddlewareRegistry.register(store => next => action => {
|
||||
// TODO Remove the following calls to APP.UI once components interested
|
||||
// in track mute changes are moved into React and/or redux.
|
||||
|
||||
const { jitsiTrack } = action.track;
|
||||
const participantID = jitsiTrack.getParticipantId();
|
||||
const isVideoTrack = jitsiTrack.type !== MEDIA_TYPE.AUDIO;
|
||||
const local = jitsiTrack.isLocal();
|
||||
|
||||
// Get old muted state BEFORE updating
|
||||
const tracks = store.getState()['features/base/tracks'];
|
||||
const oldTrack = tracks.find((t: ITrack) => t.jitsiTrack === jitsiTrack);
|
||||
const oldMutedState = oldTrack?.muted;
|
||||
|
||||
const result = next(action);
|
||||
const state = store.getState();
|
||||
|
||||
@@ -125,11 +146,6 @@ MiddlewareRegistry.register(store => next => action => {
|
||||
return result;
|
||||
}
|
||||
|
||||
const { jitsiTrack } = action.track;
|
||||
const participantID = jitsiTrack.getParticipantId();
|
||||
const isVideoTrack = jitsiTrack.type !== MEDIA_TYPE.AUDIO;
|
||||
const local = jitsiTrack.isLocal();
|
||||
|
||||
if (isVideoTrack) {
|
||||
if (local && !(jitsiTrack.getVideoType() === VIDEO_TYPE.DESKTOP)) {
|
||||
APP.conference.setVideoMuteStatus();
|
||||
@@ -142,6 +158,15 @@ MiddlewareRegistry.register(store => next => action => {
|
||||
|
||||
if (typeof action.track?.muted !== 'undefined' && participantID && !local) {
|
||||
logTracksForParticipant(store.getState()['features/base/tracks'], participantID, 'Track updated');
|
||||
|
||||
// Fire participantMuted event only if muted state actually changed
|
||||
if (oldMutedState !== action.track.muted) {
|
||||
const mediaType = isVideoTrack
|
||||
? (jitsiTrack.getVideoType() === VIDEO_TYPE.DESKTOP ? 'desktop' : 'video')
|
||||
: 'audio';
|
||||
|
||||
APP.API.notifyParticipantMuted(participantID, action.track.muted, mediaType);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
import { isEqual, sortBy } from 'lodash-es';
|
||||
|
||||
import { MEDIA_TYPE } from '../media/constants';
|
||||
import { getScreenshareParticipantIds } from '../participants/functions';
|
||||
import StateListenerRegistry from '../redux/StateListenerRegistry';
|
||||
|
||||
import { isLocalTrackMuted } from './functions';
|
||||
|
||||
/**
|
||||
* Notifies when the list of currently sharing participants changes.
|
||||
*/
|
||||
StateListenerRegistry.register(
|
||||
/* selector */ state => getScreenshareParticipantIds(state),
|
||||
/* listener */ (participantIDs, store, previousParticipantIDs) => {
|
||||
if (typeof APP !== 'object') {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isEqual(sortBy(participantIDs), sortBy(previousParticipantIDs))) {
|
||||
APP.API.notifySharingParticipantsChanged(participantIDs);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
/**
|
||||
* Notifies when the local video mute state changes.
|
||||
*/
|
||||
StateListenerRegistry.register(
|
||||
/* selector */ state => isLocalTrackMuted(state['features/base/tracks'], MEDIA_TYPE.VIDEO),
|
||||
/* listener */ (muted, store, previousMuted) => {
|
||||
if (typeof APP !== 'object') {
|
||||
return;
|
||||
}
|
||||
|
||||
if (muted !== previousMuted) {
|
||||
APP.API.notifyVideoMutedStatusChanged(muted);
|
||||
}
|
||||
}
|
||||
);
|
||||
59
react/features/base/tracks/subscriber.web.ts
Normal file
59
react/features/base/tracks/subscriber.web.ts
Normal file
@@ -0,0 +1,59 @@
|
||||
import { isEqual, sortBy } from 'lodash-es';
|
||||
|
||||
// @ts-expect-error
|
||||
import VideoLayout from '../../../../modules/UI/videolayout/VideoLayout';
|
||||
import { getAutoPinSetting } from '../../video-layout/functions.any';
|
||||
import { MEDIA_TYPE } from '../media/constants';
|
||||
import { getLocalParticipant, getScreenshareParticipantIds } from '../participants/functions';
|
||||
import StateListenerRegistry from '../redux/StateListenerRegistry';
|
||||
|
||||
import { isLocalTrackMuted } from './functions';
|
||||
|
||||
/**
|
||||
* Notifies when the list of currently sharing participants changes.
|
||||
*/
|
||||
StateListenerRegistry.register(
|
||||
/* selector */ state => getScreenshareParticipantIds(state),
|
||||
/* listener */ (participantIDs, store, previousParticipantIDs) => {
|
||||
if (getAutoPinSetting() && participantIDs !== previousParticipantIDs) {
|
||||
const { participantId } = store.getState()['features/large-video'];
|
||||
|
||||
// Check if any new screenshare participants were added
|
||||
const newParticipants = participantIDs.filter((id: string) => !previousParticipantIDs.includes(id));
|
||||
|
||||
// If the current large video participant is a new screensharer, update the display. This is needed when
|
||||
// the track is created much later after the action for auto-pinning is dispatched. This usually happens in
|
||||
// very large meetings if the screenshare was already ongoing when the participant joined. The track is
|
||||
// signaled only after the receiver constraints with SS source id is processed by the bridge but the
|
||||
// auto-pinning action is dispatched when the participant tile is created as soon as the presence is
|
||||
// received.
|
||||
if (participantId && newParticipants.includes(participantId)) {
|
||||
VideoLayout.updateLargeVideo(participantId, true);
|
||||
}
|
||||
}
|
||||
|
||||
if (!isEqual(sortBy(participantIDs), sortBy(previousParticipantIDs))) {
|
||||
APP.API.notifySharingParticipantsChanged(participantIDs);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
/**
|
||||
* Notifies when the local video mute state changes.
|
||||
*/
|
||||
StateListenerRegistry.register(
|
||||
/* selector */ state => isLocalTrackMuted(state['features/base/tracks'], MEDIA_TYPE.VIDEO),
|
||||
/* listener */ (muted, store, previousMuted) => {
|
||||
if (muted !== previousMuted) {
|
||||
APP.API.notifyVideoMutedStatusChanged(muted);
|
||||
|
||||
// Also fire the participantMuted event for consistency
|
||||
const localParticipant = getLocalParticipant(store.getState());
|
||||
|
||||
if (localParticipant) {
|
||||
APP.API.notifyParticipantMuted(localParticipant.id, muted, 'video');
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
@@ -1,3 +1,4 @@
|
||||
/* eslint-disable @stylistic/no-multi-spaces */
|
||||
// Mapping between the token used and the color
|
||||
export const colorMap = {
|
||||
// ----- Surfaces -----
|
||||
@@ -7,7 +8,7 @@ export const colorMap = {
|
||||
// - JitsiMeetView.java
|
||||
uiBackground: 'surface01',
|
||||
|
||||
// Container backgrounds
|
||||
// Container backgrounds (legacy tokens)
|
||||
ui01: 'surface02',
|
||||
ui02: 'surface03',
|
||||
ui03: 'ui02',
|
||||
@@ -47,6 +48,426 @@ export const colorMap = {
|
||||
// Focus
|
||||
focus01: 'focus01',
|
||||
|
||||
// ----- Semantic Tokens (component-based, backwards compatible) -----
|
||||
|
||||
// Dialog/Modal Components
|
||||
dialogBackground: 'surface02', // Main dialog background (same as ui01)
|
||||
dialogOverlay: 'surface03', // Overlay/backdrop (same as ui02)
|
||||
dialogBorder: 'ui02', // Dialog borders
|
||||
dialogText: 'textColor01', // Primary dialog text (same as text01)
|
||||
dialogSecondaryText: 'textColor02', // Secondary dialog text (same as text02)
|
||||
|
||||
// Large Video
|
||||
largeVideoBackground: 'surface03', // Main video area background (same as ui02)
|
||||
largeVideoPlaceholder: 'surface03', // Placeholder when no video (same as ui02)
|
||||
|
||||
// Filmstrip
|
||||
filmstripBackground: 'surface03', // Filmstrip container background (same as ui02)
|
||||
filmstripBackgroundHover: 'uiBackground', // Filmstrip background on hover/focus
|
||||
filmstripDragHandle: 'icon02', // Filmstrip resize drag handle color
|
||||
filmstripDragHandleHover: 'icon01', // Filmstrip resize drag handle hover color
|
||||
thumbnailBackground: 'surface03', // Individual thumbnail background (same as ui02)
|
||||
thumbnailBorder: 'ui03', // Thumbnail borders (same as ui03)
|
||||
thumbnailHover: 'hover05', // Thumbnail hover state (same as action03Hover)
|
||||
thumbnailTintBackground: 'uiBackground', // Thumbnail tint overlay background
|
||||
thumbnailRaisedHandIcon: 'uiBackground', // Thumbnail raised hand indicator icon
|
||||
thumbnailVideoBackground: 'uiBackground', // Thumbnail video/placeholder background
|
||||
|
||||
// Chat
|
||||
chatBackground: 'surface02', // Chat panel background (same as ui01)
|
||||
chatBackdrop: 'ui04', // Chat screen background (same as ui10)
|
||||
chatEmptyText: 'ui03', // Empty component text
|
||||
chatInputBackground: 'surface03', // Chat input field background (same as ui02)
|
||||
chatInputBorder: 'surface03', // Chat input border (same as ui02)
|
||||
chatLink: 'action01', // Chat link color (same as link01)
|
||||
chatLobbyMessageBubble: 'support06', // Lobby message bubble background
|
||||
chatLobbyMessageNotice: 'surface01', // Lobby message notice text
|
||||
chatLobbyRecipientContainer: 'support06', // Lobby recipient container background
|
||||
chatMessageLocal: 'surface05', // Local participant message bubble (same as ui04)
|
||||
chatMessagePrivate: 'support05', // Private/DM message bubble
|
||||
chatMessageRemote: 'surface03', // Remote participant message bubble (same as ui02)
|
||||
chatMessageText: 'textColor01', // Chat message text
|
||||
chatPrivateNotice: 'textColor02', // Private message notice text
|
||||
chatRecipientCancelIcon: 'icon01', // Recipient cancel icon color
|
||||
chatRecipientContainer: 'support05', // Recipient container background
|
||||
chatRecipientText: 'textColor01', // Recipient text color
|
||||
chatReplyIcon: 'icon01', // Reply icon color
|
||||
chatSenderName: 'textColor02', // Sender display name color
|
||||
chatTimestamp: 'ui03', // Chat timestamp text
|
||||
|
||||
// Toolbox/Toolbar
|
||||
toolboxBackground: 'surface02', // Main toolbox background
|
||||
drawerBackground: 'surface02', // Drawer/side panel background
|
||||
toolboxIconHover: 'surface05', // Toolbox icon hover background
|
||||
toolboxIconActive: 'ui02', // Toolbox icon active/pressed background
|
||||
toolboxIconToggled: 'ui02', // Toolbox icon toggled background
|
||||
toolbarButton: 'action01', // Toolbar button color
|
||||
toolbarButtonHover: 'hover01', // Toolbar button hover (same as action01Hover)
|
||||
toolbarButtonActive: 'active01', // Toolbar button active/pressed state
|
||||
toolbarIcon: 'icon01', // Toolbar icon color
|
||||
toolbarIconHover: 'icon01', // Toolbar icon hover state
|
||||
toolbarIconActive: 'action01', // Toolbar icon active/toggled state
|
||||
|
||||
// Overflow Menu (More Actions)
|
||||
overflowMenuBackground: 'surface02', // Overflow menu background
|
||||
overflowMenuBorder: 'surface05', // Overflow menu border
|
||||
overflowMenuItemText: 'text01', // Overflow menu item text
|
||||
overflowMenuItemIcon: 'text01', // Overflow menu item icon
|
||||
overflowMenuItemHover: 'surface03', // Overflow menu item hover background
|
||||
overflowMenuItemDisabled: 'text03', // Overflow menu item disabled text/icon
|
||||
overflowMenuSeparator: 'ui03', // Overflow menu group separator
|
||||
|
||||
// Participants Pane
|
||||
participantsPaneBackground: 'surface02', // Participants list background
|
||||
participantItemBackground: 'surface03', // Individual participant item background
|
||||
participantItemHover: 'hover05', // Participant item hover
|
||||
participantItemBorder: 'ui02', // Participant item border
|
||||
participantCounterBadge: 'ui02', // Participant counter badge background
|
||||
participantCounterText: 'text01', // Participant counter text
|
||||
participantModeratorLabel: 'text03', // Moderator label text
|
||||
participantSectionText: 'text02', // Section header/subtitle text
|
||||
participantActionButton: 'action02', // Action button background
|
||||
participantLinkText: 'link01', // Link text color
|
||||
participantWarningText: 'warning02', // Warning text color
|
||||
participantRaisedHandBadge: 'warning02', // Raised hand indicator background
|
||||
participantRaisedHandIcon: 'icon04', // Raised hand icon color
|
||||
|
||||
// Lobby
|
||||
lobbyBackground: 'surface02', // Lobby screen background (same as ui01)
|
||||
lobbyPreviewBackground: 'surface03', // Video preview background (same as ui02)
|
||||
|
||||
// Speaker Stats
|
||||
speakerStatsBackground: 'surface02', // Speaker stats panel background
|
||||
speakerStatsRowBackground: 'ui02', // Individual stat row background
|
||||
speakerStatsRowAlternate: 'ui03', // Alternate row background
|
||||
speakerStatsBorder: 'surface03', // Speaker stats borders
|
||||
speakerStatsHeaderBackground: 'ui09', // Header background
|
||||
speakerStatsSearchBackground: 'field01', // Search input background
|
||||
speakerStatsSearchBorder: 'ui05', // Search input border
|
||||
speakerStatsSearchText: 'text01', // Search input text
|
||||
speakerStatsSearchPlaceholder: 'text03', // Search placeholder
|
||||
speakerStatsSearchIcon: 'icon03', // Search icon color
|
||||
speakerStatsLabelText: 'text03', // Label text color
|
||||
speakerStatsSuccessBar: 'success02', // Success/progress bar
|
||||
speakerStatsAvatarLeft: 'surface05', // Avatar background for participants who left
|
||||
|
||||
// Pre-meeting/Prejoin
|
||||
preMeetingBackground: 'surface02', // Pre-meeting screen container background
|
||||
preMeetingPreview: 'ui01', // Video preview in pre-meeting
|
||||
prejoinDialogBackground: 'uiBackground', // Prejoin dialog background
|
||||
prejoinDialogDelimiter: 'ui03', // Prejoin dialog delimiter line
|
||||
prejoinDialogDelimiterText: 'text01', // Prejoin dialog delimiter text
|
||||
prejoinTitleText: 'text01', // Prejoin title text color
|
||||
prejoinRoomNameText: 'text01', // Prejoin room name text color
|
||||
prejoinWarningBackground: 'warning01', // Warning banner background
|
||||
prejoinWarningText: 'text04', // Warning banner text
|
||||
prejoinRecordingWarningText: 'text03', // Recording warning text
|
||||
prejoinActionButtonPrimary: 'action01', // Primary action button
|
||||
prejoinActionButtonPrimaryHover: 'action01Hover', // Primary button hover
|
||||
prejoinActionButtonPrimaryText: 'text01', // Primary button text
|
||||
prejoinActionButtonSecondary: 'action02', // Secondary action button
|
||||
prejoinActionButtonSecondaryHover: 'action02Hover', // Secondary button hover
|
||||
prejoinActionButtonSecondaryText: 'text04', // Secondary button text
|
||||
prejoinActionButtonDanger: 'actionDanger', // Danger button (leave)
|
||||
prejoinActionButtonDisabled: 'disabled01', // Disabled button
|
||||
prejoinCountryPickerBackground: 'ui01', // Country picker background
|
||||
prejoinCountryPickerBorder: 'ui03', // Country picker border
|
||||
prejoinCountryPickerText: 'text01', // Country picker text
|
||||
prejoinCountryRowBackground: 'action03', // Country row background
|
||||
prejoinCountryRowHover: 'action03Hover', // Country row hover
|
||||
prejoinDeviceStatusOk: 'success01', // Device status OK background
|
||||
prejoinDeviceStatusWarning: 'warning01', // Device status warning background
|
||||
prejoinDeviceStatusText: 'uiBackground', // Device status text
|
||||
|
||||
// Notifications
|
||||
notificationBackground: 'ui04', // Notification background
|
||||
notificationNormalIcon: 'action01', // Normal notification icon
|
||||
notificationError: 'iconError', // Error notification icon
|
||||
notificationSuccess: 'success01', // Success notification icon
|
||||
notificationWarning: 'warning01', // Warning notification icon
|
||||
notificationText: 'text04', // Notification text
|
||||
notificationActionText: 'action01', // Notification action text
|
||||
notificationErrorText: 'textError', // Error notification text
|
||||
notificationActionFocus: 'action01', // Notification action focus outline
|
||||
notificationCloseIcon: 'icon04', // Notification close icon
|
||||
|
||||
// Forms/Inputs
|
||||
inputBackground: 'field01', // Input field background
|
||||
inputBorder: 'surface03', // Input field border (same as ui02)
|
||||
inputText: 'textColor01', // Input field text (same as text01)
|
||||
inputPlaceholder: 'textColor02', // Input placeholder text (same as text02)
|
||||
|
||||
// Breakout Rooms
|
||||
breakoutRoomBackground: 'ui01', // Breakout rooms panel background
|
||||
breakoutRoomItemBackground: 'surface03', // Individual breakout room background
|
||||
breakoutRoomArrowBackground: 'ui02', // Breakout room arrow container background
|
||||
|
||||
// Settings
|
||||
settingsBackground: 'ui01', // Settings dialog background
|
||||
settingsSectionBackground: 'ui02', // Settings section background
|
||||
settingsTabText: 'text01', // Settings tab text
|
||||
settingsShortcutKey: 'surface05', // Keyboard shortcut key background
|
||||
settingsVideoPreviewBorder: 'action01Hover', // Video preview border (selected)
|
||||
settingsErrorIcon: 'iconError', // Error icon color
|
||||
|
||||
// Visitors
|
||||
visitorsCountBadge: 'warning02', // Visitors count badge background
|
||||
visitorsCountText: 'uiBackground', // Visitors count badge text
|
||||
visitorsCountIcon: 'icon04', // Visitors count icon
|
||||
visitorsQueueBackground: 'ui01', // Visitors queue panel background
|
||||
visitorsQueueText: 'text01', // Visitors queue text
|
||||
visitorsArrowBackground: 'ui02', // Visitors arrow container background
|
||||
|
||||
// Welcome Page
|
||||
welcomeBackground: 'surface01', // Welcome page background (same as uiBackground)
|
||||
welcomeCard: 'ui01', // Welcome page tab bar background
|
||||
welcomeTabActive: 'icon01', // Welcome page active tab icon
|
||||
welcomeTabInactive: 'icon03', // Welcome page inactive tab icon
|
||||
|
||||
// ----- Form Components -----
|
||||
|
||||
// Input
|
||||
inputLabel: 'text01', // Input field label text
|
||||
inputFieldBackground: 'ui02', // Input field background color
|
||||
inputFieldBorder: 'ui02', // Input field border color
|
||||
inputFieldText: 'text01', // Input field text color
|
||||
inputFieldPlaceholder: 'text02', // Input field placeholder text
|
||||
inputFieldDisabled: 'text03', // Input field disabled text
|
||||
inputFieldError: 'textError', // Input field error state
|
||||
inputFieldFocus: 'focus01', // Input field focus outline
|
||||
inputClearButton: 'transparent', // Input clear button background
|
||||
inputBottomLabel: 'text02', // Input bottom label text
|
||||
inputBottomLabelError: 'textError', // Input bottom label error text
|
||||
|
||||
// Select
|
||||
selectLabel: 'text01', // Select label text
|
||||
selectBackground: 'ui02', // Select background color
|
||||
selectText: 'text01', // Select text color
|
||||
selectDisabled: 'text03', // Select disabled text
|
||||
selectError: 'textError', // Select error state
|
||||
selectFocus: 'focus01', // Select focus outline
|
||||
selectIcon: 'icon01', // Select dropdown icon (enabled)
|
||||
selectIconDisabled: 'icon03', // Select dropdown icon (disabled)
|
||||
selectBottomLabel: 'text02', // Select bottom label text
|
||||
selectBottomLabelError: 'textError', // Select bottom label error text
|
||||
|
||||
// MultiSelect
|
||||
multiSelectBackground: 'ui01', // MultiSelect dropdown background
|
||||
multiSelectBorder: 'ui04', // MultiSelect dropdown border
|
||||
multiSelectItemText: 'text01', // MultiSelect item text
|
||||
multiSelectItemHover: 'ui02', // MultiSelect item hover background
|
||||
multiSelectItemDisabled: 'text03', // MultiSelect disabled item text
|
||||
|
||||
// Checkbox
|
||||
checkboxLabel: 'text01', // Checkbox label text
|
||||
checkboxBorder: 'icon03', // Checkbox border color
|
||||
checkboxChecked: 'action01', // Checkbox checked background
|
||||
checkboxDisabledBackground: 'ui02', // Checkbox disabled background
|
||||
checkboxDisabledBorder: 'surface05', // Checkbox disabled border
|
||||
checkboxDisabledChecked: 'ui02', // Checkbox disabled checked background
|
||||
checkboxIcon: 'icon01', // Checkbox check icon (enabled)
|
||||
checkboxIconDisabled: 'icon03', // Checkbox check icon (disabled)
|
||||
|
||||
// Switch
|
||||
switchBackground: 'ui01', // Switch background (unchecked)
|
||||
switchBackgroundOn: 'action01', // Switch background (checked)
|
||||
switchToggle: 'ui04', // Switch toggle circle
|
||||
switchToggleDisabled: 'ui03', // Switch toggle circle (disabled)
|
||||
switchFocus: 'focus01', // Switch focus outline
|
||||
|
||||
// Tabs
|
||||
tabText: 'text02', // Tab text (unselected)
|
||||
tabTextHover: 'text01', // Tab text (hover)
|
||||
tabTextSelected: 'text01', // Tab text (selected)
|
||||
tabTextDisabled: 'text03', // Tab text (disabled)
|
||||
tabBorder: 'ui05', // Tab bottom border (unselected)
|
||||
tabBorderHover: 'ui10', // Tab bottom border (hover)
|
||||
tabBorderSelected: 'action01', // Tab bottom border (selected)
|
||||
tabBorderDisabled: 'ui05', // Tab bottom border (disabled)
|
||||
tabFocus: 'focus01', // Tab focus outline
|
||||
tabBadgeBackground: 'warning01', // Tab count badge background
|
||||
tabBadgeText: 'text04', // Tab count badge text
|
||||
|
||||
// ListItem
|
||||
listItemText: 'text01', // List item text color
|
||||
listItemBackground: 'ui01', // List item default background
|
||||
listItemHover: 'surface03', // List item hover background
|
||||
listItemHighlighted: 'surface03', // List item highlighted/active background
|
||||
listItemBoxShadow: 'ui02', // List item actions box shadow color
|
||||
|
||||
// ClickableIcon
|
||||
clickableIconBackground: 'transparent', // Clickable icon background
|
||||
clickableIconHover: 'ui02', // Clickable icon hover background
|
||||
clickableIconActive: 'ui03', // Clickable icon active/pressed background
|
||||
clickableIconFocus: 'focus01', // Clickable icon focus outline
|
||||
|
||||
// Label
|
||||
labelBackground: 'ui04', // Label default background
|
||||
labelText: 'text01', // Label text color
|
||||
labelWhiteBackground: 'ui08', // Label white variant background
|
||||
labelWhiteText: 'text04', // Label white variant text
|
||||
labelWhiteIcon: 'surface01', // Label white variant icon
|
||||
|
||||
// Tooltip
|
||||
tooltipBackground: 'uiBackground', // Tooltip background color
|
||||
tooltipText: 'text01', // Tooltip text color
|
||||
|
||||
// Polls
|
||||
pollsBackground: 'surface03', // Poll container background
|
||||
pollsTitle: 'text01', // Poll title text
|
||||
pollsSubtitle: 'text02', // Poll subtitle/secondary text
|
||||
pollsQuestion: 'text01', // Poll question text
|
||||
pollsAnswer: 'text01', // Poll answer text
|
||||
pollsBarBackground: 'ui03', // Poll results bar background
|
||||
pollsBarPercentage: 'text01', // Poll results percentage text
|
||||
pollsVotersBackground: 'ui03', // Poll voters list background
|
||||
pollsVotersText: 'text01', // Poll voters list text
|
||||
pollsSeparator: 'ui03', // Poll section separator
|
||||
pollsSendLabel: 'text01', // Poll send button label
|
||||
pollsSendDisabled: 'text03', // Poll send button disabled label
|
||||
pollsPaneBackground: 'ui01', // Poll pane container background
|
||||
pollsPaneBorder: 'ui05', // Poll pane border
|
||||
pollsCreateBackground: 'uiBackground', // Poll create dialog background
|
||||
pollsCreateBorder: 'ui06', // Poll create dialog border
|
||||
|
||||
// Video Quality / Slider
|
||||
sliderKnob: 'text01', // Slider knob/thumb color
|
||||
sliderTrack: 'text03', // Slider track color
|
||||
sliderFocus: 'ui06', // Slider focus outline
|
||||
videoQualityText: 'text01', // Video quality dialog text
|
||||
videoQualityBackground: 'surface02', // Video quality dialog background
|
||||
|
||||
// Connection Indicator
|
||||
connectionIndicatorLost: 'ui05', // Connection indicator lost status
|
||||
connectionIndicatorOther: 'action01', // Connection indicator other status
|
||||
|
||||
// Device Selection
|
||||
deviceSelectorBackground: 'ui01', // Device selector background
|
||||
deviceSelectorText: 'text01', // Device selector text
|
||||
deviceSelectorBorder: 'ui03', // Device selector border
|
||||
deviceSelectorTextBackground: 'uiBackground', // Device selector text-only background
|
||||
deviceSelectorVideoPreview: 'uiBackground', // Device selector video preview background
|
||||
|
||||
// Invite / Dial-in
|
||||
dialInBackground: 'ui01', // Dial-in summary background
|
||||
dialInText: 'text01', // Dial-in summary text
|
||||
dialInSecondaryText: 'text02', // Dial-in summary secondary text
|
||||
|
||||
// Reactions
|
||||
reactionsMenuBackground: 'ui01', // Reactions menu background
|
||||
reactionsMenuBorder: 'ui02', // Reactions menu border
|
||||
|
||||
// Recording / Live Stream
|
||||
recordingBackground: 'ui01', // Recording panel background
|
||||
recordingText: 'text01', // Recording panel text
|
||||
recordingHighlightButton: 'ui04', // Recording highlight button background
|
||||
recordingHighlightButtonDisabled: 'text02', // Recording highlight button disabled background
|
||||
recordingHighlightButtonIcon: 'ui02', // Recording highlight button icon color
|
||||
recordingHighlightButtonIconDisabled: 'text03', // Recording highlight button disabled icon color
|
||||
recordingNotificationText: 'surface01', // Recording notification text color
|
||||
recordingNotificationAction: 'action01', // Recording notification action color
|
||||
|
||||
// Virtual Background
|
||||
virtualBackgroundBackground: 'ui01', // Virtual background picker background
|
||||
virtualBackgroundText: 'text01', // Virtual background picker text
|
||||
virtualBackgroundBorder: 'ui03', // Virtual background item border
|
||||
virtualBackgroundPreview: 'uiBackground', // Virtual background preview container
|
||||
|
||||
// Conference / Meeting
|
||||
conferenceTimerText: 'text01', // Conference timer text
|
||||
conferenceSubjectText: 'text01', // Conference subject text
|
||||
conferenceNoticeBackground: 'uiBackground', // Conference notice background
|
||||
conferenceNoticeText: 'text01', // Conference notice text
|
||||
conferenceRaisedHandLabelText: 'uiBackground', // Raised hands count label text
|
||||
conferenceRaisedHandLabelIcon: 'surface01', // Raised hands count label icon
|
||||
|
||||
// Subtitle Messages
|
||||
subtitleMessageBackground: 'ui02', // Subtitle message background
|
||||
subtitleMessageText: 'text01', // Subtitle message text
|
||||
subtitleMessageSender: 'text02', // Subtitle message sender name
|
||||
subtitleMessageTime: 'text03', // Subtitle message timestamp
|
||||
|
||||
// Language Selector
|
||||
languageSelectorBackground: 'ui01', // Language selector background
|
||||
languageSelectorText: 'text01', // Language selector text
|
||||
languageSelectorHover: 'ui02', // Language selector item hover
|
||||
|
||||
// Video Menu
|
||||
videoMenuBackground: 'ui01', // Video menu background
|
||||
videoMenuBorder: 'ui02', // Video menu border
|
||||
videoMenuText: 'text01', // Video menu text
|
||||
videoMenuSliderBackground: 'ui03', // Video menu slider background
|
||||
|
||||
// File Sharing
|
||||
fileSharingBackground: 'ui01', // File sharing panel background
|
||||
fileSharingText: 'text01', // File sharing text
|
||||
fileSharingEmptyText: 'text02', // File sharing empty state text
|
||||
fileSharingEmptyIcon: 'icon03', // File sharing empty state icon
|
||||
fileSharingItemBackground: 'surface03', // File sharing item background
|
||||
fileSharingItemBorder: 'ui02', // File sharing item hover/border
|
||||
|
||||
// Gifs
|
||||
gifsBackground: 'ui01', // GIFs panel background
|
||||
gifsText: 'text01', // GIFs panel text
|
||||
|
||||
// Whiteboard
|
||||
whiteboardBackground: 'ui03', // Whiteboard background
|
||||
whiteboardText: 'text01', // Whiteboard panel text
|
||||
|
||||
// Salesforce
|
||||
salesforceSearchBackground: 'field01', // Salesforce search input background
|
||||
salesforceSearchBorder: 'ui05', // Salesforce search input border
|
||||
salesforceSearchText: 'dialogText', // Salesforce search input text
|
||||
salesforceSearchPlaceholder: 'text03', // Salesforce search placeholder
|
||||
salesforceSearchIcon: 'text03', // Salesforce search icon
|
||||
|
||||
// Security Dialog
|
||||
securityDialogBackground: 'ui01', // Security dialog background
|
||||
securityDialogText: 'text01', // Security dialog text
|
||||
securityDialogSecondaryText: 'text02', // Security dialog secondary text
|
||||
securityDialogBorder: 'ui07', // Security dialog border color
|
||||
|
||||
// Deep Linking
|
||||
deepLinkingBackground: 'ui01', // Deep linking page content pane background
|
||||
deepLinkingBorder: 'ui03', // Deep linking page content pane border
|
||||
deepLinkingText: 'text01', // Deep linking page text
|
||||
deepLinkingSeparator: 'ui03', // Deep linking separator line
|
||||
deepLinkingLabelText: 'text02', // Deep linking label text
|
||||
deepLinkingLink: 'link01', // Deep linking link color
|
||||
|
||||
// Base React Components
|
||||
baseReactBackground: 'ui01', // Base react component background
|
||||
baseReactText: 'text01', // Base react component text
|
||||
baseReactBorder: 'ui03', // Base react component border
|
||||
|
||||
// Inline Dialog
|
||||
inlineDialogBackground: 'ui01', // Inline dialog background
|
||||
inlineDialogText: 'text01', // Inline dialog text
|
||||
inlineDialogBorder: 'ui02', // Inline dialog border
|
||||
|
||||
// Pre-meeting / Action Button
|
||||
actionButtonBackground: 'ui01', // Action button background (different from main buttons)
|
||||
actionButtonText: 'text01', // Action button text
|
||||
actionButtonBorder: 'ui03', // Action button border
|
||||
|
||||
// Audio Route Picker
|
||||
audioRoutePickerBackground: 'ui01', // Audio route picker background
|
||||
audioRoutePickerText: 'text01', // Audio route picker text
|
||||
audioRoutePickerBorder: 'ui03', // Audio route picker border
|
||||
|
||||
// Etherpad
|
||||
etherpadBackground: 'ui01', // Etherpad panel background
|
||||
etherpadText: 'text01', // Etherpad panel text
|
||||
|
||||
// Display Name
|
||||
displayNameBackground: 'ui01', // Display name background
|
||||
displayNameText: 'text01', // Display name text
|
||||
|
||||
// Car Mode
|
||||
carModeBackground: 'ui01', // Car mode background
|
||||
carModeText: 'text01', // Car mode text
|
||||
carModeBorder: 'ui03', // Car mode border
|
||||
|
||||
// ----- Links -----
|
||||
|
||||
link01: 'action01',
|
||||
|
||||
@@ -14,7 +14,7 @@ const useStyles = makeStyles()(theme => {
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
position: 'fixed',
|
||||
color: theme.palette.text01,
|
||||
color: theme.palette.dialogText,
|
||||
...theme.typography.bodyLongRegular,
|
||||
top: 0,
|
||||
left: 0,
|
||||
@@ -49,13 +49,13 @@ const useStyles = makeStyles()(theme => {
|
||||
height: '100%',
|
||||
top: 0,
|
||||
left: 0,
|
||||
backgroundColor: theme.palette.ui02,
|
||||
backgroundColor: theme.palette.dialogOverlay,
|
||||
opacity: 0.75
|
||||
},
|
||||
|
||||
modal: {
|
||||
backgroundColor: theme.palette.ui01,
|
||||
border: `1px solid ${theme.palette.ui03}`,
|
||||
backgroundColor: theme.palette.dialogBackground,
|
||||
border: `1px solid ${theme.palette.dialogBorder}`,
|
||||
boxShadow: '0px 4px 25px 4px rgba(20, 20, 20, 0.6)',
|
||||
borderRadius: `${theme.shape.borderRadius}px`,
|
||||
display: 'flex',
|
||||
|
||||
@@ -47,7 +47,7 @@ const useStyles = makeStyles()(theme => {
|
||||
return {
|
||||
formControl: {
|
||||
...theme.typography.bodyLongRegular,
|
||||
color: theme.palette.text01,
|
||||
color: theme.palette.checkboxLabel,
|
||||
display: 'inline-flex',
|
||||
alignItems: 'center',
|
||||
|
||||
@@ -76,10 +76,10 @@ const useStyles = makeStyles()(theme => {
|
||||
backgroundColor: 'transparent',
|
||||
margin: '3px',
|
||||
font: 'inherit',
|
||||
color: theme.palette.icon03,
|
||||
color: theme.palette.checkboxBorder,
|
||||
width: '18px',
|
||||
height: '18px',
|
||||
border: `2px solid ${theme.palette.icon03}`,
|
||||
border: `2px solid ${theme.palette.checkboxBorder}`,
|
||||
borderRadius: '3px',
|
||||
|
||||
display: 'grid',
|
||||
@@ -90,7 +90,7 @@ const useStyles = makeStyles()(theme => {
|
||||
width: '18px',
|
||||
height: '18px',
|
||||
opacity: 0,
|
||||
backgroundColor: theme.palette.action01,
|
||||
backgroundColor: theme.palette.checkboxChecked,
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
@@ -104,11 +104,11 @@ const useStyles = makeStyles()(theme => {
|
||||
},
|
||||
|
||||
'&:disabled': {
|
||||
backgroundColor: theme.palette.ui03,
|
||||
borderColor: theme.palette.ui04,
|
||||
backgroundColor: theme.palette.checkboxDisabledBackground,
|
||||
borderColor: theme.palette.checkboxDisabledBorder,
|
||||
|
||||
'&::before': {
|
||||
backgroundColor: theme.palette.ui04
|
||||
backgroundColor: theme.palette.checkboxDisabledChecked
|
||||
}
|
||||
},
|
||||
|
||||
@@ -173,7 +173,7 @@ const Checkbox = ({
|
||||
<Icon
|
||||
aria-hidden = { true }
|
||||
className = 'checkmark'
|
||||
color = { disabled ? theme.palette.icon03 : theme.palette.icon01 }
|
||||
color = { disabled ? theme.palette.checkboxIconDisabled : theme.palette.checkboxIcon }
|
||||
size = { 18 }
|
||||
src = { IconCheck } />
|
||||
</div>
|
||||
|
||||
@@ -16,22 +16,22 @@ const useStyles = makeStyles()(theme => {
|
||||
return {
|
||||
button: {
|
||||
padding: '2px',
|
||||
backgroundColor: theme.palette.action03,
|
||||
backgroundColor: theme.palette.clickableIconBackground,
|
||||
border: 0,
|
||||
outline: 0,
|
||||
borderRadius: `${theme.shape.borderRadius}px`,
|
||||
|
||||
'&:hover': {
|
||||
backgroundColor: theme.palette.ui02
|
||||
backgroundColor: theme.palette.clickableIconHover
|
||||
},
|
||||
|
||||
'&.focus-visible': {
|
||||
outline: 0,
|
||||
boxShadow: `0px 0px 0px 2px ${theme.palette.focus01}`
|
||||
boxShadow: `0px 0px 0px 2px ${theme.palette.clickableIconFocus}`
|
||||
},
|
||||
|
||||
'&:active': {
|
||||
backgroundColor: theme.palette.ui03
|
||||
backgroundColor: theme.palette.clickableIconActive
|
||||
},
|
||||
|
||||
'&.is-mobile': {
|
||||
|
||||
@@ -133,11 +133,11 @@ const MAX_HEIGHT = 400;
|
||||
const useStyles = makeStyles()(theme => {
|
||||
return {
|
||||
contextMenu: {
|
||||
backgroundColor: theme.palette.ui01,
|
||||
border: `1px solid ${theme.palette.ui04}`,
|
||||
backgroundColor: theme.palette.overflowMenuBackground,
|
||||
border: `1px solid ${theme.palette.overflowMenuBorder}`,
|
||||
borderRadius: `${Number(theme.shape.borderRadius)}px`,
|
||||
boxShadow: '0px 1px 2px rgba(41, 41, 41, 0.25)',
|
||||
color: theme.palette.text01,
|
||||
color: theme.palette.overflowMenuItemText,
|
||||
...theme.typography.bodyShortRegular,
|
||||
marginTop: '48px',
|
||||
position: 'absolute',
|
||||
|
||||
@@ -122,11 +122,11 @@ const useStyles = makeStyles()(theme => {
|
||||
},
|
||||
|
||||
'&:hover': {
|
||||
backgroundColor: theme.palette.ui02
|
||||
backgroundColor: theme.palette.overflowMenuItemHover
|
||||
},
|
||||
|
||||
'&:active': {
|
||||
backgroundColor: theme.palette.ui03
|
||||
backgroundColor: theme.palette.overflowMenuItemHover
|
||||
},
|
||||
|
||||
'&.focus-visible': {
|
||||
@@ -137,7 +137,7 @@ const useStyles = makeStyles()(theme => {
|
||||
selected: {
|
||||
borderLeft: `3px solid ${theme.palette.action01Hover}`,
|
||||
paddingLeft: '13px',
|
||||
backgroundColor: theme.palette.ui02
|
||||
backgroundColor: theme.palette.overflowMenuItemHover
|
||||
},
|
||||
|
||||
contextMenuItemDisabled: {
|
||||
@@ -146,19 +146,19 @@ const useStyles = makeStyles()(theme => {
|
||||
|
||||
contextMenuItemIconDisabled: {
|
||||
'& svg': {
|
||||
fill: `${theme.palette.text03} !important`
|
||||
fill: `${theme.palette.overflowMenuItemDisabled} !important`
|
||||
}
|
||||
},
|
||||
|
||||
contextMenuItemLabelDisabled: {
|
||||
color: theme.palette.text03,
|
||||
color: theme.palette.overflowMenuItemDisabled,
|
||||
|
||||
'&:hover': {
|
||||
background: 'none'
|
||||
},
|
||||
|
||||
'& svg': {
|
||||
fill: theme.palette.text03
|
||||
fill: theme.palette.overflowMenuItemDisabled
|
||||
}
|
||||
},
|
||||
|
||||
@@ -168,13 +168,13 @@ const useStyles = makeStyles()(theme => {
|
||||
|
||||
contextMenuItemIcon: {
|
||||
'& svg': {
|
||||
fill: theme.palette.icon01
|
||||
fill: theme.palette.overflowMenuItemIcon
|
||||
}
|
||||
},
|
||||
|
||||
text: {
|
||||
...theme.typography.bodyShortRegular,
|
||||
color: theme.palette.text01
|
||||
color: theme.palette.overflowMenuItemText
|
||||
},
|
||||
|
||||
drawerText: {
|
||||
|
||||
@@ -30,7 +30,7 @@ const useStyles = makeStyles()(theme => {
|
||||
},
|
||||
|
||||
'& + &:not(:empty)': {
|
||||
borderTop: `1px solid ${theme.palette.ui03}`
|
||||
borderTop: `1px solid ${theme.palette.overflowMenuSeparator}`
|
||||
},
|
||||
|
||||
'&:first-of-type': {
|
||||
|
||||
@@ -24,7 +24,7 @@ const useStyles = makeStyles()(theme => {
|
||||
},
|
||||
|
||||
title: {
|
||||
color: theme.palette.text01,
|
||||
color: theme.palette.dialogText,
|
||||
...theme.typography.heading5,
|
||||
margin: 0,
|
||||
padding: 0
|
||||
|
||||
@@ -42,7 +42,7 @@ const useStyles = makeStyles()(theme => {
|
||||
flexDirection: 'column',
|
||||
minWidth: '211px',
|
||||
maxWidth: '100%',
|
||||
borderRight: `1px solid ${theme.palette.ui03}`,
|
||||
borderRight: `1px solid ${theme.palette.dialogBorder}`,
|
||||
|
||||
[`@media (max-width: ${MOBILE_BREAKPOINT}px)`]: {
|
||||
width: '100%',
|
||||
@@ -70,7 +70,7 @@ const useStyles = makeStyles()(theme => {
|
||||
|
||||
title: {
|
||||
...theme.typography.heading5,
|
||||
color: `${theme.palette.text01} !important`,
|
||||
color: `${theme.palette.dialogText} !important`,
|
||||
margin: 0,
|
||||
padding: 0
|
||||
},
|
||||
@@ -301,7 +301,7 @@ const DialogWithTabs = ({
|
||||
}
|
||||
|
||||
return null;
|
||||
}, [ selectedTabIndex, tabStates ]);
|
||||
}, [ selectedTabIndex, tabStates, tabs ]);
|
||||
|
||||
const closeIcon = useMemo(() => (
|
||||
<ClickableIcon
|
||||
|
||||
@@ -49,7 +49,7 @@ const useStyles = makeStyles()(theme => {
|
||||
},
|
||||
|
||||
label: {
|
||||
color: theme.palette.text01,
|
||||
color: theme.palette.inputLabel,
|
||||
...theme.typography.bodyShortRegular,
|
||||
marginBottom: theme.spacing(2),
|
||||
|
||||
@@ -64,9 +64,9 @@ const useStyles = makeStyles()(theme => {
|
||||
},
|
||||
|
||||
input: {
|
||||
backgroundColor: theme.palette.ui03,
|
||||
background: theme.palette.ui03,
|
||||
color: theme.palette.text01,
|
||||
backgroundColor: theme.palette.inputFieldBackground,
|
||||
background: theme.palette.inputFieldBackground,
|
||||
color: theme.palette.inputFieldText,
|
||||
...theme.typography.bodyShortRegular,
|
||||
padding: '10px 16px',
|
||||
borderRadius: theme.shape.borderRadius,
|
||||
@@ -76,16 +76,16 @@ const useStyles = makeStyles()(theme => {
|
||||
width: '100%',
|
||||
|
||||
'&::placeholder': {
|
||||
color: theme.palette.text02
|
||||
color: theme.palette.inputFieldPlaceholder
|
||||
},
|
||||
|
||||
'&:focus': {
|
||||
outline: 0,
|
||||
boxShadow: `0px 0px 0px 2px ${theme.palette.focus01}`
|
||||
boxShadow: `0px 0px 0px 2px ${theme.palette.inputFieldFocus}`
|
||||
},
|
||||
|
||||
'&:disabled': {
|
||||
color: theme.palette.text03
|
||||
color: theme.palette.inputFieldDisabled
|
||||
},
|
||||
|
||||
'&.is-mobile': {
|
||||
@@ -99,7 +99,7 @@ const useStyles = makeStyles()(theme => {
|
||||
},
|
||||
|
||||
'&.error': {
|
||||
boxShadow: `0px 0px 0px 2px ${theme.palette.textError}`
|
||||
boxShadow: `0px 0px 0px 2px ${theme.palette.inputFieldError}`
|
||||
},
|
||||
'&.clearable-input': {
|
||||
paddingRight: '46px'
|
||||
@@ -107,12 +107,12 @@ const useStyles = makeStyles()(theme => {
|
||||
},
|
||||
|
||||
'input::-webkit-outer-spin-button, input::-webkit-inner-spin-button': {
|
||||
'-webkit-appearance': 'none',
|
||||
WebkitAppearance: 'none',
|
||||
margin: 0
|
||||
},
|
||||
|
||||
'input[type=number]': {
|
||||
'-moz-appearance': 'textfield'
|
||||
MozAppearance: 'textfield'
|
||||
},
|
||||
|
||||
icon: {
|
||||
@@ -131,7 +131,7 @@ const useStyles = makeStyles()(theme => {
|
||||
right: '16px',
|
||||
top: '10px',
|
||||
cursor: 'pointer',
|
||||
backgroundColor: theme.palette.action03,
|
||||
backgroundColor: theme.palette.inputClearButton,
|
||||
border: 0,
|
||||
padding: 0
|
||||
},
|
||||
@@ -139,14 +139,14 @@ const useStyles = makeStyles()(theme => {
|
||||
bottomLabel: {
|
||||
marginTop: theme.spacing(2),
|
||||
...theme.typography.labelRegular,
|
||||
color: theme.palette.text02,
|
||||
color: theme.palette.inputBottomLabel,
|
||||
|
||||
'&.is-mobile': {
|
||||
...theme.typography.bodyShortRegular
|
||||
},
|
||||
|
||||
'&.error': {
|
||||
color: theme.palette.textError
|
||||
color: theme.palette.inputBottomLabelError
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -83,7 +83,7 @@ const useStyles = makeStyles()(theme => {
|
||||
return {
|
||||
container: {
|
||||
alignItems: 'center',
|
||||
color: theme.palette.text01,
|
||||
color: theme.palette.listItemText,
|
||||
display: 'flex',
|
||||
...theme.typography.bodyShortBold,
|
||||
margin: `0 -${participantsPaneTheme.panePadding}px`,
|
||||
@@ -93,7 +93,7 @@ const useStyles = makeStyles()(theme => {
|
||||
minHeight: '40px',
|
||||
|
||||
'&:hover, &:focus-within': {
|
||||
backgroundColor: theme.palette.ui02,
|
||||
backgroundColor: theme.palette.listItemHover,
|
||||
|
||||
'& .indicators': {
|
||||
display: 'none'
|
||||
@@ -103,8 +103,8 @@ const useStyles = makeStyles()(theme => {
|
||||
display: 'flex',
|
||||
position: 'relative',
|
||||
top: 'auto',
|
||||
boxShadow: `-15px 0px 10px -5px ${theme.palette.ui02}`,
|
||||
backgroundColor: theme.palette.ui02
|
||||
boxShadow: `-15px 0px 10px -5px ${theme.palette.listItemBoxShadow}`,
|
||||
backgroundColor: theme.palette.listItemHover
|
||||
}
|
||||
},
|
||||
|
||||
@@ -115,14 +115,14 @@ const useStyles = makeStyles()(theme => {
|
||||
},
|
||||
|
||||
highlighted: {
|
||||
backgroundColor: theme.palette.ui02,
|
||||
backgroundColor: theme.palette.listItemHighlighted,
|
||||
|
||||
'& .actions': {
|
||||
display: 'flex',
|
||||
position: 'relative',
|
||||
top: 'auto',
|
||||
boxShadow: `-15px 0px 10px -5px ${theme.palette.ui02}`,
|
||||
backgroundColor: theme.palette.ui02
|
||||
boxShadow: `-15px 0px 10px -5px ${theme.palette.listItemBoxShadow}`,
|
||||
backgroundColor: theme.palette.listItemHighlighted
|
||||
}
|
||||
},
|
||||
|
||||
@@ -170,20 +170,20 @@ const useStyles = makeStyles()(theme => {
|
||||
actionsContainer: {
|
||||
position: 'absolute',
|
||||
top: '-1000px',
|
||||
boxShadow: `-15px 0px 10px -5px ${theme.palette.ui02}`,
|
||||
backgroundColor: theme.palette.ui02
|
||||
boxShadow: `-15px 0px 10px -5px ${theme.palette.listItemBoxShadow}`,
|
||||
backgroundColor: theme.palette.listItemHover
|
||||
},
|
||||
|
||||
actionsPermanent: {
|
||||
display: 'flex',
|
||||
boxShadow: `-15px 0px 10px -5px ${theme.palette.ui01}`,
|
||||
backgroundColor: theme.palette.ui01
|
||||
boxShadow: `-15px 0px 10px -5px ${theme.palette.listItemBackground}`,
|
||||
backgroundColor: theme.palette.listItemBackground
|
||||
},
|
||||
|
||||
actionsVisible: {
|
||||
display: 'flex',
|
||||
boxShadow: `-15px 0px 10px -5px ${theme.palette.ui02}`,
|
||||
backgroundColor: theme.palette.ui02
|
||||
boxShadow: `-15px 0px 10px -5px ${theme.palette.listItemBoxShadow}`,
|
||||
backgroundColor: theme.palette.listItemHighlighted
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
@@ -38,8 +38,8 @@ const useStyles = makeStyles()(theme => {
|
||||
},
|
||||
marginTop: theme.spacing(2),
|
||||
width: '100%',
|
||||
backgroundColor: theme.palette.ui01,
|
||||
border: `1px solid ${theme.palette.ui04}`,
|
||||
backgroundColor: theme.palette.multiSelectBackground,
|
||||
border: `1px solid ${theme.palette.multiSelectBorder}`,
|
||||
borderRadius: `${Number(theme.shape.borderRadius)}px`,
|
||||
...theme.typography.bodyShortRegular,
|
||||
zIndex: 2,
|
||||
@@ -57,7 +57,7 @@ const useStyles = makeStyles()(theme => {
|
||||
inlineSize: 'calc(100% - 38px)',
|
||||
overflowWrap: 'break-word',
|
||||
marginLeft: theme.spacing(2),
|
||||
color: theme.palette.text01,
|
||||
color: theme.palette.multiSelectItemText,
|
||||
'&.with-remove': {
|
||||
// 60px because of the icon before the content and the remove button
|
||||
inlineSize: 'calc(100% - 60px)',
|
||||
@@ -76,15 +76,15 @@ const useStyles = makeStyles()(theme => {
|
||||
cursor: 'pointer',
|
||||
padding: `10px ${theme.spacing(3)}`,
|
||||
'&:hover': {
|
||||
backgroundColor: theme.palette.ui02
|
||||
backgroundColor: theme.palette.multiSelectItemHover
|
||||
}
|
||||
},
|
||||
'&.disabled': {
|
||||
cursor: 'not-allowed',
|
||||
'&:hover': {
|
||||
backgroundColor: theme.palette.ui01
|
||||
backgroundColor: theme.palette.multiSelectBackground
|
||||
},
|
||||
color: theme.palette.text03
|
||||
color: theme.palette.multiSelectItemDisabled
|
||||
}
|
||||
},
|
||||
errorMessage: {
|
||||
|
||||
@@ -70,7 +70,7 @@ const useStyles = makeStyles()(theme => {
|
||||
},
|
||||
|
||||
label: {
|
||||
color: theme.palette.text01,
|
||||
color: theme.palette.selectLabel,
|
||||
...theme.typography.bodyShortRegular,
|
||||
marginBottom: theme.spacing(2),
|
||||
|
||||
@@ -84,11 +84,11 @@ const useStyles = makeStyles()(theme => {
|
||||
},
|
||||
|
||||
select: {
|
||||
backgroundColor: theme.palette.ui03,
|
||||
backgroundColor: theme.palette.selectBackground,
|
||||
borderRadius: `${theme.shape.borderRadius}px`,
|
||||
width: '100%',
|
||||
...theme.typography.bodyShortRegular,
|
||||
color: theme.palette.text01,
|
||||
color: theme.palette.selectText,
|
||||
padding: '10px 16px',
|
||||
paddingRight: '42px',
|
||||
border: 0,
|
||||
@@ -99,11 +99,11 @@ const useStyles = makeStyles()(theme => {
|
||||
|
||||
'&:focus': {
|
||||
outline: 0,
|
||||
boxShadow: `0px 0px 0px 2px ${theme.palette.focus01}`
|
||||
boxShadow: `0px 0px 0px 2px ${theme.palette.selectFocus}`
|
||||
},
|
||||
|
||||
'&:disabled': {
|
||||
color: theme.palette.text03
|
||||
color: theme.palette.selectDisabled
|
||||
},
|
||||
|
||||
'&.is-mobile': {
|
||||
@@ -113,7 +113,7 @@ const useStyles = makeStyles()(theme => {
|
||||
},
|
||||
|
||||
'&.error': {
|
||||
boxShadow: `0px 0px 0px 2px ${theme.palette.textError}`
|
||||
boxShadow: `0px 0px 0px 2px ${theme.palette.selectError}`
|
||||
}
|
||||
},
|
||||
|
||||
@@ -132,14 +132,14 @@ const useStyles = makeStyles()(theme => {
|
||||
bottomLabel: {
|
||||
marginTop: theme.spacing(2),
|
||||
...theme.typography.labelRegular,
|
||||
color: theme.palette.text02,
|
||||
color: theme.palette.selectBottomLabel,
|
||||
|
||||
'&.is-mobile': {
|
||||
...theme.typography.bodyShortRegular
|
||||
},
|
||||
|
||||
'&.error': {
|
||||
color: theme.palette.textError
|
||||
color: theme.palette.selectBottomLabelError
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -180,7 +180,7 @@ const Select = ({
|
||||
</select>
|
||||
<Icon
|
||||
className = { cx(classes.icon, isMobile && 'is-mobile') }
|
||||
color = { disabled ? theme.palette.icon03 : theme.palette.icon01 }
|
||||
color = { disabled ? theme.palette.selectIconDisabled : theme.palette.selectIcon }
|
||||
size = { 22 }
|
||||
src = { IconArrowDown } />
|
||||
</div>
|
||||
|
||||
@@ -18,7 +18,7 @@ const useStyles = makeStyles()(theme => {
|
||||
return {
|
||||
container: {
|
||||
position: 'relative',
|
||||
backgroundColor: theme.palette.ui05,
|
||||
backgroundColor: theme.palette.switchBackground,
|
||||
borderRadius: '12px',
|
||||
width: '40px',
|
||||
height: '24px',
|
||||
@@ -29,11 +29,11 @@ const useStyles = makeStyles()(theme => {
|
||||
display: 'inline-block',
|
||||
|
||||
'&.disabled': {
|
||||
backgroundColor: theme.palette.ui05,
|
||||
backgroundColor: theme.palette.switchBackground,
|
||||
cursor: 'default',
|
||||
|
||||
'& .toggle': {
|
||||
backgroundColor: theme.palette.ui03
|
||||
backgroundColor: theme.palette.switchToggleDisabled
|
||||
}
|
||||
},
|
||||
|
||||
@@ -45,7 +45,7 @@ const useStyles = makeStyles()(theme => {
|
||||
},
|
||||
|
||||
containerOn: {
|
||||
backgroundColor: theme.palette.action01
|
||||
backgroundColor: theme.palette.switchBackgroundOn
|
||||
},
|
||||
|
||||
toggle: {
|
||||
@@ -55,7 +55,7 @@ const useStyles = makeStyles()(theme => {
|
||||
zIndex: 5,
|
||||
top: '4px',
|
||||
left: '4px',
|
||||
backgroundColor: theme.palette.ui10,
|
||||
backgroundColor: theme.palette.switchToggle,
|
||||
borderRadius: '100%',
|
||||
transition: '.3s',
|
||||
|
||||
@@ -87,7 +87,7 @@ const useStyles = makeStyles()(theme => {
|
||||
|
||||
'&.focus-visible + .toggle-checkbox-ring': {
|
||||
outline: 0,
|
||||
boxShadow: `0px 0px 0px 2px ${theme.palette.focus01}`
|
||||
boxShadow: `0px 0px 0px 2px ${theme.palette.switchFocus}`
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
@@ -29,13 +29,13 @@ const useStyles = makeStyles()(theme => {
|
||||
|
||||
tab: {
|
||||
...theme.typography.bodyShortBold,
|
||||
color: theme.palette.text02,
|
||||
color: theme.palette.tabText,
|
||||
flex: 1,
|
||||
padding: '14px',
|
||||
background: 'none',
|
||||
border: 0,
|
||||
appearance: 'none',
|
||||
borderBottom: `2px solid ${theme.palette.ui05}`,
|
||||
borderBottom: `2px solid ${theme.palette.tabBorder}`,
|
||||
transition: 'color, border-color 0.2s',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
@@ -43,25 +43,25 @@ const useStyles = makeStyles()(theme => {
|
||||
borderRadius: 0,
|
||||
|
||||
'&:hover': {
|
||||
color: theme.palette.text01,
|
||||
borderColor: theme.palette.ui10
|
||||
color: theme.palette.tabTextHover,
|
||||
borderColor: theme.palette.tabBorderHover
|
||||
},
|
||||
|
||||
'&.focus-visible': {
|
||||
outline: 0,
|
||||
boxShadow: `0px 0px 0px 2px ${theme.palette.focus01}`,
|
||||
boxShadow: `0px 0px 0px 2px ${theme.palette.tabFocus}`,
|
||||
border: 0,
|
||||
color: theme.palette.text01
|
||||
color: theme.palette.tabTextSelected
|
||||
},
|
||||
|
||||
'&.selected': {
|
||||
color: theme.palette.text01,
|
||||
borderColor: theme.palette.action01
|
||||
color: theme.palette.tabTextSelected,
|
||||
borderColor: theme.palette.tabBorderSelected
|
||||
},
|
||||
|
||||
'&:disabled': {
|
||||
color: theme.palette.text03,
|
||||
borderColor: theme.palette.ui05
|
||||
color: theme.palette.tabTextDisabled,
|
||||
borderColor: theme.palette.tabBorderDisabled
|
||||
},
|
||||
|
||||
'&.is-mobile': {
|
||||
@@ -72,9 +72,9 @@ const useStyles = makeStyles()(theme => {
|
||||
badge: {
|
||||
...theme.typography.labelBold,
|
||||
alignItems: 'center',
|
||||
backgroundColor: theme.palette.warning01,
|
||||
backgroundColor: theme.palette.tabBadgeBackground,
|
||||
borderRadius: theme.spacing(2),
|
||||
color: theme.palette.text04,
|
||||
color: theme.palette.tabBadgeText,
|
||||
display: 'inline-flex',
|
||||
height: theme.spacing(3),
|
||||
justifyContent: 'center',
|
||||
|
||||
@@ -11,6 +11,23 @@ export * from './constants.any';
|
||||
*/
|
||||
export const commonStyles = (theme: Theme) => {
|
||||
return {
|
||||
':root': {
|
||||
// Inject semantic tokens as CSS custom properties for use in SCSS
|
||||
'--toolbox-background-color': theme.palette.toolboxBackground,
|
||||
'--drawer-background-color': theme.palette.drawerBackground,
|
||||
'--toolbar-button-color': theme.palette.toolbarButton,
|
||||
'--toolbar-button-hover-color': theme.palette.toolbarButtonHover,
|
||||
'--toolbar-button-active-color': theme.palette.toolbarButtonActive,
|
||||
'--toolbar-icon-color': theme.palette.toolbarIcon,
|
||||
'--toolbar-icon-hover-color': theme.palette.toolbarIconHover,
|
||||
'--toolbar-icon-active-color': theme.palette.toolbarIconActive,
|
||||
'--overflow-menu-background-color': theme.palette.overflowMenuBackground,
|
||||
'--overflow-menu-item-text-color': theme.palette.overflowMenuItemText,
|
||||
'--overflow-menu-item-icon-color': theme.palette.overflowMenuItemIcon,
|
||||
'--overflow-menu-item-hover-color': theme.palette.overflowMenuItemHover,
|
||||
'--overflow-menu-item-disabled-color': theme.palette.overflowMenuItemDisabled
|
||||
},
|
||||
|
||||
'.empty-list': {
|
||||
listStyleType: 'none',
|
||||
margin: 0,
|
||||
@@ -39,7 +56,7 @@ export const commonStyles = (theme: Theme) => {
|
||||
|
||||
'.overflow-menu-item': {
|
||||
alignItems: 'center',
|
||||
color: theme.palette.text01,
|
||||
color: theme.palette.overflowMenuItemText,
|
||||
cursor: 'pointer',
|
||||
display: 'flex',
|
||||
fontSize: '0.875rem',
|
||||
@@ -59,20 +76,20 @@ export const commonStyles = (theme: Theme) => {
|
||||
|
||||
'&.disabled': {
|
||||
cursor: 'initial',
|
||||
color: theme.palette.text03,
|
||||
color: theme.palette.overflowMenuItemDisabled,
|
||||
|
||||
'&:hover': {
|
||||
background: 'none'
|
||||
},
|
||||
|
||||
'& svg': {
|
||||
fill: theme.palette.text03
|
||||
fill: theme.palette.overflowMenuItemDisabled
|
||||
}
|
||||
},
|
||||
|
||||
'@media (hover: hover) and (pointer: fine)': {
|
||||
'&:hover': {
|
||||
background: theme.palette.action02Hover
|
||||
background: theme.palette.overflowMenuItemHover
|
||||
},
|
||||
'&.unclickable:hover': {
|
||||
background: 'inherit'
|
||||
@@ -100,14 +117,14 @@ export const commonStyles = (theme: Theme) => {
|
||||
},
|
||||
|
||||
'& svg': {
|
||||
fill: theme.palette.text01,
|
||||
fill: theme.palette.overflowMenuItemIcon,
|
||||
height: 20,
|
||||
width: 20
|
||||
}
|
||||
},
|
||||
|
||||
'.prejoin-dialog': {
|
||||
backgroundColor: theme.palette.uiBackground,
|
||||
backgroundColor: theme.palette.prejoinDialogBackground,
|
||||
boxShadow: '0px 2px 20px rgba(0, 0, 0, 0.5)',
|
||||
borderRadius: theme.shape.borderRadius,
|
||||
color: '#fff',
|
||||
@@ -173,7 +190,7 @@ export const commonStyles = (theme: Theme) => {
|
||||
},
|
||||
|
||||
'.prejoin-dialog-delimiter': {
|
||||
background: theme.palette.ui03,
|
||||
background: theme.palette.prejoinDialogDelimiter,
|
||||
border: '0',
|
||||
height: '1px',
|
||||
margin: '0',
|
||||
@@ -194,8 +211,8 @@ export const commonStyles = (theme: Theme) => {
|
||||
},
|
||||
|
||||
'.prejoin-dialog-delimiter-txt': {
|
||||
background: theme.palette.uiBackground,
|
||||
color: theme.palette.text01,
|
||||
background: theme.palette.prejoinDialogBackground,
|
||||
color: theme.palette.prejoinDialogDelimiterText,
|
||||
fontSize: '0.75rem',
|
||||
textTransform: 'uppercase' as const,
|
||||
padding: `0 ${theme.spacing(2)}`
|
||||
@@ -219,11 +236,11 @@ export const commonStyles = (theme: Theme) => {
|
||||
|
||||
'@media (hover: hover) and (pointer: fine)': {
|
||||
'&:hover': {
|
||||
backgroundColor: theme.palette.ui04
|
||||
backgroundColor: theme.palette.toolboxIconHover
|
||||
},
|
||||
|
||||
'&:active': {
|
||||
backgroundColor: theme.palette.ui03
|
||||
backgroundColor: theme.palette.toolboxIconActive
|
||||
}
|
||||
},
|
||||
[theme.breakpoints.down(320)]: {
|
||||
@@ -232,7 +249,7 @@ export const commonStyles = (theme: Theme) => {
|
||||
},
|
||||
|
||||
'&.toggled': {
|
||||
backgroundColor: theme.palette.ui03
|
||||
backgroundColor: theme.palette.toolboxIconToggled
|
||||
},
|
||||
|
||||
'&.disabled': {
|
||||
@@ -240,13 +257,13 @@ export const commonStyles = (theme: Theme) => {
|
||||
backgroundColor: `${theme.palette.disabled01} !important`,
|
||||
|
||||
'& svg': {
|
||||
fill: `${theme.palette.text03} !important`
|
||||
fill: `${theme.palette.icon03} !important`
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
'.toolbox-button': {
|
||||
color: theme.palette.text01,
|
||||
color: theme.palette.toolbarIcon,
|
||||
cursor: 'pointer',
|
||||
display: 'inline-block',
|
||||
lineHeight: '3rem',
|
||||
@@ -254,7 +271,7 @@ export const commonStyles = (theme: Theme) => {
|
||||
},
|
||||
|
||||
'.toolbox-content-items': {
|
||||
background: theme.palette.ui01,
|
||||
background: theme.palette.toolboxBackground,
|
||||
borderRadius: 6,
|
||||
margin: '0 auto',
|
||||
padding: 6,
|
||||
|
||||
11
react/features/base/ui/types.d.ts
vendored
Normal file
11
react/features/base/ui/types.d.ts
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
import '@mui/material/styles';
|
||||
|
||||
import { IPalette, ITypography } from './types';
|
||||
|
||||
declare module '@mui/material/styles' {
|
||||
interface Palette extends IPalette {}
|
||||
interface PaletteOptions extends Partial<IPalette> {}
|
||||
|
||||
interface Typography extends ITypography {}
|
||||
interface TypographyOptions extends Partial<ITypography> {}
|
||||
}
|
||||
@@ -5,6 +5,7 @@ interface ITypographyType {
|
||||
lineHeight: string;
|
||||
}
|
||||
|
||||
/* eslint-disable typescript-sort-keys/interface */
|
||||
export interface IPalette {
|
||||
action01: string;
|
||||
action01Active: string;
|
||||
@@ -58,6 +59,324 @@ export interface IPalette {
|
||||
uiBackground: string;
|
||||
warning01: string;
|
||||
warning02: string;
|
||||
|
||||
// Semantic tokens (component-based, more descriptive names)
|
||||
breakoutRoomArrowBackground: string;
|
||||
breakoutRoomBackground: string;
|
||||
breakoutRoomItemBackground: string;
|
||||
chatBackground: string;
|
||||
chatBackdrop: string;
|
||||
chatEmptyText: string;
|
||||
chatInputBackground: string;
|
||||
chatInputBorder: string;
|
||||
chatLink: string;
|
||||
chatLobbyMessageBubble: string;
|
||||
chatLobbyMessageNotice: string;
|
||||
chatLobbyRecipientContainer: string;
|
||||
chatMessageLocal: string;
|
||||
chatMessagePrivate: string;
|
||||
chatMessageRemote: string;
|
||||
chatMessageText: string;
|
||||
chatPrivateNotice: string;
|
||||
chatRecipientCancelIcon: string;
|
||||
chatRecipientContainer: string;
|
||||
chatRecipientText: string;
|
||||
chatReplyIcon: string;
|
||||
chatSenderName: string;
|
||||
chatTimestamp: string;
|
||||
dialogBackground: string;
|
||||
dialogBorder: string;
|
||||
dialogOverlay: string;
|
||||
dialogSecondaryText: string;
|
||||
dialogText: string;
|
||||
drawerBackground: string;
|
||||
filmstripBackground: string;
|
||||
filmstripBackgroundHover: string;
|
||||
filmstripDragHandle: string;
|
||||
filmstripDragHandleHover: string;
|
||||
inputBackground: string;
|
||||
inputBorder: string;
|
||||
inputPlaceholder: string;
|
||||
inputText: string;
|
||||
largeVideoBackground: string;
|
||||
largeVideoPlaceholder: string;
|
||||
lobbyBackground: string;
|
||||
lobbyPreviewBackground: string;
|
||||
notificationActionFocus: string;
|
||||
notificationActionText: string;
|
||||
notificationBackground: string;
|
||||
notificationCloseIcon: string;
|
||||
notificationError: string;
|
||||
notificationErrorText: string;
|
||||
notificationNormalIcon: string;
|
||||
notificationSuccess: string;
|
||||
notificationText: string;
|
||||
notificationWarning: string;
|
||||
overflowMenuBackground: string;
|
||||
overflowMenuBorder: string;
|
||||
overflowMenuItemDisabled: string;
|
||||
overflowMenuItemHover: string;
|
||||
overflowMenuItemIcon: string;
|
||||
overflowMenuItemText: string;
|
||||
overflowMenuSeparator: string;
|
||||
participantActionButton: string;
|
||||
participantCounterBadge: string;
|
||||
participantCounterText: string;
|
||||
participantItemBackground: string;
|
||||
participantItemBorder: string;
|
||||
participantItemHover: string;
|
||||
participantLinkText: string;
|
||||
participantModeratorLabel: string;
|
||||
participantRaisedHandBadge: string;
|
||||
participantRaisedHandIcon: string;
|
||||
participantSectionText: string;
|
||||
participantsPaneBackground: string;
|
||||
participantWarningText: string;
|
||||
preMeetingBackground: string;
|
||||
preMeetingPreview: string;
|
||||
prejoinActionButtonDanger: string;
|
||||
prejoinActionButtonDisabled: string;
|
||||
prejoinActionButtonPrimary: string;
|
||||
prejoinActionButtonPrimaryHover: string;
|
||||
prejoinActionButtonPrimaryText: string;
|
||||
prejoinActionButtonSecondary: string;
|
||||
prejoinActionButtonSecondaryHover: string;
|
||||
prejoinActionButtonSecondaryText: string;
|
||||
prejoinCountryPickerBackground: string;
|
||||
prejoinCountryPickerBorder: string;
|
||||
prejoinCountryPickerText: string;
|
||||
prejoinCountryRowBackground: string;
|
||||
prejoinCountryRowHover: string;
|
||||
prejoinDeviceStatusOk: string;
|
||||
prejoinDeviceStatusText: string;
|
||||
prejoinDeviceStatusWarning: string;
|
||||
prejoinDialogBackground: string;
|
||||
prejoinDialogDelimiter: string;
|
||||
prejoinDialogDelimiterText: string;
|
||||
prejoinRecordingWarningText: string;
|
||||
prejoinRoomNameText: string;
|
||||
prejoinTitleText: string;
|
||||
prejoinWarningBackground: string;
|
||||
prejoinWarningText: string;
|
||||
settingsBackground: string;
|
||||
settingsErrorIcon: string;
|
||||
settingsSectionBackground: string;
|
||||
settingsShortcutKey: string;
|
||||
settingsTabText: string;
|
||||
settingsVideoPreviewBorder: string;
|
||||
speakerStatsAvatarLeft: string;
|
||||
speakerStatsBackground: string;
|
||||
speakerStatsBorder: string;
|
||||
speakerStatsHeaderBackground: string;
|
||||
speakerStatsLabelText: string;
|
||||
speakerStatsRowAlternate: string;
|
||||
speakerStatsRowBackground: string;
|
||||
speakerStatsSearchBackground: string;
|
||||
speakerStatsSearchBorder: string;
|
||||
speakerStatsSearchIcon: string;
|
||||
speakerStatsSearchPlaceholder: string;
|
||||
speakerStatsSearchText: string;
|
||||
speakerStatsSuccessBar: string;
|
||||
thumbnailBackground: string;
|
||||
thumbnailBorder: string;
|
||||
thumbnailHover: string;
|
||||
thumbnailRaisedHandIcon: string;
|
||||
thumbnailTintBackground: string;
|
||||
thumbnailVideoBackground: string;
|
||||
toolbarButton: string;
|
||||
toolbarButtonActive: string;
|
||||
toolbarButtonHover: string;
|
||||
toolbarIcon: string;
|
||||
toolbarIconActive: string;
|
||||
toolbarIconHover: string;
|
||||
toolboxBackground: string;
|
||||
toolboxIconActive: string;
|
||||
toolboxIconHover: string;
|
||||
toolboxIconToggled: string;
|
||||
visitorsArrowBackground: string;
|
||||
visitorsCountBadge: string;
|
||||
visitorsCountIcon: string;
|
||||
visitorsCountText: string;
|
||||
visitorsQueueBackground: string;
|
||||
visitorsQueueText: string;
|
||||
welcomeBackground: string;
|
||||
welcomeCard: string;
|
||||
welcomeTabActive: string;
|
||||
welcomeTabInactive: string;
|
||||
|
||||
// Form components
|
||||
actionButtonBackground: string;
|
||||
actionButtonBorder: string;
|
||||
actionButtonText: string;
|
||||
audioRoutePickerBackground: string;
|
||||
audioRoutePickerBorder: string;
|
||||
audioRoutePickerText: string;
|
||||
baseReactBackground: string;
|
||||
baseReactBorder: string;
|
||||
baseReactText: string;
|
||||
carModeBackground: string;
|
||||
carModeBorder: string;
|
||||
carModeText: string;
|
||||
checkboxBorder: string;
|
||||
checkboxChecked: string;
|
||||
checkboxDisabledBackground: string;
|
||||
checkboxDisabledBorder: string;
|
||||
checkboxDisabledChecked: string;
|
||||
checkboxIcon: string;
|
||||
checkboxIconDisabled: string;
|
||||
checkboxLabel: string;
|
||||
clickableIconActive: string;
|
||||
clickableIconBackground: string;
|
||||
clickableIconFocus: string;
|
||||
clickableIconHover: string;
|
||||
conferenceNoticeBackground: string;
|
||||
conferenceNoticeText: string;
|
||||
conferenceRaisedHandLabelIcon: string;
|
||||
conferenceRaisedHandLabelText: string;
|
||||
conferenceSubjectText: string;
|
||||
conferenceTimerText: string;
|
||||
connectionIndicatorLost: string;
|
||||
connectionIndicatorOther: string;
|
||||
deepLinkingBackground: string;
|
||||
deepLinkingBorder: string;
|
||||
deepLinkingLabelText: string;
|
||||
deepLinkingLink: string;
|
||||
deepLinkingSeparator: string;
|
||||
deepLinkingText: string;
|
||||
deviceSelectorBackground: string;
|
||||
deviceSelectorBorder: string;
|
||||
deviceSelectorText: string;
|
||||
deviceSelectorTextBackground: string;
|
||||
deviceSelectorVideoPreview: string;
|
||||
dialInBackground: string;
|
||||
dialInSecondaryText: string;
|
||||
dialInText: string;
|
||||
displayNameBackground: string;
|
||||
displayNameText: string;
|
||||
etherpadBackground: string;
|
||||
etherpadText: string;
|
||||
fileSharingBackground: string;
|
||||
fileSharingEmptyIcon: string;
|
||||
fileSharingEmptyText: string;
|
||||
fileSharingItemBackground: string;
|
||||
fileSharingItemBorder: string;
|
||||
fileSharingText: string;
|
||||
gifsBackground: string;
|
||||
gifsText: string;
|
||||
inlineDialogBackground: string;
|
||||
inlineDialogBorder: string;
|
||||
inlineDialogText: string;
|
||||
inputBottomLabel: string;
|
||||
inputBottomLabelError: string;
|
||||
inputClearButton: string;
|
||||
inputFieldBackground: string;
|
||||
inputFieldBorder: string;
|
||||
inputFieldDisabled: string;
|
||||
inputFieldError: string;
|
||||
inputFieldFocus: string;
|
||||
inputFieldPlaceholder: string;
|
||||
inputFieldText: string;
|
||||
inputLabel: string;
|
||||
labelBackground: string;
|
||||
labelText: string;
|
||||
labelWhiteBackground: string;
|
||||
labelWhiteIcon: string;
|
||||
labelWhiteText: string;
|
||||
languageSelectorBackground: string;
|
||||
languageSelectorHover: string;
|
||||
languageSelectorText: string;
|
||||
listItemBackground: string;
|
||||
listItemBoxShadow: string;
|
||||
listItemHighlighted: string;
|
||||
listItemHover: string;
|
||||
listItemText: string;
|
||||
multiSelectBackground: string;
|
||||
multiSelectBorder: string;
|
||||
multiSelectItemDisabled: string;
|
||||
multiSelectItemHover: string;
|
||||
multiSelectItemText: string;
|
||||
pollsAnswer: string;
|
||||
pollsBackground: string;
|
||||
pollsBarBackground: string;
|
||||
pollsBarPercentage: string;
|
||||
pollsCreateBackground: string;
|
||||
pollsCreateBorder: string;
|
||||
pollsPaneBackground: string;
|
||||
pollsPaneBorder: string;
|
||||
pollsQuestion: string;
|
||||
pollsSendDisabled: string;
|
||||
pollsSendLabel: string;
|
||||
pollsSeparator: string;
|
||||
pollsSubtitle: string;
|
||||
pollsTitle: string;
|
||||
pollsVotersBackground: string;
|
||||
pollsVotersText: string;
|
||||
reactionsMenuBackground: string;
|
||||
reactionsMenuBorder: string;
|
||||
recordingBackground: string;
|
||||
recordingHighlightButton: string;
|
||||
recordingHighlightButtonDisabled: string;
|
||||
recordingHighlightButtonIcon: string;
|
||||
recordingHighlightButtonIconDisabled: string;
|
||||
recordingNotificationAction: string;
|
||||
recordingNotificationText: string;
|
||||
recordingText: string;
|
||||
securityDialogBackground: string;
|
||||
securityDialogBorder: string;
|
||||
securityDialogSecondaryText: string;
|
||||
securityDialogText: string;
|
||||
selectBackground: string;
|
||||
selectBottomLabel: string;
|
||||
selectBottomLabelError: string;
|
||||
selectDisabled: string;
|
||||
selectError: string;
|
||||
selectFocus: string;
|
||||
selectIcon: string;
|
||||
selectIconDisabled: string;
|
||||
selectLabel: string;
|
||||
selectText: string;
|
||||
sliderFocus: string;
|
||||
sliderKnob: string;
|
||||
sliderTrack: string;
|
||||
subtitleMessageBackground: string;
|
||||
subtitleMessageSender: string;
|
||||
subtitleMessageText: string;
|
||||
subtitleMessageTime: string;
|
||||
switchBackground: string;
|
||||
switchBackgroundOn: string;
|
||||
switchFocus: string;
|
||||
switchToggle: string;
|
||||
switchToggleDisabled: string;
|
||||
tabBadgeBackground: string;
|
||||
tabBadgeText: string;
|
||||
tabBorder: string;
|
||||
tabBorderDisabled: string;
|
||||
tabBorderHover: string;
|
||||
tabBorderSelected: string;
|
||||
tabFocus: string;
|
||||
tabText: string;
|
||||
tabTextDisabled: string;
|
||||
tabTextHover: string;
|
||||
tabTextSelected: string;
|
||||
tooltipBackground: string;
|
||||
tooltipText: string;
|
||||
videoMenuBackground: string;
|
||||
videoMenuBorder: string;
|
||||
videoMenuSliderBackground: string;
|
||||
videoMenuText: string;
|
||||
videoQualityBackground: string;
|
||||
videoQualityText: string;
|
||||
virtualBackgroundBackground: string;
|
||||
virtualBackgroundBorder: string;
|
||||
virtualBackgroundPreview: string;
|
||||
virtualBackgroundText: string;
|
||||
whiteboardBackground: string;
|
||||
whiteboardText: string;
|
||||
salesforceSearchBackground: string;
|
||||
salesforceSearchBorder: string;
|
||||
salesforceSearchIcon: string;
|
||||
salesforceSearchPlaceholder: string;
|
||||
salesforceSearchText: string;
|
||||
}
|
||||
|
||||
export interface ITypography {
|
||||
|
||||
@@ -11,13 +11,49 @@ import * as tokens from './tokens.json';
|
||||
*/
|
||||
export function createColorTokens(colorMap: Object): any {
|
||||
const allTokens = merge({}, tokens, jitsiTokens);
|
||||
const result: any = {};
|
||||
|
||||
return Object.entries(colorMap)
|
||||
.reduce((result, [ token, value ]: [any, string]) => {
|
||||
const color = allTokens[value as keyof typeof allTokens] || value;
|
||||
// First pass: resolve tokens that reference allTokens directly
|
||||
Object.entries(colorMap).forEach(([ token, value ]: [any, string]) => {
|
||||
const color = allTokens[value as keyof typeof allTokens] || value;
|
||||
|
||||
return Object.assign(result, { [token]: color });
|
||||
}, {});
|
||||
result[token] = color;
|
||||
});
|
||||
|
||||
// Second pass: resolve semantic tokens that reference other colorMap entries
|
||||
// Recursively resolve until we get actual color values
|
||||
const resolveToken = (value: string, depth = 0): string => {
|
||||
// Prevent infinite loops
|
||||
if (depth > 10) {
|
||||
return value;
|
||||
}
|
||||
|
||||
// If it's already a color (starts with # or rgb/rgba), return it
|
||||
if (value.startsWith('#') || value.startsWith('rgb')) {
|
||||
return value;
|
||||
}
|
||||
|
||||
// Look up in the result map first (for colorMap token references)
|
||||
if (result[value]) {
|
||||
return resolveToken(result[value], depth + 1);
|
||||
}
|
||||
|
||||
// Then look up in allTokens
|
||||
const resolved = allTokens[value as keyof typeof allTokens];
|
||||
|
||||
if (resolved && resolved !== value && typeof resolved === 'string') {
|
||||
return resolveToken(resolved, depth + 1);
|
||||
}
|
||||
|
||||
return value;
|
||||
};
|
||||
|
||||
// Third pass: recursively resolve all values
|
||||
Object.entries(result).forEach(([ token, value ]) => {
|
||||
result[token] = resolveToken(String(value));
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -22,7 +22,6 @@ export function assignIfDefined(target: Object, source: Object) {
|
||||
return to;
|
||||
}
|
||||
|
||||
|
||||
const MATCH_OPERATOR_REGEXP = /[|\\{}()[\]^$+*?.-]/g;
|
||||
|
||||
/**
|
||||
@@ -79,6 +78,21 @@ export function getJitsiMeetGlobalNS() {
|
||||
return window.JitsiMeetJS.app;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the Electron-specific global namespace.
|
||||
*
|
||||
* @returns {Object} The Electron namespace.
|
||||
*/
|
||||
export function getElectronGlobalNS() {
|
||||
const globalNS = getJitsiMeetGlobalNS();
|
||||
|
||||
if (!globalNS.electron) {
|
||||
globalNS.electron = {};
|
||||
}
|
||||
|
||||
return globalNS.electron;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the object that stores the connection times.
|
||||
*
|
||||
|
||||
@@ -8,7 +8,7 @@ export default {
|
||||
|
||||
button: {
|
||||
marginBottom: BaseTheme.spacing[4],
|
||||
marginHorizontal: BaseTheme.spacing[2]
|
||||
marginHorizontal: BaseTheme.spacing[3]
|
||||
},
|
||||
|
||||
collapsibleList: {
|
||||
|
||||
@@ -44,6 +44,16 @@ export const getMainRoom = (stateful: IStateful) => {
|
||||
* @returns {IRoomsInfo} The rooms info.
|
||||
*/
|
||||
export const getRoomsInfo = (stateful: IStateful) => {
|
||||
const state = toState(stateful);
|
||||
const localParticipant = getLocalParticipant(stateful);
|
||||
const jwtUser = state['features/base/jwt']?.user;
|
||||
const localUserContext = jwtUser ? {
|
||||
id: jwtUser.id,
|
||||
name: jwtUser.name
|
||||
} : {
|
||||
id: localParticipant?.jwtId,
|
||||
name: localParticipant?.name
|
||||
};
|
||||
const breakoutRooms = getBreakoutRooms(stateful);
|
||||
const conference = getCurrentConference(stateful);
|
||||
|
||||
@@ -57,7 +67,6 @@ export const getRoomsInfo = (stateful: IStateful) => {
|
||||
const conferenceParticipants = conference?.getParticipants()
|
||||
.filter((participant: IJitsiParticipant) => !participant.isHidden());
|
||||
|
||||
const localParticipant = getLocalParticipant(stateful);
|
||||
let localParticipantInfo;
|
||||
|
||||
if (localParticipant) {
|
||||
@@ -65,7 +74,8 @@ export const getRoomsInfo = (stateful: IStateful) => {
|
||||
role: localParticipant.role,
|
||||
displayName: localParticipant.name,
|
||||
avatarUrl: localParticipant.loadableAvatarUrl,
|
||||
id: localParticipant.id
|
||||
id: localParticipant.id,
|
||||
userContext: localUserContext
|
||||
};
|
||||
}
|
||||
|
||||
@@ -86,7 +96,8 @@ export const getRoomsInfo = (stateful: IStateful) => {
|
||||
role: participantItem.getRole(),
|
||||
displayName: participantItem.getDisplayName(),
|
||||
avatarUrl: storeParticipant?.loadableAvatarUrl,
|
||||
id: participantItem.getId()
|
||||
id: participantItem.getId(),
|
||||
userContext: storeParticipant?.userContext
|
||||
} as IRoomInfoParticipant;
|
||||
}) ]
|
||||
: [ localParticipantInfo ]
|
||||
@@ -110,13 +121,18 @@ export const getRoomsInfo = (stateful: IStateful) => {
|
||||
const storeParticipant = getParticipantById(stateful,
|
||||
ids.length > 1 ? ids[1] : participantItem.jid);
|
||||
|
||||
// Check if this is the local participant
|
||||
const isLocal = storeParticipant?.id === localParticipant?.id;
|
||||
const userContext = isLocal ? localUserContext : (storeParticipant?.userContext || participantItem.userContext);
|
||||
|
||||
return {
|
||||
jid: participantItem?.jid,
|
||||
role: participantItem?.role,
|
||||
displayName: participantItem?.displayName,
|
||||
avatarUrl: storeParticipant?.loadableAvatarUrl,
|
||||
id: storeParticipant ? storeParticipant.id
|
||||
: participantLongId
|
||||
: participantLongId,
|
||||
userContext
|
||||
} as IRoomInfoParticipant;
|
||||
}) : []
|
||||
} as IRoomInfo;
|
||||
|
||||
@@ -44,19 +44,59 @@ MiddlewareRegistry.register(({ dispatch, getState }) => next => action => {
|
||||
|
||||
switch (type) {
|
||||
case UPDATE_BREAKOUT_ROOMS: {
|
||||
// edit name if it was overwritten
|
||||
// Enrich participants with userContext from Redux store
|
||||
if (!action.updatedNames) {
|
||||
const { overwrittenNameList } = getState()['features/base/participants'];
|
||||
const state = getState();
|
||||
const { overwrittenNameList, local: localParticipant } = state['features/base/participants'];
|
||||
const jwtUser = state['features/base/jwt']?.user;
|
||||
const localUserContext = jwtUser ? {
|
||||
id: jwtUser.id,
|
||||
name: jwtUser.name
|
||||
} : {
|
||||
id: localParticipant?.jwtId,
|
||||
name: localParticipant?.name
|
||||
};
|
||||
|
||||
if (Object.keys(overwrittenNameList).length > 0) {
|
||||
const newRooms: IRooms = {};
|
||||
// Get existing userContext cache
|
||||
const existingCache = state['features/breakout-rooms'].userContextCache || {};
|
||||
const newCache = { ...existingCache };
|
||||
|
||||
Object.entries(action.rooms as IRooms).forEach(([ key, r ]) => {
|
||||
let participants = r?.participants || {};
|
||||
let jid;
|
||||
const newRooms: IRooms = {};
|
||||
|
||||
Object.entries(action.rooms as IRooms).forEach(([ key, r ]) => {
|
||||
let participants = r?.participants || {};
|
||||
|
||||
// Add userContext to each participant
|
||||
const enhancedParticipants: typeof participants = {};
|
||||
|
||||
for (const [ participantJid, participantData ] of Object.entries(participants)) {
|
||||
const ids = participantJid.split('/');
|
||||
const participantId = ids.length > 1 ? ids[1] : participantData.jid;
|
||||
const storeParticipant = getParticipantById(state, participantId);
|
||||
const isLocal = storeParticipant?.id === localParticipant?.id;
|
||||
|
||||
// Try to get userContext from: local, store, cache, or incoming data
|
||||
const userContext = isLocal
|
||||
? localUserContext
|
||||
: (storeParticipant?.userContext || newCache[participantId] || participantData.userContext);
|
||||
|
||||
// Update cache if we have userContext
|
||||
if (userContext && participantId) {
|
||||
newCache[participantId] = userContext;
|
||||
}
|
||||
|
||||
enhancedParticipants[participantJid] = {
|
||||
...participantData,
|
||||
userContext
|
||||
};
|
||||
}
|
||||
|
||||
participants = enhancedParticipants;
|
||||
|
||||
// Apply overwritten display names
|
||||
if (Object.keys(overwrittenNameList).length > 0) {
|
||||
for (const id of Object.keys(overwrittenNameList)) {
|
||||
jid = Object.keys(participants).find(p => p.slice(p.indexOf('/') + 1) === id);
|
||||
const jid = Object.keys(participants).find(p => p.slice(p.indexOf('/') + 1) === id);
|
||||
|
||||
if (jid) {
|
||||
participants = {
|
||||
@@ -68,15 +108,16 @@ MiddlewareRegistry.register(({ dispatch, getState }) => next => action => {
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
newRooms[key] = {
|
||||
...r,
|
||||
participants
|
||||
};
|
||||
});
|
||||
newRooms[key] = {
|
||||
...r,
|
||||
participants
|
||||
};
|
||||
});
|
||||
|
||||
action.rooms = newRooms;
|
||||
}
|
||||
action.rooms = newRooms;
|
||||
action.userContextCache = newCache;
|
||||
}
|
||||
|
||||
// edit the chat history to match names for participants in breakout rooms
|
||||
|
||||
@@ -10,12 +10,19 @@ import { IRooms } from './types';
|
||||
|
||||
const DEFAULT_STATE = {
|
||||
rooms: {},
|
||||
roomCounter: 0
|
||||
roomCounter: 0,
|
||||
userContextCache: {}
|
||||
};
|
||||
|
||||
export interface IBreakoutRoomsState {
|
||||
roomCounter: number;
|
||||
rooms: IRooms;
|
||||
userContextCache: {
|
||||
[participantId: string]: {
|
||||
id?: string;
|
||||
name?: string;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -29,12 +36,13 @@ ReducerRegistry.register<IBreakoutRoomsState>(FEATURE_KEY, (state = DEFAULT_STAT
|
||||
roomCounter: action.roomCounter
|
||||
};
|
||||
case UPDATE_BREAKOUT_ROOMS: {
|
||||
const { roomCounter, rooms } = action;
|
||||
const { roomCounter, rooms, userContextCache } = action;
|
||||
|
||||
return {
|
||||
...state,
|
||||
roomCounter,
|
||||
rooms
|
||||
rooms,
|
||||
userContextCache: userContextCache || state.userContextCache
|
||||
};
|
||||
}
|
||||
case _RESET_BREAKOUT_ROOMS: {
|
||||
|
||||
@@ -8,6 +8,10 @@ export interface IRoom {
|
||||
displayName: string;
|
||||
jid: string;
|
||||
role: string;
|
||||
userContext?: {
|
||||
id?: string;
|
||||
name?: string;
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -33,4 +37,8 @@ export interface IRoomInfoParticipant {
|
||||
id: string;
|
||||
jid: string;
|
||||
role: string;
|
||||
userContext?: {
|
||||
id?: string;
|
||||
name?: string;
|
||||
};
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user