feat(desktop): HA value-setting slider for #442 Slice 1 - #461
Merged
Conversation
Part of #442 Slice 1 (epic #445). Consumes the frozen backend contract from PR #460: an optional `control` capability descriptor on each `GET /ha/states` entry (action/kind/value/min/max/step/unit, parsed defensively so an older server behaves exactly as today), and an optional numeric `value` on `POST /cameras/:id/ha/action`. The badge detail card gains a value row (a `Slider` plus a caption) driven entirely by the descriptor's own bounds/step/unit, never hardcoded, so Slice 2's temperature control can reuse it unchanged. It commits on release with exactly one POST per drag gesture and never optimistically flips the displayed value, matching the existing button row's settle-window convention; `cover.set_position` (like the discrete cover actions) and any require_confirm link confirm first, with the target value in the prompt. Left-click still direct-fires a controllable simple domain's primary action, which never reached the card before, so a dimmable light/fan had no way to its slider. Adds a right-click (secondary-tap) gesture, plumbed through `OverlayEditorLayer`'s new optional `onSecondaryTapItem`, that opens the detail card for any controllable badge regardless of domain, leaving left-click untouched. Flutter analyze: BLOCKED. winbuild (10.1.10.90) is offline (connection timed out); dev1/dev2/macmini have no Flutter toolchain. Changes were reviewed manually instead (types, null-safety, every referenced symbol, num.clamp() return-type pitfalls). Signed-off-by: badbread <badbread@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Part of #442
Desktop client (Flutter) implementation of #442 Slice 1's HA value-setting controls (dimmable light brightness, cover position, fan speed), consuming the backend contract frozen in #460 (still open, not yet merged into
main— the contract's shape was confirmed directly against that branch'sservices/api/src/ha.rs).lib/api/ha_models.dart: newHaControlDescriptor(action/kind/value/min/max/step/unit), parsed defensively offHaEntityState.control— any missing/malformed field yieldsnullrather than throwing, so an older server (or an odd entity) never breaks the whole/ha/statesdecode.lib/api/ha_api.dart:haAction()gains an optionalvalueparam, sent only when non-null.lib/ui/ha_overlay/ha_actions.dart:haValueActionLabel(row caption),haValueActionNeedsConfirm(cover/lock parity with the discrete button confirms),haFormatControlValue(kind-agnostic display, e.g."62%").lib/ui/ha_overlay/ha_state_card.dart: a value row (Slider+ caption) below the existing button row, shown only when the host passes acontroldescriptor. Bounds/step/unit come entirely from the descriptor — never hardcoded — so Slice 2'sclimate.set_temperaturecan reuse the same widget. Commits on release with exactly one POST per drag gesture (never while dragging), never optimistically flips the displayed value (same settle-window/in-flight-spinner convention as the button row), and confirms first (with the target value in the prompt, e.g. "Set Garage Door to 20%?") forcover.set_positionor arequire_confirmlink.lib/ui/ha_overlay/ha_overlay_layer.dart: gates the slider like the button row (actuatorscapability +actuatorrole + the link'sallowed_actions), wires it toPOST /ha/action, and adds a right-click (secondary-tap) gesture on any controllable badge to open the detail card. This was needed because a controllable "simple" domain (light/fan) already direct-fires its primary action on left-click and never reaches the card (issue HA controls: single-click actuates directly; hover shows state; card only for multi-action devices (#187 follow-up) #428) — so a dimmable light had no gesture to reach its slider. Left-click behavior is unchanged.lib/ui/overlay_editor/overlay_editor_layer.dart: adds an optionalonSecondaryTapItemcallback to the shared view-mode gesture layer (used only by the HA overlay; the PTZ panel's usage is edit-mode only and unaffected).Backend, Android, and iOS were not touched.
Verify
num.clamp()return-type pitfalls (clamp()returnsnumeven when called on anint/double, soSlider'sdivisions/valueneed an explicit.toInt()/.toDouble()).flutter analyze— BLOCKED: winbuild (10.1.10.90), the only Windows Flutter box, is offline (SSH connection timed out). dev1/dev2/macmini were also checked and have no Flutter toolchain. Did not build/run on this Windows workstation per policy.Test plan
flutter analyzeon winbuild once it's back online; fix any ERRORS.percentage_step.