Watch
1
0
Fork
You've already forked souveraine
0
souveraine/docs/tasks/souveraine-lock-primitives.md

9.5 KiB
Raw Blame History

task_id title status priority phase created references
souveraine-lock-primitives-001 Souveraine-owned AGPL lock primitives — cut the cord from ii by rewriting pending high build 2026-07-18 docs/tasks/qs-souveraine-composer.md, docs/DECISIONS.md, ~/Projects/MAKE_PROPER_LICENSES_FOR_ALL_PROJECTS.md, surfaces/quickshell/modules/ii/lock/TouchLockSurface.qml, surfaces/quickshell/modules/souveraine/lock/

Souveraine-owned AGPL lock primitives

The end goal (build THIS, not an increment)

A fully Souveraine-owned, fully AGPL lock surface. Zero ii-derived files in the lock dependency graph. Every primitive the lock uses is original Souveraine-authored QML, licensed AGPLv3, designed to behave how we want — not a copy of ii.

There is no v1/v2 here. We do not vendor ii files. We do not borrow ii widgets as a bridge. We accept that the lock may not compile, or may be missing a subcomponent, while the owned primitives are built. That is preferable to a single borrowed-widget compromise. See the cord-cut rule in docs/DECISIONS.md ("Shell = own config") and docs/tasks/qs-souveraine-composer.md.

Why rewrite, not vendor

Vendoring an ii file inherits GPLv3 — we can never make it ours by relabeling. The licensing master doc governs the boundary: original Souveraine files get AGPL headers + Casey as copyright holder; genuinely inherited GPLv3 files keep their headers. Because we choose to author rather than inherit, every lock primitive will be original AGPL, and the lock surface conveys cleanly under our license. ii is behavioral reference only — read how it behaves, write our own implementation. Do not copy.

What the lock surface currently depends on

Direct external symbols referenced by the lock files (verified by grep, 2026-07-18):

Symbol Used by What it is
RippleButton TouchLockSurface.qml (KeypadButton, UtilityButton inline components) Pressable button with material-ripple feedback. Transitive ii dep: MaterialShape.
StyledText TouchLockSurface.qml (dots hint, keypad glyphs, hint labels) Themed text bound to Appearance colors/fonts.
MaterialSymbol TouchLockSurface.qml (icons: backspace, arrow, power, reboot) Material Symbols icon glyph.
ErrorShakeAnimation TouchLockSurface.qml (wrong-PIN shake on dotsArea) Frame-driven horizontal shake animation.
Appearance (singleton) TouchLockSurface.qml (15×), LockScreen.qml (1×). The host + cards use raw literals instead — evidence for the palette work below. Colors (colOnLayer1, colError, colSubtext, colOnSurfaceVariant, colOnPrimary) + font pixel sizes.
ColorUtils TouchLockSurface.qml transparentize().
Translation TouchLockSurface.qml tr() i18n.
MaterialShape transitive (used by ii's RippleButton) Material-style rounded/shape background. First-class rewrite target since our RippleButton needs it.

Everything else in the lock files is QtQuick/QtQuick.Layouts/Quickshell (primitives we keep) or Souveraine-owned already (GlobalStates, LockContext, Config, LockContentPolicy, Ai, Battery, LockSurfaceHost, LockMediaCard, LockAgentCard).

What to build (the primitive set)

All under a Souveraine-owned path — propose surfaces/quickshell/modules/souveraine/widgets/ — each file original AGPL, Casey as copyright holder, designed from the lock's needs with ii as behavioral reference only.

Tier 0 — theme singletons (these are not optional; everything below keys off them)

  • Appearance — colors + font scale. This is the single source of truth every styled component reads. Decide the Souveraine lock palette here (replacing the scattered literals #d9ffffff, #e6ffffff, #1c1b20, #b3181b20, #22000000, #33ffffff, #55ffffff currently hand-rolled across the three lock cards). One palette, named tokens.
  • ColorUtils — at minimum transparentize(color, amount).
  • Translationtr() passthrough to whatever i18n we standardize on.

Tier 1 — visual primitives

  • StyledText — text bound to Appearance tokens; the type every label uses.
  • MaterialSymbol — icon glyph renderer.
  • MaterialShape — material background shape (rounded rect minimum; designed so RippleButton can compose it).
  • ErrorShakeAnimation — horizontal shake with the midpoint-crossing termination rule (stop when the oscillation would cross the rest point, not on a fixed timer — Phosh's shake_entry model, frame-clock driven).

Tier 2 — composite primitives (compose Tier 1)

  • RippleButton — the pressable button. Ripple feedback baked in from day one (this is one of the "minor details" Casey wants to tweak — build it ours, tunable). Properties the lock uses today: contentItem, colBackground, buttonRadius, toggled, enabled, signals clicked/pressAndHold.

Tier 3 — lock-surface components (built on the owned primitives)

These replace the inline blocks in TouchLockSurface.qml:

  • AmbientCard — the shared bordered rounded-rect card both LockMediaCard and LockAgentCard currently hand-roll with different radii/alphas. One primitive, one palette.
  • PinDots — the entered-PIN dots row + empty-state hint, with ErrorShakeAnimation wired in.
  • LockKeypad — the 3×3 + 0/backspace/confirm grid, built from our RippleButton.
  • LockUtilityRow — power / battery / reboot, from our RippleButton.
  • LockReveal — the glance↔PIN stage controller. Owns the reveal intent (reveal(), retreat()) so every input path (swipe, tap-hint, hardware key, future double-tap-clock) funnels through one transition instead of each re-implementing threshold logic. Replaces the inline pressY/threshold/retreat-timer block in TouchLockSurface.qml.

The result

TouchLockSurface.qml shrinks to ~layout + intent wiring (target ~6080 lines), built entirely on Souveraine-owned AGPL QML. The lock dep graph has zero ii-derived files.

How to build it (approach, not steps)

  1. Tier 0 first. Appearance/ColorUtils/Translation — nothing else compiles without them. Define the Souveraine lock palette here as named tokens; retire the scattered literals.
  2. Tier 1 next, in dependency order: StyledText (needs Appearance), MaterialSymbol, MaterialShape, then ErrorShakeAnimation (standalone).
  3. Tier 2: RippleButton (composes MaterialShape).
  4. Tier 3: AmbientCard, PinDots, LockKeypad, LockUtilityRow, LockReveal — built on Tiers 02.
  5. Rewire TouchLockSurface and the two cards to consume the owned primitives, removing every ii import.

Each file lands with an AGPLv3 header and Casey as copyright holder. Behavioral reference from ii is fine (read how ii's RippleButton feels, what properties it exposes); copying is not.

ii reference access (behavioral, read-only)

ii's widget sources are NOT in this repo. They live on the phone at /home/casey/.config/quickshell/ii/modules/common/widgets/ (RippleButton, StyledText, MaterialSymbol, MaterialShape, ErrorShakeAnimation, etc.) and on the laptop at ~/.config/quickshell/ii/. SSH: ssh pixel. Read them to understand behavior and the property contract the lock code expects — do not copy. Write fresh AGPL implementations.

Phosh's lockscreen source is also on the phone at ~/build/phosh/src/ (lockscreen.c, ui/lockscreen.ui) — useful behavioral reference for the swipe-capture model (deck/carousel, rounded-progress page gating) and the shake midpoint-crossing termination. Do not port; implement in QML.

Manifest + composer wiring

Every new Souveraine-owned file needs a line in surfaces/quickshell/deploy.sh MANIFEST (the composer only ships files in the manifest — a missing line means "is not a type" at load). As files are written, add manifest lines pointing them into the souveraine/ composed config. Borrowed ii widget dirs stay borrowed for the rest of the shell until their own cord-cut; only the lock's deps are cut here.

License headers

Per ~/Projects/MAKE_PROPER_LICENSES_FOR_ALL_PROJECTS.md:

  • Every file written here: AGPLv3 header, Casey Tunturi as copyright holder.
  • Do NOT put inherited GPLv3 headers on these — they are original work.
  • Mixed tree is honest: the lock dep graph is all-original AGPL after this task; other parts of the shell may still carry inherited GPLv3 until their own rewrite.

Non-goals / out of scope for this task

  • Rewriting non-lock widgets (dock, sidebar, overview, etc.) — separate cord-cuts, separate tasks.
  • Changing lock behavior beyond what the primitive rewrite naturally enables. Feature additions (clock double-tap, new gesture paths, peek mode) are follow-on work on top of the owned primitives, not part of getting the substrate owned.
  • Touching sessiond (Rust) — it is already Souveraine-owned and unaffected.

Done when

  • Tier 02 primitives exist as original AGPL files under modules/souveraine/widgets/ (or agreed path), each with AGPL header.
  • Tier 3 lock components exist, built on the owned primitives.
  • TouchLockSurface.qml + both lock cards import only Souveraine-owned + Qt/Quickshell modules — zero qs.modules.common.widgets ii-borrowed imports in the lock graph.
  • The lock surface dep graph contains no ii-derived files (grep verifiable).
  • Manifest lines added; deploy.sh --phone ships and the lock runs.
  • Cord-cut ledger updated (this file's "Done when", or a dedicated ledger) recording which borrowed dirs remain.