Merge pull request #4885 from pangeachat/4877-add-full-message-info-to-lemma-info-request-whenever-available
feat: send message info in lemma info request
This commit is contained in:
commit
27358a1472
19 changed files with 79 additions and 31 deletions
|
|
@ -63,6 +63,7 @@ class VocabDetailsEmojiSelectorState extends State<VocabDetailsEmojiSelector>
|
|||
langCode: MatrixState.pangeaController.userController.userL2Code!,
|
||||
emoji: selectedEmoji,
|
||||
onEmojiSelected: _setEmoji,
|
||||
messageInfo: const {},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -151,7 +151,8 @@ class ConstructIdentifier {
|
|||
uses: [],
|
||||
);
|
||||
|
||||
LemmaInfoRequest get lemmaInfoRequest => LemmaInfoRequest(
|
||||
LemmaInfoRequest lemmaInfoRequest(Map<String, dynamic> messageInfo) =>
|
||||
LemmaInfoRequest(
|
||||
partOfSpeech: category,
|
||||
lemmaLang:
|
||||
MatrixState.pangeaController.userController.userL2?.langCodeShort ??
|
||||
|
|
@ -160,12 +161,16 @@ class ConstructIdentifier {
|
|||
MatrixState.pangeaController.userController.userL1?.langCodeShort ??
|
||||
LanguageKeys.defaultLanguage,
|
||||
lemma: lemma,
|
||||
messageInfo: messageInfo,
|
||||
);
|
||||
|
||||
/// [lemmmaLang] if not set, assumed to be userL2
|
||||
Future<Result<LemmaInfoResponse>> getLemmaInfo() => LemmaInfoRepo.get(
|
||||
Future<Result<LemmaInfoResponse>> getLemmaInfo(
|
||||
Map<String, dynamic> messageInfo,
|
||||
) =>
|
||||
LemmaInfoRepo.get(
|
||||
MatrixState.pangeaController.userController.accessToken,
|
||||
lemmaInfoRequest,
|
||||
lemmaInfoRequest(messageInfo),
|
||||
);
|
||||
|
||||
List<String> get userSetEmoji => userLemmaInfo.emojis ?? [];
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ abstract class JsonSerializable {
|
|||
}
|
||||
|
||||
class ContentFeedback<T extends JsonSerializable> {
|
||||
final JsonSerializable content;
|
||||
final T content;
|
||||
final String feedback;
|
||||
|
||||
ContentFeedback(this.content, this.feedback);
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ class LemmaHighlightEmojiRow extends StatefulWidget {
|
|||
final String langCode;
|
||||
|
||||
final Function(String) onEmojiSelected;
|
||||
final Map<String, dynamic> messageInfo;
|
||||
|
||||
final String? emoji;
|
||||
final Widget? selectedEmojiBadge;
|
||||
|
|
@ -27,6 +28,7 @@ class LemmaHighlightEmojiRow extends StatefulWidget {
|
|||
required this.cId,
|
||||
required this.langCode,
|
||||
required this.onEmojiSelected,
|
||||
required this.messageInfo,
|
||||
this.emoji,
|
||||
this.selectedEmojiBadge,
|
||||
});
|
||||
|
|
@ -63,6 +65,7 @@ class LemmaHighlightEmojiRowState extends State<LemmaHighlightEmojiRow> {
|
|||
return LemmaMeaningBuilder(
|
||||
langCode: widget.langCode,
|
||||
constructId: widget.cId,
|
||||
messageInfo: widget.messageInfo,
|
||||
builder: (context, controller) {
|
||||
if (controller.error != null) {
|
||||
return const SizedBox.shrink();
|
||||
|
|
|
|||
|
|
@ -34,7 +34,9 @@ class LemmaInfoRepo {
|
|||
static Future<Result<LemmaInfoResponse>> get(
|
||||
String accessToken,
|
||||
LemmaInfoRequest request,
|
||||
) {
|
||||
) async {
|
||||
await GetStorage.init('lemma_storage');
|
||||
|
||||
// 1. Try memory cache
|
||||
final cached = _getCached(request);
|
||||
if (cached != null) {
|
||||
|
|
@ -44,7 +46,7 @@ class LemmaInfoRepo {
|
|||
// 2. Try disk cache
|
||||
final stored = _getStored(request);
|
||||
if (stored != null) {
|
||||
return Future.value(Result.value(stored));
|
||||
return Result.value(stored);
|
||||
}
|
||||
|
||||
// 3. Fetch from network (safe future)
|
||||
|
|
@ -66,6 +68,8 @@ class LemmaInfoRepo {
|
|||
LemmaInfoRequest request,
|
||||
LemmaInfoResponse resultFuture,
|
||||
) async {
|
||||
await GetStorage.init('lemma_storage');
|
||||
|
||||
final key = request.hashCode.toString();
|
||||
try {
|
||||
await _storage.write(key, resultFuture.toJson());
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import 'package:collection/collection.dart';
|
||||
|
||||
import 'package:fluffychat/pangea/analytics_misc/construct_type_enum.dart';
|
||||
import 'package:fluffychat/pangea/constructs/construct_identifier.dart';
|
||||
import 'package:fluffychat/pangea/events/models/content_feedback.dart';
|
||||
import 'package:fluffychat/pangea/lemmas/lemma_info_response.dart';
|
||||
|
||||
class LemmaInfoRequest {
|
||||
|
|
@ -8,14 +9,16 @@ class LemmaInfoRequest {
|
|||
final String partOfSpeech;
|
||||
final String lemmaLang;
|
||||
final String userL1;
|
||||
final Map<String, dynamic> messageInfo;
|
||||
|
||||
List<ContentFeedback<LemmaInfoResponse>> feedback;
|
||||
List<LemmaInfoResponse> feedback;
|
||||
|
||||
LemmaInfoRequest({
|
||||
required String partOfSpeech,
|
||||
required String lemmaLang,
|
||||
required this.userL1,
|
||||
required this.lemma,
|
||||
required this.messageInfo,
|
||||
this.feedback = const [],
|
||||
}) : partOfSpeech = partOfSpeech.toLowerCase(),
|
||||
lemmaLang = lemmaLang.toLowerCase();
|
||||
|
|
@ -27,6 +30,7 @@ class LemmaInfoRequest {
|
|||
'lemma_lang': lemmaLang,
|
||||
'user_l1': userL1,
|
||||
'feedback': feedback.map((e) => e.toJson()).toList(),
|
||||
'message_info': messageInfo,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -37,11 +41,15 @@ class LemmaInfoRequest {
|
|||
runtimeType == other.runtimeType &&
|
||||
lemma == other.lemma &&
|
||||
partOfSpeech == other.partOfSpeech &&
|
||||
feedback == other.feedback;
|
||||
const ListEquality().equals(feedback, other.feedback) &&
|
||||
userL1 == other.userL1;
|
||||
|
||||
@override
|
||||
int get hashCode =>
|
||||
lemma.hashCode ^ partOfSpeech.hashCode ^ feedback.hashCode;
|
||||
lemma.hashCode ^
|
||||
partOfSpeech.hashCode ^
|
||||
const ListEquality().hash(feedback) ^
|
||||
userL1.hashCode;
|
||||
|
||||
String get storageKey {
|
||||
return 'l:$lemma,p:$partOfSpeech,lang:$lemmaLang,l1:$userL1';
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
import 'package:collection/collection.dart';
|
||||
|
||||
import 'package:fluffychat/pangea/events/models/content_feedback.dart';
|
||||
|
||||
class LemmaInfoResponse implements JsonSerializable {
|
||||
|
|
@ -35,12 +37,9 @@ class LemmaInfoResponse implements JsonSerializable {
|
|||
identical(this, other) ||
|
||||
other is LemmaInfoResponse &&
|
||||
runtimeType == other.runtimeType &&
|
||||
emoji.length == other.emoji.length &&
|
||||
emoji.every((element) => other.emoji.contains(element)) &&
|
||||
const ListEquality().equals(emoji, other.emoji) &&
|
||||
meaning == other.meaning;
|
||||
|
||||
@override
|
||||
int get hashCode =>
|
||||
emoji.fold(0, (prev, element) => prev ^ element.hashCode) ^
|
||||
meaning.hashCode;
|
||||
int get hashCode => const ListEquality().hash(emoji) ^ meaning.hashCode;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,6 +30,8 @@ class _LemmaMeaningLoader extends AsyncLoader<LemmaInfoResponse> {
|
|||
class LemmaMeaningBuilder extends StatefulWidget {
|
||||
final String langCode;
|
||||
final ConstructIdentifier constructId;
|
||||
final Map<String, dynamic> messageInfo;
|
||||
|
||||
final Widget Function(
|
||||
BuildContext context,
|
||||
LemmaMeaningBuilderState controller,
|
||||
|
|
@ -40,6 +42,7 @@ class LemmaMeaningBuilder extends StatefulWidget {
|
|||
required this.langCode,
|
||||
required this.constructId,
|
||||
required this.builder,
|
||||
required this.messageInfo,
|
||||
});
|
||||
|
||||
@override
|
||||
|
|
@ -85,6 +88,7 @@ class LemmaMeaningBuilderState extends State<LemmaMeaningBuilder> {
|
|||
lemmaLang: widget.langCode,
|
||||
userL1: MatrixState.pangeaController.userController.userL1?.langCode ??
|
||||
LanguageKeys.defaultLanguage,
|
||||
messageInfo: widget.messageInfo,
|
||||
);
|
||||
|
||||
void _reload() {
|
||||
|
|
|
|||
|
|
@ -12,10 +12,12 @@ class LemmaMeaningWidget extends StatelessWidget {
|
|||
final ConstructIdentifier constructId;
|
||||
final TextStyle? style;
|
||||
final InlineSpan? leading;
|
||||
final Map<String, dynamic> messageInfo;
|
||||
|
||||
const LemmaMeaningWidget({
|
||||
super.key,
|
||||
required this.constructId,
|
||||
required this.messageInfo,
|
||||
this.style,
|
||||
this.leading,
|
||||
});
|
||||
|
|
@ -25,6 +27,7 @@ class LemmaMeaningWidget extends StatelessWidget {
|
|||
return LemmaMeaningBuilder(
|
||||
langCode: MatrixState.pangeaController.userController.userL2!.langCode,
|
||||
constructId: constructId,
|
||||
messageInfo: messageInfo,
|
||||
builder: (context, controller) {
|
||||
if (controller.isLoading) {
|
||||
return const TextLoadingShimmer();
|
||||
|
|
|
|||
|
|
@ -34,7 +34,9 @@ class PhoneticTranscriptionRepo {
|
|||
static Future<Result<PhoneticTranscriptionResponse>> get(
|
||||
String accessToken,
|
||||
PhoneticTranscriptionRequest request,
|
||||
) {
|
||||
) async {
|
||||
await GetStorage.init('phonetic_transcription_storage');
|
||||
|
||||
// 1. Try memory cache
|
||||
final cached = _getCached(request);
|
||||
if (cached != null) {
|
||||
|
|
@ -66,6 +68,7 @@ class PhoneticTranscriptionRepo {
|
|||
PhoneticTranscriptionRequest request,
|
||||
PhoneticTranscriptionResponse resultFuture,
|
||||
) async {
|
||||
await GetStorage.init('phonetic_transcription_storage');
|
||||
final key = request.hashCode.toString();
|
||||
try {
|
||||
await _storage.write(key, resultFuture.toJson());
|
||||
|
|
|
|||
|
|
@ -10,18 +10,20 @@ import 'package:fluffychat/pangea/practice_activities/practice_match.dart';
|
|||
|
||||
class EmojiActivityGenerator {
|
||||
static Future<MessageActivityResponse> get(
|
||||
MessageActivityRequest req,
|
||||
) async {
|
||||
MessageActivityRequest req, {
|
||||
required Map<String, dynamic> messageInfo,
|
||||
}) async {
|
||||
if (req.targetTokens.length <= 1) {
|
||||
throw Exception("Emoji activity requires at least 2 tokens");
|
||||
}
|
||||
|
||||
return _matchActivity(req);
|
||||
return _matchActivity(req, messageInfo: messageInfo);
|
||||
}
|
||||
|
||||
static Future<MessageActivityResponse> _matchActivity(
|
||||
MessageActivityRequest req,
|
||||
) async {
|
||||
MessageActivityRequest req, {
|
||||
required Map<String, dynamic> messageInfo,
|
||||
}) async {
|
||||
final Map<ConstructForm, List<String>> matchInfo = {};
|
||||
final List<PangeaToken> missingEmojis = [];
|
||||
|
||||
|
|
@ -39,7 +41,7 @@ class EmojiActivityGenerator {
|
|||
|
||||
final List<Future<Result<LemmaInfoResponse>>> lemmaInfoFutures =
|
||||
missingEmojis
|
||||
.map((token) => token.vocabConstructID.getLemmaInfo())
|
||||
.map((token) => token.vocabConstructID.getLemmaInfo(messageInfo))
|
||||
.toList();
|
||||
|
||||
final List<Result<LemmaInfoResponse>> lemmaInfos =
|
||||
|
|
|
|||
|
|
@ -12,11 +12,12 @@ import 'package:fluffychat/widgets/future_loading_dialog.dart';
|
|||
|
||||
class LemmaMeaningActivityGenerator {
|
||||
static Future<MessageActivityResponse> get(
|
||||
MessageActivityRequest req,
|
||||
) async {
|
||||
MessageActivityRequest req, {
|
||||
required Map<String, dynamic> messageInfo,
|
||||
}) async {
|
||||
final List<Future<Result<LemmaInfoResponse>>> lemmaInfoFutures = req
|
||||
.targetTokens
|
||||
.map((token) => token.vocabConstructID.getLemmaInfo())
|
||||
.map((token) => token.vocabConstructID.getLemmaInfo(messageInfo))
|
||||
.toList();
|
||||
|
||||
final List<Result<LemmaInfoResponse>> lemmaInfos =
|
||||
|
|
|
|||
|
|
@ -57,8 +57,9 @@ class PracticeRepo {
|
|||
|
||||
/// [event] is optional and used for saving the activity event to Matrix
|
||||
static Future<Result<PracticeActivityModel>> getPracticeActivity(
|
||||
MessageActivityRequest req,
|
||||
) async {
|
||||
MessageActivityRequest req, {
|
||||
required Map<String, dynamic> messageInfo,
|
||||
}) async {
|
||||
final cached = _getCached(req);
|
||||
if (cached != null) return Result.value(cached);
|
||||
|
||||
|
|
@ -66,6 +67,7 @@ class PracticeRepo {
|
|||
final MessageActivityResponse res = await _routePracticeActivity(
|
||||
accessToken: MatrixState.pangeaController.userController.accessToken,
|
||||
req: req,
|
||||
messageInfo: messageInfo,
|
||||
);
|
||||
|
||||
_setCached(req, res);
|
||||
|
|
@ -109,18 +111,19 @@ class PracticeRepo {
|
|||
static Future<MessageActivityResponse> _routePracticeActivity({
|
||||
required String accessToken,
|
||||
required MessageActivityRequest req,
|
||||
required Map<String, dynamic> messageInfo,
|
||||
}) async {
|
||||
// some activities we'll get from the server and others we'll generate locally
|
||||
switch (req.targetType) {
|
||||
case ActivityTypeEnum.emoji:
|
||||
return EmojiActivityGenerator.get(req);
|
||||
return EmojiActivityGenerator.get(req, messageInfo: messageInfo);
|
||||
case ActivityTypeEnum.lemmaId:
|
||||
return LemmaActivityGenerator.get(req);
|
||||
case ActivityTypeEnum.morphId:
|
||||
return MorphActivityGenerator.get(req);
|
||||
case ActivityTypeEnum.wordMeaning:
|
||||
debugger(when: kDebugMode);
|
||||
return LemmaMeaningActivityGenerator.get(req);
|
||||
return LemmaMeaningActivityGenerator.get(req, messageInfo: messageInfo);
|
||||
case ActivityTypeEnum.messageMeaning:
|
||||
case ActivityTypeEnum.wordFocusListening:
|
||||
return WordFocusListeningGenerator.get(req);
|
||||
|
|
|
|||
|
|
@ -117,7 +117,7 @@ class TokenInfoFeedbackDialog extends StatelessWidget {
|
|||
LemmaInfoResponse response,
|
||||
) =>
|
||||
LemmaInfoRepo.set(
|
||||
token.vocabConstructID.lemmaInfoRequest,
|
||||
token.vocabConstructID.lemmaInfoRequest(event.event.content),
|
||||
response,
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -93,7 +93,10 @@ class PracticeController with ChangeNotifier {
|
|||
targetMorphFeature: target.morphFeature,
|
||||
);
|
||||
|
||||
final result = await PracticeRepo.getPracticeActivity(req);
|
||||
final result = await PracticeRepo.getPracticeActivity(
|
||||
req,
|
||||
messageInfo: pangeaMessageEvent.event.content,
|
||||
);
|
||||
if (result.isValue) {
|
||||
_activity = result.result;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,12 +11,14 @@ class LemmaMeaningDisplay extends StatelessWidget {
|
|||
final String langCode;
|
||||
final ConstructIdentifier constructId;
|
||||
final String text;
|
||||
final Map<String, dynamic> messageInfo;
|
||||
|
||||
const LemmaMeaningDisplay({
|
||||
super.key,
|
||||
required this.langCode,
|
||||
required this.constructId,
|
||||
required this.text,
|
||||
required this.messageInfo,
|
||||
});
|
||||
|
||||
@override
|
||||
|
|
@ -24,6 +26,7 @@ class LemmaMeaningDisplay extends StatelessWidget {
|
|||
return LemmaMeaningBuilder(
|
||||
langCode: langCode,
|
||||
constructId: constructId,
|
||||
messageInfo: messageInfo,
|
||||
builder: (context, controller) {
|
||||
if (controller.isError) {
|
||||
return ErrorIndicator(
|
||||
|
|
|
|||
|
|
@ -118,6 +118,7 @@ class LemmaReactionPickerState extends State<LemmaReactionPicker>
|
|||
? _setEmoji(emoji)
|
||||
: _sendOrRedactReaction(emoji),
|
||||
emoji: _selectedEmoji,
|
||||
messageInfo: widget.event?.content ?? {},
|
||||
selectedEmojiBadge: widget.event != null &&
|
||||
_selectedEmoji != null &&
|
||||
_sentReaction(_selectedEmoji!) == null
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ class TokenFeedbackButton extends StatelessWidget {
|
|||
final String text;
|
||||
|
||||
final Function(LemmaInfoResponse, String) onFlagTokenInfo;
|
||||
final Map<String, dynamic> messageInfo;
|
||||
|
||||
const TokenFeedbackButton({
|
||||
super.key,
|
||||
|
|
@ -20,6 +21,7 @@ class TokenFeedbackButton extends StatelessWidget {
|
|||
required this.constructId,
|
||||
required this.text,
|
||||
required this.onFlagTokenInfo,
|
||||
required this.messageInfo,
|
||||
});
|
||||
|
||||
@override
|
||||
|
|
@ -27,6 +29,7 @@ class TokenFeedbackButton extends StatelessWidget {
|
|||
return LemmaMeaningBuilder(
|
||||
langCode: textLanguage.langCode,
|
||||
constructId: constructId,
|
||||
messageInfo: messageInfo,
|
||||
builder: (context, lemmaController) {
|
||||
return PhoneticTranscriptionBuilder(
|
||||
textLanguage: textLanguage,
|
||||
|
|
|
|||
|
|
@ -115,6 +115,7 @@ class WordZoomWidget extends StatelessWidget {
|
|||
constructId: construct,
|
||||
text: token.content,
|
||||
onFlagTokenInfo: onFlagTokenInfo!,
|
||||
messageInfo: event?.content ?? {},
|
||||
)
|
||||
: const SizedBox(
|
||||
width: 40.0,
|
||||
|
|
@ -152,6 +153,7 @@ class WordZoomWidget extends StatelessWidget {
|
|||
langCode: langCode,
|
||||
constructId: construct,
|
||||
text: token.content,
|
||||
messageInfo: event?.content ?? {},
|
||||
),
|
||||
],
|
||||
),
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue