[feat]: Use HTML rendering for description

This commit is contained in:
nahnah
2026-01-27 22:50:28 +00:00
parent 0a3ff7b6af
commit e8feca77c0
3 changed files with 59 additions and 49 deletions
+25 -34
View File
@@ -5,6 +5,7 @@ import 'package:florid/widgets/changelog_preview.dart';
import 'package:florid/widgets/m_list.dart';
import 'package:flutter/material.dart';
import 'package:flutter_animate/flutter_animate.dart';
import 'package:flutter_html/flutter_html.dart';
import 'package:material_symbols_icons/symbols.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:provider/provider.dart';
@@ -1447,21 +1448,8 @@ class _DescriptionSectionState extends State<_DescriptionSection>
@override
Widget build(BuildContext context) {
final maxLines = _isExpanded ? null : 3;
final description = widget.app.description;
// Check if text would overflow with 3 lines
final textPainter = TextPainter(
text: TextSpan(
text: description,
style: Theme.of(context).textTheme.bodyMedium,
),
maxLines: 3,
textDirection: TextDirection.ltr,
);
textPainter.layout(maxWidth: MediaQuery.of(context).size.width - 32);
final isOverflowing = textPainter.didExceedMaxLines;
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 16.0),
child: Column(
@@ -1474,32 +1462,37 @@ class _DescriptionSectionState extends State<_DescriptionSection>
context,
).textTheme.titleMedium?.copyWith(fontWeight: FontWeight.w600),
),
Stack(
children: [
AnimatedSize(
duration: const Duration(milliseconds: 300),
curve: Curves.easeInOut,
child: Text(
description,
style: Theme.of(context).textTheme.bodyMedium,
maxLines: maxLines,
overflow: _isExpanded
? TextOverflow.visible
: TextOverflow.ellipsis,
child: Html(
data: description,
shrinkWrap: true,
style: {
"body": Style(
margin: Margins.zero,
padding: HtmlPaddings.zero,
fontSize: FontSize(
Theme.of(context).textTheme.bodyMedium?.fontSize ?? 14,
),
color: Theme.of(context).textTheme.bodyMedium?.color,
maxLines: _isExpanded ? null : 3,
textOverflow: _isExpanded ? null : TextOverflow.ellipsis,
),
],
),
if (isOverflowing)
Padding(
padding: const EdgeInsets.only(top: 12),
child: AnimatedDefaultTextStyle(
duration: const Duration(milliseconds: 300),
style: Theme.of(context).textTheme.labelMedium!.copyWith(
"p": Style(margin: Margins.only(bottom: 8)),
"a": Style(
color: Theme.of(context).colorScheme.primary,
fontWeight: FontWeight.w600,
textDecoration: TextDecoration.underline,
),
child: TextButton(
},
onLinkTap: (url, attributes, element) {
if (url != null) {
launchUrl(Uri.parse(url));
}
},
),
),
TextButton(
onPressed: () {
setState(() {
_isExpanded = !_isExpanded;
@@ -1512,8 +1505,6 @@ class _DescriptionSectionState extends State<_DescriptionSection>
},
child: Text(_isExpanded ? 'Show less' : 'Show more'),
),
),
),
],
),
);
+16
View File
@@ -342,6 +342,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "3.4.1"
flutter_html:
dependency: "direct main"
description:
name: flutter_html
sha256: "38a2fd702ffdf3243fb7441ab58aa1bc7e6922d95a50db76534de8260638558d"
url: "https://pub.dev"
source: hosted
version: "3.0.0"
flutter_lints:
dependency: "direct dev"
description:
@@ -557,6 +565,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "6.0.0"
list_counter:
dependency: transitive
description:
name: list_counter
sha256: c447ae3dfcd1c55f0152867090e67e219d42fe6d4f2807db4bbe8b8d69912237
url: "https://pub.dev"
source: hosted
version: "1.0.2"
logging:
dependency: transitive
description:
+3
View File
@@ -78,6 +78,9 @@ dependencies:
# Localization
easy_localization: ^3.0.8
# HTML rendering
flutter_html: ^3.0.0-beta.2
dev_dependencies:
flutter_test:
sdk: flutter