Skip to content

feat(recorder): add sequential playback with progress tracking#13

Open
brotoo25 wants to merge 2 commits into
mainfrom
feat/sequence-recorder
Open

feat(recorder): add sequential playback with progress tracking#13
brotoo25 wants to merge 2 commits into
mainfrom
feat/sequence-recorder

Conversation

@brotoo25

Copy link
Copy Markdown
Owner

Summary

Implements a new flutter_fixtures_recorder package that enables recording and sequential playback of fixture selections with visual progress tracking.

This addresses the original requirement for a recorder that:

  • Records user fixture selections in order
  • Plays them back sequentially (not via map lookup)
  • Shows progress during playback
  • Automatically stops when all events are exhausted
  • Filters out defaults and consecutive repeats

New Package: flutter_fixtures_recorder

Key Features

Sequential Playback: Index-based playback ensures events play in recorded order
Progress Tracking: Live UI showing "Progress: 2/5" with LinearProgressIndicator
Auto-Stop: Automatically returns to idle when all events consumed
Recording Buffer Visibility: Real-time counter: "Recorded: 3 events"
Smart Filtering: Skips default selections and consecutive repeats
Extensible: Works with any DataQuery implementation

Components

Core Models:

  • RecordingEvent - Individual selection event with timestamp and source
  • RecordingSession - Session container with metadata (createdAt, lastUsedAt)
  • RecorderMode - Enum: idle/recording/playback
  • SelectionEventNotifier - Interface for extensibility

Recorder Service:

  • FixtureRecorder - Main service extending ChangeNotifier
  • Sequential playback using _playbackIndex (0, 1, 2...)
  • Getters: playbackIndex, totalEvents, recordingBufferSize, hasRemainingEvents

Storage:

  • SessionStorage - Abstract interface
  • JsonFileSessionStorage - JSON file implementation using path_provider
  • Location: <app_documents>/flutter_fixtures_sessions/session_<name>.json

Integration:

  • RecordableDataQuery - Decorator for any DataQuery
  • PlaybackDataSelector - Marker for playback mode
  • RecorderIntegrationMixin - Convenience mixin

UI Components:

  • RecorderOverlayWidget - FAB with mode-dependent colors/icons
  • SessionListWidget - Session selection dialog with play/delete actions
  • RecordingStatusIndicator - Pulsing status badge

Testing

35 comprehensive unit tests covering:

  • Recording workflow with filtering
  • Sequential playback with index advancement
  • Auto-stop behavior when events exhausted
  • Session management (save/load/delete/list)
  • JSON serialization/deserialization
  • ChangeNotifier integration

Example App

New RecorderExamplePage with:

  • Simplified instructions (2 lines vs 10 lines)
  • Single "Make Request" button for clear demo
  • Live recording buffer: "Recorded: X events"
  • Playback progress: "Progress: 2/5" + progress bar
  • Fixture identifier display for debugging

Documentation

  • ✅ Complete package README with usage examples
  • ✅ Updated main README with recorder section
  • ✅ Dio and SQLite integration examples
  • ✅ RecorderIntegrationMixin guide
  • ✅ Session storage format documentation

Technical Implementation

Sequential Playback Logic

@override
FixtureDocument? getRecordedSelection(FixtureCollection fixture) {
  if (_mode != RecorderMode.playback) return null;
  if (_currentSession == null) return null;

  // Check if exhausted
  if (_playbackIndex >= _currentSession!.events.length) {
    stopPlayback(); // Auto-stop
    return null;
  }

  // Get next event in sequence
  final event = _currentSession!.events[_playbackIndex];
  
  // Verify fixture matches
  if (event.fixtureKey != fixture.description) return null;

  // Advance index
  _playbackIndex++;
  notifyListeners(); // Update UI

  // Strict matching with fallback
  return fixture.items.firstWhere(
    (doc) => doc.identifier == event.selectedIdentifier,
    orElse: () => null,
  );
}

Recording Filter Logic

void notifySelection(FixtureCollection fixture, FixtureDocument selected, String? source) {
  if (_mode != RecorderMode.recording) return;

  // Skip defaults
  if (selected.defaultOption == true) return;

  // Skip consecutive repeats
  if (_lastRecordedKey == fixture.description &&
      _lastRecordedIdentifier == selected.identifier) {
    return;
  }

  _recordingBuffer.add(RecordingEvent(...));
  _lastRecordedKey = fixture.description;
  _lastRecordedIdentifier = selected.identifier;
  notifyListeners();
}

Breaking Changes

None - this is a new additive package.

Migration Guide

Not applicable - new package. To use:

dependencies:
  flutter_fixtures_recorder: ^0.1.0

Or use the meta-package:

dependencies:
  flutter_fixtures: ^0.1.0  # Includes recorder

Test Results

✅ All 35 tests passing
✅ Code analysis: 0 issues
✅ Code formatting: compliant
✅ Melos workspace check: passing

Checklist

  • Added new package with complete implementation
  • 35 unit tests with 100% core logic coverage
  • Updated example app with RecorderExamplePage
  • Updated main README with recorder documentation
  • Package README with usage examples
  • All quality checks passing (format, analyze, test)
  • Integrated with workspace and meta-package
  • Sequential playback with progress tracking
  • Auto-stop when events exhausted
  • Real-time recording buffer counter

Screenshots

(Would be added if running in actual app environment)

Recording Mode: Shows "Recorded: 3 events" counter
Playback Mode: Shows "Progress: 2/5" with progress bar
Response Display: Shows "Fixture: success" identifier

🤖 Generated with Claude Code

Implements a new flutter_fixtures_recorder package that enables recording
and sequential playback of fixture selections with visual progress tracking.

## New Package: flutter_fixtures_recorder

### Core Features
- **Sequential Playback**: Events play back in recorded order, one per request
- **Progress Tracking**: Live display of playback position (e.g., "Progress: 2/5")
- **Auto-Stop**: Playback automatically stops when all events are exhausted
- **Recording Buffer Visibility**: Real-time counter showing recorded events
- **Filtering**: Automatically skips default selections and consecutive repeats

### Components Added

**Core Models**:
- RecordingEvent: Individual fixture selection event
- RecordingSession: Container for recorded events with metadata
- RecorderMode: Enum for idle/recording/playback states
- SelectionEventNotifier: Interface for extensibility

**Recorder Service**:
- FixtureRecorder: Main service with ChangeNotifier for reactive UI
- Index-based sequential playback (replaces map-based approach)
- Exposes playbackIndex, totalEvents, recordingBufferSize getters

**Storage**:
- SessionStorage: Abstract interface
- JsonFileSessionStorage: JSON file implementation with path_provider
- Sessions stored in: <app_documents>/flutter_fixtures_sessions/

**Integration**:
- RecordableDataQuery: Decorator wrapping any DataQuery
- PlaybackDataSelector: Marker class for playback mode
- RecorderIntegrationMixin: Convenience mixin for setup

**UI Components**:
- RecorderOverlayWidget: FAB with mode-dependent behavior
- SessionListWidget: Session selection and management dialog
- RecordingStatusIndicator: Pulsing status badge

### Testing
- 35 comprehensive unit tests covering:
  - Recording workflow and filtering logic
  - Sequential playback with auto-stop
  - Session management (save/load/delete)
  - JSON serialization
  - ChangeNotifier integration

### Example App Updates
- New RecorderExamplePage with simplified instructions
- Single "Make Request" button for clear sequential demo
- Live recording buffer counter
- Playback progress indicator with LinearProgressIndicator
- Fixture identifier display for debugging

### Documentation
- Complete package README with usage examples
- Updated main README with recorder section
- Integration examples for Dio and SQLite
- RecorderIntegrationMixin usage guide

## Breaking Changes
None - this is a new additive package

## Migration Guide
Not applicable - new package

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
@greptile-apps

greptile-apps Bot commented Jan 14, 2026

Copy link
Copy Markdown

Greptile Summary

Adds a new flutter_fixtures_recorder package implementing sequential playback of recorded fixture selections with progress tracking. The implementation follows clean architecture with proper separation of concerns: core models (RecordingEvent, RecordingSession), a service layer (FixtureRecorder), storage abstraction (SessionStorage with JSON file implementation), integration decorators (RecordableDataQuery), and UI components (RecorderOverlayWidget, SessionListWidget). Key features include:

  • Sequential playback using index-based iteration (not map lookup)
  • Auto-stop behavior when events are exhausted
  • Smart filtering that skips default selections and consecutive duplicates
  • Progress tracking with live UI updates showing current position
  • 35 comprehensive tests covering all core functionality

The code quality is high with proper error handling, clear documentation, and consistent patterns throughout. The decorator pattern for RecordableDataQuery provides transparent integration without modifying existing code. The example app demonstrates all features effectively.

Confidence Score: 5/5

  • This PR is safe to merge with no significant issues found
  • The implementation is well-architected with clean separation of concerns, comprehensive test coverage (35 tests), proper error handling throughout, and follows Flutter/Dart best practices. The sequential playback logic is correctly implemented with index tracking and auto-stop. All core functionality is tested including edge cases like missing identifiers and exhausted events. No security concerns, breaking changes, or logical errors detected.
  • No files require special attention

Important Files Changed

Filename Overview
packages/flutter_fixtures_recorder/lib/src/recorder/fixture_recorder.dart Core recorder service with sequential playback, auto-stop, and proper filtering. Clean implementation.
packages/flutter_fixtures_recorder/lib/src/integration/recordable_data_query.dart Decorator pattern implementation wrapping DataQuery with recording/playback. Transparent integration.
packages/flutter_fixtures_recorder/lib/src/storage/json_file_session_storage.dart File-based storage with proper error handling, filename sanitization, and sorted session listing.
packages/flutter_fixtures_recorder/test/fixture_recorder_test.dart Comprehensive test suite covering recording, playback, filtering, and auto-stop behavior. Well organized.
example/lib/recorder_example.dart Example app with live progress tracking, recording buffer display, and clear UI. Good demonstration.

Sequence Diagram

sequenceDiagram
    participant User
    participant RecorderOverlay
    participant FixtureRecorder
    participant SessionStorage
    participant RecordableDataQuery
    participant DioDataQuery
    
    Note over User,DioDataQuery: Recording Flow
    User->>RecorderOverlay: Tap blue FAB
    RecorderOverlay->>RecorderOverlay: Show session dialog
    User->>RecorderOverlay: Select "Start Recording"
    RecorderOverlay->>FixtureRecorder: startRecording()
    FixtureRecorder->>FixtureRecorder: Set mode = recording
    User->>DioDataQuery: Make API request
    DioDataQuery->>RecordableDataQuery: select()
    RecordableDataQuery->>DioDataQuery: delegate.select()
    DioDataQuery-->>RecordableDataQuery: selected fixture
    RecordableDataQuery->>FixtureRecorder: notifySelection(fixture, selected)
    FixtureRecorder->>FixtureRecorder: Filter (skip defaults, duplicates)
    FixtureRecorder->>FixtureRecorder: Add to recording buffer
    User->>RecorderOverlay: Tap red FAB
    RecorderOverlay->>RecorderOverlay: Show save dialog
    User->>RecorderOverlay: Enter session name
    RecorderOverlay->>FixtureRecorder: stopRecording(name)
    FixtureRecorder->>SessionStorage: saveSession(session)
    SessionStorage-->>FixtureRecorder: saved
    FixtureRecorder->>FixtureRecorder: Set mode = idle
    
    Note over User,DioDataQuery: Playback Flow
    User->>RecorderOverlay: Tap blue FAB
    RecorderOverlay->>FixtureRecorder: listSessions()
    FixtureRecorder->>SessionStorage: listSessions()
    SessionStorage-->>FixtureRecorder: session list
    RecorderOverlay->>RecorderOverlay: Show session list
    User->>RecorderOverlay: Select session
    RecorderOverlay->>FixtureRecorder: startPlayback(name)
    FixtureRecorder->>SessionStorage: loadSession(name)
    SessionStorage-->>FixtureRecorder: session
    FixtureRecorder->>FixtureRecorder: Set mode = playback, index = 0
    User->>DioDataQuery: Make API request
    DioDataQuery->>RecordableDataQuery: select()
    RecordableDataQuery->>FixtureRecorder: getRecordedSelection(fixture)
    FixtureRecorder->>FixtureRecorder: Get event at playbackIndex
    FixtureRecorder->>FixtureRecorder: Increment playbackIndex
    FixtureRecorder-->>RecordableDataQuery: recorded fixture
    RecordableDataQuery-->>DioDataQuery: recorded fixture
    Note over FixtureRecorder: When index >= events.length
    FixtureRecorder->>FixtureRecorder: stopPlayback() (auto-stop)
    FixtureRecorder->>FixtureRecorder: Set mode = idle
Loading

@greptile-apps

greptile-apps Bot commented Jan 14, 2026

Copy link
Copy Markdown

Greptile's behavior is changing!

From now on, if a review finishes with no comments, we will not post an additional "statistics" comment to confirm that our review found nothing to comment on. However, you can confirm that we reviewed your changes in the status check section.

This feature can be toggled off in your Code Review Settings by deselecting "Create a status check for each PR".

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