Merge lp:~aacid/unity8/departments into lp:unity8

Proposed by Albert Astals Cid
Status: Merged
Approved by: Michał Sawicz
Approved revision: 953
Merged at revision: 974
Proposed branch: lp:~aacid/unity8/departments
Merge into: lp:unity8
Diff against target: 1099 lines (+813/-17)
16 files modified
debian/control (+1/-1)
plugins/Dash/listviewwithpageheader.cpp (+25/-5)
plugins/Dash/listviewwithpageheader.h (+3/-0)
qml/Components/PageHeader.qml (+16/-4)
qml/Dash/DashContent.qml (+9/-1)
qml/Dash/DashDepartments.qml (+202/-0)
qml/Dash/DashDepartmentsList.qml (+195/-0)
qml/Dash/ScopeItem.qml (+12/-0)
tests/mocks/Unity/CMakeLists.txt (+2/-0)
tests/mocks/Unity/fake_department.cpp (+127/-0)
tests/mocks/Unity/fake_department.h (+61/-0)
tests/mocks/Unity/fake_scope.cpp (+36/-1)
tests/mocks/Unity/fake_scope.h (+6/-0)
tests/mocks/Unity/fake_scopes.cpp (+2/-2)
tests/mocks/Unity/fake_unity_plugin.cpp (+2/-0)
tests/qmltests/Dash/tst_DashContent.qml (+114/-3)
To merge this branch: bzr merge lp:~aacid/unity8/departments
Reviewer Review Type Date Requested Status
PS Jenkins bot (community) continuous-integration Needs Fixing
Michał Sawicz Approve
Albert Astals Cid (community) Abstain
Mike Nagle Pending
Review via email: mp+221072@code.launchpad.net

Commit message

Departments support

Description of the change

* Are there any related MPs required for this MP to build/function as expected?
https://code.launchpad.net/~unity-team/unity-api/departments/+merge/221241
and
https://code.launchpad.net/~mhr3/unity-scopes-shell/department-support/+merge/221883

 * Did you perform an exploratory manual test run of your code change and any related functionality?
Yes

 * Did you make sure that your branch does not contain spurious tags?
Yes

 * If you changed the packaging (debian), did you subscribe the ubuntu-unity team to this MP?
N/A

 * If you changed the UI, has there been a design review?
N/A

To post a comment you must log in.
Revision history for this message
Albert Astals Cid (aacid) wrote :

As said by Saviq, need to limit the width to 60gu and then bring it back to 40gu so that it doesn't look weird in wide sizes

review: Needs Fixing
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
lp:~aacid/unity8/departments updated
929. By Albert Astals Cid

Tablet mode

Revision history for this message
Albert Astals Cid (aacid) wrote :

Added the tablet mode

review: Abstain
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Michał Sawicz (saviq) wrote :

Conflict?
Also, you need to bump dep on unity-api.

review: Needs Fixing
lp:~aacid/unity8/departments updated
930. By Albert Astals Cid

Merge

931. By Albert Astals Cid

need new api

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Albert Astals Cid (aacid) wrote :

> Conflict?
> Also, you need to bump dep on unity-api.

Done.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
lp:~aacid/unity8/departments updated
932. By Albert Astals Cid

Merge

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
lp:~aacid/unity8/departments updated
933. By Albert Astals Cid

hardcode colors in labels like we do everywhere

934. By Albert Astals Cid

We need the Dash departments in the temp scope too

This shows we need some refactoring of the code, it's not cool we need to add this into two places

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Michał Sawicz (saviq) wrote :

The dark overlay needs a fade in/out.

Switching between department pages feels too slow.

Chevrons look too big everywhere.

Broke it:
- open depts
- choose a subdep
- click on header to close while it's loading
→ invisible depts

We should probably have a better place for the activity indicator, 'cause it ends up stroked through with the dividers.

And we need to take this into the hands of designers, it doesn't feel great with the pages having different height as they move about.

review: Needs Fixing
lp:~aacid/unity8/departments updated
935. By Albert Astals Cid

todo++

936. By Albert Astals Cid

rename afterLineChildItem, name wasn't great

937. By Albert Astals Cid

Animate opacity of the blackRect

938. By Albert Astals Cid

Move the movement between lists faster

939. By Albert Astals Cid

Fix the calculation of maxHeight

940. By Albert Astals Cid

better leaf detection

Revision history for this message
Albert Astals Cid (aacid) wrote :

******
Broke it:
- open depts
- choose a subdep
- click on header to close while it's loading
→ invisible depts
******

There was a logic mistake in my side, fixed.

lp:~aacid/unity8/departments updated
941. By Albert Astals Cid

test for the last leaf fix

942. By Albert Astals Cid

Make the chevrons a bit smaller

943. By Albert Astals Cid

Make sure we animate the height of the list only when we need to

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
lp:~aacid/unity8/departments updated
944. By Albert Astals Cid

Make this chevron smaller too

945. By Albert Astals Cid

Some spacing here

Revision history for this message
Michał Sawicz (saviq) wrote :

See comments inline.

review: Needs Fixing
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Albert Astals Cid (aacid) wrote :

> Any reason why not anchors?
None, uses anchors now

> Anchors instead?
Ok

> ListView.isCurrentItem not good? originX not gonna bite us here? Also shouldn't x == contentX be enough, no need for the multiply?
No, ListView.isCurrentItem is not good enough because i want the transition animation to have finished (otherwise you get the growing animation and the horizonal animation at the same time if loaded is faster than the horizontal animation). No, no problem with originX since we're not replacing stuff in the front not changing its size so originX will always be 0. Yes, x is enough, changed.

> Column would save you those calculations.
Done

> Not needed?
It's better to set the contentWidth to something than 0, otherwise the flickable can decide that since your 0 in width doens't make any sense to flick vertically anyway. (This has happened in the past, not sure if still happens)

> Group anchors please.
Ok

> Shouldn't we use ThinDivider here?
Don't know, some places we use ThinDivider, some others the rectangle, i can use ThinDivider if you prefer. Also there's our ThinDivider

> Wonder if we could use ListItems from UITK here? It's a whole lotta code for something that we have in the UITK :|
Didn't see anything in the UITK that would save me much work from here. Maybe i did look wrong?

> Why do we need this? Wouldn't model: department just work? Do we need to wait for it to be loaded?
Yes, i don't want stuff to appear one by one in case the model loads very slowly

> This could probably be just one image?
Sure, done

lp:~aacid/unity8/departments updated
946. By Albert Astals Cid

Use a Column

947. By Albert Astals Cid

Use anchors

948. By Albert Astals Cid

Use anchors

949. By Albert Astals Cid

Use x instead of multiplication

950. By Albert Astals Cid

Group anchors

951. By Albert Astals Cid

Use just one image

952. By Albert Astals Cid

TODO++

953. By Albert Astals Cid

Remove index == departmentListView.currentIndex

Since x == departmentListView.contentX is more restrictive we don't need it

Revision history for this message
Michał Sawicz (saviq) wrote :

 * Did you perform an exploratory manual test run of the code change and any related functionality?
Yes.

 * Did CI run pass? If not, please explain why.
Oh yes!

review: Approve
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'debian/control'
2--- debian/control 2014-06-11 15:41:35 +0000
3+++ debian/control 2014-06-19 10:41:43 +0000
4@@ -17,7 +17,7 @@
5 libpulse-dev,
6 libqmenumodel-dev (>= 0.2.7),
7 libqt5xmlpatterns5-dev,
8- libunity-api-dev (>= 7.80.6),
9+ libunity-api-dev (>= 7.82),
10 libunity-mir-dev,
11 libusermetricsoutput1-dev,
12 libxcb1-dev,
13
14=== modified file 'plugins/Dash/listviewwithpageheader.cpp'
15--- plugins/Dash/listviewwithpageheader.cpp 2014-06-05 08:38:51 +0000
16+++ plugins/Dash/listviewwithpageheader.cpp 2014-06-19 10:41:43 +0000
17@@ -258,6 +258,8 @@
18 if (m_headerItem) {
19 m_headerItem->setParentItem(contentItem());
20 m_headerItem->setZ(1);
21+ m_previousHeaderImplicitHeight = m_headerItem->implicitHeight();
22+ QQuickItemPrivate::get(m_headerItem)->addItemChangeListener(this, QQuickItemPrivate::ImplicitHeight);
23 }
24 qreal newHeaderHeight = m_headerItem ? m_headerItem->height() : 0;
25 if (!m_visibleItems.isEmpty() && newHeaderHeight != oldHeaderHeight) {
26@@ -496,7 +498,15 @@
27
28 QQuickFlickable::viewportMoved(orient);
29 // qDebug() << "ListViewWithPageHeader::viewportMoved" << contentY();
30- qreal diff = m_previousContentY - contentY();
31+ const qreal diff = m_previousContentY - contentY();
32+ adjustHeader(diff);
33+ m_previousContentY = contentY();
34+ layout();
35+ polish();
36+}
37+
38+void ListViewWithPageHeader::adjustHeader(qreal diff)
39+{
40 const bool showHeaderAnimationRunning = m_contentYAnimation->isRunning() && contentYAnimationType == ContentYAnimationShowHeader;
41 if (m_headerItem) {
42 const auto oldHeaderItemShownHeight = m_headerItemShownHeight;
43@@ -558,10 +568,6 @@
44 adjustMinYExtent();
45 }
46 }
47-
48- m_previousContentY = contentY();
49- layout();
50- polish();
51 }
52
53 void ListViewWithPageHeader::createDelegateModel()
54@@ -1071,6 +1077,20 @@
55 }
56 }
57
58+void ListViewWithPageHeader::itemImplicitHeightChanged(QQuickItem *item)
59+{
60+ if (item == m_headerItem) {
61+ const qreal diff = m_headerItem->implicitHeight() - m_previousHeaderImplicitHeight;
62+ if (diff != 0) {
63+ adjustHeader(diff);
64+ m_previousHeaderImplicitHeight = m_headerItem->implicitHeight();
65+ layout();
66+ polish();
67+ m_contentHeightDirty = true;
68+ }
69+ }
70+}
71+
72 void ListViewWithPageHeader::headerHeightChanged(qreal newHeaderHeight, qreal oldHeaderHeight, qreal oldHeaderY)
73 {
74 const qreal heightDiff = newHeaderHeight - oldHeaderHeight;
75
76=== modified file 'plugins/Dash/listviewwithpageheader.h'
77--- plugins/Dash/listviewwithpageheader.h 2014-06-06 11:38:19 +0000
78+++ plugins/Dash/listviewwithpageheader.h 2014-06-19 10:41:43 +0000
79@@ -106,6 +106,7 @@
80 void viewportMoved(Qt::Orientations orient) override;
81 qreal minYExtent() const override;
82 void itemGeometryChanged(QQuickItem *item, const QRectF &newGeometry, const QRectF &oldGeometry) override;
83+ void itemImplicitHeightChanged(QQuickItem *item) override;
84 void updatePolish() override;
85
86 private Q_SLOTS:
87@@ -146,6 +147,7 @@
88 bool removeNonVisibleItems(qreal bufferFrom, qreal bufferTo);
89 ListItem *createItem(int modelIndex, bool asynchronous);
90
91+ void adjustHeader(qreal diff);
92 void adjustMinYExtent();
93 void updateClipItem();
94 void headerHeightChanged(qreal newHeaderHeight, qreal oldHeaderHeight, qreal oldHeaderY);
95@@ -178,6 +180,7 @@
96
97 QQuickItem *m_headerItem;
98 qreal m_previousContentY;
99+ qreal m_previousHeaderImplicitHeight;
100 qreal m_headerItemShownHeight; // The height of header shown when the header is shown outside its topmost position
101 // i.e. it's being shown after dragging down in the middle of the list
102 enum ContentYAnimationType { ContentYAnimationShowHeader, ContentYAnimationMaximizeVisibleArea };
103
104=== modified file 'qml/Components/PageHeader.qml'
105--- qml/Components/PageHeader.qml 2014-06-11 15:36:51 +0000
106+++ qml/Components/PageHeader.qml 2014-06-19 10:41:43 +0000
107@@ -27,12 +27,13 @@
108 property ListModel searchHistory
109 property var scope: null
110 property alias childItem: itemContainer.children
111+ property alias bottomItem: bottomContainer.children
112 property alias showBackButton: backButton.visible
113
114 signal backClicked
115
116- height: units.gu(8.5)
117- implicitHeight: units.gu(8.5)
118+ height: header.height + units.gu(2) + bottomContainer.height
119+ implicitHeight: header.height + units.gu(2) + bottomContainer.height
120
121 function triggerSearch() {
122 if (searchEntryEnabled) searchField.forceActiveFocus()
123@@ -404,9 +405,20 @@
124 top: header.bottom
125 left: parent.left
126 right: parent.right
127+ bottom: bottomContainer.top
128+ }
129+
130+ source: "graphics/PageHeaderBaseDivider.sci"
131+ }
132+
133+ Item {
134+ id: bottomContainer
135+
136+ anchors {
137+ left: parent.left
138+ right: parent.right
139 bottom: parent.bottom
140 }
141-
142- source: "graphics/PageHeaderBaseDivider.sci"
143+ height: childrenRect.height
144 }
145 }
146
147=== modified file 'qml/Dash/DashContent.qml'
148--- qml/Dash/DashContent.qml 2014-05-19 11:10:58 +0000
149+++ qml/Dash/DashContent.qml 2014-06-19 10:41:43 +0000
150@@ -151,7 +151,7 @@
151 item.previewListView = previewListView;
152 item.scope = Qt.binding(function() { return scope })
153 item.isCurrent = Qt.binding(function() { return visible && ListView.isCurrentItem })
154- item.tabBarHeight = dashPageHeader.implicitHeight;
155+ item.tabBarHeight = Qt.binding(function() { return dashPageHeader.implicitHeight; })
156 dashContent.scopeLoaded(item.scope.id)
157 }
158 Connections {
159@@ -217,6 +217,14 @@
160 onTriggered: tabBar.selectionMode = false
161 }
162 }
163+
164+ bottomItem: DashDepartments {
165+ scope: dashContentList.currentItem ? dashContentList.currentItem.theScope : null
166+ width: parent.width <= units.gu(60) ? parent.width : units.gu(40)
167+ anchors.right: parent.right
168+ windowHeight: dashContent.height
169+ windowWidth: dashContent.width
170+ }
171 }
172 }
173
174
175=== added file 'qml/Dash/DashDepartments.qml'
176--- qml/Dash/DashDepartments.qml 1970-01-01 00:00:00 +0000
177+++ qml/Dash/DashDepartments.qml 2014-06-19 10:41:43 +0000
178@@ -0,0 +1,202 @@
179+/*
180+ * Copyright (C) 2014 Canonical, Ltd.
181+ *
182+ * This program is free software; you can redistribute it and/or modify
183+ * it under the terms of the GNU General Public License as published by
184+ * the Free Software Foundation; version 3.
185+ *
186+ * This program is distributed in the hope that it will be useful,
187+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
188+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
189+ * GNU General Public License for more details.
190+ *
191+ * You should have received a copy of the GNU General Public License
192+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
193+ */
194+
195+import QtQuick 2.2
196+import Ubuntu.Components 0.1
197+
198+AbstractButton {
199+ id: root
200+ objectName: "dashDepartments"
201+
202+ property var scope: null
203+
204+ property bool showList: false
205+
206+ readonly property var currentDepartment: scope && scope.hasDepartments ? scope.getDepartment(scope.currentDepartmentId) : null
207+
208+ property alias windowWidth: blackRect.width
209+ property alias windowHeight: blackRect.height
210+
211+ // Are we drilling down the tree or up?
212+ property bool isGoingBack: false
213+
214+ visible: root.currentDepartment != null
215+
216+ height: visible ? units.gu(5) : 0
217+
218+ onClicked: {
219+ root.showList = !root.showList;
220+ }
221+
222+ Rectangle {
223+ id: blackRect
224+ color: "black"
225+ opacity: departmentListView.currentItem && departmentListView.currentItem.visible ? 0.3 : 0
226+ Behavior on opacity { UbuntuNumberAnimation { duration: UbuntuAnimation.SnapDuration } }
227+ anchors.top: departmentListView.top
228+ anchors.right: parent.right
229+ visible: opacity != 0
230+ }
231+
232+ Image {
233+ anchors {
234+ top: parent.top
235+ left: parent.left
236+ right: parent.right
237+ }
238+ fillMode: Image.Stretch
239+ source: "graphics/dash_divider_top_lightgrad.png"
240+ z: -1
241+ }
242+
243+ Image {
244+ anchors {
245+ bottom: parent.bottom
246+ left: parent.left
247+ right: parent.right
248+ }
249+ fillMode: Image.Stretch
250+ source: "graphics/dash_divider_top_darkgrad.png"
251+ z: -1
252+ }
253+
254+ Label {
255+ anchors.fill: parent
256+ anchors.margins: units.gu(2)
257+ verticalAlignment: Text.AlignVCenter
258+ text: root.currentDepartment ? root.currentDepartment.label : ""
259+ color: "gray" // TODO remove once we're a separate app
260+ }
261+
262+ Image {
263+ anchors.verticalCenter: parent.verticalCenter
264+ anchors.right: parent.right
265+ anchors.rightMargin: units.gu(2)
266+ rotation: showList ? 180 : 0
267+ source: "image://theme/dropdown-menu"
268+ sourceSize.height: parent.height - units.gu(2)
269+ sourceSize.width: units.gu(2)
270+ fillMode: Image.PreserveAspectFit
271+ }
272+
273+ // departmentListView is outside root
274+ ListView {
275+ id: departmentListView
276+ objectName: "departmentListView"
277+ orientation: ListView.Horizontal
278+ interactive: false
279+ clip: root.width != windowWidth
280+ model: ListModel {
281+ id: departmentModel
282+ // We have two roles
283+ // departmentId: the department id of the department the list represents
284+ // nullifyDepartment: overrides departmentId to be null
285+ // This is used to "clear" the delegate when going "right" on the tree
286+ }
287+ anchors {
288+ left: parent.left
289+ right: parent.right
290+ top: root.bottom
291+ }
292+ readonly property int maxHeight: (windowHeight - mapToItem(null, root.x, root.y).y) - units.gu(8)
293+ property int prevHeight: maxHeight
294+ height: currentItem ? currentItem.height : maxHeight
295+ onHeightChanged: {
296+ if (root.showList) {
297+ prevHeight = currentItem.desiredHeight;
298+ }
299+ }
300+ highlightMoveDuration: UbuntuAnimation.FastDuration
301+ delegate: DashDepartmentsList {
302+ objectName: "department" + index
303+ visible: height != 0
304+ width: departmentListView.width
305+ property real desiredHeight: {
306+ if (root.showList) {
307+ if (department && department.loaded && x == departmentListView.contentX)
308+ {
309+ return Math.min(implicitHeight, departmentListView.maxHeight);
310+ } else {
311+ return departmentListView.prevHeight;
312+ }
313+ } else {
314+ return 0;
315+ }
316+ }
317+ height: desiredHeight
318+ department: (nullifyDepartment || !scope) ? null : scope.getDepartment(departmentId)
319+ currentDepartment: root.currentDepartment
320+ onEnterDepartment: {
321+ scope.loadDepartment(newDepartmentId);
322+ // We only need to add a new item to the model
323+ // if we have children, otherwise just load it
324+ if (hasChildren) {
325+ isGoingBack = false;
326+ departmentModel.append({"departmentId": newDepartmentId, "nullifyDepartment": false});
327+ departmentListView.currentIndex++;
328+ } else {
329+ showList = false;
330+ }
331+ }
332+ onGoBackToParentClicked: {
333+ scope.loadDepartment(department.parentDepartmentId);
334+ isGoingBack = true;
335+ departmentModel.setProperty(departmentListView.currentIndex - 1, "nullifyDepartment", false);
336+ departmentListView.currentIndex--;
337+ }
338+ onAllDepartmentClicked: {
339+ showList = false;
340+ if (root.currentDepartment.parentDepartmentId == department.departmentId) {
341+ // For leaves we have to go to the parent too
342+ scope.loadDepartment(root.currentDepartment.parentDepartmentId);
343+ }
344+ }
345+ }
346+ onContentXChanged: {
347+ if (contentX == width * departmentListView.currentIndex) {
348+ if (isGoingBack) {
349+ departmentModel.remove(departmentListView.currentIndex + 1);
350+ } else {
351+ departmentModel.setProperty(departmentListView.currentIndex - 1, "nullifyDepartment", true);
352+ }
353+ }
354+ }
355+ }
356+
357+ InverseMouseArea {
358+ anchors.fill: departmentListView
359+ enabled: root.showList
360+ onClicked: root.showList = false
361+ }
362+
363+ onScopeChanged: {
364+ departmentModel.clear();
365+ if (scope && scope.hasDepartments) {
366+ departmentModel.append({"departmentId": scope.currentDepartmentId, "nullifyDepartment": false});
367+ }
368+ }
369+
370+ Connections {
371+ target: scope
372+ onHasDepartmentsChanged: {
373+ if (scope.hasDepartments) {
374+ departmentModel.append({"departmentId": scope.currentDepartmentId, "nullifyDepartment": false});
375+ } else {
376+ departmentModel.clear();
377+ }
378+ }
379+ }
380+}
381
382=== added file 'qml/Dash/DashDepartmentsList.qml'
383--- qml/Dash/DashDepartmentsList.qml 1970-01-01 00:00:00 +0000
384+++ qml/Dash/DashDepartmentsList.qml 2014-06-19 10:41:43 +0000
385@@ -0,0 +1,195 @@
386+/*
387+ * Copyright (C) 2014 Canonical, Ltd.
388+ *
389+ * This program is free software; you can redistribute it and/or modify
390+ * it under the terms of the GNU General Public License as published by
391+ * the Free Software Foundation; version 3.
392+ *
393+ * This program is distributed in the hope that it will be useful,
394+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
395+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
396+ * GNU General Public License for more details.
397+ *
398+ * You should have received a copy of the GNU General Public License
399+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
400+ */
401+
402+import QtQuick 2.2
403+import Ubuntu.Components 0.1
404+
405+Item {
406+ id: root
407+ property var department: null
408+ property var currentDepartment: null
409+ signal enterDepartment(var newDepartmentId, bool hasChildren)
410+ signal goBackToParentClicked()
411+ signal allDepartmentClicked()
412+
413+ readonly property int itemHeight: units.gu(5)
414+ implicitHeight: flickable.contentHeight
415+
416+ Rectangle {
417+ color: "white"
418+ anchors.fill: parent
419+ }
420+
421+ ActivityIndicator {
422+ id: loadingIndicator
423+ anchors.centerIn: parent
424+ running: !(department && department.loaded)
425+ }
426+ clip: true
427+
428+ Behavior on height {
429+ UbuntuNumberAnimation {
430+ id: heightAnimation
431+ duration: UbuntuAnimation.SnapDuration
432+ }
433+ }
434+
435+ Flickable {
436+ id: flickable
437+
438+ anchors.fill: parent
439+
440+ contentHeight: column.height
441+ contentWidth: width
442+
443+ Column {
444+ id: column
445+ width: parent.width
446+
447+ // TODO: check if SDK ListItems could be used here
448+ // and if not make them be useful since this is a quite common pattern
449+
450+ AbstractButton {
451+ id: backButton
452+ objectName: "backButton"
453+ width: parent.width
454+ visible: department && !department.isRoot || false
455+ height: itemHeight
456+
457+ onClicked: root.goBackToParentClicked();
458+
459+ Image {
460+ id: backImage
461+ anchors {
462+ verticalCenter: parent.verticalCenter
463+ left: parent.left
464+ leftMargin: units.gu(2)
465+ }
466+ source: "image://theme/back"
467+ sourceSize.height: parent.height - units.gu(3)
468+ sourceSize.width: units.gu(3)
469+ fillMode: Image.PreserveAspectFit
470+ }
471+
472+ Label {
473+ anchors {
474+ verticalCenter: parent.verticalCenter
475+ left: backImage.right
476+ leftMargin: units.gu(0.5)
477+ }
478+ text: department ? department.parentLabel : ""
479+ color: "gray" // TODO remove once we're a separate app
480+ }
481+
482+ Rectangle {
483+ anchors {
484+ bottom: parent.bottom
485+ left: parent.left
486+ right: parent.right
487+ leftMargin: units.gu(2)
488+ rightMargin: units.gu(2)
489+ }
490+ color: "gray"
491+ opacity: 0.2
492+ height: units.dp(1)
493+ }
494+ }
495+
496+ AbstractButton {
497+ id: allButton
498+ objectName: "allButton"
499+ width: parent.width
500+ visible: department && (!department.isRoot || (root.currentDepartment && !root.currentDepartment.isRoot && root.currentDepartment.parentDepartmentId == department.departmentId)) || false
501+ height: itemHeight
502+
503+ Label {
504+ anchors {
505+ verticalCenter: parent.verticalCenter
506+ left: parent.left
507+ leftMargin: units.gu(2)
508+ }
509+ text: department ? (department.allLabel != "" ? department.allLabel : department.label) : ""
510+ font.bold: true
511+ color: "gray" // TODO remove once we're a separate app
512+ }
513+
514+ Rectangle {
515+ anchors {
516+ bottom: parent.bottom
517+ left: parent.left
518+ right: parent.right
519+ leftMargin: units.gu(2)
520+ rightMargin: units.gu(2)
521+ }
522+ color: "gray"
523+ opacity: 0.2
524+ height: units.dp(1)
525+ }
526+
527+ onClicked: root.allDepartmentClicked();
528+ }
529+
530+ Repeater {
531+ model: department && department.loaded ? department : null
532+ clip: true
533+ delegate: AbstractButton {
534+ objectName: root.objectName + "child" + index
535+ height: root.itemHeight
536+ width: root.width
537+
538+ onClicked: root.enterDepartment(departmentId, hasChildren)
539+
540+ Label {
541+ anchors {
542+ verticalCenter: parent.verticalCenter
543+ left: parent.left
544+ leftMargin: units.gu(2)
545+ }
546+ text: label
547+ color: "gray" // TODO remove once we're a separate app
548+ }
549+
550+ Image {
551+ anchors {
552+ verticalCenter: parent.verticalCenter
553+ right: parent.right
554+ rightMargin: units.gu(2)
555+ }
556+ source: hasChildren ? "image://theme/chevron" : "graphics/tick.png"
557+ sourceSize.height: parent.height - units.gu(3)
558+ sourceSize.width: units.gu(3)
559+ fillMode: Image.PreserveAspectFit
560+ visible: hasChildren || isActive
561+ }
562+
563+ Rectangle {
564+ anchors {
565+ bottom: parent.bottom
566+ left: parent.left
567+ right: parent.right
568+ leftMargin: units.gu(2)
569+ rightMargin: units.gu(2)
570+ }
571+ color: "gray"
572+ opacity: 0.1
573+ height: units.dp(1)
574+ visible: index != department.count - 1
575+ }
576+ }
577+ }
578+ }
579+ }
580+}
581
582=== modified file 'qml/Dash/ScopeItem.qml'
583--- qml/Dash/ScopeItem.qml 2014-02-21 16:19:51 +0000
584+++ qml/Dash/ScopeItem.qml 2014-06-19 10:41:43 +0000
585@@ -31,6 +31,10 @@
586 signal gotoScope(string scopeId)
587 signal openScope(var scope)
588
589+ // TODO see how much code we can share
590+ // between here and other Dash parts, it's starting to have
591+ // too much duplicated code with the DashDepartments, etc
592+
593 Item {
594 id: scopeViewHolder
595
596@@ -79,6 +83,14 @@
597 fontSize: "x-large"
598 elide: Text.ElideRight
599 }
600+
601+ bottomItem: DashDepartments {
602+ scope: root.scope
603+ width: parent.width <= units.gu(60) ? parent.width : units.gu(40)
604+ anchors.right: parent.right
605+ windowHeight: root.height
606+ windowWidth: root.width
607+ }
608 }
609 }
610
611
612=== added file 'qml/Dash/graphics/tick@30.png'
613Binary files qml/Dash/graphics/tick@30.png 1970-01-01 00:00:00 +0000 and qml/Dash/graphics/tick@30.png 2014-06-19 10:41:43 +0000 differ
614=== modified file 'tests/mocks/Unity/CMakeLists.txt'
615--- tests/mocks/Unity/CMakeLists.txt 2014-05-27 07:45:46 +0000
616+++ tests/mocks/Unity/CMakeLists.txt 2014-06-19 10:41:43 +0000
617@@ -22,12 +22,14 @@
618 fake_scope.cpp
619 fake_scopes.cpp
620 fake_categories.cpp
621+ fake_department.cpp
622 fake_resultsmodel.cpp
623 fake_previewmodel.cpp
624 fake_previewstack.cpp
625 fake_previewwidgetmodel.cpp
626 fake_unity_plugin.cpp
627 ${SCOPES_API_INCLUDEDIR}/unity/shell/scopes/CategoriesInterface.h
628+ ${SCOPES_API_INCLUDEDIR}/unity/shell/scopes/DepartmentInterface.h
629 ${SCOPES_API_INCLUDEDIR}/unity/shell/scopes/PreviewModelInterface.h
630 ${SCOPES_API_INCLUDEDIR}/unity/shell/scopes/PreviewStackInterface.h
631 ${SCOPES_API_INCLUDEDIR}/unity/shell/scopes/PreviewWidgetModelInterface.h
632
633=== added file 'tests/mocks/Unity/fake_department.cpp'
634--- tests/mocks/Unity/fake_department.cpp 1970-01-01 00:00:00 +0000
635+++ tests/mocks/Unity/fake_department.cpp 2014-06-19 10:41:43 +0000
636@@ -0,0 +1,127 @@
637+/*
638+ * Copyright (C) 2014 Canonical, Ltd.
639+ *
640+ * This program is free software; you can redistribute it and/or modify
641+ * it under the terms of the GNU General Public License as published by
642+ * the Free Software Foundation; version 3.
643+ *
644+ * This program is distributed in the hope that it will be useful,
645+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
646+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
647+ * GNU General Public License for more details.
648+ *
649+ * You should have received a copy of the GNU General Public License
650+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
651+ */
652+
653+#include "fake_department.h"
654+
655+#include "fake_scope.h"
656+
657+#include <QTimer>
658+
659+Department::Department(const QString& departmentId, const QString& label, const QString& allLabel, const QString& parentId, const QString& parentLabel, Scope* scope)
660+ : m_departmentId(departmentId)
661+ , m_label(label)
662+ , m_allLabel(allLabel)
663+ , m_parentId(parentId)
664+ , m_parentLabel(parentLabel)
665+ , m_loaded(false)
666+ , m_scope(scope)
667+{
668+ QTimer::singleShot(1500, this, SLOT(slotLoaded()));
669+ connect(scope, SIGNAL(currentDepartmentIdChanged()), this, SLOT(slotCurrentDepartmentChanged()));
670+}
671+
672+QString Department::departmentId() const
673+{
674+ return m_departmentId;
675+}
676+
677+QString Department::label() const
678+{
679+ return m_label;
680+}
681+
682+QString Department::allLabel() const
683+{
684+ return m_allLabel;
685+}
686+
687+QString Department::parentDepartmentId() const
688+{
689+ return m_parentId;
690+}
691+
692+QString Department::parentLabel() const
693+{
694+ return m_parentLabel;
695+}
696+
697+void Department::slotLoaded()
698+{
699+ m_loaded = true;
700+ Q_EMIT loadedChanged();
701+}
702+
703+bool Department::loaded() const
704+{
705+ return m_loaded;
706+}
707+
708+int Department::count() const
709+{
710+ return rowCount();
711+}
712+
713+bool Department::isRoot() const
714+{
715+ return m_departmentId == "root";
716+}
717+
718+int Department::rowCount(const QModelIndex & /*parent*/) const
719+{
720+ if (!m_loaded || m_departmentId.startsWith("child") || m_departmentId == "middle3")
721+ return 0;
722+ else
723+ return 8;
724+}
725+
726+QHash<int, QByteArray> Department::roleNames() const
727+{
728+ QHash<int, QByteArray> res;
729+ res[RoleDepartmentId] = "departmentId";
730+ res[RoleLabel] = "label";
731+ res[RoleHasChildren] = "hasChildren";
732+ res[RoleIsActive] = "isActive";
733+ return res;
734+}
735+
736+QVariant Department::data(const QModelIndex &index, int role) const
737+{
738+ switch (role) {
739+ case RoleDepartmentId:
740+ if (m_departmentId == "root")
741+ return QString("middle%1").arg(index.row());
742+ else if (m_departmentId.startsWith("middle"))
743+ return QString("child%1%2").arg(m_departmentId).arg(index.row());
744+ break;
745+ case RoleLabel:
746+ return QString("%1Child%2").arg(m_departmentId).arg(index.row());
747+ break;
748+ case RoleHasChildren:
749+ return m_departmentId == "root" && index.row() != 3;
750+ break;
751+ case RoleIsActive:
752+ return m_scope->currentDepartmentId() == data(index, RoleDepartmentId);
753+ break;
754+ }
755+ return QVariant();
756+}
757+
758+void Department::slotCurrentDepartmentChanged()
759+{
760+ // This is wasteful, should only emit it if really something changed in this
761+ // deparment, but this is a mock, so no need to optimize
762+ Q_EMIT dataChanged(index(0, 0), index(rowCount() - 1, 0), QVector<int>() << RoleIsActive);
763+}
764
765=== added file 'tests/mocks/Unity/fake_department.h'
766--- tests/mocks/Unity/fake_department.h 1970-01-01 00:00:00 +0000
767+++ tests/mocks/Unity/fake_department.h 2014-06-19 10:41:43 +0000
768@@ -0,0 +1,61 @@
769+/*
770+ * Copyright (C) 2014 Canonical, Ltd.
771+ *
772+ * This program is free software; you can redistribute it and/or modify
773+ * it under the terms of the GNU General Public License as published by
774+ * the Free Software Foundation; version 3.
775+ *
776+ * This program is distributed in the hope that it will be useful,
777+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
778+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
779+ * GNU General Public License for more details.
780+ *
781+ * You should have received a copy of the GNU General Public License
782+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
783+ */
784+
785+#ifndef FAKE_DEPARTMENT_H
786+#define FAKE_DEPARTMENT_H
787+
788+#include <unity/shell/scopes/DepartmentInterface.h>
789+
790+class Scope;
791+
792+class Department : public unity::shell::scopes::DepartmentInterface
793+{
794+ Q_OBJECT
795+
796+public:
797+ Department(const QString& departmentId, const QString& label, const QString& allLabel, const QString& parentId, const QString& parentLabel, Scope* scope);
798+
799+ QString departmentId() const override;
800+ QString label() const override;
801+ QString allLabel() const override;
802+ QString parentDepartmentId() const override;
803+ QString parentLabel() const override;
804+ bool loaded() const override;
805+ int count() const override;
806+ bool isRoot() const override;
807+
808+ int rowCount(const QModelIndex &parent = QModelIndex()) const override;
809+ QHash<int, QByteArray> roleNames() const;
810+ QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
811+
812+public Q_SLOTS:
813+ void slotCurrentDepartmentChanged();
814+
815+private Q_SLOTS:
816+ void slotLoaded();
817+
818+private:
819+ QString m_departmentId;
820+ QString m_label;
821+ QString m_allLabel;
822+ QString m_parentId;
823+ QString m_parentLabel;
824+ bool m_loaded;
825+ QString m_currentDepartment;
826+ Scope *m_scope;
827+};
828+
829+#endif // FAKE_DEPARTMENT_H
830
831=== modified file 'tests/mocks/Unity/fake_scope.cpp'
832--- tests/mocks/Unity/fake_scope.cpp 2014-05-20 14:27:57 +0000
833+++ tests/mocks/Unity/fake_scope.cpp 2014-06-19 10:41:43 +0000
834@@ -15,6 +15,7 @@
835 */
836
837 #include "fake_scope.h"
838+#include "fake_department.h"
839 #include "fake_resultsmodel.h"
840
841 Scope::Scope(QObject* parent) : Scope(QString(), QString(), false, parent)
842@@ -28,6 +29,7 @@
843 , m_visible(visible)
844 , m_searching(false)
845 , m_isActive(false)
846+ , m_currentDeparment("root")
847 , m_previewRendererName("preview-generic")
848 , m_categories(new Categories(20, this))
849 {
850@@ -102,7 +104,7 @@
851 void Scope::setActive(const bool active) {
852 if (active != m_isActive) {
853 m_isActive = active;
854- Q_EMIT isActiveChanged(active);
855+ Q_EMIT isActiveChanged();
856 }
857 }
858
859@@ -142,3 +144,36 @@
860 {
861 qFatal("Scope::closeScope is not implemented");
862 }
863+
864+QString Scope::currentDepartmentId() const
865+{
866+ return m_currentDeparment;
867+}
868+
869+bool Scope::hasDepartments() const
870+{
871+ return true;
872+}
873+
874+unity::shell::scopes::DepartmentInterface* Scope::getDepartment(const QString& id)
875+{
876+ if (id.isEmpty())
877+ return nullptr;
878+
879+ QString parentId;
880+ QString parentLabel;
881+ if (id.startsWith("middle")) {
882+ parentId = "root";
883+ parentLabel = "root";
884+ } else if (id.startsWith("child")) {
885+ parentId = id.mid(5, 7);
886+ parentLabel = parentId;
887+ }
888+ return new Department(id, id, "all"+id, parentId, parentLabel, this);
889+}
890+
891+void Scope::loadDepartment(const QString& id)
892+{
893+ m_currentDeparment = id;
894+ Q_EMIT currentDepartmentIdChanged();
895+}
896
897=== modified file 'tests/mocks/Unity/fake_scope.h'
898--- tests/mocks/Unity/fake_scope.h 2014-05-20 14:27:57 +0000
899+++ tests/mocks/Unity/fake_scope.h 2014-06-19 10:41:43 +0000
900@@ -59,6 +59,11 @@
901 Q_INVOKABLE void cancelActivation() override;
902 Q_INVOKABLE void closeScope(unity::shell::scopes::ScopeInterface* scope) override;
903
904+ QString currentDepartmentId() const override;
905+ bool hasDepartments() const override;
906+ Q_INVOKABLE unity::shell::scopes::DepartmentInterface* getDepartment(const QString& id) override;
907+ Q_INVOKABLE void loadDepartment(const QString& id) override;
908+
909 protected:
910
911 QString m_id;
912@@ -71,6 +76,7 @@
913 bool m_visible;
914 bool m_searching;
915 bool m_isActive;
916+ QString m_currentDeparment;
917
918 QString m_previewRendererName;
919
920
921=== modified file 'tests/mocks/Unity/fake_scopes.cpp'
922--- tests/mocks/Unity/fake_scopes.cpp 2014-05-27 11:47:59 +0000
923+++ tests/mocks/Unity/fake_scopes.cpp 2014-06-19 10:41:43 +0000
924@@ -49,7 +49,7 @@
925
926 if (!m_loaded) {
927 m_loaded = true;
928- Q_EMIT loadedChanged(m_loaded);
929+ Q_EMIT loadedChanged();
930 }
931 }
932
933@@ -65,7 +65,7 @@
934
935 if (m_loaded) {
936 m_loaded = false;
937- Q_EMIT loadedChanged(m_loaded);
938+ Q_EMIT loadedChanged();
939 }
940 }
941
942
943=== modified file 'tests/mocks/Unity/fake_unity_plugin.cpp'
944--- tests/mocks/Unity/fake_unity_plugin.cpp 2014-05-20 15:16:49 +0000
945+++ tests/mocks/Unity/fake_unity_plugin.cpp 2014-06-19 10:41:43 +0000
946@@ -22,6 +22,7 @@
947 // local
948 #include "fake_scopes.h"
949 #include "fake_categories.h"
950+#include "fake_department.h"
951 #include "fake_previewmodel.h"
952 #include "fake_previewwidgetmodel.h"
953 #include "fake_resultsmodel.h"
954@@ -42,6 +43,7 @@
955 qmlRegisterType<Scopes>(uri, 0, 2, "Scopes");
956 qmlRegisterType<Scope>(uri, 0, 2, "MockScope");
957 qmlRegisterUncreatableType<unity::shell::scopes::ScopeInterface>(uri, 0, 2, "Scope", "Can't create Scope object in QML.");
958+ qmlRegisterUncreatableType<unity::shell::scopes::DepartmentInterface>(uri, 0, 2, "Department", "Can't create Department object in QML.");
959 qmlRegisterUncreatableType<unity::shell::scopes::CategoriesInterface>(uri, 0, 2, "Categories", "Can't create Categories object in QML.");
960 qmlRegisterUncreatableType<ResultsModel>(uri, 0, 2, "ResultsModel", "Can't create ResultsModel object in QML.");
961 qmlRegisterType<PreviewModel>(uri, 0, 2, "FakePreviewModel");
962
963=== modified file 'tests/qmltests/Dash/tst_DashContent.qml'
964--- tests/qmltests/Dash/tst_DashContent.qml 2014-05-27 07:46:14 +0000
965+++ tests/qmltests/Dash/tst_DashContent.qml 2014-06-19 10:41:43 +0000
966@@ -124,13 +124,13 @@
967
968 waitForRendering(categoryListView);
969
970- categoryListView.contentY = units.gu(11);
971- console.log("contentY", categoryListView.contentY);
972+ categoryListView.contentY = units.gu(15);
973+ tryCompare(categoryListView, "contentY", units.gu(15));
974
975 var startX = dashContentList.width/2;
976 var startY = dashContentList.height/2;
977 touchFlick(dashContentList, startX - units.gu(2), startY, startX, startY);
978- tryCompare(categoryListView, "contentY", units.gu(11) - categoryListView.pageHeader.height);
979+ tryCompare(categoryListView, "contentY", units.gu(15) - categoryListView.pageHeader.height);
980 }
981
982 function test_set_current_scope_reset() {
983@@ -407,5 +407,116 @@
984 var carouselLV = findChild(dashCategory1, "listView");
985 verify(carouselLV.tileWidth / carouselLV.tileHeight == cardTool.components["art"]["aspect-ratio"]);
986 }
987+
988+ function test_departments() {
989+ var dashDepartments = findChild(dashContent, "dashDepartments");
990+ compare(dashDepartments.visible, true);
991+ compare(dashDepartments.showList, false);
992+ waitForRendering(dashDepartments);
993+ mouseClick(dashDepartments, 0, 0);
994+ compare(dashDepartments.showList, true);
995+
996+ var departmentListView = findChild(dashDepartments, "departmentListView");
997+ compare(departmentListView.count, 1);
998+ tryCompare(departmentListView.currentItem.department, "loaded", true);
999+
1000+ waitForRendering(departmentListView);
1001+ waitForRendering(departmentListView.currentItem);
1002+
1003+ var allButton = findChild(dashDepartments, "allButton");
1004+ compare(allButton.visible, false);
1005+
1006+ var department = findChild(dashDepartments, "department0child3");
1007+ mouseClick(department, 0, 0);
1008+ compare(dashDepartments.showList, false);
1009+ tryCompare(dashDepartments.currentDepartment, "departmentId", "middle3");
1010+ tryCompare(departmentListView.currentItem.department, "departmentId", "root");
1011+
1012+ mouseClick(dashDepartments, 0, 0);
1013+ compare(dashDepartments.showList, true);
1014+ waitForRendering(departmentListView);
1015+ waitForRendering(departmentListView.currentItem);
1016+ compare(allButton.visible, true);
1017+
1018+ mouseClick(allButton, 0, 0);
1019+ compare(dashDepartments.showList, false);
1020+ tryCompare(dashDepartments.currentDepartment, "departmentId", "root");
1021+ tryCompare(departmentListView.currentItem.department, "departmentId", "root");
1022+
1023+ mouseClick(dashDepartments, 0, 0);
1024+ compare(dashDepartments.showList, true);
1025+ waitForRendering(departmentListView);
1026+ waitForRendering(departmentListView.currentItem);
1027+ compare(allButton.visible, false);
1028+
1029+ department = findChild(dashDepartments, "department0child2");
1030+ mouseClick(department, 0, 0);
1031+ compare(dashDepartments.showList, true);
1032+ tryCompare(dashDepartments.currentDepartment, "departmentId", "middle2");
1033+ tryCompare(departmentListView.currentItem.department, "departmentId", "middle2");
1034+
1035+ var departmentList1 = findChild(dashDepartments, "department1");
1036+ allButton = findChild(departmentList1, "allButton");
1037+ var backButton = findChild(findChild(departmentList1, "department1"), "backButton");
1038+ compare(allButton.visible, true);
1039+ compare(backButton.visible, true);
1040+
1041+ mouseClick(allButton, 0, 0);
1042+ compare(dashDepartments.showList, false);
1043+ tryCompare(dashDepartments.currentDepartment, "departmentId", "middle2");
1044+ tryCompare(departmentListView.currentItem.department, "departmentId", "middle2");
1045+
1046+ mouseClick(dashDepartments, 0, 0);
1047+ compare(dashDepartments.showList, true);
1048+ waitForRendering(departmentListView);
1049+ waitForRendering(departmentListView.currentItem);
1050+ compare(allButton.visible, true);
1051+ compare(backButton.visible, true);
1052+
1053+ tryCompare(departmentList1.department, "loaded", true);
1054+ department = findChild(dashDepartments, "department1child2");
1055+ mouseClick(department, 0, 0);
1056+ compare(dashDepartments.showList, false);
1057+ tryCompare(dashDepartments.currentDepartment, "departmentId", "childmiddle22");
1058+ tryCompare(departmentListView.currentItem.department, "departmentId", "middle2");
1059+
1060+ mouseClick(dashDepartments, 0, 0);
1061+ compare(dashDepartments.showList, true);
1062+ waitForRendering(departmentListView);
1063+ waitForRendering(departmentListView.currentItem);
1064+
1065+ tryCompare(departmentList1.department, "loaded", true);
1066+ department = findChild(dashDepartments, "department1child3");
1067+ mouseClick(department, 0, 0);
1068+ compare(dashDepartments.showList, false);
1069+ tryCompare(dashDepartments.currentDepartment, "departmentId", "childmiddle23");
1070+ tryCompare(departmentListView.currentItem.department, "departmentId", "middle2");
1071+
1072+ mouseClick(dashDepartments, 0, 0);
1073+ compare(dashDepartments.showList, true);
1074+ waitForRendering(departmentListView);
1075+ waitForRendering(departmentListView.currentItem);
1076+ mouseClick(backButton, 0, 0);
1077+
1078+ tryCompare(dashDepartments.currentDepartment, "departmentId", "root");
1079+ tryCompare(departmentListView.currentItem.department, "departmentId", "root");
1080+ compare(dashDepartments.showList, true);
1081+ mouseClick(dashDepartments, 0, 0);
1082+ compare(dashDepartments.showList, false);
1083+
1084+ mouseClick(dashDepartments, 0, 0);
1085+ compare(dashDepartments.showList, true);
1086+ tryCompare(departmentListView.currentItem.department, "loaded", true);
1087+ department = findChild(dashDepartments, "department0child2");
1088+ mouseClick(department, 0, 0);
1089+ compare(dashDepartments.showList, true);
1090+ departmentList1 = findChild(dashDepartments, "department1");
1091+ compare(departmentList1.department.loaded, false);
1092+ tryCompare(dashDepartments.currentDepartment, "departmentId", "middle2");
1093+ allButton = findChild(departmentList1, "allButton");
1094+ tryCompare(dashDepartments.currentDepartment, "departmentId", "middle2");
1095+ mouseClick(allButton, 0, 0);
1096+ tryCompare(dashDepartments.currentDepartment, "departmentId", "middle2");
1097+ }
1098 }
1099 }

Subscribers

People subscribed via source and target branches