Use the crate for pair validation, settle delay, and canvas defaults
in breadpad and breadman. breadman now depends on bread-utils v0.7.2
for screenshot_cli; existing hand-rolled argv parsing stays.
Repoint bread-theme, bread-utils, and bread-screenshots at tag v0.7.2
on git.breadway.dev. breadman enables the adw feature (implies gtk).
Drop the 69ce2d67 rev pin now that screenshots is on a tagged release.
Emit bread.pad.captured after a successful quick-capture save and
bread.pad.reminder.due when breadpad fire actually shows a reminder.
Fail-silent if breadd is down. No command stubs.
App id: pad. bread-utils bread-client at v0.7.1.
bread-screenshots is not on the v0.7.1 tag, so it is rev-pinned instead
of floating on branch=main. bread-theme v0.7.1 has no adw/chip helpers;
breadman keeps local shims. CLAUDE.md records the single-trunk workflow.
bread-ecosystem's ci/build.sh used to derive the image tag and cache
volume name from basename(repo_root) — but every product's CI checks
out into a directory literally named "src", so in real CI runs this
resolved to "bread-ci:src" for every product, not "bread-ci:breadpad".
Harmless while breadpad was the only consumer; would have silently
collided (shared image tag, shared cargo-target cache) the moment a
second product started using it. Fixed upstream, bumping the pin here
to pick it up and passing "breadpad" explicitly.
Moves the Containerfile and build.sh added in the previous CI fix up
into bread-ecosystem/ci/, so other GTK4 layer-shell products in the
ecosystem can share it instead of each carrying their own copy. This
repo's ci/build.sh is now a thin wrapper that clones bread-ecosystem
at the commit pinned in ci/bread-ecosystem.rev and delegates to its
ci/build.sh — pinned by sha rather than tracking main, so an unrelated
change over there can't silently break this repo's release builds
(the failure mode the bread-theme test fix a moment ago was caused by).
Verified locally: clippy, test, and release build all pass through
the new delegator path.
Replaces the from-source libadwaita build (repeatedly broken by
version drift) with a pinned Arch container that gets everything
prebuilt via pacman, adds a fast-fail check.yml for feature/fix
branches, and fixes the clippy/test debt that check.yml surfaced now
that it's enforced for the first time.
check.yml runs clippy -D warnings and cargo test for the first time in
this repo's history, surfacing pre-existing lint debt across all four
workspace crates plus one stale test assertion (breadpad-shared's
Palette default-background test still expected bread-theme's old
#1e1e2e; the upstream design system moved to #0c0c0c a while back and
nothing caught the drift since tests never ran in CI).
All fixes are mechanical: needless returns/closures/borrows, manual
Default impls replaceable by #[derive], map_or -> is_some_and, manual
range checks -> RangeInclusive::contains, a non-idiomatic sort_by ->
sort_by_key, an overly complex inline type given an alias, and moving
a function that ended up defined after its own test module. The one
exception is NoteType::from_str, which clippy flags for shadowing
std::str::FromStr's name — left as `#[allow(...)]` with a comment
rather than renamed, since it has 30+ call sites across every crate
in the workspace and returns Self directly rather than Result.
The dev/rc/release workflows rebuilt libadwaita from source inside an
uncached Fedora container on every single run, because Ubuntu 24.04's
packaged libadwaita was too old for gtk4 0.11's v4_12 feature. That
from-source build broke repeatedly on drift (rust dep versions,
libadwaita ABI, and finally a removed meson option), producing eight
straight failed CI runs.
Arch's repos already carry current gtk4/libadwaita/gtk4-layer-shell as
prebuilt packages, and breadpad only targets BOS/Arch, so there's no
reason to build anything from source. Swap the container base to a
digest-pinned archlinux image (ci/Containerfile) with those packages
installed via pacman, and extract the shared "build the image, run
cargo inside it" logic into ci/build.sh so it isn't duplicated three
times across the workflows. Cargo's registry/git/target caches persist
in named docker volumes across runs.
Also:
- Add check.yml: clippy + test on feature/**/fix/** pushes, so lint/
build breakage surfaces before it reaches main and triggers a
dev-track release.
- Fix release.yml's tag trigger (tags-ignore) so an rc tag push no
longer also spawns a skipped release.yml run alongside rc-release.yml.
Verified locally: the container builds cleanly via pacman (no source
compilation), and `cargo build --release --locked --workspace` inside
it produces working breadpad/breadman binaries linked against
libgtk4-layer-shell.so.0 and libadwaita-1.so.0 respectively.
Replaces the dev/beta branch split with one trunk (main): dev-track
builds still publish on every push, but the beta track now publishes
from a vX.Y.Z-rc.N prerelease tag instead of a separately-maintained
beta branch. Removes the branch nobody reliably kept in sync.
The libadwaita-based settings screen (previous commit) had two real bugs a
closer look (and a screenshot from the real running app) caught:
- AdwSpinRow's internal GtkSpinButton has no width constraint of its own,
so once the row was widened to 900px, the spin button stretched to fill
it - the digits and +/- buttons ended up stranded behind a huge empty
bordered box, the exact bug the design review flagged, just worse.
- bread-theme's shared `entry, spinbutton` rule outlines every field with
an always-visible @overlay border, which on a light-cream overlay colour
reads as a stark white outline against the dark theme.
Rather than keep fighting libadwaita's internal row/spin-button opinions
(there's no supported way to reach in and constrain them), settings.rs is
now plain GTK4 mirroring bos-settings' own Row.svelte/NumberField.svelte/
TextField.svelte design exactly: same tokens (12/16px row padding, ch-width
inputs, transparent-at-rest border, accent border only on focus), built on
a plain `list.boxed-list` for the native rounded-corner-run + divider
styling. Full control over sizing, no internal widget to hunt for.
Also fixed a real ordering bug in the editor AdwDialog conversion:
`open_editor` used to call `dialog.present()` internally before returning,
so callers that connected `dialog.connect_map` afterward (screenshot mode)
missed the signal entirely - it can fire synchronously inside `present`.
Presentation now happens at each call site, after wiring `connect_map`.
Also gave the dialog's content an explicit height/vexpand + min-content-
height, since the ScrolledWindow had none and the whole dialog was
collapsing to just its header bar.
breadpad-shared's bread-theme dependency also gets fixed here: it was
still pinned to an old GitHub-mirror tag (v0.2.8) while breadman pinned
the same crate to git.breadway.dev's dev branch - two different copies of
bread-theme compiled into the same binary, so breadman's actual runtime
CSS (built through breadpad_shared::theme) never saw any of the shared
stylesheet fixes above regardless of what breadman's own direct
dependency resolved to.
Reminder alert:
- Dismiss now matches Snooze's full-opacity text color instead of 0.6
alpha, which read as a disabled button.
- Button row inset brought to 20px to match the header/body zone above
it (was 16px, visible as a step across the divider).
Snooze popover:
- Options are left-aligned (each button's label now sets its own
xalign) and span the full row width instead of centering as a
ragged-left stack of labels.
- Added a hairline divider between options so the list reads as
distinct rows even in the popover's static/non-hover state.
- Added a "Custom…" option that reveals a free-form time entry,
reusing the same rule-based time parsing breadman's dialogs use,
instead of only offering the three fixed presets.
- Popover now matches the reminder card's flat-bordered elevation
(no arrow, 1px border, no shadow) instead of GTK's default
arrow+drop-shadow popover chrome.
Compose popup: dropped the bare accent-teal checkmark submit button
(same colour as the selected type pill, unlabeled) in favor of a
"Press Enter to add" hint, since the popup already grabs focus and is
keyboard-driven. Also made the entry's CSS padding uniform (14px on
all sides, was 12px/16px).
Settings screen:
- Widen the AdwClamp to 900px, left-aligned to the note-list gutter,
instead of PreferencesPage's own ~600px clamp that made the screen
read as a narrower, bolted-on app.
- Remove the floating Save button; every control now applies instantly
(switches/combo/spin on change, entry rows via show_apply_button),
matching what AdwSwitchRow's own design language already implies.
- Replace ActionRow+suffix-Entry with real AdwEntryRow/AdwPasswordEntryRow
so fields are row-width instead of sized by leftover label space.
- Default type now uses the same pill-row widget as the New Note dialog
and editor, instead of a fourth type-picker variant.
- Local Classifier group description notes the paths are shared with
breadpad.
Note list (All/Upcoming/Todo/Idea/Note/Question):
- Replaced the two-line card (huge dead gap between title and actions)
with Archive's tighter single-line row layout, shared via the new
views::row module. Unifies the edit affordance (pencil in both active
and archive rows) and drops the type badge in views already filtered
to one type.
- Type badges now tint per-type (matching the existing note-card-{type}
accent-bar colors) instead of one flat cream fill for every type.
- Empty states are centered with type-specific copy and a "+ New X"
action instead of top-anchored generic text.
- Search bar is now scoped to note-list views (was rendering uselessly
on Settings/Errors).
- Archive sort bug: it was sorting by `created` while displaying
`completed` ("done {date}"), which is why rows could appear out of
order. Now sorts by `completed`.
- Sidebar and row-action icons are now real GTK symbolic icons instead
of a mix of emoji, Unicode glyphs, and thin monochrome characters.
Editor: converted from a bare GtkPopover (no scrim, no title, anchored
wherever the triggering button happened to be) to an AdwDialog with
AdwEntryRow fields, a shared header bar, and copy/placeholders unified
with the New Note dialog. Delete uses destructive-action styling.
Also: destructive-action buttons (breadman's row/editor delete, and
breadpad-shared's .danger-btn) now use a hardcoded red instead of
pywal's @red - a blue-toned wallpaper's "red" palette slot can itself
render blue, which made delete indistinguishable from confirm/accent
buttons regardless of which CSS class was already applied.
Proof-of-concept for the ecosystem-wide design-system work: every setting
is now an AdwPreferencesGroup/SwitchRow/SpinRow/ActionRow/ComboRow via
bread-theme::adw, instead of a hand-rolled GtkGrid of labels + raw widgets.
This directly fixes the two worst defects a design critique found here:
- Toggle switches rendered ~1400px wide, like progress bars — caused by
GtkGrid sizing a switch's column to match a sibling entry's hexpand in
the same grid, and Switch has no default that resists filling that
width. AdwSwitchRow owns its own layout, so this class of bug can't
recur.
- Spin buttons were ~1300px from the label they modified, for the same
grid-column-sizing reason. AdwSpinRow docks the spinner to its title.
Also softened the jargon-forward section titles the critique flagged
("Model (Tier 2 ONNX)", "Ollama (Tier 3)") — the tier/implementation
detail moved from the title (loud, unavoidable) to each group's
description (quieter, still there for anyone who wants it).
bread-theme now needs a direct dependency here (branch=dev, `adw`
feature) since breadpad-shared's own bread-theme dependency is tag-pinned
to a release before this feature existed.
Two more views: "reminder" (the alert window from run_reminder_window,
normally only reachable via a real due note through `fire <id>`) and
"reminder-snooze" (same window, snooze popover open).
Screenshot mode builds a throwaway sample Note directly instead of going
through cmd_fire's Store lookup — main() checks for these two view names
before ever reaching run_popup's dispatch, since the reminder window is
a completely separate GApplication entry point, not reachable through
the compose-popup path screenshot mode already covered.
Same NON_UNIQUE-on-screenshot-mode fix as run_popup already had, applied
to the reminder window's own Application builder.
--view (and now --screenshot) already opened any named stack page
directly, so the other 9 pages (upcoming/todo/reminder/idea/note/
question/archive/settings/errors) needed zero new code — just registry
entries in bread-capture.
Two more real windows needed actual wiring: the per-note editor popover
(editor::build_editor_popover, normally only reachable via a specific
note card's edit button — screenshot mode calls the builder directly
against the first real note in the store instead, since there's no
button handle to synthesize a click on) and the "New Note" modal
(show_add_note_window, same on_build-hook pattern already used for
breadbar's wifi add-network dialog).
The editor popover's first attempt parented it to the whole window,
which put it at GTK4 Popover's default Top position — entirely above the
window, clipped off the canvas in every capture despite mapping
successfully (no error, just invisible). Anchoring to a real button
(new_note_btn) with an explicit Bottom position fixed it.
Same reasoning as breadpad, extending breadman's own hand-rolled arg
parser rather than adding clap. --screenshot <view> doubles as the view
selector — breadman already supports opening directly to a named stack
page via --view/initial_view, so this just feeds that same mechanism
instead of needing a separate one. Full known-size canvas capture, plain
top-level window (not layer-shell).
Also fixes the same NON_UNIQUE footgun as breadpad/breadbox/etc.
Same reasoning as breadbar/breadbox/breadclip/breadsearch, but plumbed
through breadpad's own hand-rolled arg parser (mod args) instead of clap
— breadpad doesn't use clap at all, and adding a second, separate clap
parser alongside the existing one would reject every one of breadpad's
real flags (--type, --no-classify, --status, fire, calendar, ...) the
moment it saw one clap didn't recognize. --screenshot/--output/--width/
--height are just three more fields on the same Args struct.
Only the "popup" view (the compose window) is wired up — the reminder
window needs a real stored Note to render, not worth fabricating one
just for a screenshot pass.
Also fixes the same single-instance footgun as the other apps: without
NON_UNIQUE, a screenshot run would just toggle-close the operator's real
already-open popup instead of getting its own window.
bakery already fully covers what the PKGBUILD provided (binary, systemd
--user service where applicable, dependency declarations) except a LICENSE
copy, which bakery.toml's new license_file field now closes. Removes
packaging/arch/ and .forgejo/workflows/package.yml; adds the LICENSE
artifact to each release/dev-release/beta-release workflow's prepare
step. Not pacman-installed inside BOS today (BOS already consumes these
apps exclusively via build-local.sh's skel-staging), so this only removes
the option to `pacman -S` outside of BOS/bakery.
Documents the dev/beta/main branch and release-track workflow shared
across the bread ecosystem. See bread-ecosystem's docs/release-channels.md
for the full policy this implements.
Beta is now a real stabilization branch: publishes on every push to
`beta` (mirroring dev's model, auto-versioned X.Y.Z-beta.<ts>+<sha>,
base version from the latest published tag) instead of a manual
beta-v* tag. Fixes made during the freeze land via fix/<issue> branches
merged into `beta` directly. The gen-index.sh clone for beta pulls
bread-ecosystem's default branch (main) rather than pinning to dev,
since beta is the more stable track and main now carries the
TRACK-aware script.
Cargo.toml can drift stale relative to the actual last release (observed
on breadbox/breadpad/breadcrumbs/breadpaper), which made the auto-bumped
dev version sort as OLDER than what's already installed — bakery's semver
check correctly refused those "updates". Deriving the base version from
git ls-remote --tags instead is self-healing regardless of Cargo.toml
drift, with a Cargo.toml fallback only for a repo with no tags yet.
The fixed /tmp/bread-ecosystem-ci path races when multiple repos' dev/beta
workflows run close together on the same self-hosted runner — one job's
rm -rf/clone can stomp another's in-progress checkout, causing the
regenerate-index step to fail intermittently. Switch to mktemp -d.
Adds dev-release.yml (publishes on every push to dev) and beta-release.yml
(publishes on a beta-v* tag), mirroring the pattern landing in
bread-ecosystem/bread. See bread-ecosystem/docs/release-channels.md for
the three-track policy.