You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
fluffychat/lib/pangea/morphs/edit_morph_widget.dart

259 lines
8.9 KiB
Dart

import 'package:flutter/material.dart';
import 'package:fluffychat/l10n/l10n.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/default_morph_mapping.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_repo.dart';
import 'package:fluffychat/widgets/future_loading_dialog.dart';
class EditMorphWidget extends StatefulWidget {
final PangeaToken token;
final PangeaMessageEvent pangeaMessageEvent;
final MorphFeaturesEnum morphFeature;
final VoidCallback onClose;
const EditMorphWidget({
required this.token,
required this.pangeaMessageEvent,
required this.morphFeature,
required this.onClose,
super.key,
});
@override
State<EditMorphWidget> createState() => EditMorphWidgetState();
}
class EditMorphWidgetState extends State<EditMorphWidget> {
List<String>? _availableMorphTags;
String? _selectedMorphTag;
@override
void initState() {
super.initState();
_setAvailableMorphs(widget.morphFeature);
_selectedMorphTag = _assignedMorphTag;
}
@override
void didUpdateWidget(covariant EditMorphWidget oldWidget) {
super.didUpdateWidget(oldWidget);
if (oldWidget.morphFeature != widget.morphFeature) {
_setAvailableMorphs(widget.morphFeature);
}
}
String? get _assignedMorphTag => widget.token.morph[widget.morphFeature];
Future<void> _setAvailableMorphs(MorphFeaturesEnum feature) async {
try {
setState(() => _availableMorphTags = null);
final resp = await MorphsRepo.get();
_availableMorphTags = resp.getDisplayTags(
feature.name,
);
} catch (e) {
_availableMorphTags = defaultMorphMapping.getDisplayTags(
feature.name,
);
} finally {
if (mounted) setState(() {});
}
}
void _saveChanges() {
if (_selectedMorphTag == null) return;
showFutureLoadingDialog(
context: context,
future: () => _sendEditedMessage(
(token) {
token.morph[widget.morphFeature] = _selectedMorphTag!;
if (widget.morphFeature.name.toLowerCase() == 'pos') {
token.pos = _selectedMorphTag!;
}
return token;
},
),
);
}
Future<void> _sendEditedMessage(
PangeaToken Function(PangeaToken token) changeCallback,
) async {
try {
final pm = widget.pangeaMessageEvent;
final existingTokens = pm.originalSent!.tokens!
.map((token) => PangeaToken.fromJson(token.toJson()))
.toList();
final tokenIndex = existingTokens.indexWhere(
(token) => token.text.offset == widget.token.text.offset,
);
if (tokenIndex == -1) {
throw Exception("Token not found in message");
}
existingTokens[tokenIndex] = changeCallback(existingTokens[tokenIndex]);
await pm.room.pangeaSendTextEvent(
pm.messageDisplayText,
editEventId: pm.eventId,
originalSent: pm.originalSent?.content,
originalWritten: pm.originalWritten?.content,
tokensSent: PangeaMessageTokens(
tokens: existingTokens,
detections: pm.originalSent?.detections,
),
tokensWritten: pm.originalWritten?.tokens != null
? PangeaMessageTokens(
tokens: pm.originalWritten!.tokens!,
detections: pm.originalWritten?.detections,
)
: null,
choreo: pm.originalSent?.choreo,
messageTag: ModelKey.messageTagMorphEdit,
);
widget.onClose();
} catch (e) {
ErrorHandler.logError(
e: e,
data: {
"selectedMorphTag": _selectedMorphTag,
"morphFeature": widget.morphFeature.name,
"pangeaMessageEvent": widget.pangeaMessageEvent.event.content,
},
);
}
}
bool get _canSaveChanges =>
_selectedMorphTag != _assignedMorphTag && _selectedMorphTag != null;
@override
Widget build(BuildContext context) {
return Stack(
children: [
Padding(
padding: const EdgeInsets.only(
top: 16.0,
bottom: 48.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),
),
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(),
),
],
),
),
),
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),
),
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),
),
],
),
),
),
],
);
}
}