mirror of
https://github.com/HChaZZY/PiliPlus.git
synced 2025-12-06 09:13:48 +08:00
mod: add skeleton
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
This commit is contained in:
@@ -6,6 +6,7 @@ class DynamicCardSkeleton extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final color = Theme.of(context).colorScheme.onInverseSurface;
|
||||
return Skeleton(
|
||||
child: Container(
|
||||
padding: const EdgeInsets.only(left: 12, right: 12, top: 12),
|
||||
@@ -25,7 +26,7 @@ class DynamicCardSkeleton extends StatelessWidget {
|
||||
width: 40,
|
||||
height: 40,
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context).colorScheme.onInverseSurface,
|
||||
color: color,
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
),
|
||||
),
|
||||
@@ -34,13 +35,13 @@ class DynamicCardSkeleton extends StatelessWidget {
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Container(
|
||||
color: Theme.of(context).colorScheme.onInverseSurface,
|
||||
color: color,
|
||||
width: 100,
|
||||
height: 13,
|
||||
margin: const EdgeInsets.only(bottom: 5),
|
||||
),
|
||||
Container(
|
||||
color: Theme.of(context).colorScheme.onInverseSurface,
|
||||
color: color,
|
||||
width: 50,
|
||||
height: 11,
|
||||
),
|
||||
@@ -55,31 +56,31 @@ class DynamicCardSkeleton extends StatelessWidget {
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Container(
|
||||
color: Theme.of(context).colorScheme.onInverseSurface,
|
||||
color: color,
|
||||
width: double.infinity,
|
||||
height: 13,
|
||||
margin: const EdgeInsets.only(bottom: 7),
|
||||
),
|
||||
Container(
|
||||
color: Theme.of(context).colorScheme.onInverseSurface,
|
||||
color: color,
|
||||
width: double.infinity,
|
||||
height: 13,
|
||||
margin: const EdgeInsets.only(bottom: 7),
|
||||
),
|
||||
Container(
|
||||
color: Theme.of(context).colorScheme.onInverseSurface,
|
||||
color: color,
|
||||
width: 300,
|
||||
height: 13,
|
||||
margin: const EdgeInsets.only(bottom: 7),
|
||||
),
|
||||
Container(
|
||||
color: Theme.of(context).colorScheme.onInverseSurface,
|
||||
color: color,
|
||||
width: 250,
|
||||
height: 13,
|
||||
margin: const EdgeInsets.only(bottom: 7),
|
||||
),
|
||||
Container(
|
||||
color: Theme.of(context).colorScheme.onInverseSurface,
|
||||
color: color,
|
||||
width: 100,
|
||||
height: 13,
|
||||
margin: const EdgeInsets.only(bottom: 7),
|
||||
|
||||
67
lib/common/skeleton/fav_pgc_item.dart
Normal file
67
lib/common/skeleton/fav_pgc_item.dart
Normal file
@@ -0,0 +1,67 @@
|
||||
import 'package:PiliPlus/common/constants.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'skeleton.dart';
|
||||
|
||||
class FavPgcItemSkeleton extends StatelessWidget {
|
||||
const FavPgcItemSkeleton({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final color = Theme.of(context).colorScheme.onInverseSurface;
|
||||
return Skeleton(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: StyleString.safeSpace,
|
||||
vertical: 5,
|
||||
),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
AspectRatio(
|
||||
aspectRatio: 3 / 4,
|
||||
child: LayoutBuilder(
|
||||
builder: (context, boxConstraints) {
|
||||
return Container(
|
||||
decoration: BoxDecoration(
|
||||
color: color,
|
||||
borderRadius: BorderRadius.circular(4),
|
||||
),
|
||||
width: boxConstraints.maxWidth,
|
||||
height: boxConstraints.maxHeight,
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 10),
|
||||
Expanded(
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Container(
|
||||
width: 175,
|
||||
height: 12,
|
||||
color: color,
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
Container(
|
||||
width: 55,
|
||||
height: 11,
|
||||
color: color,
|
||||
),
|
||||
const SizedBox(height: 5),
|
||||
Container(
|
||||
width: 35,
|
||||
height: 11,
|
||||
color: color,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
53
lib/common/skeleton/msg_feed_sys_msg_.dart
Normal file
53
lib/common/skeleton/msg_feed_sys_msg_.dart
Normal file
@@ -0,0 +1,53 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'skeleton.dart';
|
||||
|
||||
class MsgFeedSysMsgSkeleton extends StatelessWidget {
|
||||
const MsgFeedSysMsgSkeleton({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final color = Theme.of(context).colorScheme.onInverseSurface;
|
||||
return Skeleton(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Container(
|
||||
width: 125,
|
||||
height: 16,
|
||||
color: color,
|
||||
),
|
||||
const SizedBox(height: 6),
|
||||
Container(
|
||||
width: double.infinity,
|
||||
height: 12,
|
||||
color: color,
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
Container(
|
||||
width: double.infinity,
|
||||
height: 12,
|
||||
color: color,
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
Container(
|
||||
width: 100,
|
||||
height: 12,
|
||||
color: color,
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
Align(
|
||||
alignment: Alignment.centerRight,
|
||||
child: Container(
|
||||
width: 100,
|
||||
height: 10,
|
||||
color: color,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
36
lib/common/skeleton/msg_feed_top.dart
Normal file
36
lib/common/skeleton/msg_feed_top.dart
Normal file
@@ -0,0 +1,36 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'skeleton.dart';
|
||||
|
||||
class MsgFeedTopSkeleton extends StatelessWidget {
|
||||
const MsgFeedTopSkeleton({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final color = Theme.of(context).colorScheme.onInverseSurface;
|
||||
return Skeleton(
|
||||
child: ListTile(
|
||||
leading: Container(
|
||||
width: 45,
|
||||
height: 45,
|
||||
decoration: BoxDecoration(
|
||||
shape: BoxShape.circle,
|
||||
color: color,
|
||||
),
|
||||
),
|
||||
title: UnconstrainedBox(
|
||||
alignment: Alignment.centerLeft,
|
||||
child: Container(
|
||||
width: 100,
|
||||
height: 11,
|
||||
color: color,
|
||||
),
|
||||
),
|
||||
subtitle: Container(
|
||||
color: color,
|
||||
width: 125,
|
||||
height: 11,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,7 @@ class VideoCardHSkeleton extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final color = Theme.of(context).colorScheme.onInverseSurface;
|
||||
return Skeleton(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
@@ -23,7 +24,7 @@ class VideoCardHSkeleton extends StatelessWidget {
|
||||
builder: (context, boxConstraints) {
|
||||
return Container(
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context).colorScheme.onInverseSurface,
|
||||
color: color,
|
||||
borderRadius: StyleString.mdRadius,
|
||||
),
|
||||
);
|
||||
@@ -37,19 +38,19 @@ class VideoCardHSkeleton extends StatelessWidget {
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Container(
|
||||
color: Theme.of(context).colorScheme.onInverseSurface,
|
||||
color: color,
|
||||
width: 200,
|
||||
height: 11,
|
||||
margin: const EdgeInsets.only(bottom: 5),
|
||||
),
|
||||
Container(
|
||||
color: Theme.of(context).colorScheme.onInverseSurface,
|
||||
color: color,
|
||||
width: 150,
|
||||
height: 13,
|
||||
),
|
||||
const Spacer(),
|
||||
Container(
|
||||
color: Theme.of(context).colorScheme.onInverseSurface,
|
||||
color: color,
|
||||
width: 100,
|
||||
height: 13,
|
||||
margin: const EdgeInsets.only(bottom: 5),
|
||||
@@ -57,13 +58,13 @@ class VideoCardHSkeleton extends StatelessWidget {
|
||||
Row(
|
||||
children: [
|
||||
Container(
|
||||
color: Theme.of(context).colorScheme.onInverseSurface,
|
||||
color: color,
|
||||
width: 40,
|
||||
height: 13,
|
||||
margin: const EdgeInsets.only(right: 8),
|
||||
),
|
||||
Container(
|
||||
color: Theme.of(context).colorScheme.onInverseSurface,
|
||||
color: color,
|
||||
width: 40,
|
||||
height: 13,
|
||||
),
|
||||
|
||||
@@ -7,6 +7,7 @@ class VideoCardVSkeleton extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final color = Theme.of(context).colorScheme.onInverseSurface;
|
||||
return Skeleton(
|
||||
child: Column(
|
||||
children: [
|
||||
@@ -16,7 +17,7 @@ class VideoCardVSkeleton extends StatelessWidget {
|
||||
builder: (context, boxConstraints) {
|
||||
return Container(
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context).colorScheme.onInverseSurface,
|
||||
color: color,
|
||||
borderRadius: StyleString.mdRadius,
|
||||
),
|
||||
);
|
||||
@@ -37,24 +38,24 @@ class VideoCardVSkeleton extends StatelessWidget {
|
||||
width: 200,
|
||||
height: 13,
|
||||
margin: const EdgeInsets.only(bottom: 5),
|
||||
color: Theme.of(context).colorScheme.onInverseSurface,
|
||||
color: color,
|
||||
),
|
||||
Container(
|
||||
width: 150,
|
||||
height: 13,
|
||||
margin: const EdgeInsets.only(bottom: 12),
|
||||
color: Theme.of(context).colorScheme.onInverseSurface,
|
||||
color: color,
|
||||
),
|
||||
Container(
|
||||
width: 110,
|
||||
height: 13,
|
||||
margin: const EdgeInsets.only(bottom: 5),
|
||||
color: Theme.of(context).colorScheme.onInverseSurface,
|
||||
color: color,
|
||||
),
|
||||
Container(
|
||||
width: 75,
|
||||
height: 13,
|
||||
color: Theme.of(context).colorScheme.onInverseSurface,
|
||||
color: color,
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
41
lib/common/skeleton/whisper_item.dart
Normal file
41
lib/common/skeleton/whisper_item.dart
Normal file
@@ -0,0 +1,41 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'skeleton.dart';
|
||||
|
||||
class WhisperItemSkeleton extends StatelessWidget {
|
||||
const WhisperItemSkeleton({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final color = Theme.of(context).colorScheme.onInverseSurface;
|
||||
return Skeleton(
|
||||
child: ListTile(
|
||||
leading: Container(
|
||||
width: 45,
|
||||
height: 45,
|
||||
decoration: BoxDecoration(
|
||||
shape: BoxShape.circle,
|
||||
color: color,
|
||||
),
|
||||
),
|
||||
title: UnconstrainedBox(
|
||||
alignment: Alignment.centerLeft,
|
||||
child: Container(
|
||||
width: 100,
|
||||
height: 11,
|
||||
color: color,
|
||||
),
|
||||
),
|
||||
subtitle: Container(
|
||||
color: color,
|
||||
width: 125,
|
||||
height: 11,
|
||||
),
|
||||
trailing: Container(
|
||||
color: color,
|
||||
width: 50,
|
||||
height: 11,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
import 'package:PiliPlus/common/widgets/loading_widget.dart';
|
||||
import 'package:PiliPlus/common/skeleton/msg_feed_top.dart';
|
||||
import 'package:PiliPlus/common/widgets/http_error.dart';
|
||||
import 'package:PiliPlus/common/widgets/refresh_indicator.dart';
|
||||
import 'package:PiliPlus/http/loading_state.dart';
|
||||
import 'package:PiliPlus/models/user/black.dart';
|
||||
@@ -40,18 +41,27 @@ class _BlackListPageState extends State<BlackListPage> {
|
||||
),
|
||||
body: refreshIndicator(
|
||||
onRefresh: () async => await _blackListController.onRefresh(),
|
||||
child: Obx(() => _buildBody(_blackListController.loadingState.value)),
|
||||
child: CustomScrollView(
|
||||
physics: const AlwaysScrollableScrollPhysics(),
|
||||
controller: _blackListController.scrollController,
|
||||
slivers: [
|
||||
Obx(() => _buildBody(_blackListController.loadingState.value))
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildBody(LoadingState<List<BlackListItem>?> loadingState) {
|
||||
return switch (loadingState) {
|
||||
Loading() => loadingWidget,
|
||||
Loading() => SliverList.builder(
|
||||
itemCount: 12,
|
||||
itemBuilder: (context, index) {
|
||||
return const MsgFeedTopSkeleton();
|
||||
},
|
||||
),
|
||||
Success() => loadingState.response?.isNotEmpty == true
|
||||
? ListView.builder(
|
||||
physics: const AlwaysScrollableScrollPhysics(),
|
||||
controller: _blackListController.scrollController,
|
||||
? SliverList.builder(
|
||||
itemCount: loadingState.response!.length,
|
||||
itemBuilder: (BuildContext context, int index) {
|
||||
if (index == loadingState.response!.length - 1) {
|
||||
@@ -94,10 +104,10 @@ class _BlackListPageState extends State<BlackListPage> {
|
||||
);
|
||||
},
|
||||
)
|
||||
: errorWidget(
|
||||
: HttpError(
|
||||
callback: _blackListController.onReload,
|
||||
),
|
||||
Error() => errorWidget(
|
||||
Error() => HttpError(
|
||||
errMsg: loadingState.errMsg,
|
||||
callback: _blackListController.onReload,
|
||||
),
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import 'package:PiliPlus/common/skeleton/msg_feed_top.dart';
|
||||
import 'package:PiliPlus/common/widgets/refresh_indicator.dart';
|
||||
import 'package:PiliPlus/http/loading_state.dart';
|
||||
import 'package:PiliPlus/models/fans/result.dart';
|
||||
@@ -51,7 +52,18 @@ class _FansPageState extends State<FansPage> {
|
||||
|
||||
Widget _buildBody(LoadingState<List<FansItemModel>?> loadingState) {
|
||||
return switch (loadingState) {
|
||||
Loading() => HttpError(),
|
||||
Loading() => SliverGrid(
|
||||
gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent(
|
||||
maxCrossAxisExtent: Grid.smallCardWidth * 2,
|
||||
mainAxisExtent: 66,
|
||||
),
|
||||
delegate: SliverChildBuilderDelegate(
|
||||
(context, index) {
|
||||
return const MsgFeedTopSkeleton();
|
||||
},
|
||||
childCount: 16,
|
||||
),
|
||||
),
|
||||
Success() => loadingState.response?.isNotEmpty == true
|
||||
? SliverPadding(
|
||||
padding: EdgeInsets.only(
|
||||
|
||||
@@ -34,7 +34,14 @@ class _FavArticlePageState extends State<FavArticlePage>
|
||||
},
|
||||
child: CustomScrollView(
|
||||
slivers: [
|
||||
Obx(() => _buildBody(_favArticleController.loadingState.value)),
|
||||
SliverPadding(
|
||||
padding: EdgeInsets.only(
|
||||
top: StyleString.safeSpace - 5,
|
||||
bottom: MediaQuery.paddingOf(context).bottom + 80,
|
||||
),
|
||||
sliver:
|
||||
Obx(() => _buildBody(_favArticleController.loadingState.value)),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
@@ -52,35 +59,29 @@ class _FavArticlePageState extends State<FavArticlePage>
|
||||
),
|
||||
),
|
||||
Success() => loadingState.response?.isNotEmpty == true
|
||||
? SliverPadding(
|
||||
padding: EdgeInsets.only(
|
||||
top: StyleString.safeSpace - 5,
|
||||
bottom: MediaQuery.paddingOf(context).bottom + 80,
|
||||
),
|
||||
sliver: SliverGrid(
|
||||
gridDelegate: Grid.videoCardHDelegate(context),
|
||||
delegate: SliverChildBuilderDelegate(
|
||||
(context, index) {
|
||||
if (index == loadingState.response!.length - 1) {
|
||||
_favArticleController.onLoadMore();
|
||||
}
|
||||
return FavArticleItem(
|
||||
item: loadingState.response![index],
|
||||
onDelete: () {
|
||||
showConfirmDialog(
|
||||
context: context,
|
||||
title: '确定取消收藏?',
|
||||
onConfirm: () {
|
||||
_favArticleController.onRemove(
|
||||
index,
|
||||
loadingState.response![index]['opus_id'],
|
||||
);
|
||||
});
|
||||
},
|
||||
);
|
||||
},
|
||||
childCount: loadingState.response!.length,
|
||||
),
|
||||
? SliverGrid(
|
||||
gridDelegate: Grid.videoCardHDelegate(context),
|
||||
delegate: SliverChildBuilderDelegate(
|
||||
(context, index) {
|
||||
if (index == loadingState.response!.length - 1) {
|
||||
_favArticleController.onLoadMore();
|
||||
}
|
||||
return FavArticleItem(
|
||||
item: loadingState.response![index],
|
||||
onDelete: () {
|
||||
showConfirmDialog(
|
||||
context: context,
|
||||
title: '确定取消收藏?',
|
||||
onConfirm: () {
|
||||
_favArticleController.onRemove(
|
||||
index,
|
||||
loadingState.response![index]['opus_id'],
|
||||
);
|
||||
});
|
||||
},
|
||||
);
|
||||
},
|
||||
childCount: loadingState.response!.length,
|
||||
),
|
||||
)
|
||||
: HttpError(callback: _favArticleController.onReload),
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import 'package:PiliPlus/common/skeleton/video_card_h.dart';
|
||||
import 'package:PiliPlus/common/skeleton/fav_pgc_item.dart';
|
||||
import 'package:PiliPlus/common/widgets/dialog.dart';
|
||||
import 'package:PiliPlus/common/widgets/http_error.dart';
|
||||
import 'package:PiliPlus/common/widgets/icon_button.dart';
|
||||
@@ -162,7 +162,7 @@ class _FavPgcChildPageState extends State<FavPgcChildPage>
|
||||
gridDelegate: Grid.videoCardHDelegate(context),
|
||||
delegate: SliverChildBuilderDelegate(
|
||||
(context, index) {
|
||||
return const VideoCardHSkeleton();
|
||||
return const FavPgcItemSkeleton();
|
||||
},
|
||||
childCount: 10,
|
||||
),
|
||||
|
||||
@@ -37,8 +37,14 @@ class _FavVideoPageState extends State<FavVideoPage>
|
||||
controller: _favController.scrollController,
|
||||
physics: const AlwaysScrollableScrollPhysics(),
|
||||
slivers: [
|
||||
Obx(
|
||||
() => _buildBody(_favController.loadingState.value),
|
||||
SliverPadding(
|
||||
padding: EdgeInsets.only(
|
||||
top: StyleString.safeSpace - 5,
|
||||
bottom: 80 + MediaQuery.paddingOf(context).bottom,
|
||||
),
|
||||
sliver: Obx(
|
||||
() => _buildBody(_favController.loadingState.value),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -57,44 +63,38 @@ class _FavVideoPageState extends State<FavVideoPage>
|
||||
),
|
||||
),
|
||||
Success() => loadingState.response?.isNotEmpty == true
|
||||
? SliverPadding(
|
||||
padding: EdgeInsets.only(
|
||||
top: StyleString.safeSpace - 5,
|
||||
bottom: 80 + MediaQuery.paddingOf(context).bottom,
|
||||
),
|
||||
sliver: SliverGrid(
|
||||
gridDelegate: Grid.videoCardHDelegate(context),
|
||||
delegate: SliverChildBuilderDelegate(
|
||||
childCount: loadingState.response!.length,
|
||||
(BuildContext context, int index) {
|
||||
if (index == loadingState.response!.length - 1) {
|
||||
_favController.onLoadMore();
|
||||
}
|
||||
final item = loadingState.response![index];
|
||||
String heroTag = Utils.makeHeroTag(item.fid);
|
||||
return FavItem(
|
||||
heroTag: heroTag,
|
||||
favFolderItem: item,
|
||||
onTap: () async {
|
||||
dynamic res = await Get.toNamed(
|
||||
'/favDetail',
|
||||
arguments: item,
|
||||
parameters: {
|
||||
'heroTag': heroTag,
|
||||
'mediaId': item.id.toString(),
|
||||
},
|
||||
);
|
||||
if (res == true) {
|
||||
List<FavFolderItemData> list =
|
||||
(_favController.loadingState.value as Success)
|
||||
.response;
|
||||
list.removeAt(index);
|
||||
_favController.loadingState.refresh();
|
||||
}
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
? SliverGrid(
|
||||
gridDelegate: Grid.videoCardHDelegate(context),
|
||||
delegate: SliverChildBuilderDelegate(
|
||||
childCount: loadingState.response!.length,
|
||||
(BuildContext context, int index) {
|
||||
if (index == loadingState.response!.length - 1) {
|
||||
_favController.onLoadMore();
|
||||
}
|
||||
final item = loadingState.response![index];
|
||||
String heroTag = Utils.makeHeroTag(item.fid);
|
||||
return FavItem(
|
||||
heroTag: heroTag,
|
||||
favFolderItem: item,
|
||||
onTap: () async {
|
||||
dynamic res = await Get.toNamed(
|
||||
'/favDetail',
|
||||
arguments: item,
|
||||
parameters: {
|
||||
'heroTag': heroTag,
|
||||
'mediaId': item.id.toString(),
|
||||
},
|
||||
);
|
||||
if (res == true) {
|
||||
List<FavFolderItemData> list =
|
||||
(_favController.loadingState.value as Success)
|
||||
.response;
|
||||
list.removeAt(index);
|
||||
_favController.loadingState.refresh();
|
||||
}
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
)
|
||||
: HttpError(
|
||||
|
||||
@@ -58,7 +58,8 @@ class _MemberBangumiState extends State<MemberBangumi>
|
||||
right: StyleString.safeSpace,
|
||||
top: StyleString.safeSpace,
|
||||
bottom: StyleString.safeSpace +
|
||||
MediaQuery.of(context).padding.bottom,
|
||||
MediaQuery.of(context).padding.bottom +
|
||||
80,
|
||||
),
|
||||
sliver: SliverGrid(
|
||||
gridDelegate: SliverGridDelegateWithExtentAndRatio(
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import 'package:PiliPlus/common/constants.dart';
|
||||
import 'package:PiliPlus/common/widgets/loading_widget.dart';
|
||||
import 'package:PiliPlus/common/skeleton/video_card_v.dart';
|
||||
import 'package:PiliPlus/common/widgets/http_error.dart';
|
||||
import 'package:PiliPlus/http/loading_state.dart';
|
||||
import 'package:PiliPlus/models/member/coin.dart';
|
||||
import 'package:PiliPlus/pages/member_coin/controller.dart';
|
||||
@@ -38,21 +39,39 @@ class _MemberCoinPageState extends State<MemberCoinPage> {
|
||||
appBar: AppBar(
|
||||
title: Text('${widget.mid == _ownerMid ? '我' : '${widget.name}'}的最近投币'),
|
||||
),
|
||||
body: Obx(() => _buildBody(_ctr.loadingState.value)),
|
||||
body: CustomScrollView(
|
||||
slivers: [
|
||||
SliverPadding(
|
||||
padding: EdgeInsets.only(
|
||||
top: StyleString.safeSpace - 5,
|
||||
left: StyleString.safeSpace,
|
||||
right: StyleString.safeSpace,
|
||||
bottom: MediaQuery.paddingOf(context).bottom + 80,
|
||||
),
|
||||
sliver: Obx(() => _buildBody(_ctr.loadingState.value)),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildBody(LoadingState<List<MemberCoinsDataModel>?> loadingState) {
|
||||
return switch (loadingState) {
|
||||
Loading() => loadingWidget,
|
||||
Loading() => SliverGrid.builder(
|
||||
gridDelegate: SliverGridDelegateWithExtentAndRatio(
|
||||
mainAxisSpacing: StyleString.cardSpace,
|
||||
crossAxisSpacing: StyleString.cardSpace,
|
||||
maxCrossAxisExtent: Grid.smallCardWidth,
|
||||
childAspectRatio: StyleString.aspectRatio,
|
||||
mainAxisExtent: MediaQuery.textScalerOf(context).scale(90),
|
||||
),
|
||||
itemCount: 16,
|
||||
itemBuilder: (context, index) {
|
||||
return const VideoCardVSkeleton();
|
||||
},
|
||||
),
|
||||
Success() => loadingState.response?.isNotEmpty == true
|
||||
? GridView.builder(
|
||||
padding: EdgeInsets.only(
|
||||
top: StyleString.safeSpace - 5,
|
||||
left: StyleString.safeSpace,
|
||||
right: StyleString.safeSpace,
|
||||
bottom: MediaQuery.paddingOf(context).bottom + 80,
|
||||
),
|
||||
? SliverGrid.builder(
|
||||
gridDelegate: SliverGridDelegateWithExtentAndRatio(
|
||||
mainAxisSpacing: StyleString.cardSpace,
|
||||
crossAxisSpacing: StyleString.cardSpace,
|
||||
@@ -65,8 +84,8 @@ class _MemberCoinPageState extends State<MemberCoinPage> {
|
||||
return MemberCoinsItem(coinItem: loadingState.response![index]);
|
||||
},
|
||||
)
|
||||
: scrollErrorWidget(callback: _ctr.onReload),
|
||||
Error() => scrollErrorWidget(
|
||||
: HttpError(callback: _ctr.onReload),
|
||||
Error() => HttpError(
|
||||
errMsg: loadingState.errMsg,
|
||||
callback: _ctr.onReload,
|
||||
),
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import 'package:PiliPlus/common/constants.dart';
|
||||
import 'package:PiliPlus/common/widgets/loading_widget.dart';
|
||||
import 'package:PiliPlus/common/skeleton/video_card_v.dart';
|
||||
import 'package:PiliPlus/common/widgets/http_error.dart';
|
||||
import 'package:PiliPlus/http/loading_state.dart';
|
||||
import 'package:PiliPlus/models/member/coin.dart';
|
||||
import 'package:PiliPlus/pages/member_coin/widgets/item.dart';
|
||||
@@ -38,21 +39,39 @@ class _MemberLikePageState extends State<MemberLikePage> {
|
||||
appBar: AppBar(
|
||||
title: Text('${widget.mid == _ownerMid ? '我' : '${widget.name}'}的推荐'),
|
||||
),
|
||||
body: Obx(() => _buildBody(_ctr.loadingState.value)),
|
||||
body: CustomScrollView(
|
||||
slivers: [
|
||||
SliverPadding(
|
||||
padding: EdgeInsets.only(
|
||||
top: StyleString.safeSpace - 5,
|
||||
left: StyleString.safeSpace,
|
||||
right: StyleString.safeSpace,
|
||||
bottom: MediaQuery.paddingOf(context).bottom + 80,
|
||||
),
|
||||
sliver: Obx(() => _buildBody(_ctr.loadingState.value)),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildBody(LoadingState<List<MemberCoinsDataModel>?> loadingState) {
|
||||
return switch (loadingState) {
|
||||
Loading() => loadingWidget,
|
||||
Loading() => SliverGrid.builder(
|
||||
gridDelegate: SliverGridDelegateWithExtentAndRatio(
|
||||
mainAxisSpacing: StyleString.cardSpace,
|
||||
crossAxisSpacing: StyleString.cardSpace,
|
||||
maxCrossAxisExtent: Grid.smallCardWidth,
|
||||
childAspectRatio: StyleString.aspectRatio,
|
||||
mainAxisExtent: MediaQuery.textScalerOf(context).scale(90),
|
||||
),
|
||||
itemCount: 16,
|
||||
itemBuilder: (context, index) {
|
||||
return const VideoCardVSkeleton();
|
||||
},
|
||||
),
|
||||
Success() => loadingState.response?.isNotEmpty == true
|
||||
? GridView.builder(
|
||||
padding: EdgeInsets.only(
|
||||
top: StyleString.safeSpace - 5,
|
||||
left: StyleString.safeSpace,
|
||||
right: StyleString.safeSpace,
|
||||
bottom: MediaQuery.paddingOf(context).bottom + 80,
|
||||
),
|
||||
? SliverGrid.builder(
|
||||
gridDelegate: SliverGridDelegateWithExtentAndRatio(
|
||||
mainAxisSpacing: StyleString.cardSpace,
|
||||
crossAxisSpacing: StyleString.cardSpace,
|
||||
@@ -65,8 +84,8 @@ class _MemberLikePageState extends State<MemberLikePage> {
|
||||
return MemberCoinsItem(coinItem: loadingState.response![index]);
|
||||
},
|
||||
)
|
||||
: scrollErrorWidget(callback: _ctr.onReload),
|
||||
Error() => scrollErrorWidget(
|
||||
: HttpError(callback: _ctr.onReload),
|
||||
Error() => HttpError(
|
||||
errMsg: loadingState.errMsg,
|
||||
callback: _ctr.onReload,
|
||||
),
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import 'package:PiliPlus/common/constants.dart';
|
||||
import 'package:PiliPlus/common/widgets/loading_widget.dart';
|
||||
import 'package:PiliPlus/common/skeleton/video_card_h.dart';
|
||||
import 'package:PiliPlus/common/widgets/http_error.dart';
|
||||
import 'package:PiliPlus/common/widgets/refresh_indicator.dart';
|
||||
import 'package:PiliPlus/common/widgets/video_card_h.dart';
|
||||
import 'package:PiliPlus/http/loading_state.dart';
|
||||
@@ -27,54 +28,64 @@ class _SearchArchiveState extends State<SearchArchive>
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
super.build(context);
|
||||
return Obx(() => _buildBody(context, widget.ctr.archiveState.value));
|
||||
return refreshIndicator(
|
||||
onRefresh: () async {
|
||||
await widget.ctr.refreshArchive();
|
||||
},
|
||||
child: CustomScrollView(
|
||||
physics: const AlwaysScrollableScrollPhysics(),
|
||||
slivers: [
|
||||
SliverPadding(
|
||||
padding: EdgeInsets.only(
|
||||
top: StyleString.safeSpace - 5,
|
||||
bottom: MediaQuery.paddingOf(context).bottom + 80,
|
||||
),
|
||||
sliver:
|
||||
Obx(() => _buildBody(context, widget.ctr.archiveState.value)),
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildBody(
|
||||
BuildContext context, LoadingState<List<VListItemModel>?> loadingState) {
|
||||
return switch (loadingState) {
|
||||
Loading() => loadingWidget,
|
||||
Loading() => SliverGrid(
|
||||
gridDelegate: Grid.videoCardHDelegate(context),
|
||||
delegate: SliverChildBuilderDelegate(
|
||||
(context, index) {
|
||||
return const VideoCardHSkeleton();
|
||||
},
|
||||
childCount: 10,
|
||||
),
|
||||
),
|
||||
Success() => loadingState.response?.isNotEmpty == true
|
||||
? refreshIndicator(
|
||||
onRefresh: () async {
|
||||
await widget.ctr.refreshArchive();
|
||||
},
|
||||
child: CustomScrollView(
|
||||
physics: const AlwaysScrollableScrollPhysics(),
|
||||
slivers: [
|
||||
SliverPadding(
|
||||
padding: EdgeInsets.only(
|
||||
top: StyleString.safeSpace - 5,
|
||||
bottom: MediaQuery.paddingOf(context).bottom + 80,
|
||||
),
|
||||
sliver: SliverGrid(
|
||||
gridDelegate: Grid.videoCardHDelegate(context),
|
||||
delegate: SliverChildBuilderDelegate(
|
||||
(context, index) {
|
||||
if (index == loadingState.response!.length - 1) {
|
||||
EasyThrottle.throttle('searchArchives',
|
||||
const Duration(milliseconds: 500), () {
|
||||
widget.ctr.searchArchives(false);
|
||||
});
|
||||
}
|
||||
return VideoCardH(
|
||||
videoItem: loadingState.response![index],
|
||||
);
|
||||
},
|
||||
childCount: loadingState.response!.length,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
? SliverGrid(
|
||||
gridDelegate: Grid.videoCardHDelegate(context),
|
||||
delegate: SliverChildBuilderDelegate(
|
||||
(context, index) {
|
||||
if (index == loadingState.response!.length - 1) {
|
||||
EasyThrottle.throttle(
|
||||
'searchArchives', const Duration(milliseconds: 500),
|
||||
() {
|
||||
widget.ctr.searchArchives(false);
|
||||
});
|
||||
}
|
||||
return VideoCardH(
|
||||
videoItem: loadingState.response![index],
|
||||
);
|
||||
},
|
||||
childCount: loadingState.response!.length,
|
||||
),
|
||||
)
|
||||
: errorWidget(
|
||||
: HttpError(
|
||||
callback: () {
|
||||
widget.ctr.archiveState.value = LoadingState.loading();
|
||||
widget.ctr.refreshArchive();
|
||||
},
|
||||
),
|
||||
Error() => errorWidget(
|
||||
Error() => HttpError(
|
||||
errMsg: loadingState.errMsg,
|
||||
callback: () {
|
||||
widget.ctr.archiveState.value = LoadingState.loading();
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import 'package:PiliPlus/common/constants.dart';
|
||||
import 'package:PiliPlus/common/widgets/loading_widget.dart';
|
||||
import 'package:PiliPlus/common/skeleton/dynamic_card.dart';
|
||||
import 'package:PiliPlus/common/widgets/http_error.dart';
|
||||
import 'package:PiliPlus/common/widgets/refresh_indicator.dart';
|
||||
import 'package:PiliPlus/http/loading_state.dart';
|
||||
import 'package:PiliPlus/models/dynamics/result.dart';
|
||||
@@ -29,86 +30,123 @@ class _SearchDynamicState extends State<SearchDynamic>
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
super.build(context);
|
||||
return Obx(() => _buildBody(context, widget.ctr.dynamicState.value));
|
||||
return refreshIndicator(
|
||||
onRefresh: () async {
|
||||
await widget.ctr.refreshDynamic();
|
||||
},
|
||||
child: CustomScrollView(
|
||||
physics: const AlwaysScrollableScrollPhysics(),
|
||||
slivers: [
|
||||
SliverPadding(
|
||||
padding: EdgeInsets.only(
|
||||
bottom: MediaQuery.paddingOf(context).bottom + 80,
|
||||
),
|
||||
sliver:
|
||||
Obx(() => _buildBody(context, widget.ctr.dynamicState.value)),
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
late final bool dynamicsWaterfallFlow = GStorage.setting
|
||||
.get(SettingBoxKey.dynamicsWaterfallFlow, defaultValue: true);
|
||||
|
||||
Widget skeleton() {
|
||||
if (!dynamicsWaterfallFlow) {
|
||||
return SliverCrossAxisGroup(
|
||||
slivers: [
|
||||
const SliverFillRemaining(),
|
||||
SliverConstrainedCrossAxis(
|
||||
maxExtent: Grid.smallCardWidth * 2,
|
||||
sliver: SliverList(
|
||||
delegate: SliverChildBuilderDelegate(
|
||||
(context, index) {
|
||||
return const DynamicCardSkeleton();
|
||||
},
|
||||
childCount: 10,
|
||||
),
|
||||
),
|
||||
),
|
||||
const SliverFillRemaining()
|
||||
],
|
||||
);
|
||||
}
|
||||
return SliverGrid(
|
||||
gridDelegate: SliverGridDelegateWithExtentAndRatio(
|
||||
crossAxisSpacing: StyleString.cardSpace / 2,
|
||||
mainAxisSpacing: StyleString.cardSpace / 2,
|
||||
maxCrossAxisExtent: Grid.smallCardWidth * 2,
|
||||
childAspectRatio: StyleString.aspectRatio,
|
||||
mainAxisExtent: 50,
|
||||
),
|
||||
delegate: SliverChildBuilderDelegate(
|
||||
(context, index) {
|
||||
return const DynamicCardSkeleton();
|
||||
},
|
||||
childCount: 10,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildBody(BuildContext context,
|
||||
LoadingState<List<DynamicItemModel>?> loadingState) {
|
||||
return switch (loadingState) {
|
||||
Loading() => loadingWidget,
|
||||
Loading() => skeleton(),
|
||||
Success() => loadingState.response?.isNotEmpty == true
|
||||
? refreshIndicator(
|
||||
onRefresh: () async {
|
||||
await widget.ctr.refreshDynamic();
|
||||
},
|
||||
child: CustomScrollView(
|
||||
physics: const AlwaysScrollableScrollPhysics(),
|
||||
slivers: [
|
||||
SliverPadding(
|
||||
padding: EdgeInsets.only(
|
||||
bottom: MediaQuery.paddingOf(context).bottom + 80,
|
||||
? dynamicsWaterfallFlow
|
||||
? SliverWaterfallFlow.extent(
|
||||
maxCrossAxisExtent: Grid.smallCardWidth * 2,
|
||||
crossAxisSpacing: StyleString.safeSpace,
|
||||
mainAxisSpacing: StyleString.safeSpace,
|
||||
lastChildLayoutTypeBuilder: (index) {
|
||||
if (index == loadingState.response!.length - 1) {
|
||||
EasyThrottle.throttle(
|
||||
'member_dynamics', const Duration(milliseconds: 1000),
|
||||
() {
|
||||
widget.ctr.searchDynamic(false);
|
||||
});
|
||||
}
|
||||
return index == loadingState.response!.length
|
||||
? LastChildLayoutType.foot
|
||||
: LastChildLayoutType.none;
|
||||
},
|
||||
children: (loadingState.response as List)
|
||||
.map((item) => DynamicPanel(item: item))
|
||||
.toList(),
|
||||
)
|
||||
: SliverCrossAxisGroup(
|
||||
slivers: [
|
||||
const SliverFillRemaining(),
|
||||
SliverConstrainedCrossAxis(
|
||||
maxExtent: Grid.smallCardWidth * 2,
|
||||
sliver: SliverList(
|
||||
delegate: SliverChildBuilderDelegate(
|
||||
(context, index) {
|
||||
if (index == loadingState.response!.length - 1) {
|
||||
EasyThrottle.throttle('member_dynamics',
|
||||
const Duration(milliseconds: 1000), () {
|
||||
widget.ctr.searchDynamic(false);
|
||||
});
|
||||
}
|
||||
return DynamicPanel(
|
||||
item: loadingState.response![index],
|
||||
);
|
||||
},
|
||||
childCount: loadingState.response!.length,
|
||||
),
|
||||
),
|
||||
),
|
||||
sliver: dynamicsWaterfallFlow
|
||||
? SliverWaterfallFlow.extent(
|
||||
maxCrossAxisExtent: Grid.smallCardWidth * 2,
|
||||
crossAxisSpacing: StyleString.safeSpace,
|
||||
mainAxisSpacing: StyleString.safeSpace,
|
||||
lastChildLayoutTypeBuilder: (index) {
|
||||
if (index == loadingState.response!.length - 1) {
|
||||
EasyThrottle.throttle('member_dynamics',
|
||||
const Duration(milliseconds: 1000), () {
|
||||
widget.ctr.searchDynamic(false);
|
||||
});
|
||||
}
|
||||
return index == loadingState.response!.length
|
||||
? LastChildLayoutType.foot
|
||||
: LastChildLayoutType.none;
|
||||
},
|
||||
children: (loadingState.response as List)
|
||||
.map((item) => DynamicPanel(item: item))
|
||||
.toList(),
|
||||
)
|
||||
: SliverCrossAxisGroup(
|
||||
slivers: [
|
||||
const SliverFillRemaining(),
|
||||
SliverConstrainedCrossAxis(
|
||||
maxExtent: Grid.smallCardWidth * 2,
|
||||
sliver: SliverList(
|
||||
delegate: SliverChildBuilderDelegate(
|
||||
(context, index) {
|
||||
if (index ==
|
||||
loadingState.response!.length - 1) {
|
||||
EasyThrottle.throttle('member_dynamics',
|
||||
const Duration(milliseconds: 1000),
|
||||
() {
|
||||
widget.ctr.searchDynamic(false);
|
||||
});
|
||||
}
|
||||
return DynamicPanel(
|
||||
item: loadingState.response![index],
|
||||
);
|
||||
},
|
||||
childCount: loadingState.response!.length,
|
||||
),
|
||||
),
|
||||
),
|
||||
const SliverFillRemaining(),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
)
|
||||
: errorWidget(
|
||||
const SliverFillRemaining(),
|
||||
],
|
||||
)
|
||||
: HttpError(
|
||||
callback: () {
|
||||
widget.ctr.dynamicState.value = LoadingState.loading();
|
||||
widget.ctr.refreshDynamic();
|
||||
},
|
||||
),
|
||||
Error() => errorWidget(
|
||||
Error() => HttpError(
|
||||
errMsg: loadingState.errMsg,
|
||||
callback: () {
|
||||
widget.ctr.dynamicState.value = LoadingState.loading();
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import 'package:PiliPlus/common/skeleton/msg_feed_top.dart';
|
||||
import 'package:PiliPlus/common/widgets/dialog.dart';
|
||||
import 'package:PiliPlus/common/widgets/loading_widget.dart';
|
||||
import 'package:PiliPlus/common/widgets/http_error.dart';
|
||||
import 'package:PiliPlus/common/widgets/network_img_layer.dart';
|
||||
import 'package:PiliPlus/common/widgets/refresh_indicator.dart';
|
||||
import 'package:PiliPlus/http/loading_state.dart';
|
||||
@@ -31,20 +32,31 @@ class _AtMePageState extends State<AtMePage> {
|
||||
onRefresh: () async {
|
||||
await _atMeController.onRefresh();
|
||||
},
|
||||
child: Obx(() => _buildBody(_atMeController.loadingState.value)),
|
||||
child: CustomScrollView(
|
||||
physics: const AlwaysScrollableScrollPhysics(),
|
||||
slivers: [
|
||||
SliverPadding(
|
||||
padding: EdgeInsets.only(
|
||||
bottom: MediaQuery.paddingOf(context).bottom + 80),
|
||||
sliver: Obx(() => _buildBody(_atMeController.loadingState.value)),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildBody(LoadingState<List<AtMeItems>?> loadingState) {
|
||||
return switch (loadingState) {
|
||||
Loading() => loadingWidget,
|
||||
Loading() => SliverList.builder(
|
||||
itemCount: 12,
|
||||
itemBuilder: (context, index) {
|
||||
return const MsgFeedTopSkeleton();
|
||||
},
|
||||
),
|
||||
Success() => loadingState.response?.isNotEmpty == true
|
||||
? ListView.separated(
|
||||
? SliverList.separated(
|
||||
itemCount: loadingState.response!.length,
|
||||
physics: const AlwaysScrollableScrollPhysics(),
|
||||
padding: EdgeInsets.only(
|
||||
bottom: MediaQuery.paddingOf(context).bottom + 80),
|
||||
itemBuilder: (context, int index) {
|
||||
if (index == loadingState.response!.length - 1) {
|
||||
_atMeController.onLoadMore();
|
||||
@@ -145,8 +157,8 @@ class _AtMePageState extends State<AtMePage> {
|
||||
);
|
||||
},
|
||||
)
|
||||
: scrollErrorWidget(callback: _atMeController.onReload),
|
||||
Error() => scrollErrorWidget(
|
||||
: HttpError(callback: _atMeController.onReload),
|
||||
Error() => HttpError(
|
||||
errMsg: loadingState.errMsg,
|
||||
callback: _atMeController.onReload,
|
||||
),
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import 'package:PiliPlus/common/skeleton/msg_feed_top.dart';
|
||||
import 'package:PiliPlus/common/widgets/dialog.dart';
|
||||
import 'package:PiliPlus/common/widgets/loading_widget.dart';
|
||||
import 'package:PiliPlus/common/widgets/http_error.dart';
|
||||
import 'package:PiliPlus/common/widgets/pair.dart';
|
||||
import 'package:PiliPlus/common/widgets/refresh_indicator.dart';
|
||||
import 'package:PiliPlus/http/loading_state.dart';
|
||||
@@ -32,22 +33,36 @@ class _LikeMePageState extends State<LikeMePage> {
|
||||
onRefresh: () async {
|
||||
await _likeMeController.onRefresh();
|
||||
},
|
||||
child: Obx(() => _buildBody(_likeMeController.loadingState.value)),
|
||||
child: CustomScrollView(
|
||||
physics: const AlwaysScrollableScrollPhysics(),
|
||||
slivers: [
|
||||
SliverPadding(
|
||||
padding: EdgeInsets.only(
|
||||
bottom: MediaQuery.paddingOf(context).bottom + 80),
|
||||
sliver:
|
||||
Obx(() => _buildBody(_likeMeController.loadingState.value)),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildBody(LoadingState loadingState) {
|
||||
return switch (loadingState) {
|
||||
Loading() => loadingWidget,
|
||||
Loading() => SliverList.builder(
|
||||
itemCount: 12,
|
||||
itemBuilder: (context, index) {
|
||||
return const MsgFeedTopSkeleton();
|
||||
},
|
||||
),
|
||||
Success() => () {
|
||||
Pair<List<LikeMeItems>, List<LikeMeItems>> pair =
|
||||
loadingState.response;
|
||||
List<LikeMeItems> latest = pair.first;
|
||||
List<LikeMeItems> total = pair.second;
|
||||
if (latest.isNotEmpty || total.isNotEmpty) {
|
||||
return CustomScrollView(
|
||||
physics: const AlwaysScrollableScrollPhysics(),
|
||||
return SliverMainAxisGroup(
|
||||
slivers: [
|
||||
if (latest.isNotEmpty) ...[
|
||||
_buildHeader('最新'),
|
||||
@@ -99,17 +114,12 @@ class _LikeMePageState extends State<LikeMePage> {
|
||||
},
|
||||
),
|
||||
],
|
||||
SliverToBoxAdapter(
|
||||
child: SizedBox(
|
||||
height: MediaQuery.paddingOf(context).bottom + 80,
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
return scrollErrorWidget(callback: _likeMeController.onReload);
|
||||
return HttpError(callback: _likeMeController.onReload);
|
||||
}(),
|
||||
Error() => scrollErrorWidget(
|
||||
Error() => HttpError(
|
||||
errMsg: loadingState.errMsg,
|
||||
callback: _likeMeController.onReload,
|
||||
),
|
||||
@@ -118,14 +128,18 @@ class _LikeMePageState extends State<LikeMePage> {
|
||||
}
|
||||
|
||||
Widget _buildHeader(String title) {
|
||||
return SliverToBoxAdapter(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(left: 16),
|
||||
child: Text(
|
||||
title,
|
||||
style: Theme.of(context).textTheme.labelLarge!.copyWith(
|
||||
color: Theme.of(context).colorScheme.secondary,
|
||||
),
|
||||
return SliverSafeArea(
|
||||
top: false,
|
||||
bottom: false,
|
||||
sliver: SliverToBoxAdapter(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(left: 16),
|
||||
child: Text(
|
||||
title,
|
||||
style: Theme.of(context).textTheme.labelLarge!.copyWith(
|
||||
color: Theme.of(context).colorScheme.secondary,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import 'package:PiliPlus/common/skeleton/msg_feed_top.dart';
|
||||
import 'package:PiliPlus/common/widgets/dialog.dart';
|
||||
import 'package:PiliPlus/common/widgets/loading_widget.dart';
|
||||
import 'package:PiliPlus/common/widgets/http_error.dart';
|
||||
import 'package:PiliPlus/common/widgets/refresh_indicator.dart';
|
||||
import 'package:PiliPlus/http/loading_state.dart';
|
||||
import 'package:PiliPlus/models/msg/msgfeed_reply_me.dart';
|
||||
@@ -29,20 +30,32 @@ class _ReplyMePageState extends State<ReplyMePage> {
|
||||
onRefresh: () async {
|
||||
await _replyMeController.onRefresh();
|
||||
},
|
||||
child: Obx(() => _buildBody(_replyMeController.loadingState.value)),
|
||||
child: CustomScrollView(
|
||||
physics: const AlwaysScrollableScrollPhysics(),
|
||||
slivers: [
|
||||
SliverPadding(
|
||||
padding: EdgeInsets.only(
|
||||
bottom: MediaQuery.paddingOf(context).bottom + 80),
|
||||
sliver:
|
||||
Obx(() => _buildBody(_replyMeController.loadingState.value)),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildBody(LoadingState<List<ReplyMeItems>?> loadingState) {
|
||||
return switch (loadingState) {
|
||||
Loading() => loadingWidget,
|
||||
Loading() => SliverList.builder(
|
||||
itemCount: 12,
|
||||
itemBuilder: (context, index) {
|
||||
return const MsgFeedTopSkeleton();
|
||||
},
|
||||
),
|
||||
Success() => loadingState.response?.isNotEmpty == true
|
||||
? ListView.separated(
|
||||
? SliverList.separated(
|
||||
itemCount: loadingState.response!.length,
|
||||
physics: const AlwaysScrollableScrollPhysics(),
|
||||
padding: EdgeInsets.only(
|
||||
bottom: MediaQuery.paddingOf(context).bottom + 80),
|
||||
itemBuilder: (context, int index) {
|
||||
if (index == loadingState.response!.length - 1) {
|
||||
_replyMeController.onLoadMore();
|
||||
@@ -165,8 +178,8 @@ class _ReplyMePageState extends State<ReplyMePage> {
|
||||
);
|
||||
},
|
||||
)
|
||||
: scrollErrorWidget(callback: _replyMeController.onReload),
|
||||
Error() => scrollErrorWidget(
|
||||
: HttpError(callback: _replyMeController.onReload),
|
||||
Error() => HttpError(
|
||||
errMsg: loadingState.errMsg,
|
||||
callback: _replyMeController.onReload,
|
||||
),
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:PiliPlus/common/skeleton/msg_feed_sys_msg_.dart';
|
||||
import 'package:PiliPlus/common/widgets/dialog.dart';
|
||||
import 'package:PiliPlus/common/widgets/loading_widget.dart';
|
||||
import 'package:PiliPlus/common/widgets/http_error.dart';
|
||||
import 'package:PiliPlus/common/widgets/refresh_indicator.dart';
|
||||
import 'package:PiliPlus/http/loading_state.dart';
|
||||
import 'package:PiliPlus/models/msg/msgfeed_sys_msg.dart';
|
||||
@@ -36,25 +37,36 @@ class _SysMsgPageState extends State<SysMsgPage> {
|
||||
onRefresh: () async {
|
||||
await _sysMsgController.onRefresh();
|
||||
},
|
||||
child: Obx(() => _buildBody(_sysMsgController.loadingState.value)),
|
||||
child: CustomScrollView(
|
||||
physics: const AlwaysScrollableScrollPhysics(),
|
||||
slivers: [
|
||||
SliverPadding(
|
||||
padding: EdgeInsets.only(
|
||||
bottom: MediaQuery.paddingOf(context).bottom + 80),
|
||||
sliver:
|
||||
Obx(() => _buildBody(_sysMsgController.loadingState.value)),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildBody(LoadingState<List<SystemNotifyList>?> loadingState) {
|
||||
return switch (loadingState) {
|
||||
Loading() => loadingWidget,
|
||||
Loading() => SliverList.builder(
|
||||
itemCount: 12,
|
||||
itemBuilder: (context, index) {
|
||||
return const MsgFeedSysMsgSkeleton();
|
||||
},
|
||||
),
|
||||
Success() => loadingState.response?.isNotEmpty == true
|
||||
? ListView.separated(
|
||||
? SliverList.separated(
|
||||
itemCount: loadingState.response!.length,
|
||||
physics: const AlwaysScrollableScrollPhysics(),
|
||||
padding: EdgeInsets.only(
|
||||
bottom: MediaQuery.paddingOf(context).bottom + 80),
|
||||
itemBuilder: (context, int index) {
|
||||
if (index == loadingState.response!.length - 1) {
|
||||
_sysMsgController.onLoadMore();
|
||||
}
|
||||
|
||||
final item = loadingState.response![index];
|
||||
String? content = item.content;
|
||||
if (content != null) {
|
||||
@@ -124,8 +136,8 @@ class _SysMsgPageState extends State<SysMsgPage> {
|
||||
);
|
||||
},
|
||||
)
|
||||
: scrollErrorWidget(callback: _sysMsgController.onReload),
|
||||
Error() => scrollErrorWidget(
|
||||
: HttpError(callback: _sysMsgController.onReload),
|
||||
Error() => HttpError(
|
||||
errMsg: loadingState.errMsg,
|
||||
callback: _sysMsgController.onReload,
|
||||
),
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import 'package:PiliPlus/common/constants.dart';
|
||||
import 'package:PiliPlus/common/skeleton/media_bangumi.dart';
|
||||
import 'package:PiliPlus/common/skeleton/msg_feed_top.dart';
|
||||
import 'package:PiliPlus/common/skeleton/video_card_h.dart';
|
||||
import 'package:PiliPlus/common/skeleton/video_card_v.dart';
|
||||
import 'package:PiliPlus/common/widgets/http_error.dart';
|
||||
import 'package:PiliPlus/common/widgets/refresh_indicator.dart';
|
||||
import 'package:PiliPlus/http/loading_state.dart';
|
||||
@@ -64,32 +66,57 @@ abstract class CommonSearchPanelState<
|
||||
|
||||
Widget get _builLoading {
|
||||
return SliverGrid(
|
||||
gridDelegate: widget.searchType == SearchType.media_bangumi ||
|
||||
widget.searchType == SearchType.media_ft
|
||||
? SliverGridDelegateWithExtentAndRatio(
|
||||
mainAxisSpacing: 2,
|
||||
maxCrossAxisExtent: Grid.smallCardWidth * 2,
|
||||
childAspectRatio: StyleString.aspectRatio * 1.5,
|
||||
minHeight: MediaQuery.textScalerOf(context).scale(155),
|
||||
)
|
||||
: Grid.videoCardHDelegate(context),
|
||||
gridDelegate: switch (widget.searchType) {
|
||||
SearchType.media_bangumi ||
|
||||
SearchType.media_ft =>
|
||||
SliverGridDelegateWithExtentAndRatio(
|
||||
mainAxisSpacing: 2,
|
||||
maxCrossAxisExtent: Grid.smallCardWidth * 2,
|
||||
childAspectRatio: StyleString.aspectRatio * 1.5,
|
||||
minHeight: MediaQuery.textScalerOf(context).scale(155),
|
||||
),
|
||||
SearchType.live_room => SliverGridDelegateWithExtentAndRatio(
|
||||
mainAxisSpacing: StyleString.cardSpace,
|
||||
crossAxisSpacing: StyleString.cardSpace,
|
||||
maxCrossAxisExtent: Grid.smallCardWidth,
|
||||
childAspectRatio: StyleString.aspectRatio,
|
||||
mainAxisExtent: MediaQuery.textScalerOf(context).scale(90),
|
||||
),
|
||||
SearchType.bili_user => SliverGridDelegateWithMaxCrossAxisExtent(
|
||||
maxCrossAxisExtent: Grid.smallCardWidth * 2,
|
||||
mainAxisExtent: 66,
|
||||
),
|
||||
_ => Grid.videoCardHDelegate(context),
|
||||
},
|
||||
delegate: SliverChildBuilderDelegate(
|
||||
(context, index) {
|
||||
switch (widget.searchType) {
|
||||
case SearchType.media_bangumi || SearchType.media_ft:
|
||||
return const MediaBangumiSkeleton();
|
||||
case SearchType.bili_user:
|
||||
return const MsgFeedTopSkeleton();
|
||||
case SearchType.live_room:
|
||||
return const VideoCardVSkeleton();
|
||||
default:
|
||||
return const VideoCardHSkeleton();
|
||||
}
|
||||
},
|
||||
childCount: 15,
|
||||
childCount: 16,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildBody(LoadingState<List<T>?> loadingState) {
|
||||
return switch (loadingState) {
|
||||
Loading() => _builLoading,
|
||||
Loading() => widget.searchType == SearchType.live_room
|
||||
? SliverPadding(
|
||||
padding: const EdgeInsets.only(
|
||||
left: StyleString.cardSpace,
|
||||
right: StyleString.cardSpace,
|
||||
),
|
||||
sliver: _builLoading,
|
||||
)
|
||||
: _builLoading,
|
||||
Success() => loadingState.response?.isNotEmpty == true
|
||||
? buildList(loadingState.response!)
|
||||
: HttpError(
|
||||
|
||||
@@ -28,7 +28,8 @@ class _RelatedVideoPanelState extends State<RelatedVideoPanel>
|
||||
Widget build(BuildContext context) {
|
||||
super.build(context);
|
||||
return SliverPadding(
|
||||
padding: const EdgeInsets.only(top: StyleString.safeSpace - 5),
|
||||
padding:
|
||||
const EdgeInsets.only(top: StyleString.safeSpace - 5, bottom: 80),
|
||||
sliver: Obx(() => _buildBody(_relatedController.loadingState.value)),
|
||||
);
|
||||
}
|
||||
@@ -45,17 +46,14 @@ class _RelatedVideoPanelState extends State<RelatedVideoPanel>
|
||||
),
|
||||
),
|
||||
Success() => loadingState.response?.isNotEmpty == true
|
||||
? SliverPadding(
|
||||
padding: const EdgeInsets.only(bottom: 80),
|
||||
sliver: SliverGrid(
|
||||
gridDelegate: Grid.videoCardHDelegate(context),
|
||||
delegate: SliverChildBuilderDelegate((context, index) {
|
||||
return VideoCardH(
|
||||
videoItem: loadingState.response![index],
|
||||
showPubdate: true,
|
||||
);
|
||||
}, childCount: loadingState.response!.length),
|
||||
),
|
||||
? SliverGrid(
|
||||
gridDelegate: Grid.videoCardHDelegate(context),
|
||||
delegate: SliverChildBuilderDelegate((context, index) {
|
||||
return VideoCardH(
|
||||
videoItem: loadingState.response![index],
|
||||
showPubdate: true,
|
||||
);
|
||||
}, childCount: loadingState.response!.length),
|
||||
)
|
||||
: const SliverToBoxAdapter(),
|
||||
Error() => HttpError(
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import 'package:PiliPlus/common/skeleton/whisper_item.dart';
|
||||
import 'package:PiliPlus/common/widgets/http_error.dart';
|
||||
import 'package:PiliPlus/common/widgets/refresh_indicator.dart';
|
||||
import 'package:PiliPlus/http/loading_state.dart';
|
||||
@@ -44,7 +45,12 @@ class _WhisperPageState extends State<WhisperPage> {
|
||||
|
||||
Widget _buildBody(LoadingState<List<SessionList>?> loadingState) {
|
||||
return switch (loadingState) {
|
||||
Loading() => const SliverToBoxAdapter(),
|
||||
Loading() => SliverList.builder(
|
||||
itemCount: 12,
|
||||
itemBuilder: (context, index) {
|
||||
return const WhisperItemSkeleton();
|
||||
},
|
||||
),
|
||||
Success() => loadingState.response?.isNotEmpty == true
|
||||
? SliverPadding(
|
||||
padding: EdgeInsets.only(
|
||||
@@ -85,58 +91,58 @@ class _WhisperPageState extends State<WhisperPage> {
|
||||
}
|
||||
|
||||
Widget get _buildTopItems => SliverToBoxAdapter(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 20),
|
||||
child: Row(
|
||||
children: List.generate(_whisperController.msgFeedTopItems.length,
|
||||
(index) {
|
||||
return Expanded(
|
||||
child: GestureDetector(
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Obx(
|
||||
() => Badge(
|
||||
isLabelVisible:
|
||||
_whisperController.unreadCounts[index] > 0,
|
||||
label: Text(
|
||||
" ${_whisperController.unreadCounts[index]} "),
|
||||
alignment: Alignment.topRight,
|
||||
child: CircleAvatar(
|
||||
radius: 22,
|
||||
backgroundColor:
|
||||
Theme.of(context).colorScheme.onInverseSurface,
|
||||
child: Icon(
|
||||
_whisperController.msgFeedTopItems[index]['icon'],
|
||||
size: 20,
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||
children:
|
||||
List.generate(_whisperController.msgFeedTopItems.length, (index) {
|
||||
return GestureDetector(
|
||||
behavior: HitTestBehavior.opaque,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(10),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Obx(
|
||||
() => Badge(
|
||||
isLabelVisible:
|
||||
_whisperController.unreadCounts[index] > 0,
|
||||
label:
|
||||
Text(" ${_whisperController.unreadCounts[index]} "),
|
||||
alignment: Alignment.topRight,
|
||||
child: CircleAvatar(
|
||||
radius: 22,
|
||||
backgroundColor:
|
||||
Theme.of(context).colorScheme.onInverseSurface,
|
||||
child: Icon(
|
||||
_whisperController.msgFeedTopItems[index]['icon'],
|
||||
size: 20,
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 6),
|
||||
Text(
|
||||
_whisperController.msgFeedTopItems[index]['name'],
|
||||
style: const TextStyle(fontSize: 13),
|
||||
),
|
||||
],
|
||||
),
|
||||
onTap: () {
|
||||
if (!_whisperController.msgFeedTopItems[index]['enabled']) {
|
||||
SmartDialog.showToast('已禁用');
|
||||
return;
|
||||
}
|
||||
_whisperController.unreadCounts[index] = 0;
|
||||
Get.toNamed(
|
||||
_whisperController.msgFeedTopItems[index]['route'],
|
||||
);
|
||||
},
|
||||
),
|
||||
const SizedBox(height: 6),
|
||||
Text(
|
||||
_whisperController.msgFeedTopItems[index]['name'],
|
||||
style: const TextStyle(fontSize: 13),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}).toList(),
|
||||
),
|
||||
),
|
||||
onTap: () {
|
||||
if (!_whisperController.msgFeedTopItems[index]['enabled']) {
|
||||
SmartDialog.showToast('已禁用');
|
||||
return;
|
||||
}
|
||||
_whisperController.unreadCounts[index] = 0;
|
||||
Get.toNamed(
|
||||
_whisperController.msgFeedTopItems[index]['route'],
|
||||
);
|
||||
},
|
||||
);
|
||||
}).toList(),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user