From 26a3a03ad60dff313b342cb387a4e9b99d53690d Mon Sep 17 00:00:00 2001 From: ggurdin <46800240+ggurdin@users.noreply.github.com> Date: Mon, 22 Sep 2025 11:33:03 -0400 Subject: [PATCH] chore: only show emoji button for save-vocab tokens, fix alignment for non-token text (#4071) --- lib/pages/chat/events/html_message.dart | 111 ++++++++++++------ .../token_emoji_button.dart | 75 ++++++------ 2 files changed, 114 insertions(+), 72 deletions(-) diff --git a/lib/pages/chat/events/html_message.dart b/lib/pages/chat/events/html_message.dart index d51faff01..322ff90e4 100644 --- a/lib/pages/chat/events/html_message.dart +++ b/lib/pages/chat/events/html_message.dart @@ -124,6 +124,7 @@ class HtmlMessage extends StatelessWidget { 'tg-forward', // #Pangea 'token', + 'nontoken', // Pangea# }; @@ -255,6 +256,12 @@ class HtmlMessage extends StatelessWidget { position = substringIndex; } + for (int i = 0; i < result.length; i++) { + if (!result[i].startsWith('<') && !result[i].endsWith('>')) { + result[i] = '${result[i]}'; + } + } + if (pangeaMessageEvent?.textDirection == TextDirection.rtl) { for (int i = 0; i < result.length; i++) { final tag = result[i]; @@ -913,48 +920,74 @@ class HtmlMessage extends StatelessWidget { 'sub' => const TextStyle(fontFeatures: [FontFeature.subscripts()]), _ => null, }; - // Pangea# - return TextSpan( - style: switch (node.localName) { - 'body' => TextStyle( - fontSize: fontSize, - color: textColor, + return WidgetSpan( + alignment: readingAssistanceMode == ReadingAssistanceMode.practiceMode + ? PlaceholderAlignment.bottom + : PlaceholderAlignment.middle, + child: Column( + children: [ + if (node.localName == 'nontoken' && + overlayController?.selectedMode == SelectMode.emoji) + TokenEmojiButton( + token: null, + eventId: event.eventId, + ), + RichText( + text: TextSpan( + style: style, + children: _renderWithLineBreaks( + node.nodes, + context, + textStyle.merge(style ?? const TextStyle()), + depth: depth, + ), + ), ), - 'a' => linkStyle, - 'strong' => const TextStyle(fontWeight: FontWeight.bold), - 'em' || 'i' => const TextStyle(fontStyle: FontStyle.italic), - 'del' || - 's' || - 'strikethrough' => - const TextStyle(decoration: TextDecoration.lineThrough), - 'u' => const TextStyle(decoration: TextDecoration.underline), - 'h1' => TextStyle(fontSize: fontSize * 1.6, height: 2), - 'h2' => TextStyle(fontSize: fontSize * 1.5, height: 2), - 'h3' => TextStyle(fontSize: fontSize * 1.4, height: 2), - 'h4' => TextStyle(fontSize: fontSize * 1.3, height: 1.75), - 'h5' => TextStyle(fontSize: fontSize * 1.2, height: 1.75), - 'h6' => TextStyle(fontSize: fontSize * 1.1, height: 1.5), - 'span' => TextStyle( - color: node.attributes['color']?.hexToColor ?? - node.attributes['data-mx-color']?.hexToColor ?? - textColor, - backgroundColor: - node.attributes['data-mx-bg-color']?.hexToColor, - ), - 'sup' => - const TextStyle(fontFeatures: [FontFeature.superscripts()]), - 'sub' => const TextStyle(fontFeatures: [FontFeature.subscripts()]), - _ => null, - }, - children: _renderWithLineBreaks( - node.nodes, - context, - // #Pangea - textStyle.merge(style ?? const TextStyle()), - // Pangea# - depth: depth, + ], ), ); + // return TextSpan( + // style: switch (node.localName) { + // 'body' => TextStyle( + // fontSize: fontSize, + // color: textColor, + // ), + // 'a' => linkStyle, + // 'strong' => const TextStyle(fontWeight: FontWeight.bold), + // 'em' || 'i' => const TextStyle(fontStyle: FontStyle.italic), + // 'del' || + // 's' || + // 'strikethrough' => + // const TextStyle(decoration: TextDecoration.lineThrough), + // 'u' => const TextStyle(decoration: TextDecoration.underline), + // 'h1' => TextStyle(fontSize: fontSize * 1.6, height: 2), + // 'h2' => TextStyle(fontSize: fontSize * 1.5, height: 2), + // 'h3' => TextStyle(fontSize: fontSize * 1.4, height: 2), + // 'h4' => TextStyle(fontSize: fontSize * 1.3, height: 1.75), + // 'h5' => TextStyle(fontSize: fontSize * 1.2, height: 1.75), + // 'h6' => TextStyle(fontSize: fontSize * 1.1, height: 1.5), + // 'span' => TextStyle( + // color: node.attributes['color']?.hexToColor ?? + // node.attributes['data-mx-color']?.hexToColor ?? + // textColor, + // backgroundColor: + // node.attributes['data-mx-bg-color']?.hexToColor, + // ), + // 'sup' => const TextStyle( + // fontFeatures: [FontFeature.superscripts()], + // ), + // 'sub' => const TextStyle( + // fontFeatures: [FontFeature.subscripts()], + // ), + // _ => null, + // }, + // children: _renderWithLineBreaks( + // node.nodes, + // context, + // depth: depth, + // ), + // ); + // Pangea# } } diff --git a/lib/pangea/message_token_text/token_emoji_button.dart b/lib/pangea/message_token_text/token_emoji_button.dart index bd041dbdd..b4dbfb864 100644 --- a/lib/pangea/message_token_text/token_emoji_button.dart +++ b/lib/pangea/message_token_text/token_emoji_button.dart @@ -5,17 +5,17 @@ import 'package:fluffychat/pangea/events/models/pangea_token_model.dart'; import 'package:fluffychat/widgets/matrix.dart'; class TokenEmojiButton extends StatefulWidget { - final PangeaToken token; + final PangeaToken? token; final String eventId; - final String targetId; - final VoidCallback onSelect; + final String? targetId; + final VoidCallback? onSelect; const TokenEmojiButton({ super.key, required this.token, required this.eventId, - required this.targetId, - required this.onSelect, + this.targetId, + this.onSelect, }); @override @@ -53,36 +53,45 @@ class TokenEmojiButtonState extends State @override Widget build(BuildContext context) { - final emoji = widget.token.vocabConstructID.userSetEmoji.firstOrNull; + final eligible = widget.token?.lemma.saveVocab ?? false; + final emoji = widget.token?.vocabConstructID.userSetEmoji.firstOrNull; if (_sizeAnimation != null) { - return CompositedTransformTarget( - link: MatrixState.pAnyState.layerLinkAndKey(widget.targetId).link, - child: AnimatedBuilder( - key: MatrixState.pAnyState.layerLinkAndKey(widget.targetId).key, - animation: _sizeAnimation!, - builder: (context, child) { - return Container( - height: _sizeAnimation!.value, - width: _sizeAnimation!.value, - alignment: Alignment.center, - child: InkWell( - onTap: widget.onSelect, - borderRadius: BorderRadius.circular(99.0), - child: emoji != null - ? Text( - emoji, - style: TextStyle(fontSize: buttonSize - 4.0), - ) - : Icon( - Icons.add_reaction_outlined, - size: buttonSize - 4.0, - color: Theme.of(context).colorScheme.primary, - ), - ), - ); - }, - ), + final content = AnimatedBuilder( + key: widget.targetId != null + ? MatrixState.pAnyState.layerLinkAndKey(widget.targetId!).key + : null, + animation: _sizeAnimation!, + builder: (context, child) { + return Container( + height: _sizeAnimation!.value, + width: eligible ? _sizeAnimation!.value : 0, + alignment: Alignment.center, + child: eligible + ? InkWell( + onTap: widget.onSelect, + borderRadius: BorderRadius.circular(99.0), + child: emoji != null + ? Text( + emoji, + style: TextStyle(fontSize: buttonSize - 4.0), + ) + : Icon( + Icons.add_reaction_outlined, + size: buttonSize - 4.0, + color: Theme.of(context).colorScheme.primary, + ), + ) + : null, + ); + }, ); + return widget.targetId != null + ? CompositedTransformTarget( + link: + MatrixState.pAnyState.layerLinkAndKey(widget.targetId!).link, + child: content, + ) + : content; } return const SizedBox.shrink();