on xenial help sign in
Fix edge cases in Drawer searching
fcc3d49Dalton Durst
qml/Launcher/Drawer.qml+22−17
@@ -1,6 +1,6 @@
1/*
1/*
2 * Copyright (C) 2016 Canonical, Ltd.
2 * Copyright (C) 2016 Canonical, Ltd.
3− * Copyright (C) 2020 UBports Foundation.
3+ * Copyright (C) 2020-2021 UBports Foundation
4 *
4 *
5 * This program is free software; you can redistribute it and/or modify
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
6 * it under the terms of the GNU General Public License as published by
@@ -56,16 +56,7 @@ FocusScope {
56 property var oldSelectionEnd: null
56 property var oldSelectionEnd: null
57
57
58 anchors {
58 anchors {
59− onRightMarginChanged: {
59+ onRightMarginChanged: refocusInputAfterUserLetsGo()
60− if (fullyOpen && hadFocus) {
61− // See onDraggingHorizontallyChanged below
62− searchField.focus = hadFocus;
63− searchField.select(oldSelectionStart, oldSelectionEnd);
64− } else if (fullyClosed || fullyOpen) {
65− searchField.text = "";
66− resetOldFocus();
67− }
68− }
69 }
60 }
70
61
71 Behavior on anchors.rightMargin {
62 Behavior on anchors.rightMargin {
@@ -77,10 +68,8 @@ FocusScope {
77 }
68 }
78
69
79 onDraggingHorizontallyChanged: {
70 onDraggingHorizontallyChanged: {
71+ // See refocusInputAfterUserLetsGo()
80 if (draggingHorizontally) {
72 if (draggingHorizontally) {
81− // Remove (and put back using anchors.onRightMarginChanged) the
82− // focus for the searchfield in order to hide the copy/paste
83− // popover when we move the drawer
84 hadFocus = searchField.focus;
73 hadFocus = searchField.focus;
85 oldSelectionStart = searchField.selectionStart;
74 oldSelectionStart = searchField.selectionStart;
86 oldSelectionEnd = searchField.selectionEnd;
75 oldSelectionEnd = searchField.selectionEnd;
@@ -91,6 +80,7 @@ FocusScope {
91 } else {
80 } else {
92 openRequested();
81 openRequested();
93 }
82 }
83+ refocusInputAfterUserLetsGo();
94 }
84 }
95 }
85 }
96
86
@@ -106,9 +96,24 @@ FocusScope {
106 hadFocus = false;
96 hadFocus = false;
107 oldSelectionStart = null;
97 oldSelectionStart = null;
108 oldSelectionEnd = null;
98 oldSelectionEnd = null;
99+ }
100+
101+ function refocusInputAfterUserLetsGo() {
102+ if (!draggingHorizontally) {
103+ if (fullyOpen && hadFocus) {
104+ searchField.focus = hadFocus;
105+ searchField.select(oldSelectionStart, oldSelectionEnd);
106+ } else if (fullyOpen || fullyClosed) {
107+ resetOldFocus();
108+ }
109+
110+ if (fullyClosed) {
111+ searchField.text = "";
109− appList.currentIndex = 0;
112+ appList.currentIndex = 0;
110− searchField.focus = false;
113+ searchField.focus = false;
111− appList.focus = false;
114+ appList.focus = false;
115+ }
116+ }
112 }
117 }
113
118
114 function focusInput() {
119 function focusInput() {
tests/qmltests/Launcher/tst_Drawer.qml+72
@@ -1,5 +1,6 @@
1/*
1/*
2 * Copyright 2013-2016 Canonical Ltd.
2 * Copyright 2013-2016 Canonical Ltd.
3+ * Copyright (C) 2021 UBports Foundation
3 *
4 *
4 * This program is free software; you can redistribute it and/or modify
5 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * it under the terms of the GNU General Public License as published by
@@ -444,5 +445,76 @@ StyledItem {
444 tryCompare(drawer, "visible", true);
445 tryCompare(drawer, "visible", true);
445 mouseRelease(root, 1, dragY);
446 mouseRelease(root, 1, dragY);
446 }
447 }
448+
449+ function test_userCancellingExitWithSearch_data() {
450+ return [
451+ {tag: "drag all the way back to fullyOpen", fullyOpen: true, cursorPosition: 3, selectedText: ""},
452+ {tag: "do not drag all the way back to fullyOpen", fullyOpen: false, cursorPosition: 3, selectedText: ""},
453+ {tag: "move cursor and drag all the way back to fullyOpen", fullyOpen: true, cursorPosition: 2, selectionStart: 2, selectionEnd: 2, selectedText: ""},
454+ {tag: "move cursor and do not drag all the way back to fullyOpen", fullyOpen: false, cursorPosition: 2, selectionStart: 2, selectionEnd: 2, selectedText: ""},
455+ {tag: "select text and drag all the way back to fullyOpen", fullyOpen: true, cursorPosition: 2, selectionStart: 0, selectionEnd: 2, selectedText: "ca"},
456+ {tag: "select text and do not drag all the way back to fullyOpen", fullyOpen: false, cursorPosition: 2, selectionStart: 0, selectionEnd: 2, selectedText: "ca"}
457+ ]
458+ }
459+
460+ function test_userCancellingExitWithSearch(data) {
461+ // * If I open the Drawer, start searching, start closing the
462+ // drawer, then change my mind and cancel my closing gesture, my
463+ // search remains.
464+ // * If I start searching, place my cursor at a different point in
465+ // the text field or select text, then start closing the Drawer:
466+ // - The keyboard text selection handles and copy/paste dialog
467+ // become invisible or move with the text box. Our keyboard
468+ // isn't quite fancy enough for the handles to move with the
469+ // search box, so we remove the search field's focus to remove
470+ // the handles.
471+ // - If I cancel my Drawer close action, my search, cursor
472+ // position, and selection rectangles are retained.
473+ var drawer = dragDrawerIntoView();
474+ var searchField = drawer.searchTextField;
475+ var dragY = drawer.height / 2;
476+ if (data.fullyOpen) {
477+ var dragEndPointX = drawer.width + units.gu(20);
478+ } else {
479+ var dragEndPointX = drawer.width - units.gu(10);
480+ }
481+
482+ typeString("cam");
483+ tryCompare(searchField, "displayText", "cam");
484+ tryCompare(searchField, "focus", true);
485+
486+ if (data.selectionStart !== undefined) {
487+ searchField.select(data.selectionStart, data.selectionEnd);
488+ }
489+
490+ // Simply clicking the drag handle shouldn't be enough to remove focus
491+ mousePress(root, drawer.width - units.gu(1), dragY);
492+ tryCompare(searchField, "focus", true);
493+
494+ // The search field should not have focus during the drag so the
495+ // cursor or drag handles don't float in place.
496+ mouseMove(root, 10, dragY, 500);
497+ tryCompare(drawer, "fullyOpen", false);
498+ tryCompare(searchField, "focus", false);
499+ mouseMove(root, dragEndPointX, dragY, 500);
500+ tryCompare(drawer, "fullyOpen", data.fullyOpen);
501+
502+ // The search field should not get focus back until the user lets go
503+ tryCompare(searchField, "focus", false);
504+ mouseRelease(root, dragEndPointX, dragY);
505+ // Wait for animations to stop so anything that results from them
506+ // can resolve
507+ wait(1000);
508+ tryCompare(drawer, "fullyOpen", true);
509+ tryCompare(searchField, "displayText", "cam");
510+ tryCompare(searchField, "focus", true);
511+ tryCompare(searchField, "cursorPosition", data.cursorPosition);
512+ tryCompare(searchField, "selectedText", data.selectedText);
513+ if (data.selectionStart) {
514+ // The selected area should be the same as it was before the drag
515+ tryCompare(searchField, "selectionStart", data.selectionStart);
516+ tryCompare(searchField, "selectionEnd", data.selectionEnd);
517+ }
518+ }
447 }
519 }
448}
520}