diff --git a/lib/pages/chat/events/html_message.dart b/lib/pages/chat/events/html_message.dart index af380fc27..ddac6cbd1 100644 --- a/lib/pages/chat/events/html_message.dart +++ b/lib/pages/chat/events/html_message.dart @@ -231,7 +231,64 @@ class HtmlMessage extends StatelessWidget { ]); } - return result.join(); + if (pangeaMessageEvent?.textDirection == TextDirection.rtl) { + for (int i = 0; i < result.length; i++) { + final tag = result[i]; + if (blockHtmlTags.contains(tag.htmlTagName) || + fullLineHtmlTag.contains(tag.htmlTagName)) { + if (i > 0 && result[i - 1] == ", ") { + result[i - 1] = ""; + } + result[i] = ", "; + } + } + result.removeWhere((element) => element == ""); + if (result[0] == ", ") result[0] = ""; + if (result.last == ", ") result.last = ""; + final inverted = _invertTags(result); + return inverted.join().trim(); + } + return result.join().trim(); + } + + List _invertTags(List tags) { + final List<(String, int)> stack = []; + final List<(int, int)> invertedTags = []; + for (int i = 0; i < tags.length; i++) { + final tag = tags[i]; + if (!tag.contains('<') || tag.contains(" + element.$1.htmlTagName == tag.htmlTagName && + !element.$1.contains(" onClick?.call(token) : null, child: RichText( + textDirection: pangeaMessageEvent?.textDirection, text: TextSpan( children: [ LinkifySpan( @@ -1006,3 +1064,8 @@ extension on String { extension on dom.Element { dom.Element get rootElement => parent?.rootElement ?? this; } + +extension on String { + String get htmlTagName => + replaceAll('<', '').replaceAll('>', '').replaceAll('/', '').split(' ')[0]; +} diff --git a/lib/pangea/events/event_wrappers/pangea_message_event.dart b/lib/pangea/events/event_wrappers/pangea_message_event.dart index f9ef56e2f..9df0b2e0d 100644 --- a/lib/pangea/events/event_wrappers/pangea_message_event.dart +++ b/lib/pangea/events/event_wrappers/pangea_message_event.dart @@ -1,5 +1,6 @@ import 'dart:convert'; import 'dart:developer'; +import 'dart:ui'; import 'package:flutter/foundation.dart'; @@ -18,6 +19,7 @@ import 'package:fluffychat/pangea/events/models/pangea_token_model.dart'; import 'package:fluffychat/pangea/events/models/representation_content_model.dart'; import 'package:fluffychat/pangea/events/models/stt_translation_model.dart'; import 'package:fluffychat/pangea/events/models/tokens_event_content_model.dart'; +import 'package:fluffychat/pangea/learning_settings/utils/p_language_store.dart'; import 'package:fluffychat/pangea/morphs/morph_features_enum.dart'; import 'package:fluffychat/pangea/practice_activities/activity_type_enum.dart'; import 'package:fluffychat/pangea/spaces/models/space_model.dart'; @@ -791,4 +793,9 @@ class PangeaMessageEvent { tag: tag, ); } + + TextDirection get textDirection => + PLanguageStore.rtlLanguageCodes.contains(messageDisplayLangCode) + ? TextDirection.rtl + : TextDirection.ltr; } diff --git a/lib/pangea/learning_settings/models/language_model.dart b/lib/pangea/learning_settings/models/language_model.dart index 2c840475e..285577bfc 100644 --- a/lib/pangea/learning_settings/models/language_model.dart +++ b/lib/pangea/learning_settings/models/language_model.dart @@ -1,20 +1,25 @@ import 'package:flutter/material.dart'; +import 'package:collection/collection.dart'; + import 'package:fluffychat/pangea/learning_settings/constants/language_constants.dart'; import 'package:fluffychat/pangea/learning_settings/enums/l2_support_enum.dart'; +import 'package:fluffychat/pangea/learning_settings/utils/p_language_store.dart'; class LanguageModel { final String langCode; final String displayName; final String script; final L2SupportEnum l2Support; + final TextDirection? _textDirection; LanguageModel({ required this.langCode, required this.displayName, this.script = LanguageKeys.unknownLanguage, this.l2Support = L2SupportEnum.na, - }); + TextDirection? textDirection, + }) : _textDirection = textDirection; factory LanguageModel.fromJson(json) { final String code = json['language_code'] ?? @@ -30,6 +35,11 @@ class LanguageModel { ? L2SupportEnum.na.fromStorageString(json['l2_support']) : L2SupportEnum.na, script: json['script'] ?? LanguageKeys.unknownLanguage, + textDirection: json['text_direction'] != null + ? TextDirection.values.firstWhereOrNull( + (e) => e.name == json['text_direction'], + ) + : null, ); } @@ -38,6 +48,7 @@ class LanguageModel { 'language_name': displayName, 'script': script, 'l2_support': l2Support.storageString, + 'text_direction': textDirection.name, }; bool get l2 => l2Support != L2SupportEnum.na; @@ -65,6 +76,16 @@ class LanguageModel { String get langCodeShort => langCode.split('-').first; + TextDirection get _defaultTextDirection { + return PLanguageStore.rtlLanguageCodes.contains(langCodeShort) + ? TextDirection.rtl + : TextDirection.ltr; + } + + TextDirection get textDirection { + return _textDirection ?? _defaultTextDirection; + } + @override bool operator ==(Object other) { if (other is LanguageModel) { diff --git a/lib/pangea/learning_settings/utils/p_language_store.dart b/lib/pangea/learning_settings/utils/p_language_store.dart index 3d4a7ec54..60310f18b 100644 --- a/lib/pangea/learning_settings/utils/p_language_store.dart +++ b/lib/pangea/learning_settings/utils/p_language_store.dart @@ -106,4 +106,19 @@ class PLanguageStore { } return null; } + + static final List rtlLanguageCodes = [ + 'ar', + 'arc', + 'dv', + 'fa', + 'ha', + 'he', + 'khw', + 'ks', + 'ku', + 'ps', + 'ur', + 'yi', + ]; }