Give video display as much space as possible (#84)

* Move room tools to top of page to use full width
Allow messages to be hidden while video is displaying
Allow video display to utilise all available width
Track unread messages while they are hidden
* Better portrait behaviour
* Show room controls by default
* Show room controls at same time as app bar
Improve video height calc.

Co-authored-by: Jeremy Kahn <jeremyckahn@gmail.com>
This commit is contained in:
Nasal Daemon 2023-01-24 03:50:14 +00:00 committed by GitHub
parent fcec242194
commit 8493ddade5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 715 additions and 320 deletions

458
package-lock.json generated
View File

@ -13,6 +13,7 @@
"@emotion/styled": "^11.10.0",
"@mui/icons-material": "^5.8.4",
"@mui/material": "^5.9.3",
"@react-hook/window-size": "^3.1.1",
"@testing-library/jest-dom": "^5.16.5",
"@testing-library/react": "^13.3.0",
"@testing-library/user-event": "^13.5.0",
@ -117,32 +118,32 @@
}
},
"node_modules/@babel/compat-data": {
"version": "7.18.8",
"resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.18.8.tgz",
"integrity": "sha512-HSmX4WZPPK3FUxYp7g2T6EyO8j96HlZJlxmKPSh6KAcqwyDrfx7hKjXpAW/0FhFfTJsR0Yt4lAjLI2coMptIHQ==",
"version": "7.20.10",
"resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.20.10.tgz",
"integrity": "sha512-sEnuDPpOJR/fcafHMjpcpGN5M2jbUGUHwmuWKM/YdPzeEDJg8bgmbcWQFUfE32MQjti1koACvoPVsDe8Uq+idg==",
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/core": {
"version": "7.18.10",
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.18.10.tgz",
"integrity": "sha512-JQM6k6ENcBFKVtWvLavlvi/mPcpYZ3+R+2EySDEMSMbp7Mn4FexlbbJVrx2R7Ijhr01T8gyqrOaABWIOgxeUyw==",
"version": "7.20.12",
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.20.12.tgz",
"integrity": "sha512-XsMfHovsUYHFMdrIHkZphTN/2Hzzi78R08NuHfDBehym2VsPDL6Zn/JAD/JQdnRvbSsbQc4mVaU1m6JgtTEElg==",
"dependencies": {
"@ampproject/remapping": "^2.1.0",
"@babel/code-frame": "^7.18.6",
"@babel/generator": "^7.18.10",
"@babel/helper-compilation-targets": "^7.18.9",
"@babel/helper-module-transforms": "^7.18.9",
"@babel/helpers": "^7.18.9",
"@babel/parser": "^7.18.10",
"@babel/template": "^7.18.10",
"@babel/traverse": "^7.18.10",
"@babel/types": "^7.18.10",
"@babel/generator": "^7.20.7",
"@babel/helper-compilation-targets": "^7.20.7",
"@babel/helper-module-transforms": "^7.20.11",
"@babel/helpers": "^7.20.7",
"@babel/parser": "^7.20.7",
"@babel/template": "^7.20.7",
"@babel/traverse": "^7.20.12",
"@babel/types": "^7.20.7",
"convert-source-map": "^1.7.0",
"debug": "^4.1.0",
"gensync": "^1.0.0-beta.2",
"json5": "^2.2.1",
"json5": "^2.2.2",
"semver": "^6.3.0"
},
"engines": {
@ -215,11 +216,11 @@
}
},
"node_modules/@babel/generator": {
"version": "7.18.12",
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.18.12.tgz",
"integrity": "sha512-dfQ8ebCN98SvyL7IxNMCUtZQSq5R7kxgN+r8qYTGDmmSion1hX2C0zq2yo1bsCDhXixokv1SAWTZUMYbO/V5zg==",
"version": "7.20.7",
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.20.7.tgz",
"integrity": "sha512-7wqMOJq8doJMZmP4ApXTzLxSr7+oO2jroJURrVEp6XShrQUObV8Tq/D0NCcoYg2uHqUrjzO0zwBjoYzelxK+sw==",
"dependencies": {
"@babel/types": "^7.18.10",
"@babel/types": "^7.20.7",
"@jridgewell/gen-mapping": "^0.3.2",
"jsesc": "^2.5.1"
},
@ -264,13 +265,14 @@
}
},
"node_modules/@babel/helper-compilation-targets": {
"version": "7.18.9",
"resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.18.9.tgz",
"integrity": "sha512-tzLCyVmqUiFlcFoAPLA/gL9TeYrF61VLNtb+hvkuVaB5SUjW7jcfrglBIX1vUIoT7CLP3bBlIMeyEsIl2eFQNg==",
"version": "7.20.7",
"resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.20.7.tgz",
"integrity": "sha512-4tGORmfQcrc+bvrjb5y3dG9Mx1IOZjsHqQVUz7XCNHO+iTmqxWnVg3KRygjGmpRLJGdQSKuvFinbIb0CnZwHAQ==",
"dependencies": {
"@babel/compat-data": "^7.18.8",
"@babel/compat-data": "^7.20.5",
"@babel/helper-validator-option": "^7.18.6",
"browserslist": "^4.20.2",
"browserslist": "^4.21.3",
"lru-cache": "^5.1.1",
"semver": "^6.3.0"
},
"engines": {
@ -280,6 +282,14 @@
"@babel/core": "^7.0.0"
}
},
"node_modules/@babel/helper-compilation-targets/node_modules/lru-cache": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
"integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==",
"dependencies": {
"yallist": "^3.0.2"
}
},
"node_modules/@babel/helper-compilation-targets/node_modules/semver": {
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
@ -288,6 +298,11 @@
"semver": "bin/semver.js"
}
},
"node_modules/@babel/helper-compilation-targets/node_modules/yallist": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
"integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="
},
"node_modules/@babel/helper-create-class-features-plugin": {
"version": "7.18.9",
"resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.18.9.tgz",
@ -367,12 +382,12 @@
}
},
"node_modules/@babel/helper-function-name": {
"version": "7.18.9",
"resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.18.9.tgz",
"integrity": "sha512-fJgWlZt7nxGksJS9a0XdSaI4XvpExnNIgRP+rVefWh5U7BL8pPuir6SJUmFKRfjWQ51OtWSzwOxhaH/EBWWc0A==",
"version": "7.19.0",
"resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.19.0.tgz",
"integrity": "sha512-WAwHBINyrpqywkUH0nTnNgI5ina5TFn85HKS0pbPDfxFfhyR/aNQEn4hGi1P1JyT//I0t4OgXUlofzWILRvS5w==",
"dependencies": {
"@babel/template": "^7.18.6",
"@babel/types": "^7.18.9"
"@babel/template": "^7.18.10",
"@babel/types": "^7.19.0"
},
"engines": {
"node": ">=6.9.0"
@ -412,18 +427,18 @@
}
},
"node_modules/@babel/helper-module-transforms": {
"version": "7.18.9",
"resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.18.9.tgz",
"integrity": "sha512-KYNqY0ICwfv19b31XzvmI/mfcylOzbLtowkw+mfvGPAQ3kfCnMLYbED3YecL5tPd8nAYFQFAd6JHp2LxZk/J1g==",
"version": "7.20.11",
"resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.20.11.tgz",
"integrity": "sha512-uRy78kN4psmji1s2QtbtcCSaj/LILFDp0f/ymhpQH5QY3nljUZCaNWz9X1dEj/8MBdBEFECs7yRhKn8i7NjZgg==",
"dependencies": {
"@babel/helper-environment-visitor": "^7.18.9",
"@babel/helper-module-imports": "^7.18.6",
"@babel/helper-simple-access": "^7.18.6",
"@babel/helper-simple-access": "^7.20.2",
"@babel/helper-split-export-declaration": "^7.18.6",
"@babel/helper-validator-identifier": "^7.18.6",
"@babel/template": "^7.18.6",
"@babel/traverse": "^7.18.9",
"@babel/types": "^7.18.9"
"@babel/helper-validator-identifier": "^7.19.1",
"@babel/template": "^7.20.7",
"@babel/traverse": "^7.20.10",
"@babel/types": "^7.20.7"
},
"engines": {
"node": ">=6.9.0"
@ -441,9 +456,9 @@
}
},
"node_modules/@babel/helper-plugin-utils": {
"version": "7.18.9",
"resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.18.9.tgz",
"integrity": "sha512-aBXPT3bmtLryXaoJLyYPXPlSD4p1ld9aYeR+sJNOZjJJGiOpb+fKfh3NkcCu7J54nUJwCERPBExCCpyCOHnu/w==",
"version": "7.20.2",
"resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.20.2.tgz",
"integrity": "sha512-8RvlJG2mj4huQ4pZ+rU9lqKi9ZKiRmuvGuM2HlWmkmgOhbs6zEAw6IEiJ5cQqGbDzGZOhwuOQNtZMi/ENLjZoQ==",
"engines": {
"node": ">=6.9.0"
}
@ -481,11 +496,11 @@
}
},
"node_modules/@babel/helper-simple-access": {
"version": "7.18.6",
"resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.18.6.tgz",
"integrity": "sha512-iNpIgTgyAvDQpDj76POqg+YEt8fPxx3yaNBg3S30dxNKm2SWfYhD0TGrK/Eu9wHpUW63VQU894TsTg+GLbUa1g==",
"version": "7.20.2",
"resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.20.2.tgz",
"integrity": "sha512-+0woI/WPq59IrqDYbVGfshjT5Dmk/nnbdpcF8SnMhhXObpTq2KNBdLFRFrkVdbDOyUmHBCxzm5FHV1rACIkIbA==",
"dependencies": {
"@babel/types": "^7.18.6"
"@babel/types": "^7.20.2"
},
"engines": {
"node": ">=6.9.0"
@ -514,17 +529,17 @@
}
},
"node_modules/@babel/helper-string-parser": {
"version": "7.18.10",
"resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.18.10.tgz",
"integrity": "sha512-XtIfWmeNY3i4t7t4D2t02q50HvqHybPqW2ki1kosnvWCwuCMeo81Jf0gwr85jy/neUdg5XDdeFE/80DXiO+njw==",
"version": "7.19.4",
"resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz",
"integrity": "sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==",
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/helper-validator-identifier": {
"version": "7.18.6",
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.18.6.tgz",
"integrity": "sha512-MmetCkz9ej86nJQV+sFCxoGGrUbU3q02kgLciwkrt9QqEB7cP39oKEY0PakknEO0Gu20SskMRi+AYZ3b1TpN9g==",
"version": "7.19.1",
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz",
"integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==",
"engines": {
"node": ">=6.9.0"
}
@ -552,13 +567,13 @@
}
},
"node_modules/@babel/helpers": {
"version": "7.18.9",
"resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.18.9.tgz",
"integrity": "sha512-Jf5a+rbrLoR4eNdUmnFu8cN5eNJT6qdTdOg5IHIzq87WwyRw9PwguLFOWYgktN/60IP4fgDUawJvs7PjQIzELQ==",
"version": "7.20.7",
"resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.20.7.tgz",
"integrity": "sha512-PBPjs5BppzsGaxHQCDKnZ6Gd9s6xl8bBCluz3vEInLGRJmnZan4F6BYCeqtyXqkk4W5IlPmjK4JlOuZkpJ3xZA==",
"dependencies": {
"@babel/template": "^7.18.6",
"@babel/traverse": "^7.18.9",
"@babel/types": "^7.18.9"
"@babel/template": "^7.20.7",
"@babel/traverse": "^7.20.7",
"@babel/types": "^7.20.7"
},
"engines": {
"node": ">=6.9.0"
@ -578,9 +593,9 @@
}
},
"node_modules/@babel/parser": {
"version": "7.18.11",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.18.11.tgz",
"integrity": "sha512-9JKn5vN+hDt0Hdqn1PiJ2guflwP+B6Ga8qbDuoF0PzzVhrzsKIJo8yGqVk6CmMHiMei9w1C1Bp9IMJSIK+HPIQ==",
"version": "7.20.7",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.7.tgz",
"integrity": "sha512-T3Z9oHybU+0vZlY9CiDSJQTD5ZapcW18ZctFMi0MOAl/4BjFF4ul7NVSARLdbGO5vDqy9eQiGTV0LtKfvCYvcg==",
"bin": {
"parser": "bin/babel-parser.js"
},
@ -1904,31 +1919,31 @@
}
},
"node_modules/@babel/template": {
"version": "7.18.10",
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.18.10.tgz",
"integrity": "sha512-TI+rCtooWHr3QJ27kJxfjutghu44DLnasDMwpDqCXVTal9RLp3RSYNh4NdBrRP2cQAoG9A8juOQl6P6oZG4JxA==",
"version": "7.20.7",
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.20.7.tgz",
"integrity": "sha512-8SegXApWe6VoNw0r9JHpSteLKTpTiLZ4rMlGIm9JQ18KiCtyQiAMEazujAHrUS5flrcqYZa75ukev3P6QmUwUw==",
"dependencies": {
"@babel/code-frame": "^7.18.6",
"@babel/parser": "^7.18.10",
"@babel/types": "^7.18.10"
"@babel/parser": "^7.20.7",
"@babel/types": "^7.20.7"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/traverse": {
"version": "7.18.11",
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.18.11.tgz",
"integrity": "sha512-TG9PiM2R/cWCAy6BPJKeHzNbu4lPzOSZpeMfeNErskGpTJx6trEvFaVCbDvpcxwy49BKWmEPwiW8mrysNiDvIQ==",
"version": "7.20.12",
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.20.12.tgz",
"integrity": "sha512-MsIbFN0u+raeja38qboyF8TIT7K0BFzz/Yd/77ta4MsUsmP2RAnidIlwq7d5HFQrH/OZJecGV6B71C4zAgpoSQ==",
"dependencies": {
"@babel/code-frame": "^7.18.6",
"@babel/generator": "^7.18.10",
"@babel/generator": "^7.20.7",
"@babel/helper-environment-visitor": "^7.18.9",
"@babel/helper-function-name": "^7.18.9",
"@babel/helper-function-name": "^7.19.0",
"@babel/helper-hoist-variables": "^7.18.6",
"@babel/helper-split-export-declaration": "^7.18.6",
"@babel/parser": "^7.18.11",
"@babel/types": "^7.18.10",
"@babel/parser": "^7.20.7",
"@babel/types": "^7.20.7",
"debug": "^4.1.0",
"globals": "^11.1.0"
},
@ -1937,12 +1952,12 @@
}
},
"node_modules/@babel/types": {
"version": "7.18.10",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.18.10.tgz",
"integrity": "sha512-MJvnbEiiNkpjo+LknnmRrqbY1GPUUggjv+wQVjetM/AONoupqRALB7I6jGqNUAZsKcRIEu2J6FRFvsczljjsaQ==",
"version": "7.20.7",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.7.tgz",
"integrity": "sha512-69OnhBxSSgK0OzTJai4kyPDiKTIe3j+ctaHdIGVbRahTLAT7L3R9oeXHC2aVSuGYt3cVnoAMDmOCgJ2yaiLMvg==",
"dependencies": {
"@babel/helper-string-parser": "^7.18.10",
"@babel/helper-validator-identifier": "^7.18.6",
"@babel/helper-string-parser": "^7.19.4",
"@babel/helper-validator-identifier": "^7.19.1",
"to-fast-properties": "^2.0.0"
},
"engines": {
@ -4528,6 +4543,57 @@
"resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz",
"integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw=="
},
"node_modules/@react-hook/debounce": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/@react-hook/debounce/-/debounce-3.0.0.tgz",
"integrity": "sha512-ir/kPrSfAzY12Gre0sOHkZ2rkEmM4fS5M5zFxCi4BnCeXh2nvx9Ujd+U4IGpKCuPA+EQD0pg1eK2NGLvfWejag==",
"dependencies": {
"@react-hook/latest": "^1.0.2"
},
"peerDependencies": {
"react": ">=16.8"
}
},
"node_modules/@react-hook/event": {
"version": "1.2.6",
"resolved": "https://registry.npmjs.org/@react-hook/event/-/event-1.2.6.tgz",
"integrity": "sha512-JUL5IluaOdn5w5Afpe/puPa1rj8X6udMlQ9dt4hvMuKmTrBS1Ya6sb4sVgvfe2eU4yDuOfAhik8xhbcCekbg9Q==",
"peerDependencies": {
"react": ">=16.8"
}
},
"node_modules/@react-hook/latest": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/@react-hook/latest/-/latest-1.0.3.tgz",
"integrity": "sha512-dy6duzl+JnAZcDbNTfmaP3xHiKtbXYOaz3G51MGVljh548Y8MWzTr+PHLOfvpypEVW9zwvl+VyKjbWKEVbV1Rg==",
"peerDependencies": {
"react": ">=16.8"
}
},
"node_modules/@react-hook/throttle": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/@react-hook/throttle/-/throttle-2.2.0.tgz",
"integrity": "sha512-LJ5eg+yMV8lXtqK3lR+OtOZ2WH/EfWvuiEEu0M3bhR7dZRfTyEJKxH1oK9uyBxiXPtWXiQggWbZirMCXam51tg==",
"dependencies": {
"@react-hook/latest": "^1.0.2"
},
"peerDependencies": {
"react": ">=16.8"
}
},
"node_modules/@react-hook/window-size": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/@react-hook/window-size/-/window-size-3.1.1.tgz",
"integrity": "sha512-yWnVS5LKnOUIrEsI44oz3bIIUYqflamPL27n+k/PC//PsX/YeWBky09oPeAoc9As6jSH16Wgo8plI+ECZaHk3g==",
"dependencies": {
"@react-hook/debounce": "^3.0.0",
"@react-hook/event": "^1.2.1",
"@react-hook/throttle": "^2.2.0"
},
"peerDependencies": {
"react": ">=16.8"
}
},
"node_modules/@rollup/plugin-babel": {
"version": "5.3.1",
"resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-5.3.1.tgz",
@ -16620,9 +16686,9 @@
"integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA=="
},
"node_modules/json5": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz",
"integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==",
"version": "2.2.3",
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
"integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
"bin": {
"json5": "lib/cli.js"
},
@ -21674,9 +21740,9 @@
}
},
"node_modules/promise": {
"version": "8.1.0",
"resolved": "https://registry.npmjs.org/promise/-/promise-8.1.0.tgz",
"integrity": "sha512-W04AqnILOL/sPRXziNicCjSNRruLAuIHEOVBazepu0545DDNGYHz7ar9ZgZ1fMU8/MA4mVxp5rkBWRi6OXIy3Q==",
"version": "8.3.0",
"resolved": "https://registry.npmjs.org/promise/-/promise-8.3.0.tgz",
"integrity": "sha512-rZPNPKTOYVNEEKFaq1HqTgOwZD+4/YHS5ukLzQCypkj+OkYx7iv0mA91lJlpPPZ8vMau3IIGj5Qlwrx+8iiSmg==",
"dependencies": {
"asap": "~2.0.6"
}
@ -24643,9 +24709,9 @@
}
},
"node_modules/terser": {
"version": "5.14.2",
"resolved": "https://registry.npmjs.org/terser/-/terser-5.14.2.tgz",
"integrity": "sha512-oL0rGeM/WFQCUd0y2QrWxYnq7tfSuKBiqTjRPWrRgB46WD/kiwHwF8T23z78H6Q6kGCuuHcPB+KULHRdxvVGQA==",
"version": "5.16.1",
"resolved": "https://registry.npmjs.org/terser/-/terser-5.16.1.tgz",
"integrity": "sha512-xvQfyfA1ayT0qdK47zskQgRZeWLoOQ8JQ6mIgRGVNwZKdQMU+5FkCBjmv4QjcrTzyZquRw2FVtlJSRUmMKQslw==",
"dependencies": {
"@jridgewell/source-map": "^0.3.2",
"acorn": "^8.5.0",
@ -26842,29 +26908,29 @@
}
},
"@babel/compat-data": {
"version": "7.18.8",
"resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.18.8.tgz",
"integrity": "sha512-HSmX4WZPPK3FUxYp7g2T6EyO8j96HlZJlxmKPSh6KAcqwyDrfx7hKjXpAW/0FhFfTJsR0Yt4lAjLI2coMptIHQ=="
"version": "7.20.10",
"resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.20.10.tgz",
"integrity": "sha512-sEnuDPpOJR/fcafHMjpcpGN5M2jbUGUHwmuWKM/YdPzeEDJg8bgmbcWQFUfE32MQjti1koACvoPVsDe8Uq+idg=="
},
"@babel/core": {
"version": "7.18.10",
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.18.10.tgz",
"integrity": "sha512-JQM6k6ENcBFKVtWvLavlvi/mPcpYZ3+R+2EySDEMSMbp7Mn4FexlbbJVrx2R7Ijhr01T8gyqrOaABWIOgxeUyw==",
"version": "7.20.12",
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.20.12.tgz",
"integrity": "sha512-XsMfHovsUYHFMdrIHkZphTN/2Hzzi78R08NuHfDBehym2VsPDL6Zn/JAD/JQdnRvbSsbQc4mVaU1m6JgtTEElg==",
"requires": {
"@ampproject/remapping": "^2.1.0",
"@babel/code-frame": "^7.18.6",
"@babel/generator": "^7.18.10",
"@babel/helper-compilation-targets": "^7.18.9",
"@babel/helper-module-transforms": "^7.18.9",
"@babel/helpers": "^7.18.9",
"@babel/parser": "^7.18.10",
"@babel/template": "^7.18.10",
"@babel/traverse": "^7.18.10",
"@babel/types": "^7.18.10",
"@babel/generator": "^7.20.7",
"@babel/helper-compilation-targets": "^7.20.7",
"@babel/helper-module-transforms": "^7.20.11",
"@babel/helpers": "^7.20.7",
"@babel/parser": "^7.20.7",
"@babel/template": "^7.20.7",
"@babel/traverse": "^7.20.12",
"@babel/types": "^7.20.7",
"convert-source-map": "^1.7.0",
"debug": "^4.1.0",
"gensync": "^1.0.0-beta.2",
"json5": "^2.2.1",
"json5": "^2.2.2",
"semver": "^6.3.0"
},
"dependencies": {
@ -26912,11 +26978,11 @@
}
},
"@babel/generator": {
"version": "7.18.12",
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.18.12.tgz",
"integrity": "sha512-dfQ8ebCN98SvyL7IxNMCUtZQSq5R7kxgN+r8qYTGDmmSion1hX2C0zq2yo1bsCDhXixokv1SAWTZUMYbO/V5zg==",
"version": "7.20.7",
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.20.7.tgz",
"integrity": "sha512-7wqMOJq8doJMZmP4ApXTzLxSr7+oO2jroJURrVEp6XShrQUObV8Tq/D0NCcoYg2uHqUrjzO0zwBjoYzelxK+sw==",
"requires": {
"@babel/types": "^7.18.10",
"@babel/types": "^7.20.7",
"@jridgewell/gen-mapping": "^0.3.2",
"jsesc": "^2.5.1"
},
@ -26951,20 +27017,34 @@
}
},
"@babel/helper-compilation-targets": {
"version": "7.18.9",
"resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.18.9.tgz",
"integrity": "sha512-tzLCyVmqUiFlcFoAPLA/gL9TeYrF61VLNtb+hvkuVaB5SUjW7jcfrglBIX1vUIoT7CLP3bBlIMeyEsIl2eFQNg==",
"version": "7.20.7",
"resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.20.7.tgz",
"integrity": "sha512-4tGORmfQcrc+bvrjb5y3dG9Mx1IOZjsHqQVUz7XCNHO+iTmqxWnVg3KRygjGmpRLJGdQSKuvFinbIb0CnZwHAQ==",
"requires": {
"@babel/compat-data": "^7.18.8",
"@babel/compat-data": "^7.20.5",
"@babel/helper-validator-option": "^7.18.6",
"browserslist": "^4.20.2",
"browserslist": "^4.21.3",
"lru-cache": "^5.1.1",
"semver": "^6.3.0"
},
"dependencies": {
"lru-cache": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
"integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==",
"requires": {
"yallist": "^3.0.2"
}
},
"semver": {
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw=="
},
"yallist": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
"integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="
}
}
},
@ -27025,12 +27105,12 @@
}
},
"@babel/helper-function-name": {
"version": "7.18.9",
"resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.18.9.tgz",
"integrity": "sha512-fJgWlZt7nxGksJS9a0XdSaI4XvpExnNIgRP+rVefWh5U7BL8pPuir6SJUmFKRfjWQ51OtWSzwOxhaH/EBWWc0A==",
"version": "7.19.0",
"resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.19.0.tgz",
"integrity": "sha512-WAwHBINyrpqywkUH0nTnNgI5ina5TFn85HKS0pbPDfxFfhyR/aNQEn4hGi1P1JyT//I0t4OgXUlofzWILRvS5w==",
"requires": {
"@babel/template": "^7.18.6",
"@babel/types": "^7.18.9"
"@babel/template": "^7.18.10",
"@babel/types": "^7.19.0"
}
},
"@babel/helper-hoist-variables": {
@ -27058,18 +27138,18 @@
}
},
"@babel/helper-module-transforms": {
"version": "7.18.9",
"resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.18.9.tgz",
"integrity": "sha512-KYNqY0ICwfv19b31XzvmI/mfcylOzbLtowkw+mfvGPAQ3kfCnMLYbED3YecL5tPd8nAYFQFAd6JHp2LxZk/J1g==",
"version": "7.20.11",
"resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.20.11.tgz",
"integrity": "sha512-uRy78kN4psmji1s2QtbtcCSaj/LILFDp0f/ymhpQH5QY3nljUZCaNWz9X1dEj/8MBdBEFECs7yRhKn8i7NjZgg==",
"requires": {
"@babel/helper-environment-visitor": "^7.18.9",
"@babel/helper-module-imports": "^7.18.6",
"@babel/helper-simple-access": "^7.18.6",
"@babel/helper-simple-access": "^7.20.2",
"@babel/helper-split-export-declaration": "^7.18.6",
"@babel/helper-validator-identifier": "^7.18.6",
"@babel/template": "^7.18.6",
"@babel/traverse": "^7.18.9",
"@babel/types": "^7.18.9"
"@babel/helper-validator-identifier": "^7.19.1",
"@babel/template": "^7.20.7",
"@babel/traverse": "^7.20.10",
"@babel/types": "^7.20.7"
}
},
"@babel/helper-optimise-call-expression": {
@ -27081,9 +27161,9 @@
}
},
"@babel/helper-plugin-utils": {
"version": "7.18.9",
"resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.18.9.tgz",
"integrity": "sha512-aBXPT3bmtLryXaoJLyYPXPlSD4p1ld9aYeR+sJNOZjJJGiOpb+fKfh3NkcCu7J54nUJwCERPBExCCpyCOHnu/w=="
"version": "7.20.2",
"resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.20.2.tgz",
"integrity": "sha512-8RvlJG2mj4huQ4pZ+rU9lqKi9ZKiRmuvGuM2HlWmkmgOhbs6zEAw6IEiJ5cQqGbDzGZOhwuOQNtZMi/ENLjZoQ=="
},
"@babel/helper-remap-async-to-generator": {
"version": "7.18.9",
@ -27109,11 +27189,11 @@
}
},
"@babel/helper-simple-access": {
"version": "7.18.6",
"resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.18.6.tgz",
"integrity": "sha512-iNpIgTgyAvDQpDj76POqg+YEt8fPxx3yaNBg3S30dxNKm2SWfYhD0TGrK/Eu9wHpUW63VQU894TsTg+GLbUa1g==",
"version": "7.20.2",
"resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.20.2.tgz",
"integrity": "sha512-+0woI/WPq59IrqDYbVGfshjT5Dmk/nnbdpcF8SnMhhXObpTq2KNBdLFRFrkVdbDOyUmHBCxzm5FHV1rACIkIbA==",
"requires": {
"@babel/types": "^7.18.6"
"@babel/types": "^7.20.2"
}
},
"@babel/helper-skip-transparent-expression-wrappers": {
@ -27133,14 +27213,14 @@
}
},
"@babel/helper-string-parser": {
"version": "7.18.10",
"resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.18.10.tgz",
"integrity": "sha512-XtIfWmeNY3i4t7t4D2t02q50HvqHybPqW2ki1kosnvWCwuCMeo81Jf0gwr85jy/neUdg5XDdeFE/80DXiO+njw=="
"version": "7.19.4",
"resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz",
"integrity": "sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw=="
},
"@babel/helper-validator-identifier": {
"version": "7.18.6",
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.18.6.tgz",
"integrity": "sha512-MmetCkz9ej86nJQV+sFCxoGGrUbU3q02kgLciwkrt9QqEB7cP39oKEY0PakknEO0Gu20SskMRi+AYZ3b1TpN9g=="
"version": "7.19.1",
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz",
"integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w=="
},
"@babel/helper-validator-option": {
"version": "7.18.6",
@ -27159,13 +27239,13 @@
}
},
"@babel/helpers": {
"version": "7.18.9",
"resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.18.9.tgz",
"integrity": "sha512-Jf5a+rbrLoR4eNdUmnFu8cN5eNJT6qdTdOg5IHIzq87WwyRw9PwguLFOWYgktN/60IP4fgDUawJvs7PjQIzELQ==",
"version": "7.20.7",
"resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.20.7.tgz",
"integrity": "sha512-PBPjs5BppzsGaxHQCDKnZ6Gd9s6xl8bBCluz3vEInLGRJmnZan4F6BYCeqtyXqkk4W5IlPmjK4JlOuZkpJ3xZA==",
"requires": {
"@babel/template": "^7.18.6",
"@babel/traverse": "^7.18.9",
"@babel/types": "^7.18.9"
"@babel/template": "^7.20.7",
"@babel/traverse": "^7.20.7",
"@babel/types": "^7.20.7"
}
},
"@babel/highlight": {
@ -27179,9 +27259,9 @@
}
},
"@babel/parser": {
"version": "7.18.11",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.18.11.tgz",
"integrity": "sha512-9JKn5vN+hDt0Hdqn1PiJ2guflwP+B6Ga8qbDuoF0PzzVhrzsKIJo8yGqVk6CmMHiMei9w1C1Bp9IMJSIK+HPIQ=="
"version": "7.20.7",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.7.tgz",
"integrity": "sha512-T3Z9oHybU+0vZlY9CiDSJQTD5ZapcW18ZctFMi0MOAl/4BjFF4ul7NVSARLdbGO5vDqy9eQiGTV0LtKfvCYvcg=="
},
"@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": {
"version": "7.18.6",
@ -28035,39 +28115,39 @@
}
},
"@babel/template": {
"version": "7.18.10",
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.18.10.tgz",
"integrity": "sha512-TI+rCtooWHr3QJ27kJxfjutghu44DLnasDMwpDqCXVTal9RLp3RSYNh4NdBrRP2cQAoG9A8juOQl6P6oZG4JxA==",
"version": "7.20.7",
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.20.7.tgz",
"integrity": "sha512-8SegXApWe6VoNw0r9JHpSteLKTpTiLZ4rMlGIm9JQ18KiCtyQiAMEazujAHrUS5flrcqYZa75ukev3P6QmUwUw==",
"requires": {
"@babel/code-frame": "^7.18.6",
"@babel/parser": "^7.18.10",
"@babel/types": "^7.18.10"
"@babel/parser": "^7.20.7",
"@babel/types": "^7.20.7"
}
},
"@babel/traverse": {
"version": "7.18.11",
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.18.11.tgz",
"integrity": "sha512-TG9PiM2R/cWCAy6BPJKeHzNbu4lPzOSZpeMfeNErskGpTJx6trEvFaVCbDvpcxwy49BKWmEPwiW8mrysNiDvIQ==",
"version": "7.20.12",
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.20.12.tgz",
"integrity": "sha512-MsIbFN0u+raeja38qboyF8TIT7K0BFzz/Yd/77ta4MsUsmP2RAnidIlwq7d5HFQrH/OZJecGV6B71C4zAgpoSQ==",
"requires": {
"@babel/code-frame": "^7.18.6",
"@babel/generator": "^7.18.10",
"@babel/generator": "^7.20.7",
"@babel/helper-environment-visitor": "^7.18.9",
"@babel/helper-function-name": "^7.18.9",
"@babel/helper-function-name": "^7.19.0",
"@babel/helper-hoist-variables": "^7.18.6",
"@babel/helper-split-export-declaration": "^7.18.6",
"@babel/parser": "^7.18.11",
"@babel/types": "^7.18.10",
"@babel/parser": "^7.20.7",
"@babel/types": "^7.20.7",
"debug": "^4.1.0",
"globals": "^11.1.0"
}
},
"@babel/types": {
"version": "7.18.10",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.18.10.tgz",
"integrity": "sha512-MJvnbEiiNkpjo+LknnmRrqbY1GPUUggjv+wQVjetM/AONoupqRALB7I6jGqNUAZsKcRIEu2J6FRFvsczljjsaQ==",
"version": "7.20.7",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.7.tgz",
"integrity": "sha512-69OnhBxSSgK0OzTJai4kyPDiKTIe3j+ctaHdIGVbRahTLAT7L3R9oeXHC2aVSuGYt3cVnoAMDmOCgJ2yaiLMvg==",
"requires": {
"@babel/helper-string-parser": "^7.18.10",
"@babel/helper-validator-identifier": "^7.18.6",
"@babel/helper-string-parser": "^7.19.4",
"@babel/helper-validator-identifier": "^7.19.1",
"to-fast-properties": "^2.0.0"
}
},
@ -29990,6 +30070,44 @@
"resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz",
"integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw=="
},
"@react-hook/debounce": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/@react-hook/debounce/-/debounce-3.0.0.tgz",
"integrity": "sha512-ir/kPrSfAzY12Gre0sOHkZ2rkEmM4fS5M5zFxCi4BnCeXh2nvx9Ujd+U4IGpKCuPA+EQD0pg1eK2NGLvfWejag==",
"requires": {
"@react-hook/latest": "^1.0.2"
}
},
"@react-hook/event": {
"version": "1.2.6",
"resolved": "https://registry.npmjs.org/@react-hook/event/-/event-1.2.6.tgz",
"integrity": "sha512-JUL5IluaOdn5w5Afpe/puPa1rj8X6udMlQ9dt4hvMuKmTrBS1Ya6sb4sVgvfe2eU4yDuOfAhik8xhbcCekbg9Q==",
"requires": {}
},
"@react-hook/latest": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/@react-hook/latest/-/latest-1.0.3.tgz",
"integrity": "sha512-dy6duzl+JnAZcDbNTfmaP3xHiKtbXYOaz3G51MGVljh548Y8MWzTr+PHLOfvpypEVW9zwvl+VyKjbWKEVbV1Rg==",
"requires": {}
},
"@react-hook/throttle": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/@react-hook/throttle/-/throttle-2.2.0.tgz",
"integrity": "sha512-LJ5eg+yMV8lXtqK3lR+OtOZ2WH/EfWvuiEEu0M3bhR7dZRfTyEJKxH1oK9uyBxiXPtWXiQggWbZirMCXam51tg==",
"requires": {
"@react-hook/latest": "^1.0.2"
}
},
"@react-hook/window-size": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/@react-hook/window-size/-/window-size-3.1.1.tgz",
"integrity": "sha512-yWnVS5LKnOUIrEsI44oz3bIIUYqflamPL27n+k/PC//PsX/YeWBky09oPeAoc9As6jSH16Wgo8plI+ECZaHk3g==",
"requires": {
"@react-hook/debounce": "^3.0.0",
"@react-hook/event": "^1.2.1",
"@react-hook/throttle": "^2.2.0"
}
},
"@rollup/plugin-babel": {
"version": "5.3.1",
"resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-5.3.1.tgz",
@ -38958,9 +39076,9 @@
"integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA=="
},
"json5": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz",
"integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA=="
"version": "2.2.3",
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
"integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg=="
},
"jsonfile": {
"version": "6.1.0",
@ -42491,9 +42609,9 @@
}
},
"promise": {
"version": "8.1.0",
"resolved": "https://registry.npmjs.org/promise/-/promise-8.1.0.tgz",
"integrity": "sha512-W04AqnILOL/sPRXziNicCjSNRruLAuIHEOVBazepu0545DDNGYHz7ar9ZgZ1fMU8/MA4mVxp5rkBWRi6OXIy3Q==",
"version": "8.3.0",
"resolved": "https://registry.npmjs.org/promise/-/promise-8.3.0.tgz",
"integrity": "sha512-rZPNPKTOYVNEEKFaq1HqTgOwZD+4/YHS5ukLzQCypkj+OkYx7iv0mA91lJlpPPZ8vMau3IIGj5Qlwrx+8iiSmg==",
"requires": {
"asap": "~2.0.6"
}
@ -44694,9 +44812,9 @@
}
},
"terser": {
"version": "5.14.2",
"resolved": "https://registry.npmjs.org/terser/-/terser-5.14.2.tgz",
"integrity": "sha512-oL0rGeM/WFQCUd0y2QrWxYnq7tfSuKBiqTjRPWrRgB46WD/kiwHwF8T23z78H6Q6kGCuuHcPB+KULHRdxvVGQA==",
"version": "5.16.1",
"resolved": "https://registry.npmjs.org/terser/-/terser-5.16.1.tgz",
"integrity": "sha512-xvQfyfA1ayT0qdK47zskQgRZeWLoOQ8JQ6mIgRGVNwZKdQMU+5FkCBjmv4QjcrTzyZquRw2FVtlJSRUmMKQslw==",
"requires": {
"@jridgewell/source-map": "^0.3.2",
"acorn": "^8.5.0",

View File

@ -9,6 +9,7 @@
"@emotion/styled": "^11.10.0",
"@mui/icons-material": "^5.8.4",
"@mui/material": "^5.9.3",
"@react-hook/window-size": "^3.1.1",
"@testing-library/jest-dom": "^5.16.5",
"@testing-library/react": "^13.3.0",
"@testing-library/user-event": "^13.5.0",

View File

@ -1,7 +1,8 @@
import { useEffect, useRef } from 'react'
import Paper from '@mui/material/Paper'
import Tooltip from '@mui/material/Tooltip'
import { PeerNameDisplay } from 'components/PeerNameDisplay'
import { getPeerName } from 'components/PeerNameDisplay'
import { VideoStreamType } from 'models/chat'
import { SelectedPeerStream } from './RoomVideoDisplay'
@ -48,7 +49,8 @@ export const PeerVideo = ({
video.srcObject = videoStream
}, [videoRef, videoStream])
const sizePercent = 100 / Math.sqrt(nextPerfectSquare(numberOfVideos - 1))
const cols = Math.sqrt(nextPerfectSquare(numberOfVideos - 1))
const rows = Math.ceil(numberOfVideos / cols)
const handleVideoClick = () => {
onVideoClick?.(userId, videoStreamType, videoStream)
@ -63,44 +65,46 @@ export const PeerVideo = ({
justifyContent: 'center',
mx: 'auto',
overflow: 'auto',
padding: 2,
padding: '0px',
marginBottom: '5px',
marginRight: '5px',
...(selectedPeerStream
? {
height: '100%',
height: 'calc(100% - 5px)',
width: 'calc(100% - 5px)',
}
: {
width: `calc(${sizePercent}% - 1em)`,
height: `calc(${sizePercent}% - 1em)`,
my: 1,
width: `calc(${100 / cols}% - 5px)`,
height: `calc(${100 / rows}% - 5px)`,
}),
...(selectedPeerStream &&
!isSelectedVideo && {
width: 'min-content',
}),
}}
elevation={10}
>
<video
playsInline
ref={videoRef}
onClick={handleVideoClick}
style={{
borderRadius: '.25em',
cursor: 'pointer',
overflow: 'auto',
marginLeft: 'auto',
marginRight: 'auto',
height: '100%',
...(isSelfVideo && {
transform: 'rotateY(180deg)',
}),
<Tooltip
title={getPeerName(userId)}
placement="top"
componentsProps={{
tooltip: { sx: { position: 'absolute', top: '25px' } },
}}
/>
<PeerNameDisplay
sx={{ textAlign: 'center', display: 'block', marginTop: 1, px: 1 }}
>
{userId}
</PeerNameDisplay>
<video
playsInline
ref={videoRef}
onClick={handleVideoClick}
style={{
borderRadius: '.25em',
cursor: 'pointer',
overflow: 'auto',
marginLeft: 'auto',
marginRight: 'auto',
height: '100%',
width: '100%',
...(isSelfVideo && {
transform: 'rotateY(180deg)',
}),
}}
/>
</Tooltip>
</Paper>
)
}

View File

@ -1,15 +1,18 @@
import Accordion from '@mui/material/Accordion'
import AccordionSummary from '@mui/material/AccordionSummary'
import AccordionDetails from '@mui/material/AccordionDetails'
import { useContext } from 'react'
import { useWindowSize } from '@react-hook/window-size'
import Collapse from '@mui/material/Collapse'
import Zoom from '@mui/material/Zoom'
import Box from '@mui/material/Box'
import Divider from '@mui/material/Divider'
import Typography from '@mui/material/Typography'
import ExpandMoreIcon from '@mui/icons-material/ExpandMore'
import { v4 as uuid } from 'uuid'
import { rtcConfig } from 'config/rtcConfig'
import { trackerUrls } from 'config/trackerUrls'
import { RoomContext } from 'contexts/RoomContext'
import { ShellContext } from 'contexts/ShellContext'
import { MessageForm } from 'components/MessageForm'
import { ChatTranscript } from 'components/ChatTranscript'
@ -19,6 +22,8 @@ import { RoomVideoControls } from './RoomVideoControls'
import { RoomScreenShareControls } from './RoomScreenShareControls'
import { RoomFileUploadControls } from './RoomFileUploadControls'
import { RoomVideoDisplay } from './RoomVideoDisplay'
import { RoomShowMessagesControls } from './RoomShowMessagesControls'
import { RoomHideRoomControls } from './RoomHideRoomControls'
export interface RoomProps {
appId?: string
@ -61,6 +66,13 @@ export function Room({
await sendMessage(message)
}
const showMessages = roomContextValue.isShowingMessages
const { showRoomControls } = useContext(ShellContext)
const [windowWidth, windowHeight] = useWindowSize()
const landscape = windowWidth > windowHeight
return (
<RoomContext.Provider value={roomContextValue}>
<Box
@ -72,7 +84,6 @@ export function Room({
overflow: 'auto',
}}
>
{showVideoDisplay && <RoomVideoDisplay userId={userId} />}
<Box
sx={{
display: 'flex',
@ -81,50 +92,70 @@ export function Room({
overflow: 'auto',
}}
>
<Accordion>
<AccordionSummary
expandIcon={<ExpandMoreIcon />}
aria-controls="panel1a-content"
id="panel1a-header"
<Collapse in={showRoomControls}>
<Box
sx={{
alignItems: 'flex-start',
display: 'flex',
justifyContent: 'center',
padding: 1,
overflowX: 'auto',
}}
>
<Typography
sx={{
color: 'text.secondary',
textAlign: 'center',
flexGrow: 1,
}}
>
Room tools
</Typography>
</AccordionSummary>
<AccordionDetails>
<RoomAudioControls peerRoom={peerRoom} />
<RoomVideoControls peerRoom={peerRoom} />
<RoomScreenShareControls peerRoom={peerRoom} />
<RoomFileUploadControls
peerRoom={peerRoom}
onInlineMediaUpload={handleInlineMediaUpload}
/>
<Zoom in={showVideoDisplay} mountOnEnter unmountOnExit>
<span>
<RoomShowMessagesControls />
</span>
</Zoom>
<RoomHideRoomControls />
</Box>
</Collapse>
<Box
sx={{
display: 'flex',
flexDirection: landscape ? 'row' : 'column',
height: '100%',
width: '100%',
overflow: 'auto',
}}
>
{showVideoDisplay && (
<RoomVideoDisplay
userId={userId}
width="100%"
height={landscape || !showMessages ? '100%' : '60%'}
/>
)}
{showMessages && (
<Box
sx={{
alignItems: 'flex-start',
display: 'flex',
justifyContent: 'center',
flexDirection: 'column',
flexGrow: '1',
width: showVideoDisplay && landscape ? '400px' : '100%',
height: landscape ? '100%' : '40%',
}}
>
<RoomAudioControls peerRoom={peerRoom} />
<RoomVideoControls peerRoom={peerRoom} />
<RoomScreenShareControls peerRoom={peerRoom} />
<RoomFileUploadControls
peerRoom={peerRoom}
onInlineMediaUpload={handleInlineMediaUpload}
<ChatTranscript
messageLog={messageLog}
userId={userId}
className="grow overflow-auto px-4"
/>
<Divider />
<MessageForm
onMessageSubmit={handleMessageSubmit}
isMessageSending={isMessageSending}
/>
</Box>
</AccordionDetails>
</Accordion>
<ChatTranscript
messageLog={messageLog}
userId={userId}
className="grow overflow-auto px-4"
/>
<Divider />
<MessageForm
onMessageSubmit={handleMessageSubmit}
isMessageSending={isMessageSending}
/>
)}
</Box>
</Box>
</Box>
</RoomContext.Provider>

View File

@ -0,0 +1,34 @@
import { useContext } from 'react'
import Fab from '@mui/material/Fab'
import Tooltip from '@mui/material/Tooltip'
import { ExpandLess } from '@mui/icons-material'
import { Box } from '@mui/material'
import { ShellContext } from 'contexts/ShellContext'
export function RoomHideRoomControls() {
const { setShowRoomControls } = useContext(ShellContext)
return (
<Box
sx={{
alignItems: 'center',
display: 'flex',
flexDirection: 'column',
justifyContent: 'center',
px: 1,
}}
>
<Tooltip title="Hide controls">
<Fab
color="primary"
aria-label="hide controls"
onClick={() => setShowRoomControls(false)}
>
<ExpandLess />
</Fab>
</Tooltip>
</Box>
)
}

View File

@ -0,0 +1,37 @@
import { useContext } from 'react'
import Fab from '@mui/material/Fab'
import Tooltip from '@mui/material/Tooltip'
import { Comment, CommentsDisabled } from '@mui/icons-material'
import { Badge, Box } from '@mui/material'
import { RoomContext } from 'contexts/RoomContext'
export function RoomShowMessagesControls() {
const { isShowingMessages, setIsShowingMessages, unreadMessages } =
useContext(RoomContext)
return (
<Box
sx={{
alignItems: 'center',
display: 'flex',
flexDirection: 'column',
justifyContent: 'center',
px: 1,
}}
>
<Tooltip title={isShowingMessages ? 'Hide messages' : 'Show messages'}>
<Fab
color={isShowingMessages ? 'error' : 'success'}
aria-label="show messages"
onClick={() => setIsShowingMessages(!isShowingMessages)}
>
<Badge color="error" badgeContent={unreadMessages}>
{isShowingMessages ? <CommentsDisabled /> : <Comment />}
</Badge>
</Fab>
</Tooltip>
</Box>
)
}

View File

@ -22,9 +22,15 @@ export interface SelectedPeerStream {
export interface RoomVideoDisplayProps {
userId: string
width: string
height: string
}
export const RoomVideoDisplay = ({ userId }: RoomVideoDisplayProps) => {
export const RoomVideoDisplay = ({
userId,
width,
height,
}: RoomVideoDisplayProps) => {
const shellContext = useContext(ShellContext)
const roomContext = useContext(RoomContext)
const [selectedPeerStream, setSelectedPeerStream] =
@ -121,11 +127,12 @@ export const RoomVideoDisplay = ({ userId }: RoomVideoDisplayProps) => {
flexDirection: 'column',
overflow: 'auto',
padding: 1,
width: '85%',
width: { width },
height: { height },
}}
>
{selectedPeerStream && (
<Box sx={{ height: '80%' }}>
<Box sx={{ height: '80%', width: '100%' }}>
<PeerVideo
isSelectedVideo
numberOfVideos={numberOfVideos}

View File

@ -88,6 +88,9 @@ export function useRoom(
_setMessageLog(messages.slice(-messageTranscriptSizeLimit))
}
const [isShowingMessages, setIsShowingMessages] = useState(true)
const [unreadMessages, setUnreadMessages] = useState(0)
const [selfVideoStream, setSelfVideoStream] = useState<MediaStream | null>(
null
)
@ -110,6 +113,9 @@ export function useRoom(
() => ({
isPrivate,
isMessageSending,
isShowingMessages,
setIsShowingMessages,
unreadMessages,
selfVideoStream,
setSelfVideoStream,
peerVideoStreams,
@ -124,6 +130,9 @@ export function useRoom(
[
isPrivate,
isMessageSending,
isShowingMessages,
setIsShowingMessages,
unreadMessages,
selfVideoStream,
setSelfVideoStream,
peerVideoStreams,
@ -168,6 +177,10 @@ export function useRoom(
}
}, [setDoShowPeers])
useEffect(() => {
if (isShowingMessages) setUnreadMessages(0)
}, [isShowingMessages, setUnreadMessages])
const [sendPeerId, receivePeerId] = usePeerRoomAction<string>(
peerRoom,
PeerActions.PEER_NAME
@ -234,7 +247,11 @@ export function useRoom(
receivePeerMessage(message => {
const userSettings = settingsContext.getUserSettings()
if (!tabHasFocus) {
if (!isShowingMessages) {
setUnreadMessages(unreadMessages + 1)
}
if (!tabHasFocus || !isShowingMessages) {
if (userSettings.playSoundOnNewMessage) {
newMessageAudio.play()
}
@ -302,6 +319,8 @@ export function useRoom(
Object.values({ ...peerVideoStreams, ...peerScreenStreams }).length > 0
)
if (!showVideoDisplay && !isShowingMessages) setIsShowingMessages(true)
const handleInlineMediaUpload = async (files: File[]) => {
const fileOfferId = await fileTransfer.offer(files)

View File

@ -1,5 +1,6 @@
import { PropsWithChildren } from 'react'
import Box from '@mui/material/Box'
import Collapse from '@mui/material/Collapse'
import { styled } from '@mui/material/styles'
import { DrawerHeader } from './DrawerHeader'
@ -38,12 +39,14 @@ const Main = styled('main', {
interface RouteContentProps extends PropsWithChildren {
isDrawerOpen: boolean
isPeerListOpen: boolean
showAppBar: boolean
}
export const RouteContent = ({
children,
isDrawerOpen,
isPeerListOpen,
showAppBar,
}: RouteContentProps) => {
return (
<Main
@ -55,7 +58,9 @@ export const RouteContent = ({
width: '100%',
}}
>
<DrawerHeader />
<Collapse in={showAppBar} sx={{ flex: 'none' }}>
<DrawerHeader />
</Collapse>
<Box sx={{ overflow: 'auto', flexGrow: 1 }}>{children}</Box>
</Main>
)

View File

@ -40,6 +40,9 @@ export const Shell = ({ appNeedsUpdate, children, userPeerId }: ShellProps) => {
const [isRoomShareDialogOpen, setIsRoomShareDialogOpen] = useState(false)
const [doShowPeers, setDoShowPeers] = useState(false)
const [alertSeverity, setAlertSeverity] = useState<AlertColor>('info')
const [showAppBar, setShowAppBar] = useState(true)
const [showRoomControls, setShowRoomControls] = useState(true)
const [isFullscreen, setIsFullscreen] = useState(false)
const [title, setTitle] = useState('')
const [alertText, setAlertText] = useState('')
const [numberOfPeers, setNumberOfPeers] = useState(1)
@ -67,6 +70,8 @@ export const Shell = ({ appNeedsUpdate, children, userPeerId }: ShellProps) => {
tabHasFocus,
setDoShowPeers,
setNumberOfPeers,
showRoomControls,
setShowRoomControls,
setTitle,
showAlert,
isPeerListOpen,
@ -97,6 +102,8 @@ export const Shell = ({ appNeedsUpdate, children, userPeerId }: ShellProps) => {
tabHasFocus,
setDoShowPeers,
setNumberOfPeers,
showRoomControls,
setShowRoomControls,
setTitle,
showAlert,
audioState,
@ -135,6 +142,57 @@ export const Shell = ({ appNeedsUpdate, children, userPeerId }: ShellProps) => {
document.title = title
}, [title])
const enterFullscreen = async () => {
const body: any = document.body
try {
if (body.requestFullscreen) {
await body.requestFullscreen()
} else if (body.webkitRequestFullscreen) {
await body.webkitRequestFullscreen()
} else if (body.mozRequestFullScreen) {
await body.mozRequestFullScreen()
} else if (body.msRequestFullscreen) {
await body.msRequestFullscreen()
}
} catch (e) {
// Silence harmless errors
}
}
const exitFullscreen = async () => {
const document: any = window.document
try {
if (document.exitFullscreen) {
await document.exitFullscreen()
} else if (document.webkitExitFullscreen) {
await document.webkitExitFullscreen()
} else if (document.mozCancelFullScreen) {
await document.mozCancelFullScreen()
} else if (document.msExitFullScreen) {
await document.msExitFullScreen()
}
} catch (e) {
// Silence harmless errors
}
}
useEffect(() => {
if (isFullscreen) {
enterFullscreen()
setShowRoomControls(false)
setShowAppBar(false)
} else {
exitFullscreen()
setShowAppBar(true)
setShowRoomControls(true)
}
}, [isFullscreen, setShowRoomControls, setShowAppBar])
useEffect(() => {
if (isFullscreen) setShowAppBar(showRoomControls)
}, [isFullscreen, showRoomControls, setShowAppBar])
useEffect(() => {
const handleFocus = () => {
setTabHasFocus(true)
@ -142,11 +200,16 @@ export const Shell = ({ appNeedsUpdate, children, userPeerId }: ShellProps) => {
const handleBlur = () => {
setTabHasFocus(false)
}
const handleFullscreen = (event: Event) => {
setIsFullscreen(!!document.fullscreenElement)
}
window.addEventListener('focus', handleFocus)
window.addEventListener('blur', handleBlur)
document.addEventListener('fullscreenchange', handleFullscreen)
return () => {
window.removeEventListener('focus', handleFocus)
window.removeEventListener('blur', handleBlur)
document.removeEventListener('fullscreenchange', handleFullscreen)
}
}, [])
@ -230,7 +293,11 @@ export const Shell = ({ appNeedsUpdate, children, userPeerId }: ShellProps) => {
numberOfPeers={numberOfPeers}
title={title}
onPeerListClick={handlePeerListClick}
onRoomControlsClick={() => setShowRoomControls(!showRoomControls)}
setIsQRCodeDialogOpen={setIsQRCodeDialogOpen}
showAppBar={showAppBar}
isFullscreen={isFullscreen}
setIsFullscreen={setIsFullscreen}
/>
<Drawer
isDrawerOpen={isDrawerOpen}
@ -245,6 +312,7 @@ export const Shell = ({ appNeedsUpdate, children, userPeerId }: ShellProps) => {
<RouteContent
isDrawerOpen={isDrawerOpen}
isPeerListOpen={isPeerListOpen}
showAppBar={showAppBar}
>
<ErrorBoundary>{children}</ErrorBoundary>
</RouteContent>

View File

@ -1,13 +1,22 @@
import { styled } from '@mui/material/styles'
import MuiAppBar, { AppBarProps as MuiAppBarProps } from '@mui/material/AppBar'
import Toolbar from '@mui/material/Toolbar'
import Typography from '@mui/material/Typography'
import StepIcon from '@mui/material/StepIcon'
import Tooltip from '@mui/material/Tooltip'
import IconButton from '@mui/material/IconButton'
import MenuIcon from '@mui/icons-material/Menu'
import LinkIcon from '@mui/icons-material/Link'
import QrCode2Icon from '@mui/icons-material/QrCode2'
import MuiAppBar, { AppBarProps as MuiAppBarProps } from '@mui/material/AppBar'
import Fab from '@mui/material/Fab'
import StepIcon from '@mui/material/StepIcon'
import Toolbar from '@mui/material/Toolbar'
import Tooltip from '@mui/material/Tooltip'
import Typography from '@mui/material/Typography'
import Slide from '@mui/material/Slide'
import Zoom from '@mui/material/Zoom'
import ExpandMore from '@mui/icons-material/ExpandMore'
import Fullscreen from '@mui/icons-material/Fullscreen'
import FullscreenExit from '@mui/icons-material/FullscreenExit'
import Link from '@mui/icons-material/Link'
import Menu from '@mui/icons-material/Menu'
import QrCode2 from '@mui/icons-material/QrCode2'
import RoomPreferences from '@mui/icons-material/RoomPreferences'
import { drawerWidth } from './Drawer'
import { peerListWidth } from './PeerList'
@ -54,7 +63,11 @@ interface ShellAppBarProps {
numberOfPeers: number
title: string
onPeerListClick: () => void
onRoomControlsClick: () => void
setIsQRCodeDialogOpen: (isOpen: boolean) => void
showAppBar: boolean
isFullscreen: boolean
setIsFullscreen: (isFullscreen: boolean) => void
}
export const ShellAppBar = ({
@ -67,76 +80,124 @@ export const ShellAppBar = ({
numberOfPeers,
title,
onPeerListClick,
onRoomControlsClick,
showAppBar,
isFullscreen,
setIsFullscreen,
}: ShellAppBarProps) => {
const handleQRCodeClick = () => setIsQRCodeDialogOpen(true)
const onClickFullscreen = () => setIsFullscreen(!isFullscreen)
return (
<AppBar
position="fixed"
isDrawerOpen={isDrawerOpen}
isPeerListOpen={isPeerListOpen}
>
<Toolbar
variant="regular"
sx={{
display: 'flex',
flexDirection: 'row',
justifyContent: 'space-between',
}}
>
<IconButton
size="large"
edge="start"
color="inherit"
aria-label="Open menu"
sx={{ mr: 2, ...(isDrawerOpen && { display: 'none' }) }}
onClick={onDrawerOpen}
<>
<Slide appear={false} in={showAppBar} mountOnEnter unmountOnExit>
<AppBar
position="fixed"
isDrawerOpen={isDrawerOpen}
isPeerListOpen={isPeerListOpen}
>
<MenuIcon />
</IconButton>
<Typography
variant="h6"
noWrap
component="div"
sx={{ marginRight: 'auto' }}
>
{title}
</Typography>
<Tooltip title="Copy current URL">
<IconButton
size="large"
color="inherit"
aria-label="Copy current URL"
onClick={onLinkButtonClick}
<Toolbar
variant="regular"
sx={{
display: 'flex',
flexDirection: 'row',
justifyContent: 'space-between',
}}
>
<LinkIcon />
</IconButton>
<IconButton
size="large"
edge="start"
color="inherit"
aria-label="Open menu"
sx={{ mr: 2, ...(isDrawerOpen && { display: 'none' }) }}
onClick={onDrawerOpen}
>
<Menu />
</IconButton>
<Typography
variant="h6"
noWrap
component="div"
sx={{ marginRight: 'auto' }}
>
{title}
</Typography>
<Tooltip title="Copy current URL">
<IconButton
size="large"
color="inherit"
aria-label="Copy current URL"
onClick={onLinkButtonClick}
>
<Link />
</IconButton>
</Tooltip>
{doShowPeers ? (
<>
<Tooltip title="Show QR Code">
<IconButton
size="large"
color="inherit"
aria-label="Show QR Code"
onClick={handleQRCodeClick}
>
<QrCode2 />
</IconButton>
</Tooltip>
<Tooltip title="Show Room Controls">
<IconButton
size="large"
color="inherit"
aria-label="show room controls"
onClick={onRoomControlsClick}
>
<RoomPreferences />
</IconButton>
</Tooltip>
<Tooltip
title={isFullscreen ? 'Exit fullscreen' : 'Enter fullscreen'}
>
<IconButton
size="large"
edge="end"
color="inherit"
aria-label="fullscreen"
onClick={onClickFullscreen}
>
{isFullscreen ? <FullscreenExit /> : <Fullscreen />}
</IconButton>
</Tooltip>
<Tooltip title="Click to show peer list">
<IconButton
size="large"
edge="end"
color="inherit"
aria-label="Peer list"
onClick={onPeerListClick}
>
<StepIcon icon={numberOfPeers} />
</IconButton>
</Tooltip>
</>
) : null}
</Toolbar>
</AppBar>
</Slide>
<Zoom
style={{ position: 'absolute', left: '16px', top: '16px' }}
in={!showAppBar}
unmountOnExit
>
<Tooltip title="Show room controls">
<Fab
size="small"
aria-label="show room controls"
color="primary"
onClick={onRoomControlsClick}
>
<ExpandMore />
</Fab>
</Tooltip>
{doShowPeers ? (
<>
<Tooltip title="Show QR Code">
<IconButton
size="large"
color="inherit"
aria-label="Show QR Code"
onClick={handleQRCodeClick}
>
<QrCode2Icon />
</IconButton>
</Tooltip>
<Tooltip title="Click to show peer list">
<IconButton
size="large"
edge="end"
color="inherit"
aria-label="Peer list"
onClick={onPeerListClick}
>
<StepIcon icon={numberOfPeers} />
</IconButton>
</Tooltip>
</>
) : null}
</Toolbar>
</AppBar>
</Zoom>
</>
)
}

View File

@ -4,6 +4,9 @@ import { FileOfferMetadata } from 'models/chat'
interface RoomContextProps {
isPrivate: boolean
isMessageSending: boolean
isShowingMessages: boolean
setIsShowingMessages: Dispatch<SetStateAction<boolean>>
unreadMessages: number
selfVideoStream: MediaStream | null
setSelfVideoStream: Dispatch<SetStateAction<MediaStream | null>>
peerVideoStreams: Record<string, MediaStream>
@ -21,6 +24,9 @@ interface RoomContextProps {
export const RoomContext = createContext<RoomContextProps>({
isPrivate: false,
isMessageSending: false,
isShowingMessages: true,
setIsShowingMessages: () => {},
unreadMessages: 0,
selfVideoStream: null,
setSelfVideoStream: () => {},
peerVideoStreams: {},

View File

@ -8,6 +8,8 @@ interface ShellContextProps {
tabHasFocus: boolean
setDoShowPeers: Dispatch<SetStateAction<boolean>>
setNumberOfPeers: Dispatch<SetStateAction<number>>
showRoomControls: boolean
setShowRoomControls: Dispatch<SetStateAction<boolean>>
setTitle: Dispatch<SetStateAction<string>>
showAlert: (message: string, options?: AlertOptions) => void
roomId?: string
@ -31,6 +33,8 @@ export const ShellContext = createContext<ShellContextProps>({
tabHasFocus: true,
setDoShowPeers: () => {},
setNumberOfPeers: () => {},
showRoomControls: false,
setShowRoomControls: () => {},
setTitle: () => {},
showAlert: () => {},
roomId: undefined,