on xenial help sign in
Rework the search to be in a bottom item instead of popover
85ff01fAlbert Astals Cid
qml/Dash/GenericScopeView.qml+21−10
@@ -16,6 +16,7 @@
16
16
17import QtQuick 2.0
17import QtQuick 2.0
18import Ubuntu.Components 1.1
18import Ubuntu.Components 1.1
19+import "../Components/SearchHistoryModel"
19import Utils 0.1
20import Utils 0.1
20import Unity 0.2
21import Unity 0.2
21import Dash 0.1
22import Dash 0.1
@@ -25,7 +26,7 @@ import "../Components/ListItems" as ListItems
25FocusScope {
26FocusScope {
26 id: scopeView
27 id: scopeView
27
28
28− readonly property bool navigationDisableParentInteractive: categoryView.pageHeader.bottomItem[0].disableParentInteractive
29+ readonly property bool navigationDisableParentInteractive: peExtraPanel.visible /*TODO bring back the dash navigation */
29 property bool forceNonInteractive: false
30 property bool forceNonInteractive: false
30 property var scope: null
31 property var scope: null
31 property UnitySortFilterProxyModel categories: categoryFilter
32 property UnitySortFilterProxyModel categories: categoryFilter
@@ -617,6 +618,8 @@ FocusScope {
617 objectName: "scopePageHeader"
618 objectName: "scopePageHeader"
618 width: parent.width
619 width: parent.width
619 title: scopeView.scope ? scopeView.scope.name : ""
620 title: scopeView.scope ? scopeView.scope.name : ""
621+ extraPanel: peExtraPanel
622+ searchHistory: SearchHistoryModel
620 searchHint: scopeView.scope && scopeView.scope.searchHint || i18n.ctr("Label: Hint for dash search line edit", "Search")
623 searchHint: scopeView.scope && scopeView.scope.searchHint || i18n.ctr("Label: Hint for dash search line edit", "Search")
621 showBackButton: scopeView.hasBackAction
624 showBackButton: scopeView.hasBackAction
622 searchEntryEnabled: true
625 searchEntryEnabled: true
@@ -627,19 +630,27 @@ FocusScope {
627 paginationCount: scopeView.paginationCount
630 paginationCount: scopeView.paginationCount
628 paginationIndex: scopeView.paginationIndex
631 paginationIndex: scopeView.paginationIndex
629
632
630− bottomItem: DashNavigation {
631− scope: scopeView.scope
632− anchors { left: parent.left; right: parent.right }
633− windowHeight: scopeView.height
634− windowWidth: scopeView.width
635− scopeStyle: scopeView.scopeStyle
636− }
637−
638 onBackClicked: scopeView.backClicked()
633 onBackClicked: scopeView.backClicked()
639 onSettingsClicked: subPageLoader.openSubPage("settings")
634 onSettingsClicked: subPageLoader.openSubPage("settings")
640 onFavoriteClicked: scopeView.scope.favorite = !scopeView.scope.favorite
635 onFavoriteClicked: scopeView.scope.favorite = !scopeView.scope.favorite
641 onSearchTextFieldFocused: scopeView.showHeader()
636 onSearchTextFieldFocused: scopeView.showHeader()
642 }
637 }
638+
639+ PageHeaderExtraPanel {
640+ id: peExtraPanel
641+ width: parent.width
642+ anchors {
643+ top: categoryView.pageHeader.bottom
644+ topMargin: -categoryView.pageHeader.signatureLineHeight
645+ }
646+ z: 1
647+ visible: false
648+ searchHistory: SearchHistoryModel
649+ onHistoryItemClicked: {
650+ SearchHistoryModel.addQuery(text);
651+ categoryView.pageHeader.searchQuery = text;
652+ }
653+ }
643 }
654 }
644
655
645 Item {
656 Item {
@@ -647,7 +658,7 @@ FocusScope {
647 anchors.left: parent.left
658 anchors.left: parent.left
648 anchors.right: parent.right
659 anchors.right: parent.right
649 anchors.bottom: parent.bottom
660 anchors.bottom: parent.bottom
650− height: parent.height - pullToRefresh.contentY + (categoryView.pageHeader.bottomItem[0].height - categoryView.pageHeader.height)
661+ height: parent.height - pullToRefresh.contentY - categoryView.pageHeader.height
651 clip: true
662 clip: true
652
663
653 PullToRefresh {
664 PullToRefresh {
qml/Dash/PageHeader.qml+9−55
@@ -20,23 +20,24 @@ import Ubuntu.Components.Themes.Ambiance 1.1
20import Ubuntu.Components.Popups 1.0
20import Ubuntu.Components.Popups 1.0
21import Ubuntu.Components.ListItems 1.0
21import Ubuntu.Components.ListItems 1.0
22import "../Components"
22import "../Components"
23−import "../Components/SearchHistoryModel"
24
23
25Item {
24Item {
26 id: root
25 id: root
27 objectName: "pageHeader"
26 objectName: "pageHeader"
28− implicitHeight: headerContainer.height + bottomContainer.height + (showSignatureLine ? units.gu(2) : 0)
27+ implicitHeight: headerContainer.height + bottomContainer.height + signatureLineHeight
28+ readonly property real signatureLineHeight: showSignatureLine ? units.gu(2) : 0
29
29
30 property bool showBackButton: false
30 property bool showBackButton: false
31 property bool backIsClose: false
31 property bool backIsClose: false
32 property string title
32 property string title
33+ property var extraPanel
33
34
34 property bool storeEntryEnabled: false
35 property bool storeEntryEnabled: false
35 property bool searchEntryEnabled: false
36 property bool searchEntryEnabled: false
36 property bool settingsEnabled: false
37 property bool settingsEnabled: false
37 property bool favoriteEnabled: false
38 property bool favoriteEnabled: false
38 property bool favorite: false
39 property bool favorite: false
39− property ListModel searchHistory: SearchHistoryModel
40+ property ListModel searchHistory
40 property alias searchQuery: searchTextField.text
41 property alias searchQuery: searchTextField.text
41 property alias searchHint: searchTextField.placeholderText
42 property alias searchHint: searchTextField.placeholderText
42 property bool showSignatureLine: true
43 property bool showSignatureLine: true
@@ -69,9 +70,8 @@ Item {
69 }
70 }
70
71
71 function closePopup(keepFocus) {
72 function closePopup(keepFocus) {
72− if (headerContainer.popover != null) {
73+ if (extraPanel.visible) {
73− headerContainer.popover.unfocusOnDestruction = !keepFocus;
74+ extraPanel.visible = false;
74− PopupUtils.close(headerContainer.popover);
75 } else if (!keepFocus) {
75 } else if (!keepFocus) {
76 unfocus();
76 unfocus();
77 }
77 }
@@ -95,13 +95,9 @@ Item {
95 function openSearchHistory() {
95 function openSearchHistory() {
96 if (openSearchAnimation.running) {
96 if (openSearchAnimation.running) {
97 openSearchAnimation.openSearchHistory = true;
97 openSearchAnimation.openSearchHistory = true;
98− } else if (root.searchHistory.count > 0 && headerContainer.popover == null) {
98+ } else if (root.searchHistory.count > 0) {
99− headerContainer.popover = PopupUtils.open(popoverComponent, searchTextField,
99+ // Show extraPanel
100− {
100+ extraPanel.visible = true;
101− "contentWidth": searchTextField.width,
102− "edgeMargins": units.gu(1)
103− }
104− );
105 }
101 }
106 }
102 }
107
103
@@ -142,7 +138,6 @@ Item {
142 contentY: showSearch ? 0 : height
138 contentY: showSearch ? 0 : height
143
139
144 property bool showSearch: false
140 property bool showSearch: false
145− property var popover: null
146
141
147 Background {
142 Background {
148 id: background
143 id: background
@@ -321,47 +316,6 @@ Item {
321 }
316 }
322 }
317 }
323
318
324− Component {
325− id: popoverComponent
326− Popover {
327− id: popover
328− autoClose: false
329−
330− property bool unfocusOnDestruction: false
331−
332− Component.onDestruction: {
333− headerContainer.popover = null;
334− if (unfocusOnDestruction) {
335− root.unfocus();
336− }
337− }
338−
339− Column {
340− anchors {
341− top: parent.top
342− left: parent.left
343− right: parent.right
344− }
345−
346− Repeater {
347− id: recentSearches
348− objectName: "recentSearches"
349− model: searchHistory
350−
351− delegate: Standard {
352− showDivider: index < recentSearches.count - 1
353− text: query
354− onClicked: {
355− searchHistory.addQuery(text);
356− searchTextField.text = text;
357− closePopup(/* keepFocus */false);
358− }
359− }
360− }
361− }
362− }
363− }
364−
365 Rectangle {
319 Rectangle {
366 id: bottomBorder
320 id: bottomBorder
367 visible: showSignatureLine
321 visible: showSignatureLine
qml/Dash/PageHeaderExtraPanel.qmlnew file+85
@@ -0,0 +1,85 @@
1+/*
2+ * Copyright (C) 2013-2015 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.2
18+import Ubuntu.Components 1.1
19+import Ubuntu.Components.ListItems 1.0
20+
21+Item {
22+ id: root
23+
24+ implicitHeight: recentSearchesRepeater.count > 0 ? searchColumn.height + recentSearchesLabels.height + recentSearchesLabels.anchors.margins : 0
25+
26+ property ListModel searchHistory
27+
28+ signal historyItemClicked(string text)
29+
30+ Rectangle {
31+ color: "white"
32+ anchors.fill: parent
33+ }
34+
35+ Label {
36+ id: recentSearchesLabels
37+ text: i18n.tr("Recent Searches")
38+ visible: recentSearchesRepeater.count > 0
39+ anchors {
40+ top: parent.top
41+ left: parent.left
42+ margins: units.gu(1)
43+ }
44+ }
45+
46+ Label {
47+ text: i18n.tr("Clear All")
48+ fontSize: "small"
49+ visible: recentSearchesRepeater.count > 0
50+ anchors {
51+ top: parent.top
52+ right: parent.right
53+ margins: units.gu(1)
54+ }
55+
56+ AbstractButton {
57+ anchors.fill: parent
58+ onClicked: searchHistory.clear();
59+ }
60+ }
61+
62+ Column {
63+ id: searchColumn
64+ anchors {
65+ top: recentSearchesLabels.bottom
66+ left: parent.left
67+ right: parent.right
68+ }
69+
70+ Repeater {
71+ id: recentSearchesRepeater
72+ objectName: "recentSearchesRepeater"
73+ model: searchHistory
74+
75+ delegate: Standard {
76+ showDivider: index < recentSearchesRepeater.count - 1
77+ height: units.gu(4)
78+ text: query
79+ iconName: "search"
80+ iconFrame: false
81+ onClicked: root.historyItemClicked(text)
82+ }
83+ }
84+ }
85+}
tests/qmltests/Dash/tst_PageHeader.qml+24−15
@@ -18,6 +18,7 @@ import QtQuick 2.0
18import QtTest 1.0
18import QtTest 1.0
19import ".."
19import ".."
20import "../../../qml/Dash"
20import "../../../qml/Dash"
21+import "../../../qml/Components/SearchHistoryModel"
21import Ubuntu.Components 0.1
22import Ubuntu.Components 0.1
22import Unity 0.2
23import Unity 0.2
23import Unity.Test 0.1 as UT
24import Unity.Test 0.1 as UT
@@ -25,7 +26,7 @@ import Unity.Test 0.1 as UT
25Item {
26Item {
26 id: root
27 id: root
27 width: units.gu(110)
28 width: units.gu(110)
28− height: units.gu(30)
29+ height: units.gu(50)
29
30
30 UT.UnityTestCase {
31 UT.UnityTestCase {
31 name: "PageHeaderLabelTest"
32 name: "PageHeaderLabelTest"
@@ -54,7 +55,7 @@ Item {
54 pageHeader.searchHistory.clear();
55 pageHeader.searchHistory.clear();
55
56
56 // Check initial state
57 // Check initial state
57− tryCompareFunction(function() { return headerContainer.popover === null; }, true);
58+ tryCompare(pageHeader.extraPanel, "visible", true);
58 compare(pageHeader.searchHistory.count, 0);
59 compare(pageHeader.searchHistory.count, 0);
59 }
60 }
60
61
@@ -146,7 +147,7 @@ Item {
146 doResetSearch();
147 doResetSearch();
147 }
148 }
148
149
149− function test_popover() {
150+ function test_extraPanel() {
150 searchEnabled = true;
151 searchEnabled = true;
151 pageHeader.searchHistory.clear();
152 pageHeader.searchHistory.clear();
152
153
@@ -155,22 +156,18 @@ Item {
155
156
156 pageHeader.triggerSearch();
157 pageHeader.triggerSearch();
157
158
158− var headerContainer = findChild(pageHeader, "headerContainer");
159− verify(headerContainer !== null, "headerContainer != null");
160− tryCompareFunction(function() { return headerContainer.popover !== null; }, true);
161−
162− tryCompare(headerContainer.popover, "visible", true);
159+ tryCompare(pageHeader.extraPanel, "visible", true);
163
160
164 var searchTextField = findChild(pageHeader, "searchTextField");
161 var searchTextField = findChild(pageHeader, "searchTextField");
165 compare(searchTextField.focus, true);
162 compare(searchTextField.focus, true);
166
163
167− var recentSearches = findChild(headerContainer.popover, "recentSearches");
164+ var recentSearches = findChild(pageHeader.extraPanel, "recentSearchesRepeater");
168− verify(recentSearches, "Could not find recent searches in the popover");
165+ verify(recentSearches, "Could not find recent searches");
169 waitForRendering(recentSearches);
166 waitForRendering(recentSearches);
170 mouseClick(recentSearches.itemAt(0));
167 mouseClick(recentSearches.itemAt(0));
171
168
172 compare(pageHeader.searchQuery, "Search2");
169 compare(pageHeader.searchQuery, "Search2");
173− tryCompareFunction(function() { return headerContainer.popover === null; }, true);
170+ tryCompare(pageHeader.extraPanel, "visible", false);
174 compare(searchTextField.focus, false);
171 compare(searchTextField.focus, false);
175 }
172 }
176
173
@@ -212,9 +209,7 @@ Item {
212 pageHeader.triggerSearch();
209 pageHeader.triggerSearch();
213
210
214 var headerContainer = findChild(pageHeader, "headerContainer");
211 var headerContainer = findChild(pageHeader, "headerContainer");
215− verify(headerContainer !== null, "headerContainer != null");
212+ tryCompare(pageHeader.extraPanel, "visible", true);
216− tryCompareFunction(function() { return headerContainer.popover !== null; }, true);
217− compare(headerContainer.popover.visible, true);
218
213
219 pageHeader.searchQuery = data.searchText;
214 pageHeader.searchQuery = data.searchText;
220
215
@@ -225,7 +220,7 @@ Item {
225 }
220 }
226
221
227 tryCompare(headerContainer, "showSearch", !data.hideSearch);
222 tryCompare(headerContainer, "showSearch", !data.hideSearch);
228− tryCompareFunction(function() { return headerContainer.popover === null; }, true);
223+ tryCompare(pageHeader.extraPanel, "visible", false);
229
224
230 doResetSearch();
225 doResetSearch();
231 }
226 }
@@ -251,8 +246,10 @@ Item {
251 right: parent.right
246 right: parent.right
252 }
247 }
253
248
249+ searchHistory: SearchHistoryModel
254 searchEntryEnabled: true
250 searchEntryEnabled: true
255 title: "%^$%^%^&%^&%^$%GHR%"
251 title: "%^$%^%^&%^&%^$%GHR%"
252+ extraPanel: peExtraPanel
256 scopeStyle: QtObject {
253 scopeStyle: QtObject {
257 readonly property color foreground: Theme.palette.normal.baseText
254 readonly property color foreground: Theme.palette.normal.baseText
258 readonly property url headerLogo: showImageCheckBox.checked ? pageHeader.titleImageSource : ""
255 readonly property url headerLogo: showImageCheckBox.checked ? pageHeader.titleImageSource : ""
@@ -264,6 +261,18 @@ Item {
264 onBackClicked: lastBackClicked = new Date()
261 onBackClicked: lastBackClicked = new Date()
265 }
262 }
266
263
264+ PageHeaderExtraPanel {
265+ id: peExtraPanel
266+ width: parent.width
267+ z: 1
268+ visible: false
269+ searchHistory: SearchHistoryModel
270+ onHistoryItemClicked: {
271+ SearchHistoryModel.addQuery(text);
272+ pageHeader.searchQuery = text;
273+ }
274+ }
275+
267 Row {
276 Row {
268 spacing: units.gu(1)
277 spacing: units.gu(1)
269 anchors {
278 anchors {