diff --git a/README.md b/README.md
index debb4230..cb4ec06f 100644
--- a/README.md
+++ b/README.md
@@ -77,5 +77,8 @@ can be found here: [config.example.js](public/config/config.example.js).
| logo | If not null, it shows the logo loaded from the specified URL, otherwise it shows the title. | `"url"` | ``"images/logo.edumeet.svg"`` |
| title | The title to show if the logo is not specified. | `"string"` | ``"edumeet"`` |
| randomizeOnBlank | Enable or disable randomize room name when it is blank. | `"boolean"` | ``true`` |
+| transcriptionEnabled | Enable or disable transcription. | `"boolean"` | ``true`` |
+| imprintUrl | Show a link to an imprint in the edumeet UI, keep blank to not show a link | `"string"` | ``""`` |
+| privacyUrl | Show a link to a privacy notice in the edumeet UI, keep blank to not show a link | `"string"` | ``""`` |
---
diff --git a/public/config/config.example.js b/public/config/config.example.js
index 8931c694..132d2132 100644
--- a/public/config/config.example.js
+++ b/public/config/config.example.js
@@ -146,6 +146,15 @@ var config = {
// otherwise, it will remain empty and users will have to enter a room name.
randomizeOnBlank: true,
+ // Enable or disable transcription.
+ transcriptionEnabled: true,
+
+ // Imprint. If you want to link your imprint, please provide a URL in this variable. If it is empty, no link will be shown.
+ imprintUrl: '',
+
+ // Privacy notice. If you want to link your privacy notices, please provide a URL in this variable. If it is empty, no link will be shown.
+ privacyUrl: '',
+
// Client theme. Take a look at mui theme documentation.
theme: {
palette: {
diff --git a/src/App.tsx b/src/App.tsx
index 481c90cc..ced67581 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -69,6 +69,9 @@ const App = (): JSX.Element => {
if (roomState ==='left') {
dispatch(roomActions.setState('new'));
navigate('/');
+ setTimeout(() => {
+ window.location.reload();
+ }, 0);
}
}, [ roomState ]);
diff --git a/src/components/controlbuttons/ImpressumButton.tsx b/src/components/controlbuttons/ImpressumButton.tsx
deleted file mode 100644
index c9020051..00000000
--- a/src/components/controlbuttons/ImpressumButton.tsx
+++ /dev/null
@@ -1,28 +0,0 @@
-import InfoIcon from '@mui/icons-material/Info';
-import React from 'react';
-import { Box, Button } from '@mui/material';
-import { styled } from '@mui/material/styles';
-import edumeetConfig from '../../utils/edumeetConfig';
-
-const ImpressumContainer = styled(Box)(({ theme }) => ({
- position: 'absolute',
- bottom: theme.spacing(1.5),
- left: theme.spacing(1.5),
- color: 'white',
-}));
-
-const impressumUrl = edumeetConfig.impressumUrl;
-
-const ImpressumButton: React.FC = () => {
- return (
-
-
-
-
-
-
-
- );
-};
-
-export default ImpressumButton;
\ No newline at end of file
diff --git a/src/components/helpdialog/HelpDialog.tsx b/src/components/helpdialog/HelpDialog.tsx
index cf3dde71..b878d61f 100644
--- a/src/components/helpdialog/HelpDialog.tsx
+++ b/src/components/helpdialog/HelpDialog.tsx
@@ -1,11 +1,11 @@
-import { Button } from '@mui/material';
+import { Button, Box, Link, Typography } from '@mui/material';
import { Close } from '@mui/icons-material';
import { useAppDispatch, useAppSelector } from '../../store/hooks';
import { uiActions } from '../../store/slices/uiSlice';
-import { closeLabel } from '../translated/translatedComponents';
+import { closeLabel, imprintLabel, privacyLabel } from '../translated/translatedComponents';
import ShortcutKeys from './ShortcutKeys';
import GenericDialog from '../genericdialog/GenericDialog';
-import ImpressumButton from '../controlbuttons/ImpressumButton';
+import edumeetConfig from '../../utils/edumeetConfig';
const HelpDialog = (): JSX.Element => {
const dispatch = useAppDispatch();
@@ -17,24 +17,41 @@ const HelpDialog = (): JSX.Element => {
}));
};
+ const privacyUrl = edumeetConfig.privacyUrl ?? '';
+ const imprintUrl = edumeetConfig.imprintUrl ?? '';
+
return (
> }
+ content={ <> > }
actions={
- }
- variant='contained'
- size='small'
- >
- { closeLabel() }
-
+
+
+ {imprintUrl.trim() !== '' && (
+
+ { imprintLabel() }
+
+ )}
+ {privacyUrl.trim() !== '' && (
+
+ { privacyLabel() }
+
+ )}
+
+ }
+ variant='contained'
+ size='small'
+ >
+ { closeLabel() }
+
+
}
/>
);
};
-export default HelpDialog;
\ No newline at end of file
+export default HelpDialog;
diff --git a/src/components/translated/translatedComponents.tsx b/src/components/translated/translatedComponents.tsx
index 74d58f0f..3df87d8d 100644
--- a/src/components/translated/translatedComponents.tsx
+++ b/src/components/translated/translatedComponents.tsx
@@ -805,4 +805,13 @@ export const managementExtraSettingsLabel = (): string => intl.formatMessage({
export const ruleSettingsLabel = (): string => intl.formatMessage({
id: 'label.managementRuleSettings',
defaultMessage: 'Rule settings'
+
+export const imprintLabel = (): string => intl.formatMessage({
+ id: 'label.imprint',
+ defaultMessage: 'Imprint'
+});
+
+export const privacyLabel = (): string => intl.formatMessage({
+ id: 'label.privacy',
+ defaultMessage: 'Privacy'
});
diff --git a/src/components/volume/MicVolume.tsx b/src/components/volume/MicVolume.tsx
new file mode 100644
index 00000000..b02a27c1
--- /dev/null
+++ b/src/components/volume/MicVolume.tsx
@@ -0,0 +1,46 @@
+import LinearProgress from '@mui/material/LinearProgress';
+import { useContext, useEffect, useState } from 'react';
+import { ServiceContext } from '../../store/store';
+import { VolumeWatcher } from '../../utils/volumeWatcher';
+import hark from 'hark';
+
+const MicVolume = (): JSX.Element => {
+ const { mediaService } = useContext(ServiceContext);
+ const [ volumeLevel, setVolume ] = useState(0);
+
+ useEffect(() => {
+ let volumeWatcher: VolumeWatcher | undefined;
+
+ // Add hark for mic
+ if (mediaService.previewMicTrack) {
+ const harkStream = new MediaStream();
+
+ harkStream.addTrack(mediaService.previewMicTrack.clone());
+
+ const micHark = hark(harkStream, {
+ play: false,
+ interval: 100,
+ threshold: -60,
+ history: 100
+ });
+
+ volumeWatcher = new VolumeWatcher({ hark: micHark });
+ }
+
+ const onVolumeChange = ({ scaledVolume }: { scaledVolume: number }): void => {
+ setVolume(scaledVolume*10); // Range: 0-100
+ };
+
+ volumeWatcher?.on('volumeChange', onVolumeChange);
+
+ return () => {
+ volumeWatcher?.off('volumeChange', onVolumeChange);
+ };
+ }, [ mediaService.previewMicTrack ]);
+
+ return (
+
+ );
+};
+
+export default MicVolume;
diff --git a/src/services/mediaService.tsx b/src/services/mediaService.tsx
index 39fa7913..315dee44 100644
--- a/src/services/mediaService.tsx
+++ b/src/services/mediaService.tsx
@@ -17,6 +17,7 @@ import { ProducerSource } from '../utils/types';
import { MediaSender } from '../utils/mediaSender';
import type { ClientMonitor } from '@observertc/client-monitor-js';
import { Logger } from '../utils/Logger';
+import edumeetConfig from '../utils/edumeetConfig';
const logger = new Logger('MediaService');
@@ -665,7 +666,7 @@ export class MediaService extends EventEmitter {
get localCapabilities(): LocalCapabilities {
return {
canRecord: Boolean(MediaRecorder),
- canTranscribe: Boolean(window.webkitSpeechRecognition),
+ canTranscribe: Boolean(window.webkitSpeechRecognition) && edumeetConfig.transcriptionEnabled,
};
}
diff --git a/src/translations/de.json b/src/translations/de.json
index f48e7735..7296e166 100644
--- a/src/translations/de.json
+++ b/src/translations/de.json
@@ -59,6 +59,7 @@
"label.fullscreen": "Vollbild",
"label.guest": null,
"label.high": "Hoch (HD)",
+ "label.imprint": "Impressum",
"label.italic": "kursiv",
"label.join": "Eintreten",
"label.joinBreakoutRoom": null,
@@ -77,6 +78,7 @@
"label.openSettings": null,
"label.participants": "Teilnehmer",
"label.password": "Passwort",
+ "label.privacy": "Datenschutz",
"label.promoteAllPeers": "Alle Teilnehmer reinlassen",
"label.recordingInProgress": "Aufnahme läuft...",
"label.removeBreakoutRoom": null,
diff --git a/src/utils/types.tsx b/src/utils/types.tsx
index 0ab2ef4c..fab7e8e5 100644
--- a/src/utils/types.tsx
+++ b/src/utils/types.tsx
@@ -3,7 +3,6 @@ import { TFLite } from '../services/effectsService';
export const defaultEdumeetConfig: EdumeetConfig = {
managementUrl: undefined,
- impressumUrl: '/privacy/privacy.html',
p2penabled: false,
loginEnabled: false,
developmentPort: 8443,
@@ -78,6 +77,7 @@ export const defaultEdumeetConfig: EdumeetConfig = {
},
title: 'edumeet',
randomizeOnBlank: true,
+ transcriptionEnabled: true,
theme: {
background: 'linear-gradient(135deg, rgba(1,42,74,1) 0%, rgba(1,58,99,1) 50%, rgba(1,73,124,1) 100%)',
appBarColor: 'rgba(0, 0, 0, 0.4)',
@@ -91,12 +91,13 @@ export const defaultEdumeetConfig: EdumeetConfig = {
sideContentItemDarkColor: 'rgba(150, 150, 150, 0.4)',
sideContainerBackgroundColor: 'rgba(255, 255, 255, 0.7)',
},
- reduxLoggingEnabled: false
+ reduxLoggingEnabled: false,
+ imprintUrl: '',
+ privacyUrl: ''
};
export interface EdumeetConfig {
managementUrl?: string;
- impressumUrl: string;
p2penabled: boolean;
loginEnabled: boolean;
developmentPort: number;
@@ -129,8 +130,11 @@ export interface EdumeetConfig {
notificationSounds: Record;
title: string;
randomizeOnBlank: boolean;
+ transcriptionEnabled: boolean;
theme: ThemeOptions;
reduxLoggingEnabled: boolean;
+ imprintUrl: string;
+ privacyUrl: string;
}
export interface HTMLMediaElementWithSink extends HTMLMediaElement {
diff --git a/src/views/join/Join.tsx b/src/views/join/Join.tsx
index 535b13ce..8f81def9 100644
--- a/src/views/join/Join.tsx
+++ b/src/views/join/Join.tsx
@@ -1,8 +1,8 @@
import { useEffect } from 'react';
-import { Button } from '@mui/material';
+import { Button, Box, Link, Typography } from '@mui/material';
import TextInputField from '../../components/textinputfield/TextInputField';
import { useAppDispatch, useAppSelector, useNotifier } from '../../store/hooks';
-import { joinLabel, yourNameLabel } from '../../components/translated/translatedComponents';
+import { joinLabel, yourNameLabel, imprintLabel, privacyLabel } from '../../components/translated/translatedComponents';
import { AccountCircle } from '@mui/icons-material';
import MediaPreview from '../../components/mediapreview/MediaPreview';
import AudioInputChooser from '../../components/devicechooser/AudioInputChooser';
@@ -18,7 +18,10 @@ import { meActions } from '../../store/slices/meSlice';
import AudioOutputChooser from '../../components/devicechooser/AudioOutputChooser';
import { canSelectAudioOutput } from '../../store/selectors';
import TestAudioOutputButton from '../../components/audiooutputtest/AudioOutputTest';
+import edumeetConfig from '../../utils/edumeetConfig';
import ImpressumButton from '../../components/controlbuttons/ImpressumButton';
+import MicVolume from '../../components/volume/MicVolume';
+
interface JoinProps {
roomId: string;
@@ -61,6 +64,9 @@ const Join = ({ roomId }: JoinProps): React.JSX.Element => {
}
}, []);
+ const privacyUrl = edumeetConfig.privacyUrl ?? '';
+ const imprintUrl = edumeetConfig.imprintUrl ?? '';
+
return (
}
@@ -70,6 +76,7 @@ const Join = ({ roomId }: JoinProps): React.JSX.Element => {
{ showAudioOutputChooser && }
+
@@ -85,15 +92,28 @@ const Join = ({ roomId }: JoinProps): React.JSX.Element => {
>
}
actions={
- <>
- {joinLabel()}
- >
-
+
+
+ {imprintUrl.trim() !== '' && (
+
+ { imprintLabel() }
+
+ )}
+ {privacyUrl.trim() !== '' && (
+
+ { privacyLabel() }
+
+ )}
+
+
+ { joinLabel() }
+
+
}
/>
);
diff --git a/src/views/landingpage/LandingPage.tsx b/src/views/landingpage/LandingPage.tsx
index 52467bf0..3882d159 100644
--- a/src/views/landingpage/LandingPage.tsx
+++ b/src/views/landingpage/LandingPage.tsx
@@ -1,14 +1,13 @@
import { useState } from 'react';
import { useNavigate } from 'react-router-dom';
-import { Button, Container } from '@mui/material';
+import { Button, Container, Box, Link, Typography } from '@mui/material';
import randomString from 'random-string';
import TextInputField from '../../components/textinputfield/TextInputField';
-import { joinLabel, roomNameLabel } from '../../components/translated/translatedComponents';
+import { joinLabel, roomNameLabel, imprintLabel, privacyLabel } from '../../components/translated/translatedComponents';
import GenericDialog from '../../components/genericdialog/GenericDialog';
import StyledBackground from '../../components/StyledBackground';
import PrecallTitle from '../../components/precalltitle/PrecallTitle';
import { QRCode } from 'react-qrcode-logo';
-import ImpressumButton from '../../components/controlbuttons/ImpressumButton';
import edumeetConfig from '../../utils/edumeetConfig';
const LandingPage = (): JSX.Element => {
@@ -17,6 +16,9 @@ const LandingPage = (): JSX.Element => {
const [ roomId, setRoomId ] = useState(randomizeOnBlank ? randomString({ length: 8 }).toLowerCase() : '');
const onClicked = () => navigate(`/${roomId}`);
+ const privacyUrl = edumeetConfig.privacyUrl ?? '';
+ const imprintUrl = edumeetConfig.imprintUrl ?? '';
+
return (
{
}
actions={
- <>
+
+
+ {imprintUrl.trim() !== '' && (
+
+ { imprintLabel() }
+
+ )}
+ {privacyUrl.trim() !== '' && (
+
+ { privacyLabel() }
+
+ )}
+
{
size='small'
>
{ joinLabel()}
- >
+
+
}
/>
@@ -52,4 +67,4 @@ const LandingPage = (): JSX.Element => {
);
};
-export default LandingPage;
\ No newline at end of file
+export default LandingPage;
diff --git a/src/views/lobby/Lobby.tsx b/src/views/lobby/Lobby.tsx
index a4a1a038..21bcfa1e 100644
--- a/src/views/lobby/Lobby.tsx
+++ b/src/views/lobby/Lobby.tsx
@@ -1,11 +1,12 @@
import { AccountCircle } from '@mui/icons-material';
+import { Box, Link, Typography } from '@mui/material';
import { useState } from 'react';
import AudioInputChooser from '../../components/devicechooser/AudioInputChooser';
import VideoInputChooser from '../../components/devicechooser/VideoInputChooser';
import MediaPreview from '../../components/mediapreview/MediaPreview';
import GenericDialog from '../../components/genericdialog/GenericDialog';
import TextInputField from '../../components/textinputfield/TextInputField';
-import { roomLockedLabel, yourNameLabel } from '../../components/translated/translatedComponents';
+import { roomLockedLabel, yourNameLabel, imprintLabel, privacyLabel } from '../../components/translated/translatedComponents';
import { setDisplayName } from '../../store/actions/meActions';
import {
useAppDispatch,
@@ -17,6 +18,7 @@ import { ChooserDiv } from '../../components/devicechooser/DeviceChooser';
import AudioOutputChooser from '../../components/devicechooser/AudioOutputChooser';
import { canSelectAudioOutput } from '../../store/selectors';
import TestAudioOutputButton from '../../components/audiooutputtest/AudioOutputTest';
+import edumeetConfig from '../../utils/edumeetConfig';
const Lobby = (): React.JSX.Element => {
useNotifier();
@@ -32,6 +34,9 @@ const Lobby = (): React.JSX.Element => {
));
};
+ const privacyUrl = edumeetConfig.privacyUrl ?? '';
+ const imprintUrl = edumeetConfig.imprintUrl ?? '';
+
return (
}
@@ -53,9 +58,25 @@ const Lobby = (): React.JSX.Element => {
>
}
- actions={roomLockedLabel()}
+ actions={
+
+ {roomLockedLabel()}
+
+ {imprintUrl.trim() !== '' && (
+
+ { imprintLabel() }
+
+ )}
+ {privacyUrl.trim() !== '' && (
+
+ { privacyLabel() }
+
+ )}
+
+
+ }
/>
);
};
-export default Lobby;
\ No newline at end of file
+export default Lobby;
diff --git a/src/views/unsupported/UnsupportedBrowser.tsx b/src/views/unsupported/UnsupportedBrowser.tsx
index 00ef8cc2..33ac9fca 100644
--- a/src/views/unsupported/UnsupportedBrowser.tsx
+++ b/src/views/unsupported/UnsupportedBrowser.tsx
@@ -8,13 +8,17 @@ import {
List,
ListItem,
ListItemAvatar,
- ListItemText
+ ListItemText,
+ Link,
+ Typography
} from '@mui/material';
import WebAssetIcon from '@mui/icons-material/WebAsset';
import ErrorIcon from '@mui/icons-material/Error';
import { FormattedMessage } from 'react-intl';
import { memo } from 'react';
import { RawStyledDialog } from '../../components/genericdialog/GenericDialog';
+import { imprintLabel, privacyLabel } from '../../components/translated/translatedComponents';
+import edumeetConfig from '../../utils/edumeetConfig';
interface UnsupportedBrowserProps {
platform: string;
@@ -39,6 +43,9 @@ const UnsupportedBrowser = ({
if (platform !== 'desktop')
dense = true;
+ const privacyUrl = edumeetConfig.privacyUrl ?? '';
+ const imprintUrl = edumeetConfig.imprintUrl ?? '';
+
return (
+
+ {imprintUrl.trim() !== '' && (
+
+ { imprintLabel() }
+
+ )}
+ {privacyUrl.trim() !== '' && (
+
+ { privacyLabel() }
+
+ )}
+
);
};
-export default memo(UnsupportedBrowser);
\ No newline at end of file
+export default memo(UnsupportedBrowser);