fix(reading_assistance): fixed a bug in scoring matches

pull/1817/head
wcjord 7 months ago
parent c60b16dfe2
commit 88369ba8f7

@ -1,9 +1,7 @@
import 'package:fluffychat/pangea/common/config/environment.dart';
import 'package:flutter/material.dart';
import 'package:matrix/matrix.dart';
import 'package:fluffychat/pangea/common/config/environment.dart';
abstract class AppConfig {
// #Pangea
// static String _applicationName = 'FluffyChat';
@ -55,7 +53,8 @@ abstract class AppConfig {
// static const Color primaryColorLight = Color(0xFFCCBDEA);
static const Color primaryColor = Color(0xFF8560E0);
static const Color primaryColorLight = Color(0xFFDBC9FF);
static const Color secondaryColor = Color(0xFF41a2bc);
// static const Color secondaryColor = Color(0xFF41a2bc);
static const Color secondaryColor = Color.fromARGB(255, 253, 191, 1);
static const Color activeToggleColor = Color(0xFF33D057);
static const Color success = Color(0xFF33D057);
static const Color warning = Color.fromARGB(255, 210, 124, 12);

@ -68,6 +68,8 @@ abstract class FluffyThemes {
seedColor: seed ??
AppConfig.colorSchemeSeed ??
Theme.of(context).colorScheme.primary,
// primary: AppConfig.primaryColor,
// secondary: AppConfig.gold,
);
final isColumnMode = FluffyThemes.isColumnMode(context);
return ThemeData(

@ -1,10 +1,8 @@
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:fluffychat/config/app_config.dart';
import 'package:fluffychat/config/themes.dart';
import 'package:fluffychat/pangea/instructions/instructions_enum.dart';
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart';
class InstructionsInlineTooltip extends StatefulWidget {
final InstructionsEnum instructionsEnum;
@ -103,7 +101,7 @@ class InstructionsInlineTooltipState extends State<InstructionsInlineTooltip>
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(AppConfig.borderRadius),
color: Color.alphaBlend(
Colors.black.withAlpha(70),
Theme.of(context).colorScheme.surface.withAlpha(70),
AppConfig.gold,
),
),

@ -1,13 +1,7 @@
import 'dart:developer';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:collection/collection.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:sentry_flutter/sentry_flutter.dart';
import 'package:fluffychat/pangea/analytics_misc/construct_use_type_enum.dart';
import 'package:fluffychat/pangea/analytics_misc/construct_type_enum.dart';
import 'package:fluffychat/pangea/analytics_misc/constructs_model.dart';
import 'package:fluffychat/pangea/analytics_misc/put_analytics_controller.dart';
import 'package:fluffychat/pangea/common/utils/error_handler.dart';
@ -23,6 +17,10 @@ import 'package:fluffychat/pangea/practice_activities/practice_record.dart';
import 'package:fluffychat/pangea/practice_activities/practice_target.dart';
import 'package:fluffychat/pangea/practice_activities/relevant_span_display_details.dart';
import 'package:fluffychat/widgets/matrix.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:sentry_flutter/sentry_flutter.dart';
class PracticeActivityModel {
List<PangeaToken> targetTokens;
@ -95,9 +93,9 @@ class PracticeActivityModel {
score: isCorrect ? 1 : 0,
);
debugPrint(
"onMultipleChoiceSelect: ${choice.form} ${responseUseType(choice)}",
);
// debugPrint(
// "onMultipleChoiceSelect: ${choice.form} ${responseUseType(choice)}",
// );
MatrixState.pangeaController.putAnalytics.setState(
AnalyticsStream(
@ -105,7 +103,7 @@ class PracticeActivityModel {
roomId: event?.room.id,
constructs: [
OneConstructUse(
useType: responseUseType(choice)!,
useType: practiceTarget.record.responses.last.useType(activityType),
lemma: choice.form.cId.lemma,
constructType: choice.form.cId.type,
metadata: ConstructUseMetaData(
@ -133,8 +131,12 @@ class PracticeActivityModel {
) {
// the user has already selected this choice
// so we don't want to record it again
if (practiceTarget.record.hasTextResponse(choice.choiceContent) ||
if (practiceTarget.record.alreadyHasMatchResponse(
token.vocabConstructID,
choice.choiceContent,
) ||
isComplete) {
debugger(when: kDebugMode);
return;
}
@ -144,8 +146,12 @@ class PracticeActivityModel {
(answer) => answer.toLowerCase() == choice.choiceContent.toLowerCase(),
);
} else if (matchContent != null) {
isCorrect = matchContent!.matchInfo[token.vocabForm]!
.contains(choice.choiceContent);
// we check to see if it's in the list of acceptable answers
// rather than if the vocabForm is the same because an emoji
// could be in multiple constructs so there could be multiple answers
final answers = matchContent!.matchInfo[token.vocabForm];
debugger(when: answers == null && kDebugMode);
isCorrect = answers!.contains(choice.choiceContent);
} else {
debugger(when: kDebugMode);
ErrorHandler.logError(
@ -156,11 +162,11 @@ class PracticeActivityModel {
return;
}
// NOTE: the response is associated with the contructId of the choice, not the selected token
// NOTE: the response is associated with the contructId of the selected token, not the choice
// example: the user selects the word "cat" to match with the emoji 🐶
// the response is associated with correct word "dog", not the word "cat"
// the response is associated with incorrect word "cat", not the word "dog"
practiceTarget.record.addResponse(
cId: choice.form.cId,
cId: token.vocabConstructID,
text: choice.choiceContent,
target: practiceTarget,
score: isCorrect ? 1 : 0,
@ -174,15 +180,16 @@ class PracticeActivityModel {
roomId: event?.room.id,
constructs: [
OneConstructUse(
useType: responseUseType(choice)!,
lemma: choice.form.cId.lemma,
constructType: choice.form.cId.type,
useType:
practiceTarget.record.responses.last.useType(activityType),
lemma: token.lemma.text,
constructType: ConstructTypeEnum.vocab,
metadata: ConstructUseMetaData(
roomId: event?.room.id,
timeStamp: DateTime.now(),
eventId: event?.eventId,
),
category: choice.form.cId.category,
category: token.pos,
// in the case of a wrong answer, the cId doesn't match the token
form: token.text.content,
),
@ -226,27 +233,18 @@ class PracticeActivityModel {
/// if null, it means the user has not yet responded with that choice
bool? wasCorrectMatch(PracticeChoice choice) {
for (final response in practiceTarget.record.responses) {
if (response.cId == choice.form.cId && response.isCorrect) {
if (response.text == choice.choiceContent && response.isCorrect) {
return true;
}
}
for (final response in practiceTarget.record.responses) {
if (response.cId == choice.form.cId) {
if (response.text == choice.choiceContent) {
return false;
}
}
return null;
}
ConstructUseTypeEnum? responseUseType(PracticeChoice choice) {
for (final response in practiceTarget.record.responses) {
if (response.cId == choice.form.cId) {
return response.useType(activityType);
}
}
return null;
}
PracticeRecord get record => practiceTarget.record;
PracticeTarget get practiceTarget => PracticeTarget(

@ -2,12 +2,6 @@ import 'dart:async';
import 'dart:convert';
import 'dart:developer';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:http/http.dart';
import 'package:matrix/matrix.dart';
import 'package:fluffychat/pangea/common/config/environment.dart';
import 'package:fluffychat/pangea/common/controllers/pangea_controller.dart';
import 'package:fluffychat/pangea/common/network/requests.dart';
@ -25,6 +19,10 @@ import 'package:fluffychat/pangea/practice_activities/practice_activity_model.da
import 'package:fluffychat/pangea/practice_activities/word_focus_listening_generator.dart';
import 'package:fluffychat/pangea/toolbar/event_wrappers/practice_activity_event.dart';
import 'package:fluffychat/widgets/matrix.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:http/http.dart';
import 'package:matrix/matrix.dart';
/// Represents an item in the completion cache.
class _RequestCacheItem {
@ -173,7 +171,6 @@ class PracticeRepo {
// TODO resolve some wierdness here whereby the activity can be null but then... it's not
final eventCompleter = Completer<PracticeActivityEvent?>();
debugPrint('Activity generated: ${res.activity.toJson()}');
if (event != null) {
_sendAndPackageEvent(res.activity, event).then((event) {
eventCompleter.complete(event);

@ -1,7 +1,7 @@
import 'package:collection/collection.dart';
import 'package:fluffychat/pangea/constructs/construct_form.dart';
import 'package:fluffychat/pangea/practice_activities/practice_choice.dart';
import 'package:flutter/material.dart';
class PracticeMatchActivity {
/// The constructIdenfifiers involved in the activity
@ -13,6 +13,11 @@ class PracticeMatchActivity {
PracticeMatchActivity({
required this.matchInfo,
}) {
for (final ith in matchInfo.entries) {
debugPrint(
'Construct: ${ith.key}, Forms: ${ith.value}',
);
}
// if there are multiple forms for a construct, pick one to display
// each cosntruct will have ~3 forms
// sometimes a form could be in multiple constructs
@ -21,13 +26,17 @@ class PracticeMatchActivity {
// either from that construct's options, or returning to the previous construct
// and picking a different form from there
for (final ith in matchInfo.entries) {
for (final acceptableAnswer in ith.value) {
for (int i = 0; i < ith.value.length; i++) {
final String acceptableAnswer = ith.value[i];
if (!choices
.any((element) => element.choiceContent == acceptableAnswer)) {
choices.add(
PracticeChoice(choiceContent: acceptableAnswer, form: ith.key),
);
break;
debugPrint(
'Added choice: ${choices.last.choiceContent} for form: ${choices.last.form.form}',
);
i = ith.value.length; // break out of the loop
}
// TODO: if none found, we can probably pick a different form for the other one
}

@ -5,8 +5,6 @@
import 'dart:developer';
import 'package:flutter/foundation.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';
@ -16,6 +14,7 @@ import 'package:fluffychat/pangea/practice_activities/activity_type_enum.dart';
import 'package:fluffychat/pangea/practice_activities/practice_activity_model.dart';
import 'package:fluffychat/pangea/practice_activities/practice_record_repo.dart';
import 'package:fluffychat/pangea/practice_activities/practice_target.dart';
import 'package:flutter/foundation.dart';
class PracticeRecord {
late DateTime createdAt;
@ -72,6 +71,15 @@ class PracticeRecord {
return responses.any((element) => element.text == text);
}
bool alreadyHasMatchResponse(
ConstructIdentifier cId,
String text,
) {
return responses.any(
(element) => element.cId == cId && element.text == text,
);
}
/// [target] needed for saving the record, little funky
/// [cId] identifies the construct in the case of match activities which have multiple
/// [text] is the user's response
@ -111,6 +119,7 @@ class PracticeRecord {
score: score,
),
);
debugPrint("responses: ${responses.map((r) => r.toJson())}");
PracticeRecordRepo.save(target, this);
} catch (e) {
@ -156,6 +165,9 @@ class PracticeRecord {
}
class ActivityRecordResponse {
/// the cId of the construct that the user attached their response to
/// ie. in the "I like the dog" if the user erroneously attaches a dog emoji to the word like
/// then the cId is that of 'like
ConstructIdentifier cId;
// the user's response
// has nullable string, nullable audio bytes, nullable image bytes, and timestamp

@ -1,10 +1,9 @@
import 'package:flutter/foundation.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';
import 'package:fluffychat/pangea/practice_activities/practice_record.dart';
import 'package:fluffychat/pangea/practice_activities/practice_record_repo.dart';
import 'package:flutter/foundation.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
@ -90,7 +89,8 @@ class PracticeTarget {
}
return tokens.every(
(t) => record.responses.any((res) => res.cId == t.vocabConstructID),
(t) => record.responses
.any((res) => res.cId == t.vocabConstructID && res.isCorrect),
);
}
}

Loading…
Cancel
Save