Skip to content

feat(ui): character status dock with per-chip threat state#63

Merged
AreteDriver merged 2 commits into
feat/intel-aware-preview-bordersfrom
feat/character-status-dock
Apr 26, 2026
Merged

feat(ui): character status dock with per-chip threat state#63
AreteDriver merged 2 commits into
feat/intel-aware-preview-bordersfrom
feat/character-status-dock

Conversation

@AreteDriver
Copy link
Copy Markdown
Owner

Stacked on #62 — base is `feat/intel-aware-preview-borders`. Merge that first; this PR will retarget to `main` automatically.

Summary

  • New `StatusDock` widget — horizontal strip of `CharacterChip` widgets above the preview grid
  • Each chip: 28px colored-initials avatar (deterministic accent per character), name, system label, threat-tint dot
  • Click a chip to activate the matching window — reuses `_on_window_activated` so Qt focus path is unchanged
  • Threat dots track the same intel signal that tints preview borders (PR feat(ui): intel-aware preview borders with decay and pulse #62) so border + chip stay in lock-step
  • Visibility gated on `thumbnails.show_status_dock` (default true)

Why this matters

EVE-O Preview cannot show per-character system or threat state — it has no access to the chat-log intel parser running in this process. The dock makes that data first-class, glanceable, and clickable. It's also the foundation for the next round of differentiators (focus mode, system-cluster grouping, etc.).

Architecture notes

  • `StatusDock` owns chip lifecycle (`add_chip`/`remove_chip`/`clear`/`sync_from_window_ids`)
  • `MainTab._sync_status_dock` mirrors `window_manager.preview_frames` on every add/remove site
  • `MainWindowV21._on_intel_alert` pushes `VISUAL_BORDER` alerts to the dock alongside the preview-frame fan-out from feat(ui): intel-aware preview borders with decay and pulse #62
  • Per-character system tracking still uses the shared parser `current_system` — chip API already takes a `system` arg so per-char tracking can land later without API changes

Test plan

  • 35 new tests in `tests/test_status_dock.py` (chip init/clicks/threat state/paint smoke; dock add/remove/clear/sync/fan-out; main_window wiring + optional-dock fallback)
  • 1 updated existing test (`test_setup_ui_creates_layout_and_widgets`) for +1 addWidget call
  • Full suite: 2239 passed, 5 skipped, 0 failures
  • `ruff check` + `ruff format --check` clean

Follow-ups

  • Per-character `current_system` tracking (each EVE char has its own log file)
  • Focus mode (clicked thumb scales up, others desaturate)
  • System-cluster grouping in the dock (visually group chips by shared system)

🤖 Generated with Claude Code

Adds a horizontal strip of CharacterChip widgets above the preview grid:
each chip shows a colored-initials avatar (deterministic accent per
character), the character name, current system, and a threat-tint dot
fed from the same intel pipeline as the preview borders (PR1). Clicking
a chip activates the matching window via the existing focus path.

StatusDock owns chip lifecycle (add/remove/clear/sync) and fans threat
state to all chips. MainTab._sync_status_dock mirrors window_manager
state on every add/remove site. MainWindowV21._on_intel_alert pushes
VISUAL_BORDER alerts to the dock alongside the existing preview-frame
fan-out, so border + chip dot stay in lock-step.

Visibility gated on thumbnails.show_status_dock (default true).
Per-character system tracking still uses the shared parser current_system
for now — the chip already accepts a system arg so per-char tracking can
land later without API changes.

35 new tests in tests/test_status_dock.py + 1 updated existing setup-ui
test for the +1 addWidget call. Suite: 2239 passed, 5 skipped.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces the StatusDock component, which provides a horizontal strip of character chips displaying character avatars, system names, and threat indicators. The changes include the implementation of the StatusDock and CharacterChip widgets, integration into the main tab and intel alert pipeline, and comprehensive unit tests. Feedback focuses on ensuring deterministic character accent colors by replacing the non-deterministic hash() function, adjusting layout margins to prevent visual overlap between threat dots and system labels, and implementing threat decay logic to synchronize behavior with the preview frames.


def accent_for(name: str) -> QColor:
"""Deterministic accent color for a character name."""
r, g, b = CHIP_ACCENT_COLORS[abs(hash(name)) % len(CHIP_ACCENT_COLORS)]
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The use of Python's built-in hash() function is not deterministic across different application sessions because of hash randomization (salting) introduced in Python 3.3. This means character accent colors will change every time the application is restarted, which contradicts the goal of having a stable accent palette as stated in the comments. Consider using a stable hashing method like a sum of character codes or zlib.adler32 to ensure consistency.

Suggested change
r, g, b = CHIP_ACCENT_COLORS[abs(hash(name)) % len(CHIP_ACCENT_COLORS)]
r, g, b = CHIP_ACCENT_COLORS[sum(ord(c) for c in name) % len(CHIP_ACCENT_COLORS)]

self._apply_base_style()

layout = QHBoxLayout(self)
layout.setContentsMargins(6, 4, 8, 4)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The current right margin of 8px is insufficient to prevent the threat dot (which is 10px wide and offset by 8px from the right edge) from overlapping with the _system_label text, especially since the label is right-aligned. Increasing the right margin to 24px will ensure the dot is drawn in the margin area and does not obscure the system name.

Suggested change
layout.setContentsMargins(6, 4, 8, 4)
layout.setContentsMargins(6, 4, 24, 4)

Comment on lines +170 to +184
def set_threat_state(
self, level: ThreatLevel | None, system: str | None = None, alpha: float = 1.0
) -> None:
if level is None or level == ThreatLevel.CLEAR:
self._threat_level = None
self._threat_alpha = 0.0
else:
self._threat_level = level
self._threat_alpha = max(0.0, min(1.0, alpha))
if system is not None:
self.set_system(system)
else:
self.setToolTip(self._tooltip_text())
self.update()

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The CharacterChip lacks the threat decay logic implemented in WindowPreviewWidget. While the preview borders fade over time (via THREAT_DECAY_DURATION_MS), the threat dots in the status dock will remain at full opacity until a CLEAR report is received or the character changes systems. This breaks the 'lock-step' behavior mentioned in the PR description. Consider implementing a similar decay timer here or passing the current alpha from the preview frames if they are intended to be perfectly synchronized.

@AreteDriver AreteDriver merged commit 6f0fa7e into feat/intel-aware-preview-borders Apr 26, 2026
1 check passed
@AreteDriver AreteDriver deleted the feat/character-status-dock branch April 26, 2026 09:40
AreteDriver added a commit that referenced this pull request Apr 26, 2026
Bumps version to 3.2.0 and documents the 10-PR intel-aware UI arc that
landed via #74. Also fixes the pre-existing version drift between
pyproject.toml (3.1.2) and __init__.py (3.0.4) by syncing both to 3.2.0.

CHANGELOG entry covers:
- Intel-aware preview borders (PR #62)
- Character status dock (PR #63)
- Preview focus mode (PR #64)
- Per-character system tracking from EVE Local logs (PR #65)
- Smart per-character threat fan-out (PR #66)
- Jumps-from fan-out with adjacency falloff (PR #67)
- "+Nj" distance badges on chips + frames (PR #68 + PR #71)
- Per-character accent border (PR #70)
- Toggleable replay strip with frame scrubbing (PR #72)

Plus the supporting infrastructure (intel/threat_filter, accent palette
promotion, set_threat_state kwarg additions) and the new settings keys
that gate the features.

Co-authored-by: AreteDriver <AreteDriver@users.noreply.github.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant