From 0bd25736ba321433094e47b595e12c87877ffbb5 Mon Sep 17 00:00:00 2001 From: Miroslav Pejic Date: Fri, 22 Oct 2021 23:28:47 +0200 Subject: [PATCH] [mirotalksfu] - UI-UX improve --- public/css/Room.css | 247 +++++++++++++++++++--------------------- public/js/Room.js | 108 +++++++++--------- public/js/RoomClient.js | 90 ++++++++++++--- public/view/Room.html | 230 +++++++++++++++++++++++++------------ 4 files changed, 407 insertions(+), 268 deletions(-) diff --git a/public/css/Room.css b/public/css/Room.css index 3a88825..9e1aa6b 100644 --- a/public/css/Room.css +++ b/public/css/Room.css @@ -45,6 +45,21 @@ --right-msg-bg: #0a0b0c; --box-shadow: 0px 8px 16px 0px rgba(0, 0, 0, 0.2); --btns-hover-scale: scale(1.1); + /* buttons bar horizontal */ + --btns-top: 50%; + --btns-right: 0%; + --btns-left: 20px; + --btns-margin-left: 0px; + --btns-width: 60px; + --btns-flex-direction: column; + /* buttons bar horizontal + --btns-top: 95%; + --btns-right: 25%; + --btns-left: 50%; + --btns-margin-left: -160px; + --btns-width: 320px; + --btns-flex-direction: row; + */ } * { @@ -79,99 +94,54 @@ body { font-family: 'Comfortaa'; } +#initAudioButton, +#initVideoButton { + font-size: 1.8rem; +} + /*-------------------------------------------------------------- # Buttons bar --------------------------------------------------------------*/ -#openNavButton { +#control { z-index: 3; position: absolute; - cursor: pointer; - padding: 10px; - font-size: 24px; - color: white; - background: rgba(0, 0, 0, 0.4); - border-radius: 10px; - /* pulsate */ - animation: pulsate 5s ease-out; - animation-iteration-count: infinite; - -webkit-animation: pulsate 5s ease-out; - -webkit-animation-iteration-count: infinite; - opacity: 0.5; -} - -.sidenav { - z-index: 4; - height: 100%; - width: 0; - position: fixed; - top: 0; - left: 0; - background-color: transparent; - overflow-x: hidden; - transition: 0.5s; - padding-top: 60px; - animation: show 0.4s ease; -} - -.sidenav button { - padding: 8px 8px 8px 32px; - text-decoration: none; - font-size: 20px; - transition: 0.3s; -} - -.sidenav button:hover { - color: grey; - transform: var(--btns-hover-scale); -} + display: flex; + padding: 15px; -.sidenav .closebtn { - position: absolute; - top: 0; - right: 25px; - font-size: 36px; - margin-left: 50px; -} + top: var(--btns-top); + right: var(--btns-right); + left: var(--btns-left); + margin-left: var(--btns-margin-left); + width: var(--btns-width); + flex-direction: var(--btns-flex-direction); -.sidenav::-webkit-scrollbar { - width: 5px; -} -.sidenav::-webkit-scrollbar-track { - background: transparent; -} -.sidenav::-webkit-scrollbar-thumb { - background: rgb(255 255 255 / 40%); -} + grid-gap: 0.4rem; + align-items: center; + justify-content: center; -@media screen and (max-height: 450px) { - .sidenav { - padding-top: 20px; - } - .sidenav button { - font-size: 20px; - } -} + -webkit-transform: translate(0%, -50%); + -ms-transform: translate(0%, -50%); + transform: translate(0%, -50%); -#control { - position: fixed; - padding: 10px; - top: 0; - width: 250px; - background: var(--body-bg); + border-radius: 20px; + background: rgba(0, 0, 0, 0.7); } #control button { + border: none; + font-size: 1.5rem; + transition: all 0.3s ease-in-out; + background: transparent; border-radius: 5px; } - -#exitButton:hover { - color: red; +#control p { + font-size: small; + cursor: default; } -#settings { - position: relative; - background: var(--body-bg); +#exitButton { + color: red; } /*-------------------------------------------------------------- @@ -185,47 +155,89 @@ body { } /*-------------------------------------------------------------- -# Dropdown menù +# My settings --------------------------------------------------------------*/ -.dropdown { - position: relative; - display: inline-block; -} - -.dropdown-content { - display: none; +#mySettings { + z-index: 6; position: absolute; margin: auto; padding: 10px; - max-width: 230px; - background-color: rgba(0, 0, 0, 0.7); + width: 320px; + height: 480px; + background: var(--msger-bg); + box-shadow: var(--box-shadow); + border-radius: 10px; + overflow: scroll; +} + +#mySettingsHeader { + cursor: move; +} + +#mySettings i, +#mySettings p { + display: inline-block; color: white; - overflow: hidden; + padding: 5px; + background: transparent; +} + +#mySettings select { + width: auto; + max-width: 270px; + height: 40px; + color: white; + background-color: transparent; border-radius: 5px; - box-shadow: var(--box-shadow); } -.dropdown-content select { - width: 210px; - font-size: small; +#mySettings button:hover { + background-color: rgb(42 42 42 / 70%); + border-radius: 5px; } /*-------------------------------------------------------------- -# Recording +# Style the tab --------------------------------------------------------------*/ +.tab { + overflow: hidden; + background-color: rgba(0, 0, 0, 0.4); +} -#recording { - position: relative; - background: var(--body-bg); +/* Style the buttons inside the tab */ +.tab button { + background-color: inherit; + float: left; + border: none; + outline: none; + cursor: pointer; + padding: 14px 16px; + transition: 0.3s; + color: white; } -#recording button, -#recording p { - padding: 5px; - margin: 1px; - font-size: 1.2rem; - border-radius: 5px; +/* Change background color of buttons on hover */ +.tab button:hover { + background-color: transparent; + color: grey; +} + +/* Create an active/current tablink class */ +.tab button.active { + background-color: rgb(42 42 42 / 70%); +} + +/* Style the tab content */ +.tabcontent { + display: none; + padding: 6px 12px; + border-top: none; +} + +/* on open display devices tab */ +#tabDevices { + display: block; } /*-------------------------------------------------------------- @@ -539,11 +551,11 @@ button:hover { --------------------------------------------------------------*/ #participants { - z-index: 6; + z-index: 7; position: absolute; margin: auto; padding: 10px; - min-width: 320px; + width: 320px; background: var(--body-bg); border-radius: 10px; overflow: hidden; @@ -589,7 +601,7 @@ button:hover { #sendFileDiv, #receiveFileDiv { - z-index: 7; + z-index: 8; display: none; padding: 10px; margin: auto; @@ -618,29 +630,10 @@ progress { min-width: 100%; } -/*-------------------------------------------------------------- -# YouTube Video ---------------------------------------------------------------*/ - -#youTubeSettings { - display: 'none'; - position: relative; - background: var(--body-bg); -} - -#youTubeCloseBtn:hover { - color: red; -} - /*-------------------------------------------------------------- # Whiteboard --------------------------------------------------------------*/ -#whiteboardSettings { - position: relative; - background: var(--body-bg); -} - #whiteboard { z-index: 2; position: absolute; @@ -716,9 +709,9 @@ progress { z-index: - 1 videoMediaContainer - 2 whiteboard - - 3 buttonBar - - 4 sidenav - - 4 whiteboard + - 3 control buttons - 5 chat - - 6 participants + - 6 settings + - 7 participants + - 8 send receive progress */ diff --git a/public/js/Room.js b/public/js/Room.js index d6316bd..53116a3 100644 --- a/public/js/Room.js +++ b/public/js/Room.js @@ -40,7 +40,6 @@ let isAudioOn = true; let isVideoOn = true; let initAudioButton = null; let initVideoButton = null; -let initDisableAllButton = null; let recTimer = null; let recElapsedTime = null; @@ -55,6 +54,8 @@ let wbIsRedoing = false; let wbIsEraser = false; let wbPop = []; +let isButtonsVisible = false; + const socket = io(); function getRandomNumber(length) { @@ -69,8 +70,12 @@ function getRandomNumber(length) { function initClient() { if (!DetectRTC.isMobileDevice) { - setTippy('openNavButton', 'Open', 'right'); - setTippy('closeNavButton', 'Close', 'right'); + setTippy('tabDevicesBtn', 'Devices', 'top'); + setTippy('tabWhiteboardBtn', 'Whiteboard', 'top'); + setTippy('tabRecordingBtn', 'Recording', 'top'); + setTippy('tabRoomBtn', 'Room', 'top'); + setTippy('tabYoutubeBtn', 'YouTube', 'top'); + setTippy('tabStylingBtn', 'Styling', 'top'); setTippy('whiteboardPencilBtn', 'Drawing mode', 'top'); setTippy('whiteboardObjectBtn', 'Object mode', 'top'); setTippy('whiteboardUndoBtn', 'Undo', 'top'); @@ -84,15 +89,12 @@ function initClient() { setTippy('whiteboardSaveBtn', 'Save', 'top'); setTippy('whiteboardEraserBtn', 'Eraser', 'top'); setTippy('whiteboardCleanBtn', 'Clear', 'top'); - setTippy('whiteboardCloseBtn', 'Close', 'top'); setTippy('participantsRefreshBtn', 'Refresh', 'top'); - setTippy('participantsCloseBtn', 'Close', 'top'); setTippy('chatMessage', 'Press enter to send', 'top-start'); setTippy('chatSendButton', 'Send', 'top'); setTippy('chatEmojiButton', 'Emoji', 'top'); setTippy('chatCleanButton', 'Clean', 'bottom'); setTippy('chatSaveButton', 'Save', 'bottom'); - setTippy('chatCloseButton', 'Close', 'bottom'); setTippy('sessionTime', 'Session time', 'right'); } setupWhiteboard(); @@ -247,8 +249,7 @@ function whoAreYou() { html: `
-  | - +
`, confirmButtonText: `Join meeting`, showClass: { @@ -269,19 +270,8 @@ function whoAreYou() { initAudioButton = document.getElementById('initAudioButton'); initVideoButton = document.getElementById('initVideoButton'); - initDisableAllButton = document.getElementById('initDisableAllButton'); - let separator = document.getElementById('separator'); if (!isAudioAllowed) initAudioButton.className = 'hidden'; - if (!isVideoAllowed) { - initVideoButton.className = 'hidden'; - initDisableAllButton.className = 'hidden'; - separator.className = 'hidden'; - } - if (!DetectRTC.isMobileDevice) { - setTippy('initAudioButton', 'Enable / Disable audio', 'left'); - setTippy('initVideoButton', 'Enable / Disable video', 'right'); - setTippy('initDisableAllButton', 'Disable audio & video', 'right'); - } + if (!isVideoAllowed) initVideoButton.className = 'hidden'; } function handleAudio(e) { @@ -298,15 +288,6 @@ function handleVideo(e) { setColor(startVideoButton, isVideoOn ? 'white' : 'red'); } -function disableAudioVideo() { - isAudioOn = false; - isVideoOn = false; - initAudioButton.className = 'fas fa-microphone-slash'; - initVideoButton.className = 'fas fa-video-slash'; - setColor(initAudioButton, 'red'); - setColor(initVideoButton, 'red'); -} - // #################################################### // SHARE ROOM // #################################################### @@ -427,10 +408,8 @@ function joinRoom(peer_name, room_id) { } function roomIsReady() { - show(openNavButton); show(exitButton); show(shareButton); - show(recButton); show(startRecButton); show(chatButton); show(chatSendButton); @@ -440,6 +419,7 @@ function roomIsReady() { setChatSize(); } else { rc.makeDraggable(chatRoom, chatHeader); + rc.makeDraggable(mySettings, mySettingsHeader); rc.makeDraggable(participants, participantsHeader); rc.makeDraggable(whiteboard, whiteboardHeader); if (navigator.getDisplayMedia || navigator.mediaDevices.getDisplayMedia) { @@ -456,9 +436,7 @@ function roomIsReady() { show(raiseHandButton); if (isAudioAllowed) show(startAudioButton); if (isVideoAllowed) show(startVideoButton); - show(youTubeShareButton); show(fileShareButton); - show(whiteboardButton); show(participantsButton); show(lockRoomButton); show(aboutButton); @@ -466,6 +444,9 @@ function roomIsReady() { handleSelects(); handleInputs(); startSessionTimer(); + document.body.addEventListener('mousemove', (e) => { + showButtons(); + }); } function hide(elem) { @@ -548,20 +529,35 @@ function stopRecordingTimer() { // #################################################### function handleButtons() { - openNavButton.onclick = () => { - rc.toggleNav(); - }; - closeNavButton.onclick = () => { - rc.toggleNav(); - }; exitButton.onclick = () => { - rc.exit(); + rc.exitRoom(); }; shareButton.onclick = () => { shareRoom(true); }; settingsButton.onclick = () => { - rc.toggleDevices(); + rc.toggleMySettings(); + }; + mySettingsCloseBtn.onclick = () => { + rc.toggleMySettings(); + }; + tabDevicesBtn.onclick = (e) => { + rc.openTab(e, 'tabDevices'); + }; + tabWhiteboardBtn.onclick = (e) => { + rc.openTab(e, 'tabWhiteboard'); + }; + tabRecordingBtn.onclick = (e) => { + rc.openTab(e, 'tabRecording'); + }; + tabRoomBtn.onclick = (e) => { + rc.openTab(e, 'tabRoom'); + }; + tabYoutubeBtn.onclick = (e) => { + rc.openTab(e, 'tabYoutube'); + }; + tabStylingBtn.onclick = (e) => { + rc.openTab(e, 'tabStyling'); }; chatButton.onclick = () => { rc.toggleChat(); @@ -584,9 +580,6 @@ function handleButtons() { fullScreenButton.onclick = () => { rc.toggleFullScreen(); }; - recButton.onclick = () => { - rc.toggleRecording(); - }; startRecButton.onclick = () => { rc.startRecording(); }; @@ -727,6 +720,10 @@ function handleSelects() { videoSelect.onchange = () => { rc.closeThenProduce(RoomClient.mediaType.video, videoSelect.value); }; + // styling + BtnsBarPosition.onchange = () => { + rc.changeBtnsBarPosition(BtnsBarPosition.value); + }; // whiteboard options wbDrawingLineWidthEl.onchange = () => { wbCanvas.freeDrawingBrush.width = parseInt(wbDrawingLineWidthEl.value, 10) || 1; @@ -916,6 +913,16 @@ function getDataTimeString() { return `${date}-${time}`; } +function showButtons() { + if (isButtonsVisible || (rc.isMobileDevice && rc.isChatOpen) || (rc.isMobileDevice && rc.isMySettingsOpen)) return; + control.style.display = 'flex'; + isButtonsVisible = true; + setTimeout(() => { + control.style.display = 'none'; + isButtonsVisible = false; + }, 10000); +} + // #################################################### // UTILITY // #################################################### @@ -940,7 +947,6 @@ function isImageURL(url) { function toggleWhiteboard() { if (!wbIsOpen) rc.sound('open'); - toggleWhiteboardSettings(); let whiteboard = rc.getId('whiteboard'); whiteboard.classList.toggle('show'); whiteboard.style.top = '50%'; @@ -948,10 +954,6 @@ function toggleWhiteboard() { wbIsOpen = wbIsOpen ? false : true; } -function toggleWhiteboardSettings() { - rc.getId('whiteboardSettings').classList.toggle('show'); -} - function setupWhiteboard() { setupWhiteboardCanvas(); setupWhiteboardCanvasSize(); @@ -1329,11 +1331,11 @@ async function getParticipantsTable(peers) { table += ` 👥 All - - + + - - + + `; diff --git a/public/js/RoomClient.js b/public/js/RoomClient.js index ecf5187..951cc06 100644 --- a/public/js/RoomClient.js +++ b/public/js/RoomClient.js @@ -88,6 +88,8 @@ class RoomClient { this.isMobileDevice = DetectRTC.isMobileDevice; + this.isMySettingsOpen = false; + this._isConnected = false; this.isVideoOnFullScreen = false; this.isChatOpen = false; @@ -1054,6 +1056,27 @@ class RoomClient { this.event(_EVENTS.exitRoom); } + exitRoom() { + this.sound('open'); + + Swal.fire({ + background: swalBackground, + position: 'center', + title: 'Leave this room?', + showDenyButton: true, + confirmButtonText: `Yes`, + denyButtonText: `No`, + showClass: { + popup: 'animate__animated animate__fadeInDown', + }, + hideClass: { + popup: 'animate__animated animate__fadeOutUp', + }, + }).then((result) => { + if (result.isConfirmed) this.exit(); + }); + } + // #################################################### // HELPERS // #################################################### @@ -1177,6 +1200,10 @@ class RoomClient { return document.getElementById(id); } + getEcN(cn) { + return document.getElementsByClassName(cn); + } + async getRoomInfo() { let room_info = await this.socket.request('getRoomInfo'); return room_info; @@ -1198,14 +1225,6 @@ class RoomClient { // UTILITY // #################################################### - toggleNav() { - this.getId('control').classList.toggle('show'); - } - - toggleDevices() { - this.getId('settings').classList.toggle('show'); - } - async sound(name) { let sound = '../sounds/' + name + '.wav'; let audio = new Audio(sound); @@ -1238,6 +1257,53 @@ class RoomClient { return false; } + // #################################################### + // MY SETTINGS + // #################################################### + + toggleMySettings() { + let mySettings = this.getId('mySettings'); + mySettings.style.top = '50%'; + mySettings.style.left = '50%'; + mySettings.classList.toggle('show'); + this.isMySettingsOpen = this.isMySettingsOpen ? false : true; + } + + openTab(evt, tabName) { + let i, tabcontent, tablinks; + tabcontent = this.getEcN('tabcontent'); + for (i = 0; i < tabcontent.length; i++) { + tabcontent[i].style.display = 'none'; + } + tablinks = this.getEcN('tablinks'); + for (i = 0; i < tablinks.length; i++) { + tablinks[i].className = tablinks[i].className.replace(' active', ''); + } + this.getId(tabName).style.display = 'block'; + evt.currentTarget.className += ' active'; + } + + changeBtnsBarPosition(position) { + switch (position) { + case 'vertical': + document.documentElement.style.setProperty('--btns-top', '50%'); + document.documentElement.style.setProperty('--btns-right', '0px'); + document.documentElement.style.setProperty('--btns-left', '20px'); + document.documentElement.style.setProperty('--btns-margin-left', '0px'); + document.documentElement.style.setProperty('--btns-width', '40px'); + document.documentElement.style.setProperty('--btns-flex-direction', 'column'); + break; + case 'horizontal': + document.documentElement.style.setProperty('--btns-top', '95%'); + document.documentElement.style.setProperty('--btns-right', '25%'); + document.documentElement.style.setProperty('--btns-left', '50%'); + document.documentElement.style.setProperty('--btns-margin-left', '-160px'); + document.documentElement.style.setProperty('--btns-width', '320px'); + document.documentElement.style.setProperty('--btns-flex-direction', 'row'); + break; + } + } + // #################################################### // FULL SCREEN // #################################################### @@ -1454,10 +1520,6 @@ class RoomClient { // RECORDING // #################################################### - toggleRecording() { - this.getId('recording').classList.toggle('show'); - } - getSupportedMimeTypes() { const possibleTypes = [ 'video/webm;codecs=vp9,opus', @@ -1931,7 +1993,7 @@ class RoomClient { let peer_name = data.peer_name; let you_tube_url = data.you_tube_url; this.closeYouTube(); - youTubeSettings.style.display = 'block'; + show(youTubeCloseBtn); d = document.createElement('div'); d.className = 'Camera'; d.id = '__youTube'; @@ -1963,7 +2025,7 @@ class RoomClient { } let youTubeDiv = this.getId('__youTube'); if (youTubeDiv) { - youTubeSettings.style.display = 'none'; + hide(youTubeCloseBtn); youTubeDiv.parentNode.removeChild(youTubeDiv); resizeVideoMedia(); this.sound('left'); diff --git a/public/view/Room.html b/public/view/Room.html index 8d789c2..8d0a2bc 100644 --- a/public/view/Room.html +++ b/public/view/Room.html @@ -96,84 +96,166 @@ access to use this app. - -