Skip to content

chore: keep marker label visible till startTimeCollapsed marker exists - #494

Merged
behnam-deriv merged 1 commit into
masterfrom
keep-marker-label-visible
Aug 17, 2026
Merged

chore: keep marker label visible till startTimeCollapsed marker exists#494
behnam-deriv merged 1 commit into
masterfrom
keep-marker-label-visible

Conversation

@behnam-deriv

@behnam-deriv behnam-deriv commented Aug 17, 2026

Copy link
Copy Markdown
Collaborator

This PR contains the following changes:

The marker label before a contract's start time (e.g. the 2/10 tick counter) is now read from startTimeCollapsed instead of contractMarker.

Consumers drop the contractMarker when a contract finishes, so the label — read off that marker and painted as part of its dashed connector line — vanished on settlement. It now stays as long as the finished contract's other markers do, while the connector line still goes with the contractMarker it belongs to.

contractMarker startTimeCollapsed.text Result
present set line + label (unchanged)
present empty line only (unchanged)
absent set label only — new
absent empty nothing (unchanged)

Without the contractMarker, the label anchors to the same fixed left-edge offset that marker would have occupied, so it doesn't shift on settlement.

  • ✨ New feature (non-breaking change which adds functionality)
  • ❌ Breaking change (fix or feature that would cause existing functionality to change)

⚠️ Consumer action required

text / textType on the contractMarker are no longer rendered, with no fallback and no warning. Send them on startTimeCollapsed instead, in both the running and finished payloads. That marker must also be present, since the label is positioned relative to it.

@sourcery-ai

sourcery-ai Bot commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

Reviewer's Guide

Refactors tick marker radius calculation and changes how the dashed connector line and label are drawn so that the label tied to the startTimeCollapsed marker remains visible even after the contractMarker disappears, optionally without the connector line.

File-Level Changes

Change Details Files
Refactor contract marker outer radius handling and adjust marker positions to use a shared helper.
  • Replace inline contract outer radius computation with a dedicated _contractOuterRadius helper using zoom-based radius and stroke.
  • Use the shared contractOuterRadius value when positioning contractMarker-related offsets instead of duplicating the calculation.
lib/src/deriv_chart/chart/data_visualization/markers/marker_icon_painters/tick_marker_icon_painter.dart
Rework dashed connector line and label drawing logic so the label is anchored to startTimeCollapsed and can persist without the contractMarker or connector line.
  • Change dashed line drawing condition to be driven by the presence of startTimeCollapsed, and derive the label from the startTimeCollapsed marker text.
  • Introduce logic to compute a synthetic lineStart offset at the fixed contractMarker left padding when the contractMarker no longer exists so the label stays aligned.
  • Extend _paintDashedLineWithText with a paintConnectorLine flag that allows drawing just the label (no line) while still using lineStart for vertical positioning.
  • Guard the left and right portions of the dashed line inside paintConnectorLine checks so no connector line is drawn when the contract marker is gone.
lib/src/deriv_chart/chart/data_visualization/markers/marker_icon_painters/tick_marker_icon_painter.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

Dependency Review

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

OpenSSF Scorecard

PackageVersionScoreDetails

Scanned Manifest Files

@github-actions

github-actions Bot commented Aug 17, 2026

Copy link
Copy Markdown

Claude finished @behnam-deriv's task in 3m 42s —— View job


I'll analyze this and get back to you.

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Hey - I've left some high level feedback:

  • In the block that draws the horizontal dashed line/label, when _startCollapsedOffset is non-null but both _contractMarkerOffset and labelMarker are null, nothing is rendered; consider explicitly handling this case (or documenting why it's intentionally a no-op) to make the behaviour clearer.
  • Within paint you repeatedly call _contractOuterRadius(painterProps) for the same painterProps; consider computing this once per invocation and reusing the value to avoid unnecessary recalculation and make the code slightly clearer.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In the block that draws the horizontal dashed line/label, when `_startCollapsedOffset` is non-null but both `_contractMarkerOffset` and `labelMarker` are null, nothing is rendered; consider explicitly handling this case (or documenting why it's intentionally a no-op) to make the behaviour clearer.
- Within `paint` you repeatedly call `_contractOuterRadius(painterProps)` for the same `painterProps`; consider computing this once per invocation and reusing the value to avoid unnecessary recalculation and make the code slightly clearer.

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.

@github-actions

Copy link
Copy Markdown

🤖 Claude PR Review Complete

Model: claude-sonnet-5 | Review Type: 📋 Initial Review

Summary

This PR refactors TickMarkerIconPainter so the tick-counter label next to the contract line is sourced from the startTimeCollapsed marker instead of the contractMarker, so the label keeps rendering after contractMarker is removed (e.g. once a contract finishes). It also extracts the duplicated contract-outer-radius calculation into a _contractOuterRadius helper, which is a nice DRY cleanup. The core logic is sound and well-commented, but the change silently alters where the label's text/textType must come from, which is a real regression risk if the consuming app (outside this repo) still only sets text on the contractMarker. There is also no test coverage added for the new branching logic.

Recommendation: REQUEST CHANGES


🟠 High Priority Issues

🟠 1. Label text source moved from contractMarker to startTimeCollapsed with no fallbacklib/src/deriv_chart/chart/data_visualization/markers/marker_icon_painters/tick_marker_icon_painter.dart:204-229

Details

Severity File Lines
HIGH lib/src/.../tick_marker_icon_painter.dart 204-229

❌ Problematic Code:

final ChartMarker? labelMarker = markerGroup.markers.firstWhereOrNull(
  (ChartMarker marker) =>
      marker.markerType == MarkerType.startTimeCollapsed &&
      (marker.text?.isNotEmpty ?? false),
);

if (_contractMarkerOffset != null || labelMarker != null) {
  ...
  if (labelMarker != null) {
    _paintDashedLineWithText(
      canvas,
      lineStart,
      _startCollapsedOffset,
      finalLineColor,
      labelMarker.text!,
      labelMarker.textType,
      theme,
      opacity,
      paintConnectorLine: _contractMarkerOffset != null,
    );
  }
  ...
}

📋 Issue: Before this PR, the label text/type came exclusively from the contractMarker (contractMarker?.text). After this PR, it is read exclusively from a marker with markerType == MarkerType.startTimeCollapsed. This package itself never constructs ChartMarker instances — they are built by the consuming application (e.g. deriv-app) and passed in via MarkerGroup. If the producer of these markers is not updated in lock-step to also (or instead) populate text/textType on the startTimeCollapsed marker, the label will simply stop rendering for every contract once contractMarker disappears — and, depending on producer timing, potentially even while contractMarker is still present, since the new code path only reads startTimeCollapsed.text and no longer falls back to contractMarker.text at all.

⚠️ Impact: Silent, hard-to-detect regression: no exception is thrown, the tick counter/label simply disappears in production for any caller that hasn't been updated to set text on the startTimeCollapsed marker. Since this is a UI library consumed by another repo, there's nothing in this diff (or in CI here) that would catch the mismatch.

✅ Fix:

final ChartMarker? contractMarker = markerGroup.markers.firstWhereOrNull(
  (ChartMarker marker) => marker.markerType == MarkerType.contractMarker,
);

final ChartMarker? labelMarker = markerGroup.markers.firstWhereOrNull(
      (ChartMarker marker) =>
          marker.markerType == MarkerType.startTimeCollapsed &&
          (marker.text?.isNotEmpty ?? false),
    ) ??
    (contractMarker?.text?.isNotEmpty ?? false ? contractMarker : null);

💡 Explanation: Falling back to contractMarker.text when startTimeCollapsed.text isn't populated preserves backward compatibility with existing callers during the transition, while still allowing the new source to take priority once callers are updated. At minimum, please confirm with the author/reviewers that the corresponding change to populate text on startTimeCollapsed markers has already landed (or is landing together) in the consuming application(s), since this repo has no way to verify that from the diff alone.


🟡 Medium Priority Issues

🟡 2. New branching logic has no test coveragelib/src/deriv_chart/chart/data_visualization/markers/marker_icon_painters/tick_marker_icon_painter.dart:203-243,331-405

Details

Severity File Lines
MEDIUM lib/src/.../tick_marker_icon_painter.dart 203-243, 331-405

❌ Problematic Code:

if (_startCollapsedOffset != null) {
  final ChartMarker? labelMarker = markerGroup.markers.firstWhereOrNull(...);
  if (_contractMarkerOffset != null || labelMarker != null) {
    final Offset lineStart = _contractMarkerOffset ?? Offset(...);
    if (labelMarker != null) {
      _paintDashedLineWithText(..., paintConnectorLine: _contractMarkerOffset != null);
    } else {
      paintHorizontalDashedLine(...);
    }
  }
}

📋 Issue: There is no test file for tick_marker_icon_painter.dart in the repo (pre-existing gap), so this PR adds several new conditional paths — (a) contract marker present + label present, (b) contract marker absent + label present (the new "label outlives contractMarker" case this PR is meant to fix), (c) contract marker present + label absent, (d) both absent — without any automated regression test to lock in the intended behavior (e.g. verifying paintConnectorLine is false and the fallback anchor position is used when _contractMarkerOffset is null).

⚠️ Impact: Future refactors could silently break the "label survives contractMarker removal" behavior this PR specifically sets out to fix, with no test to catch it.

✅ Fix:

testWidgets('renders label anchored at fixed offset when contractMarker is absent but startTimeCollapsed has text', (tester) async {
  // Build a MarkerGroup with only a startTimeCollapsed marker (text: '3/10')
  // and no contractMarker; verify paintHorizontalDashedLine/text painter
  // is invoked with paintConnectorLine == false and the expected anchor.
});

💡 Explanation: A focused unit/widget test (using a TestCanvas/RecordingCanvas or golden test, consistent with other painter tests in this repo if any exist for sibling painters) would pin down this new behavior and prevent regressions.


Summary Table

Priority Count Categories
🔴 Critical 0
🟠 High 1 Regression risk / data contract change
🟡 Medium 1 Missing test coverage
🟢 Low 0

Recommendations

  1. Confirm (in the PR description or with the consuming app's maintainers) that text/textType will be populated on startTimeCollapsed markers going forward, or add a fallback to contractMarker.text to avoid a silent feature regression for existing callers.
  2. Add at least one test exercising the new "contractMarker absent, label present" branch to lock in the intended fix and guard against future regressions.
  3. The _contractOuterRadius extraction (tick_marker_icon_painter.dart:322-323) is a good deduplication and does not need changes.

Auto Fix Claude Reviews

Action Open Dashboard

@behnam-deriv
behnam-deriv merged commit 39fc96c into master Aug 17, 2026
9 checks passed
@behnam-deriv
behnam-deriv deleted the keep-marker-label-visible branch August 17, 2026 09:07
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