Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update domain/models to conform to server structure #289

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
117 changes: 57 additions & 60 deletions flutter/lib/domain/models/collection.dart
Original file line number Diff line number Diff line change
@@ -1,97 +1,74 @@
import 'package:equatable/equatable.dart';
import 'package:memo/domain/enums/memo_difficulty.dart';
import 'package:memo/domain/enums/resource_type.dart';
import 'package:memo/domain/models/memo_execution.dart';
import 'package:meta/meta.dart';

/// Metadata for a collection (group) of its associated `Memo`s.
///
/// Through [MemoExecutionsMetadata], this class also includes properties that describes its executed `Memo`s.
@immutable
class Collection extends MemoExecutionsMetadata with EquatableMixin implements CollectionMetadata {
class Collection with EquatableMixin {
Collection({
required this.id,
required this.name,
required this.description,
required this.category,
required this.tags,
required this.uniqueMemosAmount,
required this.contributors,
this.uniqueMemoExecutionsAmount = 0,
Map<MemoDifficulty, int> executionsAmounts = const {},
int timeSpentInMillis = 0,
}) : assert(uniqueMemosAmount > 0, 'must be a positive integer'),
assert(uniqueMemoExecutionsAmount >= 0, 'must be a positive (or zero) integer'),
assert(timeSpentInMillis >= 0, 'must be a positive (or zero) integer'),
assert(
uniqueMemosAmount >= uniqueMemoExecutionsAmount,
'executions should never exceed the unique total amount',
),
assert(contributors.isNotEmpty, 'must have at least one contributor'),
super(timeSpentInMillis, executionsAmounts);
required this.memosAmount,
required this.memosOrder,
this.category,
this.description,
this.locale,
this.tags,
this.contributors,
this.resources,
});

@override
final String id;

@override
final String name;

@override
final String description;

@override
final String category;

@override
final List<String> tags;
final int memosAmount;
final List<String> memosOrder;

@override
final List<Contributor> contributors;
final String? locale;
final String? description;
final String? category;

@override
final int uniqueMemosAmount;

@override
final int uniqueMemoExecutionsAmount;

/// `true` if this [Collection] has never executed any `Memo`.
bool get isPristine => uniqueMemoExecutionsAmount == 0;

/// `true` if this [Collection] has executed (at least once) all of its `Memo`s.
bool get isCompleted => uniqueMemoExecutionsAmount == uniqueMemosAmount;
final List<String>? tags;
final List<Contributor>? contributors;
final List<Resource>? resources;

@override
List<Object?> get props => [
id,
name,
memosAmount,
memosOrder,
locale,
description,
category,
tags,
contributors,
uniqueMemoExecutionsAmount,
uniqueMemosAmount,
...super.props,
resources,
];
}

/// Metadata for a collection.
abstract class CollectionMetadata {
String get id;
String get name;
String get description;
String get category;
// abstract class CollectionMetadata {
// String get id;
// String get name;
// String get description;
// String get category;

/// Abstract tags that are used to group and identify this collection.
List<String> get tags;
// /// Abstract tags that are used to group and identify this collection.
// List<String> get tags;

/// Contributors (or owners) that have created (or made changes) to this collection.
List<Contributor> get contributors;
// /// Contributors (or owners) that have created (or made changes) to this collection.
// List<Contributor> get contributors;

/// Total amount of unique `Memo`s associated with this collection.
int get uniqueMemosAmount;
// /// Total amount of unique `Memo`s associated with this collection.
// int get uniqueMemosAmount;

/// Total amount of unique `Memo`s associated with this collection that have been executed at least once.
int get uniqueMemoExecutionsAmount;
}
// /// Total amount of unique `Memo`s associated with this collection that have been executed at least once.
// int get uniqueMemoExecutionsAmount;
// }

/// A collection contributor.
@immutable
Expand All @@ -110,3 +87,23 @@ class Contributor extends Equatable {
@override
List<Object?> get props => [name, imageUrl, url];
}

/// Enhances the usage of a single [url] with associated properties, like [description] and [type].
@immutable
class Resource extends Equatable {
const Resource({required this.id, required this.description, required this.type, required this.url});

final String id;

/// Human-readable description for this description.
final String description;

/// Describes which type of [url] this resource refers to.
final ResourceType type;

/// URL that links to this particular [Resource].
final String url;

@override
List<Object?> get props => [id, description, type, url];
}
51 changes: 51 additions & 0 deletions flutter/lib/domain/models/collection_execution.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import 'package:memo/domain/enums/memo_difficulty.dart';
import 'package:memo/domain/models/memo_executions_metadata.dart';

typedef MemoId = String;

class CollectionExecution extends MemoExecutionsMetadata {
CollectionExecution({
required this.id,
required this.executions,
required int timeSpentInMillis,
required Map<MemoDifficulty, int> difficulties,
}) : assert(executions.isNotEmpty, 'Requires memos executions'),
super(timeSpentInMillis, difficulties);

final String id;
final Map<MemoId, MemoExecutionRecallMetadata> executions;

int get totalMemos => executions.entries.length;
int get uniqueExecutedMemos => executions.values.where((exec) => !exec.isPristine).length;

/// `true` if not a single `Memo` have been executed.
bool get isPristine => uniqueExecutedMemos == 0;

/// `true` if all `Memo` have been executed at least once.
bool get isCompleted => totalMemos == uniqueExecutedMemos;

@override
List<Object?> get props => [id, executions, ...super.props];
}

class MemoExecutionRecallMetadata {
MemoExecutionRecallMetadata({
required this.id,
required this.totalExecutions,
required this.lastExecution,
required this.lastMarkedDifficulty,
}) : assert(
(lastExecution != null && lastMarkedDifficulty != null && totalExecutions > 0) ^
(lastExecution == null && lastMarkedDifficulty == null && totalExecutions == 0),
'Inconsistency between one or multiple execution-related properties, as they must be mutually exclusive',
);

final String id;

/// `true` if this `Memo` was never executed.
bool get isPristine => lastExecution != null;

final int totalExecutions;
final DateTime? lastExecution;
final MemoDifficulty? lastMarkedDifficulty;
}
78 changes: 23 additions & 55 deletions flutter/lib/domain/models/memo.dart
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
import 'package:equatable/equatable.dart';
import 'package:memo/domain/enums/memo_difficulty.dart';
import 'package:memo/domain/models/memo_collection_metadata.dart';
import 'package:memo/domain/models/memo_execution.dart';
import 'package:meta/meta.dart';

/// Metadata for an unit of a collection - a `Memo`.
Expand All @@ -15,58 +12,29 @@ import 'package:meta/meta.dart';
/// - `MemoExecution`, which represents an individual execution of a `Memo`.
@immutable
// ignore: avoid_implementing_value_types
class Memo extends MemoExecutionsMetadata with EquatableMixin implements MemoCollectionMetadata {
Memo({
required this.collectionId,
required this.uniqueId,
required this.rawQuestion,
required this.rawAnswer,
this.lastExecution,
Map<MemoDifficulty, int> executionsAmounts = const {},
int timeSpentInMillis = 0,
}) : assert(
(timeSpentInMillis > 0 && lastExecution != null) || (timeSpentInMillis == 0 && lastExecution == null),
'both properties must be simultaneously empty (zero) or not',
),
super(timeSpentInMillis, executionsAmounts);
class Memo with EquatableMixin {
Memo({required this.id, required this.question, required this.answer})
: assert(question.isNotEmpty),
assert(question.first.isNotEmpty),
assert(answer.isNotEmpty),
assert(answer.first.isNotEmpty);

final String id;

/// Raw representation of a `Memo` question.
///
/// A question may be composed of an arbitrary amount of styled elements. Each of these elements - an untyped `Map` -
/// are a raw representation of this styled element, allowing each to have a completely different structure from the
/// other.
final List<Map<String, dynamic>> question;

/// Raw representation of a `Memo` answer
///
/// An answer may be composed of an arbitrary amount of styled elements. Each of these elements - an untyped `Map` -
/// are a raw representation of this styled element, allowing each to have a completely different structure from the
/// other.
final List<Map<String, dynamic>> answer;

@override
final String uniqueId;

@override
final List<Map<String, dynamic>> rawQuestion;

@override
final List<Map<String, dynamic>> rawAnswer;

/// Parent collection's id.
final String collectionId;

final MemoExecution? lastExecution;
DateTime? get lastExecuted => lastExecution?.finished;
MemoDifficulty? get lastMarkedDifficulty => lastExecution?.markedDifficulty;

/// `true` if this [Memo] was never executed.
bool get isPristine => lastExecution == null;

@override
List<Object?> get props => [collectionId, lastExecution, uniqueId, rawQuestion, rawAnswer, ...super.props];

Memo copyWith({
List<Map<String, dynamic>>? rawQuestion,
List<Map<String, dynamic>>? rawAnswer,
MemoExecution? lastExecution,
Map<MemoDifficulty, int>? executionsAmounts,
int? timeSpentInMillis,
}) {
return Memo(
collectionId: collectionId,
uniqueId: uniqueId,
rawQuestion: rawQuestion ?? this.rawQuestion,
rawAnswer: rawAnswer ?? this.rawAnswer,
lastExecution: lastExecution ?? this.lastExecution,
executionsAmounts: executionsAmounts ?? this.executionsAmounts,
timeSpentInMillis: timeSpentInMillis ?? this.timeSpentInMillis,
);
}
List<Object?> get props => [id, question, answer];
}
32 changes: 0 additions & 32 deletions flutter/lib/domain/models/memo_collection_metadata.dart

This file was deleted.

Loading