Skip to content

feat: add counter text type for tick contract markers#472

Merged
behnam-deriv merged 2 commits intomasterfrom
add-marker-text-counter
Apr 3, 2026
Merged

feat: add counter text type for tick contract markers#472
behnam-deriv merged 2 commits intomasterfrom
add-marker-text-counter

Conversation

@behnam-deriv
Copy link
Copy Markdown
Collaborator

@behnam-deriv behnam-deriv commented Apr 3, 2026

Summary

This PR introduces a MarkerTextType enum and the supporting rendering logic to display styled text inline on the dashed connector line of a contract marker; specifically to show a live tick counter (e.g. 2/10) for tick-duration contracts.

Changes

ChartMarker / MarkerType

  • Added MarkerTextType enum with two variants:

    • plain — renders the text in a uniform style (default, backward-compatible)
    • counter — splits the text on / and renders the left part prominently (larger, bold) and the right part (including /) smaller, to convey a "current / total" progress
  • Added textType field to ChartMarker (defaults to MarkerTextType.plain)

TickMarkerIconPainter

  • When a contractMarker has non-empty text, the dashed connector line is now split around an inline text label instead of drawing a plain line
  • A new private _paintDashedLineWithText method handles layout: it positions the text near the start-time marker, then draws the dashed line in two segments on either side

paint_text.dart

  • Added makeDelimitedTextPainter. a helper that splits a string on a given delimiter and builds a TextPainter with a TextSpan applying different styles to each part

Theme

  • Added markerTextColor to MarkerStyle and wired it up in both ChartDefaultDarkTheme and ChartDefaultLightTheme using the appropriate design tokens

How it works

contractMarker.text     = "2/10"
contractMarker.textType = MarkerTextType.counter

The painter splits "2/10" at /, renders "2" at 20 px / bold and "/10" at 12 px / regular, then draws the dashed line on both sides of the label along the connector.

For markers without text (or with textType: plain) the existing rendering path is unchanged.

Summary by Sourcery

Add support for styled inline text on contract marker connector lines, enabling counter-style tick labels and theming for marker text.

New Features:

  • Introduce MarkerTextType enum and textType property on ChartMarker to control marker text styling, including a new counter style for progress-like labels.
  • Add inline text rendering on the tick contract dashed connector line, splitting the line around the label when marker text is present.
  • Provide a makeDelimitedTextPainter helper to build differently styled text segments from a delimited string.

Enhancements:

  • Extend MarkerStyle and chart themes with a configurable markerTextColor used when rendering marker text.

  Introduce `MarkerTextType` enum (`plain` / `counter`) on `ChartMarker`
  to control how the `text` field is rendered on the dashed connector line.

  - Add `makeDelimitedTextPainter` helper that splits text on a delimiter
    and applies distinct styles to each part (e.g. "2" vs "/10")
  - Render text inline on the dashed line in `TickMarkerIconPainter`,
    splitting the line around the label when text is present
  - Add `markerTextColor` to `MarkerStyle` and both default themes
@sourcery-ai
Copy link
Copy Markdown
Contributor

sourcery-ai bot commented Apr 3, 2026

Reviewer's Guide

Implements inline text rendering (including a new counter style) on the tick contract connector line by extending marker metadata, adding a delimited text painter helper, and wiring theme colors for marker text; existing markers without text remain visually unchanged.

Sequence diagram for painting tick connector line with optional counter text

sequenceDiagram
  participant TickMarkerIconPainter
  participant MarkerGroup
  participant ChartMarker
  participant ChartTheme
  participant PaintTextHelpers
  participant Canvas

  TickMarkerIconPainter->>MarkerGroup: markers
  TickMarkerIconPainter->>MarkerGroup: firstWhereOrNull(markerType == contractMarker)
  MarkerGroup-->>TickMarkerIconPainter: ChartMarker contractMarker
  TickMarkerIconPainter->>ChartMarker: get text, textType
  TickMarkerIconPainter->>ChartTheme: get markerStyle.markerTextColor
  alt contractMarker has non empty text
    TickMarkerIconPainter->>TickMarkerIconPainter: _paintDashedLineWithText(canvas, offsets, color, text, textType, theme, opacity)
    alt textType == counter
      TickMarkerIconPainter->>PaintTextHelpers: makeDelimitedTextPainter(text, '/', primaryStyle, secondaryStyle)
      PaintTextHelpers-->>TickMarkerIconPainter: TextPainter
    else textType == plain
      TickMarkerIconPainter->>PaintTextHelpers: makeTextPainter(text, style)
      PaintTextHelpers-->>TickMarkerIconPainter: TextPainter
    end
    TickMarkerIconPainter->>Canvas: paintHorizontalDashedLine(left segment)
    TickMarkerIconPainter->>Canvas: paintHorizontalDashedLine(right segment)
    TickMarkerIconPainter->>PaintTextHelpers: paintWithTextPainter(canvas, textPainter, anchor)
  else no text
    TickMarkerIconPainter->>Canvas: paintHorizontalDashedLine(full line)
  end
Loading

Class diagram for updated marker text styling and theming

classDiagram
  class MarkerType {
  }

  class MarkerTextType {
    <<enumeration>>
    plain
    counter
  }

  class Marker {
  }

  class ChartMarker {
    String~nullable~ text
    MarkerType~nullable~ markerType
    MarkerTextType textType
    Color~nullable~ color
    bool hasReducedOpacity
    Offset displayOffset
  }

  class MarkerStyle {
    Color lineProfitColor
    Color lineLossColor
    Color lineDefaultColor
    Color markerTextColor
    double radius
    TextStyle activeMarkerText
  }

  class LightThemeColors {
    Color upColorProminent
    Color downColorProminent
    Color markerTextColor
  }

  class DarkThemeColors {
    Color upColorProminent
    Color downColorProminent
    Color markerTextColor
  }

  class ChartDefaultTheme {
  }

  class ChartDefaultLightTheme {
  }

  class ChartDefaultDarkTheme {
  }

  Marker <|-- ChartMarker
  ChartMarker --> MarkerType
  ChartMarker --> MarkerTextType

  ChartDefaultTheme <|-- ChartDefaultLightTheme
  ChartDefaultTheme <|-- ChartDefaultDarkTheme

  ChartDefaultLightTheme --> MarkerStyle : creates
  ChartDefaultDarkTheme --> MarkerStyle : creates

  LightThemeColors --> MarkerStyle : provides markerTextColor
  DarkThemeColors --> MarkerStyle : provides markerTextColor

  MarkerStyle --> Marker : styling for markers
  MarkerStyle --> ChartMarker : styling for chart markers

  MarkerTextType ..> MarkerStyle : controls text styling
Loading

File-Level Changes

Change Details Files
Render contract marker text inline on the dashed connector between contract marker and start time, with optional counter styling.
  • Extend TickMarkerIconPainter to look up the contract marker in the group and, when non-empty text is present, route rendering through a new _paintDashedLineWithText helper instead of always drawing a single dashed line.
  • Implement _paintDashedLineWithText to layout text near the start-time marker, compute its bounds, and draw two dashed line segments on either side while vertically centering the text on the line.
  • Keep the legacy path (single dashed line) when there is no contract marker, no text, or empty text to preserve existing behavior.
  • Import collection/firstWhereOrNull to safely find the contract marker without throwing when missing.
lib/src/deriv_chart/chart/data_visualization/markers/marker_icon_painters/tick_marker_icon_painter.dart
Introduce a delimited text painter to style counter-like text (e.g. current/total) with different emphasis on each part.
  • Add makeDelimitedTextPainter helper that splits on the first occurrence of a delimiter, applies a primary TextStyle to the leading segment and a secondary TextStyle to the delimiter+trailing segment, then lays out the TextPainter.
  • Fall back to the existing makeTextPainter with the primary style when the delimiter is missing or at index 0 to avoid odd rendering cases.
lib/src/deriv_chart/chart/helpers/paint_functions/paint_text.dart
Extend ChartMarker metadata with a MarkerTextType enum to control text styling, defaulting to plain.
  • Define MarkerTextType enum with plain and counter variants, documenting that counter expects a '/' separator and is intended for progress counters like "2/10".
  • Add a textType field to ChartMarker with a default of MarkerTextType.plain and expose it as a final property that controls how associated text is styled.
lib/src/deriv_chart/chart/data_visualization/markers/chart_marker.dart
Add theme-driven configuration for marker text color and use it in marker styling.
  • Introduce markerTextColor to MarkerStyle, with a default white color and documentation indicating it controls marker text color.
  • Extend ChartDefaultLightTheme and ChartDefaultDarkTheme to pass markerTextColor from their respective LightThemeColors and DarkThemeColors.
  • Add markerTextColor constants to LightThemeColors and DarkThemeColors, wired to the appropriate Component/Design tokens for prominent text/icon colors.
lib/src/theme/colors.dart
lib/src/theme/painting_styles/marker_style.dart
lib/src/theme/chart_default_dark_theme.dart
lib/src/theme/chart_default_light_theme.dart

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@github-actions
Copy link
Copy Markdown

github-actions bot commented Apr 3, 2026

Dependency Review

✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.

Snapshot Warnings

⚠️: No snapshots were found for the head SHA 4bf3387.
Ensure that dependencies are being submitted on PR branches and consider enabling retry-on-snapshot-warnings. See the documentation for more information and troubleshooting advice.

OpenSSF Scorecard

PackageVersionScoreDetails

Scanned Manifest Files

Copy link
Copy Markdown
Contributor

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

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

Hey - I've found 1 issue, and left some high level feedback:

  • In _paintDashedLineWithText, the logic assumes lineStart.dx < lineEnd.dx and specific left-to-right geometry; it may be worth explicitly constraining or asserting this (or handling the reversed case) to avoid subtle layout issues if marker positions ever invert.
  • The plain/counter text styles in _paintDashedLineWithText are hard-coded (font sizes 20/12, weights, etc.); consider moving these into theme/MarkerStyle so they can be tuned consistently with the rest of the chart typography.
  • The non-text path now calls paintHorizontalDashedLine with the start and end X coordinates reversed from the previous implementation; double-check whether paintHorizontalDashedLine expects a specific ordering and, if so, keep the call sites consistent to avoid unexpected dash rendering.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In `_paintDashedLineWithText`, the logic assumes `lineStart.dx < lineEnd.dx` and specific left-to-right geometry; it may be worth explicitly constraining or asserting this (or handling the reversed case) to avoid subtle layout issues if marker positions ever invert.
- The plain/counter text styles in `_paintDashedLineWithText` are hard-coded (font sizes 20/12, weights, etc.); consider moving these into theme/MarkerStyle so they can be tuned consistently with the rest of the chart typography.
- The non-text path now calls `paintHorizontalDashedLine` with the start and end X coordinates reversed from the previous implementation; double-check whether `paintHorizontalDashedLine` expects a specific ordering and, if so, keep the call sites consistent to avoid unexpected dash rendering.

## Individual Comments

### Comment 1
<location path="lib/src/deriv_chart/chart/data_visualization/markers/marker_icon_painters/tick_marker_icon_painter.dart" line_range="338-349" />
<code_context>
+            ),
+          );
+
+    final double textRight = lineEnd.dx - _textPaddingFromStartLine;
+    final double textLeft = textRight - textPainter.width;
+
+    if (lineStart.dx < textLeft - _textGap) {
</code_context>
<issue_to_address>
**suggestion (bug_risk):** Text layout does not guard against insufficient horizontal space between markers.

With narrow space between `lineStart` and `lineEnd`, `textPainter.width` can exceed the available width so that `textLeft` < `lineStart.dx`, causing the text to overlap the marker or bleed outside the segment. The current guards (`lineStart.dx < textLeft - _textGap` / `lineStart.dx < lineEnd.dx`) don’t prevent this. Consider checking whether `textPainter.width + 2 * (_textGap + _textPaddingFromStartLine)` exceeds `lineEnd.dx - lineStart.dx` and then either skip the text and draw only the dashed line, reduce the font size, or clamp the text so it never crosses `lineStart.dx`.

```suggestion
        : makeTextPainter(
            text,
            TextStyle(
              color: textColor,
              fontSize: 12,
              fontWeight: FontWeight.w700,
              height: 1,
            ),
          );

    // Guard against insufficient horizontal space between markers for the label.
    final double availableWidth = lineEnd.dx - lineStart.dx;
    final double requiredWidth =
        textPainter.width + 2 * (_textGap + _textPaddingFromStartLine);

    if (requiredWidth > availableWidth && lineStart.dx < lineEnd.dx) {
      // Not enough space to render the text without overlapping markers
      // or bleeding outside the segment. Draw only the dashed line.
      paintHorizontalDashedLine(
        canvas,
        lineEnd.dx,
        lineStart.dx,
        lineStart.dy,
        lineColor,
        1,
        dashWidth: 2,
        dashSpace: 2,
      );
      return;
    }

    final double textRight = lineEnd.dx - _textPaddingFromStartLine;
    final double textLeft = textRight - textPainter.width;
```
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

@claude
Copy link
Copy Markdown

claude bot commented Apr 3, 2026

Claude finished @behnam-deriv's task —— View job


Code Review Complete

I've completed my review of PR #472. Here's my comprehensive feedback:


Priority Issues

HIGH Priority: Text Layout Overflow Guard Missing 🔴

Location: tick_marker_icon_painter.dart:307-386 (in _paintDashedLineWithText)

Issue: The current implementation doesn't guard against insufficient horizontal space between the contract marker and start time marker. When the distance is too small for the text width plus padding/gaps, the text can:

  • Overlap the contract marker circle
  • Extend beyond lineStart.dx
  • Cause visual artifacts

Current Logic:

final double textRight = lineEnd.dx - _textPaddingFromStartLine;
final double textLeft = textRight - textPainter.width;

if (lineStart.dx < textLeft - _textGap) {
  // Draw left line segment
}

The check lineStart.dx < textLeft - _textGap only determines whether to draw the left line segment, but doesn't prevent rendering text that doesn't fit.

Recommended Fix:

// Add guard at the beginning of _paintDashedLineWithText
final double availableWidth = lineEnd.dx - lineStart.dx;
final double requiredWidth = textPainter.width + 2 * (_textGap + _textPaddingFromStartLine);

if (requiredWidth > availableWidth) {
  // Not enough space - fall back to plain dashed line
  paintHorizontalDashedLine(
    canvas,
    lineEnd.dx,
    lineStart.dx,
    lineStart.dy,
    lineColor,
    1,
    dashWidth: 2,
    dashSpace: 2,
  );
  return;
}

This matches the suggestion from Sourcery's review.


MEDIUM Priority: Hard-Coded Text Styles 🟡

Location: tick_marker_icon_painter.dart:323-346

Issue: The text styles for both plain and counter types are hard-coded directly in the painter:

  • Counter primary: 20px, FontWeight.w700
  • Counter secondary: 12px, FontWeight.w400
  • Plain: 12px, FontWeight.w700

Problems:

  1. Inconsistent with architecture: The codebase follows a clear pattern of externalizing styles to MarkerStyle (see activeMarkerText, markerLabelTextStyle)
  2. Not customizable: Users can't adjust these styles through theming
  3. Maintenance burden: Style changes require modifying painter code instead of theme definitions

Recommended Fix:
Add to MarkerStyle (marker_style.dart):

/// Text style for counter primary (current value) portion
final TextStyle markerCounterPrimaryTextStyle;

/// Text style for counter secondary (total value) portion  
final TextStyle markerCounterSecondaryTextStyle;

/// Text style for plain marker text
final TextStyle markerPlainTextStyle;

Then use these in the painter instead of inline TextStyle definitions.


MEDIUM Priority: Coordinate Ordering Assumption 🟡

Location: tick_marker_icon_painter.dart:307-386

Issue: The method assumes lineStart.dx < lineEnd.dx (contract marker is left of start time marker) but doesn't explicitly validate or handle the inverted case.

Potential Problem:

  • Check at line 366: if (lineStart.dx < lineEnd.dx) suggests awareness of possible inversion
  • However, calculations at lines 348-349 don't account for this:
    final double textRight = lineEnd.dx - _textPaddingFromStartLine;
    final double textLeft = textRight - textPainter.width;
    If lineStart.dx > lineEnd.dx, this positioning logic breaks.

Recommended Fix:
Add assertion or early guard:

void _paintDashedLineWithText(...) {
  assert(lineStart.dx < lineEnd.dx, 
    'Contract marker must be positioned left of start time marker');
  // ... rest of implementation
}

Or handle both cases if this inversion is valid.


Code Quality Issues

LOW Priority: Missing Documentation for Constants 🟢

Location: tick_marker_icon_painter.dart:317-318

The constants _textPaddingFromStartLine and _textGap lack documentation:

const double _textPaddingFromStartLine = 16;
const double _textGap = 4;

Recommendation:

/// Distance (in pixels) from the start time marker to the right edge of the text label.
const double _textPaddingFromStartLine = 16;

/// Gap (in pixels) between the text label and adjacent dashed line segments.
const double _textGap = 4;

LOW Priority: Enhanced Enum Documentation 🟢

Location: chart_marker.dart:152-162

The MarkerTextType.counter documentation is good but could be more explicit about error handling:

Current:

/// The text must contain a `/` separator.

Suggested:

/// The text must contain a `/` separator. If the delimiter is not found
/// or appears at index 0, rendering falls back to `plain` style.
/// Example: "2/10" renders as "**2**/10" (bold/large + regular/small).

This matches the actual fallback behavior in makeDelimitedTextPainter:83-101.


Test Coverage

MEDIUM Priority: No Tests for New Functionality 🟡

Finding: Grep search for makeDelimitedTextPainter, MarkerTextType, and _paintDashedLineWithText returns zero test files.

Missing Test Coverage:

  1. makeDelimitedTextPainter unit tests:

    • Valid delimiter in middle: "2/10" → two styled spans
    • Missing delimiter: "210" → fallback to plain
    • Delimiter at start: "/10" → fallback to plain
    • Empty string edge cases
  2. MarkerTextType integration tests:

    • Verify counter rendering produces correct TextPainter layout
    • Verify plain rendering matches existing behavior
    • Verify fallback behavior when delimiter missing
  3. Visual/Golden tests:

    • Snapshot test showing counter text "2/10" on connector line
    • Verify proper alignment and spacing
    • Verify theme color application

Recommendation: Add test file test/deriv_chart/chart/helpers/paint_functions/paint_text_test.dart covering the new makeDelimitedTextPainter function at minimum.


Positive Observations ✅

  1. Clean Architecture: The separation between model (MarkerTextType, ChartMarker) and rendering (TickMarkerIconPainter, makeDelimitedTextPainter) follows the codebase patterns well.

  2. Backward Compatibility: The default textType = MarkerTextType.plain ensures existing code continues to work without changes.

  3. Theme Integration: The addition of markerTextColor to both light and dark themes is implemented correctly and uses proper design tokens.

  4. Fallback Handling: makeDelimitedTextPainter gracefully falls back to plain style when delimiter is missing or invalid.

  5. Good Documentation: The MarkerType and MarkerTextType enums have excellent dartdoc comments explaining their purpose and usage.

  6. Consistent Styling: The implementation respects opacity throughout and integrates with the existing marker opacity system.


Summary

Priority Count Issues
🔴 High 1 Text overflow guard missing
🟡 Medium 3 Hard-coded styles, coordinate assumptions, no tests
🟢 Low 2 Documentation improvements

Overall Assessment: The implementation is functionally sound but has important edge case handling gaps that should be addressed before merging. The missing overflow guard is the most critical issue as it can cause visual artifacts in production. The hard-coded text styles violate the established theming architecture and should be refactored for consistency.

Recommendation: Request changes to address the HIGH priority overflow guard and consider addressing MEDIUM priority issues for better code quality and maintainability.


@behnam-deriv
Copy link
Copy Markdown
Collaborator Author

The overlaping of contractMarker with marker text is actually the expected behaviour , hence the high priority issue comment from claude is not a valid in this case.

@claude
Copy link
Copy Markdown

claude bot commented Apr 3, 2026

Claude finished @behnam-deriv's task —— View job


Todo

  • Analyze the user's clarification about expected behavior
  • Review and update previous assessment
  • Provide revised review summary

Updated Review Based on Clarification

Thank you for the clarification! I understand now that the text overlapping with the contract marker is intentional design behavior for this feature. I've updated my review accordingly.


Revised Priority Issues

HIGH Priority: Hard-Coded Text Styles Should Use Theme 🔴

Location: tick_marker_icon_painter.dart:326-338

Issue: The implementation references theme properties that don't exist yet:

  • theme.markerStyle.markerCounterPrimaryTextStyle (line 330)
  • theme.markerStyle.markerCounterSecondaryTextStyle (line 332)
  • theme.markerStyle.markerPlainTextStyle (line 337)

Looking at the actual code in lib/src/theme/painting_styles/marker_style.dart, these properties are not defined. The current MarkerStyle only has:

  • markerTextColor (added in this PR)
  • activeMarkerText (existing)
  • markerLabelTextStyle (existing)

Impact: This code will fail at runtime with "The getter 'markerCounterPrimaryTextStyle' isn't defined for the type 'MarkerStyle'".

Recommended Fix:
Add these three properties to MarkerStyle in lib/src/theme/painting_styles/marker_style.dart:

/// Text style for counter primary (current value) portion - e.g., "2" in "2/10"
final TextStyle markerCounterPrimaryTextStyle;

/// Text style for counter secondary (total value) portion - e.g., "/10" in "2/10"
final TextStyle markerCounterSecondaryTextStyle;

/// Text style for plain marker text
final TextStyle markerPlainTextStyle;

And initialize them in both ChartDefaultDarkTheme and ChartDefaultLightTheme:

// In MarkerStyle constructor in both theme files:
markerCounterPrimaryTextStyle: const TextStyle(
  fontSize: 20,
  fontWeight: FontWeight.w700,
  height: 1,
),
markerCounterSecondaryTextStyle: const TextStyle(
  fontSize: 12,
  fontWeight: FontWeight.w400,
  height: 1,
),
markerPlainTextStyle: const TextStyle(
  fontSize: 12,
  fontWeight: FontWeight.w700,
  height: 1,
),

MEDIUM Priority: Missing Test Coverage 🟡

Finding: No tests exist for the new functionality.

Missing Test Coverage:

  1. makeDelimitedTextPainter unit tests (paint_text.dart):

    • Valid delimiter in middle: "2/10" → two styled spans
    • Missing delimiter: "210" → fallback to plain
    • Delimiter at start: "/10" → fallback to plain
    • Empty string edge cases
  2. MarkerTextType integration tests:

    • Verify counter rendering produces correct TextPainter layout
    • Verify plain rendering matches existing behavior
    • Verify fallback behavior when delimiter missing
  3. Visual/Golden tests:

    • Snapshot test showing counter text "2/10" on connector line
    • Verify proper alignment and spacing (text intentionally near contract marker)
    • Verify theme color application

Recommendation: Add test file test/deriv_chart/chart/helpers/paint_functions/paint_text_test.dart covering the new makeDelimitedTextPainter function at minimum.


LOW Priority: Coordinate Ordering Assumption 🟢

Location: tick_marker_icon_painter.dart:343-358

Issue: The method assumes lineStart.dx < lineEnd.dx but doesn't explicitly validate this assumption at the method entry.

Current Logic:

  • Line 343: if (lineStart.dx < textLeft - _textGap) - draws left segment conditionally
  • Line 358: if (lineStart.dx < lineEnd.dx) - draws right segment conditionally

Recommendation: Add assertion for clarity:

void _paintDashedLineWithText(...) {
  assert(lineStart.dx < lineEnd.dx, 
    'Contract marker must be positioned left of start time marker');
  // ... rest of implementation
}

This makes the coordinate ordering assumption explicit and helps catch unexpected usage during development.


Code Quality Observations

Positive: Documentation Improvements

The constants now have excellent documentation (lines 317-321):

// Distance (in pixels) from the start time marker to the right edge of the text label.
const double _textPaddingFromStartLine = 16;

// Gap (in pixels) between the text label and adjacent dashed line segments.
const double _textGap = 4;

Positive: Clean Architecture

The separation between model (MarkerTextType, ChartMarker) and rendering (TickMarkerIconPainter, makeDelimitedTextPainter) follows the codebase patterns well.

Positive: Backward Compatibility

The default textType = MarkerTextType.plain ensures existing code continues to work without changes.

Positive: Theme Integration

The addition of markerTextColor to both light and dark themes is implemented correctly and uses proper design tokens.


Revised Summary

Priority Count Issues
🔴 High 1 Missing theme properties will cause runtime failure
🟡 Medium 1 No test coverage for new functionality
🟢 Low 1 Coordinate ordering assumption not explicit

Overall Assessment: The implementation has a critical issue - the code references theme properties that don't exist in MarkerStyle, which will cause runtime failures. Once the missing theme properties are added, the feature is well-designed and follows the established architecture patterns.

Recommendation:

  1. Must fix before merge: Add the three missing text style properties to MarkerStyle and initialize them in both theme classes
  2. Should fix: Add unit tests for makeDelimitedTextPainter to ensure delimiter handling works correctly
  3. Nice to have: Add assertion for coordinate ordering assumption

Note: I've removed the previous "overflow guard" issue from my review since you've confirmed that text overlapping the contract marker is the intended visual design. The implementation correctly positions the text near the contract marker as designed.


@behnam-deriv behnam-deriv merged commit 46ab366 into master Apr 3, 2026
6 checks passed
@behnam-deriv behnam-deriv deleted the add-marker-text-counter branch April 3, 2026 11: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.

1 participant