Add Command to mark reminders as done #274

Closed
opened 2026-10-16 17:49:45 +02:00 by kfickel · 2 comments
Owner

Add append to file command

add streamd <file-command> append (content of the line) that adds a shard on top-level to the end of the file the corresponding file-command would have opened / created.

The line should be a H1-heading #, with if added to an existing file with a leading line before and a date + time marker (so that it's marked as "now") if the shard would have a different value otherwise (can only become time value if date is already correct).

Change Remind Commands to have a fixed name

Instead of a rule list, it should be a command

[commands.remind.called_xyz]
name = "Go, call @XYZ"
start = 2026-10-11
trigger = { since = "FREQ=WEEKLY;BYDAY=SU;BYHOUR=9;BYMINUTE=0;BYSECOND=0" }
expect = { remind = "CalledXYZ" }

Add streamd <remind command> done

  • add a configuration option "into_file" that contains a file command name. This will add the tags required to silence the reminder for now.

Android App

Reminders in the Config or top of the stream should have a button "Done" on the buttom right that uses the logic from streamd <remind command> done to mark the reminder as done.

The text of the reminder should not be mentioned twice, that doesn't look too great.

# Add `append` to file command add `streamd <file-command> append (content of the line)` that adds a shard on top-level to the end of the file the corresponding file-command would have opened / created. The line should be a H1-heading `#`, with if added to an existing file with a leading line before and a date + time marker (so that it's marked as "now") if the shard would have a different value otherwise (can only become time value if date is already correct). # Change Remind Commands to have a fixed name Instead of a rule list, it should be a command ``` [commands.remind.called_xyz] name = "Go, call @XYZ" start = 2026-10-11 trigger = { since = "FREQ=WEEKLY;BYDAY=SU;BYHOUR=9;BYMINUTE=0;BYSECOND=0" } expect = { remind = "CalledXYZ" } ``` # Add `streamd <remind command> done` * add a configuration option "into_file" that contains a file command name. This will add the tags required to silence the reminder for now. # Android App Reminders in the Config or top of the stream should have a button "Done" on the buttom right that uses the logic from `streamd <remind command> done` to mark the reminder as done. The text of the reminder should not be mentioned twice, that doesn't look too great.
kfickel changed title from Add Command to mark rem to Add Command to mark reminders as done 2026-10-16 17:49:52 +02:00
Collaborator

Implementation plan

Decisions (from refinement)

  • One command per reminder. [[commands.<key>.rules]] is removed. Each reminder is its own [commands.<key>] with type = "reminder". The rule's fields move up into the command: description, start, trigger, expect, and the new optional into_file. There is no name field: the description is the reminder's text (Go, call @XYZ: due since 2026-10-11 09:00 (never)), and the key is used when it is missing.
    [commands.called_xyz]
    type = "reminder"
    description = "Go, call @XYZ"
    start = 2026-10-11
    trigger = { since = "FREQ=WEEKLY;BYDAY=SU;BYHOUR=9;BYMINUTE=0;BYSECOND=0" }
    expect = { remind = "CalledXYZ" }
    into_file = "daily"
    
    An old rules field is rejected with a message that says how to rewrite it: one [commands.<key>] per rule.
  • The line that is written has only tags and markers, no text: # @CalledXYZ @143000. A date marker is added only when it is needed (see below).
  • done supports only days and since reminders. For if reminders (which are due per past day), done fails, and the app shows no Done button.
  • Creating a file: when append/done has to create the target file, the file holds only the line, not the template. The file name already gives the moment, so no markers are added.
  • into_file is optional. Without it, streamd <key> done fails with a clear message, and the app shows no Done button.
  • One shared view for all reminders: the TUI gets a single reminder view (the due reminders of all reminder commands). Reminder commands get no tab of their own. In the app, reminder commands stay out of the bottom bar and the pins, as now. They are listed under Reminders in All.

1. Core: append on file commands (commands/file/)

New in commands/file/target.rs (or a new append.rs), on a StreamStore:

  • pub fn append(store, shards, command: &FileCommand, line_body: &str, now, tz, config) -> Result<Appended, CoreError>:
    1. Resolve the target as target does for the current span: the existing match of the span, else a file to create. Reuse file_target, but do not create the template file.
    2. Existing file (Appended::Existing { id }): read it, add \n if it does not end in one, add a blank line, then # <markers> <body>\n. Write it.
    3. Missing file (Appended::Created { id }): create_new with the content # <body>\n alone (no template, no markers), named as file_name(command, now).
  • Moment markers (fn moment_markers(file_moment, now, tz) -> Vec<String>), pure: the shard must read as now. If the local date of the file's moment equals today, only @HHMMSS is added. Otherwise @YYYYMMDD @HHMMSS is added. A created file needs none. Unit-test this next to local_to_utc edge cases (DST).
  • If the match is a section in another file, append at the end of that file (top level). Document this.
  • api.rs: append_to_file(project, stream, store, key, body, now) -> Appended. Add Appended to streamd-ffi (records.rs) and as a Project method.

CLI (commands/file/cli.rs / run.rs): streamd <file-key> append <TEXT...> (the words are joined by spaces). It cannot be combined with a date, edit or -i (usage error, exit 2). It prints Appended to <path> or Created <path> (paths as in R21). It does not open an editor. <TEXT> is written as given; leading tags in it become markers, so streamd daily append @Task call Bob works.

2. Core: reminder configuration (config/project/)

  • file.rs: ReminderCommandFile { description, expect, trigger, start, into_file }, with deny_unknown_fields. ReminderRuleFile is removed. rules becomes a dedicated error (reminders have no rules anymore; write one [commands.<key>] with type = "reminder" per rule). Hook it into the hand-written command reading so the error keeps its line.
  • validate.rs → runtime ReminderCommand { description: Option<String>, expect, trigger, start, into_file: Option<String> }. The ReminderRule struct is removed, and its expects moves onto the command. Validation is as in R29 today, at commands.<key>.expect… / .trigger…. In addition:
    • into_file MUST name a configured file command (typo suggestion via closest).
    • With into_file, the trigger MUST NOT be if (`done` cannot mark a day in the past; remove into_file or use days/since).
    • With into_file, the done tags MUST be derivable (see §3). Otherwise: no tag places { remind = "CalledXYZ" } on its own, so done cannot write it; … (listing and suggestions as in R31 rule 2).
  • due.rs: due_reminders works on one command, and DueReminder.rule becomes the command's display text (description or key). stream_reminders keeps the (key, DueReminder) pairs. summary() is unchanged.
  • Update everything that knows rules: schema.rs (fields of ConfigTable::Command(Reminder)), complete.rs (values offered in expect / if are now at the command's top level, plus into_file completing file command keys), index.rs (the occurrences in expect/if, and into_file as a reference to a command so rename_command updates it), rename.rs (rename_command also rewrites into_file), outline.rs and change.rs (a reminder command has the rule's fields directly; a field added to the file model needs its line in change.rs), and locate.rs.
  • init.toml: replace the commented [commands.remind] + rules with commented examples of two reminder commands, one with into_file = "daily". Mention streamd <key> done.

3. Core: done

  • commands/reminder/done.rs:
    • pub fn done_tags(command: &ReminderCommand, file: &FileCommand, config) -> Option<Vec<String>>, pure. For each alternative of expect in order: remove the entries that the file command's placement already gives (its files carry them). Then find one configured tag whose unconditional rules (no with), applied alone, place every remaining entry. The approach is analogous to file_types_placing: run placement_of a shard with only that marker. The first alternative that has such a tag wins. If several tags qualify, the canonical one that sorts first by name wins (deterministic). An empty remainder needs no tag, but the line is still written for its moment. Returns the tags written as @Name (never an alias, as derivations never write one).
    • pub fn done(store, shards, project, key, now, tz) -> Result<Appended, CoreError>: it checks that the command is a reminder with into_file, and not if. Then it calls append of §1 with the body @Tag (+ markers from moment_markers). New CoreError variants: NoIntoFile { key } and DoneNotSupported { key } (for if), each with a wording. Add them to StreamdException in streamd-ffi/error.rs.
    • done is allowed even when the reminder is not due (it just records it). It is idempotent in effect.
  • api.rs: reminder_done(project, stream, store, key, now) -> Appended, and can_mark_done(project, key) -> bool (into_file set and the trigger is not if) for the hosts. Bind both in streamd-ffi/project.rs. Add done: Boolean to the due-reminder record (or expose canMarkDone) and add key to the record so the app knows what to call.
  • Tests on MemoryStore: appending to today's daily (only @HHMMSS), to an older match (date + time), to a created file (line only), an alias in expect (writes the canonical tag), expect already satisfied by the file placement, a since reminder that is no longer due afterwards (due_reminders on the reloaded stream is empty), and the errors.

4. CLI

  • streamd <reminder-key> still prints its due line or Nothing due.
  • streamd <reminder-key> done calls done through FsStore and prints Marked <description> as done in <path>. Without into_file / with if, it prints the core's error, exit 1.
  • Front-end (commands/frontend/views.rs, commands/reminder/interactive/): reminder commands are no longer tabs. One built-in view remind is built next to the maintenance (like config, apart from the others, but only if at least one reminder command exists). It lists the due reminders of all reminder commands, with the key bar j/k move e edit d done r reload. d runs done on the selected reminder (if it cannot be marked done, the status line says why), then reloads. streamd <reminder-key> -i opens the front-end on this view with that reminder selected.
  • LSP: diagnostics and config_actions that iterate rules are adapted. Optionally offer a code action "Mark as done" — not in scope, skip.

5. Android

  • core/StreamCard.kt: Reminder gets key: String and canMarkDone: Boolean. The summary stays and rule is dropped (it was the duplicated text).
  • core/StreamSession.kt: reminderDone(key) → project.reminderDone(stream, store, key, now), then changed(id) of the appended/created file. It goes through RepositoryConnection.written(id) in the view model, so a commit-every-save commits it.
  • StreamViewModel / StreamReading: markDone(key). A failure is shown as a snackbar with reason().
  • ui/Stream.kt (reminder banners) and ui/AllCommands.kt (Reminders section): each reminder row shows the summary once (no second line with the rule name). When canMarkDone, a "Done" text button sits at the bottom right of the banner. Tapping the row still opens the file of an if reminder. Build this on Banner in Components.kt (with an optional action slot) so both screens share it.
  • Config UI (ConfigCommandForms.kt ReminderFields, ConfigList.kt ruleText/commandText, ConfigDraft.newCommand): the reminder form edits description, expect, trigger, start directly (no rule list), plus into_file as a ChoiceEntry of the file commands. FFI ReminderSettings changes accordingly (outline.rs, with its round-trip test).
  • Screenshot tests: update StreamScreenshots (reminders with and without Done), AllCommandsScreenshots, ConfigScreenshots / ConfigEditScreenshots (reminder form). Re-record and review every changed image.

6. Documentation

  • REQUIREMENTS.md: rewrite R29 (one command per reminder, the fields, the validation of into_file and the done tags, streamd <key> done, the shared view with d). Extend R31 with append (the target, the line, the moment markers, the created file without template). Update R28's field list for reminder, R30 (the shared reminder view instead of one tab per command), and the app requirement for the Done button.
  • README.md: the reminder examples, streamd <key> done, streamd <key> append.
  • AGENTS.md: the commands/reminder/ description (done.rs, no rules), commands/file/ (append), the front-end's built-in reminder view, the facade functions (append_to_file, reminder_done, can_mark_done), and the Android Reminder fields / markDone.

Order of work (each its own commit)

  1. feat(file): append a line to the file of a file command (core + CLI + FFI)
  2. feat(reminder)!: one command per reminder (config model, validation, outline/change/index/complete/schema, init.toml, CLI, LSP, FFI records, app config forms). This is a breaking config change.
  3. feat(reminder): mark a reminder as done into a file command (core done, CLI done, shared TUI view with d)
  4. feat(android): mark reminders as done, show their text once
  5. docs: …

Run cargo test, nix flake check and nix build .#streamd-app (screenshot validation) at the end.

# Implementation plan ## Decisions (from refinement) - **One command per reminder.** `[[commands.<key>.rules]]` is removed. Each reminder is its own `[commands.<key>]` with `type = "reminder"`. The rule's fields move up into the command: `description`, `start`, `trigger`, `expect`, and the new optional `into_file`. There is no `name` field: the **`description` is the reminder's text** (`Go, call @XYZ: due since 2026-10-11 09:00 (never)`), and the key is used when it is missing. ```toml [commands.called_xyz] type = "reminder" description = "Go, call @XYZ" start = 2026-10-11 trigger = { since = "FREQ=WEEKLY;BYDAY=SU;BYHOUR=9;BYMINUTE=0;BYSECOND=0" } expect = { remind = "CalledXYZ" } into_file = "daily" ``` An old `rules` field is rejected with a message that says how to rewrite it: one `[commands.<key>]` per rule. - **The line that is written** has only tags and markers, no text: `# @CalledXYZ @143000`. A date marker is added only when it is needed (see below). - **`done` supports only `days` and `since` reminders.** For `if` reminders (which are due per past day), `done` fails, and the app shows no Done button. - **Creating a file:** when `append`/`done` has to create the target file, the file holds **only the line**, not the template. The file name already gives the moment, so no markers are added. - **`into_file` is optional.** Without it, `streamd <key> done` fails with a clear message, and the app shows no Done button. - **One shared view** for all reminders: the TUI gets a single reminder view (the due reminders of all reminder commands). Reminder commands get no tab of their own. In the app, reminder commands stay out of the bottom bar and the pins, as now. They are listed under Reminders in All. ## 1. Core: `append` on file commands (`commands/file/`) New in `commands/file/target.rs` (or a new `append.rs`), on a `StreamStore`: - `pub fn append(store, shards, command: &FileCommand, line_body: &str, now, tz, config) -> Result<Appended, CoreError>`: 1. Resolve the target as `target` does for the current span: the existing match of the span, else a file to create. Reuse `file_target`, but do **not** create the template file. 2. **Existing file** (`Appended::Existing { id }`): read it, add `\n` if it does not end in one, add a blank line, then `# <markers> <body>\n`. Write it. 3. **Missing file** (`Appended::Created { id }`): `create_new` with the content `# <body>\n` alone (no template, no markers), named as `file_name(command, now)`. - **Moment markers** (`fn moment_markers(file_moment, now, tz) -> Vec<String>`), pure: the shard must read as *now*. If the local date of the file's moment equals today, only `@HHMMSS` is added. Otherwise `@YYYYMMDD @HHMMSS` is added. A created file needs none. Unit-test this next to `local_to_utc` edge cases (DST). - If the match is a section in another file, append at the end of **that file** (top level). Document this. - `api.rs`: `append_to_file(project, stream, store, key, body, now) -> Appended`. Add `Appended` to `streamd-ffi` (`records.rs`) and as a `Project` method. CLI (`commands/file/cli.rs` / `run.rs`): `streamd <file-key> append <TEXT...>` (the words are joined by spaces). It cannot be combined with a date, `edit` or `-i` (usage error, exit 2). It prints `Appended to <path>` or `Created <path>` (paths as in R21). It does not open an editor. `<TEXT>` is written as given; leading tags in it become markers, so `streamd daily append @Task call Bob` works. ## 2. Core: reminder configuration (`config/project/`) - `file.rs`: `ReminderCommandFile { description, expect, trigger, start, into_file }`, with `deny_unknown_fields`. `ReminderRuleFile` is removed. `rules` becomes a dedicated error (`reminders have no rules anymore; write one [commands.<key>] with type = "reminder" per rule`). Hook it into the hand-written command reading so the error keeps its line. - `validate.rs` → runtime `ReminderCommand { description: Option<String>, expect, trigger, start, into_file: Option<String> }`. The `ReminderRule` struct is removed, and its `expects` moves onto the command. Validation is as in R29 today, at `commands.<key>.expect…` / `.trigger…`. In addition: - `into_file` MUST name a configured **file command** (typo suggestion via `closest`). - With `into_file`, the trigger MUST NOT be `if` (`` `done` cannot mark a day in the past; remove into_file or use days/since ``). - With `into_file`, the **done tags** MUST be derivable (see §3). Otherwise: `no tag places { remind = "CalledXYZ" } on its own, so done cannot write it; …` (listing and suggestions as in R31 rule 2). - `due.rs`: `due_reminders` works on one command, and `DueReminder.rule` becomes the command's display text (`description` or key). `stream_reminders` keeps the `(key, DueReminder)` pairs. `summary()` is unchanged. - Update everything that knows `rules`: `schema.rs` (fields of `ConfigTable::Command(Reminder)`), `complete.rs` (values offered in `expect` / `if` are now at the command's top level, plus `into_file` completing file command keys), `index.rs` (the occurrences in `expect`/`if`, and `into_file` as a reference to a command so `rename_command` updates it), `rename.rs` (`rename_command` also rewrites `into_file`), `outline.rs` and `change.rs` (a reminder command has the rule's fields directly; **a field added to the file model needs its line in `change.rs`**), and `locate.rs`. - `init.toml`: replace the commented `[commands.remind]` + rules with commented examples of two reminder commands, one with `into_file = "daily"`. Mention `streamd <key> done`. ## 3. Core: `done` - `commands/reminder/done.rs`: - `pub fn done_tags(command: &ReminderCommand, file: &FileCommand, config) -> Option<Vec<String>>`, pure. For each alternative of `expect` in order: remove the entries that the file command's `placement` already gives (its files carry them). Then find **one configured tag** whose unconditional rules (no `with`), applied alone, place every remaining entry. The approach is analogous to `file_types_placing`: run `placement_of` a shard with only that marker. The first alternative that has such a tag wins. If several tags qualify, the canonical one that sorts first by name wins (deterministic). An empty remainder needs no tag, but the line is still written for its moment. Returns the tags written as `@Name` (never an alias, as derivations never write one). - `pub fn done(store, shards, project, key, now, tz) -> Result<Appended, CoreError>`: it checks that the command is a reminder with `into_file`, and not `if`. Then it calls `append` of §1 with the body `@Tag` (+ markers from `moment_markers`). New `CoreError` variants: `NoIntoFile { key }` and `DoneNotSupported { key }` (for `if`), each with a wording. **Add them to `StreamdException`** in `streamd-ffi/error.rs`. - `done` is allowed even when the reminder is not due (it just records it). It is idempotent in effect. - `api.rs`: `reminder_done(project, stream, store, key, now) -> Appended`, and `can_mark_done(project, key) -> bool` (into_file set and the trigger is not `if`) for the hosts. Bind both in `streamd-ffi/project.rs`. Add `done: Boolean` to the due-reminder record (or expose `canMarkDone`) and add `key` to the record so the app knows what to call. - Tests on `MemoryStore`: appending to today's daily (only `@HHMMSS`), to an older match (date + time), to a created file (line only), an alias in `expect` (writes the canonical tag), `expect` already satisfied by the file placement, a `since` reminder that is no longer due afterwards (`due_reminders` on the reloaded stream is empty), and the errors. ## 4. CLI - `streamd <reminder-key>` still prints its due line or `Nothing due`. - `streamd <reminder-key> done` calls `done` through `FsStore` and prints `Marked <description> as done in <path>`. Without `into_file` / with `if`, it prints the core's error, exit 1. - Front-end (`commands/frontend/views.rs`, `commands/reminder/interactive/`): reminder commands are no longer tabs. One built-in view `remind` is built next to the maintenance (like `config`, apart from the others, but only if at least one reminder command exists). It lists the due reminders of **all** reminder commands, with the key bar `j/k move e edit d done r reload`. `d` runs `done` on the selected reminder (if it cannot be marked done, the status line says why), then reloads. `streamd <reminder-key> -i` opens the front-end on this view with that reminder selected. - LSP: diagnostics and `config_actions` that iterate `rules` are adapted. Optionally offer a code action "Mark as done" — **not in scope**, skip. ## 5. Android - `core/StreamCard.kt`: `Reminder` gets `key: String` and `canMarkDone: Boolean`. The `summary` stays and `rule` is **dropped** (it was the duplicated text). - `core/StreamSession.kt`: `reminderDone(key)` → `project.reminderDone(stream, store, key, now)`, then `changed(id)` of the appended/created file. It goes through `RepositoryConnection.written(id)` in the view model, so a commit-every-save commits it. - `StreamViewModel` / `StreamReading`: `markDone(key)`. A failure is shown as a snackbar with `reason()`. - `ui/Stream.kt` (reminder banners) and `ui/AllCommands.kt` (Reminders section): each reminder row shows the **summary once** (no second line with the rule name). When `canMarkDone`, a **"Done" text button sits at the bottom right** of the banner. Tapping the row still opens the file of an `if` reminder. Build this on `Banner` in `Components.kt` (with an optional action slot) so both screens share it. - Config UI (`ConfigCommandForms.kt` `ReminderFields`, `ConfigList.kt` `ruleText`/`commandText`, `ConfigDraft.newCommand`): the reminder form edits `description`, `expect`, `trigger`, `start` directly (no rule list), plus `into_file` as a `ChoiceEntry` of the file commands. FFI `ReminderSettings` changes accordingly (`outline.rs`, with its round-trip test). - Screenshot tests: update `StreamScreenshots` (reminders with and without Done), `AllCommandsScreenshots`, `ConfigScreenshots` / `ConfigEditScreenshots` (reminder form). Re-record and review every changed image. ## 6. Documentation - `REQUIREMENTS.md`: rewrite **R29** (one command per reminder, the fields, the validation of `into_file` and the done tags, `streamd <key> done`, the shared view with `d`). Extend **R31** with `append` (the target, the line, the moment markers, the created file without template). Update R28's field list for `reminder`, R30 (the shared reminder view instead of one tab per command), and the app requirement for the Done button. - `README.md`: the reminder examples, `streamd <key> done`, `streamd <key> append`. - `AGENTS.md`: the `commands/reminder/` description (`done.rs`, no rules), `commands/file/` (`append`), the front-end's built-in reminder view, the facade functions (`append_to_file`, `reminder_done`, `can_mark_done`), and the Android `Reminder` fields / `markDone`. ## Order of work (each its own commit) 1. `feat(file): append a line to the file of a file command` (core + CLI + FFI) 2. `feat(reminder)!: one command per reminder` (config model, validation, outline/change/index/complete/schema, init.toml, CLI, LSP, FFI records, app config forms). This is a breaking config change. 3. `feat(reminder): mark a reminder as done into a file command` (core `done`, CLI `done`, shared TUI view with `d`) 4. `feat(android): mark reminders as done, show their text once` 5. `docs: …` Run `cargo test`, `nix flake check` and `nix build .#streamd-app` (screenshot validation) at the end.
Collaborator

Implemented in #275.

Effort: about 36 minutes of wall-clock time by the session's clock, and roughly 375k tokens (an estimate from the session's token budget, not an exact count).

Findings during the implementation

  • done can only write a reminder off if some tag places what it expects on its own. A reminder that expects only a file type (expect = { file_type = "daily" }) cannot be done into a file command, so validation rejects such an into_file instead of failing later. The issue's example (expect = { remind = "CalledXYZ" }) needs a tag such as [tags.CalledXYZ] with dimension = "remind".
  • The issue's syntax [commands.remind.called_xyz] became [commands.called_xyz], as decided in refinement. Command keys may not contain _ (the init examples are daily-note and weekly-review).
  • The tag the file's type hands down is taken into account: if the target file already places what is expected, done writes only the moment markers.
  • The moment markers go after the tags the line starts with (# @Task @143000 call Bob), so they always stay among the shard's markers.
  • A match that is a section of another file gets the line at the end of that file, at the top level. The line then inherits the file's placement, not the section's.
  • Since there is no longer one tab per reminder, the front-end got a second built-in tab, remind. tui::tab_line_apart now takes a list of tabs apart.
  • In the app, a failed Done shows its reason inside the reminder rather than in a snackbar, because the Stream and All screens have no snackbar host.
  • An existing app session test needed a file command in its configuration once into_file was validated.
  • Not tried on a device or the emulator; the app is checked by its unit and screenshot tests.
Implemented in #275. **Effort:** about 36 minutes of wall-clock time by the session's clock, and roughly 375k tokens (an estimate from the session's token budget, not an exact count). **Findings during the implementation** - `done` can only write a reminder off if some tag places what it expects on its own. A reminder that expects only a file type (`expect = { file_type = "daily" }`) cannot be done into a file command, so validation rejects such an `into_file` instead of failing later. The issue's example (`expect = { remind = "CalledXYZ" }`) needs a tag such as `[tags.CalledXYZ]` with `dimension = "remind"`. - The issue's syntax `[commands.remind.called_xyz]` became `[commands.called_xyz]`, as decided in refinement. Command keys may not contain `_` (the init examples are `daily-note` and `weekly-review`). - The tag the file's type hands down is taken into account: if the target file already places what is expected, `done` writes only the moment markers. - The moment markers go after the tags the line starts with (`# @Task @143000 call Bob`), so they always stay among the shard's markers. - A match that is a section of another file gets the line at the end of that file, at the top level. The line then inherits the file's placement, not the section's. - Since there is no longer one tab per reminder, the front-end got a second built-in tab, `remind`. `tui::tab_line_apart` now takes a list of tabs apart. - In the app, a failed Done shows its reason inside the reminder rather than in a snackbar, because the Stream and All screens have no snackbar host. - An existing app session test needed a file command in its configuration once `into_file` was validated. - Not tried on a device or the emulator; the app is checked by its unit and screenshot tests.
Sign in to join this conversation.
No labels
android
cli
epic
planned
tui
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Reference
kfickel/streamd#274
No description provided.