on xenial help sign in
Implement the Expandable Preview Widget
2756788Albert Astals
debian/control+1−1
@@ -23,7 +23,7 @@ Build-Depends: cmake,
23 libpulse-dev,
23 libpulse-dev,
24 libqmenumodel-dev (>= 0.2.8),
24 libqmenumodel-dev (>= 0.2.8),
25 libqt5xmlpatterns5-dev,
25 libqt5xmlpatterns5-dev,
26− libunity-api-dev (>= 7.85),
26+ libunity-api-dev (>= 7.87),
27 libunity-mir-dev,
27 libunity-mir-dev,
28 libusermetricsoutput1-dev,
28 libusermetricsoutput1-dev,
29 libxcb1-dev,
29 libxcb1-dev,
qml/Components/SeeMore.qmldeleted−70
@@ -1,70 +0,0 @@
1−/*
2− * Copyright (C) 2014 Canonical, Ltd.
3− *
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU General Public License as published by
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU General Public License for more details.
12− *
13− * You should have received a copy of the GNU General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− */
16−
17−import QtQuick 2.0
18−import Ubuntu.Components 0.1
19−
20−/*! Widget that can be used in combination with a text area to allow easy 'expand/collapse' functionality. */
21−
22−Item {
23− //! Boolean set to true when it suggests expanded functionality
24− property bool more: false
25−
26− implicitHeight: seeMoreLabel.height + units.gu(2)
27−
28− Row {
29− anchors.centerIn: parent
30− spacing: units.gu(2)
31−
32− Label {
33− id: seeMoreLabel
34− objectName: "seeMoreLabel"
35− text: i18n.tr("See more")
36− opacity: !more ? 0.8 : 0.4
37− // TODO: Fix requiring Palette update
38− color: "grey" //Theme.palette.selected.backgroundText
39− font.weight: Font.Bold
40−
41− MouseArea {
42− anchors.fill: parent
43− onClicked: more = true
44− }
45− }
46−
47− Image {
48− anchors {
49− top: parent.top
50− bottom: parent.bottom
51− }
52− width: units.dp(2)
53− source: "ListItems/graphics/ListItemDividerVertical.png"
54− }
55−
56− Label {
57− objectName: "seeLessLabel"
58− text: i18n.tr("See less")
59− opacity: more ? 0.8 : 0.4
60− // TODO: Fix requiring Palette update
61− color: "grey" //Theme.palette.selected.backgroundText
62− font.weight: Font.Bold
63−
64− MouseArea {
65− anchors.fill: parent
66− onClicked: more = false
67− }
68− }
69− }
70−}
qml/Dash/Previews/PreviewExpandable.qmlnew file+106
@@ -0,0 +1,106 @@
1+/*
2+ * Copyright (C) 2014 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+import QtQuick 2.0
18+import Ubuntu.Components 0.1
19+import "../../Components"
20+
21+/*! \brief Preview widget for expandable widgets.
22+
23+ This widget shows a list of widgets defined in widgetData["widgets"]
24+ Those widgets can be collapsed or uncollapsed. When uncollapsed
25+ all the widgets are shown, when collapsed only the first
26+ widgetData["collapsed-widgets"] are shown. It has a title that comes
27+ in via widgetData["title"]
28+ */
29+
30+PreviewWidget {
31+ id: root
32+ implicitHeight: childrenRect.height
33+
34+ expanded: false
35+
36+ Label {
37+ id: titleLabel
38+ objectName: "titleLabel"
39+ anchors {
40+ left: parent.left
41+ right: expandButton.left
42+ }
43+ fontSize: "large"
44+ color: root.scopeStyle ? root.scopeStyle.foreground : "grey"
45+ visible: text !== ""
46+ opacity: .8
47+ text: widgetData["title"] || ""
48+ wrapMode: Text.Wrap
49+ }
50+
51+ AbstractButton {
52+ id: expandButton
53+ objectName: "expandButton"
54+ width: titleLabel.height
55+ height: titleLabel.height
56+ anchors.right: parent.right
57+ onClicked: {
58+ root.expanded = !root.expanded;
59+ }
60+ // TODO Remove when "view-collapse" : "view-expand" are there
61+ Rectangle {
62+ anchors.fill: parent
63+ color: root.expanded ? "red" : "green"
64+ }
65+ Icon {
66+ anchors.fill: parent
67+ width: 64
68+ height: 64
69+ name: root.expanded ? "view-collapse" : "view-expand"
70+ }
71+ }
72+
73+ Column {
74+ anchors {
75+ top: titleLabel.bottom
76+ topMargin: units.gu(1)
77+ left: parent.left
78+ right: parent.right
79+ }
80+ spacing: units.gu(1)
81+ Repeater {
82+ id: repeater
83+ objectName: "repeater"
84+ model: widgetData["widgets"]
85+ delegate: PreviewWidgetFactory {
86+ height: visible ? implicitHeight : 0
87+ width: parent.width
88+ widgetId: modelData.widgetId
89+ widgetType: modelData.type
90+ widgetData: modelData.properties
91+ isCurrentPreview: root.isCurrentPreview
92+ scopeStyle: root.scopeStyle
93+ anchors {
94+ left: parent.left
95+ right: parent.right
96+ }
97+ expanded: root.expanded
98+ visible: root.expanded || index < root.widgetData["collapsed-widgets"]
99+
100+ onTriggered: {
101+ root.triggered(widgetId, actionId, data);
102+ }
103+ }
104+ }
105+ }
106+}
qml/Dash/Previews/PreviewTextSummary.qml+2−15
@@ -50,14 +50,14 @@ PreviewWidget {
50 id: textLabel
50 id: textLabel
51 objectName: "textLabel"
51 objectName: "textLabel"
52
52
53− readonly property int maximumCollapsedLineCount: 7
53+ readonly property int maximumCollapsedLineCount: 3
54
54
55 anchors {
55 anchors {
56 left: parent.left
56 left: parent.left
57 right: parent.right
57 right: parent.right
58 top: titleLabel.visible ? titleLabel.bottom : parent.top
58 top: titleLabel.visible ? titleLabel.bottom : parent.top
59 }
59 }
60− height: (!seeMore.visible || seeMore.more) ? contentHeight : contentHeight / lineCount * (maximumCollapsedLineCount - 2)
60+ height: (lineCount <= maximumCollapsedLineCount || root.expanded) ? contentHeight : contentHeight / lineCount * maximumCollapsedLineCount
61 clip: true
61 clip: true
62 fontSize: "small"
62 fontSize: "small"
63 lineHeight: 1.2
63 lineHeight: 1.2
@@ -70,17 +70,4 @@ PreviewWidget {
70 UbuntuNumberAnimation { duration: UbuntuAnimation.SnapDuration }
70 UbuntuNumberAnimation { duration: UbuntuAnimation.SnapDuration }
71 }
71 }
72 }
72 }
73−
74− SeeMore {
75− id: seeMore
76− objectName: "seeMore"
77− anchors {
78− left: parent.left
79− right: parent.right
80− top: textLabel.bottom
81− topMargin: visible ? units.gu(1) : 0
82− }
83− height: visible ? implicitHeight : 0
84− visible: textLabel.lineCount > textLabel.maximumCollapsedLineCount
85− }
86}
73}
qml/Dash/Previews/PreviewWidget.qml+3
@@ -31,6 +31,9 @@ Item {
31 //! The ScopeStyle component.
31 //! The ScopeStyle component.
32 property var scopeStyle: null
32 property var scopeStyle: null
33
33
34+ //! Should the widget show in expanded mode (For those that support it)
35+ property bool expanded: true
36+
34 /*! \brief This signal should be emitted when a preview action was triggered.
37 /*! \brief This signal should be emitted when a preview action was triggered.
35 *
38 *
36 * \param widgetId, actionId Respective identifiers from widgetData.
39 * \param widgetId, actionId Respective identifiers from widgetData.
qml/Dash/Previews/PreviewWidgetFactory.qml+5
@@ -34,6 +34,9 @@ Loader {
34 //! The ScopeStyle component.
34 //! The ScopeStyle component.
35 property var scopeStyle: null
35 property var scopeStyle: null
36
36
37+ //! Should the widget show in expanded mode (For those that support it)
38+ property bool expanded: true
39+
37 //! Set to true if the parent preview is displayed.
40 //! Set to true if the parent preview is displayed.
38 property bool isCurrentPreview: false
41 property bool isCurrentPreview: false
39
42
@@ -47,6 +50,7 @@ Loader {
47 switch (widgetType) {
50 switch (widgetType) {
48 case "actions": return "PreviewActions.qml";
51 case "actions": return "PreviewActions.qml";
49 case "audio": return "PreviewAudioPlayback.qml";
52 case "audio": return "PreviewAudioPlayback.qml";
53+ case "expandable": return "PreviewExpandable.qml";
50 case "gallery": return "PreviewImageGallery.qml";
54 case "gallery": return "PreviewImageGallery.qml";
51 case "header": return "PreviewHeader.qml";
55 case "header": return "PreviewHeader.qml";
52 case "image": return "PreviewZoomableImage.qml";
56 case "image": return "PreviewZoomableImage.qml";
@@ -65,6 +69,7 @@ Loader {
65 item.widgetId = Qt.binding(function() { return root.widgetId } )
69 item.widgetId = Qt.binding(function() { return root.widgetId } )
66 item.widgetData = Qt.binding(function() { return root.widgetData } )
70 item.widgetData = Qt.binding(function() { return root.widgetData } )
67 item.isCurrentPreview = Qt.binding(function() { return root.isCurrentPreview } )
71 item.isCurrentPreview = Qt.binding(function() { return root.isCurrentPreview } )
72+ item.expanded = Qt.binding(function() { return root.expanded } )
68 if (item.hasOwnProperty("scopeStyle")) item.scopeStyle = root.scopeStyle;
73 if (item.hasOwnProperty("scopeStyle")) item.scopeStyle = root.scopeStyle;
69 }
74 }
70
75
tests/mocks/Unity/CMakeLists.txt+1−1
@@ -6,7 +6,7 @@ add_subdirectory(Notifications)
6pkg_search_module(DEE dee-1.0 REQUIRED)
6pkg_search_module(DEE dee-1.0 REQUIRED)
7pkg_search_module(GOBJECT gobject-2.0 REQUIRED)
7pkg_search_module(GOBJECT gobject-2.0 REQUIRED)
8pkg_search_module(DEEQT libdee-qt5 REQUIRED)
8pkg_search_module(DEEQT libdee-qt5 REQUIRED)
9−pkg_check_modules(SCOPES_API REQUIRED unity-shell-scopes=2)
9+pkg_check_modules(SCOPES_API REQUIRED unity-shell-scopes=3)
10
10
11include_directories(
11include_directories(
12 ${CMAKE_CURRENT_BINARY_DIR}
12 ${CMAKE_CURRENT_BINARY_DIR}
tests/mocks/Unity/fake_scopes.cpp+5
@@ -125,6 +125,11 @@ bool Scopes::loaded() const
125 return m_loaded;
125 return m_loaded;
126}
126}
127
127
128+unity::shell::scopes::ScopeInterface* Scopes::overviewScope() const
129+{
130+ return nullptr;
131+}
132+
128void Scopes::addScope(Scope* scope)
133void Scopes::addScope(Scope* scope)
129{
134{
130 int index = rowCount();
135 int index = rowCount();
tests/mocks/Unity/fake_scopes.h+1
@@ -50,6 +50,7 @@ public:
50 QModelIndex parent ( const QModelIndex & index ) const;
50 QModelIndex parent ( const QModelIndex & index ) const;
51
51
52 bool loaded() const override;
52 bool loaded() const override;
53+ unity::shell::scopes::ScopeInterface* overviewScope() const override;
53
54
54private Q_SLOTS:
55private Q_SLOTS:
55 void updateScopes();
56 void updateScopes();
tests/qmltests/CMakeLists.txt+1−1
@@ -30,7 +30,6 @@ add_qml_test(Components Rating)
30add_qml_test(Components ResponsiveFlowView)
30add_qml_test(Components ResponsiveFlowView)
31add_qml_test(Components ResponsiveGridView)
31add_qml_test(Components ResponsiveGridView)
32add_qml_test(Components ResponsiveVerticalJournal IMPORT_PATHS ${qmltest_DEFAULT_IMPORT_PATHS} ${CMAKE_BINARY_DIR}/plugins)
32add_qml_test(Components ResponsiveVerticalJournal IMPORT_PATHS ${qmltest_DEFAULT_IMPORT_PATHS} ${CMAKE_BINARY_DIR}/plugins)
33−add_qml_test(Components SeeMore)
34add_qml_test(Components Showable)
33add_qml_test(Components Showable)
35add_qml_test(Components PageHeader)
34add_qml_test(Components PageHeader)
36add_qml_test(Components ZoomableImage)
35add_qml_test(Components ZoomableImage)
@@ -44,6 +43,7 @@ add_qml_test(Dash/Apps RunningApplicationsGrid)
44add_qml_test(Dash/Previews Preview)
43add_qml_test(Dash/Previews Preview)
45add_qml_test(Dash/Previews PreviewActions)
44add_qml_test(Dash/Previews PreviewActions)
46add_qml_test(Dash/Previews PreviewAudioPlayback)
45add_qml_test(Dash/Previews PreviewAudioPlayback)
46+add_qml_test(Dash/Previews PreviewExpandable)
47add_qml_test(Dash/Previews PreviewHeader)
47add_qml_test(Dash/Previews PreviewHeader)
48add_qml_test(Dash/Previews PreviewImageGallery)
48add_qml_test(Dash/Previews PreviewImageGallery)
49add_qml_test(Dash/Previews PreviewPayments)
49add_qml_test(Dash/Previews PreviewPayments)
tests/qmltests/Components/tst_SeeMore.qmldeleted−52
@@ -1,52 +0,0 @@
1−/*
2− * Copyright 2014 Canonical Ltd.
3− *
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU General Public License as published by
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU General Public License for more details.
12− *
13− * You should have received a copy of the GNU General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− */
16−
17−import QtQuick 2.0
18−import QtTest 1.0
19−import Ubuntu.Components 0.1
20−import "../../../qml/Components"
21−import Unity.Test 0.1 as UT
22−
23−Rectangle {
24− id: root
25− width: units.gu(40)
26− height: units.gu(10)
27− color: Theme.palette.selected.background
28−
29− SeeMore {
30− id: seeMore
31− anchors.fill: parent
32− more: false
33− }
34−
35− UT.UnityTestCase {
36− name: "SeeMoreTest"
37− when: windowShown
38−
39− function test_interaction() {
40− var seeMoreLabel = findChild(seeMore, "seeMoreLabel")
41− var seeLessLabel = findChild(seeMore, "seeLessLabel")
42−
43− compare(seeMore.more, false)
44−
45− mouseClick(seeMoreLabel, seeMoreLabel.width / 2, seeMoreLabel.height / 2)
46− compare(seeMore.more, true)
47−
48− mouseClick(seeLessLabel, seeLessLabel.width / 2, seeLessLabel.height / 2)
49− compare(seeMore.more, false)
50− }
51− }
52−}
tests/qmltests/Dash/Previews/tst_PreviewTextSummary.qml+3−16
@@ -72,28 +72,15 @@ Rectangle {
72 tryCompare(textLabel, "y", 0)
72 tryCompare(textLabel, "y", 0)
73 }
73 }
74
74
75− function test_see_more() {
75+ function test_show_collapsed() {
76− var seeMore = findChild(previewTextSummary, "seeMore")
77−
78 // when it's more than textLabel.maximumCollapsedLineCount lines of text, show SeeMore component
76 // when it's more than textLabel.maximumCollapsedLineCount lines of text, show SeeMore component
79 verify(textLabel.lineCount > textLabel.maximumCollapsedLineCount)
77 verify(textLabel.lineCount > textLabel.maximumCollapsedLineCount)
80− compare(seeMore.visible, true)
81− verify(seeMore.more === false)
82− verify(textLabel.height < textLabel.contentHeight)
83
78
84− // test interactions with SeeMore
79+ previewTextSummary.expanded = false;
85− var seeMoreLabel = findChild(seeMore, "seeMoreLabel")
80+ tryCompareFunction(function() { return textLabel.height < textLabel.contentHeight; }, true)
86− var seeLessLabel = findChild(seeMore, "seeLessLabel")
87− var initialTextLabelHeight = textLabel.height
88− mouseClick(seeMoreLabel, seeMoreLabel.width / 2, seeMoreLabel.height / 2)
89− tryCompare(textLabel, "height", textLabel.contentHeight)
90− mouseClick(seeLessLabel, seeLessLabel.width / 2, seeLessLabel.height / 2)
91− tryCompare(textLabel, "height", initialTextLabelHeight)
92
81
93− // text SeeMore automatic hiding
94 previewTextSummary.widgetData = widgetDataShortText
82 previewTextSummary.widgetData = widgetDataShortText
95 verify(textLabel.lineCount <= textLabel.maximumCollapsedLineCount)
83 verify(textLabel.lineCount <= textLabel.maximumCollapsedLineCount)
96− compare(seeMore.visible, false)
97 tryCompare(textLabel, "height", textLabel.contentHeight)
84 tryCompare(textLabel, "height", textLabel.contentHeight)
98 tryCompare(previewTextSummary, "height", titleLabel.height + textLabel.height)
85 tryCompare(previewTextSummary, "height", titleLabel.height + textLabel.height)
99 }
86 }
tests/qmltests/Dash/Previews/tst_PreviewWidgetFactory.qml+1
@@ -77,6 +77,7 @@ Rectangle {
77 return [
77 return [
78 { tag: "Actions", type: "actions", source: "PreviewActions.qml" },
78 { tag: "Actions", type: "actions", source: "PreviewActions.qml" },
79 { tag: "Audio", type: "audio", source: "PreviewAudioPlayback.qml" },
79 { tag: "Audio", type: "audio", source: "PreviewAudioPlayback.qml" },
80+ { tag: "Expandable", type: "expandable", source: "PreviewExpandable.qml" },
80 { tag: "Gallery", type: "gallery", source: "PreviewImageGallery.qml" },
81 { tag: "Gallery", type: "gallery", source: "PreviewImageGallery.qml" },
81 { tag: "Header", type: "header", source: "PreviewHeader.qml" },
82 { tag: "Header", type: "header", source: "PreviewHeader.qml" },
82 { tag: "Image", type: "image", source: "PreviewZoomableImage.qml" },
83 { tag: "Image", type: "image", source: "PreviewZoomableImage.qml" },