From 5f8c659928499d471bc75f5d0355b5d620d2db85 Mon Sep 17 00:00:00 2001 From: Son Bui Date: Wed, 1 May 2024 13:33:28 +0700 Subject: [PATCH 1/2] Feat: add support json for card class #5 Signed-off-by: Son Bui --- lib/src/fsrs_base.dart | 2 +- lib/src/models.dart | 77 +++--- lib/src/models.freezed.dart | 463 ++++++++++++++++++++++++++++++++++++ lib/src/models.g.dart | 39 +++ pubspec.yaml | 5 + 5 files changed, 535 insertions(+), 51 deletions(-) create mode 100644 lib/src/models.freezed.dart create mode 100644 lib/src/models.g.dart diff --git a/lib/src/fsrs_base.dart b/lib/src/fsrs_base.dart index 470c081..8690571 100644 --- a/lib/src/fsrs_base.dart +++ b/lib/src/fsrs_base.dart @@ -14,7 +14,7 @@ class FSRS { } Map repeat(Card card, DateTime now) { - card = Card.copyFrom(card); + card = card.copyWith(); if (card.state == State.newState) { card.elapsedDays = 0; } else { diff --git a/lib/src/models.dart b/lib/src/models.dart index 929e7a8..d803def 100644 --- a/lib/src/models.dart +++ b/lib/src/models.dart @@ -1,6 +1,10 @@ import 'dart:core'; import 'dart:math'; import 'dart:convert'; +import 'package:freezed_annotation/freezed_annotation.dart'; + +part 'models.freezed.dart'; +part 'models.g.dart'; enum State { newState(0), @@ -46,54 +50,27 @@ class ReviewLog { } /// Store card data -class Card { - /// The time when the card is scheduled to be reviewed again - late DateTime due; - double stability = 0; - - /// How challenging or easy you find a specific flashcard during a review session - double difficulty = 0; - int elapsedDays = 0; - int scheduledDays = 0; - int reps = 0; - int lapses = 0; - State state = State.newState; - late DateTime lastReview; - - @override - String toString() { - return jsonEncode({ - "due": due.toString(), - "stability": stability, - "difficulty": difficulty, - "elapsedDays": elapsedDays, - "scheduledDays": scheduledDays, - "reps": reps, - "lapses": lapses, - "state": state.toString(), - "lastReview": lastReview.toString(), - }); - } +@unfreezed +class Card with _$Card { + const Card._(); + + factory Card.def( + DateTime due, + DateTime lastReview, [ + @Default(0) double stability, + @Default(0) double difficulty, + @Default(0) int elapsedDays, + @Default(0) int scheduledDays, + @Default(0) int reps, + @Default(0) int lapses, + @Default(State.newState) State state, + ]) = _Card; + + factory Card.fromJson(Map json) => _$CardFromJson(json); /// Construct current time for due and last review - Card() { - due = DateTime.now().toUtc(); - lastReview = DateTime.now().toUtc(); - } - - /// Helper to clone from a card - factory Card.copyFrom(Card card) { - Card newCard = Card(); - newCard.due = card.due; - newCard.stability = card.stability; - newCard.difficulty = card.difficulty; - newCard.elapsedDays = card.elapsedDays; - newCard.scheduledDays = card.scheduledDays; - newCard.reps = card.reps; - newCard.lapses = card.lapses; - newCard.state = card.state; - newCard.lastReview = card.lastReview; - return newCard; + factory Card() { + return _Card(DateTime.now().toUtc(), DateTime.now().toUtc()); } double? getRetrievability(DateTime now) { @@ -126,10 +103,10 @@ class SchedulingCards { late Card easy; SchedulingCards(Card card) { - again = Card.copyFrom(card); - hard = Card.copyFrom(card); - good = Card.copyFrom(card); - easy = Card.copyFrom(card); + again = card.copyWith(); + hard = card.copyWith(); + good = card.copyWith(); + easy = card.copyWith(); } void updateState(State state) { diff --git a/lib/src/models.freezed.dart b/lib/src/models.freezed.dart new file mode 100644 index 0000000..64a529a --- /dev/null +++ b/lib/src/models.freezed.dart @@ -0,0 +1,463 @@ +// coverage:ignore-file +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: type=lint +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark + +part of 'models.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(T value) => value; + +final _privateConstructorUsedError = UnsupportedError( + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models'); + +Card _$CardFromJson(Map json) { + return _Card.fromJson(json); +} + +/// @nodoc +mixin _$Card { + DateTime get due => throw _privateConstructorUsedError; + set due(DateTime value) => throw _privateConstructorUsedError; + DateTime get lastReview => throw _privateConstructorUsedError; + set lastReview(DateTime value) => throw _privateConstructorUsedError; + double get stability => throw _privateConstructorUsedError; + set stability(double value) => throw _privateConstructorUsedError; + double get difficulty => throw _privateConstructorUsedError; + set difficulty(double value) => throw _privateConstructorUsedError; + int get elapsedDays => throw _privateConstructorUsedError; + set elapsedDays(int value) => throw _privateConstructorUsedError; + int get scheduledDays => throw _privateConstructorUsedError; + set scheduledDays(int value) => throw _privateConstructorUsedError; + int get reps => throw _privateConstructorUsedError; + set reps(int value) => throw _privateConstructorUsedError; + int get lapses => throw _privateConstructorUsedError; + set lapses(int value) => throw _privateConstructorUsedError; + State get state => throw _privateConstructorUsedError; + set state(State value) => throw _privateConstructorUsedError; + @optionalTypeArgs + TResult when({ + required TResult Function( + DateTime due, + DateTime lastReview, + double stability, + double difficulty, + int elapsedDays, + int scheduledDays, + int reps, + int lapses, + State state) + def, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function( + DateTime due, + DateTime lastReview, + double stability, + double difficulty, + int elapsedDays, + int scheduledDays, + int reps, + int lapses, + State state)? + def, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult maybeWhen({ + TResult Function( + DateTime due, + DateTime lastReview, + double stability, + double difficulty, + int elapsedDays, + int scheduledDays, + int reps, + int lapses, + State state)? + def, + required TResult orElse(), + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult map({ + required TResult Function(_Card value) def, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(_Card value)? def, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult maybeMap({ + TResult Function(_Card value)? def, + required TResult orElse(), + }) => + throw _privateConstructorUsedError; + Map toJson() => throw _privateConstructorUsedError; + @JsonKey(ignore: true) + $CardCopyWith get copyWith => throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $CardCopyWith<$Res> { + factory $CardCopyWith(Card value, $Res Function(Card) then) = + _$CardCopyWithImpl<$Res, Card>; + @useResult + $Res call( + {DateTime due, + DateTime lastReview, + double stability, + double difficulty, + int elapsedDays, + int scheduledDays, + int reps, + int lapses, + State state}); +} + +/// @nodoc +class _$CardCopyWithImpl<$Res, $Val extends Card> + implements $CardCopyWith<$Res> { + _$CardCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? due = null, + Object? lastReview = null, + Object? stability = null, + Object? difficulty = null, + Object? elapsedDays = null, + Object? scheduledDays = null, + Object? reps = null, + Object? lapses = null, + Object? state = null, + }) { + return _then(_value.copyWith( + due: null == due + ? _value.due + : due // ignore: cast_nullable_to_non_nullable + as DateTime, + lastReview: null == lastReview + ? _value.lastReview + : lastReview // ignore: cast_nullable_to_non_nullable + as DateTime, + stability: null == stability + ? _value.stability + : stability // ignore: cast_nullable_to_non_nullable + as double, + difficulty: null == difficulty + ? _value.difficulty + : difficulty // ignore: cast_nullable_to_non_nullable + as double, + elapsedDays: null == elapsedDays + ? _value.elapsedDays + : elapsedDays // ignore: cast_nullable_to_non_nullable + as int, + scheduledDays: null == scheduledDays + ? _value.scheduledDays + : scheduledDays // ignore: cast_nullable_to_non_nullable + as int, + reps: null == reps + ? _value.reps + : reps // ignore: cast_nullable_to_non_nullable + as int, + lapses: null == lapses + ? _value.lapses + : lapses // ignore: cast_nullable_to_non_nullable + as int, + state: null == state + ? _value.state + : state // ignore: cast_nullable_to_non_nullable + as State, + ) as $Val); + } +} + +/// @nodoc +abstract class _$$CardImplCopyWith<$Res> implements $CardCopyWith<$Res> { + factory _$$CardImplCopyWith( + _$CardImpl value, $Res Function(_$CardImpl) then) = + __$$CardImplCopyWithImpl<$Res>; + @override + @useResult + $Res call( + {DateTime due, + DateTime lastReview, + double stability, + double difficulty, + int elapsedDays, + int scheduledDays, + int reps, + int lapses, + State state}); +} + +/// @nodoc +class __$$CardImplCopyWithImpl<$Res> + extends _$CardCopyWithImpl<$Res, _$CardImpl> + implements _$$CardImplCopyWith<$Res> { + __$$CardImplCopyWithImpl(_$CardImpl _value, $Res Function(_$CardImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? due = null, + Object? lastReview = null, + Object? stability = null, + Object? difficulty = null, + Object? elapsedDays = null, + Object? scheduledDays = null, + Object? reps = null, + Object? lapses = null, + Object? state = null, + }) { + return _then(_$CardImpl( + null == due + ? _value.due + : due // ignore: cast_nullable_to_non_nullable + as DateTime, + null == lastReview + ? _value.lastReview + : lastReview // ignore: cast_nullable_to_non_nullable + as DateTime, + null == stability + ? _value.stability + : stability // ignore: cast_nullable_to_non_nullable + as double, + null == difficulty + ? _value.difficulty + : difficulty // ignore: cast_nullable_to_non_nullable + as double, + null == elapsedDays + ? _value.elapsedDays + : elapsedDays // ignore: cast_nullable_to_non_nullable + as int, + null == scheduledDays + ? _value.scheduledDays + : scheduledDays // ignore: cast_nullable_to_non_nullable + as int, + null == reps + ? _value.reps + : reps // ignore: cast_nullable_to_non_nullable + as int, + null == lapses + ? _value.lapses + : lapses // ignore: cast_nullable_to_non_nullable + as int, + null == state + ? _value.state + : state // ignore: cast_nullable_to_non_nullable + as State, + )); + } +} + +/// @nodoc +@JsonSerializable() +class _$CardImpl extends _Card { + _$CardImpl(this.due, this.lastReview, + [this.stability = 0, + this.difficulty = 0, + this.elapsedDays = 0, + this.scheduledDays = 0, + this.reps = 0, + this.lapses = 0, + this.state = State.newState]) + : super._(); + + factory _$CardImpl.fromJson(Map json) => + _$$CardImplFromJson(json); + + @override + DateTime due; + @override + DateTime lastReview; + @override + @JsonKey() + double stability; + @override + @JsonKey() + double difficulty; + @override + @JsonKey() + int elapsedDays; + @override + @JsonKey() + int scheduledDays; + @override + @JsonKey() + int reps; + @override + @JsonKey() + int lapses; + @override + @JsonKey() + State state; + + @override + String toString() { + return 'Card.def(due: $due, lastReview: $lastReview, stability: $stability, difficulty: $difficulty, elapsedDays: $elapsedDays, scheduledDays: $scheduledDays, reps: $reps, lapses: $lapses, state: $state)'; + } + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$CardImplCopyWith<_$CardImpl> get copyWith => + __$$CardImplCopyWithImpl<_$CardImpl>(this, _$identity); + + @override + @optionalTypeArgs + TResult when({ + required TResult Function( + DateTime due, + DateTime lastReview, + double stability, + double difficulty, + int elapsedDays, + int scheduledDays, + int reps, + int lapses, + State state) + def, + }) { + return def(due, lastReview, stability, difficulty, elapsedDays, + scheduledDays, reps, lapses, state); + } + + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function( + DateTime due, + DateTime lastReview, + double stability, + double difficulty, + int elapsedDays, + int scheduledDays, + int reps, + int lapses, + State state)? + def, + }) { + return def?.call(due, lastReview, stability, difficulty, elapsedDays, + scheduledDays, reps, lapses, state); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function( + DateTime due, + DateTime lastReview, + double stability, + double difficulty, + int elapsedDays, + int scheduledDays, + int reps, + int lapses, + State state)? + def, + required TResult orElse(), + }) { + if (def != null) { + return def(due, lastReview, stability, difficulty, elapsedDays, + scheduledDays, reps, lapses, state); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(_Card value) def, + }) { + return def(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(_Card value)? def, + }) { + return def?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(_Card value)? def, + required TResult orElse(), + }) { + if (def != null) { + return def(this); + } + return orElse(); + } + + @override + Map toJson() { + return _$$CardImplToJson( + this, + ); + } +} + +abstract class _Card extends Card { + factory _Card(DateTime due, DateTime lastReview, + [double stability, + double difficulty, + int elapsedDays, + int scheduledDays, + int reps, + int lapses, + State state]) = _$CardImpl; + _Card._() : super._(); + + factory _Card.fromJson(Map json) = _$CardImpl.fromJson; + + @override + DateTime get due; + set due(DateTime value); + @override + DateTime get lastReview; + set lastReview(DateTime value); + @override + double get stability; + set stability(double value); + @override + double get difficulty; + set difficulty(double value); + @override + int get elapsedDays; + set elapsedDays(int value); + @override + int get scheduledDays; + set scheduledDays(int value); + @override + int get reps; + set reps(int value); + @override + int get lapses; + set lapses(int value); + @override + State get state; + set state(State value); + @override + @JsonKey(ignore: true) + _$$CardImplCopyWith<_$CardImpl> get copyWith => + throw _privateConstructorUsedError; +} diff --git a/lib/src/models.g.dart b/lib/src/models.g.dart new file mode 100644 index 0000000..1cdad12 --- /dev/null +++ b/lib/src/models.g.dart @@ -0,0 +1,39 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'models.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +_$CardImpl _$$CardImplFromJson(Map json) => _$CardImpl( + DateTime.parse(json['due'] as String), + DateTime.parse(json['lastReview'] as String), + (json['stability'] as num?)?.toDouble() ?? 0, + (json['difficulty'] as num?)?.toDouble() ?? 0, + (json['elapsedDays'] as num?)?.toInt() ?? 0, + (json['scheduledDays'] as num?)?.toInt() ?? 0, + (json['reps'] as num?)?.toInt() ?? 0, + (json['lapses'] as num?)?.toInt() ?? 0, + $enumDecodeNullable(_$StateEnumMap, json['state']) ?? State.newState, + ); + +Map _$$CardImplToJson(_$CardImpl instance) => + { + 'due': instance.due.toIso8601String(), + 'lastReview': instance.lastReview.toIso8601String(), + 'stability': instance.stability, + 'difficulty': instance.difficulty, + 'elapsedDays': instance.elapsedDays, + 'scheduledDays': instance.scheduledDays, + 'reps': instance.reps, + 'lapses': instance.lapses, + 'state': _$StateEnumMap[instance.state]!, + }; + +const _$StateEnumMap = { + State.newState: 'newState', + State.learning: 'learning', + State.review: 'review', + State.relearning: 'relearning', +}; diff --git a/pubspec.yaml b/pubspec.yaml index 9b50e39..0dbcdef 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -10,8 +10,13 @@ environment: # Add regular dependencies here. dependencies: collection: ^1.18.0 + freezed_annotation: ^2.4.1 + json_annotation: ^4.9.0 # path: ^1.8.0 dev_dependencies: + build_runner: ^2.4.9 + freezed: ^2.5.2 + json_serializable: ^6.8.0 lints: ^3.0.0 test: ^1.24.0 From d95c5e89d04fbb01e5d77fa2cfb67c990cd76bd2 Mon Sep 17 00:00:00 2001 From: Son Bui Date: Wed, 1 May 2024 13:37:00 +0700 Subject: [PATCH 2/2] add new version Signed-off-by: Son Bui --- CHANGELOG.md | 4 ++++ pubspec.yaml | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 42f8c60..882db8d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.1.1 + +- Add support json function on Card class + ## 1.1.0 - Fix coding standard. diff --git a/pubspec.yaml b/pubspec.yaml index 0dbcdef..1f84939 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: fsrs description: A Dart package for FSRS, which implements the Free Spaced Repetition Scheduler algorithm. This package assists developers in incorporating FSRS into their flashcard applications. -version: 1.1.0 +version: 1.1.1 repository: https://github.com/open-spaced-repetition/dart-fsrs environment: