💄 Optimize skeleton effect

This commit is contained in:
2025-12-06 19:01:40 +08:00
parent dff84dde58
commit e4cd0c99df
4 changed files with 88 additions and 33 deletions

View File

@@ -1489,5 +1489,6 @@
"accountActivationAlert": "请记住激活您的账户", "accountActivationAlert": "请记住激活您的账户",
"accountActivationAlertHint": "未激活的账户可能会导致各种权限问题,请点击我们发送到您邮箱收件箱的链接来激活您的账户。", "accountActivationAlertHint": "未激活的账户可能会导致各种权限问题,请点击我们发送到您邮箱收件箱的链接来激活您的账户。",
"accountActivationResendHint": "没收到?请尝试点击下方按钮重新发送。如果您在账户未激活期间需要更新邮箱,请随时联系我们的客服。", "accountActivationResendHint": "没收到?请尝试点击下方按钮重新发送。如果您在账户未激活期间需要更新邮箱,请随时联系我们的客服。",
"accountActivationResend": "重新发送" "accountActivationResend": "重新发送",
"noFurtherData": "已经到底了"
} }

View File

@@ -40,8 +40,23 @@ class PaginationList<T> extends HookConsumerWidget {
final noti = ref.watch(notifier); final noti = ref.watch(notifier);
if ((data.isLoading || noti.isLoading) && data.value?.isEmpty == true) { if ((data.isLoading || noti.isLoading) && data.value?.isEmpty == true) {
final content = ResponseLoadingWidget(); final content = List<Widget>.generate(
return isSliver ? SliverFillRemaining(child: content) : content; 10,
(_) => Skeletonizer(
enabled: true,
effect: ShimmerEffect(
baseColor: Theme.of(context).colorScheme.surfaceContainerHigh,
highlightColor: Theme.of(
context,
).colorScheme.surfaceContainerHighest,
),
containersColor: Theme.of(context).colorScheme.surfaceContainerLow,
child: footerSkeletonChild ?? const _DefaultSkeletonChild(),
),
);
return isSliver
? SliverList.list(children: content)
: ListView(children: content);
} }
if (data.hasError) { if (data.hasError) {
@@ -116,8 +131,23 @@ class PaginationWidget<T> extends HookConsumerWidget {
final noti = ref.watch(notifier); final noti = ref.watch(notifier);
if ((data.isLoading || noti.isLoading) && data.value?.isEmpty == true) { if ((data.isLoading || noti.isLoading) && data.value?.isEmpty == true) {
final content = ResponseLoadingWidget(); final content = List<Widget>.generate(
return isSliver ? SliverFillRemaining(child: content) : content; 10,
(_) => Skeletonizer(
enabled: true,
effect: ShimmerEffect(
baseColor: Theme.of(context).colorScheme.surfaceContainerHigh,
highlightColor: Theme.of(
context,
).colorScheme.surfaceContainerHighest,
),
containersColor: Theme.of(context).colorScheme.surfaceContainerLow,
child: footerSkeletonChild ?? const _DefaultSkeletonChild(),
),
);
return isSliver
? SliverList.list(children: content)
: ListView(children: content);
} }
if (data.hasError) { if (data.hasError) {
@@ -161,13 +191,12 @@ class PaginationListFooter<T> extends HookConsumerWidget {
final placeholder = Skeletonizer( final placeholder = Skeletonizer(
enabled: true, enabled: true,
child: effect: ShimmerEffect(
skeletonChild ?? baseColor: Theme.of(context).colorScheme.surfaceContainerHigh,
ListTile( highlightColor: Theme.of(context).colorScheme.surfaceContainerHighest,
title: Text('Some data'),
subtitle: const Text('Subtitle here'),
trailing: const Icon(Icons.ac_unit),
), ),
containersColor: Theme.of(context).colorScheme.surfaceContainerLow,
child: skeletonChild ?? _DefaultSkeletonChild(),
); );
final child = hasBeenVisible.value final child = hasBeenVisible.value
? data.isLoading ? data.isLoading
@@ -194,3 +223,16 @@ class PaginationListFooter<T> extends HookConsumerWidget {
); );
} }
} }
class _DefaultSkeletonChild extends StatelessWidget {
const _DefaultSkeletonChild();
@override
Widget build(BuildContext context) {
return ListTile(
title: Text('Some data'),
subtitle: const Text('Subtitle here'),
trailing: const Icon(Icons.ac_unit),
);
}
}

View File

@@ -26,7 +26,12 @@ class PostItemSkeleton extends StatelessWidget {
final renderingPadding = final renderingPadding =
padding ?? const EdgeInsets.symmetric(horizontal: 8, vertical: 8); padding ?? const EdgeInsets.symmetric(horizontal: 8, vertical: 8);
return Column( return Center(
child: ConstrainedBox(
constraints: BoxConstraints(maxWidth: 640),
child: Card(
margin: EdgeInsets.only(bottom: 8),
child: Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
@@ -41,13 +46,18 @@ class PostItemSkeleton extends StatelessWidget {
renderingPadding: renderingPadding, renderingPadding: renderingPadding,
), ),
if (isShowReference) if (isShowReference)
_ReferencedPostWidgetSkeleton(renderingPadding: renderingPadding), _ReferencedPostWidgetSkeleton(
renderingPadding: renderingPadding,
),
if (isEmbedReply) if (isEmbedReply)
_PostReplyPreviewSkeleton( _PostReplyPreviewSkeleton(
renderingPadding: renderingPadding, renderingPadding: renderingPadding,
).padding(horizontal: renderingPadding.horizontal, top: 8), ).padding(horizontal: renderingPadding.horizontal, top: 8),
Gap(renderingPadding.vertical), Gap(renderingPadding.vertical),
], ],
),
),
),
); );
} }
} }

View File

@@ -5,6 +5,7 @@ import 'package:island/pods/network.dart';
import 'package:island/pods/paging.dart'; import 'package:island/pods/paging.dart';
import 'package:island/widgets/paging/pagination_list.dart'; import 'package:island/widgets/paging/pagination_list.dart';
import 'package:island/widgets/post/post_item.dart'; import 'package:island/widgets/post/post_item.dart';
import 'package:island/widgets/post/post_item_skeleton.dart';
final postRepliesProvider = AsyncNotifierProvider.autoDispose.family( final postRepliesProvider = AsyncNotifierProvider.autoDispose.family(
PostRepliesNotifier.new, PostRepliesNotifier.new,
@@ -52,6 +53,7 @@ class PostRepliesList extends HookConsumerWidget {
notifier: provider.notifier, notifier: provider.notifier,
isRefreshable: false, isRefreshable: false,
isSliver: true, isSliver: true,
footerSkeletonChild: const PostItemSkeleton(),
itemBuilder: (context, index, item) { itemBuilder: (context, index, item) {
final contentWidget = Card( final contentWidget = Card(
margin: EdgeInsets.symmetric(horizontal: 8, vertical: 4), margin: EdgeInsets.symmetric(horizontal: 8, vertical: 4),