import 'package:flutter/foundation.dart'; import 'package:collection/collection.dart'; import 'package:fluffychat/pangea/constructs/construct_identifier.dart'; import 'package:fluffychat/pangea/events/models/pangea_token_model.dart'; import 'package:fluffychat/pangea/morphs/morph_features_enum.dart'; import 'package:fluffychat/pangea/practice_activities/activity_type_enum.dart'; /// Picks which tokens to do activities on and what types of activities to do /// Caches result so that we don't have to recompute it /// Most importantly, we can't do this in the state of a message widget because the state is disposed of and recreated /// If we decided that the first token should have a hidden word listening, we need to remember that /// Otherwise, the user might leave the chat, return, and see a different word hidden class PracticeTarget { /// this is the tokens involved in the activity /// for most, this will be a single token final List tokens; /// this is the type of activity to do on the tokens final ActivityTypeEnum activityType; /// this is only defined for morphId activities final MorphFeaturesEnum? morphFeature; PracticeTarget({ required this.tokens, required this.activityType, this.morphFeature, }) { if (ActivityTypeEnum.morphId == activityType && morphFeature == null) { throw Exception("morphFeature must be defined for morphId activities"); } } @override bool operator ==(Object other) { if (identical(this, other)) return true; return other is PracticeTarget && listEquals(other.tokens, tokens) && other.activityType == activityType && other.morphFeature == morphFeature; } @override int get hashCode => tokens.hashCode ^ activityType.hashCode ^ morphFeature.hashCode; static PracticeTarget fromJson(Map json) { final type = ActivityTypeEnum.values.firstWhereOrNull( (v) => json['activityType'] == v.name, ); if (type == null) { throw Exception( "ActivityTypeEnum ${json['activityType']} not found in enum", ); } return PracticeTarget( tokens: (json['tokens'] as List).map((e) => PangeaToken.fromJson(e)).toList(), activityType: type, morphFeature: json['morphFeature'] == null ? null : MorphFeaturesEnumExtension.fromString(json['morphFeature']), ); } Map toJson() { return { 'tokens': tokens.map((e) => e.toJson()).toList(), 'activityType': activityType.name, 'morphFeature': morphFeature?.name, }; } //unique condensed deterministic key for local storage String get storageKey { return tokens.map((e) => e.text.content).join() + activityType.name + (morphFeature?.name ?? ""); } ConstructIdentifier targetTokenConstructID(PangeaToken token) { final defaultID = token.vocabConstructID; final ConstructIdentifier? cId = morphFeature == null ? defaultID : token.morphIdByFeature(morphFeature!); return cId ?? defaultID; } }