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/widgets/igc/pangea_rich_text.dart

206 lines
6.3 KiB
Dart

import 'dart:developer';
import 'dart:ui';
import 'package:fluffychat/config/app_config.dart';
import 'package:fluffychat/pangea/controllers/pangea_controller.dart';
import 'package:fluffychat/pangea/matrix_event_wrappers/pangea_message_event.dart';
import 'package:fluffychat/pangea/models/representation_content_model.dart';
import 'package:fluffychat/pangea/utils/error_handler.dart';
import 'package:fluffychat/pangea/utils/instructions.dart';
import 'package:fluffychat/pangea/widgets/chat/message_context_menu.dart';
import 'package:fluffychat/pangea/widgets/chat/message_toolbar.dart';
import 'package:fluffychat/widgets/matrix.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import '../../enum/message_mode_enum.dart';
import '../../models/pangea_match_model.dart';
class PangeaRichText extends StatefulWidget {
final PangeaMessageEvent pangeaMessageEvent;
final bool immersionMode;
final ToolbarDisplayController? toolbarController;
final TextStyle? style;
const PangeaRichText({
super.key,
required this.pangeaMessageEvent,
required this.immersionMode,
required this.toolbarController,
this.style,
});
@override
PangeaRichTextState createState() => PangeaRichTextState();
}
class PangeaRichTextState extends State<PangeaRichText> {
final PangeaController pangeaController = MatrixState.pangeaController;
bool _fetchingRepresentation = false;
double get blur => (_fetchingRepresentation && widget.immersionMode) ||
!pangeaController.languageController.languagesSet
? 5
: 0;
String textSpan = "";
PangeaRepresentation? repEvent;
@override
void initState() {
super.initState();
setTextSpan();
}
@override
void didUpdateWidget(PangeaRichText oldWidget) {
super.didUpdateWidget(oldWidget);
setTextSpan();
}
void _setTextSpan(String newTextSpan) {
try {
if (!mounted) return; // Early exit if the widget is no longer in the tree
widget.toolbarController?.toolbar?.textSelection.setMessageText(
newTextSpan,
);
setState(() {
textSpan = newTextSpan;
});
} catch (error, stackTrace) {
ErrorHandler.logError(e: error, s: stackTrace, m: "Error setting text span in PangeaRichText");
}
}
void setTextSpan() {
if (_fetchingRepresentation) {
_setTextSpan(widget.pangeaMessageEvent.event.getDisplayEvent(widget.pangeaMessageEvent.timeline).body);
return;
}
if (widget.pangeaMessageEvent.eventId.contains("webdebug")) {
debugger(when: kDebugMode);
}
repEvent = widget.pangeaMessageEvent
.representationByLanguage(widget.pangeaMessageEvent.messageDisplayLangCode)
?.content;
if (repEvent == null) {
setState(() => _fetchingRepresentation = true);
widget.pangeaMessageEvent
.representationByLanguageGlobal(langCode: widget.pangeaMessageEvent.messageDisplayLangCode)
.onError((error, stackTrace) => ErrorHandler.logError(e: error, s: stackTrace, m: "Error fetching representation"))
.then((event) {
if (!mounted) return;
repEvent = event;
_setTextSpan(repEvent?.text ?? widget.pangeaMessageEvent.body);
}).whenComplete(() {
if (mounted) {
setState(() => _fetchingRepresentation = false);
}
});
_setTextSpan(widget.pangeaMessageEvent.body);
} else {
_setTextSpan(repEvent!.text);
}
}
@override
Widget build(BuildContext context) {
if (blur > 0) {
pangeaController.instructions.show(
context,
InstructionsEnum.blurMeansTranslate,
widget.pangeaMessageEvent.eventId,
);
}
//TODO - take out of build function of every message
final Widget richText = SelectableText.rich(
onSelectionChanged: (selection, cause) {
if (cause == SelectionChangedCause.longPress &&
!(widget.toolbarController?.highlighted ?? false) &&
!(widget.toolbarController?.controller.selectedEvents.any(
(e) => e.eventId == widget.pangeaMessageEvent.eventId,
) ??
false)) {
widget.toolbarController?.controller.onSelectMessage(
widget.pangeaMessageEvent.event,
);
return;
}
widget.toolbarController?.toolbar?.textSelection
.onTextSelection(selection);
},
onTap: () => widget.toolbarController?.showToolbar(context),
enableInteractiveSelection:
widget.toolbarController?.highlighted ?? false,
contextMenuBuilder: (context, state) =>
widget.toolbarController?.highlighted ?? true
? const SizedBox.shrink()
: MessageContextMenu.contextMenuOverride(
context: context,
textSelection: state,
onDefine: () => widget.toolbarController?.showToolbar(
context,
mode: MessageMode.definition,
),
onListen: () => widget.toolbarController?.showToolbar(
context,
mode: MessageMode.textToSpeech,
),
),
TextSpan(
text: textSpan,
style: widget.style,
children: [
if (_fetchingRepresentation)
const WidgetSpan(
child: Padding(
padding: EdgeInsets.only(left: 5.0),
child: SizedBox(
height: 14,
width: 14,
child: CircularProgressIndicator(
strokeWidth: 2.0,
color: AppConfig.secondaryColor,
),
),
),
),
],
),
);
return blur > 0
? ImageFiltered(
imageFilter: ImageFilter.blur(
sigmaX: blur,
sigmaY: blur,
),
child: richText,
)
: richText;
}
Future<void> onIgnore() async {
debugPrint("PTODO implement onIgnore");
}
Future<void> onITStart() async {
debugPrint("PTODO implement onITStart");
}
Future<void> onReplacementSelect(
PangeaMatch pangeaMatch,
String replacement,
) async {
debugPrint("PTODO implement onReplacementSelect");
}
Future<void> onSentenceRewrite(String sentenceRewrite) async {
debugPrint("PTODO implement onSentenceRewrite");
}
}