⚡ Fix post list ui jank
This commit is contained in:
		| @@ -1,3 +1,4 @@ | |||||||
| description: This file stores settings for Dart & Flutter DevTools. | description: This file stores settings for Dart & Flutter DevTools. | ||||||
| documentation: https://docs.flutter.dev/tools/devtools/extensions#configure-extension-enablement-states | documentation: https://docs.flutter.dev/tools/devtools/extensions#configure-extension-enablement-states | ||||||
| extensions: | extensions: | ||||||
|  |   - provider: true | ||||||
| @@ -1,10 +1,12 @@ | |||||||
| import 'package:flutter/material.dart'; | import 'package:flutter/material.dart'; | ||||||
| import 'package:flutter_animate/flutter_animate.dart'; | import 'package:flutter_animate/flutter_animate.dart'; | ||||||
| import 'package:get/get.dart'; | import 'package:get/get.dart'; | ||||||
|  | import 'package:provider/provider.dart'; | ||||||
| import 'package:solian/exts.dart'; | import 'package:solian/exts.dart'; | ||||||
| import 'package:solian/providers/auth.dart'; | import 'package:solian/providers/auth.dart'; | ||||||
| import 'package:solian/providers/content/channel.dart'; | import 'package:solian/providers/content/channel.dart'; | ||||||
| import 'package:solian/providers/relation.dart'; | import 'package:solian/providers/relation.dart'; | ||||||
|  | import 'package:solian/providers/theme_switcher.dart'; | ||||||
| import 'package:solian/providers/websocket.dart'; | import 'package:solian/providers/websocket.dart'; | ||||||
| import 'package:solian/services.dart'; | import 'package:solian/services.dart'; | ||||||
| import 'package:solian/widgets/sized_container.dart'; | import 'package:solian/widgets/sized_container.dart'; | ||||||
| @@ -29,6 +31,12 @@ class _BootstrapperShellState extends State<BootstrapperShell> { | |||||||
|   int _periodCursor = 0; |   int _periodCursor = 0; | ||||||
|  |  | ||||||
|   late final List<({String label, Future<void> Function() action})> _periods = [ |   late final List<({String label, Future<void> Function() action})> _periods = [ | ||||||
|  |     ( | ||||||
|  |       label: 'bsLoadingTheme', | ||||||
|  |       action: () async { | ||||||
|  |         await context.read<ThemeSwitcher>().restoreTheme(); | ||||||
|  |       }, | ||||||
|  |     ), | ||||||
|     ( |     ( | ||||||
|       label: 'bsCheckingServer', |       label: 'bsCheckingServer', | ||||||
|       action: () async { |       action: () async { | ||||||
|   | |||||||
| @@ -76,7 +76,7 @@ Future<void> _initializePlatformComponents() async { | |||||||
| final themeSwitcher = ThemeSwitcher( | final themeSwitcher = ThemeSwitcher( | ||||||
|   lightThemeData: SolianTheme.build(Brightness.light), |   lightThemeData: SolianTheme.build(Brightness.light), | ||||||
|   darkThemeData: SolianTheme.build(Brightness.dark), |   darkThemeData: SolianTheme.build(Brightness.dark), | ||||||
| )..restoreTheme(); | ); | ||||||
|  |  | ||||||
| class SolianApp extends StatelessWidget { | class SolianApp extends StatelessWidget { | ||||||
|   const SolianApp({super.key}); |   const SolianApp({super.key}); | ||||||
|   | |||||||
| @@ -13,8 +13,8 @@ import 'package:solian/theme.dart'; | |||||||
| import 'package:solian/widgets/account/account_avatar.dart'; | import 'package:solian/widgets/account/account_avatar.dart'; | ||||||
| import 'package:solian/widgets/app_bar_leading.dart'; | import 'package:solian/widgets/app_bar_leading.dart'; | ||||||
| import 'package:solian/widgets/attachments/attachment_list.dart'; | import 'package:solian/widgets/attachments/attachment_list.dart'; | ||||||
| import 'package:solian/widgets/feed/feed_list.dart'; |  | ||||||
| import 'package:solian/widgets/posts/post_list.dart'; | import 'package:solian/widgets/posts/post_list.dart'; | ||||||
|  | import 'package:solian/widgets/posts/post_warped_list.dart'; | ||||||
| import 'package:solian/widgets/sized_container.dart'; | import 'package:solian/widgets/sized_container.dart'; | ||||||
|  |  | ||||||
| class AccountProfilePage extends StatefulWidget { | class AccountProfilePage extends StatefulWidget { | ||||||
| @@ -292,7 +292,7 @@ class _AccountProfilePageState extends State<AccountProfilePage> { | |||||||
|                       child: Center(child: CircularProgressIndicator()), |                       child: Center(child: CircularProgressIndicator()), | ||||||
|                     ), |                     ), | ||||||
|                   if (_userinfo != null) |                   if (_userinfo != null) | ||||||
|                     FeedListWidget( |                     PostWarpedListWidget( | ||||||
|                       isPinned: false, |                       isPinned: false, | ||||||
|                       controller: _postController.pagingController, |                       controller: _postController.pagingController, | ||||||
|                     ), |                     ), | ||||||
|   | |||||||
| @@ -3,7 +3,7 @@ import 'package:get/get.dart'; | |||||||
| import 'package:infinite_scroll_pagination/infinite_scroll_pagination.dart'; | import 'package:infinite_scroll_pagination/infinite_scroll_pagination.dart'; | ||||||
| import 'package:solian/models/pagination.dart'; | import 'package:solian/models/pagination.dart'; | ||||||
| import 'package:solian/providers/content/posts.dart'; | import 'package:solian/providers/content/posts.dart'; | ||||||
| import 'package:solian/widgets/feed/feed_list.dart'; | import 'package:solian/widgets/posts/post_warped_list.dart'; | ||||||
|  |  | ||||||
| import '../../models/post.dart'; | import '../../models/post.dart'; | ||||||
|  |  | ||||||
| @@ -77,7 +77,7 @@ class _FeedSearchScreenState extends State<FeedSearchScreen> { | |||||||
|                 onRefresh: () => Future.sync(() => _pagingController.refresh()), |                 onRefresh: () => Future.sync(() => _pagingController.refresh()), | ||||||
|                 child: CustomScrollView( |                 child: CustomScrollView( | ||||||
|                   slivers: [ |                   slivers: [ | ||||||
|                     FeedListWidget(controller: _pagingController), |                     PostWarpedListWidget(controller: _pagingController), | ||||||
|                   ], |                   ], | ||||||
|                 ), |                 ), | ||||||
|               ), |               ), | ||||||
|   | |||||||
| @@ -8,8 +8,8 @@ import 'package:solian/theme.dart'; | |||||||
| import 'package:solian/widgets/app_bar_title.dart'; | import 'package:solian/widgets/app_bar_title.dart'; | ||||||
| import 'package:solian/widgets/current_state_action.dart'; | import 'package:solian/widgets/current_state_action.dart'; | ||||||
| import 'package:solian/widgets/app_bar_leading.dart'; | import 'package:solian/widgets/app_bar_leading.dart'; | ||||||
| import 'package:solian/widgets/feed/feed_list.dart'; |  | ||||||
| import 'package:solian/widgets/posts/post_shuffle_swiper.dart'; | import 'package:solian/widgets/posts/post_shuffle_swiper.dart'; | ||||||
|  | import 'package:solian/widgets/posts/post_warped_list.dart'; | ||||||
|  |  | ||||||
| class HomeScreen extends StatefulWidget { | class HomeScreen extends StatefulWidget { | ||||||
|   const HomeScreen({super.key}); |   const HomeScreen({super.key}); | ||||||
| @@ -95,7 +95,7 @@ class _HomeScreenState extends State<HomeScreen> | |||||||
|                 RefreshIndicator( |                 RefreshIndicator( | ||||||
|                   onRefresh: () => _postController.reloadAllOver(), |                   onRefresh: () => _postController.reloadAllOver(), | ||||||
|                   child: CustomScrollView(slivers: [ |                   child: CustomScrollView(slivers: [ | ||||||
|                     FeedListWidget( |                     PostWarpedListWidget( | ||||||
|                       controller: _postController.pagingController, |                       controller: _postController.pagingController, | ||||||
|                     ), |                     ), | ||||||
|                   ]), |                   ]), | ||||||
|   | |||||||
| @@ -36,11 +36,11 @@ abstract class SolianTheme { | |||||||
|         seedColor: seedColor ?? const Color.fromRGBO(154, 98, 91, 1), |         seedColor: seedColor ?? const Color.fromRGBO(154, 98, 91, 1), | ||||||
|       ), |       ), | ||||||
|       fontFamily: 'Comfortaa', |       fontFamily: 'Comfortaa', | ||||||
|       fontFamilyFallback: const [ |       fontFamilyFallback: [ | ||||||
|         'NotoSansSC', |         'NotoSansSC', | ||||||
|         'NotoSansHK', |         'NotoSansHK', | ||||||
|         'NotoSansJP', |         'NotoSansJP', | ||||||
|         'NotoSansEmoji' |         if (PlatformInfo.isWeb) 'NotoSansEmoji', | ||||||
|       ], |       ], | ||||||
|       typography: Typography.material2021( |       typography: Typography.material2021( | ||||||
|         colorScheme: brightness == Brightness.light |         colorScheme: brightness == Brightness.light | ||||||
|   | |||||||
| @@ -19,7 +19,9 @@ class MarkdownTextContent extends StatelessWidget { | |||||||
|       physics: const NeverScrollableScrollPhysics(), |       physics: const NeverScrollableScrollPhysics(), | ||||||
|       data: content, |       data: content, | ||||||
|       padding: EdgeInsets.zero, |       padding: EdgeInsets.zero, | ||||||
|       styleSheet: MarkdownStyleSheet.fromTheme(Theme.of(context)).copyWith( |       styleSheet: MarkdownStyleSheet.fromTheme( | ||||||
|  |         Theme.of(context), | ||||||
|  |       ).copyWith( | ||||||
|         horizontalRuleDecoration: BoxDecoration( |         horizontalRuleDecoration: BoxDecoration( | ||||||
|           border: Border( |           border: Border( | ||||||
|             top: BorderSide( |             top: BorderSide( | ||||||
|   | |||||||
| @@ -325,7 +325,7 @@ class _PostItemState extends State<PostItem> { | |||||||
|                   _buildFooter().paddingOnly(left: 12), |                   _buildFooter().paddingOnly(left: 12), | ||||||
|                 ], |                 ], | ||||||
|               ), |               ), | ||||||
|             ) |             ), | ||||||
|           ], |           ], | ||||||
|         ).paddingOnly( |         ).paddingOnly( | ||||||
|           top: 10, |           top: 10, | ||||||
|   | |||||||
| @@ -48,6 +48,7 @@ class PostListWidget extends StatelessWidget { | |||||||
| } | } | ||||||
|  |  | ||||||
| class PostListEntryWidget extends StatelessWidget { | class PostListEntryWidget extends StatelessWidget { | ||||||
|  |   final int renderOrder; | ||||||
|   final bool isShowEmbed; |   final bool isShowEmbed; | ||||||
|   final bool isNestedClickable; |   final bool isNestedClickable; | ||||||
|   final bool isClickable; |   final bool isClickable; | ||||||
| @@ -56,6 +57,7 @@ class PostListEntryWidget extends StatelessWidget { | |||||||
|  |  | ||||||
|   const PostListEntryWidget({ |   const PostListEntryWidget({ | ||||||
|     super.key, |     super.key, | ||||||
|  |     this.renderOrder = 0, | ||||||
|     required this.isShowEmbed, |     required this.isShowEmbed, | ||||||
|     required this.isNestedClickable, |     required this.isNestedClickable, | ||||||
|     required this.isClickable, |     required this.isClickable, | ||||||
|   | |||||||
| @@ -85,65 +85,65 @@ class _PostQuickActionState extends State<PostQuickAction> { | |||||||
|   Widget build(BuildContext context) { |   Widget build(BuildContext context) { | ||||||
|     const density = VisualDensity(horizontal: -4, vertical: -3); |     const density = VisualDensity(horizontal: -4, vertical: -3); | ||||||
|  |  | ||||||
|  |     final reactionEntries = widget.item.metric!.reactionList.entries.toList(); | ||||||
|  |  | ||||||
|     return SizedBox( |     return SizedBox( | ||||||
|       height: 32, |       height: 32, | ||||||
|       width: double.infinity, |       width: double.infinity, | ||||||
|       child: Row( |       child: CustomScrollView( | ||||||
|         mainAxisAlignment: MainAxisAlignment.start, |         scrollDirection: Axis.horizontal, | ||||||
|         crossAxisAlignment: CrossAxisAlignment.center, |         slivers: [ | ||||||
|         children: [ |  | ||||||
|           if (widget.isReactable && widget.isShowReply) |           if (widget.isReactable && widget.isShowReply) | ||||||
|             ActionChip( |             SliverToBoxAdapter( | ||||||
|               avatar: const Icon(Icons.comment), |               child: ActionChip( | ||||||
|               label: Text(widget.item.metric!.replyCount.toString()), |                 avatar: const Icon(Icons.comment), | ||||||
|               visualDensity: density, |                 label: Text(widget.item.metric!.replyCount.toString()), | ||||||
|               onPressed: () { |                 visualDensity: density, | ||||||
|                 showModalBottomSheet( |                 onPressed: () { | ||||||
|                   useRootNavigator: true, |                   showModalBottomSheet( | ||||||
|                   context: context, |                     useRootNavigator: true, | ||||||
|                   builder: (context) { |                     context: context, | ||||||
|                     return PostReplyListPopup(item: widget.item); |                     builder: (context) { | ||||||
|                   }, |                       return PostReplyListPopup(item: widget.item); | ||||||
|                 ); |                     }, | ||||||
|               }, |  | ||||||
|             ), |  | ||||||
|           if (widget.isReactable && widget.isShowReply) |  | ||||||
|             const VerticalDivider( |  | ||||||
|               thickness: 0.3, |  | ||||||
|               width: 0.3, |  | ||||||
|               indent: 8, |  | ||||||
|               endIndent: 8, |  | ||||||
|             ).paddingSymmetric(horizontal: 8), |  | ||||||
|           Expanded( |  | ||||||
|             child: ListView( |  | ||||||
|               shrinkWrap: true, |  | ||||||
|               scrollDirection: Axis.horizontal, |  | ||||||
|               children: [ |  | ||||||
|                 ...widget.item.metric!.reactionList.entries.map((x) { |  | ||||||
|                   final info = reactions[x.key]; |  | ||||||
|                   return Padding( |  | ||||||
|                     padding: const EdgeInsets.only(right: 8), |  | ||||||
|                     child: ActionChip( |  | ||||||
|                       avatar: Text(info!.icon), |  | ||||||
|                       label: Text(x.value.toString()), |  | ||||||
|                       tooltip: ':${x.key}:', |  | ||||||
|                       visualDensity: density, |  | ||||||
|                       onPressed: _isSubmitting |  | ||||||
|                           ? null |  | ||||||
|                           : () => doWidgetReact(x.key, info.attitude), |  | ||||||
|                     ), |  | ||||||
|                   ); |                   ); | ||||||
|                 }), |                 }, | ||||||
|                 if (widget.isReactable) |               ), | ||||||
|                   ActionChip( |             ), | ||||||
|                     avatar: const Icon(Icons.add_reaction, color: Colors.teal), |           if (widget.isReactable && widget.isShowReply) | ||||||
|                     label: Text('reactAdd'.tr), |             SliverToBoxAdapter( | ||||||
|                     visualDensity: density, |               child: const VerticalDivider( | ||||||
|                     onPressed: () => showReactMenu(), |                 thickness: 0.3, | ||||||
|                   ), |                 width: 0.3, | ||||||
|               ], |                 indent: 8, | ||||||
|  |                 endIndent: 8, | ||||||
|  |               ).paddingSymmetric(horizontal: 8), | ||||||
|  |             ), | ||||||
|  |           SliverList.builder( | ||||||
|  |             itemCount: reactionEntries.length, | ||||||
|  |             itemBuilder: (context, index) { | ||||||
|  |               final x = reactionEntries[index]; | ||||||
|  |               final info = reactions[x.key]; | ||||||
|  |               return ActionChip( | ||||||
|  |                 avatar: Text(info!.icon), | ||||||
|  |                 label: Text(x.value.toString()), | ||||||
|  |                 tooltip: ':${x.key}:', | ||||||
|  |                 visualDensity: density, | ||||||
|  |                 onPressed: _isSubmitting | ||||||
|  |                     ? null | ||||||
|  |                     : () => doWidgetReact(x.key, info.attitude), | ||||||
|  |               ).paddingOnly(right: 8); | ||||||
|  |             }, | ||||||
|  |           ), | ||||||
|  |           if (widget.isReactable) | ||||||
|  |             SliverToBoxAdapter( | ||||||
|  |               child: ActionChip( | ||||||
|  |                 avatar: const Icon(Icons.add_reaction, color: Colors.teal), | ||||||
|  |                 label: Text('reactAdd'.tr), | ||||||
|  |                 visualDensity: density, | ||||||
|  |                 onPressed: () => showReactMenu(), | ||||||
|  |               ), | ||||||
|             ), |             ), | ||||||
|           ) |  | ||||||
|         ], |         ], | ||||||
|       ), |       ), | ||||||
|     ); |     ); | ||||||
|   | |||||||
| @@ -3,14 +3,14 @@ import 'package:infinite_scroll_pagination/infinite_scroll_pagination.dart'; | |||||||
| import 'package:solian/models/post.dart'; | import 'package:solian/models/post.dart'; | ||||||
| import 'package:solian/widgets/posts/post_list.dart'; | import 'package:solian/widgets/posts/post_list.dart'; | ||||||
| 
 | 
 | ||||||
| class FeedListWidget extends StatelessWidget { | class PostWarpedListWidget extends StatelessWidget { | ||||||
|   final bool isShowEmbed; |   final bool isShowEmbed; | ||||||
|   final bool isClickable; |   final bool isClickable; | ||||||
|   final bool isNestedClickable; |   final bool isNestedClickable; | ||||||
|   final bool isPinned; |   final bool isPinned; | ||||||
|   final PagingController<int, Post> controller; |   final PagingController<int, Post> controller; | ||||||
| 
 | 
 | ||||||
|   const FeedListWidget({ |   const PostWarpedListWidget({ | ||||||
|     super.key, |     super.key, | ||||||
|     required this.controller, |     required this.controller, | ||||||
|     this.isShowEmbed = true, |     this.isShowEmbed = true, | ||||||
| @@ -30,6 +30,7 @@ class FeedListWidget extends StatelessWidget { | |||||||
|             return const SizedBox(); |             return const SizedBox(); | ||||||
|           } |           } | ||||||
|           return PostListEntryWidget( |           return PostListEntryWidget( | ||||||
|  |             renderOrder: index, | ||||||
|             isShowEmbed: isShowEmbed, |             isShowEmbed: isShowEmbed, | ||||||
|             isNestedClickable: isNestedClickable, |             isNestedClickable: isNestedClickable, | ||||||
|             isClickable: isClickable, |             isClickable: isClickable, | ||||||
| @@ -2,7 +2,7 @@ name: solian | |||||||
| description: "The Solar Network App" | description: "The Solar Network App" | ||||||
| publish_to: "none" | publish_to: "none" | ||||||
|  |  | ||||||
| version: 1.2.0+4 | version: 1.2.0+6 | ||||||
|  |  | ||||||
| environment: | environment: | ||||||
|   sdk: ">=3.3.4 <4.0.0" |   sdk: ">=3.3.4 <4.0.0" | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user