diff --git a/lib/widgets/post/fediverse_post_item.dart b/lib/widgets/post/fediverse_post_item.dart index fe25e1f..3495af5 100644 --- a/lib/widgets/post/fediverse_post_item.dart +++ b/lib/widgets/post/fediverse_post_item.dart @@ -1,25 +1,25 @@ import 'package:flutter/material.dart'; import 'package:gap/gap.dart'; +import 'package:html2md/html2md.dart' as html2md; +import 'package:relative_time/relative_time.dart'; import 'package:styled_widget/styled_widget.dart'; import 'package:surface/types/post.dart'; -import 'package:html/parser.dart'; import 'package:surface/widgets/account/account_image.dart'; import 'package:surface/widgets/attachment/attachment_list.dart'; -import 'package:surface/widgets/html.dart'; +import 'package:surface/widgets/markdown_content.dart'; import 'package:surface/widgets/universal_image.dart'; class FediversePostWidget extends StatelessWidget { final SnFediversePost data; final double maxWidth; - const FediversePostWidget( - {super.key, required this.data, required this.maxWidth}); + const FediversePostWidget({ + super.key, + required this.data, + required this.maxWidth, + }); @override Widget build(BuildContext context) { - final borderSide = - BorderSide(width: 1, color: Theme.of(context).dividerColor); - final backgroundColor = Theme.of(context).colorScheme.surfaceContainer; - return Center( child: Container( constraints: BoxConstraints(maxWidth: maxWidth), @@ -30,8 +30,11 @@ class FediversePostWidget extends StatelessWidget { children: [ Row( children: [ - AccountImage(content: data.user.avatar), - const Gap(8), + AccountImage( + content: data.user.avatar, + radius: 20, + ), + const Gap(12), Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ @@ -40,66 +43,125 @@ class FediversePostWidget extends StatelessWidget { ? data.user.nick : '@${data.user.name}', ).bold(), - Text(data.user.identifier), + Row( + children: [ + Text( + data.user.identifier.contains('@') + ? data.user.identifier + : '${data.user.identifier}@${data.user.origin}', + ).fontSize(13), + const Gap(4), + Text( + RelativeTime(context) + .format(data.createdAt.toLocal()), + ).fontSize(13), + ], + ), ], ), ], - ), - const Gap(8), - ...parseHtmlToWidgets(context, parse(data.content).children), + ).padding(horizontal: 12, vertical: 8), + MarkdownTextContent( + isAutoWarp: true, + content: html2md.convert(data.content), + ).padding(horizontal: 16, bottom: 6), if (data.images.isNotEmpty) - AspectRatio( - aspectRatio: 1, - child: ScrollConfiguration( - behavior: AttachmentListScrollBehavior(), - child: ListView.separated( - shrinkWrap: true, - itemCount: data.images.length, - itemBuilder: (context, idx) { - return Container( - constraints: BoxConstraints(maxWidth: maxWidth), - child: AspectRatio( - aspectRatio: 1, - child: Stack( - fit: StackFit.expand, - children: [ - Container( - decoration: BoxDecoration( - color: backgroundColor, - border: Border( - top: borderSide, - bottom: borderSide, - ), - borderRadius: AttachmentList.kDefaultRadius, - ), - child: ClipRRect( - borderRadius: AttachmentList.kDefaultRadius, - child: AutoResizeUniversalImage( - data.images[idx], - ), - ), - ), - Positioned( - right: 8, - bottom: 8, - child: Chip( - label: Text( - '${idx + 1}/${data.images.length}'), - ), - ), - ], - ), - ), - ); - }, - separatorBuilder: (context, index) => const Gap(8), - physics: const BouncingScrollPhysics(), - scrollDirection: Axis.horizontal, - ), - ), + _FediversePostImageList( + data: data, + maxWidth: maxWidth, ), ], - ).padding(all: 8), + ), + ), + ), + ); + } +} + +class _FediversePostImageList extends StatelessWidget { + const _FediversePostImageList({ + required this.data, + required this.maxWidth, + }); + + final SnFediversePost data; + final double maxWidth; + + @override + Widget build(BuildContext context) { + final borderSide = + BorderSide(width: 1, color: Theme.of(context).dividerColor); + final backgroundColor = Theme.of(context).colorScheme.surfaceContainer; + + if (data.images.length == 1) { + return AspectRatio( + aspectRatio: 1, + child: Container( + constraints: BoxConstraints(maxWidth: maxWidth), + decoration: BoxDecoration( + color: backgroundColor, + border: Border( + top: borderSide, + bottom: borderSide, + ), + borderRadius: AttachmentList.kDefaultRadius, + ), + child: ClipRRect( + borderRadius: AttachmentList.kDefaultRadius, + child: AutoResizeUniversalImage( + data.images.first, + ), + ), + ), + ).padding(horizontal: 8); + } + + return AspectRatio( + aspectRatio: 1, + child: ScrollConfiguration( + behavior: AttachmentListScrollBehavior(), + child: ListView.separated( + shrinkWrap: true, + itemCount: data.images.length, + itemBuilder: (context, idx) { + return Container( + constraints: BoxConstraints(maxWidth: maxWidth), + child: AspectRatio( + aspectRatio: 1, + child: Stack( + fit: StackFit.expand, + children: [ + Container( + decoration: BoxDecoration( + color: backgroundColor, + border: Border( + top: borderSide, + bottom: borderSide, + ), + borderRadius: AttachmentList.kDefaultRadius, + ), + child: ClipRRect( + borderRadius: AttachmentList.kDefaultRadius, + child: AutoResizeUniversalImage( + data.images[idx], + ), + ), + ), + Positioned( + right: 8, + bottom: 8, + child: Chip( + label: Text('${idx + 1}/${data.images.length}'), + ), + ), + ], + ), + ), + ); + }, + separatorBuilder: (context, index) => const Gap(8), + physics: const BouncingScrollPhysics(), + scrollDirection: Axis.horizontal, ), ), ); diff --git a/pubspec.lock b/pubspec.lock index 9494ad9..592e531 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -53,10 +53,10 @@ packages: dependency: transitive description: name: args - sha256: bf9f5caeea8d8fe6721a9c358dd8a5c1947b27f1cfaa18b39c301273594919e6 + sha256: d0481093c50b1da8910eb0bb301626d4d8eb7284aa739614d2b394ee09e3ea04 url: "https://pub.dev" source: hosted - version: "2.6.0" + version: "2.7.0" async: dependency: transitive description: @@ -213,10 +213,10 @@ packages: dependency: transitive description: name: chalkdart - sha256: "08c910ee341fcdd1e46f20ddce59b13c1d85f5d97f2fd2f12014c46ede670e40" + sha256: e7cfcc9a9d9546843304c1ff87fe0696c7eb82ee70e6df63f555f321b15a40d8 url: "https://pub.dev" source: hosted - version: "2.3.2" + version: "2.3.3" characters: dependency: transitive description: @@ -301,10 +301,10 @@ packages: dependency: "direct main" description: name: croppy - sha256: "99f4fbb4a4b44d2712e8dcd61c57c1acac151bd53cab11de3babec80407ed266" + sha256: "2a69059d9ec007b79d6a494854094b2e3c0a4f7ed609cf55a4805c9de9ec171d" url: "https://pub.dev" source: hosted - version: "1.3.5" + version: "1.3.6" cross_file: dependency: "direct main" description: @@ -541,10 +541,10 @@ packages: dependency: "direct main" description: name: file_picker - sha256: "7423298f08f6fc8cce05792bae329f9a93653fc9c08712831b1a55540127995d" + sha256: "2458a41b4dc53899263bb16b17961797deaa18d4660e4d33e4de8a6c2a13db9c" url: "https://pub.dev" source: hosted - version: "9.0.2" + version: "9.0.3" file_saver: dependency: "direct main" description: @@ -702,6 +702,14 @@ packages: url: "https://pub.dev" source: hosted version: "3.2.2" + flutter_blurhash: + dependency: "direct main" + description: + name: flutter_blurhash + sha256: "5e67678e479ac639069d7af1e133f4a4702311491188ff3e0227486430db0c06" + url: "https://pub.dev" + source: hosted + version: "0.8.2" flutter_cache_manager: dependency: "direct main" description: @@ -937,10 +945,10 @@ packages: dependency: "direct main" description: name: flutter_webrtc - sha256: "6ea3a86d95b61cfe42d5715426d355b3cece6c88d0119de428d56f6c653811ce" + sha256: b832dc76c0d1577f14aaf35e9c38d4ed7667cbc89c492b7bf4505d8d5f62e08b url: "https://pub.dev" source: hosted - version: "0.12.11" + version: "0.12.12+hotfix.1" freezed: dependency: "direct dev" description: @@ -1133,6 +1141,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.15.5" + html2md: + dependency: "direct main" + description: + name: html2md + sha256: "465cf8ffa1b510fe0e97941579bf5b22e2d575f2cecb500a9c0254efe33a8036" + url: "https://pub.dev" + source: hosted + version: "1.3.2" http: dependency: transitive description: @@ -1353,10 +1369,10 @@ packages: dependency: "direct main" description: name: livekit_client - sha256: "753bbf484c6b70f10f3dc1dc808dfe3755f472d80eb9682323cff07ad8e2609d" + sha256: "7f489fa415253d8d99c649b7efc95a733c5e5ac38dcfb02362ced99feb139376" url: "https://pub.dev" source: hosted - version: "2.4.0" + version: "2.4.1" local_notifier: dependency: "direct main" description: @@ -1417,10 +1433,10 @@ packages: dependency: "direct main" description: name: material_symbols_icons - sha256: ca30ccbd97763353bde6bb1076aa4f4d17a40db0804384da77df142102aa225d + sha256: ee916e08fc0e15d4544a3544b3a46821808b8c965629b56e076e4da1cfe69915 url: "https://pub.dev" source: hosted - version: "4.2808.0" + version: "4.2808.1" media_kit: dependency: "direct main" description: @@ -1553,10 +1569,10 @@ packages: dependency: transitive description: name: package_config - sha256: "92d4488434b520a62570293fbd33bb556c7d49230791c1b4bbd973baf6d2dc67" + sha256: f096c55ebb7deb7e384101542bfba8c52696c1b56fca2eb62827989ef2353bbc url: "https://pub.dev" source: hosted - version: "2.1.1" + version: "2.2.0" package_info_plus: dependency: "direct main" description: @@ -2526,10 +2542,10 @@ packages: dependency: transitive description: name: win32 - sha256: b89e6e24d1454e149ab20fbb225af58660f0c0bf4475544650700d8e2da54aef + sha256: dc6ecaa00a7c708e5b4d10ee7bec8c270e9276dfcab1783f57e9962d7884305f url: "https://pub.dev" source: hosted - version: "5.11.0" + version: "5.12.0" win32_registry: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 36b1e84..7e6b5de 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -139,6 +139,8 @@ dependencies: geolocator: ^13.0.2 fast_rsa: ^3.8.0 flutter_card_swiper: ^7.0.2 + html2md: ^1.3.2 + flutter_blurhash: ^0.8.2 dev_dependencies: flutter_test: