From f82a7f9a2fe176d58412b653e365be42f00408ff Mon Sep 17 00:00:00 2001 From: Yurin Andrey Date: Wed, 26 Nov 2025 16:40:28 +0300 Subject: [PATCH 1/4] =?UTF-8?q?=D0=98=D1=81=D0=BF=D1=80=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D0=BB=20htmlToPlainText?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../misc/html_utils/html_to_plain_text.dart | 21 ++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/lib/core/misc/html_utils/html_to_plain_text.dart b/lib/core/misc/html_utils/html_to_plain_text.dart index c5d5eb14..4c6247db 100644 --- a/lib/core/misc/html_utils/html_to_plain_text.dart +++ b/lib/core/misc/html_utils/html_to_plain_text.dart @@ -1,11 +1,30 @@ // SPDX-License-Identifier: Apache-2.0 // Copyright 2025 BitCodersNN +import 'package:html/dom.dart' as dom; import 'package:html/parser.dart'; import 'package:html_unescape/html_unescape.dart'; +void _processNodes(dom.Node node) { + if (node is dom.Element) { + if (node.localName == 'a') { + final href = node.attributes['href']; + if (href != null && href.isNotEmpty) { + node.innerHtml = href; + } + } + for (final child in node.children.toList()) { + _processNodes(child); + } + } +} + String htmlToPlainText(String htmlText) { final unescaped = HtmlUnescape().convert(htmlText); final document = parse(unescaped); - return document.body?.text ?? ''; + final body = document.body; + if (body != null) { + _processNodes(body); + } + return document.body?.text.trim() ?? ''; } From 063ac1e94aa4513905c5cd6edba84aae419961d7 Mon Sep 17 00:00:00 2001 From: UNN MOBILE runner Date: Wed, 26 Nov 2025 13:41:25 +0000 Subject: [PATCH 2/4] Change version in pubspec --- pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pubspec.yaml b/pubspec.yaml index 86f6c3d1..847790b9 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: unn_mobile description: A mobile application for UNN Portal website publish_to: 'none' -version: 0.6.0+372 +version: 0.6.0+373 environment: sdk: '>=3.1.2 <4.0.0' From b9faeb06c9576a12d0e1fcd809c29ac67fa8f53a Mon Sep 17 00:00:00 2001 From: Yurin Andrey Date: Wed, 26 Nov 2025 16:46:29 +0300 Subject: [PATCH 3/4] =?UTF-8?q?=D0=98=D0=B7=D0=BC=D0=B5=D0=BD=D0=B5=D0=BD?= =?UTF-8?q?=D0=B8=D0=B5=20text=20=D0=B2=D0=BC=D0=B5=D1=81=D1=82=D0=BE=20in?= =?UTF-8?q?nerHtml?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/core/misc/html_utils/html_to_plain_text.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/core/misc/html_utils/html_to_plain_text.dart b/lib/core/misc/html_utils/html_to_plain_text.dart index 4c6247db..523f3bc7 100644 --- a/lib/core/misc/html_utils/html_to_plain_text.dart +++ b/lib/core/misc/html_utils/html_to_plain_text.dart @@ -10,10 +10,10 @@ void _processNodes(dom.Node node) { if (node.localName == 'a') { final href = node.attributes['href']; if (href != null && href.isNotEmpty) { - node.innerHtml = href; + node.text = href; } } - for (final child in node.children.toList()) { + for (final child in node.children) { _processNodes(child); } } From 4865133d77462c3ed67f2e68ef4afe9b0ede6145 Mon Sep 17 00:00:00 2001 From: Yurin Andrey Date: Wed, 26 Nov 2025 17:24:10 +0300 Subject: [PATCH 4/4] =?UTF-8?q?=D0=98=D1=81=D0=BF=D1=80=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D0=BB=20=D1=84=D0=BE=D1=80=D0=BC=D0=B0=D1=82=D0=B8=D1=80=D0=BE?= =?UTF-8?q?=D0=B2=D0=B0=D0=BD=D0=B8=D0=B5=20=D0=BF=D1=80=D0=B8=20=D0=BA?= =?UTF-8?q?=D0=BE=D0=BF=D0=B8=D1=80=D0=BE=D0=B2=D0=B0=D0=BD=D0=B8=D0=B5=20?= =?UTF-8?q?=D1=82=D0=B5=D0=BA=D1=81=D1=82=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../misc/html_utils/html_to_plain_text.dart | 79 ++++++++++++++++--- .../main_page/feed/widgets/feed_post.dart | 2 +- 2 files changed, 69 insertions(+), 12 deletions(-) diff --git a/lib/core/misc/html_utils/html_to_plain_text.dart b/lib/core/misc/html_utils/html_to_plain_text.dart index 523f3bc7..6d2866fd 100644 --- a/lib/core/misc/html_utils/html_to_plain_text.dart +++ b/lib/core/misc/html_utils/html_to_plain_text.dart @@ -2,29 +2,86 @@ // Copyright 2025 BitCodersNN import 'package:html/dom.dart' as dom; -import 'package:html/parser.dart'; +import 'package:html/parser.dart' as parser; import 'package:html_unescape/html_unescape.dart'; -void _processNodes(dom.Node node) { - if (node is dom.Element) { - if (node.localName == 'a') { +void _processNode( + dom.Node node, + StringBuffer buffer, + Set blockTags, +) { + if (node is dom.Text) { + final text = node.text.replaceAll(RegExp(r'\s+'), ' ').trim(); + if (text.isNotEmpty) { + buffer.write('$text '); + } + } else if (node is dom.Element) { + final tagName = node.localName?.toLowerCase(); + + if (tagName == 'a') { final href = node.attributes['href']; - if (href != null && href.isNotEmpty) { - node.text = href; + if (href != null && href.trim().isNotEmpty) { + buffer.write(href); + } else { + for (final child in node.nodes) { + _processNode(child, buffer, blockTags); + } + } + } else { + for (final child in node.nodes) { + _processNode(child, buffer, blockTags); } } - for (final child in node.children) { - _processNodes(child); + + if (blockTags.contains(tagName)) { + buffer.write('\n'); } } } +String _getElementTextWithFormatting(dom.Element element) { + final buffer = StringBuffer(); + final blockTags = { + 'br', + 'p', + 'div', + 'h1', + 'h2', + 'h3', + 'h4', + 'h5', + 'h6', + 'li', + 'tr', + 'pre', + 'blockquote', + 'hr', + 'ul', + 'ol', + 'dl', + 'section', + 'article', + 'aside', + 'header', + 'footer', + 'main', + }; + + _processNode(element, buffer, blockTags); + + return buffer + .toString() + .replaceAll(RegExp(r'[ \t]*\n[ \t]*'), '\n') + .replaceAll(RegExp(r'\n{3,}'), '\n\n') + .trim(); +} + String htmlToPlainText(String htmlText) { final unescaped = HtmlUnescape().convert(htmlText); - final document = parse(unescaped); + final document = parser.parse(unescaped); final body = document.body; if (body != null) { - _processNodes(body); + return _getElementTextWithFormatting(body); } - return document.body?.text.trim() ?? ''; + return ''; } diff --git a/lib/ui/views/main_page/feed/widgets/feed_post.dart b/lib/ui/views/main_page/feed/widgets/feed_post.dart index 29285b32..c2ecaaee 100644 --- a/lib/ui/views/main_page/feed/widgets/feed_post.dart +++ b/lib/ui/views/main_page/feed/widgets/feed_post.dart @@ -291,7 +291,7 @@ class _FeedPostState extends State { ShareParams( files: xFiles.isEmpty ? null : xFiles, text: - 'Из ленты Портала ННГУ (автор ${model.profileViewModel.fullname}):\n${htmlToPlainText(model.postText)}', + '${htmlToPlainText(model.postText)}\n\nИсточник: Портал ННГУ\nАвтор: ${model.profileViewModel.fullname}', ), ); }