diff --git a/lib/pangea/widgets/chat/overlay_message_text.dart b/lib/pangea/widgets/chat/overlay_message_text.dart index 4d91ed359..1ca2f8473 100644 --- a/lib/pangea/widgets/chat/overlay_message_text.dart +++ b/lib/pangea/widgets/chat/overlay_message_text.dart @@ -65,33 +65,71 @@ class OverlayMessageTextState extends State { ); } - int lastEnd = 0; +// Convert the entire message into a list of characters + final Characters messageCharacters = + widget.pangeaMessageEvent.event.body.characters; + + // When building token positions, use grapheme cluster indices final List tokenPositions = []; + int globalIndex = 0; for (int i = 0; i < tokens!.length; i++) { final token = tokens![i]; final start = token.start; final end = token.end; - if (lastEnd < start) { - tokenPositions.add(TokenPosition(start: lastEnd, end: start)); + // Calculate the number of grapheme clusters up to the start and end positions + final int startIndex = messageCharacters.take(start).length; + final int endIndex = messageCharacters.take(end).length; + + if (globalIndex < startIndex) { + tokenPositions.add(TokenPosition(start: globalIndex, end: startIndex)); } tokenPositions.add( TokenPosition( - start: start, - end: end, + start: startIndex, + end: endIndex, tokenIndex: i, token: token, ), ); - lastEnd = end; + globalIndex = endIndex; } + // debug prints for fixing words sticking together + // void printEscapedString(String input) { + // // Escaped string using Unicode escape sequences + // final String escapedString = input.replaceAllMapped( + // RegExp(r'[^\w\s]', unicode: true), + // (match) { + // final codeUnits = match.group(0)!.runes; + // String unicodeEscapes = ''; + // for (final rune in codeUnits) { + // unicodeEscapes += '\\u{${rune.toRadixString(16)}}'; + // } + // return unicodeEscapes; + // }, + // ); + // print("Escaped String: $escapedString"); + + // // Printing each character with its index + // int index = 0; + // for (final char in input.characters) { + // print("Index $index: $char"); + // index++; + // } + // } + //TODO - take out of build function of every message return RichText( text: TextSpan( children: tokenPositions.map((tokenPosition) { + final substring = messageCharacters + .skip(tokenPosition.start) + .take(tokenPosition.end - tokenPosition.start) + .toString(); + if (tokenPosition.token != null) { final isSelected = widget.overlayController.isTokenSelected(tokenPosition.token!); @@ -106,7 +144,7 @@ class OverlayMessageTextState extends State { ); setState(() {}); }, - text: tokenPosition.token!.text.content, + text: substring, style: style.merge( TextStyle( backgroundColor: isSelected @@ -119,10 +157,7 @@ class OverlayMessageTextState extends State { ); } else { return TextSpan( - text: widget.pangeaMessageEvent.event.body.substring( - tokenPosition.start, - tokenPosition.end, - ), + text: substring, style: style, ); } diff --git a/pubspec.lock b/pubspec.lock index c8a53d2c7..1beb361d5 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -162,7 +162,7 @@ packages: source: hosted version: "1.1.2" characters: - dependency: transitive + dependency: "direct main" description: name: characters sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605" diff --git a/pubspec.yaml b/pubspec.yaml index 69f0f1a63..be22ad146 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -19,6 +19,7 @@ dependencies: badges: ^3.1.2 blurhash_dart: ^1.2.1 callkeep: ^0.3.2 + characters: ^1.2.0 chewie: ^1.8.1 collection: ^1.18.0 cupertino_icons: any