Warning, /network/angelfish/src/contents/ui/mobile.qml is written in an unsupported language. File is not indexed.

0001 // SPDX-FileCopyrightText: 2014-2015 Sebastian Kügler <sebas@kde.org>
0002 //
0003 // SPDX-License-Identifier: GPL-2.0-or-later
0004 
0005 import QtQuick 2.1
0006 import QtWebEngine 1.6
0007 import QtQuick.Window 2.3
0008 import Qt5Compat.GraphicalEffects
0009 import QtQuick.Layouts 1.2
0010 import QtQuick.Controls 2.2 as Controls
0011 
0012 import org.kde.kirigami 2.7 as Kirigami
0013 
0014 import org.kde.angelfish 1.0
0015 
0016 Kirigami.ApplicationWindow {
0017     id: webBrowser
0018     title: i18n("Angelfish Web Browser")
0019 
0020     /** Pointer to the currently active view.
0021      *
0022      * Browser-level functionality should use this to refer to the current
0023      * view, rather than looking up views in the mode, as far as possible.
0024      */
0025     property WebView currentWebView: tabs.currentItem
0026 
0027     // Pointer to the currently active list of tabs.
0028     //
0029     // As there are private and normal tabs, switch between
0030     // them according to the current mode.
0031     property ListWebView tabs: rootPage.privateMode ? privateTabs : regularTabs
0032 
0033     // Used to determine if the window is in landscape mode
0034     property bool landscape: width > height
0035 
0036     onCurrentWebViewChanged: {
0037         print("Current WebView is now : " + tabs.currentIndex);
0038     }
0039     property int borderWidth: Math.round(Kirigami.Units.gridUnit / 18);
0040     property color borderColor: Kirigami.Theme.highlightColor;
0041 
0042     pageStack.globalToolBar.style: Kirigami.ApplicationHeaderStyle.ToolBar
0043     pageStack.globalToolBar.showNavigationButtons: Kirigami.ApplicationHeaderStyle.ShowBackButton
0044     
0045     pageStack.columnView.columnResizeMode: Kirigami.ColumnView.SingleColumn
0046     
0047     x: Settings.windowX
0048     y: Settings.windowY
0049     width: Settings.windowWidth
0050     height: Settings.windowHeight
0051 
0052     globalDrawer: Kirigami.GlobalDrawer {
0053         id: globalDrawer
0054 
0055         handleVisible: false
0056 
0057         actions: [
0058             Kirigami.Action {
0059                 icon.name: "tab-duplicate"
0060                 onTriggered: {
0061                     popSubPages();
0062                     tabsSheetLoader.open();
0063                 }
0064                 text: i18n("Tabs")
0065             },
0066             Kirigami.Action {
0067                 icon.name: "view-private"
0068                 onTriggered: {
0069                     rootPage.privateMode ? rootPage.privateMode = false : rootPage.privateMode = true
0070                 }
0071                 text: rootPage.privateMode ? i18n("Leave private mode") : i18n("Private mode")
0072             },
0073             Kirigami.Action {
0074                 icon.name: "bookmarks"
0075                 onTriggered: {
0076                     popSubPages();
0077                     pageStack.push(Qt.resolvedUrl("Bookmarks.qml"))
0078                 }
0079                 text: i18n("Bookmarks")
0080             },
0081             Kirigami.Action {
0082                 icon.name: "shallow-history"
0083                 onTriggered: {
0084                     popSubPages();
0085                     pageStack.push(Qt.resolvedUrl("History.qml"))
0086                 }
0087                 text: i18n("History")
0088             },
0089             Kirigami.Action {
0090                 icon.name: "download"
0091                 text: i18n("Downloads")
0092                 onTriggered: {
0093                     popSubPages();
0094                     pageStack.push(Qt.resolvedUrl("Downloads.qml"))
0095                 }
0096             },
0097             Kirigami.Action {
0098                 icon.name: "configure"
0099                 text: i18n("Settings")
0100                 onTriggered: {
0101                     popSubPages();
0102                     pageStack.push("qrc:/SettingsPage.qml");
0103                 }
0104             }
0105         ]
0106     }
0107 
0108     contextDrawer: Kirigami.ContextDrawer {
0109         id: contextDrawer
0110         actions: pageStack.currentItem?.actions ?? []
0111         enabled: true
0112 
0113         handleVisible: false
0114     }
0115 
0116     // Main Page
0117     pageStack.initialPage: Kirigami.Page {
0118         id: rootPage
0119         title: currentWebView.title
0120         leftPadding: 0
0121         rightPadding: 0
0122         topPadding: 0
0123         bottomPadding: 0
0124         globalToolBarStyle: Kirigami.ApplicationHeaderStyle.None
0125         Kirigami.ColumnView.fillWidth: true
0126         Kirigami.ColumnView.pinned: true
0127         Kirigami.ColumnView.preventStealing: true
0128 
0129         // Required to enforce active tab reload
0130         // on start. As a result, mixed isMobile
0131         // tabs will work correctly
0132         property bool initialized: false
0133 
0134         property bool privateMode: false
0135 
0136         // Used for automatically show or hid navigation
0137         // bar. Set separately to combine with other options
0138         // for navigation bar management (webapp and others)
0139         property bool navigationAutoShow: true
0140 
0141         property alias questionLoader: questionLoader
0142         property alias questions: questions
0143 
0144         ListWebView {
0145             id: regularTabs
0146             objectName: "regularTabsObject"
0147             anchors.fill: parent
0148             activeTabs: rootPage.initialized && !rootPage.privateMode
0149         }
0150 
0151         ListWebView {
0152             id: privateTabs
0153             anchors.fill: parent
0154             activeTabs: rootPage.initialized && rootPage.privateMode
0155             privateTabsMode: true
0156         }
0157 
0158         Controls.ScrollBar {
0159             visible: true
0160             anchors.right: parent.right
0161             anchors.top: parent.top
0162             anchors.bottom: parent.bottom
0163             position: currentWebView.scrollPosition.y / currentWebView.contentsSize.height
0164             orientation: Qt.Vertical
0165             size: currentWebView.height / currentWebView.contentsSize.height
0166             interactive: false
0167         }
0168 
0169         ErrorHandler {
0170             id: errorHandler
0171 
0172             errorString: currentWebView.errorString
0173             errorCode: currentWebView.errorCode
0174 
0175             anchors {
0176                 top: parent.top
0177                 left: parent.left
0178                 right: parent.right
0179                 bottom: navigation.top
0180             }
0181             visible: currentWebView.errorCode !== ""
0182 
0183             onRefreshRequested: currentWebView.reload()
0184             onCertificateIgnored: {
0185                 visible = Qt.binding(() => {
0186                     return currentWebView.errorCode !== "";
0187                 })
0188             }
0189 
0190             function enqueue(error){
0191                 errorString = error.description;
0192                 errorCode = error.error;
0193                 visible = true;
0194                 errorHandler.open(error);
0195             }
0196         }
0197 
0198         Loader {
0199             id: questionLoader
0200 
0201             Component.onCompleted: {
0202                 if (AdblockUrlInterceptor.adblockSupported && AdblockUrlInterceptor.downloadNeeded) {
0203                     questionLoader.setSource("AdblockFilterDownloadQuestion.qml")
0204                 }
0205             }
0206 
0207             anchors.bottom: navigation.top
0208             anchors.left: parent.left
0209             anchors.right: parent.right
0210         }
0211 
0212         Questions {
0213             id: questions
0214 
0215             anchors.bottom: navigation.top
0216             anchors.left: parent.left
0217             anchors.right: parent.right
0218         }
0219 
0220         // Container for the progress bar
0221         Item {
0222             id: progressItem
0223 
0224             height: Math.round(Kirigami.Units.gridUnit / 6)
0225             z: navigation.z + 1
0226             anchors {
0227                 bottom: findInPage.active ? findInPage.top : navigation.top
0228                 bottomMargin: -Math.round(height / 2)
0229                 left: tabs.left
0230                 right: tabs.right
0231             }
0232 
0233             opacity: currentWebView.loading ? 1 : 0
0234             Behavior on opacity { NumberAnimation { duration: Kirigami.Units.longDuration; easing.type: Easing.InOutQuad; } }
0235 
0236             Rectangle {
0237                 color: Kirigami.Theme.highlightColor
0238 
0239                 width: Math.round((currentWebView.loadProgress / 100) * parent.width)
0240                 anchors {
0241                     top: parent.top
0242                     left: parent.left
0243                     bottom: parent.bottom
0244                 }
0245             }
0246         }
0247 
0248         Loader {
0249             id: sheetLoader
0250         }
0251 
0252         // Unload the ShareSheet again after it closed
0253         Connections {
0254             target: sheetLoader.item
0255             function onVisibleChanged() {
0256                 if (!sheetLoader.item.visible) {
0257                     sheetLoader.source = ""
0258                 }
0259             }
0260         }
0261 
0262         UrlObserver {
0263             id: urlObserver
0264             url: currentWebView.url
0265         }
0266 
0267         WebAppCreator {
0268             id: webAppCreator
0269             websiteName: currentWebView.title
0270         }
0271 
0272         // The menu at the bottom right
0273         actions: [
0274             Kirigami.Action {
0275                 icon.name: "edit-find"
0276                 shortcut: "Ctrl+F"
0277                 onTriggered: findInPage.activate()
0278                 text: i18n("Find in page")
0279             },
0280             Kirigami.Action {
0281                 icon.name: "document-share"
0282                 text: i18n("Share page")
0283                 onTriggered: {
0284                     sheetLoader.setSource("ShareSheet.qml")
0285                     sheetLoader.item.url = currentWebView.url
0286                     sheetLoader.item.inputTitle = currentWebView.title
0287                     sheetLoader.item.open()
0288                 }
0289             },
0290             Kirigami.Action {
0291                 id: addHomeScreenAction
0292                 icon.name: "list-add"
0293                 text: i18n("Add to homescreen")
0294                 enabled: !webAppCreator.exists
0295                 onTriggered: {
0296                     webAppCreator.createDesktopFile(currentWebView.title,
0297                                                            currentWebView.url,
0298                                                            currentWebView.icon)
0299                 }
0300             },
0301             Kirigami.Action {
0302                 icon.name: "application-x-object"
0303                 text: i18n("Open in app")
0304                 onTriggered: {
0305                     Qt.openUrlExternally(currentWebView.url)
0306                 }
0307             },
0308             Kirigami.Action {
0309                 enabled: currentWebView.canGoBack
0310                 icon.name: "go-previous"
0311                 text: i18n("Go previous")
0312                 onTriggered: {
0313                     currentWebView.goBack()
0314                 }
0315             },
0316             Kirigami.Action {
0317                 enabled: currentWebView.canGoForward
0318                 icon.name: "go-next"
0319                 text: i18n("Go forward")
0320                 onTriggered: {
0321                     currentWebView.goForward()
0322                 }
0323             },
0324             Kirigami.Action {
0325                 icon.name: currentWebView.loading ? "process-stop" : "view-refresh"
0326                 text: currentWebView.loading ? i18n("Stop loading") : i18n("Refresh")
0327                 onTriggered: {
0328                     currentWebView.loading ? currentWebView.stopLoading() : currentWebView.reload()
0329                 }
0330             },
0331             Kirigami.Action {
0332                 id: bookmarkAction
0333                 checkable: true
0334                 checked: urlObserver.bookmarked
0335                 icon.name: "bookmarks"
0336                 text: checked ? i18n("Bookmarked") : i18n("Bookmark")
0337                 onTriggered: {
0338                     if (checked) {
0339                         var request = {
0340                             url: currentWebView.url,
0341                             title: currentWebView.title,
0342                             icon: currentWebView.icon
0343                         }
0344                         BrowserManager.addBookmark(request);
0345                     } else {
0346                         BrowserManager.removeBookmark(currentWebView.url);
0347                     }
0348                 }
0349             },
0350             Kirigami.Action {
0351                 icon.name: "computer"
0352                 text: i18n("Show desktop site")
0353                 checkable: true
0354                 checked: !currentWebView.userAgent.isMobile
0355                 onTriggered: {
0356                     currentWebView.userAgent.isMobile = !currentWebView.userAgent.isMobile;
0357                 }
0358             },
0359             Kirigami.Action {
0360                 icon.name: currentWebView.readerMode ? "view-readermode-active" : "view-readermode"
0361                 text: i18n("Reader Mode")
0362                 checkable: true
0363                 checked: currentWebView.readerMode
0364                 onTriggered: currentWebView.readerModeSwitch()
0365 
0366             },
0367             Kirigami.Action {
0368                 icon.name: "edit-select-text"
0369                 text: rootPage.navigationAutoShow ? i18n("Hide navigation bar") : i18n("Show navigation bar")
0370                 visible: navigation.visible
0371                 onTriggered: {
0372                     if (!navigation.visible) return;
0373                     rootPage.navigationAutoShow = !rootPage.navigationAutoShow;
0374                 }
0375             },
0376             Kirigami.Action {
0377                 icon.name: "dialog-scripts"
0378                 text: i18n("Show developer tools")
0379                 checkable: true
0380                 checked: tabs.itemAt(tabs.currentIndex).isDeveloperToolsOpen
0381                 onTriggered: {
0382                     tabs.tabsModel.toggleDeveloperTools(tabs.currentIndex)
0383                 }
0384             }
0385         ]
0386 
0387         // Tabs sheet
0388         Loader {
0389             id: tabsSheetLoader
0390             active: false
0391             function open() {
0392                 active = true;
0393                 item.open();
0394             }
0395             sourceComponent: Tabs {}
0396         }
0397 
0398         // Find bar
0399         FindInPageBar {
0400             id: findInPage
0401 
0402             Kirigami.Theme.colorSet: rootPage.privateMode ? Kirigami.Theme.Complementary : Kirigami.Theme.Window
0403 
0404             layer.enabled: active
0405             layer.effect: DropShadow {
0406                 verticalOffset: - 1
0407                 color: Kirigami.Theme.disabledTextColor
0408                 samples: 10
0409                 spread: 0.1
0410                 cached: true // element is static
0411             }
0412         }
0413 
0414         // Bottom navigation bar
0415         Navigation {
0416             id: navigation
0417 
0418             anchors {
0419                 bottom: parent.bottom
0420                 left: parent.left
0421                 right: parent.right
0422             }
0423 
0424             navigationShown: visible && rootPage.navigationAutoShow
0425             visible: webBrowser.visibility !== Window.FullScreen && !findInPage.active
0426 
0427             tabsSheet: tabsSheetLoader
0428             
0429             Kirigami.Theme.colorSet: rootPage.privateMode ? Kirigami.Theme.Complementary : Kirigami.Theme.Window
0430 
0431             layer.enabled: navigation.navigationShown
0432             layer.effect: DropShadow {
0433                 verticalOffset: - 1
0434                 color: Kirigami.Theme.disabledTextColor
0435                 samples: 10
0436                 spread: 0.1
0437                 cached: true // element is static
0438             }
0439 
0440             onActivateUrlEntry: urlEntry.open()
0441         }
0442 
0443         NavigationEntrySheet {
0444             id: urlEntry
0445         }
0446 
0447         HistorySheet {
0448             id: historySheet
0449         }
0450 
0451         // Thin line above navigation or find
0452         Rectangle {
0453             height: webBrowser.borderWidth
0454             color: webBrowser.borderColor
0455             anchors {
0456                 left: parent.left
0457                 bottom: findInPage.active ? findInPage.top : navigation.top
0458                 right: parent.right
0459             }
0460             visible: navigation.navigationShown || findInPage.active
0461         }
0462 
0463         // dealing with hiding and showing navigation bar
0464         property point oldScrollPosition: Qt.point(0, 0)
0465         property bool  pageAlmostReady: !currentWebView.loading || currentWebView.loadProgress > 90
0466 
0467         onPageAlmostReadyChanged: {
0468             if (!rootPage.pageAlmostReady)
0469                 rootPage.navigationAutoShow = true;
0470             else
0471                 rootPage.oldScrollPosition = currentWebView.scrollPosition;
0472         }
0473 
0474         Connections {
0475             target: currentWebView
0476             function onScrollPositionChanged() {
0477                 var delta = 100;
0478                 if (rootPage.navigationAutoShow && rootPage.pageAlmostReady) {
0479                     if (rootPage.oldScrollPosition.y + delta < currentWebView.scrollPosition.y) {
0480                         // hide navbar
0481                         rootPage.oldScrollPosition = currentWebView.scrollPosition;
0482                         rootPage.navigationAutoShow = false;
0483                     } else if (rootPage.oldScrollPosition.y > currentWebView.scrollPosition.y) {
0484                         // navbar open and scrolling up
0485                         rootPage.oldScrollPosition = currentWebView.scrollPosition;
0486                     }
0487                 } else if (!rootPage.navigationAutoShow) {
0488                     if (rootPage.oldScrollPosition.y - delta > currentWebView.scrollPosition.y) {
0489                         // show navbar
0490                         rootPage.oldScrollPosition = currentWebView.scrollPosition;
0491                         rootPage.navigationAutoShow = true;
0492                     } else if (rootPage.oldScrollPosition.y < currentWebView.scrollPosition.y) {
0493                         // navbar closed and scrolling down
0494                         rootPage.oldScrollPosition = currentWebView.scrollPosition;
0495                     }
0496                 }
0497             }
0498         }
0499     }
0500 
0501     Connections {
0502         target: webBrowser.pageStack
0503         function onCurrentIndexChanged() {
0504             // drop all sub pages as soon as the browser window is the
0505             // focussed one
0506             if (webBrowser.pageStack.currentIndex === 0)
0507                 popSubPages();
0508         }
0509     }
0510 
0511     // Store window dimensions
0512     Component.onCompleted: {
0513         rootPage.initialized = true
0514     }
0515 
0516     function popSubPages() {
0517         while (webBrowser.pageStack.depth > 1)
0518             webBrowser.pageStack.pop();
0519     }
0520 }