Skip to content

refactor: centralize inline colors to DashColors constants#572

Merged
PastaPastaPasta merged 6 commits into
v1.0-devfrom
refactor/centralize-dash-colors
Feb 17, 2026
Merged

refactor: centralize inline colors to DashColors constants#572
PastaPastaPasta merged 6 commits into
v1.0-devfrom
refactor/centralize-dash-colors

Conversation

@PastaPastaPasta
Copy link
Copy Markdown
Member

@PastaPastaPasta PastaPastaPasta commented Feb 12, 2026

Summary

  • Replace ~120 hardcoded Color32::from_rgb() values with semantic DashColors constants across 64 UI files
  • Add 30+ new color constants and helper functions to DashColors in theme.rs
  • Network accent colors with dark mode variants (TESTNET_ORANGE, DEVNET_RED, REGTEST_BROWN)
  • Popup/modal helpers (modal_overlay(), popup_shadow(), popup_fill(), popup_border_glow())
  • Icon tint helpers (icon_tint(), ICON_SELECTED, ICON_UNSELECTED)
  • Button state colors (DANGER_HOVER, DANGER_RED, BUTTON_DISABLED, ACTION_BUTTON_BLUE)
  • Validation/warning colors (VALIDATION_WARNING, WARNING_BRIGHT, PLATFORM_PURPLE)
  • Password strength indicators (STRENGTH_WEAK/FAIR/GOOD/STRONG)
  • Theme-adaptive helpers: network_accent(), stripe(), unselected_fill()

Motivation

Inline magic RGB values make it difficult to maintain consistent theming and impossible to change colors centrally. This PR centralizes all hardcoded colors into semantic DashColors constants, making future theme changes trivial and ensuring visual consistency.

Test plan

  • cargo clippy --all-features --all-targets -- -D warnings passes with zero warnings
  • cargo +nightly fmt --all produces no changes
  • Visual inspection: verify UI screens render identically (colors are the same values, just centralized)

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Refactor

    • Centralized UI theming: modals, popups, overlays, shadows, borders and network accents now use a unified theme for consistent light/dark visuals.
    • Added many new theme color tokens and helpers for improved, coherent styling.
  • Style

    • Updated numerous screens to use the unified theme, harmonizing button fills, error banners, text, labels, spinners, and other UI elements.
  • New Features

    • Improved entropy grid interaction feedback for clearer bit-toggling behavior.

… UI screens

Replace ~120 hardcoded Color32::from_rgb() values with semantic DashColors
constants across 64 files. Add 30+ new color constants and helper functions
to DashColors including network accent colors, icon tints, popup/modal
overlays, password strength indicators, and button states.

This improves maintainability by centralizing color definitions, making
theme changes trivial and ensuring visual consistency across all screens.

Key additions to DashColors:
- Network colors: TESTNET_ORANGE, DEVNET_RED, REGTEST_BROWN (+ dark variants)
- Icon tints: ICON_SELECTED, ICON_UNSELECTED, icon_tint() helper
- Popup helpers: modal_overlay(), popup_shadow(), popup_fill(), popup_border_glow()
- Button states: DANGER_HOVER, DANGER_RED, BUTTON_DISABLED, ACTION_BUTTON_BLUE
- Validation: VALIDATION_WARNING, WARNING_BRIGHT, PLATFORM_PURPLE
- Strength: STRENGTH_WEAK/FAIR/GOOD/STRONG
- Helpers: network_accent(), stripe(), unselected_fill()

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@PastaPastaPasta PastaPastaPasta force-pushed the refactor/centralize-dash-colors branch from 6eef762 to 6b44146 Compare February 12, 2026 16:37
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Feb 12, 2026

📝 Walkthrough

Walkthrough

Centralizes UI color theming by adding many DashColors constants/helpers in src/ui/theme.rs and replacing hard-coded Color32 values across numerous UI components; adds a private field last_bit_changed: u8 to U256EntropyGrid. Changes are visual-only aside from the added entropy field.

Changes

Cohort / File(s) Summary
Theme Core
src/ui/theme.rs
Added many public color constants and helper functions (modal/popup colors, accents, network helpers, icon tints, strength colors, action/error/button tokens) to centralize theming; large additive API surface.
Modal & Popup Styling
src/ui/components/confirmation_dialog.rs, src/ui/components/info_popup.rs, src/ui/components/wallet_unlock_popup.rs, src/ui/wallets/wallets_screen/dialogs.rs, src/ui/components/wallet_unlock.rs, src/ui/components/info_popup.rs
Replaced overlay, shadow, border-glow, and popup fill/stroke hardcodes with DashColors::modal_overlay(), popup_shadow(), popup_border_glow(), and popup_fill(...).
Panels, Icons & Button Variants
src/ui/components/left_panel.rs, src/ui/components/left_wallet_panel.rs, src/ui/components/top_panel.rs, src/ui/components/styled.rs
Switched button/icon tint and accent logic to DashColors::icon_tint(...), network_accent(...), and action/danger tokens; removed many local Color32 literals.
Entropy Grid
src/ui/components/entropy_grid.rs
Switched off-state colors to DashColors variants and added private field last_bit_changed: u8 to U256EntropyGrid for tracking the last-toggled bit.
Primary Actions & Buttons
src/ui/contracts_documents/..., src/ui/identities/..., src/ui/tokens/..., src/ui/dpns/..., src/ui/tools/transition_visualizer_screen.rs
Replaced primary/disabled button colors (previously Color32::from_rgb(0,128,255) etc.) with DashColors::ACTION_BUTTON_BLUE, DASH_BLUE, and BUTTON_DISABLED across many screens.
Error, Validation & Warning Colors
src/ui/components/wallet_unlock.rs, src/ui/contracts_documents/*, src/ui/identities/*, src/ui/tokens/*, src/ui/dashpay/*, src/ui/tools/*, src/ui/wallets/*
Replaced many hard-coded error/validation colors with DashColors::ERROR, VALIDATION_WARNING, WARNING_BRIGHT, and related tokens (frames, text, strokes updated).
State Indicators & Misc UI Tokens
src/ui/wallets/add_new_wallet_screen.rs, src/ui/wallets/import_mnemonic_screen.rs, src/ui/wallets/asset_lock_detail_screen.rs, src/ui/tools/proof_log_screen.rs
Replaced strength, success, warning, highlight, and platform colors with STRENGTH_*, SUCCESS, WARNING_BRIGHT, HIGHLIGHT_GOLD, PLATFORM_PURPLE.
Imports & Path Adjustments
many files under src/ui/... (e.g., tokens/..., tools/..., dashpay/..., identities/..., helpers.rs, tokens_screen/mod.rs)
Replaced fully-qualified crate::ui::theme::DashColors paths with use crate::ui::theme::DashColors and updated color references across many files; mostly path and literal-to-token substitutions.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

🐇 I nibbled at stray RGBs with cheer,

stitched DashColors so the UI's clear.
Popups now glow from one tidy well,
bits remembered in a tiny shell.
🥕 Hop, patch, and palette — rabbit's cheer.

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 31.82% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title accurately reflects the main change: centralizing inline hardcoded colors to DashColors constants across the codebase. This is the primary objective evident throughout all 64 modified files.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch refactor/centralize-dash-colors

Tip

Issue Planner is now in beta. Read the docs and try it out! Share your feedback on Discord.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 Fix all issues with AI agents
In `@src/ui/components/wallet_unlock.rs`:
- Line 137: Replace the hardcoded DashColors::error_color(true) call so it uses
the actual theme state instead of always passing true; call
DashColors::error_color with the real dark-mode boolean (for example the
component/state variable named dark_mode or by querying egui's visuals via
ctx.style().visuals.dark_mode) so error_color receives the current theme value
rather than a hardcoded true.

In `@src/ui/tokens/tokens_screen/keyword_search.rs`:
- Line 142: Replace the hardcoded theme-insensitive DashColors::ERROR with the
theme-aware helper: obtain dark_mode via ui.visuals().dark_mode in the scope
where error_color is set (in keyword_search.rs near the code setting
error_color), then call DashColors::error_color(dark_mode) instead of
DashColors::ERROR; apply the same change pattern where you see DashColors::ERROR
used (e.g., in grovestark_screen.rs, transfer_screen.rs, key_info_screen.rs) to
ensure the error color respects light/dark themes.

In `@src/ui/tools/document_visualizer_screen.rs`:
- Line 170: Replace the hard-coded DashColors::ERROR usage with the theme-aware
DashColors::error_color(dark_mode): locate the assignment using
DashColors::ERROR and change it to call DashColors::error_color(dark_mode);
ensure you have a boolean dark_mode (obtainable from the UI context, e.g.,
ctx.style().visuals.dark_mode or pass it into the component) in scope when
calling error_color; apply the same replacement pattern for similar occurrences
so error banners adapt to light/dark themes.
🧹 Nitpick comments (16)
src/ui/wallets/import_mnemonic_screen.rs (1)

402-407: Inconsistent use of fully-qualified path vs. the imported DashColors.

Line 14 imports DashColors, and the new changed lines (e.g., 472, 480, 610) use it directly. However, these pre-existing lines still use the fully-qualified crate::ui::theme::DashColors::… form. Consider updating them to use the short DashColors:: form for consistency.

♻️ Suggested cleanup
                             let response = ui.add_sized(
                                 Vec2::new(input_width, 20.0),
                                 egui::TextEdit::singleline(&mut word)
-                                    .text_color(crate::ui::theme::DashColors::text_primary(
-                                        dark_mode,
-                                    ))
-                                    .background_color(
-                                        crate::ui::theme::DashColors::input_background(dark_mode),
-                                    ),
+                                    .text_color(DashColors::text_primary(dark_mode))
+                                    .background_color(DashColors::input_background(dark_mode)),
                             );
             egui::TextEdit::singleline(&mut self.private_key_input)
                 .hint_text("Enter private key (WIF: 51-52 chars, or hex: 64 chars)")
-                .text_color(crate::ui::theme::DashColors::text_primary(dark_mode))
-                .background_color(crate::ui::theme::DashColors::input_background(dark_mode))
+                .text_color(DashColors::text_primary(dark_mode))
+                .background_color(DashColors::input_background(dark_mode))
                 .password(true),

Also applies to: 455-456

src/ui/contracts_documents/document_action_screen.rs (2)

621-631: Consider using DashColors::error_color(dark_mode) instead of DashColors::ERROR for theme adaptivity.

The relevant snippet from src/ui/theme.rs shows that error_color(dark_mode) returns a lighter red for dark mode and DARK_RED for light mode. Using the constant DashColors::ERROR here loses that adaptivity. Since ui is available, you can easily obtain dark_mode.

The same applies to the identical pattern at Line 1801.

Proposed fix
-            let error_color = DashColors::ERROR;
+            let error_color = DashColors::error_color(ui.ctx().style().visuals.dark_mode);

1780-1784: A few inline colors remain unconverted in this file.

Line 601 (Color32::DARK_GREEN), Line 865 (Color32::DARK_RED), and Line 1782 (Color32::from_rgb(200, 150, 50)) still use hardcoded colors. If these were intentionally left out of scope, no action needed — just flagging for completeness.

src/ui/identities/add_new_identity_screen/by_using_unused_balance.rs (1)

6-6: Inconsistent use of imported DashColors vs fully-qualified path.

Line 87 uses the imported DashColors::DASH_BLUE, but lines 68, 75, and 79 use the fully-qualified crate::ui::theme::DashColors::surface(...), text_secondary(...), and text_primary(...). Since DashColors is already imported on line 6, prefer using the short form consistently.

Also applies to: 68-79

src/ui/tools/document_visualizer_screen.rs (1)

148-149: Fully-qualified paths used despite DashColors import on line 10.

Same as in other files — crate::ui::theme::DashColors::text_primary(dark_mode) and input_background(dark_mode) can just be DashColors::text_primary(dark_mode) and DashColors::input_background(dark_mode).

src/ui/tools/platform_info_screen.rs (1)

9-9: Fully-qualified crate::ui::theme::DashColors::DASH_BLUE on line 120 despite import on line 9.

Use DashColors::DASH_BLUE for consistency with line 132.

Also applies to: 120-120

src/ui/tools/transition_visualizer_screen.rs (2)

295-316: Several hardcoded colors remain in this file.

Lines 306, 328, 361, 368, 373 still use raw Color32::from_rgba_premultiplied(...) values for the fade-out status messages and the "View in Contracts" button. The base colors (dark red, dark green, steel blue) could be defined as DashColors constants, with the alpha computed at the call site. This would complete the centralization for this file.

Also applies to: 327-328, 360-361, 368-368


159-160: Fully-qualified DashColors paths despite import on line 9.

Lines 159–160 and 213–214 use crate::ui::theme::DashColors::text_primary(dark_mode) / input_background(dark_mode) — use the short form via the existing import.

Also applies to: 213-214

src/ui/identities/keys/add_key_screen.rs (1)

388-389: Hardcoded warning color Color32::from_rgb(200, 150, 50) not migrated.

This "wallet locked" warning color could use one of the new DashColors warning constants (e.g., VALIDATION_WARNING) to complete the centralization in this file.

src/ui/tools/contract_visualizer_screen.rs (1)

129-130: Fully-qualified DashColors paths despite import on line 8.

Use DashColors::text_primary(dark_mode) and DashColors::input_background(dark_mode) via the existing import.

src/ui/identities/add_new_identity_screen/by_using_unused_asset_lock.rs (1)

112-123: Fully-qualified DashColors paths despite import on line 6.

Lines 112, 119, and 123 use crate::ui::theme::DashColors::surface(...), text_secondary(...), and text_primary(...) — use the short form.

src/ui/tools/grovestark_screen.rs (1)

577-577: Several hardcoded Color32::DARK_GREEN values remain un-centralized.

This file still has ~8 instances of egui::Color32::DARK_GREEN (Lines 577, 633, 695, 733, 769, 833, 838, 938) and egui::Color32::RED (Lines 972, 975) that weren't migrated to DashColors constants. Given the PR's goal of centralizing inline colors, these should be addressed for consistency — or at minimum tracked for a follow-up.

Also applies to: 593-593, 633-633, 695-695, 733-733, 769-769

src/ui/tokens/set_token_price_screen.rs (1)

1114-1118: Inconsistency: disabled button color not centralized.

The enabled state was updated to DashColors::ACTION_BUTTON_BLUE, but the disabled state on Line 1117 still uses a hardcoded Color32::from_rgb(100, 100, 100). In by_platform_address.rs (line 247), the same pattern uses DashColors::BUTTON_DISABLED. Consider aligning for consistency.

Proposed fix
 let button_color = if validation_result.is_ok() {
     DashColors::ACTION_BUTTON_BLUE
 } else {
-    Color32::from_rgb(100, 100, 100)
+    DashColors::BUTTON_DISABLED
 };
src/ui/components/entropy_grid.rs (1)

5-26: Avoid skipping the first hover on bit position 0.
last_bit_changed starts at 0, so an initial hover over bit 0 won’t toggle (only clicks will). Consider using Option<u8> to avoid the “pre-selected” bit edge case.

♻️ Proposed adjustment
 pub struct U256EntropyGrid {
     random_number: [u8; 32], // Current 256-bit number (32 bytes)
-    last_bit_changed: u8,    // Store the last bit position changed
+    last_bit_changed: Option<u8>, // Store the last bit position changed
 }

 ...

         Self {
             random_number,
-            last_bit_changed: 0, // Initialize to 0
+            last_bit_changed: None, // No bit changed yet
         }
     }

 ...

     fn was_bit_different(&self, bit_position: u8) -> bool {
-        self.last_bit_changed != bit_position
+        self.last_bit_changed != Some(bit_position)
     }

 ...

         // Update the last changed bit position
-        self.last_bit_changed = (byte_index * 8 + bit_in_byte) as u8;
+        self.last_bit_changed = Some((byte_index * 8 + bit_in_byte) as u8);
src/ui/identities/identities_screen.rs (1)

1218-1221: Remaining hardcoded colors for message indicators.

Lines 1219 and 1221 still use egui::Color32::DARK_RED and egui::Color32::DARK_GREEN directly. Given that DashColors::ERROR and a theme-aware error_color() helper exist in theme.rs, consider centralizing these as well for consistency with the rest of this PR's changes.

src/ui/identities/add_existing_identity_screen.rs (1)

1022-1041: DashColors::ERROR is not theme-adaptive — intentional?

Both error display blocks use the static DashColors::ERROR constant. The theme.rs file also provides DashColors::error_color(dark_mode) which returns a lighter red for dark mode and DARK_RED for light mode. The constant approach is consistent with top_up_identity_screen (see relevant snippet), so this is fine if the intent is a uniform error color regardless of theme. Just flagging in case the theme-adaptive variant was intended.

Also applies to: 1147-1168

Comment thread src/ui/components/wallet_unlock.rs Outdated
Comment thread src/ui/tokens/tokens_screen/keyword_search.rs Outdated
Comment thread src/ui/tools/document_visualizer_screen.rs Outdated
Copy link
Copy Markdown
Contributor

@lklimek lklimek left a comment

Choose a reason for hiding this comment

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

See Rabbit's comments, once you apply them, it's gtm

PastaPastaPasta and others added 2 commits February 16, 2026 09:37
Replace all `crate::ui::theme::DashColors::` fully-qualified paths with
`DashColors::` across 28 files, adding `use crate::ui::theme::DashColors`
imports where missing. This improves readability and consistency.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Replace hardcoded error_color(true) with actual theme state
- Replace DashColors::ERROR with DashColors::error_color(dark_mode) for
  theme-adaptive error styling
- Replace hardcoded disabled button color with DashColors::BUTTON_DISABLED
- Clean up formatting from fully-qualified path removal

Addresses CodeRabbit review feedback on PR #572.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/ui/tokens/mint_tokens_screen.rs (1)

614-664: ⚠️ Potential issue | 🟡 Minor

Pre-existing: duplicate fee estimation frames rendered on screen.

Two fee estimation frames are displayed — one at lines 617–634 using estimate_document_batch(1) and another at lines 648–664 using estimate_token_transition(). This appears to be a pre-existing issue rather than something introduced by this PR, but it results in two "Estimated fee" boxes being rendered consecutively, which is likely unintended.

🤖 Fix all issues with AI agents
In `@src/ui/contracts_documents/register_contract_screen.rs`:
- Around line 180-181: Replace the non-adaptive DashColors::ERROR usage in the
error rendering branch with the theme-aware helper
DashColors::error_color(dark_mode); specifically, in register_contract_screen
(the block that checks if let Some(msg) = error_msg) swap DashColors::ERROR for
DashColors::error_color(dark_mode) and ensure the same dark_mode boolean you
already use for text_primary(dark_mode)/surface(dark_mode) is in scope (or
obtain it the same way) so the error color adapts to theme.

In `@src/ui/tokens/update_token_config.rs`:
- Line 1105: Replace the static, non-theme-adaptive DashColors::ERROR usage with
the theme-aware helper by calling DashColors::error_color(dark_mode); locate the
occurrence of DashColors::ERROR in update_token_config (where dark_mode is in
scope) and swap it to DashColors::error_color(dark_mode) so the error_color
matches the rest of theme-aware calls like surface(dark_mode) and
text_primary(dark_mode).
🧹 Nitpick comments (10)
src/ui/helpers.rs (2)

215-219: Remaining hardcoded colors in info_icon_button — inconsistent with PR goal.

This function still uses two inline Color32::from_rgb(…) values for the info icon's hover and default states. Given that this PR aims to centralize all inline colors to DashColors constants, these should be migrated as well.

Suggested approach
         let color = if is_hovered {
-            Color32::from_rgb(100, 180, 255) // Brighter blue on hover
+            DashColors::INFO_ICON_HOVER   // or a suitable existing/new constant
         } else {
-            Color32::from_rgb(70, 130, 180) // Steel blue
+            DashColors::INFO_ICON          // or a suitable existing/new constant
         };

860-894: Remaining hardcoded Color32::DARK_RED in render_group_action_text.

Three occurrences of Color32::DARK_RED (lines 863, 882, 888) were not migrated to a DashColors constant. This is inconsistent with the rest of the PR. Consider using DashColors::DANGER_RED or an equivalent semantic constant.

src/ui/identities/add_new_identity_screen/by_platform_address.rs (1)

80-81: Remaining hardcoded Color32::GRAY could be centralized too.

Line 81 still uses Color32::GRAY and line 243 uses Color32::WHITE. For full consistency with this PR's goal, consider replacing these with DashColors constants (e.g., a TEXT_DISABLED or similar token for gray, and a button-text color for white).

src/ui/identities/add_new_identity_screen/mod.rs (2)

1131-1134: Hardcoded warning color Color32::from_rgb(200, 150, 50) not centralized.

This is exactly the kind of inline color this PR aims to eliminate. Consider replacing with one of the new warning constants (e.g., DashColors::VALIDATION_WARNING or DashColors::WARNING_BRIGHT) introduced in theme.rs.


566-566: Hardcoded Color32::DARK_GREEN not centralized.

This could be replaced with a DashColors constant (e.g., DashColors::SUCCESS or a dedicated semantic token) for consistency with the broader refactor.

src/ui/tokens/direct_token_purchase_screen.rs (1)

613-617: Use DashColors::BUTTON_DISABLED for disabled button fill.

Line 616 has a hardcoded color for a disabled button. The BUTTON_DISABLED constant exists for this purpose and is already used consistently in other screen implementations (add_new_identity_screen, add_existing_identity_screen, set_token_price_screen).

Proposed fix
                    let button = egui::Button::new(
                        RichText::new(purchase_text).color(DashColors::muted_color(dark_mode)),
                    )
-                    .fill(Color32::from_rgb(50, 50, 50))
+                    .fill(DashColors::BUTTON_DISABLED)
                     .corner_radius(3.0);
src/ui/tokens/burn_tokens_screen.rs (1)

473-476: Replace hardcoded color with DashColors::WARNING_BRIGHT.

Line 474 uses a hardcoded egui::Color32::from_rgb(200, 150, 50) instead of leveraging the DashColors constants added in this PR. For a blocking wallet state like "Wallet is locked," use WARNING_BRIGHT (which is designed for important warnings requiring user action) rather than a custom color.

Suggested fix
                        ui.colored_label(
-                            egui::Color32::from_rgb(200, 150, 50),
+                            DashColors::WARNING_BRIGHT,
                             "Wallet is locked. Please unlock to continue.",
                         );
src/ui/contracts_documents/update_contract_screen.rs (1)

195-195: Use DashColors::error_color(dark_mode) for theme consistency.

Every other color change in this file uses the theme-aware helpers (text_primary(dark_mode), surface(dark_mode), etc.), but the error bubble uses the static DashColors::ERROR constant. The error_color() helper (see src/ui/theme.rs:304-310) returns a lighter red for dark mode, which would be more readable against a dark background. Since ui is available here, obtaining dark_mode is trivial.

♻️ Proposed fix
     if let Some(msg) = error_msg {
-            let error_color = DashColors::ERROR;
+            let dark_mode = ui.ctx().style().visuals.dark_mode;
+            let error_color = DashColors::error_color(dark_mode);
src/ui/contracts_documents/register_contract_screen.rs (1)

288-292: Remaining hardcoded colors not centralized.

A few Color32 literals remain in this file (DARK_GREEN at Line 289, DARK_RED at Lines 416/438, from_rgb(200, 150, 50) at Line 531) that weren't migrated to DashColors constants. These are unchanged lines so likely out of scope for this PR, but worth noting for a follow-up pass to fully centralize colors in this file.

Also applies to: 414-442, 529-533

src/ui/tokens/freeze_tokens_screen.rs (1)

622-622: Use theme-adaptive error_color(dark_mode) instead of static DashColors::ERROR for consistency.

Lines 571–582 correctly use theme-adaptive helpers (DashColors::surface(dark_mode), text_secondary(dark_mode), etc.). Line 622 breaks this pattern by using the static constant DashColors::ERROR, which won't adjust for dark mode. Since dark_mode is in scope (line 569), use DashColors::error_color(dark_mode) instead, which returns a lighter red in dark mode for better contrast.

♻️ Proposed fix
-                        let error_color = DashColors::ERROR;
+                        let error_color = DashColors::error_color(dark_mode);

Comment thread src/ui/contracts_documents/register_contract_screen.rs Outdated
Comment thread src/ui/tokens/update_token_config.rs Outdated
…update_token_config screens

Replace static DashColors::ERROR with DashColors::error_color(dark_mode)
so error bubbles adapt to the current light/dark theme.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
src/ui/tokens/update_token_config.rs (1)

1059-1061: Hardcoded Color32::from_rgb(200, 150, 50) — inconsistent with centralisation goal.

This inline warning color for a locked-wallet message should use a DashColors constant (e.g., VALIDATION_WARNING or a new wallet_locked_warning helper) for consistency with the rest of the refactor in this PR. The same applies to the other remaining hardcoded colors in this file (Color32::RED on lines 596/631/872, Color32::DARK_GREEN on lines 870/1102, Color32::DARK_RED on Line 1017, Color32::WHITE on Line 744).

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/ui/tokens/update_token_config.rs` around lines 1059 - 1061, Replace
hardcoded egui::Color32 usages in this file with the centralized DashColors
constants: change the ui.colored_label call that currently uses
Color32::from_rgb(200, 150, 50) to use DashColors::VALIDATION_WARNING or a new
DashColors::WALLET_LOCKED_WARNING constant (create it in DashColors if needed)
and update other occurrences (Color32::RED, Color32::DARK_GREEN,
Color32::DARK_RED, Color32::WHITE) to their corresponding DashColors values;
locate calls like ui.colored_label and any places referencing Color32 (e.g., the
ui.colored_label at the wallet-locked message and the other hardcoded colors
noted) and swap them to use the centralized constants so the file follows the
refactor’s color scheme.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@src/ui/tokens/update_token_config.rs`:
- Around line 1105-1106: The static color constant was replaced with a
theme-aware call—ensure the new lines use ui.ctx().style().visuals.dark_mode to
compute dark_mode and call DashColors::error_color(dark_mode) (replacing any
remaining DashColors::ERROR usages in this module), and run the UI to verify
error color adapts to theme; keep the updated calls as-is if no other
occurrences remain.

---

Nitpick comments:
In `@src/ui/tokens/update_token_config.rs`:
- Around line 1059-1061: Replace hardcoded egui::Color32 usages in this file
with the centralized DashColors constants: change the ui.colored_label call that
currently uses Color32::from_rgb(200, 150, 50) to use
DashColors::VALIDATION_WARNING or a new DashColors::WALLET_LOCKED_WARNING
constant (create it in DashColors if needed) and update other occurrences
(Color32::RED, Color32::DARK_GREEN, Color32::DARK_RED, Color32::WHITE) to their
corresponding DashColors values; locate calls like ui.colored_label and any
places referencing Color32 (e.g., the ui.colored_label at the wallet-locked
message and the other hardcoded colors noted) and swap them to use the
centralized constants so the file follows the refactor’s color scheme.

Keep both DashColors import (from this branch) and format_relative_time
function with chrono imports (from v1.0-dev).
* fix: skip best chain lock polling in SPV mode (#567)

* Initial plan

* Skip chain lock refresh in SPV mode

Co-authored-by: lklimek <842586+lklimek@users.noreply.github.com>

* Document SPV guard intent

Co-authored-by: lklimek <842586+lklimek@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: lklimek <842586+lklimek@users.noreply.github.com>

* fix: compute relative timestamps from actual data (#581)

* fix: compute relative timestamps from actual data

Replace hardcoded display strings like "Received: 1 day ago" with
real relative timestamps computed from document createdAt/updatedAt
fields using chrono::Utc::now().

Fixes #579

* style: fix import ordering per cargo fmt

* refactor: extract format_relative_time to shared dashpay module

Deduplicate the identical format_relative_time function that existed
in both contact_requests.rs and send_payment.rs. Move it to the
dashpay mod.rs as a pub(crate) function and import from both files.

---------

Co-authored-by: PastaClaw <thepastaclaw@users.noreply.github.com>

* fix: update platform for DIP-18 HRP and improve SPV sync progress (#575)

* fix: update dashpay/platform to d6f4eb9 for DIP-18 HRP fix

The previous platform revision used incorrect bech32m HRP prefixes
(evo/tevo) for Platform addresses. The updated commit uses the
correct DIP-0018 prefixes (dash/tdash).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* refactor(spv): use dash-spv SyncProgress API directly

Replace the intermediate SyncProgress/DetailedSyncProgress/SyncStage
translation layer with direct use of dash_spv::sync::SyncProgress.
This eliminates ~120 lines of bridge code in spawn_progress_watcher()
and determine_sync_stage(), and lets the UI query per-manager progress
(headers, filter_headers, filters, masternodes, blocks) via the
upstream API.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix(spv): improve sync progress accuracy and robustness

- Log headers() error before discarding for easier debugging
- Restore download-window optimization for headers progress on
  checkpoint-resumed syncs (progress starts near 0% not 83%)
- Replace catch-all _ => 0.0 with explicit SyncState variant matches
  so new variants produce compile errors
- Fix filters progress to use current_height/target_height instead of
  downloaded/target_height (session count vs absolute height mismatch)
- Restore peer count in sync status text
- Add "Querying peer heights" label and diffs_processed to masternode
  status for more informative sync messages

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix(spv): use height-based blocks progress to prevent bar from jumping

The blocks progress bar was bouncing backward because it used
processed/requested session counters whose denominator grows as filters
discover more matching blocks. Switch to last_processed block height
relative to headers target_height, which only increases. Display
"current / target" heights instead of percentage on the blocks bar.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix(spv): improve progress bar resilience across resume and network switch

- Add windowed progress tracking for filters (consistent with headers/filter_headers)
- Reset blocks_stage_start on Error state so recovery gets a fresh window
- Track spv_progress_network to detect network changes and rebuild progress
  state from the new network's sync_progress instead of resetting to zero
- Eliminate redundant clone in progress watcher (move instead of clone twice)
- Consolidate all progress state reset logic into rebuild_spv_progress_state()

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>

* build: add git and cargo permissions to Claude Code workflow (#565)

* build: add git and cargo permissions to Claude Code workflow

Allow Claude to run git fetch/merge/checkout/rebase/push and
cargo build/test/clippy/fmt commands. Switch model to opus.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: use claude_args for model and allowed tools

The `model` and `allowed_tools` inputs are not declared in
claude-code-action@v1 and are silently ignored. Move them to
`claude_args` with --model and --allowedTools flags. Also fix
deprecated colon syntax (`:*`) to space syntax (` *`).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: use single quotes to prevent glob expansion in allowed tools

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* build: sandbox cargo commands and add git permissions for Claude

- Add safe-cargo.sh wrapper that strips CI secrets before running cargo
- Use --allowedTools for git and safe-cargo, --disallowedTools for raw cargo
- Document safe-cargo usage in CLAUDE.md

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: switch safe-cargo.sh from denylist to allowlist approach

Use `env -i` (start with empty environment, explicitly pass only
what cargo needs) instead of `env -u` (strip known secrets). This
is more robust against future secrets being added to the workflow.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* build: deny Claude from editing CI scripts and workflows

Prevent Claude from modifying .github/scripts/ and .github/workflows/
to ensure the safe-cargo wrapper cannot be tampered with.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: conditionally pass optional env vars in safe-cargo.sh

Empty PROTOC="" caused prost build scripts to fail with
"protoc not found". Now optional vars (PROTOC, CC, CXX, etc.)
are only passed when set and non-empty.

Tested: build, test, fmt all pass through the wrapper.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* rabbit feedback

* build: move safe-cargo.sh to scripts/ and allow +nightly fmt

Move safe-cargo.sh from .github/scripts/ to top-level scripts/ for
better discoverability. Add detailed comment explaining why the wrapper
exists (prevent CI secret exfiltration via build scripts). Update all
references in claude.yml, CLAUDE.md, and permission settings. Add
`+nightly fmt` to allowedTools so Claude can follow CLAUDE.md
formatting instructions in CI.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>

* fix: handle errors instead of panicking on corrupted database blobs (#561)

* fix: return error instead of panicking on corrupted database blobs (#560)

- Replace `unreachable!()` in `get_scheduled_votes` with warning log and
  default to false for unexpected `executed` column values
- Change `QualifiedIdentity::from_bytes()` to return `Result` instead of
  panicking via `.expect()`
- Propagate deserialization errors as `rusqlite::Error` in all 6 callers
  so corrupted database is surfaced to the user rather than silently
  ignored or crashing the app
- Add `CorruptedBlobError` newtype in database module to eliminate
  repeated `FromSqlConversionFailure` boilerplate

Closes #560

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* chore: impl thiserror

* chore: fmt

* build: add Claude Code GitHub workflow and settings (#552)

Cherry-pick from v1.0-dev to enable @claude mentions in PRs.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* chore: fix after merge

* fix: skip corrupted identity blobs in get_wallets instead of aborting

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* chore: fail on corrupted identity

* doc: document error handling in the db

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>

* feat: track DAPI endpoint availability in connection status (#533)

* fix: connection status not updated

* chore: rabbit feedback

* Initial plan

* Track DAPI connection status and display in tooltips and connection info

- Add dapi_total_endpoints and dapi_available fields to ConnectionStatus
- Factor DAPI availability into overall_connected status (RED when no endpoints available)
- Query SDK AddressList during periodic refresh for endpoint counts and availability
- Display DAPI status in connection indicator tooltip
- Display DAPI status in network chooser Connection Status card (all modes)
- Add dapi_status_label() helper for consistent status text formatting

Co-authored-by: lklimek <842586+lklimek@users.noreply.github.com>

* Address review feedback: store available endpoint count and extract DRY helper

- Changed dapi_available from AtomicBool to AtomicU16 (dapi_available_endpoints) to store
  the count of available endpoints instead of just a boolean
- Display format now shows "Available ({available}/{total} endpoints)"
- Extracted repeated DAPI status rendering into add_dapi_status_label() helper function
  in network_chooser_screen.rs to eliminate code duplication

Co-authored-by: lklimek <842586+lklimek@users.noreply.github.com>

* Fix rustfmt formatting issues in connection_status.rs

- Reorder atomic imports (AtomicU8 before AtomicU16) per rustfmt
- Wrap long .store() call to respect line length
- Wrap long format!() strings to respect line length

Co-authored-by: lklimek <842586+lklimek@users.noreply.github.com>

* Fix borrow checker error: extract DAPI status values before mutable self borrow

The add_dapi_status_label helper was capturing a &ConnectionStatus reference
(derived from self) in closures, which extended the immutable borrow past the
self.render_spv_sync_progress() mutable borrow on line 594.

Fix: change add_dapi_status_label to accept pre-computed owned values
(dapi_total, dapi_available, dapi_label) instead of &ConnectionStatus, and
extract those values early alongside other status fields.

Co-authored-by: lklimek <842586+lklimek@users.noreply.github.com>

* Switch Platform to c2c88e4 and use get_live_addresses() for accurate available count

Updated dash-sdk dependency to Platform commit c2c88e4a988ce930 which adds
AddressList::get_live_addresses() method. Replaced the workaround that used
get_live_address().is_some() (which could only tell if at least one endpoint
was live) with get_live_addresses().len() to get the exact count of available
non-banned DAPI endpoints.

Co-authored-by: lklimek <842586+lklimek@users.noreply.github.com>

* chore: typo + network changes

* chore: apply feedback

* chore: rabbit review

* chore: rabbit feedback

* chore: rabbitting

* Remove overall_connected_with method (deleted upstream in base branch)

Co-authored-by: lklimek <842586+lklimek@users.noreply.github.com>

* Merge v1.0-dev into copilot/update-dapi-connection-status

Resolved modify/delete conflict on src/context.rs: removed the file
since v1.0-dev refactored it into src/context/mod.rs and submodules,
which already include our Arc<ConnectionStatus> changes.

Co-authored-by: lklimek <842586+lklimek@users.noreply.github.com>

* chore: fix platfom versioning issues

* chore: add todo

* chore: fmt

---------

Co-authored-by: Lukasz Klimek <842586+lklimek@users.noreply.github.com>
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>

* refactor(spv): eliminate separate thread/runtime, improve shutdown and UX (#577)

* fix: update dashpay/platform to d6f4eb9 for DIP-18 HRP fix

The previous platform revision used incorrect bech32m HRP prefixes
(evo/tevo) for Platform addresses. The updated commit uses the
correct DIP-0018 prefixes (dash/tdash).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* refactor(spv): use dash-spv SyncProgress API directly

Replace the intermediate SyncProgress/DetailedSyncProgress/SyncStage
translation layer with direct use of dash_spv::sync::SyncProgress.
This eliminates ~120 lines of bridge code in spawn_progress_watcher()
and determine_sync_stage(), and lets the UI query per-manager progress
(headers, filter_headers, filters, masternodes, blocks) via the
upstream API.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix(spv): improve sync progress accuracy and robustness

- Log headers() error before discarding for easier debugging
- Restore download-window optimization for headers progress on
  checkpoint-resumed syncs (progress starts near 0% not 83%)
- Replace catch-all _ => 0.0 with explicit SyncState variant matches
  so new variants produce compile errors
- Fix filters progress to use current_height/target_height instead of
  downloaded/target_height (session count vs absolute height mismatch)
- Restore peer count in sync status text
- Add "Querying peer heights" label and diffs_processed to masternode
  status for more informative sync messages

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix(spv): use height-based blocks progress to prevent bar from jumping

The blocks progress bar was bouncing backward because it used
processed/requested session counters whose denominator grows as filters
discover more matching blocks. Switch to last_processed block height
relative to headers target_height, which only increases. Display
"current / target" heights instead of percentage on the blocks bar.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix(spv): improve progress bar resilience across resume and network switch

- Add windowed progress tracking for filters (consistent with headers/filter_headers)
- Reset blocks_stage_start on Error state so recovery gets a fresh window
- Track spv_progress_network to detect network changes and rebuild progress
  state from the new network's sync_progress instead of resetting to zero
- Eliminate redundant clone in progress watcher (move instead of clone twice)
- Consolidate all progress state reset logic into rebuild_spv_progress_state()

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix(spv): update ConnectionStatus immediately on connect/disconnect

Propagate SPV status into ConnectionStatus right after start_spv() and
stop_spv() so the UI reflects the change on the next frame instead of
waiting for the next throttled trigger_refresh() cycle (2-10 seconds).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix(spv): check cancellation token in listener tasks to prevent shutdown hang

SPV finality and reconcile listeners blocked app shutdown for up to 10s
because they never checked the global cancellation token. Add cancel
branches to their tokio::select! loops so they exit immediately on
shutdown.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* chore: remove log spamming line

* fix(spv): make listener handler calls cancellation-aware and add shutdown trace logging

Wrap reconcile_spv_wallets(), handle_spv_finality_event(), and the
debounce sleep inside tokio::select! with the cancellation token so
shutdown can interrupt them even when blocked on locks held by the
SPV sync thread.

Add trace-level logging to TaskManager::shutdown() for per-task join
timing to aid future shutdown diagnostics.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix(spv): disable Disconnect button during stopping and poll status faster

- Disable the Disconnect button while SPV status is Stopping to prevent
  double-clicks and provide visual feedback
- Poll SPV status every 200ms during Stopping instead of the 10s
  connected interval so the Stopped transition is reflected within 1s
- Reset the throttle timer in stop_spv() so fast polling starts
  immediately

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* refactor(tasks): add mandatory task names to spawn_sync for shutdown diagnostics

Change spawn_sync() signature to require a &'static str name. The
JoinSet now yields the task name on completion, letting shutdown()
log which tasks finished and which ones timed out.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* chore: log task names

* refactor(spv): eliminate separate OS thread and tokio runtime

Replace the dedicated SPV thread + 4-worker tokio runtime with a
spawned task on the main 12-worker runtime via TaskManager::spawn_sync.

This simplifies shutdown (SPV loop now tracked in unified JoinSet),
removes cross-runtime complexity, and improves debuggability.

Additional changes:
- Fix: zeroize xprv_str after wallet import (security H-1)
- Fix: sanitize devnet_name in build_spv_data_dir to prevent path traversal
- Add 21 integration tests covering lifecycle, concurrency, deadlock
  detection, and live testnet sync

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix(spv): derive stop_token as child of global cancel for clean shutdown

The spv_request_handler selected on stop_token, which was independent
of the global cancellation token.  During window-close shutdown only
the global token was cancelled, leaving the request handler running
and causing a ~5s hang until the TaskManager timeout aborted it.

Fix by creating stop_token as a child_token() of the global cancel.
This also simplifies run_spv_loop and run_sync_and_monitor by removing
the redundant global_cancel parameter — a single stop_token now covers
both explicit SpvManager::stop() and application-wide shutdown.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* CLAUDE: minor changes about docs

* fix(spv): bump rust-dashcore to d8bc066 for faster disconnect and add shutdown tracing

Pin rust-dashcore patches to commit d8bc066 which includes:
- sync manager task loop exits on network errors instead of logging indefinitely
- sync coordinator signal_shutdown() cancels tasks before network disconnect
- connection tasks race Peer::connect() against shutdown token

Add debug tracing to SpvManager::stop() and run_sync_and_monitor() to
measure client.stop() duration, and trace-level polling of SPV status
in ConnectionStatus.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* chore: update rust-dashcore rev

* merge: resolve v1.0-dev conflicts for #577 (#585)

* fix: compute relative timestamps from actual data (#581)

* fix: compute relative timestamps from actual data

Replace hardcoded display strings like "Received: 1 day ago" with
real relative timestamps computed from document createdAt/updatedAt
fields using chrono::Utc::now().

Fixes #579

* style: fix import ordering per cargo fmt

* refactor: extract format_relative_time to shared dashpay module

Deduplicate the identical format_relative_time function that existed
in both contact_requests.rs and send_payment.rs. Move it to the
dashpay mod.rs as a pub(crate) function and import from both files.

---------

Co-authored-by: PastaClaw <thepastaclaw@users.noreply.github.com>

* fix: update platform for DIP-18 HRP and improve SPV sync progress (#575)

* fix: update dashpay/platform to d6f4eb9 for DIP-18 HRP fix

The previous platform revision used incorrect bech32m HRP prefixes
(evo/tevo) for Platform addresses. The updated commit uses the
correct DIP-0018 prefixes (dash/tdash).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* refactor(spv): use dash-spv SyncProgress API directly

Replace the intermediate SyncProgress/DetailedSyncProgress/SyncStage
translation layer with direct use of dash_spv::sync::SyncProgress.
This eliminates ~120 lines of bridge code in spawn_progress_watcher()
and determine_sync_stage(), and lets the UI query per-manager progress
(headers, filter_headers, filters, masternodes, blocks) via the
upstream API.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix(spv): improve sync progress accuracy and robustness

- Log headers() error before discarding for easier debugging
- Restore download-window optimization for headers progress on
  checkpoint-resumed syncs (progress starts near 0% not 83%)
- Replace catch-all _ => 0.0 with explicit SyncState variant matches
  so new variants produce compile errors
- Fix filters progress to use current_height/target_height instead of
  downloaded/target_height (session count vs absolute height mismatch)
- Restore peer count in sync status text
- Add "Querying peer heights" label and diffs_processed to masternode
  status for more informative sync messages

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix(spv): use height-based blocks progress to prevent bar from jumping

The blocks progress bar was bouncing backward because it used
processed/requested session counters whose denominator grows as filters
discover more matching blocks. Switch to last_processed block height
relative to headers target_height, which only increases. Display
"current / target" heights instead of percentage on the blocks bar.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix(spv): improve progress bar resilience across resume and network switch

- Add windowed progress tracking for filters (consistent with headers/filter_headers)
- Reset blocks_stage_start on Error state so recovery gets a fresh window
- Track spv_progress_network to detect network changes and rebuild progress
  state from the new network's sync_progress instead of resetting to zero
- Eliminate redundant clone in progress watcher (move instead of clone twice)
- Consolidate all progress state reset logic into rebuild_spv_progress_state()

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>

* build: add git and cargo permissions to Claude Code workflow (#565)

* build: add git and cargo permissions to Claude Code workflow

Allow Claude to run git fetch/merge/checkout/rebase/push and
cargo build/test/clippy/fmt commands. Switch model to opus.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: use claude_args for model and allowed tools

The `model` and `allowed_tools` inputs are not declared in
claude-code-action@v1 and are silently ignored. Move them to
`claude_args` with --model and --allowedTools flags. Also fix
deprecated colon syntax (`:*`) to space syntax (` *`).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: use single quotes to prevent glob expansion in allowed tools

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* build: sandbox cargo commands and add git permissions for Claude

- Add safe-cargo.sh wrapper that strips CI secrets before running cargo
- Use --allowedTools for git and safe-cargo, --disallowedTools for raw cargo
- Document safe-cargo usage in CLAUDE.md

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: switch safe-cargo.sh from denylist to allowlist approach

Use `env -i` (start with empty environment, explicitly pass only
what cargo needs) instead of `env -u` (strip known secrets). This
is more robust against future secrets being added to the workflow.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* build: deny Claude from editing CI scripts and workflows

Prevent Claude from modifying .github/scripts/ and .github/workflows/
to ensure the safe-cargo wrapper cannot be tampered with.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: conditionally pass optional env vars in safe-cargo.sh

Empty PROTOC="" caused prost build scripts to fail with
"protoc not found". Now optional vars (PROTOC, CC, CXX, etc.)
are only passed when set and non-empty.

Tested: build, test, fmt all pass through the wrapper.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* rabbit feedback

* build: move safe-cargo.sh to scripts/ and allow +nightly fmt

Move safe-cargo.sh from .github/scripts/ to top-level scripts/ for
better discoverability. Add detailed comment explaining why the wrapper
exists (prevent CI secret exfiltration via build scripts). Update all
references in claude.yml, CLAUDE.md, and permission settings. Add
`+nightly fmt` to allowedTools so Claude can follow CLAUDE.md
formatting instructions in CI.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: PastaClaw <thepastaclaw@users.noreply.github.com>
Co-authored-by: lklimek <842586+lklimek@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>

* chore: bump rust-dashcore

* chore: imports

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Pasta Lil Claw <pasta+claw@dashboost.org>
Co-authored-by: PastaClaw <thepastaclaw@users.noreply.github.com>
Co-authored-by: PastaPastaPasta <6443210+PastaPastaPasta@users.noreply.github.com>

* ci: cancel in-progress workflow runs on new push (#590)

* ci: cancel in-progress workflow runs on new push

Add concurrency groups to Tests and Clippy workflows so that
previous runs are automatically cancelled when a new commit is
pushed to the same branch or PR.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* trigger ci

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>

* fix: use correct DashPay profile field "publicMessage" instead of "bio" (#582)

The DashPay contract schema defines the field as "publicMessage",
not "bio". This caused profile bios to never load in contact info.

Co-authored-by: PastaClaw <thepastaclaw@users.noreply.github.com>

---------

Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com>
Co-authored-by: lklimek <842586+lklimek@users.noreply.github.com>
Co-authored-by: PastaClaw <thepastaclaw@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: PastaPastaPasta <6443210+PastaPastaPasta@users.noreply.github.com>
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (3)
src/ui/dashpay/contact_requests.rs (3)

401-407: Consider using DashColors::error_color(dark_mode) instead of the manual branch.

DashColors::ERROR is rgb(235, 87, 87), which differs from the previous dark-mode value rgb(255, 100, 100) — that value is exactly what DashColors::error_color(dark_mode) returns for dark mode. The commit message also states the intent was to use error_color(dark_mode). You can collapse the conditional into a single call:

Proposed fix
-            let dark_mode = ui.ctx().style().visuals.dark_mode;
-            let error_color = if dark_mode {
-                DashColors::ERROR
-            } else {
-                egui::Color32::DARK_RED
-            };
+            let dark_mode = ui.ctx().style().visuals.dark_mode;
+            let error_color = DashColors::error_color(dark_mode);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/ui/dashpay/contact_requests.rs` around lines 401 - 407, The code
currently computes error_color with a manual dark_mode branch inside the block
that checks self.error (see the if let Some(err) = self.error.clone() block and
the error_color variable), but should call DashColors::error_color(dark_mode)
instead; replace the conditional that selects DashColors::ERROR vs
egui::Color32::DARK_RED with a single call to
DashColors::error_color(dark_mode), keeping the same dark_mode value derived
from ui.ctx().style().visuals.dark_mode so the error color matches the intended
theme.

733-735: "Add Contact" button still uses inline color literals.

Color32::WHITE and Color32::from_rgb(0, 141, 228) (which is DashColors::DASH_BLUE) are hardcoded here. This is the exact pattern this PR aims to eliminate.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/ui/dashpay/contact_requests.rs` around lines 733 - 735, Replace the
hardcoded color literals used on the "Add Contact" button (the
RichText::new(...).color(Color32::WHITE) and the .fill(Color32::from_rgb(0, 141,
228)) call) with the shared color constants from DashColors (e.g.
DashColors::WHITE and DashColors::DASH_BLUE). Update the
RichText::new(...).color(...) and .fill(...) invocations to reference those
constants and add the DashColors import if missing so the button uses the
centralized theme colors.

610-622: Remaining hardcoded colors not migrated to DashColors.

Lines 614 and 621 still use inline Color32::from_rgb(...) for the "Accepted" (green) and "Rejected" (red) status labels. These could use DashColors::success_color(dark_mode) and DashColors::error_color(dark_mode) respectively to stay consistent with the PR's centralization goal.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/ui/dashpay/contact_requests.rs` around lines 610 - 622, Replace the
inline Color32::from_rgb(...) calls used for the status labels with the
centralized DashColors helpers: where the code checks
self.accepted_requests.contains(&request.request_id) and creates
RichText::new("Accepted") use DashColors::success_color(dark_mode) for the
color; where it checks self.rejected_requests.contains(&request.request_id) and
creates RichText::new("Rejected") use DashColors::error_color(dark_mode). Ensure
you pass the appropriate dark_mode variable in scope (e.g., dark_mode or
self.dark_mode) to the success_color and error_color calls so styling is
consistent with the rest of the UI.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@src/ui/dashpay/contact_requests.rs`:
- Around line 401-407: The code currently computes error_color with a manual
dark_mode branch inside the block that checks self.error (see the if let
Some(err) = self.error.clone() block and the error_color variable), but should
call DashColors::error_color(dark_mode) instead; replace the conditional that
selects DashColors::ERROR vs egui::Color32::DARK_RED with a single call to
DashColors::error_color(dark_mode), keeping the same dark_mode value derived
from ui.ctx().style().visuals.dark_mode so the error color matches the intended
theme.
- Around line 733-735: Replace the hardcoded color literals used on the "Add
Contact" button (the RichText::new(...).color(Color32::WHITE) and the
.fill(Color32::from_rgb(0, 141, 228)) call) with the shared color constants from
DashColors (e.g. DashColors::WHITE and DashColors::DASH_BLUE). Update the
RichText::new(...).color(...) and .fill(...) invocations to reference those
constants and add the DashColors import if missing so the button uses the
centralized theme colors.
- Around line 610-622: Replace the inline Color32::from_rgb(...) calls used for
the status labels with the centralized DashColors helpers: where the code checks
self.accepted_requests.contains(&request.request_id) and creates
RichText::new("Accepted") use DashColors::success_color(dark_mode) for the
color; where it checks self.rejected_requests.contains(&request.request_id) and
creates RichText::new("Rejected") use DashColors::error_color(dark_mode). Ensure
you pass the appropriate dark_mode variable in scope (e.g., dark_mode or
self.dark_mode) to the success_color and error_color calls so styling is
consistent with the rest of the UI.

@PastaPastaPasta PastaPastaPasta merged commit 042d872 into v1.0-dev Feb 17, 2026
5 checks passed
@PastaPastaPasta PastaPastaPasta deleted the refactor/centralize-dash-colors branch February 17, 2026 18:35
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.

3 participants