flutter_spaced_repetition 1.0.0 copy "flutter_spaced_repetition: ^1.0.0" to clipboard
flutter_spaced_repetition: ^1.0.0 copied to clipboard

A pure Dart implementation of the SM-2 spaced repetition algorithm for Flutter apps. Perfect for flashcard apps, language learning, and any spaced learning application.

example/flutter_spaced_repetition_example.dart

/// Example demonstrating the flutter_spaced_repetition package.
///
/// This example shows:
/// - Creating and reviewing flashcards
/// - Using different quality ratings
/// - Checking card statistics
/// - Configuring the algorithm
library;

import 'package:flutter_spaced_repetition/flutter_spaced_repetition.dart';

void main() {
  print('=== Flutter Spaced Repetition Example ===\n');

  // Basic Usage Example
  basicUsageExample();

  // Custom Settings Example
  customSettingsExample();

  // Statistics Example
  statisticsExample();

  // Batch Processing Example
  batchProcessingExample();

  // Scheduler Example
  schedulerExample();
}

/// Demonstrates basic usage of the spaced repetition engine.
void basicUsageExample() {
  print('--- Basic Usage ---');

  // Create engine with default Anki-like settings
  final engine = SpacedRepetitionEngine();

  // Create a new flashcard
  var card = engine.createCard(
    id: 'vocab_hello',
    metadata: {'front': 'Hello', 'back': 'Hola'},
  );

  print('Created new card: ${card.id}');
  print('Phase: ${card.phase.name}');
  print('Due: ${card.formattedDueTime}');

  // Preview intervals before reviewing
  final preview = engine.previewIntervals(card);
  print('\nInterval preview:');
  print('  Again: ${preview.formattedAgainInterval}');
  print('  Hard: ${preview.formattedHardInterval}');
  print('  Good: ${preview.formattedGoodInterval}');
  print('  Easy: ${preview.formattedEasyInterval}');

  // Process first review - user answered "Good"
  var result = engine.processReview(card, ReviewQuality.good);
  card = result.updatedCard;

  print('\nAfter first review (Good):');
  print('  Phase: ${card.phase.name}');
  print('  Interval: ${card.formattedInterval}');
  print('  Due: ${card.formattedDueTime}');

  // Simulate the card becoming due again
  card = card.copyWith(
    nextReviewTime: DateTime.now().subtract(const Duration(minutes: 1)),
  );

  // Process second review - graduated!
  result = engine.processReview(card, ReviewQuality.good);
  card = result.updatedCard;

  print('\nAfter second review (Good):');
  print('  Graduated: ${result.graduatedFromLearning}');
  print('  Phase: ${card.phase.name}');
  print('  Interval: ${card.formattedInterval}');
  print('  Ease: ${card.easeFactor.toStringAsFixed(2)}');

  print('\n');
}

/// Demonstrates using custom settings.
void customSettingsExample() {
  print('--- Custom Settings ---');

  // Use preset configurations
  print('Available presets:');
  print('  - SRSSettings.anki() - Standard Anki defaults');
  print('  - SRSSettings.supermemo() - Original SuperMemo');
  print('  - SRSSettings.aggressive() - More frequent reviews');
  print('  - SRSSettings.relaxed() - Fewer reviews');

  // Create engine with aggressive settings
  final aggressiveEngine = SpacedRepetitionEngine(
    settings: SRSSettings.aggressive(),
  );

  print('\nAggressive settings:');
  print('  Learning steps: ${aggressiveEngine.settings.learningSteps.length}');
  print(
    '  Graduating interval: ${aggressiveEngine.settings.graduatingInterval.inHours}h',
  );
  print('  Max interval: ${aggressiveEngine.settings.maximumInterval.inDays}d');

  // Or fully customize
  final customEngine = SpacedRepetitionEngine(
    settings: const SRSSettings(
      learningSteps: [
        Duration(minutes: 1),
        Duration(minutes: 5),
        Duration(minutes: 15),
      ],
      graduationsRequired: 3,
      graduatingInterval: Duration(hours: 12),
      easyInterval: Duration(days: 3),
      initialEaseFactor: 2.3,
      minimumEaseFactor: 1.5,
      algorithmType: SRSAlgorithmType.sm2Plus,
    ),
  );

  print('\nCustom settings:');
  print('  Algorithm: ${customEngine.settings.algorithmType.name}');
  print('  Learning steps: ${customEngine.settings.learningSteps.length}');
  print('  Initial ease: ${customEngine.settings.initialEaseFactor}');

  print('\n');
}

/// Demonstrates card and deck statistics.
void statisticsExample() {
  print('--- Statistics ---');

  final engine = SpacedRepetitionEngine();

  // Create and review some cards
  final cards = <ReviewCard>[];
  for (var i = 0; i < 5; i++) {
    var card = engine.createCard(id: 'card_$i');

    // Simulate some reviews
    for (var j = 0; j < 3 + i; j++) {
      final result = engine.processReview(card, ReviewQuality.good);
      card = result.updatedCard.copyWith(
        nextReviewTime: DateTime.now().subtract(const Duration(minutes: 1)),
      );
    }
    cards.add(card);
  }

  // Card-level statistics
  final cardStats = CardStatistics(cards[2]);
  print('Card statistics:');
  print('  Total reviews: ${cardStats.totalReviews}');
  print(
    '  Success rate: ${(cardStats.successRate * 100).toStringAsFixed(1)}%',
  );
  print('  Stability: ${(cardStats.stability * 100).toStringAsFixed(1)}%');
  print('  Difficulty: ${(cardStats.difficulty * 100).toStringAsFixed(1)}%');

  // Deck-level statistics
  final deckStats = DeckStatistics(cards);
  print('\nDeck statistics:');
  print('  Total cards: ${deckStats.totalCards}');
  print('  New cards: ${deckStats.newCards}');
  print('  Learning: ${deckStats.learningCards}');
  print('  Review: ${deckStats.reviewCards}');
  print('  Total reviews: ${deckStats.totalReviews}');
  print(
    '  Avg success: ${(deckStats.averageSuccessRate * 100).toStringAsFixed(1)}%',
  );

  // Mastery calculation
  const calculator = MasteryCalculator();
  final mastery = calculator.calculate(cards[4]);
  print('\nMastery for card_4:');
  print('  Level: ${mastery.level.label}');
  print('  Score: ${(mastery.score * 100).toStringAsFixed(1)}%');
  print('  Progress: ${(mastery.progress * 100).toStringAsFixed(1)}%');

  print('\n');
}

/// Demonstrates batch processing of reviews.
void batchProcessingExample() {
  print('--- Batch Processing ---');

  final engine = SpacedRepetitionEngine();

  // Create multiple cards
  final cards = List.generate(
    5,
    (i) => engine.createCard(id: 'batch_$i'),
  );

  // Process multiple reviews at once
  final reviews = [
    (cards[0], ReviewQuality.good),
    (cards[1], ReviewQuality.easy),
    (cards[2], ReviewQuality.hard),
    (cards[3], ReviewQuality.again),
    (cards[4], ReviewQuality.good),
  ];

  final results = engine.processBatch(reviews);

  print('Batch results:');
  for (var i = 0; i < results.length; i++) {
    final r = results[i];
    print(
      '  ${r.updatedCard.id}: ${r.quality.label} -> ${r.updatedCard.formattedInterval}',
    );
  }

  print('\n');
}

/// Demonstrates the review scheduler.
void schedulerExample() {
  print('--- Review Scheduler ---');

  final engine = SpacedRepetitionEngine();
  final scheduler = ReviewScheduler(
    config: SchedulerConfig.standard(),
  );

  // Create cards in various states
  final now = DateTime.now();
  final cards = [
    // Overdue cards
    engine.createCard(id: 'overdue_1').copyWith(
      phase: CardPhase.review,
      nextReviewTime: now.subtract(const Duration(days: 2)),
      intervalMinutes: 1440,
    ),
    engine.createCard(id: 'overdue_2').copyWith(
      phase: CardPhase.review,
      nextReviewTime: now.subtract(const Duration(hours: 12)),
      intervalMinutes: 1440,
    ),
    // New cards
    engine.createCard(id: 'new_1'),
    engine.createCard(id: 'new_2'),
    // Learning cards
    engine.createCard(id: 'learning_1').copyWith(
      phase: CardPhase.learning,
      nextReviewTime: now.subtract(const Duration(minutes: 5)),
    ),
    // Future due
    engine.createCard(id: 'future_1').copyWith(
      phase: CardPhase.review,
      nextReviewTime: now.add(const Duration(days: 1)),
    ),
  ];

  // Get scheduling summary
  final summary = scheduler.getSummary(cards);
  print('Scheduling summary:');
  print('  New available: ${summary.newCardsAvailable}');
  print('  Learning due: ${summary.learningCardsDue}');
  print('  Review due: ${summary.reviewCardsDue}');
  print('  Overdue: ${summary.overdueCards}');

  // Get next batch
  final batch = scheduler.getNextBatch(cards);
  print('\nNext batch to review:');
  for (final card in batch) {
    print('  ${card.id} (${card.phase.name})');
  }

  print('\n');
}
1
likes
160
points
112
downloads

Publisher

unverified uploader

Weekly Downloads

A pure Dart implementation of the SM-2 spaced repetition algorithm for Flutter apps. Perfect for flashcard apps, language learning, and any spaced learning application.

Repository (GitHub)
View/report issues

Topics

#spaced-repetition #flashcards #learning #education #algorithm

Documentation

API reference

License

MIT (license)

More

Packages that depend on flutter_spaced_repetition