4036 playtest 91825 (#4051)
* chore: improve constrast in message practice * fix typo * chore: disable learning settings save button until change is made * show word card on click vocab in activity dropdown
This commit is contained in:
parent
652c1fe4a6
commit
54918d4969
12 changed files with 175 additions and 168 deletions
|
|
@ -4721,7 +4721,7 @@
|
|||
"whoIsAllowedToJoinThisChat": "Who is allowed to join this chat",
|
||||
"dontForgetPassword": "Don't forget your password!",
|
||||
"enableAutocorrectToolName": "Enable device autocorrect",
|
||||
"enableAutocorrectDescription": "If your device supports the language your learning, you can enable device autocorrect to fix common errors as you type.",
|
||||
"enableAutocorrectDescription": "If your device supports the language you're learning, you can enable device autocorrect to fix common errors as you type.",
|
||||
"ttsDisbledTitle": "Text-to-speech disabled",
|
||||
"ttsDisabledBody": "You can enable text-to-speech in your learning settings",
|
||||
"noSpaceDescriptionYet": "No course description created yet.",
|
||||
|
|
|
|||
|
|
@ -140,20 +140,6 @@ class ActivityPlanModel {
|
|||
return vocabString;
|
||||
}
|
||||
|
||||
List get vocabList {
|
||||
final List<String> vocabList = [];
|
||||
// cycle through vocab with index
|
||||
for (var i = 0; i < vocab.length; i++) {
|
||||
// if the lemma appears more than once in the vocab list, show the pos
|
||||
// vocab is a wrapped list of string, separated by commas
|
||||
final v = vocab[i];
|
||||
final bool showPos =
|
||||
vocab.where((vocab) => vocab.lemma == v.lemma).length > 1;
|
||||
vocabList.add("${v.lemma}${showPos ? ' (${v.pos})' : ''}");
|
||||
}
|
||||
return vocabList;
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
if (identical(this, other)) return true;
|
||||
|
|
|
|||
|
|
@ -9,13 +9,19 @@ import 'package:fluffychat/config/app_config.dart';
|
|||
import 'package:fluffychat/config/themes.dart';
|
||||
import 'package:fluffychat/l10n/l10n.dart';
|
||||
import 'package:fluffychat/pages/chat/chat.dart';
|
||||
import 'package:fluffychat/pangea/activity_planner/activity_plan_model.dart';
|
||||
import 'package:fluffychat/pangea/activity_sessions/activity_room_extension.dart';
|
||||
import 'package:fluffychat/pangea/activity_sessions/activity_session_details_row.dart';
|
||||
import 'package:fluffychat/pangea/activity_summary/activity_summary_analytics_model.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/construct_type_enum.dart';
|
||||
import 'package:fluffychat/pangea/bot/utils/bot_name.dart';
|
||||
import 'package:fluffychat/pangea/common/utils/overlay.dart';
|
||||
import 'package:fluffychat/pangea/constructs/construct_identifier.dart';
|
||||
import 'package:fluffychat/pangea/events/models/pangea_token_text_model.dart';
|
||||
import 'package:fluffychat/pangea/extensions/pangea_room_extension.dart';
|
||||
import 'package:fluffychat/pangea/toolbar/widgets/word_zoom/word_zoom_widget.dart';
|
||||
import 'package:fluffychat/widgets/future_loading_dialog.dart';
|
||||
import 'package:fluffychat/widgets/matrix.dart';
|
||||
|
||||
class ActivityStatsMenu extends StatefulWidget {
|
||||
final ChatController controller;
|
||||
|
|
@ -60,7 +66,7 @@ class ActivityStatsMenuState extends State<ActivityStatsMenu> {
|
|||
.toSet();
|
||||
|
||||
double get _percentVocabComplete {
|
||||
final vocabList = room.activityPlan?.vocabList ?? [];
|
||||
final vocabList = room.activityPlan?.vocab.map((v) => v.lemma) ?? [];
|
||||
if (vocabList.isEmpty || _usedVocab == null) {
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -226,11 +232,13 @@ class ActivityStatsMenuState extends State<ActivityStatsMenu> {
|
|||
spacing: 4.0,
|
||||
runSpacing: 4.0,
|
||||
children: [
|
||||
...room.activityPlan!.vocabList.map(
|
||||
(vocabWord) => VocabTile(
|
||||
vocabWord: vocabWord,
|
||||
...room.activityPlan!.vocab.map(
|
||||
(v) => VocabTile(
|
||||
vocab: v,
|
||||
langCode:
|
||||
room.activityPlan!.req.targetLanguage,
|
||||
isUsed:
|
||||
(_usedVocab ?? {}).contains(vocabWord),
|
||||
(_usedVocab ?? {}).contains(v.lemma),
|
||||
),
|
||||
),
|
||||
],
|
||||
|
|
@ -316,12 +324,14 @@ class ActivityStatsMenuState extends State<ActivityStatsMenu> {
|
|||
}
|
||||
|
||||
class VocabTile extends StatelessWidget {
|
||||
final String vocabWord;
|
||||
final Vocab vocab;
|
||||
final String langCode;
|
||||
final bool isUsed;
|
||||
|
||||
const VocabTile({
|
||||
super.key,
|
||||
required this.vocabWord,
|
||||
required this.vocab,
|
||||
required this.langCode,
|
||||
required this.isUsed,
|
||||
});
|
||||
|
||||
|
|
@ -329,20 +339,81 @@ class VocabTile extends StatelessWidget {
|
|||
Widget build(BuildContext context) {
|
||||
final color =
|
||||
isUsed ? AppConfig.goldLight.withAlpha(100) : Colors.transparent;
|
||||
return Container(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 8.0,
|
||||
vertical: 4.0,
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
color: color,
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
),
|
||||
child: Text(
|
||||
vocabWord,
|
||||
style: TextStyle(
|
||||
color: Theme.of(context).colorScheme.onSurface,
|
||||
fontSize: 14.0,
|
||||
return CompositedTransformTarget(
|
||||
link: MatrixState.pAnyState
|
||||
.layerLinkAndKey(
|
||||
"activity-vocab-${vocab.lemma}",
|
||||
)
|
||||
.link,
|
||||
child: InkWell(
|
||||
key: MatrixState.pAnyState
|
||||
.layerLinkAndKey(
|
||||
"activity-vocab-${vocab.lemma}",
|
||||
)
|
||||
.key,
|
||||
borderRadius: BorderRadius.circular(
|
||||
24.0,
|
||||
),
|
||||
onTap: () {
|
||||
OverlayUtil.showPositionedCard(
|
||||
overlayKey: "activity-vocab-${vocab.lemma}",
|
||||
context: context,
|
||||
cardToShow: Material(
|
||||
type: MaterialType.transparency,
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context).cardColor,
|
||||
border: Border.all(
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
width: 4.0,
|
||||
),
|
||||
borderRadius: const BorderRadius.all(
|
||||
Radius.circular(AppConfig.borderRadius),
|
||||
),
|
||||
),
|
||||
child: WordZoomWidget(
|
||||
token: PangeaTokenText(
|
||||
content: vocab.lemma,
|
||||
length: vocab.lemma.characters.length,
|
||||
offset: 0,
|
||||
),
|
||||
construct: ConstructIdentifier(
|
||||
lemma: vocab.lemma,
|
||||
type: ConstructTypeEnum.vocab,
|
||||
category: vocab.pos,
|
||||
),
|
||||
langCode: langCode,
|
||||
onClose: () {
|
||||
MatrixState.pAnyState.closeOverlay(
|
||||
"activity-vocab-${vocab.lemma}",
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
transformTargetId: "activity-vocab-${vocab.lemma}",
|
||||
closePrevOverlay: false,
|
||||
addBorder: false,
|
||||
maxWidth: AppConfig.toolbarMinWidth,
|
||||
maxHeight: AppConfig.toolbarMaxHeight,
|
||||
);
|
||||
},
|
||||
child: Container(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 8.0,
|
||||
vertical: 4.0,
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
color: color,
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
),
|
||||
child: Text(
|
||||
vocab.lemma,
|
||||
style: TextStyle(
|
||||
color: Theme.of(context).colorScheme.onSurface,
|
||||
fontSize: 14.0,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:get_storage/get_storage.dart';
|
||||
|
||||
import 'package:fluffychat/pangea/course_plans/course_plan_model.dart';
|
||||
import 'package:fluffychat/pangea/course_plans/course_plans_repo.dart';
|
||||
|
||||
|
|
@ -33,7 +35,9 @@ class CoursePlanController extends State<CoursePlanBuilder> {
|
|||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_loadCourse();
|
||||
_initStorage().then((_) {
|
||||
if (mounted) _loadCourse();
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
|
|
@ -44,13 +48,20 @@ class CoursePlanController extends State<CoursePlanBuilder> {
|
|||
}
|
||||
}
|
||||
|
||||
Future<void> _loadCourse() async {
|
||||
setState(() {
|
||||
loading = false;
|
||||
error = null;
|
||||
course = null;
|
||||
});
|
||||
Future<void> _initStorage() async {
|
||||
final futures = [
|
||||
GetStorage.init("course_storage"),
|
||||
GetStorage.init("course_activity_storage"),
|
||||
GetStorage.init("course_location_media_storage"),
|
||||
GetStorage.init("course_location_storage"),
|
||||
GetStorage.init("course_media_storage"),
|
||||
GetStorage.init("course_topic_storage"),
|
||||
];
|
||||
|
||||
await Future.wait(futures);
|
||||
}
|
||||
|
||||
Future<void> _loadCourse() async {
|
||||
if (widget.courseId == null) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -59,10 +70,10 @@ class CoursePlanController extends State<CoursePlanBuilder> {
|
|||
setState(() {
|
||||
loading = true;
|
||||
error = null;
|
||||
course = null;
|
||||
});
|
||||
|
||||
course = await CoursePlansRepo.get(widget.courseId!);
|
||||
|
||||
widget.onLoaded?.call(course!);
|
||||
} catch (e) {
|
||||
widget.onNotFound?.call();
|
||||
|
|
|
|||
|
|
@ -55,25 +55,8 @@ class SettingsLearningController extends State<SettingsLearning> {
|
|||
super.dispose();
|
||||
}
|
||||
|
||||
// compare settings in _profile with the settings in the userController
|
||||
// if they are different, return true, else return false
|
||||
bool get haveSettingsBeenChanged {
|
||||
for (final setting in _profile.userSettings.toJson().entries) {
|
||||
if (setting.value !=
|
||||
pangeaController.userController.profile.userSettings
|
||||
.toJson()[setting.key]) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
for (final setting in _profile.toolSettings.toJson().entries) {
|
||||
if (setting.value !=
|
||||
pangeaController.userController.profile.toolSettings
|
||||
.toJson()[setting.key]) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool get haveSettingsBeenChanged =>
|
||||
pangeaController.userController.profile != _profile;
|
||||
|
||||
// if the settings have been changed, show a dialog the user wants to exit without saving
|
||||
// if the settings have not been changed, just close the settings page
|
||||
|
|
@ -275,7 +258,7 @@ class SettingsLearningController extends State<SettingsLearning> {
|
|||
LanguageModel? get userL1 => pangeaController.languageController.userL1;
|
||||
LanguageModel? get userL2 => pangeaController.languageController.userL2;
|
||||
|
||||
bool get publicProfile => _profile.userSettings.publicProfile ?? true;
|
||||
bool get publicProfile => _profile.userSettings.publicProfile ?? false;
|
||||
|
||||
LanguageLevelTypeEnum get cefrLevel => _profile.userSettings.cefrLevel;
|
||||
|
||||
|
|
|
|||
|
|
@ -319,7 +319,9 @@ class SettingsLearningView extends StatelessWidget {
|
|||
child: SizedBox(
|
||||
width: double.infinity,
|
||||
child: ElevatedButton(
|
||||
onPressed: controller.submit,
|
||||
onPressed: controller.haveSettingsBeenChanged
|
||||
? controller.submit
|
||||
: null,
|
||||
child: Text(L10n.of(context).saveChanges),
|
||||
),
|
||||
),
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@ import 'package:flutter/material.dart';
|
|||
import 'package:collection/collection.dart';
|
||||
import 'package:matrix/matrix.dart';
|
||||
|
||||
import 'package:fluffychat/pages/chat/chat.dart';
|
||||
import 'package:fluffychat/pangea/lemmas/lemma_emoji_picker.dart';
|
||||
import 'package:fluffychat/widgets/future_loading_dialog.dart';
|
||||
import 'package:fluffychat/widgets/matrix.dart';
|
||||
|
|
@ -11,21 +10,22 @@ import 'package:fluffychat/widgets/matrix.dart';
|
|||
class LemmaReactionPicker extends StatelessWidget {
|
||||
final List<String> emojis;
|
||||
final bool loading;
|
||||
|
||||
final Event event;
|
||||
final ChatController controller;
|
||||
final Event? event;
|
||||
|
||||
const LemmaReactionPicker({
|
||||
super.key,
|
||||
required this.emojis,
|
||||
required this.loading,
|
||||
required this.event,
|
||||
required this.controller,
|
||||
});
|
||||
|
||||
void setEmoji(String emoji, BuildContext context) {
|
||||
final allReactionEvents = event.aggregatedEvents(
|
||||
controller.timeline!,
|
||||
if (event?.room.timeline == null) {
|
||||
throw Exception("Timeline is null in reaction picker");
|
||||
}
|
||||
|
||||
final allReactionEvents = event!.aggregatedEvents(
|
||||
event!.room.timeline!,
|
||||
RelationshipTypes.reaction,
|
||||
);
|
||||
|
||||
|
|
@ -42,8 +42,8 @@ class LemmaReactionPicker extends StatelessWidget {
|
|||
future: () => reactionEvent.redactEvent(),
|
||||
);
|
||||
} else {
|
||||
controller.room.sendReaction(
|
||||
event.eventId,
|
||||
event!.room.sendReaction(
|
||||
event!.eventId,
|
||||
emoji,
|
||||
);
|
||||
}
|
||||
|
|
@ -52,12 +52,11 @@ class LemmaReactionPicker extends StatelessWidget {
|
|||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final sentReactions = <String>{};
|
||||
if (controller.selectedEvents.isNotEmpty) {
|
||||
final selectedEvent = controller.selectedEvents.first;
|
||||
if (event?.room.timeline != null) {
|
||||
sentReactions.addAll(
|
||||
selectedEvent
|
||||
event!
|
||||
.aggregatedEvents(
|
||||
controller.timeline!,
|
||||
event!.room.timeline!,
|
||||
RelationshipTypes.reaction,
|
||||
)
|
||||
.where(
|
||||
|
|
|
|||
|
|
@ -294,17 +294,6 @@ class MessageTokenButtonContent extends StatelessWidget {
|
|||
static final _borderRadius =
|
||||
BorderRadius.circular(AppConfig.borderRadius - 4);
|
||||
|
||||
Color _color(BuildContext context) {
|
||||
final bool isLight = Theme.of(context).brightness == Brightness.light;
|
||||
final defaultColor = isLight
|
||||
? Theme.of(context).colorScheme.primary
|
||||
: Theme.of(context).colorScheme.primaryContainer;
|
||||
|
||||
return activity != null && isActivityCompleteOrNullForToken
|
||||
? AppConfig.gold
|
||||
: defaultColor;
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
if (isActivityCompleteOrNullForToken || activity == null) {
|
||||
|
|
@ -362,13 +351,13 @@ class MessageTokenButtonContent extends StatelessWidget {
|
|||
child: SizedBox(
|
||||
height: height,
|
||||
child: Opacity(
|
||||
opacity: isSelected ? 1.0 : 0.4,
|
||||
opacity: isSelected ? 1.0 : 0.6,
|
||||
child: AnimatedBuilder(
|
||||
animation: sizeAnimation,
|
||||
builder: (context, child) {
|
||||
return Icon(
|
||||
Symbols.toys_and_games,
|
||||
color: _color(context),
|
||||
color: Theme.of(context).colorScheme.onSurface,
|
||||
size: sizeAnimation.value, // Use the new animation
|
||||
);
|
||||
},
|
||||
|
|
@ -393,11 +382,8 @@ class MessageTokenButtonContent extends StatelessWidget {
|
|||
borderRadius: _borderRadius,
|
||||
child: CustomPaint(
|
||||
painter: DottedBorderPainter(
|
||||
color: theme.brightness == Brightness.light
|
||||
? theme.colorScheme.primary
|
||||
.withAlpha((colorAlpha * 255).toInt())
|
||||
: theme.colorScheme.primaryContainer
|
||||
.withAlpha((colorAlpha * 255).toInt()),
|
||||
color: theme.colorScheme.onSurface
|
||||
.withAlpha((colorAlpha * 255).toInt()),
|
||||
borderRadius: _borderRadius,
|
||||
),
|
||||
child: Container(
|
||||
|
|
|
|||
|
|
@ -115,10 +115,14 @@ class ReadingAssistanceContentState extends State<ReadingAssistanceContent> {
|
|||
"word-zoom-card-${widget.overlayController.selectedToken!.text.uniqueKey}",
|
||||
)
|
||||
.key,
|
||||
token: widget.overlayController.selectedToken!,
|
||||
overlayController: widget.overlayController,
|
||||
token: widget.overlayController.selectedToken!.text,
|
||||
construct: widget.overlayController.selectedToken!.vocabConstructID,
|
||||
event: widget.overlayController.event,
|
||||
wordIsNew: widget.overlayController
|
||||
.isNewToken(widget.overlayController.selectedToken!),
|
||||
onClose: () => widget.overlayController.updateSelectedSpan(null),
|
||||
langCode: widget
|
||||
.overlayController.pangeaMessageEvent.messageDisplayLangCode,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,21 +5,15 @@ import 'package:flutter/material.dart';
|
|||
import 'package:fluffychat/config/themes.dart';
|
||||
import 'package:fluffychat/pangea/common/utils/overlay.dart';
|
||||
import 'package:fluffychat/pangea/constructs/construct_level_enum.dart';
|
||||
import 'package:fluffychat/pangea/events/models/pangea_token_model.dart';
|
||||
import 'package:fluffychat/pangea/toolbar/widgets/message_selection_overlay.dart';
|
||||
import 'package:fluffychat/widgets/matrix.dart';
|
||||
|
||||
class NewWordOverlay extends StatefulWidget {
|
||||
final Color overlayColor;
|
||||
final MessageOverlayController overlayController;
|
||||
final PangeaToken token;
|
||||
final String transformTargetId;
|
||||
|
||||
const NewWordOverlay({
|
||||
super.key,
|
||||
required this.overlayColor,
|
||||
required this.overlayController,
|
||||
required this.token,
|
||||
required this.transformTargetId,
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -1,59 +1,51 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:matrix/matrix.dart';
|
||||
|
||||
import 'package:fluffychat/config/app_config.dart';
|
||||
import 'package:fluffychat/l10n/l10n.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/construct_type_enum.dart';
|
||||
import 'package:fluffychat/pangea/common/widgets/error_indicator.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/constructs/construct_identifier.dart';
|
||||
import 'package:fluffychat/pangea/events/models/pangea_token_text_model.dart';
|
||||
import 'package:fluffychat/pangea/learning_settings/models/language_model.dart';
|
||||
import 'package:fluffychat/pangea/learning_settings/utils/p_language_store.dart';
|
||||
import 'package:fluffychat/pangea/lemmas/construct_xp_widget.dart';
|
||||
import 'package:fluffychat/pangea/lemmas/lemma_reaction_picker.dart';
|
||||
import 'package:fluffychat/pangea/phonetic_transcription/phonetic_transcription_widget.dart';
|
||||
import 'package:fluffychat/pangea/practice_activities/activity_type_enum.dart';
|
||||
import 'package:fluffychat/pangea/toolbar/widgets/message_selection_overlay.dart';
|
||||
import 'package:fluffychat/pangea/toolbar/widgets/practice_activity/word_audio_button.dart';
|
||||
import 'package:fluffychat/pangea/toolbar/widgets/word_zoom/lemma_meaning_builder.dart';
|
||||
import 'package:fluffychat/pangea/toolbar/widgets/word_zoom/new_word_overlay.dart';
|
||||
import 'package:fluffychat/widgets/matrix.dart';
|
||||
|
||||
class WordZoomWidget extends StatelessWidget {
|
||||
final PangeaToken token;
|
||||
final MessageOverlayController overlayController;
|
||||
final PangeaTokenText token;
|
||||
final ConstructIdentifier construct;
|
||||
|
||||
final String langCode;
|
||||
final VoidCallback onClose;
|
||||
|
||||
final bool wordIsNew;
|
||||
final Event? event;
|
||||
|
||||
const WordZoomWidget({
|
||||
super.key,
|
||||
required this.token,
|
||||
required this.overlayController,
|
||||
required this.wordIsNew,
|
||||
required this.construct,
|
||||
required this.langCode,
|
||||
required this.onClose,
|
||||
this.wordIsNew = false,
|
||||
this.event,
|
||||
});
|
||||
|
||||
PangeaToken get _selectedToken => overlayController.selectedToken!;
|
||||
|
||||
bool get hasEmojiActivity =>
|
||||
overlayController.practiceSelection?.hasActiveActivityByToken(
|
||||
ActivityTypeEnum.emoji,
|
||||
_selectedToken,
|
||||
) ==
|
||||
true &&
|
||||
overlayController.hideWordCardContent;
|
||||
|
||||
String get transformTargetId => "word-zoom-card-${token.text.uniqueKey}";
|
||||
String get transformTargetId => "word-zoom-card-${token.uniqueKey}";
|
||||
|
||||
LayerLink get layerLink =>
|
||||
MatrixState.pAnyState.layerLinkAndKey(transformTargetId).link;
|
||||
|
||||
PangeaMessageEvent get messageEvent => overlayController.pangeaMessageEvent;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
// final GlobalKey cardKey = MatrixState.pAnyState
|
||||
// .layerLinkAndKey("word-zoom-card-${token.text.uniqueKey}")
|
||||
// .key;
|
||||
final overlayColor = Theme.of(context).scaffoldBackgroundColor;
|
||||
return Stack(
|
||||
children: [
|
||||
|
|
@ -81,8 +73,7 @@ class WordZoomWidget extends StatelessWidget {
|
|||
child: MouseRegion(
|
||||
cursor: SystemMouseCursors.click,
|
||||
child: GestureDetector(
|
||||
onTap: () =>
|
||||
overlayController.updateSelectedSpan(null),
|
||||
onTap: onClose,
|
||||
child: const Icon(
|
||||
Icons.close,
|
||||
size: 16.0,
|
||||
|
|
@ -92,7 +83,7 @@ class WordZoomWidget extends StatelessWidget {
|
|||
),
|
||||
Flexible(
|
||||
child: Text(
|
||||
token.text.content,
|
||||
token.content,
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 28.0,
|
||||
|
|
@ -106,16 +97,16 @@ class WordZoomWidget extends StatelessWidget {
|
|||
),
|
||||
),
|
||||
ConstructXpWidget(
|
||||
id: token.vocabConstructID,
|
||||
id: construct,
|
||||
onTap: () => context.go(
|
||||
"/rooms/analytics/${ConstructTypeEnum.vocab.string}/${token.vocabConstructID.string}",
|
||||
"/rooms/analytics/${ConstructTypeEnum.vocab.string}/${construct.string}",
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
LemmaMeaningBuilder(
|
||||
langCode: messageEvent.messageDisplayLangCode,
|
||||
constructId: token.vocabConstructID,
|
||||
langCode: langCode,
|
||||
constructId: construct,
|
||||
builder: (context, controller) {
|
||||
if (controller.editMode) {
|
||||
return Column(
|
||||
|
|
@ -123,8 +114,8 @@ class WordZoomWidget extends StatelessWidget {
|
|||
children: [
|
||||
Text(
|
||||
"${L10n.of(context).pangeaBotIsFallible} ${L10n.of(context).whatIsMeaning(
|
||||
token.vocabConstructID.lemma,
|
||||
token.vocabConstructID.category,
|
||||
construct.lemma,
|
||||
construct.category,
|
||||
)}",
|
||||
textAlign: TextAlign.center,
|
||||
style:
|
||||
|
|
@ -192,9 +183,9 @@ class WordZoomWidget extends StatelessWidget {
|
|||
if (MatrixState.pangeaController.languageController
|
||||
.showTranscription)
|
||||
PhoneticTranscriptionWidget(
|
||||
text: token.text.content,
|
||||
text: token.content,
|
||||
textLanguage: PLanguageStore.byLangCode(
|
||||
messageEvent.messageDisplayLangCode,
|
||||
langCode,
|
||||
) ??
|
||||
LanguageModel.unknown,
|
||||
style: const TextStyle(fontSize: 14.0),
|
||||
|
|
@ -202,16 +193,15 @@ class WordZoomWidget extends StatelessWidget {
|
|||
)
|
||||
else
|
||||
WordAudioButton(
|
||||
text: token.text.content,
|
||||
uniqueID: "lemma-content-${token.text.content}",
|
||||
langCode: messageEvent.messageDisplayLangCode,
|
||||
text: token.content,
|
||||
uniqueID: "lemma-content-${token.content}",
|
||||
langCode: langCode,
|
||||
iconSize: 24.0,
|
||||
),
|
||||
LemmaReactionPicker(
|
||||
emojis: controller.lemmaInfo?.emoji ?? [],
|
||||
loading: controller.isLoading,
|
||||
event: messageEvent.event,
|
||||
controller: overlayController.widget.chatController,
|
||||
event: event,
|
||||
),
|
||||
if (controller.error != null)
|
||||
ErrorIndicator(
|
||||
|
|
@ -227,8 +217,8 @@ class WordZoomWidget extends StatelessWidget {
|
|||
controller.toggleEditMode(true),
|
||||
onDoubleTap: () =>
|
||||
controller.toggleEditMode(true),
|
||||
child: token.lemma.text.toLowerCase() ==
|
||||
token.text.content.toLowerCase()
|
||||
child: construct.lemma.toLowerCase() ==
|
||||
token.content.toLowerCase()
|
||||
? Text(
|
||||
controller.lemmaInfo!.meaning,
|
||||
style: const TextStyle(fontSize: 14.0),
|
||||
|
|
@ -242,7 +232,7 @@ class WordZoomWidget extends StatelessWidget {
|
|||
fontSize: 14.0,
|
||||
),
|
||||
children: [
|
||||
TextSpan(text: token.lemma.text),
|
||||
TextSpan(text: construct.lemma),
|
||||
const WidgetSpan(
|
||||
child: SizedBox(width: 8.0),
|
||||
),
|
||||
|
|
@ -269,9 +259,7 @@ class WordZoomWidget extends StatelessWidget {
|
|||
wordIsNew
|
||||
? NewWordOverlay(
|
||||
key: ValueKey(transformTargetId),
|
||||
token: token,
|
||||
overlayColor: overlayColor,
|
||||
overlayController: overlayController,
|
||||
transformTargetId: transformTargetId,
|
||||
)
|
||||
: const SizedBox.shrink(),
|
||||
|
|
|
|||
|
|
@ -12,23 +12,19 @@ import '../../learning_settings/models/language_model.dart';
|
|||
class UserSettings {
|
||||
DateTime? dateOfBirth;
|
||||
DateTime? createdAt;
|
||||
bool? autoPlayMessages;
|
||||
bool? publicProfile;
|
||||
String? targetLanguage;
|
||||
String? sourceLanguage;
|
||||
String? country;
|
||||
bool? hasJoinedHelpSpace;
|
||||
LanguageLevelTypeEnum cefrLevel;
|
||||
|
||||
UserSettings({
|
||||
this.dateOfBirth,
|
||||
this.createdAt,
|
||||
this.autoPlayMessages,
|
||||
this.publicProfile,
|
||||
this.targetLanguage,
|
||||
this.sourceLanguage,
|
||||
this.country,
|
||||
this.hasJoinedHelpSpace,
|
||||
this.cefrLevel = LanguageLevelTypeEnum.a1,
|
||||
});
|
||||
|
||||
|
|
@ -39,12 +35,10 @@ class UserSettings {
|
|||
createdAt: json[ModelKey.userCreatedAt] != null
|
||||
? DateTime.parse(json[ModelKey.userCreatedAt])
|
||||
: null,
|
||||
autoPlayMessages: json[ModelKey.autoPlayMessages],
|
||||
publicProfile: json[ModelKey.publicProfile],
|
||||
targetLanguage: json[ModelKey.l2LanguageKey],
|
||||
sourceLanguage: json[ModelKey.l1LanguageKey],
|
||||
country: json[ModelKey.userCountry],
|
||||
hasJoinedHelpSpace: json[ModelKey.hasJoinedHelpSpace],
|
||||
cefrLevel: json[ModelKey.cefrLevel] is String
|
||||
? LanguageLevelTypeEnumExtension.fromString(
|
||||
json[ModelKey.cefrLevel],
|
||||
|
|
@ -56,12 +50,10 @@ class UserSettings {
|
|||
final Map<String, dynamic> data = <String, dynamic>{};
|
||||
data[ModelKey.userDateOfBirth] = dateOfBirth?.toIso8601String();
|
||||
data[ModelKey.userCreatedAt] = createdAt?.toIso8601String();
|
||||
data[ModelKey.autoPlayMessages] = autoPlayMessages;
|
||||
data[ModelKey.publicProfile] = publicProfile;
|
||||
data[ModelKey.l2LanguageKey] = targetLanguage;
|
||||
data[ModelKey.l1LanguageKey] = sourceLanguage;
|
||||
data[ModelKey.userCountry] = country;
|
||||
data[ModelKey.hasJoinedHelpSpace] = hasJoinedHelpSpace;
|
||||
data[ModelKey.cefrLevel] = cefrLevel.string;
|
||||
return data;
|
||||
}
|
||||
|
|
@ -100,9 +92,6 @@ class UserSettings {
|
|||
return UserSettings(
|
||||
dateOfBirth: dob,
|
||||
createdAt: createdAt,
|
||||
autoPlayMessages: (accountData[ModelKey.autoPlayMessages]
|
||||
?.content[ModelKey.autoPlayMessages] as bool?) ??
|
||||
false,
|
||||
publicProfile: (accountData[ModelKey.publicProfile]
|
||||
?.content[ModelKey.publicProfile] as bool?) ??
|
||||
false,
|
||||
|
|
@ -119,12 +108,10 @@ class UserSettings {
|
|||
return UserSettings(
|
||||
dateOfBirth: dateOfBirth,
|
||||
createdAt: createdAt,
|
||||
autoPlayMessages: autoPlayMessages,
|
||||
publicProfile: publicProfile,
|
||||
targetLanguage: targetLanguage,
|
||||
sourceLanguage: sourceLanguage,
|
||||
country: country,
|
||||
hasJoinedHelpSpace: hasJoinedHelpSpace,
|
||||
cefrLevel: cefrLevel,
|
||||
);
|
||||
}
|
||||
|
|
@ -136,12 +123,10 @@ class UserSettings {
|
|||
return other is UserSettings &&
|
||||
other.dateOfBirth == dateOfBirth &&
|
||||
other.createdAt == createdAt &&
|
||||
other.autoPlayMessages == autoPlayMessages &&
|
||||
other.publicProfile == publicProfile &&
|
||||
(other.publicProfile ?? false) == (publicProfile ?? false) &&
|
||||
other.targetLanguage == targetLanguage &&
|
||||
other.sourceLanguage == sourceLanguage &&
|
||||
other.country == country &&
|
||||
other.hasJoinedHelpSpace == hasJoinedHelpSpace &&
|
||||
other.cefrLevel == cefrLevel;
|
||||
}
|
||||
|
||||
|
|
@ -149,12 +134,10 @@ class UserSettings {
|
|||
int get hashCode => Object.hashAll([
|
||||
dateOfBirth.hashCode,
|
||||
createdAt.hashCode,
|
||||
autoPlayMessages.hashCode,
|
||||
publicProfile.hashCode,
|
||||
(publicProfile ?? false).hashCode,
|
||||
targetLanguage.hashCode,
|
||||
sourceLanguage.hashCode,
|
||||
country.hashCode,
|
||||
hasJoinedHelpSpace.hashCode,
|
||||
cefrLevel.hashCode,
|
||||
]);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue