shift-shell/kwin/mobiletaskswitcher/package/contents/ui/TaskSwitcher.qml

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

776 lines
35 KiB
QML
Raw Normal View History

2023-03-06 06:38:43 +00:00
// SPDX-FileCopyrightText: 2015 Marco Martin <notmart@gmail.com>
// SPDX-FileCopyrightText: 2021-2024 Devin Lin <devin@kde.org>
// SPDX-FileCopyrightText: 2024-2025 Luis Büchi <luis.buechi@kdemail.net>
2023-03-06 06:38:43 +00:00
// SPDX-License-Identifier: GPL-2.0-or-later
pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Layouts
2023-03-06 06:38:43 +00:00
import org.kde.kirigami 2.20 as Kirigami
import org.kde.plasma.core as PlasmaCore
2023-03-06 06:38:43 +00:00
import org.kde.plasma.components 3.0 as PlasmaComponents
import org.kde.plasma.private.mobileshell as MobileShell
import org.kde.plasma.private.mobileshell.state as MobileShellState
import org.kde.plasma.private.mobileshell.shellsettingsplugin as ShellSettings
import org.kde.plasma.private.mobileshell.taskswitcherplugin as TaskSwitcherPlugin
2023-03-06 06:38:43 +00:00
import org.kde.kwin 3.0 as KWinComponents
import org.kde.kwin.private.effects 1.0
import org.kde.kitemmodels
2023-03-06 06:38:43 +00:00
taskswitcher: enhance gesture with flick speed tracking and orthogonal movement tracking This MR contains work to track the speed with which the taskswitcher gesture has occurred to allow different handling of a "fast flick" (eg: go to homescreen instead of taskswitcher). # Features The center piece of the overhaul is tracking recent velocity (averaged over the last ~50ms) of the gesture to determine behavior: - Swipe: A normal swipe is a "slow" finger move - Flick: A "fast" swipe The determining factor is the speed at the end of the gesture (= when lifting the finger up), anything before is irrelevant - Swipe up goes to task switcher - Flick up goes to homescreen directly instead of task switcher - this is suppressed when already on homescreen - it makes no sense there - Note: On Android that is actually mapped to "going to the first page of the home screen if not there already" - I don't care much for that and it can lead to nothing happening if you're already there, I think I prefer the consistency of always opening the task switcher vs a "quick way to get to the main (first) page of the homescreen" - especially since what that means depends a lot on the active home screen. - added orthogonal gesture movement tracking (2-axis gestures) - gesture properly follows finger movement in all directions now making it feel much more responsive and nice - diagonal flick for quick task switch - horizontal only movement (while holding, not releasing) triggers task scrub gesture for scrubbing through larger number of task in the switcher backlog - Complete refactor of state keeping logic, not just in relation to gestures - state keeper fully in one place in C++ except for - a few derived values that are very directly UI related which are kept in `TaskSwitcherHelpers.qml` - and directly touch gesture related state which are kept separate to maybe allow upstreaming the new touch border gesture handling to KWin in the future <details><summary>done TODO items</summary> - [x] currentTaskIndex tracking is majorly broken - [x] old TaskSwitcherState.qml is still around, should be removed - [x] clamping minimum scale for some reason also clamps y position which makes the task not track the finger when moving past the "full activation" point - [x] switching between tasks when task switcher is open is super crap - [x] task switching when switcher is fully open works now, but flicks don't work - you have to fully move at least halfway to the next task for it to "snap" to that task when you let go, there is 0 momentum and I don't know why -> *Flickable is just broken and refuses to flick on touch input, same behavior on master with old implementation, so I reimplemented the same workaround from before* - [x] the gestures don't work until the notification drawer was invoked at least once after every screen geometry change (resolution change, screen rotation etc) - [x] keyboard shortcut for toggling task switcher is kinda hacky right now and feels awful when closing (some delay noticable, maybe to do with animations?) *NOTE: I disabled it for now because the hacky implementation interfered with/created bugs in other parts* - [x] task scrub mode has broken offsets/positions (can scroll past the end of the list, but not reach all elements) when opening task index is not 0 - [x] fast flick velocity threshold is a mostly arbitrary number and I think it also depends on pixel density - ideally we want a mm (or cm or whatever) per ms, not logical pixels per ms </details> # Design decisions I made during development: - Changed the y opening animation from OutBack (with a bounce) to a simple OutExpo (quickly move towards and then approach slowly) as the bouncy look and feel from the OutBack animation felt wrong to me in that place - To fit better with the new docked mode: - the task switcher now shows the screen geometry behind a task that is not fullscreened. This allows to consistently press (and see) the adjacent tasks which might not always be the case if it's a thin window on a landscape screen. - This is not great overall yet - actually it just checks the windows actual aspect ratio, so if it's smaller but same aspect ratio as screen it shows as if it's a full screen task - also it maximizes and centers the window thumbnail in the task switcher so it really isn't ideal, I just don't know what the behavior *should* ideally be. This change at least doesn't break the switcher when in docked mode. - on opening an app from task switcher it doesn't get force-fullscreened anymore - either it already is fullscreen (because fullscreen in docked mode or just not in docked mode) or it should just keep its geometry (this could be gated behind checking if docked mode is on or not, but I think it's fine without) # TODO before merge - [x] IMPORTANT: Because of regular crashing on interaction I've commented out any code that uses WindowFilterModel::data() which seems to be the cause for that. Since master also uses this and experiences these crashes (at least on both dev machines I tested), I don't think this MR necessarily needs to be held up for that issue (especially since it feels like it could be upstream). I removed this to have an easier time with testing my code without constant crashes, but before merging this would need to be put in again as it breaks: skipping windows with "skipSwitcher" flag set, and showing the correct task when opening the switcher in certain situations. - seems to be a bug with WindowFilterModel::data sometimes returning an invalid/null element? But not in C++, it just doesn't make its way to QML. - feels like it could be a timing thing (but maybe not?) when reverting the skipSwitcher filter rule on `tasksModel` *or* adding some lengthy debug console log in `TaskList.qml:minimizeAll()` before trying to access item.window properties it seems to be fine. When keeping skipSwitcher and having no lengthy debug output I get crashes rather reliably every ~3rd to 5th time invoking the task switcher. - While this does seem to be reproducible on master and thus "the same", if it is timing based it may be that my code triggers the error *more often* technically making it a regression (though also easier to track down?) - Interestingly I don't seem to be able to reproduce this on-device, my PinePhone doesn't have this behavior at all. Maybe a bug with nested KWin session? - [ ] task scrub mode may need to have a dynamic amount of items to scrub through based on display size/orientation (maybe keep distance for task scrubbing the same on portrait vs landscape to aid muscle memory)? or instead of using percentages/pixel distances use mm distance based on dpi? - [ ] is task scrub mode even something we want? Since I prefer the "quick switch gesture" only being able to switch between the two most recent windows (because of immediate reordering by recency), this leaves our task switcher in gesture mode with no quick "shortcut gesture" to switch to older tasks, task scrub mode makes this possible in IMO a nice way, but would love input there. - [ ] get rid of all code comments marked with `TODO!` (with an exclamation mark) - [x] One last pass on removing all superfluous console logs, includes and unused functions. I cleaned that up a lot already, but not completely (one std::cout is still left in on purpose until last minute because of a very rare gesture bug I saw twice and I'm not sure if my fix really got it) # Other - I've only ever tested on my laptop with touch screen (ie: effectively a large tablet form factor), if this merges and we get it on nightly I'll definitely try on the PinePhone, there I will closely scrutinize whether the undoYThreshold and task scrub mode number of tasks feels good to use on a small portrait mode display. This may lead to followup MRs to tweak those essentially arbitrarily chosen values. # TODOs for later MRs - [ ] consider moving velocity calculation/generic 2-dimensional gesture tracking to kwin if it's robust and generic enough for that to be useful on their end. (maybe do that later after it has proven itself for a while on our side) - [ ] (optional?) vibration feedback to tell if it goes to taskswitcher or homescreen? android has that (at least mine) with a tight vibration when task switcher is invoked vs homescree - [ ] flick to homescreen animation kinda looks bad - [ ] task sorting by recency - [ ] polish task scrub mode if we intend to keep it - [ ] task scrub mode can "run out of space" for the gesture and thus can only scrub through a maximum number of tasks (currently 8 either direction in my implementation), but we could add a timer if reaching the end that goes through tasks eg: one per second (acceleration?) to "unlock" the full task list - [ ] task scrub mode should have some visual cue when it's activated (eg: fully "opening" the switcher y position, maybe some extra UI with window thumbnails) - [ ] Positioning after screen geometry change (resize, rotation) of the task switcher is kinda broken (task may end off-screen etc) - fixed by interacting with it or re-opening and not a huge issue IMO - [ ] some bound for y position above the "fully opened position" (maybe make it more and more "reluctant" to follow the finger upwards the further up you go - I think that just makes it feel a bit nicer - [ ] make it behave better with docked mode (currently some animations look a bit scuffed) - [ ] make it behave better with multi screen (currently it's mirrored on all screens, we probably only want it on the screen that currently has focus?) - [ ] navbar buttons when not in gesture mode seem to have slightly different button icon sizes than the system wide navbar (is there no better way to add the navbar than to essentially reimplement it?)
2024-05-05 01:17:54 +00:00
2023-03-06 06:38:43 +00:00
/**
* Component that provides a task switcher.
*/
FocusScope {
id: root
focus: true
property TaskSwitcherPlugin.MobileTaskSwitcherState state
2023-03-06 06:38:43 +00:00
readonly property QtObject effect: KWinComponents.SceneView.effect
readonly property QtObject targetScreen: KWinComponents.SceneView.screen
readonly property real navBottomMargin: MobileShell.Constants.navigationPanelOnSide(width, height) ? 0 : MobileShell.Constants.navigationPanelThickness
readonly property real navRightMargin: MobileShell.Constants.navigationPanelOnSide(width, height) ? MobileShell.Constants.navigationPanelThickness : 0
readonly property real topMargin: ShellSettings.Settings.autoHidePanelsEnabled ? 0 : MobileShell.Constants.topPanelHeight
readonly property real bottomMargin: ShellSettings.Settings.autoHidePanelsEnabled ? 0 : navBottomMargin
2023-03-06 06:38:43 +00:00
readonly property real leftMargin: 0
readonly property real rightMargin: ShellSettings.Settings.autoHidePanelsEnabled ? 0 : navRightMargin
2023-03-06 06:38:43 +00:00
taskswitcher: enhance gesture with flick speed tracking and orthogonal movement tracking This MR contains work to track the speed with which the taskswitcher gesture has occurred to allow different handling of a "fast flick" (eg: go to homescreen instead of taskswitcher). # Features The center piece of the overhaul is tracking recent velocity (averaged over the last ~50ms) of the gesture to determine behavior: - Swipe: A normal swipe is a "slow" finger move - Flick: A "fast" swipe The determining factor is the speed at the end of the gesture (= when lifting the finger up), anything before is irrelevant - Swipe up goes to task switcher - Flick up goes to homescreen directly instead of task switcher - this is suppressed when already on homescreen - it makes no sense there - Note: On Android that is actually mapped to "going to the first page of the home screen if not there already" - I don't care much for that and it can lead to nothing happening if you're already there, I think I prefer the consistency of always opening the task switcher vs a "quick way to get to the main (first) page of the homescreen" - especially since what that means depends a lot on the active home screen. - added orthogonal gesture movement tracking (2-axis gestures) - gesture properly follows finger movement in all directions now making it feel much more responsive and nice - diagonal flick for quick task switch - horizontal only movement (while holding, not releasing) triggers task scrub gesture for scrubbing through larger number of task in the switcher backlog - Complete refactor of state keeping logic, not just in relation to gestures - state keeper fully in one place in C++ except for - a few derived values that are very directly UI related which are kept in `TaskSwitcherHelpers.qml` - and directly touch gesture related state which are kept separate to maybe allow upstreaming the new touch border gesture handling to KWin in the future <details><summary>done TODO items</summary> - [x] currentTaskIndex tracking is majorly broken - [x] old TaskSwitcherState.qml is still around, should be removed - [x] clamping minimum scale for some reason also clamps y position which makes the task not track the finger when moving past the "full activation" point - [x] switching between tasks when task switcher is open is super crap - [x] task switching when switcher is fully open works now, but flicks don't work - you have to fully move at least halfway to the next task for it to "snap" to that task when you let go, there is 0 momentum and I don't know why -> *Flickable is just broken and refuses to flick on touch input, same behavior on master with old implementation, so I reimplemented the same workaround from before* - [x] the gestures don't work until the notification drawer was invoked at least once after every screen geometry change (resolution change, screen rotation etc) - [x] keyboard shortcut for toggling task switcher is kinda hacky right now and feels awful when closing (some delay noticable, maybe to do with animations?) *NOTE: I disabled it for now because the hacky implementation interfered with/created bugs in other parts* - [x] task scrub mode has broken offsets/positions (can scroll past the end of the list, but not reach all elements) when opening task index is not 0 - [x] fast flick velocity threshold is a mostly arbitrary number and I think it also depends on pixel density - ideally we want a mm (or cm or whatever) per ms, not logical pixels per ms </details> # Design decisions I made during development: - Changed the y opening animation from OutBack (with a bounce) to a simple OutExpo (quickly move towards and then approach slowly) as the bouncy look and feel from the OutBack animation felt wrong to me in that place - To fit better with the new docked mode: - the task switcher now shows the screen geometry behind a task that is not fullscreened. This allows to consistently press (and see) the adjacent tasks which might not always be the case if it's a thin window on a landscape screen. - This is not great overall yet - actually it just checks the windows actual aspect ratio, so if it's smaller but same aspect ratio as screen it shows as if it's a full screen task - also it maximizes and centers the window thumbnail in the task switcher so it really isn't ideal, I just don't know what the behavior *should* ideally be. This change at least doesn't break the switcher when in docked mode. - on opening an app from task switcher it doesn't get force-fullscreened anymore - either it already is fullscreen (because fullscreen in docked mode or just not in docked mode) or it should just keep its geometry (this could be gated behind checking if docked mode is on or not, but I think it's fine without) # TODO before merge - [x] IMPORTANT: Because of regular crashing on interaction I've commented out any code that uses WindowFilterModel::data() which seems to be the cause for that. Since master also uses this and experiences these crashes (at least on both dev machines I tested), I don't think this MR necessarily needs to be held up for that issue (especially since it feels like it could be upstream). I removed this to have an easier time with testing my code without constant crashes, but before merging this would need to be put in again as it breaks: skipping windows with "skipSwitcher" flag set, and showing the correct task when opening the switcher in certain situations. - seems to be a bug with WindowFilterModel::data sometimes returning an invalid/null element? But not in C++, it just doesn't make its way to QML. - feels like it could be a timing thing (but maybe not?) when reverting the skipSwitcher filter rule on `tasksModel` *or* adding some lengthy debug console log in `TaskList.qml:minimizeAll()` before trying to access item.window properties it seems to be fine. When keeping skipSwitcher and having no lengthy debug output I get crashes rather reliably every ~3rd to 5th time invoking the task switcher. - While this does seem to be reproducible on master and thus "the same", if it is timing based it may be that my code triggers the error *more often* technically making it a regression (though also easier to track down?) - Interestingly I don't seem to be able to reproduce this on-device, my PinePhone doesn't have this behavior at all. Maybe a bug with nested KWin session? - [ ] task scrub mode may need to have a dynamic amount of items to scrub through based on display size/orientation (maybe keep distance for task scrubbing the same on portrait vs landscape to aid muscle memory)? or instead of using percentages/pixel distances use mm distance based on dpi? - [ ] is task scrub mode even something we want? Since I prefer the "quick switch gesture" only being able to switch between the two most recent windows (because of immediate reordering by recency), this leaves our task switcher in gesture mode with no quick "shortcut gesture" to switch to older tasks, task scrub mode makes this possible in IMO a nice way, but would love input there. - [ ] get rid of all code comments marked with `TODO!` (with an exclamation mark) - [x] One last pass on removing all superfluous console logs, includes and unused functions. I cleaned that up a lot already, but not completely (one std::cout is still left in on purpose until last minute because of a very rare gesture bug I saw twice and I'm not sure if my fix really got it) # Other - I've only ever tested on my laptop with touch screen (ie: effectively a large tablet form factor), if this merges and we get it on nightly I'll definitely try on the PinePhone, there I will closely scrutinize whether the undoYThreshold and task scrub mode number of tasks feels good to use on a small portrait mode display. This may lead to followup MRs to tweak those essentially arbitrarily chosen values. # TODOs for later MRs - [ ] consider moving velocity calculation/generic 2-dimensional gesture tracking to kwin if it's robust and generic enough for that to be useful on their end. (maybe do that later after it has proven itself for a while on our side) - [ ] (optional?) vibration feedback to tell if it goes to taskswitcher or homescreen? android has that (at least mine) with a tight vibration when task switcher is invoked vs homescree - [ ] flick to homescreen animation kinda looks bad - [ ] task sorting by recency - [ ] polish task scrub mode if we intend to keep it - [ ] task scrub mode can "run out of space" for the gesture and thus can only scrub through a maximum number of tasks (currently 8 either direction in my implementation), but we could add a timer if reaching the end that goes through tasks eg: one per second (acceleration?) to "unlock" the full task list - [ ] task scrub mode should have some visual cue when it's activated (eg: fully "opening" the switcher y position, maybe some extra UI with window thumbnails) - [ ] Positioning after screen geometry change (resize, rotation) of the task switcher is kinda broken (task may end off-screen etc) - fixed by interacting with it or re-opening and not a huge issue IMO - [ ] some bound for y position above the "fully opened position" (maybe make it more and more "reluctant" to follow the finger upwards the further up you go - I think that just makes it feel a bit nicer - [ ] make it behave better with docked mode (currently some animations look a bit scuffed) - [ ] make it behave better with multi screen (currently it's mirrored on all screens, we probably only want it on the screen that currently has focus?) - [ ] navbar buttons when not in gesture mode seem to have slightly different button icon sizes than the system wide navbar (is there no better way to add the navbar than to essentially reimplement it?)
2024-05-05 01:17:54 +00:00
property var taskSwitcherHelpers: TaskSwitcherHelpers {
2023-03-06 06:38:43 +00:00
taskSwitcher: root
taskList: taskList
2023-03-06 06:38:43 +00:00
}
MobileShell.HapticsEffect {
id: haptics
}
property TaskSwitcherPlugin.TaskFilterModel tasksModel: TaskSwitcherPlugin.TaskFilterModel {
2023-03-06 06:38:43 +00:00
screenName: root.targetScreen.name
windowModel: root.state.taskModel
}
2023-03-06 06:38:43 +00:00
readonly property int tasksCount: taskList.count
// keep track of task list events
property int oldTasksCount: tasksCount
onTasksCountChanged: {
// we need to subtract 1 from the current index when the closed task index is smaller
// this is because this part of the list has been shifted down by 1 when the closed task was removed.
if (taskSwitcherHelpers.lastClosedTask < state.currentTaskIndex) {
state.currentTaskIndex -= 1;
// animated at the same speed as the task x position in the TaskList so that the task appears not to move from the perspective of the user.
taskSwitcherHelpers.animateGoToTaskIndex(state.currentTaskIndex, Kirigami.Units.longDuration, Easing.InOutQuad);
taskSwitcherHelpers.lastClosedTask = -1;
}
2023-03-06 06:38:43 +00:00
if (tasksCount === 0 && oldTasksCount !== 0) {
hide();
} else if (tasksCount < oldTasksCount) {
if (state.currentTaskIndex < 0) {
// if the user is on the frist task, and it is closed, scroll right
taskSwitcherHelpers.animateGoToTaskIndex(0, Kirigami.Units.longDuration);
} else if (state.currentTaskIndex >= tasksCount) {
// if the user is on the last task, and it is closed, scroll left
taskSwitcherHelpers.animateGoToTaskIndex(tasksCount - 1, Kirigami.Units.longDuration);
}
2023-03-06 06:38:43 +00:00
}
oldTasksCount = tasksCount;
}
Keys.onEscapePressed: hide();
Component.onCompleted: {
initialSetup();
}
function initialSetup(): void {
taskSwitcherHelpers.cancelAnimations();
taskswitcher: enhance gesture with flick speed tracking and orthogonal movement tracking This MR contains work to track the speed with which the taskswitcher gesture has occurred to allow different handling of a "fast flick" (eg: go to homescreen instead of taskswitcher). # Features The center piece of the overhaul is tracking recent velocity (averaged over the last ~50ms) of the gesture to determine behavior: - Swipe: A normal swipe is a "slow" finger move - Flick: A "fast" swipe The determining factor is the speed at the end of the gesture (= when lifting the finger up), anything before is irrelevant - Swipe up goes to task switcher - Flick up goes to homescreen directly instead of task switcher - this is suppressed when already on homescreen - it makes no sense there - Note: On Android that is actually mapped to "going to the first page of the home screen if not there already" - I don't care much for that and it can lead to nothing happening if you're already there, I think I prefer the consistency of always opening the task switcher vs a "quick way to get to the main (first) page of the homescreen" - especially since what that means depends a lot on the active home screen. - added orthogonal gesture movement tracking (2-axis gestures) - gesture properly follows finger movement in all directions now making it feel much more responsive and nice - diagonal flick for quick task switch - horizontal only movement (while holding, not releasing) triggers task scrub gesture for scrubbing through larger number of task in the switcher backlog - Complete refactor of state keeping logic, not just in relation to gestures - state keeper fully in one place in C++ except for - a few derived values that are very directly UI related which are kept in `TaskSwitcherHelpers.qml` - and directly touch gesture related state which are kept separate to maybe allow upstreaming the new touch border gesture handling to KWin in the future <details><summary>done TODO items</summary> - [x] currentTaskIndex tracking is majorly broken - [x] old TaskSwitcherState.qml is still around, should be removed - [x] clamping minimum scale for some reason also clamps y position which makes the task not track the finger when moving past the "full activation" point - [x] switching between tasks when task switcher is open is super crap - [x] task switching when switcher is fully open works now, but flicks don't work - you have to fully move at least halfway to the next task for it to "snap" to that task when you let go, there is 0 momentum and I don't know why -> *Flickable is just broken and refuses to flick on touch input, same behavior on master with old implementation, so I reimplemented the same workaround from before* - [x] the gestures don't work until the notification drawer was invoked at least once after every screen geometry change (resolution change, screen rotation etc) - [x] keyboard shortcut for toggling task switcher is kinda hacky right now and feels awful when closing (some delay noticable, maybe to do with animations?) *NOTE: I disabled it for now because the hacky implementation interfered with/created bugs in other parts* - [x] task scrub mode has broken offsets/positions (can scroll past the end of the list, but not reach all elements) when opening task index is not 0 - [x] fast flick velocity threshold is a mostly arbitrary number and I think it also depends on pixel density - ideally we want a mm (or cm or whatever) per ms, not logical pixels per ms </details> # Design decisions I made during development: - Changed the y opening animation from OutBack (with a bounce) to a simple OutExpo (quickly move towards and then approach slowly) as the bouncy look and feel from the OutBack animation felt wrong to me in that place - To fit better with the new docked mode: - the task switcher now shows the screen geometry behind a task that is not fullscreened. This allows to consistently press (and see) the adjacent tasks which might not always be the case if it's a thin window on a landscape screen. - This is not great overall yet - actually it just checks the windows actual aspect ratio, so if it's smaller but same aspect ratio as screen it shows as if it's a full screen task - also it maximizes and centers the window thumbnail in the task switcher so it really isn't ideal, I just don't know what the behavior *should* ideally be. This change at least doesn't break the switcher when in docked mode. - on opening an app from task switcher it doesn't get force-fullscreened anymore - either it already is fullscreen (because fullscreen in docked mode or just not in docked mode) or it should just keep its geometry (this could be gated behind checking if docked mode is on or not, but I think it's fine without) # TODO before merge - [x] IMPORTANT: Because of regular crashing on interaction I've commented out any code that uses WindowFilterModel::data() which seems to be the cause for that. Since master also uses this and experiences these crashes (at least on both dev machines I tested), I don't think this MR necessarily needs to be held up for that issue (especially since it feels like it could be upstream). I removed this to have an easier time with testing my code without constant crashes, but before merging this would need to be put in again as it breaks: skipping windows with "skipSwitcher" flag set, and showing the correct task when opening the switcher in certain situations. - seems to be a bug with WindowFilterModel::data sometimes returning an invalid/null element? But not in C++, it just doesn't make its way to QML. - feels like it could be a timing thing (but maybe not?) when reverting the skipSwitcher filter rule on `tasksModel` *or* adding some lengthy debug console log in `TaskList.qml:minimizeAll()` before trying to access item.window properties it seems to be fine. When keeping skipSwitcher and having no lengthy debug output I get crashes rather reliably every ~3rd to 5th time invoking the task switcher. - While this does seem to be reproducible on master and thus "the same", if it is timing based it may be that my code triggers the error *more often* technically making it a regression (though also easier to track down?) - Interestingly I don't seem to be able to reproduce this on-device, my PinePhone doesn't have this behavior at all. Maybe a bug with nested KWin session? - [ ] task scrub mode may need to have a dynamic amount of items to scrub through based on display size/orientation (maybe keep distance for task scrubbing the same on portrait vs landscape to aid muscle memory)? or instead of using percentages/pixel distances use mm distance based on dpi? - [ ] is task scrub mode even something we want? Since I prefer the "quick switch gesture" only being able to switch between the two most recent windows (because of immediate reordering by recency), this leaves our task switcher in gesture mode with no quick "shortcut gesture" to switch to older tasks, task scrub mode makes this possible in IMO a nice way, but would love input there. - [ ] get rid of all code comments marked with `TODO!` (with an exclamation mark) - [x] One last pass on removing all superfluous console logs, includes and unused functions. I cleaned that up a lot already, but not completely (one std::cout is still left in on purpose until last minute because of a very rare gesture bug I saw twice and I'm not sure if my fix really got it) # Other - I've only ever tested on my laptop with touch screen (ie: effectively a large tablet form factor), if this merges and we get it on nightly I'll definitely try on the PinePhone, there I will closely scrutinize whether the undoYThreshold and task scrub mode number of tasks feels good to use on a small portrait mode display. This may lead to followup MRs to tweak those essentially arbitrarily chosen values. # TODOs for later MRs - [ ] consider moving velocity calculation/generic 2-dimensional gesture tracking to kwin if it's robust and generic enough for that to be useful on their end. (maybe do that later after it has proven itself for a while on our side) - [ ] (optional?) vibration feedback to tell if it goes to taskswitcher or homescreen? android has that (at least mine) with a tight vibration when task switcher is invoked vs homescree - [ ] flick to homescreen animation kinda looks bad - [ ] task sorting by recency - [ ] polish task scrub mode if we intend to keep it - [ ] task scrub mode can "run out of space" for the gesture and thus can only scrub through a maximum number of tasks (currently 8 either direction in my implementation), but we could add a timer if reaching the end that goes through tasks eg: one per second (acceleration?) to "unlock" the full task list - [ ] task scrub mode should have some visual cue when it's activated (eg: fully "opening" the switcher y position, maybe some extra UI with window thumbnails) - [ ] Positioning after screen geometry change (resize, rotation) of the task switcher is kinda broken (task may end off-screen etc) - fixed by interacting with it or re-opening and not a huge issue IMO - [ ] some bound for y position above the "fully opened position" (maybe make it more and more "reluctant" to follow the finger upwards the further up you go - I think that just makes it feel a bit nicer - [ ] make it behave better with docked mode (currently some animations look a bit scuffed) - [ ] make it behave better with multi screen (currently it's mirrored on all screens, we probably only want it on the screen that currently has focus?) - [ ] navbar buttons when not in gesture mode seem to have slightly different button icon sizes than the system wide navbar (is there no better way to add the navbar than to essentially reimplement it?)
2024-05-05 01:17:54 +00:00
state.updateWasInActiveTask(KWinComponents.Workspace.activeWindow);
// ensure the task drawer is not opened and reset values to defaults
taskSwitcherHelpers.reachedHeightThreshold = false;
taskSwitcherHelpers.gestureState = TaskSwitcherHelpers.GestureStates.Undecided;
taskSwitcherHelpers.isInTaskScrubMode = false;
taskSwitcherHelpers.inLastFrame = false;
taskSwitcherHelpers.hasVibrated = false;
taskSwitcherHelpers.closingFactor = 1;
taskSwitcherHelpers.taskSwitchCanLaunch = false;
taskSwitchCanLaunchTimer.restart()
taskList.taskOffsetEasing = Easing.InOutQuart;
taskList.homeTouchPositionX = 0;
backgroundColorOpacityAn.enabled = false;
backgroundColorOpacity = state.wasInActiveTask ? 1 : 0;
backgroundColorOpacityAn.enabled = true;
// reset the offset to have the task drawer off screen
taskList.setTaskOffsetValue(state.wasInActiveTask ? taskSwitcherHelpers.taskOffsetValue : taskSwitcherHelpers.homeOffsetValue, true);
// task index from the last time using the switcher
taskswitcher: enhance gesture with flick speed tracking and orthogonal movement tracking This MR contains work to track the speed with which the taskswitcher gesture has occurred to allow different handling of a "fast flick" (eg: go to homescreen instead of taskswitcher). # Features The center piece of the overhaul is tracking recent velocity (averaged over the last ~50ms) of the gesture to determine behavior: - Swipe: A normal swipe is a "slow" finger move - Flick: A "fast" swipe The determining factor is the speed at the end of the gesture (= when lifting the finger up), anything before is irrelevant - Swipe up goes to task switcher - Flick up goes to homescreen directly instead of task switcher - this is suppressed when already on homescreen - it makes no sense there - Note: On Android that is actually mapped to "going to the first page of the home screen if not there already" - I don't care much for that and it can lead to nothing happening if you're already there, I think I prefer the consistency of always opening the task switcher vs a "quick way to get to the main (first) page of the homescreen" - especially since what that means depends a lot on the active home screen. - added orthogonal gesture movement tracking (2-axis gestures) - gesture properly follows finger movement in all directions now making it feel much more responsive and nice - diagonal flick for quick task switch - horizontal only movement (while holding, not releasing) triggers task scrub gesture for scrubbing through larger number of task in the switcher backlog - Complete refactor of state keeping logic, not just in relation to gestures - state keeper fully in one place in C++ except for - a few derived values that are very directly UI related which are kept in `TaskSwitcherHelpers.qml` - and directly touch gesture related state which are kept separate to maybe allow upstreaming the new touch border gesture handling to KWin in the future <details><summary>done TODO items</summary> - [x] currentTaskIndex tracking is majorly broken - [x] old TaskSwitcherState.qml is still around, should be removed - [x] clamping minimum scale for some reason also clamps y position which makes the task not track the finger when moving past the "full activation" point - [x] switching between tasks when task switcher is open is super crap - [x] task switching when switcher is fully open works now, but flicks don't work - you have to fully move at least halfway to the next task for it to "snap" to that task when you let go, there is 0 momentum and I don't know why -> *Flickable is just broken and refuses to flick on touch input, same behavior on master with old implementation, so I reimplemented the same workaround from before* - [x] the gestures don't work until the notification drawer was invoked at least once after every screen geometry change (resolution change, screen rotation etc) - [x] keyboard shortcut for toggling task switcher is kinda hacky right now and feels awful when closing (some delay noticable, maybe to do with animations?) *NOTE: I disabled it for now because the hacky implementation interfered with/created bugs in other parts* - [x] task scrub mode has broken offsets/positions (can scroll past the end of the list, but not reach all elements) when opening task index is not 0 - [x] fast flick velocity threshold is a mostly arbitrary number and I think it also depends on pixel density - ideally we want a mm (or cm or whatever) per ms, not logical pixels per ms </details> # Design decisions I made during development: - Changed the y opening animation from OutBack (with a bounce) to a simple OutExpo (quickly move towards and then approach slowly) as the bouncy look and feel from the OutBack animation felt wrong to me in that place - To fit better with the new docked mode: - the task switcher now shows the screen geometry behind a task that is not fullscreened. This allows to consistently press (and see) the adjacent tasks which might not always be the case if it's a thin window on a landscape screen. - This is not great overall yet - actually it just checks the windows actual aspect ratio, so if it's smaller but same aspect ratio as screen it shows as if it's a full screen task - also it maximizes and centers the window thumbnail in the task switcher so it really isn't ideal, I just don't know what the behavior *should* ideally be. This change at least doesn't break the switcher when in docked mode. - on opening an app from task switcher it doesn't get force-fullscreened anymore - either it already is fullscreen (because fullscreen in docked mode or just not in docked mode) or it should just keep its geometry (this could be gated behind checking if docked mode is on or not, but I think it's fine without) # TODO before merge - [x] IMPORTANT: Because of regular crashing on interaction I've commented out any code that uses WindowFilterModel::data() which seems to be the cause for that. Since master also uses this and experiences these crashes (at least on both dev machines I tested), I don't think this MR necessarily needs to be held up for that issue (especially since it feels like it could be upstream). I removed this to have an easier time with testing my code without constant crashes, but before merging this would need to be put in again as it breaks: skipping windows with "skipSwitcher" flag set, and showing the correct task when opening the switcher in certain situations. - seems to be a bug with WindowFilterModel::data sometimes returning an invalid/null element? But not in C++, it just doesn't make its way to QML. - feels like it could be a timing thing (but maybe not?) when reverting the skipSwitcher filter rule on `tasksModel` *or* adding some lengthy debug console log in `TaskList.qml:minimizeAll()` before trying to access item.window properties it seems to be fine. When keeping skipSwitcher and having no lengthy debug output I get crashes rather reliably every ~3rd to 5th time invoking the task switcher. - While this does seem to be reproducible on master and thus "the same", if it is timing based it may be that my code triggers the error *more often* technically making it a regression (though also easier to track down?) - Interestingly I don't seem to be able to reproduce this on-device, my PinePhone doesn't have this behavior at all. Maybe a bug with nested KWin session? - [ ] task scrub mode may need to have a dynamic amount of items to scrub through based on display size/orientation (maybe keep distance for task scrubbing the same on portrait vs landscape to aid muscle memory)? or instead of using percentages/pixel distances use mm distance based on dpi? - [ ] is task scrub mode even something we want? Since I prefer the "quick switch gesture" only being able to switch between the two most recent windows (because of immediate reordering by recency), this leaves our task switcher in gesture mode with no quick "shortcut gesture" to switch to older tasks, task scrub mode makes this possible in IMO a nice way, but would love input there. - [ ] get rid of all code comments marked with `TODO!` (with an exclamation mark) - [x] One last pass on removing all superfluous console logs, includes and unused functions. I cleaned that up a lot already, but not completely (one std::cout is still left in on purpose until last minute because of a very rare gesture bug I saw twice and I'm not sure if my fix really got it) # Other - I've only ever tested on my laptop with touch screen (ie: effectively a large tablet form factor), if this merges and we get it on nightly I'll definitely try on the PinePhone, there I will closely scrutinize whether the undoYThreshold and task scrub mode number of tasks feels good to use on a small portrait mode display. This may lead to followup MRs to tweak those essentially arbitrarily chosen values. # TODOs for later MRs - [ ] consider moving velocity calculation/generic 2-dimensional gesture tracking to kwin if it's robust and generic enough for that to be useful on their end. (maybe do that later after it has proven itself for a while on our side) - [ ] (optional?) vibration feedback to tell if it goes to taskswitcher or homescreen? android has that (at least mine) with a tight vibration when task switcher is invoked vs homescree - [ ] flick to homescreen animation kinda looks bad - [ ] task sorting by recency - [ ] polish task scrub mode if we intend to keep it - [ ] task scrub mode can "run out of space" for the gesture and thus can only scrub through a maximum number of tasks (currently 8 either direction in my implementation), but we could add a timer if reaching the end that goes through tasks eg: one per second (acceleration?) to "unlock" the full task list - [ ] task scrub mode should have some visual cue when it's activated (eg: fully "opening" the switcher y position, maybe some extra UI with window thumbnails) - [ ] Positioning after screen geometry change (resize, rotation) of the task switcher is kinda broken (task may end off-screen etc) - fixed by interacting with it or re-opening and not a huge issue IMO - [ ] some bound for y position above the "fully opened position" (maybe make it more and more "reluctant" to follow the finger upwards the further up you go - I think that just makes it feel a bit nicer - [ ] make it behave better with docked mode (currently some animations look a bit scuffed) - [ ] make it behave better with multi screen (currently it's mirrored on all screens, we probably only want it on the screen that currently has focus?) - [ ] navbar buttons when not in gesture mode seem to have slightly different button icon sizes than the system wide navbar (is there no better way to add the navbar than to essentially reimplement it?)
2024-05-05 01:17:54 +00:00
state.initialTaskIndex = Math.min(state.currentTaskIndex, tasksCount - 1);
if (state.wasInActiveTask) {
// if we were in an active task instead set initial task index to the position of that task
state.initialTaskIndex = taskSwitcherHelpers.getTaskIndexFromWindow(KWinComponents.Workspace.activeWindow);
} else {
// reset the task index to the start if on home screen
state.initialTaskIndex = 0
taskswitcher: enhance gesture with flick speed tracking and orthogonal movement tracking This MR contains work to track the speed with which the taskswitcher gesture has occurred to allow different handling of a "fast flick" (eg: go to homescreen instead of taskswitcher). # Features The center piece of the overhaul is tracking recent velocity (averaged over the last ~50ms) of the gesture to determine behavior: - Swipe: A normal swipe is a "slow" finger move - Flick: A "fast" swipe The determining factor is the speed at the end of the gesture (= when lifting the finger up), anything before is irrelevant - Swipe up goes to task switcher - Flick up goes to homescreen directly instead of task switcher - this is suppressed when already on homescreen - it makes no sense there - Note: On Android that is actually mapped to "going to the first page of the home screen if not there already" - I don't care much for that and it can lead to nothing happening if you're already there, I think I prefer the consistency of always opening the task switcher vs a "quick way to get to the main (first) page of the homescreen" - especially since what that means depends a lot on the active home screen. - added orthogonal gesture movement tracking (2-axis gestures) - gesture properly follows finger movement in all directions now making it feel much more responsive and nice - diagonal flick for quick task switch - horizontal only movement (while holding, not releasing) triggers task scrub gesture for scrubbing through larger number of task in the switcher backlog - Complete refactor of state keeping logic, not just in relation to gestures - state keeper fully in one place in C++ except for - a few derived values that are very directly UI related which are kept in `TaskSwitcherHelpers.qml` - and directly touch gesture related state which are kept separate to maybe allow upstreaming the new touch border gesture handling to KWin in the future <details><summary>done TODO items</summary> - [x] currentTaskIndex tracking is majorly broken - [x] old TaskSwitcherState.qml is still around, should be removed - [x] clamping minimum scale for some reason also clamps y position which makes the task not track the finger when moving past the "full activation" point - [x] switching between tasks when task switcher is open is super crap - [x] task switching when switcher is fully open works now, but flicks don't work - you have to fully move at least halfway to the next task for it to "snap" to that task when you let go, there is 0 momentum and I don't know why -> *Flickable is just broken and refuses to flick on touch input, same behavior on master with old implementation, so I reimplemented the same workaround from before* - [x] the gestures don't work until the notification drawer was invoked at least once after every screen geometry change (resolution change, screen rotation etc) - [x] keyboard shortcut for toggling task switcher is kinda hacky right now and feels awful when closing (some delay noticable, maybe to do with animations?) *NOTE: I disabled it for now because the hacky implementation interfered with/created bugs in other parts* - [x] task scrub mode has broken offsets/positions (can scroll past the end of the list, but not reach all elements) when opening task index is not 0 - [x] fast flick velocity threshold is a mostly arbitrary number and I think it also depends on pixel density - ideally we want a mm (or cm or whatever) per ms, not logical pixels per ms </details> # Design decisions I made during development: - Changed the y opening animation from OutBack (with a bounce) to a simple OutExpo (quickly move towards and then approach slowly) as the bouncy look and feel from the OutBack animation felt wrong to me in that place - To fit better with the new docked mode: - the task switcher now shows the screen geometry behind a task that is not fullscreened. This allows to consistently press (and see) the adjacent tasks which might not always be the case if it's a thin window on a landscape screen. - This is not great overall yet - actually it just checks the windows actual aspect ratio, so if it's smaller but same aspect ratio as screen it shows as if it's a full screen task - also it maximizes and centers the window thumbnail in the task switcher so it really isn't ideal, I just don't know what the behavior *should* ideally be. This change at least doesn't break the switcher when in docked mode. - on opening an app from task switcher it doesn't get force-fullscreened anymore - either it already is fullscreen (because fullscreen in docked mode or just not in docked mode) or it should just keep its geometry (this could be gated behind checking if docked mode is on or not, but I think it's fine without) # TODO before merge - [x] IMPORTANT: Because of regular crashing on interaction I've commented out any code that uses WindowFilterModel::data() which seems to be the cause for that. Since master also uses this and experiences these crashes (at least on both dev machines I tested), I don't think this MR necessarily needs to be held up for that issue (especially since it feels like it could be upstream). I removed this to have an easier time with testing my code without constant crashes, but before merging this would need to be put in again as it breaks: skipping windows with "skipSwitcher" flag set, and showing the correct task when opening the switcher in certain situations. - seems to be a bug with WindowFilterModel::data sometimes returning an invalid/null element? But not in C++, it just doesn't make its way to QML. - feels like it could be a timing thing (but maybe not?) when reverting the skipSwitcher filter rule on `tasksModel` *or* adding some lengthy debug console log in `TaskList.qml:minimizeAll()` before trying to access item.window properties it seems to be fine. When keeping skipSwitcher and having no lengthy debug output I get crashes rather reliably every ~3rd to 5th time invoking the task switcher. - While this does seem to be reproducible on master and thus "the same", if it is timing based it may be that my code triggers the error *more often* technically making it a regression (though also easier to track down?) - Interestingly I don't seem to be able to reproduce this on-device, my PinePhone doesn't have this behavior at all. Maybe a bug with nested KWin session? - [ ] task scrub mode may need to have a dynamic amount of items to scrub through based on display size/orientation (maybe keep distance for task scrubbing the same on portrait vs landscape to aid muscle memory)? or instead of using percentages/pixel distances use mm distance based on dpi? - [ ] is task scrub mode even something we want? Since I prefer the "quick switch gesture" only being able to switch between the two most recent windows (because of immediate reordering by recency), this leaves our task switcher in gesture mode with no quick "shortcut gesture" to switch to older tasks, task scrub mode makes this possible in IMO a nice way, but would love input there. - [ ] get rid of all code comments marked with `TODO!` (with an exclamation mark) - [x] One last pass on removing all superfluous console logs, includes and unused functions. I cleaned that up a lot already, but not completely (one std::cout is still left in on purpose until last minute because of a very rare gesture bug I saw twice and I'm not sure if my fix really got it) # Other - I've only ever tested on my laptop with touch screen (ie: effectively a large tablet form factor), if this merges and we get it on nightly I'll definitely try on the PinePhone, there I will closely scrutinize whether the undoYThreshold and task scrub mode number of tasks feels good to use on a small portrait mode display. This may lead to followup MRs to tweak those essentially arbitrarily chosen values. # TODOs for later MRs - [ ] consider moving velocity calculation/generic 2-dimensional gesture tracking to kwin if it's robust and generic enough for that to be useful on their end. (maybe do that later after it has proven itself for a while on our side) - [ ] (optional?) vibration feedback to tell if it goes to taskswitcher or homescreen? android has that (at least mine) with a tight vibration when task switcher is invoked vs homescree - [ ] flick to homescreen animation kinda looks bad - [ ] task sorting by recency - [ ] polish task scrub mode if we intend to keep it - [ ] task scrub mode can "run out of space" for the gesture and thus can only scrub through a maximum number of tasks (currently 8 either direction in my implementation), but we could add a timer if reaching the end that goes through tasks eg: one per second (acceleration?) to "unlock" the full task list - [ ] task scrub mode should have some visual cue when it's activated (eg: fully "opening" the switcher y position, maybe some extra UI with window thumbnails) - [ ] Positioning after screen geometry change (resize, rotation) of the task switcher is kinda broken (task may end off-screen etc) - fixed by interacting with it or re-opening and not a huge issue IMO - [ ] some bound for y position above the "fully opened position" (maybe make it more and more "reluctant" to follow the finger upwards the further up you go - I think that just makes it feel a bit nicer - [ ] make it behave better with docked mode (currently some animations look a bit scuffed) - [ ] make it behave better with multi screen (currently it's mirrored on all screens, we probably only want it on the screen that currently has focus?) - [ ] navbar buttons when not in gesture mode seem to have slightly different button icon sizes than the system wide navbar (is there no better way to add the navbar than to essentially reimplement it?)
2024-05-05 01:17:54 +00:00
}
state.currentTaskIndex = state.initialTaskIndex
taskSwitcherHelpers.currentDisplayTask = state.currentTaskIndex;
taskswitcher: enhance gesture with flick speed tracking and orthogonal movement tracking This MR contains work to track the speed with which the taskswitcher gesture has occurred to allow different handling of a "fast flick" (eg: go to homescreen instead of taskswitcher). # Features The center piece of the overhaul is tracking recent velocity (averaged over the last ~50ms) of the gesture to determine behavior: - Swipe: A normal swipe is a "slow" finger move - Flick: A "fast" swipe The determining factor is the speed at the end of the gesture (= when lifting the finger up), anything before is irrelevant - Swipe up goes to task switcher - Flick up goes to homescreen directly instead of task switcher - this is suppressed when already on homescreen - it makes no sense there - Note: On Android that is actually mapped to "going to the first page of the home screen if not there already" - I don't care much for that and it can lead to nothing happening if you're already there, I think I prefer the consistency of always opening the task switcher vs a "quick way to get to the main (first) page of the homescreen" - especially since what that means depends a lot on the active home screen. - added orthogonal gesture movement tracking (2-axis gestures) - gesture properly follows finger movement in all directions now making it feel much more responsive and nice - diagonal flick for quick task switch - horizontal only movement (while holding, not releasing) triggers task scrub gesture for scrubbing through larger number of task in the switcher backlog - Complete refactor of state keeping logic, not just in relation to gestures - state keeper fully in one place in C++ except for - a few derived values that are very directly UI related which are kept in `TaskSwitcherHelpers.qml` - and directly touch gesture related state which are kept separate to maybe allow upstreaming the new touch border gesture handling to KWin in the future <details><summary>done TODO items</summary> - [x] currentTaskIndex tracking is majorly broken - [x] old TaskSwitcherState.qml is still around, should be removed - [x] clamping minimum scale for some reason also clamps y position which makes the task not track the finger when moving past the "full activation" point - [x] switching between tasks when task switcher is open is super crap - [x] task switching when switcher is fully open works now, but flicks don't work - you have to fully move at least halfway to the next task for it to "snap" to that task when you let go, there is 0 momentum and I don't know why -> *Flickable is just broken and refuses to flick on touch input, same behavior on master with old implementation, so I reimplemented the same workaround from before* - [x] the gestures don't work until the notification drawer was invoked at least once after every screen geometry change (resolution change, screen rotation etc) - [x] keyboard shortcut for toggling task switcher is kinda hacky right now and feels awful when closing (some delay noticable, maybe to do with animations?) *NOTE: I disabled it for now because the hacky implementation interfered with/created bugs in other parts* - [x] task scrub mode has broken offsets/positions (can scroll past the end of the list, but not reach all elements) when opening task index is not 0 - [x] fast flick velocity threshold is a mostly arbitrary number and I think it also depends on pixel density - ideally we want a mm (or cm or whatever) per ms, not logical pixels per ms </details> # Design decisions I made during development: - Changed the y opening animation from OutBack (with a bounce) to a simple OutExpo (quickly move towards and then approach slowly) as the bouncy look and feel from the OutBack animation felt wrong to me in that place - To fit better with the new docked mode: - the task switcher now shows the screen geometry behind a task that is not fullscreened. This allows to consistently press (and see) the adjacent tasks which might not always be the case if it's a thin window on a landscape screen. - This is not great overall yet - actually it just checks the windows actual aspect ratio, so if it's smaller but same aspect ratio as screen it shows as if it's a full screen task - also it maximizes and centers the window thumbnail in the task switcher so it really isn't ideal, I just don't know what the behavior *should* ideally be. This change at least doesn't break the switcher when in docked mode. - on opening an app from task switcher it doesn't get force-fullscreened anymore - either it already is fullscreen (because fullscreen in docked mode or just not in docked mode) or it should just keep its geometry (this could be gated behind checking if docked mode is on or not, but I think it's fine without) # TODO before merge - [x] IMPORTANT: Because of regular crashing on interaction I've commented out any code that uses WindowFilterModel::data() which seems to be the cause for that. Since master also uses this and experiences these crashes (at least on both dev machines I tested), I don't think this MR necessarily needs to be held up for that issue (especially since it feels like it could be upstream). I removed this to have an easier time with testing my code without constant crashes, but before merging this would need to be put in again as it breaks: skipping windows with "skipSwitcher" flag set, and showing the correct task when opening the switcher in certain situations. - seems to be a bug with WindowFilterModel::data sometimes returning an invalid/null element? But not in C++, it just doesn't make its way to QML. - feels like it could be a timing thing (but maybe not?) when reverting the skipSwitcher filter rule on `tasksModel` *or* adding some lengthy debug console log in `TaskList.qml:minimizeAll()` before trying to access item.window properties it seems to be fine. When keeping skipSwitcher and having no lengthy debug output I get crashes rather reliably every ~3rd to 5th time invoking the task switcher. - While this does seem to be reproducible on master and thus "the same", if it is timing based it may be that my code triggers the error *more often* technically making it a regression (though also easier to track down?) - Interestingly I don't seem to be able to reproduce this on-device, my PinePhone doesn't have this behavior at all. Maybe a bug with nested KWin session? - [ ] task scrub mode may need to have a dynamic amount of items to scrub through based on display size/orientation (maybe keep distance for task scrubbing the same on portrait vs landscape to aid muscle memory)? or instead of using percentages/pixel distances use mm distance based on dpi? - [ ] is task scrub mode even something we want? Since I prefer the "quick switch gesture" only being able to switch between the two most recent windows (because of immediate reordering by recency), this leaves our task switcher in gesture mode with no quick "shortcut gesture" to switch to older tasks, task scrub mode makes this possible in IMO a nice way, but would love input there. - [ ] get rid of all code comments marked with `TODO!` (with an exclamation mark) - [x] One last pass on removing all superfluous console logs, includes and unused functions. I cleaned that up a lot already, but not completely (one std::cout is still left in on purpose until last minute because of a very rare gesture bug I saw twice and I'm not sure if my fix really got it) # Other - I've only ever tested on my laptop with touch screen (ie: effectively a large tablet form factor), if this merges and we get it on nightly I'll definitely try on the PinePhone, there I will closely scrutinize whether the undoYThreshold and task scrub mode number of tasks feels good to use on a small portrait mode display. This may lead to followup MRs to tweak those essentially arbitrarily chosen values. # TODOs for later MRs - [ ] consider moving velocity calculation/generic 2-dimensional gesture tracking to kwin if it's robust and generic enough for that to be useful on their end. (maybe do that later after it has proven itself for a while on our side) - [ ] (optional?) vibration feedback to tell if it goes to taskswitcher or homescreen? android has that (at least mine) with a tight vibration when task switcher is invoked vs homescree - [ ] flick to homescreen animation kinda looks bad - [ ] task sorting by recency - [ ] polish task scrub mode if we intend to keep it - [ ] task scrub mode can "run out of space" for the gesture and thus can only scrub through a maximum number of tasks (currently 8 either direction in my implementation), but we could add a timer if reaching the end that goes through tasks eg: one per second (acceleration?) to "unlock" the full task list - [ ] task scrub mode should have some visual cue when it's activated (eg: fully "opening" the switcher y position, maybe some extra UI with window thumbnails) - [ ] Positioning after screen geometry change (resize, rotation) of the task switcher is kinda broken (task may end off-screen etc) - fixed by interacting with it or re-opening and not a huge issue IMO - [ ] some bound for y position above the "fully opened position" (maybe make it more and more "reluctant" to follow the finger upwards the further up you go - I think that just makes it feel a bit nicer - [ ] make it behave better with docked mode (currently some animations look a bit scuffed) - [ ] make it behave better with multi screen (currently it's mirrored on all screens, we probably only want it on the screen that currently has focus?) - [ ] navbar buttons when not in gesture mode seem to have slightly different button icon sizes than the system wide navbar (is there no better way to add the navbar than to essentially reimplement it?)
2024-05-05 01:17:54 +00:00
taskSwitcherHelpers.goToTaskIndex(state.initialTaskIndex);
2023-03-06 06:38:43 +00:00
taskList.minimizeAll();
taskswitcher: enhance gesture with flick speed tracking and orthogonal movement tracking This MR contains work to track the speed with which the taskswitcher gesture has occurred to allow different handling of a "fast flick" (eg: go to homescreen instead of taskswitcher). # Features The center piece of the overhaul is tracking recent velocity (averaged over the last ~50ms) of the gesture to determine behavior: - Swipe: A normal swipe is a "slow" finger move - Flick: A "fast" swipe The determining factor is the speed at the end of the gesture (= when lifting the finger up), anything before is irrelevant - Swipe up goes to task switcher - Flick up goes to homescreen directly instead of task switcher - this is suppressed when already on homescreen - it makes no sense there - Note: On Android that is actually mapped to "going to the first page of the home screen if not there already" - I don't care much for that and it can lead to nothing happening if you're already there, I think I prefer the consistency of always opening the task switcher vs a "quick way to get to the main (first) page of the homescreen" - especially since what that means depends a lot on the active home screen. - added orthogonal gesture movement tracking (2-axis gestures) - gesture properly follows finger movement in all directions now making it feel much more responsive and nice - diagonal flick for quick task switch - horizontal only movement (while holding, not releasing) triggers task scrub gesture for scrubbing through larger number of task in the switcher backlog - Complete refactor of state keeping logic, not just in relation to gestures - state keeper fully in one place in C++ except for - a few derived values that are very directly UI related which are kept in `TaskSwitcherHelpers.qml` - and directly touch gesture related state which are kept separate to maybe allow upstreaming the new touch border gesture handling to KWin in the future <details><summary>done TODO items</summary> - [x] currentTaskIndex tracking is majorly broken - [x] old TaskSwitcherState.qml is still around, should be removed - [x] clamping minimum scale for some reason also clamps y position which makes the task not track the finger when moving past the "full activation" point - [x] switching between tasks when task switcher is open is super crap - [x] task switching when switcher is fully open works now, but flicks don't work - you have to fully move at least halfway to the next task for it to "snap" to that task when you let go, there is 0 momentum and I don't know why -> *Flickable is just broken and refuses to flick on touch input, same behavior on master with old implementation, so I reimplemented the same workaround from before* - [x] the gestures don't work until the notification drawer was invoked at least once after every screen geometry change (resolution change, screen rotation etc) - [x] keyboard shortcut for toggling task switcher is kinda hacky right now and feels awful when closing (some delay noticable, maybe to do with animations?) *NOTE: I disabled it for now because the hacky implementation interfered with/created bugs in other parts* - [x] task scrub mode has broken offsets/positions (can scroll past the end of the list, but not reach all elements) when opening task index is not 0 - [x] fast flick velocity threshold is a mostly arbitrary number and I think it also depends on pixel density - ideally we want a mm (or cm or whatever) per ms, not logical pixels per ms </details> # Design decisions I made during development: - Changed the y opening animation from OutBack (with a bounce) to a simple OutExpo (quickly move towards and then approach slowly) as the bouncy look and feel from the OutBack animation felt wrong to me in that place - To fit better with the new docked mode: - the task switcher now shows the screen geometry behind a task that is not fullscreened. This allows to consistently press (and see) the adjacent tasks which might not always be the case if it's a thin window on a landscape screen. - This is not great overall yet - actually it just checks the windows actual aspect ratio, so if it's smaller but same aspect ratio as screen it shows as if it's a full screen task - also it maximizes and centers the window thumbnail in the task switcher so it really isn't ideal, I just don't know what the behavior *should* ideally be. This change at least doesn't break the switcher when in docked mode. - on opening an app from task switcher it doesn't get force-fullscreened anymore - either it already is fullscreen (because fullscreen in docked mode or just not in docked mode) or it should just keep its geometry (this could be gated behind checking if docked mode is on or not, but I think it's fine without) # TODO before merge - [x] IMPORTANT: Because of regular crashing on interaction I've commented out any code that uses WindowFilterModel::data() which seems to be the cause for that. Since master also uses this and experiences these crashes (at least on both dev machines I tested), I don't think this MR necessarily needs to be held up for that issue (especially since it feels like it could be upstream). I removed this to have an easier time with testing my code without constant crashes, but before merging this would need to be put in again as it breaks: skipping windows with "skipSwitcher" flag set, and showing the correct task when opening the switcher in certain situations. - seems to be a bug with WindowFilterModel::data sometimes returning an invalid/null element? But not in C++, it just doesn't make its way to QML. - feels like it could be a timing thing (but maybe not?) when reverting the skipSwitcher filter rule on `tasksModel` *or* adding some lengthy debug console log in `TaskList.qml:minimizeAll()` before trying to access item.window properties it seems to be fine. When keeping skipSwitcher and having no lengthy debug output I get crashes rather reliably every ~3rd to 5th time invoking the task switcher. - While this does seem to be reproducible on master and thus "the same", if it is timing based it may be that my code triggers the error *more often* technically making it a regression (though also easier to track down?) - Interestingly I don't seem to be able to reproduce this on-device, my PinePhone doesn't have this behavior at all. Maybe a bug with nested KWin session? - [ ] task scrub mode may need to have a dynamic amount of items to scrub through based on display size/orientation (maybe keep distance for task scrubbing the same on portrait vs landscape to aid muscle memory)? or instead of using percentages/pixel distances use mm distance based on dpi? - [ ] is task scrub mode even something we want? Since I prefer the "quick switch gesture" only being able to switch between the two most recent windows (because of immediate reordering by recency), this leaves our task switcher in gesture mode with no quick "shortcut gesture" to switch to older tasks, task scrub mode makes this possible in IMO a nice way, but would love input there. - [ ] get rid of all code comments marked with `TODO!` (with an exclamation mark) - [x] One last pass on removing all superfluous console logs, includes and unused functions. I cleaned that up a lot already, but not completely (one std::cout is still left in on purpose until last minute because of a very rare gesture bug I saw twice and I'm not sure if my fix really got it) # Other - I've only ever tested on my laptop with touch screen (ie: effectively a large tablet form factor), if this merges and we get it on nightly I'll definitely try on the PinePhone, there I will closely scrutinize whether the undoYThreshold and task scrub mode number of tasks feels good to use on a small portrait mode display. This may lead to followup MRs to tweak those essentially arbitrarily chosen values. # TODOs for later MRs - [ ] consider moving velocity calculation/generic 2-dimensional gesture tracking to kwin if it's robust and generic enough for that to be useful on their end. (maybe do that later after it has proven itself for a while on our side) - [ ] (optional?) vibration feedback to tell if it goes to taskswitcher or homescreen? android has that (at least mine) with a tight vibration when task switcher is invoked vs homescree - [ ] flick to homescreen animation kinda looks bad - [ ] task sorting by recency - [ ] polish task scrub mode if we intend to keep it - [ ] task scrub mode can "run out of space" for the gesture and thus can only scrub through a maximum number of tasks (currently 8 either direction in my implementation), but we could add a timer if reaching the end that goes through tasks eg: one per second (acceleration?) to "unlock" the full task list - [ ] task scrub mode should have some visual cue when it's activated (eg: fully "opening" the switcher y position, maybe some extra UI with window thumbnails) - [ ] Positioning after screen geometry change (resize, rotation) of the task switcher is kinda broken (task may end off-screen etc) - fixed by interacting with it or re-opening and not a huge issue IMO - [ ] some bound for y position above the "fully opened position" (maybe make it more and more "reluctant" to follow the finger upwards the further up you go - I think that just makes it feel a bit nicer - [ ] make it behave better with docked mode (currently some animations look a bit scuffed) - [ ] make it behave better with multi screen (currently it's mirrored on all screens, we probably only want it on the screen that currently has focus?) - [ ] navbar buttons when not in gesture mode seem to have slightly different button icon sizes than the system wide navbar (is there no better way to add the navbar than to essentially reimplement it?)
2024-05-05 01:17:54 +00:00
// fully open the switcher (if this is a button press, not gesture)
if (!state.gestureInProgress) {
taskSwitcherHelpers.fromButton = true;
if (state.wasInActiveTask) {
taskList.setTaskOffsetValue(0, true);
} else {
taskList.setTaskOffsetValue(0);
}
backgroundColorOpacity = 1;
taskswitcher: enhance gesture with flick speed tracking and orthogonal movement tracking This MR contains work to track the speed with which the taskswitcher gesture has occurred to allow different handling of a "fast flick" (eg: go to homescreen instead of taskswitcher). # Features The center piece of the overhaul is tracking recent velocity (averaged over the last ~50ms) of the gesture to determine behavior: - Swipe: A normal swipe is a "slow" finger move - Flick: A "fast" swipe The determining factor is the speed at the end of the gesture (= when lifting the finger up), anything before is irrelevant - Swipe up goes to task switcher - Flick up goes to homescreen directly instead of task switcher - this is suppressed when already on homescreen - it makes no sense there - Note: On Android that is actually mapped to "going to the first page of the home screen if not there already" - I don't care much for that and it can lead to nothing happening if you're already there, I think I prefer the consistency of always opening the task switcher vs a "quick way to get to the main (first) page of the homescreen" - especially since what that means depends a lot on the active home screen. - added orthogonal gesture movement tracking (2-axis gestures) - gesture properly follows finger movement in all directions now making it feel much more responsive and nice - diagonal flick for quick task switch - horizontal only movement (while holding, not releasing) triggers task scrub gesture for scrubbing through larger number of task in the switcher backlog - Complete refactor of state keeping logic, not just in relation to gestures - state keeper fully in one place in C++ except for - a few derived values that are very directly UI related which are kept in `TaskSwitcherHelpers.qml` - and directly touch gesture related state which are kept separate to maybe allow upstreaming the new touch border gesture handling to KWin in the future <details><summary>done TODO items</summary> - [x] currentTaskIndex tracking is majorly broken - [x] old TaskSwitcherState.qml is still around, should be removed - [x] clamping minimum scale for some reason also clamps y position which makes the task not track the finger when moving past the "full activation" point - [x] switching between tasks when task switcher is open is super crap - [x] task switching when switcher is fully open works now, but flicks don't work - you have to fully move at least halfway to the next task for it to "snap" to that task when you let go, there is 0 momentum and I don't know why -> *Flickable is just broken and refuses to flick on touch input, same behavior on master with old implementation, so I reimplemented the same workaround from before* - [x] the gestures don't work until the notification drawer was invoked at least once after every screen geometry change (resolution change, screen rotation etc) - [x] keyboard shortcut for toggling task switcher is kinda hacky right now and feels awful when closing (some delay noticable, maybe to do with animations?) *NOTE: I disabled it for now because the hacky implementation interfered with/created bugs in other parts* - [x] task scrub mode has broken offsets/positions (can scroll past the end of the list, but not reach all elements) when opening task index is not 0 - [x] fast flick velocity threshold is a mostly arbitrary number and I think it also depends on pixel density - ideally we want a mm (or cm or whatever) per ms, not logical pixels per ms </details> # Design decisions I made during development: - Changed the y opening animation from OutBack (with a bounce) to a simple OutExpo (quickly move towards and then approach slowly) as the bouncy look and feel from the OutBack animation felt wrong to me in that place - To fit better with the new docked mode: - the task switcher now shows the screen geometry behind a task that is not fullscreened. This allows to consistently press (and see) the adjacent tasks which might not always be the case if it's a thin window on a landscape screen. - This is not great overall yet - actually it just checks the windows actual aspect ratio, so if it's smaller but same aspect ratio as screen it shows as if it's a full screen task - also it maximizes and centers the window thumbnail in the task switcher so it really isn't ideal, I just don't know what the behavior *should* ideally be. This change at least doesn't break the switcher when in docked mode. - on opening an app from task switcher it doesn't get force-fullscreened anymore - either it already is fullscreen (because fullscreen in docked mode or just not in docked mode) or it should just keep its geometry (this could be gated behind checking if docked mode is on or not, but I think it's fine without) # TODO before merge - [x] IMPORTANT: Because of regular crashing on interaction I've commented out any code that uses WindowFilterModel::data() which seems to be the cause for that. Since master also uses this and experiences these crashes (at least on both dev machines I tested), I don't think this MR necessarily needs to be held up for that issue (especially since it feels like it could be upstream). I removed this to have an easier time with testing my code without constant crashes, but before merging this would need to be put in again as it breaks: skipping windows with "skipSwitcher" flag set, and showing the correct task when opening the switcher in certain situations. - seems to be a bug with WindowFilterModel::data sometimes returning an invalid/null element? But not in C++, it just doesn't make its way to QML. - feels like it could be a timing thing (but maybe not?) when reverting the skipSwitcher filter rule on `tasksModel` *or* adding some lengthy debug console log in `TaskList.qml:minimizeAll()` before trying to access item.window properties it seems to be fine. When keeping skipSwitcher and having no lengthy debug output I get crashes rather reliably every ~3rd to 5th time invoking the task switcher. - While this does seem to be reproducible on master and thus "the same", if it is timing based it may be that my code triggers the error *more often* technically making it a regression (though also easier to track down?) - Interestingly I don't seem to be able to reproduce this on-device, my PinePhone doesn't have this behavior at all. Maybe a bug with nested KWin session? - [ ] task scrub mode may need to have a dynamic amount of items to scrub through based on display size/orientation (maybe keep distance for task scrubbing the same on portrait vs landscape to aid muscle memory)? or instead of using percentages/pixel distances use mm distance based on dpi? - [ ] is task scrub mode even something we want? Since I prefer the "quick switch gesture" only being able to switch between the two most recent windows (because of immediate reordering by recency), this leaves our task switcher in gesture mode with no quick "shortcut gesture" to switch to older tasks, task scrub mode makes this possible in IMO a nice way, but would love input there. - [ ] get rid of all code comments marked with `TODO!` (with an exclamation mark) - [x] One last pass on removing all superfluous console logs, includes and unused functions. I cleaned that up a lot already, but not completely (one std::cout is still left in on purpose until last minute because of a very rare gesture bug I saw twice and I'm not sure if my fix really got it) # Other - I've only ever tested on my laptop with touch screen (ie: effectively a large tablet form factor), if this merges and we get it on nightly I'll definitely try on the PinePhone, there I will closely scrutinize whether the undoYThreshold and task scrub mode number of tasks feels good to use on a small portrait mode display. This may lead to followup MRs to tweak those essentially arbitrarily chosen values. # TODOs for later MRs - [ ] consider moving velocity calculation/generic 2-dimensional gesture tracking to kwin if it's robust and generic enough for that to be useful on their end. (maybe do that later after it has proven itself for a while on our side) - [ ] (optional?) vibration feedback to tell if it goes to taskswitcher or homescreen? android has that (at least mine) with a tight vibration when task switcher is invoked vs homescree - [ ] flick to homescreen animation kinda looks bad - [ ] task sorting by recency - [ ] polish task scrub mode if we intend to keep it - [ ] task scrub mode can "run out of space" for the gesture and thus can only scrub through a maximum number of tasks (currently 8 either direction in my implementation), but we could add a timer if reaching the end that goes through tasks eg: one per second (acceleration?) to "unlock" the full task list - [ ] task scrub mode should have some visual cue when it's activated (eg: fully "opening" the switcher y position, maybe some extra UI with window thumbnails) - [ ] Positioning after screen geometry change (resize, rotation) of the task switcher is kinda broken (task may end off-screen etc) - fixed by interacting with it or re-opening and not a huge issue IMO - [ ] some bound for y position above the "fully opened position" (maybe make it more and more "reluctant" to follow the finger upwards the further up you go - I think that just makes it feel a bit nicer - [ ] make it behave better with docked mode (currently some animations look a bit scuffed) - [ ] make it behave better with multi screen (currently it's mirrored on all screens, we probably only want it on the screen that currently has focus?) - [ ] navbar buttons when not in gesture mode seem to have slightly different button icon sizes than the system wide navbar (is there no better way to add the navbar than to essentially reimplement it?)
2024-05-05 01:17:54 +00:00
taskSwitcherHelpers.open();
2023-03-06 06:38:43 +00:00
}
}
// called by c++ plugin
function hideAnimation(): void {
2023-03-06 06:38:43 +00:00
closeAnim.restart();
}
function instantHide(): void {
state.deactivate(true);
2023-03-06 06:38:43 +00:00
}
function hide(): void {
state.deactivate(false);
2023-03-06 06:38:43 +00:00
}
Connections {
taskswitcher: enhance gesture with flick speed tracking and orthogonal movement tracking This MR contains work to track the speed with which the taskswitcher gesture has occurred to allow different handling of a "fast flick" (eg: go to homescreen instead of taskswitcher). # Features The center piece of the overhaul is tracking recent velocity (averaged over the last ~50ms) of the gesture to determine behavior: - Swipe: A normal swipe is a "slow" finger move - Flick: A "fast" swipe The determining factor is the speed at the end of the gesture (= when lifting the finger up), anything before is irrelevant - Swipe up goes to task switcher - Flick up goes to homescreen directly instead of task switcher - this is suppressed when already on homescreen - it makes no sense there - Note: On Android that is actually mapped to "going to the first page of the home screen if not there already" - I don't care much for that and it can lead to nothing happening if you're already there, I think I prefer the consistency of always opening the task switcher vs a "quick way to get to the main (first) page of the homescreen" - especially since what that means depends a lot on the active home screen. - added orthogonal gesture movement tracking (2-axis gestures) - gesture properly follows finger movement in all directions now making it feel much more responsive and nice - diagonal flick for quick task switch - horizontal only movement (while holding, not releasing) triggers task scrub gesture for scrubbing through larger number of task in the switcher backlog - Complete refactor of state keeping logic, not just in relation to gestures - state keeper fully in one place in C++ except for - a few derived values that are very directly UI related which are kept in `TaskSwitcherHelpers.qml` - and directly touch gesture related state which are kept separate to maybe allow upstreaming the new touch border gesture handling to KWin in the future <details><summary>done TODO items</summary> - [x] currentTaskIndex tracking is majorly broken - [x] old TaskSwitcherState.qml is still around, should be removed - [x] clamping minimum scale for some reason also clamps y position which makes the task not track the finger when moving past the "full activation" point - [x] switching between tasks when task switcher is open is super crap - [x] task switching when switcher is fully open works now, but flicks don't work - you have to fully move at least halfway to the next task for it to "snap" to that task when you let go, there is 0 momentum and I don't know why -> *Flickable is just broken and refuses to flick on touch input, same behavior on master with old implementation, so I reimplemented the same workaround from before* - [x] the gestures don't work until the notification drawer was invoked at least once after every screen geometry change (resolution change, screen rotation etc) - [x] keyboard shortcut for toggling task switcher is kinda hacky right now and feels awful when closing (some delay noticable, maybe to do with animations?) *NOTE: I disabled it for now because the hacky implementation interfered with/created bugs in other parts* - [x] task scrub mode has broken offsets/positions (can scroll past the end of the list, but not reach all elements) when opening task index is not 0 - [x] fast flick velocity threshold is a mostly arbitrary number and I think it also depends on pixel density - ideally we want a mm (or cm or whatever) per ms, not logical pixels per ms </details> # Design decisions I made during development: - Changed the y opening animation from OutBack (with a bounce) to a simple OutExpo (quickly move towards and then approach slowly) as the bouncy look and feel from the OutBack animation felt wrong to me in that place - To fit better with the new docked mode: - the task switcher now shows the screen geometry behind a task that is not fullscreened. This allows to consistently press (and see) the adjacent tasks which might not always be the case if it's a thin window on a landscape screen. - This is not great overall yet - actually it just checks the windows actual aspect ratio, so if it's smaller but same aspect ratio as screen it shows as if it's a full screen task - also it maximizes and centers the window thumbnail in the task switcher so it really isn't ideal, I just don't know what the behavior *should* ideally be. This change at least doesn't break the switcher when in docked mode. - on opening an app from task switcher it doesn't get force-fullscreened anymore - either it already is fullscreen (because fullscreen in docked mode or just not in docked mode) or it should just keep its geometry (this could be gated behind checking if docked mode is on or not, but I think it's fine without) # TODO before merge - [x] IMPORTANT: Because of regular crashing on interaction I've commented out any code that uses WindowFilterModel::data() which seems to be the cause for that. Since master also uses this and experiences these crashes (at least on both dev machines I tested), I don't think this MR necessarily needs to be held up for that issue (especially since it feels like it could be upstream). I removed this to have an easier time with testing my code without constant crashes, but before merging this would need to be put in again as it breaks: skipping windows with "skipSwitcher" flag set, and showing the correct task when opening the switcher in certain situations. - seems to be a bug with WindowFilterModel::data sometimes returning an invalid/null element? But not in C++, it just doesn't make its way to QML. - feels like it could be a timing thing (but maybe not?) when reverting the skipSwitcher filter rule on `tasksModel` *or* adding some lengthy debug console log in `TaskList.qml:minimizeAll()` before trying to access item.window properties it seems to be fine. When keeping skipSwitcher and having no lengthy debug output I get crashes rather reliably every ~3rd to 5th time invoking the task switcher. - While this does seem to be reproducible on master and thus "the same", if it is timing based it may be that my code triggers the error *more often* technically making it a regression (though also easier to track down?) - Interestingly I don't seem to be able to reproduce this on-device, my PinePhone doesn't have this behavior at all. Maybe a bug with nested KWin session? - [ ] task scrub mode may need to have a dynamic amount of items to scrub through based on display size/orientation (maybe keep distance for task scrubbing the same on portrait vs landscape to aid muscle memory)? or instead of using percentages/pixel distances use mm distance based on dpi? - [ ] is task scrub mode even something we want? Since I prefer the "quick switch gesture" only being able to switch between the two most recent windows (because of immediate reordering by recency), this leaves our task switcher in gesture mode with no quick "shortcut gesture" to switch to older tasks, task scrub mode makes this possible in IMO a nice way, but would love input there. - [ ] get rid of all code comments marked with `TODO!` (with an exclamation mark) - [x] One last pass on removing all superfluous console logs, includes and unused functions. I cleaned that up a lot already, but not completely (one std::cout is still left in on purpose until last minute because of a very rare gesture bug I saw twice and I'm not sure if my fix really got it) # Other - I've only ever tested on my laptop with touch screen (ie: effectively a large tablet form factor), if this merges and we get it on nightly I'll definitely try on the PinePhone, there I will closely scrutinize whether the undoYThreshold and task scrub mode number of tasks feels good to use on a small portrait mode display. This may lead to followup MRs to tweak those essentially arbitrarily chosen values. # TODOs for later MRs - [ ] consider moving velocity calculation/generic 2-dimensional gesture tracking to kwin if it's robust and generic enough for that to be useful on their end. (maybe do that later after it has proven itself for a while on our side) - [ ] (optional?) vibration feedback to tell if it goes to taskswitcher or homescreen? android has that (at least mine) with a tight vibration when task switcher is invoked vs homescree - [ ] flick to homescreen animation kinda looks bad - [ ] task sorting by recency - [ ] polish task scrub mode if we intend to keep it - [ ] task scrub mode can "run out of space" for the gesture and thus can only scrub through a maximum number of tasks (currently 8 either direction in my implementation), but we could add a timer if reaching the end that goes through tasks eg: one per second (acceleration?) to "unlock" the full task list - [ ] task scrub mode should have some visual cue when it's activated (eg: fully "opening" the switcher y position, maybe some extra UI with window thumbnails) - [ ] Positioning after screen geometry change (resize, rotation) of the task switcher is kinda broken (task may end off-screen etc) - fixed by interacting with it or re-opening and not a huge issue IMO - [ ] some bound for y position above the "fully opened position" (maybe make it more and more "reluctant" to follow the finger upwards the further up you go - I think that just makes it feel a bit nicer - [ ] make it behave better with docked mode (currently some animations look a bit scuffed) - [ ] make it behave better with multi screen (currently it's mirrored on all screens, we probably only want it on the screen that currently has focus?) - [ ] navbar buttons when not in gesture mode seem to have slightly different button icon sizes than the system wide navbar (is there no better way to add the navbar than to essentially reimplement it?)
2024-05-05 01:17:54 +00:00
target: root.state
// task scrub mode allows scrubbing through a number of tasks with a mostly horizontal motion
function taskScrubMode(): void {
taskList.setTaskOffsetValue(0, false, Easing.OutQuart);
if (!root.taskSwitcherHelpers.isInTaskScrubMode) {
root.backgroundColorOpacity = 1;
root.taskSwitcherHelpers.cancelAnimations();
root.taskSwitcherHelpers.open();
if (!root.taskSwitcherHelpers.hasVibrated) {
// Haptic feedback when the task scrub mode engages
haptics.buttonVibrate();
root.taskSwitcherHelpers.hasVibrated = true;
}
taskswitcher: enhance gesture with flick speed tracking and orthogonal movement tracking This MR contains work to track the speed with which the taskswitcher gesture has occurred to allow different handling of a "fast flick" (eg: go to homescreen instead of taskswitcher). # Features The center piece of the overhaul is tracking recent velocity (averaged over the last ~50ms) of the gesture to determine behavior: - Swipe: A normal swipe is a "slow" finger move - Flick: A "fast" swipe The determining factor is the speed at the end of the gesture (= when lifting the finger up), anything before is irrelevant - Swipe up goes to task switcher - Flick up goes to homescreen directly instead of task switcher - this is suppressed when already on homescreen - it makes no sense there - Note: On Android that is actually mapped to "going to the first page of the home screen if not there already" - I don't care much for that and it can lead to nothing happening if you're already there, I think I prefer the consistency of always opening the task switcher vs a "quick way to get to the main (first) page of the homescreen" - especially since what that means depends a lot on the active home screen. - added orthogonal gesture movement tracking (2-axis gestures) - gesture properly follows finger movement in all directions now making it feel much more responsive and nice - diagonal flick for quick task switch - horizontal only movement (while holding, not releasing) triggers task scrub gesture for scrubbing through larger number of task in the switcher backlog - Complete refactor of state keeping logic, not just in relation to gestures - state keeper fully in one place in C++ except for - a few derived values that are very directly UI related which are kept in `TaskSwitcherHelpers.qml` - and directly touch gesture related state which are kept separate to maybe allow upstreaming the new touch border gesture handling to KWin in the future <details><summary>done TODO items</summary> - [x] currentTaskIndex tracking is majorly broken - [x] old TaskSwitcherState.qml is still around, should be removed - [x] clamping minimum scale for some reason also clamps y position which makes the task not track the finger when moving past the "full activation" point - [x] switching between tasks when task switcher is open is super crap - [x] task switching when switcher is fully open works now, but flicks don't work - you have to fully move at least halfway to the next task for it to "snap" to that task when you let go, there is 0 momentum and I don't know why -> *Flickable is just broken and refuses to flick on touch input, same behavior on master with old implementation, so I reimplemented the same workaround from before* - [x] the gestures don't work until the notification drawer was invoked at least once after every screen geometry change (resolution change, screen rotation etc) - [x] keyboard shortcut for toggling task switcher is kinda hacky right now and feels awful when closing (some delay noticable, maybe to do with animations?) *NOTE: I disabled it for now because the hacky implementation interfered with/created bugs in other parts* - [x] task scrub mode has broken offsets/positions (can scroll past the end of the list, but not reach all elements) when opening task index is not 0 - [x] fast flick velocity threshold is a mostly arbitrary number and I think it also depends on pixel density - ideally we want a mm (or cm or whatever) per ms, not logical pixels per ms </details> # Design decisions I made during development: - Changed the y opening animation from OutBack (with a bounce) to a simple OutExpo (quickly move towards and then approach slowly) as the bouncy look and feel from the OutBack animation felt wrong to me in that place - To fit better with the new docked mode: - the task switcher now shows the screen geometry behind a task that is not fullscreened. This allows to consistently press (and see) the adjacent tasks which might not always be the case if it's a thin window on a landscape screen. - This is not great overall yet - actually it just checks the windows actual aspect ratio, so if it's smaller but same aspect ratio as screen it shows as if it's a full screen task - also it maximizes and centers the window thumbnail in the task switcher so it really isn't ideal, I just don't know what the behavior *should* ideally be. This change at least doesn't break the switcher when in docked mode. - on opening an app from task switcher it doesn't get force-fullscreened anymore - either it already is fullscreen (because fullscreen in docked mode or just not in docked mode) or it should just keep its geometry (this could be gated behind checking if docked mode is on or not, but I think it's fine without) # TODO before merge - [x] IMPORTANT: Because of regular crashing on interaction I've commented out any code that uses WindowFilterModel::data() which seems to be the cause for that. Since master also uses this and experiences these crashes (at least on both dev machines I tested), I don't think this MR necessarily needs to be held up for that issue (especially since it feels like it could be upstream). I removed this to have an easier time with testing my code without constant crashes, but before merging this would need to be put in again as it breaks: skipping windows with "skipSwitcher" flag set, and showing the correct task when opening the switcher in certain situations. - seems to be a bug with WindowFilterModel::data sometimes returning an invalid/null element? But not in C++, it just doesn't make its way to QML. - feels like it could be a timing thing (but maybe not?) when reverting the skipSwitcher filter rule on `tasksModel` *or* adding some lengthy debug console log in `TaskList.qml:minimizeAll()` before trying to access item.window properties it seems to be fine. When keeping skipSwitcher and having no lengthy debug output I get crashes rather reliably every ~3rd to 5th time invoking the task switcher. - While this does seem to be reproducible on master and thus "the same", if it is timing based it may be that my code triggers the error *more often* technically making it a regression (though also easier to track down?) - Interestingly I don't seem to be able to reproduce this on-device, my PinePhone doesn't have this behavior at all. Maybe a bug with nested KWin session? - [ ] task scrub mode may need to have a dynamic amount of items to scrub through based on display size/orientation (maybe keep distance for task scrubbing the same on portrait vs landscape to aid muscle memory)? or instead of using percentages/pixel distances use mm distance based on dpi? - [ ] is task scrub mode even something we want? Since I prefer the "quick switch gesture" only being able to switch between the two most recent windows (because of immediate reordering by recency), this leaves our task switcher in gesture mode with no quick "shortcut gesture" to switch to older tasks, task scrub mode makes this possible in IMO a nice way, but would love input there. - [ ] get rid of all code comments marked with `TODO!` (with an exclamation mark) - [x] One last pass on removing all superfluous console logs, includes and unused functions. I cleaned that up a lot already, but not completely (one std::cout is still left in on purpose until last minute because of a very rare gesture bug I saw twice and I'm not sure if my fix really got it) # Other - I've only ever tested on my laptop with touch screen (ie: effectively a large tablet form factor), if this merges and we get it on nightly I'll definitely try on the PinePhone, there I will closely scrutinize whether the undoYThreshold and task scrub mode number of tasks feels good to use on a small portrait mode display. This may lead to followup MRs to tweak those essentially arbitrarily chosen values. # TODOs for later MRs - [ ] consider moving velocity calculation/generic 2-dimensional gesture tracking to kwin if it's robust and generic enough for that to be useful on their end. (maybe do that later after it has proven itself for a while on our side) - [ ] (optional?) vibration feedback to tell if it goes to taskswitcher or homescreen? android has that (at least mine) with a tight vibration when task switcher is invoked vs homescree - [ ] flick to homescreen animation kinda looks bad - [ ] task sorting by recency - [ ] polish task scrub mode if we intend to keep it - [ ] task scrub mode can "run out of space" for the gesture and thus can only scrub through a maximum number of tasks (currently 8 either direction in my implementation), but we could add a timer if reaching the end that goes through tasks eg: one per second (acceleration?) to "unlock" the full task list - [ ] task scrub mode should have some visual cue when it's activated (eg: fully "opening" the switcher y position, maybe some extra UI with window thumbnails) - [ ] Positioning after screen geometry change (resize, rotation) of the task switcher is kinda broken (task may end off-screen etc) - fixed by interacting with it or re-opening and not a huge issue IMO - [ ] some bound for y position above the "fully opened position" (maybe make it more and more "reluctant" to follow the finger upwards the further up you go - I think that just makes it feel a bit nicer - [ ] make it behave better with docked mode (currently some animations look a bit scuffed) - [ ] make it behave better with multi screen (currently it's mirrored on all screens, we probably only want it on the screen that currently has focus?) - [ ] navbar buttons when not in gesture mode seem to have slightly different button icon sizes than the system wide navbar (is there no better way to add the navbar than to essentially reimplement it?)
2024-05-05 01:17:54 +00:00
}
// TODO this makes sense, but makes scrub mode feel a bit weird
// improve trigger distance logic for task scrub mode to fix
let newTaskIndex = Math.max(0, Math.min(root.tasksCount - 1, Math.floor(root.state.touchXPosition / root.taskSwitcherHelpers.taskScrubDistance) + root.state.initialTaskIndex - (root.state.wasInActiveTask ? 0 : 1)));
if (newTaskIndex != root.state.currentTaskIndex || !root.taskSwitcherHelpers.isInTaskScrubMode) {
root.taskSwitcherHelpers.animateGoToTaskIndex(newTaskIndex);
root.taskSwitcherHelpers.isInTaskScrubMode = true;
taskswitcher: enhance gesture with flick speed tracking and orthogonal movement tracking This MR contains work to track the speed with which the taskswitcher gesture has occurred to allow different handling of a "fast flick" (eg: go to homescreen instead of taskswitcher). # Features The center piece of the overhaul is tracking recent velocity (averaged over the last ~50ms) of the gesture to determine behavior: - Swipe: A normal swipe is a "slow" finger move - Flick: A "fast" swipe The determining factor is the speed at the end of the gesture (= when lifting the finger up), anything before is irrelevant - Swipe up goes to task switcher - Flick up goes to homescreen directly instead of task switcher - this is suppressed when already on homescreen - it makes no sense there - Note: On Android that is actually mapped to "going to the first page of the home screen if not there already" - I don't care much for that and it can lead to nothing happening if you're already there, I think I prefer the consistency of always opening the task switcher vs a "quick way to get to the main (first) page of the homescreen" - especially since what that means depends a lot on the active home screen. - added orthogonal gesture movement tracking (2-axis gestures) - gesture properly follows finger movement in all directions now making it feel much more responsive and nice - diagonal flick for quick task switch - horizontal only movement (while holding, not releasing) triggers task scrub gesture for scrubbing through larger number of task in the switcher backlog - Complete refactor of state keeping logic, not just in relation to gestures - state keeper fully in one place in C++ except for - a few derived values that are very directly UI related which are kept in `TaskSwitcherHelpers.qml` - and directly touch gesture related state which are kept separate to maybe allow upstreaming the new touch border gesture handling to KWin in the future <details><summary>done TODO items</summary> - [x] currentTaskIndex tracking is majorly broken - [x] old TaskSwitcherState.qml is still around, should be removed - [x] clamping minimum scale for some reason also clamps y position which makes the task not track the finger when moving past the "full activation" point - [x] switching between tasks when task switcher is open is super crap - [x] task switching when switcher is fully open works now, but flicks don't work - you have to fully move at least halfway to the next task for it to "snap" to that task when you let go, there is 0 momentum and I don't know why -> *Flickable is just broken and refuses to flick on touch input, same behavior on master with old implementation, so I reimplemented the same workaround from before* - [x] the gestures don't work until the notification drawer was invoked at least once after every screen geometry change (resolution change, screen rotation etc) - [x] keyboard shortcut for toggling task switcher is kinda hacky right now and feels awful when closing (some delay noticable, maybe to do with animations?) *NOTE: I disabled it for now because the hacky implementation interfered with/created bugs in other parts* - [x] task scrub mode has broken offsets/positions (can scroll past the end of the list, but not reach all elements) when opening task index is not 0 - [x] fast flick velocity threshold is a mostly arbitrary number and I think it also depends on pixel density - ideally we want a mm (or cm or whatever) per ms, not logical pixels per ms </details> # Design decisions I made during development: - Changed the y opening animation from OutBack (with a bounce) to a simple OutExpo (quickly move towards and then approach slowly) as the bouncy look and feel from the OutBack animation felt wrong to me in that place - To fit better with the new docked mode: - the task switcher now shows the screen geometry behind a task that is not fullscreened. This allows to consistently press (and see) the adjacent tasks which might not always be the case if it's a thin window on a landscape screen. - This is not great overall yet - actually it just checks the windows actual aspect ratio, so if it's smaller but same aspect ratio as screen it shows as if it's a full screen task - also it maximizes and centers the window thumbnail in the task switcher so it really isn't ideal, I just don't know what the behavior *should* ideally be. This change at least doesn't break the switcher when in docked mode. - on opening an app from task switcher it doesn't get force-fullscreened anymore - either it already is fullscreen (because fullscreen in docked mode or just not in docked mode) or it should just keep its geometry (this could be gated behind checking if docked mode is on or not, but I think it's fine without) # TODO before merge - [x] IMPORTANT: Because of regular crashing on interaction I've commented out any code that uses WindowFilterModel::data() which seems to be the cause for that. Since master also uses this and experiences these crashes (at least on both dev machines I tested), I don't think this MR necessarily needs to be held up for that issue (especially since it feels like it could be upstream). I removed this to have an easier time with testing my code without constant crashes, but before merging this would need to be put in again as it breaks: skipping windows with "skipSwitcher" flag set, and showing the correct task when opening the switcher in certain situations. - seems to be a bug with WindowFilterModel::data sometimes returning an invalid/null element? But not in C++, it just doesn't make its way to QML. - feels like it could be a timing thing (but maybe not?) when reverting the skipSwitcher filter rule on `tasksModel` *or* adding some lengthy debug console log in `TaskList.qml:minimizeAll()` before trying to access item.window properties it seems to be fine. When keeping skipSwitcher and having no lengthy debug output I get crashes rather reliably every ~3rd to 5th time invoking the task switcher. - While this does seem to be reproducible on master and thus "the same", if it is timing based it may be that my code triggers the error *more often* technically making it a regression (though also easier to track down?) - Interestingly I don't seem to be able to reproduce this on-device, my PinePhone doesn't have this behavior at all. Maybe a bug with nested KWin session? - [ ] task scrub mode may need to have a dynamic amount of items to scrub through based on display size/orientation (maybe keep distance for task scrubbing the same on portrait vs landscape to aid muscle memory)? or instead of using percentages/pixel distances use mm distance based on dpi? - [ ] is task scrub mode even something we want? Since I prefer the "quick switch gesture" only being able to switch between the two most recent windows (because of immediate reordering by recency), this leaves our task switcher in gesture mode with no quick "shortcut gesture" to switch to older tasks, task scrub mode makes this possible in IMO a nice way, but would love input there. - [ ] get rid of all code comments marked with `TODO!` (with an exclamation mark) - [x] One last pass on removing all superfluous console logs, includes and unused functions. I cleaned that up a lot already, but not completely (one std::cout is still left in on purpose until last minute because of a very rare gesture bug I saw twice and I'm not sure if my fix really got it) # Other - I've only ever tested on my laptop with touch screen (ie: effectively a large tablet form factor), if this merges and we get it on nightly I'll definitely try on the PinePhone, there I will closely scrutinize whether the undoYThreshold and task scrub mode number of tasks feels good to use on a small portrait mode display. This may lead to followup MRs to tweak those essentially arbitrarily chosen values. # TODOs for later MRs - [ ] consider moving velocity calculation/generic 2-dimensional gesture tracking to kwin if it's robust and generic enough for that to be useful on their end. (maybe do that later after it has proven itself for a while on our side) - [ ] (optional?) vibration feedback to tell if it goes to taskswitcher or homescreen? android has that (at least mine) with a tight vibration when task switcher is invoked vs homescree - [ ] flick to homescreen animation kinda looks bad - [ ] task sorting by recency - [ ] polish task scrub mode if we intend to keep it - [ ] task scrub mode can "run out of space" for the gesture and thus can only scrub through a maximum number of tasks (currently 8 either direction in my implementation), but we could add a timer if reaching the end that goes through tasks eg: one per second (acceleration?) to "unlock" the full task list - [ ] task scrub mode should have some visual cue when it's activated (eg: fully "opening" the switcher y position, maybe some extra UI with window thumbnails) - [ ] Positioning after screen geometry change (resize, rotation) of the task switcher is kinda broken (task may end off-screen etc) - fixed by interacting with it or re-opening and not a huge issue IMO - [ ] some bound for y position above the "fully opened position" (maybe make it more and more "reluctant" to follow the finger upwards the further up you go - I think that just makes it feel a bit nicer - [ ] make it behave better with docked mode (currently some animations look a bit scuffed) - [ ] make it behave better with multi screen (currently it's mirrored on all screens, we probably only want it on the screen that currently has focus?) - [ ] navbar buttons when not in gesture mode seem to have slightly different button icon sizes than the system wide navbar (is there no better way to add the navbar than to essentially reimplement it?)
2024-05-05 01:17:54 +00:00
}
}
function onTouchPositionChanged(): void {
let unmodifiedYposition = Math.abs(root.state.touchYPosition)
if (root.taskSwitcherHelpers.isInTaskScrubMode || // once in scrub mode, let's not allow to go out, that can result in inconsistent UX
(Math.abs(root.state.xVelocity) > Math.abs(root.state.yVelocity) * 3 && // gesture needs to be almost completely horizontal
Math.abs(root.state.xVelocity) < 2.5 && // and not with a fast flick TODO! evaluate whether to keep this, it's kinda awkward
Math.abs(root.state.touchXPosition) > root.taskSwitcherHelpers.taskScrubDistance * 0.95 && // and have moved far enough sideways
unmodifiedYposition < Kirigami.Units.largeSpacing * 2 && // and be close to the screen edge
root.tasksCount > 0 && // and there needs to be more than none task open
!root.taskSwitcherHelpers.taskDrawerOpened // and the task drawer must not be open
taskswitcher: enhance gesture with flick speed tracking and orthogonal movement tracking This MR contains work to track the speed with which the taskswitcher gesture has occurred to allow different handling of a "fast flick" (eg: go to homescreen instead of taskswitcher). # Features The center piece of the overhaul is tracking recent velocity (averaged over the last ~50ms) of the gesture to determine behavior: - Swipe: A normal swipe is a "slow" finger move - Flick: A "fast" swipe The determining factor is the speed at the end of the gesture (= when lifting the finger up), anything before is irrelevant - Swipe up goes to task switcher - Flick up goes to homescreen directly instead of task switcher - this is suppressed when already on homescreen - it makes no sense there - Note: On Android that is actually mapped to "going to the first page of the home screen if not there already" - I don't care much for that and it can lead to nothing happening if you're already there, I think I prefer the consistency of always opening the task switcher vs a "quick way to get to the main (first) page of the homescreen" - especially since what that means depends a lot on the active home screen. - added orthogonal gesture movement tracking (2-axis gestures) - gesture properly follows finger movement in all directions now making it feel much more responsive and nice - diagonal flick for quick task switch - horizontal only movement (while holding, not releasing) triggers task scrub gesture for scrubbing through larger number of task in the switcher backlog - Complete refactor of state keeping logic, not just in relation to gestures - state keeper fully in one place in C++ except for - a few derived values that are very directly UI related which are kept in `TaskSwitcherHelpers.qml` - and directly touch gesture related state which are kept separate to maybe allow upstreaming the new touch border gesture handling to KWin in the future <details><summary>done TODO items</summary> - [x] currentTaskIndex tracking is majorly broken - [x] old TaskSwitcherState.qml is still around, should be removed - [x] clamping minimum scale for some reason also clamps y position which makes the task not track the finger when moving past the "full activation" point - [x] switching between tasks when task switcher is open is super crap - [x] task switching when switcher is fully open works now, but flicks don't work - you have to fully move at least halfway to the next task for it to "snap" to that task when you let go, there is 0 momentum and I don't know why -> *Flickable is just broken and refuses to flick on touch input, same behavior on master with old implementation, so I reimplemented the same workaround from before* - [x] the gestures don't work until the notification drawer was invoked at least once after every screen geometry change (resolution change, screen rotation etc) - [x] keyboard shortcut for toggling task switcher is kinda hacky right now and feels awful when closing (some delay noticable, maybe to do with animations?) *NOTE: I disabled it for now because the hacky implementation interfered with/created bugs in other parts* - [x] task scrub mode has broken offsets/positions (can scroll past the end of the list, but not reach all elements) when opening task index is not 0 - [x] fast flick velocity threshold is a mostly arbitrary number and I think it also depends on pixel density - ideally we want a mm (or cm or whatever) per ms, not logical pixels per ms </details> # Design decisions I made during development: - Changed the y opening animation from OutBack (with a bounce) to a simple OutExpo (quickly move towards and then approach slowly) as the bouncy look and feel from the OutBack animation felt wrong to me in that place - To fit better with the new docked mode: - the task switcher now shows the screen geometry behind a task that is not fullscreened. This allows to consistently press (and see) the adjacent tasks which might not always be the case if it's a thin window on a landscape screen. - This is not great overall yet - actually it just checks the windows actual aspect ratio, so if it's smaller but same aspect ratio as screen it shows as if it's a full screen task - also it maximizes and centers the window thumbnail in the task switcher so it really isn't ideal, I just don't know what the behavior *should* ideally be. This change at least doesn't break the switcher when in docked mode. - on opening an app from task switcher it doesn't get force-fullscreened anymore - either it already is fullscreen (because fullscreen in docked mode or just not in docked mode) or it should just keep its geometry (this could be gated behind checking if docked mode is on or not, but I think it's fine without) # TODO before merge - [x] IMPORTANT: Because of regular crashing on interaction I've commented out any code that uses WindowFilterModel::data() which seems to be the cause for that. Since master also uses this and experiences these crashes (at least on both dev machines I tested), I don't think this MR necessarily needs to be held up for that issue (especially since it feels like it could be upstream). I removed this to have an easier time with testing my code without constant crashes, but before merging this would need to be put in again as it breaks: skipping windows with "skipSwitcher" flag set, and showing the correct task when opening the switcher in certain situations. - seems to be a bug with WindowFilterModel::data sometimes returning an invalid/null element? But not in C++, it just doesn't make its way to QML. - feels like it could be a timing thing (but maybe not?) when reverting the skipSwitcher filter rule on `tasksModel` *or* adding some lengthy debug console log in `TaskList.qml:minimizeAll()` before trying to access item.window properties it seems to be fine. When keeping skipSwitcher and having no lengthy debug output I get crashes rather reliably every ~3rd to 5th time invoking the task switcher. - While this does seem to be reproducible on master and thus "the same", if it is timing based it may be that my code triggers the error *more often* technically making it a regression (though also easier to track down?) - Interestingly I don't seem to be able to reproduce this on-device, my PinePhone doesn't have this behavior at all. Maybe a bug with nested KWin session? - [ ] task scrub mode may need to have a dynamic amount of items to scrub through based on display size/orientation (maybe keep distance for task scrubbing the same on portrait vs landscape to aid muscle memory)? or instead of using percentages/pixel distances use mm distance based on dpi? - [ ] is task scrub mode even something we want? Since I prefer the "quick switch gesture" only being able to switch between the two most recent windows (because of immediate reordering by recency), this leaves our task switcher in gesture mode with no quick "shortcut gesture" to switch to older tasks, task scrub mode makes this possible in IMO a nice way, but would love input there. - [ ] get rid of all code comments marked with `TODO!` (with an exclamation mark) - [x] One last pass on removing all superfluous console logs, includes and unused functions. I cleaned that up a lot already, but not completely (one std::cout is still left in on purpose until last minute because of a very rare gesture bug I saw twice and I'm not sure if my fix really got it) # Other - I've only ever tested on my laptop with touch screen (ie: effectively a large tablet form factor), if this merges and we get it on nightly I'll definitely try on the PinePhone, there I will closely scrutinize whether the undoYThreshold and task scrub mode number of tasks feels good to use on a small portrait mode display. This may lead to followup MRs to tweak those essentially arbitrarily chosen values. # TODOs for later MRs - [ ] consider moving velocity calculation/generic 2-dimensional gesture tracking to kwin if it's robust and generic enough for that to be useful on their end. (maybe do that later after it has proven itself for a while on our side) - [ ] (optional?) vibration feedback to tell if it goes to taskswitcher or homescreen? android has that (at least mine) with a tight vibration when task switcher is invoked vs homescree - [ ] flick to homescreen animation kinda looks bad - [ ] task sorting by recency - [ ] polish task scrub mode if we intend to keep it - [ ] task scrub mode can "run out of space" for the gesture and thus can only scrub through a maximum number of tasks (currently 8 either direction in my implementation), but we could add a timer if reaching the end that goes through tasks eg: one per second (acceleration?) to "unlock" the full task list - [ ] task scrub mode should have some visual cue when it's activated (eg: fully "opening" the switcher y position, maybe some extra UI with window thumbnails) - [ ] Positioning after screen geometry change (resize, rotation) of the task switcher is kinda broken (task may end off-screen etc) - fixed by interacting with it or re-opening and not a huge issue IMO - [ ] some bound for y position above the "fully opened position" (maybe make it more and more "reluctant" to follow the finger upwards the further up you go - I think that just makes it feel a bit nicer - [ ] make it behave better with docked mode (currently some animations look a bit scuffed) - [ ] make it behave better with multi screen (currently it's mirrored on all screens, we probably only want it on the screen that currently has focus?) - [ ] navbar buttons when not in gesture mode seem to have slightly different button icon sizes than the system wide navbar (is there no better way to add the navbar than to essentially reimplement it?)
2024-05-05 01:17:54 +00:00
)) {
taskScrubMode();
} else {
if (root.taskSwitcherHelpers.currentlyBeingClosed) {
// if the task switch is still open but playing the close animation
// setup some values and return to the initial setup so that the user can always navigate with no down time
root.state.wasInActiveTask = root.taskSwitcherHelpers.openAppAnim.running ? true : false
taskList.setTaskOffsetValue(root.state.wasInActiveTask ? root.taskSwitcherHelpers.taskOffsetValue : root.taskSwitcherHelpers.homeOffsetValue, true);
root.state.status = !root.state.wasInActiveTask ? (root.taskSwitcherHelpers.openAppAnim.closeAnim && !root.taskSwitcherHelpers.taskDrawerWillOpen ? TaskSwitcherPlugin.MobileTaskSwitcherState.Active : TaskSwitcherPlugin.MobileTaskSwitcherState.Inactive) : TaskSwitcherPlugin.MobileTaskSwitcherState.Inactive
root.initialSetup();
} else if (root.taskSwitcherHelpers.openAnim.running) {
root.taskSwitcherHelpers.cancelAnimations();
root.state.status = root.taskSwitcherHelpers.stateClass.Active;
}
root.state.yPosition = unmodifiedYposition + (root.taskSwitcherHelpers.taskDrawerOpened || !root.state.wasInActiveTask ? root.taskSwitcherHelpers.openedYPosition : 0);
let newXPosition = root.taskSwitcherHelpers.xPositionFromTaskIndex(root.state.initialTaskIndex);
if (root.taskSwitcherHelpers.notHomeScreenState && !root.taskSwitcherHelpers.currentlyBeingClosed) {
newXPosition = newXPosition - (root.state.touchXPosition / root.taskSwitcherHelpers.currentScale);
taskswitcher: enhance gesture with flick speed tracking and orthogonal movement tracking This MR contains work to track the speed with which the taskswitcher gesture has occurred to allow different handling of a "fast flick" (eg: go to homescreen instead of taskswitcher). # Features The center piece of the overhaul is tracking recent velocity (averaged over the last ~50ms) of the gesture to determine behavior: - Swipe: A normal swipe is a "slow" finger move - Flick: A "fast" swipe The determining factor is the speed at the end of the gesture (= when lifting the finger up), anything before is irrelevant - Swipe up goes to task switcher - Flick up goes to homescreen directly instead of task switcher - this is suppressed when already on homescreen - it makes no sense there - Note: On Android that is actually mapped to "going to the first page of the home screen if not there already" - I don't care much for that and it can lead to nothing happening if you're already there, I think I prefer the consistency of always opening the task switcher vs a "quick way to get to the main (first) page of the homescreen" - especially since what that means depends a lot on the active home screen. - added orthogonal gesture movement tracking (2-axis gestures) - gesture properly follows finger movement in all directions now making it feel much more responsive and nice - diagonal flick for quick task switch - horizontal only movement (while holding, not releasing) triggers task scrub gesture for scrubbing through larger number of task in the switcher backlog - Complete refactor of state keeping logic, not just in relation to gestures - state keeper fully in one place in C++ except for - a few derived values that are very directly UI related which are kept in `TaskSwitcherHelpers.qml` - and directly touch gesture related state which are kept separate to maybe allow upstreaming the new touch border gesture handling to KWin in the future <details><summary>done TODO items</summary> - [x] currentTaskIndex tracking is majorly broken - [x] old TaskSwitcherState.qml is still around, should be removed - [x] clamping minimum scale for some reason also clamps y position which makes the task not track the finger when moving past the "full activation" point - [x] switching between tasks when task switcher is open is super crap - [x] task switching when switcher is fully open works now, but flicks don't work - you have to fully move at least halfway to the next task for it to "snap" to that task when you let go, there is 0 momentum and I don't know why -> *Flickable is just broken and refuses to flick on touch input, same behavior on master with old implementation, so I reimplemented the same workaround from before* - [x] the gestures don't work until the notification drawer was invoked at least once after every screen geometry change (resolution change, screen rotation etc) - [x] keyboard shortcut for toggling task switcher is kinda hacky right now and feels awful when closing (some delay noticable, maybe to do with animations?) *NOTE: I disabled it for now because the hacky implementation interfered with/created bugs in other parts* - [x] task scrub mode has broken offsets/positions (can scroll past the end of the list, but not reach all elements) when opening task index is not 0 - [x] fast flick velocity threshold is a mostly arbitrary number and I think it also depends on pixel density - ideally we want a mm (or cm or whatever) per ms, not logical pixels per ms </details> # Design decisions I made during development: - Changed the y opening animation from OutBack (with a bounce) to a simple OutExpo (quickly move towards and then approach slowly) as the bouncy look and feel from the OutBack animation felt wrong to me in that place - To fit better with the new docked mode: - the task switcher now shows the screen geometry behind a task that is not fullscreened. This allows to consistently press (and see) the adjacent tasks which might not always be the case if it's a thin window on a landscape screen. - This is not great overall yet - actually it just checks the windows actual aspect ratio, so if it's smaller but same aspect ratio as screen it shows as if it's a full screen task - also it maximizes and centers the window thumbnail in the task switcher so it really isn't ideal, I just don't know what the behavior *should* ideally be. This change at least doesn't break the switcher when in docked mode. - on opening an app from task switcher it doesn't get force-fullscreened anymore - either it already is fullscreen (because fullscreen in docked mode or just not in docked mode) or it should just keep its geometry (this could be gated behind checking if docked mode is on or not, but I think it's fine without) # TODO before merge - [x] IMPORTANT: Because of regular crashing on interaction I've commented out any code that uses WindowFilterModel::data() which seems to be the cause for that. Since master also uses this and experiences these crashes (at least on both dev machines I tested), I don't think this MR necessarily needs to be held up for that issue (especially since it feels like it could be upstream). I removed this to have an easier time with testing my code without constant crashes, but before merging this would need to be put in again as it breaks: skipping windows with "skipSwitcher" flag set, and showing the correct task when opening the switcher in certain situations. - seems to be a bug with WindowFilterModel::data sometimes returning an invalid/null element? But not in C++, it just doesn't make its way to QML. - feels like it could be a timing thing (but maybe not?) when reverting the skipSwitcher filter rule on `tasksModel` *or* adding some lengthy debug console log in `TaskList.qml:minimizeAll()` before trying to access item.window properties it seems to be fine. When keeping skipSwitcher and having no lengthy debug output I get crashes rather reliably every ~3rd to 5th time invoking the task switcher. - While this does seem to be reproducible on master and thus "the same", if it is timing based it may be that my code triggers the error *more often* technically making it a regression (though also easier to track down?) - Interestingly I don't seem to be able to reproduce this on-device, my PinePhone doesn't have this behavior at all. Maybe a bug with nested KWin session? - [ ] task scrub mode may need to have a dynamic amount of items to scrub through based on display size/orientation (maybe keep distance for task scrubbing the same on portrait vs landscape to aid muscle memory)? or instead of using percentages/pixel distances use mm distance based on dpi? - [ ] is task scrub mode even something we want? Since I prefer the "quick switch gesture" only being able to switch between the two most recent windows (because of immediate reordering by recency), this leaves our task switcher in gesture mode with no quick "shortcut gesture" to switch to older tasks, task scrub mode makes this possible in IMO a nice way, but would love input there. - [ ] get rid of all code comments marked with `TODO!` (with an exclamation mark) - [x] One last pass on removing all superfluous console logs, includes and unused functions. I cleaned that up a lot already, but not completely (one std::cout is still left in on purpose until last minute because of a very rare gesture bug I saw twice and I'm not sure if my fix really got it) # Other - I've only ever tested on my laptop with touch screen (ie: effectively a large tablet form factor), if this merges and we get it on nightly I'll definitely try on the PinePhone, there I will closely scrutinize whether the undoYThreshold and task scrub mode number of tasks feels good to use on a small portrait mode display. This may lead to followup MRs to tweak those essentially arbitrarily chosen values. # TODOs for later MRs - [ ] consider moving velocity calculation/generic 2-dimensional gesture tracking to kwin if it's robust and generic enough for that to be useful on their end. (maybe do that later after it has proven itself for a while on our side) - [ ] (optional?) vibration feedback to tell if it goes to taskswitcher or homescreen? android has that (at least mine) with a tight vibration when task switcher is invoked vs homescree - [ ] flick to homescreen animation kinda looks bad - [ ] task sorting by recency - [ ] polish task scrub mode if we intend to keep it - [ ] task scrub mode can "run out of space" for the gesture and thus can only scrub through a maximum number of tasks (currently 8 either direction in my implementation), but we could add a timer if reaching the end that goes through tasks eg: one per second (acceleration?) to "unlock" the full task list - [ ] task scrub mode should have some visual cue when it's activated (eg: fully "opening" the switcher y position, maybe some extra UI with window thumbnails) - [ ] Positioning after screen geometry change (resize, rotation) of the task switcher is kinda broken (task may end off-screen etc) - fixed by interacting with it or re-opening and not a huge issue IMO - [ ] some bound for y position above the "fully opened position" (maybe make it more and more "reluctant" to follow the finger upwards the further up you go - I think that just makes it feel a bit nicer - [ ] make it behave better with docked mode (currently some animations look a bit scuffed) - [ ] make it behave better with multi screen (currently it's mirrored on all screens, we probably only want it on the screen that currently has focus?) - [ ] navbar buttons when not in gesture mode seem to have slightly different button icon sizes than the system wide navbar (is there no better way to add the navbar than to essentially reimplement it?)
2024-05-05 01:17:54 +00:00
}
root.state.xPosition = newXPosition;
// allows the user to move the task drawer left and right when on the home screen
taskList.homeTouchPositionX = root.taskSwitcherHelpers.notHomeScreenState ? 0 : (root.state.touchXPosition * 0.35);
// dynamically update the task switcher state based off of the touch position and velocity
updateTaskSwitcherState()
taskswitcher: enhance gesture with flick speed tracking and orthogonal movement tracking This MR contains work to track the speed with which the taskswitcher gesture has occurred to allow different handling of a "fast flick" (eg: go to homescreen instead of taskswitcher). # Features The center piece of the overhaul is tracking recent velocity (averaged over the last ~50ms) of the gesture to determine behavior: - Swipe: A normal swipe is a "slow" finger move - Flick: A "fast" swipe The determining factor is the speed at the end of the gesture (= when lifting the finger up), anything before is irrelevant - Swipe up goes to task switcher - Flick up goes to homescreen directly instead of task switcher - this is suppressed when already on homescreen - it makes no sense there - Note: On Android that is actually mapped to "going to the first page of the home screen if not there already" - I don't care much for that and it can lead to nothing happening if you're already there, I think I prefer the consistency of always opening the task switcher vs a "quick way to get to the main (first) page of the homescreen" - especially since what that means depends a lot on the active home screen. - added orthogonal gesture movement tracking (2-axis gestures) - gesture properly follows finger movement in all directions now making it feel much more responsive and nice - diagonal flick for quick task switch - horizontal only movement (while holding, not releasing) triggers task scrub gesture for scrubbing through larger number of task in the switcher backlog - Complete refactor of state keeping logic, not just in relation to gestures - state keeper fully in one place in C++ except for - a few derived values that are very directly UI related which are kept in `TaskSwitcherHelpers.qml` - and directly touch gesture related state which are kept separate to maybe allow upstreaming the new touch border gesture handling to KWin in the future <details><summary>done TODO items</summary> - [x] currentTaskIndex tracking is majorly broken - [x] old TaskSwitcherState.qml is still around, should be removed - [x] clamping minimum scale for some reason also clamps y position which makes the task not track the finger when moving past the "full activation" point - [x] switching between tasks when task switcher is open is super crap - [x] task switching when switcher is fully open works now, but flicks don't work - you have to fully move at least halfway to the next task for it to "snap" to that task when you let go, there is 0 momentum and I don't know why -> *Flickable is just broken and refuses to flick on touch input, same behavior on master with old implementation, so I reimplemented the same workaround from before* - [x] the gestures don't work until the notification drawer was invoked at least once after every screen geometry change (resolution change, screen rotation etc) - [x] keyboard shortcut for toggling task switcher is kinda hacky right now and feels awful when closing (some delay noticable, maybe to do with animations?) *NOTE: I disabled it for now because the hacky implementation interfered with/created bugs in other parts* - [x] task scrub mode has broken offsets/positions (can scroll past the end of the list, but not reach all elements) when opening task index is not 0 - [x] fast flick velocity threshold is a mostly arbitrary number and I think it also depends on pixel density - ideally we want a mm (or cm or whatever) per ms, not logical pixels per ms </details> # Design decisions I made during development: - Changed the y opening animation from OutBack (with a bounce) to a simple OutExpo (quickly move towards and then approach slowly) as the bouncy look and feel from the OutBack animation felt wrong to me in that place - To fit better with the new docked mode: - the task switcher now shows the screen geometry behind a task that is not fullscreened. This allows to consistently press (and see) the adjacent tasks which might not always be the case if it's a thin window on a landscape screen. - This is not great overall yet - actually it just checks the windows actual aspect ratio, so if it's smaller but same aspect ratio as screen it shows as if it's a full screen task - also it maximizes and centers the window thumbnail in the task switcher so it really isn't ideal, I just don't know what the behavior *should* ideally be. This change at least doesn't break the switcher when in docked mode. - on opening an app from task switcher it doesn't get force-fullscreened anymore - either it already is fullscreen (because fullscreen in docked mode or just not in docked mode) or it should just keep its geometry (this could be gated behind checking if docked mode is on or not, but I think it's fine without) # TODO before merge - [x] IMPORTANT: Because of regular crashing on interaction I've commented out any code that uses WindowFilterModel::data() which seems to be the cause for that. Since master also uses this and experiences these crashes (at least on both dev machines I tested), I don't think this MR necessarily needs to be held up for that issue (especially since it feels like it could be upstream). I removed this to have an easier time with testing my code without constant crashes, but before merging this would need to be put in again as it breaks: skipping windows with "skipSwitcher" flag set, and showing the correct task when opening the switcher in certain situations. - seems to be a bug with WindowFilterModel::data sometimes returning an invalid/null element? But not in C++, it just doesn't make its way to QML. - feels like it could be a timing thing (but maybe not?) when reverting the skipSwitcher filter rule on `tasksModel` *or* adding some lengthy debug console log in `TaskList.qml:minimizeAll()` before trying to access item.window properties it seems to be fine. When keeping skipSwitcher and having no lengthy debug output I get crashes rather reliably every ~3rd to 5th time invoking the task switcher. - While this does seem to be reproducible on master and thus "the same", if it is timing based it may be that my code triggers the error *more often* technically making it a regression (though also easier to track down?) - Interestingly I don't seem to be able to reproduce this on-device, my PinePhone doesn't have this behavior at all. Maybe a bug with nested KWin session? - [ ] task scrub mode may need to have a dynamic amount of items to scrub through based on display size/orientation (maybe keep distance for task scrubbing the same on portrait vs landscape to aid muscle memory)? or instead of using percentages/pixel distances use mm distance based on dpi? - [ ] is task scrub mode even something we want? Since I prefer the "quick switch gesture" only being able to switch between the two most recent windows (because of immediate reordering by recency), this leaves our task switcher in gesture mode with no quick "shortcut gesture" to switch to older tasks, task scrub mode makes this possible in IMO a nice way, but would love input there. - [ ] get rid of all code comments marked with `TODO!` (with an exclamation mark) - [x] One last pass on removing all superfluous console logs, includes and unused functions. I cleaned that up a lot already, but not completely (one std::cout is still left in on purpose until last minute because of a very rare gesture bug I saw twice and I'm not sure if my fix really got it) # Other - I've only ever tested on my laptop with touch screen (ie: effectively a large tablet form factor), if this merges and we get it on nightly I'll definitely try on the PinePhone, there I will closely scrutinize whether the undoYThreshold and task scrub mode number of tasks feels good to use on a small portrait mode display. This may lead to followup MRs to tweak those essentially arbitrarily chosen values. # TODOs for later MRs - [ ] consider moving velocity calculation/generic 2-dimensional gesture tracking to kwin if it's robust and generic enough for that to be useful on their end. (maybe do that later after it has proven itself for a while on our side) - [ ] (optional?) vibration feedback to tell if it goes to taskswitcher or homescreen? android has that (at least mine) with a tight vibration when task switcher is invoked vs homescree - [ ] flick to homescreen animation kinda looks bad - [ ] task sorting by recency - [ ] polish task scrub mode if we intend to keep it - [ ] task scrub mode can "run out of space" for the gesture and thus can only scrub through a maximum number of tasks (currently 8 either direction in my implementation), but we could add a timer if reaching the end that goes through tasks eg: one per second (acceleration?) to "unlock" the full task list - [ ] task scrub mode should have some visual cue when it's activated (eg: fully "opening" the switcher y position, maybe some extra UI with window thumbnails) - [ ] Positioning after screen geometry change (resize, rotation) of the task switcher is kinda broken (task may end off-screen etc) - fixed by interacting with it or re-opening and not a huge issue IMO - [ ] some bound for y position above the "fully opened position" (maybe make it more and more "reluctant" to follow the finger upwards the further up you go - I think that just makes it feel a bit nicer - [ ] make it behave better with docked mode (currently some animations look a bit scuffed) - [ ] make it behave better with multi screen (currently it's mirrored on all screens, we probably only want it on the screen that currently has focus?) - [ ] navbar buttons when not in gesture mode seem to have slightly different button icon sizes than the system wide navbar (is there no better way to add the navbar than to essentially reimplement it?)
2024-05-05 01:17:54 +00:00
}
}
function updateTaskSwitcherState(): void {
let unmodifiedYposition = Math.abs(root.state.touchYPosition)
// if the touch is above heightThreshold, set reachedHeightThreshold to true
if (unmodifiedYposition > root.taskSwitcherHelpers.heightThreshold) {
// set reachedHeightThreshold when above or below two separate points to helps prevent flickering when the task switcher moves in and out of view
root.taskSwitcherHelpers.reachedHeightThreshold = true;
root.backgroundColorOpacity = root.taskSwitcherHelpers.notHomeScreenState ? 0 : 1;
} else if (unmodifiedYposition > root.taskSwitcherHelpers.undoYThreshold) {
root.backgroundColorOpacity = 1;
taskswitcher: enhance gesture with flick speed tracking and orthogonal movement tracking This MR contains work to track the speed with which the taskswitcher gesture has occurred to allow different handling of a "fast flick" (eg: go to homescreen instead of taskswitcher). # Features The center piece of the overhaul is tracking recent velocity (averaged over the last ~50ms) of the gesture to determine behavior: - Swipe: A normal swipe is a "slow" finger move - Flick: A "fast" swipe The determining factor is the speed at the end of the gesture (= when lifting the finger up), anything before is irrelevant - Swipe up goes to task switcher - Flick up goes to homescreen directly instead of task switcher - this is suppressed when already on homescreen - it makes no sense there - Note: On Android that is actually mapped to "going to the first page of the home screen if not there already" - I don't care much for that and it can lead to nothing happening if you're already there, I think I prefer the consistency of always opening the task switcher vs a "quick way to get to the main (first) page of the homescreen" - especially since what that means depends a lot on the active home screen. - added orthogonal gesture movement tracking (2-axis gestures) - gesture properly follows finger movement in all directions now making it feel much more responsive and nice - diagonal flick for quick task switch - horizontal only movement (while holding, not releasing) triggers task scrub gesture for scrubbing through larger number of task in the switcher backlog - Complete refactor of state keeping logic, not just in relation to gestures - state keeper fully in one place in C++ except for - a few derived values that are very directly UI related which are kept in `TaskSwitcherHelpers.qml` - and directly touch gesture related state which are kept separate to maybe allow upstreaming the new touch border gesture handling to KWin in the future <details><summary>done TODO items</summary> - [x] currentTaskIndex tracking is majorly broken - [x] old TaskSwitcherState.qml is still around, should be removed - [x] clamping minimum scale for some reason also clamps y position which makes the task not track the finger when moving past the "full activation" point - [x] switching between tasks when task switcher is open is super crap - [x] task switching when switcher is fully open works now, but flicks don't work - you have to fully move at least halfway to the next task for it to "snap" to that task when you let go, there is 0 momentum and I don't know why -> *Flickable is just broken and refuses to flick on touch input, same behavior on master with old implementation, so I reimplemented the same workaround from before* - [x] the gestures don't work until the notification drawer was invoked at least once after every screen geometry change (resolution change, screen rotation etc) - [x] keyboard shortcut for toggling task switcher is kinda hacky right now and feels awful when closing (some delay noticable, maybe to do with animations?) *NOTE: I disabled it for now because the hacky implementation interfered with/created bugs in other parts* - [x] task scrub mode has broken offsets/positions (can scroll past the end of the list, but not reach all elements) when opening task index is not 0 - [x] fast flick velocity threshold is a mostly arbitrary number and I think it also depends on pixel density - ideally we want a mm (or cm or whatever) per ms, not logical pixels per ms </details> # Design decisions I made during development: - Changed the y opening animation from OutBack (with a bounce) to a simple OutExpo (quickly move towards and then approach slowly) as the bouncy look and feel from the OutBack animation felt wrong to me in that place - To fit better with the new docked mode: - the task switcher now shows the screen geometry behind a task that is not fullscreened. This allows to consistently press (and see) the adjacent tasks which might not always be the case if it's a thin window on a landscape screen. - This is not great overall yet - actually it just checks the windows actual aspect ratio, so if it's smaller but same aspect ratio as screen it shows as if it's a full screen task - also it maximizes and centers the window thumbnail in the task switcher so it really isn't ideal, I just don't know what the behavior *should* ideally be. This change at least doesn't break the switcher when in docked mode. - on opening an app from task switcher it doesn't get force-fullscreened anymore - either it already is fullscreen (because fullscreen in docked mode or just not in docked mode) or it should just keep its geometry (this could be gated behind checking if docked mode is on or not, but I think it's fine without) # TODO before merge - [x] IMPORTANT: Because of regular crashing on interaction I've commented out any code that uses WindowFilterModel::data() which seems to be the cause for that. Since master also uses this and experiences these crashes (at least on both dev machines I tested), I don't think this MR necessarily needs to be held up for that issue (especially since it feels like it could be upstream). I removed this to have an easier time with testing my code without constant crashes, but before merging this would need to be put in again as it breaks: skipping windows with "skipSwitcher" flag set, and showing the correct task when opening the switcher in certain situations. - seems to be a bug with WindowFilterModel::data sometimes returning an invalid/null element? But not in C++, it just doesn't make its way to QML. - feels like it could be a timing thing (but maybe not?) when reverting the skipSwitcher filter rule on `tasksModel` *or* adding some lengthy debug console log in `TaskList.qml:minimizeAll()` before trying to access item.window properties it seems to be fine. When keeping skipSwitcher and having no lengthy debug output I get crashes rather reliably every ~3rd to 5th time invoking the task switcher. - While this does seem to be reproducible on master and thus "the same", if it is timing based it may be that my code triggers the error *more often* technically making it a regression (though also easier to track down?) - Interestingly I don't seem to be able to reproduce this on-device, my PinePhone doesn't have this behavior at all. Maybe a bug with nested KWin session? - [ ] task scrub mode may need to have a dynamic amount of items to scrub through based on display size/orientation (maybe keep distance for task scrubbing the same on portrait vs landscape to aid muscle memory)? or instead of using percentages/pixel distances use mm distance based on dpi? - [ ] is task scrub mode even something we want? Since I prefer the "quick switch gesture" only being able to switch between the two most recent windows (because of immediate reordering by recency), this leaves our task switcher in gesture mode with no quick "shortcut gesture" to switch to older tasks, task scrub mode makes this possible in IMO a nice way, but would love input there. - [ ] get rid of all code comments marked with `TODO!` (with an exclamation mark) - [x] One last pass on removing all superfluous console logs, includes and unused functions. I cleaned that up a lot already, but not completely (one std::cout is still left in on purpose until last minute because of a very rare gesture bug I saw twice and I'm not sure if my fix really got it) # Other - I've only ever tested on my laptop with touch screen (ie: effectively a large tablet form factor), if this merges and we get it on nightly I'll definitely try on the PinePhone, there I will closely scrutinize whether the undoYThreshold and task scrub mode number of tasks feels good to use on a small portrait mode display. This may lead to followup MRs to tweak those essentially arbitrarily chosen values. # TODOs for later MRs - [ ] consider moving velocity calculation/generic 2-dimensional gesture tracking to kwin if it's robust and generic enough for that to be useful on their end. (maybe do that later after it has proven itself for a while on our side) - [ ] (optional?) vibration feedback to tell if it goes to taskswitcher or homescreen? android has that (at least mine) with a tight vibration when task switcher is invoked vs homescree - [ ] flick to homescreen animation kinda looks bad - [ ] task sorting by recency - [ ] polish task scrub mode if we intend to keep it - [ ] task scrub mode can "run out of space" for the gesture and thus can only scrub through a maximum number of tasks (currently 8 either direction in my implementation), but we could add a timer if reaching the end that goes through tasks eg: one per second (acceleration?) to "unlock" the full task list - [ ] task scrub mode should have some visual cue when it's activated (eg: fully "opening" the switcher y position, maybe some extra UI with window thumbnails) - [ ] Positioning after screen geometry change (resize, rotation) of the task switcher is kinda broken (task may end off-screen etc) - fixed by interacting with it or re-opening and not a huge issue IMO - [ ] some bound for y position above the "fully opened position" (maybe make it more and more "reluctant" to follow the finger upwards the further up you go - I think that just makes it feel a bit nicer - [ ] make it behave better with docked mode (currently some animations look a bit scuffed) - [ ] make it behave better with multi screen (currently it's mirrored on all screens, we probably only want it on the screen that currently has focus?) - [ ] navbar buttons when not in gesture mode seem to have slightly different button icon sizes than the system wide navbar (is there no better way to add the navbar than to essentially reimplement it?)
2024-05-05 01:17:54 +00:00
} else {
root.backgroundColorOpacity = root.taskSwitcherHelpers.notHomeScreenState ? 1 : 0;
}
if (root.state.totalSquaredVelocity > root.state.flickVelocityThreshold) {
// flick
// ratio between y and x velocity as threshold between vertical and horizontal flick
let xyVelocityRatio = 1.7; // with 1.7 swipes up to ~60° from horizontal are counted as horizontal
if (root.state.yVelocity > Math.abs(root.state.xVelocity) * xyVelocityRatio) {
// downwards flick
root.setTaskDrawerState(TaskSwitcherHelpers.GestureStates.Undecided);
if (unmodifiedYposition < root.taskSwitcherHelpers.undoYThreshold) {
taskList.setTaskOffsetValue(root.taskSwitcherHelpers.notHomeScreenState ? 0 : root.taskSwitcherHelpers.homeOffsetValue);
}
} else if (-root.state.yVelocity > Math.abs(root.state.xVelocity) * xyVelocityRatio || (root.taskSwitcherHelpers.reachedHeightThreshold && root.taskSwitcherHelpers.notHomeScreenState)) {
// upwards flick or if the touch is above heightThreshold
if (root.taskSwitcherHelpers.notHomeScreenState) {
// if in app or task switcher, go home
root.setTaskDrawerState(TaskSwitcherHelpers.GestureStates.Home);
if (root.taskSwitcherHelpers.reachedHeightThreshold) {
taskList.setTaskOffsetValue(root.taskSwitcherHelpers.taskOffsetValue);
}
} else if (unmodifiedYposition > root.taskSwitcherHelpers.undoYThreshold) {
// else, keep the task switcher in view
root.setTaskDrawerState(TaskSwitcherHelpers.GestureStates.TaskSwitcher);
taskList.setTaskOffsetValue(root.taskSwitcherHelpers.peekOffsetValue);
}
} else if (!root.taskSwitcherHelpers.reachedHeightThreshold && !root.taskSwitcherHelpers.isInTaskScrubMode) {
// sideways flick
if (root.taskSwitcherHelpers.notHomeScreenState) {
taskList.setTaskOffsetValue(0, unmodifiedYposition < root.taskSwitcherHelpers.openedYPosition ? true : false);
}
root.setTaskDrawerState(TaskSwitcherHelpers.GestureStates.HorizontalSwipe);
}
} else {
if (unmodifiedYposition > root.taskSwitcherHelpers.undoYThreshold) {
// if just moveing out of undoYThreshold, set the state to home
if (root.taskSwitcherHelpers.gestureState < TaskSwitcherHelpers.GestureStates.TaskSwitcher) {
root.setTaskDrawerState(TaskSwitcherHelpers.GestureStates.Home)
}
// if the touch is above heightThreshold, it will retrun home
if (unmodifiedYposition > root.taskSwitcherHelpers.heightThreshold) {
root.taskSwitcherHelpers.hasVibrated = true;
if (root.taskSwitcherHelpers.notHomeScreenState) {
// move the task switcher out of view
root.setTaskDrawerState(TaskSwitcherHelpers.GestureStates.Home);
taskList.setTaskOffsetValue(root.taskSwitcherHelpers.taskOffsetValue);
} else {
// keep the task switcher in view when above heightThreshold and from home
root.setTaskDrawerState(TaskSwitcherHelpers.GestureStates.TaskSwitcher);
taskList.setTaskOffsetValue(root.taskSwitcherHelpers.peekOffsetValue);
}
// minus largeSpacing from the heightThreshold to help prevent flickering when the task switcher moves in and out of view
} else if ((unmodifiedYposition < root.taskSwitcherHelpers.heightThreshold - Kirigami.Units.largeSpacing) || root.taskSwitcherHelpers.reachedHeightThreshold == false) {
// set reachedHeightThreshold when above or below two separate points to helps prevent flickering when the task switcher moves in and out of view
root.taskSwitcherHelpers.reachedHeightThreshold = false;
if (root.state.totalSquaredVelocity < root.state.flickVelocityThreshold && root.taskSwitcherHelpers.taskSwitchCanLaunch) {
// if velocity is small enough, move the task switcher into view
root.setTaskDrawerState(TaskSwitcherHelpers.GestureStates.TaskSwitcher);
taskList.setTaskOffsetValue(root.taskSwitcherHelpers.notHomeScreenState ? 0 : root.taskSwitcherHelpers.peekOffsetValue);
}
}
} else {
// if under the undo threshold, it will go back to the task switcher if it is open
if (root.taskSwitcherHelpers.taskDrawerOpened) {
root.taskSwitcherHelpers.reachedHeightThreshold = false;
root.setTaskDrawerState(TaskSwitcherHelpers.GestureStates.TaskSwitcher)
taskList.setTaskOffsetValue(0);
} else {
root.taskSwitcherHelpers.reachedHeightThreshold = false;
root.setTaskDrawerState(TaskSwitcherHelpers.GestureStates.Undecided)
taskList.setTaskOffsetValue(root.taskSwitcherHelpers.notHomeScreenState ? 0 : root.taskSwitcherHelpers.homeOffsetValue);
}
}
taskswitcher: enhance gesture with flick speed tracking and orthogonal movement tracking This MR contains work to track the speed with which the taskswitcher gesture has occurred to allow different handling of a "fast flick" (eg: go to homescreen instead of taskswitcher). # Features The center piece of the overhaul is tracking recent velocity (averaged over the last ~50ms) of the gesture to determine behavior: - Swipe: A normal swipe is a "slow" finger move - Flick: A "fast" swipe The determining factor is the speed at the end of the gesture (= when lifting the finger up), anything before is irrelevant - Swipe up goes to task switcher - Flick up goes to homescreen directly instead of task switcher - this is suppressed when already on homescreen - it makes no sense there - Note: On Android that is actually mapped to "going to the first page of the home screen if not there already" - I don't care much for that and it can lead to nothing happening if you're already there, I think I prefer the consistency of always opening the task switcher vs a "quick way to get to the main (first) page of the homescreen" - especially since what that means depends a lot on the active home screen. - added orthogonal gesture movement tracking (2-axis gestures) - gesture properly follows finger movement in all directions now making it feel much more responsive and nice - diagonal flick for quick task switch - horizontal only movement (while holding, not releasing) triggers task scrub gesture for scrubbing through larger number of task in the switcher backlog - Complete refactor of state keeping logic, not just in relation to gestures - state keeper fully in one place in C++ except for - a few derived values that are very directly UI related which are kept in `TaskSwitcherHelpers.qml` - and directly touch gesture related state which are kept separate to maybe allow upstreaming the new touch border gesture handling to KWin in the future <details><summary>done TODO items</summary> - [x] currentTaskIndex tracking is majorly broken - [x] old TaskSwitcherState.qml is still around, should be removed - [x] clamping minimum scale for some reason also clamps y position which makes the task not track the finger when moving past the "full activation" point - [x] switching between tasks when task switcher is open is super crap - [x] task switching when switcher is fully open works now, but flicks don't work - you have to fully move at least halfway to the next task for it to "snap" to that task when you let go, there is 0 momentum and I don't know why -> *Flickable is just broken and refuses to flick on touch input, same behavior on master with old implementation, so I reimplemented the same workaround from before* - [x] the gestures don't work until the notification drawer was invoked at least once after every screen geometry change (resolution change, screen rotation etc) - [x] keyboard shortcut for toggling task switcher is kinda hacky right now and feels awful when closing (some delay noticable, maybe to do with animations?) *NOTE: I disabled it for now because the hacky implementation interfered with/created bugs in other parts* - [x] task scrub mode has broken offsets/positions (can scroll past the end of the list, but not reach all elements) when opening task index is not 0 - [x] fast flick velocity threshold is a mostly arbitrary number and I think it also depends on pixel density - ideally we want a mm (or cm or whatever) per ms, not logical pixels per ms </details> # Design decisions I made during development: - Changed the y opening animation from OutBack (with a bounce) to a simple OutExpo (quickly move towards and then approach slowly) as the bouncy look and feel from the OutBack animation felt wrong to me in that place - To fit better with the new docked mode: - the task switcher now shows the screen geometry behind a task that is not fullscreened. This allows to consistently press (and see) the adjacent tasks which might not always be the case if it's a thin window on a landscape screen. - This is not great overall yet - actually it just checks the windows actual aspect ratio, so if it's smaller but same aspect ratio as screen it shows as if it's a full screen task - also it maximizes and centers the window thumbnail in the task switcher so it really isn't ideal, I just don't know what the behavior *should* ideally be. This change at least doesn't break the switcher when in docked mode. - on opening an app from task switcher it doesn't get force-fullscreened anymore - either it already is fullscreen (because fullscreen in docked mode or just not in docked mode) or it should just keep its geometry (this could be gated behind checking if docked mode is on or not, but I think it's fine without) # TODO before merge - [x] IMPORTANT: Because of regular crashing on interaction I've commented out any code that uses WindowFilterModel::data() which seems to be the cause for that. Since master also uses this and experiences these crashes (at least on both dev machines I tested), I don't think this MR necessarily needs to be held up for that issue (especially since it feels like it could be upstream). I removed this to have an easier time with testing my code without constant crashes, but before merging this would need to be put in again as it breaks: skipping windows with "skipSwitcher" flag set, and showing the correct task when opening the switcher in certain situations. - seems to be a bug with WindowFilterModel::data sometimes returning an invalid/null element? But not in C++, it just doesn't make its way to QML. - feels like it could be a timing thing (but maybe not?) when reverting the skipSwitcher filter rule on `tasksModel` *or* adding some lengthy debug console log in `TaskList.qml:minimizeAll()` before trying to access item.window properties it seems to be fine. When keeping skipSwitcher and having no lengthy debug output I get crashes rather reliably every ~3rd to 5th time invoking the task switcher. - While this does seem to be reproducible on master and thus "the same", if it is timing based it may be that my code triggers the error *more often* technically making it a regression (though also easier to track down?) - Interestingly I don't seem to be able to reproduce this on-device, my PinePhone doesn't have this behavior at all. Maybe a bug with nested KWin session? - [ ] task scrub mode may need to have a dynamic amount of items to scrub through based on display size/orientation (maybe keep distance for task scrubbing the same on portrait vs landscape to aid muscle memory)? or instead of using percentages/pixel distances use mm distance based on dpi? - [ ] is task scrub mode even something we want? Since I prefer the "quick switch gesture" only being able to switch between the two most recent windows (because of immediate reordering by recency), this leaves our task switcher in gesture mode with no quick "shortcut gesture" to switch to older tasks, task scrub mode makes this possible in IMO a nice way, but would love input there. - [ ] get rid of all code comments marked with `TODO!` (with an exclamation mark) - [x] One last pass on removing all superfluous console logs, includes and unused functions. I cleaned that up a lot already, but not completely (one std::cout is still left in on purpose until last minute because of a very rare gesture bug I saw twice and I'm not sure if my fix really got it) # Other - I've only ever tested on my laptop with touch screen (ie: effectively a large tablet form factor), if this merges and we get it on nightly I'll definitely try on the PinePhone, there I will closely scrutinize whether the undoYThreshold and task scrub mode number of tasks feels good to use on a small portrait mode display. This may lead to followup MRs to tweak those essentially arbitrarily chosen values. # TODOs for later MRs - [ ] consider moving velocity calculation/generic 2-dimensional gesture tracking to kwin if it's robust and generic enough for that to be useful on their end. (maybe do that later after it has proven itself for a while on our side) - [ ] (optional?) vibration feedback to tell if it goes to taskswitcher or homescreen? android has that (at least mine) with a tight vibration when task switcher is invoked vs homescree - [ ] flick to homescreen animation kinda looks bad - [ ] task sorting by recency - [ ] polish task scrub mode if we intend to keep it - [ ] task scrub mode can "run out of space" for the gesture and thus can only scrub through a maximum number of tasks (currently 8 either direction in my implementation), but we could add a timer if reaching the end that goes through tasks eg: one per second (acceleration?) to "unlock" the full task list - [ ] task scrub mode should have some visual cue when it's activated (eg: fully "opening" the switcher y position, maybe some extra UI with window thumbnails) - [ ] Positioning after screen geometry change (resize, rotation) of the task switcher is kinda broken (task may end off-screen etc) - fixed by interacting with it or re-opening and not a huge issue IMO - [ ] some bound for y position above the "fully opened position" (maybe make it more and more "reluctant" to follow the finger upwards the further up you go - I think that just makes it feel a bit nicer - [ ] make it behave better with docked mode (currently some animations look a bit scuffed) - [ ] make it behave better with multi screen (currently it's mirrored on all screens, we probably only want it on the screen that currently has focus?) - [ ] navbar buttons when not in gesture mode seem to have slightly different button icon sizes than the system wide navbar (is there no better way to add the navbar than to essentially reimplement it?)
2024-05-05 01:17:54 +00:00
}
}
2023-03-06 06:38:43 +00:00
taskswitcher: enhance gesture with flick speed tracking and orthogonal movement tracking This MR contains work to track the speed with which the taskswitcher gesture has occurred to allow different handling of a "fast flick" (eg: go to homescreen instead of taskswitcher). # Features The center piece of the overhaul is tracking recent velocity (averaged over the last ~50ms) of the gesture to determine behavior: - Swipe: A normal swipe is a "slow" finger move - Flick: A "fast" swipe The determining factor is the speed at the end of the gesture (= when lifting the finger up), anything before is irrelevant - Swipe up goes to task switcher - Flick up goes to homescreen directly instead of task switcher - this is suppressed when already on homescreen - it makes no sense there - Note: On Android that is actually mapped to "going to the first page of the home screen if not there already" - I don't care much for that and it can lead to nothing happening if you're already there, I think I prefer the consistency of always opening the task switcher vs a "quick way to get to the main (first) page of the homescreen" - especially since what that means depends a lot on the active home screen. - added orthogonal gesture movement tracking (2-axis gestures) - gesture properly follows finger movement in all directions now making it feel much more responsive and nice - diagonal flick for quick task switch - horizontal only movement (while holding, not releasing) triggers task scrub gesture for scrubbing through larger number of task in the switcher backlog - Complete refactor of state keeping logic, not just in relation to gestures - state keeper fully in one place in C++ except for - a few derived values that are very directly UI related which are kept in `TaskSwitcherHelpers.qml` - and directly touch gesture related state which are kept separate to maybe allow upstreaming the new touch border gesture handling to KWin in the future <details><summary>done TODO items</summary> - [x] currentTaskIndex tracking is majorly broken - [x] old TaskSwitcherState.qml is still around, should be removed - [x] clamping minimum scale for some reason also clamps y position which makes the task not track the finger when moving past the "full activation" point - [x] switching between tasks when task switcher is open is super crap - [x] task switching when switcher is fully open works now, but flicks don't work - you have to fully move at least halfway to the next task for it to "snap" to that task when you let go, there is 0 momentum and I don't know why -> *Flickable is just broken and refuses to flick on touch input, same behavior on master with old implementation, so I reimplemented the same workaround from before* - [x] the gestures don't work until the notification drawer was invoked at least once after every screen geometry change (resolution change, screen rotation etc) - [x] keyboard shortcut for toggling task switcher is kinda hacky right now and feels awful when closing (some delay noticable, maybe to do with animations?) *NOTE: I disabled it for now because the hacky implementation interfered with/created bugs in other parts* - [x] task scrub mode has broken offsets/positions (can scroll past the end of the list, but not reach all elements) when opening task index is not 0 - [x] fast flick velocity threshold is a mostly arbitrary number and I think it also depends on pixel density - ideally we want a mm (or cm or whatever) per ms, not logical pixels per ms </details> # Design decisions I made during development: - Changed the y opening animation from OutBack (with a bounce) to a simple OutExpo (quickly move towards and then approach slowly) as the bouncy look and feel from the OutBack animation felt wrong to me in that place - To fit better with the new docked mode: - the task switcher now shows the screen geometry behind a task that is not fullscreened. This allows to consistently press (and see) the adjacent tasks which might not always be the case if it's a thin window on a landscape screen. - This is not great overall yet - actually it just checks the windows actual aspect ratio, so if it's smaller but same aspect ratio as screen it shows as if it's a full screen task - also it maximizes and centers the window thumbnail in the task switcher so it really isn't ideal, I just don't know what the behavior *should* ideally be. This change at least doesn't break the switcher when in docked mode. - on opening an app from task switcher it doesn't get force-fullscreened anymore - either it already is fullscreen (because fullscreen in docked mode or just not in docked mode) or it should just keep its geometry (this could be gated behind checking if docked mode is on or not, but I think it's fine without) # TODO before merge - [x] IMPORTANT: Because of regular crashing on interaction I've commented out any code that uses WindowFilterModel::data() which seems to be the cause for that. Since master also uses this and experiences these crashes (at least on both dev machines I tested), I don't think this MR necessarily needs to be held up for that issue (especially since it feels like it could be upstream). I removed this to have an easier time with testing my code without constant crashes, but before merging this would need to be put in again as it breaks: skipping windows with "skipSwitcher" flag set, and showing the correct task when opening the switcher in certain situations. - seems to be a bug with WindowFilterModel::data sometimes returning an invalid/null element? But not in C++, it just doesn't make its way to QML. - feels like it could be a timing thing (but maybe not?) when reverting the skipSwitcher filter rule on `tasksModel` *or* adding some lengthy debug console log in `TaskList.qml:minimizeAll()` before trying to access item.window properties it seems to be fine. When keeping skipSwitcher and having no lengthy debug output I get crashes rather reliably every ~3rd to 5th time invoking the task switcher. - While this does seem to be reproducible on master and thus "the same", if it is timing based it may be that my code triggers the error *more often* technically making it a regression (though also easier to track down?) - Interestingly I don't seem to be able to reproduce this on-device, my PinePhone doesn't have this behavior at all. Maybe a bug with nested KWin session? - [ ] task scrub mode may need to have a dynamic amount of items to scrub through based on display size/orientation (maybe keep distance for task scrubbing the same on portrait vs landscape to aid muscle memory)? or instead of using percentages/pixel distances use mm distance based on dpi? - [ ] is task scrub mode even something we want? Since I prefer the "quick switch gesture" only being able to switch between the two most recent windows (because of immediate reordering by recency), this leaves our task switcher in gesture mode with no quick "shortcut gesture" to switch to older tasks, task scrub mode makes this possible in IMO a nice way, but would love input there. - [ ] get rid of all code comments marked with `TODO!` (with an exclamation mark) - [x] One last pass on removing all superfluous console logs, includes and unused functions. I cleaned that up a lot already, but not completely (one std::cout is still left in on purpose until last minute because of a very rare gesture bug I saw twice and I'm not sure if my fix really got it) # Other - I've only ever tested on my laptop with touch screen (ie: effectively a large tablet form factor), if this merges and we get it on nightly I'll definitely try on the PinePhone, there I will closely scrutinize whether the undoYThreshold and task scrub mode number of tasks feels good to use on a small portrait mode display. This may lead to followup MRs to tweak those essentially arbitrarily chosen values. # TODOs for later MRs - [ ] consider moving velocity calculation/generic 2-dimensional gesture tracking to kwin if it's robust and generic enough for that to be useful on their end. (maybe do that later after it has proven itself for a while on our side) - [ ] (optional?) vibration feedback to tell if it goes to taskswitcher or homescreen? android has that (at least mine) with a tight vibration when task switcher is invoked vs homescree - [ ] flick to homescreen animation kinda looks bad - [ ] task sorting by recency - [ ] polish task scrub mode if we intend to keep it - [ ] task scrub mode can "run out of space" for the gesture and thus can only scrub through a maximum number of tasks (currently 8 either direction in my implementation), but we could add a timer if reaching the end that goes through tasks eg: one per second (acceleration?) to "unlock" the full task list - [ ] task scrub mode should have some visual cue when it's activated (eg: fully "opening" the switcher y position, maybe some extra UI with window thumbnails) - [ ] Positioning after screen geometry change (resize, rotation) of the task switcher is kinda broken (task may end off-screen etc) - fixed by interacting with it or re-opening and not a huge issue IMO - [ ] some bound for y position above the "fully opened position" (maybe make it more and more "reluctant" to follow the finger upwards the further up you go - I think that just makes it feel a bit nicer - [ ] make it behave better with docked mode (currently some animations look a bit scuffed) - [ ] make it behave better with multi screen (currently it's mirrored on all screens, we probably only want it on the screen that currently has focus?) - [ ] navbar buttons when not in gesture mode seem to have slightly different button icon sizes than the system wide navbar (is there no better way to add the navbar than to essentially reimplement it?)
2024-05-05 01:17:54 +00:00
// returns to the currently centered app. usually used to "back out" of the switcher
// if accidentally invoked, but can also be used to switch to an adjacent app and then open it
function returnToApp(): void {
let newIndex = root.taskSwitcherHelpers.getNearestTaskIndex();
root.taskSwitcherHelpers.openApp(newIndex);
2023-03-06 06:38:43 +00:00
}
taskswitcher: enhance gesture with flick speed tracking and orthogonal movement tracking This MR contains work to track the speed with which the taskswitcher gesture has occurred to allow different handling of a "fast flick" (eg: go to homescreen instead of taskswitcher). # Features The center piece of the overhaul is tracking recent velocity (averaged over the last ~50ms) of the gesture to determine behavior: - Swipe: A normal swipe is a "slow" finger move - Flick: A "fast" swipe The determining factor is the speed at the end of the gesture (= when lifting the finger up), anything before is irrelevant - Swipe up goes to task switcher - Flick up goes to homescreen directly instead of task switcher - this is suppressed when already on homescreen - it makes no sense there - Note: On Android that is actually mapped to "going to the first page of the home screen if not there already" - I don't care much for that and it can lead to nothing happening if you're already there, I think I prefer the consistency of always opening the task switcher vs a "quick way to get to the main (first) page of the homescreen" - especially since what that means depends a lot on the active home screen. - added orthogonal gesture movement tracking (2-axis gestures) - gesture properly follows finger movement in all directions now making it feel much more responsive and nice - diagonal flick for quick task switch - horizontal only movement (while holding, not releasing) triggers task scrub gesture for scrubbing through larger number of task in the switcher backlog - Complete refactor of state keeping logic, not just in relation to gestures - state keeper fully in one place in C++ except for - a few derived values that are very directly UI related which are kept in `TaskSwitcherHelpers.qml` - and directly touch gesture related state which are kept separate to maybe allow upstreaming the new touch border gesture handling to KWin in the future <details><summary>done TODO items</summary> - [x] currentTaskIndex tracking is majorly broken - [x] old TaskSwitcherState.qml is still around, should be removed - [x] clamping minimum scale for some reason also clamps y position which makes the task not track the finger when moving past the "full activation" point - [x] switching between tasks when task switcher is open is super crap - [x] task switching when switcher is fully open works now, but flicks don't work - you have to fully move at least halfway to the next task for it to "snap" to that task when you let go, there is 0 momentum and I don't know why -> *Flickable is just broken and refuses to flick on touch input, same behavior on master with old implementation, so I reimplemented the same workaround from before* - [x] the gestures don't work until the notification drawer was invoked at least once after every screen geometry change (resolution change, screen rotation etc) - [x] keyboard shortcut for toggling task switcher is kinda hacky right now and feels awful when closing (some delay noticable, maybe to do with animations?) *NOTE: I disabled it for now because the hacky implementation interfered with/created bugs in other parts* - [x] task scrub mode has broken offsets/positions (can scroll past the end of the list, but not reach all elements) when opening task index is not 0 - [x] fast flick velocity threshold is a mostly arbitrary number and I think it also depends on pixel density - ideally we want a mm (or cm or whatever) per ms, not logical pixels per ms </details> # Design decisions I made during development: - Changed the y opening animation from OutBack (with a bounce) to a simple OutExpo (quickly move towards and then approach slowly) as the bouncy look and feel from the OutBack animation felt wrong to me in that place - To fit better with the new docked mode: - the task switcher now shows the screen geometry behind a task that is not fullscreened. This allows to consistently press (and see) the adjacent tasks which might not always be the case if it's a thin window on a landscape screen. - This is not great overall yet - actually it just checks the windows actual aspect ratio, so if it's smaller but same aspect ratio as screen it shows as if it's a full screen task - also it maximizes and centers the window thumbnail in the task switcher so it really isn't ideal, I just don't know what the behavior *should* ideally be. This change at least doesn't break the switcher when in docked mode. - on opening an app from task switcher it doesn't get force-fullscreened anymore - either it already is fullscreen (because fullscreen in docked mode or just not in docked mode) or it should just keep its geometry (this could be gated behind checking if docked mode is on or not, but I think it's fine without) # TODO before merge - [x] IMPORTANT: Because of regular crashing on interaction I've commented out any code that uses WindowFilterModel::data() which seems to be the cause for that. Since master also uses this and experiences these crashes (at least on both dev machines I tested), I don't think this MR necessarily needs to be held up for that issue (especially since it feels like it could be upstream). I removed this to have an easier time with testing my code without constant crashes, but before merging this would need to be put in again as it breaks: skipping windows with "skipSwitcher" flag set, and showing the correct task when opening the switcher in certain situations. - seems to be a bug with WindowFilterModel::data sometimes returning an invalid/null element? But not in C++, it just doesn't make its way to QML. - feels like it could be a timing thing (but maybe not?) when reverting the skipSwitcher filter rule on `tasksModel` *or* adding some lengthy debug console log in `TaskList.qml:minimizeAll()` before trying to access item.window properties it seems to be fine. When keeping skipSwitcher and having no lengthy debug output I get crashes rather reliably every ~3rd to 5th time invoking the task switcher. - While this does seem to be reproducible on master and thus "the same", if it is timing based it may be that my code triggers the error *more often* technically making it a regression (though also easier to track down?) - Interestingly I don't seem to be able to reproduce this on-device, my PinePhone doesn't have this behavior at all. Maybe a bug with nested KWin session? - [ ] task scrub mode may need to have a dynamic amount of items to scrub through based on display size/orientation (maybe keep distance for task scrubbing the same on portrait vs landscape to aid muscle memory)? or instead of using percentages/pixel distances use mm distance based on dpi? - [ ] is task scrub mode even something we want? Since I prefer the "quick switch gesture" only being able to switch between the two most recent windows (because of immediate reordering by recency), this leaves our task switcher in gesture mode with no quick "shortcut gesture" to switch to older tasks, task scrub mode makes this possible in IMO a nice way, but would love input there. - [ ] get rid of all code comments marked with `TODO!` (with an exclamation mark) - [x] One last pass on removing all superfluous console logs, includes and unused functions. I cleaned that up a lot already, but not completely (one std::cout is still left in on purpose until last minute because of a very rare gesture bug I saw twice and I'm not sure if my fix really got it) # Other - I've only ever tested on my laptop with touch screen (ie: effectively a large tablet form factor), if this merges and we get it on nightly I'll definitely try on the PinePhone, there I will closely scrutinize whether the undoYThreshold and task scrub mode number of tasks feels good to use on a small portrait mode display. This may lead to followup MRs to tweak those essentially arbitrarily chosen values. # TODOs for later MRs - [ ] consider moving velocity calculation/generic 2-dimensional gesture tracking to kwin if it's robust and generic enough for that to be useful on their end. (maybe do that later after it has proven itself for a while on our side) - [ ] (optional?) vibration feedback to tell if it goes to taskswitcher or homescreen? android has that (at least mine) with a tight vibration when task switcher is invoked vs homescree - [ ] flick to homescreen animation kinda looks bad - [ ] task sorting by recency - [ ] polish task scrub mode if we intend to keep it - [ ] task scrub mode can "run out of space" for the gesture and thus can only scrub through a maximum number of tasks (currently 8 either direction in my implementation), but we could add a timer if reaching the end that goes through tasks eg: one per second (acceleration?) to "unlock" the full task list - [ ] task scrub mode should have some visual cue when it's activated (eg: fully "opening" the switcher y position, maybe some extra UI with window thumbnails) - [ ] Positioning after screen geometry change (resize, rotation) of the task switcher is kinda broken (task may end off-screen etc) - fixed by interacting with it or re-opening and not a huge issue IMO - [ ] some bound for y position above the "fully opened position" (maybe make it more and more "reluctant" to follow the finger upwards the further up you go - I think that just makes it feel a bit nicer - [ ] make it behave better with docked mode (currently some animations look a bit scuffed) - [ ] make it behave better with multi screen (currently it's mirrored on all screens, we probably only want it on the screen that currently has focus?) - [ ] navbar buttons when not in gesture mode seem to have slightly different button icon sizes than the system wide navbar (is there no better way to add the navbar than to essentially reimplement it?)
2024-05-05 01:17:54 +00:00
// diagonal quick switch gesture logic
function quickSwitch(): void {
taskswitcher: enhance gesture with flick speed tracking and orthogonal movement tracking This MR contains work to track the speed with which the taskswitcher gesture has occurred to allow different handling of a "fast flick" (eg: go to homescreen instead of taskswitcher). # Features The center piece of the overhaul is tracking recent velocity (averaged over the last ~50ms) of the gesture to determine behavior: - Swipe: A normal swipe is a "slow" finger move - Flick: A "fast" swipe The determining factor is the speed at the end of the gesture (= when lifting the finger up), anything before is irrelevant - Swipe up goes to task switcher - Flick up goes to homescreen directly instead of task switcher - this is suppressed when already on homescreen - it makes no sense there - Note: On Android that is actually mapped to "going to the first page of the home screen if not there already" - I don't care much for that and it can lead to nothing happening if you're already there, I think I prefer the consistency of always opening the task switcher vs a "quick way to get to the main (first) page of the homescreen" - especially since what that means depends a lot on the active home screen. - added orthogonal gesture movement tracking (2-axis gestures) - gesture properly follows finger movement in all directions now making it feel much more responsive and nice - diagonal flick for quick task switch - horizontal only movement (while holding, not releasing) triggers task scrub gesture for scrubbing through larger number of task in the switcher backlog - Complete refactor of state keeping logic, not just in relation to gestures - state keeper fully in one place in C++ except for - a few derived values that are very directly UI related which are kept in `TaskSwitcherHelpers.qml` - and directly touch gesture related state which are kept separate to maybe allow upstreaming the new touch border gesture handling to KWin in the future <details><summary>done TODO items</summary> - [x] currentTaskIndex tracking is majorly broken - [x] old TaskSwitcherState.qml is still around, should be removed - [x] clamping minimum scale for some reason also clamps y position which makes the task not track the finger when moving past the "full activation" point - [x] switching between tasks when task switcher is open is super crap - [x] task switching when switcher is fully open works now, but flicks don't work - you have to fully move at least halfway to the next task for it to "snap" to that task when you let go, there is 0 momentum and I don't know why -> *Flickable is just broken and refuses to flick on touch input, same behavior on master with old implementation, so I reimplemented the same workaround from before* - [x] the gestures don't work until the notification drawer was invoked at least once after every screen geometry change (resolution change, screen rotation etc) - [x] keyboard shortcut for toggling task switcher is kinda hacky right now and feels awful when closing (some delay noticable, maybe to do with animations?) *NOTE: I disabled it for now because the hacky implementation interfered with/created bugs in other parts* - [x] task scrub mode has broken offsets/positions (can scroll past the end of the list, but not reach all elements) when opening task index is not 0 - [x] fast flick velocity threshold is a mostly arbitrary number and I think it also depends on pixel density - ideally we want a mm (or cm or whatever) per ms, not logical pixels per ms </details> # Design decisions I made during development: - Changed the y opening animation from OutBack (with a bounce) to a simple OutExpo (quickly move towards and then approach slowly) as the bouncy look and feel from the OutBack animation felt wrong to me in that place - To fit better with the new docked mode: - the task switcher now shows the screen geometry behind a task that is not fullscreened. This allows to consistently press (and see) the adjacent tasks which might not always be the case if it's a thin window on a landscape screen. - This is not great overall yet - actually it just checks the windows actual aspect ratio, so if it's smaller but same aspect ratio as screen it shows as if it's a full screen task - also it maximizes and centers the window thumbnail in the task switcher so it really isn't ideal, I just don't know what the behavior *should* ideally be. This change at least doesn't break the switcher when in docked mode. - on opening an app from task switcher it doesn't get force-fullscreened anymore - either it already is fullscreen (because fullscreen in docked mode or just not in docked mode) or it should just keep its geometry (this could be gated behind checking if docked mode is on or not, but I think it's fine without) # TODO before merge - [x] IMPORTANT: Because of regular crashing on interaction I've commented out any code that uses WindowFilterModel::data() which seems to be the cause for that. Since master also uses this and experiences these crashes (at least on both dev machines I tested), I don't think this MR necessarily needs to be held up for that issue (especially since it feels like it could be upstream). I removed this to have an easier time with testing my code without constant crashes, but before merging this would need to be put in again as it breaks: skipping windows with "skipSwitcher" flag set, and showing the correct task when opening the switcher in certain situations. - seems to be a bug with WindowFilterModel::data sometimes returning an invalid/null element? But not in C++, it just doesn't make its way to QML. - feels like it could be a timing thing (but maybe not?) when reverting the skipSwitcher filter rule on `tasksModel` *or* adding some lengthy debug console log in `TaskList.qml:minimizeAll()` before trying to access item.window properties it seems to be fine. When keeping skipSwitcher and having no lengthy debug output I get crashes rather reliably every ~3rd to 5th time invoking the task switcher. - While this does seem to be reproducible on master and thus "the same", if it is timing based it may be that my code triggers the error *more often* technically making it a regression (though also easier to track down?) - Interestingly I don't seem to be able to reproduce this on-device, my PinePhone doesn't have this behavior at all. Maybe a bug with nested KWin session? - [ ] task scrub mode may need to have a dynamic amount of items to scrub through based on display size/orientation (maybe keep distance for task scrubbing the same on portrait vs landscape to aid muscle memory)? or instead of using percentages/pixel distances use mm distance based on dpi? - [ ] is task scrub mode even something we want? Since I prefer the "quick switch gesture" only being able to switch between the two most recent windows (because of immediate reordering by recency), this leaves our task switcher in gesture mode with no quick "shortcut gesture" to switch to older tasks, task scrub mode makes this possible in IMO a nice way, but would love input there. - [ ] get rid of all code comments marked with `TODO!` (with an exclamation mark) - [x] One last pass on removing all superfluous console logs, includes and unused functions. I cleaned that up a lot already, but not completely (one std::cout is still left in on purpose until last minute because of a very rare gesture bug I saw twice and I'm not sure if my fix really got it) # Other - I've only ever tested on my laptop with touch screen (ie: effectively a large tablet form factor), if this merges and we get it on nightly I'll definitely try on the PinePhone, there I will closely scrutinize whether the undoYThreshold and task scrub mode number of tasks feels good to use on a small portrait mode display. This may lead to followup MRs to tweak those essentially arbitrarily chosen values. # TODOs for later MRs - [ ] consider moving velocity calculation/generic 2-dimensional gesture tracking to kwin if it's robust and generic enough for that to be useful on their end. (maybe do that later after it has proven itself for a while on our side) - [ ] (optional?) vibration feedback to tell if it goes to taskswitcher or homescreen? android has that (at least mine) with a tight vibration when task switcher is invoked vs homescree - [ ] flick to homescreen animation kinda looks bad - [ ] task sorting by recency - [ ] polish task scrub mode if we intend to keep it - [ ] task scrub mode can "run out of space" for the gesture and thus can only scrub through a maximum number of tasks (currently 8 either direction in my implementation), but we could add a timer if reaching the end that goes through tasks eg: one per second (acceleration?) to "unlock" the full task list - [ ] task scrub mode should have some visual cue when it's activated (eg: fully "opening" the switcher y position, maybe some extra UI with window thumbnails) - [ ] Positioning after screen geometry change (resize, rotation) of the task switcher is kinda broken (task may end off-screen etc) - fixed by interacting with it or re-opening and not a huge issue IMO - [ ] some bound for y position above the "fully opened position" (maybe make it more and more "reluctant" to follow the finger upwards the further up you go - I think that just makes it feel a bit nicer - [ ] make it behave better with docked mode (currently some animations look a bit scuffed) - [ ] make it behave better with multi screen (currently it's mirrored on all screens, we probably only want it on the screen that currently has focus?) - [ ] navbar buttons when not in gesture mode seem to have slightly different button icon sizes than the system wide navbar (is there no better way to add the navbar than to essentially reimplement it?)
2024-05-05 01:17:54 +00:00
// should "quick switch" to adjacent app in task switcher, but only if we were in an app before
let unmodifiedYposition = Math.abs(root.state.touchYPosition)
let newIndex = root.state.currentTaskIndex;
taskswitcher: enhance gesture with flick speed tracking and orthogonal movement tracking This MR contains work to track the speed with which the taskswitcher gesture has occurred to allow different handling of a "fast flick" (eg: go to homescreen instead of taskswitcher). # Features The center piece of the overhaul is tracking recent velocity (averaged over the last ~50ms) of the gesture to determine behavior: - Swipe: A normal swipe is a "slow" finger move - Flick: A "fast" swipe The determining factor is the speed at the end of the gesture (= when lifting the finger up), anything before is irrelevant - Swipe up goes to task switcher - Flick up goes to homescreen directly instead of task switcher - this is suppressed when already on homescreen - it makes no sense there - Note: On Android that is actually mapped to "going to the first page of the home screen if not there already" - I don't care much for that and it can lead to nothing happening if you're already there, I think I prefer the consistency of always opening the task switcher vs a "quick way to get to the main (first) page of the homescreen" - especially since what that means depends a lot on the active home screen. - added orthogonal gesture movement tracking (2-axis gestures) - gesture properly follows finger movement in all directions now making it feel much more responsive and nice - diagonal flick for quick task switch - horizontal only movement (while holding, not releasing) triggers task scrub gesture for scrubbing through larger number of task in the switcher backlog - Complete refactor of state keeping logic, not just in relation to gestures - state keeper fully in one place in C++ except for - a few derived values that are very directly UI related which are kept in `TaskSwitcherHelpers.qml` - and directly touch gesture related state which are kept separate to maybe allow upstreaming the new touch border gesture handling to KWin in the future <details><summary>done TODO items</summary> - [x] currentTaskIndex tracking is majorly broken - [x] old TaskSwitcherState.qml is still around, should be removed - [x] clamping minimum scale for some reason also clamps y position which makes the task not track the finger when moving past the "full activation" point - [x] switching between tasks when task switcher is open is super crap - [x] task switching when switcher is fully open works now, but flicks don't work - you have to fully move at least halfway to the next task for it to "snap" to that task when you let go, there is 0 momentum and I don't know why -> *Flickable is just broken and refuses to flick on touch input, same behavior on master with old implementation, so I reimplemented the same workaround from before* - [x] the gestures don't work until the notification drawer was invoked at least once after every screen geometry change (resolution change, screen rotation etc) - [x] keyboard shortcut for toggling task switcher is kinda hacky right now and feels awful when closing (some delay noticable, maybe to do with animations?) *NOTE: I disabled it for now because the hacky implementation interfered with/created bugs in other parts* - [x] task scrub mode has broken offsets/positions (can scroll past the end of the list, but not reach all elements) when opening task index is not 0 - [x] fast flick velocity threshold is a mostly arbitrary number and I think it also depends on pixel density - ideally we want a mm (or cm or whatever) per ms, not logical pixels per ms </details> # Design decisions I made during development: - Changed the y opening animation from OutBack (with a bounce) to a simple OutExpo (quickly move towards and then approach slowly) as the bouncy look and feel from the OutBack animation felt wrong to me in that place - To fit better with the new docked mode: - the task switcher now shows the screen geometry behind a task that is not fullscreened. This allows to consistently press (and see) the adjacent tasks which might not always be the case if it's a thin window on a landscape screen. - This is not great overall yet - actually it just checks the windows actual aspect ratio, so if it's smaller but same aspect ratio as screen it shows as if it's a full screen task - also it maximizes and centers the window thumbnail in the task switcher so it really isn't ideal, I just don't know what the behavior *should* ideally be. This change at least doesn't break the switcher when in docked mode. - on opening an app from task switcher it doesn't get force-fullscreened anymore - either it already is fullscreen (because fullscreen in docked mode or just not in docked mode) or it should just keep its geometry (this could be gated behind checking if docked mode is on or not, but I think it's fine without) # TODO before merge - [x] IMPORTANT: Because of regular crashing on interaction I've commented out any code that uses WindowFilterModel::data() which seems to be the cause for that. Since master also uses this and experiences these crashes (at least on both dev machines I tested), I don't think this MR necessarily needs to be held up for that issue (especially since it feels like it could be upstream). I removed this to have an easier time with testing my code without constant crashes, but before merging this would need to be put in again as it breaks: skipping windows with "skipSwitcher" flag set, and showing the correct task when opening the switcher in certain situations. - seems to be a bug with WindowFilterModel::data sometimes returning an invalid/null element? But not in C++, it just doesn't make its way to QML. - feels like it could be a timing thing (but maybe not?) when reverting the skipSwitcher filter rule on `tasksModel` *or* adding some lengthy debug console log in `TaskList.qml:minimizeAll()` before trying to access item.window properties it seems to be fine. When keeping skipSwitcher and having no lengthy debug output I get crashes rather reliably every ~3rd to 5th time invoking the task switcher. - While this does seem to be reproducible on master and thus "the same", if it is timing based it may be that my code triggers the error *more often* technically making it a regression (though also easier to track down?) - Interestingly I don't seem to be able to reproduce this on-device, my PinePhone doesn't have this behavior at all. Maybe a bug with nested KWin session? - [ ] task scrub mode may need to have a dynamic amount of items to scrub through based on display size/orientation (maybe keep distance for task scrubbing the same on portrait vs landscape to aid muscle memory)? or instead of using percentages/pixel distances use mm distance based on dpi? - [ ] is task scrub mode even something we want? Since I prefer the "quick switch gesture" only being able to switch between the two most recent windows (because of immediate reordering by recency), this leaves our task switcher in gesture mode with no quick "shortcut gesture" to switch to older tasks, task scrub mode makes this possible in IMO a nice way, but would love input there. - [ ] get rid of all code comments marked with `TODO!` (with an exclamation mark) - [x] One last pass on removing all superfluous console logs, includes and unused functions. I cleaned that up a lot already, but not completely (one std::cout is still left in on purpose until last minute because of a very rare gesture bug I saw twice and I'm not sure if my fix really got it) # Other - I've only ever tested on my laptop with touch screen (ie: effectively a large tablet form factor), if this merges and we get it on nightly I'll definitely try on the PinePhone, there I will closely scrutinize whether the undoYThreshold and task scrub mode number of tasks feels good to use on a small portrait mode display. This may lead to followup MRs to tweak those essentially arbitrarily chosen values. # TODOs for later MRs - [ ] consider moving velocity calculation/generic 2-dimensional gesture tracking to kwin if it's robust and generic enough for that to be useful on their end. (maybe do that later after it has proven itself for a while on our side) - [ ] (optional?) vibration feedback to tell if it goes to taskswitcher or homescreen? android has that (at least mine) with a tight vibration when task switcher is invoked vs homescree - [ ] flick to homescreen animation kinda looks bad - [ ] task sorting by recency - [ ] polish task scrub mode if we intend to keep it - [ ] task scrub mode can "run out of space" for the gesture and thus can only scrub through a maximum number of tasks (currently 8 either direction in my implementation), but we could add a timer if reaching the end that goes through tasks eg: one per second (acceleration?) to "unlock" the full task list - [ ] task scrub mode should have some visual cue when it's activated (eg: fully "opening" the switcher y position, maybe some extra UI with window thumbnails) - [ ] Positioning after screen geometry change (resize, rotation) of the task switcher is kinda broken (task may end off-screen etc) - fixed by interacting with it or re-opening and not a huge issue IMO - [ ] some bound for y position above the "fully opened position" (maybe make it more and more "reluctant" to follow the finger upwards the further up you go - I think that just makes it feel a bit nicer - [ ] make it behave better with docked mode (currently some animations look a bit scuffed) - [ ] make it behave better with multi screen (currently it's mirrored on all screens, we probably only want it on the screen that currently has focus?) - [ ] navbar buttons when not in gesture mode seem to have slightly different button icon sizes than the system wide navbar (is there no better way to add the navbar than to essentially reimplement it?)
2024-05-05 01:17:54 +00:00
let shouldSwitch = false;
if (root.state.xVelocity > 0) {
if (root.taskSwitcherHelpers.notHomeScreenState) {
// flick to the right, go to the app on the left
newIndex = root.state.currentTaskIndex + 1;
}
if (newIndex < root.tasksCount) {
taskswitcher: enhance gesture with flick speed tracking and orthogonal movement tracking This MR contains work to track the speed with which the taskswitcher gesture has occurred to allow different handling of a "fast flick" (eg: go to homescreen instead of taskswitcher). # Features The center piece of the overhaul is tracking recent velocity (averaged over the last ~50ms) of the gesture to determine behavior: - Swipe: A normal swipe is a "slow" finger move - Flick: A "fast" swipe The determining factor is the speed at the end of the gesture (= when lifting the finger up), anything before is irrelevant - Swipe up goes to task switcher - Flick up goes to homescreen directly instead of task switcher - this is suppressed when already on homescreen - it makes no sense there - Note: On Android that is actually mapped to "going to the first page of the home screen if not there already" - I don't care much for that and it can lead to nothing happening if you're already there, I think I prefer the consistency of always opening the task switcher vs a "quick way to get to the main (first) page of the homescreen" - especially since what that means depends a lot on the active home screen. - added orthogonal gesture movement tracking (2-axis gestures) - gesture properly follows finger movement in all directions now making it feel much more responsive and nice - diagonal flick for quick task switch - horizontal only movement (while holding, not releasing) triggers task scrub gesture for scrubbing through larger number of task in the switcher backlog - Complete refactor of state keeping logic, not just in relation to gestures - state keeper fully in one place in C++ except for - a few derived values that are very directly UI related which are kept in `TaskSwitcherHelpers.qml` - and directly touch gesture related state which are kept separate to maybe allow upstreaming the new touch border gesture handling to KWin in the future <details><summary>done TODO items</summary> - [x] currentTaskIndex tracking is majorly broken - [x] old TaskSwitcherState.qml is still around, should be removed - [x] clamping minimum scale for some reason also clamps y position which makes the task not track the finger when moving past the "full activation" point - [x] switching between tasks when task switcher is open is super crap - [x] task switching when switcher is fully open works now, but flicks don't work - you have to fully move at least halfway to the next task for it to "snap" to that task when you let go, there is 0 momentum and I don't know why -> *Flickable is just broken and refuses to flick on touch input, same behavior on master with old implementation, so I reimplemented the same workaround from before* - [x] the gestures don't work until the notification drawer was invoked at least once after every screen geometry change (resolution change, screen rotation etc) - [x] keyboard shortcut for toggling task switcher is kinda hacky right now and feels awful when closing (some delay noticable, maybe to do with animations?) *NOTE: I disabled it for now because the hacky implementation interfered with/created bugs in other parts* - [x] task scrub mode has broken offsets/positions (can scroll past the end of the list, but not reach all elements) when opening task index is not 0 - [x] fast flick velocity threshold is a mostly arbitrary number and I think it also depends on pixel density - ideally we want a mm (or cm or whatever) per ms, not logical pixels per ms </details> # Design decisions I made during development: - Changed the y opening animation from OutBack (with a bounce) to a simple OutExpo (quickly move towards and then approach slowly) as the bouncy look and feel from the OutBack animation felt wrong to me in that place - To fit better with the new docked mode: - the task switcher now shows the screen geometry behind a task that is not fullscreened. This allows to consistently press (and see) the adjacent tasks which might not always be the case if it's a thin window on a landscape screen. - This is not great overall yet - actually it just checks the windows actual aspect ratio, so if it's smaller but same aspect ratio as screen it shows as if it's a full screen task - also it maximizes and centers the window thumbnail in the task switcher so it really isn't ideal, I just don't know what the behavior *should* ideally be. This change at least doesn't break the switcher when in docked mode. - on opening an app from task switcher it doesn't get force-fullscreened anymore - either it already is fullscreen (because fullscreen in docked mode or just not in docked mode) or it should just keep its geometry (this could be gated behind checking if docked mode is on or not, but I think it's fine without) # TODO before merge - [x] IMPORTANT: Because of regular crashing on interaction I've commented out any code that uses WindowFilterModel::data() which seems to be the cause for that. Since master also uses this and experiences these crashes (at least on both dev machines I tested), I don't think this MR necessarily needs to be held up for that issue (especially since it feels like it could be upstream). I removed this to have an easier time with testing my code without constant crashes, but before merging this would need to be put in again as it breaks: skipping windows with "skipSwitcher" flag set, and showing the correct task when opening the switcher in certain situations. - seems to be a bug with WindowFilterModel::data sometimes returning an invalid/null element? But not in C++, it just doesn't make its way to QML. - feels like it could be a timing thing (but maybe not?) when reverting the skipSwitcher filter rule on `tasksModel` *or* adding some lengthy debug console log in `TaskList.qml:minimizeAll()` before trying to access item.window properties it seems to be fine. When keeping skipSwitcher and having no lengthy debug output I get crashes rather reliably every ~3rd to 5th time invoking the task switcher. - While this does seem to be reproducible on master and thus "the same", if it is timing based it may be that my code triggers the error *more often* technically making it a regression (though also easier to track down?) - Interestingly I don't seem to be able to reproduce this on-device, my PinePhone doesn't have this behavior at all. Maybe a bug with nested KWin session? - [ ] task scrub mode may need to have a dynamic amount of items to scrub through based on display size/orientation (maybe keep distance for task scrubbing the same on portrait vs landscape to aid muscle memory)? or instead of using percentages/pixel distances use mm distance based on dpi? - [ ] is task scrub mode even something we want? Since I prefer the "quick switch gesture" only being able to switch between the two most recent windows (because of immediate reordering by recency), this leaves our task switcher in gesture mode with no quick "shortcut gesture" to switch to older tasks, task scrub mode makes this possible in IMO a nice way, but would love input there. - [ ] get rid of all code comments marked with `TODO!` (with an exclamation mark) - [x] One last pass on removing all superfluous console logs, includes and unused functions. I cleaned that up a lot already, but not completely (one std::cout is still left in on purpose until last minute because of a very rare gesture bug I saw twice and I'm not sure if my fix really got it) # Other - I've only ever tested on my laptop with touch screen (ie: effectively a large tablet form factor), if this merges and we get it on nightly I'll definitely try on the PinePhone, there I will closely scrutinize whether the undoYThreshold and task scrub mode number of tasks feels good to use on a small portrait mode display. This may lead to followup MRs to tweak those essentially arbitrarily chosen values. # TODOs for later MRs - [ ] consider moving velocity calculation/generic 2-dimensional gesture tracking to kwin if it's robust and generic enough for that to be useful on their end. (maybe do that later after it has proven itself for a while on our side) - [ ] (optional?) vibration feedback to tell if it goes to taskswitcher or homescreen? android has that (at least mine) with a tight vibration when task switcher is invoked vs homescree - [ ] flick to homescreen animation kinda looks bad - [ ] task sorting by recency - [ ] polish task scrub mode if we intend to keep it - [ ] task scrub mode can "run out of space" for the gesture and thus can only scrub through a maximum number of tasks (currently 8 either direction in my implementation), but we could add a timer if reaching the end that goes through tasks eg: one per second (acceleration?) to "unlock" the full task list - [ ] task scrub mode should have some visual cue when it's activated (eg: fully "opening" the switcher y position, maybe some extra UI with window thumbnails) - [ ] Positioning after screen geometry change (resize, rotation) of the task switcher is kinda broken (task may end off-screen etc) - fixed by interacting with it or re-opening and not a huge issue IMO - [ ] some bound for y position above the "fully opened position" (maybe make it more and more "reluctant" to follow the finger upwards the further up you go - I think that just makes it feel a bit nicer - [ ] make it behave better with docked mode (currently some animations look a bit scuffed) - [ ] make it behave better with multi screen (currently it's mirrored on all screens, we probably only want it on the screen that currently has focus?) - [ ] navbar buttons when not in gesture mode seem to have slightly different button icon sizes than the system wide navbar (is there no better way to add the navbar than to essentially reimplement it?)
2024-05-05 01:17:54 +00:00
// switch only if flick doesn't go over end of list
shouldSwitch = true;
}
} else if (root.state.xVelocity < 0) {
if (root.taskSwitcherHelpers.notHomeScreenState) {
// flick to the left, go to app to the right
newIndex = root.state.currentTaskIndex - 1;
if (newIndex >= 0) {
// switch only if flick doesn't go over end of list
shouldSwitch = true;
}
} else {
// flick to the left on the home screen, dismiss the gesture
root.taskSwitcherHelpers.close();
return;
taskswitcher: enhance gesture with flick speed tracking and orthogonal movement tracking This MR contains work to track the speed with which the taskswitcher gesture has occurred to allow different handling of a "fast flick" (eg: go to homescreen instead of taskswitcher). # Features The center piece of the overhaul is tracking recent velocity (averaged over the last ~50ms) of the gesture to determine behavior: - Swipe: A normal swipe is a "slow" finger move - Flick: A "fast" swipe The determining factor is the speed at the end of the gesture (= when lifting the finger up), anything before is irrelevant - Swipe up goes to task switcher - Flick up goes to homescreen directly instead of task switcher - this is suppressed when already on homescreen - it makes no sense there - Note: On Android that is actually mapped to "going to the first page of the home screen if not there already" - I don't care much for that and it can lead to nothing happening if you're already there, I think I prefer the consistency of always opening the task switcher vs a "quick way to get to the main (first) page of the homescreen" - especially since what that means depends a lot on the active home screen. - added orthogonal gesture movement tracking (2-axis gestures) - gesture properly follows finger movement in all directions now making it feel much more responsive and nice - diagonal flick for quick task switch - horizontal only movement (while holding, not releasing) triggers task scrub gesture for scrubbing through larger number of task in the switcher backlog - Complete refactor of state keeping logic, not just in relation to gestures - state keeper fully in one place in C++ except for - a few derived values that are very directly UI related which are kept in `TaskSwitcherHelpers.qml` - and directly touch gesture related state which are kept separate to maybe allow upstreaming the new touch border gesture handling to KWin in the future <details><summary>done TODO items</summary> - [x] currentTaskIndex tracking is majorly broken - [x] old TaskSwitcherState.qml is still around, should be removed - [x] clamping minimum scale for some reason also clamps y position which makes the task not track the finger when moving past the "full activation" point - [x] switching between tasks when task switcher is open is super crap - [x] task switching when switcher is fully open works now, but flicks don't work - you have to fully move at least halfway to the next task for it to "snap" to that task when you let go, there is 0 momentum and I don't know why -> *Flickable is just broken and refuses to flick on touch input, same behavior on master with old implementation, so I reimplemented the same workaround from before* - [x] the gestures don't work until the notification drawer was invoked at least once after every screen geometry change (resolution change, screen rotation etc) - [x] keyboard shortcut for toggling task switcher is kinda hacky right now and feels awful when closing (some delay noticable, maybe to do with animations?) *NOTE: I disabled it for now because the hacky implementation interfered with/created bugs in other parts* - [x] task scrub mode has broken offsets/positions (can scroll past the end of the list, but not reach all elements) when opening task index is not 0 - [x] fast flick velocity threshold is a mostly arbitrary number and I think it also depends on pixel density - ideally we want a mm (or cm or whatever) per ms, not logical pixels per ms </details> # Design decisions I made during development: - Changed the y opening animation from OutBack (with a bounce) to a simple OutExpo (quickly move towards and then approach slowly) as the bouncy look and feel from the OutBack animation felt wrong to me in that place - To fit better with the new docked mode: - the task switcher now shows the screen geometry behind a task that is not fullscreened. This allows to consistently press (and see) the adjacent tasks which might not always be the case if it's a thin window on a landscape screen. - This is not great overall yet - actually it just checks the windows actual aspect ratio, so if it's smaller but same aspect ratio as screen it shows as if it's a full screen task - also it maximizes and centers the window thumbnail in the task switcher so it really isn't ideal, I just don't know what the behavior *should* ideally be. This change at least doesn't break the switcher when in docked mode. - on opening an app from task switcher it doesn't get force-fullscreened anymore - either it already is fullscreen (because fullscreen in docked mode or just not in docked mode) or it should just keep its geometry (this could be gated behind checking if docked mode is on or not, but I think it's fine without) # TODO before merge - [x] IMPORTANT: Because of regular crashing on interaction I've commented out any code that uses WindowFilterModel::data() which seems to be the cause for that. Since master also uses this and experiences these crashes (at least on both dev machines I tested), I don't think this MR necessarily needs to be held up for that issue (especially since it feels like it could be upstream). I removed this to have an easier time with testing my code without constant crashes, but before merging this would need to be put in again as it breaks: skipping windows with "skipSwitcher" flag set, and showing the correct task when opening the switcher in certain situations. - seems to be a bug with WindowFilterModel::data sometimes returning an invalid/null element? But not in C++, it just doesn't make its way to QML. - feels like it could be a timing thing (but maybe not?) when reverting the skipSwitcher filter rule on `tasksModel` *or* adding some lengthy debug console log in `TaskList.qml:minimizeAll()` before trying to access item.window properties it seems to be fine. When keeping skipSwitcher and having no lengthy debug output I get crashes rather reliably every ~3rd to 5th time invoking the task switcher. - While this does seem to be reproducible on master and thus "the same", if it is timing based it may be that my code triggers the error *more often* technically making it a regression (though also easier to track down?) - Interestingly I don't seem to be able to reproduce this on-device, my PinePhone doesn't have this behavior at all. Maybe a bug with nested KWin session? - [ ] task scrub mode may need to have a dynamic amount of items to scrub through based on display size/orientation (maybe keep distance for task scrubbing the same on portrait vs landscape to aid muscle memory)? or instead of using percentages/pixel distances use mm distance based on dpi? - [ ] is task scrub mode even something we want? Since I prefer the "quick switch gesture" only being able to switch between the two most recent windows (because of immediate reordering by recency), this leaves our task switcher in gesture mode with no quick "shortcut gesture" to switch to older tasks, task scrub mode makes this possible in IMO a nice way, but would love input there. - [ ] get rid of all code comments marked with `TODO!` (with an exclamation mark) - [x] One last pass on removing all superfluous console logs, includes and unused functions. I cleaned that up a lot already, but not completely (one std::cout is still left in on purpose until last minute because of a very rare gesture bug I saw twice and I'm not sure if my fix really got it) # Other - I've only ever tested on my laptop with touch screen (ie: effectively a large tablet form factor), if this merges and we get it on nightly I'll definitely try on the PinePhone, there I will closely scrutinize whether the undoYThreshold and task scrub mode number of tasks feels good to use on a small portrait mode display. This may lead to followup MRs to tweak those essentially arbitrarily chosen values. # TODOs for later MRs - [ ] consider moving velocity calculation/generic 2-dimensional gesture tracking to kwin if it's robust and generic enough for that to be useful on their end. (maybe do that later after it has proven itself for a while on our side) - [ ] (optional?) vibration feedback to tell if it goes to taskswitcher or homescreen? android has that (at least mine) with a tight vibration when task switcher is invoked vs homescree - [ ] flick to homescreen animation kinda looks bad - [ ] task sorting by recency - [ ] polish task scrub mode if we intend to keep it - [ ] task scrub mode can "run out of space" for the gesture and thus can only scrub through a maximum number of tasks (currently 8 either direction in my implementation), but we could add a timer if reaching the end that goes through tasks eg: one per second (acceleration?) to "unlock" the full task list - [ ] task scrub mode should have some visual cue when it's activated (eg: fully "opening" the switcher y position, maybe some extra UI with window thumbnails) - [ ] Positioning after screen geometry change (resize, rotation) of the task switcher is kinda broken (task may end off-screen etc) - fixed by interacting with it or re-opening and not a huge issue IMO - [ ] some bound for y position above the "fully opened position" (maybe make it more and more "reluctant" to follow the finger upwards the further up you go - I think that just makes it feel a bit nicer - [ ] make it behave better with docked mode (currently some animations look a bit scuffed) - [ ] make it behave better with multi screen (currently it's mirrored on all screens, we probably only want it on the screen that currently has focus?) - [ ] navbar buttons when not in gesture mode seem to have slightly different button icon sizes than the system wide navbar (is there no better way to add the navbar than to essentially reimplement it?)
2024-05-05 01:17:54 +00:00
}
}
if (shouldSwitch) {
if (!root.taskSwitcherHelpers.taskDrawerOpened && unmodifiedYposition < root.taskSwitcherHelpers.openedYPosition) {
// if in a app, switch it to the new task when it is under the openedYPosition
taskList.setTaskOffsetValue(0, unmodifiedYposition < root.taskSwitcherHelpers.openedYPosition && root.taskSwitcherHelpers.notHomeScreenState);
root.taskSwitcherHelpers.openApp(newIndex, Kirigami.Units.longDuration * 4, Easing.OutExpo);
} else {
// if already in the task switcher or above the openedYPosition, only change the focus to the new task
root.taskSwitcherHelpers.animateGoToTaskIndex(newIndex);
root.taskSwitcherHelpers.open();
}
taskswitcher: enhance gesture with flick speed tracking and orthogonal movement tracking This MR contains work to track the speed with which the taskswitcher gesture has occurred to allow different handling of a "fast flick" (eg: go to homescreen instead of taskswitcher). # Features The center piece of the overhaul is tracking recent velocity (averaged over the last ~50ms) of the gesture to determine behavior: - Swipe: A normal swipe is a "slow" finger move - Flick: A "fast" swipe The determining factor is the speed at the end of the gesture (= when lifting the finger up), anything before is irrelevant - Swipe up goes to task switcher - Flick up goes to homescreen directly instead of task switcher - this is suppressed when already on homescreen - it makes no sense there - Note: On Android that is actually mapped to "going to the first page of the home screen if not there already" - I don't care much for that and it can lead to nothing happening if you're already there, I think I prefer the consistency of always opening the task switcher vs a "quick way to get to the main (first) page of the homescreen" - especially since what that means depends a lot on the active home screen. - added orthogonal gesture movement tracking (2-axis gestures) - gesture properly follows finger movement in all directions now making it feel much more responsive and nice - diagonal flick for quick task switch - horizontal only movement (while holding, not releasing) triggers task scrub gesture for scrubbing through larger number of task in the switcher backlog - Complete refactor of state keeping logic, not just in relation to gestures - state keeper fully in one place in C++ except for - a few derived values that are very directly UI related which are kept in `TaskSwitcherHelpers.qml` - and directly touch gesture related state which are kept separate to maybe allow upstreaming the new touch border gesture handling to KWin in the future <details><summary>done TODO items</summary> - [x] currentTaskIndex tracking is majorly broken - [x] old TaskSwitcherState.qml is still around, should be removed - [x] clamping minimum scale for some reason also clamps y position which makes the task not track the finger when moving past the "full activation" point - [x] switching between tasks when task switcher is open is super crap - [x] task switching when switcher is fully open works now, but flicks don't work - you have to fully move at least halfway to the next task for it to "snap" to that task when you let go, there is 0 momentum and I don't know why -> *Flickable is just broken and refuses to flick on touch input, same behavior on master with old implementation, so I reimplemented the same workaround from before* - [x] the gestures don't work until the notification drawer was invoked at least once after every screen geometry change (resolution change, screen rotation etc) - [x] keyboard shortcut for toggling task switcher is kinda hacky right now and feels awful when closing (some delay noticable, maybe to do with animations?) *NOTE: I disabled it for now because the hacky implementation interfered with/created bugs in other parts* - [x] task scrub mode has broken offsets/positions (can scroll past the end of the list, but not reach all elements) when opening task index is not 0 - [x] fast flick velocity threshold is a mostly arbitrary number and I think it also depends on pixel density - ideally we want a mm (or cm or whatever) per ms, not logical pixels per ms </details> # Design decisions I made during development: - Changed the y opening animation from OutBack (with a bounce) to a simple OutExpo (quickly move towards and then approach slowly) as the bouncy look and feel from the OutBack animation felt wrong to me in that place - To fit better with the new docked mode: - the task switcher now shows the screen geometry behind a task that is not fullscreened. This allows to consistently press (and see) the adjacent tasks which might not always be the case if it's a thin window on a landscape screen. - This is not great overall yet - actually it just checks the windows actual aspect ratio, so if it's smaller but same aspect ratio as screen it shows as if it's a full screen task - also it maximizes and centers the window thumbnail in the task switcher so it really isn't ideal, I just don't know what the behavior *should* ideally be. This change at least doesn't break the switcher when in docked mode. - on opening an app from task switcher it doesn't get force-fullscreened anymore - either it already is fullscreen (because fullscreen in docked mode or just not in docked mode) or it should just keep its geometry (this could be gated behind checking if docked mode is on or not, but I think it's fine without) # TODO before merge - [x] IMPORTANT: Because of regular crashing on interaction I've commented out any code that uses WindowFilterModel::data() which seems to be the cause for that. Since master also uses this and experiences these crashes (at least on both dev machines I tested), I don't think this MR necessarily needs to be held up for that issue (especially since it feels like it could be upstream). I removed this to have an easier time with testing my code without constant crashes, but before merging this would need to be put in again as it breaks: skipping windows with "skipSwitcher" flag set, and showing the correct task when opening the switcher in certain situations. - seems to be a bug with WindowFilterModel::data sometimes returning an invalid/null element? But not in C++, it just doesn't make its way to QML. - feels like it could be a timing thing (but maybe not?) when reverting the skipSwitcher filter rule on `tasksModel` *or* adding some lengthy debug console log in `TaskList.qml:minimizeAll()` before trying to access item.window properties it seems to be fine. When keeping skipSwitcher and having no lengthy debug output I get crashes rather reliably every ~3rd to 5th time invoking the task switcher. - While this does seem to be reproducible on master and thus "the same", if it is timing based it may be that my code triggers the error *more often* technically making it a regression (though also easier to track down?) - Interestingly I don't seem to be able to reproduce this on-device, my PinePhone doesn't have this behavior at all. Maybe a bug with nested KWin session? - [ ] task scrub mode may need to have a dynamic amount of items to scrub through based on display size/orientation (maybe keep distance for task scrubbing the same on portrait vs landscape to aid muscle memory)? or instead of using percentages/pixel distances use mm distance based on dpi? - [ ] is task scrub mode even something we want? Since I prefer the "quick switch gesture" only being able to switch between the two most recent windows (because of immediate reordering by recency), this leaves our task switcher in gesture mode with no quick "shortcut gesture" to switch to older tasks, task scrub mode makes this possible in IMO a nice way, but would love input there. - [ ] get rid of all code comments marked with `TODO!` (with an exclamation mark) - [x] One last pass on removing all superfluous console logs, includes and unused functions. I cleaned that up a lot already, but not completely (one std::cout is still left in on purpose until last minute because of a very rare gesture bug I saw twice and I'm not sure if my fix really got it) # Other - I've only ever tested on my laptop with touch screen (ie: effectively a large tablet form factor), if this merges and we get it on nightly I'll definitely try on the PinePhone, there I will closely scrutinize whether the undoYThreshold and task scrub mode number of tasks feels good to use on a small portrait mode display. This may lead to followup MRs to tweak those essentially arbitrarily chosen values. # TODOs for later MRs - [ ] consider moving velocity calculation/generic 2-dimensional gesture tracking to kwin if it's robust and generic enough for that to be useful on their end. (maybe do that later after it has proven itself for a while on our side) - [ ] (optional?) vibration feedback to tell if it goes to taskswitcher or homescreen? android has that (at least mine) with a tight vibration when task switcher is invoked vs homescree - [ ] flick to homescreen animation kinda looks bad - [ ] task sorting by recency - [ ] polish task scrub mode if we intend to keep it - [ ] task scrub mode can "run out of space" for the gesture and thus can only scrub through a maximum number of tasks (currently 8 either direction in my implementation), but we could add a timer if reaching the end that goes through tasks eg: one per second (acceleration?) to "unlock" the full task list - [ ] task scrub mode should have some visual cue when it's activated (eg: fully "opening" the switcher y position, maybe some extra UI with window thumbnails) - [ ] Positioning after screen geometry change (resize, rotation) of the task switcher is kinda broken (task may end off-screen etc) - fixed by interacting with it or re-opening and not a huge issue IMO - [ ] some bound for y position above the "fully opened position" (maybe make it more and more "reluctant" to follow the finger upwards the further up you go - I think that just makes it feel a bit nicer - [ ] make it behave better with docked mode (currently some animations look a bit scuffed) - [ ] make it behave better with multi screen (currently it's mirrored on all screens, we probably only want it on the screen that currently has focus?) - [ ] navbar buttons when not in gesture mode seem to have slightly different button icon sizes than the system wide navbar (is there no better way to add the navbar than to essentially reimplement it?)
2024-05-05 01:17:54 +00:00
} else {
// if not switching, just open task switcher
root.taskSwitcherHelpers.animateGoToTaskIndex(root.state.currentTaskIndex);
root.taskSwitcherHelpers.open();
taskswitcher: enhance gesture with flick speed tracking and orthogonal movement tracking This MR contains work to track the speed with which the taskswitcher gesture has occurred to allow different handling of a "fast flick" (eg: go to homescreen instead of taskswitcher). # Features The center piece of the overhaul is tracking recent velocity (averaged over the last ~50ms) of the gesture to determine behavior: - Swipe: A normal swipe is a "slow" finger move - Flick: A "fast" swipe The determining factor is the speed at the end of the gesture (= when lifting the finger up), anything before is irrelevant - Swipe up goes to task switcher - Flick up goes to homescreen directly instead of task switcher - this is suppressed when already on homescreen - it makes no sense there - Note: On Android that is actually mapped to "going to the first page of the home screen if not there already" - I don't care much for that and it can lead to nothing happening if you're already there, I think I prefer the consistency of always opening the task switcher vs a "quick way to get to the main (first) page of the homescreen" - especially since what that means depends a lot on the active home screen. - added orthogonal gesture movement tracking (2-axis gestures) - gesture properly follows finger movement in all directions now making it feel much more responsive and nice - diagonal flick for quick task switch - horizontal only movement (while holding, not releasing) triggers task scrub gesture for scrubbing through larger number of task in the switcher backlog - Complete refactor of state keeping logic, not just in relation to gestures - state keeper fully in one place in C++ except for - a few derived values that are very directly UI related which are kept in `TaskSwitcherHelpers.qml` - and directly touch gesture related state which are kept separate to maybe allow upstreaming the new touch border gesture handling to KWin in the future <details><summary>done TODO items</summary> - [x] currentTaskIndex tracking is majorly broken - [x] old TaskSwitcherState.qml is still around, should be removed - [x] clamping minimum scale for some reason also clamps y position which makes the task not track the finger when moving past the "full activation" point - [x] switching between tasks when task switcher is open is super crap - [x] task switching when switcher is fully open works now, but flicks don't work - you have to fully move at least halfway to the next task for it to "snap" to that task when you let go, there is 0 momentum and I don't know why -> *Flickable is just broken and refuses to flick on touch input, same behavior on master with old implementation, so I reimplemented the same workaround from before* - [x] the gestures don't work until the notification drawer was invoked at least once after every screen geometry change (resolution change, screen rotation etc) - [x] keyboard shortcut for toggling task switcher is kinda hacky right now and feels awful when closing (some delay noticable, maybe to do with animations?) *NOTE: I disabled it for now because the hacky implementation interfered with/created bugs in other parts* - [x] task scrub mode has broken offsets/positions (can scroll past the end of the list, but not reach all elements) when opening task index is not 0 - [x] fast flick velocity threshold is a mostly arbitrary number and I think it also depends on pixel density - ideally we want a mm (or cm or whatever) per ms, not logical pixels per ms </details> # Design decisions I made during development: - Changed the y opening animation from OutBack (with a bounce) to a simple OutExpo (quickly move towards and then approach slowly) as the bouncy look and feel from the OutBack animation felt wrong to me in that place - To fit better with the new docked mode: - the task switcher now shows the screen geometry behind a task that is not fullscreened. This allows to consistently press (and see) the adjacent tasks which might not always be the case if it's a thin window on a landscape screen. - This is not great overall yet - actually it just checks the windows actual aspect ratio, so if it's smaller but same aspect ratio as screen it shows as if it's a full screen task - also it maximizes and centers the window thumbnail in the task switcher so it really isn't ideal, I just don't know what the behavior *should* ideally be. This change at least doesn't break the switcher when in docked mode. - on opening an app from task switcher it doesn't get force-fullscreened anymore - either it already is fullscreen (because fullscreen in docked mode or just not in docked mode) or it should just keep its geometry (this could be gated behind checking if docked mode is on or not, but I think it's fine without) # TODO before merge - [x] IMPORTANT: Because of regular crashing on interaction I've commented out any code that uses WindowFilterModel::data() which seems to be the cause for that. Since master also uses this and experiences these crashes (at least on both dev machines I tested), I don't think this MR necessarily needs to be held up for that issue (especially since it feels like it could be upstream). I removed this to have an easier time with testing my code without constant crashes, but before merging this would need to be put in again as it breaks: skipping windows with "skipSwitcher" flag set, and showing the correct task when opening the switcher in certain situations. - seems to be a bug with WindowFilterModel::data sometimes returning an invalid/null element? But not in C++, it just doesn't make its way to QML. - feels like it could be a timing thing (but maybe not?) when reverting the skipSwitcher filter rule on `tasksModel` *or* adding some lengthy debug console log in `TaskList.qml:minimizeAll()` before trying to access item.window properties it seems to be fine. When keeping skipSwitcher and having no lengthy debug output I get crashes rather reliably every ~3rd to 5th time invoking the task switcher. - While this does seem to be reproducible on master and thus "the same", if it is timing based it may be that my code triggers the error *more often* technically making it a regression (though also easier to track down?) - Interestingly I don't seem to be able to reproduce this on-device, my PinePhone doesn't have this behavior at all. Maybe a bug with nested KWin session? - [ ] task scrub mode may need to have a dynamic amount of items to scrub through based on display size/orientation (maybe keep distance for task scrubbing the same on portrait vs landscape to aid muscle memory)? or instead of using percentages/pixel distances use mm distance based on dpi? - [ ] is task scrub mode even something we want? Since I prefer the "quick switch gesture" only being able to switch between the two most recent windows (because of immediate reordering by recency), this leaves our task switcher in gesture mode with no quick "shortcut gesture" to switch to older tasks, task scrub mode makes this possible in IMO a nice way, but would love input there. - [ ] get rid of all code comments marked with `TODO!` (with an exclamation mark) - [x] One last pass on removing all superfluous console logs, includes and unused functions. I cleaned that up a lot already, but not completely (one std::cout is still left in on purpose until last minute because of a very rare gesture bug I saw twice and I'm not sure if my fix really got it) # Other - I've only ever tested on my laptop with touch screen (ie: effectively a large tablet form factor), if this merges and we get it on nightly I'll definitely try on the PinePhone, there I will closely scrutinize whether the undoYThreshold and task scrub mode number of tasks feels good to use on a small portrait mode display. This may lead to followup MRs to tweak those essentially arbitrarily chosen values. # TODOs for later MRs - [ ] consider moving velocity calculation/generic 2-dimensional gesture tracking to kwin if it's robust and generic enough for that to be useful on their end. (maybe do that later after it has proven itself for a while on our side) - [ ] (optional?) vibration feedback to tell if it goes to taskswitcher or homescreen? android has that (at least mine) with a tight vibration when task switcher is invoked vs homescree - [ ] flick to homescreen animation kinda looks bad - [ ] task sorting by recency - [ ] polish task scrub mode if we intend to keep it - [ ] task scrub mode can "run out of space" for the gesture and thus can only scrub through a maximum number of tasks (currently 8 either direction in my implementation), but we could add a timer if reaching the end that goes through tasks eg: one per second (acceleration?) to "unlock" the full task list - [ ] task scrub mode should have some visual cue when it's activated (eg: fully "opening" the switcher y position, maybe some extra UI with window thumbnails) - [ ] Positioning after screen geometry change (resize, rotation) of the task switcher is kinda broken (task may end off-screen etc) - fixed by interacting with it or re-opening and not a huge issue IMO - [ ] some bound for y position above the "fully opened position" (maybe make it more and more "reluctant" to follow the finger upwards the further up you go - I think that just makes it feel a bit nicer - [ ] make it behave better with docked mode (currently some animations look a bit scuffed) - [ ] make it behave better with multi screen (currently it's mirrored on all screens, we probably only want it on the screen that currently has focus?) - [ ] navbar buttons when not in gesture mode seem to have slightly different button icon sizes than the system wide navbar (is there no better way to add the navbar than to essentially reimplement it?)
2024-05-05 01:17:54 +00:00
}
}
// Logic for deciding how to handle the end of a gesture input
function onGestureInProgressChanged(): void {
root.taskSwitcherHelpers.fromButton = false;
if (root.state.gestureInProgress) {
root.taskSwitcherHelpers.currentDisplayTask = root.state.currentTaskIndex;
taskswitcher: enhance gesture with flick speed tracking and orthogonal movement tracking This MR contains work to track the speed with which the taskswitcher gesture has occurred to allow different handling of a "fast flick" (eg: go to homescreen instead of taskswitcher). # Features The center piece of the overhaul is tracking recent velocity (averaged over the last ~50ms) of the gesture to determine behavior: - Swipe: A normal swipe is a "slow" finger move - Flick: A "fast" swipe The determining factor is the speed at the end of the gesture (= when lifting the finger up), anything before is irrelevant - Swipe up goes to task switcher - Flick up goes to homescreen directly instead of task switcher - this is suppressed when already on homescreen - it makes no sense there - Note: On Android that is actually mapped to "going to the first page of the home screen if not there already" - I don't care much for that and it can lead to nothing happening if you're already there, I think I prefer the consistency of always opening the task switcher vs a "quick way to get to the main (first) page of the homescreen" - especially since what that means depends a lot on the active home screen. - added orthogonal gesture movement tracking (2-axis gestures) - gesture properly follows finger movement in all directions now making it feel much more responsive and nice - diagonal flick for quick task switch - horizontal only movement (while holding, not releasing) triggers task scrub gesture for scrubbing through larger number of task in the switcher backlog - Complete refactor of state keeping logic, not just in relation to gestures - state keeper fully in one place in C++ except for - a few derived values that are very directly UI related which are kept in `TaskSwitcherHelpers.qml` - and directly touch gesture related state which are kept separate to maybe allow upstreaming the new touch border gesture handling to KWin in the future <details><summary>done TODO items</summary> - [x] currentTaskIndex tracking is majorly broken - [x] old TaskSwitcherState.qml is still around, should be removed - [x] clamping minimum scale for some reason also clamps y position which makes the task not track the finger when moving past the "full activation" point - [x] switching between tasks when task switcher is open is super crap - [x] task switching when switcher is fully open works now, but flicks don't work - you have to fully move at least halfway to the next task for it to "snap" to that task when you let go, there is 0 momentum and I don't know why -> *Flickable is just broken and refuses to flick on touch input, same behavior on master with old implementation, so I reimplemented the same workaround from before* - [x] the gestures don't work until the notification drawer was invoked at least once after every screen geometry change (resolution change, screen rotation etc) - [x] keyboard shortcut for toggling task switcher is kinda hacky right now and feels awful when closing (some delay noticable, maybe to do with animations?) *NOTE: I disabled it for now because the hacky implementation interfered with/created bugs in other parts* - [x] task scrub mode has broken offsets/positions (can scroll past the end of the list, but not reach all elements) when opening task index is not 0 - [x] fast flick velocity threshold is a mostly arbitrary number and I think it also depends on pixel density - ideally we want a mm (or cm or whatever) per ms, not logical pixels per ms </details> # Design decisions I made during development: - Changed the y opening animation from OutBack (with a bounce) to a simple OutExpo (quickly move towards and then approach slowly) as the bouncy look and feel from the OutBack animation felt wrong to me in that place - To fit better with the new docked mode: - the task switcher now shows the screen geometry behind a task that is not fullscreened. This allows to consistently press (and see) the adjacent tasks which might not always be the case if it's a thin window on a landscape screen. - This is not great overall yet - actually it just checks the windows actual aspect ratio, so if it's smaller but same aspect ratio as screen it shows as if it's a full screen task - also it maximizes and centers the window thumbnail in the task switcher so it really isn't ideal, I just don't know what the behavior *should* ideally be. This change at least doesn't break the switcher when in docked mode. - on opening an app from task switcher it doesn't get force-fullscreened anymore - either it already is fullscreen (because fullscreen in docked mode or just not in docked mode) or it should just keep its geometry (this could be gated behind checking if docked mode is on or not, but I think it's fine without) # TODO before merge - [x] IMPORTANT: Because of regular crashing on interaction I've commented out any code that uses WindowFilterModel::data() which seems to be the cause for that. Since master also uses this and experiences these crashes (at least on both dev machines I tested), I don't think this MR necessarily needs to be held up for that issue (especially since it feels like it could be upstream). I removed this to have an easier time with testing my code without constant crashes, but before merging this would need to be put in again as it breaks: skipping windows with "skipSwitcher" flag set, and showing the correct task when opening the switcher in certain situations. - seems to be a bug with WindowFilterModel::data sometimes returning an invalid/null element? But not in C++, it just doesn't make its way to QML. - feels like it could be a timing thing (but maybe not?) when reverting the skipSwitcher filter rule on `tasksModel` *or* adding some lengthy debug console log in `TaskList.qml:minimizeAll()` before trying to access item.window properties it seems to be fine. When keeping skipSwitcher and having no lengthy debug output I get crashes rather reliably every ~3rd to 5th time invoking the task switcher. - While this does seem to be reproducible on master and thus "the same", if it is timing based it may be that my code triggers the error *more often* technically making it a regression (though also easier to track down?) - Interestingly I don't seem to be able to reproduce this on-device, my PinePhone doesn't have this behavior at all. Maybe a bug with nested KWin session? - [ ] task scrub mode may need to have a dynamic amount of items to scrub through based on display size/orientation (maybe keep distance for task scrubbing the same on portrait vs landscape to aid muscle memory)? or instead of using percentages/pixel distances use mm distance based on dpi? - [ ] is task scrub mode even something we want? Since I prefer the "quick switch gesture" only being able to switch between the two most recent windows (because of immediate reordering by recency), this leaves our task switcher in gesture mode with no quick "shortcut gesture" to switch to older tasks, task scrub mode makes this possible in IMO a nice way, but would love input there. - [ ] get rid of all code comments marked with `TODO!` (with an exclamation mark) - [x] One last pass on removing all superfluous console logs, includes and unused functions. I cleaned that up a lot already, but not completely (one std::cout is still left in on purpose until last minute because of a very rare gesture bug I saw twice and I'm not sure if my fix really got it) # Other - I've only ever tested on my laptop with touch screen (ie: effectively a large tablet form factor), if this merges and we get it on nightly I'll definitely try on the PinePhone, there I will closely scrutinize whether the undoYThreshold and task scrub mode number of tasks feels good to use on a small portrait mode display. This may lead to followup MRs to tweak those essentially arbitrarily chosen values. # TODOs for later MRs - [ ] consider moving velocity calculation/generic 2-dimensional gesture tracking to kwin if it's robust and generic enough for that to be useful on their end. (maybe do that later after it has proven itself for a while on our side) - [ ] (optional?) vibration feedback to tell if it goes to taskswitcher or homescreen? android has that (at least mine) with a tight vibration when task switcher is invoked vs homescree - [ ] flick to homescreen animation kinda looks bad - [ ] task sorting by recency - [ ] polish task scrub mode if we intend to keep it - [ ] task scrub mode can "run out of space" for the gesture and thus can only scrub through a maximum number of tasks (currently 8 either direction in my implementation), but we could add a timer if reaching the end that goes through tasks eg: one per second (acceleration?) to "unlock" the full task list - [ ] task scrub mode should have some visual cue when it's activated (eg: fully "opening" the switcher y position, maybe some extra UI with window thumbnails) - [ ] Positioning after screen geometry change (resize, rotation) of the task switcher is kinda broken (task may end off-screen etc) - fixed by interacting with it or re-opening and not a huge issue IMO - [ ] some bound for y position above the "fully opened position" (maybe make it more and more "reluctant" to follow the finger upwards the further up you go - I think that just makes it feel a bit nicer - [ ] make it behave better with docked mode (currently some animations look a bit scuffed) - [ ] make it behave better with multi screen (currently it's mirrored on all screens, we probably only want it on the screen that currently has focus?) - [ ] navbar buttons when not in gesture mode seem to have slightly different button icon sizes than the system wide navbar (is there no better way to add the navbar than to essentially reimplement it?)
2024-05-05 01:17:54 +00:00
return;
}
if (taskList.count === 0) {
// dismiss the gesture if the task list is empty
root.taskSwitcherHelpers.close();
} if (root.taskSwitcherHelpers.isInTaskScrubMode) {
// TODO! do we want to handle upwards flick to dismiss in task scrub mode?
let unmodifiedYposition = Math.abs(root.state.touchYPosition)
root.backgroundColorOpacity = 1;
if (root.taskSwitcherHelpers.taskDrawerOpened || unmodifiedYposition > root.taskSwitcherHelpers.undoYThreshold) {
root.taskSwitcherHelpers.animateGoToTaskIndex(root.state.currentTaskIndex);
root.taskSwitcherHelpers.open();
root.taskSwitcherHelpers.isInTaskScrubMode = false;
} else {
root.taskSwitcherHelpers.openApp(root.state.currentTaskIndex);
taskswitcher: enhance gesture with flick speed tracking and orthogonal movement tracking This MR contains work to track the speed with which the taskswitcher gesture has occurred to allow different handling of a "fast flick" (eg: go to homescreen instead of taskswitcher). # Features The center piece of the overhaul is tracking recent velocity (averaged over the last ~50ms) of the gesture to determine behavior: - Swipe: A normal swipe is a "slow" finger move - Flick: A "fast" swipe The determining factor is the speed at the end of the gesture (= when lifting the finger up), anything before is irrelevant - Swipe up goes to task switcher - Flick up goes to homescreen directly instead of task switcher - this is suppressed when already on homescreen - it makes no sense there - Note: On Android that is actually mapped to "going to the first page of the home screen if not there already" - I don't care much for that and it can lead to nothing happening if you're already there, I think I prefer the consistency of always opening the task switcher vs a "quick way to get to the main (first) page of the homescreen" - especially since what that means depends a lot on the active home screen. - added orthogonal gesture movement tracking (2-axis gestures) - gesture properly follows finger movement in all directions now making it feel much more responsive and nice - diagonal flick for quick task switch - horizontal only movement (while holding, not releasing) triggers task scrub gesture for scrubbing through larger number of task in the switcher backlog - Complete refactor of state keeping logic, not just in relation to gestures - state keeper fully in one place in C++ except for - a few derived values that are very directly UI related which are kept in `TaskSwitcherHelpers.qml` - and directly touch gesture related state which are kept separate to maybe allow upstreaming the new touch border gesture handling to KWin in the future <details><summary>done TODO items</summary> - [x] currentTaskIndex tracking is majorly broken - [x] old TaskSwitcherState.qml is still around, should be removed - [x] clamping minimum scale for some reason also clamps y position which makes the task not track the finger when moving past the "full activation" point - [x] switching between tasks when task switcher is open is super crap - [x] task switching when switcher is fully open works now, but flicks don't work - you have to fully move at least halfway to the next task for it to "snap" to that task when you let go, there is 0 momentum and I don't know why -> *Flickable is just broken and refuses to flick on touch input, same behavior on master with old implementation, so I reimplemented the same workaround from before* - [x] the gestures don't work until the notification drawer was invoked at least once after every screen geometry change (resolution change, screen rotation etc) - [x] keyboard shortcut for toggling task switcher is kinda hacky right now and feels awful when closing (some delay noticable, maybe to do with animations?) *NOTE: I disabled it for now because the hacky implementation interfered with/created bugs in other parts* - [x] task scrub mode has broken offsets/positions (can scroll past the end of the list, but not reach all elements) when opening task index is not 0 - [x] fast flick velocity threshold is a mostly arbitrary number and I think it also depends on pixel density - ideally we want a mm (or cm or whatever) per ms, not logical pixels per ms </details> # Design decisions I made during development: - Changed the y opening animation from OutBack (with a bounce) to a simple OutExpo (quickly move towards and then approach slowly) as the bouncy look and feel from the OutBack animation felt wrong to me in that place - To fit better with the new docked mode: - the task switcher now shows the screen geometry behind a task that is not fullscreened. This allows to consistently press (and see) the adjacent tasks which might not always be the case if it's a thin window on a landscape screen. - This is not great overall yet - actually it just checks the windows actual aspect ratio, so if it's smaller but same aspect ratio as screen it shows as if it's a full screen task - also it maximizes and centers the window thumbnail in the task switcher so it really isn't ideal, I just don't know what the behavior *should* ideally be. This change at least doesn't break the switcher when in docked mode. - on opening an app from task switcher it doesn't get force-fullscreened anymore - either it already is fullscreen (because fullscreen in docked mode or just not in docked mode) or it should just keep its geometry (this could be gated behind checking if docked mode is on or not, but I think it's fine without) # TODO before merge - [x] IMPORTANT: Because of regular crashing on interaction I've commented out any code that uses WindowFilterModel::data() which seems to be the cause for that. Since master also uses this and experiences these crashes (at least on both dev machines I tested), I don't think this MR necessarily needs to be held up for that issue (especially since it feels like it could be upstream). I removed this to have an easier time with testing my code without constant crashes, but before merging this would need to be put in again as it breaks: skipping windows with "skipSwitcher" flag set, and showing the correct task when opening the switcher in certain situations. - seems to be a bug with WindowFilterModel::data sometimes returning an invalid/null element? But not in C++, it just doesn't make its way to QML. - feels like it could be a timing thing (but maybe not?) when reverting the skipSwitcher filter rule on `tasksModel` *or* adding some lengthy debug console log in `TaskList.qml:minimizeAll()` before trying to access item.window properties it seems to be fine. When keeping skipSwitcher and having no lengthy debug output I get crashes rather reliably every ~3rd to 5th time invoking the task switcher. - While this does seem to be reproducible on master and thus "the same", if it is timing based it may be that my code triggers the error *more often* technically making it a regression (though also easier to track down?) - Interestingly I don't seem to be able to reproduce this on-device, my PinePhone doesn't have this behavior at all. Maybe a bug with nested KWin session? - [ ] task scrub mode may need to have a dynamic amount of items to scrub through based on display size/orientation (maybe keep distance for task scrubbing the same on portrait vs landscape to aid muscle memory)? or instead of using percentages/pixel distances use mm distance based on dpi? - [ ] is task scrub mode even something we want? Since I prefer the "quick switch gesture" only being able to switch between the two most recent windows (because of immediate reordering by recency), this leaves our task switcher in gesture mode with no quick "shortcut gesture" to switch to older tasks, task scrub mode makes this possible in IMO a nice way, but would love input there. - [ ] get rid of all code comments marked with `TODO!` (with an exclamation mark) - [x] One last pass on removing all superfluous console logs, includes and unused functions. I cleaned that up a lot already, but not completely (one std::cout is still left in on purpose until last minute because of a very rare gesture bug I saw twice and I'm not sure if my fix really got it) # Other - I've only ever tested on my laptop with touch screen (ie: effectively a large tablet form factor), if this merges and we get it on nightly I'll definitely try on the PinePhone, there I will closely scrutinize whether the undoYThreshold and task scrub mode number of tasks feels good to use on a small portrait mode display. This may lead to followup MRs to tweak those essentially arbitrarily chosen values. # TODOs for later MRs - [ ] consider moving velocity calculation/generic 2-dimensional gesture tracking to kwin if it's robust and generic enough for that to be useful on their end. (maybe do that later after it has proven itself for a while on our side) - [ ] (optional?) vibration feedback to tell if it goes to taskswitcher or homescreen? android has that (at least mine) with a tight vibration when task switcher is invoked vs homescree - [ ] flick to homescreen animation kinda looks bad - [ ] task sorting by recency - [ ] polish task scrub mode if we intend to keep it - [ ] task scrub mode can "run out of space" for the gesture and thus can only scrub through a maximum number of tasks (currently 8 either direction in my implementation), but we could add a timer if reaching the end that goes through tasks eg: one per second (acceleration?) to "unlock" the full task list - [ ] task scrub mode should have some visual cue when it's activated (eg: fully "opening" the switcher y position, maybe some extra UI with window thumbnails) - [ ] Positioning after screen geometry change (resize, rotation) of the task switcher is kinda broken (task may end off-screen etc) - fixed by interacting with it or re-opening and not a huge issue IMO - [ ] some bound for y position above the "fully opened position" (maybe make it more and more "reluctant" to follow the finger upwards the further up you go - I think that just makes it feel a bit nicer - [ ] make it behave better with docked mode (currently some animations look a bit scuffed) - [ ] make it behave better with multi screen (currently it's mirrored on all screens, we probably only want it on the screen that currently has focus?) - [ ] navbar buttons when not in gesture mode seem to have slightly different button icon sizes than the system wide navbar (is there no better way to add the navbar than to essentially reimplement it?)
2024-05-05 01:17:54 +00:00
}
} else if (root.taskSwitcherHelpers.gestureState == TaskSwitcherHelpers.GestureStates.Undecided) {
if (root.taskSwitcherHelpers.taskDrawerOpened) {
// if in the task switcher, return to it
root.taskSwitcherHelpers.animateGoToTaskIndex(root.state.currentTaskIndex);
root.taskSwitcherHelpers.open();
} else if (root.state.wasInActiveTask) {
// if inside a app, return to it
returnToApp();
taskswitcher: enhance gesture with flick speed tracking and orthogonal movement tracking This MR contains work to track the speed with which the taskswitcher gesture has occurred to allow different handling of a "fast flick" (eg: go to homescreen instead of taskswitcher). # Features The center piece of the overhaul is tracking recent velocity (averaged over the last ~50ms) of the gesture to determine behavior: - Swipe: A normal swipe is a "slow" finger move - Flick: A "fast" swipe The determining factor is the speed at the end of the gesture (= when lifting the finger up), anything before is irrelevant - Swipe up goes to task switcher - Flick up goes to homescreen directly instead of task switcher - this is suppressed when already on homescreen - it makes no sense there - Note: On Android that is actually mapped to "going to the first page of the home screen if not there already" - I don't care much for that and it can lead to nothing happening if you're already there, I think I prefer the consistency of always opening the task switcher vs a "quick way to get to the main (first) page of the homescreen" - especially since what that means depends a lot on the active home screen. - added orthogonal gesture movement tracking (2-axis gestures) - gesture properly follows finger movement in all directions now making it feel much more responsive and nice - diagonal flick for quick task switch - horizontal only movement (while holding, not releasing) triggers task scrub gesture for scrubbing through larger number of task in the switcher backlog - Complete refactor of state keeping logic, not just in relation to gestures - state keeper fully in one place in C++ except for - a few derived values that are very directly UI related which are kept in `TaskSwitcherHelpers.qml` - and directly touch gesture related state which are kept separate to maybe allow upstreaming the new touch border gesture handling to KWin in the future <details><summary>done TODO items</summary> - [x] currentTaskIndex tracking is majorly broken - [x] old TaskSwitcherState.qml is still around, should be removed - [x] clamping minimum scale for some reason also clamps y position which makes the task not track the finger when moving past the "full activation" point - [x] switching between tasks when task switcher is open is super crap - [x] task switching when switcher is fully open works now, but flicks don't work - you have to fully move at least halfway to the next task for it to "snap" to that task when you let go, there is 0 momentum and I don't know why -> *Flickable is just broken and refuses to flick on touch input, same behavior on master with old implementation, so I reimplemented the same workaround from before* - [x] the gestures don't work until the notification drawer was invoked at least once after every screen geometry change (resolution change, screen rotation etc) - [x] keyboard shortcut for toggling task switcher is kinda hacky right now and feels awful when closing (some delay noticable, maybe to do with animations?) *NOTE: I disabled it for now because the hacky implementation interfered with/created bugs in other parts* - [x] task scrub mode has broken offsets/positions (can scroll past the end of the list, but not reach all elements) when opening task index is not 0 - [x] fast flick velocity threshold is a mostly arbitrary number and I think it also depends on pixel density - ideally we want a mm (or cm or whatever) per ms, not logical pixels per ms </details> # Design decisions I made during development: - Changed the y opening animation from OutBack (with a bounce) to a simple OutExpo (quickly move towards and then approach slowly) as the bouncy look and feel from the OutBack animation felt wrong to me in that place - To fit better with the new docked mode: - the task switcher now shows the screen geometry behind a task that is not fullscreened. This allows to consistently press (and see) the adjacent tasks which might not always be the case if it's a thin window on a landscape screen. - This is not great overall yet - actually it just checks the windows actual aspect ratio, so if it's smaller but same aspect ratio as screen it shows as if it's a full screen task - also it maximizes and centers the window thumbnail in the task switcher so it really isn't ideal, I just don't know what the behavior *should* ideally be. This change at least doesn't break the switcher when in docked mode. - on opening an app from task switcher it doesn't get force-fullscreened anymore - either it already is fullscreen (because fullscreen in docked mode or just not in docked mode) or it should just keep its geometry (this could be gated behind checking if docked mode is on or not, but I think it's fine without) # TODO before merge - [x] IMPORTANT: Because of regular crashing on interaction I've commented out any code that uses WindowFilterModel::data() which seems to be the cause for that. Since master also uses this and experiences these crashes (at least on both dev machines I tested), I don't think this MR necessarily needs to be held up for that issue (especially since it feels like it could be upstream). I removed this to have an easier time with testing my code without constant crashes, but before merging this would need to be put in again as it breaks: skipping windows with "skipSwitcher" flag set, and showing the correct task when opening the switcher in certain situations. - seems to be a bug with WindowFilterModel::data sometimes returning an invalid/null element? But not in C++, it just doesn't make its way to QML. - feels like it could be a timing thing (but maybe not?) when reverting the skipSwitcher filter rule on `tasksModel` *or* adding some lengthy debug console log in `TaskList.qml:minimizeAll()` before trying to access item.window properties it seems to be fine. When keeping skipSwitcher and having no lengthy debug output I get crashes rather reliably every ~3rd to 5th time invoking the task switcher. - While this does seem to be reproducible on master and thus "the same", if it is timing based it may be that my code triggers the error *more often* technically making it a regression (though also easier to track down?) - Interestingly I don't seem to be able to reproduce this on-device, my PinePhone doesn't have this behavior at all. Maybe a bug with nested KWin session? - [ ] task scrub mode may need to have a dynamic amount of items to scrub through based on display size/orientation (maybe keep distance for task scrubbing the same on portrait vs landscape to aid muscle memory)? or instead of using percentages/pixel distances use mm distance based on dpi? - [ ] is task scrub mode even something we want? Since I prefer the "quick switch gesture" only being able to switch between the two most recent windows (because of immediate reordering by recency), this leaves our task switcher in gesture mode with no quick "shortcut gesture" to switch to older tasks, task scrub mode makes this possible in IMO a nice way, but would love input there. - [ ] get rid of all code comments marked with `TODO!` (with an exclamation mark) - [x] One last pass on removing all superfluous console logs, includes and unused functions. I cleaned that up a lot already, but not completely (one std::cout is still left in on purpose until last minute because of a very rare gesture bug I saw twice and I'm not sure if my fix really got it) # Other - I've only ever tested on my laptop with touch screen (ie: effectively a large tablet form factor), if this merges and we get it on nightly I'll definitely try on the PinePhone, there I will closely scrutinize whether the undoYThreshold and task scrub mode number of tasks feels good to use on a small portrait mode display. This may lead to followup MRs to tweak those essentially arbitrarily chosen values. # TODOs for later MRs - [ ] consider moving velocity calculation/generic 2-dimensional gesture tracking to kwin if it's robust and generic enough for that to be useful on their end. (maybe do that later after it has proven itself for a while on our side) - [ ] (optional?) vibration feedback to tell if it goes to taskswitcher or homescreen? android has that (at least mine) with a tight vibration when task switcher is invoked vs homescree - [ ] flick to homescreen animation kinda looks bad - [ ] task sorting by recency - [ ] polish task scrub mode if we intend to keep it - [ ] task scrub mode can "run out of space" for the gesture and thus can only scrub through a maximum number of tasks (currently 8 either direction in my implementation), but we could add a timer if reaching the end that goes through tasks eg: one per second (acceleration?) to "unlock" the full task list - [ ] task scrub mode should have some visual cue when it's activated (eg: fully "opening" the switcher y position, maybe some extra UI with window thumbnails) - [ ] Positioning after screen geometry change (resize, rotation) of the task switcher is kinda broken (task may end off-screen etc) - fixed by interacting with it or re-opening and not a huge issue IMO - [ ] some bound for y position above the "fully opened position" (maybe make it more and more "reluctant" to follow the finger upwards the further up you go - I think that just makes it feel a bit nicer - [ ] make it behave better with docked mode (currently some animations look a bit scuffed) - [ ] make it behave better with multi screen (currently it's mirrored on all screens, we probably only want it on the screen that currently has focus?) - [ ] navbar buttons when not in gesture mode seem to have slightly different button icon sizes than the system wide navbar (is there no better way to add the navbar than to essentially reimplement it?)
2024-05-05 01:17:54 +00:00
} else {
// else dismiss the gesture
root.taskSwitcherHelpers.close();
taskswitcher: enhance gesture with flick speed tracking and orthogonal movement tracking This MR contains work to track the speed with which the taskswitcher gesture has occurred to allow different handling of a "fast flick" (eg: go to homescreen instead of taskswitcher). # Features The center piece of the overhaul is tracking recent velocity (averaged over the last ~50ms) of the gesture to determine behavior: - Swipe: A normal swipe is a "slow" finger move - Flick: A "fast" swipe The determining factor is the speed at the end of the gesture (= when lifting the finger up), anything before is irrelevant - Swipe up goes to task switcher - Flick up goes to homescreen directly instead of task switcher - this is suppressed when already on homescreen - it makes no sense there - Note: On Android that is actually mapped to "going to the first page of the home screen if not there already" - I don't care much for that and it can lead to nothing happening if you're already there, I think I prefer the consistency of always opening the task switcher vs a "quick way to get to the main (first) page of the homescreen" - especially since what that means depends a lot on the active home screen. - added orthogonal gesture movement tracking (2-axis gestures) - gesture properly follows finger movement in all directions now making it feel much more responsive and nice - diagonal flick for quick task switch - horizontal only movement (while holding, not releasing) triggers task scrub gesture for scrubbing through larger number of task in the switcher backlog - Complete refactor of state keeping logic, not just in relation to gestures - state keeper fully in one place in C++ except for - a few derived values that are very directly UI related which are kept in `TaskSwitcherHelpers.qml` - and directly touch gesture related state which are kept separate to maybe allow upstreaming the new touch border gesture handling to KWin in the future <details><summary>done TODO items</summary> - [x] currentTaskIndex tracking is majorly broken - [x] old TaskSwitcherState.qml is still around, should be removed - [x] clamping minimum scale for some reason also clamps y position which makes the task not track the finger when moving past the "full activation" point - [x] switching between tasks when task switcher is open is super crap - [x] task switching when switcher is fully open works now, but flicks don't work - you have to fully move at least halfway to the next task for it to "snap" to that task when you let go, there is 0 momentum and I don't know why -> *Flickable is just broken and refuses to flick on touch input, same behavior on master with old implementation, so I reimplemented the same workaround from before* - [x] the gestures don't work until the notification drawer was invoked at least once after every screen geometry change (resolution change, screen rotation etc) - [x] keyboard shortcut for toggling task switcher is kinda hacky right now and feels awful when closing (some delay noticable, maybe to do with animations?) *NOTE: I disabled it for now because the hacky implementation interfered with/created bugs in other parts* - [x] task scrub mode has broken offsets/positions (can scroll past the end of the list, but not reach all elements) when opening task index is not 0 - [x] fast flick velocity threshold is a mostly arbitrary number and I think it also depends on pixel density - ideally we want a mm (or cm or whatever) per ms, not logical pixels per ms </details> # Design decisions I made during development: - Changed the y opening animation from OutBack (with a bounce) to a simple OutExpo (quickly move towards and then approach slowly) as the bouncy look and feel from the OutBack animation felt wrong to me in that place - To fit better with the new docked mode: - the task switcher now shows the screen geometry behind a task that is not fullscreened. This allows to consistently press (and see) the adjacent tasks which might not always be the case if it's a thin window on a landscape screen. - This is not great overall yet - actually it just checks the windows actual aspect ratio, so if it's smaller but same aspect ratio as screen it shows as if it's a full screen task - also it maximizes and centers the window thumbnail in the task switcher so it really isn't ideal, I just don't know what the behavior *should* ideally be. This change at least doesn't break the switcher when in docked mode. - on opening an app from task switcher it doesn't get force-fullscreened anymore - either it already is fullscreen (because fullscreen in docked mode or just not in docked mode) or it should just keep its geometry (this could be gated behind checking if docked mode is on or not, but I think it's fine without) # TODO before merge - [x] IMPORTANT: Because of regular crashing on interaction I've commented out any code that uses WindowFilterModel::data() which seems to be the cause for that. Since master also uses this and experiences these crashes (at least on both dev machines I tested), I don't think this MR necessarily needs to be held up for that issue (especially since it feels like it could be upstream). I removed this to have an easier time with testing my code without constant crashes, but before merging this would need to be put in again as it breaks: skipping windows with "skipSwitcher" flag set, and showing the correct task when opening the switcher in certain situations. - seems to be a bug with WindowFilterModel::data sometimes returning an invalid/null element? But not in C++, it just doesn't make its way to QML. - feels like it could be a timing thing (but maybe not?) when reverting the skipSwitcher filter rule on `tasksModel` *or* adding some lengthy debug console log in `TaskList.qml:minimizeAll()` before trying to access item.window properties it seems to be fine. When keeping skipSwitcher and having no lengthy debug output I get crashes rather reliably every ~3rd to 5th time invoking the task switcher. - While this does seem to be reproducible on master and thus "the same", if it is timing based it may be that my code triggers the error *more often* technically making it a regression (though also easier to track down?) - Interestingly I don't seem to be able to reproduce this on-device, my PinePhone doesn't have this behavior at all. Maybe a bug with nested KWin session? - [ ] task scrub mode may need to have a dynamic amount of items to scrub through based on display size/orientation (maybe keep distance for task scrubbing the same on portrait vs landscape to aid muscle memory)? or instead of using percentages/pixel distances use mm distance based on dpi? - [ ] is task scrub mode even something we want? Since I prefer the "quick switch gesture" only being able to switch between the two most recent windows (because of immediate reordering by recency), this leaves our task switcher in gesture mode with no quick "shortcut gesture" to switch to older tasks, task scrub mode makes this possible in IMO a nice way, but would love input there. - [ ] get rid of all code comments marked with `TODO!` (with an exclamation mark) - [x] One last pass on removing all superfluous console logs, includes and unused functions. I cleaned that up a lot already, but not completely (one std::cout is still left in on purpose until last minute because of a very rare gesture bug I saw twice and I'm not sure if my fix really got it) # Other - I've only ever tested on my laptop with touch screen (ie: effectively a large tablet form factor), if this merges and we get it on nightly I'll definitely try on the PinePhone, there I will closely scrutinize whether the undoYThreshold and task scrub mode number of tasks feels good to use on a small portrait mode display. This may lead to followup MRs to tweak those essentially arbitrarily chosen values. # TODOs for later MRs - [ ] consider moving velocity calculation/generic 2-dimensional gesture tracking to kwin if it's robust and generic enough for that to be useful on their end. (maybe do that later after it has proven itself for a while on our side) - [ ] (optional?) vibration feedback to tell if it goes to taskswitcher or homescreen? android has that (at least mine) with a tight vibration when task switcher is invoked vs homescree - [ ] flick to homescreen animation kinda looks bad - [ ] task sorting by recency - [ ] polish task scrub mode if we intend to keep it - [ ] task scrub mode can "run out of space" for the gesture and thus can only scrub through a maximum number of tasks (currently 8 either direction in my implementation), but we could add a timer if reaching the end that goes through tasks eg: one per second (acceleration?) to "unlock" the full task list - [ ] task scrub mode should have some visual cue when it's activated (eg: fully "opening" the switcher y position, maybe some extra UI with window thumbnails) - [ ] Positioning after screen geometry change (resize, rotation) of the task switcher is kinda broken (task may end off-screen etc) - fixed by interacting with it or re-opening and not a huge issue IMO - [ ] some bound for y position above the "fully opened position" (maybe make it more and more "reluctant" to follow the finger upwards the further up you go - I think that just makes it feel a bit nicer - [ ] make it behave better with docked mode (currently some animations look a bit scuffed) - [ ] make it behave better with multi screen (currently it's mirrored on all screens, we probably only want it on the screen that currently has focus?) - [ ] navbar buttons when not in gesture mode seem to have slightly different button icon sizes than the system wide navbar (is there no better way to add the navbar than to essentially reimplement it?)
2024-05-05 01:17:54 +00:00
}
} else if (root.taskSwitcherHelpers.gestureState == TaskSwitcherHelpers.GestureStates.HorizontalSwipe) {
// sideways flick
root.backgroundColorOpacity = 1;
quickSwitch();
} else if (root.taskSwitcherHelpers.gestureState == TaskSwitcherHelpers.GestureStates.TaskSwitcher) {
// open the task drawer
root.backgroundColorOpacity = 1;
root.taskSwitcherHelpers.animateGoToTaskIndex(root.state.currentTaskIndex);
root.taskSwitcherHelpers.open();
} else if (root.taskSwitcherHelpers.gestureState == TaskSwitcherHelpers.GestureStates.Home) {
root.taskSwitcherHelpers.close();
2023-03-06 06:38:43 +00:00
}
}
taskswitcher: enhance gesture with flick speed tracking and orthogonal movement tracking This MR contains work to track the speed with which the taskswitcher gesture has occurred to allow different handling of a "fast flick" (eg: go to homescreen instead of taskswitcher). # Features The center piece of the overhaul is tracking recent velocity (averaged over the last ~50ms) of the gesture to determine behavior: - Swipe: A normal swipe is a "slow" finger move - Flick: A "fast" swipe The determining factor is the speed at the end of the gesture (= when lifting the finger up), anything before is irrelevant - Swipe up goes to task switcher - Flick up goes to homescreen directly instead of task switcher - this is suppressed when already on homescreen - it makes no sense there - Note: On Android that is actually mapped to "going to the first page of the home screen if not there already" - I don't care much for that and it can lead to nothing happening if you're already there, I think I prefer the consistency of always opening the task switcher vs a "quick way to get to the main (first) page of the homescreen" - especially since what that means depends a lot on the active home screen. - added orthogonal gesture movement tracking (2-axis gestures) - gesture properly follows finger movement in all directions now making it feel much more responsive and nice - diagonal flick for quick task switch - horizontal only movement (while holding, not releasing) triggers task scrub gesture for scrubbing through larger number of task in the switcher backlog - Complete refactor of state keeping logic, not just in relation to gestures - state keeper fully in one place in C++ except for - a few derived values that are very directly UI related which are kept in `TaskSwitcherHelpers.qml` - and directly touch gesture related state which are kept separate to maybe allow upstreaming the new touch border gesture handling to KWin in the future <details><summary>done TODO items</summary> - [x] currentTaskIndex tracking is majorly broken - [x] old TaskSwitcherState.qml is still around, should be removed - [x] clamping minimum scale for some reason also clamps y position which makes the task not track the finger when moving past the "full activation" point - [x] switching between tasks when task switcher is open is super crap - [x] task switching when switcher is fully open works now, but flicks don't work - you have to fully move at least halfway to the next task for it to "snap" to that task when you let go, there is 0 momentum and I don't know why -> *Flickable is just broken and refuses to flick on touch input, same behavior on master with old implementation, so I reimplemented the same workaround from before* - [x] the gestures don't work until the notification drawer was invoked at least once after every screen geometry change (resolution change, screen rotation etc) - [x] keyboard shortcut for toggling task switcher is kinda hacky right now and feels awful when closing (some delay noticable, maybe to do with animations?) *NOTE: I disabled it for now because the hacky implementation interfered with/created bugs in other parts* - [x] task scrub mode has broken offsets/positions (can scroll past the end of the list, but not reach all elements) when opening task index is not 0 - [x] fast flick velocity threshold is a mostly arbitrary number and I think it also depends on pixel density - ideally we want a mm (or cm or whatever) per ms, not logical pixels per ms </details> # Design decisions I made during development: - Changed the y opening animation from OutBack (with a bounce) to a simple OutExpo (quickly move towards and then approach slowly) as the bouncy look and feel from the OutBack animation felt wrong to me in that place - To fit better with the new docked mode: - the task switcher now shows the screen geometry behind a task that is not fullscreened. This allows to consistently press (and see) the adjacent tasks which might not always be the case if it's a thin window on a landscape screen. - This is not great overall yet - actually it just checks the windows actual aspect ratio, so if it's smaller but same aspect ratio as screen it shows as if it's a full screen task - also it maximizes and centers the window thumbnail in the task switcher so it really isn't ideal, I just don't know what the behavior *should* ideally be. This change at least doesn't break the switcher when in docked mode. - on opening an app from task switcher it doesn't get force-fullscreened anymore - either it already is fullscreen (because fullscreen in docked mode or just not in docked mode) or it should just keep its geometry (this could be gated behind checking if docked mode is on or not, but I think it's fine without) # TODO before merge - [x] IMPORTANT: Because of regular crashing on interaction I've commented out any code that uses WindowFilterModel::data() which seems to be the cause for that. Since master also uses this and experiences these crashes (at least on both dev machines I tested), I don't think this MR necessarily needs to be held up for that issue (especially since it feels like it could be upstream). I removed this to have an easier time with testing my code without constant crashes, but before merging this would need to be put in again as it breaks: skipping windows with "skipSwitcher" flag set, and showing the correct task when opening the switcher in certain situations. - seems to be a bug with WindowFilterModel::data sometimes returning an invalid/null element? But not in C++, it just doesn't make its way to QML. - feels like it could be a timing thing (but maybe not?) when reverting the skipSwitcher filter rule on `tasksModel` *or* adding some lengthy debug console log in `TaskList.qml:minimizeAll()` before trying to access item.window properties it seems to be fine. When keeping skipSwitcher and having no lengthy debug output I get crashes rather reliably every ~3rd to 5th time invoking the task switcher. - While this does seem to be reproducible on master and thus "the same", if it is timing based it may be that my code triggers the error *more often* technically making it a regression (though also easier to track down?) - Interestingly I don't seem to be able to reproduce this on-device, my PinePhone doesn't have this behavior at all. Maybe a bug with nested KWin session? - [ ] task scrub mode may need to have a dynamic amount of items to scrub through based on display size/orientation (maybe keep distance for task scrubbing the same on portrait vs landscape to aid muscle memory)? or instead of using percentages/pixel distances use mm distance based on dpi? - [ ] is task scrub mode even something we want? Since I prefer the "quick switch gesture" only being able to switch between the two most recent windows (because of immediate reordering by recency), this leaves our task switcher in gesture mode with no quick "shortcut gesture" to switch to older tasks, task scrub mode makes this possible in IMO a nice way, but would love input there. - [ ] get rid of all code comments marked with `TODO!` (with an exclamation mark) - [x] One last pass on removing all superfluous console logs, includes and unused functions. I cleaned that up a lot already, but not completely (one std::cout is still left in on purpose until last minute because of a very rare gesture bug I saw twice and I'm not sure if my fix really got it) # Other - I've only ever tested on my laptop with touch screen (ie: effectively a large tablet form factor), if this merges and we get it on nightly I'll definitely try on the PinePhone, there I will closely scrutinize whether the undoYThreshold and task scrub mode number of tasks feels good to use on a small portrait mode display. This may lead to followup MRs to tweak those essentially arbitrarily chosen values. # TODOs for later MRs - [ ] consider moving velocity calculation/generic 2-dimensional gesture tracking to kwin if it's robust and generic enough for that to be useful on their end. (maybe do that later after it has proven itself for a while on our side) - [ ] (optional?) vibration feedback to tell if it goes to taskswitcher or homescreen? android has that (at least mine) with a tight vibration when task switcher is invoked vs homescree - [ ] flick to homescreen animation kinda looks bad - [ ] task sorting by recency - [ ] polish task scrub mode if we intend to keep it - [ ] task scrub mode can "run out of space" for the gesture and thus can only scrub through a maximum number of tasks (currently 8 either direction in my implementation), but we could add a timer if reaching the end that goes through tasks eg: one per second (acceleration?) to "unlock" the full task list - [ ] task scrub mode should have some visual cue when it's activated (eg: fully "opening" the switcher y position, maybe some extra UI with window thumbnails) - [ ] Positioning after screen geometry change (resize, rotation) of the task switcher is kinda broken (task may end off-screen etc) - fixed by interacting with it or re-opening and not a huge issue IMO - [ ] some bound for y position above the "fully opened position" (maybe make it more and more "reluctant" to follow the finger upwards the further up you go - I think that just makes it feel a bit nicer - [ ] make it behave better with docked mode (currently some animations look a bit scuffed) - [ ] make it behave better with multi screen (currently it's mirrored on all screens, we probably only want it on the screen that currently has focus?) - [ ] navbar buttons when not in gesture mode seem to have slightly different button icon sizes than the system wide navbar (is there no better way to add the navbar than to essentially reimplement it?)
2024-05-05 01:17:54 +00:00
function onVelocityChanged(): void {
}
function onXPositionChanged(): void {
root.taskSwitcherHelpers.updateTaskIndex();
taskswitcher: enhance gesture with flick speed tracking and orthogonal movement tracking This MR contains work to track the speed with which the taskswitcher gesture has occurred to allow different handling of a "fast flick" (eg: go to homescreen instead of taskswitcher). # Features The center piece of the overhaul is tracking recent velocity (averaged over the last ~50ms) of the gesture to determine behavior: - Swipe: A normal swipe is a "slow" finger move - Flick: A "fast" swipe The determining factor is the speed at the end of the gesture (= when lifting the finger up), anything before is irrelevant - Swipe up goes to task switcher - Flick up goes to homescreen directly instead of task switcher - this is suppressed when already on homescreen - it makes no sense there - Note: On Android that is actually mapped to "going to the first page of the home screen if not there already" - I don't care much for that and it can lead to nothing happening if you're already there, I think I prefer the consistency of always opening the task switcher vs a "quick way to get to the main (first) page of the homescreen" - especially since what that means depends a lot on the active home screen. - added orthogonal gesture movement tracking (2-axis gestures) - gesture properly follows finger movement in all directions now making it feel much more responsive and nice - diagonal flick for quick task switch - horizontal only movement (while holding, not releasing) triggers task scrub gesture for scrubbing through larger number of task in the switcher backlog - Complete refactor of state keeping logic, not just in relation to gestures - state keeper fully in one place in C++ except for - a few derived values that are very directly UI related which are kept in `TaskSwitcherHelpers.qml` - and directly touch gesture related state which are kept separate to maybe allow upstreaming the new touch border gesture handling to KWin in the future <details><summary>done TODO items</summary> - [x] currentTaskIndex tracking is majorly broken - [x] old TaskSwitcherState.qml is still around, should be removed - [x] clamping minimum scale for some reason also clamps y position which makes the task not track the finger when moving past the "full activation" point - [x] switching between tasks when task switcher is open is super crap - [x] task switching when switcher is fully open works now, but flicks don't work - you have to fully move at least halfway to the next task for it to "snap" to that task when you let go, there is 0 momentum and I don't know why -> *Flickable is just broken and refuses to flick on touch input, same behavior on master with old implementation, so I reimplemented the same workaround from before* - [x] the gestures don't work until the notification drawer was invoked at least once after every screen geometry change (resolution change, screen rotation etc) - [x] keyboard shortcut for toggling task switcher is kinda hacky right now and feels awful when closing (some delay noticable, maybe to do with animations?) *NOTE: I disabled it for now because the hacky implementation interfered with/created bugs in other parts* - [x] task scrub mode has broken offsets/positions (can scroll past the end of the list, but not reach all elements) when opening task index is not 0 - [x] fast flick velocity threshold is a mostly arbitrary number and I think it also depends on pixel density - ideally we want a mm (or cm or whatever) per ms, not logical pixels per ms </details> # Design decisions I made during development: - Changed the y opening animation from OutBack (with a bounce) to a simple OutExpo (quickly move towards and then approach slowly) as the bouncy look and feel from the OutBack animation felt wrong to me in that place - To fit better with the new docked mode: - the task switcher now shows the screen geometry behind a task that is not fullscreened. This allows to consistently press (and see) the adjacent tasks which might not always be the case if it's a thin window on a landscape screen. - This is not great overall yet - actually it just checks the windows actual aspect ratio, so if it's smaller but same aspect ratio as screen it shows as if it's a full screen task - also it maximizes and centers the window thumbnail in the task switcher so it really isn't ideal, I just don't know what the behavior *should* ideally be. This change at least doesn't break the switcher when in docked mode. - on opening an app from task switcher it doesn't get force-fullscreened anymore - either it already is fullscreen (because fullscreen in docked mode or just not in docked mode) or it should just keep its geometry (this could be gated behind checking if docked mode is on or not, but I think it's fine without) # TODO before merge - [x] IMPORTANT: Because of regular crashing on interaction I've commented out any code that uses WindowFilterModel::data() which seems to be the cause for that. Since master also uses this and experiences these crashes (at least on both dev machines I tested), I don't think this MR necessarily needs to be held up for that issue (especially since it feels like it could be upstream). I removed this to have an easier time with testing my code without constant crashes, but before merging this would need to be put in again as it breaks: skipping windows with "skipSwitcher" flag set, and showing the correct task when opening the switcher in certain situations. - seems to be a bug with WindowFilterModel::data sometimes returning an invalid/null element? But not in C++, it just doesn't make its way to QML. - feels like it could be a timing thing (but maybe not?) when reverting the skipSwitcher filter rule on `tasksModel` *or* adding some lengthy debug console log in `TaskList.qml:minimizeAll()` before trying to access item.window properties it seems to be fine. When keeping skipSwitcher and having no lengthy debug output I get crashes rather reliably every ~3rd to 5th time invoking the task switcher. - While this does seem to be reproducible on master and thus "the same", if it is timing based it may be that my code triggers the error *more often* technically making it a regression (though also easier to track down?) - Interestingly I don't seem to be able to reproduce this on-device, my PinePhone doesn't have this behavior at all. Maybe a bug with nested KWin session? - [ ] task scrub mode may need to have a dynamic amount of items to scrub through based on display size/orientation (maybe keep distance for task scrubbing the same on portrait vs landscape to aid muscle memory)? or instead of using percentages/pixel distances use mm distance based on dpi? - [ ] is task scrub mode even something we want? Since I prefer the "quick switch gesture" only being able to switch between the two most recent windows (because of immediate reordering by recency), this leaves our task switcher in gesture mode with no quick "shortcut gesture" to switch to older tasks, task scrub mode makes this possible in IMO a nice way, but would love input there. - [ ] get rid of all code comments marked with `TODO!` (with an exclamation mark) - [x] One last pass on removing all superfluous console logs, includes and unused functions. I cleaned that up a lot already, but not completely (one std::cout is still left in on purpose until last minute because of a very rare gesture bug I saw twice and I'm not sure if my fix really got it) # Other - I've only ever tested on my laptop with touch screen (ie: effectively a large tablet form factor), if this merges and we get it on nightly I'll definitely try on the PinePhone, there I will closely scrutinize whether the undoYThreshold and task scrub mode number of tasks feels good to use on a small portrait mode display. This may lead to followup MRs to tweak those essentially arbitrarily chosen values. # TODOs for later MRs - [ ] consider moving velocity calculation/generic 2-dimensional gesture tracking to kwin if it's robust and generic enough for that to be useful on their end. (maybe do that later after it has proven itself for a while on our side) - [ ] (optional?) vibration feedback to tell if it goes to taskswitcher or homescreen? android has that (at least mine) with a tight vibration when task switcher is invoked vs homescree - [ ] flick to homescreen animation kinda looks bad - [ ] task sorting by recency - [ ] polish task scrub mode if we intend to keep it - [ ] task scrub mode can "run out of space" for the gesture and thus can only scrub through a maximum number of tasks (currently 8 either direction in my implementation), but we could add a timer if reaching the end that goes through tasks eg: one per second (acceleration?) to "unlock" the full task list - [ ] task scrub mode should have some visual cue when it's activated (eg: fully "opening" the switcher y position, maybe some extra UI with window thumbnails) - [ ] Positioning after screen geometry change (resize, rotation) of the task switcher is kinda broken (task may end off-screen etc) - fixed by interacting with it or re-opening and not a huge issue IMO - [ ] some bound for y position above the "fully opened position" (maybe make it more and more "reluctant" to follow the finger upwards the further up you go - I think that just makes it feel a bit nicer - [ ] make it behave better with docked mode (currently some animations look a bit scuffed) - [ ] make it behave better with multi screen (currently it's mirrored on all screens, we probably only want it on the screen that currently has focus?) - [ ] navbar buttons when not in gesture mode seem to have slightly different button icon sizes than the system wide navbar (is there no better way to add the navbar than to essentially reimplement it?)
2024-05-05 01:17:54 +00:00
}
2023-03-06 06:38:43 +00:00
}
// kind of a hack, but this prevents the gesture from immediately activting the task switcher when it is not supposed to
Timer {
id: taskSwitchCanLaunchTimer
interval: 1; running: true; repeat: false
onTriggered: root.taskSwitcherHelpers.taskSwitchCanLaunch = true;
}
function setTaskDrawerState(value: int): void {
if (taskSwitcherHelpers.gestureState != TaskSwitcherHelpers.GestureStates.TaskSwitcher && value == TaskSwitcherHelpers.GestureStates.TaskSwitcher) {
// vibrate only if switching to task drawer
if (!taskSwitcherHelpers.hasVibrated) {
// Haptic feedback when the task scrub mode engages
haptics.buttonVibrate();
taskSwitcherHelpers.hasVibrated = true;
}
}
taskSwitcherHelpers.gestureState = value;
}
// view of the desktop background
2023-03-06 06:38:43 +00:00
KWinComponents.DesktopBackground {
id: backgroundItem
activity: KWinComponents.Workspace.currentActivity
desktop: KWinComponents.Workspace.currentDesktop
outputName: root.targetScreen.name
2023-03-06 06:38:43 +00:00
}
// background colour
Rectangle {
id: backgroundRect
anchors.fill: root
2023-03-06 06:38:43 +00:00
opacity: container.opacity
color: {
return Qt.rgba(0, 0, 0, 0.6 * root.taskSwitcherHelpers.closingFactor * root.backgroundColorOpacity);
}
}
// animate the background opacity based off of the state.
property real backgroundColorOpacity: 1
Behavior on backgroundColorOpacity {
id: backgroundColorOpacityAn
NumberAnimation {
duration: Kirigami.Units.longDuration
2023-03-06 06:38:43 +00:00
}
}
// status bar
// TODO: improve load times, it is quite slow
// MobileShell.StatusBar {
// id: statusBar
// z: 1
// colorGroup: Kirigami.Theme.ComplementaryColorGroup
// backgroundColor: "transparent"
//
// height: root.topMargin
// anchors.top: parent.top
// anchors.left: parent.left
// anchors.right: parent.right
// }
// navigation panel
MobileShell.NavigationPanel {
id: navigationPanel
z: root.taskSwitcherHelpers.taskDrawerOpened && !root.taskSwitcherHelpers.currentlyBeingClosed ? 1 : 0
visible: ShellSettings.Settings.navigationPanelEnabled
backgroundColor: Qt.rgba(0, 0, 0, 0.1)
foregroundColorGroup: Kirigami.Theme.Complementary
shadow: false
isVertical: MobileShell.Constants.navigationPanelOnSide(root.width, root.height)
leftAction: MobileShell.NavigationPanelAction {
enabled: true
iconSource: "mobile-task-switcher"
iconSizeFactor: 0.75
onTriggered: {
if (taskList.count === 0) {
root.hide();
} else {
if (taskList.count > 1 &&
root.state.elapsedTimeSinceStart != -1 &&
root.state.elapsedTimeSinceStart < root.state.doubleClickInterval) {
root.taskSwitcherHelpers.openApp(1);
return;
}
const currentIndex = root.state.currentTaskIndex;
root.taskSwitcherHelpers.openApp(root.state.currentTaskIndex);
}
}
}
// home button
middleAction: MobileShell.NavigationPanelAction {
enabled: true
iconSource: "start-here-kde"
iconSizeFactor: 1
onTriggered: root.hide()
}
// close app/keyboard button
rightAction: MobileShell.NavigationPanelAction {
enabled: true
iconSource: "mobile-close-app"
iconSizeFactor: 0.75
onTriggered: {
taskList.getTaskAt(root.state.currentTaskIndex).closeApp();
}
}
rightCornerAction: MobileShell.NavigationPanelAction {
visible: false
}
}
states: [
State {
name: "landscape"
when: MobileShell.Constants.navigationPanelOnSide(root.width, root.height)
AnchorChanges {
target: navigationPanel
anchors {
right: root.right
top: root.top
bottom: root.bottom
left: undefined
}
}
PropertyChanges {
target: navigationPanel
width: navRightMargin
anchors.topMargin: root.topMargin
}
},
State {
name: "portrait"
when: !MobileShell.Constants.navigationPanelOnSide(root.width, root.height)
AnchorChanges {
target: navigationPanel
anchors {
top: undefined
right: root.right
left: root.left
bottom: root.bottom
}
}
PropertyChanges {
target: navigationPanel
height: navBottomMargin
}
}
]
// task list
2023-03-06 06:38:43 +00:00
Item {
id: container
// provide shell margins
anchors.fill: root
2023-03-06 06:38:43 +00:00
anchors.leftMargin: root.leftMargin
anchors.rightMargin: root.rightMargin
anchors.bottomMargin: root.bottomMargin
anchors.topMargin: root.topMargin
NumberAnimation on opacity {
id: closeAnim
running: false
to: 0
duration: 200
easing.type: Easing.InOutQuad
onFinished: {
closeAllButton.closeRequested = false;
}
}
// placeholder message
ColumnLayout {
id: placeholder
spacing: Kirigami.Units.gridUnit
opacity: {
let baseOpacity = ((root.tasksCount === 0 && !root.taskSwitcherHelpers.currentlyBeingClosed) ? 0.9 : 0);
return root.taskSwitcherHelpers.gestureState == TaskSwitcherHelpers.GestureStates.TaskSwitcher ? baseOpacity : 0;
}
2023-03-06 06:38:43 +00:00
Behavior on opacity { NumberAnimation { duration: 500 } }
anchors.centerIn: container
2023-03-06 06:38:43 +00:00
Kirigami.Icon {
2023-03-06 06:38:43 +00:00
id: icon
Layout.alignment: Qt.AlignHCenter
implicitWidth: Kirigami.Units.iconSizes.large
implicitHeight: Kirigami.Units.iconSizes.large
source: "edit-none-symbolic"
color: "white"
2023-03-06 06:38:43 +00:00
}
Kirigami.Heading {
2023-03-06 06:38:43 +00:00
Layout.fillWidth: true
Layout.maximumWidth: root.width * 0.75
Layout.alignment: Qt.AlignHCenter
color: "white"
level: 3
wrapMode: Text.Wrap
horizontalAlignment: Text.AlignHCenter
text: i18n("No applications are running.")
}
}
2024-06-01 23:46:03 +00:00
RowLayout {
id: scrubIconList
opacity: root.taskSwitcherHelpers.isInTaskScrubMode ? 1 : 0
2024-06-01 23:46:03 +00:00
Behavior on opacity { NumberAnimation { duration: Kirigami.Units.longDuration } }
anchors.bottom: container.bottom
anchors.right: container.horizontalCenter
anchors.bottomMargin: root.taskSwitcherHelpers.scrubModeBottomMargin
2024-06-01 23:46:03 +00:00
anchors.rightMargin: {
2024-06-01 23:46:03 +00:00
let size = Kirigami.Units.iconSizes.large + Kirigami.Units.largeSpacing * 2;
let offset = (root.state.currentTaskIndex + 0.5) * size;
return -offset;
2024-06-01 23:46:03 +00:00
}
Behavior on anchors.rightMargin {
2024-06-01 23:46:03 +00:00
NumberAnimation {
duration: root.taskSwitcherHelpers.xAnimDuration;
easing.type: root.taskSwitcherHelpers.xAnimEasingType;
2024-06-01 23:46:03 +00:00
}
}
spacing: Kirigami.Units.largeSpacing * 2
layoutDirection: Qt.RightToLeft
Repeater {
model: root.tasksModel
delegate: Kirigami.Icon {
id: iconDelegate
required property QtObject window
required property int index
readonly property bool isCenteredIcon: iconDelegate.index === root.state.currentTaskIndex;
Layout.preferredHeight: isCenteredIcon ? Kirigami.Units.iconSizes.huge : Kirigami.Units.iconSizes.large
Layout.preferredWidth: isCenteredIcon ? Kirigami.Units.iconSizes.huge : Kirigami.Units.iconSizes.large
Layout.alignment: Qt.AlignVCenter
source: iconDelegate.window.icon
}
}
}
RowLayout {
id: scrubIndicator
opacity: root.taskSwitcherHelpers.isInTaskScrubMode ? 1 : 0
2024-06-01 23:46:03 +00:00
Behavior on opacity { NumberAnimation { duration: 200 } }
anchors.bottom: container.bottom
anchors.horizontalCenter: container.horizontalCenter
anchors.bottomMargin: root.taskSwitcherHelpers.openedYPosition * 1 / 4
Kirigami.Icon {
id: iconScrubBack
opacity: root.state.currentTaskIndex == 0 ? 0.3 : 1
2024-06-01 23:46:03 +00:00
Behavior on opacity { NumberAnimation { duration: Kirigami.Units.longDuration * 2; easing.type: Easing.OutExpo } }
Layout.alignment: Qt.AlignHCenter
implicitWidth: Kirigami.Units.iconSizes.medium
implicitHeight: Kirigami.Units.iconSizes.medium
source: "draw-arrow-back"
color: "white"
}
Item {
width: root.taskSwitcherHelpers.windowWidth / 4
}
Kirigami.Icon {
id: iconScrubFront
opacity: root.state.currentTaskIndex == root.tasksCount - 1 ? 0.3 : 1
2024-06-01 23:46:03 +00:00
Behavior on opacity { NumberAnimation { duration: Kirigami.Units.longDuration * 2; easing.type: Easing.OutExpo } }
Layout.alignment: Qt.AlignHCenter
implicitWidth: Kirigami.Units.iconSizes.medium
implicitHeight: Kirigami.Units.iconSizes.medium
source: "draw-arrow-forward"
color: "white"
}
}
2023-03-06 06:38:43 +00:00
// flicking area for task switcher
FlickContainer {
id: flickable
anchors.fill: container
2023-03-06 06:38:43 +00:00
taskswitcher: enhance gesture with flick speed tracking and orthogonal movement tracking This MR contains work to track the speed with which the taskswitcher gesture has occurred to allow different handling of a "fast flick" (eg: go to homescreen instead of taskswitcher). # Features The center piece of the overhaul is tracking recent velocity (averaged over the last ~50ms) of the gesture to determine behavior: - Swipe: A normal swipe is a "slow" finger move - Flick: A "fast" swipe The determining factor is the speed at the end of the gesture (= when lifting the finger up), anything before is irrelevant - Swipe up goes to task switcher - Flick up goes to homescreen directly instead of task switcher - this is suppressed when already on homescreen - it makes no sense there - Note: On Android that is actually mapped to "going to the first page of the home screen if not there already" - I don't care much for that and it can lead to nothing happening if you're already there, I think I prefer the consistency of always opening the task switcher vs a "quick way to get to the main (first) page of the homescreen" - especially since what that means depends a lot on the active home screen. - added orthogonal gesture movement tracking (2-axis gestures) - gesture properly follows finger movement in all directions now making it feel much more responsive and nice - diagonal flick for quick task switch - horizontal only movement (while holding, not releasing) triggers task scrub gesture for scrubbing through larger number of task in the switcher backlog - Complete refactor of state keeping logic, not just in relation to gestures - state keeper fully in one place in C++ except for - a few derived values that are very directly UI related which are kept in `TaskSwitcherHelpers.qml` - and directly touch gesture related state which are kept separate to maybe allow upstreaming the new touch border gesture handling to KWin in the future <details><summary>done TODO items</summary> - [x] currentTaskIndex tracking is majorly broken - [x] old TaskSwitcherState.qml is still around, should be removed - [x] clamping minimum scale for some reason also clamps y position which makes the task not track the finger when moving past the "full activation" point - [x] switching between tasks when task switcher is open is super crap - [x] task switching when switcher is fully open works now, but flicks don't work - you have to fully move at least halfway to the next task for it to "snap" to that task when you let go, there is 0 momentum and I don't know why -> *Flickable is just broken and refuses to flick on touch input, same behavior on master with old implementation, so I reimplemented the same workaround from before* - [x] the gestures don't work until the notification drawer was invoked at least once after every screen geometry change (resolution change, screen rotation etc) - [x] keyboard shortcut for toggling task switcher is kinda hacky right now and feels awful when closing (some delay noticable, maybe to do with animations?) *NOTE: I disabled it for now because the hacky implementation interfered with/created bugs in other parts* - [x] task scrub mode has broken offsets/positions (can scroll past the end of the list, but not reach all elements) when opening task index is not 0 - [x] fast flick velocity threshold is a mostly arbitrary number and I think it also depends on pixel density - ideally we want a mm (or cm or whatever) per ms, not logical pixels per ms </details> # Design decisions I made during development: - Changed the y opening animation from OutBack (with a bounce) to a simple OutExpo (quickly move towards and then approach slowly) as the bouncy look and feel from the OutBack animation felt wrong to me in that place - To fit better with the new docked mode: - the task switcher now shows the screen geometry behind a task that is not fullscreened. This allows to consistently press (and see) the adjacent tasks which might not always be the case if it's a thin window on a landscape screen. - This is not great overall yet - actually it just checks the windows actual aspect ratio, so if it's smaller but same aspect ratio as screen it shows as if it's a full screen task - also it maximizes and centers the window thumbnail in the task switcher so it really isn't ideal, I just don't know what the behavior *should* ideally be. This change at least doesn't break the switcher when in docked mode. - on opening an app from task switcher it doesn't get force-fullscreened anymore - either it already is fullscreen (because fullscreen in docked mode or just not in docked mode) or it should just keep its geometry (this could be gated behind checking if docked mode is on or not, but I think it's fine without) # TODO before merge - [x] IMPORTANT: Because of regular crashing on interaction I've commented out any code that uses WindowFilterModel::data() which seems to be the cause for that. Since master also uses this and experiences these crashes (at least on both dev machines I tested), I don't think this MR necessarily needs to be held up for that issue (especially since it feels like it could be upstream). I removed this to have an easier time with testing my code without constant crashes, but before merging this would need to be put in again as it breaks: skipping windows with "skipSwitcher" flag set, and showing the correct task when opening the switcher in certain situations. - seems to be a bug with WindowFilterModel::data sometimes returning an invalid/null element? But not in C++, it just doesn't make its way to QML. - feels like it could be a timing thing (but maybe not?) when reverting the skipSwitcher filter rule on `tasksModel` *or* adding some lengthy debug console log in `TaskList.qml:minimizeAll()` before trying to access item.window properties it seems to be fine. When keeping skipSwitcher and having no lengthy debug output I get crashes rather reliably every ~3rd to 5th time invoking the task switcher. - While this does seem to be reproducible on master and thus "the same", if it is timing based it may be that my code triggers the error *more often* technically making it a regression (though also easier to track down?) - Interestingly I don't seem to be able to reproduce this on-device, my PinePhone doesn't have this behavior at all. Maybe a bug with nested KWin session? - [ ] task scrub mode may need to have a dynamic amount of items to scrub through based on display size/orientation (maybe keep distance for task scrubbing the same on portrait vs landscape to aid muscle memory)? or instead of using percentages/pixel distances use mm distance based on dpi? - [ ] is task scrub mode even something we want? Since I prefer the "quick switch gesture" only being able to switch between the two most recent windows (because of immediate reordering by recency), this leaves our task switcher in gesture mode with no quick "shortcut gesture" to switch to older tasks, task scrub mode makes this possible in IMO a nice way, but would love input there. - [ ] get rid of all code comments marked with `TODO!` (with an exclamation mark) - [x] One last pass on removing all superfluous console logs, includes and unused functions. I cleaned that up a lot already, but not completely (one std::cout is still left in on purpose until last minute because of a very rare gesture bug I saw twice and I'm not sure if my fix really got it) # Other - I've only ever tested on my laptop with touch screen (ie: effectively a large tablet form factor), if this merges and we get it on nightly I'll definitely try on the PinePhone, there I will closely scrutinize whether the undoYThreshold and task scrub mode number of tasks feels good to use on a small portrait mode display. This may lead to followup MRs to tweak those essentially arbitrarily chosen values. # TODOs for later MRs - [ ] consider moving velocity calculation/generic 2-dimensional gesture tracking to kwin if it's robust and generic enough for that to be useful on their end. (maybe do that later after it has proven itself for a while on our side) - [ ] (optional?) vibration feedback to tell if it goes to taskswitcher or homescreen? android has that (at least mine) with a tight vibration when task switcher is invoked vs homescree - [ ] flick to homescreen animation kinda looks bad - [ ] task sorting by recency - [ ] polish task scrub mode if we intend to keep it - [ ] task scrub mode can "run out of space" for the gesture and thus can only scrub through a maximum number of tasks (currently 8 either direction in my implementation), but we could add a timer if reaching the end that goes through tasks eg: one per second (acceleration?) to "unlock" the full task list - [ ] task scrub mode should have some visual cue when it's activated (eg: fully "opening" the switcher y position, maybe some extra UI with window thumbnails) - [ ] Positioning after screen geometry change (resize, rotation) of the task switcher is kinda broken (task may end off-screen etc) - fixed by interacting with it or re-opening and not a huge issue IMO - [ ] some bound for y position above the "fully opened position" (maybe make it more and more "reluctant" to follow the finger upwards the further up you go - I think that just makes it feel a bit nicer - [ ] make it behave better with docked mode (currently some animations look a bit scuffed) - [ ] make it behave better with multi screen (currently it's mirrored on all screens, we probably only want it on the screen that currently has focus?) - [ ] navbar buttons when not in gesture mode seem to have slightly different button icon sizes than the system wide navbar (is there no better way to add the navbar than to essentially reimplement it?)
2024-05-05 01:17:54 +00:00
taskSwitcherState: root.state
taskSwitcherHelpers: root.taskSwitcherHelpers
tasksCount: root.tasksCount
2023-03-06 06:38:43 +00:00
// don't allow FlickContainer to steal from swiping on tasks
interactive: taskList.taskInteractingCount === 0
2023-03-06 06:38:43 +00:00
// the item is effectively anchored to the flickable bounds
TaskList {
id: taskList
taskSwitcher: root
shellTopMargin: root.topMargin
shellBottomMargin: root.bottomMargin
x: flickable.contentX
width: flickable.width
height: flickable.height
}
2023-03-06 06:38:43 +00:00
PlasmaComponents.ToolButton {
id: closeAllButton
property bool closeRequested: false
visible: root.tasksCount !== 0 && !root.taskSwitcherHelpers.isInTaskScrubMode
enabled: !root.taskSwitcherHelpers.currentlyBeingClosed && !root.state.gestureInProgress
2023-03-06 06:38:43 +00:00
Kirigami.Theme.inherit: false
Kirigami.Theme.colorSet: Kirigami.Theme.Complementary
anchors {
bottom: taskList.bottom
bottomMargin: (taskList.taskYBase) * 0.75
horizontalCenter: taskList.horizontalCenter
}
2023-03-06 06:38:43 +00:00
opacity: (root.taskSwitcherHelpers.currentlyBeingClosed || root.state.gestureInProgress || !root.taskSwitcherHelpers.taskDrawerOpened) ? 0.0 : 1.0
Behavior on opacity { NumberAnimation { duration: Kirigami.Units.shortDuration } }
2023-03-06 06:38:43 +00:00
icon.name: "edit-clear-history"
font.bold: true
2023-03-06 06:38:43 +00:00
text: closeRequested ? i18n("Confirm Close All") : i18n("Close All")
2023-03-06 06:38:43 +00:00
onClicked: {
if (closeRequested) {
taskList.closeAll();
} else {
closeRequested = true;
2023-03-06 06:38:43 +00:00
}
}
}
}
}
}