Skip to content

Commit e118703

Browse files
authored
Merge branch 'develop' into behei-vonage/precall-testr
2 parents 8a1f3e7 + 3f48e8a commit e118703

File tree

32 files changed

+1341
-92
lines changed

32 files changed

+1341
-92
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ This application provides features for common conferencing use cases, such as:
6565
<img src="docs/assets/NoiseSupression.png" alt="Screenshot of noise supression toggle">
6666
</details>
6767
- <details>
68-
<summary>Background effects in meeting and waiting room. You can set predefined images, custom image or slight/strong background blur. Images can be uploaded from local device or URL in these formats: JPG, PNG, GIF or BMP.</summary>
68+
<summary>Background effects in meeting and waiting room. You can set predefined images, custom image or slight/strong background blur. Images can be uploaded from local device or URL in these formats: JPG, PNG, GIF or BMP. Background effects are not supported in non-Chromium-based browsers or on iOS. </summary>
6969
<img src="docs/assets/BGEffects.png" alt="Screenshot of background effects">
7070
</details>
7171
- <details>

backend/routes/wellKnown.ts

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,26 @@ wellKnownRouter.get('/assetlinks.json', (_req: Request, res: Response) => {
1414
target: {
1515
namespace: 'android_app',
1616
// Package name for the Android app
17-
package_name: 'com.vonage.android',
17+
package_name: 'com.vonage.android.debug',
1818
// SHA-256 certificate fingerprints for the Android app
1919
sha256_cert_fingerprints: [
2020
'A4:26:72:80:DA:75:99:75:ED:D2:32:ED:0A:DC:2C:7C:27:78:6A:8C:9A:37:22:41:23:CF:9E:DB:03:78:FC:6C',
2121
],
2222
},
2323
},
24+
{
25+
// Grants the target permission to handle all URLs that the source can handle
26+
relation: ['delegate_permission/common.handle_all_urls'],
27+
target: {
28+
namespace: 'android_app',
29+
// Package name for the Android app
30+
package_name: 'com.vonage.android',
31+
// SHA-256 certificate fingerprints for the Android app
32+
sha256_cert_fingerprints: [
33+
'A5:77:34:82:4C:98:13:CF:88:DF:20:46:2C:B7:7E:33:C0:4C:FC:C6:A1:E4:B3:25:5F:43:49:BA:FE:B5:43:27',
34+
],
35+
},
36+
},
2437
]);
2538
});
2639

backend/tests/assetlinks.test.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,12 +40,22 @@ describe('GET /.well-known/assetlinks.json', () => {
4040
relation: expect.arrayContaining(['delegate_permission/common.handle_all_urls']),
4141
target: expect.objectContaining({
4242
namespace: 'android_app',
43-
package_name: 'com.vonage.android',
43+
package_name: 'com.vonage.android.debug',
4444
sha256_cert_fingerprints: expect.arrayContaining([
4545
'A4:26:72:80:DA:75:99:75:ED:D2:32:ED:0A:DC:2C:7C:27:78:6A:8C:9A:37:22:41:23:CF:9E:DB:03:78:FC:6C',
4646
]),
4747
}),
4848
}),
49+
expect.objectContaining({
50+
relation: expect.arrayContaining(['delegate_permission/common.handle_all_urls']),
51+
target: expect.objectContaining({
52+
namespace: 'android_app',
53+
package_name: 'com.vonage.android',
54+
sha256_cert_fingerprints: expect.arrayContaining([
55+
'A5:77:34:82:4C:98:13:CF:88:DF:20:46:2C:B7:7E:33:C0:4C:FC:C6:A1:E4:B3:25:5F:43:49:BA:FE:B5:43:27',
56+
]),
57+
}),
58+
}),
4959
])
5060
);
5161
});

frontend/src/components/BackgroundEffects/AddBackgroundEffect/AddBackgroundEffectLayout/AddBackgroundEffectLayout.spec.tsx

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,31 @@
11
import { render, screen, fireEvent, waitFor } from '@testing-library/react';
22
import { vi, describe, it, expect, beforeAll } from 'vitest';
33
import AddBackgroundEffectLayout from './AddBackgroundEffectLayout';
4+
import enTranslations from '../../../../locales/en.json';
5+
6+
vi.mock('react-i18next', () => ({
7+
useTranslation: () => ({
8+
t: (key: string, options?: Record<string, string | number>) => {
9+
const translations: Record<string, string> = {
10+
'backgroundEffects.invalidFileType': enTranslations['backgroundEffects.invalidFileType'],
11+
'backgroundEffects.fileTooLarge': enTranslations['backgroundEffects.fileTooLarge'],
12+
'backgroundEffects.linkPlaceholder': enTranslations['backgroundEffects.linkPlaceholder'],
13+
'backgroundEffects.dragDropText': enTranslations['backgroundEffects.dragDropText'],
14+
'backgroundEffects.maxSize': enTranslations['backgroundEffects.maxSize'],
15+
};
16+
17+
let translation = translations[key] || key;
18+
19+
if (options && typeof translation === 'string') {
20+
Object.keys(options).forEach((param) => {
21+
translation = translation.replace(`{{${param}}}`, String(options[param]));
22+
});
23+
}
24+
25+
return translation;
26+
},
27+
}),
28+
}));
429

530
vi.mock('../../../../utils/useImageStorage/useImageStorage', () => ({
631
__esModule: true,

frontend/src/components/BackgroundEffects/AddBackgroundEffect/AddBackgroundEffectLayout/AddBackgroundEffectLayout.tsx

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import {
99
import { ChangeEvent, ReactElement, useState } from 'react';
1010
import ArrowForwardIcon from '@mui/icons-material/ArrowForward';
1111
import LinkIcon from '@mui/icons-material/Link';
12+
import { useTranslation } from 'react-i18next';
1213
import FileUploader from '../../FileUploader/FileUploader';
1314
import { ALLOWED_TYPES, MAX_SIZE_MB } from '../../../../utils/constants';
1415
import useImageStorage from '../../../../utils/useImageStorage/useImageStorage';
@@ -32,6 +33,7 @@ const AddBackgroundEffectLayout = ({
3233
const [imageLink, setImageLink] = useState<string>('');
3334
const [linkLoading, setLinkLoading] = useState<boolean>(false);
3435
const { storageError, handleImageFromFile, handleImageFromLink } = useImageStorage();
36+
const { t } = useTranslation();
3537

3638
type HandleFileChangeType = ChangeEvent<HTMLInputElement> | { target: { files: FileList } };
3739

@@ -47,12 +49,12 @@ const AddBackgroundEffectLayout = ({
4749
}
4850

4951
if (!ALLOWED_TYPES.includes(file.type)) {
50-
setFileError('Only JPG, PNG, GIF, or BMP images are allowed.');
52+
setFileError(t('backgroundEffects.invalidFileType'));
5153
return;
5254
}
5355

5456
if (file.size > MAX_SIZE_MB * 1024 * 1024) {
55-
setFileError(`Image must be less than ${MAX_SIZE_MB}MB.`);
57+
setFileError(t('backgroundEffects.fileTooLarge', { maxSize: MAX_SIZE_MB }));
5658
return;
5759
}
5860

@@ -63,7 +65,7 @@ const AddBackgroundEffectLayout = ({
6365
customBackgroundImageChange(newImage.dataUrl);
6466
}
6567
} catch {
66-
setFileError('Failed to process uploaded image.');
68+
setFileError(t('backgroundEffects.processingError'));
6769
}
6870
};
6971

@@ -76,7 +78,7 @@ const AddBackgroundEffectLayout = ({
7678
setFileError('');
7779
customBackgroundImageChange(newImage.dataUrl);
7880
} else {
79-
setFileError('Failed to store image.');
81+
setFileError(t('backgroundEffects.storageError'));
8082
}
8183
} catch {
8284
// error handled in hook
@@ -103,7 +105,7 @@ const AddBackgroundEffectLayout = ({
103105
<TextField
104106
fullWidth
105107
size="small"
106-
placeholder="Link from the web"
108+
placeholder={t('backgroundEffects.linkPlaceholder')}
107109
className="add-background-effect-input"
108110
value={imageLink}
109111
onChange={(e) => setImageLink(e.target.value)}

frontend/src/components/BackgroundEffects/BackgroundEffectTabs/BackgroundEffectTabs.tsx

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { Box, Tabs, Tab } from '@mui/material';
22
import { Publisher } from '@vonage/client-sdk-video';
33
import { ReactElement } from 'react';
4+
import { useTranslation } from 'react-i18next';
45
import EffectOptionButtons from '../EffectOptionButtons/EffectOptionButtons';
56
import BackgroundGallery from '../BackgroundGallery/BackgroundGallery';
67
import AddBackgroundEffectLayout from '../AddBackgroundEffect/AddBackgroundEffectLayout/AddBackgroundEffectLayout';
@@ -58,6 +59,7 @@ const BackgroundEffectTabs = ({
5859
setBackgroundSelected(value);
5960
};
6061
const isTabletViewport = useIsTabletViewport();
62+
const { t } = useTranslation();
6163

6264
return (
6365
<Box
@@ -81,10 +83,10 @@ const BackgroundEffectTabs = ({
8183
}}
8284
value={tabSelected}
8385
onChange={(_event, newValue) => setTabSelected(newValue)}
84-
aria-label="backgrounds tabs"
86+
aria-label={t('backgroundEffects.title.tabs')}
8587
>
86-
<Tab sx={{ textTransform: 'none' }} label="Backgrounds" />
87-
<Tab sx={{ textTransform: 'none' }} label="Add Background" />
88+
<Tab sx={{ textTransform: 'none' }} label={t('backgroundEffects.tabs.backgrounds')} />
89+
<Tab sx={{ textTransform: 'none' }} label={t('backgroundEffects.tabs.addBackground')} />
8890
</Tabs>
8991

9092
<Box className="choose-background-effect-box" flex={1} minWidth={0}>

frontend/src/components/BackgroundEffects/BackgroundEffectsLayout/BackgroundEffectsLayout.spec.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ vi.mock('react-i18next', () => ({
1212
const translations: Record<string, string> = {
1313
'backgroundEffects.title': enTranslations['backgroundEffects.title'],
1414
'backgroundEffects.choice': enTranslations['backgroundEffects.choice'],
15+
'backgroundEffects.tabs.backgrounds': enTranslations['backgroundEffects.tabs.backgrounds'],
16+
'backgroundEffects.tabs.addBackground':
17+
enTranslations['backgroundEffects.tabs.addBackground'],
1518
'button.cancel': enTranslations['button.cancel'],
1619
'button.apply': enTranslations['button.apply'],
1720
};

frontend/src/components/BackgroundEffects/BackgroundGallery/BackgroundGallery.spec.tsx

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,29 @@
11
import { describe, expect, it, vi, beforeEach } from 'vitest';
22
import { render, screen } from '@testing-library/react';
33
import userEvent from '@testing-library/user-event';
4-
import BackgroundGallery, { backgrounds } from './BackgroundGallery';
4+
import BackgroundGallery from './BackgroundGallery';
5+
import enTranslations from '../../../locales/en.json';
56

67
const customImages = [
78
{ id: 'custom1', dataUrl: 'data:image/png;base64,custom1' },
89
{ id: 'custom2', dataUrl: 'data:image/png;base64,custom2' },
910
];
1011

12+
const backgrounds = [
13+
{
14+
id: 'bg4',
15+
file: 'hogwarts.jpg',
16+
name: enTranslations['backgroundEffects.backgrounds.hogwarts'],
17+
},
18+
{ id: 'bg5', file: 'library.jpg', name: enTranslations['backgroundEffects.backgrounds.library'] },
19+
{
20+
id: 'bg6',
21+
file: 'new-york.jpg',
22+
name: enTranslations['backgroundEffects.backgrounds.newYork'],
23+
},
24+
{ id: 'bg7', file: 'plane.jpg', name: enTranslations['backgroundEffects.backgrounds.plane'] },
25+
];
26+
1127
const mockDeleteImageFromStorage = vi.fn();
1228
const mockGetImagesFromStorage = vi.fn(() => customImages);
1329

frontend/src/components/BackgroundEffects/BackgroundGallery/BackgroundGallery.tsx

Lines changed: 21 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,11 @@
11
import { ReactElement, useEffect, useState } from 'react';
22
import { Box, IconButton, Tooltip } from '@mui/material';
33
import DeleteIcon from '@mui/icons-material/Delete';
4+
import { useTranslation } from 'react-i18next';
45
import { BACKGROUNDS_PATH } from '../../../utils/constants';
56
import SelectableOption from '../SelectableOption';
67
import useImageStorage, { StoredImage } from '../../../utils/useImageStorage/useImageStorage';
78

8-
export const backgrounds = [
9-
{ id: 'bg1', file: 'bookshelf-room.jpg', name: 'Bookshelf Room' },
10-
{ id: 'bg2', file: 'busy-room.jpg', name: 'Busy Room' },
11-
{ id: 'bg3', file: 'dune-view.jpg', name: 'Dune View' },
12-
{ id: 'bg4', file: 'hogwarts.jpg', name: 'Hogwarts' },
13-
{ id: 'bg5', file: 'library.jpg', name: 'Library' },
14-
{ id: 'bg6', file: 'new-york.jpg', name: 'New York' },
15-
{ id: 'bg7', file: 'plane.jpg', name: 'Plane' },
16-
{ id: 'bg8', file: 'white-room.jpg', name: 'White Room' },
17-
];
18-
199
export type BackgroundGalleryProps = {
2010
backgroundSelected: string;
2111
setBackgroundSelected: (dataUrl: string) => void;
@@ -39,6 +29,22 @@ const BackgroundGallery = ({
3929
}: BackgroundGalleryProps): ReactElement => {
4030
const { getImagesFromStorage, deleteImageFromStorage } = useImageStorage();
4131
const [customImages, setCustomImages] = useState<StoredImage[]>([]);
32+
const { t } = useTranslation();
33+
34+
const backgrounds = [
35+
{
36+
id: 'bg1',
37+
file: 'bookshelf-room.jpg',
38+
name: t('backgroundEffects.backgrounds.bookshelfRoom'),
39+
},
40+
{ id: 'bg2', file: 'busy-room.jpg', name: t('backgroundEffects.backgrounds.busyRoom') },
41+
{ id: 'bg3', file: 'dune-view.jpg', name: t('backgroundEffects.backgrounds.duneView') },
42+
{ id: 'bg4', file: 'hogwarts.jpg', name: t('backgroundEffects.backgrounds.hogwarts') },
43+
{ id: 'bg5', file: 'library.jpg', name: t('backgroundEffects.backgrounds.library') },
44+
{ id: 'bg6', file: 'new-york.jpg', name: t('backgroundEffects.backgrounds.newYork') },
45+
{ id: 'bg7', file: 'plane.jpg', name: t('backgroundEffects.backgrounds.plane') },
46+
{ id: 'bg8', file: 'white-room.jpg', name: t('backgroundEffects.backgrounds.whiteRoom') },
47+
];
4248

4349
useEffect(() => {
4450
setCustomImages(getImagesFromStorage());
@@ -67,22 +73,22 @@ const BackgroundGallery = ({
6773
>
6874
<SelectableOption
6975
id={id}
70-
title="Your Background"
76+
title={t('backgroundEffects.yourBackground')}
7177
isSelected={isSelected}
7278
onClick={() => setBackgroundSelected(dataUrl)}
7379
image={dataUrl}
7480
>
7581
<Tooltip
7682
title={
7783
isSelected
78-
? "You can't remove this background while it's in use"
79-
: 'Delete background'
84+
? t('backgroundEffects.deleteTooltipInUse')
85+
: t('backgroundEffects.deleteTooltip')
8086
}
8187
arrow
8288
>
8389
<IconButton
8490
data-testid={`background-delete-${id}`}
85-
aria-label="Delete custom background"
91+
aria-label={t('backgroundEffects.deleteAriaLabel')}
8692
onClick={(e) => {
8793
e.stopPropagation();
8894
if (!isSelected) {

frontend/src/components/BackgroundEffects/EffectOptionButtons/EffectOptionButtons.tsx

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,9 @@
11
import { ReactElement } from 'react';
22
import BlockIcon from '@mui/icons-material/Block';
33
import BlurOnIcon from '@mui/icons-material/BlurOn';
4+
import { useTranslation } from 'react-i18next';
45
import SelectableOption from '../SelectableOption';
56

6-
const options = [
7-
{ key: 'none', icon: <BlockIcon sx={{ fontSize: '30px' }} />, name: 'Remove background' },
8-
{ key: 'low-blur', icon: <BlurOnIcon />, name: 'Slight background blur' },
9-
{
10-
key: 'high-blur',
11-
icon: <BlurOnIcon sx={{ fontSize: '30px' }} />,
12-
name: 'Strong background blur',
13-
},
14-
];
15-
167
export type EffectOptionButtonsProps = {
178
backgroundSelected: string;
189
setBackgroundSelected: (key: string) => void;
@@ -31,6 +22,20 @@ const EffectOptionButtons = ({
3122
backgroundSelected,
3223
setBackgroundSelected,
3324
}: EffectOptionButtonsProps): ReactElement => {
25+
const { t } = useTranslation();
26+
const options = [
27+
{
28+
key: 'none',
29+
icon: <BlockIcon sx={{ fontSize: '30px' }} />,
30+
name: t('backgroundEffects.removeBackground'),
31+
},
32+
{ key: 'low-blur', icon: <BlurOnIcon />, name: t('backgroundEffects.slightBlur') },
33+
{
34+
key: 'high-blur',
35+
icon: <BlurOnIcon sx={{ fontSize: '30px' }} />,
36+
name: t('backgroundEffects.strongBlur'),
37+
},
38+
];
3439
return (
3540
<>
3641
{options.map(({ key, icon, name }) => (

0 commit comments

Comments
 (0)