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