the app scales into multitasking; pill has two destinations
This commit is contained in:
parent
277a0d2b32
commit
0e7dec53d1
3 changed files with 97 additions and 0 deletions
|
|
@ -273,6 +273,12 @@ PanelWindow {
|
|||
// Square one. `goHome` clears multitasking, the overview, the
|
||||
// dock and the OSK before moving, so the zone is not arrived at
|
||||
// with the last screen's furniture still up.
|
||||
//
|
||||
// The pose is released here rather than on arrival: home is a
|
||||
// different zone, and a window left at 0.6 on the zone behind
|
||||
// you is one you would find shrunken next time you swiped back
|
||||
// to it, with no gesture in flight to explain why.
|
||||
ViewtopControl.clearPose()
|
||||
goHome()
|
||||
shortSwipes = 0
|
||||
return
|
||||
|
|
@ -282,6 +288,11 @@ PanelWindow {
|
|||
// belongs to zone one and is shown by being *there*, not by a
|
||||
// gesture that reveals it over whatever else is on screen.
|
||||
GlobalStates.missionControlOpen = !GlobalStates.missionControlOpen
|
||||
// Multitasking draws its own cards over the scene, so the live
|
||||
// windows go back to full size underneath it. Leaving them
|
||||
// posed would mean two shrunken pictures of the same app —
|
||||
// the card and the window behind it.
|
||||
ViewtopControl.clearPose()
|
||||
if (GlobalStates.missionControlOpen
|
||||
&& !Persistent.states.navigation.missionControlDiscovered)
|
||||
Persistent.states.navigation.missionControlDiscovered = true
|
||||
|
|
@ -302,6 +313,24 @@ PanelWindow {
|
|||
// Upward travel is positive; downward drags leave travel at 0 so
|
||||
// the handle doesn't chase a dismiss gesture.
|
||||
rail.dragTravel = Math.max(0, startY - mouse.y)
|
||||
|
||||
// The app shrinks under the thumb. Casey, 2026-08-05: *"swipe up
|
||||
// just a bit makes the app sorta scale and you fall into a multi
|
||||
// tasking area"* — and Phosh's home is the same shape, a drag
|
||||
// surface travelling between two states rather than a button that
|
||||
// teleports.
|
||||
//
|
||||
// Scaled against `missionAt`, the multitasking detent, so the app
|
||||
// has visibly become a card by the moment it would commit. It
|
||||
// keeps shrinking past that toward home, which is what makes the
|
||||
// long pull feel like a further degree of the same motion instead
|
||||
// of a second, unrelated gesture.
|
||||
//
|
||||
// Nothing is scaled below 0.6: past that the window is a thumbnail
|
||||
// and its own inverse-mapped touch targets stop being findable if
|
||||
// the drag is abandoned there.
|
||||
const progress = Math.min(1.0, rail.dragTravel / Math.max(1, rail.missionAt))
|
||||
ViewtopControl.poseActiveZone(1.0 - 0.4 * progress)
|
||||
}
|
||||
|
||||
onReleased: mouse => {
|
||||
|
|
@ -347,6 +376,12 @@ PanelWindow {
|
|||
return
|
||||
}
|
||||
|
||||
// A climb that did not reach the first detent. The app was shrinking
|
||||
// under the thumb and has to spring back, or an abandoned gesture
|
||||
// leaves a permanently smaller window and no way to say so.
|
||||
if (wasDragging)
|
||||
ViewtopControl.clearPose()
|
||||
|
||||
// Downward: peel the nearest surface (keyboard, then dock).
|
||||
if (deltaY >= rail.revealAt) {
|
||||
singleTapTimer.stop()
|
||||
|
|
@ -412,6 +447,10 @@ PanelWindow {
|
|||
rail.dragging = false
|
||||
rail.dragTravel = 0
|
||||
lastTapAt = -1
|
||||
// A cancel is the compositor taking the sequence away mid-drag —
|
||||
// the FTS controller does exactly this after a wake. The scale must
|
||||
// still come home; nothing else will do it.
|
||||
ViewtopControl.clearPose()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -54,6 +54,11 @@ Scope {
|
|||
// this is true — it would be covering the thing being moved — so the only
|
||||
// surface up is the Done bar.
|
||||
property bool moving: false
|
||||
// Which size Resize last applied. Kept on the scope rather than the button
|
||||
// so it survives the sheet closing and reopening on the same window —
|
||||
// tapping Resize twice in two visits should continue the cycle, not restart
|
||||
// it and appear to do nothing.
|
||||
property int sizeStep: 0
|
||||
|
||||
// How long a hold on Close means kill. Longer than a tap could ever be,
|
||||
// short enough that a stuck app does not feel like a negotiation.
|
||||
|
|
@ -287,6 +292,27 @@ Scope {
|
|||
}
|
||||
}
|
||||
|
||||
SheetButton {
|
||||
icon: "aspect_ratio"
|
||||
label: "Resize"
|
||||
// Cycles the window through sizes rather than opening a
|
||||
// drag-handle mode: Move already owns "follow my finger",
|
||||
// and a second finger-driven mode would need a way to tell
|
||||
// them apart mid-gesture. Tapping through half → two-thirds
|
||||
// → full → back is reachable one-handed and needs no
|
||||
// second gesture vocabulary.
|
||||
//
|
||||
// A real corner handle is still owed; this is the verb
|
||||
// reaching the window, which is what was missing when the
|
||||
// button said Move and there was no Resize at all.
|
||||
onTapped: {
|
||||
scope.sizeStep = (scope.sizeStep + 1) % 3;
|
||||
const frac = [0.5, 0.67, 1.0][scope.sizeStep];
|
||||
ViewtopControl.place(scope.target, 0, 0,
|
||||
win.width, Math.round(win.height * frac));
|
||||
}
|
||||
}
|
||||
|
||||
SheetButton {
|
||||
icon: "splitscreen"
|
||||
label: "Split"
|
||||
|
|
|
|||
|
|
@ -156,6 +156,38 @@ Singleton {
|
|||
root.scene("drop", {});
|
||||
}
|
||||
|
||||
// Scale every window on the zone in front, live, as a drag progresses.
|
||||
//
|
||||
// This is the iOS/Android "the app shrinks into a card while your thumb
|
||||
// climbs" feel, and it is the first thing in the tree to actually drive
|
||||
// `pose`. The verb and its inverse input-mapping have been implemented and
|
||||
// tested in the compositor for weeks with nothing calling them, which is
|
||||
// the whole reason the behaviour has never been seen on the device.
|
||||
//
|
||||
// Throttled on the value, not on a timer: a drag emits a motion event per
|
||||
// frame and each one would otherwise be a socket round-trip. Anything
|
||||
// smaller than a percent of scale is invisible and not worth a write.
|
||||
property real _lastPose: 1.0
|
||||
|
||||
function poseActiveZone(scale) {
|
||||
if (Math.abs(scale - root._lastPose) < 0.01)
|
||||
return;
|
||||
root._lastPose = scale;
|
||||
for (const w of root.windows) {
|
||||
if (w.workspace === root.activeZone)
|
||||
root.pose(w.id, scale, 0.0, 0.5, 0.5);
|
||||
}
|
||||
}
|
||||
|
||||
// Put them back. Called on every path out of a drag — commit, abandon and
|
||||
// cancel — because a window left posed by a gesture that ended is a window
|
||||
// the user cannot restore without knowing a verb exists.
|
||||
function clearPose() {
|
||||
root._lastPose = 1.0;
|
||||
for (const w of root.windows)
|
||||
root.pose(w.id, 1.0, 0.0, 0.5, 0.5);
|
||||
}
|
||||
|
||||
function raise(id) {
|
||||
root.scene("raise", { id: id });
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue