diff --git a/lib/common/widgets/stat/stat.dart b/lib/common/widgets/stat/stat.dart
index 94e05f456..53780027f 100644
--- a/lib/common/widgets/stat/stat.dart
+++ b/lib/common/widgets/stat/stat.dart
@@ -23,6 +23,7 @@ class StatWidget extends StatelessWidget {
Theme.of(context).colorScheme.outline.withValues(alpha: 0.8);
return Row(
spacing: 2,
+ mainAxisSize: MainAxisSize.min,
children: [
Icon(
type.iconData,
diff --git a/lib/models_new/pgc/pgc_info_model/brief.dart b/lib/models_new/pgc/pgc_info_model/brief.dart
new file mode 100644
index 000000000..06b067a3c
--- /dev/null
+++ b/lib/models_new/pgc/pgc_info_model/brief.dart
@@ -0,0 +1,26 @@
+class Brief {
+ List
? img;
+
+ Brief({
+ this.img,
+ });
+
+ factory Brief.fromJson(Map json) => Brief(
+ img: (json['img'] as List?)?.map((e) => Img.fromJson(e)).toList(),
+ );
+}
+
+class Img {
+ num? aspectRatio;
+ String? url;
+
+ Img({
+ this.aspectRatio,
+ this.url,
+ });
+
+ factory Img.fromJson(Map json) => Img(
+ aspectRatio: json['aspect_ratio'],
+ url: json['url'] as String?,
+ );
+}
diff --git a/lib/models_new/pgc/pgc_info_model/cooperator.dart b/lib/models_new/pgc/pgc_info_model/cooperator.dart
new file mode 100644
index 000000000..583c5196f
--- /dev/null
+++ b/lib/models_new/pgc/pgc_info_model/cooperator.dart
@@ -0,0 +1,20 @@
+class Cooperator {
+ int? mid;
+ String? avatar;
+ String? nickName;
+ String? role;
+
+ Cooperator({
+ this.mid,
+ this.avatar,
+ this.nickName,
+ this.role,
+ });
+
+ factory Cooperator.fromJson(Map json) => Cooperator(
+ mid: json['mid'] as int?,
+ avatar: json['avatar'] as String?,
+ nickName: json['nick_name'] as String?,
+ role: json['role'] as String?,
+ );
+}
diff --git a/lib/models_new/pgc/pgc_info_model/result.dart b/lib/models_new/pgc/pgc_info_model/result.dart
index 6bdc9da27..7d529e5e5 100644
--- a/lib/models_new/pgc/pgc_info_model/result.dart
+++ b/lib/models_new/pgc/pgc_info_model/result.dart
@@ -1,5 +1,7 @@
import 'package:PiliPlus/models_new/pgc/pgc_info_model/activity.dart';
import 'package:PiliPlus/models_new/pgc/pgc_info_model/area.dart';
+import 'package:PiliPlus/models_new/pgc/pgc_info_model/brief.dart';
+import 'package:PiliPlus/models_new/pgc/pgc_info_model/cooperator.dart';
import 'package:PiliPlus/models_new/pgc/pgc_info_model/episode.dart';
import 'package:PiliPlus/models_new/pgc/pgc_info_model/icon_font.dart';
import 'package:PiliPlus/models_new/pgc/pgc_info_model/new_ep.dart';
@@ -53,6 +55,8 @@ class PgcInfoModel {
int? type;
UpInfo? upInfo;
UserStatus? userStatus;
+ List? cooperators;
+ Brief? brief;
PgcInfoModel({
this.activity,
@@ -94,6 +98,8 @@ class PgcInfoModel {
this.type,
this.upInfo,
this.userStatus,
+ this.cooperators,
+ this.brief,
});
factory PgcInfoModel.fromJson(Map json) => PgcInfoModel(
@@ -164,5 +170,11 @@ class PgcInfoModel {
userStatus: json['user_status'] == null
? null
: UserStatus.fromJson(json['user_status'] as Map),
+ cooperators: (json['cooperators'] as List?)
+ ?.map((e) => Cooperator.fromJson(e))
+ .toList(),
+ brief: json['brief'] == null
+ ? null
+ : Brief.fromJson(json['brief'] as Map),
);
}
diff --git a/lib/pages/common/multi_select/base.dart b/lib/pages/common/multi_select/base.dart
index f012f3958..fe0ac96c9 100644
--- a/lib/pages/common/multi_select/base.dart
+++ b/lib/pages/common/multi_select/base.dart
@@ -81,13 +81,10 @@ mixin DeleteItemMixin
} else {
list.removeWhere(removeList.contains);
}
- if (list.isNotEmpty) {
- loadingState.refresh();
- } else if (!isEnd) {
+ if (!isEnd) {
onReload();
} else {
- // empty && end
- loadingState.value = const Success(null);
+ loadingState.refresh();
}
if (enableMultiSelect.value) {
rxCount.value = 0;
diff --git a/lib/pages/mine/view.dart b/lib/pages/mine/view.dart
index d3af70199..aef6385a7 100644
--- a/lib/pages/mine/view.dart
+++ b/lib/pages/mine/view.dart
@@ -329,6 +329,7 @@ class _MediaPageState extends CommonPageState
alpha: 0.4,
),
valueColor: AlwaysStoppedAnimation(secondary),
+ stopIndicatorColor: Colors.transparent,
),
),
],
diff --git a/lib/pages/video/introduction/pgc/view.dart b/lib/pages/video/introduction/pgc/view.dart
index 26b1fba52..ff8be74c4 100644
--- a/lib/pages/video/introduction/pgc/view.dart
+++ b/lib/pages/video/introduction/pgc/view.dart
@@ -1,4 +1,5 @@
import 'dart:async';
+import 'dart:math';
import 'package:PiliPlus/common/constants.dart';
import 'package:PiliPlus/common/widgets/badge.dart';
@@ -6,6 +7,7 @@ import 'package:PiliPlus/common/widgets/dialog/dialog.dart';
import 'package:PiliPlus/common/widgets/image/network_img_layer.dart';
import 'package:PiliPlus/common/widgets/stat/stat.dart';
import 'package:PiliPlus/models/common/image_preview_type.dart';
+import 'package:PiliPlus/models/common/image_type.dart';
import 'package:PiliPlus/models/common/stat_type.dart';
import 'package:PiliPlus/models_new/pgc/pgc_info_model/result.dart';
import 'package:PiliPlus/pages/video/controller.dart';
@@ -70,6 +72,43 @@ class _PgcIntroPageState extends State
final ThemeData theme = Theme.of(context);
final item = pgcIntroController.pgcItem;
final isLandscape = context.isLandscape;
+ Widget sliver = SliverToBoxAdapter(
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Row(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ spacing: 10,
+ children: [
+ _buildCover(isLandscape, item),
+ Expanded(child: _buildInfoPanel(isLandscape, theme, item)),
+ ],
+ ),
+ const SizedBox(height: 6),
+ // 点赞收藏转发 布局样式2
+ if (pgcIntroController.isPgc)
+ actionGrid(theme, item, pgcIntroController),
+ // 番剧分集
+ if (item.episodes?.isNotEmpty == true)
+ PgcPanel(
+ heroTag: widget.heroTag,
+ pages: item.episodes!,
+ cid: videoDetailCtr.cid.value,
+ onChangeEpisode: pgcIntroController.onChangeEpisode,
+ showEpisodes: widget.showEpisodes,
+ newEp: item.newEp,
+ ),
+ ],
+ ),
+ );
+ if (!pgcIntroController.isPgc) {
+ sliver = SliverMainAxisGroup(
+ slivers: [
+ sliver,
+ ?_buildBreif(item),
+ ],
+ );
+ }
return SliverPadding(
padding: EdgeInsets.only(
left: StyleString.safeSpace,
@@ -77,216 +116,281 @@ class _PgcIntroPageState extends State
top: StyleString.safeSpace,
bottom: StyleString.safeSpace + MediaQuery.paddingOf(context).bottom,
),
- sliver: SliverToBoxAdapter(
- child: Column(
- crossAxisAlignment: CrossAxisAlignment.start,
- children: [
- Row(
- crossAxisAlignment: CrossAxisAlignment.start,
- spacing: 10,
- children: [
- Stack(
- clipBehavior: Clip.none,
- children: [
- GestureDetector(
- onTap: () {
- videoDetailCtr.onViewImage();
- PageUtils.imageView(
- imgList: [
- SourceModel(
- url: item.cover!,
- ),
- ],
- onDismissed: videoDetailCtr.onDismissed,
- );
- },
- child: Hero(
- tag: item.cover!,
- child: NetworkImgLayer(
- width: isLandscape ? 115 / 0.75 : 115,
- height: isLandscape ? 115 : 115 / 0.75,
- src: item.cover!,
- semanticsLabel: '封面',
- ),
- ),
- ),
- if (item.rating != null)
- PBadge(
- text: '评分 ${item.rating!.score!}',
- top: null,
- right: 6,
- bottom: 6,
- left: null,
- ),
- ],
- ),
- Expanded(
- child: !pgcIntroController.isPgc
- ? Column(
- crossAxisAlignment: CrossAxisAlignment.start,
- children: [
- Text(
- item.title!,
- style: const TextStyle(fontSize: 16),
- ),
- const SizedBox(height: 5),
- if (item.subtitle?.isNotEmpty == true)
- Text(
- item.subtitle!,
- style: TextStyle(
- fontSize: 13,
- color: theme.colorScheme.onSurfaceVariant,
- ),
- ),
- ],
- )
- : GestureDetector(
- onTap: () => widget.showIntroDetail(
- item,
- pgcIntroController.videoTags.value,
- ),
- behavior: HitTestBehavior.opaque,
- child: SizedBox(
- height: isLandscape ? 115 : 115 / 0.75,
- child: Column(
- crossAxisAlignment: CrossAxisAlignment.start,
- mainAxisSize: MainAxisSize.min,
- children: [
- Row(
- crossAxisAlignment: CrossAxisAlignment.start,
- spacing: 20,
- children: [
- Expanded(
- child: Text(
- item.title!,
- style: const TextStyle(
- fontSize: 16,
- ),
- maxLines: 1,
- overflow: TextOverflow.ellipsis,
- ),
- ),
- Obx(
- () {
- final isFollowed =
- pgcIntroController.isFollowed.value;
- final followStatus = pgcIntroController
- .followStatus
- .value;
- return FilledButton.tonal(
- style: FilledButton.styleFrom(
- tapTargetSize: MaterialTapTargetSize
- .shrinkWrap,
- padding: const EdgeInsets.symmetric(
- horizontal: 20,
- vertical: 10,
- ),
- visualDensity:
- VisualDensity.compact,
- foregroundColor: isFollowed
- ? theme.colorScheme.outline
- : null,
- backgroundColor: isFollowed
- ? theme
- .colorScheme
- .onInverseSurface
- : null,
- ),
- onPressed: followStatus == -1
- ? null
- : () {
- if (isFollowed) {
- showPgcFollowDialog(
- context: context,
- type: pgcIntroController
- .pgcType,
- followStatus:
- followStatus,
- onUpdateStatus:
- (followStatus) {
- if (followStatus ==
- -1) {
- pgcIntroController
- .pgcDel();
- } else {
- pgcIntroController
- .pgcUpdate(
- followStatus,
- );
- }
- },
- );
- } else {
- pgcIntroController.pgcAdd();
- }
- },
- child: Text(
- isFollowed
- ? '已${pgcIntroController.pgcType}'
- : pgcIntroController.pgcType,
- ),
- );
- },
- ),
- ],
- ),
- Row(
- spacing: 6,
- children: [
- StatWidget(
- type: StatType.play,
- value: item.stat!.view,
- ),
- StatWidget(
- type: StatType.danmaku,
- value: item.stat!.danmaku,
- ),
- if (isLandscape) ...[
- areasAndPubTime(theme, item),
- newEpDesc(theme, item),
- ],
- ],
- ),
- SizedBox(height: isLandscape ? 2 : 6),
- if (!isLandscape) ...[
- areasAndPubTime(theme, item),
- newEpDesc(theme, item),
- ],
- const Spacer(),
- Text(
- '简介:${item.evaluate}',
- maxLines: isLandscape ? 2 : 3,
- overflow: TextOverflow.ellipsis,
- style: TextStyle(
- fontSize: 13,
- color: theme.colorScheme.outline,
- ),
- ),
- ],
- ),
- ),
- ),
- ),
- ],
+ sliver: sliver,
+ );
+ }
+
+ Widget? _buildBreif(PgcInfoModel item) {
+ final img = item.brief?.img;
+ if (img != null && img.isNotEmpty) {
+ return SliverLayoutBuilder(
+ builder: (context, constraints) {
+ final maxWidth = constraints.crossAxisExtent;
+ double padding = max(0, maxWidth - 400);
+ final imgWidth = maxWidth - padding;
+ padding = padding / 2;
+ return SliverPadding(
+ padding: EdgeInsetsGeometry.only(
+ top: 10,
+ left: padding,
+ right: padding,
),
- const SizedBox(height: 6),
- // 点赞收藏转发 布局样式2
- if (pgcIntroController.isPgc)
- actionGrid(theme, item, pgcIntroController),
- // 番剧分p
- if (item.episodes!.isNotEmpty) ...[
- PgcPanel(
- heroTag: widget.heroTag,
- pages: item.episodes!,
- cid: videoDetailCtr.cid.value,
- onChangeEpisode: pgcIntroController.onChangeEpisode,
- showEpisodes: widget.showEpisodes,
- newEp: item.newEp,
+ sliver: SliverMainAxisGroup(
+ slivers: img.map((e) {
+ return SliverToBoxAdapter(
+ child: NetworkImgLayer(
+ radius: 0,
+ src: e.url,
+ width: imgWidth,
+ ),
+ );
+ }).toList(),
+ ),
+ );
+ },
+ );
+ }
+ return null;
+ }
+
+ Widget _buildCover(bool isLandscape, PgcInfoModel item) {
+ return Stack(
+ clipBehavior: Clip.none,
+ children: [
+ GestureDetector(
+ onTap: () {
+ videoDetailCtr.onViewImage();
+ PageUtils.imageView(
+ imgList: [SourceModel(url: item.cover!)],
+ onDismissed: videoDetailCtr.onDismissed,
+ );
+ },
+ child: Hero(
+ tag: item.cover!,
+ child: NetworkImgLayer(
+ width: 115,
+ height: 153,
+ src: item.cover!,
+ semanticsLabel: '封面',
+ ),
+ ),
+ ),
+ if (item.rating != null)
+ PBadge(
+ text: '评分 ${item.rating!.score!}',
+ top: null,
+ right: 6,
+ bottom: 6,
+ left: null,
+ ),
+ ],
+ );
+ }
+
+ Widget _buildInfoPanel(bool isLandscape, ThemeData theme, PgcInfoModel item) {
+ if (pgcIntroController.isPgc) {
+ Widget subBtn() => Obx(
+ () {
+ final isFollowed = pgcIntroController.isFollowed.value;
+ final followStatus = pgcIntroController.followStatus.value;
+ return FilledButton.tonal(
+ style: FilledButton.styleFrom(
+ tapTargetSize: MaterialTapTargetSize.shrinkWrap,
+ padding: const EdgeInsets.symmetric(
+ horizontal: 20,
+ vertical: 10,
+ ),
+ visualDensity: VisualDensity.compact,
+ foregroundColor: isFollowed ? theme.colorScheme.outline : null,
+ backgroundColor: isFollowed
+ ? theme.colorScheme.onInverseSurface
+ : null,
+ ),
+ onPressed: followStatus == -1
+ ? null
+ : () {
+ if (isFollowed) {
+ showPgcFollowDialog(
+ context: context,
+ type: pgcIntroController.pgcType,
+ followStatus: followStatus,
+ onUpdateStatus: (followStatus) {
+ if (followStatus == -1) {
+ pgcIntroController.pgcDel();
+ } else {
+ pgcIntroController.pgcUpdate(
+ followStatus,
+ );
+ }
+ },
+ );
+ } else {
+ pgcIntroController.pgcAdd();
+ }
+ },
+ child: Text(
+ isFollowed
+ ? '已${pgcIntroController.pgcType}'
+ : pgcIntroController.pgcType,
+ ),
+ );
+ },
+ );
+ Widget title() => Row(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ spacing: 20,
+ children: [
+ Expanded(
+ child: Text(
+ item.title!,
+ style: const TextStyle(fontSize: 16),
+ maxLines: 1,
+ overflow: TextOverflow.ellipsis,
+ ),
+ ),
+ subBtn(),
+ ],
+ );
+ List desc() => [
+ Text(
+ item.newEp!.desc!,
+ style: TextStyle(
+ fontSize: 12,
+ color: theme.colorScheme.outline,
+ ),
+ ),
+ Text.rich(
+ TextSpan(
+ children: [
+ if (item.areas?.isNotEmpty == true)
+ TextSpan(text: '${item.areas!.first.name!} '),
+ TextSpan(
+ text: item.publish!.pubTimeShow!,
),
],
- ],
+ ),
+ style: TextStyle(
+ fontSize: 12,
+ color: theme.colorScheme.outline,
+ ),
),
- ),
+ ];
+ Widget stat() => Wrap(
+ spacing: 6,
+ runSpacing: 2,
+ children: [
+ StatWidget(
+ type: StatType.play,
+ value: item.stat!.view,
+ ),
+ StatWidget(
+ type: StatType.danmaku,
+ value: item.stat!.danmaku,
+ ),
+ if (isLandscape) ...desc(),
+ ],
+ );
+ return GestureDetector(
+ onTap: () => widget.showIntroDetail(
+ item,
+ pgcIntroController.videoTags.value,
+ ),
+ behavior: HitTestBehavior.opaque,
+ child: SizedBox(
+ height: 153,
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ title(),
+ stat(),
+ const SizedBox(height: 5),
+ if (!isLandscape) ...desc(),
+ const SizedBox(height: 5),
+ Expanded(
+ child: Text(
+ '简介:${item.evaluate}',
+ style: TextStyle(
+ fontSize: 13,
+ color: theme.colorScheme.outline,
+ ),
+ ),
+ ),
+ ],
+ ),
+ ),
+ );
+ }
+
+ // pugv
+ Widget upInfo(int mid, String avatar, String name, {String? role}) =>
+ GestureDetector(
+ behavior: HitTestBehavior.opaque,
+ onTap: () => Get.toNamed('/member?mid=$mid'),
+ child: Row(
+ spacing: 8,
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ NetworkImgLayer(
+ src: avatar,
+ width: 35,
+ height: 35,
+ type: ImageType.avatar,
+ ),
+ Column(
+ mainAxisSize: MainAxisSize.min,
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Text(name),
+ if (role?.isNotEmpty == true)
+ Text(
+ role!,
+ style: TextStyle(
+ fontSize: 12,
+ color: theme.colorScheme.outline,
+ ),
+ ),
+ ],
+ ),
+ ],
+ ),
+ );
+ return Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ if (item.cooperators?.isNotEmpty == true) ...[
+ SingleChildScrollView(
+ scrollDirection: Axis.horizontal,
+ child: Row(
+ spacing: 25,
+ children: item.cooperators!.map((e) {
+ return upInfo(e.mid!, e.avatar!, e.nickName!, role: e.role);
+ }).toList(),
+ ),
+ ),
+ const SizedBox(height: 6),
+ ] else if (item.upInfo?.mid != null) ...[
+ upInfo(
+ item.upInfo!.mid!,
+ item.upInfo!.avatar!,
+ item.upInfo!.uname!,
+ ),
+ const SizedBox(height: 8),
+ ],
+ Text(
+ item.title!,
+ style: const TextStyle(fontSize: 16),
+ ),
+ if (item.subtitle?.isNotEmpty == true) ...[
+ const SizedBox(height: 5),
+ Text(
+ item.subtitle!,
+ style: TextStyle(
+ fontSize: 13,
+ color: theme.colorScheme.onSurfaceVariant,
+ ),
+ ),
+ ],
+ ],
);
}
@@ -374,37 +478,4 @@ class _PgcIntroPageState extends State
),
);
}
-
- Widget areasAndPubTime(ThemeData theme, PgcInfoModel item) {
- return Row(
- spacing: 6,
- children: [
- if (item.areas?.isNotEmpty == true)
- Text(
- item.areas!.first.name!,
- style: TextStyle(
- fontSize: 12,
- color: theme.colorScheme.outline,
- ),
- ),
- Text(
- item.publish!.pubTimeShow!,
- style: TextStyle(
- fontSize: 12,
- color: theme.colorScheme.outline,
- ),
- ),
- ],
- );
- }
-
- Widget newEpDesc(ThemeData theme, PgcInfoModel item) {
- return Text(
- item.newEp!.desc!,
- style: TextStyle(
- fontSize: 12,
- color: theme.colorScheme.outline,
- ),
- );
- }
}