✨ Featured replies on post
This commit is contained in:
parent
47eb6cbc66
commit
ce16de9c71
@ -1,6 +1,7 @@
|
|||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:solian/exceptions/request.dart';
|
import 'package:solian/exceptions/request.dart';
|
||||||
import 'package:solian/exceptions/unauthorized.dart';
|
import 'package:solian/exceptions/unauthorized.dart';
|
||||||
|
import 'package:solian/models/post.dart';
|
||||||
import 'package:solian/providers/auth.dart';
|
import 'package:solian/providers/auth.dart';
|
||||||
import 'package:solian/services.dart';
|
import 'package:solian/services.dart';
|
||||||
|
|
||||||
@ -96,6 +97,15 @@ class PostProvider extends GetConnect {
|
|||||||
return resp;
|
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 {
|
Future<Response> getPost(String alias) async {
|
||||||
final resp = await get('/posts/$alias');
|
final resp = await get('/posts/$alias');
|
||||||
if (resp.statusCode != 200) {
|
if (resp.statusCode != 200) {
|
||||||
|
@ -302,6 +302,7 @@ class _AccountProfilePageState extends State<AccountProfilePage> {
|
|||||||
isClickable: true,
|
isClickable: true,
|
||||||
isNestedClickable: true,
|
isNestedClickable: true,
|
||||||
isShowEmbed: true,
|
isShowEmbed: true,
|
||||||
|
showFeaturedReply: true,
|
||||||
onUpdate: () {
|
onUpdate: () {
|
||||||
_postController.reloadAllOver();
|
_postController.reloadAllOver();
|
||||||
},
|
},
|
||||||
|
@ -379,6 +379,7 @@ class _DashboardScreenState extends State<DashboardScreen> {
|
|||||||
isClickable: true,
|
isClickable: true,
|
||||||
isShowEmbed: true,
|
isShowEmbed: true,
|
||||||
isNestedClickable: true,
|
isNestedClickable: true,
|
||||||
|
showFeaturedReply: true,
|
||||||
onUpdate: (_) {
|
onUpdate: (_) {
|
||||||
_pullPosts();
|
_pullPosts();
|
||||||
},
|
},
|
||||||
|
@ -3,9 +3,10 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:flutter/rendering.dart';
|
import 'package:flutter/rendering.dart';
|
||||||
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
||||||
import 'package:gap/gap.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:intl/intl.dart';
|
||||||
import 'package:solian/models/post.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/screens/posts/post_detail.dart';
|
||||||
import 'package:solian/shells/title_shell.dart';
|
import 'package:solian/shells/title_shell.dart';
|
||||||
import 'package:solian/theme.dart';
|
import 'package:solian/theme.dart';
|
||||||
@ -30,6 +31,7 @@ class PostItem extends StatefulWidget {
|
|||||||
final bool isFullDate;
|
final bool isFullDate;
|
||||||
final bool isFullContent;
|
final bool isFullContent;
|
||||||
final bool isContentSelectable;
|
final bool isContentSelectable;
|
||||||
|
final bool showFeaturedReply;
|
||||||
final String? attachmentParent;
|
final String? attachmentParent;
|
||||||
final Color? backgroundColor;
|
final Color? backgroundColor;
|
||||||
|
|
||||||
@ -45,6 +47,7 @@ class PostItem extends StatefulWidget {
|
|||||||
this.isFullDate = false,
|
this.isFullDate = false,
|
||||||
this.isFullContent = false,
|
this.isFullContent = false,
|
||||||
this.isContentSelectable = false,
|
this.isContentSelectable = false,
|
||||||
|
this.showFeaturedReply = false,
|
||||||
this.attachmentParent,
|
this.attachmentParent,
|
||||||
this.backgroundColor,
|
this.backgroundColor,
|
||||||
});
|
});
|
||||||
@ -103,7 +106,7 @@ class _PostItemState extends State<PostItem> {
|
|||||||
children: [
|
children: [
|
||||||
if (widget.isCompact)
|
if (widget.isCompact)
|
||||||
AccountAvatar(
|
AccountAvatar(
|
||||||
content: item.author.avatar.toString(),
|
content: item.author.avatar,
|
||||||
radius: 10,
|
radius: 10,
|
||||||
).paddingOnly(left: 2, top: 1),
|
).paddingOnly(left: 2, top: 1),
|
||||||
Expanded(
|
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;
|
double _contentHeight = 0;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -417,7 +509,7 @@ class _PostItemState extends State<PostItem> {
|
|||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
GestureDetector(
|
GestureDetector(
|
||||||
child: AccountAvatar(content: item.author.avatar.toString()),
|
child: AccountAvatar(content: item.author.avatar),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
showModalBottomSheet(
|
showModalBottomSheet(
|
||||||
useRootNavigator: true,
|
useRootNavigator: true,
|
||||||
@ -506,6 +598,7 @@ class _PostItemState extends State<PostItem> {
|
|||||||
left: 16,
|
left: 16,
|
||||||
),
|
),
|
||||||
_buildAttachments(),
|
_buildAttachments(),
|
||||||
|
if (widget.showFeaturedReply) _buildFeaturedReply(),
|
||||||
if (widget.isShowReply || widget.isReactable)
|
if (widget.isShowReply || widget.isReactable)
|
||||||
PostQuickAction(
|
PostQuickAction(
|
||||||
isShowReply: widget.isShowReply,
|
isShowReply: widget.isShowReply,
|
||||||
|
@ -33,6 +33,7 @@ class PostListWidget extends StatelessWidget {
|
|||||||
isShowEmbed: isShowEmbed,
|
isShowEmbed: isShowEmbed,
|
||||||
isNestedClickable: isNestedClickable,
|
isNestedClickable: isNestedClickable,
|
||||||
isClickable: isClickable,
|
isClickable: isClickable,
|
||||||
|
showFeaturedReply: true,
|
||||||
item: item,
|
item: item,
|
||||||
backgroundColor: backgroundColor,
|
backgroundColor: backgroundColor,
|
||||||
onUpdate: () {
|
onUpdate: () {
|
||||||
@ -51,6 +52,7 @@ class PostListEntryWidget extends StatelessWidget {
|
|||||||
final bool isShowEmbed;
|
final bool isShowEmbed;
|
||||||
final bool isNestedClickable;
|
final bool isNestedClickable;
|
||||||
final bool isClickable;
|
final bool isClickable;
|
||||||
|
final bool showFeaturedReply;
|
||||||
final Post item;
|
final Post item;
|
||||||
final Function onUpdate;
|
final Function onUpdate;
|
||||||
final Color? backgroundColor;
|
final Color? backgroundColor;
|
||||||
@ -61,6 +63,7 @@ class PostListEntryWidget extends StatelessWidget {
|
|||||||
required this.isShowEmbed,
|
required this.isShowEmbed,
|
||||||
required this.isNestedClickable,
|
required this.isNestedClickable,
|
||||||
required this.isClickable,
|
required this.isClickable,
|
||||||
|
required this.showFeaturedReply,
|
||||||
required this.item,
|
required this.item,
|
||||||
required this.onUpdate,
|
required this.onUpdate,
|
||||||
this.backgroundColor,
|
this.backgroundColor,
|
||||||
@ -74,6 +77,7 @@ class PostListEntryWidget extends StatelessWidget {
|
|||||||
item: item,
|
item: item,
|
||||||
isShowEmbed: isShowEmbed,
|
isShowEmbed: isShowEmbed,
|
||||||
isClickable: isNestedClickable,
|
isClickable: isNestedClickable,
|
||||||
|
showFeaturedReply: showFeaturedReply,
|
||||||
backgroundColor: backgroundColor,
|
backgroundColor: backgroundColor,
|
||||||
).paddingSymmetric(vertical: 8),
|
).paddingSymmetric(vertical: 8),
|
||||||
onLongPress: () {
|
onLongPress: () {
|
||||||
|
@ -23,6 +23,7 @@ class PostSingleDisplay extends StatelessWidget {
|
|||||||
isClickable: true,
|
isClickable: true,
|
||||||
isShowEmbed: true,
|
isShowEmbed: true,
|
||||||
isNestedClickable: true,
|
isNestedClickable: true,
|
||||||
|
showFeaturedReply: true,
|
||||||
onUpdate: onUpdate,
|
onUpdate: onUpdate,
|
||||||
backgroundColor: Theme.of(context).colorScheme.surfaceContainerLow,
|
backgroundColor: Theme.of(context).colorScheme.surfaceContainerLow,
|
||||||
),
|
),
|
||||||
|
@ -36,6 +36,7 @@ class PostWarpedListWidget extends StatelessWidget {
|
|||||||
isShowEmbed: isShowEmbed,
|
isShowEmbed: isShowEmbed,
|
||||||
isNestedClickable: isNestedClickable,
|
isNestedClickable: isNestedClickable,
|
||||||
isClickable: isClickable,
|
isClickable: isClickable,
|
||||||
|
showFeaturedReply: true,
|
||||||
item: item,
|
item: item,
|
||||||
onUpdate: onUpdate ?? () {},
|
onUpdate: onUpdate ?? () {},
|
||||||
);
|
);
|
||||||
|
@ -1894,10 +1894,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: sqflite_common
|
name: sqflite_common
|
||||||
sha256: "7b41b6c3507854a159e24ae90a8e3e9cc01eb26a477c118d6dca065b5f55453e"
|
sha256: "4058172e418eb7e7f2058dcb7657d451a8fc264afa0dea4dbd0f304a57131611"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.5.4+2"
|
version: "2.5.4+3"
|
||||||
sqlite3:
|
sqlite3:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
Loading…
Reference in New Issue
Block a user