💄 Optimize post reply preview

This commit is contained in:
2025-12-06 13:53:22 +08:00
parent 504e4d55ad
commit 60b8e2bcad

View File

@@ -1,3 +1,5 @@
import 'dart:math' as math;
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
@@ -66,6 +68,7 @@ class PostReplyPreview extends HookConsumerWidget {
final bool isOpenable;
final bool isCompact;
final bool isAutoload;
final double? itemMaxWidth;
final VoidCallback? onOpen;
const PostReplyPreview({
super.key,
@@ -73,6 +76,7 @@ class PostReplyPreview extends HookConsumerWidget {
this.isOpenable = false,
this.isCompact = false,
this.isAutoload = true,
this.itemMaxWidth,
this.onOpen,
});
@@ -114,17 +118,22 @@ class PostReplyPreview extends HookConsumerWidget {
return null;
}, [parent]);
final featuredReply =
isOpenable ? null : ref.watch(postFeaturedReplyProvider(parent.id));
final featuredReply = isOpenable
? null
: ref.watch(postFeaturedReplyProvider(parent.id));
final itemWidget =
isOpenable
Widget itemBuilder(double maxWidth) {
return isOpenable
? Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
for (final post in posts.value)
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
InkWell(
child: ConstrainedBox(
constraints: BoxConstraints(maxWidth: maxWidth),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
spacing: 8,
@@ -142,12 +151,17 @@ class PostReplyPreview extends HookConsumerWidget {
)
else
Expanded(
child: Text(
child:
Text(
'postHasAttachments',
).plural(post.attachments.length),
style: TextStyle(height: 2),
)
.plural(post.attachments.length)
.padding(top: 2),
),
],
),
),
onTap: () {
onOpen?.call();
context.pushNamed(
@@ -162,12 +176,14 @@ class PostReplyPreview extends HookConsumerWidget {
isOpenable: true,
isCompact: true,
isAutoload: false,
itemMaxWidth: math.max(maxWidth - 24, 200),
onOpen: onOpen,
).padding(left: 24),
],
),
if (loading.value)
Row(
mainAxisSize: MainAxisSize.min,
spacing: 8,
children: [
SizedBox(
@@ -179,8 +195,9 @@ class PostReplyPreview extends HookConsumerWidget {
],
)
else if (posts.value.length < parent.repliesCount)
InkWell(
GestureDetector(
child: Row(
mainAxisSize: MainAxisSize.min,
spacing: 8,
children: [
const Icon(Symbols.keyboard_arrow_down, size: 20),
@@ -194,8 +211,9 @@ class PostReplyPreview extends HookConsumerWidget {
],
)
: (featuredReply!).map(
data:
(data) => Row(
data: (data) => ConstrainedBox(
constraints: BoxConstraints(maxWidth: maxWidth),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
spacing: 8,
children: [
@@ -218,16 +236,15 @@ class PostReplyPreview extends HookConsumerWidget {
),
],
),
error:
(e) => Row(
),
error: (e) => Row(
spacing: 8,
children: [
const Icon(Symbols.close, size: 18),
Text(e.error.toString()),
],
),
loading:
(_) => Row(
loading: (_) => Row(
spacing: 8,
children: [
SizedBox(
@@ -239,10 +256,10 @@ class PostReplyPreview extends HookConsumerWidget {
],
),
);
}
final contentWidget =
isCompact
? itemWidget
final contentWidget = isCompact
? itemBuilder(itemMaxWidth ?? MediaQuery.of(context).size.width)
: Container(
padding: EdgeInsets.symmetric(horizontal: 16, vertical: 12),
decoration: BoxDecoration(
@@ -252,8 +269,10 @@ class PostReplyPreview extends HookConsumerWidget {
),
borderRadius: BorderRadius.all(Radius.circular(8)),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
child: LayoutBuilder(
builder: (context, constraints) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
spacing: 4,
children: [
Text('repliesCount')
@@ -261,13 +280,17 @@ class PostReplyPreview extends HookConsumerWidget {
.fontSize(15)
.bold()
.padding(horizontal: 5),
itemWidget,
SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: itemBuilder(constraints.maxWidth),
),
],
);
},
),
);
return InkWell(
borderRadius: const BorderRadius.all(Radius.circular(8)),
return GestureDetector(
onTap: () {
showModalBottomSheet(
context: context,
@@ -479,8 +502,9 @@ class ReferencedPostWidget extends StatelessWidget {
referencePost.description!,
style: TextStyle(
fontSize: 12,
color:
Theme.of(context).colorScheme.onSurfaceVariant,
color: Theme.of(
context,
).colorScheme.onSurfaceVariant,
),
maxLines: 2,
overflow: TextOverflow.ellipsis,
@@ -490,8 +514,7 @@ class ReferencedPostWidget extends StatelessWidget {
content: referencePost.content!,
textStyle: const TextStyle(fontSize: 14),
isSelectable: false,
linesMargin:
referencePost.type == 0
linesMargin: referencePost.type == 0
? const EdgeInsets.only(bottom: 4)
: null,
attachments: item.attachments,
@@ -537,8 +560,7 @@ class ReferencedPostWidget extends StatelessWidget {
}
return content.gestures(
onTap:
() => context.pushNamed(
onTap: () => context.pushNamed(
'postDetail',
pathParameters: {'id': referencePost!.id},
),
@@ -577,8 +599,7 @@ class PostHeader extends StatelessWidget {
spacing: 12,
children: [
GestureDetector(
onTap:
isInteractive
onTap: isInteractive
? () {
context.pushNamed(
'publisherProfile',
@@ -627,8 +648,7 @@ class PostHeader extends StatelessWidget {
),
if (item.realm == null)
Flexible(
child:
isCompact
child: isCompact
? const SizedBox.shrink()
: Text(
'@${item.publisher.name}',
@@ -734,8 +754,7 @@ class PostBody extends ConsumerWidget {
const Icon(Symbols.label, size: 16).padding(top: 2),
for (final tag in isFullPost ? item.tags : item.tags.take(3))
InkWell(
onTap:
isInteractive
onTap: isInteractive
? () {
GoRouter.of(context).pushNamed(
'postTagDetail',
@@ -761,8 +780,7 @@ class PostBody extends ConsumerWidget {
for (final category
in isFullPost ? item.categories : item.categories.take(2))
InkWell(
onTap:
isInteractive
onTap: isInteractive
? () {
GoRouter.of(context).pushNamed(
'postCategoryDetail',
@@ -798,8 +816,7 @@ class PostBody extends ConsumerWidget {
hideOverlay
? text
: Tooltip(
message:
!isFullPost && isRelativeTime
message: !isFullPost && isRelativeTime
? item.editedAt!.formatSystem()
: item.editedAt!.formatRelative(context),
child: text,
@@ -936,8 +953,7 @@ class PostBody extends ConsumerWidget {
],
).padding(bottom: 4),
MarkdownTextContent(
content:
item.isTruncated
content: item.isTruncated
? '${item.content!}...'
: item.content ?? '',
isSelectable: isTextSelectable,