Morph-repo-2 (#1681)
* feat(morphs): repo for getting lang-specific list of morphs * integrated repo into use of morph features and tags * generated * merged with previous push * generated * generated * chore: fix .env file path --------- Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: ggurdin <46800240+ggurdin@users.noreply.github.com> Co-authored-by: ggurdin <ggurdin@gmail.com>
This commit is contained in:
parent
9eb83de21f
commit
d773347d6e
91 changed files with 2025 additions and 1443 deletions
|
|
@ -4782,7 +4782,13 @@
|
|||
"numberOfLearners": "Number of learners",
|
||||
"mustBeInteger": "Must be an integer e.g. 1, 2, 3, ...",
|
||||
"noBookmarkedActivities": "No bookmarked activities",
|
||||
"noLemmasFound": "No lemmas found",
|
||||
"noLemmasFound": "There are no vocabulary with more than {xp} XP. Keep practicing!",
|
||||
"@noLemmasFound": {
|
||||
"type": "text",
|
||||
"placeholders": {
|
||||
"xp": {}
|
||||
}
|
||||
},
|
||||
"constructUsePvmDesc": "Produced in voice message",
|
||||
"lockedMorphFeature": "Waiting to be unlocked",
|
||||
"leaveSpaceDescription": "The space will be moved to the archive. Other users will be able to see that you have left the chat."
|
||||
|
|
|
|||
|
|
@ -29,9 +29,9 @@ import 'package:fluffychat/pages/chat/chat_view.dart';
|
|||
import 'package:fluffychat/pages/chat/event_info_dialog.dart';
|
||||
import 'package:fluffychat/pages/chat/recording_dialog.dart';
|
||||
import 'package:fluffychat/pages/chat_details/chat_details.dart';
|
||||
import 'package:fluffychat/pangea/analytics/controllers/put_analytics_controller.dart';
|
||||
import 'package:fluffychat/pangea/analytics/models/constructs_model.dart';
|
||||
import 'package:fluffychat/pangea/analytics/widgets/level_up/level_up.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/constructs_model.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/level_up.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/put_analytics_controller.dart';
|
||||
import 'package:fluffychat/pangea/choreographer/controllers/choreographer.dart';
|
||||
import 'package:fluffychat/pangea/choreographer/models/choreo_record.dart';
|
||||
import 'package:fluffychat/pangea/choreographer/widgets/igc/pangea_text_controller.dart';
|
||||
|
|
|
|||
|
|
@ -17,8 +17,8 @@ import 'package:fluffychat/pages/chat/chat_event_list.dart';
|
|||
import 'package:fluffychat/pages/chat/pinned_events.dart';
|
||||
import 'package:fluffychat/pages/chat/reply_display.dart';
|
||||
import 'package:fluffychat/pangea/activity_planner/activity_plan_page_launch_icon_button.dart';
|
||||
import 'package:fluffychat/pangea/analytics/controllers/put_analytics_controller.dart';
|
||||
import 'package:fluffychat/pangea/analytics/widgets/gain_points.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/gain_points_animation.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/put_analytics_controller.dart';
|
||||
import 'package:fluffychat/pangea/chat/widgets/chat_floating_action_button.dart';
|
||||
import 'package:fluffychat/pangea/chat/widgets/chat_view_background.dart';
|
||||
import 'package:fluffychat/pangea/chat/widgets/input_bar_wrapper.dart';
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import 'package:flutter_gen/gen_l10n/l10n.dart';
|
|||
import 'package:fluffychat/config/themes.dart';
|
||||
import 'package:fluffychat/pages/chat_list/chat_list.dart';
|
||||
import 'package:fluffychat/pages/chat_list/client_chooser_button.dart';
|
||||
import 'package:fluffychat/pangea/analytics/widgets/analytics_summary/learning_progress_indicators.dart';
|
||||
import 'package:fluffychat/pangea/analytics_summary/learning_progress_indicators.dart';
|
||||
|
||||
class ChatListHeader extends StatelessWidget implements PreferredSizeWidget {
|
||||
final ChatListController controller;
|
||||
|
|
|
|||
|
|
@ -1,230 +0,0 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:material_symbols_icons/symbols.dart';
|
||||
|
||||
const Map<String, List<String>> morphCategoriesAndLabels = {
|
||||
"pos": [
|
||||
"ADJ",
|
||||
"ADP",
|
||||
"ADV",
|
||||
"AFFIX",
|
||||
"AUX",
|
||||
"CCONJ",
|
||||
"DET",
|
||||
"INTJ",
|
||||
"NOUN",
|
||||
"NUM",
|
||||
"PART",
|
||||
"PRON",
|
||||
"PROPN",
|
||||
"PUNCT",
|
||||
"SCONJ",
|
||||
"SPACE",
|
||||
"SYM",
|
||||
"VERB",
|
||||
"X",
|
||||
],
|
||||
"advtype": ["Adverbial", "Tim"],
|
||||
"aspect": [
|
||||
"Imp",
|
||||
"Perf",
|
||||
"Prog",
|
||||
"Hab",
|
||||
],
|
||||
"case": [
|
||||
"Nom",
|
||||
"Acc",
|
||||
"Dat",
|
||||
"Gen",
|
||||
"Voc",
|
||||
"Abl",
|
||||
"Loc",
|
||||
"All",
|
||||
"Ins",
|
||||
"Ess",
|
||||
"Tra",
|
||||
"Com",
|
||||
"Par",
|
||||
"Adv",
|
||||
"Ref",
|
||||
"Rel",
|
||||
"Equ",
|
||||
"Dis",
|
||||
"Abs",
|
||||
"Erg",
|
||||
"Cau",
|
||||
"Ben",
|
||||
"Sub",
|
||||
"Sup",
|
||||
"Tem",
|
||||
"Obl",
|
||||
"Acc,Dat",
|
||||
"Acc,Nom",
|
||||
"Pre",
|
||||
],
|
||||
"conjtype": ["Coord", "Sub", "Cmp"],
|
||||
"definite": ["Def", "Ind", "Cons"],
|
||||
"degree": [
|
||||
"Pos",
|
||||
"Cmp",
|
||||
"Sup",
|
||||
"Abs",
|
||||
],
|
||||
"evident": ["Fh", "Nfh"],
|
||||
"foreign": ["Yes"],
|
||||
"gender": ["Masc", "Fem", "Neut", "Com"],
|
||||
"mood": [
|
||||
"Ind",
|
||||
"Imp",
|
||||
"Sub",
|
||||
"Cnd",
|
||||
"Opt",
|
||||
"Jus",
|
||||
"Adm",
|
||||
"Des",
|
||||
"Nec",
|
||||
"Pot",
|
||||
"Prp",
|
||||
"Qot",
|
||||
"Int",
|
||||
],
|
||||
"nountype": ["Prop", "Comm", "Not_proper"],
|
||||
"numform": [
|
||||
"Digit",
|
||||
"Word",
|
||||
"Roman",
|
||||
"Letter",
|
||||
],
|
||||
"numtype": [
|
||||
"Card",
|
||||
"Ord",
|
||||
"Mult",
|
||||
"Frac",
|
||||
"Sets",
|
||||
"Range",
|
||||
"Dist",
|
||||
],
|
||||
"number": [
|
||||
"Sing",
|
||||
"Plur",
|
||||
"Dual",
|
||||
"Tri",
|
||||
"Pauc",
|
||||
"Grpa",
|
||||
"Grpl",
|
||||
"Inv",
|
||||
],
|
||||
"number[psor]": ["Sing", "Plur", "Dual"],
|
||||
"person": [
|
||||
"0",
|
||||
"1",
|
||||
"2",
|
||||
"3",
|
||||
"4",
|
||||
],
|
||||
"polarity": ["Pos", "Neg"],
|
||||
"polite": ["Infm", "Form", "Elev", "Humb"],
|
||||
"poss": ["Yes"],
|
||||
"prepcase": ["Npr"],
|
||||
"prontype": [
|
||||
"Prs",
|
||||
"Int",
|
||||
"Rel",
|
||||
"Dem",
|
||||
"Tot",
|
||||
"Neg",
|
||||
"Art",
|
||||
"Emp",
|
||||
"Exc",
|
||||
"Ind",
|
||||
"Rcp",
|
||||
"Int,Rel",
|
||||
],
|
||||
"punctside": ["Ini", "Fin"],
|
||||
"puncttype": [
|
||||
"Brck",
|
||||
"Dash",
|
||||
"Excl",
|
||||
"Peri",
|
||||
"Qest",
|
||||
"Quot",
|
||||
"Semi",
|
||||
"Colo",
|
||||
"Comm",
|
||||
],
|
||||
"reflex": ["Yes"],
|
||||
"tense": ["Pres", "Past", "Fut", "Imp", "Pqp", "Aor", "Eps", "Prosp"],
|
||||
"verbform": [
|
||||
"Fin",
|
||||
"Inf",
|
||||
"Sup",
|
||||
"Part",
|
||||
"Conv",
|
||||
"Vnoun",
|
||||
"Ger",
|
||||
"Adn",
|
||||
"Lng",
|
||||
],
|
||||
"verbtype": ["Mod", "Caus"],
|
||||
"voice": ["Act", "Mid", "Pass", "Antip", "Cau", "Dir", "Inv", "Rcp", "Caus"],
|
||||
"x": ["X"],
|
||||
};
|
||||
|
||||
// TODO Use the icons that Khue is creating
|
||||
IconData getIconForMorphFeature(String feature) {
|
||||
// Define a function to get the icon based on the universal dependency morphological feature (key)
|
||||
switch (feature.toLowerCase()) {
|
||||
case 'number':
|
||||
// google material 123 icon
|
||||
return Icons.format_list_numbered;
|
||||
case 'gender':
|
||||
return Icons.wc;
|
||||
case 'tense':
|
||||
return Icons.access_time;
|
||||
case 'mood':
|
||||
return Icons.mood;
|
||||
case 'person':
|
||||
return Icons.person;
|
||||
case 'case':
|
||||
return Icons.format_list_bulleted;
|
||||
case 'degree':
|
||||
return Icons.trending_up;
|
||||
case 'verbform':
|
||||
return Icons.text_format;
|
||||
case 'voice':
|
||||
return Icons.record_voice_over;
|
||||
case 'aspect':
|
||||
return Icons.aspect_ratio;
|
||||
case 'prontype':
|
||||
return Icons.text_fields;
|
||||
case 'numtype':
|
||||
return Icons.format_list_numbered;
|
||||
case 'poss':
|
||||
return Icons.account_balance;
|
||||
case 'reflex':
|
||||
return Icons.refresh;
|
||||
case 'foreign':
|
||||
return Icons.language;
|
||||
case 'abbr':
|
||||
return Icons.text_format;
|
||||
case 'nountype':
|
||||
return Symbols.abc;
|
||||
case 'pos':
|
||||
return Symbols.toys_and_games;
|
||||
case 'polarity':
|
||||
return Icons.swap_vert;
|
||||
case 'definite':
|
||||
return Icons.check_circle_outline;
|
||||
case 'prepcase':
|
||||
return Icons.location_on_outlined;
|
||||
case 'conjtype':
|
||||
return Icons.compare_arrows;
|
||||
default:
|
||||
return Icons.help_outline;
|
||||
}
|
||||
}
|
||||
|
||||
List<String> getLabelsForMorphCategory(String feature) =>
|
||||
morphCategoriesAndLabels[feature.toLowerCase()] ?? [];
|
||||
|
||||
List<String> getMorphCategories() => morphCategoriesAndLabels.keys.toList();
|
||||
|
|
@ -1,351 +0,0 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:flutter_gen/gen_l10n/l10n.dart';
|
||||
|
||||
import 'package:fluffychat/config/app_config.dart';
|
||||
import 'package:fluffychat/pangea/analytics/constants/morph_categories_and_labels.dart';
|
||||
import 'package:fluffychat/pangea/analytics/enums/construct_type_enum.dart';
|
||||
import 'package:fluffychat/pangea/analytics/enums/progress_indicators_enum.dart';
|
||||
import 'package:fluffychat/pangea/analytics/models/construct_list_model.dart';
|
||||
import 'package:fluffychat/pangea/analytics/models/construct_use_model.dart';
|
||||
import 'package:fluffychat/pangea/analytics/utils/get_grammar_copy.dart';
|
||||
import 'package:fluffychat/pangea/analytics/utils/get_svg_link.dart';
|
||||
import 'package:fluffychat/pangea/common/widgets/customized_svg.dart';
|
||||
import 'package:fluffychat/pangea/common/widgets/full_width_dialog.dart';
|
||||
import 'package:fluffychat/utils/color_value.dart';
|
||||
import 'package:fluffychat/widgets/matrix.dart';
|
||||
|
||||
class MorphAnalyticsPopup extends StatelessWidget {
|
||||
const MorphAnalyticsPopup({
|
||||
super.key,
|
||||
});
|
||||
|
||||
ConstructListModel get _constructsModel =>
|
||||
MatrixState.pangeaController.getAnalytics.constructListModel;
|
||||
|
||||
Map<String, List<ConstructUses>> get _categoriesToUses =>
|
||||
_constructsModel.categoriesToUses(type: ConstructTypeEnum.morph);
|
||||
|
||||
List<MapEntry<String, List<ConstructUses>>> get _sortedEntries {
|
||||
final entries = _categoriesToUses.entries.toList();
|
||||
// Sort the list with custom logic
|
||||
entries.sort((a, b) {
|
||||
// Check if one of the keys is 'Other'
|
||||
if (a.key.toLowerCase() == 'other') return 1;
|
||||
if (b.key.toLowerCase() == 'other') return -1;
|
||||
|
||||
// Sort by the length of the list in descending order
|
||||
final aTotalPoints = a.value.fold<int>(
|
||||
0,
|
||||
(previousValue, element) => previousValue + element.points,
|
||||
);
|
||||
final bTotalPoints = b.value.fold<int>(
|
||||
0,
|
||||
(previousValue, element) => previousValue + element.points,
|
||||
);
|
||||
return bTotalPoints.compareTo(aTotalPoints);
|
||||
});
|
||||
return entries;
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final availableFeatures = getMorphCategories();
|
||||
final List<MapEntry<String, List<ConstructUses>>> morphUses =
|
||||
List.from(_sortedEntries);
|
||||
|
||||
return FullWidthDialog(
|
||||
dialogContent: Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text(ConstructTypeEnum.morph.indicator.tooltip(context)),
|
||||
leading: IconButton(
|
||||
icon: const Icon(Icons.close),
|
||||
onPressed: Navigator.of(context).pop,
|
||||
),
|
||||
),
|
||||
body: Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 20),
|
||||
child: _constructsModel
|
||||
.constructList(type: ConstructTypeEnum.morph)
|
||||
.isEmpty
|
||||
? Center(child: Text(L10n.of(context).noDataFound))
|
||||
: ListView.builder(
|
||||
itemCount: availableFeatures.length,
|
||||
itemBuilder: (context, index) {
|
||||
final category =
|
||||
index < morphUses.length ? morphUses[index] : null;
|
||||
final ids = category?.value
|
||||
.map(
|
||||
(use) => MorphIdentifier(
|
||||
morphFeature: category.key,
|
||||
morphTag: use.lemma,
|
||||
),
|
||||
)
|
||||
.toList() ??
|
||||
[];
|
||||
|
||||
debugPrint(
|
||||
"category: ${category?.key}, points: ${category?.value.fold<int>(
|
||||
0,
|
||||
(previousValue, element) =>
|
||||
previousValue + element.points,
|
||||
)}");
|
||||
|
||||
return MorphFeatureBox(morphIdentifiers: ids);
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
maxWidth: 600,
|
||||
maxHeight: 800,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class MorphFeatureBox extends StatelessWidget {
|
||||
final List<MorphIdentifier> morphIdentifiers;
|
||||
|
||||
const MorphFeatureBox({
|
||||
super.key,
|
||||
required this.morphIdentifiers,
|
||||
});
|
||||
|
||||
String get _morphFeature => morphIdentifiers.first.morphFeature;
|
||||
|
||||
String _categoryCopy(
|
||||
String category,
|
||||
BuildContext context,
|
||||
) {
|
||||
if (category.toLowerCase() == "other") {
|
||||
return L10n.of(context).other;
|
||||
}
|
||||
|
||||
return ConstructTypeEnum.morph.getDisplayCopy(
|
||||
category,
|
||||
context,
|
||||
) ??
|
||||
category;
|
||||
}
|
||||
|
||||
Set<String> get _lockedTags {
|
||||
final availableLabels = getLabelsForMorphCategory(_morphFeature)
|
||||
.map((tag) => tag.toLowerCase())
|
||||
.toSet();
|
||||
final usedLabels =
|
||||
morphIdentifiers.map((morph) => morph.morphTag.toLowerCase()).toSet();
|
||||
return availableLabels.difference(usedLabels);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
if (morphIdentifiers.isEmpty) {
|
||||
return Opacity(
|
||||
opacity: 0.5,
|
||||
child: Container(
|
||||
padding: const EdgeInsets.all(24.0),
|
||||
margin: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(16.0),
|
||||
color: Theme.of(context).disabledColor,
|
||||
),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
const Icon(Icons.lock, size: 24.0),
|
||||
const SizedBox(width: 24.0),
|
||||
Text(
|
||||
L10n.of(context).lockedMorphFeature,
|
||||
style: Theme.of(context).textTheme.bodyLarge?.copyWith(
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
final allMorphIdentifiers = List.from(morphIdentifiers);
|
||||
allMorphIdentifiers.addAll(
|
||||
_lockedTags.map(
|
||||
(tag) => MorphIdentifier(
|
||||
morphFeature: _morphFeature,
|
||||
morphTag: tag,
|
||||
isLocked: true,
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
final theme = Theme.of(context);
|
||||
|
||||
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: AppConfig.gold, width: 2),
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
spacing: 16.0,
|
||||
children: [
|
||||
SizedBox(
|
||||
height: 30.0,
|
||||
width: 30.0,
|
||||
child: CustomizedSvg(
|
||||
svgUrl: getMorphSvgLink(
|
||||
morphFeature: _morphFeature,
|
||||
context: context,
|
||||
),
|
||||
colorReplacements: theme.brightness == Brightness.dark
|
||||
? {
|
||||
"white": theme.cardColor.hexValue.toString(),
|
||||
"black": "white",
|
||||
}
|
||||
: {},
|
||||
errorIcon: Icon(getIconForMorphFeature(_morphFeature)),
|
||||
),
|
||||
),
|
||||
Text(
|
||||
_categoryCopy(_morphFeature, context),
|
||||
style: theme.textTheme.bodyLarge?.copyWith(
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 16.0),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Flexible(
|
||||
child: Wrap(
|
||||
alignment: WrapAlignment.center,
|
||||
spacing: 16.0,
|
||||
runSpacing: 16.0,
|
||||
children: [
|
||||
for (final morph in allMorphIdentifiers)
|
||||
MorphTagChip(morphIdentifier: morph),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class MorphTagChip extends StatelessWidget {
|
||||
final MorphIdentifier morphIdentifier;
|
||||
|
||||
const MorphTagChip({
|
||||
super.key,
|
||||
required this.morphIdentifier,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final theme = Theme.of(context);
|
||||
|
||||
if (morphIdentifier.isLocked) {
|
||||
return Container(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
vertical: 4.0,
|
||||
horizontal: 24.0,
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(32.0),
|
||||
color: theme.disabledColor,
|
||||
),
|
||||
child: SizedBox(
|
||||
width: 28.0,
|
||||
height: 28.0,
|
||||
child: Icon(
|
||||
Icons.lock,
|
||||
color: theme.brightness == Brightness.dark
|
||||
? Colors.black
|
||||
: Colors.white,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
return Container(
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(32.0),
|
||||
gradient: LinearGradient(
|
||||
begin: Alignment.topLeft,
|
||||
colors: <Color>[
|
||||
Color.alphaBlend(
|
||||
theme.brightness == Brightness.dark
|
||||
? Colors.black.withAlpha(220)
|
||||
: Colors.white.withAlpha(220),
|
||||
AppConfig.gold,
|
||||
),
|
||||
AppConfig.gold,
|
||||
],
|
||||
),
|
||||
),
|
||||
padding: const EdgeInsets.symmetric(
|
||||
vertical: 4.0,
|
||||
horizontal: 8.0,
|
||||
),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
spacing: 8.0,
|
||||
children: [
|
||||
SizedBox(
|
||||
width: 28.0,
|
||||
height: 28.0,
|
||||
child: CustomizedSvg(
|
||||
svgUrl: getMorphSvgLink(
|
||||
morphFeature: morphIdentifier.morphFeature,
|
||||
morphTag: morphIdentifier.morphTag,
|
||||
context: context,
|
||||
),
|
||||
colorReplacements: theme.brightness == Brightness.dark
|
||||
? {
|
||||
"white": theme.cardColor.hexValue.toString(),
|
||||
"black": "white",
|
||||
}
|
||||
: {},
|
||||
errorIcon: Icon(
|
||||
getIconForMorphFeature(morphIdentifier.morphFeature),
|
||||
),
|
||||
),
|
||||
),
|
||||
Text(
|
||||
getGrammarCopy(
|
||||
category: morphIdentifier.morphFeature,
|
||||
lemma: morphIdentifier.morphTag,
|
||||
context: context,
|
||||
) ??
|
||||
morphIdentifier.morphTag,
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
color: theme.brightness == Brightness.dark
|
||||
? Colors.white
|
||||
: Colors.black,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class MorphIdentifier {
|
||||
final String morphFeature;
|
||||
final String morphTag;
|
||||
final bool isLocked;
|
||||
|
||||
const MorphIdentifier({
|
||||
required this.morphFeature,
|
||||
required this.morphTag,
|
||||
this.isLocked = false,
|
||||
});
|
||||
}
|
||||
|
|
@ -1,62 +0,0 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:fluffychat/config/app_config.dart';
|
||||
import 'package:fluffychat/pangea/analytics/enums/construct_type_enum.dart';
|
||||
import 'package:fluffychat/pangea/analytics/enums/progress_indicators_enum.dart';
|
||||
import 'package:fluffychat/pangea/analytics/models/construct_use_model.dart';
|
||||
import 'package:fluffychat/pangea/analytics/utils/get_grammar_copy.dart';
|
||||
|
||||
class ConstructUsesXPTile extends StatelessWidget {
|
||||
final ConstructUses constructUses;
|
||||
|
||||
const ConstructUsesXPTile(
|
||||
this.constructUses, {
|
||||
super.key,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final ProgressIndicatorEnum indicator =
|
||||
constructUses.constructType == ConstructTypeEnum.morph
|
||||
? ProgressIndicatorEnum.morphsUsed
|
||||
: ProgressIndicatorEnum.wordsUsed;
|
||||
|
||||
return Tooltip(
|
||||
message:
|
||||
"${constructUses.points} / ${constructUses.constructType.maxXPPerLemma}",
|
||||
child: ListTile(
|
||||
onTap: () {},
|
||||
title: Text(
|
||||
constructUses.constructType == ConstructTypeEnum.morph
|
||||
? getGrammarCopy(
|
||||
category: constructUses.category,
|
||||
lemma: constructUses.lemma,
|
||||
context: context,
|
||||
) ??
|
||||
constructUses.lemma
|
||||
: constructUses.lemma,
|
||||
),
|
||||
subtitle: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: LinearProgressIndicator(
|
||||
value: constructUses.points /
|
||||
constructUses.constructType.maxXPPerLemma,
|
||||
minHeight: 20,
|
||||
borderRadius: const BorderRadius.all(
|
||||
Radius.circular(AppConfig.borderRadius),
|
||||
),
|
||||
color: indicator.color(context),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
Text("${constructUses.points}xp"),
|
||||
],
|
||||
),
|
||||
contentPadding: const EdgeInsets.symmetric(
|
||||
horizontal: 20,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,278 +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/config/app_config.dart';
|
||||
import 'package:fluffychat/pangea/analytics/constants/analytics_constants.dart';
|
||||
import 'package:fluffychat/pangea/analytics/enums/construct_type_enum.dart';
|
||||
import 'package:fluffychat/pangea/analytics/enums/lemma_category_enum.dart';
|
||||
import 'package:fluffychat/pangea/analytics/enums/progress_indicators_enum.dart';
|
||||
import 'package:fluffychat/pangea/analytics/models/construct_list_model.dart';
|
||||
import 'package:fluffychat/pangea/analytics/models/construct_use_model.dart';
|
||||
import 'package:fluffychat/pangea/analytics/utils/get_grammar_copy.dart';
|
||||
import 'package:fluffychat/pangea/analytics/widgets/analytics_summary/vocab_analytics_popup/vocab_definition_popup.dart';
|
||||
import 'package:fluffychat/pangea/common/widgets/customized_svg.dart';
|
||||
import 'package:fluffychat/pangea/common/widgets/full_width_dialog.dart';
|
||||
import 'package:fluffychat/widgets/matrix.dart';
|
||||
|
||||
/// Displays vocab analytics, sorted into categories
|
||||
/// (flowers, greens, and seeds) by points
|
||||
class VocabAnalyticsPopup extends StatefulWidget {
|
||||
const VocabAnalyticsPopup({
|
||||
super.key,
|
||||
});
|
||||
|
||||
@override
|
||||
VocabAnalyticsPopupState createState() => VocabAnalyticsPopupState();
|
||||
}
|
||||
|
||||
class VocabAnalyticsPopupState extends State<VocabAnalyticsPopup> {
|
||||
ConstructListModel get _constructsModel =>
|
||||
MatrixState.pangeaController.getAnalytics.constructListModel;
|
||||
|
||||
/// Sort entries alphabetically, to better detect duplicates
|
||||
List<ConstructUses> get _sortedEntries {
|
||||
final entries =
|
||||
_constructsModel.constructList(type: ConstructTypeEnum.vocab);
|
||||
entries
|
||||
.sort((a, b) => a.lemma.toLowerCase().compareTo(b.lemma.toLowerCase()));
|
||||
return entries;
|
||||
}
|
||||
|
||||
ConstructUses? _selectedConstruct;
|
||||
|
||||
void _setSelectedConstruct(ConstructUses? construct) {
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
_selectedConstruct = construct;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return FullWidthDialog(
|
||||
dialogContent: _selectedConstruct == null
|
||||
? LemmaListDialogContent(
|
||||
lemmas: _sortedEntries,
|
||||
onTap: _setSelectedConstruct,
|
||||
)
|
||||
: VocabDefinitionPopup(
|
||||
construct: _selectedConstruct!,
|
||||
onClose: () => _setSelectedConstruct(null),
|
||||
),
|
||||
maxWidth: 600,
|
||||
maxHeight: 800,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class VocabChip {
|
||||
final ConstructUses construct;
|
||||
final String? displayText;
|
||||
|
||||
VocabChip({
|
||||
required this.construct,
|
||||
this.displayText,
|
||||
});
|
||||
}
|
||||
|
||||
class LemmaListSection extends StatelessWidget {
|
||||
final LemmaCategoryEnum type;
|
||||
final List<VocabChip> lemmas;
|
||||
final Function(ConstructUses) onTap;
|
||||
|
||||
const LemmaListSection({
|
||||
super.key,
|
||||
required this.type,
|
||||
required this.lemmas,
|
||||
required this.onTap,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
padding: const EdgeInsets.all(20),
|
||||
margin: const EdgeInsets.symmetric(vertical: 6.0, horizontal: 16.0),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: const BorderRadius.all(
|
||||
Radius.circular(AppConfig.borderRadius),
|
||||
),
|
||||
color: type.color,
|
||||
),
|
||||
child: Column(
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
CustomizedSvg(
|
||||
svgUrl: type.svgURL,
|
||||
colorReplacements: const {},
|
||||
errorIcon: Text(type.emoji),
|
||||
),
|
||||
Text(
|
||||
" ${type.xpString} XP",
|
||||
style: TextStyle(
|
||||
fontSize: Theme.of(context).textTheme.bodyLarge?.fontSize,
|
||||
color: Theme.of(context).colorScheme.onPrimaryFixed,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 8),
|
||||
child: lemmas.isEmpty
|
||||
? Text(
|
||||
L10n.of(context).noLemmasFound,
|
||||
style: TextStyle(
|
||||
color: Theme.of(context).colorScheme.onPrimaryFixed,
|
||||
),
|
||||
)
|
||||
: Wrap(
|
||||
spacing: 0,
|
||||
runSpacing: 0,
|
||||
children: lemmas.mapIndexed((index, lemma) {
|
||||
return MouseRegion(
|
||||
cursor: SystemMouseCursors.click,
|
||||
child: GestureDetector(
|
||||
onTap: () => onTap(lemma.construct),
|
||||
child: Text(
|
||||
"${lemma.displayText ?? lemma.construct.lemma}${index < lemmas.length - 1 ? ', ' : ''}",
|
||||
style: TextStyle(
|
||||
shadows: [
|
||||
Shadow(
|
||||
color: Theme.of(context)
|
||||
.colorScheme
|
||||
.onPrimaryFixed,
|
||||
offset: const Offset(0, -2.5),
|
||||
),
|
||||
],
|
||||
color: Colors.transparent,
|
||||
decoration: TextDecoration.underline,
|
||||
decorationStyle: TextDecorationStyle.dotted,
|
||||
decorationColor:
|
||||
Theme.of(context).colorScheme.onPrimaryFixed,
|
||||
decorationThickness: 1,
|
||||
fontSize: Theme.of(context)
|
||||
.textTheme
|
||||
.bodyLarge
|
||||
?.fontSize,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}).toList(),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class LemmaListDialogContent extends StatelessWidget {
|
||||
final List<ConstructUses> lemmas;
|
||||
final Function(ConstructUses) onTap;
|
||||
|
||||
const LemmaListDialogContent({
|
||||
super.key,
|
||||
required this.lemmas,
|
||||
required this.onTap,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
if (lemmas.isEmpty) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text(ProgressIndicatorEnum.wordsUsed.tooltip(context)),
|
||||
leading: IconButton(
|
||||
icon: const Icon(Icons.close),
|
||||
onPressed: Navigator.of(context).pop,
|
||||
),
|
||||
// TODO: add search and training buttons?
|
||||
),
|
||||
body: Center(child: Text(L10n.of(context).noDataFound)),
|
||||
);
|
||||
}
|
||||
|
||||
// Get lists of lemmas by category
|
||||
final List<VocabChip> flowerLemmas = [];
|
||||
final List<VocabChip> greenLemmas = [];
|
||||
final List<VocabChip> seedLemmas = [];
|
||||
|
||||
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 String pos = getGrammarCopy(
|
||||
category: "pos",
|
||||
lemma: construct.category,
|
||||
context: context,
|
||||
) ??
|
||||
construct.category;
|
||||
displayText = "${lemmas[i].lemma} (${pos.toLowerCase()})";
|
||||
}
|
||||
|
||||
final lemma = VocabChip(
|
||||
construct: construct,
|
||||
displayText: displayText,
|
||||
);
|
||||
|
||||
if (points < AnalyticsConstants.xpForGreens) {
|
||||
seedLemmas.add(lemma);
|
||||
} else if (points >= AnalyticsConstants.xpForFlower) {
|
||||
flowerLemmas.add(lemma);
|
||||
} else {
|
||||
greenLemmas.add(lemma);
|
||||
}
|
||||
}
|
||||
|
||||
// Pass sorted lemmas to background tile widgets
|
||||
final Widget flowers = LemmaListSection(
|
||||
type: LemmaCategoryEnum.flowers,
|
||||
lemmas: flowerLemmas,
|
||||
onTap: onTap,
|
||||
);
|
||||
|
||||
final Widget greens = LemmaListSection(
|
||||
type: LemmaCategoryEnum.greens,
|
||||
lemmas: greenLemmas,
|
||||
onTap: onTap,
|
||||
);
|
||||
|
||||
final Widget seeds = LemmaListSection(
|
||||
type: LemmaCategoryEnum.seeds,
|
||||
lemmas: seedLemmas,
|
||||
onTap: onTap,
|
||||
);
|
||||
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text(ProgressIndicatorEnum.wordsUsed.tooltip(context)),
|
||||
leading: IconButton(
|
||||
icon: const Icon(Icons.close),
|
||||
onPressed: Navigator.of(context).pop,
|
||||
),
|
||||
// TODO: add search and training buttons?
|
||||
),
|
||||
body: Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 20),
|
||||
child: ListView(
|
||||
children: [flowers, greens, seeds],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,87 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:fluffychat/config/app_config.dart';
|
||||
import 'package:fluffychat/pangea/analytics_details_popup/morph_analytics_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_misc/construct_type_enum.dart';
|
||||
import 'package:fluffychat/pangea/analytics_summary/progress_indicators_enum.dart';
|
||||
import 'package:fluffychat/pangea/common/widgets/full_width_dialog.dart';
|
||||
|
||||
class AnalyticsPopupWrapper extends StatefulWidget {
|
||||
AnalyticsPopupWrapper({super.key, this.constructZoom, required this.view});
|
||||
|
||||
ConstructTypeEnum view;
|
||||
ConstructIdentifier? constructZoom;
|
||||
|
||||
@override
|
||||
_AnalyticsPopupWrapperState createState() => _AnalyticsPopupWrapperState();
|
||||
}
|
||||
|
||||
class _AnalyticsPopupWrapperState extends State<AnalyticsPopupWrapper> {
|
||||
ConstructIdentifier? localConstructZoom;
|
||||
ConstructTypeEnum localView = ConstructTypeEnum.vocab;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
localView = widget.view;
|
||||
setConstructZoom(widget.constructZoom);
|
||||
}
|
||||
|
||||
void setConstructZoom(ConstructIdentifier? id) {
|
||||
if (id != null && id.type != localView) {
|
||||
localView = id.type;
|
||||
}
|
||||
localConstructZoom = id;
|
||||
setState(() => {});
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return FullWidthDialog(
|
||||
dialogContent: Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text(
|
||||
localView == ConstructTypeEnum.morph
|
||||
? ConstructTypeEnum.morph.indicator.tooltip(context)
|
||||
: ConstructTypeEnum.vocab.indicator.tooltip(context),
|
||||
),
|
||||
leading: IconButton(
|
||||
icon: localConstructZoom == null
|
||||
? const Icon(Icons.close)
|
||||
: const Icon(Icons.arrow_back),
|
||||
onPressed: localConstructZoom == null
|
||||
? () => Navigator.of(context).pop()
|
||||
: () => setConstructZoom(null),
|
||||
),
|
||||
actions: ConstructTypeEnum.values
|
||||
.map(
|
||||
(c) => IconButton(
|
||||
icon: Icon(c.indicator.icon),
|
||||
onPressed: () => setState(() {
|
||||
localView = c;
|
||||
localConstructZoom = null;
|
||||
}),
|
||||
isSelected: localView == c,
|
||||
color: localView == c
|
||||
? Theme.of(context).brightness == Brightness.dark
|
||||
? AppConfig.primaryColorLight
|
||||
: AppConfig.primaryColor
|
||||
: null,
|
||||
),
|
||||
)
|
||||
.toList(),
|
||||
),
|
||||
body: localView == ConstructTypeEnum.morph
|
||||
? const MorphAnalyticsView()
|
||||
: localConstructZoom == null
|
||||
? VocabAnalyticsView(onConstructZoom: setConstructZoom)
|
||||
: VocabDetailsView(constructId: localConstructZoom!),
|
||||
),
|
||||
maxWidth: 600,
|
||||
maxHeight: 800,
|
||||
);
|
||||
}
|
||||
}
|
||||
88
lib/pangea/analytics_details_popup/lemma_usage_dots.dart
Normal file
88
lib/pangea/analytics_details_popup/lemma_usage_dots.dart
Normal file
|
|
@ -0,0 +1,88 @@
|
|||
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';
|
||||
|
||||
class LemmaUsageDots extends StatelessWidget {
|
||||
final ConstructUses construct;
|
||||
final LearningSkillsEnum category;
|
||||
|
||||
final String tooltip;
|
||||
final IconData icon;
|
||||
|
||||
const LemmaUsageDots({
|
||||
required this.construct,
|
||||
required this.category,
|
||||
required this.tooltip,
|
||||
required this.icon,
|
||||
super.key,
|
||||
});
|
||||
|
||||
/// Find lemma uses for the given exercise type, to create dot list
|
||||
List<bool> sortedUses(LearningSkillsEnum category) {
|
||||
final List<bool> useList = [];
|
||||
for (final OneConstructUse use in construct.uses) {
|
||||
if (use.useType.pointValue == 0) {
|
||||
continue;
|
||||
}
|
||||
// If the use type matches the given category, save to list
|
||||
// Usage with positive XP is saved as true, else false
|
||||
if (category == use.useType.skillsEnumType) {
|
||||
useList.add(use.useType.pointValue > 0);
|
||||
}
|
||||
}
|
||||
return useList;
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final List<Widget> dots = [];
|
||||
for (final bool use in sortedUses(category)) {
|
||||
dots.add(
|
||||
Container(
|
||||
width: 15.0,
|
||||
height: 15.0,
|
||||
decoration: BoxDecoration(
|
||||
color: use ? AppConfig.success : Colors.red,
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
final Color textColor = Theme.of(context).brightness != Brightness.light
|
||||
? construct.lemmaCategory.color
|
||||
: construct.lemmaCategory.darkColor;
|
||||
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 20),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
Tooltip(
|
||||
triggerMode: TooltipTriggerMode.tap,
|
||||
message: tooltip,
|
||||
child: Icon(
|
||||
icon,
|
||||
size: 24,
|
||||
color: textColor.withValues(alpha: 0.7),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 8.0),
|
||||
Flexible(
|
||||
child: Wrap(
|
||||
spacing: 3,
|
||||
runSpacing: 5,
|
||||
children: dots,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,157 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:matrix/matrix.dart';
|
||||
|
||||
import 'package:fluffychat/config/app_config.dart';
|
||||
import 'package:fluffychat/config/themes.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/events/event_wrappers/pangea_message_event.dart';
|
||||
import 'package:fluffychat/widgets/matrix.dart';
|
||||
|
||||
class LemmaUseExampleMessages extends StatelessWidget {
|
||||
final ConstructUses construct;
|
||||
|
||||
const LemmaUseExampleMessages({
|
||||
super.key,
|
||||
required this.construct,
|
||||
});
|
||||
|
||||
Future<List<ExampleMessage>> _getExampleMessages() async {
|
||||
final Set<ExampleMessage> examples = {};
|
||||
for (final OneConstructUse use in construct.uses) {
|
||||
if (use.useType.skillsEnumType != LearningSkillsEnum.writing ||
|
||||
use.metadata.eventId == null ||
|
||||
use.form == null ||
|
||||
use.pointValue <= 0) {
|
||||
continue;
|
||||
}
|
||||
final Room? room = MatrixState.pangeaController.matrixState.client
|
||||
.getRoomById(use.metadata.roomId);
|
||||
if (room == null) continue;
|
||||
|
||||
Timeline? timeline = room.timeline;
|
||||
if (room.timeline == null) {
|
||||
timeline = await room.getTimeline();
|
||||
}
|
||||
|
||||
final Event? event = await room.getEventById(use.metadata.eventId!);
|
||||
if (event == null) continue;
|
||||
final PangeaMessageEvent pangeaMessageEvent = PangeaMessageEvent(
|
||||
event: event,
|
||||
timeline: timeline!,
|
||||
ownMessage: event.senderId ==
|
||||
MatrixState.pangeaController.matrixState.client.userID,
|
||||
);
|
||||
final tokens = pangeaMessageEvent.messageDisplayRepresentation?.tokens;
|
||||
if (tokens == null || tokens.isEmpty) continue;
|
||||
final token =
|
||||
tokens.firstWhereOrNull((token) => token.text.content == use.form);
|
||||
if (token == null) continue;
|
||||
|
||||
final int offset = token.text.offset;
|
||||
examples.add(
|
||||
ExampleMessage(
|
||||
message: pangeaMessageEvent.messageDisplayText,
|
||||
offset: offset,
|
||||
length: use.form!.length,
|
||||
),
|
||||
);
|
||||
if (examples.length > 4) break;
|
||||
}
|
||||
|
||||
return examples.toList();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return FutureBuilder(
|
||||
future: _getExampleMessages(),
|
||||
builder: (context, snapshot) {
|
||||
if (snapshot.hasData) {
|
||||
return Align(
|
||||
alignment: Alignment.topLeft,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: snapshot.data!.map((e) {
|
||||
return Container(
|
||||
decoration: BoxDecoration(
|
||||
color: construct.lemmaCategory.color,
|
||||
borderRadius: BorderRadius.circular(4),
|
||||
),
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 16,
|
||||
vertical: 8,
|
||||
),
|
||||
margin: const EdgeInsets.only(bottom: 8),
|
||||
constraints: const BoxConstraints(
|
||||
maxWidth: FluffyThemes.columnWidth * 1.5,
|
||||
),
|
||||
child: RichText(
|
||||
text: TextSpan(
|
||||
style: TextStyle(
|
||||
color: Theme.of(context).colorScheme.onPrimaryFixed,
|
||||
fontSize: AppConfig.fontSizeFactor *
|
||||
AppConfig.messageFontSize,
|
||||
),
|
||||
children: [
|
||||
TextSpan(text: e.message.substring(0, e.offset)),
|
||||
TextSpan(
|
||||
text: e.message
|
||||
.substring(e.offset, e.offset + e.length),
|
||||
style: const TextStyle(fontWeight: FontWeight.bold),
|
||||
),
|
||||
TextSpan(
|
||||
text: e.message.substring(e.offset + e.length),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}).toList(),
|
||||
),
|
||||
);
|
||||
} else {
|
||||
return const Column(
|
||||
children: [
|
||||
SizedBox(height: 10),
|
||||
CircularProgressIndicator.adaptive(
|
||||
strokeWidth: 2,
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class ExampleMessage {
|
||||
final String message;
|
||||
final int offset;
|
||||
final int length;
|
||||
|
||||
ExampleMessage({
|
||||
required this.message,
|
||||
required this.offset,
|
||||
required this.length,
|
||||
});
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
if (identical(this, other)) return true;
|
||||
|
||||
return other is ExampleMessage &&
|
||||
other.message == message &&
|
||||
other.offset == offset &&
|
||||
other.length == length;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => message.hashCode ^ offset.hashCode ^ length.hashCode;
|
||||
}
|
||||
222
lib/pangea/analytics_details_popup/morph_analytics_view.dart
Normal file
222
lib/pangea/analytics_details_popup/morph_analytics_view.dart
Normal file
|
|
@ -0,0 +1,222 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:flutter_gen/gen_l10n/l10n.dart';
|
||||
|
||||
import 'package:fluffychat/config/app_config.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/morphs/get_grammar_copy.dart';
|
||||
import 'package:fluffychat/pangea/morphs/morph_icon.dart';
|
||||
import 'package:fluffychat/pangea/morphs/morph_models.dart';
|
||||
import 'package:fluffychat/widgets/matrix.dart';
|
||||
import '../morphs/morph_repo.dart';
|
||||
|
||||
class MorphAnalyticsView extends StatelessWidget {
|
||||
const MorphAnalyticsView({
|
||||
super.key,
|
||||
});
|
||||
|
||||
List<MorphFeature> get availableFeatures => MorphsRepo.get().displayFeatures;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 20),
|
||||
child: ListView.builder(
|
||||
itemCount: availableFeatures.length,
|
||||
itemBuilder: (context, index) =>
|
||||
availableFeatures[index].displayTags.isNotEmpty
|
||||
? MorphFeatureBox(
|
||||
morphFeature: availableFeatures[index].feature,
|
||||
)
|
||||
: const SizedBox.shrink(),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
class MorphFeatureBox extends StatelessWidget {
|
||||
final String morphFeature;
|
||||
|
||||
const MorphFeatureBox({
|
||||
super.key,
|
||||
required this.morphFeature,
|
||||
});
|
||||
|
||||
// get constructData => MatrixState.pangeaController.
|
||||
|
||||
String _categoryCopy(
|
||||
String category,
|
||||
BuildContext context,
|
||||
) {
|
||||
if (category.toLowerCase() == "other") {
|
||||
return L10n.of(context).other;
|
||||
}
|
||||
|
||||
return ConstructTypeEnum.morph.getDisplayCopy(
|
||||
category,
|
||||
context,
|
||||
) ??
|
||||
category;
|
||||
}
|
||||
|
||||
Set<String> get allTags => MorphsRepo.get()
|
||||
.getDisplayTags(morphFeature)
|
||||
.map((tag) => tag.toLowerCase())
|
||||
.toSet();
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final theme = Theme.of(context);
|
||||
|
||||
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: Theme.of(context).brightness == Brightness.dark
|
||||
? AppConfig.primaryColorLight
|
||||
: AppConfig.primaryColor,
|
||||
width: 2,
|
||||
),
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
spacing: 16.0,
|
||||
children: [
|
||||
SizedBox(
|
||||
height: 30.0,
|
||||
width: 30.0,
|
||||
child: MorphIcon(morphFeature: morphFeature, morphTag: null),
|
||||
),
|
||||
Text(
|
||||
_categoryCopy(morphFeature, context),
|
||||
style: theme.textTheme.bodyLarge?.copyWith(
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 16.0),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Flexible(
|
||||
child: Wrap(
|
||||
alignment: WrapAlignment.center,
|
||||
spacing: 16.0,
|
||||
runSpacing: 16.0,
|
||||
children: allTags
|
||||
.map(
|
||||
(morphTag) => MorphTagChip(
|
||||
morphFeature: morphFeature,
|
||||
morphTag: morphTag,
|
||||
constructAnalytics: MatrixState.pangeaController
|
||||
.getAnalytics.constructListModel
|
||||
.getConstructUses(
|
||||
ConstructIdentifier(
|
||||
lemma: morphTag,
|
||||
type: ConstructTypeEnum.morph,
|
||||
category: morphFeature,
|
||||
),
|
||||
) ??
|
||||
ConstructUses(
|
||||
lemma: morphTag,
|
||||
constructType: ConstructTypeEnum.morph,
|
||||
category: morphFeature,
|
||||
uses: [],
|
||||
),
|
||||
),
|
||||
)
|
||||
.sortedBy<num>((chip) => chip.constructAnalytics.points)
|
||||
.reversed
|
||||
.toList(),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class MorphTagChip extends StatelessWidget {
|
||||
final String morphFeature;
|
||||
final String morphTag;
|
||||
final ConstructUses constructAnalytics;
|
||||
|
||||
const MorphTagChip({
|
||||
super.key,
|
||||
required this.morphFeature,
|
||||
required this.morphTag,
|
||||
required this.constructAnalytics,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final theme = Theme.of(context);
|
||||
|
||||
return Opacity(
|
||||
opacity: constructAnalytics.points > 0 ? 1.0 : 0.3,
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(32.0),
|
||||
gradient: constructAnalytics.points > 0
|
||||
? LinearGradient(
|
||||
begin: Alignment.centerLeft,
|
||||
end: Alignment.centerRight,
|
||||
colors: <Color>[
|
||||
Colors.transparent,
|
||||
constructAnalytics.lemmaCategory.color,
|
||||
],
|
||||
)
|
||||
: null,
|
||||
color: constructAnalytics.points > 0 ? null : theme.disabledColor,
|
||||
),
|
||||
padding: const EdgeInsets.symmetric(
|
||||
vertical: 4.0,
|
||||
horizontal: 8.0,
|
||||
),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
spacing: 8.0,
|
||||
children: [
|
||||
SizedBox(
|
||||
width: 28.0,
|
||||
height: 28.0,
|
||||
child: constructAnalytics.points > 0
|
||||
? MorphIcon(
|
||||
morphFeature: morphFeature,
|
||||
morphTag: morphTag,
|
||||
)
|
||||
: const Icon(
|
||||
Icons.lock,
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
Text(
|
||||
getGrammarCopy(
|
||||
category: morphFeature,
|
||||
lemma: morphTag,
|
||||
context: context,
|
||||
) ??
|
||||
morphTag,
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
color: theme.brightness == Brightness.dark
|
||||
? Colors.white
|
||||
: Colors.black,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,10 +1,10 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:fluffychat/config/app_config.dart';
|
||||
import 'package:fluffychat/pangea/analytics/enums/construct_type_enum.dart';
|
||||
import 'package:fluffychat/pangea/analytics/enums/progress_indicators_enum.dart';
|
||||
import 'package:fluffychat/pangea/analytics/models/construct_use_model.dart';
|
||||
import 'package:fluffychat/pangea/analytics/utils/get_grammar_copy.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_summary/progress_indicators_enum.dart';
|
||||
import 'package:fluffychat/pangea/morphs/get_grammar_copy.dart';
|
||||
|
||||
class ConstructUsesXPTile extends StatelessWidget {
|
||||
final ConstructUses constructUses;
|
||||
181
lib/pangea/analytics_details_popup/vocab_analytics_view.dart
Normal file
181
lib/pangea/analytics_details_popup/vocab_analytics_view.dart
Normal file
|
|
@ -0,0 +1,181 @@
|
|||
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(
|
||||
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(),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,42 +1,39 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:flutter_gen/gen_l10n/l10n.dart';
|
||||
import 'package:material_symbols_icons/symbols.dart';
|
||||
import 'package:matrix/matrix.dart';
|
||||
|
||||
import 'package:fluffychat/config/app_config.dart';
|
||||
import 'package:fluffychat/config/themes.dart';
|
||||
import 'package:fluffychat/pangea/analytics/enums/construct_use_type_enum.dart';
|
||||
import 'package:fluffychat/pangea/analytics/enums/learning_skills_enum.dart';
|
||||
import 'package:fluffychat/pangea/analytics/enums/lemma_category_enum.dart';
|
||||
import 'package:fluffychat/pangea/analytics/models/construct_use_model.dart';
|
||||
import 'package:fluffychat/pangea/analytics/models/constructs_model.dart';
|
||||
import 'package:fluffychat/pangea/analytics/models/lemma.dart';
|
||||
import 'package:fluffychat/pangea/analytics/repo/lemma_info_repo.dart';
|
||||
import 'package:fluffychat/pangea/analytics/repo/lemma_info_request.dart';
|
||||
import 'package:fluffychat/pangea/analytics/repo/lemma_info_response.dart';
|
||||
import 'package:fluffychat/pangea/analytics/utils/get_grammar_copy.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/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/analytics_misc/learning_skills_enum.dart';
|
||||
import 'package:fluffychat/pangea/common/widgets/customized_svg.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/pangea_token_text_model.dart';
|
||||
import 'package:fluffychat/pangea/learning_settings/constants/language_constants.dart';
|
||||
import 'package:fluffychat/pangea/lemmas/lemma.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';
|
||||
import 'package:fluffychat/pangea/morphs/get_grammar_copy.dart';
|
||||
import 'package:fluffychat/pangea/toolbar/controllers/tts_controller.dart';
|
||||
import 'package:fluffychat/pangea/toolbar/widgets/practice_activity/word_audio_button.dart';
|
||||
import 'package:fluffychat/widgets/matrix.dart';
|
||||
|
||||
/// Displays information about selected lemma, and its usage
|
||||
class VocabDefinitionPopup extends StatelessWidget {
|
||||
final ConstructUses construct;
|
||||
final VoidCallback onClose;
|
||||
class VocabDetailsView extends StatelessWidget {
|
||||
final ConstructIdentifier constructId;
|
||||
|
||||
const VocabDefinitionPopup({
|
||||
const VocabDetailsView({
|
||||
super.key,
|
||||
required this.construct,
|
||||
required this.onClose,
|
||||
required this.constructId,
|
||||
});
|
||||
|
||||
ConstructUses get construct => constructId.constructUses;
|
||||
|
||||
String? get emoji => PangeaToken(
|
||||
text: PangeaTokenText(
|
||||
offset: 0,
|
||||
|
|
@ -101,6 +98,7 @@ class VocabDefinitionPopup extends StatelessWidget {
|
|||
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
leading: const SizedBox(),
|
||||
title: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
|
|
@ -132,10 +130,10 @@ class VocabDefinitionPopup extends StatelessWidget {
|
|||
],
|
||||
),
|
||||
centerTitle: true,
|
||||
leading: SizedBox(
|
||||
width: 24,
|
||||
child: BackButton(onPressed: onClose),
|
||||
),
|
||||
// leading: SizedBox(
|
||||
// width: 24,
|
||||
// child: BackButton(onPressed: onClose),
|
||||
// ),
|
||||
),
|
||||
body: SingleChildScrollView(
|
||||
child: Padding(
|
||||
|
|
@ -311,226 +309,3 @@ class VocabDefinitionPopup extends StatelessWidget {
|
|||
);
|
||||
}
|
||||
}
|
||||
|
||||
class LemmaUseExampleMessages extends StatelessWidget {
|
||||
final ConstructUses construct;
|
||||
|
||||
const LemmaUseExampleMessages({
|
||||
super.key,
|
||||
required this.construct,
|
||||
});
|
||||
|
||||
Future<List<ExampleMessage>> _getExampleMessages() async {
|
||||
final Set<ExampleMessage> examples = {};
|
||||
for (final OneConstructUse use in construct.uses) {
|
||||
if (use.useType.skillsEnumType != LearningSkillsEnum.writing ||
|
||||
use.metadata.eventId == null ||
|
||||
use.form == null ||
|
||||
use.pointValue <= 0) {
|
||||
continue;
|
||||
}
|
||||
final Room? room = MatrixState.pangeaController.matrixState.client
|
||||
.getRoomById(use.metadata.roomId);
|
||||
if (room == null) continue;
|
||||
|
||||
Timeline? timeline = room.timeline;
|
||||
if (room.timeline == null) {
|
||||
timeline = await room.getTimeline();
|
||||
}
|
||||
|
||||
final Event? event = await room.getEventById(use.metadata.eventId!);
|
||||
if (event == null) continue;
|
||||
final PangeaMessageEvent pangeaMessageEvent = PangeaMessageEvent(
|
||||
event: event,
|
||||
timeline: timeline!,
|
||||
ownMessage: event.senderId ==
|
||||
MatrixState.pangeaController.matrixState.client.userID,
|
||||
);
|
||||
final tokens = pangeaMessageEvent.messageDisplayRepresentation?.tokens;
|
||||
if (tokens == null || tokens.isEmpty) continue;
|
||||
final token =
|
||||
tokens.firstWhereOrNull((token) => token.text.content == use.form);
|
||||
if (token == null) continue;
|
||||
|
||||
final int offset = token.text.offset;
|
||||
examples.add(
|
||||
ExampleMessage(
|
||||
message: pangeaMessageEvent.messageDisplayText,
|
||||
offset: offset,
|
||||
length: use.form!.length,
|
||||
),
|
||||
);
|
||||
if (examples.length > 4) break;
|
||||
}
|
||||
|
||||
return examples.toList();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return FutureBuilder(
|
||||
future: _getExampleMessages(),
|
||||
builder: (context, snapshot) {
|
||||
if (snapshot.hasData) {
|
||||
return Align(
|
||||
alignment: Alignment.topLeft,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: snapshot.data!.map((e) {
|
||||
return Container(
|
||||
decoration: BoxDecoration(
|
||||
color: construct.lemmaCategory.color,
|
||||
borderRadius: BorderRadius.circular(4),
|
||||
),
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 16,
|
||||
vertical: 8,
|
||||
),
|
||||
margin: const EdgeInsets.only(bottom: 8),
|
||||
constraints: const BoxConstraints(
|
||||
maxWidth: FluffyThemes.columnWidth * 1.5,
|
||||
),
|
||||
child: RichText(
|
||||
text: TextSpan(
|
||||
style: TextStyle(
|
||||
color: Theme.of(context).colorScheme.onPrimaryFixed,
|
||||
fontSize: AppConfig.fontSizeFactor *
|
||||
AppConfig.messageFontSize,
|
||||
),
|
||||
children: [
|
||||
TextSpan(text: e.message.substring(0, e.offset)),
|
||||
TextSpan(
|
||||
text: e.message
|
||||
.substring(e.offset, e.offset + e.length),
|
||||
style: const TextStyle(fontWeight: FontWeight.bold),
|
||||
),
|
||||
TextSpan(
|
||||
text: e.message.substring(e.offset + e.length),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}).toList(),
|
||||
),
|
||||
);
|
||||
} else {
|
||||
return const Column(
|
||||
children: [
|
||||
SizedBox(height: 10),
|
||||
CircularProgressIndicator.adaptive(
|
||||
strokeWidth: 2,
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class LemmaUsageDots extends StatelessWidget {
|
||||
final ConstructUses construct;
|
||||
final LearningSkillsEnum category;
|
||||
|
||||
final String tooltip;
|
||||
final IconData icon;
|
||||
|
||||
const LemmaUsageDots({
|
||||
required this.construct,
|
||||
required this.category,
|
||||
required this.tooltip,
|
||||
required this.icon,
|
||||
super.key,
|
||||
});
|
||||
|
||||
/// Find lemma uses for the given exercise type, to create dot list
|
||||
List<bool> sortedUses(LearningSkillsEnum category) {
|
||||
final List<bool> useList = [];
|
||||
for (final OneConstructUse use in construct.uses) {
|
||||
if (use.useType.pointValue == 0) {
|
||||
continue;
|
||||
}
|
||||
// If the use type matches the given category, save to list
|
||||
// Usage with positive XP is saved as true, else false
|
||||
if (category == use.useType.skillsEnumType) {
|
||||
useList.add(use.useType.pointValue > 0);
|
||||
}
|
||||
}
|
||||
return useList;
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final List<Widget> dots = [];
|
||||
for (final bool use in sortedUses(category)) {
|
||||
dots.add(
|
||||
Container(
|
||||
width: 15.0,
|
||||
height: 15.0,
|
||||
decoration: BoxDecoration(
|
||||
color: use ? AppConfig.success : Colors.red,
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
final Color textColor = Theme.of(context).brightness != Brightness.light
|
||||
? construct.lemmaCategory.color
|
||||
: construct.lemmaCategory.darkColor;
|
||||
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 20),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
Tooltip(
|
||||
triggerMode: TooltipTriggerMode.tap,
|
||||
message: tooltip,
|
||||
child: Icon(
|
||||
icon,
|
||||
size: 24,
|
||||
color: textColor.withValues(alpha: 0.7),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 8.0),
|
||||
Flexible(
|
||||
child: Wrap(
|
||||
spacing: 3,
|
||||
runSpacing: 5,
|
||||
children: dots,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class ExampleMessage {
|
||||
final String message;
|
||||
final int offset;
|
||||
final int length;
|
||||
|
||||
ExampleMessage({
|
||||
required this.message,
|
||||
required this.offset,
|
||||
required this.length,
|
||||
});
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
if (identical(this, other)) return true;
|
||||
|
||||
return other is ExampleMessage &&
|
||||
other.message == message &&
|
||||
other.offset == offset &&
|
||||
other.length == length;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => message.hashCode ^ offset.hashCode ^ length.hashCode;
|
||||
}
|
||||
|
|
@ -2,11 +2,11 @@ import 'package:flutter/material.dart';
|
|||
|
||||
import 'package:flutter_gen/gen_l10n/l10n.dart';
|
||||
|
||||
import 'package:fluffychat/pangea/analytics/enums/analytics_summary_enum.dart';
|
||||
import 'package:fluffychat/pangea/analytics/enums/construct_type_enum.dart';
|
||||
import 'package:fluffychat/pangea/analytics/enums/construct_use_type_enum.dart';
|
||||
import 'package:fluffychat/pangea/analytics/models/construct_list_model.dart';
|
||||
import 'package:fluffychat/pangea/analytics/models/construct_use_model.dart';
|
||||
import 'package:fluffychat/pangea/analytics_downloads/analytics_summary_enum.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/construct_list_model.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';
|
||||
|
||||
class AnalyticsSummaryModel {
|
||||
String username;
|
||||
|
|
@ -5,8 +5,10 @@ import 'package:flutter/foundation.dart';
|
|||
import 'package:collection/collection.dart';
|
||||
import 'package:sentry_flutter/sentry_flutter.dart';
|
||||
|
||||
import 'package:fluffychat/pangea/analytics/enums/construct_type_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/utils/error_handler.dart';
|
||||
import 'package:fluffychat/widgets/matrix.dart';
|
||||
|
||||
class ConstructIdentifier {
|
||||
final String lemma;
|
||||
|
|
@ -89,4 +91,16 @@ class ConstructIdentifier {
|
|||
}
|
||||
|
||||
String get partialKey => "$lemma-${type.string}";
|
||||
|
||||
ConstructUses get constructUses =>
|
||||
MatrixState.pangeaController.getAnalytics.constructListModel
|
||||
.getConstructUses(
|
||||
this,
|
||||
) ??
|
||||
ConstructUses(
|
||||
lemma: lemma,
|
||||
constructType: ConstructTypeEnum.morph,
|
||||
category: category,
|
||||
uses: [],
|
||||
);
|
||||
}
|
||||
|
|
@ -1,71 +1,82 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:fluffychat/config/app_config.dart';
|
||||
import 'package:fluffychat/pangea/analytics/constants/analytics_constants.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/analytics_constants.dart';
|
||||
|
||||
enum LemmaCategoryEnum {
|
||||
enum ConstructLevelEnum {
|
||||
flowers,
|
||||
greens,
|
||||
seeds,
|
||||
}
|
||||
|
||||
extension LemmaCategoryExtension on LemmaCategoryEnum {
|
||||
extension ConstructLevelEnumExt on ConstructLevelEnum {
|
||||
Color get color {
|
||||
switch (this) {
|
||||
case LemmaCategoryEnum.flowers:
|
||||
case ConstructLevelEnum.flowers:
|
||||
return Color.lerp(AppConfig.primaryColor, Colors.white, 0.6) ??
|
||||
AppConfig.primaryColor;
|
||||
case LemmaCategoryEnum.greens:
|
||||
case ConstructLevelEnum.greens:
|
||||
return Color.lerp(AppConfig.success, Colors.white, 0.6) ??
|
||||
AppConfig.success;
|
||||
case LemmaCategoryEnum.seeds:
|
||||
case ConstructLevelEnum.seeds:
|
||||
return Color.lerp(AppConfig.gold, Colors.white, 0.6) ?? AppConfig.gold;
|
||||
}
|
||||
}
|
||||
|
||||
Color get darkColor {
|
||||
switch (this) {
|
||||
case LemmaCategoryEnum.flowers:
|
||||
case ConstructLevelEnum.flowers:
|
||||
return Color.lerp(AppConfig.primaryColor, Colors.white, 0.3) ??
|
||||
AppConfig.primaryColor;
|
||||
case LemmaCategoryEnum.greens:
|
||||
case ConstructLevelEnum.greens:
|
||||
return Color.lerp(AppConfig.success, Colors.black, 0.3) ??
|
||||
AppConfig.success;
|
||||
case LemmaCategoryEnum.seeds:
|
||||
case ConstructLevelEnum.seeds:
|
||||
return Color.lerp(AppConfig.gold, Colors.black, 0.3) ?? AppConfig.gold;
|
||||
}
|
||||
}
|
||||
|
||||
String get svgURL {
|
||||
switch (this) {
|
||||
case LemmaCategoryEnum.seeds:
|
||||
case ConstructLevelEnum.seeds:
|
||||
return "${AppConfig.assetsBaseURL}/${AnalyticsConstants.seedSvgFileName}";
|
||||
case LemmaCategoryEnum.greens:
|
||||
case ConstructLevelEnum.greens:
|
||||
return "${AppConfig.assetsBaseURL}/${AnalyticsConstants.leafSvgFileName}";
|
||||
case LemmaCategoryEnum.flowers:
|
||||
case ConstructLevelEnum.flowers:
|
||||
return "${AppConfig.assetsBaseURL}/${AnalyticsConstants.flowerSvgFileName}";
|
||||
}
|
||||
}
|
||||
|
||||
String get emoji {
|
||||
switch (this) {
|
||||
case LemmaCategoryEnum.flowers:
|
||||
case ConstructLevelEnum.flowers:
|
||||
return AnalyticsConstants.emojiForFlower;
|
||||
case LemmaCategoryEnum.greens:
|
||||
case ConstructLevelEnum.greens:
|
||||
return AnalyticsConstants.emojiForGreen;
|
||||
case LemmaCategoryEnum.seeds:
|
||||
case ConstructLevelEnum.seeds:
|
||||
return AnalyticsConstants.emojiForSeed;
|
||||
}
|
||||
}
|
||||
|
||||
String get xpString {
|
||||
switch (this) {
|
||||
case LemmaCategoryEnum.flowers:
|
||||
case ConstructLevelEnum.flowers:
|
||||
return ">${AnalyticsConstants.xpForFlower}";
|
||||
case LemmaCategoryEnum.greens:
|
||||
case ConstructLevelEnum.greens:
|
||||
return ">${AnalyticsConstants.xpForGreens}";
|
||||
case LemmaCategoryEnum.seeds:
|
||||
case ConstructLevelEnum.seeds:
|
||||
return "<${AnalyticsConstants.xpForGreens}";
|
||||
}
|
||||
}
|
||||
|
||||
int get xpNeeded {
|
||||
switch (this) {
|
||||
case ConstructLevelEnum.flowers:
|
||||
return AnalyticsConstants.xpForFlower;
|
||||
case ConstructLevelEnum.greens:
|
||||
return AnalyticsConstants.xpForGreens;
|
||||
case ConstructLevelEnum.seeds:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -4,13 +4,13 @@ import 'package:flutter/material.dart';
|
|||
|
||||
import 'package:collection/collection.dart';
|
||||
|
||||
import 'package:fluffychat/pangea/analytics/constants/analytics_constants.dart';
|
||||
import 'package:fluffychat/pangea/analytics/enums/construct_type_enum.dart';
|
||||
import 'package:fluffychat/pangea/analytics/models/construct_identifier.dart';
|
||||
import 'package:fluffychat/pangea/analytics/models/construct_use_model.dart';
|
||||
import 'package:fluffychat/pangea/analytics/models/constructs_model.dart';
|
||||
import 'package:fluffychat/pangea/analytics/utils/get_grammar_copy.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/morphs/get_grammar_copy.dart';
|
||||
|
||||
/// A wrapper around a list of [OneConstructUse]s, used to simplify
|
||||
/// the process of filtering / sorting / displaying the events.
|
||||
|
|
@ -187,6 +187,7 @@ class ConstructListModel {
|
|||
}
|
||||
}
|
||||
|
||||
// TODO; make this non-nullable, returning empty if not found
|
||||
ConstructUses? getConstructUses(ConstructIdentifier identifier) {
|
||||
final partialKey = "${identifier.lemma}-${identifier.type.string}";
|
||||
|
||||
|
|
@ -3,10 +3,10 @@ import 'dart:developer';
|
|||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:fluffychat/pangea/analytics/constants/analytics_constants.dart';
|
||||
import 'package:fluffychat/pangea/analytics/enums/morph_categories_enum.dart';
|
||||
import 'package:fluffychat/pangea/analytics/enums/parts_of_speech_enum.dart';
|
||||
import 'package:fluffychat/pangea/analytics/enums/progress_indicators_enum.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/analytics_constants.dart';
|
||||
import 'package:fluffychat/pangea/analytics_summary/progress_indicators_enum.dart';
|
||||
import 'package:fluffychat/pangea/morphs/morph_categories_enum.dart';
|
||||
import 'package:fluffychat/pangea/morphs/parts_of_speech_enum.dart';
|
||||
|
||||
enum ConstructTypeEnum {
|
||||
/// for vocabulary words
|
||||
|
|
@ -1,9 +1,9 @@
|
|||
import 'package:fluffychat/pangea/analytics/constants/analytics_constants.dart';
|
||||
import 'package:fluffychat/pangea/analytics/enums/construct_type_enum.dart';
|
||||
import 'package:fluffychat/pangea/analytics/enums/construct_use_type_enum.dart';
|
||||
import 'package:fluffychat/pangea/analytics/enums/lemma_category_enum.dart';
|
||||
import 'package:fluffychat/pangea/analytics/models/construct_identifier.dart';
|
||||
import 'package:fluffychat/pangea/analytics/models/constructs_model.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_type_enum.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/constructs_model.dart';
|
||||
|
||||
/// One lemma and a list of construct uses for that lemma
|
||||
class ConstructUses {
|
||||
|
|
@ -68,12 +68,12 @@ class ConstructUses {
|
|||
}
|
||||
|
||||
/// Get the lemma category, based on points
|
||||
LemmaCategoryEnum get lemmaCategory {
|
||||
ConstructLevelEnum get lemmaCategory {
|
||||
if (points < AnalyticsConstants.xpForGreens) {
|
||||
return LemmaCategoryEnum.seeds;
|
||||
return ConstructLevelEnum.seeds;
|
||||
} else if (points >= AnalyticsConstants.xpForFlower) {
|
||||
return LemmaCategoryEnum.flowers;
|
||||
return ConstructLevelEnum.flowers;
|
||||
}
|
||||
return LemmaCategoryEnum.greens;
|
||||
return ConstructLevelEnum.greens;
|
||||
}
|
||||
}
|
||||
|
|
@ -2,8 +2,8 @@ import 'package:flutter/material.dart';
|
|||
|
||||
import 'package:flutter_gen/gen_l10n/l10n.dart';
|
||||
|
||||
import 'package:fluffychat/pangea/analytics/enums/analytics_summary_enum.dart';
|
||||
import 'package:fluffychat/pangea/analytics/enums/learning_skills_enum.dart';
|
||||
import 'package:fluffychat/pangea/analytics_downloads/analytics_summary_enum.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/learning_skills_enum.dart';
|
||||
import 'package:fluffychat/pangea/toolbar/enums/activity_type_enum.dart';
|
||||
|
||||
enum ConstructUseTypeEnum {
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
import 'package:matrix/matrix.dart';
|
||||
|
||||
import 'package:fluffychat/pangea/analytics/models/constructs_model.dart';
|
||||
import '../../events/constants/pangea_event_types.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/constructs_model.dart';
|
||||
import '../events/constants/pangea_event_types.dart';
|
||||
|
||||
class ConstructAnalyticsEvent {
|
||||
late Event _event;
|
||||
|
|
@ -4,11 +4,12 @@ import 'package:flutter/foundation.dart';
|
|||
|
||||
import 'package:matrix/matrix.dart';
|
||||
|
||||
import 'package:fluffychat/pangea/analytics/constants/morph_categories_and_labels.dart';
|
||||
import 'package:fluffychat/pangea/analytics/enums/construct_use_type_enum.dart';
|
||||
import 'package:fluffychat/pangea/analytics/models/construct_identifier.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 '../enums/construct_type_enum.dart';
|
||||
import 'package:fluffychat/pangea/morphs/morph_models.dart';
|
||||
import '../morphs/morph_repo.dart';
|
||||
import 'construct_type_enum.dart';
|
||||
|
||||
class ConstructAnalyticsModel {
|
||||
List<OneConstructUse> uses;
|
||||
|
|
@ -154,13 +155,15 @@ class OneConstructUse {
|
|||
return category ?? "Other";
|
||||
}
|
||||
|
||||
final MorphFeatuuresAndTags morphs = MorphsRepo.get();
|
||||
|
||||
if (categoryEntry == null) {
|
||||
return _guessGrammarCategory(json["lemma"]);
|
||||
return morphs.guessMorphCategory(json["lemma"]);
|
||||
}
|
||||
|
||||
if ((categoryEntry is List)) {
|
||||
if (categoryEntry.isEmpty) {
|
||||
return _guessGrammarCategory(json["lemma"]);
|
||||
return morphs.guessMorphCategory(json["lemma"]);
|
||||
}
|
||||
return categoryEntry.first;
|
||||
} else if (categoryEntry is String) {
|
||||
|
|
@ -170,25 +173,7 @@ class OneConstructUse {
|
|||
debugPrint(
|
||||
"Category entry is not a list or string -${json['cat'] ?? json['categories']}-",
|
||||
);
|
||||
return _guessGrammarCategory(json["lemma"]);
|
||||
}
|
||||
|
||||
static String _guessGrammarCategory(String morphLemma) {
|
||||
for (final String category in morphCategoriesAndLabels.keys) {
|
||||
if (morphCategoriesAndLabels[category]!.contains(morphLemma)) {
|
||||
// debugPrint(
|
||||
// "found missing construct category for $morphLemma: $category",
|
||||
// );
|
||||
return category;
|
||||
}
|
||||
}
|
||||
ErrorHandler.logError(
|
||||
m: "Morph construct lemma $morphLemma not found in morph categories and labels",
|
||||
data: {
|
||||
"morphLemma": morphLemma,
|
||||
},
|
||||
);
|
||||
return "Other";
|
||||
return morphs.guessMorphCategory(json["lemma"]);
|
||||
}
|
||||
|
||||
Room? getRoom(Client client) {
|
||||
|
|
@ -4,8 +4,8 @@ import 'dart:math';
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:fluffychat/config/app_config.dart';
|
||||
import 'package:fluffychat/pangea/analytics/controllers/get_analytics_controller.dart';
|
||||
import 'package:fluffychat/pangea/analytics/controllers/put_analytics_controller.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/get_analytics_controller.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/put_analytics_controller.dart';
|
||||
import 'package:fluffychat/pangea/bot/utils/bot_style.dart';
|
||||
import 'package:fluffychat/widgets/matrix.dart';
|
||||
|
||||
|
|
@ -6,13 +6,13 @@ import 'package:flutter/material.dart';
|
|||
import 'package:matrix/matrix.dart';
|
||||
import 'package:sentry_flutter/sentry_flutter.dart';
|
||||
|
||||
import 'package:fluffychat/pangea/analytics/controllers/message_analytics_controller.dart';
|
||||
import 'package:fluffychat/pangea/analytics/controllers/put_analytics_controller.dart';
|
||||
import 'package:fluffychat/pangea/analytics/enums/construct_type_enum.dart';
|
||||
import 'package:fluffychat/pangea/analytics/extensions/client_analytics_extension.dart';
|
||||
import 'package:fluffychat/pangea/analytics/models/construct_list_model.dart';
|
||||
import 'package:fluffychat/pangea/analytics/models/constructs_event.dart';
|
||||
import 'package:fluffychat/pangea/analytics/models/constructs_model.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/client_analytics_extension.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/construct_list_model.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/construct_type_enum.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/constructs_event.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/constructs_model.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/message_analytics_controller.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/put_analytics_controller.dart';
|
||||
import 'package:fluffychat/pangea/common/constants/local.key.dart';
|
||||
import 'package:fluffychat/pangea/common/controllers/pangea_controller.dart';
|
||||
import 'package:fluffychat/pangea/common/utils/error_handler.dart';
|
||||
|
|
@ -8,7 +8,7 @@ import 'package:flutter_gen/gen_l10n/l10n.dart';
|
|||
import 'package:http/http.dart' as http;
|
||||
|
||||
import 'package:fluffychat/config/app_config.dart';
|
||||
import 'package:fluffychat/pangea/analytics/constants/analytics_constants.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/analytics_constants.dart';
|
||||
|
||||
class LevelUpUtil {
|
||||
static void showLevelUpDialog(
|
||||
|
|
@ -2,8 +2,8 @@ import 'dart:math';
|
|||
|
||||
import 'package:flutter/foundation.dart';
|
||||
|
||||
import 'package:fluffychat/pangea/analytics/controllers/get_analytics_controller.dart';
|
||||
import 'package:fluffychat/pangea/analytics/models/construct_identifier.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/construct_identifier.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/get_analytics_controller.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';
|
||||
|
|
@ -4,10 +4,10 @@ import 'package:flutter/foundation.dart';
|
|||
|
||||
import 'package:matrix/matrix.dart';
|
||||
|
||||
import 'package:fluffychat/pangea/analytics/enums/construct_type_enum.dart';
|
||||
import 'package:fluffychat/pangea/analytics/enums/construct_use_type_enum.dart';
|
||||
import 'package:fluffychat/pangea/analytics/extensions/client_analytics_extension.dart';
|
||||
import 'package:fluffychat/pangea/analytics/models/constructs_model.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/client_analytics_extension.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/common/constants/local.key.dart';
|
||||
import 'package:fluffychat/pangea/common/controllers/base_controller.dart';
|
||||
import 'package:fluffychat/pangea/common/controllers/pangea_controller.dart';
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
part of "../../extensions/pangea_room_extension.dart";
|
||||
part of "../extensions/pangea_room_extension.dart";
|
||||
|
||||
extension AnalyticsRoomExtension on Room {
|
||||
/// Get next n analytics rooms via the space hierarchy
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:fluffychat/pangea/analytics/widgets/progress_bar/progress_bar.dart';
|
||||
import 'package:fluffychat/pangea/analytics/widgets/progress_bar/progress_bar_details.dart';
|
||||
import 'package:fluffychat/pangea/analytics_summary/progress_bar/progress_bar.dart';
|
||||
import 'package:fluffychat/pangea/analytics_summary/progress_bar/progress_bar_details.dart';
|
||||
import 'package:fluffychat/widgets/matrix.dart';
|
||||
|
||||
class LearningProgressBar extends StatelessWidget {
|
||||
|
|
@ -5,16 +5,16 @@ import 'package:flutter/material.dart';
|
|||
import 'package:flutter_gen/gen_l10n/l10n.dart';
|
||||
|
||||
import 'package:fluffychat/pages/chat_list/client_chooser_button.dart';
|
||||
import 'package:fluffychat/pangea/analytics/controllers/get_analytics_controller.dart';
|
||||
import 'package:fluffychat/pangea/analytics/enums/progress_indicators_enum.dart';
|
||||
import 'package:fluffychat/pangea/analytics/models/construct_list_model.dart';
|
||||
import 'package:fluffychat/pangea/analytics/widgets/analytics_summary/learning_progress_bar.dart';
|
||||
import 'package:fluffychat/pangea/analytics/widgets/analytics_summary/learning_settings_button.dart';
|
||||
import 'package:fluffychat/pangea/analytics/widgets/analytics_summary/level_badge.dart';
|
||||
import 'package:fluffychat/pangea/analytics/widgets/analytics_summary/level_bar_popup.dart';
|
||||
import 'package:fluffychat/pangea/analytics/widgets/analytics_summary/morph_analytics_popup/morph_analytics_popup.dart';
|
||||
import 'package:fluffychat/pangea/analytics/widgets/analytics_summary/progress_indicator.dart';
|
||||
import 'package:fluffychat/pangea/analytics/widgets/analytics_summary/vocab_analytics_popup/vocab_analytics_popup.dart';
|
||||
import 'package:fluffychat/pangea/analytics_details_popup/analytics_details_popup.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/construct_list_model.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/construct_type_enum.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/get_analytics_controller.dart';
|
||||
import 'package:fluffychat/pangea/analytics_summary/learning_progress_bar.dart';
|
||||
import 'package:fluffychat/pangea/analytics_summary/learning_settings_button.dart';
|
||||
import 'package:fluffychat/pangea/analytics_summary/level_badge.dart';
|
||||
import 'package:fluffychat/pangea/analytics_summary/level_bar_popup.dart';
|
||||
import 'package:fluffychat/pangea/analytics_summary/progress_indicator.dart';
|
||||
import 'package:fluffychat/pangea/analytics_summary/progress_indicators_enum.dart';
|
||||
import 'package:fluffychat/pangea/learning_settings/pages/settings_learning.dart';
|
||||
import 'package:fluffychat/widgets/matrix.dart';
|
||||
|
||||
|
|
@ -110,30 +110,23 @@ class LearningProgressIndicatorsState
|
|||
l2: userL2?.getDisplayName(context) ?? userL2?.langCode,
|
||||
),
|
||||
Row(
|
||||
children: [
|
||||
ProgressIndicatorBadge(
|
||||
points: uniqueLemmas(ProgressIndicatorEnum.wordsUsed),
|
||||
loading: _loading,
|
||||
onTap: () {
|
||||
showDialog<VocabAnalyticsPopup>(
|
||||
context: context,
|
||||
builder: (c) => const VocabAnalyticsPopup(),
|
||||
);
|
||||
},
|
||||
indicator: ProgressIndicatorEnum.wordsUsed,
|
||||
),
|
||||
ProgressIndicatorBadge(
|
||||
points: uniqueLemmas(ProgressIndicatorEnum.morphsUsed),
|
||||
loading: _loading,
|
||||
onTap: () {
|
||||
showDialog<MorphAnalyticsPopup>(
|
||||
context: context,
|
||||
builder: (c) => const MorphAnalyticsPopup(),
|
||||
);
|
||||
},
|
||||
indicator: ProgressIndicatorEnum.morphsUsed,
|
||||
),
|
||||
],
|
||||
children: ConstructTypeEnum.values
|
||||
.map(
|
||||
(c) => ProgressIndicatorBadge(
|
||||
points: uniqueLemmas(c.indicator),
|
||||
loading: _loading,
|
||||
onTap: () {
|
||||
showDialog<AnalyticsPopupWrapper>(
|
||||
context: context,
|
||||
builder: (context) => AnalyticsPopupWrapper(
|
||||
view: c,
|
||||
),
|
||||
);
|
||||
},
|
||||
indicator: c.indicator,
|
||||
),
|
||||
)
|
||||
.toList(),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
|
@ -3,7 +3,7 @@ import 'package:flutter/material.dart';
|
|||
import 'package:flutter_gen/gen_l10n/l10n.dart';
|
||||
|
||||
import 'package:fluffychat/config/app_config.dart';
|
||||
import 'package:fluffychat/pangea/analytics/widgets/analytics_summary/level_bar_popup.dart';
|
||||
import 'package:fluffychat/pangea/analytics_summary/level_bar_popup.dart';
|
||||
import 'package:fluffychat/pangea/common/widgets/pressable_button.dart';
|
||||
|
||||
class LevelBadge extends StatelessWidget {
|
||||
|
|
@ -3,12 +3,12 @@ import 'package:flutter/material.dart';
|
|||
import 'package:flutter_gen/gen_l10n/l10n.dart';
|
||||
|
||||
import 'package:fluffychat/config/app_config.dart';
|
||||
import 'package:fluffychat/pangea/analytics/controllers/get_analytics_controller.dart';
|
||||
import 'package:fluffychat/pangea/analytics/enums/construct_type_enum.dart';
|
||||
import 'package:fluffychat/pangea/analytics/enums/construct_use_type_enum.dart';
|
||||
import 'package:fluffychat/pangea/analytics/models/constructs_model.dart';
|
||||
import 'package:fluffychat/pangea/analytics/utils/get_grammar_copy.dart';
|
||||
import 'package:fluffychat/pangea/analytics/widgets/analytics_summary/learning_progress_bar.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/construct_type_enum.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/construct_use_type_enum.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/constructs_model.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/get_analytics_controller.dart';
|
||||
import 'package:fluffychat/pangea/analytics_summary/learning_progress_bar.dart';
|
||||
import 'package:fluffychat/pangea/morphs/get_grammar_copy.dart';
|
||||
import 'package:fluffychat/widgets/matrix.dart';
|
||||
|
||||
class LevelBarPopup extends StatelessWidget {
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:fluffychat/config/app_config.dart';
|
||||
import 'package:fluffychat/pangea/analytics/widgets/progress_bar/animated_level_dart.dart';
|
||||
import 'package:fluffychat/pangea/analytics/widgets/progress_bar/progress_bar_details.dart';
|
||||
import 'package:fluffychat/pangea/analytics_summary/progress_bar/animated_level_dart.dart';
|
||||
import 'package:fluffychat/pangea/analytics_summary/progress_bar/progress_bar_details.dart';
|
||||
|
||||
class LevelBar extends StatefulWidget {
|
||||
final LevelBarDetails details;
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:fluffychat/pangea/analytics/widgets/progress_bar/level_bar.dart';
|
||||
import 'package:fluffychat/pangea/analytics/widgets/progress_bar/progress_bar_background.dart';
|
||||
import 'package:fluffychat/pangea/analytics/widgets/progress_bar/progress_bar_details.dart';
|
||||
import 'package:fluffychat/pangea/analytics_summary/progress_bar/level_bar.dart';
|
||||
import 'package:fluffychat/pangea/analytics_summary/progress_bar/progress_bar_background.dart';
|
||||
import 'package:fluffychat/pangea/analytics_summary/progress_bar/progress_bar_details.dart';
|
||||
|
||||
// Provide an order list of level indicators, each with it's color
|
||||
// and stream. Also provide an overall width and pointsPerLevel.
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:fluffychat/config/app_config.dart';
|
||||
import 'package:fluffychat/pangea/analytics/widgets/progress_bar/progress_bar_details.dart';
|
||||
import 'package:fluffychat/pangea/analytics_summary/progress_bar/progress_bar_details.dart';
|
||||
|
||||
class ProgressBarBackground extends StatelessWidget {
|
||||
final ProgressBarDetails details;
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:fluffychat/pangea/analytics/enums/progress_indicators_enum.dart';
|
||||
import 'package:fluffychat/pangea/analytics_summary/progress_indicators_enum.dart';
|
||||
import 'package:fluffychat/pangea/common/widgets/pressable_button.dart';
|
||||
|
||||
/// A badge that represents one learning progress indicator (i.e., construct uses)
|
||||
|
|
@ -3,7 +3,7 @@ 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/enums/construct_type_enum.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/construct_type_enum.dart';
|
||||
|
||||
enum ProgressIndicatorEnum {
|
||||
level,
|
||||
|
|
@ -23,6 +23,17 @@ extension ProgressIndicatorsExtension on ProgressIndicatorEnum {
|
|||
}
|
||||
}
|
||||
|
||||
IconData get iconSelected {
|
||||
switch (this) {
|
||||
case ProgressIndicatorEnum.wordsUsed:
|
||||
return Symbols.dictionary;
|
||||
case ProgressIndicatorEnum.morphsUsed:
|
||||
return Symbols.toys_and_games;
|
||||
case ProgressIndicatorEnum.level:
|
||||
return Icons.star;
|
||||
}
|
||||
}
|
||||
|
||||
static bool isDarkMode(BuildContext context) =>
|
||||
Theme.of(context).brightness == Brightness.dark;
|
||||
|
||||
|
|
@ -3,7 +3,7 @@ import 'package:flutter/material.dart';
|
|||
import 'package:flutter_gen/gen_l10n/l10n.dart';
|
||||
|
||||
import 'package:fluffychat/pages/chat_list/chat_list.dart';
|
||||
import 'package:fluffychat/pangea/analytics/widgets/analytics_summary/learning_progress_indicators.dart';
|
||||
import 'package:fluffychat/pangea/analytics_summary/learning_progress_indicators.dart';
|
||||
|
||||
class PangeaChatListHeader extends StatelessWidget
|
||||
implements PreferredSizeWidget {
|
||||
|
|
|
|||
|
|
@ -1,14 +1,15 @@
|
|||
import 'package:fluffychat/pangea/common/config/environment.dart';
|
||||
import 'package:fluffychat/pangea/extensions/pangea_room_extension.dart';
|
||||
import 'package:fluffychat/pangea/spaces/constants/space_constants.dart';
|
||||
import 'package:fluffychat/widgets/matrix.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
import 'package:flutter_gen/gen_l10n/l10n.dart';
|
||||
import 'package:matrix/matrix.dart';
|
||||
import 'package:universal_html/html.dart' as html;
|
||||
|
||||
import 'package:fluffychat/pangea/common/config/environment.dart';
|
||||
import 'package:fluffychat/pangea/extensions/pangea_room_extension.dart';
|
||||
import 'package:fluffychat/pangea/spaces/constants/space_constants.dart';
|
||||
import 'package:fluffychat/widgets/matrix.dart';
|
||||
import '../../../utils/fluffy_share.dart';
|
||||
|
||||
class ClassInvitationButtons extends StatelessWidget {
|
||||
|
|
|
|||
|
|
@ -7,8 +7,8 @@ import 'package:flutter/material.dart';
|
|||
import 'package:http/http.dart' as http;
|
||||
import 'package:sentry_flutter/sentry_flutter.dart';
|
||||
|
||||
import 'package:fluffychat/pangea/analytics/controllers/put_analytics_controller.dart';
|
||||
import 'package:fluffychat/pangea/analytics/enums/construct_use_type_enum.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/construct_use_type_enum.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/put_analytics_controller.dart';
|
||||
import 'package:fluffychat/pangea/choreographer/constants/choreo_constants.dart';
|
||||
import 'package:fluffychat/pangea/choreographer/controllers/error_service.dart';
|
||||
import 'package:fluffychat/pangea/choreographer/enums/edit_type.dart';
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ import 'dart:convert';
|
|||
|
||||
import 'package:http/http.dart';
|
||||
|
||||
import 'package:fluffychat/pangea/analytics/models/lemma.dart';
|
||||
import 'package:fluffychat/pangea/choreographer/models/language_detection_model.dart';
|
||||
import 'package:fluffychat/pangea/choreographer/models/pangea_match_model.dart';
|
||||
import 'package:fluffychat/pangea/choreographer/repo/language_detection_request.dart';
|
||||
|
|
@ -10,6 +9,7 @@ import 'package:fluffychat/pangea/choreographer/repo/span_data_repo.dart';
|
|||
import 'package:fluffychat/pangea/common/config/environment.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';
|
||||
import '../../common/constants/model_keys.dart';
|
||||
import '../../common/network/requests.dart';
|
||||
import '../../common/network/urls.dart';
|
||||
|
|
|
|||
|
|
@ -6,9 +6,9 @@ import 'package:flutter/material.dart';
|
|||
import 'package:flutter_gen/gen_l10n/l10n.dart';
|
||||
|
||||
import 'package:fluffychat/config/app_config.dart';
|
||||
import 'package:fluffychat/pangea/analytics/controllers/put_analytics_controller.dart';
|
||||
import 'package:fluffychat/pangea/analytics/enums/construct_use_type_enum.dart';
|
||||
import 'package:fluffychat/pangea/analytics/widgets/gain_points.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/construct_use_type_enum.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/gain_points_animation.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/put_analytics_controller.dart';
|
||||
import 'package:fluffychat/pangea/bot/utils/bot_style.dart';
|
||||
import 'package:fluffychat/pangea/choreographer/enums/span_data_type.dart';
|
||||
import 'package:fluffychat/pangea/choreographer/models/span_data.dart';
|
||||
|
|
|
|||
|
|
@ -4,9 +4,9 @@ import 'dart:developer';
|
|||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:fluffychat/pangea/analytics/controllers/put_analytics_controller.dart';
|
||||
import 'package:fluffychat/pangea/analytics/enums/construct_use_type_enum.dart';
|
||||
import 'package:fluffychat/pangea/analytics/widgets/gain_points.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/construct_use_type_enum.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/gain_points_animation.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/put_analytics_controller.dart';
|
||||
import 'package:fluffychat/pangea/choreographer/constants/choreo_constants.dart';
|
||||
import 'package:fluffychat/pangea/choreographer/controllers/choreographer.dart';
|
||||
import 'package:fluffychat/pangea/choreographer/controllers/it_controller.dart';
|
||||
|
|
|
|||
|
|
@ -8,8 +8,8 @@ import 'package:get_storage/get_storage.dart';
|
|||
import 'package:matrix/matrix.dart';
|
||||
import 'package:sentry_flutter/sentry_flutter.dart';
|
||||
|
||||
import 'package:fluffychat/pangea/analytics/controllers/get_analytics_controller.dart';
|
||||
import 'package:fluffychat/pangea/analytics/controllers/put_analytics_controller.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/get_analytics_controller.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/put_analytics_controller.dart';
|
||||
import 'package:fluffychat/pangea/bot/utils/bot_name.dart';
|
||||
import 'package:fluffychat/pangea/chat_settings/constants/bot_mode.dart';
|
||||
import 'package:fluffychat/pangea/chat_settings/models/bot_options_model.dart';
|
||||
|
|
|
|||
|
|
@ -72,6 +72,8 @@ class PApiUrls {
|
|||
static String objectiveList = "${PApiUrls.choreoEndpoint}/objectives";
|
||||
static String topicList = "${PApiUrls.choreoEndpoint}/topics";
|
||||
|
||||
static String morphFeaturesAndTags = "${PApiUrls.choreoEndpoint}/morphs";
|
||||
|
||||
///-------------------------------- revenue cat --------------------------
|
||||
static String rcAppsChoreo = "${PApiUrls.subscriptionEndpoint}/app_ids";
|
||||
static String rcProductsChoreo =
|
||||
|
|
|
|||
|
|
@ -5,26 +5,26 @@ import 'package:flutter/foundation.dart';
|
|||
import 'package:collection/collection.dart';
|
||||
import 'package:matrix/matrix.dart';
|
||||
|
||||
import 'package:fluffychat/pangea/analytics/constants/analytics_constants.dart';
|
||||
import 'package:fluffychat/pangea/analytics/enums/construct_type_enum.dart';
|
||||
import 'package:fluffychat/pangea/analytics/enums/construct_use_type_enum.dart';
|
||||
import 'package:fluffychat/pangea/analytics/enums/lemma_category_enum.dart';
|
||||
import 'package:fluffychat/pangea/analytics/extensions/client_analytics_extension.dart';
|
||||
import 'package:fluffychat/pangea/analytics/models/construct_identifier.dart';
|
||||
import 'package:fluffychat/pangea/analytics/models/construct_use_model.dart';
|
||||
import 'package:fluffychat/pangea/analytics/models/constructs_model.dart';
|
||||
import 'package:fluffychat/pangea/analytics/repo/lemma_info_repo.dart';
|
||||
import 'package:fluffychat/pangea/analytics/repo/lemma_info_request.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/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/toolbar/enums/activity_type_enum.dart';
|
||||
import 'package:fluffychat/pangea/toolbar/repo/lemma_activity_generator.dart';
|
||||
import 'package:fluffychat/pangea/toolbar/repo/lemma_meaning_activity_generator.dart';
|
||||
import 'package:fluffychat/widgets/matrix.dart';
|
||||
import '../../analytics/models/lemma.dart';
|
||||
import '../../common/constants/model_keys.dart';
|
||||
import '../../lemmas/lemma.dart';
|
||||
|
||||
class PangeaToken {
|
||||
PangeaTokenText text;
|
||||
|
|
@ -624,13 +624,13 @@ class PangeaToken {
|
|||
}
|
||||
}
|
||||
|
||||
LemmaCategoryEnum get lemmaXPCategory {
|
||||
ConstructLevelEnum get lemmaXPCategory {
|
||||
if (vocabConstruct.points >= AnalyticsConstants.xpForFlower) {
|
||||
return LemmaCategoryEnum.flowers;
|
||||
return ConstructLevelEnum.flowers;
|
||||
} else if (vocabConstruct.points >= AnalyticsConstants.xpForGreens) {
|
||||
return LemmaCategoryEnum.greens;
|
||||
return ConstructLevelEnum.greens;
|
||||
} else {
|
||||
return LemmaCategoryEnum.seeds;
|
||||
return ConstructLevelEnum.seeds;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
import 'package:matrix/matrix.dart';
|
||||
|
||||
import 'package:fluffychat/pangea/analytics/enums/construct_type_enum.dart';
|
||||
import 'package:fluffychat/pangea/analytics/enums/construct_use_type_enum.dart';
|
||||
import 'package:fluffychat/pangea/analytics/models/constructs_model.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/choreographer/models/choreo_record.dart';
|
||||
import 'package:fluffychat/pangea/choreographer/models/pangea_match_model.dart';
|
||||
import 'package:fluffychat/pangea/events/models/pangea_token_model.dart';
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:fluffychat/pangea/analytics/controllers/message_analytics_controller.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/message_analytics_controller.dart';
|
||||
import 'package:fluffychat/pangea/common/utils/error_handler.dart';
|
||||
import 'package:fluffychat/pangea/events/event_wrappers/pangea_message_event.dart';
|
||||
import 'package:fluffychat/pangea/events/models/pangea_token_model.dart';
|
||||
|
|
|
|||
|
|
@ -15,8 +15,8 @@ import 'package:matrix/matrix.dart';
|
|||
import 'package:matrix/src/utils/markdown.dart';
|
||||
import 'package:sentry_flutter/sentry_flutter.dart';
|
||||
|
||||
import 'package:fluffychat/pangea/analytics/models/constructs_event.dart';
|
||||
import 'package:fluffychat/pangea/analytics/models/constructs_model.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/constructs_event.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/constructs_model.dart';
|
||||
import 'package:fluffychat/pangea/bot/utils/bot_name.dart';
|
||||
import 'package:fluffychat/pangea/chat_settings/constants/bot_mode.dart';
|
||||
import 'package:fluffychat/pangea/chat_settings/constants/pangea_room_types.dart';
|
||||
|
|
@ -30,7 +30,7 @@ import '../choreographer/models/choreo_record.dart';
|
|||
import '../events/constants/pangea_event_types.dart';
|
||||
import '../events/models/representation_content_model.dart';
|
||||
|
||||
part "../analytics/extensions/room_analytics_extension.dart";
|
||||
part "../analytics_misc/room_analytics_extension.dart";
|
||||
part "room_children_and_parents_extension.dart";
|
||||
part "room_events_extension.dart";
|
||||
part "room_information_extension.dart";
|
||||
|
|
|
|||
|
|
@ -6,14 +6,14 @@ import 'package:flutter/foundation.dart';
|
|||
import 'package:get_storage/get_storage.dart';
|
||||
import 'package:http/http.dart';
|
||||
|
||||
import 'package:fluffychat/pangea/analytics/repo/lemma_info_request.dart';
|
||||
import 'package:fluffychat/pangea/analytics/repo/lemma_info_response.dart';
|
||||
import 'package:fluffychat/pangea/common/network/urls.dart';
|
||||
import 'package:fluffychat/pangea/common/utils/error_handler.dart';
|
||||
import 'package:fluffychat/pangea/events/models/content_feedback.dart';
|
||||
import 'package:fluffychat/pangea/lemmas/lemma_info_request.dart';
|
||||
import 'package:fluffychat/pangea/lemmas/lemma_info_response.dart';
|
||||
import 'package:fluffychat/widgets/matrix.dart';
|
||||
import '../../common/config/environment.dart';
|
||||
import '../../common/network/requests.dart';
|
||||
import '../common/config/environment.dart';
|
||||
import '../common/network/requests.dart';
|
||||
|
||||
class LemmaInfoRepo {
|
||||
static final GetStorage _lemmaStorage = GetStorage('lemma_storage');
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
import 'package:fluffychat/pangea/analytics/repo/lemma_info_response.dart';
|
||||
import 'package:fluffychat/pangea/events/models/content_feedback.dart';
|
||||
import 'package:fluffychat/pangea/lemmas/lemma_info_response.dart';
|
||||
|
||||
class LemmaInfoRequest {
|
||||
final String lemma;
|
||||
235
lib/pangea/morphs/default_morph_mapping.dart
Normal file
235
lib/pangea/morphs/default_morph_mapping.dart
Normal file
|
|
@ -0,0 +1,235 @@
|
|||
import 'package:fluffychat/pangea/morphs/morph_models.dart';
|
||||
|
||||
final MorphFeatuuresAndTags defaultMorphMapping =
|
||||
MorphFeatuuresAndTags.fromJson({
|
||||
"language_code": "default",
|
||||
"features": [
|
||||
{
|
||||
"feature": "pos",
|
||||
"tag": [
|
||||
"ADJ",
|
||||
"ADP",
|
||||
"ADV",
|
||||
"AFFIX",
|
||||
"AUX",
|
||||
"CCONJ",
|
||||
"DET",
|
||||
"INTJ",
|
||||
"NOUN",
|
||||
"NUM",
|
||||
"PART",
|
||||
"PRON",
|
||||
"PROPN",
|
||||
"PUNCT",
|
||||
"SCONJ",
|
||||
"SPACE",
|
||||
"SYM",
|
||||
"VERB",
|
||||
"X",
|
||||
],
|
||||
},
|
||||
{
|
||||
"feature": "advtype",
|
||||
"tag": ["Adverbial", "Tim"],
|
||||
},
|
||||
{
|
||||
"feature": "aspect",
|
||||
"tag": ["Imp", "Perf", "Prog", "Hab"],
|
||||
},
|
||||
{
|
||||
"feature": "case",
|
||||
"tag": [
|
||||
"Nom",
|
||||
"Acc",
|
||||
"Dat",
|
||||
"Gen",
|
||||
"Voc",
|
||||
"Abl",
|
||||
"Loc",
|
||||
"All",
|
||||
"Ins",
|
||||
"Ess",
|
||||
"Tra",
|
||||
"Com",
|
||||
"Par",
|
||||
"Adv",
|
||||
"Ref",
|
||||
"Rel",
|
||||
"Equ",
|
||||
"Dis",
|
||||
"Abs",
|
||||
"Erg",
|
||||
"Cau",
|
||||
"Ben",
|
||||
"Sub",
|
||||
"Sup",
|
||||
"Tem",
|
||||
"Obl",
|
||||
"Acc,Dat",
|
||||
"Acc,Nom",
|
||||
"Pre",
|
||||
],
|
||||
},
|
||||
{
|
||||
"feature": "conjtype",
|
||||
"tag": ["Coord", "Sub", "Cmp"],
|
||||
},
|
||||
{
|
||||
"feature": "definite",
|
||||
"tag": ["Def", "Ind", "Cons"],
|
||||
},
|
||||
{
|
||||
"feature": "degree",
|
||||
"tag": ["Pos", "Cmp", "Sup", "Abs"],
|
||||
},
|
||||
{
|
||||
"feature": "evident",
|
||||
"tag": ["Fh", "Nfh"],
|
||||
},
|
||||
{
|
||||
"feature": "foreign",
|
||||
"tag": ["Yes"],
|
||||
},
|
||||
{
|
||||
"feature": "gender",
|
||||
"tag": ["Masc", "Fem", "Neut", "Com"],
|
||||
},
|
||||
{
|
||||
"feature": "mood",
|
||||
"tag": [
|
||||
"Ind",
|
||||
"Imp",
|
||||
"Sub",
|
||||
"Cnd",
|
||||
"Opt",
|
||||
"Jus",
|
||||
"Adm",
|
||||
"Des",
|
||||
"Nec",
|
||||
"Pot",
|
||||
"Prp",
|
||||
"Qot",
|
||||
"Int",
|
||||
],
|
||||
},
|
||||
{
|
||||
"feature": "nountype",
|
||||
"tag": ["Prop", "Comm", "Not_proper"],
|
||||
},
|
||||
{
|
||||
"feature": "numform",
|
||||
"tag": ["Digit", "Word", "Roman", "Letter"],
|
||||
},
|
||||
{
|
||||
"feature": "numtype",
|
||||
"tag": ["Card", "Ord", "Mult", "Frac", "Sets", "Range", "Dist"],
|
||||
},
|
||||
{
|
||||
"feature": "number",
|
||||
"tag": ["Sing", "Plur", "Dual", "Tri", "Pauc", "Grpa", "Grpl", "Inv"],
|
||||
},
|
||||
{
|
||||
"feature": "number[psor]",
|
||||
"tag": ["Sing", "Plur", "Dual"],
|
||||
},
|
||||
{
|
||||
"feature": "person",
|
||||
"tag": ["0", "1", "2", "3", "4"],
|
||||
},
|
||||
{
|
||||
"feature": "polarity",
|
||||
"tag": ["Pos", "Neg"],
|
||||
},
|
||||
{
|
||||
"feature": "polite",
|
||||
"tag": ["Infm", "Form", "Elev", "Humb"],
|
||||
},
|
||||
{
|
||||
"feature": "poss",
|
||||
"tag": ["Yes"],
|
||||
},
|
||||
{
|
||||
"feature": "prepcase",
|
||||
"tag": ["Npr"],
|
||||
},
|
||||
{
|
||||
"feature": "prontype",
|
||||
"tag": [
|
||||
"Prs",
|
||||
"Int",
|
||||
"Rel",
|
||||
"Dem",
|
||||
"Tot",
|
||||
"Neg",
|
||||
"Art",
|
||||
"Emp",
|
||||
"Exc",
|
||||
"Ind",
|
||||
"Rcp",
|
||||
"Int,Rel",
|
||||
],
|
||||
},
|
||||
{
|
||||
"feature": "punctside",
|
||||
"tag": ["Ini", "Fin"],
|
||||
},
|
||||
{
|
||||
"feature": "puncttype",
|
||||
"tag": [
|
||||
"Brck",
|
||||
"Dash",
|
||||
"Excl",
|
||||
"Peri",
|
||||
"Qest",
|
||||
"Quot",
|
||||
"Semi",
|
||||
"Colo",
|
||||
"Comm",
|
||||
],
|
||||
},
|
||||
{
|
||||
"feature": "reflex",
|
||||
"tag": ["Yes"],
|
||||
},
|
||||
{
|
||||
"feature": "tense",
|
||||
"tag": ["Pres", "Past", "Fut", "Imp", "Pqp", "Aor", "Eps", "Prosp"],
|
||||
},
|
||||
{
|
||||
"feature": "verbform",
|
||||
"tag": [
|
||||
"Fin",
|
||||
"Inf",
|
||||
"Sup",
|
||||
"Part",
|
||||
"Conv",
|
||||
"Vnoun",
|
||||
"Ger",
|
||||
"Adn",
|
||||
"Lng",
|
||||
],
|
||||
},
|
||||
{
|
||||
"feature": "verbtype",
|
||||
"tag": ["Mod", "Caus"],
|
||||
},
|
||||
{
|
||||
"feature": "voice",
|
||||
"tag": [
|
||||
"Act",
|
||||
"Mid",
|
||||
"Pass",
|
||||
"Antip",
|
||||
"Cau",
|
||||
"Dir",
|
||||
"Inv",
|
||||
"Rcp",
|
||||
"Caus",
|
||||
],
|
||||
},
|
||||
{
|
||||
"feature": "x",
|
||||
"tag": ["X"],
|
||||
}
|
||||
],
|
||||
});
|
||||
234
lib/pangea/morphs/default_ud_mapping.dart
Normal file
234
lib/pangea/morphs/default_ud_mapping.dart
Normal file
|
|
@ -0,0 +1,234 @@
|
|||
import 'package:fluffychat/pangea/morphs/morph_models.dart';
|
||||
|
||||
final MorphFeatuuresAndTags defaultUDMapping = MorphFeatuuresAndTags.fromJson({
|
||||
"language_code": "default",
|
||||
"features": [
|
||||
{
|
||||
"feature": "pos",
|
||||
"tag": [
|
||||
"ADJ",
|
||||
"ADP",
|
||||
"ADV",
|
||||
"AFFIX",
|
||||
"AUX",
|
||||
"CCONJ",
|
||||
"DET",
|
||||
"INTJ",
|
||||
"NOUN",
|
||||
"NUM",
|
||||
"PART",
|
||||
"PRON",
|
||||
"PROPN",
|
||||
"PUNCT",
|
||||
"SCONJ",
|
||||
"SPACE",
|
||||
"SYM",
|
||||
"VERB",
|
||||
"X",
|
||||
],
|
||||
},
|
||||
{
|
||||
"feature": "advtype",
|
||||
"tag": ["Adverbial", "Tim"],
|
||||
},
|
||||
{
|
||||
"feature": "aspect",
|
||||
"tag": ["Imp", "Perf", "Prog", "Hab"],
|
||||
},
|
||||
{
|
||||
"feature": "case",
|
||||
"tag": [
|
||||
"Nom",
|
||||
"Acc",
|
||||
"Dat",
|
||||
"Gen",
|
||||
"Voc",
|
||||
"Abl",
|
||||
"Loc",
|
||||
"All",
|
||||
"Ins",
|
||||
"Ess",
|
||||
"Tra",
|
||||
"Com",
|
||||
"Par",
|
||||
"Adv",
|
||||
"Ref",
|
||||
"Rel",
|
||||
"Equ",
|
||||
"Dis",
|
||||
"Abs",
|
||||
"Erg",
|
||||
"Cau",
|
||||
"Ben",
|
||||
"Sub",
|
||||
"Sup",
|
||||
"Tem",
|
||||
"Obl",
|
||||
"Acc,Dat",
|
||||
"Acc,Nom",
|
||||
"Pre",
|
||||
],
|
||||
},
|
||||
{
|
||||
"feature": "conjtype",
|
||||
"tag": ["Coord", "Sub", "Cmp"],
|
||||
},
|
||||
{
|
||||
"feature": "definite",
|
||||
"tag": ["Def", "Ind", "Cons"],
|
||||
},
|
||||
{
|
||||
"feature": "degree",
|
||||
"tag": ["Pos", "Cmp", "Sup", "Abs"],
|
||||
},
|
||||
{
|
||||
"feature": "evident",
|
||||
"tag": ["Fh", "Nfh"],
|
||||
},
|
||||
{
|
||||
"feature": "foreign",
|
||||
"tag": ["Yes"],
|
||||
},
|
||||
{
|
||||
"feature": "gender",
|
||||
"tag": ["Masc", "Fem", "Neut", "Com"],
|
||||
},
|
||||
{
|
||||
"feature": "mood",
|
||||
"tag": [
|
||||
"Ind",
|
||||
"Imp",
|
||||
"Sub",
|
||||
"Cnd",
|
||||
"Opt",
|
||||
"Jus",
|
||||
"Adm",
|
||||
"Des",
|
||||
"Nec",
|
||||
"Pot",
|
||||
"Prp",
|
||||
"Qot",
|
||||
"Int",
|
||||
],
|
||||
},
|
||||
{
|
||||
"feature": "nountype",
|
||||
"tag": ["Prop", "Comm", "Not_proper"],
|
||||
},
|
||||
{
|
||||
"feature": "numform",
|
||||
"tag": ["Digit", "Word", "Roman", "Letter"],
|
||||
},
|
||||
{
|
||||
"feature": "numtype",
|
||||
"tag": ["Card", "Ord", "Mult", "Frac", "Sets", "Range", "Dist"],
|
||||
},
|
||||
{
|
||||
"feature": "number",
|
||||
"tag": ["Sing", "Plur", "Dual", "Tri", "Pauc", "Grpa", "Grpl", "Inv"],
|
||||
},
|
||||
{
|
||||
"feature": "number[psor]",
|
||||
"tag": ["Sing", "Plur", "Dual"],
|
||||
},
|
||||
{
|
||||
"feature": "person",
|
||||
"tag": ["0", "1", "2", "3", "4"],
|
||||
},
|
||||
{
|
||||
"feature": "polarity",
|
||||
"tag": ["Pos", "Neg"],
|
||||
},
|
||||
{
|
||||
"feature": "polite",
|
||||
"tag": ["Infm", "Form", "Elev", "Humb"],
|
||||
},
|
||||
{
|
||||
"feature": "poss",
|
||||
"tag": ["Yes"],
|
||||
},
|
||||
{
|
||||
"feature": "prepcase",
|
||||
"tag": ["Npr"],
|
||||
},
|
||||
{
|
||||
"feature": "prontype",
|
||||
"tag": [
|
||||
"Prs",
|
||||
"Int",
|
||||
"Rel",
|
||||
"Dem",
|
||||
"Tot",
|
||||
"Neg",
|
||||
"Art",
|
||||
"Emp",
|
||||
"Exc",
|
||||
"Ind",
|
||||
"Rcp",
|
||||
"Int,Rel",
|
||||
],
|
||||
},
|
||||
{
|
||||
"feature": "punctside",
|
||||
"tag": ["Ini", "Fin"],
|
||||
},
|
||||
{
|
||||
"feature": "puncttype",
|
||||
"tag": [
|
||||
"Brck",
|
||||
"Dash",
|
||||
"Excl",
|
||||
"Peri",
|
||||
"Qest",
|
||||
"Quot",
|
||||
"Semi",
|
||||
"Colo",
|
||||
"Comm",
|
||||
],
|
||||
},
|
||||
{
|
||||
"feature": "reflex",
|
||||
"tag": ["Yes"],
|
||||
},
|
||||
{
|
||||
"feature": "tense",
|
||||
"tag": ["Pres", "Past", "Fut", "Imp", "Pqp", "Aor", "Eps", "Prosp"],
|
||||
},
|
||||
{
|
||||
"feature": "verbform",
|
||||
"tag": [
|
||||
"Fin",
|
||||
"Inf",
|
||||
"Sup",
|
||||
"Part",
|
||||
"Conv",
|
||||
"Vnoun",
|
||||
"Ger",
|
||||
"Adn",
|
||||
"Lng",
|
||||
],
|
||||
},
|
||||
{
|
||||
"feature": "verbtype",
|
||||
"tag": ["Mod", "Caus"],
|
||||
},
|
||||
{
|
||||
"feature": "voice",
|
||||
"tag": [
|
||||
"Act",
|
||||
"Mid",
|
||||
"Pass",
|
||||
"Antip",
|
||||
"Cau",
|
||||
"Dir",
|
||||
"Inv",
|
||||
"Rcp",
|
||||
"Caus",
|
||||
],
|
||||
},
|
||||
{
|
||||
"feature": "x",
|
||||
"tag": ["X"],
|
||||
}
|
||||
],
|
||||
});
|
||||
57
lib/pangea/morphs/get_icon_for_morph_feature.dart
Normal file
57
lib/pangea/morphs/get_icon_for_morph_feature.dart
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:material_symbols_icons/symbols.dart';
|
||||
|
||||
// TODO Use the icons that Khue is creating
|
||||
IconData getIconForMorphFeature(String feature) {
|
||||
// Define a function to get the icon based on the universal dependency morphological feature (key)
|
||||
switch (feature.toLowerCase()) {
|
||||
case 'number':
|
||||
// google material 123 icon
|
||||
return Icons.format_list_numbered;
|
||||
case 'gender':
|
||||
return Icons.wc;
|
||||
case 'tense':
|
||||
return Icons.access_time;
|
||||
case 'mood':
|
||||
return Icons.mood;
|
||||
case 'person':
|
||||
return Icons.person;
|
||||
case 'case':
|
||||
return Icons.format_list_bulleted;
|
||||
case 'degree':
|
||||
return Icons.trending_up;
|
||||
case 'verbform':
|
||||
return Icons.text_format;
|
||||
case 'voice':
|
||||
return Icons.record_voice_over;
|
||||
case 'aspect':
|
||||
return Icons.aspect_ratio;
|
||||
case 'prontype':
|
||||
return Icons.text_fields;
|
||||
case 'numtype':
|
||||
return Icons.format_list_numbered;
|
||||
case 'poss':
|
||||
return Icons.account_balance;
|
||||
case 'reflex':
|
||||
return Icons.refresh;
|
||||
case 'foreign':
|
||||
return Icons.language;
|
||||
case 'abbr':
|
||||
return Icons.text_format;
|
||||
case 'nountype':
|
||||
return Symbols.abc;
|
||||
case 'pos':
|
||||
return Symbols.toys_and_games;
|
||||
case 'polarity':
|
||||
return Icons.swap_vert;
|
||||
case 'definite':
|
||||
return Icons.check_circle_outline;
|
||||
case 'prepcase':
|
||||
return Icons.location_on_outlined;
|
||||
case 'conjtype':
|
||||
return Icons.compare_arrows;
|
||||
default:
|
||||
return Icons.help_outline;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,232 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:flutter_gen/gen_l10n/l10n.dart';
|
||||
|
||||
import 'package:fluffychat/config/app_config.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_summary/progress_indicators_enum.dart';
|
||||
import 'package:fluffychat/pangea/common/widgets/full_width_dialog.dart';
|
||||
import 'package:fluffychat/pangea/morphs/get_grammar_copy.dart';
|
||||
import 'package:fluffychat/pangea/morphs/morph_icon.dart';
|
||||
import 'package:fluffychat/pangea/morphs/morph_models.dart';
|
||||
import 'package:fluffychat/widgets/matrix.dart';
|
||||
import '../../morphs/morph_repo.dart';
|
||||
|
||||
class MorphAnalyticsPopup extends StatelessWidget {
|
||||
const MorphAnalyticsPopup({
|
||||
super.key,
|
||||
});
|
||||
|
||||
List<MorphFeature> get availableFeatures => MorphsRepo.get().displayFeatures;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => FullWidthDialog(
|
||||
dialogContent: Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text(ConstructTypeEnum.morph.indicator.tooltip(context)),
|
||||
leading: IconButton(
|
||||
icon: const Icon(Icons.close),
|
||||
onPressed: Navigator.of(context).pop,
|
||||
),
|
||||
),
|
||||
body: Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 20),
|
||||
child: ListView.builder(
|
||||
itemCount: availableFeatures.length,
|
||||
itemBuilder: (context, index) =>
|
||||
availableFeatures[index].displayTags.isNotEmpty
|
||||
? MorphFeatureBox(
|
||||
morphFeature: availableFeatures[index].feature,
|
||||
)
|
||||
: const SizedBox.shrink(),
|
||||
),
|
||||
),
|
||||
),
|
||||
maxWidth: 600,
|
||||
maxHeight: 800,
|
||||
);
|
||||
}
|
||||
|
||||
class MorphFeatureBox extends StatelessWidget {
|
||||
final String morphFeature;
|
||||
|
||||
const MorphFeatureBox({
|
||||
super.key,
|
||||
required this.morphFeature,
|
||||
});
|
||||
|
||||
// get constructData => MatrixState.pangeaController.
|
||||
|
||||
String _categoryCopy(
|
||||
String category,
|
||||
BuildContext context,
|
||||
) {
|
||||
if (category.toLowerCase() == "other") {
|
||||
return L10n.of(context).other;
|
||||
}
|
||||
|
||||
return ConstructTypeEnum.morph.getDisplayCopy(
|
||||
category,
|
||||
context,
|
||||
) ??
|
||||
category;
|
||||
}
|
||||
|
||||
Set<String> get allTags => MorphsRepo.get()
|
||||
.getDisplayTags(morphFeature)
|
||||
.map((tag) => tag.toLowerCase())
|
||||
.toSet();
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final theme = Theme.of(context);
|
||||
|
||||
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: AppConfig.gold.withAlpha(100), width: 2),
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
spacing: 16.0,
|
||||
children: [
|
||||
SizedBox(
|
||||
height: 30.0,
|
||||
width: 30.0,
|
||||
child: MorphIcon(morphFeature: morphFeature, morphTag: null),
|
||||
),
|
||||
Text(
|
||||
_categoryCopy(morphFeature, context),
|
||||
style: theme.textTheme.bodyLarge?.copyWith(
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 16.0),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Flexible(
|
||||
child: Wrap(
|
||||
alignment: WrapAlignment.center,
|
||||
spacing: 16.0,
|
||||
runSpacing: 16.0,
|
||||
children: allTags
|
||||
.map(
|
||||
(morphTag) => MorphTagChip(
|
||||
morphFeature: morphFeature,
|
||||
morphTag: morphTag,
|
||||
constructAnalytics: MatrixState.pangeaController
|
||||
.getAnalytics.constructListModel
|
||||
.getConstructUses(
|
||||
ConstructIdentifier(
|
||||
lemma: morphTag,
|
||||
type: ConstructTypeEnum.morph,
|
||||
category: morphFeature,
|
||||
),
|
||||
) ??
|
||||
ConstructUses(
|
||||
lemma: morphTag,
|
||||
constructType: ConstructTypeEnum.morph,
|
||||
category: morphFeature,
|
||||
uses: [],
|
||||
),
|
||||
),
|
||||
)
|
||||
.sortedBy<num>((chip) => chip.constructAnalytics.points)
|
||||
.reversed
|
||||
.toList(),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class MorphTagChip extends StatelessWidget {
|
||||
final String morphFeature;
|
||||
final String morphTag;
|
||||
final ConstructUses constructAnalytics;
|
||||
|
||||
const MorphTagChip({
|
||||
super.key,
|
||||
required this.morphFeature,
|
||||
required this.morphTag,
|
||||
required this.constructAnalytics,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final theme = Theme.of(context);
|
||||
|
||||
return Opacity(
|
||||
opacity: constructAnalytics.points > 0 ? 1.0 : 0.3,
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(32.0),
|
||||
gradient: constructAnalytics.points > 0
|
||||
? LinearGradient(
|
||||
begin: Alignment.centerLeft,
|
||||
end: Alignment.centerRight,
|
||||
colors: <Color>[
|
||||
Colors.transparent,
|
||||
constructAnalytics.lemmaCategory.color,
|
||||
],
|
||||
)
|
||||
: null,
|
||||
color: constructAnalytics.points > 0 ? null : theme.disabledColor,
|
||||
),
|
||||
padding: const EdgeInsets.symmetric(
|
||||
vertical: 4.0,
|
||||
horizontal: 8.0,
|
||||
),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
spacing: 8.0,
|
||||
children: [
|
||||
SizedBox(
|
||||
width: 28.0,
|
||||
height: 28.0,
|
||||
child: constructAnalytics.points > 0
|
||||
? MorphIcon(
|
||||
morphFeature: morphFeature,
|
||||
morphTag: morphTag,
|
||||
)
|
||||
: const Icon(
|
||||
Icons.lock,
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
Text(
|
||||
getGrammarCopy(
|
||||
category: morphFeature,
|
||||
lemma: morphTag,
|
||||
context: context,
|
||||
) ??
|
||||
morphTag,
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
color: theme.brightness == Brightness.dark
|
||||
? Colors.white
|
||||
: Colors.black,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
37
lib/pangea/morphs/morph_icon.dart
Normal file
37
lib/pangea/morphs/morph_icon.dart
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:fluffychat/pangea/common/widgets/customized_svg.dart';
|
||||
import 'package:fluffychat/pangea/morphs/get_icon_for_morph_feature.dart';
|
||||
import 'package:fluffychat/pangea/morphs/get_svg_link.dart';
|
||||
import 'package:fluffychat/utils/color_value.dart';
|
||||
|
||||
class MorphIcon extends StatelessWidget {
|
||||
const MorphIcon({
|
||||
super.key,
|
||||
required this.morphFeature,
|
||||
required this.morphTag,
|
||||
});
|
||||
|
||||
final String morphFeature;
|
||||
final String? morphTag;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final ThemeData theme = Theme.of(context);
|
||||
|
||||
return CustomizedSvg(
|
||||
svgUrl: getMorphSvgLink(
|
||||
morphFeature: morphFeature,
|
||||
morphTag: morphTag,
|
||||
context: context,
|
||||
),
|
||||
colorReplacements: theme.brightness == Brightness.dark
|
||||
? {
|
||||
"white": theme.cardColor.hexValue.toString(),
|
||||
"black": "white",
|
||||
}
|
||||
: {},
|
||||
errorIcon: Icon(getIconForMorphFeature(morphFeature)),
|
||||
);
|
||||
}
|
||||
}
|
||||
95
lib/pangea/morphs/morph_models.dart
Normal file
95
lib/pangea/morphs/morph_models.dart
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
import 'package:collection/collection.dart';
|
||||
|
||||
import 'package:fluffychat/pangea/common/utils/error_handler.dart';
|
||||
|
||||
class MorphFeature {
|
||||
final String feature;
|
||||
final List<String> tags;
|
||||
|
||||
MorphFeature({required this.feature, required this.tags});
|
||||
|
||||
factory MorphFeature.fromJson(Map<String, dynamic> json) {
|
||||
return MorphFeature(
|
||||
feature: json['feature'],
|
||||
tags: List<String>.from(json['tag']),
|
||||
);
|
||||
}
|
||||
|
||||
List<String> get displayTags => tags
|
||||
.where(
|
||||
(t) =>
|
||||
!["punct", "space", "sym", "x", "other"].contains(t.toLowerCase()),
|
||||
)
|
||||
.toList();
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
return {
|
||||
'feature': feature,
|
||||
'tag': tags,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
class MorphFeatuuresAndTags {
|
||||
final String languageCode;
|
||||
final List<MorphFeature> features;
|
||||
|
||||
MorphFeatuuresAndTags({required this.languageCode, required this.features});
|
||||
|
||||
factory MorphFeatuuresAndTags.fromJson(Map<String, dynamic> json) {
|
||||
return MorphFeatuuresAndTags(
|
||||
languageCode: json['language_code'],
|
||||
features: List<MorphFeature>.from(
|
||||
json['features'].map((x) => MorphFeature.fromJson(x)),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
return {
|
||||
'language_code': languageCode,
|
||||
'features': features.map((x) => x.toJson()).toList(),
|
||||
};
|
||||
}
|
||||
|
||||
/// Returns the tags for a given feature
|
||||
List<String> getAllTags(String feature) =>
|
||||
features
|
||||
.firstWhereOrNull((element) => element.feature == feature)
|
||||
?.tags ??
|
||||
[];
|
||||
|
||||
/// Returns the display tags for a given feature
|
||||
/// i.e. minus punc, space, x, etc
|
||||
List<String> getDisplayTags(String feature) =>
|
||||
features
|
||||
.firstWhereOrNull((element) => element.feature == feature)
|
||||
?.displayTags ??
|
||||
[];
|
||||
|
||||
List<MorphFeature> get displayFeatures => features
|
||||
.where(
|
||||
(f) => f.feature.toLowerCase() != "foreign",
|
||||
)
|
||||
.toList();
|
||||
|
||||
List<String> get categories => features.map((e) => e.feature).toList();
|
||||
|
||||
String guessMorphCategory(String morphLemma) {
|
||||
for (final MorphFeature feature in features) {
|
||||
if (feature.tags.contains(morphLemma)) {
|
||||
// debugPrint(
|
||||
// "found missing construct category for $morphLemma: $category",
|
||||
// );
|
||||
return feature.feature;
|
||||
}
|
||||
}
|
||||
ErrorHandler.logError(
|
||||
m: "Morph construct lemma $morphLemma not found in morph categories and labels",
|
||||
data: {
|
||||
"morphLemma": morphLemma,
|
||||
},
|
||||
);
|
||||
return "Other";
|
||||
}
|
||||
}
|
||||
110
lib/pangea/morphs/morph_repo.dart
Normal file
110
lib/pangea/morphs/morph_repo.dart
Normal file
|
|
@ -0,0 +1,110 @@
|
|||
import 'dart:convert';
|
||||
import 'dart:developer';
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
|
||||
import 'package:get_storage/get_storage.dart';
|
||||
import 'package:http/http.dart';
|
||||
|
||||
import 'package:fluffychat/pangea/common/config/environment.dart';
|
||||
import 'package:fluffychat/pangea/common/network/urls.dart';
|
||||
import 'package:fluffychat/pangea/common/utils/error_handler.dart';
|
||||
import 'package:fluffychat/pangea/morphs/default_morph_mapping.dart';
|
||||
import 'package:fluffychat/pangea/morphs/morph_models.dart';
|
||||
import 'package:fluffychat/widgets/matrix.dart';
|
||||
import '../common/network/requests.dart';
|
||||
|
||||
class _APICallCacheItem {
|
||||
final DateTime time;
|
||||
final Future<MorphFeatuuresAndTags> future;
|
||||
|
||||
_APICallCacheItem(this.time, this.future);
|
||||
}
|
||||
|
||||
class MorphsRepo {
|
||||
// long-term storage of morphs
|
||||
static final GetStorage _morphsStorage = GetStorage('morphs_storage');
|
||||
|
||||
// to avoid multiple fetches for the same language code
|
||||
// by different parts of the app within a short time
|
||||
static final shortTermCache = <String, _APICallCacheItem>{};
|
||||
static const int _cacheDurationMinutes = 1;
|
||||
|
||||
static void set(String languageCode, MorphFeatuuresAndTags response) {
|
||||
_morphsStorage.write(
|
||||
languageCode,
|
||||
response.toJson(),
|
||||
);
|
||||
}
|
||||
|
||||
static MorphFeatuuresAndTags fromJson(Map<String, dynamic> json) {
|
||||
return MorphFeatuuresAndTags.fromJson(json);
|
||||
}
|
||||
|
||||
static Future<MorphFeatuuresAndTags> _fetch(String languageCode) async {
|
||||
try {
|
||||
final Requests req = Requests(
|
||||
choreoApiKey: Environment.choreoApiKey,
|
||||
accessToken: MatrixState.pangeaController.userController.accessToken,
|
||||
);
|
||||
|
||||
final Response res = await req.get(
|
||||
url: '${PApiUrls.morphFeaturesAndTags}/$languageCode',
|
||||
);
|
||||
|
||||
final decodedBody = jsonDecode(utf8.decode(res.bodyBytes));
|
||||
final response = MorphsRepo.fromJson(decodedBody);
|
||||
|
||||
set(languageCode, response);
|
||||
|
||||
return response;
|
||||
} catch (e, s) {
|
||||
debugger(when: kDebugMode);
|
||||
ErrorHandler.logError(
|
||||
e: e,
|
||||
s: s,
|
||||
data: {
|
||||
"languageCode": languageCode,
|
||||
},
|
||||
);
|
||||
return defaultMorphMapping;
|
||||
}
|
||||
}
|
||||
|
||||
/// this function fetches the morphs for a given language code
|
||||
/// while remaining synchronous by using a default value
|
||||
/// if the morphs are not yet fetched. we'll see if this works well
|
||||
/// if not, we can make it async and update uses of this function
|
||||
/// to be async as well
|
||||
static MorphFeatuuresAndTags get([String? languageCode]) {
|
||||
languageCode ??=
|
||||
MatrixState.pangeaController.languageController.userL2?.langCode;
|
||||
|
||||
if (languageCode == null) {
|
||||
return defaultMorphMapping;
|
||||
}
|
||||
|
||||
// check if we have a cached morphs for this language code
|
||||
final cachedJson = _morphsStorage.read(languageCode);
|
||||
if (cachedJson != null) {
|
||||
return MorphsRepo.fromJson(cachedJson);
|
||||
}
|
||||
|
||||
// check if we have a cached call for this language code
|
||||
final _APICallCacheItem? cachedCall = shortTermCache[languageCode];
|
||||
if (cachedCall != null) {
|
||||
if (DateTime.now().difference(cachedCall.time).inMinutes <
|
||||
_cacheDurationMinutes) {
|
||||
return defaultMorphMapping;
|
||||
} else {
|
||||
shortTermCache.remove(languageCode);
|
||||
}
|
||||
}
|
||||
|
||||
// fetch the morphs but don't wait for it
|
||||
final future = _fetch(languageCode);
|
||||
shortTermCache[languageCode] = _APICallCacheItem(DateTime.now(), future);
|
||||
|
||||
return defaultMorphMapping;
|
||||
}
|
||||
}
|
||||
|
|
@ -7,16 +7,16 @@ import 'package:matrix/matrix.dart';
|
|||
|
||||
import 'package:fluffychat/config/app_config.dart';
|
||||
import 'package:fluffychat/config/themes.dart';
|
||||
import 'package:fluffychat/pangea/analytics/enums/analytics_summary_enum.dart';
|
||||
import 'package:fluffychat/pangea/analytics/models/analytics_summary_model.dart';
|
||||
import 'package:fluffychat/pangea/analytics/models/construct_list_model.dart';
|
||||
import 'package:fluffychat/pangea/analytics/models/construct_use_model.dart';
|
||||
import 'package:fluffychat/pangea/analytics/models/constructs_model.dart';
|
||||
import 'package:fluffychat/pangea/analytics/utils/get_grammar_copy.dart';
|
||||
import 'package:fluffychat/pangea/analytics_downloads/analytics_summary_enum.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/analytics_summary_model.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/construct_list_model.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/construct_use_model.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/constructs_model.dart';
|
||||
import 'package:fluffychat/pangea/bot/utils/bot_name.dart';
|
||||
import 'package:fluffychat/pangea/chat_settings/utils/download_file.dart';
|
||||
import 'package:fluffychat/pangea/common/utils/error_handler.dart';
|
||||
import 'package:fluffychat/pangea/extensions/pangea_room_extension.dart';
|
||||
import 'package:fluffychat/pangea/morphs/get_grammar_copy.dart';
|
||||
import 'package:fluffychat/widgets/matrix.dart';
|
||||
|
||||
class DownloadAnalyticsDialog extends StatefulWidget {
|
||||
|
|
|
|||
|
|
@ -2,9 +2,9 @@ import 'package:flutter/material.dart';
|
|||
|
||||
import 'package:material_symbols_icons/symbols.dart';
|
||||
|
||||
import 'package:fluffychat/pangea/analytics/enums/construct_type_enum.dart';
|
||||
import 'package:fluffychat/pangea/analytics/enums/construct_use_type_enum.dart';
|
||||
import 'package:fluffychat/pangea/analytics/models/construct_identifier.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';
|
||||
|
||||
enum ActivityTypeEnum {
|
||||
wordMeaning,
|
||||
|
|
|
|||
|
|
@ -7,10 +7,10 @@ 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/enums/construct_type_enum.dart';
|
||||
import 'package:fluffychat/pangea/analytics/enums/morph_categories_enum.dart';
|
||||
import 'package:fluffychat/pangea/analytics/models/construct_identifier.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/construct_identifier.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/construct_type_enum.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';
|
||||
import 'package:fluffychat/pangea/toolbar/enums/activity_type_enum.dart';
|
||||
import 'package:fluffychat/pangea/toolbar/models/multiple_choice_activity_model.dart';
|
||||
|
|
|
|||
|
|
@ -7,9 +7,9 @@ import 'dart:developer';
|
|||
|
||||
import 'package:flutter/foundation.dart';
|
||||
|
||||
import 'package:fluffychat/pangea/analytics/enums/construct_type_enum.dart';
|
||||
import 'package:fluffychat/pangea/analytics/enums/construct_use_type_enum.dart';
|
||||
import 'package:fluffychat/pangea/analytics/models/constructs_model.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/toolbar/enums/activity_type_enum.dart';
|
||||
import 'package:fluffychat/pangea/toolbar/models/practice_activity_model.dart';
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import 'package:flutter/material.dart';
|
|||
|
||||
import 'package:flutter_gen/gen_l10n/l10n.dart';
|
||||
|
||||
import 'package:fluffychat/pangea/analytics/enums/construct_type_enum.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/construct_type_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/models/message_activity_request.dart';
|
||||
|
|
|
|||
|
|
@ -2,12 +2,12 @@ import 'dart:async';
|
|||
|
||||
import 'package:flutter_gen/gen_l10n/l10n.dart';
|
||||
|
||||
import 'package:fluffychat/pangea/analytics/enums/construct_type_enum.dart';
|
||||
import 'package:fluffychat/pangea/analytics/models/construct_identifier.dart';
|
||||
import 'package:fluffychat/pangea/analytics/models/construct_use_model.dart';
|
||||
import 'package:fluffychat/pangea/analytics/repo/lemma_info_repo.dart';
|
||||
import 'package:fluffychat/pangea/analytics/repo/lemma_info_request.dart';
|
||||
import 'package:fluffychat/pangea/analytics/repo/lemma_info_response.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/lemmas/lemma_info_repo.dart';
|
||||
import 'package:fluffychat/pangea/lemmas/lemma_info_request.dart';
|
||||
import 'package:fluffychat/pangea/lemmas/lemma_info_response.dart';
|
||||
import 'package:fluffychat/pangea/toolbar/enums/activity_type_enum.dart';
|
||||
import 'package:fluffychat/pangea/toolbar/models/message_activity_request.dart';
|
||||
import 'package:fluffychat/pangea/toolbar/models/multiple_choice_activity_model.dart';
|
||||
|
|
|
|||
|
|
@ -2,11 +2,11 @@ import 'dart:developer';
|
|||
|
||||
import 'package:flutter/foundation.dart';
|
||||
|
||||
import 'package:fluffychat/pangea/analytics/enums/construct_type_enum.dart';
|
||||
import 'package:fluffychat/pangea/analytics/enums/morph_categories_enum.dart';
|
||||
import 'package:fluffychat/pangea/analytics/models/construct_identifier.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/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';
|
||||
import 'package:fluffychat/pangea/toolbar/models/message_activity_request.dart';
|
||||
import 'package:fluffychat/pangea/toolbar/models/multiple_choice_activity_model.dart';
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import 'package:collection/collection.dart';
|
|||
import 'package:matrix/matrix.dart';
|
||||
|
||||
import 'package:fluffychat/pages/chat/chat.dart';
|
||||
import 'package:fluffychat/pangea/analytics/controllers/message_analytics_controller.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/message_analytics_controller.dart';
|
||||
import 'package:fluffychat/pangea/common/utils/error_handler.dart';
|
||||
import 'package:fluffychat/pangea/events/event_wrappers/pangea_message_event.dart';
|
||||
import 'package:fluffychat/pangea/events/models/pangea_token_model.dart';
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import 'package:flutter/material.dart';
|
|||
import 'package:collection/collection.dart';
|
||||
|
||||
import 'package:fluffychat/config/app_config.dart';
|
||||
import 'package:fluffychat/pangea/analytics/controllers/message_analytics_controller.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/message_analytics_controller.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/utils/message_text_util.dart';
|
||||
|
|
|
|||
|
|
@ -6,10 +6,10 @@ import 'package:flutter/material.dart';
|
|||
import 'package:matrix/matrix.dart';
|
||||
|
||||
import 'package:fluffychat/config/app_config.dart';
|
||||
import 'package:fluffychat/pangea/analytics/controllers/put_analytics_controller.dart';
|
||||
import 'package:fluffychat/pangea/analytics/utils/get_grammar_copy.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/put_analytics_controller.dart';
|
||||
import 'package:fluffychat/pangea/choreographer/widgets/choice_array.dart';
|
||||
import 'package:fluffychat/pangea/common/utils/error_handler.dart';
|
||||
import 'package:fluffychat/pangea/morphs/get_grammar_copy.dart';
|
||||
import 'package:fluffychat/pangea/toolbar/controllers/tts_controller.dart';
|
||||
import 'package:fluffychat/pangea/toolbar/enums/activity_type_enum.dart';
|
||||
import 'package:fluffychat/pangea/toolbar/models/practice_activity_model.dart';
|
||||
|
|
|
|||
|
|
@ -6,11 +6,11 @@ import 'package:flutter/material.dart';
|
|||
|
||||
import 'package:collection/collection.dart';
|
||||
|
||||
import 'package:fluffychat/pangea/analytics/controllers/message_analytics_controller.dart';
|
||||
import 'package:fluffychat/pangea/analytics/controllers/put_analytics_controller.dart';
|
||||
import 'package:fluffychat/pangea/analytics/enums/construct_type_enum.dart';
|
||||
import 'package:fluffychat/pangea/analytics/models/constructs_model.dart';
|
||||
import 'package:fluffychat/pangea/analytics/widgets/gain_points.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/gain_points_animation.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/message_analytics_controller.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/put_analytics_controller.dart';
|
||||
import 'package:fluffychat/pangea/choreographer/widgets/igc/card_error_widget.dart';
|
||||
import 'package:fluffychat/pangea/common/controllers/pangea_controller.dart';
|
||||
import 'package:fluffychat/pangea/common/utils/error_handler.dart';
|
||||
|
|
|
|||
|
|
@ -5,12 +5,12 @@ import 'package:flutter/material.dart';
|
|||
|
||||
import 'package:flutter_gen/gen_l10n/l10n.dart';
|
||||
|
||||
import 'package:fluffychat/pangea/analytics/repo/lemma_info_repo.dart';
|
||||
import 'package:fluffychat/pangea/analytics/repo/lemma_info_request.dart';
|
||||
import 'package:fluffychat/pangea/analytics/repo/lemma_info_response.dart';
|
||||
import 'package:fluffychat/pangea/analytics/widgets/text_loading_shimmer.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/text_loading_shimmer.dart';
|
||||
import 'package:fluffychat/pangea/events/models/pangea_token_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/lemmas/lemma_info_response.dart';
|
||||
import 'package:fluffychat/widgets/matrix.dart';
|
||||
|
||||
class LemmaMeaningWidget extends StatefulWidget {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:fluffychat/pangea/analytics/enums/lemma_category_enum.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/construct_level_enum.dart';
|
||||
import 'package:fluffychat/pangea/common/widgets/customized_svg.dart';
|
||||
import 'package:fluffychat/pangea/events/models/pangea_token_model.dart';
|
||||
|
||||
|
|
|
|||
|
|
@ -5,15 +5,15 @@ import 'package:flutter/material.dart';
|
|||
|
||||
import 'package:flutter_gen/gen_l10n/l10n.dart';
|
||||
|
||||
import 'package:fluffychat/pangea/analytics/constants/morph_categories_and_labels.dart';
|
||||
import 'package:fluffychat/pangea/analytics/enums/morph_categories_enum.dart';
|
||||
import 'package:fluffychat/pangea/analytics/utils/get_grammar_copy.dart';
|
||||
import 'package:fluffychat/pangea/common/constants/model_keys.dart';
|
||||
import 'package:fluffychat/pangea/common/utils/error_handler.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';
|
||||
import 'package:fluffychat/pangea/extensions/pangea_room_extension.dart';
|
||||
import 'package:fluffychat/pangea/morphs/get_grammar_copy.dart';
|
||||
import 'package:fluffychat/pangea/morphs/morph_categories_enum.dart';
|
||||
import 'package:fluffychat/pangea/morphs/morph_repo.dart';
|
||||
import 'package:fluffychat/pangea/toolbar/widgets/message_selection_overlay.dart';
|
||||
import 'package:fluffychat/widgets/future_loading_dialog.dart';
|
||||
|
||||
|
|
@ -140,12 +140,7 @@ class MorphologicalCenterWidgetState extends State<MorphologicalCenterWidget> {
|
|||
/// all morphological tags for the selected morphological category
|
||||
/// that are eligible for setting as the morphological tag
|
||||
List<String> get allMorphTagsForEdit =>
|
||||
getLabelsForMorphCategory(widget.morphFeature)
|
||||
.where(
|
||||
(tag) => !["punct", "space", "sym", "x", "other"]
|
||||
.contains(tag.toLowerCase()),
|
||||
)
|
||||
.toList();
|
||||
MorphsRepo.get().getDisplayTags(widget.morphFeature);
|
||||
|
||||
String get morphCopy =>
|
||||
getMorphologicalCategoryCopy(widget.morphFeature, context) ??
|
||||
|
|
|
|||
|
|
@ -1,17 +1,14 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:fluffychat/pangea/analytics/enums/morph_categories_enum.dart';
|
||||
import 'package:fluffychat/pangea/analytics/utils/get_grammar_copy.dart';
|
||||
import 'package:fluffychat/pangea/common/widgets/customized_svg.dart';
|
||||
import 'package:fluffychat/pangea/morphs/get_grammar_copy.dart';
|
||||
import 'package:fluffychat/pangea/morphs/morph_categories_enum.dart';
|
||||
import 'package:fluffychat/pangea/morphs/morph_icon.dart';
|
||||
import 'package:fluffychat/pangea/toolbar/widgets/practice_activity/word_zoom_activity_button.dart';
|
||||
import 'package:fluffychat/utils/color_value.dart';
|
||||
|
||||
class MorphologicalListItem extends StatelessWidget {
|
||||
final Function(String) onPressed;
|
||||
final String morphFeature;
|
||||
final String morphTag;
|
||||
final IconData icon;
|
||||
final String? svgLink;
|
||||
|
||||
final bool isUnlocked;
|
||||
final bool isSelected;
|
||||
|
|
@ -20,8 +17,6 @@ class MorphologicalListItem extends StatelessWidget {
|
|||
required this.onPressed,
|
||||
required this.morphFeature,
|
||||
required this.morphTag,
|
||||
required this.icon,
|
||||
this.svgLink,
|
||||
this.isUnlocked = true,
|
||||
this.isSelected = false,
|
||||
super.key,
|
||||
|
|
@ -33,20 +28,7 @@ class MorphologicalListItem extends StatelessWidget {
|
|||
width: 40,
|
||||
height: 40,
|
||||
child: WordZoomActivityButton(
|
||||
icon: svgLink != null
|
||||
? CustomizedSvg(
|
||||
svgUrl: svgLink!,
|
||||
colorReplacements:
|
||||
Theme.of(context).brightness == Brightness.dark
|
||||
? {
|
||||
"white":
|
||||
Theme.of(context).cardColor.hexValue.toString(),
|
||||
"black": "white",
|
||||
}
|
||||
: {},
|
||||
errorIcon: Icon(icon),
|
||||
)
|
||||
: Icon(icon),
|
||||
icon: MorphIcon(morphFeature: morphFeature, morphTag: morphTag),
|
||||
isSelected: isSelected,
|
||||
onPressed: () => onPressed(morphFeature),
|
||||
tooltip: isUnlocked
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:fluffychat/pangea/analytics/constants/morph_categories_and_labels.dart';
|
||||
import 'package:fluffychat/pangea/analytics/utils/get_svg_link.dart';
|
||||
import 'package:fluffychat/pangea/events/models/pangea_token_model.dart';
|
||||
import 'package:fluffychat/pangea/toolbar/widgets/word_zoom/morphs/morphological_list_item.dart';
|
||||
|
||||
|
|
@ -76,12 +74,6 @@ class MorphologicalListWidget extends StatelessWidget {
|
|||
onPressed: setMorphFeature,
|
||||
morphFeature: morph.morphFeature,
|
||||
morphTag: morph.morphTag,
|
||||
icon: getIconForMorphFeature(morph.morphFeature),
|
||||
svgLink: getMorphSvgLink(
|
||||
morphFeature: morph.morphFeature,
|
||||
morphTag: morph.revealed ? morph.morphTag : null,
|
||||
context: context,
|
||||
),
|
||||
isUnlocked: morph.revealed,
|
||||
isSelected: selectedMorphFeature == morph.morphFeature,
|
||||
),
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import 'dart:developer';
|
|||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:fluffychat/pangea/analytics/controllers/message_analytics_controller.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/message_analytics_controller.dart';
|
||||
import 'package:fluffychat/pangea/events/models/pangea_token_model.dart';
|
||||
import 'package:fluffychat/pangea/toolbar/widgets/message_selection_overlay.dart';
|
||||
import 'package:fluffychat/pangea/toolbar/widgets/practice_activity/practice_activity_card.dart';
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue