9.5 KiB
| 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,#55ffffffcurrently hand-rolled across the three lock cards). One palette, named tokens.ColorUtils— at minimumtransparentize(color, amount).Translation—tr()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 soRippleButtoncan 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'sshake_entrymodel, 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, signalsclicked/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 bothLockMediaCardandLockAgentCardcurrently hand-roll with different radii/alphas. One primitive, one palette.PinDots— the entered-PIN dots row + empty-state hint, withErrorShakeAnimationwired in.LockKeypad— the 3×3 + 0/backspace/confirm grid, built from ourRippleButton.LockUtilityRow— power / battery / reboot, from ourRippleButton.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 inlinepressY/threshold/retreat-timer block inTouchLockSurface.qml.
The result
TouchLockSurface.qml shrinks to ~layout + intent wiring (target ~60–80
lines), built entirely on Souveraine-owned AGPL QML. The lock dep graph has
zero ii-derived files.
How to build it (approach, not steps)
- Tier 0 first.
Appearance/ColorUtils/Translation— nothing else compiles without them. Define the Souveraine lock palette here as named tokens; retire the scattered literals. - Tier 1 next, in dependency order:
StyledText(needs Appearance),MaterialSymbol,MaterialShape, thenErrorShakeAnimation(standalone). - Tier 2:
RippleButton(composesMaterialShape). - Tier 3:
AmbientCard,PinDots,LockKeypad,LockUtilityRow,LockReveal— built on Tiers 0–2. - Rewire
TouchLockSurfaceand 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 0–2 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 — zeroqs.modules.common.widgetsii-borrowed imports in the lock graph.- The lock surface dep graph contains no ii-derived files (grep verifiable).
- Manifest lines added;
deploy.sh --phoneships and the lock runs. - Cord-cut ledger updated (this file's "Done when", or a dedicated ledger) recording which borrowed dirs remain.