diff --git a/src/contents/ui/AuthSheet.qml b/src/contents/ui/AuthSheet.qml new file mode 100644 index 0000000..f13e25f --- /dev/null +++ b/src/contents/ui/AuthSheet.qml @@ -0,0 +1,58 @@ +import QtQuick 2.0 +import QtQuick.Layouts 1.1 +import QtQuick.Controls 2.2 as Controls +import org.kde.kirigami 2.5 as Kirigami + +Kirigami.OverlaySheet { + id: authSheet + property var request + + Kirigami.FormLayout { + Layout.fillWidth: true + + Kirigami.Heading { + elide: Text.ElideRight + wrapMode: Text.WordWrap + Layout.fillWidth: true + + text: i18n("Authentication required") + } + + Controls.TextField { + id: usernameField + + Kirigami.FormData.label: i18n("Username") + Layout.fillWidth: true + } + Controls.TextField { + id: passwordField + echoMode: TextInput.Password + + Kirigami.FormData.label: i18n("Password") + Layout.fillWidth: true + } + + RowLayout { + Layout.fillWidth: true + + Controls.Button { + Layout.fillWidth: true + text: i18n("Accept") + + onClicked: { + authSheet.request.dialogAccept(usernameField.text, passwordField.text) + authSheet.close() + } + } + Controls.Button { + Layout.fillWidth: true + text: i18n("Cancel") + + onClicked: { + authSheet.request.dialogReject() + authSheet.close() + } + } + } + } +} diff --git a/src/contents/ui/DownloadQuestion.qml b/src/contents/ui/DownloadQuestion.qml new file mode 100644 index 0000000..6d17feb --- /dev/null +++ b/src/contents/ui/DownloadQuestion.qml @@ -0,0 +1,29 @@ +import QtQuick 2.0 +import org.kde.kirigami 2.4 as Kirigami + +Kirigami.InlineMessage { + id: downloadQuestion + text: i18n("Do you want to download this file?") + showCloseButton: false + + property var download + + actions: [ + Kirigami.Action { + iconName: "download" + text: i18n("Download") + onTriggered: { + downloadQuestion.download.resume() + downloadQuestion.visible = false + } + }, + Kirigami.Action { + icon.name: "dialog-cancel" + text: i18n("Cancel") + onTriggered: { + downloadQuestion.download.cancel() + downloadQuestion.visible = false + } + } + ] +} diff --git a/src/contents/ui/FindInPageSheet.qml b/src/contents/ui/FindInPageSheet.qml new file mode 100644 index 0000000..aee2acc --- /dev/null +++ b/src/contents/ui/FindInPageSheet.qml @@ -0,0 +1,7 @@ +InputSheet { + id: findSheet + title: i18n("Find in page") + placeholderText: i18n("Find...") + description: i18n("Highlight text on the current website") + onAccepted: currentWebView.findText(findSheet.text) +} diff --git a/src/contents/ui/NewTabQuestion.qml b/src/contents/ui/NewTabQuestion.qml new file mode 100644 index 0000000..5751732 --- /dev/null +++ b/src/contents/ui/NewTabQuestion.qml @@ -0,0 +1,24 @@ +import QtQuick 2.0 +import org.kde.kirigami 2.4 as Kirigami + + +Kirigami.InlineMessage { + id: newTabQuestion + type: Kirigami.MessageType.Warning + text: url? i18n("Site wants to open a new tab: \n%1", url.toString()) : "" + showCloseButton: true + + property var url + + actions: [ + Kirigami.Action { + icon.name: "tab-new" + text: i18n("Open") + onTriggered: { + tabs.newTab(newTabQuestion.url.toString()) + newTabQuestion.visible = false + } + } + + ] +} diff --git a/src/contents/ui/PermissionQuestion.qml b/src/contents/ui/PermissionQuestion.qml new file mode 100644 index 0000000..c47ba54 --- /dev/null +++ b/src/contents/ui/PermissionQuestion.qml @@ -0,0 +1,43 @@ +import org.kde.kirigami 2.4 as Kirigami +import QtWebEngine 1.5 + +Kirigami.InlineMessage { + property int permission + property string origin + + id: permissionQuestion + text: { + if (permission === WebEngineView.Geolocation) + i18n("Do you want to allow the website to access the geo location?") + else if (permission === WebEngineView.MediaAudioCapture) + i18n("Do you want to allow the website to access the microphone?") + else if (permission === WebEngineView.MediaVideoCapture) + i18n("Do you want to allow the website to access the camera?") + else if (permission === WebEngineView.MediaAudioVideoCapture) + i18n("Do you want to allow the website to access the camera and the microphone?") + } + showCloseButton: false + + actions: [ + Kirigami.Action { + icon.name: "dialog-ok-apply" + text: i18n("Accept") + onTriggered: { + currentWebView.grantFeaturePermission( + permissionQuestion.origin, + permissionQuestion.permission, true) + permissionQuestion.visible = false + } + }, + Kirigami.Action { + icon.name: "dialog-cancel" + text: i18n("Decline") + onTriggered: { + currentWebView.grantFeaturePermission( + permissionQuestion.origin, + permissionQuestion.permission, false) + downloadQuestion.visible = false + } + } + ] +} diff --git a/src/contents/ui/ShareSheet.qml b/src/contents/ui/ShareSheet.qml index 93a054c..143f5b9 100644 --- a/src/contents/ui/ShareSheet.qml +++ b/src/contents/ui/ShareSheet.qml @@ -1,57 +1,58 @@ /*************************************************************************** * * * Copyright 2019 Nicolas Fella * * * * 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 2 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 . * * * ***************************************************************************/ import QtQuick.Controls 2.1 as Controls import QtQuick.Layouts 1.7 import QtQuick 2.7 import org.kde.kirigami 2.5 as Kirigami import org.kde.purpose 1.0 as Purpose Kirigami.OverlaySheet { id: inputSheet property var url property var title Purpose.AlternativesView { id: view pluginType: "ShareUrl" implicitHeight: initialItem.contentHeight + clip: true delegate: Kirigami.BasicListItem { label: model.display icon: "arrow-right" onClicked: view.createJob (model.index) Keys.onReturnPressed: view.createJob (model.index) Keys.onEnterPressed: view.createJob (model.index) } onFinished: close() } onSheetOpenChanged: { view.inputData = { "urls": [inputSheet.url.toString()], "title": inputSheet.title } } } diff --git a/src/contents/ui/Tabs.qml b/src/contents/ui/Tabs.qml index e9043e4..619d60c 100644 --- a/src/contents/ui/Tabs.qml +++ b/src/contents/ui/Tabs.qml @@ -1,161 +1,161 @@ /*************************************************************************** * * * Copyright 2014-2015 Sebastian Kügler * * * * 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 2 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 . * * * ***************************************************************************/ import QtQuick 2.3 import QtQuick.Controls 2.0 as Controls //import QtWebEngine 1.0 import QtQuick.Layouts 1.0 import org.kde.kirigami 2.0 as Kirigami // import org.kde.plasma.components 2.0 as PlasmaComponents // import org.kde.plasma.extras 2.0 as PlasmaExtras Kirigami.ScrollablePage { id: tabsRoot title: i18n("Tabs") property int itemHeight: Math.round(itemWidth/ 3 * 2) property int itemWidth: Kirigami.Units.gridUnit * 9 //Rectangle { anchors.fill: parent; color: "brown"; opacity: 0.5; } GridView { anchors.fill: parent model: tabs.model cellWidth: itemWidth cellHeight: itemHeight delegate: Item { id: tabItem width: itemWidth height: itemHeight ShaderEffectSource { id: shaderItem //live: true anchors.fill: parent - anchors.margins: Kirigami.Units.gridUnit / 2 + anchors.margins: Kirigami.Units.gridUnit * 0.5 sourceRect: Qt.rect(0, 0, width * 2, height * 2) sourceItem: { tabs.itemAt(tabs.pageWidth * index, 0); } //opacity: tabs.currentIndex == index ? 1 : 0.0 Behavior on height { SequentialAnimation { ScriptAction { script: { print("Animation start"); // switch to tabs } } NumberAnimation { duration: Kirigami.Units.longDuration; easing.type: Easing.InOutQuad } NumberAnimation { duration: Kirigami.Units.longDuration; easing.type: Easing.InOutQuad; target: contentView; property: opacity } ScriptAction { script: { print("Animation done"); contentView.state = "hidden" } } } } Behavior on width { NumberAnimation { duration: Kirigami.Units.longDuration; easing.type: Easing.InOutQuad} } } Rectangle { anchors.fill: parent; anchors.margins: Kirigami.Units.gridUnit / 4; border.color: Kirigami.Theme.textColor; border.width: webBrowser.borderWidth color: "transparent" opacity: 0.3; } MouseArea { anchors.fill: parent onClicked: { print("Switch from " + tabs.currentIndex + " to tab " + index); tabs.currentIndex = index; tabs.positionViewAtIndex(index, ListView.Beginning); //tabs.positionViewAtEnd(); pageStack.layers.pop() } } Controls.ToolButton { icon.name: "window-close" height: Kirigami.gridUnit width: height anchors.right: parent.right anchors.rightMargin: Kirigami.Units.smallSpacing anchors.top: parent.top anchors.topMargin: Kirigami.Units.smallSpacing onClicked: tabs.closeTab(index) } Controls.Label { anchors { left: tabItem.left right: tabItem.right bottom: tabItem.bottom margins: Kirigami.Units.gridUnit * 0.5 } width: itemWidth text: tabs.itemAt(tabs.pageWidth * index, 0).title elide: Qt.ElideRight } } footer: Item { width: itemWidth height: itemHeight Kirigami.Icon { anchors.fill: parent anchors.margins: Math.round(itemHeight / 4) source: "list-add" } MouseArea { anchors.fill: parent onClicked: { tabs.newTab(browserManager.homepage) //addressBar.forceActiveFocus(); //addressBar.selectAll(); tabs.currentIndex = tabs.count - 1; pageStack.layers.pop() } } } } } diff --git a/src/contents/ui/WebView.qml b/src/contents/ui/WebView.qml index af4afa8..e42f227 100644 --- a/src/contents/ui/WebView.qml +++ b/src/contents/ui/WebView.qml @@ -1,262 +1,212 @@ /*************************************************************************** * * * Copyright 2014-2015 Sebastian Kügler * * * * 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 2 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 . * * * ***************************************************************************/ import QtQuick 2.3 import QtQuick.Controls 2.4 as Controls import QtQuick.Window 2.1 import QtQuick.Layouts 1.3 import QtWebEngine 1.7 import org.kde.kirigami 2.4 as Kirigami WebEngineView { id: webEngineView property string errorCode: "" property string errorString: "" /** * User agent used on mobile devices */ property string mobileUserAgent: "Mozilla/5.0 (Linux; Plasma Mobile, like Android 9.0 ) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/69.0.3497.128 Mobile Safari/537.36" /** * User agent used on desktop devices, * Defaults to QtWebEngine's default (it is only supported on desktop devices by Qt currently) */ property string desktopUserAgent: profile.httpUserAgent width: pageWidth height: pageHeight profile { httpUserAgent: { if (Kirigami.Settings.isMobile) return mobileUserAgent else return desktopUserAgent } offTheRecord: rootPage.privateMode onDownloadRequested: { // if we don't accept the request right away, it will be deleted download.accept() // therefore just stop the download again as quickly as possible, // and ask the user for confirmation download.pause() - downloadQuestion.download = download - downloadQuestion.visible = true + + questionLoader.setSource("DownloadQuestion.qml") + questionLoader.item.download = download + questionLoader.item.visible = true } onDownloadFinished: { if (download.state === WebEngineDownloadItem.DownloadCompleted) { showPassiveNotification(i18n("Download finished")) } else if (download.state === WebEngineDownloadItem.DownloadInterrupted) { showPassiveNotification(i18n("Download failed")) console.log("Download interrupt reason: " + download.interruptReason) } else if (download.state === WebEngineDownloadItem.DownloadCancelled) { console.log("Download cancelled by the user") } } } settings { // Disable builtin error pages in favor of our own errorPageEnabled: false } // Custom context menu Controls.Menu { property var request id: contextMenu Controls.MenuItem { text: i18n("Copy") enabled: (contextMenu.request.editFlags & ContextMenuRequest.CanCopy) != 0 onTriggered: webEngineView.triggerWebAction(WebEngineView.Copy) } Controls.MenuItem { text: i18n("Cut") enabled: (contextMenu.request.editFlags & ContextMenuRequest.CanCut) != 0 onTriggered: webEngineView.triggerWebAction(WebEngineView.Cut) } Controls.MenuItem { text: i18n("Paste") enabled: (contextMenu.request.editFlags & ContextMenuRequest.CanPaste) != 0 onTriggered: webEngineView.triggerWebAction(WebEngineView.Paste) } Controls.MenuItem { enabled: contextMenu.request.linkUrl !== "" text: i18n("Copy Url") - onTriggered: webEngineView.triggerWebAction(WebEngineView.CopyLinkToClipboard) + onTriggered: webEngineView.triggerWebAction(WebEngineView.CopyLinkToClipboard) } Controls.MenuItem { text: i18n("View source") onTriggered: newTab("view-source:" + webEngineView.url) } Controls.MenuItem { text: i18n("Download") onTriggered: webEngineView.triggerWebAction(WebEngineView.DownloadLinkToDisk) } Controls.MenuItem { enabled: contextMenu.request.linkUrl !== "" text: i18n("Open in new Tab") onTriggered: webEngineView.triggerWebAction(WebEngineView.OpenLinkInNewTab) } } - Kirigami.OverlaySheet { - id: authSheet - property var request - - Kirigami.FormLayout { - Layout.fillWidth: true - - Kirigami.Heading { - elide: Text.ElideRight - wrapMode: Text.WordWrap - Layout.fillWidth: true - - text: i18n("Authentication required") - } - - Controls.TextField { - id: usernameField - - Kirigami.FormData.label: i18n("Username") - Layout.fillWidth: true - } - Controls.TextField { - id: passwordField - echoMode: TextInput.Password - - Kirigami.FormData.label: i18n("Password") - Layout.fillWidth: true - } - - RowLayout { - Layout.fillWidth: true - - Controls.Button { - Layout.fillWidth: true - text: i18n("Accept") - - onClicked: { - authSheet.request.dialogAccept(usernameField.text, passwordField.text) - authSheet.close() - } - } - Controls.Button { - Layout.fillWidth: true - text: i18n("Cancel") - - onClicked: { - authSheet.request.dialogReject() - authSheet.close() - } - } - } - } - } - - //Rectangle { color: "yellow"; opacity: 0.3; anchors.fill: parent } focus: true onLoadingChanged: { //print("Loading: " + loading); print(" url: " + loadRequest.url) //print(" icon: " + webEngineView.icon) //print(" title: " + webEngineView.title) /* Handle * - WebEngineView::LoadStartedStatus, * - WebEngineView::LoadStoppedStatus, * - WebEngineView::LoadSucceededStatus and * - WebEngineView::LoadFailedStatus */ var ec = ""; var es = ""; if (loadRequest.status === WebEngineView.LoadSucceededStatus) { if (!rootPage.privateMode) { addHistoryEntry(); } } if (loadRequest.status === WebEngineView.LoadFailedStatus) { print("Load failed: " + loadRequest.errorCode + " " + loadRequest.errorString); ec = loadRequest.errorCode; es = loadRequest.errorString; } errorCode = ec; errorString = es; } Component.onCompleted: { print("WebView completed."); var settings = webEngineView.settings; print("Settings: " + settings); } onIconChanged: { if (icon) browserManager.history.updateIcon(url, icon) } onNewViewRequested: { if (request.userInitiated) { newTab(request.requestedUrl.toString()) showPassiveNotification(i18n("Website was opened in a new tab")) } else { - newTabQuestion.url = request.requestedUrl - newTabQuestion.visible = true + questionLoader.setSource("NewTabQuestion.qml") + questionLoader.item.url = request.requestedUrl + questionLoader.item.visible = true } } onFullScreenRequested: { request.accept() if (webBrowser.visibility !== Window.FullScreen) webBrowser.showFullScreen() else webBrowser.showNormal() } onContextMenuRequested: { request.accepted = true // Make sure QtWebEngine doesn't show its own context menu. contextMenu.request = request contextMenu.x = request.x contextMenu.y = request.y contextMenu.open() } onAuthenticationDialogRequested: { request.accepted = true - authSheet.request = request - authSheet.open() + sheetLoader.setSource("AuthSheet.qml") + sheetLoader.item.request = request + sheetLoader.item.open() } onFeaturePermissionRequested: { - permissionQuestion.permission = feature - permissionQuestion.origin = securityOrigin - permissionQuestion.visible = true + questionLoader.setSource("PermissionQuestion.qml") + questionLoader.item.permission = feature + questionLoader.item.origin = securityOrigin + questionLoader.item.visible = true } } diff --git a/src/contents/ui/webbrowser.qml b/src/contents/ui/webbrowser.qml index 54ae05f..c4e200b 100644 --- a/src/contents/ui/webbrowser.qml +++ b/src/contents/ui/webbrowser.qml @@ -1,430 +1,337 @@ /*************************************************************************** * * * Copyright 2014-2015 Sebastian Kügler * * * * 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 2 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 . * * * ***************************************************************************/ import QtQuick 2.1 import QtWebEngine 1.6 import QtQuick.Window 2.3 import QtGraphicalEffects 1.0 import org.kde.kirigami 2.4 as Kirigami import org.kde.mobile.angelfish 1.0 Kirigami.ApplicationWindow { id: webBrowser title: i18n("Angelfish Web Browser") /** Pointer to the currently active view. * * Browser-level functionality should use this to refer to the current * view, rather than looking up views in the mode, as far as possible. */ property Item currentWebView: tabs.currentIndex < tabs.count ? tabs.currentItem : null onCurrentWebViewChanged: { print("Current WebView is now : " + tabs.currentIndex); } property int borderWidth: Math.round(Kirigami.Units.gridUnit / 18); property color borderColor: Kirigami.Theme.highlightColor; /** * Load a url in the current tab */ function load(url) { print("Loading url: " + url); currentWebView.url = url; currentWebView.forceActiveFocus() } BrowserManager { id: browserManager } /** * Make loading available to c++ */ Connections { target: browserManager onLoadUrlRequested: { load(url) } } width: Kirigami.Units.gridUnit * 20 height: Kirigami.Units.gridUnit * 30 /** * Add page of currently active webview to history */ function addHistoryEntry() { //print("Adding history"); var request = new Object;// FIXME request.url = currentWebView.url; request.title = currentWebView.title; request.icon = currentWebView.icon; browserManager.addToHistory(request); } // Only show ToolBar if a layer is open property bool layerShown : pageStack.layers.depth > 1 pageStack.globalToolBar.style: layerShown ? Kirigami.ApplicationHeaderStyle.Auto : Kirigami.ApplicationHeaderStyle.None globalDrawer: Kirigami.GlobalDrawer { id: globalDrawer handleVisible: false actions: [ Kirigami.Action { icon.name: "tab-duplicate" onTriggered: { pageStack.layers.push("Tabs.qml") } text: i18n("Tabs") }, Kirigami.Action { icon.name: "view-private" onTriggered: { rootPage.privateMode ? rootPage.privateMode = false : rootPage.privateMode = true } text: rootPage.privateMode ? i18n("Leave private mode") : i18n("Private mode") }, Kirigami.Action { icon.name: "bookmarks" onTriggered: { pageStack.layers.push("Bookmarks.qml") } text: i18n("Bookmarks") }, Kirigami.Action { icon.name: "view-history" onTriggered: { pageStack.layers.push("History.qml") } text: i18n("History") }, Kirigami.Action { icon.name: "configure" text: i18n("Settings") onTriggered: { pageStack.layers.push("Settings.qml") } } ] } contextDrawer: Kirigami.ContextDrawer { id: contextDrawer handleVisible: false } // Main Page pageStack.initialPage: Kirigami.Page { id: rootPage leftPadding: 0 rightPadding: 0 topPadding: 0 bottomPadding: 0 property bool privateMode: false ListWebView { id: tabs anchors { top: parent.top left: parent.left right: parent.right bottom: navigation.top } } ErrorHandler { id: errorHandler errorString: currentWebView.errorString errorCode: currentWebView.errorCode anchors { top: parent.top left: parent.left right: parent.right bottom: navigation.top } visible: currentWebView.errorCode !== "" } - Kirigami.InlineMessage { - id: newTabQuestion - type: Kirigami.MessageType.Warning - text: url? i18n("Site wants to open a new tab: \n%1", url.toString()) : "" - showCloseButton: true - anchors.bottom: navigation.top - anchors.left: parent.left - anchors.right: parent.right - - property var url - - actions: [ - Kirigami.Action { - icon.name: "tab-new" - text: i18n("Open") - onTriggered: { - tabs.newTab(newTabQuestion.url.toString()) - newTabQuestion.visible = false - } - } + Loader { + id: questionLoader - ] - } - - Kirigami.InlineMessage { - id: downloadQuestion - text: i18n("Do you want to download this file?") - showCloseButton: false anchors.bottom: navigation.top anchors.left: parent.left anchors.right: parent.right - - property var download - - actions: [ - Kirigami.Action { - iconName: "download" - text: i18n("Download") - onTriggered: { - downloadQuestion.download.resume() - downloadQuestion.visible = false - } - }, - Kirigami.Action { - icon.name: "dialog-cancel" - text: i18n("Cancel") - onTriggered: { - downloadQuestion.download.cancel() - downloadQuestion.visible = false - } - } - ] - } - - Kirigami.InlineMessage { - property int permission - property string origin - - id: permissionQuestion - text: { - if (permission === WebEngineView.Geolocation) - i18n("Do you want to allow the website to access the geo location?") - else if (permission === WebEngineView.MediaAudioCapture) - i18n("Do you want to allow the website to access the microphone?") - else if (permission === WebEngineView.MediaVideoCapture) - i18n("Do you want to allow the website to access the camera?") - else if (permission === WebEngineView.MediaAudioVideoCapture) - i18n("Do you want to allow the website to access the camera and the microphone?") - } - showCloseButton: false - anchors.bottom: navigation.top - anchors.left: parent.left - anchors.right: parent.right - - actions: [ - Kirigami.Action { - icon.name: "dialog-ok-apply" - text: i18n("Accept") - onTriggered: { - currentWebView.grantFeaturePermission(permissionQuestion.origin, permissionQuestion.permission, true) - permissionQuestion.visible = false - } - }, - Kirigami.Action { - icon.name: "dialog-cancel" - text: i18n("Decline") - onTriggered: { - currentWebView.grantFeaturePermission(permissionQuestion.origin, permissionQuestion.permission, false) - downloadQuestion.visible = false - } - } - ] } // Container for the progress bar Item { id: progressItem height: Math.round(Kirigami.Units.gridUnit / 6) z: navigation.z + 1 anchors { top: tabs.bottom topMargin: -Math.round(height / 2) left: tabs.left right: tabs.right } opacity: currentWebView.loading ? 1 : 0 Behavior on opacity { NumberAnimation { duration: Kirigami.Units.longDuration; easing.type: Easing.InOutQuad; } } Rectangle { color: Kirigami.Theme.highlightColor width: Math.round((currentWebView.loadProgress / 100) * parent.width) anchors { top: parent.top left: parent.left bottom: parent.bottom } } - - } - - // Find in page - InputSheet { - id: findSheet - title: i18n("Find in page") - placeholderText: i18n("Find...") - description: i18n("Highlight text on the current website") - onAccepted: currentWebView.findText(findSheet.text) } - // Share page - ShareSheet { - id: shareSheet + Loader { + id: sheetLoader } // The menu at the bottom right contextualActions: [ Kirigami.Action { icon.name: "edit-find" - onTriggered: findSheet.open() + onTriggered: { + sheetLoader.setSource("FindInPageSheet.qml") + sheetLoader.item.open() + } text: i18n("Find in page") }, Kirigami.Action { icon.name: "document-share" text: i18n("Share page") onTriggered: { - shareSheet.url = currentWebView.url - shareSheet.title = currentWebView.title - shareSheet.open() + sheetLoader.setSource("ShareSheet.qml") + sheetLoader.item.url = currentWebView.url + sheetLoader.item.title = currentWebView.title + sheetLoader.item.open() } }, Kirigami.Action { enabled: currentWebView.canGoBack icon.name: "go-previous" text: i18n("Go previous") onTriggered: { currentWebView.goBack() } }, Kirigami.Action { enabled: currentWebView.canGoForward icon.name: "go-next" text: i18n("Go forward") onTriggered: { currentWebView.goForward() } }, Kirigami.Action { icon.name: currentWebView.loading ? "process-stop" : "view-refresh" text: currentWebView.loading ? i18n("Stop loading") : i18n("Refresh") onTriggered: { currentWebView.loading ? currentWebView.stop() : currentWebView.reload() } }, Kirigami.Action { icon.name: "bookmarks" text: i18n("Add bookmark") onTriggered: { print("Adding bookmark"); var request = new Object;// FIXME request.url = currentWebView.url; request.title = currentWebView.title; request.icon = currentWebView.icon; request.bookmarked = true; browserManager.addBookmark(request); } } ] // Bottom navigation bar Navigation { id: navigation navigationShown: !webappcontainer && webBrowser.visibility !== Window.FullScreen Kirigami.Theme.colorSet: rootPage.privateMode ? Kirigami.Theme.Complementary : Kirigami.Theme.Window layer.enabled: navigation.visible layer.effect: DropShadow { verticalOffset: - 1 color: Kirigami.Theme.disabledTextColor samples: 10 spread: 0.1 cached: true // element is static } anchors { bottom: completion.top left: parent.left right: parent.right } onTextChanged: urlFilter.setFilterFixedString(text) } Completion { id: completion model: UrlFilterProxyModel { id: urlFilter sourceModel: browserManager.history } width: parent.width height: 0.5 * parent.height visible: navigation.textFocus searchText: navigation.text Behavior on height { NumberAnimation { duration: Kirigami.Units.shortDuration * 2 } } anchors { bottom: parent.bottom horizontalCenter: navigation.horizontalCenter } } // Thin line above navigation Rectangle { height: webBrowser.borderWidth color: webBrowser.borderColor anchors { left: parent.left bottom: navigation.top right: parent.right } } } } diff --git a/src/resources.qrc b/src/resources.qrc index 716c299..78ee850 100644 --- a/src/resources.qrc +++ b/src/resources.qrc @@ -1,18 +1,23 @@ contents/ui/Bookmarks.qml contents/ui/ErrorHandler.qml contents/ui/History.qml contents/ui/ListWebView.qml contents/ui/Navigation.qml contents/ui/Settings.qml contents/ui/Tabs.qml contents/ui/UrlDelegate.qml contents/ui/webbrowser.qml contents/ui/WebView.qml regex-weburl/regex-weburl.js contents/ui/InputSheet.qml contents/ui/ShareSheet.qml contents/ui/Completion.qml + contents/ui/AuthSheet.qml + contents/ui/NewTabQuestion.qml + contents/ui/DownloadQuestion.qml + contents/ui/PermissionQuestion.qml + contents/ui/FindInPageSheet.qml