Commit Graph
10 Commits
Author SHA1 Message Date
Jean-Pierre MartineauandClaude Fable 5 36e8173b5a Map: arrows-only movement, find-as-you-type node filter
Panning is the arrow keys (Shift for fine), zoom is PgUp/PgDn alone, and
reset moves to Home — freeing every letter and +/- so typing can drive a
live name filter instead: matches keep bright white labels and always win
the label contest, everything else dims to bare context glyphs, Enter
frames the matches, Backspace edits, and Esc peels the filter before the
map. The footer swaps to the query while a find is active, the title
counts matches, and the location picker follows the same movement keys
with find disabled (typing there has no job). Hints fit 72 columns.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-11 15:17:33 -04:00
Jean-Pierre MartineauandClaude Opus 4.8 99643f52d9 Overhaul the config editor into a modal-dialog experience
Rework the device-configuration screen from a flat list with an
advert-laden "danger zone" into one grouped menu whose every prompt is
a real floating modal popup over a persistent backdrop, matching the
quit dialog. The main menu now stays pushed on the session stack for
the whole editor session, so sub-prompts float over it rather than
replacing the screen.

Settings are staged and applied together (with a dirty-cancel
confirmation); device actions — adverts, reboot, backup/restore,
identity key, factory reset — run immediately behind their own
dialogs. Adverts get a dedicated menu (zero-hop, flood, or share this
node as a QR/URI contact card). Destructive actions gate behind a new
TypedConfirmDialog that requires typing RESET / IMPORT. Reboot hands
off to the reconnect dialog and waits for the companion to return.
Location can be set by pointing at the full-screen map (new
LocationPickScreen) or by typing coordinates.

Make every dialog consistent: a short title in the border, the
instruction as an in-body prompt, and a width sized to its content
instead of a fixed wide cap. TextScreen/SelectScreen/AutocompleteScreen
gain an optional in-body prompt, and those plus ConfirmScreen gain a
dialog_width; the prompt is threaded through the surface and session.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-09 22:28:42 -04:00
Jean-Pierre MartineauandClaude Opus 4.8 b02e3b9f4b Always render the map in braille, dropping block mode
The block-element fallback halved the vertical resolution and looked
poor, so remove the braille/block toggle entirely. Drops the `t` key,
the persisted map_block preference, and the quadrant-glyph rendering
path; the map now always draws 2x4 braille dots.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-08 23:18:51 -04:00
Jean-Pierre MartineauandClaude Opus 4.8 bfae10b387 Repaint the map's edge instead of the whole frame, and remember the mode
The braille base map leans on glyphs a terminal font may lack; the terminal
draws each missing glyph as a double-width fallback, which shoves the row and
smears the panel's right padding and border. prompt_toolkit's differential
paint models those cells as single-width, so its picture of the screen diverges
from the terminal and it never rewrites the smear.

The previous fix forced a full-frame repaint every paint while in braille mode,
which the 1s header-refresh tick turned into a visible periodic flicker. Replace
it with a targeted scrub: after a move, force just the two right-edge columns
(padding + border) to repaint by poking a sentinel into pt's cached frame. The
map body redraws wholesale as it pans, so its interior self-heals; only the
static edge needed help. Block mode can't smear, so it scrubs nothing.

Also:
- Persist the braille/block mode (app_state.map_block) so the map reopens the
  way it was left; braille stays the default.
- Blank the frame on exit (drop pt's cached frame once) so the menu drawn
  underneath doesn't inherit leftover braille garbage.
- Reword the t hint to "toggle braille/block".

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-08 22:20:09 -04:00
Jean-Pierre MartineauandClaude Opus 4.8 97557fc9b8 Frame the map's dense node core by default, tunable with --fraction
The default view fitted every located node, so a few distant outliers
(here a node near Toronto, 500+ km from the Montréal core) zoomed the
whole mesh out to a continental scale. Frame the densest half instead —
the nodes nearest the median centre — so the map opens on a useful local
region; the rest simply fall off the edges. Verified against a live
159-node mesh: 0.5 lands on the Greater Montréal metro (~77 km across,
two-thirds of nodes visible) rather than eastern Canada.

Viewport.fit gains a `fraction` argument (default 1.0, unchanged for
existing callers); the map's opening view and `r` reset pass 0.5, and
`meshterm map --fraction/-f` exposes the knob on the CLI.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-07 22:03:26 -04:00
Jean-Pierre MartineauandClaude Opus 4.8 2ec18138a7 Rename project from MeshTools to MeshTerm
Rename the package directory, imports, brand strings, env-var prefixes,
console-script entry point, and the config/data dir (~/.config/meshterm).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-07 19:40:49 -04:00
Jean-Pierre MartineauandClaude Opus 4.8 850a1b3f34 Remember the map viewport across sessions
The interactive map now reopens on the centre and zoom the user left it
at, instead of always refitting to the nodes. Adds a generic app_state
key/value table (schema v6) and typed repository accessors; MapScreen
restores a saved view on open and persists every pan/zoom. Pressing r
still refits to the nodes.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-07 19:12:40 -04:00
Jean-Pierre MartineauandClaude Opus 4.8 a9091006eb Brighten map markers where nodes pile on one cell
A braille cell shows a single glyph, so nodes landing on the same spot
hid the crowd behind one marker. Count the nodes per cell and wash the
surviving glyph toward white on a log2 ramp, so a bright marker reads as
a busy cluster. Shape still encodes node type; only brightness encodes
count. A lone node keeps its exact base colour.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-07 18:41:24 -04:00
Jean-Pierre MartineauandClaude Opus 4.8 8c1c9959e3 Plot contacts on the map and add fine cell-by-cell panning
Drive map markers from the device's contact list, the authoritative
source for a node's name, type, and advertised position, enriching each
with reception detail from passive-monitor observations when overheard.
Contacts advertising 0.0/0.0 (null island) are treated as unlocated.

On crowded maps, draw every marker glyph but place labels highest-
priority first (self, then repeaters, then leaf nodes), dropping labels
that would collide so important ones win the space. Labels now also keep
a one-row vertical gap so dense areas don't silt into a block of text.

Add Shift+arrow / uppercase WASD to pan by a single character cell for
fine positioning.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-07 17:52:05 -04:00
Jean-Pierre MartineauandClaude Opus 4.8 d652a4e012 Add an interactive braille OpenStreetMap map of mesh nodes
New `map` tool (menu + `meshtools map` CLI) that plots the mesh's
location-sharing nodes over a real OSM street basemap rendered as Unicode
braille — streets, rivers, water, and place names — the mapscii idea, but
able to plot our own nodes and live inside the TUI.

- core/mvt.py: dependency-free MVT/protobuf vector-tile decoder.
- core/geo.py: Web Mercator + a pannable/zoomable Viewport and tile math.
- services/basemap.py: OpenFreeMap vector tiles (free, no API key), resolved
  from the versioned TileJSON, disk-cached, offline-safe (stdlib urllib only).
- ui/mapcanvas.py: colored braille canvas (per-cell priority, line raster,
  polygon fill, collision-avoided labels), emits truecolor ANSI.
- ui/map_render.py: compositor — basemap styling + node markers with names.
- ui/map_screen.py: full-screen screen; wasd/arrows pan, =/- zoom, r reset,
  Esc/q exit; background tile loading. Offline falls back to nodes on a grid.
- tools/map.py: interactive in the menu, one-shot static render on the CLI.

Repeaters are prioritised over leaf nodes via advert type: threaded `node_type`
through Observation/HeardNode and the persistence layer (schema v4->v5, with an
idempotent migration adding observations.node_type). Added
TuiSession.base_body_size() so a full-screen screen can size itself to the frame.

Tests: tests/test_map.py (24) cover MVT decode against a real cached tile
fixture, projection, the canvas, the compositor, offline behavior, and the
interactive pan/zoom/reset logic. Full suite: 261 passing.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-07 17:38:39 -04:00