5053 can get points from lemma with max score (#5078)
* make uses a private field for ConstructUses * expose capped list of uses in ConstructUses * filter capped construct uses in getUses
This commit is contained in:
parent
0ba50f9d73
commit
2c176c052d
10 changed files with 164 additions and 146 deletions
|
|
@ -241,7 +241,23 @@ class AnalyticsDataService {
|
||||||
);
|
);
|
||||||
|
|
||||||
final blocked = blockedConstructs;
|
final blocked = blockedConstructs;
|
||||||
return uses.where((use) => !blocked.contains(use.identifier)).toList();
|
final List<OneConstructUse> filtered = [];
|
||||||
|
|
||||||
|
final Map<ConstructIdentifier, DateTime?> cappedLastUseCache = {};
|
||||||
|
for (final use in uses) {
|
||||||
|
if (blocked.contains(use.identifier)) continue;
|
||||||
|
if (!cappedLastUseCache.containsKey(use.identifier)) {
|
||||||
|
final constructs = await getConstructUse(use.identifier);
|
||||||
|
cappedLastUseCache[use.identifier] = constructs.cappedLastUse;
|
||||||
|
}
|
||||||
|
final cappedLastUse = cappedLastUseCache[use.identifier];
|
||||||
|
if (cappedLastUse != null && use.timeStamp.isAfter(cappedLastUse)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
filtered.add(use);
|
||||||
|
}
|
||||||
|
|
||||||
|
return filtered;
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<List<OneConstructUse>> getLocalUses() async {
|
Future<List<OneConstructUse>> getLocalUses() async {
|
||||||
|
|
|
||||||
|
|
@ -199,82 +199,55 @@ class AnalyticsDatabase with DatabaseFileStorage {
|
||||||
DateTime? since,
|
DateTime? since,
|
||||||
}) async {
|
}) async {
|
||||||
final stopwatch = Stopwatch()..start();
|
final stopwatch = Stopwatch()..start();
|
||||||
final List<OneConstructUse> uses = [];
|
final results = <OneConstructUse>[];
|
||||||
|
|
||||||
// first, get all of the local (most recent) keys
|
bool addUseIfValid(OneConstructUse use) {
|
||||||
final localKeys = await _localConstructsBox.getAllKeys();
|
if (since != null && use.timeStamp.isBefore(since)) {
|
||||||
final localValues = await _localConstructsBox.getAll(localKeys);
|
return false; // stop iteration entirely
|
||||||
final local = Map.fromIterables(
|
}
|
||||||
localKeys,
|
if (roomId != null && use.metadata.roomId != roomId) {
|
||||||
localValues,
|
return true; // skip but continue
|
||||||
).entries.toList();
|
|
||||||
|
|
||||||
local.sort(
|
|
||||||
(a, b) => int.parse(b.key).compareTo(int.parse(a.key)),
|
|
||||||
);
|
|
||||||
|
|
||||||
for (final entry in local) {
|
|
||||||
// filter by date
|
|
||||||
if (since != null &&
|
|
||||||
int.parse(entry.key) < since.millisecondsSinceEpoch) {
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
final rawUses = entry.value;
|
results.add(use);
|
||||||
if (rawUses == null) continue;
|
return count == null || results.length < count;
|
||||||
for (final raw in rawUses) {
|
|
||||||
// filter by count
|
|
||||||
if (count != null && uses.length >= count) break;
|
|
||||||
|
|
||||||
final use = OneConstructUse.fromJson(
|
|
||||||
Map<String, dynamic>.from(raw),
|
|
||||||
);
|
|
||||||
|
|
||||||
// filter by roomID
|
|
||||||
if (roomId != null && use.metadata.roomId != roomId) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
uses.add(use);
|
|
||||||
}
|
|
||||||
if (count != null && uses.length >= count) break;
|
|
||||||
}
|
}
|
||||||
if (count != null && uses.length >= count) return uses;
|
|
||||||
|
|
||||||
// then get server uses
|
// ---- Local uses ----
|
||||||
final serverKeys = await _serverConstructsBox.getAllKeys();
|
final localUses = await getLocalUses()
|
||||||
serverKeys.sort(
|
..sort((a, b) => b.timeStamp.compareTo(a.timeStamp));
|
||||||
(a, b) =>
|
|
||||||
int.parse(b.split('|')[1]).compareTo(int.parse(a.split('|')[1])),
|
for (final use in localUses) {
|
||||||
);
|
if (!addUseIfValid(use)) break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count != null && results.length >= count) {
|
||||||
|
stopwatch.stop();
|
||||||
|
Logs().i("Get uses took ${stopwatch.elapsedMilliseconds} ms");
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---- Server uses ----
|
||||||
|
final serverKeys = await _serverConstructsBox.getAllKeys()
|
||||||
|
..sort(
|
||||||
|
(a, b) =>
|
||||||
|
int.parse(b.split('|')[1]).compareTo(int.parse(a.split('|')[1])),
|
||||||
|
);
|
||||||
|
|
||||||
for (final key in serverKeys) {
|
for (final key in serverKeys) {
|
||||||
// filter by count
|
final serverUses = await getServerUses(key)
|
||||||
if (count != null && uses.length >= count) break;
|
..sort((a, b) => b.timeStamp.compareTo(a.timeStamp));
|
||||||
final rawUses = await _serverConstructsBox.get(key);
|
|
||||||
if (rawUses == null) continue;
|
|
||||||
for (final raw in rawUses) {
|
|
||||||
if (count != null && uses.length >= count) break;
|
|
||||||
final use = OneConstructUse.fromJson(
|
|
||||||
Map<String, dynamic>.from(raw),
|
|
||||||
);
|
|
||||||
|
|
||||||
// filter by roomID
|
for (final use in serverUses) {
|
||||||
if (roomId != null && use.metadata.roomId != roomId) {
|
if (!addUseIfValid(use)) break;
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// filter by date
|
|
||||||
if (since != null && use.timeStamp.isBefore(since)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
uses.add(use);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (count != null && results.length >= count) break;
|
||||||
}
|
}
|
||||||
|
|
||||||
stopwatch.stop();
|
stopwatch.stop();
|
||||||
Logs().i("Get uses took ${stopwatch.elapsedMilliseconds} ms");
|
Logs().i("Get uses took ${stopwatch.elapsedMilliseconds} ms");
|
||||||
|
return results;
|
||||||
return uses.take(count ?? uses.length).toList();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<List<OneConstructUse>> getLocalUses() async {
|
Future<List<OneConstructUse>> getLocalUses() async {
|
||||||
|
|
@ -293,6 +266,21 @@ class AnalyticsDatabase with DatabaseFileStorage {
|
||||||
return uses;
|
return uses;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<List<OneConstructUse>> getServerUses(String key) async {
|
||||||
|
final List<OneConstructUse> uses = [];
|
||||||
|
final serverValues = await _serverConstructsBox.get(key);
|
||||||
|
if (serverValues == null) return [];
|
||||||
|
|
||||||
|
for (final entry in serverValues) {
|
||||||
|
uses.add(
|
||||||
|
OneConstructUse.fromJson(
|
||||||
|
Map<String, dynamic>.from(entry),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return uses;
|
||||||
|
}
|
||||||
|
|
||||||
Future<int> getLocalConstructCount() async {
|
Future<int> getLocalConstructCount() async {
|
||||||
final keys = await _localConstructsBox.getAllKeys();
|
final keys = await _localConstructsBox.getAllKeys();
|
||||||
return keys.length;
|
return keys.length;
|
||||||
|
|
@ -408,8 +396,7 @@ class AnalyticsDatabase with DatabaseFileStorage {
|
||||||
}
|
}
|
||||||
|
|
||||||
for (final u in usesForKey) {
|
for (final u in usesForKey) {
|
||||||
model.uses.add(u);
|
model.addUse(u);
|
||||||
model.setLastUsed(u.timeStamp);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
updates[key] = model;
|
updates[key] = model;
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,10 @@ class ConstructMergeTable {
|
||||||
List<ConstructUses> constructs,
|
List<ConstructUses> constructs,
|
||||||
Set<ConstructIdentifier> exclude,
|
Set<ConstructIdentifier> exclude,
|
||||||
) {
|
) {
|
||||||
addConstructsByUses(constructs.expand((c) => c.uses).toList(), exclude);
|
addConstructsByUses(
|
||||||
|
constructs.expand((c) => c.cappedUses).toList(),
|
||||||
|
exclude,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void addConstructsByUses(
|
void addConstructsByUses(
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@ class LemmaUsageDots extends StatelessWidget {
|
||||||
/// Find lemma uses for the given exercise type, to create dot list
|
/// Find lemma uses for the given exercise type, to create dot list
|
||||||
List<bool> sortedUses(LearningSkillsEnum category) {
|
List<bool> sortedUses(LearningSkillsEnum category) {
|
||||||
final List<bool> useList = [];
|
final List<bool> useList = [];
|
||||||
for (final OneConstructUse use in construct.uses) {
|
for (final OneConstructUse use in construct.cappedUses) {
|
||||||
if (use.xp == 0) {
|
if (use.xp == 0) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@ class LemmaUseExampleMessages extends StatelessWidget {
|
||||||
|
|
||||||
Future<List<ExampleMessage>> _getExampleMessages() async {
|
Future<List<ExampleMessage>> _getExampleMessages() async {
|
||||||
final List<ExampleMessage> examples = [];
|
final List<ExampleMessage> examples = [];
|
||||||
for (final OneConstructUse use in construct.uses) {
|
for (final OneConstructUse use in construct.cappedUses) {
|
||||||
if (use.useType.skillsEnumType != LearningSkillsEnum.writing ||
|
if (use.useType.skillsEnumType != LearningSkillsEnum.writing ||
|
||||||
use.metadata.eventId == null ||
|
use.metadata.eventId == null ||
|
||||||
use.form == null ||
|
use.form == null ||
|
||||||
|
|
|
||||||
|
|
@ -65,13 +65,7 @@ class VocabDetailsView extends StatelessWidget {
|
||||||
? level.color(context)
|
? level.color(context)
|
||||||
: level.darkColor(context));
|
: level.darkColor(context));
|
||||||
|
|
||||||
final forms = construct?.uses
|
final forms = construct?.forms ?? [];
|
||||||
.map((e) => e.form)
|
|
||||||
.whereType<String>()
|
|
||||||
.toSet()
|
|
||||||
.toList() ??
|
|
||||||
[];
|
|
||||||
|
|
||||||
final tokenText = PangeaTokenText.fromString(constructId.lemma);
|
final tokenText = PangeaTokenText.fromString(constructId.lemma);
|
||||||
final token = PangeaToken(
|
final token = PangeaToken(
|
||||||
text: tokenText,
|
text: tokenText,
|
||||||
|
|
|
||||||
|
|
@ -165,7 +165,8 @@ class AnalyticsDownloadDialogState extends State<AnalyticsDownloadDialog> {
|
||||||
|
|
||||||
final xp = uses.map((e) => e.points).reduce((a, total) => a + total);
|
final xp = uses.map((e) => e.points).reduce((a, total) => a + total);
|
||||||
final exampleMessages = await _getExampleMessages(uses);
|
final exampleMessages = await _getExampleMessages(uses);
|
||||||
final allUses = uses.map((u) => u.uses).expand((element) => element);
|
final allUses =
|
||||||
|
uses.map((u) => u.cappedUses).expand((element) => element);
|
||||||
|
|
||||||
int independantUseOccurrences = 0;
|
int independantUseOccurrences = 0;
|
||||||
int assistedUseOccurrences = 0;
|
int assistedUseOccurrences = 0;
|
||||||
|
|
@ -218,7 +219,7 @@ class AnalyticsDownloadDialogState extends State<AnalyticsDownloadDialog> {
|
||||||
|
|
||||||
final xp = uses.points;
|
final xp = uses.points;
|
||||||
final exampleMessages = await _getExampleMessages([uses]);
|
final exampleMessages = await _getExampleMessages([uses]);
|
||||||
final allUses = uses.uses;
|
final allUses = uses.cappedUses;
|
||||||
|
|
||||||
int independantUseOccurrences = 0;
|
int independantUseOccurrences = 0;
|
||||||
int assistedUseOccurrences = 0;
|
int assistedUseOccurrences = 0;
|
||||||
|
|
@ -261,7 +262,8 @@ class AnalyticsDownloadDialogState extends State<AnalyticsDownloadDialog> {
|
||||||
Future<List<String>> _getExampleMessages(
|
Future<List<String>> _getExampleMessages(
|
||||||
List<ConstructUses> constructUses,
|
List<ConstructUses> constructUses,
|
||||||
) async {
|
) async {
|
||||||
final allUses = constructUses.map((e) => e.uses).expand((e) => e).toList();
|
final allUses =
|
||||||
|
constructUses.map((e) => e.cappedUses).expand((e) => e).toList();
|
||||||
final List<PangeaMessageEvent> examples = [];
|
final List<PangeaMessageEvent> examples = [];
|
||||||
for (final OneConstructUse use in allUses) {
|
for (final OneConstructUse use in allUses) {
|
||||||
if (use.metadata.roomId == null) continue;
|
if (use.metadata.roomId == null) continue;
|
||||||
|
|
|
||||||
|
|
@ -252,7 +252,7 @@ class SpaceAnalyticsSummaryModel {
|
||||||
final systemUsesCorrect = [];
|
final systemUsesCorrect = [];
|
||||||
final systemUsesIncorrect = [];
|
final systemUsesIncorrect = [];
|
||||||
|
|
||||||
for (final use in entry.uses) {
|
for (final use in entry.cappedUses) {
|
||||||
if (originalUseTypes.contains(use.useType)) {
|
if (originalUseTypes.contains(use.useType)) {
|
||||||
use.xp > 0
|
use.xp > 0
|
||||||
? originalUsesCorrect.add(use)
|
? originalUsesCorrect.add(use)
|
||||||
|
|
|
||||||
|
|
@ -1,30 +1,35 @@
|
||||||
import 'dart:math';
|
import 'dart:math';
|
||||||
|
|
||||||
|
import 'package:collection/collection.dart';
|
||||||
|
|
||||||
import 'package:fluffychat/pangea/analytics_misc/analytics_constants.dart';
|
import 'package:fluffychat/pangea/analytics_misc/analytics_constants.dart';
|
||||||
import 'package:fluffychat/pangea/analytics_misc/construct_type_enum.dart';
|
import 'package:fluffychat/pangea/analytics_misc/construct_type_enum.dart';
|
||||||
|
import 'package:fluffychat/pangea/analytics_misc/construct_use_type_enum.dart';
|
||||||
import 'package:fluffychat/pangea/analytics_misc/constructs_model.dart';
|
import 'package:fluffychat/pangea/analytics_misc/constructs_model.dart';
|
||||||
import 'package:fluffychat/pangea/constructs/construct_identifier.dart';
|
import 'package:fluffychat/pangea/constructs/construct_identifier.dart';
|
||||||
import 'package:fluffychat/pangea/constructs/construct_level_enum.dart';
|
import 'package:fluffychat/pangea/constructs/construct_level_enum.dart';
|
||||||
|
|
||||||
/// One lemma and a list of construct uses for that lemma
|
/// One lemma and a list of construct uses for that lemma
|
||||||
class ConstructUses {
|
class ConstructUses {
|
||||||
final List<OneConstructUse> uses;
|
final List<OneConstructUse> _uses;
|
||||||
final ConstructTypeEnum constructType;
|
final ConstructTypeEnum constructType;
|
||||||
final String lemma;
|
final String lemma;
|
||||||
String? _category;
|
String? _category;
|
||||||
DateTime? _lastUsed;
|
|
||||||
|
|
||||||
ConstructUses({
|
ConstructUses({
|
||||||
required this.uses,
|
required List<OneConstructUse> uses,
|
||||||
required this.constructType,
|
required this.constructType,
|
||||||
required this.lemma,
|
required this.lemma,
|
||||||
required category,
|
required category,
|
||||||
}) : _category = category;
|
}) : _category = category,
|
||||||
|
_uses = List<OneConstructUse>.from(uses) {
|
||||||
|
_sortUses();
|
||||||
|
}
|
||||||
|
|
||||||
// Total points for all uses of this lemma
|
// Total points for all uses of this lemma
|
||||||
int get points {
|
int get points {
|
||||||
return min(
|
return min(
|
||||||
uses.fold<int>(
|
_uses.fold<int>(
|
||||||
0,
|
0,
|
||||||
(total, use) => total + use.xp,
|
(total, use) => total + use.xp,
|
||||||
),
|
),
|
||||||
|
|
@ -32,28 +37,16 @@ class ConstructUses {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
DateTime? get lastUsed {
|
DateTime? get lastUsed => _uses.lastOrNull?.timeStamp;
|
||||||
if (_lastUsed != null) return _lastUsed;
|
DateTime? get cappedLastUse => cappedUses.lastOrNull?.timeStamp;
|
||||||
final lastUse = uses.fold<DateTime?>(null, (DateTime? last, use) {
|
|
||||||
if (last == null) return use.timeStamp;
|
|
||||||
return use.timeStamp.isAfter(last) ? use.timeStamp : last;
|
|
||||||
});
|
|
||||||
return _lastUsed = lastUse;
|
|
||||||
}
|
|
||||||
|
|
||||||
void setLastUsed(DateTime time) {
|
|
||||||
if (_lastUsed == null || time.isAfter(_lastUsed!)) {
|
|
||||||
_lastUsed = time;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
String get category {
|
String get category {
|
||||||
if (_category == null || _category!.isEmpty) return "other";
|
if (_category == null || _category!.isEmpty) return "other";
|
||||||
return _category!.toLowerCase();
|
return _category!.toLowerCase();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool get hasCorrectUse => uses.any((use) => use.xp > 0);
|
bool get hasCorrectUse => _uses.any((use) => use.xp > 0);
|
||||||
bool get hasIncorrectUse => uses.any((use) => use.xp < 0);
|
bool get hasIncorrectUse => _uses.any((use) => use.xp < 0);
|
||||||
|
|
||||||
ConstructIdentifier get id => ConstructIdentifier(
|
ConstructIdentifier get id => ConstructIdentifier(
|
||||||
lemma: lemma,
|
lemma: lemma,
|
||||||
|
|
@ -61,38 +54,6 @@ class ConstructUses {
|
||||||
category: category,
|
category: category,
|
||||||
);
|
);
|
||||||
|
|
||||||
Map<String, dynamic> toJson() {
|
|
||||||
final json = {
|
|
||||||
'construct_id': id.toJson(),
|
|
||||||
'xp': points,
|
|
||||||
'last_used': lastUsed?.toIso8601String(),
|
|
||||||
'uses': uses.map((e) => e.toJson()).toList(),
|
|
||||||
};
|
|
||||||
return json;
|
|
||||||
}
|
|
||||||
|
|
||||||
factory ConstructUses.fromJson(Map<String, dynamic> json) {
|
|
||||||
final constructId = ConstructIdentifier.fromJson(
|
|
||||||
Map<String, dynamic>.from(json['construct_id']),
|
|
||||||
);
|
|
||||||
|
|
||||||
List<dynamic> usesJson = [];
|
|
||||||
if (json['uses'] is List) {
|
|
||||||
usesJson = List<dynamic>.from(json['uses']);
|
|
||||||
}
|
|
||||||
|
|
||||||
final uses = usesJson
|
|
||||||
.map((e) => OneConstructUse.fromJson(Map<String, dynamic>.from(e)))
|
|
||||||
.toList();
|
|
||||||
|
|
||||||
return ConstructUses(
|
|
||||||
uses: uses,
|
|
||||||
constructType: constructId.type,
|
|
||||||
lemma: constructId.lemma,
|
|
||||||
category: constructId.category,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get the lemma category, based on points
|
/// Get the lemma category, based on points
|
||||||
ConstructLevelEnum get lemmaCategory {
|
ConstructLevelEnum get lemmaCategory {
|
||||||
if (points < AnalyticsConstants.xpForGreens) {
|
if (points < AnalyticsConstants.xpForGreens) {
|
||||||
|
|
@ -122,6 +83,66 @@ class ConstructUses {
|
||||||
_ => ConstructLevelEnum.flowers,
|
_ => ConstructLevelEnum.flowers,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
List<String> get forms =>
|
||||||
|
_uses.map((e) => e.form).whereType<String>().toSet().toList();
|
||||||
|
|
||||||
|
List<OneConstructUse> get cappedUses {
|
||||||
|
final result = <OneConstructUse>[];
|
||||||
|
var totalXp = 0;
|
||||||
|
|
||||||
|
for (final use in _uses) {
|
||||||
|
if (totalXp >= AnalyticsConstants.xpForFlower) break;
|
||||||
|
totalXp += use.xp;
|
||||||
|
result.add(use);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
DateTime? lastUseByTypes(List<ConstructUseTypeEnum> types) =>
|
||||||
|
_uses.lastWhereOrNull((u) => types.contains(u.useType))?.timeStamp;
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
final json = {
|
||||||
|
'construct_id': id.toJson(),
|
||||||
|
'xp': points,
|
||||||
|
'last_used': lastUsed?.toIso8601String(),
|
||||||
|
'uses': _uses.map((e) => e.toJson()).toList(),
|
||||||
|
};
|
||||||
|
return json;
|
||||||
|
}
|
||||||
|
|
||||||
|
factory ConstructUses.fromJson(Map<String, dynamic> json) {
|
||||||
|
final constructId = ConstructIdentifier.fromJson(
|
||||||
|
Map<String, dynamic>.from(json['construct_id']),
|
||||||
|
);
|
||||||
|
|
||||||
|
List<dynamic> usesJson = [];
|
||||||
|
if (json['uses'] is List) {
|
||||||
|
usesJson = List<dynamic>.from(json['uses']);
|
||||||
|
}
|
||||||
|
|
||||||
|
final uses = usesJson
|
||||||
|
.map((e) => OneConstructUse.fromJson(Map<String, dynamic>.from(e)))
|
||||||
|
.toList();
|
||||||
|
|
||||||
|
return ConstructUses(
|
||||||
|
uses: uses,
|
||||||
|
constructType: constructId.type,
|
||||||
|
lemma: constructId.lemma,
|
||||||
|
category: constructId.category,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _sortUses() {
|
||||||
|
_uses.sort((a, b) => a.timeStamp.compareTo(b.timeStamp));
|
||||||
|
}
|
||||||
|
|
||||||
|
void addUse(OneConstructUse use) {
|
||||||
|
_uses.add(use);
|
||||||
|
_sortUses();
|
||||||
|
}
|
||||||
|
|
||||||
void merge(ConstructUses other) {
|
void merge(ConstructUses other) {
|
||||||
if (other.lemma.toLowerCase() != lemma.toLowerCase() ||
|
if (other.lemma.toLowerCase() != lemma.toLowerCase() ||
|
||||||
other.constructType != constructType) {
|
other.constructType != constructType) {
|
||||||
|
|
@ -130,10 +151,8 @@ class ConstructUses {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
uses.addAll(other.uses);
|
_uses.addAll(other._uses);
|
||||||
if (other.lastUsed != null) {
|
_sortUses();
|
||||||
setLastUsed(other.lastUsed!);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (category == 'other' && other.category != 'other') {
|
if (category == 'other' && other.category != 'other') {
|
||||||
_category = other.category;
|
_category = other.category;
|
||||||
|
|
@ -147,7 +166,7 @@ class ConstructUses {
|
||||||
String? category,
|
String? category,
|
||||||
}) {
|
}) {
|
||||||
return ConstructUses(
|
return ConstructUses(
|
||||||
uses: uses ?? this.uses,
|
uses: uses ?? _uses,
|
||||||
constructType: constructType ?? this.constructType,
|
constructType: constructType ?? this.constructType,
|
||||||
lemma: lemma ?? this.lemma,
|
lemma: lemma ?? this.lemma,
|
||||||
category: category ?? _category,
|
category: category ?? _category,
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
import 'package:collection/collection.dart';
|
|
||||||
import 'package:get_storage/get_storage.dart';
|
import 'package:get_storage/get_storage.dart';
|
||||||
|
|
||||||
import 'package:fluffychat/pangea/events/models/pangea_token_model.dart';
|
import 'package:fluffychat/pangea/events/models/pangea_token_model.dart';
|
||||||
|
|
@ -242,13 +241,11 @@ class PracticeSelectionRepo {
|
||||||
|
|
||||||
for (final token in tokens) {
|
for (final token in tokens) {
|
||||||
final construct = constructs[idMap[token]];
|
final construct = constructs[idMap[token]];
|
||||||
final lastUsed = construct?.uses.firstWhereOrNull(
|
final lastUsed =
|
||||||
(u) => activityType.associatedUseTypes.contains(u.useType),
|
construct?.lastUseByTypes(activityType.associatedUseTypes);
|
||||||
);
|
|
||||||
|
|
||||||
final daysSinceLastUsed = lastUsed == null
|
final daysSinceLastUsed =
|
||||||
? 20
|
lastUsed == null ? 20 : DateTime.now().difference(lastUsed).inDays;
|
||||||
: DateTime.now().difference(lastUsed.timeStamp).inDays;
|
|
||||||
|
|
||||||
scores[token] =
|
scores[token] =
|
||||||
daysSinceLastUsed * (token.vocabConstructID.isContentWord ? 10 : 9);
|
daysSinceLastUsed * (token.vocabConstructID.isContentWord ? 10 : 9);
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue