diff --git a/app/src/server.js b/app/src/server.js index eb224eab4..9da266abb 100755 --- a/app/src/server.js +++ b/app/src/server.js @@ -39,7 +39,7 @@ dependencies: { * @license For commercial use or closed source, contact us at license.mirotalk@gmail.com or purchase directly from CodeCanyon * @license CodeCanyon: https://codecanyon.net/item/mirotalk-p2p-webrtc-realtime-video-conferences/38376661 * @author Miroslav Pejic - miroslav.pejic.85@gmail.com - * @version 1.3.68 + * @version 1.3.70 * */ diff --git a/package.json b/package.json index f3a3f29dc..37fb4f8a6 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "mirotalk", - "version": "1.3.68", + "version": "1.3.70", "description": "A free WebRTC browser-based video call", "main": "server.js", "scripts": { @@ -55,7 +55,7 @@ "js-yaml": "^4.1.0", "ngrok": "^5.0.0-beta.2", "nodemailer": "^6.9.14", - "openai": "^4.55.7", + "openai": "^4.56.0", "qs": "^6.13.0", "socket.io": "^4.7.5", "swagger-ui-express": "^5.0.1", diff --git a/public/css/client.css b/public/css/client.css index 435e51969..e5cb2fd71 100755 --- a/public/css/client.css +++ b/public/css/client.css @@ -16,6 +16,8 @@ --msger-width: 420px; --msger-bubble-width: 85%; + --caption-top: 50%; + --caption-left: 50%; --caption-height: 680px; --caption-width: 420px; @@ -345,10 +347,6 @@ body { z-index: 14; display: none; position: fixed; - /* center screen */ - top: var(--caption-top); - left: var(--caption-left); - transform: translate(-50%, -50%); /* end center screen */ height: var(--caption-height); width: var(--caption-width); @@ -361,6 +359,7 @@ body { overflow: hidden; border-radius: 10px; box-shadow: var(--box-shadow); + transition: width 0.5s ease-in-out; } .caption { @@ -386,7 +385,7 @@ body { padding: 5px; /* border: var(--border); */ border: none; - font-size: 1.1rem; + font-size: 1rem; background: transparent; color: #fff; border-radius: 5px; @@ -467,10 +466,6 @@ body { z-index: 14; display: none; position: fixed; - /* center screen */ - top: var(--msger-top); - left: var(--msger-left); - transform: translate(-50%, -50%); /* end center screen */ height: var(--msger-height); width: var(--msger-width); @@ -483,6 +478,7 @@ body { overflow: hidden; border-radius: 10px; box-shadow: var(--box-shadow); + transition: width 0.5s ease-in-out; } .msger { @@ -520,7 +516,7 @@ body { padding: 5px; /* border: var(--border); */ border: none; - font-size: 1.1rem; + font-size: 1rem; background: transparent; color: #fff; border-radius: 5px; @@ -860,10 +856,11 @@ button:hover { position: absolute; bottom: 105px; left: 10px; + background: var(--body-bg); border: var(--border); border-radius: 5px; - --rgb-background: var(--body-bg); - --color-border-over: var(--body-bg); + --rgb-background: var(--body-bg) !important; + --color-border-over: var(--body-bg) !important; --font-family: 'Comfortaa'; } @@ -1875,11 +1872,11 @@ hr { /* Styles for the dropdown button */ .dropdown-toggle { - background-color: var(--body-bg); + /* padding: 10px 20px; */ color: #fff; border: none; border-radius: 5px; - /* padding: 10px 20px; */ + background-color: var(--body-bg); cursor: pointer; } @@ -1894,6 +1891,59 @@ hr { box-shadow: var(--box-shadow); } +/*-------------------------------------------------------------- +# Dropdown menu custom +--------------------------------------------------------------*/ + +/* General container for the dropdown */ +.dropdown-custom { + position: relative; + display: inline-block; +} + +/* Style the button that triggers the dropdown */ +.dropdown-toggle-custom { + color: #fff; + border: var(--border); + background: var(--body-bg); + cursor: pointer; +} + +/* Dropdown menu */ +.dropdown-menu-custom { + z-index: 1; + display: none; + position: absolute; + right: 0; + padding: 10px 0; + min-width: 240px; + border-radius: 5px; + border: var(--border); + background: var(--body-bg); + box-shadow: var(--box-shadow); +} + +/* Style for dropdown items */ +.dropdown-menu-custom li { + padding: 8px 16px; + list-style-type: none; +} + +.dropdown-menu-custom li button { + border: none; + background: none; + width: 100%; + text-align: left; + padding: 8px 16px; + font-size: 0.8em; + cursor: pointer; + color: #fff; +} + +.dropdown-menu-custom li button:hover { + background-color: var(--hover-bg); /* Use a default hover color if --hover-bg is not defined */ +} + /* Styles for table cell with title (td) */ .microphone-table-width { width: 50%; diff --git a/public/js/client.js b/public/js/client.js index 55d65ca87..d5bd7fbc6 100644 --- a/public/js/client.js +++ b/public/js/client.js @@ -15,7 +15,7 @@ * @license For commercial use or closed source, contact us at license.mirotalk@gmail.com or purchase directly from CodeCanyon * @license CodeCanyon: https://codecanyon.net/item/mirotalk-p2p-webrtc-realtime-video-conferences/38376661 * @author Miroslav Pejic - miroslav.pejic.85@gmail.com - * @version 1.3.68 + * @version 1.3.70 * */ @@ -166,6 +166,7 @@ const buttons = { showAboutBtn: true, // Please keep me always true, Thank you! }, chat: { + showTogglePinBtn: true, showMaxBtn: true, showSaveMessageBtn: true, showMarkDownBtn: true, @@ -175,6 +176,7 @@ const buttons = { showParticipantsBtn: true, }, caption: { + showTogglePinBtn: true, showMaxBtn: true, }, settings: { @@ -265,8 +267,11 @@ const userEmoji = getId(`userEmoji`); // Chat room const msgerDraggable = getId('msgerDraggable'); const msgerHeader = getId('msgerHeader'); +const msgerTogglePin = getId('msgerTogglePin'); const msgerTheme = getId('msgerTheme'); const msgerCPBtn = getId('msgerCPBtn'); +const msgerDropDownMenuBtn = getId('msgerDropDownMenuBtn'); +const msgerDropDownContent = getId('msgerDropDownContent'); const msgerClean = getId('msgerClean'); const msgerSaveBtn = getId('msgerSaveBtn'); const msgerClose = getId('msgerClose'); @@ -349,6 +354,7 @@ const searchPeerBarName = getId('searchPeerBarName'); // Caption section const captionDraggable = getId('captionDraggable'); const captionHeader = getId('captionHeader'); +const captionTogglePin = getId('captionTogglePin'); const captionTheme = getId('captionTheme'); const captionMaxBtn = getId('captionMaxBtn'); const captionMinBtn = getId('captionMinBtn'); @@ -652,6 +658,8 @@ let leftChatAvatar; let rightChatAvatar; let chatMessagesId = 0; let showChatOnMessage = true; +let isChatPinned = false; +let isCaptionPinned = false; let isChatRoomVisible = false; let isCaptionBoxVisible = false; let isChatEmojiVisible = false; @@ -764,9 +772,8 @@ function setButtonsToolTip() { setTippy(msgerClose, 'Close', 'bottom'); setTippy(msgerShowChatOnMsgDiv, 'Show chat when you receive a new message', 'bottom'); setTippy(msgerSpeechMsgDiv, 'Speech the incoming messages', 'bottom'); + setTippy(msgerTogglePin, 'Toggle chat pin', 'bottom'); setTippy(msgerTheme, 'Ghost theme', 'bottom'); - setTippy(msgerClean, 'Clean the messages', 'bottom'); - setTippy(msgerSaveBtn, 'Save the messages', 'bottom'); setTippy(msgerMaxBtn, 'Maximize', 'bottom'); setTippy(msgerMinBtn, 'Minimize', 'bottom'); setTippy(msgerEmojiBtn, 'Emoji', 'top'); @@ -783,6 +790,7 @@ function setButtonsToolTip() { setTippy(captionClose, 'Close', 'bottom'); setTippy(captionMaxBtn, 'Maximize', 'bottom'); setTippy(captionMinBtn, 'Minimize', 'bottom'); + setTippy(captionTogglePin, 'Toggle caption pin', 'bottom'); setTippy(captionTheme, 'Ghost theme', 'bottom'); setTippy(captionClean, 'Clean the messages', 'bottom'); setTippy(captionSaveBtn, 'Save the messages', 'bottom'); @@ -1405,6 +1413,7 @@ function handleButtonsRule() { elemDisplay(mySettingsBtn, buttons.main.showMySettingsBtn); elemDisplay(aboutBtn, buttons.main.showAboutBtn); // chat + elemDisplay(msgerTogglePin, !isMobileDevice && buttons.chat.showTogglePinBtn); elemDisplay(msgerMaxBtn, !isMobileDevice && buttons.chat.showMaxBtn); elemDisplay(msgerSaveBtn, buttons.chat.showSaveMessageBtn); elemDisplay(msgerMarkdownBtn, buttons.chat.showMarkDownBtn); @@ -1413,6 +1422,7 @@ function handleButtonsRule() { elemDisplay(msgerVideoUrlBtn, buttons.chat.showShareVideoAudioBtn); elemDisplay(msgerCPBtn, buttons.chat.showParticipantsBtn); // caption + elemDisplay(captionTogglePin, !isMobileDevice && buttons.caption.showTogglePinBtn); elemDisplay(captionMaxBtn, !isMobileDevice && buttons.caption.showMaxBtn); // Settings elemDisplay(dropDownMicOptions, buttons.settings.showMicOptionsBtn && isPresenter); // auto-detected @@ -4260,13 +4270,39 @@ function removeVideoPinMediaContainer(peer_id, force_remove = false) { force_remove ) { elemDisplay(videoPinMediaContainer, false); + isVideoPinned = false; + pinnedVideoPlayerId = null; + videoMediaContainerUnpin(); + if (isChatPinned) { + chatPin(); + } + if (isCaptionPinned) { + captionPin(); + } + resizeVideoMedia(); + } +} + +/** + * Pin videoMediaContainer + */ +function videoMediaContainerPin() { + if (!isVideoPinned) { + videoMediaContainer.style.top = 0; + videoMediaContainer.style.width = '75%'; + videoMediaContainer.style.height = '100%'; + } +} + +/** + * Unpin videoMediaContainer + */ +function videoMediaContainerUnpin() { + if (!isVideoPinned) { videoMediaContainer.style.top = 0; videoMediaContainer.style.right = null; videoMediaContainer.style.width = '100%'; videoMediaContainer.style.height = '100%'; - pinnedVideoPlayerId = null; - isVideoPinned = false; - resizeVideoMedia(); } } @@ -4542,6 +4578,11 @@ function setChatRoomBtn() { } }); + // pin/unpin + msgerTogglePin.addEventListener('click', () => { + toggleChatPin(); + }); + // ghost theme + undo msgerTheme.addEventListener('click', (e) => { if (e.target.className == className.ghost) { @@ -4553,6 +4594,11 @@ function setChatRoomBtn() { } }); + // dropdown chat menu + msgerDropDownMenuBtn.addEventListener('click', () => { + toggleChatDropDownMenu(); + }); + // show msger participants section msgerCPBtn.addEventListener('click', (e) => { if (!thereArePeerConnections()) { @@ -4714,6 +4760,11 @@ function setCaptionRoomBtn() { captionMinimize(); }); + // toggle caption pin + captionTogglePin.addEventListener('click', () => { + toggleCaptionPin(); + }); + // ghost theme + undo captionTheme.addEventListener('click', (e) => { if (e.target.className == className.ghost) { @@ -7068,9 +7119,7 @@ function showChatRoomDraggable() { isButtonsVisible = false; } chatRoomBtn.className = className.chatOff; - msgerDraggable.style.top = '50%'; - msgerDraggable.style.left = isMobileDevice ? '50%' : '25%'; - msgerDraggable.style.display = 'flex'; + chatLeftCenter(); isChatRoomVisible = true; setTippy(chatRoomBtn, 'Close the chat', placement); } @@ -7086,13 +7135,20 @@ function showCaptionDraggable() { isButtonsVisible = false; } captionBtn.className = 'far fa-closed-captioning'; - captionDraggable.style.top = '50%'; - captionDraggable.style.left = isMobileDevice ? '50%' : '75%'; - captionDraggable.style.display = 'flex'; + captionRightCenter(); isCaptionBoxVisible = true; setTippy(captionBtn, 'Close the caption', placement); } +/** + * Toggle Chat dropdown menu + */ +function toggleChatDropDownMenu() { + msgerDropDownContent.style.display === 'block' + ? (msgerDropDownContent.style.display = 'none') + : (msgerDropDownContent.style.display = 'block'); +} + /** * Chat maximize */ @@ -7111,16 +7167,87 @@ function chatMinimize() { elemDisplay(msgerMinBtn, false); elemDisplay(msgerMaxBtn, true); chatCenter(); - setSP('--msger-width', '420px'); - setSP('--msger-height', '680px'); + if (!isChatPinned) { + setSP('--msger-width', '420px'); + setSP('--msger-height', '680px'); + } else { + setSP('--msger-width', '25%'); + setSP('--msger-height', '100%'); + } } /** * Set chat position */ function chatCenter() { + if (!isChatPinned) { + msgerDraggable.style.top = '50%'; + msgerDraggable.style.left = '50%'; + } +} + +/** + * Toggle Chat Pin + */ +function toggleChatPin() { + if (isCaptionPinned) { + return userLog('toast', 'Please unpin the Caption that appears to be currently pinned'); + } + isChatPinned ? chatUnpin() : chatPin(); + playSound('click'); +} + +/** + * Handle chat pin + */ +function chatPin() { + videoMediaContainerPin(); + chatPinned(); + isChatPinned = true; + setColor(msgerTogglePin, 'lime'); + resizeVideoMedia(); + msgerDraggable.style.resize = 'none'; + if (!isMobileDevice) undragElement(msgerDraggable, msgerHeader); +} + +/** + * Handle chat unpin + */ +function chatUnpin() { + videoMediaContainerUnpin(); + setSP('--msger-width', '420px'); + setSP('--msger-height', '680px'); + elemDisplay(msgerMinBtn, false); + buttons.chat.showMaxBtn && elemDisplay(msgerMaxBtn, true); + chatLeftCenter(); + isChatPinned = false; + setColor(msgerTogglePin, 'white'); + resizeVideoMedia(); + if (!isMobileDevice) dragElement(msgerDraggable, msgerHeader); +} + +/** + * Move Chat center left + */ +function chatLeftCenter() { + msgerDraggable.style.position = 'fixed'; + msgerDraggable.style.display = 'flex'; msgerDraggable.style.top = '50%'; - msgerDraggable.style.left = '50%'; + msgerDraggable.style.left = isMobileDevice ? '50%' : '25%'; + msgerDraggable.style.transform = 'translate(-50%, -50%)'; +} + +/** + * Chat is pinned + */ +function chatPinned() { + msgerDraggable.style.position = 'absolute'; + msgerDraggable.style.top = 0; + msgerDraggable.style.right = 0; + msgerDraggable.style.left = null; + msgerDraggable.style.transform = null; + setSP('--msger-width', '25%'); + setSP('--msger-height', '100%'); } /** @@ -7141,16 +7268,87 @@ function captionMinimize() { elemDisplay(captionMinBtn, false); elemDisplay(captionMaxBtn, true); captionCenter(); + if (!isCaptionPinned) { + setSP('--caption-width', '420px'); + setSP('--caption-height', '680px'); + } else { + setSP('--caption-width', '25%'); + setSP('--caption-height', '100%'); + } +} + +/** + * Set chat position + */ +function captionCenter() { + if (!isCaptionPinned) { + captionDraggable.style.top = '50%'; + captionDraggable.style.left = '50%'; + } +} + +/** + * Toggle Caption Pin + */ +function toggleCaptionPin() { + if (isChatPinned) { + return userLog('toast', 'Please unpin the Chat that appears to be currently pinned'); + } + isCaptionPinned ? captionUnpin() : captionPin(); + playSound('click'); +} + +/** + * Handle caption pin + */ +function captionPin() { + videoMediaContainerPin(); + captionPinned(); + isCaptionPinned = true; + setColor(captionTogglePin, 'lime'); + resizeVideoMedia(); + captionDraggable.style.resize = 'none'; + if (!isMobileDevice) undragElement(captionDraggable, captionHeader); +} + +/** + * Handle caption unpin + */ +function captionUnpin() { + videoMediaContainerUnpin(); setSP('--caption-width', '420px'); setSP('--caption-height', '680px'); + elemDisplay(captionMinBtn, false); + buttons.caption.showMaxBtn && elemDisplay(captionMaxBtn, true); + captionRightCenter(); + isCaptionPinned = false; + setColor(captionTogglePin, 'white'); + resizeVideoMedia(); + if (!isMobileDevice) dragElement(captionDraggable, captionHeader); } /** - * Set caption position + * Move Caption center right */ -function captionCenter() { +function captionRightCenter() { + captionDraggable.style.position = 'fixed'; + captionDraggable.style.display = 'flex'; captionDraggable.style.top = '50%'; - captionDraggable.style.left = '50%'; + captionDraggable.style.left = isMobileDevice ? '50%' : '75%'; + captionDraggable.style.transform = 'translate(-50%, -50%)'; +} + +/** + * Caption is pinned + */ +function captionPinned() { + captionDraggable.style.position = 'absolute'; + captionDraggable.style.top = 0; + captionDraggable.style.right = 0; + captionDraggable.style.left = null; + captionDraggable.style.transform = null; + setSP('--caption-width', '25%'); + setSP('--caption-height', '100%'); } /** @@ -7219,6 +7417,9 @@ function cleanCaptions() { * Hide chat room and emoji picker */ function hideChatRoomAndEmojiPicker() { + if (isChatPinned) { + chatUnpin(); + } elemDisplay(msgerDraggable, false); elemDisplay(msgerEmojiPicker, false); setColor(msgerEmojiBtn, '#FFFFFF'); @@ -7232,6 +7433,9 @@ function hideChatRoomAndEmojiPicker() { * Hide chat room and emoji picker */ function hideCaptionBox() { + if (isCaptionPinned) { + captionUnpin(); + } elemDisplay(captionDraggable, false); captionBtn.className = className.captionOn; isCaptionBoxVisible = false; @@ -10291,7 +10495,7 @@ function showAbout() { Swal.fire({ background: swBg, position: 'center', - title: 'WebRTC P2P v1.3.68', + title: 'WebRTC P2P v1.3.70', imageAlt: 'mirotalk-about', imageUrl: images.about, customClass: { image: 'img-about' }, @@ -10419,6 +10623,21 @@ function dragElement(elmnt, dragObj) { } } +/** + * Make Obj Undraggable + * @param {object} elmnt father element + * @param {object} dragObj children element to make father undraggable + */ +function undragElement(elmnt, dragObj) { + if (dragObj) { + dragObj.onmousedown = null; + } else { + elmnt.onmousedown = null; + } + elmnt.style.top = ''; + elmnt.style.left = ''; +} + /** * Date Format: https://convertio.co/it/ * @returns {string} date string format: DD-MM-YYYY-H_M_S diff --git a/public/views/client.html b/public/views/client.html index 20093e9f5..7b940e901 100755 --- a/public/views/client.html +++ b/public/views/client.html @@ -160,28 +160,53 @@

Loading

-
-
- - -
-
- - -
-
+
+ - - +
@@ -257,6 +282,7 @@

Loading

+