feat: pgc timeline

Closes #653

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
This commit is contained in:
bggRGjQaUbCoE
2025-04-13 19:54:21 +08:00
parent d9c6c31a4d
commit 68df173558
19 changed files with 791 additions and 378 deletions

View File

@@ -1,5 +1,6 @@
import 'package:PiliPlus/http/loading_state.dart';
import 'package:PiliPlus/models/bangumi/list.dart';
import 'package:PiliPlus/models/bangumi/pgc_timeline/result.dart';
import 'package:PiliPlus/models/common/tab_type.dart';
import 'package:PiliPlus/pages/common/common_list_controller.dart';
import 'package:PiliPlus/utils/extension.dart';
@@ -24,6 +25,9 @@ class BangumiController extends CommonListController<
queryData();
queryBangumiFollow();
if (tabType == TabType.bangumi) {
queryPgcTimeline();
}
if (isLogin.value) {
followController = ScrollController();
}
@@ -36,16 +40,30 @@ class BangumiController extends CommonListController<
followEnd = false;
}
queryBangumiFollow();
if (tabType == TabType.bangumi) {
queryPgcTimeline();
}
return super.onRefresh();
}
// follow
late int followPage = 1;
late RxInt followCount = (-1).obs;
late bool followLoading = false;
late bool followEnd = false;
late Rx<LoadingState> followState = LoadingState.loading().obs;
late Rx<LoadingState<List<BangumiListItemModel>?>> followState =
LoadingState<List<BangumiListItemModel>?>.loading().obs;
ScrollController? followController;
// timeline
late Rx<LoadingState<List<Result>?>> timelineState =
LoadingState<List<Result>?>.loading().obs;
Future queryPgcTimeline() async {
final res = await BangumiHttp.pgcTimeline(types: 1, before: 6, after: 6);
timelineState.value = res;
}
// 我的订阅
Future queryBangumiFollow([bool isRefresh = true]) async {
if (isLogin.value.not || followLoading || (isRefresh.not && followEnd)) {

View File

@@ -1,12 +1,15 @@
import 'dart:async';
import 'dart:math';
import 'package:PiliPlus/common/widgets/loading_widget.dart';
import 'package:PiliPlus/common/widgets/refresh_indicator.dart';
import 'package:PiliPlus/http/loading_state.dart';
import 'package:PiliPlus/models/bangumi/list.dart';
import 'package:PiliPlus/models/bangumi/pgc_timeline/result.dart';
import 'package:PiliPlus/models/common/tab_type.dart';
import 'package:PiliPlus/pages/bangumi/pgc_index/pgc_index_page.dart';
import 'package:PiliPlus/pages/bangumi/widgets/bangumi_card_v_timeline.dart';
import 'package:PiliPlus/pages/common/common_page.dart';
import 'package:PiliPlus/utils/extension.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:PiliPlus/common/constants.dart';
@@ -45,199 +48,229 @@ class _BangumiPageState extends CommonPageState<BangumiPage, BangumiController>
super.build(context);
return refreshIndicator(
onRefresh: () async {
await Future.wait([
controller.onRefresh(),
controller.queryBangumiFollow(),
]);
await controller.onRefresh();
},
child: CustomScrollView(
controller: controller.scrollController,
physics: const AlwaysScrollableScrollPhysics(),
slivers: [
SliverToBoxAdapter(
child: Obx(
() => controller.isLogin.value
? Column(
children: [
Padding(
padding: const EdgeInsets.only(left: 16),
child: Row(
children: [
Obx(
() => Text(
'最近${widget.tabType == TabType.bangumi ? '追番' : '追剧'}${controller.followCount.value == -1 ? '' : ' ${controller.followCount.value}'}',
style:
Theme.of(context).textTheme.titleMedium,
),
),
const Spacer(),
IconButton(
tooltip: '刷新',
onPressed: () {
controller
..followPage = 1
..followEnd = false
..queryBangumiFollow();
},
icon: const Icon(
Icons.refresh,
size: 20,
),
),
Obx(
() => controller.isLogin.value
? Padding(
padding: const EdgeInsets.symmetric(
horizontal: 10),
child: GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () {
Get.toNamed(
'/fav',
arguments: widget.tabType ==
TabType.bangumi
? 1
: 2,
);
},
child: Padding(
padding: const EdgeInsets.symmetric(
vertical: 8),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Text(
'查看全部',
strutStyle: StrutStyle(
leading: 0, height: 1),
style: TextStyle(
height: 1,
color: Theme.of(context)
.colorScheme
.secondary,
),
),
Icon(
Icons.chevron_right,
color: Theme.of(context)
.colorScheme
.secondary,
),
],
),
),
),
)
: const SizedBox.shrink(),
),
],
),
),
SizedBox(
height: Grid.smallCardWidth / 2 / 0.75 +
MediaQuery.textScalerOf(context).scale(50),
child: Obx(
() =>
_buildFollowBody(controller.followState.value),
),
),
],
)
: const SizedBox.shrink(),
),
),
SliverToBoxAdapter(
child: Padding(
padding: const EdgeInsets.only(
top: 10,
bottom: 10,
left: 16,
right: 10,
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'推荐',
style: Theme.of(context).textTheme.titleMedium,
),
GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () {
if (widget.tabType == TabType.bangumi) {
Get.to(PgcIndexPage());
} else {
List<String> titles = const [
'全部',
'电影',
'电视剧',
'纪录片',
'综艺',
];
List<int> types = const [102, 2, 5, 3, 7];
Get.to(
Scaffold(
appBar: AppBar(title: const Text('索引')),
body: DefaultTabController(
length: types.length,
child: Column(
children: [
TabBar(
tabs: titles
.map((title) => Tab(text: title))
.toList()),
Expanded(
child: tabBarView(
children: types
.map((type) =>
PgcIndexPage(indexType: type))
.toList()),
)
],
),
),
),
);
}
},
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 2),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Text(
'查看更多',
strutStyle: StrutStyle(leading: 0, height: 1),
style: TextStyle(
height: 1,
color: Theme.of(context).colorScheme.secondary,
),
),
Icon(
Icons.chevron_right,
color: Theme.of(context).colorScheme.secondary,
),
],
),
),
),
],
_buildFollow,
if (widget.tabType == TabType.bangumi)
SliverToBoxAdapter(
child: Container(
margin: const EdgeInsets.only(top: 10),
height: Grid.smallCardWidth / 2 / 0.75 +
MediaQuery.textScalerOf(context).scale(110),
child:
Obx(() => _buildTimeline(controller.timelineState.value)),
),
),
),
SliverPadding(
padding: const EdgeInsets.fromLTRB(
StyleString.safeSpace, 0, StyleString.safeSpace, 0),
sliver: Obx(
() => _buildBody(controller.loadingState.value),
),
),
..._buildRcmd,
],
),
);
}
Widget _buildBody(LoadingState<List<BangumiListItemModel>?> loadingState) {
late final List<String> weekList = [
'',
'',
'',
'',
'',
'',
'',
];
Widget _buildTimeline(LoadingState<List<Result>?> loadingState) =>
switch (loadingState) {
Loading() => loadingWidget,
Success() => loadingState.response?.isNotEmpty == true
? Builder(builder: (context) {
final initialIndex = max(
0,
loadingState.response!
.indexWhere((item) => item.isToday == 1));
return DefaultTabController(
initialIndex: initialIndex,
length: loadingState.response!.length,
child: Column(
children: [
Row(
children: [
const SizedBox(width: 16),
Text(
'追番时间表',
style: Theme.of(context).textTheme.titleMedium,
),
const SizedBox(width: 16),
Expanded(
child: Material(
color: Colors.transparent,
child: TabBar(
isScrollable: true,
tabAlignment: TabAlignment.start,
tabs: loadingState.response!
.map(
(item) => Tab(
text:
'${item.date} ${item.isToday == 1 ? '今天' : '${weekList[item.dayOfWeek! - 1]}'}',
),
)
.toList(),
),
),
),
],
),
const SizedBox(height: 10),
Expanded(
child: TabBarView(
physics: const NeverScrollableScrollPhysics(),
children: loadingState.response!.map((item) {
if (item.episodes!.isNullOrEmpty) {
return const SizedBox.shrink();
}
return MediaQuery.removePadding(
context: context,
removeLeft: context.orientation ==
Orientation.landscape,
child: ListView.builder(
physics:
const AlwaysScrollableScrollPhysics(),
scrollDirection: Axis.horizontal,
itemCount: item.episodes!.length,
itemBuilder: (context, index) {
return Container(
width: Grid.smallCardWidth / 2,
margin: EdgeInsets.only(
left: StyleString.safeSpace,
right:
index == item.episodes!.length - 1
? StyleString.safeSpace
: 0,
),
child: BangumiCardVTimeline(
item: item.episodes![index],
),
);
},
),
);
}).toList()),
),
],
),
);
})
: const SizedBox.shrink(),
Error() => GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: controller.queryPgcTimeline,
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 16),
alignment: Alignment.center,
child: Text(
loadingState.errMsg,
textAlign: TextAlign.center,
),
),
),
LoadingState() => throw UnimplementedError(),
};
List<Widget> get _buildRcmd => [
_buildRcmdTitle,
SliverPadding(
padding: const EdgeInsets.fromLTRB(
StyleString.safeSpace, 0, StyleString.safeSpace, 0),
sliver: Obx(
() => _buildRcmdBody(controller.loadingState.value),
),
),
];
Widget get _buildRcmdTitle => SliverToBoxAdapter(
child: Padding(
padding: const EdgeInsets.only(
top: 10,
bottom: 10,
left: 16,
right: 10,
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'推荐',
style: Theme.of(context).textTheme.titleMedium,
),
GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () {
if (widget.tabType == TabType.bangumi) {
Get.to(PgcIndexPage());
} else {
List<String> titles = const [
'全部',
'电影',
'电视剧',
'纪录片',
'综艺',
];
List<int> types = const [102, 2, 5, 3, 7];
Get.to(
Scaffold(
appBar: AppBar(title: const Text('索引')),
body: DefaultTabController(
length: types.length,
child: Column(
children: [
TabBar(
tabs: titles
.map((title) => Tab(text: title))
.toList()),
Expanded(
child: tabBarView(
children: types
.map((type) =>
PgcIndexPage(indexType: type))
.toList()),
)
],
),
),
),
);
}
},
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 2),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Text(
'查看更多',
strutStyle: StrutStyle(leading: 0, height: 1),
style: TextStyle(
height: 1,
color: Theme.of(context).colorScheme.secondary,
),
),
Icon(
Icons.chevron_right,
color: Theme.of(context).colorScheme.secondary,
),
],
),
),
),
],
),
),
);
Widget _buildRcmdBody(
LoadingState<List<BangumiListItemModel>?> loadingState) {
return switch (loadingState) {
Loading() => const SliverToBoxAdapter(),
Success() => loadingState.response?.isNotEmpty == true
@@ -274,36 +307,122 @@ class _BangumiPageState extends CommonPageState<BangumiPage, BangumiController>
};
}
Widget _buildFollowList(Success loadingState) {
return ListView.builder(
controller: controller.followController,
scrollDirection: Axis.horizontal,
itemCount: loadingState.response.length,
itemBuilder: (context, index) {
if (index == loadingState.response.length - 1) {
controller.queryBangumiFollow(false);
}
return Container(
width: Grid.smallCardWidth / 2,
margin: EdgeInsets.only(
left: StyleString.safeSpace,
right: index == loadingState.response.length - 1
? StyleString.safeSpace
: 0,
),
child: BangumiCardV(
bangumiItem: loadingState.response[index],
),
);
},
);
}
Widget get _buildFollow => SliverToBoxAdapter(
child: Obx(
() => controller.isLogin.value
? Column(
children: [
_buildFollowTitle,
SizedBox(
height: Grid.smallCardWidth / 2 / 0.75 +
MediaQuery.textScalerOf(context).scale(50),
child: Obx(
() => _buildFollowBody(controller.followState.value),
),
),
],
)
: const SizedBox.shrink(),
),
);
Widget _buildFollowBody(LoadingState loadingState) {
Widget get _buildFollowTitle => Padding(
padding: const EdgeInsets.only(left: 16),
child: Row(
children: [
Obx(
() => Text(
'最近${widget.tabType == TabType.bangumi ? '追番' : '追剧'}${controller.followCount.value == -1 ? '' : ' ${controller.followCount.value}'}',
style: Theme.of(context).textTheme.titleMedium,
),
),
const Spacer(),
IconButton(
tooltip: '刷新',
onPressed: () {
controller
..followPage = 1
..followEnd = false
..queryBangumiFollow();
},
icon: const Icon(
Icons.refresh,
size: 20,
),
),
Obx(
() => controller.isLogin.value
? Padding(
padding: const EdgeInsets.symmetric(horizontal: 10),
child: GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () {
Get.toNamed(
'/fav',
arguments:
widget.tabType == TabType.bangumi ? 1 : 2,
);
},
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 8),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Text(
'查看全部',
strutStyle: StrutStyle(leading: 0, height: 1),
style: TextStyle(
height: 1,
color:
Theme.of(context).colorScheme.secondary,
),
),
Icon(
Icons.chevron_right,
color: Theme.of(context).colorScheme.secondary,
),
],
),
),
),
)
: const SizedBox.shrink(),
),
],
),
);
Widget _buildFollowBody(
LoadingState<List<BangumiListItemModel>?> loadingState) {
return switch (loadingState) {
Loading() => loadingWidget,
Success() => (loadingState.response as List?)?.isNotEmpty == true
? _buildFollowList(loadingState)
Success() => loadingState.response?.isNotEmpty == true
? MediaQuery.removePadding(
context: context,
removeLeft: context.orientation == Orientation.landscape,
child: ListView.builder(
controller: controller.followController,
scrollDirection: Axis.horizontal,
itemCount: loadingState.response!.length,
itemBuilder: (context, index) {
if (index == loadingState.response!.length - 1) {
controller.queryBangumiFollow(false);
}
return Container(
width: Grid.smallCardWidth / 2,
margin: EdgeInsets.only(
left: StyleString.safeSpace,
right: index == loadingState.response!.length - 1
? StyleString.safeSpace
: 0,
),
child: BangumiCardV(
bangumiItem: loadingState.response![index],
),
);
},
),
)
: Center(
child: Text(
'还没有${widget.tabType == TabType.bangumi ? '追番' : '追剧'}')),

View File

@@ -31,6 +31,7 @@ class BangumiCardV extends StatelessWidget {
Utils.viewBangumi(seasonId: seasonId);
},
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
ClipRRect(
borderRadius: StyleString.mdRadius,
@@ -49,14 +50,13 @@ class BangumiCardV extends StatelessWidget {
height: maxHeight,
),
),
if (bangumiItem.badge != null)
PBadge(
text: bangumiItem.badge,
top: 6,
right: 6,
bottom: null,
left: null,
),
PBadge(
text: bangumiItem.badge,
top: 6,
right: 6,
bottom: null,
left: null,
),
if (bangumiItem.isFinish == 0 &&
bangumiItem.renewalTime?.isNotEmpty == true)
PBadge(
@@ -97,19 +97,14 @@ class BangumiCardV extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start,
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
Expanded(
child: Text(
bangumiItem.title,
textAlign: TextAlign.start,
style: const TextStyle(
letterSpacing: 0.3,
),
maxLines: 1,
overflow: TextOverflow.ellipsis,
)),
],
Text(
bangumiItem.title,
textAlign: TextAlign.start,
style: const TextStyle(
letterSpacing: 0.3,
),
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
const SizedBox(height: 1),
if (bangumiItem.indexShow != null)

View File

@@ -31,6 +31,7 @@ class BangumiCardVMemberHome extends StatelessWidget {
cover: bangumiItem.cover,
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
ClipRRect(
borderRadius: const BorderRadius.only(
@@ -94,19 +95,14 @@ Widget bangumiContent(Item bangumiItem) {
crossAxisAlignment: CrossAxisAlignment.start,
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
Expanded(
child: Text(
bangumiItem.title,
textAlign: TextAlign.start,
style: const TextStyle(
letterSpacing: 0.3,
),
maxLines: 2,
overflow: TextOverflow.ellipsis,
)),
],
Text(
bangumiItem.title,
textAlign: TextAlign.start,
style: const TextStyle(
letterSpacing: 0.3,
),
maxLines: 2,
overflow: TextOverflow.ellipsis,
),
const SizedBox(height: 1),
// if (bangumiItem.indexShow != null)

View File

@@ -29,6 +29,7 @@ class BangumiCardVPgcIndex extends StatelessWidget {
Utils.viewBangumi(seasonId: bangumiItem['season_id']);
},
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
ClipRRect(
borderRadius: StyleString.mdRadius,
@@ -44,25 +45,21 @@ class BangumiCardVPgcIndex extends StatelessWidget {
width: maxWidth,
height: maxHeight,
),
if (bangumiItem['badge'] != null &&
bangumiItem['badge'] != '')
PBadge(
text: bangumiItem['badge'],
top: 6,
right: 6,
bottom: null,
left: null,
),
if (bangumiItem['order'] != null &&
bangumiItem['order'] != '')
PBadge(
text: bangumiItem['order'],
top: null,
right: null,
bottom: 6,
left: 6,
type: 'gray',
),
PBadge(
text: bangumiItem['badge'],
top: 6,
right: 6,
bottom: null,
left: null,
),
PBadge(
text: bangumiItem['order'],
top: null,
right: null,
bottom: 6,
left: 6,
type: 'gray',
),
],
);
}),
@@ -86,19 +83,14 @@ class BangumiCardVPgcIndex extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start,
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
Expanded(
child: Text(
bangumiItem['title'],
textAlign: TextAlign.start,
style: const TextStyle(
letterSpacing: 0.3,
),
maxLines: 1,
overflow: TextOverflow.ellipsis,
)),
],
Text(
bangumiItem['title'],
textAlign: TextAlign.start,
style: const TextStyle(
letterSpacing: 0.3,
),
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
const SizedBox(height: 1),
if (bangumiItem['index_show'] != null)

View File

@@ -0,0 +1,105 @@
import 'package:PiliPlus/common/widgets/image_save.dart';
import 'package:PiliPlus/models/bangumi/pgc_timeline/episode.dart';
import 'package:flutter/material.dart';
import 'package:PiliPlus/common/constants.dart';
import 'package:PiliPlus/common/widgets/badge.dart';
import 'package:PiliPlus/utils/utils.dart';
import 'package:PiliPlus/common/widgets/network_img_layer.dart';
// 视频卡片 - 垂直布局
class BangumiCardVTimeline extends StatelessWidget {
const BangumiCardVTimeline({
super.key,
required this.item,
});
final Episode item;
@override
Widget build(BuildContext context) {
return Card(
clipBehavior: Clip.hardEdge,
margin: EdgeInsets.zero,
child: InkWell(
onLongPress: () => imageSaveDialog(
context: context,
title: item.title,
cover: item.cover,
),
onTap: () async {
Utils.viewBangumi(
seasonId: item.seasonId,
epId: item.episodeId,
);
},
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
ClipRRect(
borderRadius: StyleString.mdRadius,
child: AspectRatio(
aspectRatio: 0.75,
child: LayoutBuilder(builder: (context, boxConstraints) {
final double maxWidth = boxConstraints.maxWidth;
final double maxHeight = boxConstraints.maxHeight;
return Stack(
children: [
NetworkImgLayer(
src: item.cover,
width: maxWidth,
height: maxHeight,
),
if (item.follow == 1)
PBadge(
text: '已追番',
right: 6,
top: 6,
),
PBadge(
text: '${item.pubTime}',
left: 6,
bottom: 6,
type: 'gray',
),
],
);
}),
),
),
bagumiContent(context)
],
),
),
);
}
Widget bagumiContent(context) {
return Expanded(
child: Padding(
padding: const EdgeInsets.fromLTRB(4, 5, 0, 3),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
item.title ?? '',
textAlign: TextAlign.start,
style: const TextStyle(
letterSpacing: 0.3,
),
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
Text(
item.pubIndex ?? '',
maxLines: 1,
style: TextStyle(
fontSize: Theme.of(context).textTheme.labelMedium!.fontSize,
color: Theme.of(context).colorScheme.outline,
),
),
],
),
),
);
}
}

View File

@@ -516,15 +516,12 @@ Widget forWard(bool isSave, item, BuildContext context, source, callback,
src: item.modules.moduleDynamic.major.medialist['cover'],
),
),
if (item.modules.moduleDynamic.major.medialist['badge']
?['text'] !=
null)
PBadge(
right: 6,
top: 6,
text: item.modules.moduleDynamic.major.medialist['badge']
['text'],
)
PBadge(
right: 6,
top: 6,
text: item.modules.moduleDynamic.major.medialist['badge']
?['text'],
)
],
),
const SizedBox(width: 14),

View File

@@ -65,17 +65,16 @@ class FavPgcItem extends StatelessWidget {
width: boxConstraints.maxWidth,
height: boxConstraints.maxHeight,
),
if (item.badge?.isNotEmpty == true)
PBadge(
right: 4,
top: 4,
text: item.badge,
fs: 10,
padding: const EdgeInsets.symmetric(
horizontal: 2,
vertical: 1,
),
PBadge(
right: 4,
top: 4,
text: item.badge,
fs: 10,
padding: const EdgeInsets.symmetric(
horizontal: 2,
vertical: 1,
),
),
Positioned.fill(
child: IgnorePointer(
child: LayoutBuilder(

View File

@@ -123,14 +123,13 @@ class FavVideoCardH extends StatelessWidget {
bottom: 6.0,
type: 'gray',
),
if (videoItem.ogv != null)
PBadge(
text: videoItem.ogv!['type_name'],
top: 6.0,
right: 6.0,
bottom: null,
left: null,
),
PBadge(
text: videoItem.ogv?['type_name'],
top: 6.0,
right: 6.0,
bottom: null,
left: null,
),
],
);
},

View File

@@ -186,67 +186,71 @@ class _LivePageState extends CommonPageState<LivePage, LiveController>
child: loadingWidget,
),
Success() => (loadingState.response as List?)?.isNotEmpty == true
? SelfSizedHorizontalList(
gapSize: 5,
childBuilder: (index) {
if (index == loadingState.response.length - 1) {
controller.fetchLiveFollowing(false);
}
return SizedBox(
width: 65,
child: GestureDetector(
onTap: () {
Get.toNamed(
'/liveRoom?roomid=${loadingState.response[index].roomId}',
);
},
onLongPress: () {
Feedback.forLongPress(context);
Get.toNamed(
'/member?mid=${loadingState.response[index].uid}',
arguments: {
'face': loadingState.response[index].face,
'heroTag': Utils.makeHeroTag(
loadingState.response[index].uid)
},
);
},
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
const SizedBox(height: 8),
Container(
margin: const EdgeInsets.all(2),
padding: const EdgeInsets.all(2),
decoration: BoxDecoration(
border: Border.all(
width: 1.5,
color: Theme.of(context).colorScheme.primary,
strokeAlign: BorderSide.strokeAlignOutside,
? MediaQuery.removePadding(
context: context,
removeLeft: context.orientation == Orientation.landscape,
child: SelfSizedHorizontalList(
gapSize: 5,
childBuilder: (index) {
if (index == loadingState.response.length - 1) {
controller.fetchLiveFollowing(false);
}
return SizedBox(
width: 65,
child: GestureDetector(
onTap: () {
Get.toNamed(
'/liveRoom?roomid=${loadingState.response[index].roomId}',
);
},
onLongPress: () {
Feedback.forLongPress(context);
Get.toNamed(
'/member?mid=${loadingState.response[index].uid}',
arguments: {
'face': loadingState.response[index].face,
'heroTag': Utils.makeHeroTag(
loadingState.response[index].uid)
},
);
},
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
const SizedBox(height: 8),
Container(
margin: const EdgeInsets.all(2),
padding: const EdgeInsets.all(2),
decoration: BoxDecoration(
border: Border.all(
width: 1.5,
color: Theme.of(context).colorScheme.primary,
strokeAlign: BorderSide.strokeAlignOutside,
),
shape: BoxShape.circle,
),
child: NetworkImgLayer(
type: 'avatar',
width: 45,
height: 45,
src: loadingState.response[index].face,
),
shape: BoxShape.circle,
),
child: NetworkImgLayer(
type: 'avatar',
width: 45,
height: 45,
src: loadingState.response[index].face,
const SizedBox(height: 4),
Text(
loadingState.response[index].uname,
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: TextStyle(fontSize: 12),
textAlign: TextAlign.center,
),
),
const SizedBox(height: 2),
Text(
loadingState.response[index].uname,
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: TextStyle(fontSize: 11),
textAlign: TextAlign.center,
),
],
],
),
),
),
);
},
itemCount: loadingState.response.length,
);
},
itemCount: loadingState.response.length,
),
)
: const SizedBox.shrink(),
Error() => GestureDetector(

View File

@@ -60,14 +60,13 @@ Widget searchBangumiPanel(
height: 148,
src: i.cover,
),
if (i.seasonTypeName?.isNotEmpty == true)
PBadge(
text: i.seasonTypeName,
top: 6.0,
right: 4.0,
bottom: null,
left: null,
)
PBadge(
text: i.seasonTypeName,
top: 6.0,
right: 4.0,
bottom: null,
left: null,
)
],
),
const SizedBox(width: 10),