mirror of
https://github.com/bggRGjQaUbCoE/PiliPlus.git
synced 2026-06-10 13:04:50 +08:00
@@ -196,8 +196,11 @@ class _BangumiPageState extends CommonPageState<BangumiPage, BangumiController>
|
||||
List<Widget> _buildRcmd(ThemeData theme) => [
|
||||
_buildRcmdTitle(theme),
|
||||
SliverPadding(
|
||||
padding: const EdgeInsets.fromLTRB(
|
||||
StyleString.safeSpace, 0, StyleString.safeSpace, 0),
|
||||
padding: EdgeInsets.only(
|
||||
left: StyleString.safeSpace,
|
||||
right: StyleString.safeSpace,
|
||||
bottom: MediaQuery.paddingOf(context).bottom + 80,
|
||||
),
|
||||
sliver: Obx(
|
||||
() => _buildRcmdBody(controller.loadingState.value),
|
||||
),
|
||||
@@ -330,11 +333,15 @@ class _BangumiPageState extends CommonPageState<BangumiPage, BangumiController>
|
||||
? Column(
|
||||
children: [
|
||||
_buildFollowTitle(theme),
|
||||
SizedBox(
|
||||
height: Grid.smallCardWidth / 2 / 0.75 +
|
||||
MediaQuery.textScalerOf(context).scale(50),
|
||||
child: Obx(
|
||||
() => _buildFollowBody(controller.followState.value),
|
||||
MediaQuery.removePadding(
|
||||
context: context,
|
||||
removeLeft: context.orientation == Orientation.landscape,
|
||||
child: SizedBox(
|
||||
height: Grid.smallCardWidth / 2 / 0.75 +
|
||||
MediaQuery.textScalerOf(context).scale(50),
|
||||
child: Obx(
|
||||
() => _buildFollowBody(controller.followState.value),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
@@ -415,31 +422,27 @@ class _BangumiPageState extends CommonPageState<BangumiPage, BangumiController>
|
||||
return switch (loadingState) {
|
||||
Loading() => loadingWidget,
|
||||
Success(:var response) => response?.isNotEmpty == true
|
||||
? MediaQuery.removePadding(
|
||||
context: context,
|
||||
removeLeft: context.orientation == Orientation.landscape,
|
||||
child: ListView.builder(
|
||||
controller: controller.followController,
|
||||
scrollDirection: Axis.horizontal,
|
||||
itemCount: response!.length,
|
||||
itemBuilder: (context, index) {
|
||||
if (index == response.length - 1) {
|
||||
controller.queryBangumiFollow(false);
|
||||
}
|
||||
return Container(
|
||||
width: Grid.smallCardWidth / 2,
|
||||
margin: EdgeInsets.only(
|
||||
left: StyleString.safeSpace,
|
||||
right: index == response.length - 1
|
||||
? StyleString.safeSpace
|
||||
: 0,
|
||||
),
|
||||
child: BangumiCardV(
|
||||
bangumiItem: response[index],
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
? ListView.builder(
|
||||
controller: controller.followController,
|
||||
scrollDirection: Axis.horizontal,
|
||||
itemCount: response!.length,
|
||||
itemBuilder: (context, index) {
|
||||
if (index == response.length - 1) {
|
||||
controller.queryBangumiFollow(false);
|
||||
}
|
||||
return Container(
|
||||
width: Grid.smallCardWidth / 2,
|
||||
margin: EdgeInsets.only(
|
||||
left: StyleString.safeSpace,
|
||||
right: index == response.length - 1
|
||||
? StyleString.safeSpace
|
||||
: 0,
|
||||
),
|
||||
child: BangumiCardV(
|
||||
bangumiItem: response[index],
|
||||
),
|
||||
);
|
||||
},
|
||||
)
|
||||
: Center(
|
||||
child: Text(
|
||||
|
||||
@@ -46,7 +46,12 @@ class _BlackListPageState extends State<BlackListPage> {
|
||||
physics: const AlwaysScrollableScrollPhysics(),
|
||||
controller: _blackListController.scrollController,
|
||||
slivers: [
|
||||
Obx(() => _buildBody(_blackListController.loadingState.value))
|
||||
SliverPadding(
|
||||
padding: EdgeInsets.only(
|
||||
bottom: MediaQuery.paddingOf(context).bottom + 80),
|
||||
sliver: Obx(
|
||||
() => _buildBody(_blackListController.loadingState.value)),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
@@ -55,7 +55,12 @@ abstract class CommonSearchPageState<S extends CommonSearchPage, R, T>
|
||||
physics: const AlwaysScrollableScrollPhysics(),
|
||||
controller: controller.scrollController,
|
||||
slivers: [
|
||||
Obx(() => _buildBody(controller.loadingState.value)),
|
||||
SliverPadding(
|
||||
padding: EdgeInsets.only(
|
||||
bottom: MediaQuery.of(context).padding.bottom + 80,
|
||||
),
|
||||
sliver: Obx(() => _buildBody(controller.loadingState.value)),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
@@ -124,7 +124,12 @@ class _DynamicsTabPageState
|
||||
physics: const AlwaysScrollableScrollPhysics(),
|
||||
controller: controller.scrollController,
|
||||
slivers: [
|
||||
Obx(() => _buildBody(controller.loadingState.value)),
|
||||
SliverPadding(
|
||||
padding: EdgeInsets.only(
|
||||
bottom: MediaQuery.paddingOf(context).bottom + 80,
|
||||
),
|
||||
sliver: Obx(() => _buildBody(controller.loadingState.value)),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
@@ -134,57 +139,51 @@ class _DynamicsTabPageState
|
||||
return switch (loadingState) {
|
||||
Loading() => DynamicsTabPage.dynSkeleton(dynamicsWaterfallFlow),
|
||||
Success(:var response) => response?.isNotEmpty == true
|
||||
? SliverPadding(
|
||||
padding: EdgeInsets.only(
|
||||
bottom: MediaQuery.paddingOf(context).bottom + 80,
|
||||
),
|
||||
sliver: dynamicsWaterfallFlow
|
||||
? SliverWaterfallFlow.extent(
|
||||
maxCrossAxisExtent: Grid.smallCardWidth * 2,
|
||||
crossAxisSpacing: StyleString.cardSpace / 2,
|
||||
lastChildLayoutTypeBuilder: (index) {
|
||||
if (index == response.length - 1) {
|
||||
controller.onLoadMore();
|
||||
}
|
||||
return index == response.length
|
||||
? LastChildLayoutType.foot
|
||||
: LastChildLayoutType.none;
|
||||
},
|
||||
children: [
|
||||
for (int index = 0; index < response!.length; index++)
|
||||
DynamicPanel(
|
||||
item: response[index],
|
||||
? dynamicsWaterfallFlow
|
||||
? SliverWaterfallFlow.extent(
|
||||
maxCrossAxisExtent: Grid.smallCardWidth * 2,
|
||||
crossAxisSpacing: StyleString.cardSpace / 2,
|
||||
lastChildLayoutTypeBuilder: (index) {
|
||||
if (index == response.length - 1) {
|
||||
controller.onLoadMore();
|
||||
}
|
||||
return index == response.length
|
||||
? LastChildLayoutType.foot
|
||||
: LastChildLayoutType.none;
|
||||
},
|
||||
children: [
|
||||
for (int index = 0; index < response!.length; index++)
|
||||
DynamicPanel(
|
||||
item: response[index],
|
||||
onRemove: (idStr) => controller.onRemove(index, idStr),
|
||||
onBlock: () => controller.onBlock(index),
|
||||
)
|
||||
],
|
||||
)
|
||||
: SliverCrossAxisGroup(
|
||||
slivers: [
|
||||
const SliverFillRemaining(),
|
||||
SliverConstrainedCrossAxis(
|
||||
maxExtent: Grid.smallCardWidth * 2,
|
||||
sliver: SliverList.builder(
|
||||
itemBuilder: (context, index) {
|
||||
if (index == response.length - 1) {
|
||||
controller.onLoadMore();
|
||||
}
|
||||
final item = response[index];
|
||||
return DynamicPanel(
|
||||
item: item,
|
||||
onRemove: (idStr) =>
|
||||
controller.onRemove(index, idStr),
|
||||
onBlock: () => controller.onBlock(index),
|
||||
)
|
||||
],
|
||||
)
|
||||
: SliverCrossAxisGroup(
|
||||
slivers: [
|
||||
const SliverFillRemaining(),
|
||||
SliverConstrainedCrossAxis(
|
||||
maxExtent: Grid.smallCardWidth * 2,
|
||||
sliver: SliverList.builder(
|
||||
itemBuilder: (context, index) {
|
||||
if (index == response.length - 1) {
|
||||
controller.onLoadMore();
|
||||
}
|
||||
final item = response[index];
|
||||
return DynamicPanel(
|
||||
item: item,
|
||||
onRemove: (idStr) =>
|
||||
controller.onRemove(index, idStr),
|
||||
onBlock: () => controller.onBlock(index),
|
||||
);
|
||||
},
|
||||
itemCount: response!.length,
|
||||
),
|
||||
),
|
||||
const SliverFillRemaining(),
|
||||
],
|
||||
);
|
||||
},
|
||||
itemCount: response!.length,
|
||||
),
|
||||
),
|
||||
)
|
||||
const SliverFillRemaining(),
|
||||
],
|
||||
)
|
||||
: HttpError(
|
||||
onReload: controller.onReload,
|
||||
),
|
||||
|
||||
@@ -109,7 +109,12 @@ class _DynTopicPageState extends State<DynTopicPage> {
|
||||
}
|
||||
return const SliverToBoxAdapter();
|
||||
}),
|
||||
Obx(() => _buildBody(_controller.loadingState.value)),
|
||||
SliverPadding(
|
||||
padding: EdgeInsets.only(
|
||||
bottom: MediaQuery.paddingOf(context).bottom + 80,
|
||||
),
|
||||
sliver: Obx(() => _buildBody(_controller.loadingState.value)),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
@@ -302,56 +307,51 @@ class _DynTopicPageState extends State<DynTopicPage> {
|
||||
return switch (loadingState) {
|
||||
Loading() => DynamicsTabPage.dynSkeleton(dynamicsWaterfallFlow),
|
||||
Success(:var response) => response?.isNotEmpty == true
|
||||
? SliverPadding(
|
||||
padding: EdgeInsets.only(
|
||||
bottom: MediaQuery.paddingOf(context).bottom + 80,
|
||||
),
|
||||
sliver: dynamicsWaterfallFlow
|
||||
? SliverWaterfallFlow.extent(
|
||||
maxCrossAxisExtent: Grid.smallCardWidth * 2,
|
||||
crossAxisSpacing: StyleString.cardSpace / 2,
|
||||
lastChildLayoutTypeBuilder: (index) {
|
||||
if (index == response.length - 1) {
|
||||
_controller.onLoadMore();
|
||||
}
|
||||
return index == response.length
|
||||
? LastChildLayoutType.foot
|
||||
: LastChildLayoutType.none;
|
||||
},
|
||||
children: [
|
||||
for (var item in response!)
|
||||
if (item.dynamicCardItem != null)
|
||||
DynamicPanel(item: item.dynamicCardItem!)
|
||||
else
|
||||
Text(item.topicType ?? 'err'),
|
||||
],
|
||||
)
|
||||
: SliverCrossAxisGroup(
|
||||
slivers: [
|
||||
const SliverFillRemaining(),
|
||||
SliverConstrainedCrossAxis(
|
||||
maxExtent: Grid.smallCardWidth * 2,
|
||||
sliver: SliverList.builder(
|
||||
itemBuilder: (context, index) {
|
||||
if (index == response.length - 1) {
|
||||
_controller.onLoadMore();
|
||||
}
|
||||
final item = response[index];
|
||||
if (item.dynamicCardItem != null) {
|
||||
return DynamicPanel(
|
||||
item: item.dynamicCardItem!,
|
||||
);
|
||||
} else {
|
||||
return Text(item.topicType ?? 'err');
|
||||
}
|
||||
},
|
||||
itemCount: response!.length,
|
||||
),
|
||||
),
|
||||
const SliverFillRemaining(),
|
||||
],
|
||||
? dynamicsWaterfallFlow
|
||||
? SliverWaterfallFlow.extent(
|
||||
maxCrossAxisExtent: Grid.smallCardWidth * 2,
|
||||
crossAxisSpacing: StyleString.cardSpace / 2,
|
||||
lastChildLayoutTypeBuilder: (index) {
|
||||
if (index == response.length - 1) {
|
||||
_controller.onLoadMore();
|
||||
}
|
||||
return index == response.length
|
||||
? LastChildLayoutType.foot
|
||||
: LastChildLayoutType.none;
|
||||
},
|
||||
children: [
|
||||
for (var item in response!)
|
||||
if (item.dynamicCardItem != null)
|
||||
DynamicPanel(item: item.dynamicCardItem!)
|
||||
else
|
||||
Text(item.topicType ?? 'err'),
|
||||
],
|
||||
)
|
||||
: SliverCrossAxisGroup(
|
||||
slivers: [
|
||||
const SliverFillRemaining(),
|
||||
SliverConstrainedCrossAxis(
|
||||
maxExtent: Grid.smallCardWidth * 2,
|
||||
sliver: SliverList.builder(
|
||||
itemBuilder: (context, index) {
|
||||
if (index == response.length - 1) {
|
||||
_controller.onLoadMore();
|
||||
}
|
||||
final item = response[index];
|
||||
if (item.dynamicCardItem != null) {
|
||||
return DynamicPanel(
|
||||
item: item.dynamicCardItem!,
|
||||
);
|
||||
} else {
|
||||
return Text(item.topicType ?? 'err');
|
||||
}
|
||||
},
|
||||
itemCount: response!.length,
|
||||
),
|
||||
),
|
||||
)
|
||||
const SliverFillRemaining(),
|
||||
],
|
||||
)
|
||||
: HttpError(
|
||||
onReload: _controller.onReload,
|
||||
),
|
||||
|
||||
@@ -61,7 +61,12 @@ class _FansPageState extends State<FansPage> {
|
||||
physics: const AlwaysScrollableScrollPhysics(),
|
||||
controller: _fansController.scrollController,
|
||||
slivers: [
|
||||
Obx(() => _buildBody(_fansController.loadingState.value)),
|
||||
SliverPadding(
|
||||
padding: EdgeInsets.only(
|
||||
bottom: MediaQuery.paddingOf(context).bottom + 80),
|
||||
sliver:
|
||||
Obx(() => _buildBody(_fansController.loadingState.value)),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
@@ -84,74 +89,70 @@ class _FansPageState extends State<FansPage> {
|
||||
),
|
||||
),
|
||||
Success(:var response) => response?.isNotEmpty == true
|
||||
? SliverPadding(
|
||||
padding: EdgeInsets.only(
|
||||
bottom: MediaQuery.paddingOf(context).bottom + 80),
|
||||
sliver: SliverGrid(
|
||||
gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent(
|
||||
maxCrossAxisExtent: Grid.smallCardWidth * 2,
|
||||
mainAxisExtent: 66,
|
||||
),
|
||||
delegate: SliverChildBuilderDelegate(
|
||||
(BuildContext context, int index) {
|
||||
if (index == response.length - 1) {
|
||||
_fansController.onLoadMore();
|
||||
}
|
||||
final item = response[index];
|
||||
String heroTag = Utils.makeHeroTag(item.mid);
|
||||
return ListTile(
|
||||
onTap: () {
|
||||
if (widget.onSelect != null) {
|
||||
widget.onSelect!(UserModel(
|
||||
mid: item.mid!,
|
||||
name: item.uname!,
|
||||
avatar: item.face!,
|
||||
));
|
||||
return;
|
||||
}
|
||||
Get.toNamed(
|
||||
'/member?mid=${item.mid}',
|
||||
arguments: {'face': item.face, 'heroTag': heroTag},
|
||||
);
|
||||
},
|
||||
onLongPress: widget.onSelect != null
|
||||
? null
|
||||
: isOwner
|
||||
? () {
|
||||
showConfirmDialog(
|
||||
context: context,
|
||||
title: '确定移除 ${item.uname} ?',
|
||||
onConfirm: () {
|
||||
_fansController.onRemoveFan(
|
||||
index, item.mid!);
|
||||
},
|
||||
);
|
||||
}
|
||||
: null,
|
||||
leading: Hero(
|
||||
tag: heroTag,
|
||||
child: NetworkImgLayer(
|
||||
width: 45,
|
||||
height: 45,
|
||||
type: ImageType.avatar,
|
||||
src: item.face,
|
||||
),
|
||||
? SliverGrid(
|
||||
gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent(
|
||||
maxCrossAxisExtent: Grid.smallCardWidth * 2,
|
||||
mainAxisExtent: 66,
|
||||
),
|
||||
delegate: SliverChildBuilderDelegate(
|
||||
(BuildContext context, int index) {
|
||||
if (index == response.length - 1) {
|
||||
_fansController.onLoadMore();
|
||||
}
|
||||
final item = response[index];
|
||||
String heroTag = Utils.makeHeroTag(item.mid);
|
||||
return ListTile(
|
||||
onTap: () {
|
||||
if (widget.onSelect != null) {
|
||||
widget.onSelect!(UserModel(
|
||||
mid: item.mid!,
|
||||
name: item.uname!,
|
||||
avatar: item.face!,
|
||||
));
|
||||
return;
|
||||
}
|
||||
Get.toNamed(
|
||||
'/member?mid=${item.mid}',
|
||||
arguments: {'face': item.face, 'heroTag': heroTag},
|
||||
);
|
||||
},
|
||||
onLongPress: widget.onSelect != null
|
||||
? null
|
||||
: isOwner
|
||||
? () {
|
||||
showConfirmDialog(
|
||||
context: context,
|
||||
title: '确定移除 ${item.uname} ?',
|
||||
onConfirm: () {
|
||||
_fansController.onRemoveFan(
|
||||
index, item.mid!);
|
||||
},
|
||||
);
|
||||
}
|
||||
: null,
|
||||
leading: Hero(
|
||||
tag: heroTag,
|
||||
child: NetworkImgLayer(
|
||||
width: 45,
|
||||
height: 45,
|
||||
type: ImageType.avatar,
|
||||
src: item.face,
|
||||
),
|
||||
title: Text(
|
||||
item.uname!,
|
||||
style: const TextStyle(fontSize: 14),
|
||||
),
|
||||
subtitle: Text(
|
||||
item.sign ?? '',
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
dense: true,
|
||||
trailing: const SizedBox(width: 6),
|
||||
);
|
||||
},
|
||||
childCount: response!.length,
|
||||
),
|
||||
),
|
||||
title: Text(
|
||||
item.uname!,
|
||||
style: const TextStyle(fontSize: 14),
|
||||
),
|
||||
subtitle: Text(
|
||||
item.sign ?? '',
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
dense: true,
|
||||
trailing: const SizedBox(width: 6),
|
||||
);
|
||||
},
|
||||
childCount: response!.length,
|
||||
),
|
||||
)
|
||||
: HttpError(
|
||||
|
||||
@@ -37,7 +37,12 @@ class _FavNoteChildPageState extends State<FavNoteChildPage>
|
||||
onRefresh: _favNoteController.onRefresh,
|
||||
child: CustomScrollView(
|
||||
slivers: [
|
||||
Obx(() => _buildBody(_favNoteController.loadingState.value)),
|
||||
SliverPadding(
|
||||
padding: EdgeInsets.only(
|
||||
bottom: MediaQuery.paddingOf(context).bottom + 80),
|
||||
sliver: Obx(
|
||||
() => _buildBody(_favNoteController.loadingState.value)),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
@@ -139,26 +144,22 @@ class _FavNoteChildPageState extends State<FavNoteChildPage>
|
||||
),
|
||||
),
|
||||
Success(:var response) => response?.isNotEmpty == true
|
||||
? SliverPadding(
|
||||
padding: EdgeInsets.only(
|
||||
bottom: MediaQuery.paddingOf(context).bottom + 80),
|
||||
sliver: SliverGrid(
|
||||
gridDelegate: Grid.videoCardHDelegate(context),
|
||||
delegate: SliverChildBuilderDelegate(
|
||||
(context, index) {
|
||||
if (index == response.length - 1) {
|
||||
_favNoteController.onLoadMore();
|
||||
}
|
||||
return FavNoteItem(
|
||||
item: response[index],
|
||||
ctr: _favNoteController,
|
||||
onSelect: () {
|
||||
_favNoteController.onSelect(index);
|
||||
},
|
||||
);
|
||||
},
|
||||
childCount: response!.length,
|
||||
),
|
||||
? SliverGrid(
|
||||
gridDelegate: Grid.videoCardHDelegate(context),
|
||||
delegate: SliverChildBuilderDelegate(
|
||||
(context, index) {
|
||||
if (index == response.length - 1) {
|
||||
_favNoteController.onLoadMore();
|
||||
}
|
||||
return FavNoteItem(
|
||||
item: response[index],
|
||||
ctr: _favNoteController,
|
||||
onSelect: () {
|
||||
_favNoteController.onSelect(index);
|
||||
},
|
||||
);
|
||||
},
|
||||
childCount: response!.length,
|
||||
),
|
||||
)
|
||||
: HttpError(onReload: _favNoteController.onReload),
|
||||
|
||||
@@ -44,7 +44,12 @@ class _FavPgcChildPageState extends State<FavPgcChildPage>
|
||||
onRefresh: _favPgcController.onRefresh,
|
||||
child: CustomScrollView(
|
||||
slivers: [
|
||||
Obx(() => _buildBody(_favPgcController.loadingState.value)),
|
||||
SliverPadding(
|
||||
padding: EdgeInsets.only(
|
||||
bottom: MediaQuery.paddingOf(context).bottom + 80),
|
||||
sliver: Obx(
|
||||
() => _buildBody(_favPgcController.loadingState.value)),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
@@ -162,48 +167,44 @@ class _FavPgcChildPageState extends State<FavPgcChildPage>
|
||||
),
|
||||
),
|
||||
Success(:var response) => response?.isNotEmpty == true
|
||||
? SliverPadding(
|
||||
padding: EdgeInsets.only(
|
||||
bottom: MediaQuery.paddingOf(context).bottom + 80),
|
||||
sliver: SliverGrid(
|
||||
gridDelegate: Grid.videoCardHDelegate(context),
|
||||
delegate: SliverChildBuilderDelegate(
|
||||
(context, index) {
|
||||
if (index == response.length - 1) {
|
||||
_favPgcController.onLoadMore();
|
||||
}
|
||||
final item = response[index];
|
||||
return FavPgcItem(
|
||||
item: item,
|
||||
ctr: _favPgcController,
|
||||
onSelect: () {
|
||||
_favPgcController.onSelect(index);
|
||||
},
|
||||
onUpdateStatus: () {
|
||||
showPgcFollowDialog(
|
||||
context: context,
|
||||
type: widget.type == 0 ? '追番' : '追剧',
|
||||
followStatus: widget.followStatus,
|
||||
onUpdateStatus: (followStatus) {
|
||||
if (followStatus == -1) {
|
||||
_favPgcController.bangumiDel(
|
||||
index,
|
||||
item.seasonId,
|
||||
);
|
||||
} else {
|
||||
_favPgcController.onUpdate(
|
||||
index,
|
||||
followStatus,
|
||||
item.seasonId,
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
childCount: response!.length,
|
||||
),
|
||||
? SliverGrid(
|
||||
gridDelegate: Grid.videoCardHDelegate(context),
|
||||
delegate: SliverChildBuilderDelegate(
|
||||
(context, index) {
|
||||
if (index == response.length - 1) {
|
||||
_favPgcController.onLoadMore();
|
||||
}
|
||||
final item = response[index];
|
||||
return FavPgcItem(
|
||||
item: item,
|
||||
ctr: _favPgcController,
|
||||
onSelect: () {
|
||||
_favPgcController.onSelect(index);
|
||||
},
|
||||
onUpdateStatus: () {
|
||||
showPgcFollowDialog(
|
||||
context: context,
|
||||
type: widget.type == 0 ? '追番' : '追剧',
|
||||
followStatus: widget.followStatus,
|
||||
onUpdateStatus: (followStatus) {
|
||||
if (followStatus == -1) {
|
||||
_favPgcController.bangumiDel(
|
||||
index,
|
||||
item.seasonId,
|
||||
);
|
||||
} else {
|
||||
_favPgcController.onUpdate(
|
||||
index,
|
||||
followStatus,
|
||||
item.seasonId,
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
childCount: response!.length,
|
||||
),
|
||||
)
|
||||
: HttpError(onReload: _favPgcController.onReload),
|
||||
|
||||
@@ -70,8 +70,13 @@ class _FavDetailPageState extends State<FavDetailPage> {
|
||||
controller: _favDetailController.scrollController,
|
||||
slivers: [
|
||||
_buildHeader(theme),
|
||||
Obx(() => _buildBody(
|
||||
theme, _favDetailController.loadingState.value)),
|
||||
SliverPadding(
|
||||
padding: EdgeInsets.only(
|
||||
bottom: MediaQuery.of(context).padding.bottom + 85,
|
||||
),
|
||||
sliver: Obx(() => _buildBody(
|
||||
theme, _favDetailController.loadingState.value)),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
@@ -365,123 +370,116 @@ class _FavDetailPageState extends State<FavDetailPage> {
|
||||
),
|
||||
),
|
||||
Success(:var response) => response?.isNotEmpty == true
|
||||
? SliverPadding(
|
||||
padding: EdgeInsets.only(
|
||||
bottom: MediaQuery.of(context).padding.bottom + 85,
|
||||
),
|
||||
sliver: SliverGrid(
|
||||
gridDelegate: Grid.videoCardHDelegate(context),
|
||||
delegate: SliverChildBuilderDelegate(
|
||||
(context, index) {
|
||||
if (index == response.length) {
|
||||
_favDetailController.onLoadMore();
|
||||
return Container(
|
||||
height: 60,
|
||||
alignment: Alignment.center,
|
||||
child: Text(
|
||||
_favDetailController.isEnd ? '没有更多了' : '加载中...',
|
||||
style: TextStyle(
|
||||
color: theme.colorScheme.outline,
|
||||
fontSize: 13,
|
||||
),
|
||||
? SliverGrid(
|
||||
gridDelegate: Grid.videoCardHDelegate(context),
|
||||
delegate: SliverChildBuilderDelegate(
|
||||
(context, index) {
|
||||
if (index == response.length) {
|
||||
_favDetailController.onLoadMore();
|
||||
return Container(
|
||||
height: 60,
|
||||
alignment: Alignment.center,
|
||||
child: Text(
|
||||
_favDetailController.isEnd ? '没有更多了' : '加载中...',
|
||||
style: TextStyle(
|
||||
color: theme.colorScheme.outline,
|
||||
fontSize: 13,
|
||||
),
|
||||
);
|
||||
}
|
||||
FavDetailItemData item = response[index];
|
||||
return Stack(
|
||||
clipBehavior: Clip.none,
|
||||
children: [
|
||||
Positioned.fill(
|
||||
child: FavVideoCardH(
|
||||
videoItem: item,
|
||||
onDelFav: _favDetailController.isOwner.value
|
||||
? () => _favDetailController.onCancelFav(
|
||||
index,
|
||||
item.id!,
|
||||
item.type!,
|
||||
)
|
||||
: null,
|
||||
onViewFav: () {
|
||||
PageUtils.toVideoPage(
|
||||
'bvid=${item.bvid}&cid=${item.cid}',
|
||||
arguments: {
|
||||
'videoItem': item,
|
||||
'heroTag': Utils.makeHeroTag(item.bvid),
|
||||
'sourceType': 'fav',
|
||||
'mediaId': _favDetailController.item.value.id,
|
||||
'oid': item.id,
|
||||
'favTitle':
|
||||
_favDetailController.item.value.title,
|
||||
'count': _favDetailController
|
||||
.item.value.mediaCount,
|
||||
'desc': true,
|
||||
'isContinuePlaying': index != 0,
|
||||
'isOwner': _favDetailController.isOwner.value,
|
||||
},
|
||||
);
|
||||
},
|
||||
onTap: _favDetailController.enableMultiSelect.value
|
||||
? () {
|
||||
),
|
||||
);
|
||||
}
|
||||
FavDetailItemData item = response[index];
|
||||
return Stack(
|
||||
clipBehavior: Clip.none,
|
||||
children: [
|
||||
Positioned.fill(
|
||||
child: FavVideoCardH(
|
||||
videoItem: item,
|
||||
onDelFav: _favDetailController.isOwner.value
|
||||
? () => _favDetailController.onCancelFav(
|
||||
index,
|
||||
item.id!,
|
||||
item.type!,
|
||||
)
|
||||
: null,
|
||||
onViewFav: () {
|
||||
PageUtils.toVideoPage(
|
||||
'bvid=${item.bvid}&cid=${item.cid}',
|
||||
arguments: {
|
||||
'videoItem': item,
|
||||
'heroTag': Utils.makeHeroTag(item.bvid),
|
||||
'sourceType': 'fav',
|
||||
'mediaId': _favDetailController.item.value.id,
|
||||
'oid': item.id,
|
||||
'favTitle':
|
||||
_favDetailController.item.value.title,
|
||||
'count':
|
||||
_favDetailController.item.value.mediaCount,
|
||||
'desc': true,
|
||||
'isContinuePlaying': index != 0,
|
||||
'isOwner': _favDetailController.isOwner.value,
|
||||
},
|
||||
);
|
||||
},
|
||||
onTap: _favDetailController.enableMultiSelect.value
|
||||
? () {
|
||||
_favDetailController.onSelect(index);
|
||||
}
|
||||
: null,
|
||||
onLongPress: _favDetailController.isOwner.value
|
||||
? () {
|
||||
if (_favDetailController
|
||||
.enableMultiSelect.value.not) {
|
||||
_favDetailController
|
||||
.enableMultiSelect.value = true;
|
||||
_favDetailController.onSelect(index);
|
||||
}
|
||||
: null,
|
||||
onLongPress: _favDetailController.isOwner.value
|
||||
? () {
|
||||
if (_favDetailController
|
||||
.enableMultiSelect.value.not) {
|
||||
_favDetailController
|
||||
.enableMultiSelect.value = true;
|
||||
_favDetailController.onSelect(index);
|
||||
}
|
||||
}
|
||||
: null,
|
||||
),
|
||||
}
|
||||
: null,
|
||||
),
|
||||
Positioned(
|
||||
top: 5,
|
||||
left: 12,
|
||||
bottom: 5,
|
||||
child: IgnorePointer(
|
||||
child: LayoutBuilder(
|
||||
builder: (context, constraints) =>
|
||||
AnimatedOpacity(
|
||||
opacity: item.checked == true ? 1 : 0,
|
||||
duration: const Duration(milliseconds: 200),
|
||||
child: Container(
|
||||
alignment: Alignment.center,
|
||||
height: constraints.maxHeight,
|
||||
width: constraints.maxHeight *
|
||||
StyleString.aspectRatio,
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: StyleString.mdRadius,
|
||||
color: Colors.black.withValues(alpha: 0.6),
|
||||
),
|
||||
child: SizedBox(
|
||||
width: 34,
|
||||
height: 34,
|
||||
child: AnimatedScale(
|
||||
scale: item.checked == true ? 1 : 0,
|
||||
duration:
|
||||
const Duration(milliseconds: 250),
|
||||
curve: Curves.easeInOut,
|
||||
child: IconButton(
|
||||
style: ButtonStyle(
|
||||
padding: WidgetStateProperty.all(
|
||||
EdgeInsets.zero),
|
||||
backgroundColor:
|
||||
WidgetStateProperty.resolveWith(
|
||||
(states) {
|
||||
return theme.colorScheme.surface
|
||||
.withValues(alpha: 0.8);
|
||||
},
|
||||
),
|
||||
),
|
||||
onPressed: null,
|
||||
icon: Icon(
|
||||
Icons.done_all_outlined,
|
||||
color: theme.colorScheme.primary,
|
||||
),
|
||||
Positioned(
|
||||
top: 5,
|
||||
left: 12,
|
||||
bottom: 5,
|
||||
child: IgnorePointer(
|
||||
child: LayoutBuilder(
|
||||
builder: (context, constraints) => AnimatedOpacity(
|
||||
opacity: item.checked == true ? 1 : 0,
|
||||
duration: const Duration(milliseconds: 200),
|
||||
child: Container(
|
||||
alignment: Alignment.center,
|
||||
height: constraints.maxHeight,
|
||||
width: constraints.maxHeight *
|
||||
StyleString.aspectRatio,
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: StyleString.mdRadius,
|
||||
color: Colors.black.withValues(alpha: 0.6),
|
||||
),
|
||||
child: SizedBox(
|
||||
width: 34,
|
||||
height: 34,
|
||||
child: AnimatedScale(
|
||||
scale: item.checked == true ? 1 : 0,
|
||||
duration: const Duration(milliseconds: 250),
|
||||
curve: Curves.easeInOut,
|
||||
child: IconButton(
|
||||
style: ButtonStyle(
|
||||
padding: WidgetStateProperty.all(
|
||||
EdgeInsets.zero),
|
||||
backgroundColor:
|
||||
WidgetStateProperty.resolveWith(
|
||||
(states) {
|
||||
return theme.colorScheme.surface
|
||||
.withValues(alpha: 0.8);
|
||||
},
|
||||
),
|
||||
),
|
||||
onPressed: null,
|
||||
icon: Icon(
|
||||
Icons.done_all_outlined,
|
||||
color: theme.colorScheme.primary,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -489,11 +487,11 @@ class _FavDetailPageState extends State<FavDetailPage> {
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
childCount: response!.length + 1,
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
childCount: response!.length + 1,
|
||||
),
|
||||
)
|
||||
: HttpError(
|
||||
|
||||
@@ -25,49 +25,44 @@ class _FavSearchPageState extends CommonSearchPageState<FavSearchPage,
|
||||
|
||||
@override
|
||||
Widget buildList(List<FavDetailItemData> list) {
|
||||
return SliverPadding(
|
||||
padding: EdgeInsets.only(
|
||||
bottom: MediaQuery.of(context).padding.bottom + 80,
|
||||
),
|
||||
sliver: SliverGrid(
|
||||
gridDelegate: Grid.videoCardHDelegate(context, minHeight: 110),
|
||||
delegate: SliverChildBuilderDelegate(
|
||||
childCount: list.length,
|
||||
(context, index) {
|
||||
if (index == list.length - 1) {
|
||||
controller.onLoadMore();
|
||||
}
|
||||
final item = list[index];
|
||||
return FavVideoCardH(
|
||||
videoItem: item,
|
||||
onDelFav: controller.isOwner == true
|
||||
? () {
|
||||
controller.onCancelFav(
|
||||
index,
|
||||
item.id!,
|
||||
item.type,
|
||||
);
|
||||
}
|
||||
: null,
|
||||
onViewFav: () {
|
||||
PageUtils.toVideoPage(
|
||||
'bvid=${item.bvid}&cid=${item.cid}',
|
||||
arguments: {
|
||||
'videoItem': item,
|
||||
'heroTag': Utils.makeHeroTag(item.bvid),
|
||||
'sourceType': 'fav',
|
||||
'mediaId': controller.mediaId,
|
||||
'oid': item.id,
|
||||
'favTitle': controller.title,
|
||||
'count': controller.count,
|
||||
'desc': true,
|
||||
'isContinuePlaying': true,
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
return SliverGrid(
|
||||
gridDelegate: Grid.videoCardHDelegate(context, minHeight: 110),
|
||||
delegate: SliverChildBuilderDelegate(
|
||||
childCount: list.length,
|
||||
(context, index) {
|
||||
if (index == list.length - 1) {
|
||||
controller.onLoadMore();
|
||||
}
|
||||
final item = list[index];
|
||||
return FavVideoCardH(
|
||||
videoItem: item,
|
||||
onDelFav: controller.isOwner == true
|
||||
? () {
|
||||
controller.onCancelFav(
|
||||
index,
|
||||
item.id!,
|
||||
item.type,
|
||||
);
|
||||
}
|
||||
: null,
|
||||
onViewFav: () {
|
||||
PageUtils.toVideoPage(
|
||||
'bvid=${item.bvid}&cid=${item.cid}',
|
||||
arguments: {
|
||||
'videoItem': item,
|
||||
'heroTag': Utils.makeHeroTag(item.bvid),
|
||||
'sourceType': 'fav',
|
||||
'mediaId': controller.mediaId,
|
||||
'oid': item.id,
|
||||
'favTitle': controller.title,
|
||||
'count': controller.count,
|
||||
'desc': true,
|
||||
'isContinuePlaying': true,
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -30,26 +30,21 @@ class _FollowSearchPageState extends CommonSearchPageState<FollowSearchPage,
|
||||
|
||||
@override
|
||||
Widget buildList(List<FollowItemModel> list) {
|
||||
return SliverPadding(
|
||||
padding: EdgeInsets.only(
|
||||
bottom: MediaQuery.of(context).padding.bottom + 80,
|
||||
),
|
||||
sliver: SliverList.builder(
|
||||
itemCount: list.length,
|
||||
itemBuilder: ((context, index) {
|
||||
if (index == list.length - 1) {
|
||||
controller.onLoadMore();
|
||||
}
|
||||
return FollowItem(
|
||||
item: list[index],
|
||||
onSelect: widget.mid != null && widget.isFromSelect != false
|
||||
? (userModel) {
|
||||
Get.back(result: userModel);
|
||||
}
|
||||
: null,
|
||||
);
|
||||
}),
|
||||
),
|
||||
return SliverList.builder(
|
||||
itemCount: list.length,
|
||||
itemBuilder: ((context, index) {
|
||||
if (index == list.length - 1) {
|
||||
controller.onLoadMore();
|
||||
}
|
||||
return FollowItem(
|
||||
item: list[index],
|
||||
onSelect: widget.mid != null && widget.isFromSelect != false
|
||||
? (userModel) {
|
||||
Get.back(result: userModel);
|
||||
}
|
||||
: null,
|
||||
);
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,29 +24,24 @@ class _HistorySearchPageState
|
||||
|
||||
@override
|
||||
Widget buildList(List<HisListItem> list) {
|
||||
return SliverPadding(
|
||||
padding: EdgeInsets.only(
|
||||
bottom: MediaQuery.of(context).padding.bottom + 80,
|
||||
),
|
||||
sliver: SliverGrid(
|
||||
gridDelegate: Grid.videoCardHDelegate(context, minHeight: 110),
|
||||
delegate: SliverChildBuilderDelegate(
|
||||
childCount: list.length,
|
||||
(context, index) {
|
||||
if (index == list.length - 1) {
|
||||
controller.onLoadMore();
|
||||
}
|
||||
final item = list[index];
|
||||
return HistoryItem(
|
||||
videoItem: item,
|
||||
ctr: controller,
|
||||
onChoose: null,
|
||||
onDelete: (kid, business) {
|
||||
controller.onDelHistory(index, kid, business);
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
return SliverGrid(
|
||||
gridDelegate: Grid.videoCardHDelegate(context, minHeight: 110),
|
||||
delegate: SliverChildBuilderDelegate(
|
||||
childCount: list.length,
|
||||
(context, index) {
|
||||
if (index == list.length - 1) {
|
||||
controller.onLoadMore();
|
||||
}
|
||||
final item = list[index];
|
||||
return HistoryItem(
|
||||
videoItem: item,
|
||||
ctr: controller,
|
||||
onChoose: null,
|
||||
onDelete: (kid, business) {
|
||||
controller.onDelHistory(index, kid, business);
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -26,64 +26,59 @@ class _LaterSearchPageState
|
||||
|
||||
@override
|
||||
Widget buildList(List<HotVideoItemModel> list) {
|
||||
return SliverPadding(
|
||||
padding: EdgeInsets.only(
|
||||
bottom: MediaQuery.of(context).padding.bottom + 80,
|
||||
),
|
||||
sliver: SliverGrid(
|
||||
gridDelegate: Grid.videoCardHDelegate(context, minHeight: 110),
|
||||
delegate: SliverChildBuilderDelegate(
|
||||
childCount: list.length,
|
||||
(context, index) {
|
||||
if (index == list.length - 1) {
|
||||
controller.onLoadMore();
|
||||
}
|
||||
final item = list[index];
|
||||
return Stack(
|
||||
clipBehavior: Clip.none,
|
||||
children: [
|
||||
VideoCardH(
|
||||
videoItem: item,
|
||||
source: 'later',
|
||||
onViewLater: (cid) {
|
||||
PageUtils.toVideoPage(
|
||||
'bvid=${item.bvid}&cid=$cid',
|
||||
arguments: {
|
||||
'videoItem': item,
|
||||
'oid': item.aid,
|
||||
'heroTag': Utils.makeHeroTag(item.bvid),
|
||||
'sourceType': 'watchLater',
|
||||
'count': controller.count,
|
||||
'favTitle': '稍后再看',
|
||||
'mediaId': controller.mid,
|
||||
'desc': false,
|
||||
'isContinuePlaying': index != 0,
|
||||
},
|
||||
return SliverGrid(
|
||||
gridDelegate: Grid.videoCardHDelegate(context, minHeight: 110),
|
||||
delegate: SliverChildBuilderDelegate(
|
||||
childCount: list.length,
|
||||
(context, index) {
|
||||
if (index == list.length - 1) {
|
||||
controller.onLoadMore();
|
||||
}
|
||||
final item = list[index];
|
||||
return Stack(
|
||||
clipBehavior: Clip.none,
|
||||
children: [
|
||||
VideoCardH(
|
||||
videoItem: item,
|
||||
source: 'later',
|
||||
onViewLater: (cid) {
|
||||
PageUtils.toVideoPage(
|
||||
'bvid=${item.bvid}&cid=$cid',
|
||||
arguments: {
|
||||
'videoItem': item,
|
||||
'oid': item.aid,
|
||||
'heroTag': Utils.makeHeroTag(item.bvid),
|
||||
'sourceType': 'watchLater',
|
||||
'count': controller.count,
|
||||
'favTitle': '稍后再看',
|
||||
'mediaId': controller.mid,
|
||||
'desc': false,
|
||||
'isContinuePlaying': index != 0,
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
Positioned(
|
||||
right: 12,
|
||||
bottom: 0,
|
||||
child: iconButton(
|
||||
tooltip: '移除',
|
||||
context: context,
|
||||
onPressed: () {
|
||||
controller.toViewDel(
|
||||
context,
|
||||
index,
|
||||
item.aid,
|
||||
);
|
||||
},
|
||||
icon: Icons.clear,
|
||||
iconColor: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||
bgColor: Colors.transparent,
|
||||
),
|
||||
Positioned(
|
||||
right: 12,
|
||||
bottom: 0,
|
||||
child: iconButton(
|
||||
tooltip: '移除',
|
||||
context: context,
|
||||
onPressed: () {
|
||||
controller.toViewDel(
|
||||
context,
|
||||
index,
|
||||
item.aid,
|
||||
);
|
||||
},
|
||||
icon: Icons.clear,
|
||||
iconColor: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||
bgColor: Colors.transparent,
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -41,7 +41,14 @@ class _MemberFavoriteState extends State<MemberFavorite>
|
||||
return refreshIndicator(
|
||||
onRefresh: _controller.onRefresh,
|
||||
child: CustomScrollView(
|
||||
slivers: [Obx(() => _buildBody(theme, _controller.loadingState.value))],
|
||||
slivers: [
|
||||
SliverPadding(
|
||||
padding: EdgeInsets.only(
|
||||
bottom: MediaQuery.paddingOf(context).bottom + 80),
|
||||
sliver:
|
||||
Obx(() => _buildBody(theme, _controller.loadingState.value)),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -68,11 +75,6 @@ class _MemberFavoriteState extends State<MemberFavorite>
|
||||
child: Obx(
|
||||
() => _buildItem(theme, _controller.second.value, false)),
|
||||
),
|
||||
SliverToBoxAdapter(
|
||||
child: SizedBox(
|
||||
height: 80 + MediaQuery.of(context).padding.bottom,
|
||||
),
|
||||
),
|
||||
],
|
||||
)
|
||||
: HttpError(
|
||||
|
||||
@@ -219,7 +219,7 @@ class _MemberVideoState extends State<MemberVideo>
|
||||
}
|
||||
final SpaceArchiveItem item = response[index];
|
||||
return VideoCardHMemberVideo(
|
||||
key: ValueKey('${item.param}'),
|
||||
// key: ValueKey('${item.param}'),
|
||||
videoItem: item,
|
||||
fromViewAid: _controller.fromViewAid,
|
||||
);
|
||||
|
||||
@@ -121,8 +121,12 @@ class _SearchTrendingPageState extends State<SearchTrendingPage> {
|
||||
filterQuality: FilterQuality.low,
|
||||
),
|
||||
),
|
||||
Obx(() =>
|
||||
_buildBody(theme, _controller.loadingState.value)),
|
||||
SliverPadding(
|
||||
padding: EdgeInsets.only(
|
||||
bottom: MediaQuery.paddingOf(context).bottom + 100),
|
||||
sliver: Obx(() =>
|
||||
_buildBody(theme, _controller.loadingState.value)),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
@@ -138,77 +142,73 @@ class _SearchTrendingPageState extends State<SearchTrendingPage> {
|
||||
return switch (loadingState) {
|
||||
Loading() => const SliverToBoxAdapter(child: LinearProgressIndicator()),
|
||||
Success(:var response) => response?.isNotEmpty == true
|
||||
? SliverPadding(
|
||||
padding: EdgeInsets.only(
|
||||
bottom: MediaQuery.paddingOf(context).bottom + 100),
|
||||
sliver: SliverList.separated(
|
||||
itemCount: response!.length,
|
||||
itemBuilder: (context, index) {
|
||||
final item = response[index];
|
||||
return ListTile(
|
||||
dense: true,
|
||||
onTap: () {
|
||||
Get.toNamed(
|
||||
'/searchResult',
|
||||
parameters: {
|
||||
'keyword': item.keyword!,
|
||||
},
|
||||
);
|
||||
},
|
||||
leading: index < _controller.topCount
|
||||
? const Icon(
|
||||
size: 17,
|
||||
Icons.vertical_align_top_outlined,
|
||||
color: Color(0xFFd1403e),
|
||||
)
|
||||
: Text(
|
||||
'${index + 1 - _controller.topCount}',
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
color: switch (index - _controller.topCount) {
|
||||
0 => const Color(0xFFfdad13),
|
||||
1 => const Color(0xFF8aace1),
|
||||
2 => const Color(0xFFdfa777),
|
||||
_ => theme.colorScheme.outline,
|
||||
},
|
||||
fontSize: 17,
|
||||
fontStyle: FontStyle.italic,
|
||||
),
|
||||
),
|
||||
title: Row(
|
||||
children: [
|
||||
Flexible(
|
||||
child: Text(
|
||||
item.keyword!,
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
strutStyle: const StrutStyle(height: 1, leading: 0),
|
||||
style: const TextStyle(height: 1, fontSize: 15),
|
||||
? SliverList.separated(
|
||||
itemCount: response!.length,
|
||||
itemBuilder: (context, index) {
|
||||
final item = response[index];
|
||||
return ListTile(
|
||||
dense: true,
|
||||
onTap: () {
|
||||
Get.toNamed(
|
||||
'/searchResult',
|
||||
parameters: {
|
||||
'keyword': item.keyword!,
|
||||
},
|
||||
);
|
||||
},
|
||||
leading: index < _controller.topCount
|
||||
? const Icon(
|
||||
size: 17,
|
||||
Icons.vertical_align_top_outlined,
|
||||
color: Color(0xFFd1403e),
|
||||
)
|
||||
: Text(
|
||||
'${index + 1 - _controller.topCount}',
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
color: switch (index - _controller.topCount) {
|
||||
0 => const Color(0xFFfdad13),
|
||||
1 => const Color(0xFF8aace1),
|
||||
2 => const Color(0xFFdfa777),
|
||||
_ => theme.colorScheme.outline,
|
||||
},
|
||||
fontSize: 17,
|
||||
fontStyle: FontStyle.italic,
|
||||
),
|
||||
),
|
||||
if (item.icon?.isNotEmpty == true) ...[
|
||||
const SizedBox(width: 4),
|
||||
CachedNetworkImage(
|
||||
imageUrl: Utils.thumbnailImgUrl(item.icon!),
|
||||
height: 16,
|
||||
),
|
||||
] else if (item.showLiveIcon == true) ...[
|
||||
const SizedBox(width: 4),
|
||||
Image.asset(
|
||||
'assets/images/live/live.gif',
|
||||
width: 51,
|
||||
height: 16,
|
||||
),
|
||||
],
|
||||
title: Row(
|
||||
children: [
|
||||
Flexible(
|
||||
child: Text(
|
||||
item.keyword!,
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
strutStyle: const StrutStyle(height: 1, leading: 0),
|
||||
style: const TextStyle(height: 1, fontSize: 15),
|
||||
),
|
||||
),
|
||||
if (item.icon?.isNotEmpty == true) ...[
|
||||
const SizedBox(width: 4),
|
||||
CachedNetworkImage(
|
||||
imageUrl: Utils.thumbnailImgUrl(item.icon!),
|
||||
height: 16,
|
||||
),
|
||||
] else if (item.showLiveIcon == true) ...[
|
||||
const SizedBox(width: 4),
|
||||
Image.asset(
|
||||
'assets/images/live/live.gif',
|
||||
width: 51,
|
||||
height: 16,
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
separatorBuilder: (context, index) => Divider(
|
||||
height: 1,
|
||||
indent: 48,
|
||||
color: theme.colorScheme.outline.withValues(alpha: 0.1),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
separatorBuilder: (context, index) => Divider(
|
||||
height: 1,
|
||||
indent: 48,
|
||||
color: theme.colorScheme.outline.withValues(alpha: 0.1),
|
||||
),
|
||||
)
|
||||
: HttpError(
|
||||
|
||||
@@ -82,20 +82,20 @@ class _SettingsSearchPageState extends State<SettingsSearchPage> {
|
||||
bottom: false,
|
||||
child: CustomScrollView(
|
||||
slivers: [
|
||||
Obx(
|
||||
() => _list.isEmpty
|
||||
? const HttpError()
|
||||
: SliverPadding(
|
||||
padding: EdgeInsets.only(
|
||||
bottom: MediaQuery.paddingOf(context).bottom + 80,
|
||||
),
|
||||
sliver: SliverWaterfallFlow.extent(
|
||||
SliverPadding(
|
||||
padding: EdgeInsets.only(
|
||||
bottom: MediaQuery.paddingOf(context).bottom + 80,
|
||||
),
|
||||
sliver: Obx(
|
||||
() => _list.isEmpty
|
||||
? const HttpError()
|
||||
: SliverWaterfallFlow.extent(
|
||||
maxCrossAxisExtent: Grid.smallCardWidth * 2,
|
||||
children: [
|
||||
..._list.map((item) => item.widget),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
@@ -40,7 +40,13 @@ class _SubDetailPageState extends State<SubDetailPage> {
|
||||
slivers: [
|
||||
_buildAppBar(theme),
|
||||
_buildCount(theme),
|
||||
Obx(() => _buildBody(_subDetailController.loadingState.value)),
|
||||
SliverPadding(
|
||||
padding: EdgeInsets.only(
|
||||
bottom: MediaQuery.paddingOf(context).bottom + 80,
|
||||
),
|
||||
sliver: Obx(
|
||||
() => _buildBody(_subDetailController.loadingState.value)),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
@@ -58,23 +64,18 @@ class _SubDetailPageState extends State<SubDetailPage> {
|
||||
),
|
||||
),
|
||||
Success(:var response) => response?.isNotEmpty == true
|
||||
? SliverPadding(
|
||||
padding: EdgeInsets.only(
|
||||
bottom: MediaQuery.paddingOf(context).bottom + 80,
|
||||
),
|
||||
sliver: SliverGrid(
|
||||
gridDelegate: Grid.videoCardHDelegate(context),
|
||||
delegate: SliverChildBuilderDelegate(
|
||||
childCount: response!.length,
|
||||
(context, index) {
|
||||
if (index == response.length - 1) {
|
||||
_subDetailController.onLoadMore();
|
||||
}
|
||||
return SubVideoCardH(
|
||||
videoItem: response[index],
|
||||
);
|
||||
},
|
||||
),
|
||||
? SliverGrid(
|
||||
gridDelegate: Grid.videoCardHDelegate(context),
|
||||
delegate: SliverChildBuilderDelegate(
|
||||
childCount: response!.length,
|
||||
(context, index) {
|
||||
if (index == response.length - 1) {
|
||||
_subDetailController.onLoadMore();
|
||||
}
|
||||
return SubVideoCardH(
|
||||
videoItem: response[index],
|
||||
);
|
||||
},
|
||||
),
|
||||
)
|
||||
: HttpError(
|
||||
|
||||
@@ -155,7 +155,7 @@ class _MediaListPanelState
|
||||
widget.loadMoreMedia();
|
||||
}
|
||||
return SizedBox(
|
||||
key: ValueKey('${item.aid}'),
|
||||
// key: ValueKey('${item.aid}'),
|
||||
height: 98,
|
||||
child: InkWell(
|
||||
onTap: () async {
|
||||
|
||||
@@ -4,16 +4,16 @@ import 'package:PiliPlus/models/common/member/contribute_type.dart';
|
||||
import 'package:PiliPlus/models/member/info.dart';
|
||||
import 'package:PiliPlus/models/space_archive/data.dart';
|
||||
import 'package:PiliPlus/models/space_archive/item.dart';
|
||||
import 'package:PiliPlus/pages/common/common_data_controller.dart';
|
||||
import 'package:PiliPlus/pages/common/common_list_controller.dart';
|
||||
import 'package:PiliPlus/utils/extension.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
class HorizontalMemberPageController extends CommonDataController {
|
||||
HorizontalMemberPageController({this.mid, required this.lastAid});
|
||||
class HorizontalMemberPageController
|
||||
extends CommonListController<SpaceArchiveData, SpaceArchiveItem> {
|
||||
HorizontalMemberPageController({this.mid, required this.currAid});
|
||||
|
||||
dynamic mid;
|
||||
|
||||
int currentPage = 0;
|
||||
|
||||
Rx<LoadingState<MemberInfoModel>> userState =
|
||||
LoadingState<MemberInfoModel>.loading().obs;
|
||||
RxMap userStat = {}.obs;
|
||||
@@ -54,27 +54,29 @@ class HorizontalMemberPageController extends CommonDataController {
|
||||
bool customHandleResponse(bool isRefresh, Success response) {
|
||||
SpaceArchiveData data = response.response;
|
||||
count.value = data.count ?? -1;
|
||||
if (currentPage == 0 || isLoadPrevious) {
|
||||
hasPrev = data.hasPrev ?? false;
|
||||
}
|
||||
if (currentPage == 0 || !isLoadPrevious) {
|
||||
hasNext = data.hasNext ?? false;
|
||||
}
|
||||
if (currentPage != 0 && loadingState.value is Success) {
|
||||
data.item ??= <SpaceArchiveItem>[];
|
||||
if (isRefresh) {
|
||||
if (isLoadPrevious) {
|
||||
data.item!.addAll((loadingState.value as Success).response);
|
||||
hasPrev = data.hasPrev ?? false;
|
||||
} else {
|
||||
data.item!.insertAll(0, (loadingState.value as Success).response);
|
||||
hasNext = data.hasNext ?? false;
|
||||
}
|
||||
}
|
||||
if (isLoadPrevious && loadingState.value is Success) {
|
||||
data.item ??= <SpaceArchiveItem>[];
|
||||
data.item!.addAll((loadingState.value as Success).response);
|
||||
} else if (!isRefresh && loadingState.value is Success) {
|
||||
data.item ??= <SpaceArchiveItem>[];
|
||||
data.item!.insertAll(0, (loadingState.value as Success).response);
|
||||
}
|
||||
firstAid = data.item?.firstOrNull?.param;
|
||||
lastAid = data.item?.lastOrNull?.param;
|
||||
loadingState.value = Success(data.item);
|
||||
isLoadPrevious = false;
|
||||
page++;
|
||||
return true;
|
||||
}
|
||||
|
||||
String? currAid;
|
||||
String? firstAid;
|
||||
String? lastAid;
|
||||
RxString order = 'pubdate'.obs;
|
||||
@@ -84,27 +86,45 @@ class HorizontalMemberPageController extends CommonDataController {
|
||||
bool hasNext = true;
|
||||
|
||||
@override
|
||||
Future<LoadingState> customGetData() => MemberHttp.spaceArchive(
|
||||
Future<LoadingState<SpaceArchiveData>> customGetData() =>
|
||||
MemberHttp.spaceArchive(
|
||||
type: ContributeType.video,
|
||||
mid: mid,
|
||||
aid: isLoadPrevious ? firstAid : lastAid,
|
||||
aid: page == 1
|
||||
? currAid
|
||||
: isLoadPrevious
|
||||
? firstAid
|
||||
: lastAid,
|
||||
order: order.value,
|
||||
sort: isLoadPrevious ? 'asc' : null,
|
||||
sort: page != 1 && isLoadPrevious ? 'asc' : null,
|
||||
pn: null,
|
||||
next: null,
|
||||
seasonId: null,
|
||||
seriesId: null,
|
||||
includeCursor: currentPage == 0 ? true : null,
|
||||
includeCursor: page == 1 ? true : null,
|
||||
);
|
||||
|
||||
@override
|
||||
Future<void> onRefresh() {
|
||||
currentPage = 0;
|
||||
hasPrev = true;
|
||||
hasNext = true;
|
||||
if (!hasPrev) {
|
||||
return Future.value();
|
||||
}
|
||||
isLoadPrevious = true;
|
||||
return queryData();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> onReload() {
|
||||
firstAid = null;
|
||||
lastAid = null;
|
||||
hasNext = true;
|
||||
hasPrev = true;
|
||||
isEnd = false;
|
||||
page = 1;
|
||||
scrollController.jumpToTop();
|
||||
return super.onReload();
|
||||
}
|
||||
|
||||
void queryBySort() {
|
||||
order.value = order.value == 'pubdate' ? 'click' : 'pubdate';
|
||||
onReload();
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
import 'package:PiliPlus/common/skeleton/video_card_h.dart';
|
||||
import 'package:PiliPlus/common/widgets/button/icon_button.dart';
|
||||
import 'package:PiliPlus/common/widgets/custom_sliver_persistent_header_delegate.dart';
|
||||
import 'package:PiliPlus/common/widgets/image/network_img_layer.dart';
|
||||
import 'package:PiliPlus/common/widgets/loading_widget/http_error.dart';
|
||||
import 'package:PiliPlus/common/widgets/loading_widget/loading_widget.dart';
|
||||
import 'package:PiliPlus/common/widgets/scroll_physics.dart';
|
||||
import 'package:PiliPlus/common/widgets/refresh_indicator.dart';
|
||||
import 'package:PiliPlus/common/widgets/video_card/video_card_h_member_video.dart';
|
||||
import 'package:PiliPlus/http/loading_state.dart';
|
||||
import 'package:PiliPlus/models/common/image_preview_type.dart';
|
||||
@@ -49,31 +51,12 @@ class _HorizontalMemberPageState extends State<HorizontalMemberPage> {
|
||||
_controller = Get.put(
|
||||
HorizontalMemberPageController(
|
||||
mid: widget.mid,
|
||||
lastAid: widget.videoDetailController.oid.value.toString(),
|
||||
currAid: widget.videoDetailController.oid.value.toString(),
|
||||
),
|
||||
tag: widget.videoDetailController.heroTag,
|
||||
);
|
||||
_bvid = widget.videoDetailController.bvid;
|
||||
_ownerMid = Accounts.main.mid;
|
||||
if (_controller.hasPrev) {
|
||||
_controller.scrollController.addListener(listener);
|
||||
}
|
||||
}
|
||||
|
||||
void listener() {
|
||||
if (_controller.scrollController.position.pixels == 0) {
|
||||
if (_controller.hasPrev) {
|
||||
_controller
|
||||
..isLoadPrevious = true
|
||||
..onLoadMore();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_controller.scrollController.removeListener(listener);
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -104,10 +87,22 @@ class _HorizontalMemberPageState extends State<HorizontalMemberPage> {
|
||||
],
|
||||
),
|
||||
_buildUserInfo(theme, response),
|
||||
const SizedBox(height: 5),
|
||||
Expanded(
|
||||
child: Obx(
|
||||
() => _buildVideoList(theme, _controller.loadingState.value)),
|
||||
child: refreshIndicator(
|
||||
onRefresh: _controller.onRefresh,
|
||||
child: CustomScrollView(
|
||||
controller: _controller.scrollController,
|
||||
// physics: PositionRetainedScrollPhysics(
|
||||
// shouldRetain: _controller.hasPrev,
|
||||
// parent: const ClampingScrollPhysics(),
|
||||
// ),
|
||||
slivers: [
|
||||
_buildSliverHeader(theme),
|
||||
Obx(() =>
|
||||
_buildVideoList(theme, _controller.loadingState.value)),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -176,33 +171,34 @@ class _HorizontalMemberPageState extends State<HorizontalMemberPage> {
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildVideoList(ThemeData theme, LoadingState loadingState) {
|
||||
Widget _buildVideoList(
|
||||
ThemeData theme, LoadingState<List<SpaceArchiveItem>?> loadingState) {
|
||||
return switch (loadingState) {
|
||||
Loading() => loadingWidget,
|
||||
Success(:var response) => Material(
|
||||
color: Colors.transparent,
|
||||
child: CustomScrollView(
|
||||
controller: _controller.scrollController,
|
||||
physics: PositionRetainedScrollPhysics(
|
||||
shouldRetain: _controller.hasPrev,
|
||||
parent: const ClampingScrollPhysics(),
|
||||
),
|
||||
slivers: [
|
||||
_buildSliverHeader(theme),
|
||||
SliverPadding(
|
||||
padding: EdgeInsets.only(
|
||||
bottom: MediaQuery.of(context).padding.bottom + 80,
|
||||
),
|
||||
sliver: SliverGrid(
|
||||
gridDelegate: Grid.videoCardHDelegate(context),
|
||||
delegate: SliverChildBuilderDelegate(
|
||||
(context, index) {
|
||||
if (index == response.length - 1 && _controller.hasNext) {
|
||||
_controller.onLoadMore();
|
||||
}
|
||||
final SpaceArchiveItem videoItem = response[index];
|
||||
return VideoCardHMemberVideo(
|
||||
key: ValueKey('${videoItem.param}'),
|
||||
Loading() => SliverGrid(
|
||||
gridDelegate: Grid.videoCardHDelegate(context),
|
||||
delegate: SliverChildBuilderDelegate(
|
||||
childCount: 10,
|
||||
(context, index) {
|
||||
return const VideoCardHSkeleton();
|
||||
},
|
||||
),
|
||||
),
|
||||
Success(:var response) => response?.isNotEmpty == true
|
||||
? SliverPadding(
|
||||
padding: EdgeInsets.only(
|
||||
bottom: MediaQuery.of(context).padding.bottom + 80,
|
||||
),
|
||||
sliver: SliverGrid(
|
||||
gridDelegate: Grid.videoCardHDelegate(context),
|
||||
delegate: SliverChildBuilderDelegate(
|
||||
(context, index) {
|
||||
if (index == response.length - 1 && _controller.hasNext) {
|
||||
_controller.onLoadMore();
|
||||
}
|
||||
final SpaceArchiveItem videoItem = response[index];
|
||||
return Material(
|
||||
color: Colors.transparent,
|
||||
child: VideoCardHMemberVideo(
|
||||
videoItem: videoItem,
|
||||
bvid: _bvid,
|
||||
onTap: () {
|
||||
@@ -219,17 +215,15 @@ class _HorizontalMemberPageState extends State<HorizontalMemberPage> {
|
||||
setState(() {});
|
||||
}
|
||||
},
|
||||
);
|
||||
},
|
||||
childCount: response.length,
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
childCount: response!.length,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Error(:var errMsg) => scrollErrorWidget(
|
||||
controller: _controller.scrollController,
|
||||
)
|
||||
: HttpError(onReload: _controller.onReload),
|
||||
Error(:var errMsg) => HttpError(
|
||||
errMsg: errMsg,
|
||||
onReload: _controller.onReload,
|
||||
),
|
||||
|
||||
@@ -10,7 +10,7 @@ import 'package:PiliPlus/pages/video/note/controller.dart';
|
||||
import 'package:PiliPlus/pages/webview/view.dart';
|
||||
import 'package:PiliPlus/utils/app_scheme.dart';
|
||||
import 'package:PiliPlus/utils/extension.dart';
|
||||
import 'package:PiliPlus/utils/storage.dart';
|
||||
import 'package:PiliPlus/utils/storage.dart' show Accounts;
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
||||
import 'package:get/get.dart';
|
||||
@@ -84,52 +84,73 @@ class _NoteListPageState extends CommonSlidePageState<NoteListPage> {
|
||||
const SizedBox(width: 16),
|
||||
],
|
||||
),
|
||||
body: enableSlide
|
||||
? slideList(theme,
|
||||
Obx(() => _buildBody(theme, _controller.loadingState.value)))
|
||||
: Obx(() => _buildBody(theme, _controller.loadingState.value)),
|
||||
bottomNavigationBar: Container(
|
||||
padding: EdgeInsets.only(
|
||||
left: 12,
|
||||
right: 12,
|
||||
top: 6,
|
||||
bottom: MediaQuery.paddingOf(context).bottom + 6,
|
||||
),
|
||||
width: double.infinity,
|
||||
decoration: BoxDecoration(
|
||||
color: theme.colorScheme.onInverseSurface,
|
||||
border: Border(
|
||||
top: BorderSide(
|
||||
width: 0.5,
|
||||
color: theme.colorScheme.outline.withValues(alpha: 0.1),
|
||||
),
|
||||
),
|
||||
),
|
||||
child: FilledButton.tonal(
|
||||
style: FilledButton.styleFrom(
|
||||
tapTargetSize: MaterialTapTargetSize.shrinkWrap,
|
||||
padding: EdgeInsets.zero,
|
||||
shape: const RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.all(Radius.circular(6)),
|
||||
),
|
||||
),
|
||||
onPressed: () {
|
||||
if (!Accounts.main.isLogin) {
|
||||
SmartDialog.showToast('账号未登录');
|
||||
return;
|
||||
}
|
||||
_key.currentState?.showBottomSheet(
|
||||
(context) => WebviewPage(
|
||||
oid: widget.oid,
|
||||
title: widget.title,
|
||||
url:
|
||||
'https://www.bilibili.com/h5/note-app?oid=${widget.oid}&pagefrom=ugcvideo&is_stein_gate=${widget.isStein ? 1 : 0}',
|
||||
body: enableSlide ? slideList(theme) : buildList(theme),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget buildList(ThemeData theme) {
|
||||
return refreshIndicator(
|
||||
onRefresh: _controller.onRefresh,
|
||||
child: Column(
|
||||
children: [
|
||||
Expanded(
|
||||
child: CustomScrollView(
|
||||
controller: _controller.scrollController,
|
||||
physics: const AlwaysScrollableScrollPhysics(),
|
||||
slivers: [
|
||||
SliverPadding(
|
||||
padding: const EdgeInsets.only(bottom: 80),
|
||||
sliver: Obx(
|
||||
() => _buildBody(theme, _controller.loadingState.value)),
|
||||
),
|
||||
);
|
||||
},
|
||||
child: const Text('开始记笔记'),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
Container(
|
||||
padding: EdgeInsets.only(
|
||||
left: 12,
|
||||
right: 12,
|
||||
top: 6,
|
||||
bottom: MediaQuery.paddingOf(context).bottom + 6,
|
||||
),
|
||||
width: double.infinity,
|
||||
decoration: BoxDecoration(
|
||||
color: theme.colorScheme.onInverseSurface,
|
||||
border: Border(
|
||||
top: BorderSide(
|
||||
width: 0.5,
|
||||
color: theme.colorScheme.outline.withValues(alpha: 0.1),
|
||||
),
|
||||
),
|
||||
),
|
||||
child: FilledButton.tonal(
|
||||
style: FilledButton.styleFrom(
|
||||
tapTargetSize: MaterialTapTargetSize.shrinkWrap,
|
||||
padding: EdgeInsets.zero,
|
||||
shape: const RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.all(Radius.circular(6)),
|
||||
),
|
||||
),
|
||||
onPressed: () {
|
||||
if (!Accounts.main.isLogin) {
|
||||
SmartDialog.showToast('账号未登录');
|
||||
return;
|
||||
}
|
||||
_key.currentState?.showBottomSheet(
|
||||
(context) => WebviewPage(
|
||||
oid: widget.oid,
|
||||
title: widget.title,
|
||||
url:
|
||||
'https://www.bilibili.com/h5/note-app?oid=${widget.oid}&pagefrom=ugcvideo&is_stein_gate=${widget.isStein ? 1 : 0}',
|
||||
),
|
||||
);
|
||||
},
|
||||
child: const Text('开始记笔记'),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -137,59 +158,37 @@ class _NoteListPageState extends CommonSlidePageState<NoteListPage> {
|
||||
Widget _buildBody(
|
||||
ThemeData theme, LoadingState<List<dynamic>?> loadingState) {
|
||||
return switch (loadingState) {
|
||||
Loading() => CustomScrollView(
|
||||
physics: const NeverScrollableScrollPhysics(),
|
||||
slivers: [
|
||||
SliverList.builder(
|
||||
itemBuilder: (context, index) {
|
||||
return const VideoReplySkeleton();
|
||||
},
|
||||
itemCount: 8,
|
||||
)
|
||||
],
|
||||
Loading() => SliverToBoxAdapter(
|
||||
child: ListView.builder(
|
||||
shrinkWrap: true,
|
||||
physics: const NeverScrollableScrollPhysics(),
|
||||
itemBuilder: (context, index) {
|
||||
return const VideoReplySkeleton();
|
||||
},
|
||||
itemCount: 8,
|
||||
),
|
||||
),
|
||||
Success(:var response) => response?.isNotEmpty == true
|
||||
? refreshIndicator(
|
||||
onRefresh: _controller.onRefresh,
|
||||
child: CustomScrollView(
|
||||
controller: _controller.scrollController,
|
||||
physics: const AlwaysScrollableScrollPhysics(),
|
||||
slivers: [
|
||||
SliverList.separated(
|
||||
itemBuilder: (context, index) {
|
||||
if (index == response.length - 1) {
|
||||
_controller.onLoadMore();
|
||||
}
|
||||
return _itemWidget(context, theme, response[index]);
|
||||
},
|
||||
itemCount: response!.length,
|
||||
separatorBuilder: (context, index) => Divider(
|
||||
height: 1,
|
||||
color: theme.colorScheme.outline.withValues(alpha: 0.1),
|
||||
),
|
||||
),
|
||||
SliverToBoxAdapter(
|
||||
child: SizedBox(
|
||||
height: MediaQuery.paddingOf(context).bottom + 80,
|
||||
),
|
||||
),
|
||||
],
|
||||
? SliverList.separated(
|
||||
itemBuilder: (context, index) {
|
||||
if (index == response.length - 1) {
|
||||
_controller.onLoadMore();
|
||||
}
|
||||
return _itemWidget(context, theme, response[index]);
|
||||
},
|
||||
itemCount: response!.length,
|
||||
separatorBuilder: (context, index) => Divider(
|
||||
height: 1,
|
||||
color: theme.colorScheme.outline.withValues(alpha: 0.1),
|
||||
),
|
||||
)
|
||||
: errWidget(),
|
||||
Error(:var errMsg) => errWidget(errMsg),
|
||||
: HttpError(onReload: _controller.onReload),
|
||||
Error(:var errMsg) => HttpError(
|
||||
errMsg: errMsg,
|
||||
onReload: _controller.onReload,
|
||||
),
|
||||
};
|
||||
}
|
||||
|
||||
Widget errWidget([errMsg]) => CustomScrollView(
|
||||
controller: _controller.scrollController,
|
||||
slivers: [
|
||||
HttpError(
|
||||
errMsg: errMsg,
|
||||
onReload: _controller.onReload,
|
||||
)
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget _itemWidget(BuildContext context, ThemeData theme, dynamic item) {
|
||||
|
||||
@@ -387,17 +387,13 @@ class _VideoReplyReplyPanelState
|
||||
ThemeData theme, LoadingState<List<ReplyInfo>?> loadingState, int index) {
|
||||
return switch (loadingState) {
|
||||
Loading() => IgnorePointer(
|
||||
child: CustomScrollView(
|
||||
child: ListView.builder(
|
||||
shrinkWrap: true,
|
||||
physics: const NeverScrollableScrollPhysics(),
|
||||
slivers: [
|
||||
SliverList.builder(
|
||||
itemBuilder: (context, index) {
|
||||
return const VideoReplySkeleton();
|
||||
},
|
||||
itemCount: 8,
|
||||
)
|
||||
],
|
||||
itemBuilder: (context, index) {
|
||||
return const VideoReplySkeleton();
|
||||
},
|
||||
itemCount: 8,
|
||||
),
|
||||
),
|
||||
Success(:var response) => () {
|
||||
|
||||
@@ -123,8 +123,11 @@ class _WhisperDetailPageState
|
||||
hidePanel();
|
||||
},
|
||||
behavior: HitTestBehavior.opaque,
|
||||
child: Obx(() =>
|
||||
_buildBody(_whisperDetailController.loadingState.value)),
|
||||
child: refreshIndicator(
|
||||
onRefresh: _whisperDetailController.onRefresh,
|
||||
child: Obx(() =>
|
||||
_buildBody(_whisperDetailController.loadingState.value)),
|
||||
),
|
||||
),
|
||||
),
|
||||
if (_whisperDetailController.mid != null) ...[
|
||||
@@ -142,66 +145,63 @@ class _WhisperDetailPageState
|
||||
return switch (loadingState) {
|
||||
Loading() => loadingWidget,
|
||||
Success(:var response) => response?.isNotEmpty == true
|
||||
? refreshIndicator(
|
||||
onRefresh: _whisperDetailController.onRefresh,
|
||||
child: ListView.separated(
|
||||
shrinkWrap: true,
|
||||
reverse: true,
|
||||
itemCount: response!.length,
|
||||
padding: const EdgeInsets.all(12),
|
||||
physics: const AlwaysScrollableScrollPhysics(
|
||||
parent: ClampingScrollPhysics(),
|
||||
),
|
||||
controller: _whisperDetailController.scrollController,
|
||||
itemBuilder: (context, int index) {
|
||||
if (index == response.length - 1) {
|
||||
_whisperDetailController.onLoadMore();
|
||||
}
|
||||
final item = response[index];
|
||||
return ChatItem(
|
||||
item: item,
|
||||
eInfos: _whisperDetailController.eInfos,
|
||||
onLongPress: item.senderUid ==
|
||||
_whisperDetailController.ownerMid
|
||||
? () {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return AlertDialog(
|
||||
clipBehavior: Clip.hardEdge,
|
||||
contentPadding:
|
||||
const EdgeInsets.symmetric(vertical: 12),
|
||||
content: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
ListTile(
|
||||
onTap: () {
|
||||
Get.back();
|
||||
_whisperDetailController.sendMsg(
|
||||
message: '${item.msgKey}',
|
||||
onClearText: editController.clear,
|
||||
msgType: 5,
|
||||
index: index,
|
||||
);
|
||||
},
|
||||
dense: true,
|
||||
title: const Text(
|
||||
'撤回',
|
||||
style: TextStyle(fontSize: 14),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
: null,
|
||||
);
|
||||
},
|
||||
separatorBuilder: (BuildContext context, int index) =>
|
||||
const SizedBox(height: 12),
|
||||
? ListView.separated(
|
||||
shrinkWrap: true,
|
||||
reverse: true,
|
||||
itemCount: response!.length,
|
||||
padding: const EdgeInsets.all(12),
|
||||
physics: const AlwaysScrollableScrollPhysics(
|
||||
parent: ClampingScrollPhysics(),
|
||||
),
|
||||
controller: _whisperDetailController.scrollController,
|
||||
itemBuilder: (context, int index) {
|
||||
if (index == response.length - 1) {
|
||||
_whisperDetailController.onLoadMore();
|
||||
}
|
||||
final item = response[index];
|
||||
return ChatItem(
|
||||
item: item,
|
||||
eInfos: _whisperDetailController.eInfos,
|
||||
onLongPress: item.senderUid ==
|
||||
_whisperDetailController.ownerMid
|
||||
? () {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return AlertDialog(
|
||||
clipBehavior: Clip.hardEdge,
|
||||
contentPadding:
|
||||
const EdgeInsets.symmetric(vertical: 12),
|
||||
content: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
ListTile(
|
||||
onTap: () {
|
||||
Get.back();
|
||||
_whisperDetailController.sendMsg(
|
||||
message: '${item.msgKey}',
|
||||
onClearText: editController.clear,
|
||||
msgType: 5,
|
||||
index: index,
|
||||
);
|
||||
},
|
||||
dense: true,
|
||||
title: const Text(
|
||||
'撤回',
|
||||
style: TextStyle(fontSize: 14),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
: null,
|
||||
);
|
||||
},
|
||||
separatorBuilder: (BuildContext context, int index) =>
|
||||
const SizedBox(height: 12),
|
||||
)
|
||||
: scrollErrorWidget(
|
||||
onReload: _whisperDetailController.onReload,
|
||||
|
||||
Reference in New Issue
Block a user