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,3 +1,4 @@
import 'package:PiliPlus/utils/extension.dart';
import 'package:flutter/material.dart';
class PBadge extends StatelessWidget {
@@ -17,7 +18,7 @@ class PBadge extends StatelessWidget {
const PBadge({
super.key,
this.text,
required this.text,
this.top,
this.right,
this.bottom,
@@ -34,15 +35,19 @@ class PBadge extends StatelessWidget {
@override
Widget build(BuildContext context) {
if (text.isNullOrEmpty) {
return const SizedBox.shrink();
}
ColorScheme t = Theme.of(context).colorScheme;
// 背景色
Color bgColor = t.primary;
// 前景色
Color color = t.onPrimary;
// 边框色
Color borderColor = Colors.transparent;
Color? borderColor;
if (type == 'gray') {
bgColor = Colors.black54.withOpacity(0.45);
bgColor = Colors.black45;
color = Colors.white;
} else if (type == 'color') {
bgColor = t.secondaryContainer.withOpacity(0.5);
@@ -72,10 +77,10 @@ class PBadge extends StatelessWidget {
decoration: BoxDecoration(
borderRadius: br,
color: bgColor,
border: Border.all(color: borderColor),
border: borderColor != null ? Border.all(color: borderColor) : null,
),
child: Text(
text ?? "",
text!,
textScaler: textScaleFactor != null
? TextScaler.linear(textScaleFactor!)
: null,

View File

@@ -141,11 +141,7 @@ class VideoCardH extends StatelessWidget {
width: maxWidth,
height: maxHeight,
),
if (videoItem is HotVideoItemModel &&
(videoItem as HotVideoItemModel)
.pgcLabel
?.isNotEmpty ==
true)
if (videoItem is HotVideoItemModel)
PBadge(
text:
(videoItem as HotVideoItemModel).pgcLabel,

View File

@@ -760,4 +760,6 @@ class Api {
static const String getLiveEmoticons =
'${HttpString.liveBaseUrl}/xlive/web-ucenter/v2/emoticon/GetEmoticons';
static const String pgcTimeline = '/pgc/web/timeline';
}

View File

@@ -1,4 +1,6 @@
import 'package:PiliPlus/http/loading_state.dart';
import 'package:PiliPlus/models/bangumi/pgc_timeline/pgc_timeline.dart';
import 'package:PiliPlus/models/bangumi/pgc_timeline/result.dart';
import '../models/bangumi/list.dart';
import '../models/bangumi/pgc_index/condition.dart';
@@ -86,4 +88,24 @@ class BangumiHttp {
return LoadingState.error(res.data['message']);
}
}
static Future<LoadingState<List<Result>?>> pgcTimeline({
int types = 1, // 1`番剧`<br />3`电影`<br />4`国创` |
required int before,
required int after,
}) async {
var res = await Request().get(
Api.pgcTimeline,
queryParameters: {
'types': types,
'before': before,
'after': after,
},
);
if (res.data['code'] == 0) {
return LoadingState.success(PgcTimeline.fromJson(res.data).result);
} else {
return LoadingState.error(res.data['message']);
}
}
}

View File

@@ -0,0 +1,91 @@
import 'icon_font.dart';
class Episode {
String? cover;
int? delay;
int? delayId;
String? delayIndex;
String? delayReason;
bool? enableVt;
String? epCover;
int? episodeId;
int? follow;
String? follows;
IconFont? iconFont;
String? plays;
String? pubIndex;
String? pubTime;
int? pubTs;
int? published;
int? seasonId;
String? squareCover;
String? title;
Episode({
this.cover,
this.delay,
this.delayId,
this.delayIndex,
this.delayReason,
this.enableVt,
this.epCover,
this.episodeId,
this.follow,
this.follows,
this.iconFont,
this.plays,
this.pubIndex,
this.pubTime,
this.pubTs,
this.published,
this.seasonId,
this.squareCover,
this.title,
});
factory Episode.fromJson(Map<String, dynamic> json) => Episode(
cover: json['cover'] as String?,
delay: json['delay'] as int?,
delayId: json['delay_id'] as int?,
delayIndex: json['delay_index'] as String?,
delayReason: json['delay_reason'] as String?,
enableVt: json['enable_vt'] as bool?,
epCover: json['ep_cover'] as String?,
episodeId: json['episode_id'] as int?,
follow: json['follow'] as int?,
follows: json['follows'] as String?,
iconFont: json['icon_font'] == null
? null
: IconFont.fromJson(json['icon_font'] as Map<String, dynamic>),
plays: json['plays'] as String?,
pubIndex: json['pub_index'] as String?,
pubTime: json['pub_time'] as String?,
pubTs: json['pub_ts'] as int?,
published: json['published'] as int?,
seasonId: json['season_id'] as int?,
squareCover: json['square_cover'] as String?,
title: json['title'] as String?,
);
Map<String, dynamic> toJson() => {
'cover': cover,
'delay': delay,
'delay_id': delayId,
'delay_index': delayIndex,
'delay_reason': delayReason,
'enable_vt': enableVt,
'ep_cover': epCover,
'episode_id': episodeId,
'follow': follow,
'follows': follows,
'icon_font': iconFont?.toJson(),
'plays': plays,
'pub_index': pubIndex,
'pub_time': pubTime,
'pub_ts': pubTs,
'published': published,
'season_id': seasonId,
'square_cover': squareCover,
'title': title,
};
}

View File

@@ -0,0 +1,16 @@
class IconFont {
String? name;
String? text;
IconFont({this.name, this.text});
factory IconFont.fromJson(Map<String, dynamic> json) => IconFont(
name: json['name'] as String?,
text: json['text'] as String?,
);
Map<String, dynamic> toJson() => {
'name': name,
'text': text,
};
}

View File

@@ -0,0 +1,23 @@
import 'result.dart';
class PgcTimeline {
int? code;
String? message;
List<Result>? result;
PgcTimeline({this.code, this.message, this.result});
factory PgcTimeline.fromJson(Map<String, dynamic> json) => PgcTimeline(
code: json['code'] as int?,
message: json['message'] as String?,
result: (json['result'] as List<dynamic>?)
?.map((e) => Result.fromJson(e as Map<String, dynamic>))
.toList(),
);
Map<String, dynamic> toJson() => {
'code': code,
'message': message,
'result': result?.map((e) => e.toJson()).toList(),
};
}

View File

@@ -0,0 +1,35 @@
import 'episode.dart';
class Result {
String? date;
int? dateTs;
int? dayOfWeek;
List<Episode>? episodes;
int? isToday;
Result({
this.date,
this.dateTs,
this.dayOfWeek,
this.episodes,
this.isToday,
});
factory Result.fromJson(Map<String, dynamic> json) => Result(
date: json['date'] as String?,
dateTs: json['date_ts'] as int?,
dayOfWeek: json['day_of_week'] as int?,
episodes: (json['episodes'] as List<dynamic>?)
?.map((e) => Episode.fromJson(e as Map<String, dynamic>))
.toList(),
isToday: json['is_today'] as int?,
);
Map<String, dynamic> toJson() => {
'date': date,
'date_ts': dateTs,
'day_of_week': dayOfWeek,
'episodes': episodes?.map((e) => e.toJson()).toList(),
'is_today': isToday,
};
}

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,108 +48,148 @@ 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: [
_buildFollow,
if (widget.tabType == TabType.bangumi)
SliverToBoxAdapter(
child: Obx(
() => controller.isLogin.value
? Column(
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)),
),
),
..._buildRcmd,
],
),
);
}
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: [
Padding(
padding: const EdgeInsets.only(left: 16),
child: Row(
Row(
children: [
Obx(
() => Text(
'最近${widget.tabType == TabType.bangumi ? '追番' : '追剧'}${controller.followCount.value == -1 ? '' : ' ${controller.followCount.value}'}',
style:
Theme.of(context).textTheme.titleMedium,
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 Spacer(),
IconButton(
tooltip: '刷新',
onPressed: () {
controller
..followPage = 1
..followEnd = false
..queryBangumiFollow();
},
icon: const Icon(
Icons.refresh,
size: 20,
),
],
),
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],
),
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,
);
}).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,
),
),
SizedBox(
height: Grid.smallCardWidth / 2 / 0.75 +
MediaQuery.textScalerOf(context).scale(50),
child: Obx(
() =>
_buildFollowBody(controller.followState.value),
),
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),
),
),
],
)
: const SizedBox.shrink(),
),
),
SliverToBoxAdapter(
];
Widget get _buildRcmdTitle => SliverToBoxAdapter(
child: Padding(
padding: const EdgeInsets.only(
top: 10,
@@ -224,20 +267,10 @@ class _BangumiPageState extends CommonPageState<BangumiPage, BangumiController>
],
),
),
),
SliverPadding(
padding: const EdgeInsets.fromLTRB(
StyleString.safeSpace, 0, StyleString.safeSpace, 0),
sliver: Obx(
() => _buildBody(controller.loadingState.value),
),
),
],
),
);
}
Widget _buildBody(LoadingState<List<BangumiListItemModel>?> loadingState) {
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(
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 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?.isNotEmpty == true
? MediaQuery.removePadding(
context: context,
removeLeft: context.orientation == Orientation.landscape,
child: ListView.builder(
controller: controller.followController,
scrollDirection: Axis.horizontal,
itemCount: loadingState.response.length,
itemCount: loadingState.response!.length,
itemBuilder: (context, index) {
if (index == loadingState.response.length - 1) {
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
right: index == loadingState.response!.length - 1
? StyleString.safeSpace
: 0,
),
child: BangumiCardV(
bangumiItem: loadingState.response[index],
bangumiItem: loadingState.response![index],
),
);
},
);
}
Widget _buildFollowBody(LoadingState loadingState) {
return switch (loadingState) {
Loading() => loadingWidget,
Success() => (loadingState.response as List?)?.isNotEmpty == true
? _buildFollowList(loadingState)
),
)
: 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,7 +50,6 @@ class BangumiCardV extends StatelessWidget {
height: maxHeight,
),
),
if (bangumiItem.badge != null)
PBadge(
text: bangumiItem.badge,
top: 6,
@@ -97,10 +97,7 @@ class BangumiCardV extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start,
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
Expanded(
child: Text(
Text(
bangumiItem.title,
textAlign: TextAlign.start,
style: const TextStyle(
@@ -108,8 +105,6 @@ class BangumiCardV extends StatelessWidget {
),
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,10 +95,7 @@ Widget bangumiContent(Item bangumiItem) {
crossAxisAlignment: CrossAxisAlignment.start,
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
Expanded(
child: Text(
Text(
bangumiItem.title,
textAlign: TextAlign.start,
style: const TextStyle(
@@ -105,8 +103,6 @@ Widget bangumiContent(Item bangumiItem) {
),
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,8 +45,6 @@ class BangumiCardVPgcIndex extends StatelessWidget {
width: maxWidth,
height: maxHeight,
),
if (bangumiItem['badge'] != null &&
bangumiItem['badge'] != '')
PBadge(
text: bangumiItem['badge'],
top: 6,
@@ -53,8 +52,6 @@ class BangumiCardVPgcIndex extends StatelessWidget {
bottom: null,
left: null,
),
if (bangumiItem['order'] != null &&
bangumiItem['order'] != '')
PBadge(
text: bangumiItem['order'],
top: null,
@@ -86,10 +83,7 @@ class BangumiCardVPgcIndex extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start,
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
Expanded(
child: Text(
Text(
bangumiItem['title'],
textAlign: TextAlign.start,
style: const TextStyle(
@@ -97,8 +91,6 @@ class BangumiCardVPgcIndex extends StatelessWidget {
),
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,14 +516,11 @@ 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'],
?['text'],
)
],
),

View File

@@ -65,7 +65,6 @@ class FavPgcItem extends StatelessWidget {
width: boxConstraints.maxWidth,
height: boxConstraints.maxHeight,
),
if (item.badge?.isNotEmpty == true)
PBadge(
right: 4,
top: 4,

View File

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

View File

@@ -186,7 +186,10 @@ class _LivePageState extends CommonPageState<LivePage, LiveController>
child: loadingWidget,
),
Success() => (loadingState.response as List?)?.isNotEmpty == true
? SelfSizedHorizontalList(
? MediaQuery.removePadding(
context: context,
removeLeft: context.orientation == Orientation.landscape,
child: SelfSizedHorizontalList(
gapSize: 5,
childBuilder: (index) {
if (index == loadingState.response.length - 1) {
@@ -233,12 +236,12 @@ class _LivePageState extends CommonPageState<LivePage, LiveController>
src: loadingState.response[index].face,
),
),
const SizedBox(height: 2),
const SizedBox(height: 4),
Text(
loadingState.response[index].uname,
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: TextStyle(fontSize: 11),
style: TextStyle(fontSize: 12),
textAlign: TextAlign.center,
),
],
@@ -247,6 +250,7 @@ class _LivePageState extends CommonPageState<LivePage, LiveController>
);
},
itemCount: loadingState.response.length,
),
)
: const SizedBox.shrink(),
Error() => GestureDetector(

View File

@@ -60,7 +60,6 @@ Widget searchBangumiPanel(
height: 148,
src: i.cover,
),
if (i.seasonTypeName?.isNotEmpty == true)
PBadge(
text: i.seasonTypeName,
top: 6.0,