chore: move morph editting into morph popup (#2565)

This commit is contained in:
ggurdin 2025-04-28 11:13:06 -04:00 committed by GitHub
parent 51b5ec1163
commit 9175a05fd1
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 295 additions and 244 deletions

View file

@ -15,11 +15,13 @@ import 'package:fluffychat/widgets/matrix.dart';
class ConstructXpWidget extends StatefulWidget {
final ConstructIdentifier id;
final VoidCallback? onTap;
final double size;
const ConstructXpWidget({
super.key,
required this.id,
this.onTap,
this.size = 24.0,
});
@override
@ -100,12 +102,17 @@ class ConstructXpWidgetState extends State<ConstructXpWidget>
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: widget.onTap,
child: MouseRegion(
cursor: SystemMouseCursors.click,
child: Opacity(
opacity: constructLemmaCategory == null ? 0.2 : 1.0,
if (constructLemmaCategory == null) {
return const SizedBox();
}
return SizedBox(
width: widget.size,
height: widget.size,
child: GestureDetector(
onTap: widget.onTap,
child: MouseRegion(
cursor: SystemMouseCursors.click,
child: Stack(
alignment: Alignment.center,
children: [

View file

@ -139,93 +139,119 @@ class EditMorphWidgetState extends State<EditMorphWidget> {
@override
Widget build(BuildContext context) {
return Column(
mainAxisSize: MainAxisSize.min,
spacing: 8.0,
return Stack(
children: [
Text(
"${L10n.of(context).pangeaBotIsFallible} ${L10n.of(context).chooseCorrectLabel}",
textAlign: TextAlign.center,
style: const TextStyle(fontStyle: FontStyle.italic),
),
if (_availableMorphTags == null || _availableMorphTags!.isEmpty)
const CircularProgressIndicator()
else
Wrap(
alignment: WrapAlignment.center,
children: _availableMorphTags!.map((tag) {
return Container(
margin: const EdgeInsets.all(2),
padding: EdgeInsets.zero,
decoration: BoxDecoration(
borderRadius: const BorderRadius.all(
Radius.circular(10),
),
border: Border.all(
color: _selectedMorphTag == tag
? Theme.of(context).colorScheme.primary
: Colors.transparent,
style: BorderStyle.solid,
width: 2.0,
),
),
child: TextButton(
style: ButtonStyle(
padding: WidgetStateProperty.all(
const EdgeInsets.symmetric(
horizontal: 7,
),
),
backgroundColor: WidgetStateProperty.all<Color>(
_selectedMorphTag == tag
? Theme.of(context).colorScheme.primary.withAlpha(50)
: Colors.transparent,
),
shape: WidgetStateProperty.all(
RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10),
),
),
),
onPressed: () => setState(() => _selectedMorphTag = tag),
child: Text(
getGrammarCopy(
category: widget.morphFeature.name,
lemma: tag,
context: context,
) ??
tag,
textAlign: TextAlign.center,
),
),
);
}).toList(),
Padding(
padding: const EdgeInsets.only(
top: 16.0,
bottom: 48.0,
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
spacing: 10,
children: [
ElevatedButton(
style: ElevatedButton.styleFrom(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10.0),
child: SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.min,
spacing: 8.0,
children: [
Text(
"${L10n.of(context).pangeaBotIsFallible} ${L10n.of(context).chooseCorrectLabel}",
textAlign: TextAlign.center,
style: const TextStyle(fontStyle: FontStyle.italic),
),
padding: const EdgeInsets.symmetric(horizontal: 10),
),
onPressed: widget.onClose,
child: Text(L10n.of(context).cancel),
if (_availableMorphTags == null || _availableMorphTags!.isEmpty)
const CircularProgressIndicator()
else
Wrap(
alignment: WrapAlignment.center,
children: _availableMorphTags!.map((tag) {
return Container(
margin: const EdgeInsets.all(2),
padding: EdgeInsets.zero,
decoration: BoxDecoration(
borderRadius: const BorderRadius.all(
Radius.circular(10),
),
border: Border.all(
color: _selectedMorphTag == tag
? Theme.of(context).colorScheme.primary
: Colors.transparent,
style: BorderStyle.solid,
width: 2.0,
),
),
child: TextButton(
style: ButtonStyle(
padding: WidgetStateProperty.all(
const EdgeInsets.symmetric(
horizontal: 7,
),
),
backgroundColor: WidgetStateProperty.all<Color>(
_selectedMorphTag == tag
? Theme.of(context)
.colorScheme
.primary
.withAlpha(50)
: Colors.transparent,
),
shape: WidgetStateProperty.all(
RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10),
),
),
),
onPressed: () =>
setState(() => _selectedMorphTag = tag),
child: Text(
getGrammarCopy(
category: widget.morphFeature.name,
lemma: tag,
context: context,
) ??
tag,
textAlign: TextAlign.center,
),
),
);
}).toList(),
),
],
),
ElevatedButton(
style: ElevatedButton.styleFrom(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10.0),
),
),
Positioned(
bottom: 0,
left: 0,
right: 0,
child: Container(
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.surface,
),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
spacing: 10,
children: [
ElevatedButton(
style: ElevatedButton.styleFrom(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10.0),
),
padding: const EdgeInsets.symmetric(horizontal: 10),
),
onPressed: widget.onClose,
child: Text(L10n.of(context).cancel),
),
padding: const EdgeInsets.symmetric(horizontal: 10),
),
onPressed: _canSaveChanges ? _saveChanges : null,
child: Text(L10n.of(context).saveChanges),
ElevatedButton(
style: ElevatedButton.styleFrom(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10.0),
),
padding: const EdgeInsets.symmetric(horizontal: 10),
),
onPressed: _canSaveChanges ? _saveChanges : null,
child: Text(L10n.of(context).saveChanges),
),
],
),
],
),
),
],
);

View file

@ -8,7 +8,6 @@ import 'package:matrix/matrix_api_lite/model/message_types.dart';
import 'package:fluffychat/config/app_config.dart';
import 'package:fluffychat/config/themes.dart';
import 'package:fluffychat/pangea/events/event_wrappers/pangea_message_event.dart';
import 'package:fluffychat/pangea/morphs/morph_features_enum.dart';
import 'package:fluffychat/pangea/practice_activities/activity_type_enum.dart';
import 'package:fluffychat/pangea/toolbar/controllers/tts_controller.dart';
import 'package:fluffychat/pangea/toolbar/enums/message_mode_enum.dart';
@ -39,8 +38,6 @@ class ReadingAssistanceContent extends StatefulWidget {
}
class ReadingAssistanceContentState extends State<ReadingAssistanceContent> {
MorphFeaturesEnum? _selectedEditMorphFeature;
TtsController get ttsController =>
widget.overlayController.widget.chatController.choreographer.tts;
@ -128,8 +125,6 @@ class ReadingAssistanceContentState extends State<ReadingAssistanceContent> {
messageEvent: widget.overlayController.pangeaMessageEvent!,
tts: ttsController,
overlayController: widget.overlayController,
editMorph: (m) => setState(() => _selectedEditMorphFeature = m),
selectedEditMorphFeature: _selectedEditMorphFeature,
);
}
}

View file

@ -12,8 +12,10 @@ import 'package:fluffychat/pangea/analytics_misc/construct_type_enum.dart';
import 'package:fluffychat/pangea/common/utils/error_handler.dart';
import 'package:fluffychat/pangea/common/utils/overlay.dart';
import 'package:fluffychat/pangea/constructs/construct_identifier.dart';
import 'package:fluffychat/pangea/events/event_wrappers/pangea_message_event.dart';
import 'package:fluffychat/pangea/events/models/pangea_token_model.dart';
import 'package:fluffychat/pangea/lemmas/construct_xp_widget.dart';
import 'package:fluffychat/pangea/morphs/edit_morph_widget.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';
@ -29,13 +31,13 @@ class MorphologicalListItem extends StatelessWidget {
final MorphFeaturesEnum morphFeature;
final PangeaToken token;
final MessageOverlayController overlayController;
final VoidCallback editMorph;
// final VoidCallback editMorph;
const MorphologicalListItem({
required this.morphFeature,
required this.token,
required this.overlayController,
required this.editMorph,
// required this.editMorph,
super.key,
});
@ -64,15 +66,26 @@ class MorphologicalListItem extends StatelessWidget {
void _openDefintionPopup(BuildContext context) async {
const width = 300.0;
const height = 150.0;
const height = 200.0;
try {
if (overlayController.pangeaMessageEvent == null) {
return;
}
OverlayUtil.showPositionedCard(
context: context,
cardToShow: MorphMeaningPopup(
token: token,
pangeaMessageEvent: overlayController.pangeaMessageEvent!,
cId: cId,
width: width,
height: height,
refresh: () {
overlayController.onMorphActivitySelect(
MorphSelection(token, morphFeature),
);
},
),
transformTargetId: cId.string,
backDropToDismiss: true,
@ -114,11 +127,6 @@ class MorphologicalListItem extends StatelessWidget {
.onMorphActivitySelect(MorphSelection(token, morphFeature));
_openDefintionPopup(context);
},
onLongPress: () {
overlayController
.onMorphActivitySelect(MorphSelection(token, morphFeature));
editMorph();
},
tooltip: shouldDoActivity
? morphFeature.getDisplayCopy(context)
: getGrammarCopy(
@ -134,15 +142,21 @@ class MorphologicalListItem extends StatelessWidget {
}
class MorphMeaningPopup extends StatefulWidget {
final PangeaToken token;
final PangeaMessageEvent pangeaMessageEvent;
final ConstructIdentifier cId;
final double width;
final double height;
final VoidCallback refresh;
const MorphMeaningPopup({
super.key,
required this.token,
required this.pangeaMessageEvent,
required this.cId,
required this.width,
required this.height,
required this.refresh,
});
@override
@ -154,9 +168,10 @@ class MorphMeaningPopupState extends State<MorphMeaningPopup> {
MorphFeaturesEnumExtension.fromString(widget.cId.category);
String get _morphTag => widget.cId.lemma;
String? _defintion;
bool _isEditMode = false;
@override
void initState() {
super.initState();
@ -193,84 +208,121 @@ class MorphMeaningPopupState extends State<MorphMeaningPopup> {
}
}
void _setEditMode(bool editing) {
setState(() => _isEditMode = editing);
}
@override
Widget build(BuildContext context) {
return Material(
borderRadius: BorderRadius.circular(AppConfig.borderRadius),
child: Container(
padding: const EdgeInsets.all(8),
height: widget.height,
width: widget.width,
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.surface,
borderRadius: BorderRadius.circular(AppConfig.borderRadius),
boxShadow: [
BoxShadow(
color: Theme.of(context).colorScheme.onSurface.withAlpha(50),
blurRadius: 4,
offset: const Offset(0, 2),
child: Stack(
children: [
Container(
padding: const EdgeInsets.all(8),
height: widget.height,
width: widget.width,
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.surface,
borderRadius: BorderRadius.circular(AppConfig.borderRadius),
boxShadow: [
BoxShadow(
color: Theme.of(context).colorScheme.onSurface.withAlpha(50),
blurRadius: 4,
offset: const Offset(0, 2),
),
],
),
],
),
alignment: Alignment.center,
child: SingleChildScrollView(
child: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
spacing: 16.0,
children: [
SizedBox(
width: 24.0,
height: 24.0,
child: MorphIcon(
morphFeature: _morphFeature,
morphTag: _morphTag,
),
),
Text(
getGrammarCopy(
category: _morphFeature.name,
lemma: _morphTag,
context: context,
) ??
_morphTag,
style: Theme.of(context).textTheme.titleMedium,
),
SizedBox(
width: 24.0,
height: 24.0,
child: ConstructXpWidget(
id: widget.cId,
onTap: () => showDialog<AnalyticsPopupWrapper>(
context: context,
builder: (context) => AnalyticsPopupWrapper(
constructZoom: widget.cId,
view: ConstructTypeEnum.morph,
backButtonOverride: IconButton(
icon: const Icon(Icons.close),
onPressed: () => Navigator.of(context).pop(),
),
alignment: Alignment.center,
child: _isEditMode
? EditMorphWidget(
token: widget.token,
pangeaMessageEvent: widget.pangeaMessageEvent,
morphFeature: _morphFeature,
onClose: () {
_setEditMode(false);
_fetchDefinition();
widget.refresh();
},
)
: SingleChildScrollView(
child: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.center,
spacing: 16.0,
children: [
SizedBox(
width: 24.0,
height: 24.0,
child: MorphIcon(
morphFeature: _morphFeature,
morphTag: _morphTag,
),
),
Text(
getGrammarCopy(
category: _morphFeature.name,
lemma: _morphTag,
context: context,
) ??
_morphTag,
style: Theme.of(context).textTheme.titleMedium,
),
if (MatrixState.pangeaController.getAnalytics
.constructListModel
.getConstructUses(widget.cId) !=
null)
ConstructXpWidget(
id: widget.cId,
onTap: () => showDialog<AnalyticsPopupWrapper>(
context: context,
builder: (context) => AnalyticsPopupWrapper(
constructZoom: widget.cId,
view: ConstructTypeEnum.morph,
backButtonOverride: IconButton(
icon: const Icon(Icons.close),
onPressed: () =>
Navigator.of(context).pop(),
),
),
),
),
],
),
),
Padding(
padding: const EdgeInsets.only(top: 16.0),
child: _defintion != null
? Text(
_defintion!,
textAlign: TextAlign.center,
style: Theme.of(context).textTheme.bodyMedium,
)
: const LinearProgressIndicator(),
),
],
),
),
],
),
Padding(
padding: const EdgeInsets.only(top: 16.0),
child: _defintion != null
? Text(
_defintion!,
textAlign: TextAlign.center,
style: Theme.of(context).textTheme.bodyMedium,
)
: const LinearProgressIndicator(),
),
],
),
),
if (!_isEditMode)
Positioned(
top: 12.0,
right: 12.0,
child: MouseRegion(
cursor: SystemMouseCursors.click,
child: GestureDetector(
child: Icon(
Icons.edit_outlined,
size: 20.0,
color: Theme.of(context).disabledColor,
),
onTap: () {
_setEditMode(true);
},
),
),
),
],
),
);
}

View file

@ -8,7 +8,6 @@ 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/construct_xp_widget.dart';
import 'package:fluffychat/pangea/lemmas/lemma_emoji_row.dart';
import 'package:fluffychat/pangea/morphs/edit_morph_widget.dart';
import 'package:fluffychat/pangea/morphs/morph_features_enum.dart';
import 'package:fluffychat/pangea/practice_activities/activity_type_enum.dart';
import 'package:fluffychat/pangea/toolbar/controllers/tts_controller.dart';
@ -25,9 +24,6 @@ class WordZoomWidget extends StatelessWidget {
final PangeaMessageEvent messageEvent;
final TtsController tts;
final MessageOverlayController overlayController;
final Function(MorphFeaturesEnum?) editMorph;
final MorphFeaturesEnum? selectedEditMorphFeature;
const WordZoomWidget({
super.key,
@ -35,8 +31,6 @@ class WordZoomWidget extends StatelessWidget {
required this.messageEvent,
required this.tts,
required this.overlayController,
required this.editMorph,
required this.selectedEditMorphFeature,
});
PangeaToken get _selectedToken => overlayController.selectedToken!;
@ -111,68 +105,56 @@ class WordZoomWidget extends StatelessWidget {
const SizedBox(
height: 8.0,
),
if (selectedEditMorphFeature == null)
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
constraints: const BoxConstraints(
minHeight: 40,
),
alignment: Alignment.center,
child: LemmaEmojiRow(
cId: _selectedToken.vocabConstructID,
onTapOverride: overlayController.hideWordCardContent &&
hasEmojiActivity
? () => overlayController.updateToolbarMode(
MessageMode.wordEmoji,
)
: null,
isSelected: overlayController.toolbarMode ==
MessageMode.wordEmoji,
emojiSetCallback: () => overlayController.setState(() {}),
shouldShowEmojis: !hasEmojiActivity,
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
constraints: const BoxConstraints(
minHeight: 40,
),
],
),
alignment: Alignment.center,
child: LemmaEmojiRow(
cId: _selectedToken.vocabConstructID,
onTapOverride: overlayController.hideWordCardContent &&
hasEmojiActivity
? () => overlayController.updateToolbarMode(
MessageMode.wordEmoji,
)
: null,
isSelected:
overlayController.toolbarMode == MessageMode.wordEmoji,
emojiSetCallback: () => overlayController.setState(() {}),
shouldShowEmojis: !hasEmojiActivity,
),
),
],
),
const SizedBox(
height: 8.0,
),
if (selectedEditMorphFeature == null)
Container(
constraints: const BoxConstraints(
minHeight: 40,
),
alignment: Alignment.center,
child: Wrap(
alignment: WrapAlignment.center,
runAlignment: WrapAlignment.center,
crossAxisAlignment: WrapCrossAlignment.center,
spacing: 8,
children: [
LemmaMeaningWidget(
constructUse: token.vocabConstructID.constructUses,
langCode: MatrixState.pangeaController.languageController
.userL2?.langCodeShort ??
LanguageKeys.defaultLanguage,
token: overlayController.selectedToken!,
controller: overlayController,
style: Theme.of(context).textTheme.bodyLarge,
),
],
),
)
else
EditMorphWidget(
token: token,
pangeaMessageEvent: overlayController.pangeaMessageEvent!,
morphFeature: selectedEditMorphFeature!,
onClose: () {
editMorph(null);
overlayController.setState(() {});
},
Container(
constraints: const BoxConstraints(
minHeight: 40,
),
alignment: Alignment.center,
child: Wrap(
alignment: WrapAlignment.center,
runAlignment: WrapAlignment.center,
crossAxisAlignment: WrapCrossAlignment.center,
spacing: 8,
children: [
LemmaMeaningWidget(
constructUse: token.vocabConstructID.constructUses,
langCode: MatrixState.pangeaController.languageController
.userL2?.langCodeShort ??
LanguageKeys.defaultLanguage,
token: overlayController.selectedToken!,
controller: overlayController,
style: Theme.of(context).textTheme.bodyLarge,
),
],
),
),
const SizedBox(
height: 8.0,
),
@ -215,21 +197,10 @@ class WordZoomWidget extends StatelessWidget {
),
token: _selectedToken,
overlayController: overlayController,
editMorph: () => editMorph(
MorphFeaturesEnumExtension.fromString(cId.category),
),
),
),
],
),
// if (_selectedMorphFeature != null)
// MorphologicalCenterWidget(
// token: token,
// morphFeature: _selectedMorphFeature!,
// pangeaMessageEvent: messageEvent,
// overlayController: overlayController,
// onEditDone: onEditDone,
// ),
],
),
),