mirror of
https://github.com/HChaZZY/PiliPlus.git
synced 2025-12-06 09:13:48 +08:00
feat: pgc timeline
Closes #653 Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
This commit is contained in:
@@ -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)) {
|
||||
|
||||
@@ -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 ? '追番' : '追剧'}')),
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
105
lib/pages/bangumi/widgets/bangumi_card_v_timeline.dart
Normal file
105
lib/pages/bangumi/widgets/bangumi_card_v_timeline.dart
Normal 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,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user