Skip to content

Conversation

Yugesh-Kumar-S
Copy link
Contributor

@Yugesh-Kumar-S Yugesh-Kumar-S commented Aug 31, 2025

Fixes #2888

Changes

  • Added csv playback functionality for the luxmeter instrument.

Screenshots / Recordings

screen-20250831-174654.mp4

Checklist:

  • No hard coding: I have used resources from strings.xml, dimens.xml and colors.xml without hard coding any value.
  • No end of file edits: No modifications done at end of resource files strings.xml, dimens.xml or colors.xml.
  • Code reformatting: I have reformatted code and fixed indentation in every file included in this pull request.
  • No extra space: My code does not contain any extra lines or extra spaces than the ones that are necessary.

Summary by Sourcery

Implement CSV playback for the luxmeter instrument by adding playback state and control methods in the provider, updating the LuxMeterScreen UI to support playback mode, and enabling navigation from the logged data screen to replay CSV recordings.

New Features:

  • Add CSV playback state and control methods (start, pause, resume, stop) in LuxMeterStateProvider for timed row processing.
  • Update LuxMeterScreen to accept playbackData and present playback-specific UI (title, disabled options/recording, pause/resume/stop buttons).
  • Enable navigation from LoggedDataScreen to LuxMeterScreen with CSV data to replay logged luxmeter sessions.

Enhancements:

  • Extend the data update logic to include playback mode alongside live sensor readings.

Copy link
Contributor

sourcery-ai bot commented Aug 31, 2025

Reviewer's Guide

Implements CSV playback for the luxmeter instrument by extending the state provider with playback controls and timers, updating the LuxMeterScreen UI to handle playback modes and controls, and integrating navigation for playback in the logged data screen.

Sequence diagram for CSV playback initiation from logged data screen

sequenceDiagram
  actor User
  participant LoggedDataScreen
  participant LuxMeterScreen
  participant LuxMeterStateProvider
  User->>LoggedDataScreen: Selects luxmeter CSV log and presses play
  LoggedDataScreen->>LuxMeterScreen: Navigates with playbackData
  LuxMeterScreen->>LuxMeterStateProvider: startPlayback(playbackData)
  LuxMeterStateProvider->>LuxMeterStateProvider: Initializes playback state and starts timer
  LuxMeterStateProvider-->>LuxMeterScreen: Updates UI with playback state
Loading

Updated class diagram for LuxMeterStateProvider with playback functionality

classDiagram
  class LuxMeterStateProvider {
    - bool _isPlayingBack
    - List<List<dynamic>>? _playbackData
    - int _playbackIndex
    - Timer? _playbackTimer
    - bool _isPlaybackPaused
    + bool get isPlayingBack
    + bool get isPlaybackPaused
    + void startPlayback(List<List<dynamic>> data)
    + void stopPlayback()
    + void pausePlayback()
    + void resumePlayback()
    + Function? onPlaybackEnd
  }

  class LuxMeterScreen {
    + List<List<dynamic>>? playbackData
  }

  LuxMeterScreen --> LuxMeterStateProvider: uses
Loading

Updated class diagram for LuxMeterScreen with playback integration

classDiagram
  class LuxMeterScreen {
    + bool isExperiment
    + List<List<dynamic>>? playbackData
    + onPlaybackEnd callback
  }

  LuxMeterScreen --> LuxMeterStateProvider: interacts with
  LuxMeterScreen --> CommonScaffold: passes playback controls
Loading

Updated class diagram for LoggedDataScreen with playback navigation

classDiagram
  class LoggedDataScreen {
    + void _onPlayPressed()
  }

  LoggedDataScreen --> LuxMeterScreen: navigates to with playbackData
Loading

File-Level Changes

Change Details Files
Add playback logic and controls to the LuxMeterStateProvider
  • Introduce playback state variables and getters
  • Implement startPlayback, _startPlaybackTimer, stopPlayback, pausePlayback, and resumePlayback methods
  • Enhance _updateData to process playback values
  • Cancel playback timer in dispose
lib/providers/luxmeter_state_provider.dart
Extend LuxMeterScreen to initialize and control playback
  • Add playbackData constructor parameter and onPlaybackEnd callback
  • Branch initialization to start playback or sensors based on playbackData
  • Update scaffold title and disable record/options during playback
  • Add playback pause/resume and stop callbacks and flags
lib/view/luxmeter_screen.dart
Integrate luxmeter playback navigation in logged data list
  • Import LuxMeterScreen and pass CSV data on navigation
  • Handle 'luxmeter' case in instrument selection to push playback screen
  • Enable play icon for luxmeter entries
lib/view/logged_data_screen.dart

Assessment against linked issues

Issue Objective Addressed Explanation
#2888 Implement CSV playback functionality in the luxmeter instrument.

Possibly linked issues


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

Copy link
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 there - I've reviewed your changes - here's some feedback:

  • There’s a lot of duplicated state-reset logic in startPlayback, stopPlayback, and stopRecording—consider extracting the data-clearing steps into a private helper to make it DRY and easier to maintain.
  • Rather than setting _currentTime to (index – 1), it may be more accurate to compute and use the actual timestamp differences from your CSV rows so the playback timeline reflects the original recording intervals.
  • Automatically popping the navigation stack in onPlaybackEnd can be surprising; you might want to decouple the playback-end callback from direct navigation and let the screen decide how to handle closing or presenting a summary.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- There’s a lot of duplicated state-reset logic in startPlayback, stopPlayback, and stopRecording—consider extracting the data-clearing steps into a private helper to make it DRY and easier to maintain.
- Rather than setting _currentTime to (index – 1), it may be more accurate to compute and use the actual timestamp differences from your CSV rows so the playback timeline reflects the original recording intervals.
- Automatically popping the navigation stack in onPlaybackEnd can be surprising; you might want to decouple the playback-end callback from direct navigation and let the screen decide how to handle closing or presenting a summary.

## Individual Comments

### Comment 1
<location> `lib/providers/luxmeter_state_provider.dart:165` </location>
<code_context>
+        if (currentTimestamp != null && nextTimestamp != null) {
+          final timeDiff = nextTimestamp - currentTimestamp;
+          interval = Duration(milliseconds: timeDiff);
+          if (interval.inMilliseconds < 100) {
+            interval = const Duration(milliseconds: 100);
+          } else if (interval.inMilliseconds > 10000) {
+            interval = const Duration(seconds: 10);
+          }
+        }
+      } catch (e) {
</code_context>

<issue_to_address>
Playback interval clamping may affect playback fidelity.

These hardcoded limits may not suit all datasets. Allowing configuration or clarifying the reasoning would improve flexibility and transparency.

Suggested implementation:

```
    if (_playbackIndex < _playbackData!.length && _playbackIndex > 1) {
      try {
        final currentTimestamp =
            int.tryParse(_playbackData![_playbackIndex - 1][0].toString());
        final nextTimestamp =
            int.tryParse(_playbackData![_playbackIndex][0].toString());

        // Use configurable min/max interval values for playback fidelity
        if (currentTimestamp != null && nextTimestamp != null) {
          final timeDiff = nextTimestamp - currentTimestamp;
          interval = Duration(milliseconds: timeDiff);
          if (interval.inMilliseconds < minPlaybackIntervalMs) {
            interval = Duration(milliseconds: minPlaybackIntervalMs);
          } else if (interval.inMilliseconds > maxPlaybackIntervalMs) {
            interval = Duration(milliseconds: maxPlaybackIntervalMs);
          }
        }
      } catch (e) {
        interval = const Duration(seconds: 1);
      }
    }

```

1. Add two fields to your provider class:
   ```dart
   final int minPlaybackIntervalMs;
   final int maxPlaybackIntervalMs;
   ```
   and initialize them in the constructor, e.g.:
   ```dart
   LuxmeterStateProvider({
     this.minPlaybackIntervalMs = 100,
     this.maxPlaybackIntervalMs = 10000,
     // ... other params
   });
   ```
2. Optionally, document these fields to clarify their purpose:
   ```dart
   /// Minimum playback interval in milliseconds (prevents too-fast playback)
   /// Maximum playback interval in milliseconds (prevents too-slow playback)
   ```
3. Update any code that instantiates this provider to pass custom values if needed.
</issue_to_address>

### Comment 2
<location> `lib/view/luxmeter_screen.dart:227` </location>
<code_context>
         _provider.setConfigProvider(_configProvider);
-        _provider.initializeSensors(onError: _showSensorErrorSnackbar);
+
+        if (widget.playbackData != null) {
+          _provider.startPlayback(widget.playbackData!);
+        } else {
+          _provider.initializeSensors(onError: _showSensorErrorSnackbar);
+        }
       }
     });
</code_context>

<issue_to_address>
Initialization logic branches based on playbackData presence.

If playbackData is empty or invalid, sensor initialization is skipped, which may cause the screen to malfunction. Please add explicit handling for invalid playbackData cases.

Suggested implementation:

```
        if (widget.playbackData != null && widget.playbackData!.isNotEmpty) {
          // Optionally, add more validity checks for playbackData here
          _provider.startPlayback(widget.playbackData!);
        } else if (widget.playbackData != null && widget.playbackData!.isEmpty) {
          // playbackData is present but empty/invalid
          // Show a warning and initialize sensors instead
          ScaffoldMessenger.of(context).showSnackBar(
            SnackBar(content: Text(appLocalizations.invalidPlaybackData)),
          );
          _provider.initializeSensors(onError: _showSensorErrorSnackbar);
        } else {
          _provider.initializeSensors(onError: _showSensorErrorSnackbar);
        }

```

1. You may need to define a localized string for `invalidPlaybackData` in your `AppLocalizations` class.
2. If there are more specific validity checks for `playbackData` (e.g., structure, required fields), add them to the conditional.
3. If you want to handle other types of invalid data (not just empty), expand the conditional accordingly.
</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.

Copy link

Build Status

Build successful. APKs to test: https://github.com/fossasia/pslab-app/actions/runs/17357092703/artifacts/3892475078.

Screenshots

Android Screenshots
iPhone Screenshots
iPad Screenshots

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add CSV playback for luxmeter
1 participant