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