mirror of
https://github.com/praktimarc/kst4contest.git
synced 2026-11-08 14:38:36 +01:00
Apply live beacon settings and improve station map (#164)
Apply beacon checkbox changes at runtime and keep the aggregate status chip synchronized. Improve explicit station-map navigation, spatial filter overlays, overlay legend, selected-path contrast, and the documented map screenshot.
This commit is contained in:
1 parent
4d96822c0c
commit
d925c83412
61 files changed
+2686
-299
No files matched your search
@@ -186,23 +186,25 @@ CR/LF framing, XML framing, ports/transports, callsign normalization and frequen
|
||||
|
||||
- Contest operating speed and low-friction interaction are primary goals.
|
||||
- Incidental code changes must not unexpectedly change selection, focus, sorting, tab state, map zoom or prefilled text.
|
||||
- Map reset clears the selected target without changing zoom unless explicitly redesigned.
|
||||
- Map reset clears the selected target and recentres on the local station without changing zoom.
|
||||
- **Grouping** changes only spatial clustering of the existing Compose map markers. It must not reload tiles or station data, request a new controller snapshot, or change zoom, viewport or selection.
|
||||
- Base-callsign aggregation into one geographical marker happens before screen-based clustering. Disabling clustering displays each resulting positionable map station individually but never splits active variants of the same normalised base callsign into separate geographical markers.
|
||||
- A hidden Station Map is not continuously refreshed. Relevant background changes mark it dirty; the next `showWindow()` performs one current full refresh before normal visible-window updates resume.
|
||||
- Maidenhead grid construction depends only on viewport bounds, zoom and WebView size. Ordinary station-data refreshes must not rebuild or serialise the grid when those inputs are unchanged.
|
||||
- Maidenhead grid construction depends only on viewport bounds, zoom and Compose-canvas size. Unwrapped viewport bounds may cross the international date line and must be split into valid world intervals without duplicating grid cells. Ordinary station-data refreshes must not rebuild the grid when those inputs are unchanged.
|
||||
- Panning updates viewport and grid state through `notifyViewport()` without rebuilding station markers or screen-based clusters. Zoom changes, station-data changes and clustering toggles still rebuild the marker layer.
|
||||
- Debug file logging reports Station Map refreshes only when total FX-thread refresh time reaches 100 ms. The diagnostic separates snapshot and render time and includes visible-member and station counts.
|
||||
- Station selection preserves the established `/cq callsign` prefill behaviour.
|
||||
- `StationSelectionState` is the canonical selection shared by the station table and Further Info panel. Its identity is the complete callsign plus chat category. Explicit actions carry a `StationSelectionSource` and increment a separate scroll-request revision even when the same station is selected again; roster reconciliation replaces the selected instance without moving the table.
|
||||
- `StationSelectionState` is the canonical selection shared by the station table and Further Info panel. Its identity is the complete callsign plus chat category. Explicit actions carry a `StationSelectionSource` and increment separate scroll and explicit-selection revisions even when the same station is selected again; roster reconciliation replaces the selected instance without moving the table or map.
|
||||
- Recent-join state is transient domain state keyed by complete callsign plus chat category. Only live `UA5`/`UA2` frames can create an entry; the `UA0`/`UE` initial or reconnect snapshot and `UM3` profile updates never do. Duplicate live updates do not renew the timestamp, a leave removes the entry, and a genuine rejoin begins a new ten-minute interval. The local login callsign is excluded. The core `ObservableRoster` is mirrored through `UiDispatcher`; New-joined actions reuse the canonical station selection and scroll request.
|
||||
- The station table starts with a case-insensitive ascending callsign sort. A user-selected sort remains authoritative across roster and filter updates. An externally selected filtered station is pinned into the table only; `filteredRows` remains the exact filter result used by the map.
|
||||
- The station table starts with a case-insensitive ascending callsign sort. A user-selected sort remains authoritative across roster and filter updates. An externally selected filtered station is pinned into the table. `filteredRows` remains the exact filter result used for ordinary map markers; the map renders the current filtered-out selection separately without counting or clustering it.
|
||||
- PM, Public, QSO-of-the-other, priority, timeline and individual map-marker actions route through the application-level station selector. Directed messages target the sender, except that an outgoing local PM targets its receiver. Public and QSO-of-the-other rows target their sender in the message category. Direct clicks and context clicks inside the station table select without issuing an automatic scroll request; selections originating in the map, messages, priority, New joined or other station controls issue one even when the identity was already selected.
|
||||
- The selected-station message radio mode is independent of station identity and always retains the complete callsign plus chat category. `PM_TO_ME` is the private conversation with the local station plus public traffic from the selected station carrying the structured leading `(LOCALCALL)` address, `PM_TO_OTHER` is private traffic sent by the selected station to other participants, `PUBLIC` is traffic sent by it to `ALL`, and `NOTHING` applies no additional type/receiver restriction. An arbitrary callsign mention in prose is not a structured public address.
|
||||
- ON4KST chat parsing records `messageDirectedToCommunity` from the receiver field and `messageDirectedToMe` from either a genuine private receiver or the exact leading public address. The selected-station Compose message mirror is initialized with the main window state, before the first selection callback, and roster changes recompute and push the filtered rows automatically.
|
||||
- The map's **Reset filters** action uses the same `StationFilterState.reset()` path as the main filter bar and does not change sort, selection, zoom, viewport or the display-only Grid-color toggle. Individual raw-callsign markers retain an already selected category variant; otherwise they use the configured Main category. Spatial clusters zoom and never choose an arbitrary member.
|
||||
- The user list and map share one station context-menu implementation. A secondary click selects a unique target through `StationSelectionState`; base-call markers or screen clusters containing several full-callsign/category identities first require an explicit target choice. Message snippets reuse the existing send-field action, and the context sked editor owns an isolated draft with the target fixed at opening time.
|
||||
- Map markers draw only the display callsign; bands, `B+`, locator and QRG details remain in tooltips. When Grid color is enabled, the canvas draws a black outline and a 30 percent black fill overlay for four-character squares from `WorkedGrossFieldCache.snapshotWorkedGrossFieldsAny()`, independently of visible station markers. The cache is rebuilt from SQLite at startup and is the same any-band state used by **Only new grids**.
|
||||
- Explicit station selections publish a map-navigation request separate from ordinary selected-state reconciliation. The map fits the complete home-to-target path with padding, preserves an already sufficient zoom and only zooms out when required. Explicit QTF field and compass-button actions preserve zoom and shift the local station 25 percent of the shorter canvas dimension opposite the selected bearing. Background roster changes, filter restoration, reset, rotor feedback and asynchronous path analysis never publish these requests; the latest explicit request wins. A selection without valid coordinates leaves the camera unchanged. Reset view clears selection and recentres on home without changing zoom.
|
||||
- Active QTF and QRB predicates are visualised by a distinct semi-transparent overlay using the same filter state and semantics: minimum QRB is exclusive, maximum QRB inclusive, and the QTF sector uses the configured complete beamwidth. An unbounded distance range is clipped by the visible canvas rather than a fabricated radio range. An empty minimum/maximum combination has no fill but retains both boundary lines. The actual antenna beam remains a separate overlay driven by `actualQTF`, `stn_antennaBeamWidthDeg` and `stn_maxQRBDefault`; applying Station settings refreshes its Compose-observable geometry immediately without issuing rotor commands. The map header shows a localized red/blue legend only for overlays that are currently drawable, and the legend reuses the exact canvas line colours rather than defining a parallel colour scheme.
|
||||
- The AP timeline renders the producer's four candidate lanes in order (two in-beam, two global priority) plus a separate sked lane. Its relative 0–30 minute axis normally uses five-minute ticks and increases the interval when labels would overlap. The vertical message splitter applies pane-specific minimums for the timeline, shortcut row and send row, so older stored divider positions cannot clip these fixed-height controls; stored positions remain the unconstrained baseline.
|
||||
- Sending without an explicitly selected send category preserves the established Main-category fallback unless explicitly changed.
|
||||
- The lower selected-station panel contains a vertical two-pane `SplitterPane`: the upper pane owns the independently scrollable message table, while the lower pane scrolls NOT-QRV and Sked above a pinned lookup group. The lower pane reserves 160 dp before stored divider positions are applied, so normal small-window layouts retain direct access to lookup actions; impossible smaller layouts keep the action groups scrollable. `GUIselectedCallSignSplitPane_dividerposition` persists this divider through the existing profile-scoped layout autosave. Station or message updates never reset it. Empty `DataTableView` instances retain their header and border and show an explicit empty-state label. Header metadata and message filters use width-aware flow layouts; the NOT-QRV and sked groups switch between a row and a column from the panel's actual Compose constraint, without duplicating their domain state.
|
||||
@@ -215,6 +217,8 @@ CR/LF framing, XML framing, ports/transports, callsign normalization and frequen
|
||||
- Automated-message loops must be prevented.
|
||||
- Cooldown/minimum-interval rules must be preserved.
|
||||
- A reply rejected before a complete valid TX item is queued must not consume cooldown.
|
||||
- Both category beacons share one timer, while their enable flags and templates remain profile-scoped and independent. The enable flags are observable runtime preferences: Settings changes and the `MyBeacon` status-chip action update them immediately, and every timer run reads their current values without restarting the timer or causing an immediate transmission. Only the explicit full settings write persists those flags; layout autosave deliberately leaves the on-disk functional state untouched.
|
||||
- `MyBeacon` owns one aggregate thread-status entry for both categories (`off`, a partial `enabled/available` count, `on`, or `FAILED`). Its action disables all currently usable beacons if any is enabled, otherwise it enables all currently usable beacons. A disabled second chat is not usable and its dormant enable flag must not be changed by the aggregate action. Category-specific timer failures remain authoritative while the affected beacon stays active; independent switch changes cannot hide them. The status bar resolves the aggregate from current controller state when a queued UI update is applied, so a delayed timer snapshot cannot overwrite a newer manual switch. Open Settings views observe the same preference values, so changes from the status chip remain synchronized without a parallel UI state.
|
||||
- Current implementation/tests define the exact message markers and timer details.
|
||||
|
||||
## Build / Verification
|
||||
@@ -413,7 +417,7 @@ Before implementing planned items, re-check current decisions and obtain a fresh
|
||||
- Historical project context is useful but may be stale; current code/tests win.
|
||||
- External service/API behaviour must be verified against current upstream documentation when uncertain.
|
||||
- Screenshots in manuals/website may need targeted replacement after visible UI changes; never fabricate them.
|
||||
- `station_map_path_analysis.png` and `station_map_reset.png` predate the current header controls, callsign-only markers, shared station context menu and Worked-square overlay. Replace them with current screenshots when suitable source images are available; the website reuses `station_map_path_analysis.png` through `/manual/assets/`.
|
||||
- `station_map_path_analysis.png` and `station_map_reset.png` predate the current header controls, callsign-only markers, shared station context menu and Worked-square overlay. The former remains useful only where the visible analysis panel itself is the subject. `station_map_spatial_filters.png` is the current general map screenshot shared by the DE/EN interface manuals and the website through `/manual/assets/`.
|
||||
|
||||
## Recent Significant Changes
|
||||
|
||||
|
||||
@@ -0,0 +1,108 @@
|
||||
# Live Beacon Control Implementation Plan
|
||||
|
||||
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
||||
|
||||
**Goal:** Make both beacon enable switches effective immediately at runtime and make the aggregate beacon status chip an accurate shared toggle.
|
||||
|
||||
**Architecture:** Keep `ChatPreferences` as the profile-scoped source of truth, but expose the two activation flags as thread-safe observable values. Route settings and chip actions through `ChatController`, publish one aggregate `MyBeacon` status, and give only that thread-status chip an optional click action.
|
||||
|
||||
**Tech Stack:** Java 21, Kotlin 2.2, Compose Multiplatform, JUnit 5, Mockito, Gradle wrapper
|
||||
|
||||
**Spec:** `docs/superpowers/specs/2026-11-04-live-beacon-control-design.md`
|
||||
|
||||
## Global Constraints
|
||||
|
||||
- Work directly on `main`, as explicitly authorized.
|
||||
- Do not stage, commit, push, merge, tag, release or deploy.
|
||||
- Keep beacon templates, interval handling, TX framing and second-chat eligibility unchanged.
|
||||
- Write source-code and configuration comments in English.
|
||||
- Use focused tests first and finish with `./gradlew.bat build --console=plain`.
|
||||
|
||||
## Review Focus
|
||||
|
||||
- A disabled second chat must leave its dormant second-beacon flag unchanged when the chip is clicked.
|
||||
- An external chip toggle must update an already open Beacon settings tab without reopening it.
|
||||
- A runtime toggle must not restart the timer or enqueue an immediate message.
|
||||
- An invalid beacon template must still be reported as a critical status rather than hidden by the aggregate state.
|
||||
- Profile reload must replace the observable values without carrying the previous profile's runtime flags across.
|
||||
|
||||
---
|
||||
|
||||
### Task 1: Observable profile-scoped beacon activation
|
||||
|
||||
**Files:**
|
||||
- Modify: `core/src/main/java/kst4contest/model/ChatPreferences.java`
|
||||
- Test: `core/src/test/java/kst4contest/model/ChatPreferencesBeaconStateTest.java`
|
||||
|
||||
**Interfaces:**
|
||||
- Produces: existing boolean getters/setters plus observable main/second beacon value accessors
|
||||
- Consumes: existing `MutableValue` / `SimpleValue` infrastructure
|
||||
|
||||
- [x] Write tests that changes are observable, values remain independent, XML reload restores both values, and an unsaved in-memory change does not survive a fresh load.
|
||||
- [x] Run `./gradlew.bat :core:test --tests kst4contest.model.ChatPreferencesBeaconStateTest --console=plain` and verify the new observable-accessor tests fail because the API is absent.
|
||||
- [x] Back the two flags with `SimpleValue<Boolean>` while preserving the existing getters, setters and XML element names.
|
||||
- [x] Re-run the focused test and the existing ChatPreferences tests.
|
||||
|
||||
### Task 2: Immediate settings effect and aggregate controller semantics
|
||||
|
||||
**Files:**
|
||||
- Modify: `core/src/main/java/kst4contest/controller/ChatController.java`
|
||||
- Modify: `core/src/main/java/kst4contest/controller/BeaconTask.java`
|
||||
- Create: `core/src/main/java/kst4contest/controller/BeaconStatus.java`
|
||||
- Test: `core/src/test/java/kst4contest/controller/BeaconControlTest.java`
|
||||
- Test: `core/src/test/java/kst4contest/controller/BeaconTaskTest.java`
|
||||
- Modify: `app-desktop/src/main/kotlin/kst4contest/view/compose/tabs/BeaconTabState.kt`
|
||||
- Modify: `app-desktop/src/main/kotlin/kst4contest/view/compose/tabs/BeaconTab.kt`
|
||||
- Modify: `app-desktop/src/main/kotlin/kst4contest/view/compose/ObservedValue.kt`
|
||||
- Modify: `app-desktop/src/main/kotlin/kst4contest/view/compose/SettingsTabs.kt`
|
||||
- Modify: `app-desktop/src/test/kotlin/kst4contest/view/compose/tabs/BeaconTabStateTest.kt`
|
||||
- Modify: `app-desktop/src/test/kotlin/kst4contest/view/compose/tabs/SettingsApplyScreenTest.kt`
|
||||
- Modify: `app-desktop/src/test/kotlin/kst4contest/view/compose/tabs/DraftedSettingsTableTest.kt`
|
||||
|
||||
**Interfaces:**
|
||||
- Consumes: observable preference values from Task 1
|
||||
- Produces: controller setters, usable-beacon toggle, aggregate status publication, Compose observation bridge
|
||||
|
||||
- [x] Write failing controller tests for `off`, `1/2`, `on`, main-only toggling when second chat is disabled, and both-category toggling when it is enabled.
|
||||
- [x] Write failing BeaconTask tests proving a flag changed between two runs changes queued output without restarting a timer, and that the final status is aggregate.
|
||||
- [x] Change Beacon settings tests so activation is immediate while templates and interval still wait for Apply; verify RED against the current draft-backed flags.
|
||||
- [x] Implement the aggregate status helper and controller actions without changing the outbound-message path.
|
||||
- [x] Make only the enable flags bypass `SettingsDraft`, observe their preference values in Compose, and wire their setters through the controller.
|
||||
- [x] Run the core and app-desktop focused tests and verify GREEN.
|
||||
|
||||
### Task 3: Clickable beacon status chip
|
||||
|
||||
**Files:**
|
||||
- Modify: `app-desktop/src/main/kotlin/kst4contest/view/compose/StatusIndicatorState.kt`
|
||||
- Modify: `app-desktop/src/main/kotlin/kst4contest/view/compose/StatusBar.kt`
|
||||
- Modify: `app-desktop/src/main/java/kst4contest/view/Kst4ContestApplication.java`
|
||||
- Modify: `app-desktop/src/test/kotlin/kst4contest/view/compose/StatusIndicatorStateTest.kt`
|
||||
- Create or modify: focused Compose status-bar rendering test under `app-desktop/src/test/kotlin/kst4contest/view/compose/`
|
||||
|
||||
**Interfaces:**
|
||||
- Consumes: controller usable-beacon toggle from Task 2
|
||||
- Produces: optional per-source chip action registered only for `MyBeacon`
|
||||
|
||||
- [x] Write failing state tests for actions registered before and after the first status report and for non-action thread chips.
|
||||
- [x] Write a failing Compose test proving the beacon chip invokes its action while an ordinary status chip remains non-clickable.
|
||||
- [x] Add optional actions to thread-status buttons and apply button semantics only when an action exists.
|
||||
- [x] Register the controller toggle for `MyBeacon` during main-window state construction.
|
||||
- [x] Run the focused status tests and the affected main-window tests.
|
||||
|
||||
### Task 4: Documentation and verification
|
||||
|
||||
**Files:**
|
||||
- Modify: relevant beacon sections in `github_docs/de-Konfiguration.md`
|
||||
- Modify: corresponding sections in `github_docs/en-Configuration.md`
|
||||
- Modify: `docs/PROJECT_CONTEXT.md`
|
||||
- Review: relevant screenshots and changelog impact only
|
||||
|
||||
**Interfaces:**
|
||||
- Consumes: completed runtime and UI behavior from Tasks 1-3
|
||||
- Produces: aligned user documentation and durable state/persistence invariant
|
||||
|
||||
- [x] Update both manuals with immediate runtime effect, explicit-save persistence, aggregate chip behavior and second-chat handling.
|
||||
- [x] Record the observable canonical state, timer-read rule and persistence boundary in `docs/PROJECT_CONTEXT.md`.
|
||||
- [x] Run all focused tests, then `./gradlew.bat build --console=plain` and read test-result XML summaries.
|
||||
- [x] Run `git diff --check`, inspect PMD/SpotBugs XML for findings in changed production files, and review the final diff for unrelated changes.
|
||||
- [x] Leave all changes unstaged and uncommitted and report remaining manual UI checks.
|
||||
@@ -0,0 +1,110 @@
|
||||
# Map Overlay Legend and Screenshot Implementation Plan
|
||||
|
||||
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
||||
|
||||
**Goal:** Add a responsive, localized map-overlay legend and document the spatial QRB overlay with the supplied screenshot.
|
||||
|
||||
**Architecture:** A focused Compose legend consumes the same red antenna and theme-aware blue filter colours as the canvas. `StationMapWindow` derives visibility from the effective antenna and spatial-filter state and places the legend in the existing header `FlowRow`. Documentation receives a new immutable screenshot asset without repurposing the path-analysis image.
|
||||
|
||||
**Tech Stack:** Kotlin, Compose Multiplatform, generated properties-based i18n, JUnit 5 Compose UI tests, Markdown, Eleventy
|
||||
|
||||
**Spec:** `docs/superpowers/specs/2026-11-04-map-overlay-legend-and-screenshot-design.md`
|
||||
|
||||
## Global Constraints
|
||||
|
||||
- Preserve map filtering, station selection, antenna heading, rotor control and overlay geometry.
|
||||
- Reuse existing design tokens and exact overlay colours; add no dependency.
|
||||
- Keep German and English strings and documentation semantically aligned.
|
||||
- Keep all changes ungestaged and uncommitted.
|
||||
|
||||
## Review Focus
|
||||
|
||||
- A map with no drawable overlay must not reserve an empty legend area; Task 1 tests both items absent.
|
||||
- A QRB-only filter must show the blue item without implying QTF is active; Task 1 tests the generic **Active filters** wording.
|
||||
- Invalid spatial values must not show the blue item; Task 1 uses `hasRenderableValues` as the gate.
|
||||
- Narrow windows must wrap rather than clip controls; Task 1 retains the existing `FlowRow` and adds a narrow rendering assertion.
|
||||
- The screenshot must not replace an image whose caption promises visible path-analysis panels; Task 2 checks all asset references.
|
||||
|
||||
---
|
||||
|
||||
### Task 1: Localized responsive overlay legend
|
||||
|
||||
**Files:**
|
||||
- Create: `app-desktop/src/main/kotlin/kst4contest/view/compose/map/MapOverlayLegend.kt`
|
||||
- Modify: `app-desktop/src/main/kotlin/kst4contest/view/compose/map/ComposeStationMap.kt`
|
||||
- Modify: `app-desktop/src/main/kotlin/kst4contest/view/compose/map/SpatialFilterOverlay.kt`
|
||||
- Modify: `app-desktop/src/main/kotlin/kst4contest/view/compose/map/StationMapWindow.kt`
|
||||
- Modify: `app-desktop/src/main/i18n/strings_en.properties`
|
||||
- Modify: `app-desktop/src/main/i18n/strings_de.properties`
|
||||
- Test: `app-desktop/src/test/kotlin/kst4contest/view/compose/map/StationMapWindowScreenTest.kt`
|
||||
- Test: existing i18n-generator and translation tests
|
||||
|
||||
**Interfaces:**
|
||||
- Consumes: antenna-sector visibility, `SpatialFilterOverlayState.isActive`, `SpatialFilterOverlayState.hasRenderableValues`, current theme.
|
||||
- Produces: `MapOverlayLegend(showAntenna: Boolean, showSpatialFilters: Boolean, darkMode: Boolean)` and shared overlay-colour accessors.
|
||||
|
||||
- [ ] **Step 1: Add failing Compose tests**
|
||||
|
||||
Assert that the red item appears for a drawable antenna sector, the blue item appears only for an active valid spatial filter, both disappear with neither overlay, and the header remains laid out at a narrow test width.
|
||||
|
||||
- [ ] **Step 2: Run the focused screen test and confirm the missing legend fails**
|
||||
|
||||
Run: `./gradlew.bat :app-desktop:test --tests kst4contest.view.compose.map.StationMapWindowScreenTest --console=plain`
|
||||
|
||||
- [ ] **Step 3: Add localized labels and tooltip text**
|
||||
|
||||
Add English `Antenna`, `Active filters` and the two-colour explanation, with equivalent German strings `Antenne`, `Aktive Filter` and its explanation.
|
||||
|
||||
- [ ] **Step 4: Implement the legend with shared colours**
|
||||
|
||||
Expose the existing antenna colour and theme-aware spatial-filter line colour within the map package. Implement compact colour swatches and labels in `MapOverlayLegend.kt`, and add the component to the existing header `FlowRow` with dynamic visibility.
|
||||
|
||||
- [ ] **Step 5: Run focused Compose and i18n tests**
|
||||
|
||||
Expected: all selected tests pass in both languages; existing map interactions remain unchanged.
|
||||
|
||||
### Task 2: Replace the outdated general map screenshot
|
||||
|
||||
**Files:**
|
||||
- Create: `github_docs/station_map_spatial_filters.png`
|
||||
- Modify: `github_docs/de-Benutzeroberflaeche.md`
|
||||
- Modify: `github_docs/en-User-Interface.md`
|
||||
- Modify: `website/src/features/station-map.md`
|
||||
- Modify when the durable UI invariant changes: `docs/PROJECT_CONTEXT.md`
|
||||
|
||||
**Interfaces:**
|
||||
- Consumes: supplied 1257×1016 PNG showing `QRB > 500 km` and `QRB ≤ 666 km`.
|
||||
- Produces: one shared manual/website asset copied by Eleventy to `/manual/assets/`.
|
||||
|
||||
- [ ] **Step 1: Copy the supplied PNG without resampling**
|
||||
|
||||
Verify its dimensions and file hash after copying.
|
||||
|
||||
- [ ] **Step 2: Update targeted DE/EN manual references**
|
||||
|
||||
Use captions that describe the selected path, red antenna sector and blue QRB ring. Remove only the obsolete screenshot note attached to the replaced general map image.
|
||||
|
||||
- [ ] **Step 3: Update the Station Map website feature page**
|
||||
|
||||
Reference `/manual/assets/station_map_spatial_filters.png` and retain the older path-analysis image for manual sections where the analysis panels are explicitly described.
|
||||
|
||||
- [ ] **Step 4: Verify asset references and website output**
|
||||
|
||||
Run: `npm.cmd test` and `npm.cmd run build` in `website`; verify the generated image path exists.
|
||||
|
||||
### Task 3: Final verification
|
||||
|
||||
**Files:**
|
||||
- Review all files from Tasks 1 and 2.
|
||||
|
||||
**Interfaces:**
|
||||
- Consumes: completed legend, translations and screenshot references.
|
||||
- Produces: verified uncommitted working tree.
|
||||
|
||||
- [ ] **Step 1: Run focused map and translation tests**
|
||||
|
||||
- [ ] **Step 2: Run `./gradlew.bat build --console=plain` and inspect test XML plus PMD/SpotBugs reports**
|
||||
|
||||
- [ ] **Step 3: Run `git diff --check` and inspect `git status --short --branch`**
|
||||
|
||||
- [ ] **Step 4: Report native visual checks separately from automated rendering evidence**
|
||||
@@ -0,0 +1,46 @@
|
||||
# Live Beacon Control Design
|
||||
|
||||
Freigegeben von Marc am 2026-11-04.
|
||||
|
||||
## Ziel
|
||||
|
||||
Die beiden Beacon-Aktivierungsschalter wirken in der laufenden Sitzung sofort. Der gemeinsame
|
||||
Beacon-Timer bleibt bestehen und liest bei jedem Lauf die aktuellen Zustände. Der Beacon-Chip
|
||||
im Hauptfenster zeigt den zusammengefassten Zustand und kann die aktuell nutzbaren Beacons
|
||||
gemeinsam ein- oder ausschalten.
|
||||
|
||||
## Verbindliches Verhalten
|
||||
|
||||
- Die gespeicherten Beacon-Zustände werden beim Profilstart geladen.
|
||||
- Ein Klick auf eine Beacon-Checkbox wirkt sofort im Speicher und damit beim nächsten
|
||||
regulären Timerlauf.
|
||||
- Aktivieren sendet nicht sofort und startet den Timer nicht neu.
|
||||
- Erst **Einstellungen speichern** schreibt die Zustände in die Profil-XML. Ohne explizites
|
||||
Speichern gilt die Änderung nur für die laufende Sitzung.
|
||||
- Beacon-Text und Intervall bleiben normale Settings-Entwurfswerte. Das Intervall startet den
|
||||
Timer erst beim Anwenden neu.
|
||||
- Der Status-Chip zeigt `off`, `1/2` oder `on` für die aktuell nutzbaren Kategorien.
|
||||
- Sind alle nutzbaren Beacons aus, aktiviert ein Chip-Klick alle nutzbaren Beacons. Ist
|
||||
mindestens eine nutzbare Beacon an, deaktiviert der Klick alle nutzbaren Beacons.
|
||||
- Bei deaktiviertem zweiten Chat schaltet der Chip nur die Hauptkategorie und verändert das
|
||||
gespeicherte Flag der zweiten Kategorie nicht.
|
||||
- Chip und geöffnetes Settings-Fenster zeigen denselben beobachtbaren Zustand.
|
||||
- Nur der Beacon-Chip wird anklickbar. Andere Thread-Status-Chips bleiben reine Anzeigen.
|
||||
|
||||
## Unveränderte Grenzen
|
||||
|
||||
- Beide Kategorien behalten eigene Aktivierungsflags und Texte.
|
||||
- Der zweite Beacon-Versand setzt weiterhin einen aktivierten zweiten Chat voraus.
|
||||
- Nachrichtenvalidierung, TX-Warteschlange und ON4KST-Protokoll bleiben unverändert.
|
||||
- Mindestintervall, gemeinsamer Timer und Intervall-Persistenz bleiben unverändert.
|
||||
- Profilzustände werden nicht miteinander vermischt.
|
||||
|
||||
## Technischer Ansatz
|
||||
|
||||
Die vorhandenen `ChatPreferences`-Getter und -Setter bleiben die kompatible Schnittstelle,
|
||||
werden für die beiden Aktivierungsflags aber auf thread-sichere beobachtbare Werte gestellt.
|
||||
Der Settings-Tab liest diese Werte als Compose-State und schreibt Aktivierungen direkt durch
|
||||
den Controller. Der Controller veröffentlicht nach jeder manuellen Umschaltung einen
|
||||
zusammengefassten `MyBeacon`-Status. `BeaconTask` meldet nach einem Timerlauf ebenfalls genau
|
||||
diesen zusammengefassten Status. `ThreadStatusButtons` erhält eine optionale Aktion pro
|
||||
Quelle; die Anwendung registriert sie nur für `MyBeacon`.
|
||||
@@ -0,0 +1,26 @@
|
||||
# Map Overlay Legend and Screenshot Design
|
||||
|
||||
## Intent
|
||||
|
||||
Make the two map overlays understandable without consulting the manual and replace the outdated general map image with the supplied screenshot of an active QRB range.
|
||||
|
||||
## Behaviour
|
||||
|
||||
- The map header shows a compact red **Antenna** legend item only while the antenna sector can be drawn.
|
||||
- It shows a compact blue **Active filters** legend item only while a valid QTF or QRB overlay is active.
|
||||
- A localized tooltip explains that red represents the actual antenna heading, beamwidth and maximum QRB, while blue represents active QTF and QRB filters.
|
||||
- The existing responsive `FlowRow` may wrap the legend with the other header controls.
|
||||
- Overlay rendering, filtering, antenna heading and rotor behaviour do not change.
|
||||
|
||||
## Screenshot
|
||||
|
||||
- Store the supplied image as `github_docs/station_map_spatial_filters.png` without altering its pixels.
|
||||
- Use it in the German and English UI manual and on the Station Map website feature page.
|
||||
- Describe the visible range correctly as minimum and maximum QRB, not QTF.
|
||||
- Retain `station_map_path_analysis.png` where the visible path-analysis panels are the subject.
|
||||
|
||||
## Constraints
|
||||
|
||||
- Reuse the exact overlay colours rather than duplicating colour literals.
|
||||
- Keep English and German UI strings and documentation aligned.
|
||||
- Do not stage, commit, push or publish any change.
|
||||
Reference in new issue
Block a user