From aefcbad02f76611d5e22609b00800b755d59c7ac Mon Sep 17 00:00:00 2001 From: LittleSheep Date: Fri, 2 Aug 2024 04:42:38 +0800 Subject: [PATCH] :dizzy: Better animated post list --- ios/Podfile.lock | 4 +- lib/screens/posts/post_detail.dart | 12 +- lib/shells/title_shell.dart | 10 +- lib/widgets/posts/post_item.dart | 303 +++++++++++++++-------------- pubspec.lock | 40 ++-- pubspec.yaml | 1 + 6 files changed, 203 insertions(+), 167 deletions(-) diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 2084b67..9da6c6f 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -145,7 +145,7 @@ PODS: - SDWebImage/Core (= 5.19.4) - SDWebImage/Core (5.19.4) - Sentry/HybridSDK (8.32.0) - - sentry_flutter (8.5.0): + - sentry_flutter (8.6.0): - Flutter - FlutterMacOS - Sentry/HybridSDK (= 8.32.0) @@ -309,7 +309,7 @@ SPEC CHECKSUMS: screen_brightness_ios: 715ca807df953bf676d339f11464e438143ee625 SDWebImage: 066c47b573f408f18caa467d71deace7c0f8280d Sentry: 96ae1dcdf01a644bc3a3b1dc279cecaf48a833fb - sentry_flutter: f1d86adcb93a959bc47a40d8d55059bdf7569bc5 + sentry_flutter: 090351ce1ff5f96a4b33ef9455b7e3b28185387d share_plus: 8875f4f2500512ea181eef553c3e27dba5135aad shared_preferences_foundation: fcdcbc04712aee1108ac7fda236f363274528f78 sqflite: 673a0e54cc04b7d6dba8d24fb8095b31c3a99eec diff --git a/lib/screens/posts/post_detail.dart b/lib/screens/posts/post_detail.dart index 9f8ee09..8425616 100644 --- a/lib/screens/posts/post_detail.dart +++ b/lib/screens/posts/post_detail.dart @@ -9,8 +9,13 @@ import 'package:solian/widgets/posts/post_replies.dart'; class PostDetailScreen extends StatefulWidget { final String id; + final Post? post; - const PostDetailScreen({super.key, required this.id}); + const PostDetailScreen({ + super.key, + required this.id, + this.post, + }); @override State createState() => _PostDetailScreenState(); @@ -20,6 +25,11 @@ class _PostDetailScreenState extends State { Post? item; Future getDetail() async { + if (widget.post != null) { + item = widget.post; + return widget.post; + } + final PostProvider provider = Get.find(); try { diff --git a/lib/shells/title_shell.dart b/lib/shells/title_shell.dart index a835e56..fa35e4c 100644 --- a/lib/shells/title_shell.dart +++ b/lib/shells/title_shell.dart @@ -8,13 +8,15 @@ import 'package:solian/widgets/app_bar_leading.dart'; class TitleShell extends StatelessWidget { final bool showAppBar; final bool isCenteredTitle; - final GoRouterState state; + final String? title; + final GoRouterState? state; final Widget child; const TitleShell({ super.key, required this.child, - required this.state, + this.title, + this.state, this.showAppBar = true, this.isCenteredTitle = false, }); @@ -25,7 +27,9 @@ class TitleShell extends StatelessWidget { appBar: showAppBar ? AppBar( leading: AppBarLeadingButton.adaptive(context), - title: AppBarTitle(state.topRoute?.name?.tr ?? 'page'.tr), + title: AppBarTitle( + title ?? (state!.topRoute?.name?.tr ?? 'page'.tr), + ), centerTitle: isCenteredTitle, toolbarHeight: SolianTheme.toolbarHeight(context), ) diff --git a/lib/widgets/posts/post_item.dart b/lib/widgets/posts/post_item.dart index ffeef16..e0c77d7 100644 --- a/lib/widgets/posts/post_item.dart +++ b/lib/widgets/posts/post_item.dart @@ -1,9 +1,11 @@ +import 'package:animations/animations.dart'; import 'package:flutter/material.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:get/get_utils/get_utils.dart'; import 'package:intl/intl.dart'; import 'package:solian/models/post.dart'; -import 'package:solian/router.dart'; +import 'package:solian/screens/posts/post_detail.dart'; +import 'package:solian/shells/title_shell.dart'; import 'package:solian/widgets/account/account_avatar.dart'; import 'package:solian/widgets/account/account_profile_popup.dart'; import 'package:solian/widgets/attachments/attachment_list.dart'; @@ -159,66 +161,88 @@ class _PostItemState extends State { } Widget _buildReply(BuildContext context) { - return Column( - children: [ - Row( - children: [ - FaIcon( - FontAwesomeIcons.reply, - size: 16, - color: _unFocusColor, - ), - Expanded( - child: Text( - 'postRepliedNotify'.trParams( - {'username': '@${widget.item.replyTo!.author.name}'}, - ), - style: TextStyle(color: _unFocusColor), - ).paddingOnly(left: 6), - ), - ], - ).paddingOnly(left: 12), - Card( - elevation: 1, - child: PostItem( - item: widget.item.replyTo!, - isCompact: true, - overrideAttachmentParent: widget.item.id.toString(), - ).paddingSymmetric(vertical: 8), + return OpenContainer( + closedBuilder: (_, openContainer) => Column( + children: [ + Row( + children: [ + FaIcon( + FontAwesomeIcons.reply, + size: 16, + color: _unFocusColor, + ), + Expanded( + child: Text( + 'postRepliedNotify'.trParams( + {'username': '@${widget.item.replyTo!.author.name}'}, + ), + style: TextStyle(color: _unFocusColor), + ).paddingOnly(left: 6), + ), + ], + ).paddingOnly(left: 12), + Card( + elevation: 1, + child: PostItem( + item: widget.item.replyTo!, + isCompact: true, + overrideAttachmentParent: widget.item.id.toString(), + ).paddingSymmetric(vertical: 8), + ), + ], + ), + openBuilder: (_, __) => TitleShell( + title: 'postDetail'.tr, + child: PostDetailScreen( + id: widget.item.replyTo!.id.toString(), + post: widget.item.replyTo!, ), - ], + ), + closedColor: Theme.of(context).colorScheme.surface, + openColor: Theme.of(context).colorScheme.surface, ); } Widget _buildRepost(BuildContext context) { - return Column( - children: [ - Row( - children: [ - FaIcon( - FontAwesomeIcons.retweet, - size: 16, - color: _unFocusColor, - ), - Expanded( - child: Text( - 'postRepostedNotify'.trParams( - {'username': '@${widget.item.repostTo!.author.name}'}, - ), - style: TextStyle(color: _unFocusColor), - ).paddingOnly(left: 6), - ), - ], - ).paddingOnly(left: 12), - Card( - elevation: 1, - child: PostItem( - item: widget.item.repostTo!, - isCompact: true, - overrideAttachmentParent: widget.item.id.toString(), - ).paddingSymmetric(vertical: 8), + return OpenContainer( + closedBuilder: (_, openContainer) => Column( + children: [ + Row( + children: [ + FaIcon( + FontAwesomeIcons.retweet, + size: 16, + color: _unFocusColor, + ), + Expanded( + child: Text( + 'postRepostedNotify'.trParams( + {'username': '@${widget.item.repostTo!.author.name}'}, + ), + style: TextStyle(color: _unFocusColor), + ).paddingOnly(left: 6), + ), + ], + ).paddingOnly(left: 12), + Card( + elevation: 1, + child: PostItem( + item: widget.item.repostTo!, + isCompact: true, + overrideAttachmentParent: widget.item.id.toString(), + ).paddingSymmetric(vertical: 8), + ), + ], + ), + openBuilder: (_, __) => TitleShell( + title: 'postDetail'.tr, + child: PostDetailScreen( + id: widget.item.repostTo!.id.toString(), + post: widget.item.repostTo!, ), - ], + ), + closedColor: Theme.of(context).colorScheme.surface, + openColor: Theme.of(context).colorScheme.surface, ); } @@ -264,100 +288,89 @@ class _PostItemState extends State { ); } - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - GestureDetector( - child: AccountAvatar(content: item.author.avatar.toString()), - onTap: () { - showModalBottomSheet( - useRootNavigator: true, - isScrollControlled: true, - backgroundColor: Theme.of(context).colorScheme.surface, - context: context, - builder: (context) => AccountProfilePopup( - account: item.author, - ), - ); - }, - ), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - _buildHeader(), - SizedContainer( - maxWidth: 640, - child: MarkdownTextContent( - content: item.body['content'], - isSelectable: widget.isContentSelectable, - ).paddingOnly(left: 12, right: 8), - ), - if (widget.item.replyTo != null && widget.isShowEmbed) - GestureDetector( - child: _buildReply(context).paddingOnly(top: 4), - onTap: () { - if (!widget.isClickable) return; - AppRouter.instance.pushNamed( - 'postDetail', - pathParameters: { - 'id': widget.item.replyTo!.id.toString(), - }, - ); - }, + return OpenContainer( + closedBuilder: (_, openContainer) => Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + GestureDetector( + child: AccountAvatar(content: item.author.avatar.toString()), + onTap: () { + showModalBottomSheet( + useRootNavigator: true, + isScrollControlled: true, + backgroundColor: Theme.of(context).colorScheme.surface, + context: context, + builder: (context) => AccountProfilePopup( + account: item.author, ), - if (widget.item.repostTo != null && widget.isShowEmbed) - GestureDetector( - child: _buildRepost(context).paddingOnly(top: 4), - onTap: () { - if (!widget.isClickable) return; - AppRouter.instance.pushNamed( - 'postDetail', - pathParameters: { - 'alias': widget.item.repostTo!.id.toString(), - }, - ); - }, - ), - _buildFooter().paddingOnly(left: 12), - ], + ); + }, ), - ), - ], - ).paddingOnly( - top: 10, - bottom: hasAttachment ? 10 : 0, - right: 16, - left: 16, - ), - AttachmentList( - parentId: widget.item.id.toString(), - attachmentsId: attachments, - isGrid: attachments.length > 1, - ), - if (widget.isShowReply && widget.isReactable) - PostQuickAction( - isShowReply: widget.isShowReply, - isReactable: widget.isReactable, - item: widget.item, - onReact: (symbol, changes) { - setState(() { - item.metric!.reactionList[symbol] = - (item.metric!.reactionList[symbol] ?? 0) + changes; - }); - }, + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + _buildHeader(), + SizedContainer( + maxWidth: 640, + child: MarkdownTextContent( + content: item.body['content'], + isSelectable: widget.isContentSelectable, + ).paddingOnly(left: 12, right: 8), + ), + if (widget.item.replyTo != null && widget.isShowEmbed) + _buildReply(context).paddingOnly(top: 4), + if (widget.item.repostTo != null && widget.isShowEmbed) + _buildRepost(context).paddingOnly(top: 4), + _buildFooter().paddingOnly(left: 12), + ], + ), + ), + ], ).paddingOnly( - top: hasAttachment ? 10 : 6, - left: hasAttachment ? 24 : 60, + top: 10, + bottom: hasAttachment ? 10 : 0, right: 16, - bottom: 10, - ) - else - const SizedBox(height: 10), - ], + left: 16, + ), + AttachmentList( + parentId: widget.item.id.toString(), + attachmentsId: attachments, + isGrid: attachments.length > 1, + ), + if (widget.isShowReply && widget.isReactable) + PostQuickAction( + isShowReply: widget.isShowReply, + isReactable: widget.isReactable, + item: widget.item, + onReact: (symbol, changes) { + setState(() { + item.metric!.reactionList[symbol] = + (item.metric!.reactionList[symbol] ?? 0) + changes; + }); + }, + ).paddingOnly( + top: hasAttachment ? 10 : 6, + left: hasAttachment ? 24 : 60, + right: 16, + bottom: 10, + ) + else + const SizedBox(height: 10), + ], + ), + openBuilder: (_, __) => TitleShell( + title: 'postDetail'.tr, + child: PostDetailScreen( + id: item.id.toString(), + post: item, + ), + ), + closedColor: Theme.of(context).colorScheme.surface, + openColor: Theme.of(context).colorScheme.surface, ); } } diff --git a/pubspec.lock b/pubspec.lock index a8c5acd..11fbe78 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -25,6 +25,14 @@ packages: url: "https://pub.dev" source: hosted version: "6.4.1" + animations: + dependency: "direct main" + description: + name: animations + sha256: d3d6dcfb218225bbe68e87ccf6378bbb2e32a94900722c5f81611dad089911cb + url: "https://pub.dev" + source: hosted + version: "2.0.11" archive: dependency: transitive description: @@ -133,26 +141,26 @@ packages: dependency: "direct main" description: name: cached_network_image - sha256: "28ea9690a8207179c319965c13cd8df184d5ee721ae2ce60f398ced1219cea1f" + sha256: "4a5d8d2c728b0f3d0245f69f921d7be90cae4c2fd5288f773088672c0893f819" url: "https://pub.dev" source: hosted - version: "3.3.1" + version: "3.4.0" cached_network_image_platform_interface: dependency: transitive description: name: cached_network_image_platform_interface - sha256: "9e90e78ae72caa874a323d78fa6301b3fb8fa7ea76a8f96dc5b5bf79f283bf2f" + sha256: ff0c949e323d2a1b52be73acce5b4a7b04063e61414c8ca542dbba47281630a7 url: "https://pub.dev" source: hosted - version: "4.0.0" + version: "4.1.0" cached_network_image_web: dependency: transitive description: name: cached_network_image_web - sha256: "205d6a9f1862de34b93184f22b9d2d94586b2f05c581d546695e3d8f6a805cd7" + sha256: "6322dde7a5ad92202e64df659241104a43db20ed594c41ca18de1014598d7996" url: "https://pub.dev" source: hosted - version: "1.2.0" + version: "1.3.0" carousel_slider: dependency: "direct main" description: @@ -301,10 +309,10 @@ packages: dependency: transitive description: name: dev_build - sha256: "5600100e28f7424ed53728e8e7aa6bc0e0506ec04bb49a82616f62112c1822c3" + sha256: "76dd5b2587a891ab9c1e7f7eea6ca4a3504667321e0186ecb1e385183889d89b" url: "https://pub.dev" source: hosted - version: "1.0.0+8" + version: "1.0.0+10" device_info_plus: dependency: "direct main" description: @@ -1092,10 +1100,10 @@ packages: dependency: transitive description: name: octo_image - sha256: "45b40f99622f11901238e18d48f5f12ea36426d8eced9f4cbf58479c7aa2430d" + sha256: "34faa6639a78c7e3cbe79be6f9f96535867e879748ade7d17c9b1ae7536293bd" url: "https://pub.dev" source: hosted - version: "2.0.0" + version: "2.1.0" package_config: dependency: transitive description: @@ -1436,18 +1444,18 @@ packages: dependency: transitive description: name: sentry - sha256: "60756499f09c3ed944640d7993ac527a89f7c3033f13ec12ae145706b269b5c8" + sha256: "76ad4fab90ff82427c26939bd79dc4df345a081e2b1cd5954b947e340b9af9a5" url: "https://pub.dev" source: hosted - version: "8.5.0" + version: "8.6.0" sentry_flutter: dependency: "direct main" description: name: sentry_flutter - sha256: "26cfe89cb08a60d9bc0c4e748a0508e223ae378265aec8ed2a2b48f0d2c936b9" + sha256: a7c92014701093a7c0a373e1a47c54ec428d8468d8bf2b793fee7ea1b085c21b url: "https://pub.dev" source: hosted - version: "8.5.0" + version: "8.6.0" share_plus: dependency: "direct main" description: @@ -1468,10 +1476,10 @@ packages: dependency: "direct main" description: name: shared_preferences - sha256: c3f888ba2d659f3e75f4686112cc1e71f46177f74452d40d8307edc332296ead + sha256: c272f9cabca5a81adc9b0894381e9c1def363e980f960fa903c604c471b22f68 url: "https://pub.dev" source: hosted - version: "2.3.0" + version: "2.3.1" shared_preferences_android: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 5c88eb2..dc606b1 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -66,6 +66,7 @@ dependencies: dio: ^5.5.0+1 image_cropper: ^8.0.1 markdown_toolbar: ^0.5.0 + animations: ^2.0.11 dev_dependencies: flutter_test: