← Back to team overview

ubuntu-touch-coreapps-reviewers team mailing list archive

[Merge] lp:~verzegnassi-stefano/ubuntu-docviewer-app/uitk13-documents-page into lp:ubuntu-docviewer-app

 

Stefano Verzegnassi has proposed merging lp:~verzegnassi-stefano/ubuntu-docviewer-app/uitk13-documents-page into lp:ubuntu-docviewer-app.

Commit message:
* Use PageHeader and ScrollView in documents page

* Removed width limitation of units.gu(80) from documents page

* Code refactoring

* Use a 'Label' instead of the SD card icon.
Sure, it's a bit ugly but it has no alignment issue. In any case, we should replace the current documents view soon.

* Fixed a few typos in the pickMode header (i.e. we were pushing the wrong file through content-hub)

* UI changes to headers:
--- Search header: use search header style recently introduced in unity8-dash
--- Pick mode header: use textual buttons


Requested reviews:
  Jenkins Bot (ubuntu-core-apps-jenkins-bot): continuous-integration
  Ubuntu Document Viewer Developers (ubuntu-docviewer-dev)
Related bugs:
  Bug #1523114 in Ubuntu Document Viewer App: "[DocumentsPage] SD card icon not aligned in ListItemLayout"
  https://bugs.launchpad.net/ubuntu-docviewer-app/+bug/1523114

For more details, see:
https://code.launchpad.net/~verzegnassi-stefano/ubuntu-docviewer-app/uitk13-documents-page/+merge/290170

* Use PageHeader and ScrollView in documents page

* Removed width limitation of units.gu(80) from documents page

* Code refactoring

* Use a 'Label' instead of the SD card icon.
Sure, it's a bit ugly but it has no alignment issue. In any case, we should replace the current documents view soon.

* Fixed a few typos in the pickMode header (i.e. we were pushing the wrong file through content-hub)

* UI changes to headers:
--- Search header: use search header style recently introduced in unity8-dash
--- Pick mode header: use textual buttons


-- 
Your team Ubuntu Document Viewer Developers is requested to review the proposed merge of lp:~verzegnassi-stefano/ubuntu-docviewer-app/uitk13-documents-page into lp:ubuntu-docviewer-app.
=== modified file 'src/app/qml/documentPage/DeleteFileDialog.qml'
--- src/app/qml/documentPage/DeleteFileDialog.qml	2015-10-23 11:19:19 +0000
+++ src/app/qml/documentPage/DeleteFileDialog.qml	2016-03-26 18:25:35 +0000
@@ -1,17 +1,17 @@
 /*
-  Copyright (C) 2013-2015 Stefano Verzegnassi
+  Copyright (C) 2013-2016 Stefano Verzegnassi
 
-    This program is free software: you can redistribute it and/or modify
+  This program is free software: you can redistribute it and/or modify
   it under the terms of the GNU General Public License 3 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,
+  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
+  You should have received a copy of the GNU General Public License
   along with this program. If not, see http://www.gnu.org/licenses/.
 */
 
@@ -24,7 +24,7 @@
     id: deleteFileDialog
 
     property string path
-    property var selectedIndices: viewLoader.item.ViewItems.selectedIndices;
+    property var selectedIndices: view.ViewItems.selectedIndices
     property int deleteCount: selectedIndices.length
 
     // WORKAROUND: This property is only used when the dialog is opened from a
@@ -73,7 +73,7 @@
                         docModel.rm(folderModel.get(selectedIndices[i]).path);
                     }
 
-                    viewLoader.item.cancelSelection();
+                    view.cancelSelection();
                 }
 
                 PopupUtils.close(deleteFileDialog)

=== modified file 'src/app/qml/documentPage/DocumentListDelegate.qml'
--- src/app/qml/documentPage/DocumentListDelegate.qml	2015-12-29 17:13:25 +0000
+++ src/app/qml/documentPage/DocumentListDelegate.qml	2016-03-26 18:25:35 +0000
@@ -74,14 +74,15 @@
                    + listItemLayout.title.baselineOffset - baselineOffset
             }
 
-            Icon {
+            Label {
                 id: externalStorageLabel
-                anchors.right: parent.right
-                width: units.gu(2); height: width
-                name: "sdcard-symbolic"
+                text: i18n.tr("SD card")
+                textSize: Label.Small
+                color:  theme.palette.normal.backgroundSecondaryText
                 visible: model.isFromExternalStorage
                 y: listItemLayout.mainSlot.y + listItemLayout.subtitle.y
                    + listItemLayout.subtitle.baselineOffset - baselineOffset
+                anchors.right: parent.right
             }
         }
     }

=== modified file 'src/app/qml/documentPage/DocumentListView.qml'
--- src/app/qml/documentPage/DocumentListView.qml	2016-02-10 17:46:14 +0000
+++ src/app/qml/documentPage/DocumentListView.qml	2016-03-26 18:25:35 +0000
@@ -1,16 +1,16 @@
 /*
-  Copyright (C) 2015 Stefano Verzegnassi
+  Copyright (C) 2015, 2016 Stefano Verzegnassi
 
-    This program is free software: you can redistribute it and/or modify
+  This program is free software: you can redistribute it and/or modify
   it under the terms of the GNU General Public License 3 as published by
   the Free Software Foundation.
 
-    This program is distributed in the hope that it will be useful,
+  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
+  You should have received a copy of the GNU General Public License
   along with this program. If not, see http://www.gnu.org/licenses/.
 */
 
@@ -92,11 +92,6 @@
         }
     }
 
-    Scrollbar {
-        flickableItem: documentListView
-        parent: documentListView.parent
-    }
-
     Connections {
         target: sortSettings
         onSortModeChanged: documentListView.positionViewAtBeginning()

=== modified file 'src/app/qml/documentPage/DocumentPage.qml'
--- src/app/qml/documentPage/DocumentPage.qml	2015-10-29 14:25:18 +0000
+++ src/app/qml/documentPage/DocumentPage.qml	2016-03-26 18:25:35 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2015 Canonical, Ltd.
+ * Copyright (C) 2015, 2016 Canonical, Ltd.
  *
  * 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
@@ -20,12 +20,11 @@
 
 Page {
     id: documentPage
-    title: i18n.tr("Documents")
-    flickable: null
 
-    property bool useGridView: false
     property bool searchMode: false
-    property alias view: viewLoader
+    property alias view: view
+
+    header: defaultHeader
 
     onActiveChanged: {
         // When the page become visible, check if any new volume has been
@@ -34,66 +33,57 @@
             docModel.checkDefaultDirectories();
     }
 
-    Settings {
-        property alias useGridView: documentPage.useGridView
+    ScrollView {
+        id: scrollView
+        anchors.fill: parent
+        anchors.topMargin: documentPage.header.height
+
+        DocumentListView {
+            id: view
+            anchors.fill: parent
+        }
     }
 
     Loader {
-        id: viewLoader
-
-        width: Math.min(units.gu(80), parent.width)
-        anchors {
-            top: parent.top
-            bottom: parent.bottom
-            horizontalCenter: parent.horizontalCenter
-        }
-
-        source: {
-            if (folderModel.count === 0) {
-                return documentPage.state == "search"
-                        ? Qt.resolvedUrl("SearchEmptyState.qml")
-                        : Qt.resolvedUrl("DocumentEmptyState.qml")
-            }
-
-            return Qt.resolvedUrl("DocumentListView.qml")
-        }
-    }
-
-    // *** HEADER ***
-    states: [
-        DocumentPageDefaultHeader {
-            name: "default"
-            targetPage: documentPage
-            when: !mainView.pickMode && !viewLoader.item.ViewItems.selectMode && !documentPage.searchMode
-        },
-
-        DocumentPagePickModeHeader {
-            name: "pickMode"
-            targetPage: documentPage
-            when: mainView.pickMode
-        },
-
-        DocumentPageSelectionModeHeader {
-            name: "selection"
-            targetPage: documentPage
-            when: !mainView.pickMode && viewLoader.item.ViewItems.selectMode
-        },
-
-        DocumentPageSearchHeader {
-            name: "search"
-            targetPage: documentPage
-            when: !mainView.pickMode && !viewLoader.item.ViewItems.selectMode && documentPage.searchMode
-        }
-    ]
+        id: emptyStateLoader
+        anchors.fill: parent
+        active: folderModel.count == 0
+        source: documentPage.searchMode
+                ? Qt.resolvedUrl("SearchEmptyState.qml")
+                : Qt.resolvedUrl("DocumentEmptyState.qml")
+    }
+
+
+    /*** Headers ***/
+
+    DocumentPageDefaultHeader {
+        id: defaultHeader
+        visible: !mainView.pickMode && !view.ViewItems.selectMode && !documentPage.searchMode
+    }
+
+    DocumentPagePickModeHeader {
+        id: pickModeHeader
+        visible: mainView.pickMode
+    }
+
+    DocumentPageSearchHeader {
+        id: searchHeader
+        visible: !mainView.pickMode && !view.ViewItems.selectMode && documentPage.searchMode
+    }
+
+    DocumentPageSelectionModeHeader {
+        id: selectionHeader
+        visible: !mainView.pickMode && view.ViewItems.selectMode
+    }
 
     Connections {
         target: mainView
 
         onPickModeChanged: {
             if (mainView.pickMode) {
-                viewLoader.item.startSelection()
+                view.startSelection()
             } else {
-                viewLoader.item.cancelSelection()
+                view.cancelSelection()
             }
 
             // Reset any previous search

=== modified file 'src/app/qml/documentPage/DocumentPageDefaultHeader.qml'
--- src/app/qml/documentPage/DocumentPageDefaultHeader.qml	2015-10-23 11:19:19 +0000
+++ src/app/qml/documentPage/DocumentPageDefaultHeader.qml	2016-03-26 18:25:35 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2014-2015 Canonical, Ltd.
+ * Copyright (C) 2014-2016 Canonical, Ltd.
  *
  * 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
@@ -18,17 +18,23 @@
 import Ubuntu.Components 1.3
 import Ubuntu.Components.Popups 1.3
 
-PageHeadState {
-    id: rootItem
-
-    property Page targetPage
-    head: targetPage.head
-
-    actions: [
+PageHeader {
+    id: defaultHeader
+
+    property var view: parent.view
+    property Page parentPage: parent
+
+    title: i18n.tr("Documents")
+   // flickable: view
+
+    // FIXME: Why need this?!
+    leadingActionBar.actions: null
+
+    trailingActionBar.actions: [
         Action {
             text: i18n.tr("Search...")
             iconName: "search"
-            onTriggered: targetPage.searchMode = true
+            onTriggered: parentPage.searchMode = true
             visible: folderModel.count !== 0
         },
 
@@ -38,14 +44,5 @@
             onTriggered: PopupUtils.open(Qt.resolvedUrl("SortSettingsDialog.qml"))
             visible: folderModel.count !== 0
         }
-
-        /*
-        Action {
-            text: targetPage.useGridView ? i18n.tr("Switch to single column list") : i18n.tr("Switch to grid")
-            iconName: targetPage.useGridView ? "view-list-symbolic" : "view-grid-symbolic"
-            onTriggered: targetPage.useGridView = !targetPage.useGridView
-            visible: folderModel.count !== 0
-        }
-        */
     ]
 }

=== modified file 'src/app/qml/documentPage/DocumentPagePickModeHeader.qml'
--- src/app/qml/documentPage/DocumentPagePickModeHeader.qml	2016-02-12 13:00:37 +0000
+++ src/app/qml/documentPage/DocumentPagePickModeHeader.qml	2016-03-26 18:25:35 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2014-2015 Canonical, Ltd.
+ * Copyright (C) 2014-2016 Canonical, Ltd.
  *
  * 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
@@ -18,55 +18,58 @@
 import Ubuntu.Components 1.3
 import Ubuntu.Content 1.1
 
-PageHeadState {
-    id: rootItem
-
-    property Page targetPage
-    head: targetPage.head
-
-    backAction: Action {
-        text: i18n.tr("Cancel")
-        objectName: "cancelButton"
-        iconName: "close"
-        onTriggered: {
-            if (!contentHubProxy.activeExportTransfer)
-                return
-
-            contentHubProxy.activeExportTransfer.items = []
-            contentHubProxy.activeExportTransfer.state = ContentTransfer.Aborted
-
-            mainView.switchToBrowseMode()
+PageHeader {
+    id: pickModeHeader
+
+    property var view: parent.view
+    property Page parentPage: parent
+
+    leadingActionBar {
+        anchors.leftMargin: 0
+        delegate: textualButton
+
+        actions: Action {
+            text: i18n.tr("Cancel")
+            objectName: "cancelButton"
+            iconName: "close"
+            onTriggered: {
+                if (!contentHubProxy.activeExportTransfer) {
+                    console.log("[content-hub] No active transfer.")
+                } else {
+                    contentHubProxy.activeExportTransfer.items = []
+                    contentHubProxy.activeExportTransfer.state = ContentTransfer.Aborted
+                }
+
+                mainView.switchToBrowseMode()
+            }
         }
     }
 
-    actions: [
-        Action {
-            text: targetPage.useGridView ? i18n.tr("Switch to single column list") : i18n.tr("Switch to grid")
-            iconName: targetPage.useGridView ? "view-list-symbolic" : "view-grid-symbolic"
-            onTriggered: targetPage.useGridView = !targetPage.useGridView
-
-            visible: folderModel.count !== 0
-        },
-
-        Action {
+    trailingActionBar {
+        anchors.rightMargin: 0
+        delegate: textualButton
+
+        actions: Action {
             text: i18n.tr("Pick")
             objectName: "pickButton"
-            enabled: viewLoader.item.ViewItems.selectedIndices.length > 0
+            enabled: view.ViewItems.selectedIndices.length > 0
             iconName: "ok"
             onTriggered: {
-                if (!enabled || !contentHubProxy.activeExportTransfer)
+                if (!enabled || !contentHubProxy.activeExportTransfer) {
+                    console.log("[content-hub] No active transfer.")
                     return;
+                }
 
                 var contentList = []
-                var indices = viewLoader.item.ViewItems.selectedIndices
+                var indices = view.ViewItems.selectedIndices
 
                 console.log("[content-hub] Following files will be exported:")
 
                 for (var i=0; i < indices.length; i++) {
-                    var filePath = "file://" + folderModel.get(i).path
+                    var filePath = "file://" + folderModel.get(indices[i]).path
                     console.log(filePath)
 
-                    contentList.push(contentItem.createObject(rootItem, { "url": filePath }))
+                    contentList.push(contentItem.createObject(pickModeHeader, { "url": filePath }))
                 }
 
                 contentHubProxy.activeExportTransfer.items = contentList
@@ -75,8 +78,38 @@
                 mainView.switchToBrowseMode()
             }
         }
-    ]
-
-    property Component contentItem: Component { ContentItem {} }
+    }
+
+    Component {
+        id: textualButton
+        AbstractButton {
+            id: button
+            action: modelData
+            width: label.width + units.gu(4)
+            height: parent.height
+            Rectangle {
+                color: UbuntuColors.slate
+                opacity: 0.1
+                anchors.fill: parent
+                visible: button.pressed
+            }
+            Label {
+                anchors.centerIn: parent
+                id: label
+                text: action.text
+                font.weight: text === i18n.tr("Pick") ? Font.Normal : Font.Light
+                color: {
+                    if (button.enabled)
+                        return text === i18n.tr("Pick") ? theme.palette.selected.backgroundText : theme.palette.normal.backgroundText
+
+                    return theme.palette.disabled.backgroundText
+                }
+            }
+        }
+    }
+
+    Component {
+        id: contentItem
+        ContentItem {}
+    }
 }
-

=== modified file 'src/app/qml/documentPage/DocumentPageSearchHeader.qml'
--- src/app/qml/documentPage/DocumentPageSearchHeader.qml	2015-10-19 13:00:11 +0000
+++ src/app/qml/documentPage/DocumentPageSearchHeader.qml	2016-03-26 18:25:35 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2014-2015 Canonical, Ltd.
+ * Copyright (C) 2014-2016 Canonical, Ltd.
  *
  * 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
@@ -17,30 +17,37 @@
 import QtQuick 2.4
 import Ubuntu.Components 1.3
 
-PageHeadState {
-    id: rootItem
-
-    property Page targetPage
-    head: targetPage.head
-
-    backAction: Action {
-        text: i18n.tr("Back")
-        iconName: "back"
-
-        onTriggered: {
-            // Clear the search
-            searchField.text = ""
-            targetPage.searchMode = false
+PageHeader {
+    id: searchHeader
+
+    property var view: parent.view
+    property Page parentPage: parent
+
+    trailingActionBar {
+        anchors.rightMargin: 0
+        delegate: textualButton
+
+        actions: Action {
+            text: i18n.tr("Cancel")
+
+            onTriggered: {
+                // Clear the search
+                searchField.text = ""
+                parentPage.searchMode = false
+            }
         }
     }
 
     contents: TextField {
         id: searchField
-        width: parent.width - units.gu(4)
+        anchors {
+            left: parent.left
+            right: parent.right
+            verticalCenter: parent.verticalCenter
+        }
 
         primaryItem: Icon {
-            height: parent.height - units.gu(2)
-            width: height
+            height: units.gu(2); width: height
             name: "search"
         }
 
@@ -54,4 +61,33 @@
         // show OSK if appropriate.
         onVisibleChanged: forceActiveFocus()
     }
+
+    Component {
+        id: textualButton
+        AbstractButton {
+            id: button
+            action: modelData
+            width: label.width + units.gu(4)
+            height: parent.height
+            Rectangle {
+                color: UbuntuColors.slate
+                opacity: 0.1
+                anchors.fill: parent
+                visible: button.pressed
+            }
+            Label {
+                anchors.centerIn: parent
+                id: label
+                text: action.text
+                font.weight: text === i18n.tr("Pick") ? Font.Normal : Font.Light
+                color: {
+                    if (button.enabled)
+                        return text === i18n.tr("Pick") ? theme.palette.selected.backgroundText : theme.palette.normal.backgroundText
+
+                    return theme.palette.disabled.backgroundText
+                }
+            }
+        }
+    }
+
 }

=== modified file 'src/app/qml/documentPage/DocumentPageSelectionModeHeader.qml'
--- src/app/qml/documentPage/DocumentPageSelectionModeHeader.qml	2015-11-01 16:50:23 +0000
+++ src/app/qml/documentPage/DocumentPageSelectionModeHeader.qml	2016-03-26 18:25:35 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2014-2015 Canonical, Ltd.
+ * Copyright (C) 2014-2016 Canonical, Ltd.
  *
  * 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
@@ -18,55 +18,77 @@
 import Ubuntu.Components 1.3
 import Ubuntu.Components.Popups 1.3
 
-PageHeadState {
-    id: rootItem
-
-    property Page targetPage
-    head: targetPage.head
-
-    property bool selectedAll: viewLoader.item.ViewItems.selectedIndices.length == viewLoader.item.count
-
-    backAction: Action {
+PageHeader {
+    id: selectionHeader
+
+    property var view: parent.view
+    property Page parentPage: parent
+
+    property bool selectedAll: view.ViewItems.selectedIndices.length == view.count
+
+    leadingActionBar.actions: Action {
         iconName: "close"
         text: i18n.tr("Close")
         onTriggered: {
-            viewLoader.item.cancelSelection()
-        }
-    }
-
-    actions: [
-        Action {
-            iconName: selectedAll ? "select-none" :  "select"
-            text: selectedAll ? i18n.tr("Select None") : i18n.tr("Select All")
-
-            onTriggered: {
-                if (selectedAll) {
-                    viewLoader.item.clearSelection()
-                } else {
-                    viewLoader.item.selectAll()
-                }
-            }
-        },
-
-        Action {
-            iconName: "delete"
-            text: i18n.tr("Delete")
-            enabled: viewLoader.item.ViewItems.selectedIndices.length !== 0
-
-            onTriggered: PopupUtils.open(Qt.resolvedUrl("DeleteFileDialog.qml"), documentPage)
-        }
-    ]
-
-    // WORKAROUND: "preset" property of PageHeadConfiguration is still not
-    // exposed in PageHeadState.
-    contents: Item {
-        Connections {
-            target: targetPage
-            onStateChanged: {
-                if (targetPage.state === "selection")
-                    head.preset = "select"
-                else
-                    head.preset = ""
+            view.cancelSelection()
+        }
+    }
+
+    trailingActionBar {
+        anchors.rightMargin: 0
+        delegate: textualButtonWithIcon
+
+        actions: [
+            Action {
+                iconName: selectedAll ? "select-none" :  "select"
+                text: selectedAll ? i18n.tr("Select None") : i18n.tr("Select All")
+
+                onTriggered: {
+                    if (selectedAll)
+                        view.clearSelection()
+                    else
+                        view.selectAll()
+                }
+            },
+
+            Action {
+                iconName: "delete"
+                text: i18n.tr("Delete")
+                enabled: view.ViewItems.selectedIndices.length !== 0
+
+                onTriggered: PopupUtils.open(Qt.resolvedUrl("DeleteFileDialog.qml"), documentPage)
+            }
+        ]
+    }
+
+    Component {
+        id: textualButtonWithIcon
+        AbstractButton {
+            id: button
+            action: modelData
+            width: layout.width + units.gu(4)
+            height: parent.height
+            Rectangle {
+                color: UbuntuColors.slate
+                opacity: 0.1
+                anchors.fill: parent
+                visible: button.pressed
+            }
+            Row {
+                id: layout
+                anchors.centerIn: parent
+                spacing: units.gu(1)
+                Icon {
+                    anchors.verticalCenter: parent.verticalCenter
+                    width: units.gu(2); height: width
+                    name: action.iconName
+                    source: action.iconSource
+                }
+                Label {
+                    anchors.verticalCenter: parent.verticalCenter
+                    text: action.text
+                    font.weight: text === i18n.tr("Pick") ? Font.Normal : Font.Light
+                }
             }
         }
     }

=== modified file 'src/app/qml/documentPage/SharePage.qml'
--- src/app/qml/documentPage/SharePage.qml	2015-10-23 14:10:47 +0000
+++ src/app/qml/documentPage/SharePage.qml	2016-03-26 18:25:35 +0000
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 2015 Stefano Verzegnassi
+  Copyright (C) 2015, 2016 Stefano Verzegnassi
 
   This program is free software: you can redistribute it and/or modify
   it under the terms of the GNU General Public License 3 as published by
@@ -16,15 +16,18 @@
 
 import QtQuick 2.4
 import Ubuntu.Components 1.3
-import Ubuntu.Content 1.1
+import Ubuntu.Content 1.3
 
 Page {
     id: sharePage
-    title: i18n.tr("Share to")
 
     property url fileUrl
     property var activeTransfer
 
+    header: PageHeader {
+        title: i18n.tr("Share to")
+    }
+
     ContentPeerPicker {
         id: picker