2506 feedback on the new word card and message activities (#2525)
* fix(reading_assistance): fixed playing of sound and edited some copy * chore: show token emojis for non-activity tokens, show morph defintion below choices once correct choice has been made * chore(reading_assistance): added morph meaning for incorrect choices and adjusted some spacing * chore(reading_assistance): adjusting spacing of morph choices to accomodate meaning text --------- Co-authored-by: ggurdin <ggurdin@gmail.com>
This commit is contained in:
parent
6d8d03910f
commit
9b547d702b
10 changed files with 97 additions and 95 deletions
|
|
@ -4507,7 +4507,7 @@
|
|||
},
|
||||
"botModeValidation": "Please select a chat mode",
|
||||
"clickBestOption": "Choose the best options to translate your message!",
|
||||
"completeActivitiesToUnlock": "Complete one of the activities (emoji, meaning, listening OR grammar) to unlock the translation!",
|
||||
"completeActivitiesToUnlock": "Complete at least one activity to unlock the translation!",
|
||||
"botSettingsSubtitle": "Invite bot to moderate chat activity",
|
||||
"invitePeople": "Invite users",
|
||||
"noCapacityLimit": "No capacity limit",
|
||||
|
|
@ -4866,4 +4866,4 @@
|
|||
"shareSpaceLink": "Share link to space",
|
||||
"byUsingPangeaChat": "By using Pangea Chat, I agree to the ",
|
||||
"details": "Details"
|
||||
}
|
||||
}
|
||||
|
|
@ -316,7 +316,7 @@ class HtmlMessage extends StatelessWidget {
|
|||
),
|
||||
width: tokenWidth,
|
||||
animateIn: isTransitionAnimation,
|
||||
practiceTarget:
|
||||
practiceTargetForToken:
|
||||
overlayController?.toolbarMode.associatedActivityType !=
|
||||
null
|
||||
? overlayController?.practiceSelection
|
||||
|
|
|
|||
|
|
@ -1,28 +1,24 @@
|
|||
import 'dart:developer';
|
||||
import 'dart:math';
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:flutter_gen/gen_l10n/l10n.dart';
|
||||
|
||||
import 'package:fluffychat/pangea/analytics_misc/text_loading_shimmer.dart';
|
||||
import 'package:fluffychat/pangea/morphs/get_grammar_copy.dart';
|
||||
import 'package:fluffychat/pangea/morphs/morph_features_enum.dart';
|
||||
import 'package:fluffychat/pangea/morphs/morph_meaning/morph_info_repo.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_gen/gen_l10n/l10n.dart';
|
||||
|
||||
class MorphMeaningWidget extends StatefulWidget {
|
||||
final MorphFeaturesEnum feature;
|
||||
final String tag;
|
||||
final TextStyle? style;
|
||||
final InlineSpan? leading;
|
||||
|
||||
const MorphMeaningWidget({
|
||||
super.key,
|
||||
required this.feature,
|
||||
required this.tag,
|
||||
this.style,
|
||||
this.leading,
|
||||
});
|
||||
|
||||
@override
|
||||
|
|
@ -136,36 +132,18 @@ class MorphMeaningWidgetState extends State<MorphMeaningWidget> {
|
|||
);
|
||||
}
|
||||
|
||||
return Row(
|
||||
mainAxisAlignment: widget.leading != null
|
||||
? MainAxisAlignment.start
|
||||
: MainAxisAlignment.center,
|
||||
children: [
|
||||
Flexible(
|
||||
child: Tooltip(
|
||||
triggerMode: TooltipTriggerMode.tap,
|
||||
message: L10n.of(context).doubleClickToEdit,
|
||||
child: GestureDetector(
|
||||
onLongPress: () => _toggleEditMode(true),
|
||||
onDoubleTap: () => _toggleEditMode(true),
|
||||
child: RichText(
|
||||
textAlign:
|
||||
widget.leading == null ? TextAlign.center : TextAlign.start,
|
||||
text: TextSpan(
|
||||
style: widget.style,
|
||||
children: [
|
||||
if (widget.leading != null) widget.leading!,
|
||||
if (widget.leading != null) const TextSpan(text: ' '),
|
||||
TextSpan(
|
||||
text: _cachedResponse ?? L10n.of(context).meaningNotFound,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
return Tooltip(
|
||||
triggerMode: TooltipTriggerMode.tap,
|
||||
message: L10n.of(context).doubleClickToEdit,
|
||||
child: GestureDetector(
|
||||
onLongPress: () => _toggleEditMode(true),
|
||||
onDoubleTap: () => _toggleEditMode(true),
|
||||
child: Text(
|
||||
textAlign: TextAlign.center,
|
||||
_cachedResponse ?? L10n.of(context).meaningNotFound,
|
||||
style: widget.style,
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ class MessageTokenButton extends StatefulWidget {
|
|||
final TextStyle textStyle;
|
||||
final double width;
|
||||
final bool animateIn;
|
||||
final PracticeTarget? practiceTarget;
|
||||
final PracticeTarget? practiceTargetForToken;
|
||||
|
||||
const MessageTokenButton({
|
||||
super.key,
|
||||
|
|
@ -40,7 +40,7 @@ class MessageTokenButton extends StatefulWidget {
|
|||
required this.token,
|
||||
required this.textStyle,
|
||||
required this.width,
|
||||
required this.practiceTarget,
|
||||
required this.practiceTargetForToken,
|
||||
this.animateIn = false,
|
||||
});
|
||||
|
||||
|
|
@ -127,9 +127,9 @@ class MessageTokenButtonState extends State<MessageTokenButton>
|
|||
|
||||
bool get _animate => widget.animateIn || _finishedInitialAnimation;
|
||||
|
||||
PracticeTarget? get _activity => widget.practiceTarget;
|
||||
PracticeTarget? get _activity => widget.practiceTargetForToken;
|
||||
|
||||
bool get _isActivityCompleteForToken =>
|
||||
bool get _isActivityCompleteOrNullForToken =>
|
||||
_activity?.isCompleteByToken(
|
||||
widget.token,
|
||||
_activity!.morphFeature,
|
||||
|
|
@ -189,8 +189,13 @@ class MessageTokenButtonState extends State<MessageTokenButton>
|
|||
|
||||
bool get _isEmpty {
|
||||
final mode = widget.overlayController?.toolbarMode;
|
||||
if (MessageMode.wordEmoji == mode &&
|
||||
widget.token.vocabConstructID.userSetEmoji.firstOrNull != null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return _activity == null ||
|
||||
(_isActivityCompleteForToken &&
|
||||
(_isActivityCompleteOrNullForToken &&
|
||||
![MessageMode.wordEmoji, MessageMode.wordMorph].contains(mode)) ||
|
||||
(MessageMode.wordMorph == mode && _activity?.morphFeature == null);
|
||||
}
|
||||
|
|
@ -207,7 +212,7 @@ class MessageTokenButtonState extends State<MessageTokenButton>
|
|||
messageMode: widget.overlayController!.toolbarMode,
|
||||
token: widget.token,
|
||||
selectedChoice: widget.overlayController?.selectedChoice,
|
||||
isComplete: _isActivityCompleteForToken,
|
||||
isActivityCompleteOrNullForToken: _isActivityCompleteOrNullForToken,
|
||||
isSelected: _isSelected,
|
||||
height: tokenButtonHeight,
|
||||
width: widget.width,
|
||||
|
|
@ -229,7 +234,7 @@ class MessageTokenButtonState extends State<MessageTokenButton>
|
|||
messageMode: widget.overlayController!.toolbarMode,
|
||||
token: widget.token,
|
||||
selectedChoice: widget.overlayController?.selectedChoice,
|
||||
isComplete: _isActivityCompleteForToken,
|
||||
isActivityCompleteOrNullForToken: _isActivityCompleteOrNullForToken,
|
||||
isSelected: _isSelected,
|
||||
height: _heightAnimation.value,
|
||||
width: widget.width,
|
||||
|
|
@ -252,7 +257,7 @@ class MessageTokenButtonContent extends StatelessWidget {
|
|||
final PangeaToken token;
|
||||
final PracticeChoice? selectedChoice;
|
||||
|
||||
final bool isComplete;
|
||||
final bool isActivityCompleteOrNullForToken;
|
||||
final bool isSelected;
|
||||
final double height;
|
||||
final double width;
|
||||
|
|
@ -269,7 +274,7 @@ class MessageTokenButtonContent extends StatelessWidget {
|
|||
required this.messageMode,
|
||||
required this.token,
|
||||
required this.selectedChoice,
|
||||
required this.isComplete,
|
||||
required this.isActivityCompleteOrNullForToken,
|
||||
required this.isSelected,
|
||||
required this.height,
|
||||
required this.width,
|
||||
|
|
@ -291,7 +296,7 @@ class MessageTokenButtonContent extends StatelessWidget {
|
|||
if (activity == null) {
|
||||
return Theme.of(context).colorScheme.primary;
|
||||
}
|
||||
if (isComplete) {
|
||||
if (isActivityCompleteOrNullForToken) {
|
||||
return AppConfig.gold;
|
||||
}
|
||||
return Theme.of(context).colorScheme.primary;
|
||||
|
|
@ -299,11 +304,7 @@ class MessageTokenButtonContent extends StatelessWidget {
|
|||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
if (activity == null) {
|
||||
return SizedBox(height: height);
|
||||
}
|
||||
|
||||
if (isComplete) {
|
||||
if (isActivityCompleteOrNullForToken || activity == null) {
|
||||
if (MessageMode.wordEmoji == messageMode) {
|
||||
return SizedBox(
|
||||
height: height,
|
||||
|
|
@ -314,7 +315,7 @@ class MessageTokenButtonContent extends StatelessWidget {
|
|||
),
|
||||
);
|
||||
}
|
||||
if (MessageMode.wordMorph == messageMode) {
|
||||
if (MessageMode.wordMorph == messageMode && activity != null) {
|
||||
final morphFeature = activity!.morphFeature!;
|
||||
final morphTag = token.morphIdByFeature(morphFeature);
|
||||
if (morphTag != null) {
|
||||
|
|
@ -337,8 +338,9 @@ class MessageTokenButtonContent extends StatelessWidget {
|
|||
),
|
||||
);
|
||||
}
|
||||
} else {
|
||||
return SizedBox(height: height);
|
||||
}
|
||||
return SizedBox(height: height);
|
||||
}
|
||||
|
||||
if (MessageMode.wordMorph == messageMode) {
|
||||
|
|
|
|||
|
|
@ -1,8 +1,5 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:flutter_gen/gen_l10n/l10n.dart';
|
||||
|
||||
import 'package:fluffychat/pangea/analytics_details_popup/morph_meaning_widget.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/construct_type_enum.dart';
|
||||
import 'package:fluffychat/pangea/choreographer/widgets/choice_animation.dart';
|
||||
import 'package:fluffychat/pangea/constructs/construct_form.dart';
|
||||
|
|
@ -15,6 +12,8 @@ import 'package:fluffychat/pangea/practice_activities/practice_activity_model.da
|
|||
import 'package:fluffychat/pangea/practice_activities/practice_choice.dart';
|
||||
import 'package:fluffychat/pangea/toolbar/reading_assistance_input_row/message_morph_choice_item.dart';
|
||||
import 'package:fluffychat/pangea/toolbar/widgets/message_selection_overlay.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_gen/gen_l10n/l10n.dart';
|
||||
|
||||
// this widget will handle the content of the input bar when mode == MessageMode.wordMorph
|
||||
|
||||
|
|
@ -62,19 +61,41 @@ class MessageMorphInputBarContentState
|
|||
void didUpdateWidget(covariant MessageMorphInputBarContent oldWidget) {
|
||||
if (morph != oldWidget.overlayController.selectedMorph?.morph ||
|
||||
token != oldWidget.overlayController.selectedToken) {
|
||||
selectedTag = null;
|
||||
setState(() {});
|
||||
}
|
||||
super.didUpdateWidget(oldWidget);
|
||||
}
|
||||
|
||||
String? get _correctChoice {
|
||||
return widget.activity.multipleChoiceContent?.choices
|
||||
.firstWhereOrNull((choice) {
|
||||
return widget.activity.practiceTarget.wasCorrectChoice(choice) == true;
|
||||
});
|
||||
}
|
||||
|
||||
TextStyle? textStyle(BuildContext context) => overlay.maxWidth > 600
|
||||
? Theme.of(context).textTheme.bodyLarge?.copyWith(
|
||||
fontWeight: FontWeight.bold,
|
||||
)
|
||||
: Theme.of(context).textTheme.bodyMedium?.copyWith(
|
||||
fontWeight: FontWeight.bold,
|
||||
);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final iconSize = overlay.maxWidth > 600 ? 30.0 : 24.0;
|
||||
final spacing = overlay.maxWidth > 600 ? 16.0 : 8.0;
|
||||
final iconSize = overlay.maxWidth > 600
|
||||
? 28.0
|
||||
: overlay.maxWidth > 600
|
||||
? 24.0
|
||||
: 16.0;
|
||||
final spacing = overlay.maxWidth > 600
|
||||
? 16.0
|
||||
: overlay.maxWidth > 600
|
||||
? 8.0
|
||||
: 4.0;
|
||||
|
||||
return Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
spacing: spacing,
|
||||
children: [
|
||||
|
|
@ -94,13 +115,7 @@ class MessageMorphInputBarContentState
|
|||
morph.getDisplayCopy(context),
|
||||
token.text.content,
|
||||
),
|
||||
style: overlay.maxWidth > 600
|
||||
? Theme.of(context).textTheme.bodyLarge?.copyWith(
|
||||
fontWeight: FontWeight.bold,
|
||||
)
|
||||
: Theme.of(context).textTheme.bodyMedium?.copyWith(
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
style: textStyle(context),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
),
|
||||
|
|
@ -151,12 +166,21 @@ class MessageMorphInputBarContentState
|
|||
},
|
||||
).toList(),
|
||||
),
|
||||
// SizedBox(
|
||||
// height: 50,
|
||||
// child: selectedTag != null
|
||||
// ? MorphMeaningWidget(feature: morph, tag: selectedTag!)
|
||||
// : null,
|
||||
// ),
|
||||
Container(
|
||||
constraints: BoxConstraints(
|
||||
minHeight: overlay.maxWidth > 600 ? 20 : 34,
|
||||
),
|
||||
alignment: Alignment.center,
|
||||
child: selectedTag != null
|
||||
? MorphMeaningWidget(
|
||||
feature: morph,
|
||||
tag: selectedTag!,
|
||||
style: overlay.maxWidth > 600
|
||||
? Theme.of(context).textTheme.bodyLarge
|
||||
: Theme.of(context).textTheme.bodySmall,
|
||||
)
|
||||
: const SizedBox.shrink(),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,11 +1,10 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:fluffychat/config/app_config.dart';
|
||||
import 'package:fluffychat/config/themes.dart';
|
||||
import 'package:fluffychat/pangea/constructs/construct_identifier.dart';
|
||||
import 'package:fluffychat/pangea/morphs/get_grammar_copy.dart';
|
||||
import 'package:fluffychat/pangea/morphs/morph_features_enum.dart';
|
||||
import 'package:fluffychat/pangea/morphs/morph_icon.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class MessageMorphChoiceItem extends StatefulWidget {
|
||||
const MessageMorphChoiceItem({
|
||||
|
|
@ -61,7 +60,7 @@ class MessageMorphChoiceItemState extends State<MessageMorphChoiceItem> {
|
|||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final color = _color;
|
||||
final iconSize = FluffyThemes.isColumnMode(context) ? 32.0 : 24.0;
|
||||
final iconSize = FluffyThemes.isColumnMode(context) ? 24.0 : 16.0;
|
||||
final style = FluffyThemes.isColumnMode(context)
|
||||
? Theme.of(context).textTheme.bodyLarge
|
||||
: Theme.of(context).textTheme.bodySmall;
|
||||
|
|
@ -76,8 +75,9 @@ class MessageMorphChoiceItemState extends State<MessageMorphChoiceItem> {
|
|||
color: color,
|
||||
borderRadius: BorderRadius.circular(AppConfig.borderRadius),
|
||||
border: Border.all(
|
||||
color:
|
||||
widget.isSelected || _isHovered ? color : Colors.transparent,
|
||||
color: widget.isSelected || _isHovered
|
||||
? color.withAlpha(255)
|
||||
: Colors.transparent,
|
||||
width: 2.0,
|
||||
),
|
||||
),
|
||||
|
|
|
|||
|
|
@ -1,14 +1,13 @@
|
|||
import 'dart:developer';
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:fluffychat/config/app_config.dart';
|
||||
import 'package:fluffychat/pangea/common/utils/error_handler.dart';
|
||||
import 'package:fluffychat/pangea/events/models/pangea_token_model.dart';
|
||||
import 'package:fluffychat/pangea/practice_activities/practice_choice.dart';
|
||||
import 'package:fluffychat/pangea/toolbar/controllers/tts_controller.dart';
|
||||
import 'package:fluffychat/pangea/toolbar/widgets/message_selection_overlay.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class PracticeMatchItem extends StatefulWidget {
|
||||
const PracticeMatchItem({
|
||||
|
|
@ -129,7 +128,7 @@ class PracticeMatchItemState extends State<PracticeMatchItem> {
|
|||
borderRadius: BorderRadius.circular(AppConfig.borderRadius),
|
||||
border: isSelected
|
||||
? Border.all(
|
||||
color: color(context),
|
||||
color: color(context).withAlpha(255),
|
||||
width: 2,
|
||||
)
|
||||
: Border.all(
|
||||
|
|
|
|||
|
|
@ -538,10 +538,11 @@ class MessageOverlayController extends State<MessageSelectionOverlay>
|
|||
|
||||
/// we don't want to associate the audio with the text in this mode
|
||||
if (practiceSelection?.hasActiveActivityByToken(
|
||||
ActivityTypeEnum.wordFocusListening,
|
||||
token,
|
||||
) ==
|
||||
false) {
|
||||
ActivityTypeEnum.wordFocusListening,
|
||||
token,
|
||||
) ==
|
||||
false ||
|
||||
!hideWordCardContent) {
|
||||
widget.chatController.choreographer.tts.tryToSpeak(
|
||||
token.text.content,
|
||||
context,
|
||||
|
|
|
|||
|
|
@ -226,7 +226,7 @@ class MessageTextWidget extends StatelessWidget {
|
|||
textStyle: renderer.style(context),
|
||||
width: tokenWidth,
|
||||
animateIn: isTransitionAnimation,
|
||||
practiceTarget: overlayController
|
||||
practiceTargetForToken: overlayController
|
||||
?.toolbarMode.associatedActivityType !=
|
||||
null
|
||||
? overlayController?.practiceSelection
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:fluffychat/pangea/toolbar/enums/message_mode_enum.dart';
|
||||
import 'package:fluffychat/pangea/toolbar/widgets/message_selection_overlay.dart';
|
||||
import 'package:fluffychat/pangea/toolbar/widgets/toolbar_button.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class ToolbarButtonRow extends StatelessWidget {
|
||||
final MessageOverlayController overlayController;
|
||||
|
|
@ -14,8 +13,6 @@ class ToolbarButtonRow extends StatelessWidget {
|
|||
|
||||
static const double iconWidth = 36.0;
|
||||
static const double buttonSize = 40.0;
|
||||
static const barMargin =
|
||||
EdgeInsets.symmetric(horizontal: iconWidth / 2, vertical: buttonSize / 2);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
|
@ -85,6 +82,7 @@ class ToolbarButtonRow extends StatelessWidget {
|
|||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 4.0),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue