on xenial help sign in
merge lp:~mzanetti/unity8/appdrawer-improvements
c69314eLukáš Tinkl
data/com.canonical.Unity8.gschema.xml+5
@@ -53,6 +53,11 @@
53 <summary>Enable or disable the indicator pull down menus</summary>
53 <summary>Enable or disable the indicator pull down menus</summary>
54 <description>Toggle the availability of the indicator pull down menus</description>
54 <description>Toggle the availability of the indicator pull down menus</description>
55 </key>
55 </key>
56+ <key type="s" name="appstore-uri">
57+ <default>'scope://com.canonical.scopes.clickstore'</default>
58+ <summary>The uri to the app store</summary>
59+ <description>This will be used whenever the user triggers an action to open the app store.</description>
60+ </key>
56 </schema>
61 </schema>
57
62
58 <schema path="/com/canonical/unity8/greeter/" id="com.canonical.Unity8.Greeter" gettext-domain="unity8">
63 <schema path="/com/canonical/unity8/greeter/" id="com.canonical.Unity8.Greeter" gettext-domain="unity8">
plugins/Utils/appdrawerproxymodel.cpp+1−1
@@ -185,5 +185,5 @@ QString AppDrawerProxyModel::appId(int index) const
185 return adpm->appId(sourceIndex.row());
185 return adpm->appId(sourceIndex.row());
186 }
186 }
187 }
187 }
188− return nullptr;
188+ return QString();
189}
189}
qml/Launcher/Drawer.qml+89−4
@@ -20,6 +20,7 @@ import Unity.Launcher 0.1
20import Utils 0.1
20import Utils 0.1
21import "../Components"
21import "../Components"
22import Qt.labs.settings 1.0
22import Qt.labs.settings 1.0
23+import GSettings 1.0
23
24
24FocusScope {
25FocusScope {
25 id: root
26 id: root
@@ -43,6 +44,16 @@ FocusScope {
43 searchField.focus = true;
44 searchField.focus = true;
44 }
45 }
45
46
47+ Keys.onPressed: {
48+ if (event.text.trim() !== "") {
49+ focusInput();
50+ searchField.text = event.text;
51+ }
52+ // Catch all presses here in case the navigation lets something through
53+ // We never want to end up in the launcher with focus
54+ event.accepted = true;
55+ }
56+
46 Settings {
57 Settings {
47 property alias selectedTab: sections.selectedIndex
58 property alias selectedTab: sections.selectedIndex
48 }
59 }
@@ -76,9 +87,13 @@ FocusScope {
76
87
77 TextField {
88 TextField {
78 id: searchField
89 id: searchField
90+ objectName: "searchField"
79 anchors { left: parent.left; top: parent.top; right: parent.right; margins: units.gu(1) }
91 anchors { left: parent.left; top: parent.top; right: parent.right; margins: units.gu(1) }
80 placeholderText: i18n.tr("Search…")
92 placeholderText: i18n.tr("Search…")
81 focus: true
93 focus: true
94+
95+ KeyNavigation.down: sections
96+
82 onAccepted: {
97 onAccepted: {
83 if (searchField.displayText != "" && listLoader.item && listLoader.item.currentItem) {
98 if (searchField.displayText != "" && listLoader.item && listLoader.item.currentItem) {
84 root.applicationSelected(listLoader.item.getFirstAppId());
99 root.applicationSelected(listLoader.item.getFirstAppId());
@@ -95,14 +110,21 @@ FocusScope {
95
110
96 Sections {
111 Sections {
97 id: sections
112 id: sections
113+ objectName: "drawerSections"
98 width: parent.width
114 width: parent.width
115+
116+ KeyNavigation.up: searchField
117+ KeyNavigation.down: headerFocusScope
118+ KeyNavigation.backtab: searchField
119+ KeyNavigation.tab: headerFocusScope
120+
99 actions: [
121 actions: [
100 Action {
122 Action {
101 text: i18n.ctr("Apps sorted alphabetically", "A-Z")
123 text: i18n.ctr("Apps sorted alphabetically", "A-Z")
102 // TODO: Disabling this for now as we don't get the right input from u-a-l yet.
124 // TODO: Disabling this for now as we don't get the right input from u-a-l yet.
103−// },
125+ },
104−// Action {
126+ Action {
105−// text: i18n.ctr("Most used apps", "Most used")
127+ text: i18n.ctr("Most used apps", "Most used")
106 }
128 }
107 ]
129 ]
108
130
@@ -115,9 +137,45 @@ FocusScope {
115 }
137 }
116 }
138 }
117
139
140+ FocusScope {
141+ id: headerFocusScope
142+ objectName: "headerFocusScope"
143+ KeyNavigation.up: sections
144+ KeyNavigation.down: listLoader.item
145+ KeyNavigation.backtab: sections
146+ KeyNavigation.tab: listLoader.item
147+ activeFocusOnTab: true
148+
149+ GSettings {
150+ id: settings
151+ schema.id: "com.canonical.Unity8"
152+ }
153+
154+ Keys.onPressed: {
155+ switch (event.key) {
156+ case Qt.Key_Return:
157+ case Qt.Key_Enter:
158+ case Qt.Key_Space:
159+ trigger();
160+ event.accepted = true;
161+ }
162+ }
163+
164+ function trigger() {
165+ Qt.openUrlExternally(settings.appstoreUri)
166+ }
167+ }
168+
118 Loader {
169 Loader {
119 id: listLoader
170 id: listLoader
171+ objectName: "drawerListLoader"
120 anchors { left: parent.left; top: sectionsContainer.bottom; right: parent.right; bottom: parent.bottom; leftMargin: units.gu(1); rightMargin: units.gu(1) }
172 anchors { left: parent.left; top: sectionsContainer.bottom; right: parent.right; bottom: parent.bottom; leftMargin: units.gu(1); rightMargin: units.gu(1) }
173+
174+ KeyNavigation.up: headerFocusScope
175+ KeyNavigation.down: searchField
176+ KeyNavigation.backtab: headerFocusScope
177+ KeyNavigation.tab: searchField
178+
121 sourceComponent: {
179 sourceComponent: {
122 switch (sections.selectedIndex) {
180 switch (sections.selectedIndex) {
123 case 0: return aToZComponent;
181 case 0: return aToZComponent;
@@ -167,10 +225,13 @@ FocusScope {
167 Component {
225 Component {
168 id: mostUsedComponent
226 id: mostUsedComponent
169 DrawerListView {
227 DrawerListView {
228+ id: mostUsedListView
170
229
171 header: MoreAppsHeader {
230 header: MoreAppsHeader {
172 width: parent.width
231 width: parent.width
173 height: units.gu(6)
232 height: units.gu(6)
233+ highlighted: headerFocusScope.activeFocus
234+ onClicked: headerFocusScope.trigger();
174 }
235 }
175
236
176 model: AppDrawerProxyModel {
237 model: AppDrawerProxyModel {
@@ -196,6 +257,9 @@ FocusScope {
196 bottomMargin: units.gu(1)
257 bottomMargin: units.gu(1)
197 clip: true
258 clip: true
198
259
260+ interactive: true
261+ focus: index == mostUsedListView.currentIndex
262+
199 model: sortProxyModel
263 model: sortProxyModel
200
264
201 delegateWidth: units.gu(8)
265 delegateWidth: units.gu(8)
@@ -209,10 +273,13 @@ FocusScope {
209 Component {
273 Component {
210 id: aToZComponent
274 id: aToZComponent
211 DrawerListView {
275 DrawerListView {
276+ id: aToZListView
212
277
213 header: MoreAppsHeader {
278 header: MoreAppsHeader {
214 width: parent.width
279 width: parent.width
215 height: units.gu(6)
280 height: units.gu(6)
281+ highlighted: headerFocusScope.activeFocus
282+ onClicked: headerFocusScope.trigger();
216 }
283 }
217
284
218 model: AppDrawerProxyModel {
285 model: AppDrawerProxyModel {
@@ -244,7 +311,11 @@ FocusScope {
244 anchors { left: parent.left; top: categoryNameLabel.bottom; right: parent.right; topMargin: units.gu(1) }
311 anchors { left: parent.left; top: categoryNameLabel.bottom; right: parent.right; topMargin: units.gu(1) }
245 height: rows * delegateHeight
312 height: rows * delegateHeight
246
313
247− interactive: false
314+ interactive: true
315+ focus: index == aToZListView.currentIndex
316+ onFocusChanged: print("drawer grid", index, "has focus", focus)
317+
318+ onCurrentIndexChanged: print("grid currentIndex changed", currentIndex)
248
319
249 model: AppDrawerProxyModel {
320 model: AppDrawerProxyModel {
250 id: categoryModel
321 id: categoryModel
@@ -263,10 +334,13 @@ FocusScope {
263 Component {
334 Component {
264 id: drawerDelegateComponent
335 id: drawerDelegateComponent
265 AbstractButton {
336 AbstractButton {
337+ id: drawerDelegate
266 width: GridView.view.cellWidth
338 width: GridView.view.cellWidth
267 height: units.gu(10)
339 height: units.gu(10)
268 objectName: "drawerItem_" + model.appId
340 objectName: "drawerItem_" + model.appId
269
341
342+ readonly property bool focused: index === GridView.view.currentIndex && GridView.view.activeFocus
343+
270 onClicked: root.applicationSelected(model.appId)
344 onClicked: root.applicationSelected(model.appId)
271
345
272 Column {
346 Column {
@@ -290,6 +364,17 @@ FocusScope {
290 source: model.icon
364 source: model.icon
291 }
365 }
292 sourceFillMode: UbuntuShape.PreserveAspectCrop
366 sourceFillMode: UbuntuShape.PreserveAspectCrop
367+
368+ Image {
369+ objectName: "focusRing"
370+ anchors.centerIn: parent
371+ height: width * 15 / 16
372+ width: parent.width + units.gu(1)
373+ source: "graphics/launcher-app-focus-ring.svg"
374+ sourceSize.width: width
375+ sourceSize.height: height
376+ visible: drawerDelegate.focused
377+ }
293 }
378 }
294
379
295 Label {
380 Label {
qml/Launcher/DrawerGridView.qml+3−1
@@ -17,7 +17,7 @@
17import QtQuick 2.4
17import QtQuick 2.4
18import "../Components"
18import "../Components"
19
19
20−Item {
20+FocusScope {
21 id: root
21 id: root
22
22
23 property int delegateWidth: units.gu(10)
23 property int delegateWidth: units.gu(10)
@@ -25,6 +25,7 @@ Item {
25 property alias delegate: gridView.delegate
25 property alias delegate: gridView.delegate
26 property alias model: gridView.model
26 property alias model: gridView.model
27 property alias interactive: gridView.interactive
27 property alias interactive: gridView.interactive
28+ property alias currentIndex: gridView.currentIndex
28
29
29 property alias header: gridView.header
30 property alias header: gridView.header
30 property alias topMargin: gridView.topMargin
31 property alias topMargin: gridView.topMargin
@@ -37,6 +38,7 @@ Item {
37 id: gridView
38 id: gridView
38 anchors.fill: parent
39 anchors.fill: parent
39 leftMargin: spacing
40 leftMargin: spacing
41+ focus: true
40
42
41 readonly property int overflow: width - (root.columns * root.delegateWidth)
43 readonly property int overflow: width - (root.columns * root.delegateWidth)
42 readonly property real spacing: overflow / (root.columns)
44 readonly property real spacing: overflow / (root.columns)
qml/Launcher/DrawerListView.qml+6
@@ -25,6 +25,12 @@ ListView {
25 bottomMargin: units.gu(1)
25 bottomMargin: units.gu(1)
26 spacing: units.gu(1)
26 spacing: units.gu(1)
27 clip: true
27 clip: true
28+ focus: true
29+
30+ onActiveFocusChanged: {
31+ currentIndex = -1;
32+ currentIndex = 0;
33+ }
28
34
29 function getFirstAppId() {
35 function getFirstAppId() {
30 return model.appId(0);
36 return model.appId(0);
qml/Launcher/Launcher.qml+3−4
@@ -74,7 +74,7 @@ FocusScope {
74 } else {
74 } else {
75 superPressTimer.stop();
75 superPressTimer.stop();
76 superLongPressTimer.stop();
76 superLongPressTimer.stop();
77− launcher.switchToNextState("");
77+ switchToNextState("");
78 panel.shortcutHintsShown = false;
78 panel.shortcutHintsShown = false;
79 }
79 }
80 }
80 }
@@ -469,7 +469,7 @@ FocusScope {
469 }
469 }
470 onPassed: {
470 onPassed: {
471 if (root.drawerEnabled) {
471 if (root.drawerEnabled) {
472− root.switchToNextState("drawer");
472+ root.openDrawer()
473 }
473 }
474 }
474 }
475
475
@@ -545,8 +545,7 @@ FocusScope {
545 if (!dragging) {
545 if (!dragging) {
546 if (distance > panel.width / 2) {
546 if (distance > panel.width / 2) {
547 if (root.drawerEnabled && distance > panel.width * 3 && dragDirection() !== "left") {
547 if (root.drawerEnabled && distance > panel.width * 3 && dragDirection() !== "left") {
548− root.switchToNextState("drawer");
548+ root.openDrawer(false)
549− root.focus = true;
550 } else {
549 } else {
551 root.switchToNextState("visible");
550 root.switchToNextState("visible");
552 }
551 }
qml/Launcher/MoreAppsHeader.qml+2−5
@@ -4,15 +4,12 @@ import Ubuntu.Components 1.3
4AbstractButton {
4AbstractButton {
5 id: root
5 id: root
6
6
7− onClicked: {
7+ property bool highlighted: false
8− // TODO: Make this point to the snappy store as soon as we stop landing to vivid
9− Qt.openUrlExternally("scope://com.canonical.scopes.clickstore")
10− }
11
8
12 UbuntuShape {
9 UbuntuShape {
13 width: parent.width
10 width: parent.width
14 height: parent.height - units.gu(1)
11 height: parent.height - units.gu(1)
15− color: "#20ffffff"
12+ color: root.highlighted ? "red" : "#20ffffff"
16 aspect: UbuntuShape.Flat
13 aspect: UbuntuShape.Flat
17
14
18 Row {
15 Row {
tests/mocks/GSettings.1.0/fake_gsettings.cpp+14
@@ -29,6 +29,7 @@ GSettingsControllerQml::GSettingsControllerQml()
29 , m_edgeDragWidth(2)
29 , m_edgeDragWidth(2)
30 , m_enableLauncher(true)
30 , m_enableLauncher(true)
31 , m_enableIndicatorMenu(true)
31 , m_enableIndicatorMenu(true)
32+ , m_appstoreUri("http://uappexplorer.com")
32{
33{
33}
34}
34
35
@@ -173,6 +174,11 @@ void GSettingsControllerQml::setEnableIndicatorMenu(bool enableIndicatorMenu)
173 }
174 }
174}
175}
175
176
177+QString GSettingsControllerQml::appstoreUri() const
178+{
179+ return m_appstoreUri;
180+}
181+
176GSettingsSchemaQml::GSettingsSchemaQml(QObject *parent): QObject(parent) {
182GSettingsSchemaQml::GSettingsSchemaQml(QObject *parent): QObject(parent) {
177}
183}
178
184
@@ -376,6 +382,14 @@ QVariant GSettingsQml::enableIndicatorMenu() const
376 }
382 }
377}
383}
378
384
385+QVariant GSettingsQml::appstoreUri() const
386+{
387+ if (m_valid && m_schema->id() == "com.canonical.Unity8") {
388+ return GSettingsControllerQml::instance()->appstoreUri();
389+ }
390+ return QVariant();
391+}
392+
379void GSettingsQml::setLifecycleExemptAppids(const QVariant &appIds)
393void GSettingsQml::setLifecycleExemptAppids(const QVariant &appIds)
380{
394{
381 if (m_valid && m_schema->id() == "com.canonical.qtmir") {
395 if (m_valid && m_schema->id() == "com.canonical.qtmir") {
tests/mocks/GSettings.1.0/fake_gsettings.h+7
@@ -59,6 +59,7 @@ class GSettingsQml: public QObject, public QQmlParserStatus
59 Q_PROPERTY(QVariant edgeDragWidth READ edgeDragWidth WRITE setEdgeDragWidth NOTIFY edgeDragWidthChanged)
59 Q_PROPERTY(QVariant edgeDragWidth READ edgeDragWidth WRITE setEdgeDragWidth NOTIFY edgeDragWidthChanged)
60 Q_PROPERTY(QVariant enableLauncher READ enableLauncher WRITE setEnableLauncher NOTIFY enableLauncherChanged)
60 Q_PROPERTY(QVariant enableLauncher READ enableLauncher WRITE setEnableLauncher NOTIFY enableLauncherChanged)
61 Q_PROPERTY(QVariant enableIndicatorMenu READ enableIndicatorMenu WRITE setEnableIndicatorMenu NOTIFY enableIndicatorMenuChanged)
61 Q_PROPERTY(QVariant enableIndicatorMenu READ enableIndicatorMenu WRITE setEnableIndicatorMenu NOTIFY enableIndicatorMenuChanged)
62+ Q_PROPERTY(QVariant appstoreUri READ appstoreUri NOTIFY appstoreUriChanged)
62
63
63public:
64public:
64 GSettingsQml(QObject *parent = nullptr);
65 GSettingsQml(QObject *parent = nullptr);
@@ -77,6 +78,7 @@ public:
77 QVariant edgeDragWidth() const;
78 QVariant edgeDragWidth() const;
78 QVariant enableLauncher() const;
79 QVariant enableLauncher() const;
79 QVariant enableIndicatorMenu() const;
80 QVariant enableIndicatorMenu() const;
81+ QVariant appstoreUri() const;
80
82
81 void setDisableHeight(const QVariant &val);
83 void setDisableHeight(const QVariant &val);
82 void setPictureUri(const QVariant &str);
84 void setPictureUri(const QVariant &str);
@@ -101,6 +103,7 @@ Q_SIGNALS:
101 void edgeDragWidthChanged();
103 void edgeDragWidthChanged();
102 void enableLauncherChanged();
104 void enableLauncherChanged();
103 void enableIndicatorMenuChanged();
105 void enableIndicatorMenuChanged();
106+ void appstoreUriChanged();
104
107
105private:
108private:
106 GSettingsSchemaQml* m_schema;
109 GSettingsSchemaQml* m_schema;
@@ -147,6 +150,8 @@ public:
147 bool enableIndicatorMenu() const;
150 bool enableIndicatorMenu() const;
148 Q_INVOKABLE void setEnableIndicatorMenu(bool enableIndicatorMenu);
151 Q_INVOKABLE void setEnableIndicatorMenu(bool enableIndicatorMenu);
149
152
153+ QString appstoreUri() const;
154+
150Q_SIGNALS:
155Q_SIGNALS:
151 void disableHeightChanged();
156 void disableHeightChanged();
152 void pictureUriChanged(const QString&);
157 void pictureUriChanged(const QString&);
@@ -158,6 +163,7 @@ Q_SIGNALS:
158 void edgeDragWidthChanged(uint edgeDragWidth);
163 void edgeDragWidthChanged(uint edgeDragWidth);
159 void enableLauncherChanged(bool enableLauncher);
164 void enableLauncherChanged(bool enableLauncher);
160 void enableIndicatorMenuChanged(bool enableIndicatorMenu);
165 void enableIndicatorMenuChanged(bool enableIndicatorMenu);
166+ void appstoreUriChanged(const QString &appstoreUri);
161
167
162private:
168private:
163 GSettingsControllerQml();
169 GSettingsControllerQml();
@@ -172,6 +178,7 @@ private:
172 uint m_edgeDragWidth;
178 uint m_edgeDragWidth;
173 bool m_enableLauncher;
179 bool m_enableLauncher;
174 bool m_enableIndicatorMenu;
180 bool m_enableIndicatorMenu;
181+ QString m_appstoreUri;
175
182
176 static GSettingsControllerQml* s_controllerInstance;
183 static GSettingsControllerQml* s_controllerInstance;
177 QList<GSettingsQml *> m_registeredGSettings;
184 QList<GSettingsQml *> m_registeredGSettings;
tests/mocks/Unity/Launcher/MockAppDrawerModel.cpp+1−1
@@ -48,13 +48,13 @@ MockAppDrawerModel::MockAppDrawerModel(QObject *parent):
48 m_list.append(item);
48 m_list.append(item);
49 item = new MockLauncherItem("libreoffice", "/usr/share/applications/libreoffice.desktop","Libre Office", "libreoffice", this);
49 item = new MockLauncherItem("libreoffice", "/usr/share/applications/libreoffice.desktop","Libre Office", "libreoffice", this);
50 m_list.append(item);
50 m_list.append(item);
51− qDebug() << "mock model created";
52
51
53 qsrand(QDateTime::currentMSecsSinceEpoch() / 1000);
52 qsrand(QDateTime::currentMSecsSinceEpoch() / 1000);
54}
53}
55
54
56int MockAppDrawerModel::rowCount(const QModelIndex &parent) const
55int MockAppDrawerModel::rowCount(const QModelIndex &parent) const
57{
56{
57+ Q_UNUSED(parent)
58 return m_list.count();
58 return m_list.count();
59}
59}
60
60
tests/qmltests/Launcher/tst_Drawer.qml+56−7
@@ -26,6 +26,7 @@ import Unity.Test 0.1
26StyledItem {
26StyledItem {
27 id: root
27 id: root
28 theme.name: "Ubuntu.Components.Themes.SuruDark"
28 theme.name: "Ubuntu.Components.Themes.SuruDark"
29+ focus: true
29
30
30 width: units.gu(140)
31 width: units.gu(140)
31 height: units.gu(70)
32 height: units.gu(70)
@@ -108,6 +109,7 @@ StyledItem {
108 tryCompareFunction( function(){ return drawer.x === 0; }, true );
109 tryCompareFunction( function(){ return drawer.x === 0; }, true );
109 tryCompare(launcher, "state", "drawer");
110 tryCompare(launcher, "state", "drawer");
110 tryCompare(launcher, "drawerShown", true);
111 tryCompare(launcher, "drawerShown", true);
112+ return drawer;
111 }
113 }
112
114
113 function revealByEdgePush() {
115 function revealByEdgePush() {
@@ -134,6 +136,8 @@ StyledItem {
134 launcher.hide();
136 launcher.hide();
135 var drawer = findChild(launcher, "drawer");
137 var drawer = findChild(launcher, "drawer");
136 tryCompare(drawer, "x", -drawer.width);
138 tryCompare(drawer, "x", -drawer.width);
139+ var searchField = findChild(drawer, "searchField");
140+ searchField.text = "";
137 }
141 }
138
142
139 function test_revealByEdgeDrag() {
143 function test_revealByEdgeDrag() {
@@ -168,12 +172,10 @@ StyledItem {
168 function test_hideByDraggingDrawer(data) {
172 function test_hideByDraggingDrawer(data) {
169 launcher.lockedVisible = !data.autohide;
173 launcher.lockedVisible = !data.autohide;
170
174
171− dragDrawerIntoView();
175+ var drawer = dragDrawerIntoView();
172 waitForRendering(launcher);
176 waitForRendering(launcher);
173
177
174− var drawer = findChild(launcher, "drawer");
175−
176− mouseFlick(root, drawer.width - units.gu(1), drawer.height / 2, units.gu(2), drawer.height / 2, true, true);
178+ mouseFlick(root, drawer.width - units.gu(1), drawer.height / 2, units.gu(10), drawer.height / 2, true, true);
177
179
178 tryCompare(drawer.anchors, "rightMargin", 0);
180 tryCompare(drawer.anchors, "rightMargin", 0);
179 tryCompare(launcher, "state", data.endState);
181 tryCompare(launcher, "state", data.endState);
@@ -181,9 +183,7 @@ StyledItem {
181 }
183 }
182
184
183 function test_hideByClickingOutside() {
185 function test_hideByClickingOutside() {
184− dragDrawerIntoView();
186+ var drawer = dragDrawerIntoView();
185−
186− var drawer = findChild(launcher, "drawer");
187
187
188 mouseClick(root, drawer.width + units.gu(1), root.height / 2);
188 mouseClick(root, drawer.width + units.gu(1), root.height / 2);
189
189
@@ -260,5 +260,54 @@ StyledItem {
260
260
261 tryCompare(launcher, "state", data.endState)
261 tryCompare(launcher, "state", data.endState)
262 }
262 }
263+
264+ function test_searchDirectly() {
265+ var drawer = dragDrawerIntoView();
266+ waitForRendering(launcher);
267+ waitUntilTransitionsEnd(launcher);
268+ tryCompare(drawer, "focus", true);
269+
270+ var searchField = findChild(drawer, "searchField");
271+ verify(searchField);
272+ typeString("cam");
273+ tryCompare(searchField, "displayText", "cam");
274+ }
275+
276+ function test_kbdNavigation() {
277+ launcher.openDrawer(true);
278+ waitForRendering(launcher);
279+ waitUntilTransitionsEnd(launcher);
280+ compare(launcher.lastSelectedApplication, "");
281+
282+ var drawer = findChild(launcher, "drawer");
283+ var searchField = findChild(drawer, "searchField");
284+ var sections = findChild(drawer, "drawerSections");
285+ var header = findChild(drawer, "headerFocusScope");
286+ var listLoader = findChild(drawer, "drawerListLoader");
287+
288+ tryCompare(searchField, "activeFocus", true);
289+ // for some reason, even when the searchField has activeFocus already,
290+ // it won't react on key down events if they're coming in too early...
291+ // let's repeat the press for a bit before giving up
292+ tryCompareFunction(function() {
293+ wait(10)
294+ keyClick(Qt.Key_Down);
295+ return sections.activeFocus;
296+ }, true)
297+
298+ keyClick(Qt.Key_Down);
299+ tryCompare(header, "activeFocus", true);
300+
301+ keyClick(Qt.Key_Down);
302+ tryCompare(listLoader, "activeFocus", true);
303+
304+ keyClick(Qt.Key_Down);
305+ keyClick(Qt.Key_Left);
306+ tryCompare(listLoader, "activeFocus", true);
307+
308+ keyClick(Qt.Key_Enter);
309+
310+ compare(launcher.lastSelectedApplication, "calendar-app");
311+ }
263 }
312 }
264}
313}