diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index ff5412af6..75d475824 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -32,7 +32,7 @@ build_clazy_clang_tidy:
- apt-get update
- apt-get install --yes eatmydata
- eatmydata apt-get build-dep --yes --no-install-recommends okular
- - eatmydata apt-get install --yes --no-install-recommends ninja-build clazy clang clang-tidy libkf5crash-dev libkf5purpose-dev libegl-dev jq
+ - eatmydata apt-get install --yes --no-install-recommends ninja-build clazy clang clang-tidy libkf5crash-dev libkf5purpose-dev kirigami2-dev libegl-dev jq
script:
- srcdir=`pwd` && mkdir -p /tmp/okular_build && cd /tmp/okular_build && CC=clang CXX=clazy CXXFLAGS="-Werror -Wno-deprecated-declarations" cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -G Ninja $srcdir && cat compile_commands.json | jq '[.[] | select(.file | contains("'"$srcdir"'"))]' > compile_commands.aux.json && cat compile_commands.aux.json | jq '[.[] | select(.file | contains("/synctex/")| not)]' > compile_commands.json && cp "$srcdir/.clang-tidy" .
diff --git a/CMakeLists.txt b/CMakeLists.txt
index d561384a8..258722df0 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -169,6 +169,11 @@ add_definitions(-DKF_DEPRECATED_WARNINGS_SINCE=0x054400)
include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${PHONON_INCLUDES} core/synctex ${CMAKE_BINARY_DIR}/core)
+if(BUILD_MOBILE AND KF5Kirigami2_VERSION VERSION_LESS "5.85")
+ message(FATAL_ERROR "Disable mobile build. This requires Kirigami 5.85 or greater.")
+ set(BUILD_MOBILE OFF)
+endif()
+
if(BUILD_MOBILE)
add_subdirectory( mobile )
endif()
diff --git a/mobile/app/app.qrc b/mobile/app/app.qrc
index 6cdc30de6..8482b4142 100644
--- a/mobile/app/app.qrc
+++ b/mobile/app/app.qrc
@@ -7,7 +7,8 @@
package/contents/ui/TableOfContents.qml
package/contents/ui/Thumbnails.qml
package/contents/ui/ThumbnailsBase.qml
-package/contents/ui/TreeDelegate.qml
package/contents/ui/PlaceholderMessage.qml
+package/contents/ui/TreeItem.qml
+package/contents/ui/TreeViewDecoration.qml
diff --git a/mobile/app/package/contents/ui/Bookmarks.qml b/mobile/app/package/contents/ui/Bookmarks.qml
index 4a7ac839a..fb272c61f 100644
--- a/mobile/app/package/contents/ui/Bookmarks.qml
+++ b/mobile/app/package/contents/ui/Bookmarks.qml
@@ -5,9 +5,22 @@
*/
import QtQuick 2.1
+import org.kde.kirigami 2.8 as Kirigami
ThumbnailsBase {
+ id: root
+ header: Kirigami.AbstractApplicationHeader {
+ topPadding: Kirigami.Units.largeSpacing
+ bottomPadding: Kirigami.Units.largeSpacing
+ rightPadding: Kirigami.Units.largeSpacing
+ leftPadding: Kirigami.Units.largeSpacing
+ Kirigami.Heading {
+ level: 2
+ text: i18n("Bookmarks")
+ width: parent.width
+ }
+ }
model: documentItem.bookmarkedPages
onPageClicked: {
pageArea.delegate.pageItem.goToBookmark(pageArea.delegate.pageItem.bookmarks[0])
diff --git a/mobile/app/package/contents/ui/OkularDrawer.qml b/mobile/app/package/contents/ui/OkularDrawer.qml
index 461d55c80..4b3a2eb67 100644
--- a/mobile/app/package/contents/ui/OkularDrawer.qml
+++ b/mobile/app/package/contents/ui/OkularDrawer.qml
@@ -6,8 +6,9 @@
import QtQuick 2.1
import QtQuick.Controls 2.5 as QQC2
-import org.kde.kirigami 2.0 as Kirigami
+import org.kde.kirigami 2.15 as Kirigami
import org.kde.okular 2.0 as Okular
+import QtQuick.Layouts 1.15
Kirigami.OverlayDrawer {
@@ -17,20 +18,14 @@ Kirigami.OverlayDrawer {
rightPadding: 0
edge: Qt.application.layoutDirection == Qt.RightToLeft ? Qt.LeftEdge : Qt.RightEdge
- contentItem: Item {
+ contentItem: ColumnLayout {
id: browserFrame
- implicitWidth: Kirigami.Units.gridUnit * 45
- implicitHeight: implicitWidth
- state: "Hidden"
+ spacing: 0
QQC2.StackView {
id: pageStack
- anchors {
- left: parent.left
- top: parent.top
- right: parent.right
- bottom: tabsToolbar.top
- }
+ Layout.fillWidth: true
+ Layout.fillHeight: true
clip: true
}
@@ -43,14 +38,8 @@ Kirigami.OverlayDrawer {
QQC2.ToolBar {
id: tabsToolbar
- height: mainTabBar.height
position: QQC2.ToolBar.Footer
- anchors {
- top: undefined
- bottom: browserFrame.bottom
- left: parent.left
- right: parent.right
- }
+ Layout.fillWidth: true
Component.onCompleted: thumbnailsButton.checked = true;
Item {
width: parent.width
diff --git a/mobile/app/package/contents/ui/TableOfContents.qml b/mobile/app/package/contents/ui/TableOfContents.qml
index 71180dc9d..9a07ecf1a 100644
--- a/mobile/app/package/contents/ui/TableOfContents.qml
+++ b/mobile/app/package/contents/ui/TableOfContents.qml
@@ -7,29 +7,37 @@
import QtQuick 2.1
import QtQuick.Controls 2.2 as QQC2
import QtQuick.Layouts 1.2
-import org.kde.kirigami 2.0 as Kirigami
+import org.kde.kirigami 2.10 as Kirigami
+import org.kde.kitemmodels 1.0
-Kirigami.ScrollablePage {
+ColumnLayout {
id: root
+ Kirigami.AbstractApplicationHeader {
+ topPadding: Kirigami.Units.smallSpacing / 2;
+ bottomPadding: Kirigami.Units.smallSpacing / 2;
+ rightPadding: Kirigami.Units.smallSpacing
+ leftPadding: Kirigami.Units.smallSpacing
- header: QQC2.ToolBar {
- id: toolBarContent
width: root.width
- QQC2.TextField {
+ Kirigami.SearchField {
id: searchField
width: parent.width
- placeholderText: i18n("Search...")
}
}
- ColumnLayout {
- spacing: 0
- Repeater {
- model: VisualDataModel {
- id: tocModel
+ QQC2.ScrollView {
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+ ListView {
+ model: KDescendantsProxyModel {
model: documentItem.tableOfContents
- delegate: TreeDelegate {
- Layout.fillWidth: true
- sourceModel: tocModel
+ expandsByDefault: false
+ }
+
+ delegate: TreeItem {
+ text: model.display
+ onClicked: {
+ documentItem.currentPage = page - 1;
+ contextDrawer.drawerOpen = false;
}
}
}
diff --git a/mobile/app/package/contents/ui/Thumbnails.qml b/mobile/app/package/contents/ui/Thumbnails.qml
index eb5c2eb2d..6904478fe 100644
--- a/mobile/app/package/contents/ui/Thumbnails.qml
+++ b/mobile/app/package/contents/ui/Thumbnails.qml
@@ -5,20 +5,24 @@
*/
import QtQuick 2.1
+import QtQuick.Layouts 1.2
import QtQuick.Controls 2.0 as QQC2
import org.kde.kirigami 2.8 as Kirigami
ThumbnailsBase {
id: root
model: documentItem.matchingPages
- padding: 0
- header: QQC2.ToolBar {
- id: toolBarContent
- padding: 0
- contentItem: Kirigami.SearchField {
+ header: Kirigami.AbstractApplicationHeader {
+ topPadding: Kirigami.Units.smallSpacing / 2;
+ bottomPadding: Kirigami.Units.smallSpacing / 2;
+ rightPadding: Kirigami.Units.smallSpacing
+ leftPadding: Kirigami.Units.smallSpacing
+
+ width: root.width
+ Kirigami.SearchField {
id: searchField
- placeholderText: i18n("Search...")
+ width: parent.width
enabled: documentItem ? documentItem.supportsSearching : false
onTextChanged: {
if (text.length > 2) {
diff --git a/mobile/app/package/contents/ui/ThumbnailsBase.qml b/mobile/app/package/contents/ui/ThumbnailsBase.qml
index 09e10b662..f1b4b8fed 100644
--- a/mobile/app/package/contents/ui/ThumbnailsBase.qml
+++ b/mobile/app/package/contents/ui/ThumbnailsBase.qml
@@ -5,57 +5,74 @@
*/
import QtQuick 2.1
+import QtQuick.Layouts 1.2
import QtQuick.Controls 2.3 as QQC2
import QtGraphicalEffects 1.0
import org.kde.okular 2.0 as Okular
-import org.kde.kirigami 2.5 as Kirigami
+import org.kde.kirigami 2.15 as Kirigami
-Kirigami.ScrollablePage {
+ColumnLayout {
id: root
property alias model: resultsGrid.model
property Item view: resultsGrid
signal pageClicked(int pageNumber)
- contentItem: Kirigami.CardsListView {
- id: resultsGrid
- clip: true
+ property alias header: control.contentItem
- QQC2.Label {
- anchors.centerIn: parent
- visible: model.length == 0
- text: i18n("No results found.")
- }
+ QQC2.Control {
+ id: control
+ Layout.fillWidth: true
+ leftPadding: 0
+ topPadding: 0
+ bottomPadding: 0
+ rightPadding: 0
+ }
- delegate: Kirigami.AbstractCard {
- implicitWidth: root.width
- highlighted: delegateRecycler && delegateRecycler.GridView.isCurrentItem
- showClickFeedback: true
- readonly property real ratio: contentItem.implicitHeight/contentItem.implicitWidth
- implicitHeight: width * ratio
- contentItem: Okular.ThumbnailItem {
- document: documentItem
- pageNumber: modelData
- Rectangle {
- width: childrenRect.width
- height: childrenRect.height
- color: Kirigami.Theme.backgroundColor
- radius: width
- smooth: true
- anchors {
- top: parent.top
- right: parent.right
- }
- QQC2.Label {
- text: modelData + 1
+ QQC2.ScrollView {
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+ QQC2.ScrollBar.horizontal.policy: QQC2.ScrollBar.AlwaysOff
+ Kirigami.CardsListView {
+ id: resultsGrid
+ clip: true
+
+ Kirigami.PlaceholderMessage {
+ anchors.centerIn: parent
+ visible: model.length == 0
+ width: parent.width - Kirigami.largeSpacing * 4
+ text: i18n("No results found.")
+ }
+
+ delegate: Kirigami.AbstractCard {
+ implicitWidth: root.width
+ showClickFeedback: true
+ readonly property real ratio: contentItem.implicitHeight/contentItem.implicitWidth
+ implicitHeight: width * ratio
+ contentItem: Okular.ThumbnailItem {
+ document: documentItem
+ pageNumber: modelData
+ Rectangle {
+ width: childrenRect.width
+ height: childrenRect.height
+ color: Kirigami.Theme.backgroundColor
+ radius: width
+ smooth: true
+ anchors {
+ top: parent.top
+ right: parent.right
+ }
+ QQC2.Label {
+ text: modelData + 1
+ }
}
}
- }
- onClicked: {
- resultsGrid.currentIndex = index
- documentItem.currentPage = modelData
+ onClicked: {
+ resultsGrid.currentIndex = index
+ documentItem.currentPage = modelData
- contextDrawer.drawerOpen = false
- root.pageClicked(modelData)
+ contextDrawer.drawerOpen = false
+ root.pageClicked(modelData)
+ }
}
}
}
diff --git a/mobile/app/package/contents/ui/TreeDelegate.qml b/mobile/app/package/contents/ui/TreeDelegate.qml
deleted file mode 100644
index d06627f54..000000000
--- a/mobile/app/package/contents/ui/TreeDelegate.qml
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- SPDX-FileCopyrightText: 2012 Marco Martin
-
- SPDX-License-Identifier: GPL-2.0-or-later
-*/
-
-import QtQuick 2.1
-import QtQuick.Controls 2.0 as QQC2
-import QtQuick.Layouts 1.2
-import org.kde.kirigami 2.0 as Kirigami
-
-Column {
- id: treeDelegate
- property variant sourceModel
- property int rowIndex: index
- width: parent.width
-
- property bool matches: display.toLowerCase().indexOf(searchField.text.toLowerCase()) !== -1
-
- Kirigami.BasicListItem {
- id: delegateArea
- height: matches ? implicitHeight : 0
- opacity: matches ? 1 : 0
- Behavior on opacity {
- NumberAnimation { duration: 250 }
- }
- Behavior on height {
- NumberAnimation { duration: 250 }
- }
-
- onClicked: {
- documentItem.currentPage = page-1
- contextDrawer.drawerOpen = false
- }
-
- label: display
- highlighted: highlight
- icon: highlight || highlightedParent ? (LayoutMirroring.enabled ? "arrow-left" : "arrow-right") : ""
-
- QQC2.Label {
- text: pageLabel ? pageLabel : page
- verticalAlignment: Text.AlignBottom
- Layout.rightMargin: Kirigami.Units.largeSpacing
- }
- }
- Column {
- id: col
- x: 20
- width: parent.width - 20
- property variant model: childrenModel
- Repeater {
- id: rep
- model: VisualDataModel {
- id: childrenModel
- model: documentItem.tableOfContents
- }
- }
- }
- onParentChanged: {
- if (treeDelegate.parent && treeDelegate.parent.model) {
- sourceModel = treeDelegate.parent.model
- }
-
- childrenModel.rootIndex = sourceModel.modelIndex(index)
-
- if (model.hasModelChildren) {
- childrenModel.delegate = Qt.createComponent("TreeDelegate.qml")
- }
- }
-}
diff --git a/mobile/app/package/contents/ui/TreeItem.qml b/mobile/app/package/contents/ui/TreeItem.qml
new file mode 100644
index 000000000..be946bcc9
--- /dev/null
+++ b/mobile/app/package/contents/ui/TreeItem.qml
@@ -0,0 +1,77 @@
+/*
+ * SPDX-FileCopyrightText: 2020 Marco Martin
+ *
+ * SPDX-License-Identifier: LGPL-2.0-or-later
+ */
+
+import QtQuick 2.12
+import QtQuick.Layouts 1.4
+import QtQuick.Controls 2.14 as QQC2
+import org.kde.kirigami 2.13 as Kirigami
+import org.kde.kitemmodels 1.0
+
+/**
+ * An item delegate for the TreeListView and TreeTableView components.
+ *
+ * It has the tree expander decoration but no content otherwise,
+ * which has to be set as contentItem
+ *
+ */
+QQC2.ItemDelegate {
+ id: listItem
+
+ property alias decoration: decoration
+
+ width: ListView.view.width
+
+ data: [
+ TreeViewDecoration {
+ id: decoration
+ anchors {
+ left: parent.left
+ top:parent.top
+ bottom: parent.bottom
+ leftMargin: listItem.padding
+ }
+ parent: listItem
+ parentDelegate: listItem
+ model: listItem.ListView.view ? listItem.ListView.view.model :null
+ }
+ ]
+
+ Keys.onLeftPressed: if (kDescendantExpandable && kDescendantExpanded) {
+ decoration.model.collapseChildren(index);
+ } else if (!kDescendantExpandable && kDescendantLevel > 0) {
+ if (listItem.ListView.view) {
+ const sourceIndex = decoration.model.mapToSource(decoration.model.index(index, 0));
+ const newIndex = decoration.model.mapFromSource(sourceIndex.parent);
+ listItem.listItem.ListView.view.currentIndex = newIndex.row;
+ }
+ }
+
+ Keys.onRightPressed: if (kDescendantExpandable) {
+ if (kDescendantExpanded && listItem.ListView.view) {
+ ListView.view.incrementCurrentIndex();
+ } else {
+ decoration.model.expandChildren(index);
+ }
+ }
+
+ onDoubleClicked: if (kDescendantExpandable) {
+ decoration.model.toggleChildren(index);
+ }
+
+ contentItem: Kirigami.Heading {
+ wrapMode: Text.Wrap
+ text: listItem.text
+ level: 5
+ width: listItem.ListView.view.width - (decoration.width + listItem.padding * 3 + Kirigami.Units.smallSpacing)
+ }
+
+ leftInset: Qt.application.layoutDirection !== Qt.RightToLeft ? decoration.width + listItem.padding * 2 : 0
+ leftPadding: Qt.application.layoutDirection !== Qt.RightToLeft ? decoration.width + listItem.padding * 2 : 0
+
+ rightPadding: Qt.application.layoutDirection === Qt.RightToLeft ? decoration.width + listItem.padding * 2 : 0
+ rightInset: Qt.application.layoutDirection === Qt.RightToLeft ? decoration.width + listItem.padding * 2 : 0
+}
+
diff --git a/mobile/app/package/contents/ui/TreeViewDecoration.qml b/mobile/app/package/contents/ui/TreeViewDecoration.qml
new file mode 100644
index 000000000..413844d96
--- /dev/null
+++ b/mobile/app/package/contents/ui/TreeViewDecoration.qml
@@ -0,0 +1,113 @@
+/*
+ * SPDX-FileCopyrightText: 2020 Marco Martin
+ *
+ * SPDX-License-Identifier: LGPL-2.0-or-later
+ */
+
+import QtQuick 2.6
+import QtQuick.Layouts 1.4
+import QtQuick.Controls 2.2 as QQC2
+import QtQuick.Templates 2.2 as T
+import org.kde.kitemmodels 1.0
+import org.kde.kirigami 2.14 as Kirigami
+
+/**
+ * The tree expander decorator for item views.
+ *
+ * It will have a "> v" expander button graphics, and will have indentation on the left
+ * depending on the level of the tree the item is in
+ */
+RowLayout {
+ id: decorationLayout
+ /**
+ * The delegate this decoration will live in.
+ * It needs to be assigned explicitly by the developer.
+ */
+ property T.ItemDelegate parentDelegate
+
+ /**
+ * The KDescendantsProxyModel the view is showing.
+ * It needs to be assigned explicitly by the developer.
+ */
+ property KDescendantsProxyModel model
+
+ property color decorationHighlightColor
+
+ Layout.topMargin: -parentDelegate.topPadding
+ Layout.bottomMargin: -parentDelegate.bottomPadding
+ Repeater {
+ model: kDescendantLevel-1
+ delegate: Item {
+ Layout.preferredWidth: controlRoot.width
+ Layout.fillHeight: true
+
+ Rectangle {
+ anchors {
+ horizontalCenter: parent.horizontalCenter
+ top: parent.top
+ bottom: parent.bottom
+ }
+ visible: kDescendantHasSiblings[modelData]
+ color: Kirigami.Theme.textColor
+ opacity: 0.5
+ width: 1
+ }
+ }
+ }
+ T.Button {
+ id: controlRoot
+ Layout.preferredWidth: Kirigami.Units.gridUnit
+ Layout.fillHeight: true
+ enabled: kDescendantExpandable
+ hoverEnabled: enabled
+ onClicked: model.toggleChildren(index)
+ contentItem: Item {
+ id: styleitem
+ implicitWidth: Kirigami.Units.gridUnit
+ Rectangle {
+ anchors {
+ horizontalCenter: parent.horizontalCenter
+ top: parent.top
+ bottom: expander.visible ? expander.top : parent.verticalCenter
+ }
+ color: Kirigami.Theme.textColor
+ opacity: 0.5
+ width: 1
+ }
+ Kirigami.Icon {
+ id: expander
+ anchors.centerIn: parent
+ width: Kirigami.Units.iconSizes.small
+ height: width
+ source: kDescendantExpanded ? "go-down-symbolic" : (Qt.application.layoutDirection == Qt.RightToLeft ? "go-previous-symbolic" : "go-next-symbolic")
+ isMask: true
+ color: controlRoot.hovered ? decorationLayout.decorationHighlightColor ? decorationLayout.decorationHighlightColor :
+ Kirigami.Theme.highlightColor : Kirigami.Theme.textColor
+ Behavior on color { ColorAnimation { duration: Kirigami.Units.shortDuration; easing.type: Easing.InOutQuad } }
+ visible: kDescendantExpandable
+ }
+ Rectangle {
+ anchors {
+ horizontalCenter: parent.horizontalCenter
+ top: expander.visible ? expander.bottom : parent.verticalCenter
+ bottom: parent.bottom
+ }
+ visible: kDescendantHasSiblings[kDescendantHasSiblings.length - 1]
+ color: Kirigami.Theme.textColor
+ opacity: 0.5
+ width: 1
+ }
+ Rectangle {
+ anchors {
+ verticalCenter: parent.verticalCenter
+ left: expander.visible ? expander.right : parent.horizontalCenter
+ right: parent.right
+ }
+ color: Kirigami.Theme.textColor
+ opacity: 0.5
+ height: 1
+ }
+ }
+ background: Item {}
+ }
+}
diff --git a/mobile/app/package/contents/ui/main.qml b/mobile/app/package/contents/ui/main.qml
index 298afe63e..47aaf93f5 100644
--- a/mobile/app/package/contents/ui/main.qml
+++ b/mobile/app/package/contents/ui/main.qml
@@ -51,9 +51,11 @@ Kirigami.ApplicationWindow {
]
}
contextDrawer: OkularDrawer {
+ width: columnWidth
contentItem.implicitWidth: columnWidth
modal: !fileBrowserRoot.wideScreen
onModalChanged: drawerOpen = !modal
+ onEnabledChanged: drawerOpen = enabled && !modal
enabled: documentItem.opened && pageStack.layers.depth < 2
handleVisible: enabled && pageStack.layers.depth < 2
}