Featured replies on post

This commit is contained in:
LittleSheep 2024-09-16 23:35:44 +08:00
parent 47eb6cbc66
commit ce16de9c71
8 changed files with 116 additions and 5 deletions

View File

@ -1,6 +1,7 @@
import 'package:get/get.dart';
import 'package:solian/exceptions/request.dart';
import 'package:solian/exceptions/unauthorized.dart';
import 'package:solian/models/post.dart';
import 'package:solian/providers/auth.dart';
import 'package:solian/services.dart';
@ -96,6 +97,15 @@ class PostProvider extends GetConnect {
return resp;
}
Future<List<Post>> listPostFeaturedReply(String alias) async {
final resp = await get('/posts/$alias/replies/featured');
if (resp.statusCode != 200) {
throw RequestException(resp);
}
return List<Post>.from(resp.body.map((x) => Post.fromJson(x)));
}
Future<Response> getPost(String alias) async {
final resp = await get('/posts/$alias');
if (resp.statusCode != 200) {

View File

@ -302,6 +302,7 @@ class _AccountProfilePageState extends State<AccountProfilePage> {
isClickable: true,
isNestedClickable: true,
isShowEmbed: true,
showFeaturedReply: true,
onUpdate: () {
_postController.reloadAllOver();
},

View File

@ -379,6 +379,7 @@ class _DashboardScreenState extends State<DashboardScreen> {
isClickable: true,
isShowEmbed: true,
isNestedClickable: true,
showFeaturedReply: true,
onUpdate: (_) {
_pullPosts();
},

View File

@ -3,9 +3,10 @@ import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:gap/gap.dart';
import 'package:get/get_utils/get_utils.dart';
import 'package:get/get.dart';
import 'package:intl/intl.dart';
import 'package:solian/models/post.dart';
import 'package:solian/providers/content/posts.dart';
import 'package:solian/screens/posts/post_detail.dart';
import 'package:solian/shells/title_shell.dart';
import 'package:solian/theme.dart';
@ -30,6 +31,7 @@ class PostItem extends StatefulWidget {
final bool isFullDate;
final bool isFullContent;
final bool isContentSelectable;
final bool showFeaturedReply;
final String? attachmentParent;
final Color? backgroundColor;
@ -45,6 +47,7 @@ class PostItem extends StatefulWidget {
this.isFullDate = false,
this.isFullContent = false,
this.isContentSelectable = false,
this.showFeaturedReply = false,
this.attachmentParent,
this.backgroundColor,
});
@ -103,7 +106,7 @@ class _PostItemState extends State<PostItem> {
children: [
if (widget.isCompact)
AccountAvatar(
content: item.author.avatar.toString(),
content: item.author.avatar,
radius: 10,
).paddingOnly(left: 2, top: 1),
Expanded(
@ -320,6 +323,95 @@ class _PostItemState extends State<PostItem> {
}
}
Widget _buildFeaturedReply() {
if ((widget.item.metric?.replyCount ?? 0) == 0) {
return const SizedBox.shrink();
}
final List<String> attachments = item.body['attachments'] is List
? List.from(item.body['attachments']?.whereType<String>())
: List.empty();
final unFocusColor =
Theme.of(context).colorScheme.onSurface.withOpacity(0.75);
return FutureBuilder(
future: Get.find<PostProvider>().listPostFeaturedReply(
widget.item.id.toString(),
),
builder: (context, snapshot) {
if (!snapshot.hasData || snapshot.data!.isEmpty) {
return const SizedBox.shrink();
}
return Card(
margin: EdgeInsets.zero,
child: Column(
children: snapshot.data!
.map(
(x) => Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
AccountAvatar(content: x.author.avatar, radius: 10),
const Gap(6),
Text(
x.author.nick,
style: const TextStyle(fontWeight: FontWeight.bold),
),
const Gap(6),
Text(
format(
x.publishedAt?.toLocal() ?? DateTime.now(),
locale: 'en_short',
),
).paddingOnly(top: 0.5),
const Gap(16),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
MarkdownTextContent(
content: x.body['content'],
parentId: 'p${item.id}-featured-reply${x.id}',
),
if (x.body['attachments'] is List &&
x.body['attachments'].length > 0)
Row(
children: [
Icon(
Icons.file_copy,
size: 15,
color: unFocusColor,
).paddingOnly(right: 5),
Text(
'attachmentHint'.trParams(
{
'count': x.body['attachments'].length
.toString()
},
),
style: TextStyle(color: unFocusColor),
)
],
),
],
),
),
],
).paddingSymmetric(horizontal: 12, vertical: 8),
)
.toList(),
),
).paddingOnly(
top: (attachments.length == 1 && !AppTheme.isLargeScreen(context))
? 10
: 6,
left: (attachments.length == 1 && !AppTheme.isLargeScreen(context))
? 24
: 60,
right: 16,
);
},
);
}
double _contentHeight = 0;
@override
@ -417,7 +509,7 @@ class _PostItemState extends State<PostItem> {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
GestureDetector(
child: AccountAvatar(content: item.author.avatar.toString()),
child: AccountAvatar(content: item.author.avatar),
onTap: () {
showModalBottomSheet(
useRootNavigator: true,
@ -506,6 +598,7 @@ class _PostItemState extends State<PostItem> {
left: 16,
),
_buildAttachments(),
if (widget.showFeaturedReply) _buildFeaturedReply(),
if (widget.isShowReply || widget.isReactable)
PostQuickAction(
isShowReply: widget.isShowReply,

View File

@ -33,6 +33,7 @@ class PostListWidget extends StatelessWidget {
isShowEmbed: isShowEmbed,
isNestedClickable: isNestedClickable,
isClickable: isClickable,
showFeaturedReply: true,
item: item,
backgroundColor: backgroundColor,
onUpdate: () {
@ -51,6 +52,7 @@ class PostListEntryWidget extends StatelessWidget {
final bool isShowEmbed;
final bool isNestedClickable;
final bool isClickable;
final bool showFeaturedReply;
final Post item;
final Function onUpdate;
final Color? backgroundColor;
@ -61,6 +63,7 @@ class PostListEntryWidget extends StatelessWidget {
required this.isShowEmbed,
required this.isNestedClickable,
required this.isClickable,
required this.showFeaturedReply,
required this.item,
required this.onUpdate,
this.backgroundColor,
@ -74,6 +77,7 @@ class PostListEntryWidget extends StatelessWidget {
item: item,
isShowEmbed: isShowEmbed,
isClickable: isNestedClickable,
showFeaturedReply: showFeaturedReply,
backgroundColor: backgroundColor,
).paddingSymmetric(vertical: 8),
onLongPress: () {

View File

@ -23,6 +23,7 @@ class PostSingleDisplay extends StatelessWidget {
isClickable: true,
isShowEmbed: true,
isNestedClickable: true,
showFeaturedReply: true,
onUpdate: onUpdate,
backgroundColor: Theme.of(context).colorScheme.surfaceContainerLow,
),

View File

@ -36,6 +36,7 @@ class PostWarpedListWidget extends StatelessWidget {
isShowEmbed: isShowEmbed,
isNestedClickable: isNestedClickable,
isClickable: isClickable,
showFeaturedReply: true,
item: item,
onUpdate: onUpdate ?? () {},
);

View File

@ -1894,10 +1894,10 @@ packages:
dependency: transitive
description:
name: sqflite_common
sha256: "7b41b6c3507854a159e24ae90a8e3e9cc01eb26a477c118d6dca065b5f55453e"
sha256: "4058172e418eb7e7f2058dcb7657d451a8fc264afa0dea4dbd0f304a57131611"
url: "https://pub.dev"
source: hosted
version: "2.5.4+2"
version: "2.5.4+3"
sqlite3:
dependency: transitive
description: