on xenial help sign in
Improvements for the appdrawer
13a79d1Michael Zanetti
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+78−5
@@ -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
@@ -47,8 +48,10 @@ FocusScope {
47 if (event.text.trim() !== "") {
48 if (event.text.trim() !== "") {
48 focusInput();
49 focusInput();
49 searchField.text = event.text;
50 searchField.text = event.text;
50− event.accepted = true;
51 }
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;
52 }
55 }
53
56
54 Settings {
57 Settings {
@@ -88,6 +91,9 @@ FocusScope {
88 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) }
89 placeholderText: i18n.tr("Search…")
92 placeholderText: i18n.tr("Search…")
90 focus: true
93 focus: true
94+
95+ KeyNavigation.down: sections
96+
91 onAccepted: {
97 onAccepted: {
92 if (searchField.displayText != "" && listLoader.item && listLoader.item.currentItem) {
98 if (searchField.displayText != "" && listLoader.item && listLoader.item.currentItem) {
93 root.applicationSelected(listLoader.item.getFirstAppId());
99 root.applicationSelected(listLoader.item.getFirstAppId());
@@ -104,7 +110,14 @@ FocusScope {
104
110
105 Sections {
111 Sections {
106 id: sections
112 id: sections
113+ objectName: "drawerSections"
107 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+
108 actions: [
121 actions: [
109 Action {
122 Action {
110 text: i18n.ctr("Apps sorted alphabetically", "A-Z")
123 text: i18n.ctr("Apps sorted alphabetically", "A-Z")
@@ -124,9 +137,45 @@ FocusScope {
124 }
137 }
125 }
138 }
126
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+
127 Loader {
169 Loader {
128 id: listLoader
170 id: listLoader
171+ objectName: "drawerListLoader"
129− 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 }
173+
174+ KeyNavigation.up: headerFocusScope
175+ KeyNavigation.down: searchField
176+ KeyNavigation.backtab: headerFocusScope
177+ KeyNavigation.tab: searchField
178+
130 sourceComponent: {
179 sourceComponent: {
131 switch (sections.selectedIndex) {
180 switch (sections.selectedIndex) {
132 case 0: return aToZComponent;
181 case 0: return aToZComponent;
@@ -176,10 +225,13 @@ FocusScope {
176 Component {
225 Component {
177 id: mostUsedComponent
226 id: mostUsedComponent
178 DrawerListView {
227 DrawerListView {
228+ id: mostUsedListView
179
229
180 header: MoreAppsHeader {
230 header: MoreAppsHeader {
181 width: parent.width
231 width: parent.width
182 height: units.gu(6)
232 height: units.gu(6)
233+ highlighted: headerFocusScope.activeFocus
234+ onClicked: headerFocusScope.trigger();
183 }
235 }
184
236
185 model: AppDrawerProxyModel {
237 model: AppDrawerProxyModel {
@@ -189,7 +241,8 @@ FocusScope {
189 }
241 }
190
242
191 delegate: UbuntuShape {
243 delegate: UbuntuShape {
192− width: parent.width
244+ width: parent.width - units.gu(2)
245+ anchors.horizontalCenter: parent.horizontalCenter
193 color: "#20ffffff"
246 color: "#20ffffff"
194 aspect: UbuntuShape.Flat
247 aspect: UbuntuShape.Flat
195 // NOTE: Cannot use gridView.rows here as it would evaluate to 0 at first and only update later,
248 // NOTE: Cannot use gridView.rows here as it would evaluate to 0 at first and only update later,
@@ -205,6 +258,9 @@ FocusScope {
205 bottomMargin: units.gu(1)
258 bottomMargin: units.gu(1)
206 clip: true
259 clip: true
207
260
261+ interactive: true
262+ focus: index == mostUsedListView.currentIndex
263+
208 model: sortProxyModel
264 model: sortProxyModel
209
265
210 delegateWidth: units.gu(8)
266 delegateWidth: units.gu(8)
@@ -218,10 +274,13 @@ FocusScope {
218 Component {
274 Component {
219 id: aToZComponent
275 id: aToZComponent
220 DrawerListView {
276 DrawerListView {
277+ id: aToZListView
221
278
222 header: MoreAppsHeader {
279 header: MoreAppsHeader {
223 width: parent.width
280 width: parent.width
224 height: units.gu(6)
281 height: units.gu(6)
282+ highlighted: headerFocusScope.activeFocus
283+ onClicked: headerFocusScope.trigger();
225 }
284 }
226
285
227 model: AppDrawerProxyModel {
286 model: AppDrawerProxyModel {
@@ -231,7 +290,8 @@ FocusScope {
231 }
290 }
232
291
233 delegate: UbuntuShape {
292 delegate: UbuntuShape {
234− width: parent.width
293+ width: parent.width - units.gu(2)
294+ anchors.horizontalCenter: parent.horizontalCenter
235 color: "#20ffffff"
295 color: "#20ffffff"
236 aspect: UbuntuShape.Flat
296 aspect: UbuntuShape.Flat
237
297
@@ -253,7 +313,8 @@ FocusScope {
253 anchors { left: parent.left; top: categoryNameLabel.bottom; right: parent.right; topMargin: units.gu(1) }
313 anchors { left: parent.left; top: categoryNameLabel.bottom; right: parent.right; topMargin: units.gu(1) }
254 height: rows * delegateHeight
314 height: rows * delegateHeight
255
315
256− interactive: false
316+ interactive: true
317+ focus: index == aToZListView.currentIndex
257
318
258 model: AppDrawerProxyModel {
319 model: AppDrawerProxyModel {
259 id: categoryModel
320 id: categoryModel
@@ -272,10 +333,13 @@ FocusScope {
272 Component {
333 Component {
273 id: drawerDelegateComponent
334 id: drawerDelegateComponent
274 AbstractButton {
335 AbstractButton {
336+ id: drawerDelegate
275 width: GridView.view.cellWidth
337 width: GridView.view.cellWidth
276 height: units.gu(10)
338 height: units.gu(10)
277 objectName: "drawerItem_" + model.appId
339 objectName: "drawerItem_" + model.appId
278
340
341+ readonly property bool focused: index === GridView.view.currentIndex && GridView.view.activeFocus
342+
279 onClicked: root.applicationSelected(model.appId)
343 onClicked: root.applicationSelected(model.appId)
280
344
281 Column {
345 Column {
@@ -299,6 +363,15 @@ FocusScope {
299 source: model.icon
363 source: model.icon
300 }
364 }
301 sourceFillMode: UbuntuShape.PreserveAspectCrop
365 sourceFillMode: UbuntuShape.PreserveAspectCrop
366+
367+ StyledItem {
368+ styleName: "FocusShape"
369+ anchors.fill: parent
370+ StyleHints {
371+ visible: drawerDelegate.focused
372+ radius: units.gu(2.55)
373+ }
374+ }
302 }
375 }
303
376
304 Label {
377 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+6−10
@@ -87,14 +87,14 @@ FocusScope {
87 superPressTimer.stop();
87 superPressTimer.stop();
88 superLongPressTimer.stop();
88 superLongPressTimer.stop();
89 } else {
89 } else {
90+ switchToNextState("");
91+ root.focus = false;
90 if (panel.highlightIndex == -1) {
92 if (panel.highlightIndex == -1) {
91− showDashHome();
93+ root.showDashHome();
92 } else if (panel.highlightIndex >= 0){
94 } else if (panel.highlightIndex >= 0){
93 launcherApplicationSelected(LauncherModel.get(panel.highlightIndex).appId);
95 launcherApplicationSelected(LauncherModel.get(panel.highlightIndex).appId);
94 }
96 }
95 panel.highlightIndex = -2;
97 panel.highlightIndex = -2;
96− switchToNextState("");
97− root.focus = false;
98 }
98 }
99 }
99 }
100
100
@@ -210,7 +210,7 @@ FocusScope {
210 case Qt.Key_Return:
210 case Qt.Key_Return:
211 case Qt.Key_Space:
211 case Qt.Key_Space:
212 if (panel.highlightIndex == -1) {
212 if (panel.highlightIndex == -1) {
213− showDashHome();
213+ root.showDashHome();
214 } else if (panel.highlightIndex >= 0) {
214 } else if (panel.highlightIndex >= 0) {
215 launcherApplicationSelected(LauncherModel.get(panel.highlightIndex).appId);
215 launcherApplicationSelected(LauncherModel.get(panel.highlightIndex).appId);
216 }
216 }
@@ -473,9 +473,7 @@ FocusScope {
473 }
473 }
474 onPassed: {
474 onPassed: {
475 if (root.drawerEnabled) {
475 if (root.drawerEnabled) {
476− root.switchToNextState("drawer");
476+ root.openDrawer()
477− root.focus = true;
478− drawer.focus = true;
479 }
477 }
480 }
478 }
481
479
@@ -551,9 +549,7 @@ FocusScope {
551 if (!dragging) {
549 if (!dragging) {
552 if (distance > panel.width / 2) {
550 if (distance > panel.width / 2) {
553 if (root.drawerEnabled && distance > panel.width * 3 && dragDirection() !== "left") {
551 if (root.drawerEnabled && distance > panel.width * 3 && dragDirection() !== "left") {
554− root.switchToNextState("drawer");
552+ root.openDrawer(false)
555− root.focus = true;
556− drawer.focus = true;
557 } else {
553 } else {
558 root.switchToNextState("visible");
554 root.switchToNextState("visible");
559 }
555 }
qml/Launcher/LauncherDelegate.qml+8−9
@@ -124,15 +124,14 @@ Item {
124 height: parent.itemHeight + units.gu(1)
124 height: parent.itemHeight + units.gu(1)
125 anchors.centerIn: parent
125 anchors.centerIn: parent
126
126
127− Image {
127+ StyledItem {
128− objectName: "focusRing"
128+ styleName: "FocusShape"
129− anchors.centerIn: iconShape
129+ anchors.fill: iconShape
130− height: width * 15 / 16
130+ activeFocusOnTab: true
131− width: iconShape.width + units.gu(1)
131+ StyleHints {
132− source: "graphics/launcher-app-focus-ring.svg"
132+ visible: root.highlighted
133− sourceSize.width: width
133+ radius: units.gu(2.55)
134− sourceSize.height: height
134+ }
135− visible: root.highlighted
136 }
135 }
137
136
138 ProportionalShape {
137 ProportionalShape {
qml/Launcher/LauncherPanel.qml+11−6
@@ -80,6 +80,7 @@ Rectangle {
80 }
80 }
81
81
82 Rectangle {
82 Rectangle {
83+ id: bfb
83 objectName: "buttonShowDashHome"
84 objectName: "buttonShowDashHome"
84 width: parent.width
85 width: parent.width
85 height: width * .9
86 height: width * .9
@@ -100,13 +101,15 @@ Rectangle {
100 activeFocusOnPress: false
101 activeFocusOnPress: false
101 onClicked: root.showDashHome()
102 onClicked: root.showDashHome()
102 }
103 }
103− Rectangle {
104+
104− objectName: "bfbFocusHighlight"
105+ StyledItem {
106+ styleName: "FocusShape"
105 anchors.fill: parent
107 anchors.fill: parent
106− border.color: "white"
108+ anchors.margins: units.gu(.5)
107− border.width: units.dp(1)
109+ StyleHints {
108− color: "transparent"
109− visible: parent.highlighted
110+ visible: bfb.highlighted
111+ radius: 0
112+ }
110 }
113 }
111 }
114 }
112
115
@@ -788,6 +791,8 @@ Rectangle {
788 quickList.model = launcherListView.model.get(index).quickList;
791 quickList.model = launcherListView.model.get(index).quickList;
789 quickList.appId = launcherListView.model.get(index).appId;
792 quickList.appId = launcherListView.model.get(index).appId;
790 quickList.state = "open";
793 quickList.state = "open";
794+ root.highlightIndex = index;
795+ quickList.forceActiveFocus();
791 }
796 }
792
797
793 Item {
798 Item {
qml/Launcher/MoreAppsHeader.qml+12−5
@@ -4,17 +4,24 @@ 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 - units.gu(2)
11+ anchors.horizontalCenter: parent.horizontalCenter
14 height: parent.height - units.gu(1)
12 height: parent.height - units.gu(1)
15 color: "#20ffffff"
13 color: "#20ffffff"
16 aspect: UbuntuShape.Flat
14 aspect: UbuntuShape.Flat
17
15
16+ StyledItem {
17+ styleName: "FocusShape"
18+ anchors.fill: parent
19+ activeFocusOnTab: true
20+ StyleHints {
21+ visible: root.highlighted
22+ }
23+ }
24+
18 Row {
25 Row {
19 anchors.fill: parent
26 anchors.fill: parent
20 anchors.margins: units.gu(1)
27 anchors.margins: units.gu(1)
qml/Launcher/graphics/launcher-app-focus-ring.svgdeleted−12
@@ -1,12 +0,0 @@
1−<?xml version="1.0" encoding="UTF-8" standalone="no"?>
2−<svg width="172px" height="163px" viewBox="0 0 172 163" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sketch="http://www.bohemiancoding.com/sketch/ns">
3− <!-- Generator: Sketch 3.4.4 (17249) - http://www.bohemiancoding.com/sketch -->
4− <title>Shape</title>
5− <desc>Created with Sketch.</desc>
6− <defs></defs>
7− <g id="•-Launcher" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" sketch:type="MSPage">
8− <g id="Artboard-9" sketch:type="MSArtboardGroup" transform="translate(-163.000000, -1436.000000)" fill="#E95420">
9− <path d="M221.983432,1440 L221.983432,1440 C195.6127,1440 184.708233,1442.4723 177.107949,1450.10734 C169.476819,1457.77336 167,1468.79245 167,1495.3481 L167,1538.9019 C167,1565.45755 169.476819,1576.47664 177.107949,1584.14266 C184.708233,1591.7777 195.6127,1594.25 221.983432,1594.25 L276.016868,1594.25 C302.387595,1594.25 313.291998,1591.77771 320.892221,1584.14264 C328.523252,1576.47663 331,1565.45769 331,1538.9019 L331,1495.3481 C331,1468.79231 328.523252,1457.77337 320.892221,1450.10736 C313.291998,1442.47229 302.387595,1440 276.016868,1440 L221.983432,1440 Z M221.983432,1436 L276.016868,1436 C302.345315,1436 314.848953,1438.36655 323.727108,1447.2854 C332.633306,1456.23243 335,1468.85167 335,1495.3481 L335,1538.9019 C335,1565.39833 332.633306,1578.01757 323.727108,1586.9646 C314.848953,1595.88345 302.345315,1598.25 276.016868,1598.25 L221.983432,1598.25 C195.654985,1598.25 183.151291,1595.88345 174.273077,1586.96463 C165.366772,1578.0176 163,1565.39822 163,1538.9019 L163,1495.3481 C163,1468.85178 165.366772,1456.2324 174.273077,1447.28537 C183.151291,1438.36655 195.654985,1436 221.983432,1436 L221.983432,1436 Z" id="Shape" sketch:type="MSShapeGroup"></path>
10− </g>
11− </g>
12−</svg>
qml/Shell.qml+16−4
@@ -344,6 +344,16 @@ StyledItem {
344 onLoaded: {
344 onLoaded: {
345 item.objectName = "greeter"
345 item.objectName = "greeter"
346 }
346 }
347+ property bool openDrawerAfterUnlock: false
348+ Connections {
349+ target: greeter
350+ onActiveChanged: {
351+ if (!greeter.active && greeterLoader.openDrawerAfterUnlock) {
352+ launcher.openDrawer(false);
353+ greeterLoader.openDrawerAfterUnlock = false;
354+ }
355+ }
356+ }
347 }
357 }
348
358
349 Component {
359 Component {
@@ -435,9 +445,11 @@ StyledItem {
435 if (shell.mode === "greeter") {
445 if (shell.mode === "greeter") {
436 SessionBroadcast.requestHomeShown(AccountsService.user);
446 SessionBroadcast.requestHomeShown(AccountsService.user);
437 } else {
447 } else {
438− var animate = !LightDMService.greeter.active && !stages.shown;
448+ if (!greeter.active) {
439− dash.setCurrentScope(0, animate, false);
449+ launcher.openDrawer(false);
440− ApplicationManager.requestFocusApplication("unity8-dash");
450+ } else {
451+ greeterLoader.openDrawerAfterUnlock = true;
452+ }
441 }
453 }
442 }
454 }
443
455
@@ -513,7 +525,7 @@ StyledItem {
513 lockedVisible: shell.usageScenario == "desktop" && !settings.autohideLauncher && !panel.fullscreenMode
525 lockedVisible: shell.usageScenario == "desktop" && !settings.autohideLauncher && !panel.fullscreenMode
514 blurSource: greeter.shown ? greeter : stages
526 blurSource: greeter.shown ? greeter : stages
515 topPanelHeight: panel.panelHeight
527 topPanelHeight: panel.panelHeight
516− drawerEnabled: !greeter.shown
528+ drawerEnabled: !greeter.active
517
529
518 onShowDashHome: showHome()
530 onShowDashHome: showHome()
519 onLauncherApplicationSelected: {
531 onLauncherApplicationSelected: {
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/qmltests/Dash/tst_DashShell.qml−40
@@ -80,45 +80,5 @@ Item {
80 true, 15000);
80 true, 15000);
81 waitForRendering(findChild(dash, "scopeLoader0").item);
81 waitForRendering(findChild(dash, "scopeLoader0").item);
82 }
82 }
83−
84− function test_setShellHome() {
85− var dashContentList = findChild(dash, "dashContentList");
86− var startX = dash.width - units.gu(1);
87− var startY = dash.height / 2;
88− var stopX = units.gu(1)
89− var stopY = startY;
90− waitForRendering(dashContentList);
91− touchFlick(dash, startX, startY, stopX, stopY);
92− touchFlick(dash, startX, startY, stopX, stopY);
93− compare(dashContentList.currentIndex, 2, "Could not flick to scope id 2");
94−
95− // Flick the greeter away
96− var startX = shell.width - units.gu(1);
97− var startY = shell.height / 2;
98− var stopX = units.gu(1)
99− var stopY = startY;
100− touchFlick(shell, startX, startY, stopX, stopY);
101−
102− var greeter = findChild(shell, "greeter");
103− tryCompare(greeter, "shown", false);
104−
105− // bring in the launcher
106− var startX = units.gu(1);
107− var startY = shell.height / 2;
108− var stopX = shell.width / 3;
109− var stopY = startY;
110− touchFlick(shell, startX, startY, stopX, stopY);
111−
112− var launcher = findChild(shell, "launcher");
113− var buttonShowDashHome = findChild(launcher, "buttonShowDashHome");
114− tryCompare(buttonShowDashHome, "enabled", true);
115− tryCompare(launcher, "visibleWidth", launcher.panelWidth);
116−
117− // Make sure that opening the launcher doesn't change the scope
118− compare(dashContentList.currentIndex, 2, "Opening the launcher changed the current scope");
119−
120− mouseClick(buttonShowDashHome);
121− tryCompare(dashContentList, "currentIndex", 0);
122− }
123 }
83 }
124}
84}
tests/qmltests/Launcher/tst_Drawer.qml+42−3
@@ -136,6 +136,8 @@ StyledItem {
136 launcher.hide();
136 launcher.hide();
137 var drawer = findChild(launcher, "drawer");
137 var drawer = findChild(launcher, "drawer");
138 tryCompare(drawer, "x", -drawer.width);
138 tryCompare(drawer, "x", -drawer.width);
139+ var searchField = findChild(drawer, "searchField");
140+ searchField.text = "";
139 }
141 }
140
142
141 function test_revealByEdgeDrag() {
143 function test_revealByEdgeDrag() {
@@ -173,7 +175,7 @@ StyledItem {
173 var drawer = dragDrawerIntoView();
175 var drawer = dragDrawerIntoView();
174 waitForRendering(launcher);
176 waitForRendering(launcher);
175
177
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);
@@ -263,8 +265,8 @@ StyledItem {
263
265
264 function test_searchDirectly() {
266 function test_searchDirectly() {
265 var drawer = dragDrawerIntoView();
267 var drawer = dragDrawerIntoView();
266− waitForRendering(drawer);
268+ waitForRendering(launcher);
267− waitUntilTransitionsEnd(drawer);
269+ waitUntilTransitionsEnd(launcher);
268 tryCompare(drawer, "focus", true);
270 tryCompare(drawer, "focus", true);
269
271
270 var searchField = findChild(drawer, "searchField");
272 var searchField = findChild(drawer, "searchField");
@@ -272,5 +274,42 @@ StyledItem {
272 typeString("cam");
274 typeString("cam");
273 tryCompareFunction(function() { return searchField.displayText }, "cam");
275 tryCompareFunction(function() { return searchField.displayText }, "cam");
274 }
276 }
277+
278+ function test_kbdNavigation() {
279+ launcher.openDrawer(true);
280+ waitForRendering(launcher);
281+ waitUntilTransitionsEnd(launcher);
282+ compare(launcher.lastSelectedApplication, "");
283+
284+ var drawer = findChild(launcher, "drawer");
285+ var searchField = findChild(drawer, "searchField");
286+ var sections = findChild(drawer, "drawerSections");
287+ var header = findChild(drawer, "headerFocusScope");
288+ var listLoader = findChild(drawer, "drawerListLoader");
289+
290+ tryCompare(searchField, "activeFocus", true);
291+ // for some reason, even when the searchField has activeFocus already,
292+ // it won't react on key down events if they're coming in too early...
293+ // let's repeat the press for a bit before giving up
294+ tryCompareFunction(function() {
295+ wait(10)
296+ keyClick(Qt.Key_Down);
297+ return sections.activeFocus;
298+ }, true)
299+
300+ keyClick(Qt.Key_Down);
301+ tryCompare(header, "activeFocus", true);
302+
303+ keyClick(Qt.Key_Down);
304+ tryCompare(listLoader, "activeFocus", true);
305+
306+ keyClick(Qt.Key_Down);
307+ keyClick(Qt.Key_Left);
308+ tryCompare(listLoader, "activeFocus", true);
309+
310+ keyClick(Qt.Key_Enter);
311+
312+ compare(launcher.lastSelectedApplication, "calendar-app");
313+ }
275 }
314 }
276}
315}
tests/qmltests/Launcher/tst_Launcher.qml+5−6
@@ -371,18 +371,17 @@ Rectangle {
371 function assertFocusOnIndex(index) {
371 function assertFocusOnIndex(index) {
372 var launcherPanel = findChild(launcher, "launcherPanel");
372 var launcherPanel = findChild(launcher, "launcherPanel");
373 var launcherListView = findChild(launcher, "launcherListView");
373 var launcherListView = findChild(launcher, "launcherListView");
374− var bfbFocusHighlight = findChild(launcher, "bfbFocusHighlight");
374+ var bfb = findChild(launcher, "buttonShowDashHome");
375
375
376 waitForRendering(launcher);
376 waitForRendering(launcher);
377 tryCompare(launcherPanel, "highlightIndex", index);
377 tryCompare(launcherPanel, "highlightIndex", index);
378− compare(bfbFocusHighlight.visible, index === -1);
378+ compare(bfb.highlighted, index === -1);
379 for (var i = 0; i < launcherListView.count; i++) {
379 for (var i = 0; i < launcherListView.count; i++) {
380 var item = findChild(launcher, "launcherDelegate" + i);
380 var item = findChild(launcher, "launcherDelegate" + i);
381 // Delegates might be destroyed when not visible. We can't check if they paint a focus highlight.
381 // Delegates might be destroyed when not visible. We can't check if they paint a focus highlight.
382 // Make sure the requested index does have focus. for the others, try best effort to check if they don't
382 // Make sure the requested index does have focus. for the others, try best effort to check if they don't
383 if (index === i || item) {
383 if (index === i || item) {
384− var focusRing = findChild(item, "focusRing")
385− tryCompare(focusRing, "visible", index === i);
384+ tryCompare(item, "highlighted", index === i);
386 }
385 }
387 }
386 }
388 }
387 }
@@ -1190,13 +1189,13 @@ Rectangle {
1190 }
1189 }
1191
1190
1192 function test_keyboardNavigation(data) {
1191 function test_keyboardNavigation(data) {
1193− var bfbFocusHighlight = findChild(launcher, "bfbFocusHighlight");
1192+ var bfb = findChild(launcher, "buttonShowDashHome");
1194 var quickList = findChild(launcher, "quickList");
1193 var quickList = findChild(launcher, "quickList");
1195 var launcherPanel = findChild(launcher, "launcherPanel");
1194 var launcherPanel = findChild(launcher, "launcherPanel");
1196 var launcherListView = findChild(launcher, "launcherListView");
1195 var launcherListView = findChild(launcher, "launcherListView");
1197 var last = launcherListView.count - 1;
1196 var last = launcherListView.count - 1;
1198
1197
1199− compare(bfbFocusHighlight.visible, false);
1198+ compare(bfb.highlighted, false);
1200 launcher.openForKeyboardNavigation();
1199 launcher.openForKeyboardNavigation();
1201 tryCompare(launcherPanel, "x", 0);
1200 tryCompare(launcherPanel, "x", 0);
1202 waitForRendering(launcher);
1201 waitForRendering(launcher);
tests/qmltests/tst_Shell.qml+5−64
@@ -746,22 +746,6 @@ Rectangle {
746 mockNotificationsModel.append(n)
746 mockNotificationsModel.append(n)
747 }
747 }
748
748
749− function test_ClickUbuntuIconInLauncherTakesToAppsAndResetSearchString() {
750− loadShell("phone");
751− swipeAwayGreeter();
752− dragLauncherIntoView();
753− dashCommunicatorSpy.clear();
754−
755− var launcher = findChild(shell, "launcher");
756− var dashIcon = findChild(launcher, "dashItem");
757− verify(dashIcon != undefined);
758− mouseClick(dashIcon);
759−
760− tryCompare(ApplicationManager, "focusedApplicationId", "unity8-dash");
761−
762− compare(dashCommunicatorSpy.count, 1);
763− }
764−
765 function test_suspend() {
749 function test_suspend() {
766 loadShell("phone");
750 loadShell("phone");
767 swipeAwayGreeter();
751 swipeAwayGreeter();
@@ -1378,47 +1362,6 @@ Rectangle {
1378 tryCompare(stage, "state", "spread");
1362 tryCompare(stage, "state", "spread");
1379 }
1363 }
1380
1364
1381− function test_tapUbuntuIconInLauncherOverAppSpread() {
1382− launcherShowDashHomeSpy.clear();
1383−
1384− loadShell("phone");
1385− swipeAwayGreeter();
1386−
1387− waitUntilFocusedApplicationIsShowingItsSurface();
1388−
1389− swipeFromRightEdgeToShowAppSpread();
1390−
1391− var launcher = findChild(shell, "launcher");
1392−
1393− dragLauncherIntoView();
1394−
1395− // Emulate a tap with a finger, where the touch position drifts during the tap.
1396− // This is to test the touch ownership changes. The tap is happening on the button
1397− // area but then drifting into the left edge drag area. This test makes sure
1398− // the touch ownership stays with the button and doesn't move over to the
1399− // left edge drag area.
1400− {
1401− var buttonShowDashHome = findChild(launcher, "buttonShowDashHome");
1402− touchFlick(buttonShowDashHome,
1403− buttonShowDashHome.width * 0.2, /* startPos.x */
1404− buttonShowDashHome.height * 0.8, /* startPos.y */
1405− buttonShowDashHome.width * 0.8, /* endPos.x */
1406− buttonShowDashHome.height * 0.2 /* endPos.y */);
1407− }
1408−
1409− compare(launcherShowDashHomeSpy.count, 1);
1410−
1411− // check that the stage has left spread mode.
1412− {
1413− var stage = findChild(shell, "stage");
1414− tryCompare(stage, "state", "staged");
1415− }
1416−
1417− // check that the launcher got dismissed
1418− var launcherPanel = findChild(shell, "launcherPanel");
1419− tryCompare(launcherPanel, "x", -launcherPanel.width);
1420− }
1421−
1422 function test_physicalHomeKeyPressDoesNothingWithActiveGreeter() {
1365 function test_physicalHomeKeyPressDoesNothingWithActiveGreeter() {
1423 loadShell("phone");
1366 loadShell("phone");
1424
1367
@@ -1873,7 +1816,7 @@ Rectangle {
1873 loadDesktopShellWithApps()
1816 loadDesktopShellWithApps()
1874 var launcher = findChild(shell, "launcher");
1817 var launcher = findChild(shell, "launcher");
1875 var stage = findChild(shell, "stage");
1818 var stage = findChild(shell, "stage");
1876− var bfb = findChild(launcher, "buttonShowDashHome");
1819+ var app1 = findChild(launcher, "launcherDelegate0");
1877
1820
1878 GSettingsController.setAutohideLauncher(!data.launcherLocked);
1821 GSettingsController.setAutohideLauncher(!data.launcherLocked);
1879 waitForRendering(shell);
1822 waitForRendering(shell);
@@ -1886,17 +1829,17 @@ Rectangle {
1886 if (!data.launcherLocked) {
1829 if (!data.launcherLocked) {
1887 revealLauncherByEdgePushWithMouse();
1830 revealLauncherByEdgePushWithMouse();
1888 tryCompare(launcher, "x", 0);
1831 tryCompare(launcher, "x", 0);
1889− mouseMove(bfb, bfb.width / 2, bfb.height / 2)
1832+ mouseMove(app1, app1.width / 2, app1.height / 2)
1890 waitForRendering(shell)
1833 waitForRendering(shell)
1891 }
1834 }
1892
1835
1893− mouseClick(bfb, bfb.width / 2, bfb.height / 2)
1836+ mouseClick(app1, app1.width / 2, app1.height / 2)
1894 if (!data.launcherLocked) {
1837 if (!data.launcherLocked) {
1895 tryCompare(launcher, "state", "")
1838 tryCompare(launcher, "state", "")
1896 }
1839 }
1897 tryCompare(stage, "state", "windowed")
1840 tryCompare(stage, "state", "windowed")
1898
1841
1899− tryCompare(ApplicationManager, "focusedApplicationId", "unity8-dash")
1842+ tryCompare(ApplicationManager, "focusedApplicationId", "dialer-app")
1900
1843
1901 keyRelease(Qt.Key_Alt);
1844 keyRelease(Qt.Key_Alt);
1902 }
1845 }
@@ -2220,10 +2163,8 @@ Rectangle {
2220 tryCompare(launcher, "state", "visible");
2163 tryCompare(launcher, "state", "visible");
2221 tryCompare(launcherPanel, "highlightIndex", -1);
2164 tryCompare(launcherPanel, "highlightIndex", -1);
2222 keyRelease(Qt.Key_Super_L, Qt.MetaModifier);
2165 keyRelease(Qt.Key_Super_L, Qt.MetaModifier);
2223− tryCompare(launcher, "state", data.launcherLocked ? "visible" : "");
2166+ tryCompare(launcher, "state", "drawer");
2224 tryCompare(launcherPanel, "highlightIndex", -2);
2167 tryCompare(launcherPanel, "highlightIndex", -2);
2225− tryCompare(ApplicationManager, "focusedApplicationId", "unity8-dash");
2226− tryCompare(stage, "focus", true)
2227 }
2168 }
2228
2169
2229 function test_longpressSuperOpensLauncherAndShortcutsOverlay() {
2170 function test_longpressSuperOpensLauncherAndShortcutsOverlay() {
tests/qmltests/tst_ShellWithPin.qml+17
@@ -550,5 +550,22 @@ Item {
550 var lockscreen = findChild(shell, "lockscreen");
550 var lockscreen = findChild(shell, "lockscreen");
551 verify(lockscreen.shown);
551 verify(lockscreen.shown);
552 }
552 }
553+
554+ function test_bfbOnLockedDevice() {
555+ var launcher = findChild(shell, "launcher");
556+ touchFlick(shell, units.gu(.5), shell.height / 2, units.gu(10), shell.height / 2);
557+
558+ tryCompare(launcher, "x", 0);
559+ tryCompare(launcher, "state", "visible");
560+
561+ waitForRendering(shell)
562+
563+ var bfb = findChild(launcher, "buttonShowDashHome");
564+ mouseClick(bfb, bfb.width / 2, bfb.height / 2);
565+
566+ enterPin("1234")
567+
568+ tryCompare(launcher, "state", "drawer");
569+ }
553 }
570 }
554}
571}