diff --git a/.gitignore b/.gitignore index 8cfcb49b84b4ee0548da301001095035bab41d74..7a0b17171673cd37d632f38d4c4d9102d573fc7d 100644 --- a/.gitignore +++ b/.gitignore @@ -23,7 +23,7 @@ build-local/ *.vcxproj *.vcxproj.filters *qmlcache.qrc - +qml_without_webengine.qrc .deploy.stamp # auto-gen files diff --git a/CMakeLists.txt b/CMakeLists.txt index 8f12eeb4ab2c88c8655c14d279cfa07446792cbf..ed4ecddc27f14d31fa1d99e3d9fd78e19af67511 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -42,12 +42,22 @@ set(QT_MODULES Concurrent Core Core5Compat - WebEngineCore - WebEngineQuick - WebChannel - WebEngineWidgets Multimedia ) + +if(NOT DEFINED WITH_WEBENGINE) + set(WITH_WEBENGINE true) +endif() + +if(WITH_WEBENGINE) + list(APPEND QT_MODULES + WebEngineCore + WebEngineQuick + WebChannel + WebEngineWidgets + ) +endif() + find_package(Qt6 COMPONENTS ${QT_MODULES} REQUIRED) foreach(MODULE ${QT_MODULES}) list(APPEND QT_LIBS "Qt::${MODULE}") @@ -57,8 +67,23 @@ set(SRC_DIR ${PROJECT_SOURCE_DIR}/src) set(CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS} ${Qt5Widgets_EXECUTABLE_COMPILE_FLAGS}) set(CMAKE_INSTALL_RPATH_USE_LINK_PATH true) +if(${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.12.0") + include(FindPython3) + find_package (Python3 COMPONENTS Interpreter) + set(PYTHON_EXEC ${Python3_EXECUTABLE}) +else() + include(FindPythonInterp) + set(PYTHON_EXEC ${PYTHON_EXECUTABLE}) +endif() + set(QML_RESOURCES ${PROJECT_SOURCE_DIR}/resources.qrc) -set(QML_RESOURCES_QML ${PROJECT_SOURCE_DIR}/qml.qrc) +if(WITH_WEBENGINE) + set(QML_RESOURCES_QML ${PROJECT_SOURCE_DIR}/qml.qrc) +else() + execute_process(COMMAND ${PYTHON_EXEC} ${CMAKE_CURRENT_SOURCE_DIR}/scripts/gen-qrc-without-webengine.py + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) + set(QML_RESOURCES_QML ${PROJECT_SOURCE_DIR}/qml_without_webengine.qrc) +endif() if (APPLE) include(FetchContent) @@ -78,14 +103,6 @@ file(GLOB_RECURSE RES_FILES CONFIGURE_DEPENDS ${PROJECT_SOURCE_DIR}/resources/* ) -if(${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.12.0") - include(FindPython3) - find_package (Python3 COMPONENTS Interpreter) - set(PYTHON_EXEC ${Python3_EXECUTABLE}) -else() - include(FindPythonInterp) - set(PYTHON_EXEC ${PYTHON_EXECUTABLE}) -endif() execute_process( COMMAND ${PYTHON_EXEC} ${PROJECT_SOURCE_DIR}/gen-resources.py WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} @@ -137,7 +154,6 @@ set(COMMON_SOURCES ${SRC_DIR}/currentconversation.cpp ${SRC_DIR}/currentaccount.cpp ${SRC_DIR}/videodevices.cpp - ${SRC_DIR}/previewengine.cpp ${SRC_DIR}/videoprovider.cpp ${SRC_DIR}/callparticipantsmodel.cpp ) @@ -194,11 +210,19 @@ set(COMMON_HEADERS ${SRC_DIR}/currentconversation.h ${SRC_DIR}/currentaccount.h ${SRC_DIR}/videodevices.h - ${SRC_DIR}/previewengine.h ${SRC_DIR}/videoprovider.h ${SRC_DIR}/callparticipantsmodel.h ) +if(WITH_WEBENGINE) + list(APPEND COMMON_SOURCES + ${SRC_DIR}/previewengine.cpp) + add_definitions(-DWITH_WEBENGINE) +else() + list(APPEND COMMON_SOURCES + ${SRC_DIR}/nowebengine/previewengine.cpp) +endif() + # For libavutil/avframe. set(LIBJAMI_CONTRIB_DIR "${PROJECT_SOURCE_DIR}/../daemon/contrib") find_path(AVUTIL_INCLUDE_DIR libavutil/avutil.h diff --git a/qml.qrc b/qml.qrc index 81ef94d691d88421dda336c99b0ae50e7fe3ce59..1e587633c1dcba6e73ce62790d546e10d6b22577 100644 --- a/qml.qrc +++ b/qml.qrc @@ -30,6 +30,7 @@ <file>src/commoncomponents/PresenceIndicator.qml</file> <file>src/commoncomponents/DaemonReconnectPopup.qml</file> <file>src/commoncomponents/SpinningAnimation.qml</file> + <file>src/commoncomponents/MediaPreviewBase.qml</file> <file>src/settingsview/SettingsView.qml</file> <file>src/settingsview/components/ChatviewSettings.qml</file> <file>src/settingsview/components/FileTransferSettings.qml</file> diff --git a/scripts/gen-qrc-without-webengine.py b/scripts/gen-qrc-without-webengine.py new file mode 100755 index 0000000000000000000000000000000000000000..7cce660a83b5073117f5da507d9973b00a9f29c7 --- /dev/null +++ b/scripts/gen-qrc-without-webengine.py @@ -0,0 +1,31 @@ +#!/usr/bin/env python3 + +# Copyright (C) 2022 Savoir-faire Linux Inc. +# +# Author: Kateryna Kostiuk <kateryna.kostiuk@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, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +with open('qml_without_webengine.qrc', 'w') as outfile: + with open('qml.qrc', 'r') as infile: + line = infile.readline() + while line: + if 'EmojiPicker.qml' in line: + outfile.write('\t<file>src/nowebengine/EmojiPicker.qml</file>\n') + elif 'MediaPreviewBase.qml' in line: + outfile.write('\t<file>src/nowebengine/MediaPreviewBase.qml</file>\n') + else: + outfile.write(line) + line = infile.readline() diff --git a/src/commoncomponents/DataTransferMessageDelegate.qml b/src/commoncomponents/DataTransferMessageDelegate.qml index ca5913efc4672aae0e238604602479009b36ac82..c451e730d1ba5fdb01a00d455b6a45deb27f4aac 100644 --- a/src/commoncomponents/DataTransferMessageDelegate.qml +++ b/src/commoncomponents/DataTransferMessageDelegate.qml @@ -22,7 +22,6 @@ import QtQuick import QtQuick.Controls import QtQuick.Layouts import Qt5Compat.GraphicalEffects -import QtWebEngine import net.jami.Models 1.1 import net.jami.Constants 1.1 @@ -41,7 +40,7 @@ Loader { sourceComponent: { if (Status === Interaction.Status.TRANSFER_FINISHED) { mediaInfo = MessagesAdapter.getMediaInfo(Body) - if (Object.keys(mediaInfo).length !== 0) + if (Object.keys(mediaInfo).length !== 0 && WITH_WEBENGINE) return localMediaMsgComp } return dataTransferMsgComp @@ -264,48 +263,10 @@ Loader { } Component { id: avComp - WebEngineView { - id: wev - anchors.right: isOutgoing ? parent.right : undefined - readonly property real minSize: 192 - readonly property real maxSize: 256 - readonly property real aspectRatio: 1 / .75 - readonly property real adjustedWidth: Math.min(maxSize, - Math.max(minSize, - innerContent.width - senderMargin)) - width: isFullScreen ? parent.width : adjustedWidth - height: mediaInfo.isVideo ? - isFullScreen ? - parent.height : - Math.ceil(adjustedWidth / aspectRatio) : - 54 - onContextMenuRequested: function(request) { - request.accepted = true - } - settings.fullScreenSupportEnabled: mediaInfo.isVideo - settings.javascriptCanOpenWindows: false - Component.onCompleted: loadHtml(mediaInfo.html, 'file://') - layer.enabled: !isFullScreen - layer.effect: OpacityMask { - maskSource: MessageBubble { - out: isOutgoing - type: seq - width: wev.width - height: wev.height - radius: msgRadius - } - } - onFullScreenRequested: function(request) { - if (request.toggleOn) { - layoutManager.pushFullScreenItem( - this, - localMediaCompLoader, - null, - function() { wev.fullScreenCancelled() }) - } else if (!request.toggleOn) { - layoutManager.removeFullScreenItem(this) - } - request.accept() + Loader { + Component.onCompleted: { + var qml = WITH_WEBENGINE ? "qrc:/src/commoncomponents/MediaPreviewBase.qml" : "qrc:/src/nowebengine/MediaPreviewBase.qml" + setSource( qml, { isVideo: mediaInfo.isVideo, html:mediaInfo.html } ) } } } diff --git a/src/commoncomponents/MediaPreviewBase.qml b/src/commoncomponents/MediaPreviewBase.qml new file mode 100644 index 0000000000000000000000000000000000000000..1192638c66026ccc5d5b676f530815904163903a --- /dev/null +++ b/src/commoncomponents/MediaPreviewBase.qml @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2021-2022 Savoir-faire Linux Inc. + * Author: Andreas Traczyk <andreas.traczyk@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 +import QtQuick.Controls +import QtQuick.Layouts +import Qt5Compat.GraphicalEffects +import QtWebEngine + +import net.jami.Models 1.1 +import net.jami.Constants 1.1 +import net.jami.Adapters 1.1 + +WebEngineView { + id: wev + property bool isVideo + property string html + readonly property real minSize: 192 + readonly property real maxSize: 256 + readonly property real aspectRatio: 1 / .75 + readonly property real adjustedWidth: Math.min(maxSize, + Math.max(minSize, + innerContent.width - senderMargin)) + anchors.right: isOutgoing ? parent.right : undefined + width: isFullScreen ? parent.width : adjustedWidth + height: isVideo ? + isFullScreen ? + parent.height : + Math.ceil(adjustedWidth / aspectRatio) : + 54 + onContextMenuRequested: function(request) { + request.accepted = true + } + settings.fullScreenSupportEnabled: isVideo + settings.javascriptCanOpenWindows: false + Component.onCompleted: loadHtml(html, 'file://') + layer.enabled: !isFullScreen + layer.effect: OpacityMask { + maskSource: MessageBubble { + out: isOutgoing + type: seq + width: wev.width + height: wev.height + radius: msgRadius + } + } + onFullScreenRequested: function(request) { + if (request.toggleOn) { + layoutManager.pushFullScreenItem( + this, + localMediaCompLoader, + null, + function() { wev.fullScreenCancelled() }) + } else if (!request.toggleOn) { + layoutManager.removeFullScreenItem(this) + } + request.accept() + } +} diff --git a/src/main.cpp b/src/main.cpp index 1d6aae0d5efdfced15d2351ef10ef9fc1e8f6c91..f886cdb98f04d8d3fe82a4d7e36da66834e995fc 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -24,8 +24,11 @@ #include <QCryptographicHash> #include <QApplication> +#include <QtQuick> +#ifdef WITH_WEBENGINE #include <QtWebEngineCore> #include <QtWebEngineQuick> +#endif #if defined(HAS_VULKAN) && !defined(Q_OS_LINUX) #include <QVulkanInstance> #endif @@ -56,9 +59,11 @@ parseInputArgument(int& argc, char* argv[], QList<char*> argsToParse) return newArgv; } +#ifdef WITH_WEBENGINE // Qt WebEngine Chromium Flags static char disableWebSecurity[] {"--disable-web-security"}; static char singleProcess[] {"--single-process"}; +#endif int main(int argc, char* argv[]) @@ -88,8 +93,10 @@ main(int argc, char* argv[]) */ unsetenv("QT_STYLE_OVERRIDE"); #endif +#ifdef WITH_WEBENGINE qtWebEngineChromiumFlags << disableWebSecurity; qtWebEngineChromiumFlags << singleProcess; +#endif QApplication::setApplicationName("Jami"); QApplication::setOrganizationDomain("jami.net"); diff --git a/src/mainapplication.cpp b/src/mainapplication.cpp index 104671ceac7fe14cdc7fea06c0d1c7572539350b..7528966cc6772e8f479e83c6413817fa6e8e11ed 100644 --- a/src/mainapplication.cpp +++ b/src/mainapplication.cpp @@ -193,6 +193,11 @@ MainApplication::init() auto startMinimizedSetting = settingsManager_->getValue(Settings::Key::StartMinimized).toBool(); // The presence of start URI should override the startMinimized setting for this instance. set_startMinimized(startMinimizedSetting && runOptions_[Option::StartUri].isNull()); +#ifdef WITH_WEBENGINE + engine_.get()->rootContext()->setContextProperty("WITH_WEBENGINE", QVariant(true)); +#else + engine_.get()->rootContext()->setContextProperty("WITH_WEBENGINE", QVariant(false)); +#endif initQmlLayer(); diff --git a/src/mainview/components/ChatViewFooter.qml b/src/mainview/components/ChatViewFooter.qml index 7085b5dd4a1314dad82ca5698e91696823abce3a..5a241b180d139ffcb323b797eff2bef003eceded 100644 --- a/src/mainview/components/ChatViewFooter.qml +++ b/src/mainview/components/ChatViewFooter.qml @@ -24,7 +24,6 @@ import net.jami.Constants 1.1 import net.jami.Adapters 1.1 import "../../commoncomponents" -import "../../commoncomponents/emojipicker" Rectangle { id: root @@ -90,10 +89,19 @@ Rectangle { visible: false } - EmojiPicker { - id: emojiPicker + Loader { + id: empjiLoader + source: WITH_WEBENGINE ? "qrc:/src/commoncomponents/emojipicker/EmojiPicker.qml" : "qrc:/src/nowebengine/EmojiPicker.qml" - onEmojiIsPicked: messageBar.textAreaObj.insertText(content) + function openEmojiPicker() { + item.openEmojiPicker() + } + Connections { + target: empjiLoader.item + function onEmojiIsPicked(content) { + messageBar.textAreaObj.insertText(content) + } + } } JamiFileDialog { @@ -126,20 +134,20 @@ Rectangle { onEmojiButtonClicked: { JamiQmlUtils.updateMessageBarButtonsPoints() - emojiPicker.parent = JamiQmlUtils.mainViewRectObj + empjiLoader.parent = JamiQmlUtils.mainViewRectObj - emojiPicker.x = Qt.binding(function() { + empjiLoader.x = Qt.binding(function() { var buttonX = JamiQmlUtils.emojiPickerButtonInMainViewPoint.x + JamiQmlUtils.emojiPickerButtonObj.width - return buttonX - emojiPicker.width + return buttonX - empjiLoader.width }) - emojiPicker.y = Qt.binding(function() { + empjiLoader.y = Qt.binding(function() { var buttonY = JamiQmlUtils.audioRecordMessageButtonInMainViewPoint.y - return buttonY - emojiPicker.height - messageBar.marginSize + return buttonY - empjiLoader.height - messageBar.marginSize - JamiTheme.chatViewHairLineSize }) - emojiPicker.openEmojiPicker() + empjiLoader.openEmojiPicker() } onSendFileButtonClicked: jamiFileDialog.open() onSendMessageButtonClicked: { diff --git a/src/mainview/components/MessageBar.qml b/src/mainview/components/MessageBar.qml index 6a65e197d10a3cea1164d9130f529b2f2c01658c..c9d5ac8931dbc042e3aac68fa19ef613743b0aad 100644 --- a/src/mainview/components/MessageBar.qml +++ b/src/mainview/components/MessageBar.qml @@ -157,6 +157,7 @@ ColumnLayout { PushButton { id: emojiButton + visible: WITH_WEBENGINE Layout.alignment: Qt.AlignVCenter Layout.rightMargin: sendMessageButton.visible ? 0 : marginSize diff --git a/src/messagesadapter.cpp b/src/messagesadapter.cpp index 948d508c28f65f29f5d7754bd90d3790519271b2..ddea15a6283345719a744349908197d0a3a1a8d6 100644 --- a/src/messagesadapter.cpp +++ b/src/messagesadapter.cpp @@ -61,10 +61,7 @@ MessagesAdapter::MessagesAdapter(AppSettingsManager* settingsManager, }); connect(previewEngine_, &PreviewEngine::infoReady, this, &MessagesAdapter::onPreviewInfoReady); - connect(previewEngine_, - &PreviewEngine::linkifyReady, - this, - &MessagesAdapter::onMessageLinkified); + connect(previewEngine_, &PreviewEngine::linkified, this, &MessagesAdapter::onMessageLinkified); } void diff --git a/src/nowebengine/EmojiPicker.qml b/src/nowebengine/EmojiPicker.qml new file mode 100644 index 0000000000000000000000000000000000000000..2fafa2cb63e5e7bf536d9b23d1daf6648a392323 --- /dev/null +++ b/src/nowebengine/EmojiPicker.qml @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2022 Savoir-faire Linux Inc. + * Author: Kateryna Kostiuk <kateryna.kostiuk@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 + +Rectangle { + id: root + + signal emojiIsPicked(string content) + function openEmojiPicker() {} + function closeEmojiPicker() {} +} diff --git a/src/nowebengine/MediaPreviewBase.qml b/src/nowebengine/MediaPreviewBase.qml new file mode 100644 index 0000000000000000000000000000000000000000..e7095f29574f2fa0d932a2dfffeda5a6636413e8 --- /dev/null +++ b/src/nowebengine/MediaPreviewBase.qml @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2022 Savoir-faire Linux Inc. + * Author: Kateryna Kostiuk <kateryna.kostiuk@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 +import QtQuick.Controls +import QtQuick.Layouts + +Rectangle { + property bool isVideo + property string html +} diff --git a/src/nowebengine/previewengine.cpp b/src/nowebengine/previewengine.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b6f165a1f3a7be91191aaaae913f4cf989c33cbc --- /dev/null +++ b/src/nowebengine/previewengine.cpp @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2022 Savoir-faire Linux Inc. + * Author: Kateryna Kostiuk <kateryna.kostiuk@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/>. + */ + +#include "previewengine.h" + +struct PreviewEngine::Impl : public QObject +{ + Impl(PreviewEngine&) + : QObject(nullptr) + {} +}; + +PreviewEngine::PreviewEngine(QObject* parent) + : QObject(parent) + , pimpl_(std::make_unique<Impl>(*this)) +{} + +PreviewEngine::~PreviewEngine() {} + +void +PreviewEngine::parseMessage(const QString&, const QString&, bool) +{} + +void +PreviewEngine::log(const QString&) +{} + +#include "moc_previewengine.cpp" +#include "previewengine.moc" diff --git a/src/previewengine.cpp b/src/previewengine.cpp index b5061c7314674e340042a1f7661c214c0d0d1896..84ae798854ca080361e03d8a3a3372772f5d71c7 100644 --- a/src/previewengine.cpp +++ b/src/previewengine.cpp @@ -1,4 +1,4 @@ -/* +/* * Copyright (C) 2021-2022 Savoir-faire Linux Inc. * Author: Trevor Tabah <trevor.tabah@savoirfairelinux.com> * Author: Andreas Traczyk <andreas.traczyk@savoirfairelinux.com> @@ -23,65 +23,78 @@ #include <QWebEngineProfile> #include <QWebEngineSettings> -PreviewEngine::PreviewEngine(QObject* parent) - : QWebEnginePage(parent) - , pimpl_(new PreviewEnginePrivate(this)) +#include <QtWebChannel> +#include <QWebEnginePage> + +struct PreviewEngine::Impl : public QWebEnginePage { - QWebEngineProfile* profile = QWebEngineProfile::defaultProfile(); +public: + PreviewEngine& parent_; + QWebChannel* channel_; - QDir dataDir(QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation)); - dataDir.cdUp(); - auto cachePath = dataDir.absolutePath() + "/jami"; - profile->setCachePath(cachePath); - profile->setPersistentStoragePath(cachePath); - profile->setPersistentCookiesPolicy(QWebEngineProfile::NoPersistentCookies); - profile->setHttpCacheType(QWebEngineProfile::NoCache); + Impl(PreviewEngine& parent) + : QWebEnginePage((QObject*) nullptr) + , parent_(parent) + { + QWebEngineProfile* profile = QWebEngineProfile::defaultProfile(); - settings()->setAttribute(QWebEngineSettings::JavascriptEnabled, true); - settings()->setAttribute(QWebEngineSettings::ScrollAnimatorEnabled, false); - settings()->setAttribute(QWebEngineSettings::ErrorPageEnabled, false); - settings()->setAttribute(QWebEngineSettings::PluginsEnabled, false); - settings()->setAttribute(QWebEngineSettings::ScreenCaptureEnabled, false); - settings()->setAttribute(QWebEngineSettings::LinksIncludedInFocusChain, false); - settings()->setAttribute(QWebEngineSettings::LocalStorageEnabled, false); - settings()->setAttribute(QWebEngineSettings::AllowRunningInsecureContent, true); - settings()->setAttribute(QWebEngineSettings::LocalContentCanAccessRemoteUrls, true); - settings()->setAttribute(QWebEngineSettings::XSSAuditingEnabled, false); - settings()->setAttribute(QWebEngineSettings::LocalContentCanAccessFileUrls, true); + QDir dataDir(QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation)); + dataDir.cdUp(); + auto cachePath = dataDir.absolutePath() + "/jami"; + profile->setCachePath(cachePath); + profile->setPersistentStoragePath(cachePath); + profile->setPersistentCookiesPolicy(QWebEngineProfile::NoPersistentCookies); + profile->setHttpCacheType(QWebEngineProfile::NoCache); - channel_ = new QWebChannel(this); - channel_->registerObject(QStringLiteral("jsbridge"), pimpl_); + settings()->setAttribute(QWebEngineSettings::JavascriptEnabled, true); + settings()->setAttribute(QWebEngineSettings::ScrollAnimatorEnabled, false); + settings()->setAttribute(QWebEngineSettings::ErrorPageEnabled, false); + settings()->setAttribute(QWebEngineSettings::PluginsEnabled, false); + settings()->setAttribute(QWebEngineSettings::ScreenCaptureEnabled, false); + settings()->setAttribute(QWebEngineSettings::LinksIncludedInFocusChain, false); + settings()->setAttribute(QWebEngineSettings::LocalStorageEnabled, false); + settings()->setAttribute(QWebEngineSettings::AllowRunningInsecureContent, true); + settings()->setAttribute(QWebEngineSettings::LocalContentCanAccessRemoteUrls, true); + settings()->setAttribute(QWebEngineSettings::XSSAuditingEnabled, false); + settings()->setAttribute(QWebEngineSettings::LocalContentCanAccessFileUrls, true); - setWebChannel(channel_); - runJavaScript(Utils::QByteArrayFromFile(":/linkify.js"), QWebEngineScript::MainWorld); - runJavaScript(Utils::QByteArrayFromFile(":/linkify-string.js"), QWebEngineScript::MainWorld); - runJavaScript(Utils::QByteArrayFromFile(":/qwebchannel.js"), QWebEngineScript::MainWorld); - runJavaScript(Utils::QByteArrayFromFile(":/previewInfo.js"), QWebEngineScript::MainWorld); - runJavaScript(Utils::QByteArrayFromFile(":/misc/previewInterop.js"), - QWebEngineScript::MainWorld); -} + channel_ = new QWebChannel(this); + channel_->registerObject(QStringLiteral("jsbridge"), &parent_); + + setWebChannel(channel_); + runJavaScript(Utils::QByteArrayFromFile(":/linkify.js"), QWebEngineScript::MainWorld); + runJavaScript(Utils::QByteArrayFromFile(":/linkify-string.js"), QWebEngineScript::MainWorld); + runJavaScript(Utils::QByteArrayFromFile(":/qwebchannel.js"), QWebEngineScript::MainWorld); + runJavaScript(Utils::QByteArrayFromFile(":/previewInfo.js"), QWebEngineScript::MainWorld); + runJavaScript(Utils::QByteArrayFromFile(":/misc/previewInterop.js"), + QWebEngineScript::MainWorld); + } + + void parseMessage(const QString& messageId, const QString& msg, bool showPreview) + { + runJavaScript(QString("parseMessage(`%1`, `%2`, %3)") + .arg(messageId, msg, showPreview ? "true" : "false")); + } +}; + +PreviewEngine::PreviewEngine(QObject* parent) + : QObject(parent) + , pimpl_(std::make_unique<Impl>(*this)) +{} + +PreviewEngine::~PreviewEngine() {} void PreviewEngine::parseMessage(const QString& messageId, const QString& msg, bool showPreview) { - runJavaScript( - QString("parseMessage(`%1`, `%2`, %3)").arg(messageId, msg, showPreview ? "true" : "false")); + pimpl_->parseMessage(messageId, msg, showPreview); } void -PreviewEnginePrivate::log(const QString& str) +PreviewEngine::log(const QString& str) { qDebug() << str; } -void -PreviewEnginePrivate::infoReady(const QString& messageId, const QVariantMap& info) -{ - Q_EMIT parent_->infoReady(messageId, info); -} - -void -PreviewEnginePrivate::linkifyReady(const QString& messageId, const QString& linkified) -{ - Q_EMIT parent_->linkifyReady(messageId, linkified); -} +#include "moc_previewengine.cpp" +#include "previewengine.moc" diff --git a/src/previewengine.h b/src/previewengine.h index ea57f296a25c49dcc6f8754a37510330bc23e0d4..c929b21b8e31f76c2e09d7fe0ee5a192034e76d8 100644 --- a/src/previewengine.h +++ b/src/previewengine.h @@ -1,4 +1,4 @@ -/* +/* * Copyright (C) 2021-2022 Savoir-faire Linux Inc. * Author: Trevor Tabah <trevor.tabah@savoirfairelinux.com> * Author: Andreas Traczyk <andreas.traczyk@savoirfairelinux.com> @@ -20,42 +20,25 @@ #pragma once #include "utils.h" +#include <QObject> -#include <QtWebChannel> -#include <QWebEnginePage> - -class PreviewEngine; - -class PreviewEnginePrivate : public QObject +class PreviewEngine : public QObject { Q_OBJECT + Q_DISABLE_COPY(PreviewEngine) public: - explicit PreviewEnginePrivate(PreviewEngine* parent) - : parent_(parent) - {} - - Q_INVOKABLE void infoReady(const QString& messageId, const QVariantMap& info); - Q_INVOKABLE void linkifyReady(const QString& messageId, const QString& linkified); - Q_INVOKABLE void log(const QString& str); - -private: - PreviewEngine* parent_; -}; - -class PreviewEngine : public QWebEnginePage -{ - Q_OBJECT -public: - explicit PreviewEngine(QObject* parent = nullptr); - ~PreviewEngine() = default; + PreviewEngine(QObject* parent = nullptr); + ~PreviewEngine(); void parseMessage(const QString& messageId, const QString& msg, bool showPreview); + Q_INVOKABLE void log(const QString& str); + Q_SIGNALS: - void infoReady(const QString& messageId, const QVariantMap& info); - void linkifyReady(const QString& messageId, const QString& linkified); + Q_INVOKABLE void infoReady(const QString& messageId, const QVariantMap& info); + Q_INVOKABLE void linkified(const QString& messageId, const QString& linkified); private: - QWebChannel* channel_; - PreviewEnginePrivate* pimpl_; + struct Impl; + std::unique_ptr<Impl> pimpl_; }; diff --git a/src/settingsview/components/ChatviewSettings.qml b/src/settingsview/components/ChatviewSettings.qml index 65105700b5f0e1bf99ea24e582ffd90a7e98441d..da5c90926701f51c6df9b6de25509602910f4d0c 100644 --- a/src/settingsview/components/ChatviewSettings.qml +++ b/src/settingsview/components/ChatviewSettings.qml @@ -62,6 +62,7 @@ ColumnLayout { ToggleSwitch { id: displayImagesCheckbox + visible: WITH_WEBENGINE Layout.fillWidth: true Layout.leftMargin: JamiTheme.preferredMarginSize