on xenial help sign in
Merge
546aeefAlbert Astals
plugins/Dash/ScopeStyle.qml+12−9
@@ -38,15 +38,21 @@ QtObject {
38 /// Color used for text and symbolic icons
38 /// Color used for text and symbolic icons
39 readonly property color foreground: "foreground-color" in style ? style["foreground-color"] : d.defaultDark
39 readonly property color foreground: "foreground-color" in style ? style["foreground-color"] : d.defaultDark
40
40
41+ /// Luminance of the foreground color
42+ readonly property real foregroundLuminance: foreground ? luminance(foreground) : d.defaultForegroundLuminance
43+
41 /// Color used for the overall background
44 /// Color used for the overall background
42 readonly property color background: "background-color" in style ? style["background-color"] : "transparent"
45 readonly property color background: "background-color" in style ? style["background-color"] : "transparent"
43
46
47+ /// Luminance of the foreground color
48+ readonly property real backgroundLuminance: background ? luminance(background) : d.defaultBackgroundLuminance
49+
44 /*! \brief Luminance threshold for switching between fore and background color
50 /*! \brief Luminance threshold for switching between fore and background color
45
51
46 \note If background colour is not fully opaque, the defaultLightLuminance it's taken into account instead of it.
52 \note If background colour is not fully opaque, the defaultLightLuminance it's taken into account instead of it.
47 */
53 */
48− readonly property real threshold: background.a !== 1.0 ? (d.foregroundLuminance + d.defaultLightLuminance) / 2
54+ readonly property real threshold: background.a !== 1.0 ? (foregroundLuminance + d.defaultLightLuminance) / 2
49− : (d.foregroundLuminance + d.backgroundLuminance) / 2
55+ : (foregroundLuminance + backgroundLuminance) / 2
50
56
51 /*! \brief The lighter of foreground and background colors
57 /*! \brief The lighter of foreground and background colors
52
58
@@ -54,8 +60,8 @@ QtObject {
54 and defaults to the theme-provided light color.
60 and defaults to the theme-provided light color.
55 */
61 */
56 readonly property color light: {
62 readonly property color light: {
57− if (background.a !== 1.0) return d.foregroundLuminance > d.defaultLightLuminance ? foreground : d.defaultLight;
63+ if (background.a !== 1.0) return foregroundLuminance > d.defaultLightLuminance ? foreground : d.defaultLight;
58− return d.foregroundLuminance > d.backgroundLuminance ? foreground : background;
64+ return foregroundLuminance > backgroundLuminance ? foreground : background;
59 }
65 }
60
66
61 /*! \brief The darker of foreground and background colors
67 /*! \brief The darker of foreground and background colors
@@ -64,8 +70,8 @@ QtObject {
64 and defaults to the theme-provided dark color.
70 and defaults to the theme-provided dark color.
65 */
71 */
66 readonly property color dark: {
72 readonly property color dark: {
67− if (background.a !== 1.0) return d.foregroundLuminance < d.defaultDarkLuminance ? foreground : d.defaultDark;
73+ if (background.a !== 1.0) return foregroundLuminance < d.defaultDarkLuminance ? foreground : d.defaultDark;
68− return d.foregroundLuminance < d.backgroundLuminance ? foreground : background;
74+ return foregroundLuminance < backgroundLuminance ? foreground : background;
69 }
75 }
70
76
71 /// Source of the logo image for the header
77 /// Source of the logo image for the header
@@ -79,9 +85,6 @@ QtObject {
79
85
80 //! @cond
86 //! @cond
81 property var d: QtObject {
87 property var d: QtObject {
82− readonly property real foregroundLuminance: luminance(foreground)
83− readonly property real backgroundLuminance: luminance(background)
84−
85 // FIXME: should be taken from the theme
88 // FIXME: should be taken from the theme
86 readonly property color defaultLight: "white"
89 readonly property color defaultLight: "white"
87 readonly property color defaultDark: "grey"
90 readonly property color defaultDark: "grey"
qml/Components/PageHeader.qml+1−14
@@ -32,7 +32,6 @@ Item {
32 property bool searchEntryEnabled: false
32 property bool searchEntryEnabled: false
33 property ListModel searchHistory: SearchHistoryModel
33 property ListModel searchHistory: SearchHistoryModel
34 property alias searchQuery: searchTextField.text
34 property alias searchQuery: searchTextField.text
35− property bool searchInProgress: false
36 property alias showSignatureLine: bottomBorder.visible
35 property alias showSignatureLine: bottomBorder.visible
37
36
38 property alias bottomItem: bottomContainer.children
37 property alias bottomItem: bottomContainer.children
@@ -204,25 +203,13 @@ Item {
204 anchors.fill: parent
203 anchors.fill: parent
205 anchors.margins: units.gu(.75)
204 anchors.margins: units.gu(.75)
206 source: "image://theme/clear"
205 source: "image://theme/clear"
207− opacity: searchTextField.text.length > 0 && !searchActivityIndicator.running
206+ opacity: searchTextField.text.length > 0
208 visible: opacity > 0
207 visible: opacity > 0
209 Behavior on opacity {
208 Behavior on opacity {
210 UbuntuNumberAnimation { duration: UbuntuAnimation.FastDuration }
209 UbuntuNumberAnimation { duration: UbuntuAnimation.FastDuration }
211 }
210 }
212 }
211 }
213
212
214− ActivityIndicator {
215− id: searchActivityIndicator
216− objectName: "searchIndicator"
217− anchors.fill: parent
218− anchors.margins: units.gu(.75)
219− running: root.searchInProgress
220− opacity: running ? 1 : 0
221− Behavior on opacity {
222− UbuntuNumberAnimation { duration: UbuntuAnimation.FastDuration }
223− }
224− }
225−
226 onClicked: {
213 onClicked: {
227 root.resetSearch(true);
214 root.resetSearch(true);
228 root.openSearchHistory();
215 root.openSearchHistory();
qml/Dash/Dash.qml+67−1
@@ -14,7 +14,7 @@
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
15 */
16
16
17−import QtQuick 2.0
17+import QtQuick 2.2
18import Ubuntu.Components 0.1
18import Ubuntu.Components 0.1
19import Ubuntu.Gestures 0.1
19import Ubuntu.Gestures 0.1
20import Unity 0.2
20import Unity 0.2
@@ -260,6 +260,72 @@ Showable {
260 }
260 }
261 }
261 }
262
262
263+ Rectangle {
264+ id: indicator
265+ objectName: "processingIndicator"
266+ anchors {
267+ left: parent.left
268+ right: parent.right
269+ bottom: parent.bottom
270+ }
271+ height: units.dp(3)
272+ color: scopeStyle.backgroundLuminance > 0.7 ? "#50000000" : "#50ffffff"
273+ opacity: 0
274+ visible: opacity > 0
275+
276+ readonly property bool processing: dashContent.processing || scopeItem.processing
277+
278+ Behavior on opacity {
279+ UbuntuNumberAnimation { duration: UbuntuAnimation.FastDuration }
280+ }
281+
282+ onProcessingChanged: {
283+ if (processing) delay.start();
284+ else if (!persist.running) indicator.opacity = 0;
285+ }
286+
287+ Timer {
288+ id: delay
289+ interval: 200
290+ onTriggered: if (indicator.processing) {
291+ persist.restart();
292+ indicator.opacity = 1;
293+ }
294+ }
295+
296+ Timer {
297+ id: persist
298+ interval: 2 * UbuntuAnimation.SleepyDuration - UbuntuAnimation.FastDuration
299+ onTriggered: if (!indicator.processing) indicator.opacity = 0
300+ }
301+
302+ Rectangle {
303+ id: orange
304+ anchors { top: parent.top; bottom: parent.bottom }
305+ width: parent.width / 4
306+ color: Theme.palette.selected.foreground
307+
308+ SequentialAnimation {
309+ running: indicator.visible
310+ loops: Animation.Infinite
311+ XAnimator {
312+ from: -orange.width / 2
313+ to: indicator.width - orange.width / 2
314+ duration: UbuntuAnimation.SleepyDuration
315+ easing.type: Easing.InOutSine
316+ target: orange
317+ }
318+ XAnimator {
319+ from: indicator.width - orange.width / 2
320+ to: -orange.width / 2
321+ duration: UbuntuAnimation.SleepyDuration
322+ easing.type: Easing.InOutSine
323+ target: orange
324+ }
325+ }
326+ }
327+ }
328+
263 EdgeDragArea {
329 EdgeDragArea {
264 id: overviewDragHandle
330 id: overviewDragHandle
265 objectName: "overviewDragHandle"
331 objectName: "overviewDragHandle"
qml/Dash/DashContent.qml+2
@@ -29,6 +29,8 @@ Item {
29 readonly property var currentScope: dashContentList.currentItem ? dashContentList.currentItem.theScope : null
29 readonly property var currentScope: dashContentList.currentItem ? dashContentList.currentItem.theScope : null
30 readonly property bool previewShown: dashContentList.currentItem && dashContentList.currentItem.item ?
30 readonly property bool previewShown: dashContentList.currentItem && dashContentList.currentItem.item ?
31 dashContentList.currentItem.item.previewShown : false
31 dashContentList.currentItem.item.previewShown : false
32+ readonly property bool processing: dashContentList.currentItem && dashContentList.currentItem.item
33+ && dashContentList.currentItem.item.processing || false
32
34
33 signal scopeLoaded(string scopeId)
35 signal scopeLoaded(string scopeId)
34 signal gotoScope(string scopeId)
36 signal gotoScope(string scopeId)
qml/Dash/DashNavigationList.qml−5
@@ -35,11 +35,6 @@ Item {
35 anchors.fill: parent
35 anchors.fill: parent
36 }
36 }
37
37
38− ActivityIndicator {
39− id: loadingIndicator
40− anchors.centerIn: parent
41− running: !(navigation && navigation.loaded)
42− }
43 clip: true
38 clip: true
44
39
45 Behavior on height {
40 Behavior on height {
qml/Dash/GenericScopeView.qml+2−1
@@ -42,6 +42,8 @@ FocusScope {
42 style: scope ? scope.customizations : {}
42 style: scope ? scope.customizations : {}
43 }
43 }
44
44
45+ readonly property bool processing: scope ? scope.searchInProgress || previewListView.processing : false
46+
45 signal backClicked()
47 signal backClicked()
46
48
47 function positionAtBeginning() {
49 function positionAtBeginning() {
@@ -414,7 +416,6 @@ FocusScope {
414 title: scopeView.scope ? scopeView.scope.name : ""
416 title: scopeView.scope ? scopeView.scope.name : ""
415 showBackButton: scopeView.hasBackAction
417 showBackButton: scopeView.hasBackAction
416 searchEntryEnabled: true
418 searchEntryEnabled: true
417− searchInProgress: scopeView.scope ? scopeView.scope.searchInProgress : false
418 scopeStyle: scopeView.scopeStyle
419 scopeStyle: scopeView.scopeStyle
419
420
420 bottomItem: DashNavigation {
421 bottomItem: DashNavigation {
qml/Dash/PreviewListView.qml+23−27
@@ -32,6 +32,9 @@ Item {
32 property alias currentItem: previewListView.currentItem
32 property alias currentItem: previewListView.currentItem
33 property alias count: previewListView.count
33 property alias count: previewListView.count
34
34
35+ readonly property bool processing: currentItem && (!currentItem.previewModel.loaded
36+ || currentItem.previewModel.processingAction)
37+
35 PageHeader {
38 PageHeader {
36 id: header
39 id: header
37 objectName: "pageHeader"
40 objectName: "pageHeader"
@@ -83,39 +86,32 @@ Item {
83 }
86 }
84 }
87 }
85
88
86− delegate: Item {
89+ delegate: Previews.Preview {
90+ id: preview
87− objectName: "previewItem" + index
91+ objectName: "preview" + index
88 height: previewListView.height
92 height: previewListView.height
89 width: previewListView.width
93 width: previewListView.width
90
94
91− readonly property bool ready: preview.previewModel && preview.previewModel.loaded
95+ isCurrent: ListView.isCurrentItem
92−
93− Previews.Preview {
94− id: preview
95− objectName: "preview" + index
96− anchors.fill: parent
97
96
98− isCurrent: parent.ListView.isCurrentItem
99−
100− previewModel: {
97+ previewModel: {
101− var previewStack = root.scope.preview(result);
98+ var previewStack = root.scope.preview(result);
102− return previewStack.getPreviewModel(0);
99+ return previewStack.getPreviewModel(0);
103− }
104− scopeStyle: root.scopeStyle
105 }
100 }
101+ scopeStyle: root.scopeStyle
102+ }
103+ }
106
104
107− MouseArea {
105+ MouseArea {
108− id: processingMouseArea
106+ id: processingMouseArea
109− objectName: "processingMouseArea"
107+ objectName: "processingMouseArea"
110− anchors.fill: parent
108+ anchors {
111− enabled: preview.previewModel && (!preview.previewModel.loaded || preview.previewModel.processingAction)
109+ left: parent.left
112−
110+ right: parent.right
113− ActivityIndicator {
111+ top: pageHeader.bottom
114− anchors.centerIn: parent
112+ bottom: parent.bottom
115− visible: root.open && parent.enabled
116− running: visible
117− }
118− }
119 }
113 }
114+
115+ enabled: root.processing
120 }
116 }
121}
117}
tests/autopilot/unity8/shell/emulators/dash.py+1−1
@@ -150,7 +150,7 @@ class Dash(emulators.UnityEmulatorBase):
150 headerContainer.contentY.wait_for(0)
150 headerContainer.contentY.wait_for(0)
151 search_text_field = self._get_search_text_field()
151 search_text_field = self._get_search_text_field()
152 search_text_field.write(query)
152 search_text_field.write(query)
153− current_header.select_single(objectName="searchIndicator").running.wait_for(False)
153+ self.select_single(objectName="processingIndicator").visible.wait_for(False)
154
154
155 def _get_search_text_field(self):
155 def _get_search_text_field(self):
156 page_header = self._get_current_page_header()
156 page_header = self._get_current_page_header()
tests/plugins/Dash/tst_ScopeStyle.qml+14−7
@@ -54,6 +54,9 @@ Rectangle {
54 { tag: "lightgrey", luminance: 0.8275 },
54 { tag: "lightgrey", luminance: 0.8275 },
55 { tag: "grey", luminance: 0.5020 },
55 { tag: "grey", luminance: 0.5020 },
56 { tag: "darkgrey", luminance: 0.6627 },
56 { tag: "darkgrey", luminance: 0.6627 },
57+ { tag: "red", luminance: 0.2126 },
58+ { tag: "green", luminance: 0.3590 },
59+ { tag: "blue", luminance: 0.0722 },
57 ];
60 ];
58 }
61 }
59
62
@@ -64,10 +67,10 @@ Rectangle {
64
67
65 function test_foreground_data() {
68 function test_foreground_data() {
66 return [
69 return [
67− { tag: "default", index: 0, foreground: "grey" },
70+ { tag: "default", index: 0, foreground: "grey", luminance: 0.5020 },
68− { tag: "red on black", index: 1, foreground: "red" },
71+ { tag: "red on black", index: 1, foreground: "red", luminance: 0.2126 },
69− { tag: "green on white", index: 2, foreground: "green" },
72+ { tag: "green on white", index: 2, foreground: "green", luminance: 0.3590 },
70− { tag: "blue on darkgrey", index: 3, foreground: "blue" },
73+ { tag: "blue on darkgrey", index: 3, foreground: "blue", luminance: 0.0722 },
71 ];
74 ];
72 }
75 }
73
76
@@ -75,14 +78,15 @@ Rectangle {
75 tool.style = testCase.styles[data.index];
78 tool.style = testCase.styles[data.index];
76 verify(Qt.colorEqual(tool.foreground, data.foreground),
79 verify(Qt.colorEqual(tool.foreground, data.foreground),
77 "Foreground color not equal: %1 != %2".arg(tool.foreground).arg(data.foreground));
80 "Foreground color not equal: %1 != %2".arg(tool.foreground).arg(data.foreground));
81+ compare(tool.foregroundLuminance.toFixed(4), data.luminance.toFixed(4));
78 }
82 }
79
83
80 function test_background_data() {
84 function test_background_data() {
81 return [
85 return [
82 { tag: "default", index: 0, background: "transparent" },
86 { tag: "default", index: 0, background: "transparent" },
83− { tag: "red on black", index: 1, background: "black" },
87+ { tag: "red on black", index: 1, background: "black", luminance: 0 },
84− { tag: "green on white", index: 2, background: "white" },
88+ { tag: "green on white", index: 2, background: "white", luminance: 1 },
85− { tag: "blue on darkgrey", index: 3, background: "darkgrey" },
89+ { tag: "blue on darkgrey", index: 3, background: "darkgrey", luminance: 0.6627 },
86 ];
90 ];
87 }
91 }
88
92
@@ -90,6 +94,9 @@ Rectangle {
90 tool.style = testCase.styles[data.index];
94 tool.style = testCase.styles[data.index];
91 verify(Qt.colorEqual(tool.background, data.background),
95 verify(Qt.colorEqual(tool.background, data.background),
92 "Background color not equal: %1 != %2".arg(tool.background).arg(data.background));
96 "Background color not equal: %1 != %2".arg(tool.background).arg(data.background));
97+ if (data.hasOwnProperty("luminance")) {
98+ compare(tool.backgroundLuminance.toFixed(4), data.luminance.toFixed(4));
99+ }
93 }
100 }
94
101
95 function test_threshold_data() {
102 function test_threshold_data() {
tests/qmltests/Components/tst_PageHeader.qml−23
@@ -119,29 +119,6 @@ Item {
119 compare(pageHeader.searchHistory.get(0).query, "humppa4")
119 compare(pageHeader.searchHistory.get(0).query, "humppa4")
120 }
120 }
121
121
122− function test_search_indicator() {
123− var searchIndicator = findChild(pageHeader, "searchIndicator")
124− var clearIcon = findChild(pageHeader, "clearIcon")
125−
126− pageHeader.triggerSearch()
127−
128− tryCompare(clearIcon, "visible", false)
129− pageHeader.searchQuery = "ubuntu"
130− tryCompare(clearIcon, "visible", true)
131−
132− pageHeader.searchInProgress = false
133− compare(searchIndicator.running, false, "Search indicator is running.")
134− tryCompare(clearIcon, "visible", true)
135−
136− pageHeader.searchInProgress = true
137− compare(searchIndicator.running, true, "Search indicator isn't running.")
138− tryCompare(clearIcon, "visible", false)
139−
140− pageHeader.searchInProgress = false;
141− compare(searchIndicator.running, false, "Search indicator is running.")
142− tryCompare(clearIcon, "visible", true)
143− }
144−
145 function test_titleImage() {
122 function test_titleImage() {
146
123
147 var titleImage = findChild(pageHeader, "titleImage");
124 var titleImage = findChild(pageHeader, "titleImage");
tests/qmltests/Dash/tst_Dash.qml+23−6
@@ -43,12 +43,8 @@ Item {
43 name: "Dash"
43 name: "Dash"
44 when: windowShown
44 when: windowShown
45
45
46− property var scopes
47−
48− Component.onCompleted: {
49− var dashContent = findChild(dash, "dashContent");
46+ readonly property Item dashContent: findChild(dash, "dashContent");
50− scopes = dashContent.scopes;
47+ readonly property var scopes: dashContent.scopes
51− }
52
48
53 function init() {
49 function init() {
54 // clear and reload the scopes.
50 // clear and reload the scopes.
@@ -321,5 +317,26 @@ Item {
321 dashCommunicatorService.mockSetCurrentScope("clickscope", true, true);
317 dashCommunicatorService.mockSetCurrentScope("clickscope", true, true);
322 tryCompare(dashContentList, "currentIndex", 1)
318 tryCompare(dashContentList, "currentIndex", 1)
323 }
319 }
320+
321+ function test_processing_indicator() {
322+ tryCompare(scopes, "loaded", true);
323+
324+ var processingIndicator = findChild(dash, "processingIndicator");
325+ verify(processingIndicator, "Can't find the processing indicator.");
326+
327+ verify(!processingIndicator.visible, "Processing indicator should be visible.");
328+
329+ tryCompareFunction(function() {
330+ return scopes.getScope(dashContent.currentIndex) != null;
331+ }, true);
332+ var currentScope = scopes.getScope(dashContent.currentIndex);
333+ verify(currentScope, "Can't find the current scope.");
334+
335+ currentScope.setSearchInProgress(true);
336+ tryCompare(processingIndicator, "visible", true);
337+
338+ currentScope.setSearchInProgress(false);
339+ tryCompare(processingIndicator, "visible", false);
340+ }
324 }
341 }
325}
342}
tests/qmltests/Dash/tst_GenericScopeView.qml+1−1
@@ -320,7 +320,7 @@ Item {
320 units.gu(2),
320 units.gu(2),
321 testCase.previewListView.height / 2);
321 testCase.previewListView.height / 2);
322 tryCompare(previewListViewList, "moving", false);
322 tryCompare(previewListViewList, "moving", false);
323− tryCompare(testCase.previewListView.currentItem, "objectName", "previewItem" + i);
323+ tryCompare(testCase.previewListView.currentItem, "objectName", "preview" + i);
324
324
325 }
325 }
326 closePreview();
326 closePreview();