Skip to content

[QuickPanel] Document logic and rework buggy long-press granular adjustment#215

Open
moWerk wants to merge 4 commits into
AsteroidOS:masterfrom
moWerk:valuescruber
Open

[QuickPanel] Document logic and rework buggy long-press granular adjustment#215
moWerk wants to merge 4 commits into
AsteroidOS:masterfrom
moWerk:valuescruber

Conversation

@moWerk

@moWerk moWerk commented Apr 3, 2026

Copy link
Copy Markdown
Member

Replace QuickPanel long-press scrubber with drag-based value control

Replaces the hold-and-auto-increment pattern for brightness and volume
adjustment with a pressAndHold-activated horizontal drag scrubber,
bringing the interaction model in line with the IntSelector component
used elsewhere in the settings UI.

Interaction model

Holding a brightness or volume toggle activates the scrubber. The full
panel width is the drag range — the fill position and finger position
correspond truthfully regardless of which page or slot the toggle
occupies. A 15% fat-finger margin on each side ensures min and max are
reachable before the screen edge. Releasing ends the scrub cleanly
without firing the toggle's click action.

Swiping the sliding row before the hold threshold fires is unaffected —
the ListView steals the gesture naturally since preventStealing is
only set after hold is confirmed.

Visual transition

On scrub start, all panel elements (toggle rows, ValueMeter, pageDots)
fade out simultaneously. A morphRect pill animates from the ValueMeter's
position and fill color, expanding and darkening into the scrubCover
position. The scrubCover crossfades in over the morphRect as it arrives.
On scrub end the sequence reverses symmetrically, the morphRect shrinking
back to where the ValueMeter reappears.

The scrubCover displays a proportional fill tracking the live value. A
live value label occupies the fixed row area (always visible above the
finger). A mode label at the ValueMeter position confirms which parameter
is being adjusted. Both labels fade with the inverse timing of the panel
elements they replace.

Behaviour changes

  • Scrubbing volume to any value above zero while muted implicitly
    unmutes, clearing preMuteLevel. A confirmation sound plays on scrub
    end mirroring the click-to-unmute behaviour.
  • Brightness minimum respects the system-enforced floor from
    meta-smartwatch — rangeMin: 10, toggling off sets to rangeMin.
  • Cinema toggle onClicked branch ordering corrected following the
    checked-based API migration from the dodoradio PR.
  • ValueMeter state machine for brightness and volume display removed.
    ValueMeter now shows battery exclusively and fades during scrub.

Videos

[battery bottom layout]

1000019417.mp4

[battery top layout]

1000019416.mp4

@moWerk
moWerk marked this pull request as draft April 6, 2026 20:22
@FlorentRevest

Copy link
Copy Markdown
Member

I think I like this interaction better yes. The code is already a bit crazy but it doesn't make it much crazier so that looks OK to me

moWerk and others added 4 commits July 19, 2026 08:42
…ntrol

- Replace holdTimer and directionChangeTimer step increment pattern in
  QuickPanelToggle with pressAndHold-activated horizontal drag scrubber.
  Scrub activates only after confirmed hold, so ListView swipes are not
  intercepted before the hold threshold fires.
- Add scrubWidth property to QuickPanelToggle. Callers set this to
  rootitem.width so the full panel width is the drag range regardless of
  which toggle position initiated the scrub.
- Add snap-to-position mapping via mapToItem(rootitem) so the fill
  position and finger position correspond truthfully across all toggle
  positions on any sliding row page.
- Add 15% fat-finger margin on each side of scrubWidth so min and max
  are reachable before the screen edge.
- Add scrubbing and wasScrubbing properties. wasScrubbing survives into
  onClicked to suppress the spurious click Qt fires after a hold drag.
  onPressed clears it at the start of the next fresh interaction.
- Add activeScrub and scrubMode to rootitem as single sources of truth
  driving all simultaneous panel fades and scrub display content.
- Fade out fixedRow, slidingRow, valueMeter, valueMeterCaption, flashIcon
  and pageDots together on activeScrub via shared 200ms Behavior.
- Add scrubCover pill with layer+OpacityMask clipping, dark background at
  0.75 opacity matching active toggle visual weight, and proportional fill
  rect tracking the live brightness or volume value with 80ms animation.
- Add scrubEventGuard property and guardTimer to keep a swallowing
  MouseArea on scrubCover enabled for 250ms after scrub ends, preventing
  stray Qt touch events from reaching toggles after preventStealing
  releases.
- Add morphRect pill that animates between valueMeter geometry and
  scrubCover geometry on scrub start and end. Color and opacity animate
  from valueMeter fillColor at 0.3 alpha to scrubCover dark at 0.75,
  and reverse symmetrically on scrub end. scrubCover crossfades in over
  morphRect at 150ms into the expand animation.
- Add scrubValueLabel centered in fixedRow area showing live brightness
  or volume percentage during scrub. Add scrubCaptionLabel at valueMeter
  position showing Brightness or Volume string. Both fade opposite to the
  panel elements they replace.
- scrubValueLabel always anchors to the top position and scrubCaptionLabel
  to the bottom position regardless of batteryBottom layout state, keeping
  the live value visible above the finger during scrub.
- Disable valueMeter value Behavior during activeScrub to prevent the
  250ms animation from permanently lagging behind the live label.
- Remove valueMeter state machine and SequentialAnimation transitions for
  brightness and volume display. ValueMeter now shows battery only and
  fades out during scrub. scrubCover and scrubValueLabel take over the
  role of indicating the scrubbed value.
- Sound toggle plays confirmation sound on scrub end when rangeValue > 0,
  mirroring the click-to-unmute behaviour.
- Scrubbing to any volume > 0 while muted clears preMuteLevel, unmuting
  implicitly via the scrub gesture.
- Fix spurious valueMeter state being set on any finger-down by moving
  state activation from onPressed to onScrubbingChanged, eliminating the
  stale state bug when a swipe gesture stole the event before hold fired.
- Fix cinema toggle onClicked branch inversion introduced by the checked
  API migration.
- Fix brightness toggle minimum using rangeMin 10 to respect the
  system-enforced brightness floor from meta-smartwatch.
Qt6 rejects imperative assignment of a JS Number (double) to a QML
property int - Math.round() returns double even for whole values, so
updateValue() would log "Unable to assign double to int" on every drag
event and never move the value. Cast the result with | 0.

Drop the startScrubX/startValue properties entirely: they were dead
remnants of the earlier relative-drag design (written, never read), and
assigning the fractional mouseX to property int startScrubX would abort
the onPressAndHold handler under Qt6 before the first value update ran.
Also straighten the misleading indentation in that handler.
Without feedback at hold-detection, users wait for the visual morph
before daring to move - longer than the actual arming time. Play the
press haptic the moment onPressAndHold fires so the finger knows the
scrub is live; value tracking already starts before the first animation
frame (input sensing leads, visuals follow).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@moWerk

moWerk commented Jul 19, 2026

Copy link
Copy Markdown
Member Author

Rebased onto current master (post-ngf/systemsettings migrations, one small semantic conflict resolved in the haptics toggle). Two additions since your review: a Qt6 strict-coercion fix (| 0 on the imperative rangeValue write — without it scrubbing silently does nothing on Qt6) and a haptic confirmation at hold-detection so the finger knows the scrub is armed before the visual lands. Hardware-tested on skipjack and beluga (2026-07-19): full-width tracking, mute-clear on volume scrub, swipe-cancel cleanup, batteryTop layout all green. Ready for review.

🤖 Generated with Claude Code

@moWerk
moWerk marked this pull request as ready for review July 19, 2026 15:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants