Vocab-details-v2 (#2093)
* started activity in chat creation * starting vocab tile display * refactor(vocab_analytics_list): made into little tiles that show the user chosen emoji * chore: comment out unused file * chore: remove unused variable * chore: make eventID nullable for constructs so users can set emoji from vocab details popup --------- Co-authored-by: ggurdin <ggurdin@gmail.com> Co-authored-by: ggurdin <46800240+ggurdin@users.noreply.github.com>
This commit is contained in:
parent
74b0cfd584
commit
0128ac42cd
43 changed files with 544 additions and 396 deletions
|
|
@ -4782,7 +4782,7 @@
|
|||
},
|
||||
"cancelInSubscriptionSettings": "• Cancel at any time in subscription settings",
|
||||
"cancelToAvoidCharges": "• Cancel before {trialEnds} to avoid charges",
|
||||
"@cancelToAvoidCharges": {
|
||||
"@cancelToAvoidCharges": {
|
||||
"type": "String",
|
||||
"placeholders": {
|
||||
"trialEnds": {
|
||||
|
|
@ -4803,6 +4803,8 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"analyticsVocabListBody": "This is all your vocabulary! As you earn XP for each word, they'll go from seedling to full bloom. Click on any word to see more details.",
|
||||
"morphAnalyticsListBody": "These are all the grammar concepts in the language you're learning! You'll unlock them as you encounter them while chatting. Click for details.",
|
||||
"knockSpaceSuccess": "You have requested to join this space! An admin will respond to your request when they receive it 😀",
|
||||
"joinByCode": "Join by code",
|
||||
"createASpace": "Create a space"
|
||||
|
|
|
|||
|
|
@ -0,0 +1,46 @@
|
|||
import 'dart:convert';
|
||||
|
||||
import 'package:get_storage/get_storage.dart';
|
||||
import 'package:http/http.dart';
|
||||
|
||||
import 'package:fluffychat/pangea/activity_planner/activity_plan_request.dart';
|
||||
import 'package:fluffychat/pangea/activity_planner/activity_plan_response.dart';
|
||||
import 'package:fluffychat/pangea/common/config/environment.dart';
|
||||
import 'package:fluffychat/pangea/common/network/requests.dart';
|
||||
import 'package:fluffychat/pangea/common/network/urls.dart';
|
||||
import 'package:fluffychat/widgets/matrix.dart';
|
||||
|
||||
class ActivitySearchRepo {
|
||||
static final GetStorage _activityPlanStorage =
|
||||
GetStorage('activity_plan_search_storage');
|
||||
|
||||
static void set(ActivityPlanRequest request, ActivityPlanResponse response) {
|
||||
_activityPlanStorage.write(request.storageKey, response.toJson());
|
||||
}
|
||||
|
||||
static Future<ActivityPlanResponse> get(ActivityPlanRequest request) async {
|
||||
final cachedJson = _activityPlanStorage.read(request.storageKey);
|
||||
if (cachedJson != null) {
|
||||
final cached = ActivityPlanResponse.fromJson(cachedJson);
|
||||
|
||||
return cached;
|
||||
}
|
||||
|
||||
final Requests req = Requests(
|
||||
choreoApiKey: Environment.choreoApiKey,
|
||||
accessToken: MatrixState.pangeaController.userController.accessToken,
|
||||
);
|
||||
|
||||
final Response res = await req.post(
|
||||
url: PApiUrls.activityPlanSearch,
|
||||
body: request.toJson(),
|
||||
);
|
||||
|
||||
final decodedBody = jsonDecode(utf8.decode(res.bodyBytes));
|
||||
final response = ActivityPlanResponse.fromJson(decodedBody);
|
||||
|
||||
set(request, response);
|
||||
|
||||
return response;
|
||||
}
|
||||
}
|
||||
38
lib/pangea/activity_suggestions/activity_search_request.dart
Normal file
38
lib/pangea/activity_suggestions/activity_search_request.dart
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
import 'package:fluffychat/pangea/activity_planner/media_enum.dart';
|
||||
import 'package:fluffychat/pangea/learning_settings/enums/language_level_type_enum.dart';
|
||||
|
||||
class ActivitySearchRequest {
|
||||
final String targetLanguage;
|
||||
final String languageOfInstructions;
|
||||
final LanguageLevelTypeEnum? languageLevel;
|
||||
|
||||
final String? mode;
|
||||
final String? learningObjective;
|
||||
final String? topic;
|
||||
final MediaEnum? media;
|
||||
final int? numberOfParticipants;
|
||||
|
||||
ActivitySearchRequest({
|
||||
required this.targetLanguage,
|
||||
required this.languageOfInstructions,
|
||||
this.mode,
|
||||
this.learningObjective,
|
||||
this.topic,
|
||||
this.media,
|
||||
this.numberOfParticipants = 2,
|
||||
this.languageLevel = LanguageLevelTypeEnum.preA1,
|
||||
});
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
return {
|
||||
'target_language': targetLanguage,
|
||||
'language_of_instructions': languageOfInstructions,
|
||||
'language_level': languageLevel,
|
||||
'mode': mode,
|
||||
'objective': learningObjective,
|
||||
'topic': topic,
|
||||
'media': media,
|
||||
'number_of_participants': numberOfParticipants,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
// // shows n rows of activity suggestions vertically, where n is the number of rows
|
||||
// // as the user tries to scroll horizontally to the right, the client will fetch more activity suggestions
|
||||
|
||||
// import 'package:flutter/material.dart';
|
||||
|
||||
// import 'package:fluffychat/pangea/activity_planner/activity_plan_request.dart';
|
||||
// import 'package:fluffychat/pangea/activity_suggestions/activity_plan_search_repo.dart';
|
||||
|
||||
// class ActivitySuggestionsArea extends StatefulWidget {
|
||||
// const ActivitySuggestionsArea({super.key});
|
||||
|
||||
// @override
|
||||
// ActivitySuggestionsAreaState createState() => ActivitySuggestionsAreaState();
|
||||
// }
|
||||
|
||||
// class ActivitySuggestionsAreaState extends State<ActivitySuggestionsArea> {
|
||||
// @override
|
||||
// void initState() {
|
||||
// super.initState();
|
||||
// }
|
||||
|
||||
// Future<void> fetchMoreSuggestions() async {
|
||||
// ActivitySearchRepo.get(
|
||||
// ActivityPlanRequest(),
|
||||
// );
|
||||
// }
|
||||
|
||||
// @override
|
||||
// Widget build(BuildContext context) {
|
||||
// return Container(
|
||||
// child: ListView.builder(
|
||||
// scrollDirection: Axis.vertical,
|
||||
// itemCount: 5,
|
||||
// itemBuilder: (context, index) {
|
||||
// return Container(
|
||||
// height: 100,
|
||||
// width: 100,
|
||||
// color: Colors.blue,
|
||||
// margin: const EdgeInsets.all(10),
|
||||
// );
|
||||
// },
|
||||
// ),
|
||||
// );
|
||||
// }
|
||||
// }
|
||||
|
|
@ -4,15 +4,15 @@ import 'package:flutter/material.dart';
|
|||
import 'package:flutter_gen/gen_l10n/l10n.dart';
|
||||
import 'package:material_symbols_icons/symbols.dart';
|
||||
|
||||
import 'package:fluffychat/pangea/analytics_details_popup/morph_analytics_view.dart';
|
||||
import 'package:fluffychat/pangea/analytics_details_popup/morph_analytics_list_view.dart';
|
||||
import 'package:fluffychat/pangea/analytics_details_popup/morph_details_view.dart';
|
||||
import 'package:fluffychat/pangea/analytics_details_popup/vocab_analytics_view.dart';
|
||||
import 'package:fluffychat/pangea/analytics_details_popup/vocab_details_view.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/construct_identifier.dart';
|
||||
import 'package:fluffychat/pangea/analytics_details_popup/vocab_analytics_details_view.dart';
|
||||
import 'package:fluffychat/pangea/analytics_details_popup/vocab_analytics_list_view.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/construct_type_enum.dart';
|
||||
import 'package:fluffychat/pangea/analytics_summary/progress_indicators_enum.dart';
|
||||
import 'package:fluffychat/pangea/common/utils/error_handler.dart';
|
||||
import 'package:fluffychat/pangea/common/widgets/full_width_dialog.dart';
|
||||
import 'package:fluffychat/pangea/constructs/construct_identifier.dart';
|
||||
import 'package:fluffychat/pangea/morphs/default_morph_mapping.dart';
|
||||
import 'package:fluffychat/pangea/morphs/morph_models.dart';
|
||||
import 'package:fluffychat/pangea/morphs/morph_repo.dart';
|
||||
|
|
@ -135,13 +135,13 @@ class AnalyticsPopupWrapperState extends State<AnalyticsPopupWrapper> {
|
|||
),
|
||||
body: localView == ConstructTypeEnum.morph
|
||||
? localConstructZoom == null
|
||||
? MorphAnalyticsView(
|
||||
? MorphAnalyticsListView(
|
||||
onConstructZoom: _setConstructZoom,
|
||||
controller: this,
|
||||
)
|
||||
: MorphDetailsView(constructId: localConstructZoom!)
|
||||
: localConstructZoom == null
|
||||
? VocabAnalyticsView(onConstructZoom: _setConstructZoom)
|
||||
? VocabAnalyticsListView(onConstructZoom: _setConstructZoom)
|
||||
: VocabDetailsView(constructId: localConstructZoom!),
|
||||
),
|
||||
maxWidth: 600,
|
||||
|
|
|
|||
|
|
@ -8,10 +8,10 @@ import 'package:fluffychat/config/app_config.dart';
|
|||
import 'package:fluffychat/pangea/analytics_details_popup/lemma_usage_dots.dart';
|
||||
import 'package:fluffychat/pangea/analytics_details_popup/lemma_use_example_messages.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/analytics_constants.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/construct_identifier.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/construct_level_enum.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/construct_use_model.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/learning_skills_enum.dart';
|
||||
import 'package:fluffychat/pangea/constructs/construct_identifier.dart';
|
||||
import 'package:fluffychat/pangea/constructs/construct_level_enum.dart';
|
||||
|
||||
class AnalyticsDetailsViewContent extends StatelessWidget {
|
||||
final Widget title;
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:fluffychat/config/app_config.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/construct_level_enum.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/construct_use_model.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/learning_skills_enum.dart';
|
||||
import 'package:fluffychat/pangea/constructs/construct_level_enum.dart';
|
||||
|
||||
class LemmaUsageDots extends StatelessWidget {
|
||||
final ConstructUses construct;
|
||||
|
|
|
|||
|
|
@ -6,11 +6,11 @@ import 'package:collection/collection.dart';
|
|||
import 'package:matrix/matrix.dart';
|
||||
|
||||
import 'package:fluffychat/config/app_config.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/construct_level_enum.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/construct_use_model.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/learning_skills_enum.dart';
|
||||
import 'package:fluffychat/pangea/constructs/construct_level_enum.dart';
|
||||
import 'package:fluffychat/pangea/events/event_wrappers/pangea_message_event.dart';
|
||||
import 'package:fluffychat/pangea/events/models/pangea_token_model.dart';
|
||||
import 'package:fluffychat/widgets/matrix.dart';
|
||||
|
|
@ -49,8 +49,9 @@ class LemmaUseExampleMessages extends StatelessWidget {
|
|||
continue;
|
||||
}
|
||||
|
||||
if (use.metadata.roomId == null) continue;
|
||||
final Room? room = MatrixState.pangeaController.matrixState.client
|
||||
.getRoomById(use.metadata.roomId);
|
||||
.getRoomById(use.metadata.roomId!);
|
||||
if (room == null) continue;
|
||||
|
||||
Timeline? timeline = room.timeline;
|
||||
|
|
|
|||
|
|
@ -5,20 +5,22 @@ import 'package:flutter_gen/gen_l10n/l10n.dart';
|
|||
|
||||
import 'package:fluffychat/config/app_config.dart';
|
||||
import 'package:fluffychat/pangea/analytics_details_popup/analytics_details_popup.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/construct_identifier.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/construct_level_enum.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/construct_type_enum.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/construct_use_model.dart';
|
||||
import 'package:fluffychat/pangea/constructs/construct_identifier.dart';
|
||||
import 'package:fluffychat/pangea/constructs/construct_level_enum.dart';
|
||||
import 'package:fluffychat/pangea/instructions/instructions_enum.dart';
|
||||
import 'package:fluffychat/pangea/instructions/instructions_inline_tooltip.dart';
|
||||
import 'package:fluffychat/pangea/morphs/get_grammar_copy.dart';
|
||||
import 'package:fluffychat/pangea/morphs/morph_icon.dart';
|
||||
import 'package:fluffychat/pangea/user/client_extension.dart';
|
||||
import 'package:fluffychat/widgets/matrix.dart';
|
||||
|
||||
class MorphAnalyticsView extends StatelessWidget {
|
||||
class MorphAnalyticsListView extends StatelessWidget {
|
||||
final void Function(ConstructIdentifier) onConstructZoom;
|
||||
final AnalyticsPopupWrapperState controller;
|
||||
|
||||
const MorphAnalyticsView({
|
||||
const MorphAnalyticsListView({
|
||||
required this.onConstructZoom,
|
||||
required this.controller,
|
||||
super.key,
|
||||
|
|
@ -27,23 +29,35 @@ class MorphAnalyticsView extends StatelessWidget {
|
|||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 20),
|
||||
child: ListView.builder(
|
||||
key: const PageStorageKey<String>('morph-analytics'),
|
||||
itemCount: controller.features.length,
|
||||
itemBuilder: (context, index) {
|
||||
final feature = controller.features[index];
|
||||
return feature.displayTags.isNotEmpty
|
||||
? MorphFeatureBox(
|
||||
morphFeature: feature.feature,
|
||||
allTags: controller.morphs
|
||||
.getDisplayTags(feature.feature)
|
||||
.map((tag) => tag.toLowerCase())
|
||||
.toSet(),
|
||||
onConstructZoom: onConstructZoom,
|
||||
)
|
||||
: const SizedBox.shrink();
|
||||
},
|
||||
padding: const EdgeInsets.symmetric(vertical: 8),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
// spacing: 16.0,
|
||||
children: [
|
||||
// Add your text widget here
|
||||
const InstructionsInlineTooltip(
|
||||
instructionsEnum: InstructionsEnum.morphAnalyticsList,
|
||||
),
|
||||
Expanded(
|
||||
child: ListView.builder(
|
||||
key: const PageStorageKey<String>('morph-analytics'),
|
||||
itemCount: controller.features.length,
|
||||
itemBuilder: (context, index) {
|
||||
final feature = controller.features[index];
|
||||
return feature.displayTags.isNotEmpty
|
||||
? MorphFeatureBox(
|
||||
morphFeature: feature.feature,
|
||||
allTags: controller.morphs
|
||||
.getDisplayTags(feature.feature)
|
||||
.map((tag) => tag.toLowerCase())
|
||||
.toSet(),
|
||||
onConstructZoom: onConstructZoom,
|
||||
)
|
||||
: const SizedBox.shrink();
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
|
@ -4,10 +4,10 @@ import 'package:flutter_gen/gen_l10n/l10n.dart';
|
|||
|
||||
import 'package:fluffychat/pangea/analytics_details_popup/analytics_details_popup_content.dart';
|
||||
import 'package:fluffychat/pangea/analytics_details_popup/morph_meaning_widget.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/construct_identifier.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/construct_level_enum.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/construct_use_model.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/text_loading_shimmer.dart';
|
||||
import 'package:fluffychat/pangea/constructs/construct_identifier.dart';
|
||||
import 'package:fluffychat/pangea/constructs/construct_level_enum.dart';
|
||||
import 'package:fluffychat/pangea/lemmas/construct_xp_widget.dart';
|
||||
import 'package:fluffychat/pangea/morphs/morph_feature_display.dart';
|
||||
import 'package:fluffychat/pangea/morphs/morph_meaning/morph_info_repo.dart';
|
||||
|
|
|
|||
|
|
@ -4,11 +4,10 @@ import 'package:flutter_gen/gen_l10n/l10n.dart';
|
|||
import 'package:material_symbols_icons/symbols.dart';
|
||||
|
||||
import 'package:fluffychat/pangea/analytics_details_popup/analytics_details_popup_content.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/construct_identifier.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/construct_level_enum.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/construct_use_model.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/construct_use_type_enum.dart';
|
||||
import 'package:fluffychat/pangea/common/widgets/customized_svg.dart';
|
||||
import 'package:fluffychat/pangea/constructs/construct_identifier.dart';
|
||||
import 'package:fluffychat/pangea/constructs/construct_level_enum.dart';
|
||||
import 'package:fluffychat/pangea/events/models/pangea_token_model.dart';
|
||||
import 'package:fluffychat/pangea/events/models/pangea_token_text_model.dart';
|
||||
import 'package:fluffychat/pangea/lemmas/lemma.dart';
|
||||
|
|
@ -178,16 +177,7 @@ class VocabDetailsView extends StatelessWidget {
|
|||
],
|
||||
),
|
||||
),
|
||||
xpIcon: CustomizedSvg(
|
||||
svgUrl: _construct.lemmaCategory.svgURL,
|
||||
colorReplacements: const {},
|
||||
errorIcon: Text(
|
||||
_construct.lemmaCategory.emoji,
|
||||
style: const TextStyle(
|
||||
fontSize: 20,
|
||||
),
|
||||
),
|
||||
),
|
||||
xpIcon: _construct.lemmaCategory.icon(12),
|
||||
constructId: constructId,
|
||||
);
|
||||
}
|
||||
|
|
@ -0,0 +1,84 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:fluffychat/config/app_config.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/construct_use_model.dart';
|
||||
import 'package:fluffychat/pangea/constructs/construct_level_enum.dart';
|
||||
import 'package:fluffychat/pangea/toolbar/utils/shrinkable_text.dart';
|
||||
|
||||
class VocabAnalyticsListTile extends StatefulWidget {
|
||||
const VocabAnalyticsListTile({
|
||||
super.key,
|
||||
required this.constructUse,
|
||||
required this.onTap,
|
||||
});
|
||||
|
||||
final void Function() onTap;
|
||||
final ConstructUses constructUse;
|
||||
|
||||
@override
|
||||
VocabAnalyticsListTileState createState() => VocabAnalyticsListTileState();
|
||||
}
|
||||
|
||||
class VocabAnalyticsListTileState extends State<VocabAnalyticsListTile> {
|
||||
bool _isHovered = false;
|
||||
|
||||
final double maxWidth = 100;
|
||||
final double padding = 8.0;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return MouseRegion(
|
||||
onEnter: (_) => setState(() => _isHovered = true),
|
||||
onExit: (_) => setState(() => _isHovered = false),
|
||||
child: InkWell(
|
||||
borderRadius: BorderRadius.circular(AppConfig.borderRadius),
|
||||
onTap: widget.onTap,
|
||||
child: Container(
|
||||
height: maxWidth,
|
||||
width: maxWidth,
|
||||
padding: EdgeInsets.all(padding),
|
||||
decoration: BoxDecoration(
|
||||
color: _isHovered
|
||||
? widget.constructUse.constructLevel.color.withAlpha(30)
|
||||
: Colors.transparent,
|
||||
borderRadius: BorderRadius.circular(AppConfig.borderRadius),
|
||||
),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Container(
|
||||
alignment: Alignment.center,
|
||||
height: (maxWidth - padding * 2) * 0.6,
|
||||
child: Opacity(
|
||||
opacity:
|
||||
widget.constructUse.id.userSetEmoji == null ? 0.2 : 1,
|
||||
child: widget.constructUse.id.userSetEmoji != null
|
||||
? Text(
|
||||
widget.constructUse.id.userSetEmoji!,
|
||||
style: const TextStyle(
|
||||
fontSize: 22,
|
||||
),
|
||||
)
|
||||
: widget.constructUse.constructLevel.icon(10),
|
||||
),
|
||||
),
|
||||
Container(
|
||||
alignment: Alignment.topCenter,
|
||||
padding: const EdgeInsets.only(top: 4),
|
||||
height: (maxWidth - padding * 2) * 0.4,
|
||||
child: ShrinkableText(
|
||||
text: widget.constructUse.lemma,
|
||||
maxWidth: maxWidth - padding * 2,
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
color: widget.constructUse.constructLevel.color,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,69 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:fluffychat/pangea/analytics_details_popup/vocab_analytics_list_tile.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/construct_type_enum.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/construct_use_model.dart';
|
||||
import 'package:fluffychat/pangea/constructs/construct_identifier.dart';
|
||||
import 'package:fluffychat/pangea/constructs/construct_level_enum.dart';
|
||||
import 'package:fluffychat/pangea/instructions/instructions_enum.dart';
|
||||
import 'package:fluffychat/pangea/instructions/instructions_inline_tooltip.dart';
|
||||
import 'package:fluffychat/widgets/matrix.dart';
|
||||
|
||||
/// Displays vocab analytics, sorted into categories
|
||||
/// (flowers, greens, and seeds) by points
|
||||
class VocabAnalyticsListView extends StatelessWidget {
|
||||
final void Function(ConstructIdentifier) onConstructZoom;
|
||||
|
||||
List<ConstructUses> get vocab => MatrixState
|
||||
.pangeaController.getAnalytics.constructListModel
|
||||
.constructList(type: ConstructTypeEnum.vocab)
|
||||
..sort((a, b) => a.lemma.toLowerCase().compareTo(b.lemma.toLowerCase()));
|
||||
|
||||
const VocabAnalyticsListView({
|
||||
super.key,
|
||||
required this.onConstructZoom,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return SingleChildScrollView(
|
||||
child: Column(
|
||||
children: [
|
||||
const InstructionsInlineTooltip(
|
||||
instructionsEnum: InstructionsEnum.analyticsVocabList,
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
spacing: 50,
|
||||
children: ConstructLevelEnum.values.reversed
|
||||
.map((constructLevelCategory) {
|
||||
final int count = vocab
|
||||
.where((e) => e.lemmaCategory == constructLevelCategory)
|
||||
.length;
|
||||
|
||||
return Badge(
|
||||
label: Text(count.toString()),
|
||||
child: constructLevelCategory.icon(24),
|
||||
);
|
||||
}).toList(),
|
||||
),
|
||||
),
|
||||
Wrap(
|
||||
crossAxisAlignment: WrapCrossAlignment.center,
|
||||
runAlignment: WrapAlignment.start,
|
||||
children: vocab
|
||||
.map(
|
||||
(vocab) => VocabAnalyticsListTile(
|
||||
onTap: () => onConstructZoom(vocab.id),
|
||||
constructUse: vocab,
|
||||
),
|
||||
)
|
||||
.toList(),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,182 +0,0 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:flutter_gen/gen_l10n/l10n.dart';
|
||||
import 'package:matrix/matrix.dart';
|
||||
|
||||
import 'package:fluffychat/pangea/analytics_misc/analytics_constants.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/construct_identifier.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/construct_level_enum.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/construct_type_enum.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/construct_use_model.dart';
|
||||
import 'package:fluffychat/pangea/common/widgets/customized_svg.dart';
|
||||
import 'package:fluffychat/pangea/morphs/get_grammar_copy.dart';
|
||||
import 'package:fluffychat/widgets/matrix.dart';
|
||||
|
||||
/// Displays vocab analytics, sorted into categories
|
||||
/// (flowers, greens, and seeds) by points
|
||||
class VocabAnalyticsView extends StatelessWidget {
|
||||
final void Function(ConstructIdentifier) onConstructZoom;
|
||||
|
||||
const VocabAnalyticsView({
|
||||
super.key,
|
||||
required this.onConstructZoom,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final lemmas = MatrixState.pangeaController.getAnalytics.constructListModel
|
||||
.constructList(type: ConstructTypeEnum.vocab)
|
||||
..sort((a, b) => a.lemma.toLowerCase().compareTo(b.lemma.toLowerCase()));
|
||||
|
||||
final flowerLemmas = <VocabChip>[];
|
||||
final greenLemmas = <VocabChip>[];
|
||||
final seedLemmas = <VocabChip>[];
|
||||
for (int i = 0; i < lemmas.length; i++) {
|
||||
final construct = lemmas[i];
|
||||
if (construct.lemma.isEmpty) continue;
|
||||
final int points = construct.points;
|
||||
String? displayText;
|
||||
// Check if previous or next entry has same lemma as this entry
|
||||
if ((i > 0 && lemmas[i - 1].lemma.equals(construct.lemma)) ||
|
||||
(i < lemmas.length - 1 &&
|
||||
lemmas[i + 1].lemma.equals(construct.lemma))) {
|
||||
final pos = getGrammarCopy(
|
||||
category: "pos",
|
||||
lemma: construct.category,
|
||||
context: context,
|
||||
) ??
|
||||
construct.category;
|
||||
displayText = "${construct.lemma} (${pos.toLowerCase()})";
|
||||
}
|
||||
final lemma = VocabChip(
|
||||
construct: construct,
|
||||
displayText: displayText,
|
||||
);
|
||||
// Sort lemmas into categories
|
||||
if (points < AnalyticsConstants.xpForGreens) {
|
||||
seedLemmas.add(lemma);
|
||||
} else if (points >= AnalyticsConstants.xpForFlower) {
|
||||
flowerLemmas.add(lemma);
|
||||
} else {
|
||||
greenLemmas.add(lemma);
|
||||
}
|
||||
}
|
||||
|
||||
final flowers = LemmaListSection(
|
||||
type: ConstructLevelEnum.flowers,
|
||||
lemmas: flowerLemmas,
|
||||
onTap: onConstructZoom,
|
||||
);
|
||||
final greens = LemmaListSection(
|
||||
type: ConstructLevelEnum.greens,
|
||||
lemmas: greenLemmas,
|
||||
onTap: onConstructZoom,
|
||||
);
|
||||
final seeds = LemmaListSection(
|
||||
type: ConstructLevelEnum.seeds,
|
||||
lemmas: seedLemmas,
|
||||
onTap: onConstructZoom,
|
||||
);
|
||||
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 20),
|
||||
child: ListView(
|
||||
key: const PageStorageKey<String>('vocab-analytics'),
|
||||
children: [flowers, greens, seeds],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class VocabChip {
|
||||
final ConstructUses construct;
|
||||
final String? displayText;
|
||||
|
||||
VocabChip({
|
||||
required this.construct,
|
||||
this.displayText,
|
||||
});
|
||||
}
|
||||
|
||||
class LemmaListSection extends StatelessWidget {
|
||||
final ConstructLevelEnum type;
|
||||
final List<VocabChip> lemmas;
|
||||
final Function(ConstructIdentifier) onTap;
|
||||
|
||||
const LemmaListSection({
|
||||
super.key,
|
||||
required this.type,
|
||||
required this.lemmas,
|
||||
required this.onTap,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final theme = Theme.of(context);
|
||||
final fontColor =
|
||||
theme.brightness == Brightness.dark ? type.color : type.darkColor;
|
||||
return Container(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
margin: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(16.0),
|
||||
border: Border.all(color: type.color, width: 2),
|
||||
),
|
||||
child: Column(
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
CustomizedSvg(
|
||||
svgUrl: type.svgURL,
|
||||
colorReplacements: const {},
|
||||
errorIcon: Text(type.emoji),
|
||||
),
|
||||
],
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 8),
|
||||
child: lemmas.isEmpty
|
||||
? Text(
|
||||
L10n.of(context).noLemmasFound(type.xpNeeded),
|
||||
style: TextStyle(
|
||||
color: fontColor,
|
||||
fontStyle: FontStyle.italic,
|
||||
),
|
||||
)
|
||||
: Wrap(
|
||||
spacing: 0,
|
||||
runSpacing: 0,
|
||||
children: lemmas.mapIndexed((index, lemma) {
|
||||
return MouseRegion(
|
||||
cursor: SystemMouseCursors.click,
|
||||
child: GestureDetector(
|
||||
onTap: () => onTap(lemma.construct.id),
|
||||
child: Text(
|
||||
"${lemma.displayText ?? lemma.construct.lemma}${index < lemmas.length - 1 ? ', ' : ''}",
|
||||
style: TextStyle(
|
||||
shadows: [
|
||||
Shadow(
|
||||
color: fontColor,
|
||||
offset: const Offset(0, -2.5),
|
||||
),
|
||||
],
|
||||
color: Colors.transparent,
|
||||
decoration: TextDecoration.underline,
|
||||
decorationStyle: TextDecorationStyle.dotted,
|
||||
decorationColor: fontColor,
|
||||
decorationThickness: 1,
|
||||
fontSize: theme.textTheme.bodyLarge?.fontSize,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}).toList(),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -5,11 +5,11 @@ import 'package:flutter/material.dart';
|
|||
import 'package:collection/collection.dart';
|
||||
|
||||
import 'package:fluffychat/pangea/analytics_misc/analytics_constants.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/construct_identifier.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/construct_type_enum.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/construct_use_model.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/constructs_model.dart';
|
||||
import 'package:fluffychat/pangea/common/utils/error_handler.dart';
|
||||
import 'package:fluffychat/pangea/constructs/construct_identifier.dart';
|
||||
import 'package:fluffychat/pangea/morphs/get_grammar_copy.dart';
|
||||
|
||||
/// A wrapper around a list of [OneConstructUse]s, used to simplify
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
import 'package:fluffychat/pangea/analytics_misc/analytics_constants.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/construct_identifier.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/construct_level_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/constructs/construct_identifier.dart';
|
||||
import 'package:fluffychat/pangea/constructs/construct_level_enum.dart';
|
||||
|
||||
/// One lemma and a list of construct uses for that lemma
|
||||
class ConstructUses {
|
||||
|
|
|
|||
|
|
@ -4,9 +4,9 @@ import 'package:flutter/foundation.dart';
|
|||
|
||||
import 'package:matrix/matrix.dart';
|
||||
|
||||
import 'package:fluffychat/pangea/analytics_misc/construct_identifier.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/construct_use_type_enum.dart';
|
||||
import 'package:fluffychat/pangea/common/utils/error_handler.dart';
|
||||
import 'package:fluffychat/pangea/constructs/construct_identifier.dart';
|
||||
import 'package:fluffychat/pangea/morphs/default_morph_mapping.dart';
|
||||
import 'package:fluffychat/pangea/morphs/morph_models.dart';
|
||||
import 'construct_type_enum.dart';
|
||||
|
|
@ -97,7 +97,7 @@ class OneConstructUse {
|
|||
this.id,
|
||||
}) : _category = category ?? "other";
|
||||
|
||||
String get chatId => metadata.roomId;
|
||||
String? get chatId => metadata.roomId;
|
||||
String get msgId => metadata.eventId!;
|
||||
DateTime get timeStamp => metadata.timeStamp;
|
||||
|
||||
|
|
@ -177,7 +177,8 @@ class OneConstructUse {
|
|||
}
|
||||
|
||||
Room? getRoom(Client client) {
|
||||
return client.getRoomById(metadata.roomId);
|
||||
if (metadata.roomId == null) return null;
|
||||
return client.getRoomById(metadata.roomId!);
|
||||
}
|
||||
|
||||
Future<Event?> getEvent(Client client) async {
|
||||
|
|
@ -197,7 +198,7 @@ class OneConstructUse {
|
|||
|
||||
class ConstructUseMetaData {
|
||||
String? eventId;
|
||||
String roomId;
|
||||
String? roomId;
|
||||
DateTime timeStamp;
|
||||
|
||||
ConstructUseMetaData({
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import 'package:flutter/foundation.dart';
|
||||
|
||||
import 'package:fluffychat/pangea/analytics_misc/construct_identifier.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/get_analytics_controller.dart';
|
||||
import 'package:fluffychat/pangea/constructs/construct_identifier.dart';
|
||||
import 'package:fluffychat/pangea/events/event_wrappers/pangea_message_event.dart';
|
||||
import 'package:fluffychat/pangea/events/models/pangea_token_model.dart';
|
||||
import 'package:fluffychat/pangea/toolbar/enums/activity_type_enum.dart';
|
||||
|
|
|
|||
|
|
@ -119,13 +119,16 @@ class PutAnalyticsController extends BaseController<AnalyticsStream> {
|
|||
/// the data locally and reset the update timer
|
||||
/// Decide whether to update the analytics room
|
||||
void _onNewAnalyticsData(AnalyticsStream data) {
|
||||
final List<OneConstructUse> constructs = _getDraftUses(data.roomId);
|
||||
final String? eventID = data.eventId;
|
||||
final String? roomID = data.roomId;
|
||||
|
||||
List<OneConstructUse> constructs = [];
|
||||
if (roomID != null) {
|
||||
constructs = _getDraftUses(roomID);
|
||||
}
|
||||
|
||||
constructs.addAll(data.constructs);
|
||||
|
||||
final String eventID = data.eventId;
|
||||
final String roomID = data.roomId;
|
||||
|
||||
if (kDebugMode) {
|
||||
for (final use in constructs) {
|
||||
debugPrint(
|
||||
|
|
@ -138,7 +141,7 @@ class PutAnalyticsController extends BaseController<AnalyticsStream> {
|
|||
|
||||
_addLocalMessage(eventID, constructs).then(
|
||||
(_) {
|
||||
_clearDraftUses(roomID);
|
||||
if (roomID != null) _clearDraftUses(roomID);
|
||||
_decideWhetherToUpdateAnalyticsRoom(
|
||||
level,
|
||||
data.origin,
|
||||
|
|
@ -245,7 +248,7 @@ class PutAnalyticsController extends BaseController<AnalyticsStream> {
|
|||
/// Add a list of construct uses for a new message to the local
|
||||
/// cache of recently sent messages
|
||||
Future<void> _addLocalMessage(
|
||||
String cacheKey,
|
||||
String? cacheKey,
|
||||
List<OneConstructUse> constructs,
|
||||
) async {
|
||||
try {
|
||||
|
|
@ -254,7 +257,7 @@ class PutAnalyticsController extends BaseController<AnalyticsStream> {
|
|||
|
||||
// if this is not a draft message, add the eventId to the metadata
|
||||
// if it's missing (it will be missing for draft constructs)
|
||||
if (!cacheKey.startsWith('draft')) {
|
||||
if (cacheKey != null && !cacheKey.startsWith('draft')) {
|
||||
constructs = constructs.map((construct) {
|
||||
if (construct.metadata.eventId != null) return construct;
|
||||
construct.metadata.eventId = cacheKey;
|
||||
|
|
@ -262,6 +265,7 @@ class PutAnalyticsController extends BaseController<AnalyticsStream> {
|
|||
}).toList();
|
||||
}
|
||||
|
||||
cacheKey ??= Object.hashAll(constructs).toString();
|
||||
currentCache[cacheKey] = constructs;
|
||||
|
||||
await _setMessagesSinceUpdate(currentCache);
|
||||
|
|
@ -425,8 +429,8 @@ class PutAnalyticsController extends BaseController<AnalyticsStream> {
|
|||
}
|
||||
|
||||
class AnalyticsStream {
|
||||
final String eventId;
|
||||
final String roomId;
|
||||
final String? eventId;
|
||||
final String? roomId;
|
||||
final AnalyticsUpdateOrigin? origin;
|
||||
|
||||
final List<OneConstructUse> constructs;
|
||||
|
|
|
|||
|
|
@ -72,6 +72,8 @@ class PApiUrls {
|
|||
static String activityModeList = "${PApiUrls.choreoEndpoint}/modes";
|
||||
static String objectiveList = "${PApiUrls.choreoEndpoint}/objectives";
|
||||
static String topicList = "${PApiUrls.choreoEndpoint}/topics";
|
||||
static String activityPlanSearch =
|
||||
"${PApiUrls.choreoEndpoint}/activity_plan/search";
|
||||
|
||||
static String morphFeaturesAndTags = "${PApiUrls.choreoEndpoint}/morphs";
|
||||
|
||||
|
|
|
|||
|
|
@ -16,12 +16,24 @@ class CustomizedSvg extends StatelessWidget {
|
|||
/// Icon to show in case of error
|
||||
final Widget errorIcon;
|
||||
|
||||
/// Width of the SVG
|
||||
/// Default is 24
|
||||
/// If you want to keep the aspect ratio, set only the height
|
||||
final double? width;
|
||||
|
||||
/// Height of the SVG
|
||||
/// Default is 24
|
||||
/// If you want to keep the aspect ratio, set only the width
|
||||
final double? height;
|
||||
|
||||
static final GetStorage _svgStorage = GetStorage('svg_cache');
|
||||
const CustomizedSvg({
|
||||
super.key,
|
||||
required this.svgUrl,
|
||||
required this.colorReplacements,
|
||||
this.errorIcon = const Icon(Icons.error_outline),
|
||||
this.width = 24,
|
||||
this.height = 24,
|
||||
});
|
||||
|
||||
Future<String?> _fetchSvg() async {
|
||||
|
|
@ -110,7 +122,11 @@ class CustomizedSvg extends StatelessWidget {
|
|||
} else if (snapshot.hasError || snapshot.data == null) {
|
||||
return errorIcon;
|
||||
} else if (snapshot.hasData) {
|
||||
return SvgPicture.string(snapshot.data!);
|
||||
return SvgPicture.string(
|
||||
snapshot.data!,
|
||||
width: width,
|
||||
height: height,
|
||||
);
|
||||
} else {
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,6 +12,9 @@ import 'package:fluffychat/pangea/analytics_misc/construct_use_model.dart';
|
|||
import 'package:fluffychat/pangea/common/constants/model_keys.dart';
|
||||
import 'package:fluffychat/pangea/common/utils/error_handler.dart';
|
||||
import 'package:fluffychat/pangea/events/constants/pangea_event_types.dart';
|
||||
import 'package:fluffychat/pangea/learning_settings/constants/language_constants.dart';
|
||||
import 'package:fluffychat/pangea/lemmas/lemma_info_repo.dart';
|
||||
import 'package:fluffychat/pangea/lemmas/lemma_info_request.dart';
|
||||
import 'package:fluffychat/widgets/matrix.dart';
|
||||
|
||||
class ConstructIdentifier {
|
||||
|
|
@ -126,4 +129,51 @@ class ConstructIdentifier {
|
|||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/// [setEmoji] sets the emoji for the lemma
|
||||
/// NOTE: assumes that the language of the lemma is the same as the user's current l2
|
||||
Future<void> setEmoji(String emoji) async {
|
||||
final analyticsRoom =
|
||||
MatrixState.pangeaController.matrixState.client.analyticsRoomLocal();
|
||||
if (analyticsRoom == null) return;
|
||||
try {
|
||||
final client = MatrixState.pangeaController.matrixState.client;
|
||||
final syncFuture = client.onRoomState.stream.firstWhere((event) {
|
||||
return event.roomId == analyticsRoom.id &&
|
||||
event.state.type == PangeaEventTypes.userChosenEmoji;
|
||||
});
|
||||
client.setRoomStateWithKey(
|
||||
analyticsRoom.id,
|
||||
PangeaEventTypes.userChosenEmoji,
|
||||
string,
|
||||
{ModelKey.emoji: emoji},
|
||||
);
|
||||
await syncFuture;
|
||||
} catch (err, s) {
|
||||
debugger(when: kDebugMode);
|
||||
ErrorHandler.logError(
|
||||
e: err,
|
||||
data: {
|
||||
"construct": string,
|
||||
"emoji": emoji,
|
||||
},
|
||||
s: s,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// [getEmojiChoices] gets the emoji choices for the lemma
|
||||
// assumes that the language of the lemma is the same as the user's current l2
|
||||
Future<List<String>> getEmojiChoices() => LemmaInfoRepo.get(
|
||||
LemmaInfoRequest(
|
||||
lemma: lemma,
|
||||
partOfSpeech: category,
|
||||
lemmaLang: MatrixState
|
||||
.pangeaController.languageController.userL2?.langCode ??
|
||||
LanguageKeys.unknownLanguage,
|
||||
userL1: MatrixState
|
||||
.pangeaController.languageController.userL1?.langCode ??
|
||||
LanguageKeys.defaultLanguage,
|
||||
),
|
||||
).then((onValue) => onValue.emoji);
|
||||
}
|
||||
|
|
@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
|
|||
|
||||
import 'package:fluffychat/config/app_config.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/analytics_constants.dart';
|
||||
import 'package:fluffychat/pangea/common/widgets/customized_svg.dart';
|
||||
|
||||
enum ConstructLevelEnum {
|
||||
flowers,
|
||||
|
|
@ -79,4 +80,17 @@ extension ConstructLevelEnumExt on ConstructLevelEnum {
|
|||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
Widget icon([double? size]) => CustomizedSvg(
|
||||
svgUrl: svgURL,
|
||||
colorReplacements: const {},
|
||||
errorIcon: Text(
|
||||
emoji,
|
||||
style: TextStyle(
|
||||
fontSize: size ?? 24,
|
||||
),
|
||||
),
|
||||
width: size,
|
||||
height: size,
|
||||
);
|
||||
}
|
||||
|
|
@ -5,19 +5,14 @@ import 'package:flutter/foundation.dart';
|
|||
import 'package:collection/collection.dart';
|
||||
|
||||
import 'package:fluffychat/pangea/analytics_misc/analytics_constants.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/client_analytics_extension.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/construct_identifier.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/construct_level_enum.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/construct_type_enum.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/construct_use_model.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/common/utils/error_handler.dart';
|
||||
import 'package:fluffychat/pangea/events/constants/pangea_event_types.dart';
|
||||
import 'package:fluffychat/pangea/constructs/construct_identifier.dart';
|
||||
import 'package:fluffychat/pangea/constructs/construct_level_enum.dart';
|
||||
import 'package:fluffychat/pangea/events/models/pangea_token_text_model.dart';
|
||||
import 'package:fluffychat/pangea/learning_settings/constants/language_constants.dart';
|
||||
import 'package:fluffychat/pangea/lemmas/lemma_info_repo.dart';
|
||||
import 'package:fluffychat/pangea/lemmas/lemma_info_request.dart';
|
||||
import 'package:fluffychat/pangea/morphs/morph_repo.dart';
|
||||
import 'package:fluffychat/pangea/toolbar/enums/activity_type_enum.dart';
|
||||
import 'package:fluffychat/pangea/toolbar/enums/message_mode_enum.dart';
|
||||
|
|
@ -543,18 +538,7 @@ class PangeaToken {
|
|||
.cast<ConstructUses>()
|
||||
.toList();
|
||||
|
||||
Future<List<String>> getEmojiChoices() => LemmaInfoRepo.get(
|
||||
LemmaInfoRequest(
|
||||
lemma: lemma.text,
|
||||
partOfSpeech: pos,
|
||||
lemmaLang: MatrixState
|
||||
.pangeaController.languageController.userL2?.langCode ??
|
||||
LanguageKeys.unknownLanguage,
|
||||
userL1: MatrixState
|
||||
.pangeaController.languageController.userL1?.langCode ??
|
||||
LanguageKeys.defaultLanguage,
|
||||
),
|
||||
).then((onValue) => onValue.emoji);
|
||||
Future<List<String>> getEmojiChoices() => vocabConstructID.getEmojiChoices();
|
||||
|
||||
ConstructIdentifier get vocabConstructID => ConstructIdentifier(
|
||||
lemma: lemma.text,
|
||||
|
|
@ -562,37 +546,7 @@ class PangeaToken {
|
|||
category: pos,
|
||||
);
|
||||
|
||||
/// [setEmoji] sets the emoji for the lemma
|
||||
/// NOTE: assumes that the language of the lemma is the same as the user's current l2
|
||||
Future<void> setEmoji(String emoji) async {
|
||||
final analyticsRoom =
|
||||
MatrixState.pangeaController.matrixState.client.analyticsRoomLocal();
|
||||
if (analyticsRoom == null) return;
|
||||
try {
|
||||
final client = MatrixState.pangeaController.matrixState.client;
|
||||
final syncFuture = client.onRoomState.stream.firstWhere((event) {
|
||||
return event.roomId == analyticsRoom.id &&
|
||||
event.state.type == PangeaEventTypes.userChosenEmoji;
|
||||
});
|
||||
client.setRoomStateWithKey(
|
||||
analyticsRoom.id,
|
||||
PangeaEventTypes.userChosenEmoji,
|
||||
vocabConstructID.string,
|
||||
{ModelKey.emoji: emoji},
|
||||
);
|
||||
await syncFuture;
|
||||
} catch (err, s) {
|
||||
debugger(when: kDebugMode);
|
||||
ErrorHandler.logError(
|
||||
e: err,
|
||||
data: {
|
||||
"construct": vocabConstructID.string,
|
||||
"emoji": emoji,
|
||||
},
|
||||
s: s,
|
||||
);
|
||||
}
|
||||
}
|
||||
Future<void> setEmoji(String emoji) => vocabConstructID.setEmoji(emoji);
|
||||
|
||||
/// [getEmoji] gets the emoji for the lemma
|
||||
/// NOTE: assumes that the language of the lemma is the same as the user's current l2
|
||||
|
|
|
|||
|
|
@ -24,6 +24,8 @@ enum InstructionsEnum {
|
|||
activityPlannerOverview,
|
||||
ttsDisabled,
|
||||
chooseEmoji,
|
||||
analyticsVocabList,
|
||||
morphAnalyticsList,
|
||||
}
|
||||
|
||||
extension InstructionsEnumExtension on InstructionsEnum {
|
||||
|
|
@ -50,6 +52,8 @@ extension InstructionsEnumExtension on InstructionsEnum {
|
|||
case InstructionsEnum.clickBestOption:
|
||||
case InstructionsEnum.completeActivitiesToUnlock:
|
||||
case InstructionsEnum.lemmaMeaning:
|
||||
case InstructionsEnum.analyticsVocabList:
|
||||
case InstructionsEnum.morphAnalyticsList:
|
||||
ErrorHandler.logError(
|
||||
e: Exception("No title for this instruction"),
|
||||
m: 'InstructionsEnumExtension.title',
|
||||
|
|
@ -96,6 +100,10 @@ extension InstructionsEnumExtension on InstructionsEnum {
|
|||
return l10n.chooseEmojiInstructionsBody;
|
||||
case InstructionsEnum.ttsDisabled:
|
||||
return l10n.ttsDisabledBody;
|
||||
case InstructionsEnum.analyticsVocabList:
|
||||
return l10n.analyticsVocabListBody;
|
||||
case InstructionsEnum.morphAnalyticsList:
|
||||
return l10n.morphAnalyticsListBody;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -69,7 +69,7 @@ class InstructionsInlineTooltipState extends State<InstructionsInlineTooltip>
|
|||
child: DecoratedBox(
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(AppConfig.borderRadius),
|
||||
color: Theme.of(context).colorScheme.primary.withAlpha(20),
|
||||
color: Theme.of(context).colorScheme.primary.withAlpha(5),
|
||||
),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 8),
|
||||
|
|
|
|||
|
|
@ -2,11 +2,10 @@ import 'dart:async';
|
|||
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:fluffychat/pangea/analytics_misc/construct_identifier.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/construct_level_enum.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/construct_use_model.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/get_analytics_controller.dart';
|
||||
import 'package:fluffychat/pangea/common/widgets/customized_svg.dart';
|
||||
import 'package:fluffychat/pangea/constructs/construct_identifier.dart';
|
||||
import 'package:fluffychat/pangea/constructs/construct_level_enum.dart';
|
||||
import 'package:fluffychat/widgets/matrix.dart';
|
||||
|
||||
/// display the construct xp widget
|
||||
|
|
@ -90,17 +89,7 @@ class ConstructXpWidgetState extends State<ConstructXpWidget>
|
|||
Stream<AnalyticsStreamUpdate> get stream =>
|
||||
MatrixState.pangeaController.getAnalytics.analyticsStream.stream;
|
||||
|
||||
Widget get svg => CustomizedSvg(
|
||||
svgUrl:
|
||||
constructLemmaCategory?.svgURL ?? ConstructLevelEnum.seeds.svgURL,
|
||||
colorReplacements: const {},
|
||||
errorIcon: Text(
|
||||
constructLemmaCategory?.emoji ?? ConstructLevelEnum.seeds.svgURL,
|
||||
style: const TextStyle(
|
||||
fontSize: 20,
|
||||
),
|
||||
),
|
||||
);
|
||||
Widget get svg => constructLemmaCategory?.icon() ?? const SizedBox();
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
|
|
|
|||
|
|
@ -2,9 +2,9 @@ import 'package:flutter/material.dart';
|
|||
|
||||
import 'package:material_symbols_icons/symbols.dart';
|
||||
|
||||
import 'package:fluffychat/pangea/analytics_misc/construct_identifier.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/constructs/construct_identifier.dart';
|
||||
|
||||
enum ActivityTypeEnum {
|
||||
wordMeaning,
|
||||
|
|
|
|||
|
|
@ -7,8 +7,8 @@ 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_identifier.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/pangea_token_model.dart';
|
||||
import 'package:fluffychat/pangea/morphs/morph_categories_enum.dart';
|
||||
import 'package:fluffychat/pangea/toolbar/enums/activity_display_instructions_enum.dart';
|
||||
|
|
|
|||
|
|
@ -5,9 +5,9 @@ import 'package:matrix/matrix.dart';
|
|||
|
||||
import 'package:fluffychat/config/app_emojis.dart';
|
||||
import 'package:fluffychat/pages/chat/chat.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/construct_level_enum.dart';
|
||||
import 'package:fluffychat/pangea/common/widgets/customized_svg.dart';
|
||||
import 'package:fluffychat/pangea/constructs/construct_level_enum.dart';
|
||||
import 'package:fluffychat/pangea/events/models/pangea_token_model.dart';
|
||||
import 'package:fluffychat/pangea/toolbar/enums/activity_type_enum.dart';
|
||||
import 'package:fluffychat/pangea/toolbar/reading_assistance_input_row/message_emoji_choice_item.dart';
|
||||
import 'package:fluffychat/pangea/toolbar/widgets/message_selection_overlay.dart';
|
||||
import 'package:fluffychat/widgets/future_loading_dialog.dart';
|
||||
|
|
@ -82,13 +82,18 @@ class MessageEmojiChoice extends StatelessWidget {
|
|||
isSelected: false,
|
||||
onDoubleTap: () => onDoubleTapOrLongPress(context, emoji),
|
||||
onLongPress: () => onDoubleTapOrLongPress(context, emoji),
|
||||
token: null,
|
||||
greenHighlight: false,
|
||||
),
|
||||
)
|
||||
.toList();
|
||||
|
||||
List<Widget> perTokenEmoji(BuildContext context) =>
|
||||
tokens!.where((token) => token.lemma.saveVocab).map((token) {
|
||||
final bool greenHighlight = token.shouldDoActivity(
|
||||
a: ActivityTypeEnum.wordMeaning,
|
||||
feature: null,
|
||||
tag: null,
|
||||
);
|
||||
if (!token.lemma.saveVocab) {
|
||||
return MessageEmojiChoiceItem(
|
||||
content: token.text.content,
|
||||
|
|
@ -96,7 +101,7 @@ class MessageEmojiChoice extends StatelessWidget {
|
|||
isSelected: overlayController.isTokenSelected(token),
|
||||
onDoubleTap: null,
|
||||
onLongPress: null,
|
||||
token: token,
|
||||
greenHighlight: greenHighlight,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -104,18 +109,14 @@ class MessageEmojiChoice extends StatelessWidget {
|
|||
|
||||
if (emoji == null) {
|
||||
return MessageEmojiChoiceItem(
|
||||
topContent: CustomizedSvg(
|
||||
svgUrl: token.vocabConstruct.constructLevel.svgURL,
|
||||
colorReplacements: const {},
|
||||
errorIcon: Text(token.xpEmoji),
|
||||
),
|
||||
topContent: token.vocabConstruct.constructLevel.icon(),
|
||||
content: token.text.content,
|
||||
onTap: () => overlayController.onClickOverlayMessageToken(token),
|
||||
onDoubleTap: null,
|
||||
onLongPress: null,
|
||||
isSelected: overlayController.isTokenSelected(token),
|
||||
contentOpacity: 0.1,
|
||||
token: token,
|
||||
greenHighlight: greenHighlight,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -129,7 +130,7 @@ class MessageEmojiChoice extends StatelessWidget {
|
|||
onDoubleTap: () => onDoubleTapOrLongPress(context, emoji),
|
||||
onLongPress: () => onDoubleTapOrLongPress(context, emoji),
|
||||
isSelected: overlayController.isTokenSelected(token),
|
||||
token: token,
|
||||
greenHighlight: greenHighlight,
|
||||
);
|
||||
}).toList();
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,6 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:fluffychat/config/app_config.dart';
|
||||
import 'package:fluffychat/pangea/events/models/pangea_token_model.dart';
|
||||
import 'package:fluffychat/pangea/toolbar/enums/activity_type_enum.dart';
|
||||
|
||||
class MessageEmojiChoiceItem extends StatefulWidget {
|
||||
const MessageEmojiChoiceItem({
|
||||
|
|
@ -15,7 +13,7 @@ class MessageEmojiChoiceItem extends StatefulWidget {
|
|||
this.onLongPress,
|
||||
required this.isSelected,
|
||||
this.contentOpacity = 1.0,
|
||||
required this.token,
|
||||
required this.greenHighlight,
|
||||
});
|
||||
|
||||
final Widget? topContent;
|
||||
|
|
@ -26,7 +24,7 @@ class MessageEmojiChoiceItem extends StatefulWidget {
|
|||
final bool isSelected;
|
||||
final double textSize;
|
||||
final double contentOpacity;
|
||||
final PangeaToken? token;
|
||||
final bool greenHighlight;
|
||||
|
||||
@override
|
||||
MessageEmojiChoiceItemState createState() => MessageEmojiChoiceItemState();
|
||||
|
|
@ -54,12 +52,7 @@ class MessageEmojiChoiceItemState extends State<MessageEmojiChoiceItem> {
|
|||
? AppConfig.primaryColor.withAlpha((0.2 * 255).toInt())
|
||||
: _isHovered
|
||||
? AppConfig.primaryColor.withAlpha((0.1 * 255).toInt())
|
||||
: widget.token?.shouldDoActivity(
|
||||
a: ActivityTypeEnum.wordMeaning,
|
||||
feature: null,
|
||||
tag: null,
|
||||
) ??
|
||||
false
|
||||
: widget.greenHighlight
|
||||
? AppConfig.success.withAlpha((0.1 * 255).toInt())
|
||||
: Colors.transparent,
|
||||
borderRadius: BorderRadius.circular(AppConfig.borderRadius),
|
||||
|
|
|
|||
|
|
@ -87,8 +87,10 @@ class ReadingAssistanceInputBar extends StatelessWidget {
|
|||
|
||||
case MessageMode.wordEmoji:
|
||||
return WordEmojiChoice(
|
||||
overlayController: overlayController,
|
||||
token: overlayController.selectedToken!,
|
||||
form: overlayController.selectedToken!.text.content,
|
||||
onEmojiChosen: () =>
|
||||
overlayController.onActivityFinish(ActivityTypeEnum.emoji),
|
||||
constructID: overlayController.selectedToken!.vocabConstructID,
|
||||
);
|
||||
|
||||
case MessageMode.wordMeaning:
|
||||
|
|
|
|||
|
|
@ -9,22 +9,26 @@ import 'package:fluffychat/pangea/analytics_misc/constructs_model.dart';
|
|||
import 'package:fluffychat/pangea/analytics_misc/put_analytics_controller.dart';
|
||||
import 'package:fluffychat/pangea/choreographer/widgets/choice_array.dart';
|
||||
import 'package:fluffychat/pangea/choreographer/widgets/it_shimmer.dart';
|
||||
import 'package:fluffychat/pangea/events/models/pangea_token_model.dart';
|
||||
import 'package:fluffychat/pangea/constructs/construct_identifier.dart';
|
||||
import 'package:fluffychat/pangea/instructions/instructions_enum.dart';
|
||||
import 'package:fluffychat/pangea/instructions/instructions_inline_tooltip.dart';
|
||||
import 'package:fluffychat/pangea/toolbar/enums/activity_type_enum.dart';
|
||||
import 'package:fluffychat/pangea/toolbar/widgets/message_selection_overlay.dart';
|
||||
import 'package:fluffychat/widgets/matrix.dart';
|
||||
|
||||
class WordEmojiChoice extends StatefulWidget {
|
||||
const WordEmojiChoice({
|
||||
super.key,
|
||||
required this.overlayController,
|
||||
required this.token,
|
||||
required this.constructID,
|
||||
required this.onEmojiChosen,
|
||||
required this.form,
|
||||
this.roomId,
|
||||
this.eventId,
|
||||
});
|
||||
|
||||
final MessageOverlayController overlayController;
|
||||
final PangeaToken token;
|
||||
final ConstructIdentifier constructID;
|
||||
final String form;
|
||||
final String? roomId;
|
||||
final String? eventId;
|
||||
final void Function() onEmojiChosen;
|
||||
|
||||
@override
|
||||
WordEmojiChoiceState createState() => WordEmojiChoiceState();
|
||||
|
|
@ -36,7 +40,7 @@ class WordEmojiChoiceState extends State<WordEmojiChoice> {
|
|||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
localSelected = widget.token.getEmoji();
|
||||
localSelected = widget.constructID.userSetEmoji;
|
||||
}
|
||||
|
||||
Future<void> onChoice(BuildContext context, emoji) async {
|
||||
|
|
@ -44,33 +48,33 @@ class WordEmojiChoiceState extends State<WordEmojiChoice> {
|
|||
|
||||
MatrixState.pangeaController.putAnalytics.setState(
|
||||
AnalyticsStream(
|
||||
eventId: widget.overlayController.pangeaMessageEvent!.eventId,
|
||||
roomId: widget.overlayController.pangeaMessageEvent!.room.id,
|
||||
eventId: widget.eventId,
|
||||
roomId: widget.roomId,
|
||||
constructs: [
|
||||
OneConstructUse(
|
||||
useType: ConstructUseTypeEnum.em,
|
||||
lemma: widget.token.text.content,
|
||||
lemma: widget.constructID.lemma,
|
||||
constructType: ConstructTypeEnum.vocab,
|
||||
metadata: ConstructUseMetaData(
|
||||
roomId: widget.overlayController.pangeaMessageEvent!.room.id,
|
||||
roomId: widget.roomId,
|
||||
timeStamp: DateTime.now(),
|
||||
eventId: widget.overlayController.pangeaMessageEvent!.eventId,
|
||||
eventId: widget.eventId,
|
||||
),
|
||||
category: widget.token.pos,
|
||||
form: widget.token.text.content,
|
||||
category: widget.constructID.category,
|
||||
form: widget.form,
|
||||
),
|
||||
],
|
||||
origin: AnalyticsUpdateOrigin.wordZoom,
|
||||
),
|
||||
);
|
||||
|
||||
await widget.token.setEmoji(emoji);
|
||||
await widget.constructID.setEmoji(emoji);
|
||||
|
||||
await Future.delayed(
|
||||
const Duration(milliseconds: choiceArrayAnimationDuration),
|
||||
);
|
||||
|
||||
widget.overlayController.onActivityFinish(ActivityTypeEnum.emoji);
|
||||
widget.onEmojiChosen();
|
||||
|
||||
setState(() => {});
|
||||
}
|
||||
|
|
@ -83,7 +87,7 @@ class WordEmojiChoiceState extends State<WordEmojiChoice> {
|
|||
mainAxisSize: MainAxisSize.max,
|
||||
children: [
|
||||
FutureBuilder(
|
||||
future: widget.token.getEmojiChoices(),
|
||||
future: widget.constructID.getEmojiChoices(),
|
||||
builder: (context, snapshot) {
|
||||
if (snapshot.hasError) {
|
||||
return Text(L10n.of(context).oopsSomethingWentWrong);
|
||||
|
|
@ -111,7 +115,7 @@ class WordEmojiChoiceState extends State<WordEmojiChoice> {
|
|||
originalSpan: "😀",
|
||||
uniqueKeyForLayerLink: (int index) => "emojiChoice$index",
|
||||
selectedChoiceIndex: snapshot.data!.indexWhere(
|
||||
(element) => element == widget.token.getEmoji(),
|
||||
(element) => element == widget.constructID.userSetEmoji,
|
||||
),
|
||||
tts: null,
|
||||
fontSize: 26,
|
||||
|
|
|
|||
|
|
@ -2,9 +2,9 @@ import 'dart:async';
|
|||
|
||||
import 'package:flutter_gen/gen_l10n/l10n.dart';
|
||||
|
||||
import 'package:fluffychat/pangea/analytics_misc/construct_identifier.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/construct_type_enum.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/construct_use_model.dart';
|
||||
import 'package:fluffychat/pangea/constructs/construct_identifier.dart';
|
||||
import 'package:fluffychat/pangea/lemmas/lemma_info_repo.dart';
|
||||
import 'package:fluffychat/pangea/lemmas/lemma_info_request.dart';
|
||||
import 'package:fluffychat/pangea/lemmas/lemma_info_response.dart';
|
||||
|
|
|
|||
|
|
@ -4,9 +4,9 @@ import 'package:flutter/foundation.dart';
|
|||
|
||||
import 'package:flutter_gen/gen_l10n/l10n.dart';
|
||||
|
||||
import 'package:fluffychat/pangea/analytics_misc/construct_identifier.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/construct_type_enum.dart';
|
||||
import 'package:fluffychat/pangea/common/utils/error_handler.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_categories_enum.dart';
|
||||
import 'package:fluffychat/pangea/toolbar/enums/activity_type_enum.dart';
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import 'package:fluffychat/pangea/analytics_misc/construct_identifier.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/pangea_token_model.dart';
|
||||
import 'package:fluffychat/pangea/events/models/pangea_token_text_model.dart';
|
||||
import 'package:fluffychat/pangea/lemmas/lemma.dart';
|
||||
|
|
|
|||
33
lib/pangea/toolbar/utils/shrinkable_text.dart
Normal file
33
lib/pangea/toolbar/utils/shrinkable_text.dart
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
class ShrinkableText extends StatelessWidget {
|
||||
final String text;
|
||||
final double maxWidth;
|
||||
final TextStyle? style;
|
||||
|
||||
const ShrinkableText({
|
||||
super.key,
|
||||
required this.text,
|
||||
required this.maxWidth,
|
||||
this.style,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return LayoutBuilder(
|
||||
builder: (context, constraints) {
|
||||
return Container(
|
||||
constraints: BoxConstraints(maxWidth: maxWidth),
|
||||
child: FittedBox(
|
||||
fit: BoxFit.scaleDown,
|
||||
alignment: Alignment.centerLeft,
|
||||
child: Text(
|
||||
text,
|
||||
style: style,
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -65,14 +65,6 @@ class MessageOverlayController extends State<MessageSelectionOverlay>
|
|||
bool initialized = false;
|
||||
bool isPlayingAudio = false;
|
||||
|
||||
/// If non-null and not complete, the activity will be shown regardless of shouldDoActivity.
|
||||
/// Used to show the practice activity card's savor the joy animation.
|
||||
/// (Analytics sending triggers the point gain animation, do also
|
||||
/// causes shouldDoActivity to be false. This is a workaround.)
|
||||
Completer<void>? _activityLock;
|
||||
|
||||
// final bool _hideCenterContent = false;
|
||||
|
||||
/// The text that the toolbar should target
|
||||
/// If there is no selectedSpan, then the whole message is the target
|
||||
/// If there is a selectedSpan, then the target is the selected text
|
||||
|
|
@ -326,10 +318,6 @@ class MessageOverlayController extends State<MessageSelectionOverlay>
|
|||
selectedMorphFeature = null;
|
||||
break;
|
||||
case MessageMode.practiceActivity:
|
||||
if (messageAnalyticsEntry?.nextActivity?.activityType ==
|
||||
ActivityTypeEnum.hiddenWordListening) {
|
||||
_lockActivity();
|
||||
}
|
||||
break;
|
||||
case MessageMode.messageTextToSpeech:
|
||||
if (isPlayingAudio) {
|
||||
|
|
@ -432,18 +420,6 @@ class MessageOverlayController extends State<MessageSelectionOverlay>
|
|||
/// Functions
|
||||
/////////////////////////////////////
|
||||
|
||||
///@ggurdin - is this still needed?
|
||||
void _lockActivity() {
|
||||
if (mounted) setState(() => _activityLock = Completer());
|
||||
}
|
||||
|
||||
void _unlockActivity() {
|
||||
if (_activityLock == null) return;
|
||||
_activityLock!.complete();
|
||||
_activityLock = null;
|
||||
if (mounted) setState(() {});
|
||||
}
|
||||
|
||||
/// If sentence TTS is playing a word, highlight that word in message overlay
|
||||
void highlightCurrentText(int currentPosition, List<TTSToken> ttsTokens) {
|
||||
final List<TTSToken> textToSelect = [];
|
||||
|
|
@ -485,10 +461,6 @@ class MessageOverlayController extends State<MessageSelectionOverlay>
|
|||
/// When an activity is completed, we need to update the state
|
||||
/// and check if the toolbar should be unlocked
|
||||
void onActivityFinish(ActivityTypeEnum activityType) {
|
||||
if (activityType == ActivityTypeEnum.hiddenWordListening) {
|
||||
_unlockActivity();
|
||||
}
|
||||
|
||||
messageAnalyticsEntry!.onActivityComplete();
|
||||
|
||||
if (selectedToken == null) {
|
||||
|
|
|
|||
|
|
@ -6,11 +6,11 @@ import 'package:flutter/material.dart';
|
|||
import 'package:flutter_gen/gen_l10n/l10n.dart';
|
||||
|
||||
import 'package:fluffychat/pangea/analytics_details_popup/analytics_details_popup.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/construct_identifier.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/construct_level_enum.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/construct_type_enum.dart';
|
||||
import 'package:fluffychat/pangea/common/constants/model_keys.dart';
|
||||
import 'package:fluffychat/pangea/common/utils/error_handler.dart';
|
||||
import 'package:fluffychat/pangea/constructs/construct_identifier.dart';
|
||||
import 'package:fluffychat/pangea/constructs/construct_level_enum.dart';
|
||||
import 'package:fluffychat/pangea/events/event_wrappers/pangea_message_event.dart';
|
||||
import 'package:fluffychat/pangea/events/models/pangea_token_model.dart';
|
||||
import 'package:fluffychat/pangea/events/models/tokens_event_content_model.dart';
|
||||
|
|
|
|||
|
|
@ -63,8 +63,6 @@ class WordZoomWidget extends StatelessWidget {
|
|||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
// crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
// spacing: 4.0,
|
||||
children: [
|
||||
Container(
|
||||
constraints: const BoxConstraints(
|
||||
|
|
|
|||
|
|
@ -6,12 +6,12 @@ import 'package:flutter/foundation.dart';
|
|||
import 'package:get_storage/get_storage.dart';
|
||||
import 'package:http/http.dart';
|
||||
|
||||
import 'package:fluffychat/pangea/analytics_misc/construct_identifier.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/construct_type_enum.dart';
|
||||
import 'package:fluffychat/pangea/common/config/environment.dart';
|
||||
import 'package:fluffychat/pangea/common/network/requests.dart';
|
||||
import 'package:fluffychat/pangea/common/network/urls.dart';
|
||||
import 'package:fluffychat/pangea/common/utils/error_handler.dart';
|
||||
import 'package:fluffychat/pangea/constructs/construct_identifier.dart';
|
||||
import 'package:fluffychat/pangea/learning_settings/constants/language_constants.dart';
|
||||
import 'package:fluffychat/pangea/learning_settings/models/language_model.dart';
|
||||
import 'package:fluffychat/pangea/learning_settings/utils/p_language_store.dart';
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import 'package:fluffychat/pangea/analytics_misc/construct_identifier.dart';
|
||||
import 'package:fluffychat/pangea/constructs/construct_identifier.dart';
|
||||
|
||||
class VocabResponse {
|
||||
List<ConstructIdentifier> vocab;
|
||||
|
|
|
|||
|
|
@ -9,8 +9,8 @@ import 'package:flutter/material.dart';
|
|||
import 'package:fluffychat/config/themes.dart';
|
||||
import 'package:fluffychat/pages/chat/chat.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/analytics_constants.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/construct_identifier.dart';
|
||||
import 'package:fluffychat/pangea/choreographer/controllers/choreographer.dart';
|
||||
import 'package:fluffychat/pangea/constructs/construct_identifier.dart';
|
||||
import 'package:fluffychat/pangea/learning_settings/constants/language_constants.dart';
|
||||
import 'package:fluffychat/pangea/toolbar/reading_assistance_input_row/message_emoji_choice_item.dart';
|
||||
import 'package:fluffychat/pangea/word_bank/vocab_bank_repo.dart';
|
||||
|
|
@ -102,7 +102,7 @@ class WritingAssistanceInputRowState extends State<WritingAssistanceInputRow> {
|
|||
},
|
||||
isSelected: false,
|
||||
textSize: 16,
|
||||
token: null,
|
||||
greenHighlight: false,
|
||||
),
|
||||
)
|
||||
.toList(),
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue