191 lines
9.5 KiB
Markdown
191 lines
9.5 KiB
Markdown
---
|
||
task_id: souveraine-lock-primitives-001
|
||
title: "Souveraine-owned AGPL lock primitives — cut the cord from ii by rewriting"
|
||
status: pending
|
||
priority: high
|
||
phase: build
|
||
created: 2026-07-18
|
||
references: 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)`.
|
||
- **`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 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 ~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)
|
||
|
||
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 0–2.
|
||
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 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 — 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.
|