appDisplay: Improve app grid interaction for touch devices
Currently, handling of touch devices in the app grid is a bit awkward, paging by dragging the view can only happen if started from the gaps between icons, trying to drag from an icon will trigger DnD, and popping up the menu takes over it all. Instead, have the app grid actions play this game of rock-paper-scissors: - Fast swipes on icons trigger scrolling, beats DnD and menu - Slower press-and-drag on icons trigger DnD, beats scrolling and menu - Long press triggers menu, beats scrolling, is beaten by DnD This allows quick swipes to handle navigation, while still allowing the fine grained operations. DnD, when triggered, dismisses the menu, if shown. This all could probably be nicer with a more stateful gesture framework, we're not there yet though. Fixes: https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/3849 Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/1774>
This commit is contained in:
parent
91a7978711
commit
6fc93b78bc
@ -495,6 +495,11 @@ var BaseAppView = GObject.registerClass({
|
|||||||
if (monitor !== Main.layoutManager.primaryIndex)
|
if (monitor !== Main.layoutManager.primaryIndex)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (this._dragFocus) {
|
||||||
|
this._dragFocus.cancelActions();
|
||||||
|
this._dragFocus = null;
|
||||||
|
}
|
||||||
|
|
||||||
const adjustment = this._adjustment;
|
const adjustment = this._adjustment;
|
||||||
adjustment.remove_transition('value');
|
adjustment.remove_transition('value');
|
||||||
|
|
||||||
@ -677,6 +682,8 @@ var BaseAppView = GObject.registerClass({
|
|||||||
};
|
};
|
||||||
DND.addDragMonitor(this._dragMonitor);
|
DND.addDragMonitor(this._dragMonitor);
|
||||||
this._slideSidePages(SidePages.PREVIOUS | SidePages.NEXT | SidePages.DND);
|
this._slideSidePages(SidePages.PREVIOUS | SidePages.NEXT | SidePages.DND);
|
||||||
|
this._dragFocus = null;
|
||||||
|
this._swipeTracker.enabled = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
_onDragMotion(dragEvent) {
|
_onDragMotion(dragEvent) {
|
||||||
@ -713,6 +720,7 @@ var BaseAppView = GObject.registerClass({
|
|||||||
this._resetOvershoot();
|
this._resetOvershoot();
|
||||||
this._slideSidePages(SidePages.NONE);
|
this._slideSidePages(SidePages.NONE);
|
||||||
delete this._dropPage;
|
delete this._dropPage;
|
||||||
|
this._swipeTracker.enabled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
_onDragCancelled() {
|
_onDragCancelled() {
|
||||||
@ -720,6 +728,7 @@ var BaseAppView = GObject.registerClass({
|
|||||||
// will move all items to their original positions
|
// will move all items to their original positions
|
||||||
this._redisplay();
|
this._redisplay();
|
||||||
this._slideSidePages(SidePages.NONE);
|
this._slideSidePages(SidePages.NONE);
|
||||||
|
this._swipeTracker.enabled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
_canAccept(source) {
|
_canAccept(source) {
|
||||||
@ -1331,6 +1340,10 @@ var BaseAppView = GObject.registerClass({
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
updateDragFocus(dragFocus) {
|
||||||
|
this._dragFocus = dragFocus;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
var PageManager = GObject.registerClass({
|
var PageManager = GObject.registerClass({
|
||||||
@ -1522,6 +1535,10 @@ class AppDisplay extends BaseAppView {
|
|||||||
global.settings.is_writable('app-picker-layout');
|
global.settings.is_writable('app-picker-layout');
|
||||||
|
|
||||||
this._placeholder = new AppIcon(app, { isDraggable });
|
this._placeholder = new AppIcon(app, { isDraggable });
|
||||||
|
this._placeholder.connect('notify::pressed', () => {
|
||||||
|
if (this._placeholder.pressed)
|
||||||
|
this.updateDragFocus(this._placeholder);
|
||||||
|
});
|
||||||
this._placeholder.scaleAndFade();
|
this._placeholder.scaleAndFade();
|
||||||
this._redisplay();
|
this._redisplay();
|
||||||
}
|
}
|
||||||
@ -1597,6 +1614,10 @@ class AppDisplay extends BaseAppView {
|
|||||||
this._redisplay();
|
this._redisplay();
|
||||||
this._savePages();
|
this._savePages();
|
||||||
});
|
});
|
||||||
|
icon.connect('notify::pressed', () => {
|
||||||
|
if (icon.pressed)
|
||||||
|
this.updateDragFocus(icon);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Don't try to display empty folders
|
// Don't try to display empty folders
|
||||||
@ -1630,6 +1651,10 @@ class AppDisplay extends BaseAppView {
|
|||||||
let app = appSys.lookup_app(appId);
|
let app = appSys.lookup_app(appId);
|
||||||
|
|
||||||
icon = new AppIcon(app, { isDraggable });
|
icon = new AppIcon(app, { isDraggable });
|
||||||
|
icon.connect('notify::pressed', () => {
|
||||||
|
if (icon.pressed)
|
||||||
|
this.updateDragFocus(icon);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
appIcons.push(icon);
|
appIcons.push(icon);
|
||||||
@ -1952,7 +1977,8 @@ class AppViewItem extends St.Button {
|
|||||||
this._delegate = this;
|
this._delegate = this;
|
||||||
|
|
||||||
if (isDraggable) {
|
if (isDraggable) {
|
||||||
this._draggable = DND.makeDraggable(this);
|
this._draggable = DND.makeDraggable(this, { timeoutThreshold: 200 });
|
||||||
|
|
||||||
this._draggable.connect('drag-begin', this._onDragBegin.bind(this));
|
this._draggable.connect('drag-begin', this._onDragBegin.bind(this));
|
||||||
this._draggable.connect('drag-cancelled', this._onDragCancelled.bind(this));
|
this._draggable.connect('drag-cancelled', this._onDragCancelled.bind(this));
|
||||||
this._draggable.connect('drag-end', this._onDragEnd.bind(this));
|
this._draggable.connect('drag-end', this._onDragEnd.bind(this));
|
||||||
@ -2131,6 +2157,12 @@ class AppViewItem extends St.Button {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cancelActions() {
|
||||||
|
if (this._draggable)
|
||||||
|
this._draggable.fakeRelease();
|
||||||
|
this.fake_release();
|
||||||
|
}
|
||||||
|
|
||||||
get id() {
|
get id() {
|
||||||
return this._id;
|
return this._id;
|
||||||
}
|
}
|
||||||
@ -3128,6 +3160,8 @@ var AppIcon = GObject.registerClass({
|
|||||||
}
|
}
|
||||||
|
|
||||||
_onDragBegin() {
|
_onDragBegin() {
|
||||||
|
if (this._menu)
|
||||||
|
this._menu.close(true);
|
||||||
this._removeMenuTimeout();
|
this._removeMenuTimeout();
|
||||||
super._onDragBegin();
|
super._onDragBegin();
|
||||||
}
|
}
|
||||||
@ -3205,9 +3239,6 @@ var AppIcon = GObject.registerClass({
|
|||||||
this._removeMenuTimeout();
|
this._removeMenuTimeout();
|
||||||
this.fake_release();
|
this.fake_release();
|
||||||
|
|
||||||
if (this._draggable)
|
|
||||||
this._draggable.fakeRelease();
|
|
||||||
|
|
||||||
if (!this._menu) {
|
if (!this._menu) {
|
||||||
this._menu = new AppIconMenu(this, side);
|
this._menu = new AppIconMenu(this, side);
|
||||||
this._menu.connect('activate-window', (menu, window) => {
|
this._menu.connect('activate-window', (menu, window) => {
|
||||||
@ -3362,6 +3393,13 @@ var AppIcon = GObject.registerClass({
|
|||||||
|
|
||||||
return view.createFolder(apps);
|
return view.createFolder(apps);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cancelActions() {
|
||||||
|
if (this._menu)
|
||||||
|
this._menu.close(true);
|
||||||
|
this._removeMenuTimeout();
|
||||||
|
super.cancelActions();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
var AppIconMenu = class AppIconMenu extends PopupMenu.PopupMenu {
|
var AppIconMenu = class AppIconMenu extends PopupMenu.PopupMenu {
|
||||||
|
Loading…
Reference in New Issue
Block a user