re-integrated select defintions with new fluffychat merge
This commit is contained in:
parent
84d0dd13b9
commit
ad16c6dfef
5 changed files with 159 additions and 193 deletions
|
|
@ -23,7 +23,6 @@ import 'package:fluffychat/pangea/models/message_data_models.dart';
|
|||
import 'package:fluffychat/pangea/models/student_analytics_summary_model.dart';
|
||||
import 'package:fluffychat/pangea/utils/error_handler.dart';
|
||||
import 'package:fluffychat/pangea/utils/firebase_analytics.dart';
|
||||
import 'package:fluffychat/pangea/utils/instructions.dart';
|
||||
import 'package:fluffychat/pangea/utils/report_message.dart';
|
||||
import 'package:fluffychat/pangea/widgets/igc/pangea_text_controller.dart';
|
||||
import 'package:fluffychat/utils/adaptive_bottom_sheet.dart';
|
||||
|
|
@ -1282,11 +1281,6 @@ class ChatController extends State<ChatPageWithRoom>
|
|||
if (choreographer.itController.isOpen) {
|
||||
return;
|
||||
}
|
||||
pangeaController.instructions.show(
|
||||
context,
|
||||
InstructionsEnum.understandingMessages,
|
||||
event.eventId,
|
||||
);
|
||||
// Pangea#
|
||||
if (!event.redacted) {
|
||||
if (selectedEvents.contains(event)) {
|
||||
|
|
|
|||
|
|
@ -1,11 +1,13 @@
|
|||
import 'package:fluffychat/pages/chat/events/video_player.dart';
|
||||
import 'package:fluffychat/pangea/models/language_model.dart';
|
||||
import 'package:fluffychat/pangea/models/pangea_message_event.dart';
|
||||
import 'package:fluffychat/pangea/utils/show_defintion_util.dart';
|
||||
import 'package:fluffychat/pangea/widgets/igc/pangea_rich_text.dart';
|
||||
import 'package:fluffychat/utils/adaptive_bottom_sheet.dart';
|
||||
import 'package:fluffychat/utils/date_time_extension.dart';
|
||||
import 'package:fluffychat/utils/matrix_sdk_extensions/matrix_locals.dart';
|
||||
import 'package:fluffychat/widgets/avatar.dart';
|
||||
import 'package:fluffychat/widgets/matrix.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_gen/gen_l10n/l10n.dart';
|
||||
import 'package:flutter_linkify/flutter_linkify.dart';
|
||||
|
|
@ -36,9 +38,10 @@ class MessageContent extends StatelessWidget {
|
|||
final LanguageModel? selectedDisplayLang;
|
||||
final bool immersionMode;
|
||||
final bool definitions;
|
||||
ShowDefintionUtil? messageToolbar;
|
||||
// Pangea#
|
||||
|
||||
const MessageContent(
|
||||
MessageContent(
|
||||
this.event, {
|
||||
this.onInfoTab,
|
||||
super.key,
|
||||
|
|
@ -121,6 +124,18 @@ class MessageContent extends StatelessWidget {
|
|||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
// #Pangea
|
||||
messageToolbar = ShowDefintionUtil(
|
||||
targetId: pangeaMessageEvent.eventId,
|
||||
room: pangeaMessageEvent.room,
|
||||
langCode: selectedDisplayLang?.langCode ??
|
||||
MatrixState.pangeaController.languageController.activeL2Code(
|
||||
roomID: pangeaMessageEvent.room.id,
|
||||
) ??
|
||||
LanguageModel.unknown.langCode,
|
||||
messageText: "",
|
||||
);
|
||||
// Pangea#
|
||||
final fontSize = AppConfig.messageFontSize * AppConfig.fontSizeFactor;
|
||||
final buttonTextColor = textColor;
|
||||
switch (event.type) {
|
||||
|
|
@ -263,55 +278,74 @@ class MessageContent extends StatelessWidget {
|
|||
height: 1.3,
|
||||
);
|
||||
if (pangeaMessageEvent.showRichText) {
|
||||
return PangeaRichText(
|
||||
existingStyle: messageTextStyle,
|
||||
selected: selected,
|
||||
pangeaMessageEvent: pangeaMessageEvent,
|
||||
immersionMode: immersionMode,
|
||||
definitions: definitions,
|
||||
selectedDisplayLang: selectedDisplayLang,
|
||||
return MouseRegion(
|
||||
onHover: messageToolbar?.onMouseRegionUpdate,
|
||||
child: PangeaRichText(
|
||||
existingStyle: messageTextStyle,
|
||||
selected: selected,
|
||||
pangeaMessageEvent: pangeaMessageEvent,
|
||||
immersionMode: immersionMode,
|
||||
definitions: definitions,
|
||||
selectedDisplayLang: selectedDisplayLang,
|
||||
messageToolbar: messageToolbar,
|
||||
),
|
||||
);
|
||||
}
|
||||
//Pangea#
|
||||
return FutureBuilder<String>(
|
||||
future: event.calcLocalizedBody(
|
||||
MatrixLocals(L10n.of(context)!),
|
||||
hideReply: true,
|
||||
),
|
||||
builder: (context, snapshot) {
|
||||
// #Pangea
|
||||
if (!snapshot.hasData) {
|
||||
return Text(
|
||||
event.calcLocalizedBodyFallback(
|
||||
MatrixLocals(L10n.of(context)!),
|
||||
hideReply: true,
|
||||
),
|
||||
style: messageTextStyle,
|
||||
);
|
||||
}
|
||||
return MouseRegion(
|
||||
onHover: messageToolbar?.onMouseRegionUpdate,
|
||||
child: FutureBuilder<String>(
|
||||
// Pangea#
|
||||
return Linkify(
|
||||
text: snapshot.data ??
|
||||
future: event.calcLocalizedBody(
|
||||
MatrixLocals(L10n.of(context)!),
|
||||
hideReply: true,
|
||||
),
|
||||
builder: (context, snapshot) {
|
||||
// #Pangea
|
||||
if (!snapshot.hasData) {
|
||||
return Text(
|
||||
event.calcLocalizedBodyFallback(
|
||||
MatrixLocals(L10n.of(context)!),
|
||||
hideReply: true,
|
||||
),
|
||||
style: TextStyle(
|
||||
color: textColor,
|
||||
fontSize: bigEmotes ? fontSize * 3 : fontSize,
|
||||
decoration:
|
||||
event.redacted ? TextDecoration.lineThrough : null,
|
||||
),
|
||||
options: const LinkifyOptions(humanize: false),
|
||||
linkStyle: TextStyle(
|
||||
color: textColor.withAlpha(150),
|
||||
fontSize: bigEmotes ? fontSize * 3 : fontSize,
|
||||
decoration: TextDecoration.underline,
|
||||
decorationColor: textColor.withAlpha(150),
|
||||
),
|
||||
onOpen: (url) => UrlLauncher(context, url.url).launchUrl(),
|
||||
);
|
||||
},
|
||||
style: messageTextStyle,
|
||||
);
|
||||
}
|
||||
// return Linkify(
|
||||
final String messageText = snapshot.data ??
|
||||
event.calcLocalizedBodyFallback(
|
||||
MatrixLocals(L10n.of(context)!),
|
||||
hideReply: true,
|
||||
);
|
||||
messageToolbar?.messageText = messageText;
|
||||
return SelectableLinkify(
|
||||
// Pangea#
|
||||
text: messageText,
|
||||
focusNode: messageToolbar?.focusNode,
|
||||
contextMenuBuilder: messageToolbar?.contextMenuOverride,
|
||||
// text: snapshot.data ??
|
||||
// event.calcLocalizedBodyFallback(
|
||||
// MatrixLocals(L10n.of(context)!),
|
||||
// hideReply: true,
|
||||
// ),
|
||||
style: TextStyle(
|
||||
color: textColor,
|
||||
fontSize: bigEmotes ? fontSize * 3 : fontSize,
|
||||
decoration:
|
||||
event.redacted ? TextDecoration.lineThrough : null,
|
||||
),
|
||||
options: const LinkifyOptions(humanize: false),
|
||||
linkStyle: TextStyle(
|
||||
color: textColor.withAlpha(150),
|
||||
fontSize: bigEmotes ? fontSize * 3 : fontSize,
|
||||
decoration: TextDecoration.underline,
|
||||
decorationColor: textColor.withAlpha(150),
|
||||
),
|
||||
onOpen: (url) => UrlLauncher(context, url.url).launchUrl(),
|
||||
onSelectionChanged: (selection, cause) => messageToolbar
|
||||
?.onTextSelection(selection, cause, context),
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
case EventTypes.CallInvite:
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:flutter_gen/gen_l10n/l10n.dart';
|
||||
|
||||
import '../../config/app_config.dart';
|
||||
|
|
@ -96,7 +95,6 @@ class InstructionsController {
|
|||
enum InstructionsEnum {
|
||||
itInstructions,
|
||||
clickMessage,
|
||||
understandingMessages,
|
||||
blurMeansTranslate,
|
||||
}
|
||||
|
||||
|
|
@ -107,8 +105,6 @@ extension Copy on InstructionsEnum {
|
|||
return L10n.of(context)!.itInstructionsTitle;
|
||||
case InstructionsEnum.clickMessage:
|
||||
return L10n.of(context)!.clickMessageTitle;
|
||||
case InstructionsEnum.understandingMessages:
|
||||
return L10n.of(context)!.understandingMessagesTitle;
|
||||
case InstructionsEnum.blurMeansTranslate:
|
||||
return L10n.of(context)!.blurMeansTranslateTitle;
|
||||
}
|
||||
|
|
@ -120,8 +116,6 @@ extension Copy on InstructionsEnum {
|
|||
return L10n.of(context)!.itInstructionsBody;
|
||||
case InstructionsEnum.clickMessage:
|
||||
return L10n.of(context)!.clickMessageBody;
|
||||
case InstructionsEnum.understandingMessages:
|
||||
return L10n.of(context)!.understandingMessagesBody;
|
||||
case InstructionsEnum.blurMeansTranslate:
|
||||
return L10n.of(context)!.blurMeansTranslateBody;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,13 +11,15 @@ import 'package:flutter_gen/gen_l10n/l10n.dart';
|
|||
import 'package:matrix/matrix.dart';
|
||||
|
||||
class ShowDefintionUtil {
|
||||
final String messageText;
|
||||
String messageText;
|
||||
final String langCode;
|
||||
final String targetId;
|
||||
final FocusNode focusNode = FocusNode();
|
||||
final Room room;
|
||||
TextSelection? textSelection;
|
||||
bool inCooldown = false;
|
||||
double? dx;
|
||||
double? dy;
|
||||
|
||||
ShowDefintionUtil({
|
||||
required this.targetId,
|
||||
|
|
@ -93,17 +95,18 @@ class ShowDefintionUtil {
|
|||
Future<dynamic> showToolbar(BuildContext context) async {
|
||||
final LayerLinkAndKey layerLinkAndKey =
|
||||
MatrixState.pAnyState.layerLinkAndKey(targetId);
|
||||
final RenderBox? targetRenderBox =
|
||||
(layerLinkAndKey.key.currentContext!.findRenderObject() as RenderBox?);
|
||||
final Size? transformTargetSize = targetRenderBox?.size;
|
||||
|
||||
Offset? transformTargetOffset;
|
||||
if (transformTargetSize != null) {
|
||||
transformTargetOffset = Offset(
|
||||
(transformTargetSize.width / 2) - 65,
|
||||
transformTargetSize.height * -1,
|
||||
);
|
||||
final RenderObject? targetRenderBox =
|
||||
layerLinkAndKey.key.currentContext!.findRenderObject();
|
||||
final Offset transformTargetOffset =
|
||||
(targetRenderBox as RenderBox).localToGlobal(Offset.zero);
|
||||
|
||||
if (dx != null && dx! > MediaQuery.of(context).size.width - 130) {
|
||||
dx = MediaQuery.of(context).size.width - 130;
|
||||
}
|
||||
final double xOffset = dx != null ? dx! - transformTargetOffset.dx : 0;
|
||||
final double yOffset =
|
||||
dy != null ? dy! - transformTargetOffset.dy + 10 : 10;
|
||||
|
||||
OverlayUtil.showOverlay(
|
||||
context: context,
|
||||
|
|
@ -124,7 +127,28 @@ class ShowDefintionUtil {
|
|||
),
|
||||
size: const Size(130, 45),
|
||||
transformTargetId: targetId,
|
||||
offset: transformTargetOffset,
|
||||
offset: Offset(xOffset, yOffset),
|
||||
);
|
||||
}
|
||||
|
||||
void onMouseRegionUpdate(PointerEvent event) {
|
||||
dx = event.position.dx;
|
||||
dy = event.position.dy;
|
||||
}
|
||||
|
||||
Widget contextMenuOverride(BuildContext context, EditableTextState selection) {
|
||||
return AdaptiveTextSelectionToolbar.buttonItems(
|
||||
anchors: selection.contextMenuAnchors,
|
||||
buttonItems: [
|
||||
...selection.contextMenuButtonItems,
|
||||
ContextMenuButtonItem(
|
||||
label: L10n.of(context)!.showDefinition,
|
||||
onPressed: () {
|
||||
showDefinition(context);
|
||||
focusNode.unfocus();
|
||||
},
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
import 'dart:async';
|
||||
import 'dart:developer';
|
||||
import 'dart:ui';
|
||||
|
||||
|
|
@ -13,13 +12,13 @@ import 'package:fluffychat/pangea/utils/show_defintion_util.dart';
|
|||
import 'package:fluffychat/widgets/matrix.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_gen/gen_l10n/l10n.dart';
|
||||
import 'package:sentry_flutter/sentry_flutter.dart';
|
||||
|
||||
import '../../models/igc_text_data_model.dart';
|
||||
import '../../models/language_detection_model.dart';
|
||||
import '../../models/pangea_match_model.dart';
|
||||
import '../../models/pangea_representation_event.dart';
|
||||
import '../../utils/bot_style.dart';
|
||||
import '../../utils/instructions.dart';
|
||||
|
||||
class PangeaRichText extends StatefulWidget {
|
||||
|
|
@ -30,6 +29,7 @@ class PangeaRichText extends StatefulWidget {
|
|||
final bool immersionMode;
|
||||
final bool definitions;
|
||||
final Choreographer? choreographer;
|
||||
final ShowDefintionUtil? messageToolbar;
|
||||
|
||||
const PangeaRichText({
|
||||
super.key,
|
||||
|
|
@ -40,6 +40,7 @@ class PangeaRichText extends StatefulWidget {
|
|||
required this.definitions,
|
||||
this.choreographer,
|
||||
this.existingStyle,
|
||||
this.messageToolbar,
|
||||
});
|
||||
|
||||
@override
|
||||
|
|
@ -52,32 +53,30 @@ class PangeaRichTextState extends State<PangeaRichText> {
|
|||
bool _fetchingTokens = false;
|
||||
double get blur => _fetchingRepresentation && widget.immersionMode ? 5 : 0;
|
||||
List<TextSpan> textSpan = [];
|
||||
ShowDefintionUtil? messageToolbar;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
setState(() => textSpan = getTextSpan(context));
|
||||
updateTextSpan();
|
||||
}
|
||||
|
||||
@override
|
||||
void didUpdateWidget(PangeaRichText oldWidget) {
|
||||
super.didUpdateWidget(oldWidget);
|
||||
setState(() => textSpan = getTextSpan(context));
|
||||
updateTextSpan();
|
||||
}
|
||||
|
||||
void updateTextSpan() {
|
||||
setState(() {
|
||||
textSpan = getTextSpan(context);
|
||||
widget.messageToolbar?.messageText = textSpan.map((e) => e.text).join();
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
//TODO - take out of build function of every message
|
||||
// if (areLanguagesSet) {
|
||||
messageToolbar = ShowDefintionUtil(
|
||||
targetId: widget.pangeaMessageEvent.eventId,
|
||||
room: widget.pangeaMessageEvent.room,
|
||||
langCode: widget.selectedDisplayLang?.langCode ??
|
||||
userL2LangCode ??
|
||||
LanguageKeys.unknownLanguage,
|
||||
messageText: textSpan.map((x) => x.text).join(),
|
||||
);
|
||||
|
||||
if (!widget.selected &&
|
||||
widget.selectedDisplayLang != null &&
|
||||
|
|
@ -95,51 +94,33 @@ class PangeaRichTextState extends State<PangeaRichText> {
|
|||
);
|
||||
}
|
||||
|
||||
final TextSpan richTextSpan = TextSpan(
|
||||
children: [
|
||||
...textSpan,
|
||||
if (widget.selected && (_fetchingRepresentation || _fetchingTokens))
|
||||
const WidgetSpan(
|
||||
child: Padding(
|
||||
padding: EdgeInsets.only(left: 5.0),
|
||||
child: SizedBox(
|
||||
height: 14,
|
||||
width: 14,
|
||||
child: CircularProgressIndicator(
|
||||
strokeWidth: 2.0,
|
||||
color: AppConfig.secondaryColor,
|
||||
final Widget richText = SelectableText.rich(
|
||||
onSelectionChanged: (selection, cause) =>
|
||||
widget.messageToolbar?.onTextSelection(selection, cause, context),
|
||||
focusNode: widget.messageToolbar?.focusNode,
|
||||
contextMenuBuilder: widget.messageToolbar?.contextMenuOverride,
|
||||
TextSpan(
|
||||
children: [
|
||||
...textSpan,
|
||||
if (widget.selected && (_fetchingRepresentation || _fetchingTokens))
|
||||
// if (widget.selected)
|
||||
const WidgetSpan(
|
||||
child: Padding(
|
||||
padding: EdgeInsets.only(left: 5.0),
|
||||
child: SizedBox(
|
||||
height: 14,
|
||||
width: 14,
|
||||
child: CircularProgressIndicator(
|
||||
strokeWidth: 2.0,
|
||||
color: AppConfig.secondaryColor,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
final Widget richText = widget.selected
|
||||
? SelectableText.rich(
|
||||
richTextSpan,
|
||||
onSelectionChanged: (selection, cause) => kIsWeb
|
||||
? messageToolbar?.onTextSelection(selection, cause, context)
|
||||
: null,
|
||||
focusNode: messageToolbar?.focusNode,
|
||||
contextMenuBuilder: (context, selection) {
|
||||
return AdaptiveTextSelectionToolbar.buttonItems(
|
||||
anchors: selection.contextMenuAnchors,
|
||||
buttonItems: [
|
||||
...selection.contextMenuButtonItems,
|
||||
ContextMenuButtonItem(
|
||||
label: L10n.of(context)!.showDefinition,
|
||||
onPressed: () {
|
||||
messageToolbar?.showDefinition(context);
|
||||
messageToolbar?.focusNode.unfocus();
|
||||
},
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
)
|
||||
: RichText(text: richTextSpan);
|
||||
|
||||
return blur > 0
|
||||
? ImageFiltered(
|
||||
imageFilter: ImageFilter.blur(sigmaX: blur, sigmaY: blur),
|
||||
|
|
@ -222,8 +203,8 @@ class PangeaRichTextState extends State<PangeaRichText> {
|
|||
userL1: userL1LangCode ?? LanguageKeys.unknownLanguage,
|
||||
).constructTokenSpan(
|
||||
context: context,
|
||||
defaultStyle: widget.existingStyle,
|
||||
handleClick: true,
|
||||
defaultStyle: textStyle(repEvent, context),
|
||||
handleClick: false,
|
||||
spanCardModel: null,
|
||||
transformTargetId: widget.pangeaMessageEvent.eventId,
|
||||
room: widget.pangeaMessageEvent.room,
|
||||
|
|
@ -244,10 +225,20 @@ class PangeaRichTextState extends State<PangeaRichText> {
|
|||
[
|
||||
TextSpan(
|
||||
text: repEvent.text,
|
||||
style: widget.existingStyle,
|
||||
style: textStyle(repEvent, context),
|
||||
),
|
||||
];
|
||||
|
||||
TextStyle? textStyle(RepresentationEvent repEvent, BuildContext context) =>
|
||||
// !repEvent.botAuthored
|
||||
true
|
||||
? widget.existingStyle
|
||||
: BotStyle.text(
|
||||
context,
|
||||
existingStyle: widget.existingStyle,
|
||||
setColor: false,
|
||||
);
|
||||
|
||||
bool get areLanguagesSet =>
|
||||
userL2LangCode != null && userL2LangCode != LanguageKeys.unknownLanguage;
|
||||
|
||||
|
|
@ -279,75 +270,4 @@ class PangeaRichTextState extends State<PangeaRichText> {
|
|||
Future<void> onSentenceRewrite(String sentenceRewrite) async {
|
||||
debugPrint("PTODO implement onSentenceRewrite");
|
||||
}
|
||||
|
||||
// void onTextSelection(
|
||||
// TextSelection selection,
|
||||
// SelectionChangedCause? _,
|
||||
// ) =>
|
||||
// selection.isCollapsed
|
||||
// ? clearTextSelection()
|
||||
// : setTextSelection(selection);
|
||||
|
||||
// void setTextSelection(TextSelection selection) {
|
||||
// textSelection = selection;
|
||||
// if (BrowserContextMenu.enabled && kIsWeb) {
|
||||
// BrowserContextMenu.disableContextMenu();
|
||||
// }
|
||||
// kIsWeb ? showToolbar() : showDefinition();
|
||||
// }
|
||||
|
||||
// void clearTextSelection() {
|
||||
// textSelection = null;
|
||||
// if (kIsWeb && !BrowserContextMenu.enabled) {
|
||||
// BrowserContextMenu.enableContextMenu();
|
||||
// }
|
||||
// }
|
||||
|
||||
// void showToolbar() async {
|
||||
// if (toolbarShowing || !kIsWeb) return;
|
||||
// toolbarShowing = true;
|
||||
// await Future.delayed(const Duration(seconds: 2));
|
||||
|
||||
// final toolbarFuture = MessageToolbar.showToolbar(
|
||||
// context,
|
||||
// widget.pangeaMessageEvent.eventId,
|
||||
// _focusNode.offset,
|
||||
// );
|
||||
|
||||
// final resp = await toolbarFuture;
|
||||
// toolbarShowing = false;
|
||||
|
||||
// switch (resp) {
|
||||
// case null:
|
||||
// break;
|
||||
// case 1:
|
||||
// showDefinition();
|
||||
// break;
|
||||
// default:
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
|
||||
// void showDefinition() {
|
||||
// final String messageText = textSpan.map((x) => x.text).join();
|
||||
// final String fullText = textSelection!.textInside(messageText);
|
||||
// final String langCode = widget.selectedDisplayLang?.langCode ??
|
||||
// userL2LangCode ??
|
||||
// LanguageKeys.unknownLanguage;
|
||||
|
||||
// OverlayUtil.showPositionedCard(
|
||||
// context: context,
|
||||
// cardToShow: WordDataCard(
|
||||
// word: fullText,
|
||||
// wordLang: langCode,
|
||||
// fullText: messageText,
|
||||
// fullTextLang: langCode,
|
||||
// hasInfo: false,
|
||||
// room: widget.pangeaMessageEvent.room,
|
||||
// ),
|
||||
// cardSize: const Size(300, 300),
|
||||
// transformTargetId: widget.pangeaMessageEvent.eventId,
|
||||
// backDropToDismiss: false,
|
||||
// );
|
||||
// }
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue