diff --git a/images/icons/block_black-24dp.svg b/images/icons/block_black-24dp.svg new file mode 100644 index 0000000000000000000000000000000000000000..c24b8807dccaaf2bc4ab5b4072c12d1849a195ac --- /dev/null +++ b/images/icons/block_black-24dp.svg @@ -0,0 +1,11 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Generator: Adobe Illustrator 24.3.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) --> +<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" + viewBox="0 0 24 24" style="enable-background:new 0 0 24 24;" xml:space="preserve"> +<path d="M12,2C6.5,2,2,6.5,2,12s4.5,10,10,10s10-4.5,10-10S17.5,2,12,2z M4.1,8.4c1.4-3,4.5-5.1,7.9-5.1c2.1,0,4.1,0.7,5.6,2.1l-2,2 + c-0.3-1.8-1.7-3.1-3.6-3.1C10,4.4,8.4,6,8.4,8c0,1.7,1.1,3,2.6,3.5c-2.7,0.5-4.9,2.9-5.5,6l-0.1,0.1C3.2,15,2.7,11.4,4.1,8.4z + M12.7,10.3c-0.2,0.1-0.5,0.1-0.7,0.1c-1.4,0-2.4-1-2.4-2.4s1-2.4,2.4-2.4c1.4,0,2.4,1,2.4,2.4c0,0.3,0,0.5-0.1,0.7L12.7,10.3z + M9.8,13.2l-2.3,2.3C8.1,14.5,8.9,13.7,9.8,13.2z M6.6,18.8c0-0.2,0-0.4,0-0.6l5.6-5.6c2.8,0.2,5,2.8,5.1,6.1 + C15.9,20,14,20.7,12,20.7C10,20.7,8.2,20,6.6,18.8z M18.5,17.7c-0.5-3.1-2.5-5.5-5.1-6.1l0.4-0.4c0.5-0.3,1-0.7,1.3-1.3l3.5-3.5 + c2.2,2.6,2.7,6.2,1.3,9.2C19.5,16.4,19.1,17.1,18.5,17.7z"/> +</svg> diff --git a/images/icons/check-24px.svg b/images/icons/check-24px.svg deleted file mode 100644 index 522695ef3d51de63766b2b03d9c5e236d6366d4c..0000000000000000000000000000000000000000 --- a/images/icons/check-24px.svg +++ /dev/null @@ -1 +0,0 @@ -<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 0 24 24" width="24"><path d="M0 0h24v24H0z" fill="none"/><path d="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z"/></svg> \ No newline at end of file diff --git a/images/icons/check_black-24dp.svg b/images/icons/check_black-24dp.svg new file mode 100644 index 0000000000000000000000000000000000000000..ca0996551791735791f47ad23000bee986a39dc4 --- /dev/null +++ b/images/icons/check_black-24dp.svg @@ -0,0 +1,47 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Generator: Adobe Illustrator 24.3.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) --> +<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" + viewBox="0 0 24 24" style="enable-background:new 0 0 24 24;" xml:space="preserve"> +<style type="text/css"> + .st0{clip-path:url(#SVGID_4_);} + .st1{clip-path:url(#SVGID_6_);} +</style> +<g> + <g> + <g id="SVGID_2_"> + <path d="M8.9,19.5l-6.5-5.3c-0.4-0.4-0.5-1-0.1-1.4c0.4-0.4,1-0.5,1.4-0.1l5,4.1c1.4-1.4,2.8-2.9,4.2-4.3c2.4-2.6,5-5.2,7.4-7.7 + c0.4-0.4,1.1-0.4,1.5,0c0.4,0.4,0.4,1.1,0,1.5c-2.4,2.4-4.9,5.1-7.4,7.6c-1.6,1.7-3.2,3.4-4.8,5L8.9,19.5z"/> + </g> + </g> + <g> + <defs> + <path id="SVGID_1_" d="M8.9,19.5l-6.5-5.3c-0.4-0.4-0.5-1-0.1-1.4c0.4-0.4,1-0.5,1.4-0.1l5,4.1c1.4-1.4,2.8-2.9,4.2-4.3 + c2.4-2.6,5-5.2,7.4-7.7c0.4-0.4,1.1-0.4,1.5,0c0.4,0.4,0.4,1.1,0,1.5c-2.4,2.4-4.9,5.1-7.4,7.6c-1.6,1.7-3.2,3.4-4.8,5L8.9,19.5z + "/> + </defs> + <use xlink:href="#SVGID_1_" style="overflow:visible;"/> + <clipPath id="SVGID_4_"> + <use xlink:href="#SVGID_1_" style="overflow:visible;"/> + </clipPath> + <g class="st0"> + <g> + <g id="SVGID_3_"> + <path d="M457.6,382.9h-1483.6V-644.1H457.6V382.9z M-1024,380.9H455.5v-1023H-1024V380.9z"/> + </g> + </g> + <g> + <defs> + <path id="SVGID_5_" d="M457.6,382.9h-1483.6V-644.1H457.6V382.9z M-1024,380.9H455.5v-1023H-1024V380.9z"/> + </defs> + <use xlink:href="#SVGID_5_" style="overflow:visible;"/> + <clipPath id="SVGID_6_"> + <use xlink:href="#SVGID_5_" style="overflow:visible;"/> + </clipPath> + <g class="st1"> + <path d="M31.4,29.4H-7.1v-32h38.5V29.4z M-5.1,27.3h34.4V-0.5H-5.1V27.3z"/> + </g> + </g> + </g> + </g> +</g> +</svg> diff --git a/images/icons/ic_block_24px.svg b/images/icons/ic_block_24px.svg deleted file mode 100644 index 991f6d450d75fcf3c31885a23395b12f099cfcdc..0000000000000000000000000000000000000000 --- a/images/icons/ic_block_24px.svg +++ /dev/null @@ -1,13 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<svg width="24px" height="24px" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> - <title>BLOCK</title> - <g id="Icones_Outline" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd"> - <g id="Group" stroke="#000000" transform="translate(2.000000, 2.000000)"> - <g id="Ico_PROFIL" transform="translate(4.000000, 3.000000)" stroke-width="1.75"> - <path d="M9,3 C9,4.65681539 7.65681539,6 6,6 C4.34318461,6 3,4.65681539 3,3 C3,1.3431846 4.34318461,0 6,0 C7.65681539,0 9,1.3431846 9,3 Z" id="Stroke-1"></path> - <path d="M0,14 C0,10.1340213 2.68631843,7 6.00003624,7 C9.31368157,7 12,10.1340213 12,14" id="Stroke-3"></path> - </g> - <path d="M10,0 C4.4771525,0 0,4.4771525 0,10 C0,15.5228475 4.4771525,20 10,20 C15.5228475,20 20,15.5228475 20,10 C20,4.4771525 15.5228475,0 10,0 Z M10,1.33333168 C12.0746076,1.33204969 14.079864,2.08017366 15.6466667,3.44 L3.39333333,15.5933333 C1.21771658,13.0183471 0.73262388,9.41543918 2.14972463,6.35673232 C3.56682538,3.29802546 6.62897124,1.33855529 10,1.33333168 L10,1.33333168 Z M10,18.6666667 C7.91614814,18.6660287 5.90307168,17.9105329 4.33333333,16.54 L16.5866667,4.38 C18.7770629,6.95136307 19.2739172,10.5610635 17.8596803,13.6285834 C16.4454435,16.6961032 13.3778286,18.6624553 10,18.6666667 Z" id="Shape" stroke-width="0.5" fill="#000000" fill-rule="nonzero"></path> - </g> - </g> -</svg> \ No newline at end of file diff --git a/qml.qrc b/qml.qrc index d6c7e7dd48421414e60948fea515d90672b0591f..c33ffabbe6b55472fbd2098a9e93c32673a65dff 100644 --- a/qml.qrc +++ b/qml.qrc @@ -156,5 +156,7 @@ <file>src/mainview/components/FilesToSendContainer.qml</file> <file>src/commoncomponents/Avatar.qml</file> <file>src/mainview/components/ConversationAvatar.qml</file> + <file>src/mainview/components/InvitationView.qml</file> + <file>src/commoncomponents/GeneralWebEngineView.qml</file> </qresource> </RCC> diff --git a/resources.qrc b/resources.qrc index d54f4bfe8c2595206c27a8fcda88df31c0b288c3..383d412ea9243e1340137c90f94452e246f9906c 100644 --- a/resources.qrc +++ b/resources.qrc @@ -22,6 +22,7 @@ <file>images/icons/backup-24px.svg</file> <file>images/icons/check_box_outline_blank-24px.svg</file> <file>images/icons/check_box-24px.svg</file> + <file>images/icons/check_black-24dp.svg</file> <file>images/icons/devices-24px.svg</file> <file>images/icons/ic_arrow_back_24px.svg</file> <file>images/icons/ic_arrow_back_white_24dp.svg</file> @@ -32,13 +33,12 @@ <file>images/icons/ic_arrow_forward_white_48dp_2x.png</file> <file>images/icons/ic_arrow_tab_next_black_9dp_2x.png</file> <file>images/icons/ic_arrow_tab_previous_black_9dp_2x.png</file> - <file>images/icons/ic_block_24px.svg</file> + <file>images/icons/block_black-24dp.svg</file> <file>images/icons/ic_hangup_participant-24px.svg</file> <file>images/icons/delete_forever-24px.svg</file> <file>images/icons/phone_forwarded-24px.svg</file> <file>images/icons/ic_chat_black_24dp_2x.png</file> <file>images/icons/ic_chat_white_24dp.png</file> - <file>images/icons/ic_check_white_18dp_2x.png</file> <file>images/icons/ic_clear_24px.svg</file> <file>images/icons/ic_content_copy.svg</file> <file>images/icons/ic_done_white_24dp.png</file> @@ -102,7 +102,6 @@ <file>images/icons/qr_code-24px.svg</file> <file>images/icons/content_copy-24px.svg</file> <file>images/icons/videocam_off-24px.svg</file> - <file>images/icons/check-24px.svg</file> <file>images/icons/mic_off-24px.svg</file> <file>images/icons/mic-24px.svg</file> <file>images/icons/group_add-24px.svg</file> diff --git a/src/commoncomponents/GeneralWebEngineView.qml b/src/commoncomponents/GeneralWebEngineView.qml new file mode 100644 index 0000000000000000000000000000000000000000..8390c371ae8672233a06c0d65b2c5031ab2d09fa --- /dev/null +++ b/src/commoncomponents/GeneralWebEngineView.qml @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2020 by Savoir-faire Linux + * Author: Mingrui Zhang <mingrui.zhang@savoirfairelinux.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +import QtQuick 2.14 +import QtQuick.Controls 2.14 +import QtWebEngine 1.10 +import QtWebChannel 1.14 + +import net.jami.Adapters 1.0 +import net.jami.Constants 1.0 + +WebEngineView { + id: root + + property string onCompletedLoadHtml: "" + property string onCompletedUrl: "qrc" + onCompletedLoadHtml + + backgroundColor: "transparent" + + settings.javascriptEnabled: true + settings.javascriptCanOpenWindows: false + settings.javascriptCanAccessClipboard: true + settings.javascriptCanPaste: true + settings.fullScreenSupportEnabled: true + settings.allowRunningInsecureContent: true + settings.localContentCanAccessRemoteUrls: true + settings.localContentCanAccessFileUrls: true + settings.errorPageEnabled: false + settings.pluginsEnabled: false + settings.screenCaptureEnabled: false + settings.linksIncludedInFocusChain: false + settings.localStorageEnabled: true + + // Provide WebChannel by registering jsBridgeObject. + webChannel: WebChannel { + id: webViewChannel + } + + onNavigationRequested: { + if (request.navigationType === WebEngineView.LinkClickedNavigation) { + MessagesAdapter.openUrl(request.url) + request.action = WebEngineView.IgnoreRequest + } + } + + onContextMenuRequested: { + var needContextMenu = request.selectedText.length || request.isContentEditable + if (!needContextMenu) + request.accepted = true + } + + Component.onCompleted: { + profile.cachePath = UtilsAdapter.getCachePath() + profile.persistentStoragePath = UtilsAdapter.getCachePath() + profile.persistentCookiesPolicy = WebEngineProfile.NoPersistentCookies + profile.httpCacheType = WebEngineProfile.NoCache + profile.httpUserAgent = JamiStrings.httpUserAgentName + + root.loadHtml(UtilsAdapter.qStringFromFile(onCompletedLoadHtml), + onCompletedLoadHtml) + root.url = onCompletedUrl + } +} diff --git a/src/commoncomponents/emojipicker/EmojiPicker.qml b/src/commoncomponents/emojipicker/EmojiPicker.qml index 6e71b25581e5b3457eafe1b21f8b5968fc39e86b..ca54c2b22a16971bb4554869c7c59f2d32420769 100644 --- a/src/commoncomponents/emojipicker/EmojiPicker.qml +++ b/src/commoncomponents/emojipicker/EmojiPicker.qml @@ -67,28 +67,20 @@ Rectangle { } } - WebEngineView { + GeneralWebEngineView { id: emojiPickerWebView anchors.fill: root - backgroundColor: JamiTheme.transparentColor + webChannel.registeredObjects: [jsBridgeObject] - settings.javascriptEnabled: true - settings.javascriptCanOpenWindows: false - settings.javascriptCanAccessClipboard: true - settings.javascriptCanPaste: true - settings.fullScreenSupportEnabled: true - settings.allowRunningInsecureContent: true - settings.localContentCanAccessRemoteUrls: false - settings.localContentCanAccessFileUrls: false - settings.errorPageEnabled: false - settings.pluginsEnabled: false - settings.screenCaptureEnabled: false - settings.linksIncludedInFocusChain: false - settings.localStorageEnabled: true + onCompletedLoadHtml: ":/src/commoncomponents/emojipicker/emojiPickerLoader.html" - webChannel: emojiPickerWebViewChannel + onActiveFocusChanged: { + if (visible) { + closeEmojiPicker() + } + } onLoadingChanged: { if (loadRequest.status == WebEngineView.LoadSucceededStatus) { @@ -104,31 +96,5 @@ Rectangle { "init_emoji_picker(" + JamiTheme.darkTheme + ");") } } - - onActiveFocusChanged: { - if (visible) { - closeEmojiPicker() - } - } - - Component.onCompleted: { - profile.cachePath = UtilsAdapter.getCachePath() - profile.persistentStoragePath = UtilsAdapter.getCachePath() - profile.persistentCookiesPolicy = WebEngineProfile.NoPersistentCookies - profile.httpCacheType = WebEngineProfile.NoCache - profile.httpUserAgent = JamiStrings.httpUserAgentName - - emojiPickerWebView.loadHtml( - UtilsAdapter.qStringFromFile( - ":/src/commoncomponents/emojipicker/emojiPickerLoader.html"), - ":/src/commoncomponents/emojipicker/emojiPickerLoader.html") - emojiPickerWebView.url = "qrc:/src/commoncomponents/emojipicker/emojiPickerLoader.html" - } - } - - // Provide WebChannel by registering jsBridgeObject. - WebChannel { - id: emojiPickerWebViewChannel - registeredObjects: [jsBridgeObject] } } diff --git a/src/constant/JamiStrings.qml b/src/constant/JamiStrings.qml index d9356ba1f96f5edd1254aef4e8e673e86578b9bb..b6223327916abd88b23e85f650d4963c9eddcf6f 100644 --- a/src/constant/JamiStrings.qml +++ b/src/constant/JamiStrings.qml @@ -495,4 +495,10 @@ Item { property string send: qsTr("Send") property string remove: qsTr("Remove") property string writeTo: qsTr("Write to %1") + + // Invitation View + property string invitationViewSentRequest: qsTr("%1 has sent you a request for a conversation.") + property string invitationViewJoinConversation: qsTr("Hello,\nWould you like to join the conversation?") + property string invitationViewAcceptedConversation: qsTr("You have accepted\nthe conversation request") + property string invitationViewWaitingForSync: qsTr("Waiting until %1\nconnects to synchronize the conversation.") } diff --git a/src/constant/JamiTheme.qml b/src/constant/JamiTheme.qml index 687946aa829954bd4ca91dbde3578bdb64b4a133..ae77e712b0b1388099a4019bec7fc6c71db19c99 100644 --- a/src/constant/JamiTheme.qml +++ b/src/constant/JamiTheme.qml @@ -135,6 +135,10 @@ Item { // ParticipantCallInStatusView property color participantCallInStatusTextColor: whiteColor + // InvitationView + property color blockOrange: rgba256(232, 92, 36, 100) + property color blockOrangeTransparency: rgba256(232, 92, 36, 56) + // Chatview property color jamiLightBlue: darkTheme ? "#003b4e" : Qt.rgba(59, 193, 211, 0.3) property color jamiDarkBlue: darkTheme ? "#28b1ed" : "#003b4e" @@ -276,9 +280,16 @@ Item { property real filesToSendDelegateButtonSize: 16 property real filesToSendDelegateFontPointSize: textFontSize + 2 + // InvitationView + property real invitationViewAvatarSize: 112 + property real invitationViewButtonRadius: 25 + property real invitationViewButtonSize: 48 + property real invitationViewButtonIconSize: 24 + property real invitationViewButtonsSpacing: 30 + // Main application spec property real mainViewMinWidth: 300 - property real mainViewMinHeight: 400 + property real mainViewMinHeight: 500 property real wizardViewMinWidth: 500 property real wizardViewMinHeight: 600 diff --git a/src/mainview/components/ConversationSmartListContextMenu.qml b/src/mainview/components/ConversationSmartListContextMenu.qml index f129e98f668168652a27ebd10e41be3fee7d8a4e..1c78e0ba412c053363a64677683a95e518e9cbea 100644 --- a/src/mainview/components/ConversationSmartListContextMenu.qml +++ b/src/mainview/components/ConversationSmartListContextMenu.qml @@ -135,7 +135,7 @@ ContextMenuAutoLoader { canTrigger: !hasCall && contactType !== Profile.Type.SIP itemName: JamiStrings.blockContact - iconSource: "qrc:/images/icons/ic_block_24px.svg" + iconSource: "qrc:/images/icons/block_black-24dp.svg" addMenuSeparatorAfter: contactType !== Profile.Type.SIP onClicked: { MessagesAdapter.blockConversation(responsibleConvUid) diff --git a/src/mainview/components/InvitationView.qml b/src/mainview/components/InvitationView.qml new file mode 100644 index 0000000000000000000000000000000000000000..e928cc6290b83adcf39fa8979e0178943e150928 --- /dev/null +++ b/src/mainview/components/InvitationView.qml @@ -0,0 +1,201 @@ +/* + * Copyright (C) 2020 by Savoir-faire Linux + * Author: Mingrui Zhang <mingrui.zhang@savoirfairelinux.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +import QtQuick 2.14 +import QtQuick.Controls 2.14 +import QtQuick.Layouts 1.14 +import QtGraphicalEffects 1.14 + +import net.jami.Adapters 1.0 +import net.jami.Constants 1.0 +import net.jami.Models 1.0 + +import "../../commoncomponents" + +Rectangle { + id: root + + property string invitationViewImageId + property string invitationViewContactTitle + property bool invitationViewNeedSyncing: false + + property real marginSize: 20 + property real textMarginSize: 50 + + color: JamiTheme.primaryBackgroundColor + + Text { + id: invitationViewSentRequestText + + anchors.top: root.top + anchors.topMargin: visible ? marginSize : 0 + anchors.horizontalCenter: root.horizontalCenter + + width: infoColumnLayout.width - textMarginSize + height: visible ? contentHeight : 0 + + visible: !invitationViewNeedSyncing + + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + + font.pointSize: JamiTheme.textFontSize + color: JamiTheme.textColor + wrapMode: Text.Wrap + + text: JamiStrings.invitationViewSentRequest.arg(invitationViewContactTitle) + } + + ColumnLayout { + id: infoColumnLayout + + anchors.centerIn: root + + width: root.width + + Avatar { + id: avatarImage + + Layout.alignment: Qt.AlignHCenter + Layout.topMargin: invitationViewSentRequestText.visible ? marginSize : 0 + Layout.preferredHeight: JamiTheme.invitationViewAvatarSize + Layout.preferredWidth: JamiTheme.invitationViewAvatarSize + + showPresenceIndicator: false + mode: Avatar.Mode.Contact + imageId: invitationViewImageId + } + + Text { + id: invitationViewMiddlePhraseText + + Layout.alignment: Qt.AlignHCenter + Layout.topMargin: marginSize + Layout.preferredWidth: infoColumnLayout.width - textMarginSize + + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + + font.weight: Font.DemiBold + font.pointSize: JamiTheme.textFontSize + 3 + color: JamiTheme.textColor + wrapMode: Text.Wrap + + text: root.invitationViewNeedSyncing ? + JamiStrings.invitationViewAcceptedConversation : + JamiStrings.invitationViewJoinConversation + } + + Text { + id: invitationViewWaitingForSyncText + + Layout.alignment: Qt.AlignHCenter + Layout.topMargin: marginSize + Layout.preferredWidth: infoColumnLayout.width - textMarginSize + Layout.preferredHeight: visible ? contentHeight : 0 + + visible: invitationViewNeedSyncing + + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + + font.pointSize: JamiTheme.textFontSize + color: JamiTheme.textColor + wrapMode: Text.Wrap + + text: JamiStrings.invitationViewWaitingForSync.arg(invitationViewContactTitle) + } + + RowLayout { + id: buttonGroupRowLayout + + Layout.alignment: Qt.AlignHCenter + Layout.topMargin: marginSize + + spacing: JamiTheme.invitationViewButtonsSpacing + + visible: !invitationViewNeedSyncing + + PushButton { + id: blockButton + + Layout.alignment: Qt.AlignHCenter + Layout.preferredHeight: JamiTheme.invitationViewButtonSize + Layout.preferredWidth: JamiTheme.invitationViewButtonSize + + preferredSize: JamiTheme.invitationViewButtonIconSize + radius: JamiTheme.invitationViewButtonRadius + + toolTipText: JamiStrings.blockContact + + source: "qrc:/images/icons/block_black-24dp.svg" + imageColor: JamiTheme.primaryBackgroundColor + + normalColor: JamiTheme.blockOrangeTransparency + pressedColor: JamiTheme.blockOrange + hoveredColor: JamiTheme.blockOrange + + onClicked: MessagesAdapter.blockConversation() + } + + PushButton { + id: refuseButton + + Layout.alignment: Qt.AlignHCenter + Layout.preferredHeight: JamiTheme.invitationViewButtonSize + Layout.preferredWidth: JamiTheme.invitationViewButtonSize + + preferredSize: JamiTheme.invitationViewButtonSize + radius: JamiTheme.invitationViewButtonRadius + + toolTipText: JamiStrings.declineContactRequest + + source: "qrc:/images/icons/cross_black_24dp.svg" + imageColor: JamiTheme.primaryBackgroundColor + + normalColor: JamiTheme.refuseRedTransparent + pressedColor: JamiTheme.refuseRed + hoveredColor: JamiTheme.refuseRed + + onClicked: MessagesAdapter.refuseInvitation() + } + + PushButton { + id: acceptButton + + Layout.alignment: Qt.AlignHCenter + Layout.preferredHeight: JamiTheme.invitationViewButtonSize + Layout.preferredWidth: JamiTheme.invitationViewButtonSize + + preferredSize: JamiTheme.invitationViewButtonIconSize + radius: JamiTheme.invitationViewButtonRadius + + toolTipText: JamiStrings.acceptContactRequest + + source: "qrc:/images/icons/check_black-24dp.svg" + imageColor: JamiTheme.primaryBackgroundColor + + normalColor: JamiTheme.acceptGreenTransparency + pressedColor: JamiTheme.acceptGreen + hoveredColor: JamiTheme.acceptGreen + + onClicked: MessagesAdapter.acceptInvitation() + } + } + } +} diff --git a/src/mainview/components/MessageWebView.qml b/src/mainview/components/MessageWebView.qml index 3de94078f7c82d073f701712e6b96f93ce6e9349..4068f16bb8e3892b2832903c592f95ddc0f56596 100644 --- a/src/mainview/components/MessageWebView.qml +++ b/src/mainview/components/MessageWebView.qml @@ -32,9 +32,15 @@ import "../js/pluginhandlerpickercreation.js" as PluginHandlerPickerCreation Rectangle { id: root + enum Mode { + Chat = 0, + Invitation + } + property string headerUserAliasLabelText: "" property string headerUserUserNameLabelText: "" property bool jsLoaded: false + property var mode: MessageWebView.Mode.Chat signal needToHideConversationInCall signal messagesCleared @@ -105,6 +111,24 @@ Rectangle { } } + Connections { + target: MessagesAdapter + + function onChangeInvitationViewRequest(show, isSwarm, needsSyncing, + contactTitle, contactUri) { + if (show) + root.mode = MessageWebView.Mode.Invitation + else { + root.mode = MessageWebView.Mode.Chat + return + } + + invitationView.invitationViewImageId = contactUri + invitationView.invitationViewContactTitle = contactTitle + invitationView.invitationViewNeedSyncing = needsSyncing + } + } + QtObject { id: jsBridgeObject @@ -137,18 +161,6 @@ Rectangle { MessagesAdapter.refuseFile(arg) } - function acceptInvitation() { - MessagesAdapter.acceptInvitation() - } - - function refuseInvitation() { - MessagesAdapter.refuseInvitation() - } - - function blockConversation() { - MessagesAdapter.blockConversation() - } - function emitMessagesCleared() { root.messagesCleared() } @@ -170,12 +182,6 @@ Rectangle { } } - // Provide WebChannel by registering jsBridgeObject. - WebChannel { - id: messageWebViewChannel - registeredObjects: [jsBridgeObject] - } - ColumnLayout { anchors.fill: root @@ -215,8 +221,8 @@ Rectangle { } } - WebEngineView { - id: messageWebView + StackLayout { + id: messageWebViewStack Layout.alignment: Qt.AlignHCenter Layout.fillWidth: true @@ -224,89 +230,66 @@ Rectangle { Layout.topMargin: JamiTheme.messageWebViewHairLineSize Layout.bottomMargin: JamiTheme.messageWebViewHairLineSize - backgroundColor: "transparent" + currentIndex: root.mode - settings.javascriptEnabled: true - settings.javascriptCanOpenWindows: true - settings.javascriptCanAccessClipboard: true - settings.javascriptCanPaste: true - settings.fullScreenSupportEnabled: true - settings.allowRunningInsecureContent: true - settings.localContentCanAccessRemoteUrls: true - settings.localContentCanAccessFileUrls: true - settings.errorPageEnabled: false - settings.pluginsEnabled: false - settings.screenCaptureEnabled: false - settings.linksIncludedInFocusChain: false - settings.localStorageEnabled: true + GeneralWebEngineView { + id: messageWebView - webChannel: messageWebViewChannel + Layout.fillWidth: true + Layout.fillHeight: true - DropArea { - anchors.fill: parent - onDropped: messageWebViewFooter.setFilePathsToSend(drop.urls) - } + onCompletedLoadHtml: ":/chatview.html" - onNavigationRequested: { - if (request.navigationType === WebEngineView.LinkClickedNavigation) { - MessagesAdapter.openUrl(request.url) - request.action = WebEngineView.IgnoreRequest - } - } + webChannel.registeredObjects: [jsBridgeObject] - onLoadingChanged: { - if (loadRequest.status == WebEngineView.LoadSucceededStatus) { - messageWebView.runJavaScript(UtilsAdapter.getStyleSheet( - "chatcss", - UtilsAdapter.qStringFromFile( - ":/chatview.css"))) - messageWebView.runJavaScript(UtilsAdapter.getStyleSheet( - "chatwin", - UtilsAdapter.qStringFromFile( - ":/chatview-qt.css"))) - messageWebView.runJavaScript(UtilsAdapter.qStringFromFile( - ":/linkify.js")) - messageWebView.runJavaScript(UtilsAdapter.qStringFromFile( - ":/linkify-html.js")) - messageWebView.runJavaScript(UtilsAdapter.qStringFromFile( - ":/linkify-string.js")) - messageWebView.runJavaScript(UtilsAdapter.qStringFromFile( - ":/qwebchannel.js")) - messageWebView.runJavaScript(UtilsAdapter.qStringFromFile( - ":/jed.js")) - messageWebView.runJavaScript(UtilsAdapter.qStringFromFile( - ":/emoji.js")) - messageWebView.runJavaScript(UtilsAdapter.qStringFromFile( - ":/previewInfo.js")) - messageWebView.runJavaScript( - UtilsAdapter.qStringFromFile(":/chatview.js"), - function() { - messageWebView.runJavaScript("init_i18n();") - MessagesAdapter.setDisplayLinks() - updateChatviewTheme() - messageWebView.runJavaScript("displayNavbar(false);") - messageWebView.runJavaScript("hideMessageBar(true);") - jsLoaded = true - }) + DropArea { + anchors.fill: parent + onDropped: messageWebViewFooter.setFilePathsToSend(drop.urls) } - } - onContextMenuRequested: { - var needContextMenu = request.selectedText.length || request.isContentEditable - if (!needContextMenu) - request.accepted = true + onLoadingChanged: { + if (loadRequest.status == WebEngineView.LoadSucceededStatus) { + messageWebView.runJavaScript(UtilsAdapter.getStyleSheet( + "chatcss", + UtilsAdapter.qStringFromFile( + ":/chatview.css"))) + messageWebView.runJavaScript(UtilsAdapter.getStyleSheet( + "chatwin", + UtilsAdapter.qStringFromFile( + ":/chatview-qt.css"))) + messageWebView.runJavaScript(UtilsAdapter.qStringFromFile( + ":/linkify.js")) + messageWebView.runJavaScript(UtilsAdapter.qStringFromFile( + ":/linkify-html.js")) + messageWebView.runJavaScript(UtilsAdapter.qStringFromFile( + ":/linkify-string.js")) + messageWebView.runJavaScript(UtilsAdapter.qStringFromFile( + ":/qwebchannel.js")) + messageWebView.runJavaScript(UtilsAdapter.qStringFromFile( + ":/jed.js")) + messageWebView.runJavaScript(UtilsAdapter.qStringFromFile( + ":/emoji.js")) + messageWebView.runJavaScript(UtilsAdapter.qStringFromFile( + ":/previewInfo.js")) + messageWebView.runJavaScript( + UtilsAdapter.qStringFromFile(":/chatview.js"), + function() { + messageWebView.runJavaScript("init_i18n();") + MessagesAdapter.setDisplayLinks() + updateChatviewTheme() + messageWebView.runJavaScript("displayNavbar(false);") + messageWebView.runJavaScript("hideMessageBar(true);") + jsLoaded = true + }) + } + } } - Component.onCompleted: { - profile.cachePath = UtilsAdapter.getCachePath() - profile.persistentStoragePath = UtilsAdapter.getCachePath() - profile.persistentCookiesPolicy = WebEngineProfile.NoPersistentCookies - profile.httpCacheType = WebEngineProfile.NoCache - profile.httpUserAgent = JamiStrings.httpUserAgentName + InvitationView { + id: invitationView - messageWebView.loadHtml(UtilsAdapter.qStringFromFile( - ":/chatview.html"), ":/chatview.html") - messageWebView.url = "qrc:/chatview.html" + Layout.fillWidth: true + Layout.fillHeight: true } } diff --git a/src/mainview/components/MessageWebViewFooter.qml b/src/mainview/components/MessageWebViewFooter.qml index 66ca473b7bd53a87a5e60f950b70162dbbc82354..f945de94a22e44c6d9bbb3a3f42e637f3884a147 100644 --- a/src/mainview/components/MessageWebViewFooter.qml +++ b/src/mainview/components/MessageWebViewFooter.qml @@ -78,10 +78,11 @@ Rectangle { messageBar.textAreaObj.pasteText() } - function onChangeMessageWebViewFooterVisibilityRequest(visible) { - messageBar.visible = visible - dataTransferSendContainer.visible = visible - root.visible = visible + function onChangeInvitationViewRequest(show, isSwarm) { + var footerVisibility = show ? !isSwarm : !show + messageBar.visible = footerVisibility + dataTransferSendContainer.visible = footerVisibility + root.visible = footerVisibility } } diff --git a/src/messagesadapter.cpp b/src/messagesadapter.cpp index 1e12851d9de4649a16218fcdfe0f50ae96d0e280..622cf4872118fc9ce663d5a3035dc54b1d002c3f 100644 --- a/src/messagesadapter.cpp +++ b/src/messagesadapter.cpp @@ -85,11 +85,11 @@ MessagesAdapter::setupChatView(const QString& convUid) setMessagesVisibility(false); setIsSwarm(convInfo.isSwarm()); - setInvitation(convInfo.isRequest or convInfo.needsSyncing, - convModel->title(convInfo.uid), - contactURI, - !convInfo.isSwarm(), - convInfo.needsSyncing); + changeInvitationViewRequest(convInfo.isRequest or convInfo.needsSyncing, + !convInfo.isSwarm(), + convInfo.needsSyncing, + convModel->title(convInfo.uid), + contactURI); Utils::oneShotConnect(qmlObj_, SIGNAL(messagesCleared()), this, SLOT(slotMessagesCleared())); clearChatView(); @@ -384,11 +384,11 @@ MessagesAdapter::setConversationProfileData(const lrc::api::conversation::Info& !(convInfo.isSwarm() && (convInfo.isRequest || convInfo.needsSyncing)))); - setInvitation(convInfo.isRequest or convInfo.needsSyncing, - title, - contactUri, - convInfo.isSwarm(), - convInfo.needsSyncing); + changeInvitationViewRequest(convInfo.isRequest or convInfo.needsSyncing, + convInfo.isSwarm(), + convInfo.needsSyncing, + title, + contactUri); if (convInfo.isSwarm()) return; auto& contact = accInfo->contactModel->getContact(contactUri); @@ -439,21 +439,6 @@ MessagesAdapter::setMessagesVisibility(bool visible) QMetaObject::invokeMethod(qmlObj_, "webViewRunJavaScript", Q_ARG(QVariant, s)); } -void -MessagesAdapter::setInvitation( - bool show, const QString& contactUri, const QString& contactId, bool isSwarm, bool needsSyncing) -{ - Q_EMIT changeMessageWebViewFooterVisibilityRequest(show ? !isSwarm : !show); - - QString s = show ? QString::fromLatin1("showInvitation(\"%1\", \"%2\", %3, %4)") - .arg(contactUri) - .arg(contactId) - .arg(isSwarm) - .arg(needsSyncing) - : QString::fromLatin1("showInvitation()"); - QMetaObject::invokeMethod(qmlObj_, "webViewRunJavaScript", Q_ARG(QVariant, s)); -} - void MessagesAdapter::setIsSwarm(bool isSwarm) { @@ -618,7 +603,7 @@ MessagesAdapter::refuseInvitation(const QString& convUid) { const auto currentConvUid = convUid.isEmpty() ? lrcInstance_->get_selectedConvUid() : convUid; lrcInstance_->getCurrentConversationModel()->removeConversation(currentConvUid, false); - setInvitation(false); + changeInvitationViewRequest(false); } void @@ -626,7 +611,7 @@ MessagesAdapter::blockConversation(const QString& convUid) { const auto currentConvUid = convUid.isEmpty() ? lrcInstance_->get_selectedConvUid() : convUid; lrcInstance_->getCurrentConversationModel()->removeConversation(currentConvUid, true); - setInvitation(false); + changeInvitationViewRequest(false); } void diff --git a/src/messagesadapter.h b/src/messagesadapter.h index bdf45443e811271edb7955adece7e07742d6502c..c97d284c0a9890cf7ed35c108c08ff82f192beca 100644 --- a/src/messagesadapter.h +++ b/src/messagesadapter.h @@ -48,11 +48,11 @@ protected: const QString& convUid, bool banContact = false); Q_INVOKABLE void clearConversationHistory(const QString& accountId, const QString& convUid); - - // JS Q_INVOKABLE. Q_INVOKABLE void acceptInvitation(const QString& convId = {}); Q_INVOKABLE void refuseInvitation(const QString& convUid = ""); Q_INVOKABLE void blockConversation(const QString& convUid = ""); + + // JS Q_INVOKABLE. Q_INVOKABLE void setDisplayLinks(); Q_INVOKABLE void sendMessage(const QString& message); Q_INVOKABLE void sendFile(const QString& message); @@ -69,11 +69,6 @@ protected: // Run corrsponding js functions, c++ to qml. void setMessagesVisibility(bool visible); - void setInvitation(bool show, - const QString& contactUri = {}, - const QString& contactId = {}, - bool isSwarm = false, - bool needsSyncing = false); void setIsSwarm(bool isSwarm); void clearChatView(); void printHistory(ConversationModel& conversationModel, MessagesList interactions); @@ -98,7 +93,11 @@ Q_SIGNALS: void newMessageBarPlaceholderText(QString placeholderText); void newFilePasted(QString filePath); void newTextPasted(); - void changeMessageWebViewFooterVisibilityRequest(bool visible); + void changeInvitationViewRequest(bool show, + bool isSwarm = false, + bool needsSyncing = false, + QString contactTitle = {}, + QString contactUri = {}); private Q_SLOTS: void slotMessagesCleared();