Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
This commit is contained in:
bggRGjQaUbCoE
2025-06-13 11:49:38 +08:00
parent f824477ddb
commit c05fbde3fa
106 changed files with 2780 additions and 3200 deletions

View File

@@ -12,7 +12,6 @@ import 'package:PiliPlus/pages/video/controller.dart';
import 'package:PiliPlus/pages/video/introduction/pgc/controller.dart';
import 'package:PiliPlus/pages/video/introduction/pgc/widgets/pgc_panel.dart';
import 'package:PiliPlus/pages/video/introduction/ugc/widgets/action_item.dart';
import 'package:PiliPlus/pages/video/introduction/ugc/widgets/action_row_item.dart';
import 'package:PiliPlus/utils/extension.dart';
import 'package:PiliPlus/utils/utils.dart';
import 'package:flutter/material.dart';
@@ -261,148 +260,86 @@ class _PgcIntroPageState extends State<PgcIntroPage>
Widget actionGrid(ThemeData theme, PgcInfoModel item,
PgcIntroController pgcIntroController) {
return Material(
color: theme.colorScheme.surface,
child: Padding(
padding: const EdgeInsets.only(top: 1),
child: SizedBox(
height: 48,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
Obx(
() => ActionItem(
icon: const Icon(FontAwesomeIcons.thumbsUp),
selectIcon: const Icon(FontAwesomeIcons.solidThumbsUp),
onTap: () => handleState(pgcIntroController.actionLikeVideo),
onLongPress: pgcIntroController.actionOneThree,
selectStatus: pgcIntroController.hasLike.value,
isLoading: false,
semanticsLabel: '点赞',
text: Utils.numFormat(item.stat!.likes),
needAnim: true,
hasTriple: pgcIntroController.hasLike.value &&
pgcIntroController.hasCoin &&
pgcIntroController.hasFav.value,
callBack: (start) {
if (start) {
HapticFeedback.lightImpact();
_coinKey.currentState?.controller?.forward();
_favKey.currentState?.controller?.forward();
} else {
_coinKey.currentState?.controller?.reverse();
_favKey.currentState?.controller?.reverse();
}
},
),
),
Obx(
() => ActionItem(
key: _coinKey,
icon: const Icon(FontAwesomeIcons.b),
selectIcon: const Icon(FontAwesomeIcons.b),
onTap: () => handleState(pgcIntroController.actionCoinVideo),
selectStatus: pgcIntroController.hasCoin,
isLoading: false,
semanticsLabel: '投币',
text: Utils.numFormat(item.stat!.coins),
needAnim: true,
),
),
Obx(
() => ActionItem(
key: _favKey,
icon: const Icon(FontAwesomeIcons.star),
selectIcon: const Icon(FontAwesomeIcons.solidStar),
onTap: () => pgcIntroController.showFavBottomSheet(context),
onLongPress: () => pgcIntroController
.showFavBottomSheet(context, type: 'longPress'),
selectStatus: pgcIntroController.hasFav.value,
isLoading: false,
semanticsLabel: '收藏',
text: Utils.numFormat(item.stat!.favorite),
needAnim: true,
),
),
ActionItem(
icon: const Icon(FontAwesomeIcons.comment),
selectIcon: const Icon(FontAwesomeIcons.reply),
onTap: () => videoDetailCtr.tabCtr.animateTo(1),
selectStatus: false,
isLoading: false,
semanticsLabel: '评论',
text: Utils.numFormat(item.stat!.reply),
),
ActionItem(
icon: const Icon(FontAwesomeIcons.shareFromSquare),
onTap: () => pgcIntroController.actionShareVideo(context),
selectStatus: false,
isLoading: false,
semanticsLabel: '转发',
text: Utils.numFormat(item.stat!.share),
),
],
return SizedBox(
height: 48,
child: Row(
children: [
Obx(
() => ActionItem(
icon: const Icon(FontAwesomeIcons.thumbsUp),
selectIcon: const Icon(FontAwesomeIcons.solidThumbsUp),
onTap: () => handleState(pgcIntroController.actionLikeVideo),
onLongPress: pgcIntroController.actionOneThree,
selectStatus: pgcIntroController.hasLike.value,
isLoading: false,
semanticsLabel: '点赞',
text: Utils.numFormat(item.stat!.likes),
needAnim: true,
hasTriple: pgcIntroController.hasLike.value &&
pgcIntroController.hasCoin &&
pgcIntroController.hasFav.value,
callBack: (start) {
if (start) {
HapticFeedback.lightImpact();
_coinKey.currentState?.controller?.forward();
_favKey.currentState?.controller?.forward();
} else {
_coinKey.currentState?.controller?.reverse();
_favKey.currentState?.controller?.reverse();
}
},
),
),
),
Obx(
() => ActionItem(
key: _coinKey,
icon: const Icon(FontAwesomeIcons.b),
selectIcon: const Icon(FontAwesomeIcons.b),
onTap: () => handleState(pgcIntroController.actionCoinVideo),
selectStatus: pgcIntroController.hasCoin,
isLoading: false,
semanticsLabel: '投币',
text: Utils.numFormat(item.stat!.coins),
needAnim: true,
),
),
Obx(
() => ActionItem(
key: _favKey,
icon: const Icon(FontAwesomeIcons.star),
selectIcon: const Icon(FontAwesomeIcons.solidStar),
onTap: () => pgcIntroController.showFavBottomSheet(context),
onLongPress: () => pgcIntroController.showFavBottomSheet(context,
type: 'longPress'),
selectStatus: pgcIntroController.hasFav.value,
isLoading: false,
semanticsLabel: '收藏',
text: Utils.numFormat(item.stat!.favorite),
needAnim: true,
),
),
ActionItem(
icon: const Icon(FontAwesomeIcons.comment),
selectIcon: const Icon(FontAwesomeIcons.reply),
onTap: () => videoDetailCtr.tabCtr.animateTo(1),
selectStatus: false,
isLoading: false,
semanticsLabel: '评论',
text: Utils.numFormat(item.stat!.reply),
),
ActionItem(
icon: const Icon(FontAwesomeIcons.shareFromSquare),
onTap: () => pgcIntroController.actionShareVideo(context),
selectStatus: false,
isLoading: false,
semanticsLabel: '转发',
text: Utils.numFormat(item.stat!.share),
),
],
),
);
}
Widget actionRow(
PgcInfoModel item,
PgcIntroController pgcIntroController,
VideoDetailController videoDetailCtr,
) {
return Row(
spacing: 8,
children: [
Obx(
() => ActionRowItem(
icon: const Icon(FontAwesomeIcons.thumbsUp),
onTap: () => handleState(pgcIntroController.actionLikeVideo),
selectStatus: pgcIntroController.hasLike.value,
isLoading: false,
text: item.stat!.likes!.toString(),
),
),
Obx(
() => ActionRowItem(
icon: const Icon(FontAwesomeIcons.b),
onTap: () => handleState(pgcIntroController.actionCoinVideo),
selectStatus: pgcIntroController.hasCoin,
isLoading: false,
text: item.stat!.coins!.toString(),
),
),
Obx(
() => ActionRowItem(
icon: const Icon(FontAwesomeIcons.heart),
onTap: () => pgcIntroController.showFavBottomSheet(context),
onLongPress: () => pgcIntroController.showFavBottomSheet(context,
type: 'longPress'),
selectStatus: pgcIntroController.hasFav.value,
isLoading: false,
text: item.stat!.favorite!.toString(),
),
),
ActionRowItem(
icon: const Icon(FontAwesomeIcons.comment),
onTap: () => videoDetailCtr.tabCtr.animateTo(1),
selectStatus: false,
isLoading: false,
text: item.stat!.reply!.toString(),
),
ActionRowItem(
icon: const Icon(FontAwesomeIcons.share),
onTap: () => pgcIntroController.actionShareVideo(context),
selectStatus: false,
isLoading: false,
text: '转发',
),
],
);
}
Widget areasAndPubTime(ThemeData theme, PgcInfoModel item) {
return Row(
spacing: 6,

View File

@@ -144,8 +144,8 @@ class _PgcPanelState extends State<PgcPanel> {
child: Material(
color: theme.colorScheme.onInverseSurface,
borderRadius: const BorderRadius.all(Radius.circular(6)),
clipBehavior: Clip.hardEdge,
child: InkWell(
borderRadius: const BorderRadius.all(Radius.circular(6)),
onTap: () {
if (item.badge != null &&
item.badge == '会员' &&

View File

@@ -13,7 +13,6 @@ import 'package:PiliPlus/pages/search/widgets/search_text.dart';
import 'package:PiliPlus/pages/video/controller.dart';
import 'package:PiliPlus/pages/video/introduction/ugc/controller.dart';
import 'package:PiliPlus/pages/video/introduction/ugc/widgets/action_item.dart';
import 'package:PiliPlus/pages/video/introduction/ugc/widgets/action_row_item.dart';
import 'package:PiliPlus/pages/video/introduction/ugc/widgets/page.dart';
import 'package:PiliPlus/pages/video/introduction/ugc/widgets/season.dart';
import 'package:PiliPlus/utils/app_scheme.dart';
@@ -435,7 +434,9 @@ class _VideoInfoState extends State<VideoInfo> {
'${videoItem['staff'][index].mid}'] ==
null
? Material(
color: Colors.transparent,
type:
MaterialType.transparency,
shape: const CircleBorder(),
child: InkWell(
customBorder:
const CircleBorder(),
@@ -837,11 +838,9 @@ class _VideoInfoState extends State<VideoInfo> {
Widget actionGrid(
BuildContext context, VideoIntroController videoIntroController) {
return Container(
margin: const EdgeInsets.only(top: 1),
return SizedBox(
height: 48,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
Obx(
() => ActionItem(
@@ -941,63 +940,6 @@ class _VideoInfoState extends State<VideoInfo> {
);
}
Widget actionRow(
BuildContext context,
VideoIntroController videoIntroController,
VideoDetailController videoDetailCtr,
) {
return Row(children: <Widget>[
Obx(
() => ActionRowItem(
icon: const Icon(FontAwesomeIcons.thumbsUp),
onTap: () => handleState(videoIntroController.actionLikeVideo),
selectStatus: videoIntroController.hasLike.value,
isLoading: widget.isLoading,
text: !widget.isLoading ? videoDetail.stat!.like!.toString() : '-',
),
),
const SizedBox(width: 8),
Obx(
() => ActionRowItem(
icon: const Icon(FontAwesomeIcons.b),
onTap: () => handleState(videoIntroController.actionCoinVideo),
selectStatus: videoIntroController.hasCoin,
isLoading: widget.isLoading,
text: !widget.isLoading ? videoDetail.stat!.coin!.toString() : '-',
),
),
const SizedBox(width: 8),
Obx(
() => ActionRowItem(
icon: const Icon(FontAwesomeIcons.heart),
onTap: () => videoIntroController.showFavBottomSheet(context),
onLongPress: () => videoIntroController.showFavBottomSheet(context,
type: 'longPress'),
selectStatus: videoIntroController.hasFav.value,
isLoading: widget.isLoading,
text:
!widget.isLoading ? videoDetail.stat!.favorite!.toString() : '-',
),
),
const SizedBox(width: 8),
ActionRowItem(
icon: const Icon(FontAwesomeIcons.comment),
onTap: () => videoDetailCtr.tabCtr.animateTo(1),
selectStatus: false,
isLoading: widget.isLoading,
text: !widget.isLoading ? videoDetail.stat!.reply!.toString() : '-',
),
const SizedBox(width: 8),
ActionRowItem(
icon: const Icon(FontAwesomeIcons.share),
onTap: () => videoIntroController.actionShareVideo(context),
selectStatus: false,
isLoading: widget.isLoading,
text: '转发',
),
]);
}
InlineSpan buildContent(ThemeData theme, VideoDetailData content) {
final List descV2 = content.descV2!;
// type
@@ -1073,15 +1015,11 @@ class _VideoInfoState extends State<VideoInfo> {
return TextSpan(children: spanChildren);
case 2:
final Color colorSchemePrimary = theme.colorScheme.primary;
final String heroTag = Utils.makeHeroTag(currentDesc.bizId);
return TextSpan(
text: '@${currentDesc.rawText}',
style: TextStyle(color: colorSchemePrimary),
recognizer: TapGestureRecognizer()
..onTap = () => Get.toNamed(
'/member?mid=${currentDesc.bizId}',
arguments: {'face': '', 'heroTag': heroTag},
),
..onTap = () => Get.toNamed('/member?mid=${currentDesc.bizId}'),
);
default:
return const TextSpan();

View File

@@ -136,70 +136,73 @@ class ActionItemState extends State<ActionItem>
label: (widget.text ?? "") +
(widget.selectStatus ? "" : "") +
widget.semanticsLabel,
child: InkWell(
borderRadius: const BorderRadius.all(Radius.circular(6)),
onTap: _isThumbsUp
? null
: () {
feedBack();
widget.onTap?.call();
},
onLongPress: _isThumbsUp ? null : widget.onLongPress,
onTapDown: _isThumbsUp ? (details) => _startLongPress() : null,
onTapUp: _isThumbsUp ? (details) => _cancelLongPress() : null,
onTapCancel: _isThumbsUp ? () => _cancelLongPress(true) : null,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Stack(
clipBehavior: Clip.none,
alignment: Alignment.center,
children: [
if (widget.needAnim && !_hideCircle)
CustomPaint(
size: const Size(28, 28),
painter: _ArcPainter(
color: theme.colorScheme.primary,
sweepAngle: _animation!.value,
child: Material(
type: MaterialType.transparency,
child: InkWell(
borderRadius: const BorderRadius.all(Radius.circular(6)),
onTap: _isThumbsUp
? null
: () {
feedBack();
widget.onTap?.call();
},
onLongPress: _isThumbsUp ? null : widget.onLongPress,
onTapDown: _isThumbsUp ? (details) => _startLongPress() : null,
onTapUp: _isThumbsUp ? (details) => _cancelLongPress() : null,
onTapCancel: _isThumbsUp ? () => _cancelLongPress(true) : null,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Stack(
clipBehavior: Clip.none,
alignment: Alignment.center,
children: [
if (widget.needAnim && !_hideCircle)
CustomPaint(
size: const Size(28, 28),
painter: _ArcPainter(
color: theme.colorScheme.primary,
sweepAngle: _animation!.value,
),
)
else
const SizedBox(width: 28, height: 28),
Icon(
widget.selectStatus
? widget.selectIcon!.icon!
: widget.icon.icon,
size: 18,
color: widget.selectStatus
? theme.colorScheme.primary
: widget.icon.color ?? theme.colorScheme.outline,
),
],
),
if (widget.text != null)
AnimatedOpacity(
opacity: widget.isLoading! ? 0 : 1,
duration: const Duration(milliseconds: 200),
child: AnimatedSwitcher(
duration: const Duration(milliseconds: 300),
transitionBuilder:
(Widget child, Animation<double> animation) {
return ScaleTransition(scale: animation, child: child);
},
child: Text(
widget.text!,
key: ValueKey<String>(widget.text!),
style: TextStyle(
color: widget.selectStatus
? theme.colorScheme.primary
: theme.colorScheme.outline,
fontSize: theme.textTheme.labelSmall!.fontSize,
),
semanticsLabel: "",
),
)
else
const SizedBox(width: 28, height: 28),
Icon(
widget.selectStatus
? widget.selectIcon!.icon!
: widget.icon.icon,
size: 18,
color: widget.selectStatus
? theme.colorScheme.primary
: widget.icon.color ?? theme.colorScheme.outline,
),
],
),
if (widget.text != null)
AnimatedOpacity(
opacity: widget.isLoading! ? 0 : 1,
duration: const Duration(milliseconds: 200),
child: AnimatedSwitcher(
duration: const Duration(milliseconds: 300),
transitionBuilder:
(Widget child, Animation<double> animation) {
return ScaleTransition(scale: animation, child: child);
},
child: Text(
widget.text!,
key: ValueKey<String>(widget.text!),
style: TextStyle(
color: widget.selectStatus
? theme.colorScheme.primary
: theme.colorScheme.outline,
fontSize: theme.textTheme.labelSmall!.fontSize,
),
semanticsLabel: "",
),
),
),
],
],
),
),
),
);

View File

@@ -1,79 +0,0 @@
import 'package:PiliPlus/utils/feed_back.dart';
import 'package:flutter/material.dart';
class ActionRowItem extends StatelessWidget {
final Icon? icon;
final Icon? selectIcon;
final Function? onTap;
final bool? isLoading;
final String? text;
final bool selectStatus;
final Function? onLongPress;
const ActionRowItem({
super.key,
this.icon,
this.selectIcon,
this.onTap,
this.isLoading,
this.text,
this.selectStatus = false,
this.onLongPress,
});
@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
return Material(
color: selectStatus
? theme.colorScheme.primaryContainer.withValues(alpha: 0.6)
: theme.highlightColor.withValues(alpha: 0.2),
borderRadius: const BorderRadius.all(Radius.circular(30)),
clipBehavior: Clip.hardEdge,
child: InkWell(
onTap: () => {
feedBack(),
onTap?.call(),
},
onLongPress: () {
feedBack();
onLongPress?.call();
},
child: Padding(
padding: const EdgeInsets.fromLTRB(15, 7, 15, 7),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
if (icon != null) ...[
Icon(icon!.icon!,
size: 13,
color: selectStatus
? theme.colorScheme.primary
: theme.colorScheme.onSecondaryContainer),
const SizedBox(width: 6),
],
AnimatedOpacity(
opacity: isLoading! ? 0 : 1,
duration: const Duration(milliseconds: 200),
child: AnimatedSwitcher(
duration: const Duration(milliseconds: 300),
transitionBuilder:
(Widget child, Animation<double> animation) {
return ScaleTransition(scale: animation, child: child);
},
child: Text(
text ?? '',
key: ValueKey<String>(text ?? ''),
style: TextStyle(
color: selectStatus ? theme.colorScheme.primary : null,
fontSize: theme.textTheme.labelMedium!.fontSize),
),
),
),
],
),
),
),
);
}
}

View File

@@ -1,102 +1,6 @@
import 'package:PiliPlus/utils/feed_back.dart';
import 'package:flutter/material.dart';
class MenuRow extends StatelessWidget {
const MenuRow({
super.key,
this.isLoading,
});
final bool? isLoading;
@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
return Container(
width: double.infinity,
color: theme.colorScheme.surface,
padding: const EdgeInsets.only(top: 9, bottom: 9, left: 12),
child: SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: Row(children: [
ActionRowLineItem(
onTap: () => {},
isLoading: isLoading,
text: '推荐',
selectStatus: false,
),
const SizedBox(width: 8),
ActionRowLineItem(
onTap: () => {},
isLoading: isLoading,
text: '弹幕',
selectStatus: false,
),
const SizedBox(width: 8),
ActionRowLineItem(
onTap: () => {},
isLoading: isLoading,
text: '评论列表',
selectStatus: false,
),
const SizedBox(width: 8),
ActionRowLineItem(
onTap: () => {},
isLoading: isLoading,
text: '播放列表',
selectStatus: false,
),
]),
),
);
}
Widget actionRowLineItem(
ThemeData theme, Function? onTap, bool? isLoading, String? text,
{bool selectStatus = false}) {
return Material(
color: selectStatus
? theme.highlightColor.withValues(alpha: 0.2)
: Colors.transparent,
borderRadius: const BorderRadius.all(Radius.circular(30)),
clipBehavior: Clip.hardEdge,
child: InkWell(
onTap: () => {
feedBack(),
onTap?.call(),
},
child: Container(
padding: const EdgeInsets.fromLTRB(13, 5.5, 13, 4.5),
decoration: BoxDecoration(
borderRadius: const BorderRadius.all(Radius.circular(30)),
border: Border.all(
color: selectStatus
? Colors.transparent
: theme.highlightColor.withValues(alpha: 0.2),
),
),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
AnimatedOpacity(
opacity: isLoading! ? 0 : 1,
duration: const Duration(milliseconds: 200),
child: Text(
text!,
style: TextStyle(
fontSize: 13,
color: selectStatus
? theme.colorScheme.onSurface
: theme.colorScheme.outline),
),
),
],
),
),
),
);
}
}
class ActionRowLineItem extends StatelessWidget {
const ActionRowLineItem({
super.key,
@@ -118,12 +22,11 @@ class ActionRowLineItem extends StatelessWidget {
Widget build(BuildContext context) {
final theme = Theme.of(context);
return Material(
color: selectStatus
? theme.colorScheme.secondaryContainer
: Colors.transparent,
color: selectStatus ? theme.colorScheme.secondaryContainer : null,
type: selectStatus ? MaterialType.canvas : MaterialType.transparency,
borderRadius: const BorderRadius.all(Radius.circular(30)),
clipBehavior: Clip.hardEdge,
child: InkWell(
borderRadius: const BorderRadius.all(Radius.circular(30)),
onTap: () => {
feedBack(),
onTap?.call(),

View File

@@ -147,8 +147,8 @@ class _PagesPanelState extends State<PagesPanel> {
child: Material(
color: theme.colorScheme.onInverseSurface,
borderRadius: const BorderRadius.all(Radius.circular(6)),
clipBehavior: Clip.hardEdge,
child: InkWell(
borderRadius: const BorderRadius.all(Radius.circular(6)),
onTap: () {
if (widget.showEpisodes == null) {
Get.back();

View File

@@ -90,68 +90,66 @@ class _SeasonPanelState extends State<SeasonPanel> {
return const SizedBox.shrink();
}
final theme = Theme.of(context);
return Builder(builder: (BuildContext context) {
return Container(
margin: const EdgeInsets.only(
top: 8,
left: 2,
right: 2,
),
child: Material(
color: theme.colorScheme.onInverseSurface,
return Padding(
padding: const EdgeInsets.only(
top: 8,
left: 2,
right: 2,
),
child: Material(
color: theme.colorScheme.onInverseSurface,
borderRadius: const BorderRadius.all(Radius.circular(6)),
child: InkWell(
borderRadius: const BorderRadius.all(Radius.circular(6)),
clipBehavior: Clip.hardEdge,
child: InkWell(
onTap: widget.onTap == false
? null
: () => widget.showEpisodes(
_videoDetailController.seasonIndex.value,
videoDetail.ugcSeason,
null,
_videoDetailController.bvid,
null,
_videoDetailController.seasonCid,
),
child: Padding(
padding: const EdgeInsets.fromLTRB(8, 12, 8, 12),
child: Row(
children: <Widget>[
Expanded(
child: Text(
'合集:${videoDetail.ugcSeason!.title!}',
style: theme.textTheme.labelMedium,
overflow: TextOverflow.ellipsis,
),
onTap: widget.onTap == false
? null
: () => widget.showEpisodes(
_videoDetailController.seasonIndex.value,
videoDetail.ugcSeason,
null,
_videoDetailController.bvid,
null,
_videoDetailController.seasonCid,
),
const SizedBox(width: 15),
Image.asset(
'assets/images/live.png',
color: theme.colorScheme.primary,
height: 12,
semanticLabel: "正在播放:",
child: Padding(
padding: const EdgeInsets.fromLTRB(8, 12, 8, 12),
child: Row(
children: <Widget>[
Expanded(
child: Text(
'合集:${videoDetail.ugcSeason!.title!}',
style: theme.textTheme.labelMedium,
overflow: TextOverflow.ellipsis,
),
const SizedBox(width: 10),
Obx(
() => Text(
'${currentIndex.value + 1}/${episodes.length}',
style: theme.textTheme.labelMedium,
semanticsLabel:
'${currentIndex.value + 1}集,共${episodes.length}',
),
),
const SizedBox(width: 15),
Image.asset(
'assets/images/live.png',
color: theme.colorScheme.primary,
height: 12,
semanticLabel: "正在播放:",
),
const SizedBox(width: 10),
Obx(
() => Text(
'${currentIndex.value + 1}/${episodes.length}',
style: theme.textTheme.labelMedium,
semanticsLabel:
'${currentIndex.value + 1}集,共${episodes.length}',
),
const SizedBox(width: 6),
const Icon(
Icons.arrow_forward_ios_outlined,
size: 13,
semanticLabel: '查看',
)
],
),
),
const SizedBox(width: 6),
const Icon(
Icons.arrow_forward_ios_outlined,
size: 13,
semanticLabel: '查看',
)
],
),
),
),
);
});
),
);
}
void _findEpisode() {

View File

@@ -90,6 +90,7 @@ class _MediaListPanelState
automaticallyImplyLeading: false,
titleSpacing: 16,
title: Text(widget.panelTitle ?? '稍后再看'),
backgroundColor: Colors.transparent,
actions: [
Obx(
() => mediumButton(
@@ -155,158 +156,163 @@ class _MediaListPanelState
final isCurr = item.bvid == widget.getBvId();
return SizedBox(
height: 98,
child: InkWell(
onTap: () async {
if (item.type != 2) {
SmartDialog.showToast('不支持播放该类型视频');
return;
}
Get.back();
String bvid = item.bvid!;
int? aid = item.aid;
String cover = item.cover ?? '';
final int? cid =
item.cid ?? await SearchHttp.ab2c(aid: aid, bvid: bvid);
if (cid != null) {
widget.changeMediaList?.call(bvid, cid, aid, cover);
}
},
onLongPress: () => imageSaveDialog(
title: item.title,
cover: item.cover,
aid: item.aid,
bvid: item.bvid,
),
child: Stack(
clipBehavior: Clip.none,
children: [
Padding(
padding: const EdgeInsets.symmetric(
horizontal: 12,
vertical: 5,
),
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
AspectRatio(
aspectRatio: StyleString.aspectRatio,
child: LayoutBuilder(
builder: (context, boxConstraints) {
return Stack(
clipBehavior: Clip.none,
children: [
NetworkImgLayer(
src: item.cover,
width: boxConstraints.maxWidth,
height: boxConstraints.maxHeight,
),
if (item.badge?.text?.isNotEmpty == true)
PBadge(
text: item.badge?.text,
right: 6.0,
top: 6.0,
type: switch (item.badge?.text) {
'充电专属' => PBadgeType.error,
_ => PBadgeType.primary,
},
child: Material(
type: MaterialType.transparency,
child: InkWell(
onTap: () async {
if (item.type != 2) {
SmartDialog.showToast('不支持播放该类型视频');
return;
}
Get.back();
String bvid = item.bvid!;
int? aid = item.aid;
String cover = item.cover ?? '';
final int? cid = item.cid ??
await SearchHttp.ab2c(aid: aid, bvid: bvid);
if (cid != null) {
widget.changeMediaList?.call(bvid, cid, aid, cover);
}
},
onLongPress: () => imageSaveDialog(
title: item.title,
cover: item.cover,
aid: item.aid,
bvid: item.bvid,
),
child: Stack(
clipBehavior: Clip.none,
children: [
Padding(
padding: const EdgeInsets.symmetric(
horizontal: 12,
vertical: 5,
),
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
AspectRatio(
aspectRatio: StyleString.aspectRatio,
child: LayoutBuilder(
builder: (context, boxConstraints) {
return Stack(
clipBehavior: Clip.none,
children: [
NetworkImgLayer(
src: item.cover,
width: boxConstraints.maxWidth,
height: boxConstraints.maxHeight,
),
PBadge(
text: Utils.timeFormat(item.duration!),
right: 6.0,
bottom: 6.0,
type: PBadgeType.gray,
),
],
);
},
if (item.badge?.text?.isNotEmpty ==
true)
PBadge(
text: item.badge?.text,
right: 6.0,
top: 6.0,
type: switch (item.badge?.text) {
'充电专属' => PBadgeType.error,
_ => PBadgeType.primary,
},
),
PBadge(
text:
Utils.timeFormat(item.duration!),
right: 6.0,
bottom: 6.0,
type: PBadgeType.gray,
),
],
);
},
),
),
),
const SizedBox(width: 10),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
item.title!,
maxLines: 2,
overflow: TextOverflow.ellipsis,
style: TextStyle(
fontWeight:
isCurr ? FontWeight.bold : null,
color: isCurr
? theme.colorScheme.primary
: null,
),
),
if (item.type == 24 &&
item.intro?.isNotEmpty == true) ...[
const SizedBox(height: 3),
const SizedBox(width: 10),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
item.intro!,
item.title!,
maxLines: 2,
overflow: TextOverflow.ellipsis,
style: TextStyle(
fontSize: 13,
fontWeight:
isCurr ? FontWeight.bold : null,
color: isCurr
? theme.colorScheme.primary
: null,
),
),
if (item.type == 24 &&
item.intro?.isNotEmpty == true) ...[
const SizedBox(height: 3),
Text(
item.intro!,
maxLines: 2,
overflow: TextOverflow.ellipsis,
style: TextStyle(
fontSize: 13,
color: theme.colorScheme.outline,
),
),
],
const Spacer(),
Text(
item.upper!.name!,
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: TextStyle(
fontSize: 12,
color: theme.colorScheme.outline,
),
),
if (item.type == 2) ...[
const SizedBox(height: 3),
Row(
spacing: 8,
children: [
StatWidget(
type: StatType.play,
value: item.cntInfo!.play,
),
StatWidget(
type: StatType.danmaku,
value: item.cntInfo!.danmaku,
),
],
),
],
],
const Spacer(),
Text(
item.upper!.name!,
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: TextStyle(
fontSize: 12,
color: theme.colorScheme.outline,
),
),
if (item.type == 2) ...[
const SizedBox(height: 3),
Row(
spacing: 8,
children: [
StatWidget(
type: StatType.play,
value: item.cntInfo!.play,
),
StatWidget(
type: StatType.danmaku,
value: item.cntInfo!.danmaku,
),
],
),
],
],
),
),
),
],
],
),
),
),
if (showDelBtn && !isCurr)
Positioned(
right: 12,
bottom: -6,
child: InkWell(
customBorder: const CircleBorder(),
onTap: () => showConfirmDialog(
context: context,
title: '确定移除该视频?',
onConfirm: () => widget.onDelete!(index),
),
onLongPress: () => widget.onDelete!(index),
child: Padding(
padding: const EdgeInsets.all(9),
child: Icon(
Icons.clear,
size: 18,
color: theme.colorScheme.outline,
if (showDelBtn && !isCurr)
Positioned(
right: 12,
bottom: -6,
child: InkWell(
customBorder: const CircleBorder(),
onTap: () => showConfirmDialog(
context: context,
title: '确定移除该视频?',
onConfirm: () => widget.onDelete!(index),
),
onLongPress: () => widget.onDelete!(index),
child: Padding(
padding: const EdgeInsets.all(9),
child: Icon(
Icons.clear,
size: 18,
color: theme.colorScheme.outline,
),
),
),
),
),
],
],
),
),
),
);

View File

@@ -190,26 +190,23 @@ class _HorizontalMemberPageState extends State<HorizontalMemberPage> {
_controller.onLoadMore();
}
final SpaceArchiveItem videoItem = response[index];
return Material(
color: Colors.transparent,
child: VideoCardHMemberVideo(
videoItem: videoItem,
bvid: _bvid,
onTap: () {
final status =
widget.videoIntroController.changeSeasonOrbangu(
null,
videoItem.bvid,
videoItem.cid,
IdUtils.bv2av(videoItem.bvid!),
videoItem.cover,
);
if (status) {
_bvid = videoItem.bvid;
setState(() {});
}
},
),
return VideoCardHMemberVideo(
videoItem: videoItem,
bvid: _bvid,
onTap: () {
final status =
widget.videoIntroController.changeSeasonOrbangu(
null,
videoItem.bvid,
videoItem.cid,
IdUtils.bv2av(videoItem.bvid!),
videoItem.cover,
);
if (status) {
_bvid = videoItem.bvid;
setState(() {});
}
},
);
},
childCount: response!.length,
@@ -387,22 +384,19 @@ class _HorizontalMemberPageState extends State<HorizontalMemberPage> {
);
}
Hero _buildAvatar(String face) => Hero(
tag: face,
child: GestureDetector(
onTap: () {
widget.videoDetailController.onViewImage();
context.imageView(
imgList: [SourceModel(url: face)],
onDismissed: widget.videoDetailController.onDismissed,
);
},
child: NetworkImgLayer(
src: face,
type: ImageType.avatar,
width: 70,
height: 70,
),
Widget _buildAvatar(String face) => GestureDetector(
onTap: () {
widget.videoDetailController.onViewImage();
context.imageView(
imgList: [SourceModel(url: face)],
onDismissed: widget.videoDetailController.onDismissed,
);
},
child: NetworkImgLayer(
src: face,
type: ImageType.avatar,
width: 70,
height: 70,
),
);
}

View File

@@ -63,6 +63,7 @@ class _NoteListPageState extends CommonSlidePageState<NoteListPage> {
automaticallyImplyLeading: false,
titleSpacing: 16,
toolbarHeight: 45,
backgroundColor: Colors.transparent,
title: Obx(
() => Text(
'笔记${_controller.count.value == -1 ? '' : '(${_controller.count.value})'}'),
@@ -195,88 +196,92 @@ class _NoteListPageState extends CommonSlidePageState<NoteListPage> {
}
Widget _itemWidget(ThemeData theme, VideoNoteItemModel item) {
return InkWell(
onTap: () => Get.toNamed(
'/articlePage',
parameters: {
'id': item.cvid!.toString(),
'type': 'read',
},
),
child: Padding(
padding: const EdgeInsets.all(12),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
GestureDetector(
onTap: () => Get.toNamed('/member?mid=${item.author!.mid}'),
child: NetworkImgLayer(
height: 34,
width: 34,
src: item.author!.face,
type: ImageType.avatar,
return Material(
type: MaterialType.transparency,
child: InkWell(
onTap: () => Get.toNamed(
'/articlePage',
parameters: {
'id': item.cvid!.toString(),
'type': 'read',
},
),
child: Padding(
padding: const EdgeInsets.all(12),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
GestureDetector(
onTap: () => Get.toNamed('/member?mid=${item.author!.mid}'),
child: NetworkImgLayer(
height: 34,
width: 34,
src: item.author!.face,
type: ImageType.avatar,
),
),
),
const SizedBox(width: 12),
Expanded(
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
GestureDetector(
onTap: () => Get.toNamed('/member?mid=${item.author!.mid}'),
child: Row(
children: [
Text(
item.author!.name!,
style: TextStyle(
color: item.author?.vipInfo?.status != null &&
item.author!.vipInfo!.status > 0 &&
item.author!.vipInfo!.type == 2
? context.vipColor
: theme.colorScheme.outline,
fontSize: 13,
const SizedBox(width: 12),
Expanded(
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
GestureDetector(
onTap: () =>
Get.toNamed('/member?mid=${item.author!.mid}'),
child: Row(
children: [
Text(
item.author!.name!,
style: TextStyle(
color: item.author?.vipInfo?.status != null &&
item.author!.vipInfo!.status > 0 &&
item.author!.vipInfo!.type == 2
? context.vipColor
: theme.colorScheme.outline,
fontSize: 13,
),
),
const SizedBox(width: 6),
Image.asset(
'assets/images/lv/lv${item.author!.isSeniorMember == 1 ? '6_s' : item.author!.level}.png',
height: 11,
),
],
),
),
const SizedBox(height: 4),
if (item.pubtime != null)
Text(
item.pubtime!,
style: TextStyle(
color: theme.colorScheme.outline,
fontSize: 12,
),
const SizedBox(width: 6),
Image.asset(
'assets/images/lv/lv${item.author!.isSeniorMember == 1 ? '6_s' : item.author!.level}.png',
height: 11,
),
if (item.summary != null) ...[
const SizedBox(height: 5),
Text(
item.summary!,
style: TextStyle(
height: 1.75,
fontSize: theme.textTheme.bodyMedium!.fontSize,
),
],
),
),
const SizedBox(height: 4),
if (item.pubtime != null)
Text(
item.pubtime!,
style: TextStyle(
color: theme.colorScheme.outline,
fontSize: 12,
),
),
if (item.summary != null) ...[
const SizedBox(height: 5),
Text(
item.summary!,
style: TextStyle(
height: 1.75,
fontSize: theme.textTheme.bodyMedium!.fontSize,
Text(
'查看全部',
style: TextStyle(
color: theme.colorScheme.primary,
height: 1.75,
fontSize: theme.textTheme.bodyMedium!.fontSize,
),
),
),
Text(
'查看全部',
style: TextStyle(
color: theme.colorScheme.primary,
height: 1.75,
fontSize: theme.textTheme.bodyMedium!.fontSize,
),
),
],
],
],
),
),
),
],
],
),
),
),
);

View File

@@ -74,7 +74,7 @@ class ReplyItemGrpc extends StatelessWidget {
Widget build(BuildContext context) {
final ThemeData theme = Theme.of(context);
return Material(
color: Colors.transparent,
type: MaterialType.transparency,
child: InkWell(
onTap: () {
feedBack();

View File

@@ -1731,84 +1731,78 @@ class _VideoDetailPageVState extends State<VideoDetailPageV>
Widget videoIntro([bool needRelated = true, bool needCtr = true]) {
final bottom = MediaQuery.paddingOf(context).bottom;
Widget introPanel() => Scaffold(
resizeToAvoidBottomInset: false,
backgroundColor: Colors.transparent,
body: CustomScrollView(
key: const PageStorageKey<String>('简介'),
controller: needCtr ? _introController : null,
physics: !needCtr
? const AlwaysScrollableScrollPhysics(
parent: ClampingScrollPhysics())
: null,
slivers: [
if (videoDetailController.videoType == SearchType.video) ...[
VideoIntroPanel(
key: ugcPanelKey,
Widget introPanel() => CustomScrollView(
key: const PageStorageKey<String>('简介'),
controller: needCtr ? _introController : null,
physics: !needCtr
? const AlwaysScrollableScrollPhysics(
parent: ClampingScrollPhysics())
: null,
slivers: [
if (videoDetailController.videoType == SearchType.video) ...[
VideoIntroPanel(
key: ugcPanelKey,
heroTag: heroTag,
showAiBottomSheet: showAiBottomSheet,
showEpisodes: showEpisodes,
onShowMemberPage: onShowMemberPage,
),
if (needRelated &&
videoDetailController
.plPlayerController.showRelatedVideo) ...[
SliverToBoxAdapter(
child: Padding(
padding: const EdgeInsets.only(top: StyleString.safeSpace),
child: Divider(
height: 1,
indent: 12,
endIndent: 12,
color:
themeData.colorScheme.outline.withValues(alpha: 0.08),
),
),
),
RelatedVideoPanel(key: relatedVideoPanelKey, heroTag: heroTag),
] else
SliverToBoxAdapter(
child: SizedBox(
height: bottom + StyleString.safeSpace,
),
),
] else if (videoDetailController.videoType ==
SearchType.media_bangumi)
Obx(
() => PgcIntroPage(
key: pgcPanelKey,
heroTag: heroTag,
showAiBottomSheet: showAiBottomSheet,
cid: videoDetailController.cid.value,
showEpisodes: showEpisodes,
onShowMemberPage: onShowMemberPage,
showIntroDetail: showIntroDetail,
),
if (needRelated &&
videoDetailController
.plPlayerController.showRelatedVideo) ...[
SliverToBoxAdapter(
child: Padding(
padding:
const EdgeInsets.only(top: StyleString.safeSpace),
child: Divider(
height: 1,
indent: 12,
endIndent: 12,
color: themeData.colorScheme.outline
.withValues(alpha: 0.08),
),
),
),
RelatedVideoPanel(
key: relatedVideoPanelKey, heroTag: heroTag),
] else
SliverToBoxAdapter(
child: SizedBox(
height: bottom + StyleString.safeSpace,
),
),
] else if (videoDetailController.videoType ==
SearchType.media_bangumi)
Obx(
() => PgcIntroPage(
key: pgcPanelKey,
heroTag: heroTag,
cid: videoDetailController.cid.value,
showEpisodes: showEpisodes,
showIntroDetail: showIntroDetail,
),
),
SliverToBoxAdapter(
child: SizedBox(
height: bottom +
(videoDetailController.isPlayAll &&
MediaQuery.orientationOf(context) ==
Orientation.landscape
? 75
: 0),
),
)
],
),
),
SliverToBoxAdapter(
child: SizedBox(
height: bottom +
(videoDetailController.isPlayAll &&
MediaQuery.orientationOf(context) ==
Orientation.landscape
? 75
: 0),
),
)
],
);
if (videoDetailController.isPlayAll) {
return Stack(
clipBehavior: Clip.none,
children: [
introPanel(),
return Stack(
clipBehavior: Clip.none,
children: [
introPanel(),
if (videoDetailController.isPlayAll)
Positioned(
left: 12,
right: 12,
bottom: bottom + 12,
child: Material(
color: Colors.transparent,
type: MaterialType.transparency,
child: InkWell(
onTap: () => videoDetailController.showMediaListPanel(context),
borderRadius: const BorderRadius.all(Radius.circular(14)),
@@ -1839,12 +1833,11 @@ class _VideoDetailPageVState extends State<VideoDetailPageV>
),
),
),
),
],
);
} else {
return introPanel();
}
)
else
const SizedBox.shrink(),
],
);
}
Widget get seasonPanel => Column(

View File

@@ -4,7 +4,6 @@ import 'dart:math';
import 'package:PiliPlus/common/widgets/button/icon_button.dart';
import 'package:PiliPlus/common/widgets/custom_icon.dart';
import 'package:PiliPlus/common/widgets/self_sized_horizontal_list.dart';
import 'package:PiliPlus/models/common/search_type.dart';
import 'package:PiliPlus/models/common/super_resolution_type.dart';
import 'package:PiliPlus/models/common/video/audio_quality.dart';
@@ -125,9 +124,8 @@ class HeaderControlState extends State<HeaderControl> {
color: theme.colorScheme.surface,
borderRadius: const BorderRadius.all(Radius.circular(12)),
child: ListView(
padding: EdgeInsets.zero,
padding: const EdgeInsets.symmetric(vertical: 14),
children: [
const SizedBox(height: 14),
ListTile(
dense: true,
onTap: () {
@@ -272,66 +270,64 @@ class HeaderControlState extends State<HeaderControl> {
}
},
),
SelfSizedHorizontalList(
itemCount: 4,
gapSize: 10,
SingleChildScrollView(
scrollDirection: Axis.horizontal,
padding: const EdgeInsets.symmetric(horizontal: 16),
childBuilder: (index) {
return switch (index) {
0 => Obx(
() => ActionRowLineItem(
iconData: Icons.flip,
onTap: () => widget.controller.flipX.value =
!widget.controller.flipX.value,
text: " 左右翻转 ",
selectStatus: widget.controller.flipX.value,
),
child: Row(
spacing: 10,
children: [
Obx(
() => ActionRowLineItem(
iconData: Icons.flip,
onTap: () => widget.controller.flipX.value =
!widget.controller.flipX.value,
text: " 左右翻转 ",
selectStatus: widget.controller.flipX.value,
),
1 => Obx(
() => ActionRowLineItem(
icon: Transform.rotate(
angle: pi / 2,
child: Icon(
Icons.flip,
size: 13,
color: widget.controller.flipY.value
? theme.colorScheme.onSecondaryContainer
: theme.colorScheme.outline,
),
),
Obx(
() => ActionRowLineItem(
icon: Transform.rotate(
angle: pi / 2,
child: Icon(
Icons.flip,
size: 13,
color: widget.controller.flipY.value
? theme.colorScheme.onSecondaryContainer
: theme.colorScheme.outline,
),
onTap: () {
widget.controller.flipY.value =
!widget.controller.flipY.value;
},
text: " 上下翻转 ",
selectStatus: widget.controller.flipY.value,
),
onTap: () {
widget.controller.flipY.value =
!widget.controller.flipY.value;
},
text: " 上下翻转 ",
selectStatus: widget.controller.flipY.value,
),
2 => Obx(
() => ActionRowLineItem(
iconData: Icons.headphones,
onTap: () {
widget.controller.onlyPlayAudio.value =
!widget.controller.onlyPlayAudio.value;
widget.videoDetailCtr.playerInit();
},
text: " 听视频 ",
selectStatus: widget.controller.onlyPlayAudio.value,
),
),
Obx(
() => ActionRowLineItem(
iconData: Icons.headphones,
onTap: () {
widget.controller.onlyPlayAudio.value =
!widget.controller.onlyPlayAudio.value;
widget.videoDetailCtr.playerInit();
},
text: " 听视频 ",
selectStatus: widget.controller.onlyPlayAudio.value,
),
3 => Obx(
() => ActionRowLineItem(
iconData: Icons.play_circle_outline,
onTap:
widget.controller.setContinuePlayInBackground,
text: " 后台播放 ",
selectStatus: widget
.controller.continuePlayInBackground.value,
),
),
Obx(
() => ActionRowLineItem(
iconData: Icons.play_circle_outline,
onTap: widget.controller.setContinuePlayInBackground,
text: " 后台播放 ",
selectStatus:
widget.controller.continuePlayInBackground.value,
),
_ => throw UnimplementedError(),
};
},
),
],
),
),
ListTile(
dense: true,
@@ -536,7 +532,6 @@ class HeaderControlState extends State<HeaderControl> {
leading: const Icon(Icons.error_outline, size: 20),
title: const Text('举报', style: titleStyle),
),
const SizedBox(height: 14),
],
),
),
@@ -578,7 +573,8 @@ class HeaderControlState extends State<HeaderControl> {
clipBehavior: Clip.hardEdge,
color: theme.colorScheme.surface,
borderRadius: const BorderRadius.all(Radius.circular(12)),
child: Column(
child: ListView(
padding: EdgeInsets.zero,
children: [
SizedBox(
height: 45,
@@ -599,77 +595,59 @@ class HeaderControlState extends State<HeaderControl> {
),
),
),
Expanded(
child: Material(
color: Colors.transparent,
child: Scrollbar(
child: ListView(
padding: EdgeInsets.zero,
children: [
for (int i = 0; i < totalQaSam; i++) ...[
ListTile(
dense: true,
onTap: () async {
if (currentVideoQa.code ==
videoFormat[i].quality) {
return;
}
Get.back();
final int quality = videoFormat[i].quality!;
videoDetailCtr
..currentVideoQa =
VideoQuality.fromCode(quality)
..updatePlayer();
for (int i = 0; i < totalQaSam; i++) ...[
ListTile(
dense: true,
onTap: () async {
if (currentVideoQa.code == videoFormat[i].quality) {
return;
}
Get.back();
final int quality = videoFormat[i].quality!;
videoDetailCtr
..currentVideoQa = VideoQuality.fromCode(quality)
..updatePlayer();
// update
late String oldQualityDesc;
await Connectivity()
.checkConnectivity()
.then((res) {
if (res.contains(ConnectivityResult.wifi)) {
oldQualityDesc = VideoQuality.fromCode(
GStorage.defaultVideoQa)
.description;
setting.put(
SettingBoxKey.defaultVideoQa,
quality,
);
} else {
oldQualityDesc = VideoQuality.fromCode(
GStorage.defaultVideoQaCellular)
.description;
setting.put(
SettingBoxKey.defaultVideoQaCellular,
quality,
);
}
});
SmartDialog.showToast(
"默认画质由:$oldQualityDesc 变为:${VideoQuality.fromCode(quality).description}",
);
},
// 可能包含会员解锁画质
enabled: i >= totalQaSam - userfulQaSam,
contentPadding:
const EdgeInsets.only(left: 20, right: 20),
title: Text(videoFormat[i].newDesc!),
trailing:
currentVideoQa.code == videoFormat[i].quality
? Icon(
Icons.done,
color: theme.colorScheme.primary,
)
: Text(
videoFormat[i].format!,
style: subTitleStyle,
),
),
]
],
),
),
// update
late String oldQualityDesc;
await Connectivity().checkConnectivity().then((res) {
if (res.contains(ConnectivityResult.wifi)) {
oldQualityDesc =
VideoQuality.fromCode(GStorage.defaultVideoQa)
.description;
setting.put(
SettingBoxKey.defaultVideoQa,
quality,
);
} else {
oldQualityDesc = VideoQuality.fromCode(
GStorage.defaultVideoQaCellular)
.description;
setting.put(
SettingBoxKey.defaultVideoQaCellular,
quality,
);
}
});
SmartDialog.showToast(
"默认画质由:$oldQualityDesc 变为:${VideoQuality.fromCode(quality).description}",
);
},
// 可能包含会员解锁画质
enabled: i >= totalQaSam - userfulQaSam,
contentPadding: const EdgeInsets.only(left: 20, right: 20),
title: Text(videoFormat[i].newDesc!),
trailing: currentVideoQa.code == videoFormat[i].quality
? Icon(
Icons.done,
color: theme.colorScheme.primary,
)
: Text(
videoFormat[i].format!,
style: subTitleStyle,
),
),
),
]
],
),
),
@@ -691,77 +669,67 @@ class HeaderControlState extends State<HeaderControl> {
clipBehavior: Clip.hardEdge,
color: theme.colorScheme.surface,
borderRadius: const BorderRadius.all(Radius.circular(12)),
child: Column(
child: ListView(
padding: EdgeInsets.zero,
children: [
const SizedBox(
height: 45,
child: Center(child: Text('选择音质', style: titleStyle))),
Expanded(
child: Material(
color: Colors.transparent,
child: ListView(
padding: EdgeInsets.zero,
children: [
for (final AudioItem i in audio) ...[
ListTile(
dense: true,
onTap: () async {
if (currentAudioQa.code == i.id) {
return;
}
Get.back();
final int quality = i.id!;
videoDetailCtr
..currentAudioQa =
AudioQuality.fromCode(quality)
..updatePlayer();
// update
late String oldQualityDesc;
await Connectivity()
.checkConnectivity()
.then((res) {
if (res.contains(ConnectivityResult.wifi)) {
oldQualityDesc = AudioQuality.fromCode(
GStorage.defaultAudioQa)
.description;
setting.put(
SettingBoxKey.defaultAudioQa,
quality,
);
} else {
oldQualityDesc = AudioQuality.fromCode(
GStorage.defaultAudioQaCellular)
.description;
setting.put(
SettingBoxKey.defaultAudioQaCellular,
quality,
);
}
});
SmartDialog.showToast(
"默认音质由:$oldQualityDesc 变为:${AudioQuality.fromCode(quality).description}",
);
},
contentPadding:
const EdgeInsets.only(left: 20, right: 20),
title: Text(i.quality),
subtitle: Text(
i.codecs!,
style: subTitleStyle,
),
trailing: currentAudioQa.code == i.id
? Icon(
Icons.done,
color: theme.colorScheme.primary,
)
: const SizedBox.shrink(),
),
]
],
),
height: 45,
child: Center(
child: Text('选择音质', style: titleStyle),
),
),
for (final AudioItem i in audio) ...[
ListTile(
dense: true,
onTap: () async {
if (currentAudioQa.code == i.id) {
return;
}
Get.back();
final int quality = i.id!;
videoDetailCtr
..currentAudioQa = AudioQuality.fromCode(quality)
..updatePlayer();
// update
late String oldQualityDesc;
await Connectivity().checkConnectivity().then((res) {
if (res.contains(ConnectivityResult.wifi)) {
oldQualityDesc =
AudioQuality.fromCode(GStorage.defaultAudioQa)
.description;
setting.put(
SettingBoxKey.defaultAudioQa,
quality,
);
} else {
oldQualityDesc = AudioQuality.fromCode(
GStorage.defaultAudioQaCellular)
.description;
setting.put(
SettingBoxKey.defaultAudioQaCellular,
quality,
);
}
});
SmartDialog.showToast(
"默认音质由:$oldQualityDesc 变为:${AudioQuality.fromCode(quality).description}",
);
},
contentPadding: const EdgeInsets.only(left: 20, right: 20),
title: Text(i.quality),
subtitle: Text(
i.codecs!,
style: subTitleStyle,
),
trailing: currentAudioQa.code == i.id
? Icon(
Icons.done,
color: theme.colorScheme.primary,
)
: const SizedBox.shrink(),
),
]
],
),
),
@@ -798,45 +766,45 @@ class HeaderControlState extends State<HeaderControl> {
child: Column(
children: [
const SizedBox(
height: 45,
child: Center(child: Text('选择解码格式', style: titleStyle))),
height: 45,
child: Center(
child: Text('选择解码格式', style: titleStyle),
),
),
Expanded(
child: Material(
color: Colors.transparent,
child: ListView(
padding: EdgeInsets.zero,
children: [
for (var i in list) ...[
ListTile(
dense: true,
onTap: () {
if (i.startsWith(currentDecodeFormats.code)) {
return;
}
videoDetailCtr
..currentDecodeFormats =
VideoDecodeFormatTypeExt.fromString(i)!
..updatePlayer();
Get.back();
},
contentPadding:
const EdgeInsets.only(left: 20, right: 20),
title: Text(VideoDecodeFormatTypeExt.fromString(i)!
.description),
subtitle: Text(
i!,
style: subTitleStyle,
),
trailing: i.startsWith(currentDecodeFormats.code)
? Icon(
Icons.done,
color: theme.colorScheme.primary,
)
: const SizedBox.shrink(),
child: ListView(
padding: EdgeInsets.zero,
children: [
for (var i in list) ...[
ListTile(
dense: true,
onTap: () {
if (i.startsWith(currentDecodeFormats.code)) {
return;
}
videoDetailCtr
..currentDecodeFormats =
VideoDecodeFormatTypeExt.fromString(i)!
..updatePlayer();
Get.back();
},
contentPadding:
const EdgeInsets.only(left: 20, right: 20),
title: Text(VideoDecodeFormatTypeExt.fromString(i)!
.description),
subtitle: Text(
i!,
style: subTitleStyle,
),
]
],
),
trailing: i.startsWith(currentDecodeFormats.code)
? Icon(
Icons.done,
color: theme.colorScheme.primary,
)
: const SizedBox.shrink(),
),
]
],
),
),
],
@@ -1786,39 +1754,32 @@ class HeaderControlState extends State<HeaderControl> {
clipBehavior: Clip.hardEdge,
color: theme.colorScheme.surface,
borderRadius: const BorderRadius.all(Radius.circular(12)),
child: Column(
child: ListView(
padding: EdgeInsets.zero,
children: [
const SizedBox(
height: 45,
child: Center(child: Text('选择播放顺序', style: titleStyle))),
Expanded(
child: Material(
color: Colors.transparent,
child: ListView(
padding: EdgeInsets.zero,
children: [
for (final PlayRepeat i in PlayRepeat.values) ...[
ListTile(
dense: true,
onTap: () {
widget.controller.setPlayRepeat(i);
Get.back();
},
contentPadding:
const EdgeInsets.only(left: 20, right: 20),
title: Text(i.description),
trailing: widget.controller.playRepeat == i
? Icon(
Icons.done,
color: theme.colorScheme.primary,
)
: const SizedBox.shrink(),
)
],
],
),
height: 45,
child: Center(
child: Text('选择播放顺序', style: titleStyle),
),
),
for (final PlayRepeat i in PlayRepeat.values) ...[
ListTile(
dense: true,
onTap: () {
widget.controller.setPlayRepeat(i);
Get.back();
},
contentPadding: const EdgeInsets.only(left: 20, right: 20),
title: Text(i.description),
trailing: widget.controller.playRepeat == i
? Icon(
Icons.done,
color: theme.colorScheme.primary,
)
: const SizedBox.shrink(),
)
],
],
),
),