mirror of
https://github.com/bggRGjQaUbCoE/PiliPlus.git
synced 2026-08-05 10:10:14 +08:00
@@ -6,6 +6,8 @@ abstract final class StyleString {
|
||||
static const BorderRadius mdRadius = BorderRadius.all(imgRadius);
|
||||
static const Radius imgRadius = Radius.circular(10);
|
||||
static const double aspectRatio = 16 / 10;
|
||||
static const double aspectRatio16x9 = 16 / 9;
|
||||
static const double imgMaxRatio = 22 / 9;
|
||||
static const bottomSheetRadius = BorderRadius.vertical(
|
||||
top: Radius.circular(18),
|
||||
);
|
||||
|
||||
@@ -60,15 +60,14 @@ class ImageModel {
|
||||
bool? _isLongPic;
|
||||
bool? _isLivePhoto;
|
||||
|
||||
bool get isLongPic => _isLongPic ??= (height / width) > _maxRatio;
|
||||
bool get isLongPic =>
|
||||
_isLongPic ??= (height / width) > StyleString.imgMaxRatio;
|
||||
bool get isLivePhoto =>
|
||||
_isLivePhoto ??= enableLivePhoto && liveUrl?.isNotEmpty == true;
|
||||
|
||||
static bool enableLivePhoto = Pref.enableLivePhoto;
|
||||
}
|
||||
|
||||
const double _maxRatio = 22 / 9;
|
||||
|
||||
class CustomGridView extends StatelessWidget {
|
||||
const CustomGridView({
|
||||
super.key,
|
||||
@@ -222,7 +221,7 @@ class CustomGridView extends StatelessWidget {
|
||||
if (width != 1) {
|
||||
imageWidth = min(imageWidth, width.toDouble());
|
||||
}
|
||||
imageHeight = imageWidth * min(ratioHW, _maxRatio);
|
||||
imageHeight = imageWidth * min(ratioHW, StyleString.imgMaxRatio);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ void imageSaveDialog({
|
||||
dynamic aid,
|
||||
String? bvid,
|
||||
}) {
|
||||
final double imgWidth = MediaQuery.sizeOf(Get.context!).shortestSide - 8 * 2;
|
||||
final double imgWidth = MediaQuery.sizeOf(Get.context!).shortestSide - 16;
|
||||
SmartDialog.show(
|
||||
animationType: SmartAnimationType.centerScale_otherSlide,
|
||||
builder: (context) {
|
||||
@@ -22,7 +22,7 @@ void imageSaveDialog({
|
||||
final theme = Theme.of(context);
|
||||
return Container(
|
||||
width: imgWidth,
|
||||
margin: const EdgeInsets.symmetric(horizontal: StyleString.safeSpace),
|
||||
margin: const .symmetric(horizontal: StyleString.safeSpace),
|
||||
decoration: BoxDecoration(
|
||||
color: theme.colorScheme.surface,
|
||||
borderRadius: StyleString.mdRadius,
|
||||
@@ -36,32 +36,29 @@ void imageSaveDialog({
|
||||
GestureDetector(
|
||||
onTap: SmartDialog.dismiss,
|
||||
child: NetworkImgLayer(
|
||||
width: imgWidth,
|
||||
height: imgWidth / StyleString.aspectRatio,
|
||||
src: cover,
|
||||
quality: 100,
|
||||
width: imgWidth,
|
||||
height: imgWidth / StyleString.aspectRatio16x9,
|
||||
borderRadius: const .vertical(top: StyleString.imgRadius),
|
||||
),
|
||||
),
|
||||
Positioned(
|
||||
right: 8,
|
||||
top: 8,
|
||||
child: SizedBox(
|
||||
width: 30,
|
||||
height: 30,
|
||||
child: IconButton(
|
||||
tooltip: '关闭',
|
||||
style: ButtonStyle(
|
||||
backgroundColor: WidgetStatePropertyAll(
|
||||
Colors.black.withValues(alpha: 0.3),
|
||||
),
|
||||
padding: const WidgetStatePropertyAll(EdgeInsets.zero),
|
||||
),
|
||||
onPressed: SmartDialog.dismiss,
|
||||
icon: const Icon(
|
||||
Icons.close,
|
||||
size: 18,
|
||||
color: Colors.white,
|
||||
),
|
||||
width: 30,
|
||||
height: 30,
|
||||
child: IconButton(
|
||||
tooltip: '关闭',
|
||||
style: IconButton.styleFrom(
|
||||
padding: .zero,
|
||||
backgroundColor: Colors.black.withValues(alpha: 0.3),
|
||||
),
|
||||
onPressed: SmartDialog.dismiss,
|
||||
icon: const Icon(
|
||||
Icons.close,
|
||||
size: 18,
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
@@ -662,8 +662,7 @@ class RenderProgressBar extends RenderBox implements MouseTrackerAnnotation {
|
||||
Size computeDryLayout(BoxConstraints constraints) {
|
||||
final desiredWidth = constraints.maxWidth;
|
||||
final desiredHeight = _heightWhenNoLabels();
|
||||
final desiredSize = Size(desiredWidth, desiredHeight);
|
||||
return constraints.constrain(desiredSize);
|
||||
return constraints.constrainDimensions(desiredWidth, desiredHeight);
|
||||
}
|
||||
|
||||
double _heightWhenNoLabels() {
|
||||
|
||||
@@ -185,7 +185,7 @@ class RenderViewPointProgressBar
|
||||
|
||||
@override
|
||||
void performLayout() {
|
||||
size = constraints.constrain(Size(constraints.maxWidth, _barHeight));
|
||||
size = constraints.constrainDimensions(constraints.maxWidth, _barHeight);
|
||||
}
|
||||
|
||||
static const double _barHeight = 15.0;
|
||||
@@ -334,7 +334,6 @@ class BaseRenderProgressBar<T extends BaseSegment> extends RenderBox {
|
||||
BaseRenderProgressBar({
|
||||
required double height,
|
||||
required List<T> segments,
|
||||
ValueSetter<int>? onSeek,
|
||||
}) : _height = height,
|
||||
_segments = segments;
|
||||
|
||||
@@ -356,7 +355,7 @@ class BaseRenderProgressBar<T extends BaseSegment> extends RenderBox {
|
||||
|
||||
@override
|
||||
void performLayout() {
|
||||
size = constraints.constrain(Size(constraints.maxWidth, height));
|
||||
size = constraints.constrainDimensions(constraints.maxWidth, height);
|
||||
}
|
||||
|
||||
@override
|
||||
|
||||
@@ -96,7 +96,7 @@ class RenderProgressBar extends RenderBox {
|
||||
}
|
||||
|
||||
double _radius;
|
||||
double get borderRadius => _radius;
|
||||
double get radius => _radius;
|
||||
set radius(double value) {
|
||||
if (_radius == value) return;
|
||||
_radius = value;
|
||||
@@ -113,7 +113,7 @@ class RenderProgressBar extends RenderBox {
|
||||
|
||||
@override
|
||||
void performLayout() {
|
||||
size = constraints.constrain(Size(constraints.maxWidth, _radius));
|
||||
size = constraints.constrainDimensions(constraints.maxWidth, _radius);
|
||||
}
|
||||
|
||||
@override
|
||||
|
||||
@@ -199,8 +199,9 @@ class VideoCardH extends StatelessWidget {
|
||||
Positioned(
|
||||
bottom: 0,
|
||||
right: 12,
|
||||
width: 29,
|
||||
height: 29,
|
||||
child: VideoPopupMenu(
|
||||
size: 29,
|
||||
iconSize: 17,
|
||||
videoItem: videoItem,
|
||||
onRemove: onRemove,
|
||||
|
||||
@@ -124,8 +124,9 @@ class VideoCardV extends StatelessWidget {
|
||||
Positioned(
|
||||
right: -5,
|
||||
bottom: -2,
|
||||
width: 29,
|
||||
height: 29,
|
||||
child: VideoPopupMenu(
|
||||
size: 29,
|
||||
iconSize: 17,
|
||||
videoItem: videoItem,
|
||||
onRemove: onRemove,
|
||||
|
||||
@@ -24,7 +24,6 @@ class _VideoCustomAction {
|
||||
}
|
||||
|
||||
class VideoPopupMenu extends StatelessWidget {
|
||||
final double? size;
|
||||
final double? iconSize;
|
||||
final double menuItemHeight;
|
||||
final BaseSimpleVideoItemModel videoItem;
|
||||
@@ -32,7 +31,6 @@ class VideoPopupMenu extends StatelessWidget {
|
||||
|
||||
const VideoPopupMenu({
|
||||
super.key,
|
||||
required this.size,
|
||||
required this.iconSize,
|
||||
required this.videoItem,
|
||||
this.onRemove,
|
||||
@@ -41,358 +39,349 @@ class VideoPopupMenu extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ExcludeSemantics(
|
||||
child: SizedBox(
|
||||
width: size,
|
||||
height: size,
|
||||
child: PopupMenuButton(
|
||||
padding: EdgeInsets.zero,
|
||||
icon: Icon(
|
||||
Icons.more_vert_outlined,
|
||||
color: Theme.of(context).colorScheme.outline,
|
||||
size: iconSize,
|
||||
),
|
||||
position: PopupMenuPosition.under,
|
||||
itemBuilder: (context) =>
|
||||
[
|
||||
if (videoItem.bvid?.isNotEmpty == true) ...[
|
||||
_VideoCustomAction(
|
||||
videoItem.bvid!,
|
||||
const Stack(
|
||||
clipBehavior: Clip.none,
|
||||
children: [
|
||||
Icon(MdiIcons.identifier, size: 16),
|
||||
Icon(MdiIcons.circleOutline, size: 16),
|
||||
],
|
||||
),
|
||||
() => Utils.copyText(videoItem.bvid!),
|
||||
),
|
||||
_VideoCustomAction(
|
||||
'稍后再看',
|
||||
const Icon(MdiIcons.clockTimeEightOutline, size: 16),
|
||||
() => UserHttp.toViewLater(bvid: videoItem.bvid),
|
||||
),
|
||||
if (videoItem.cid != null && Pref.enableAi)
|
||||
_VideoCustomAction(
|
||||
'AI总结',
|
||||
const Stack(
|
||||
alignment: Alignment.center,
|
||||
clipBehavior: Clip.none,
|
||||
children: [
|
||||
Icon(Icons.circle_outlined, size: 16),
|
||||
ExcludeSemantics(
|
||||
child: Text(
|
||||
'AI',
|
||||
style: TextStyle(
|
||||
fontSize: 10,
|
||||
height: 1,
|
||||
fontWeight: FontWeight.w700,
|
||||
),
|
||||
strutStyle: StrutStyle(
|
||||
fontSize: 10,
|
||||
height: 1,
|
||||
leading: 0,
|
||||
fontWeight: FontWeight.w700,
|
||||
),
|
||||
textScaler: TextScaler.noScaling,
|
||||
),
|
||||
return PopupMenuButton(
|
||||
padding: EdgeInsets.zero,
|
||||
icon: Icon(
|
||||
Icons.more_vert_outlined,
|
||||
color: Theme.of(context).colorScheme.outline,
|
||||
size: iconSize,
|
||||
),
|
||||
position: PopupMenuPosition.under,
|
||||
itemBuilder: (context) =>
|
||||
[
|
||||
if (videoItem.bvid?.isNotEmpty == true) ...[
|
||||
_VideoCustomAction(
|
||||
videoItem.bvid!,
|
||||
const Stack(
|
||||
clipBehavior: Clip.none,
|
||||
children: [
|
||||
Icon(MdiIcons.identifier, size: 16),
|
||||
Icon(MdiIcons.circleOutline, size: 16),
|
||||
],
|
||||
),
|
||||
() => Utils.copyText(videoItem.bvid!),
|
||||
),
|
||||
_VideoCustomAction(
|
||||
'稍后再看',
|
||||
const Icon(MdiIcons.clockTimeEightOutline, size: 16),
|
||||
() => UserHttp.toViewLater(bvid: videoItem.bvid),
|
||||
),
|
||||
if (videoItem.cid != null && Pref.enableAi)
|
||||
_VideoCustomAction(
|
||||
'AI总结',
|
||||
const Stack(
|
||||
alignment: Alignment.center,
|
||||
clipBehavior: Clip.none,
|
||||
children: [
|
||||
Icon(Icons.circle_outlined, size: 16),
|
||||
ExcludeSemantics(
|
||||
child: Text(
|
||||
'AI',
|
||||
style: TextStyle(
|
||||
fontSize: 10,
|
||||
height: 1,
|
||||
fontWeight: FontWeight.w700,
|
||||
),
|
||||
],
|
||||
strutStyle: StrutStyle(
|
||||
fontSize: 10,
|
||||
height: 1,
|
||||
leading: 0,
|
||||
fontWeight: FontWeight.w700,
|
||||
),
|
||||
textScaler: TextScaler.noScaling,
|
||||
),
|
||||
),
|
||||
() async {
|
||||
final res =
|
||||
await UgcIntroController.getAiConclusion(
|
||||
videoItem.bvid!,
|
||||
videoItem.cid!,
|
||||
videoItem.owner.mid,
|
||||
);
|
||||
if (res != null && context.mounted) {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return Dialog(
|
||||
child: Padding(
|
||||
padding: const .symmetric(vertical: 14),
|
||||
child: AiConclusionPanel.buildContent(
|
||||
context,
|
||||
Theme.of(context),
|
||||
res,
|
||||
tap: false,
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
},
|
||||
),
|
||||
],
|
||||
if (videoItem is! SpaceArchiveItem) ...[
|
||||
_VideoCustomAction(
|
||||
'访问:${videoItem.owner.name}',
|
||||
const Icon(MdiIcons.accountCircleOutline, size: 16),
|
||||
() => Get.toNamed('/member?mid=${videoItem.owner.mid}'),
|
||||
],
|
||||
),
|
||||
_VideoCustomAction(
|
||||
'不感兴趣',
|
||||
const Icon(MdiIcons.thumbDownOutline, size: 16),
|
||||
() {
|
||||
String? accessKey = Accounts.get(
|
||||
AccountType.recommend,
|
||||
).accessKey;
|
||||
if (accessKey == null || accessKey == "") {
|
||||
SmartDialog.showToast("请退出账号后重新登录");
|
||||
return;
|
||||
}
|
||||
if (videoItem case final RecVideoItemAppModel item) {
|
||||
ThreePoint? tp = item.threePoint;
|
||||
if (tp == null) {
|
||||
SmartDialog.showToast("未能获取threePoint");
|
||||
return;
|
||||
}
|
||||
if (tp.dislikeReasons == null &&
|
||||
tp.feedbacks == null) {
|
||||
SmartDialog.showToast(
|
||||
"未能获取dislikeReasons或feedbacks",
|
||||
() async {
|
||||
final res = await UgcIntroController.getAiConclusion(
|
||||
videoItem.bvid!,
|
||||
videoItem.cid!,
|
||||
videoItem.owner.mid,
|
||||
);
|
||||
if (res != null && context.mounted) {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return Dialog(
|
||||
child: Padding(
|
||||
padding: const .symmetric(vertical: 14),
|
||||
child: AiConclusionPanel.buildContent(
|
||||
context,
|
||||
Theme.of(context),
|
||||
res,
|
||||
tap: false,
|
||||
),
|
||||
),
|
||||
);
|
||||
return;
|
||||
}
|
||||
Widget actionButton(Reason? r, Reason? f) {
|
||||
return SearchText(
|
||||
text: r?.name ?? f?.name ?? '未知',
|
||||
onTap: (_) async {
|
||||
Get.back();
|
||||
SmartDialog.showLoading(msg: '正在提交');
|
||||
final res = await VideoHttp.feedDislike(
|
||||
reasonId: r?.id,
|
||||
feedbackId: f?.id,
|
||||
id: item.param!,
|
||||
goto: item.goto!,
|
||||
);
|
||||
SmartDialog.dismiss();
|
||||
if (res.isSuccess) {
|
||||
SmartDialog.showToast(
|
||||
r?.toast ?? f!.toast!,
|
||||
);
|
||||
onRemove?.call();
|
||||
} else {
|
||||
res.toast();
|
||||
}
|
||||
},
|
||||
},
|
||||
);
|
||||
}
|
||||
},
|
||||
),
|
||||
],
|
||||
if (videoItem is! SpaceArchiveItem) ...[
|
||||
_VideoCustomAction(
|
||||
'访问:${videoItem.owner.name}',
|
||||
const Icon(MdiIcons.accountCircleOutline, size: 16),
|
||||
() => Get.toNamed('/member?mid=${videoItem.owner.mid}'),
|
||||
),
|
||||
_VideoCustomAction(
|
||||
'不感兴趣',
|
||||
const Icon(MdiIcons.thumbDownOutline, size: 16),
|
||||
() {
|
||||
String? accessKey = Accounts.get(
|
||||
AccountType.recommend,
|
||||
).accessKey;
|
||||
if (accessKey == null || accessKey == "") {
|
||||
SmartDialog.showToast("请退出账号后重新登录");
|
||||
return;
|
||||
}
|
||||
if (videoItem case final RecVideoItemAppModel item) {
|
||||
ThreePoint? tp = item.threePoint;
|
||||
if (tp == null) {
|
||||
SmartDialog.showToast("未能获取threePoint");
|
||||
return;
|
||||
}
|
||||
if (tp.dislikeReasons == null && tp.feedbacks == null) {
|
||||
SmartDialog.showToast(
|
||||
"未能获取dislikeReasons或feedbacks",
|
||||
);
|
||||
return;
|
||||
}
|
||||
Widget actionButton(Reason? r, Reason? f) {
|
||||
return SearchText(
|
||||
text: r?.name ?? f?.name ?? '未知',
|
||||
onTap: (_) async {
|
||||
Get.back();
|
||||
SmartDialog.showLoading(msg: '正在提交');
|
||||
final res = await VideoHttp.feedDislike(
|
||||
reasonId: r?.id,
|
||||
feedbackId: f?.id,
|
||||
id: item.param!,
|
||||
goto: item.goto!,
|
||||
);
|
||||
}
|
||||
SmartDialog.dismiss();
|
||||
if (res.isSuccess) {
|
||||
SmartDialog.showToast(
|
||||
r?.toast ?? f!.toast!,
|
||||
);
|
||||
onRemove?.call();
|
||||
} else {
|
||||
res.toast();
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return AlertDialog(
|
||||
content: SingleChildScrollView(
|
||||
child: Column(
|
||||
crossAxisAlignment: .start,
|
||||
children: [
|
||||
if (tp.dislikeReasons != null) ...[
|
||||
const Text('我不想看'),
|
||||
const SizedBox(height: 5),
|
||||
Wrap(
|
||||
spacing: 8.0,
|
||||
runSpacing: 8.0,
|
||||
children: tp.dislikeReasons!.map((
|
||||
item,
|
||||
) {
|
||||
return actionButton(item, null);
|
||||
}).toList(),
|
||||
),
|
||||
],
|
||||
if (tp.feedbacks != null) ...[
|
||||
const SizedBox(height: 5),
|
||||
const Text('反馈'),
|
||||
const SizedBox(height: 5),
|
||||
Wrap(
|
||||
spacing: 8.0,
|
||||
runSpacing: 8.0,
|
||||
children: tp.feedbacks!.map((item) {
|
||||
return actionButton(null, item);
|
||||
}).toList(),
|
||||
),
|
||||
],
|
||||
const Divider(),
|
||||
Center(
|
||||
child: FilledButton.tonal(
|
||||
onPressed: () async {
|
||||
SmartDialog.showLoading(
|
||||
msg: '正在提交',
|
||||
);
|
||||
final res =
|
||||
await VideoHttp.feedDislikeCancel(
|
||||
id: item.param!,
|
||||
goto: item.goto!,
|
||||
);
|
||||
SmartDialog.dismiss();
|
||||
SmartDialog.showToast(
|
||||
res.isSuccess
|
||||
? "成功"
|
||||
: res.toString(),
|
||||
);
|
||||
Get.back();
|
||||
},
|
||||
style: FilledButton.styleFrom(
|
||||
visualDensity:
|
||||
VisualDensity.compact,
|
||||
),
|
||||
child: const Text("撤销"),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
} else {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return AlertDialog(
|
||||
content: SingleChildScrollView(
|
||||
child: Column(
|
||||
children: [
|
||||
const SizedBox(height: 5),
|
||||
const Text("web端暂不支持精细选择"),
|
||||
const SizedBox(height: 5),
|
||||
Wrap(
|
||||
spacing: 5.0,
|
||||
runSpacing: 2.0,
|
||||
children: [
|
||||
FilledButton.tonal(
|
||||
onPressed: () async {
|
||||
Get.back();
|
||||
SmartDialog.showLoading(
|
||||
msg: '正在提交',
|
||||
);
|
||||
final res =
|
||||
await VideoHttp.dislikeVideo(
|
||||
bvid: videoItem.bvid!,
|
||||
type: true,
|
||||
);
|
||||
SmartDialog.dismiss();
|
||||
if (res.isSuccess) {
|
||||
SmartDialog.showToast('点踩成功');
|
||||
onRemove?.call();
|
||||
} else {
|
||||
res.toast();
|
||||
}
|
||||
},
|
||||
style: FilledButton.styleFrom(
|
||||
visualDensity:
|
||||
VisualDensity.compact,
|
||||
),
|
||||
child: const Text("点踩"),
|
||||
),
|
||||
FilledButton.tonal(
|
||||
onPressed: () async {
|
||||
Get.back();
|
||||
SmartDialog.showLoading(
|
||||
msg: '正在提交',
|
||||
);
|
||||
final res =
|
||||
await VideoHttp.dislikeVideo(
|
||||
bvid: videoItem.bvid!,
|
||||
type: false,
|
||||
);
|
||||
SmartDialog.dismiss();
|
||||
SmartDialog.showToast(
|
||||
res.isSuccess
|
||||
? '取消踩'
|
||||
: res.toString(),
|
||||
);
|
||||
},
|
||||
style: FilledButton.styleFrom(
|
||||
visualDensity:
|
||||
VisualDensity.compact,
|
||||
),
|
||||
child: const Text("撤销"),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
},
|
||||
),
|
||||
_VideoCustomAction(
|
||||
'拉黑:${videoItem.owner.name}',
|
||||
const Icon(MdiIcons.cancel, size: 16),
|
||||
() => showDialog(
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return AlertDialog(
|
||||
title: const Text('提示'),
|
||||
content: Text(
|
||||
'确定拉黑:${videoItem.owner.name}(${videoItem.owner.mid})?'
|
||||
'\n\n注:被拉黑的Up可以在隐私设置-黑名单管理中解除',
|
||||
),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: Get.back,
|
||||
child: Text(
|
||||
'点错了',
|
||||
style: TextStyle(
|
||||
color: Theme.of(
|
||||
context,
|
||||
).colorScheme.outline,
|
||||
content: SingleChildScrollView(
|
||||
child: Column(
|
||||
crossAxisAlignment: .start,
|
||||
children: [
|
||||
if (tp.dislikeReasons != null) ...[
|
||||
const Text('我不想看'),
|
||||
const SizedBox(height: 5),
|
||||
Wrap(
|
||||
spacing: 8.0,
|
||||
runSpacing: 8.0,
|
||||
children: tp.dislikeReasons!.map((
|
||||
item,
|
||||
) {
|
||||
return actionButton(item, null);
|
||||
}).toList(),
|
||||
),
|
||||
],
|
||||
if (tp.feedbacks != null) ...[
|
||||
const SizedBox(height: 5),
|
||||
const Text('反馈'),
|
||||
const SizedBox(height: 5),
|
||||
Wrap(
|
||||
spacing: 8.0,
|
||||
runSpacing: 8.0,
|
||||
children: tp.feedbacks!.map((item) {
|
||||
return actionButton(null, item);
|
||||
}).toList(),
|
||||
),
|
||||
],
|
||||
const Divider(),
|
||||
Center(
|
||||
child: FilledButton.tonal(
|
||||
onPressed: () async {
|
||||
SmartDialog.showLoading(
|
||||
msg: '正在提交',
|
||||
);
|
||||
final res =
|
||||
await VideoHttp.feedDislikeCancel(
|
||||
id: item.param!,
|
||||
goto: item.goto!,
|
||||
);
|
||||
SmartDialog.dismiss();
|
||||
SmartDialog.showToast(
|
||||
res.isSuccess
|
||||
? "成功"
|
||||
: res.toString(),
|
||||
);
|
||||
Get.back();
|
||||
},
|
||||
style: FilledButton.styleFrom(
|
||||
visualDensity: VisualDensity.compact,
|
||||
),
|
||||
child: const Text("撤销"),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () async {
|
||||
Get.back();
|
||||
final res = await VideoHttp.relationMod(
|
||||
mid: videoItem.owner.mid!,
|
||||
act: 5,
|
||||
reSrc: 11,
|
||||
);
|
||||
if (res.isSuccess) {
|
||||
onRemove?.call();
|
||||
} else {
|
||||
res.toast();
|
||||
}
|
||||
},
|
||||
child: const Text('确认'),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
} else {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return AlertDialog(
|
||||
content: SingleChildScrollView(
|
||||
child: Column(
|
||||
children: [
|
||||
const SizedBox(height: 5),
|
||||
const Text("web端暂不支持精细选择"),
|
||||
const SizedBox(height: 5),
|
||||
Wrap(
|
||||
spacing: 5.0,
|
||||
runSpacing: 2.0,
|
||||
children: [
|
||||
FilledButton.tonal(
|
||||
onPressed: () async {
|
||||
Get.back();
|
||||
SmartDialog.showLoading(
|
||||
msg: '正在提交',
|
||||
);
|
||||
final res =
|
||||
await VideoHttp.dislikeVideo(
|
||||
bvid: videoItem.bvid!,
|
||||
type: true,
|
||||
);
|
||||
SmartDialog.dismiss();
|
||||
if (res.isSuccess) {
|
||||
SmartDialog.showToast('点踩成功');
|
||||
onRemove?.call();
|
||||
} else {
|
||||
res.toast();
|
||||
}
|
||||
},
|
||||
style: FilledButton.styleFrom(
|
||||
visualDensity:
|
||||
VisualDensity.compact,
|
||||
),
|
||||
child: const Text("点踩"),
|
||||
),
|
||||
FilledButton.tonal(
|
||||
onPressed: () async {
|
||||
Get.back();
|
||||
SmartDialog.showLoading(
|
||||
msg: '正在提交',
|
||||
);
|
||||
final res =
|
||||
await VideoHttp.dislikeVideo(
|
||||
bvid: videoItem.bvid!,
|
||||
type: false,
|
||||
);
|
||||
SmartDialog.dismiss();
|
||||
SmartDialog.showToast(
|
||||
res.isSuccess
|
||||
? '取消踩'
|
||||
: res.toString(),
|
||||
);
|
||||
},
|
||||
style: FilledButton.styleFrom(
|
||||
visualDensity:
|
||||
VisualDensity.compact,
|
||||
),
|
||||
child: const Text("撤销"),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
},
|
||||
),
|
||||
_VideoCustomAction(
|
||||
'拉黑:${videoItem.owner.name}',
|
||||
const Icon(MdiIcons.cancel, size: 16),
|
||||
() => showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return AlertDialog(
|
||||
title: const Text('提示'),
|
||||
content: Text(
|
||||
'确定拉黑:${videoItem.owner.name}(${videoItem.owner.mid})?'
|
||||
'\n\n注:被拉黑的Up可以在隐私设置-黑名单管理中解除',
|
||||
),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: Get.back,
|
||||
child: Text(
|
||||
'点错了',
|
||||
style: TextStyle(
|
||||
color: Theme.of(
|
||||
context,
|
||||
).colorScheme.outline,
|
||||
),
|
||||
),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () async {
|
||||
Get.back();
|
||||
final res = await VideoHttp.relationMod(
|
||||
mid: videoItem.owner.mid!,
|
||||
act: 5,
|
||||
reSrc: 11,
|
||||
);
|
||||
if (res.isSuccess) {
|
||||
onRemove?.call();
|
||||
} else {
|
||||
res.toast();
|
||||
}
|
||||
},
|
||||
child: const Text('确认'),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
_VideoCustomAction(
|
||||
"${MineController.anonymity.value ? '退出' : '进入'}无痕模式",
|
||||
MineController.anonymity.value
|
||||
? const Icon(MdiIcons.incognitoOff, size: 16)
|
||||
: const Icon(MdiIcons.incognito, size: 16),
|
||||
MineController.onChangeAnonymity,
|
||||
),
|
||||
]
|
||||
.map(
|
||||
(e) => PopupMenuItem(
|
||||
height: menuItemHeight,
|
||||
onTap: e.onTap,
|
||||
child: Row(
|
||||
children: [
|
||||
e.icon,
|
||||
const SizedBox(width: 6),
|
||||
Text(e.title, style: const TextStyle(fontSize: 13)),
|
||||
],
|
||||
_VideoCustomAction(
|
||||
"${MineController.anonymity.value ? '退出' : '进入'}无痕模式",
|
||||
MineController.anonymity.value
|
||||
? const Icon(MdiIcons.incognitoOff, size: 16)
|
||||
: const Icon(MdiIcons.incognito, size: 16),
|
||||
MineController.onChangeAnonymity,
|
||||
),
|
||||
]
|
||||
.map(
|
||||
(e) => PopupMenuItem(
|
||||
height: menuItemHeight,
|
||||
onTap: e.onTap,
|
||||
child: Row(
|
||||
children: [
|
||||
e.icon,
|
||||
const SizedBox(width: 6),
|
||||
Text(e.title, style: const TextStyle(fontSize: 13)),
|
||||
],
|
||||
),
|
||||
),
|
||||
)
|
||||
.toList(),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
.toList(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -607,7 +607,7 @@ abstract final class MsgHttp {
|
||||
}
|
||||
|
||||
static Future<LoadingState<Null>> imMsgReport({
|
||||
required Object accusedUid,
|
||||
required int accusedUid,
|
||||
required int reasonType,
|
||||
required String reasonDesc,
|
||||
required Map comment,
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import 'package:PiliPlus/common/constants.dart';
|
||||
import 'package:PiliPlus/models/dynamics/result.dart';
|
||||
import 'package:PiliPlus/models/dynamics/vote_model.dart';
|
||||
|
||||
@@ -48,7 +49,7 @@ class Pic {
|
||||
style = json['style'];
|
||||
liveUrl = json['live_url'];
|
||||
if (width != null && height != null) {
|
||||
isLongPic = (height! / width!) > 22 / 9;
|
||||
isLongPic = (height! / width!) > StyleString.imgMaxRatio;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -182,69 +182,66 @@ class HistoryItem extends StatelessWidget {
|
||||
Positioned(
|
||||
right: 12,
|
||||
bottom: 0,
|
||||
child: SizedBox(
|
||||
width: 29,
|
||||
height: 29,
|
||||
child: PopupMenuButton(
|
||||
padding: EdgeInsets.zero,
|
||||
tooltip: '功能菜单',
|
||||
icon: Icon(
|
||||
Icons.more_vert_outlined,
|
||||
color: theme.colorScheme.outline,
|
||||
size: 18,
|
||||
),
|
||||
position: PopupMenuPosition.under,
|
||||
itemBuilder: (_) => [
|
||||
if (item.authorMid != null &&
|
||||
item.authorName?.isNotEmpty == true)
|
||||
PopupMenuItem(
|
||||
onTap: () =>
|
||||
Get.toNamed('/member?mid=${item.authorMid}'),
|
||||
height: 38,
|
||||
child: Row(
|
||||
children: [
|
||||
const Icon(
|
||||
MdiIcons.accountCircleOutline,
|
||||
size: 16,
|
||||
),
|
||||
const SizedBox(width: 6),
|
||||
Text(
|
||||
'访问:${item.authorName}',
|
||||
style: const TextStyle(fontSize: 13),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
if (business != 'pgc' &&
|
||||
item.badge != '番剧' &&
|
||||
item.tagName?.contains('动画') != true &&
|
||||
business != 'live' &&
|
||||
business?.contains('article') != true)
|
||||
PopupMenuItem(
|
||||
onTap: () =>
|
||||
UserHttp.toViewLater(bvid: item.history.bvid),
|
||||
height: 38,
|
||||
child: const Row(
|
||||
children: [
|
||||
Icon(Icons.watch_later_outlined, size: 16),
|
||||
SizedBox(width: 6),
|
||||
Text('稍后再看', style: TextStyle(fontSize: 13)),
|
||||
],
|
||||
),
|
||||
),
|
||||
width: 29,
|
||||
height: 29,
|
||||
child: PopupMenuButton(
|
||||
padding: EdgeInsets.zero,
|
||||
tooltip: '功能菜单',
|
||||
icon: Icon(
|
||||
Icons.more_vert_outlined,
|
||||
color: theme.colorScheme.outline,
|
||||
size: 18,
|
||||
),
|
||||
position: PopupMenuPosition.under,
|
||||
itemBuilder: (_) => [
|
||||
if (item.authorMid != null &&
|
||||
item.authorName?.isNotEmpty == true)
|
||||
PopupMenuItem(
|
||||
onTap: () => onDelete(item.kid!, business!),
|
||||
onTap: () => Get.toNamed('/member?mid=${item.authorMid}'),
|
||||
height: 38,
|
||||
child: const Row(
|
||||
child: Row(
|
||||
children: [
|
||||
Icon(Icons.close_outlined, size: 16),
|
||||
SizedBox(width: 6),
|
||||
Text('删除记录', style: TextStyle(fontSize: 13)),
|
||||
const Icon(
|
||||
MdiIcons.accountCircleOutline,
|
||||
size: 16,
|
||||
),
|
||||
const SizedBox(width: 6),
|
||||
Text(
|
||||
'访问:${item.authorName}',
|
||||
style: const TextStyle(fontSize: 13),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
if (business != 'pgc' &&
|
||||
item.badge != '番剧' &&
|
||||
item.tagName?.contains('动画') != true &&
|
||||
business != 'live' &&
|
||||
business?.contains('article') != true)
|
||||
PopupMenuItem(
|
||||
onTap: () =>
|
||||
UserHttp.toViewLater(bvid: item.history.bvid),
|
||||
height: 38,
|
||||
child: const Row(
|
||||
children: [
|
||||
Icon(Icons.watch_later_outlined, size: 16),
|
||||
SizedBox(width: 6),
|
||||
Text('稍后再看', style: TextStyle(fontSize: 13)),
|
||||
],
|
||||
),
|
||||
),
|
||||
PopupMenuItem(
|
||||
onTap: () => onDelete(item.kid!, business!),
|
||||
height: 38,
|
||||
child: const Row(
|
||||
children: [
|
||||
Icon(Icons.close_outlined, size: 16),
|
||||
SizedBox(width: 6),
|
||||
Text('删除记录', style: TextStyle(fontSize: 13)),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
|
||||
@@ -2,6 +2,7 @@ import 'dart:io';
|
||||
import 'dart:math';
|
||||
import 'dart:ui';
|
||||
|
||||
import 'package:PiliPlus/common/constants.dart';
|
||||
import 'package:PiliPlus/common/widgets/button/icon_button.dart';
|
||||
import 'package:PiliPlus/common/widgets/custom_icon.dart';
|
||||
import 'package:PiliPlus/common/widgets/flutter/text_field/controller.dart';
|
||||
@@ -308,41 +309,38 @@ class _LiveRoomPageState extends State<LiveRoomPage>
|
||||
Positioned(
|
||||
left: padding.left + 25,
|
||||
bottom: 25,
|
||||
width: 255,
|
||||
child: Obx(() {
|
||||
final item = _liveRoomController.fsSC.value;
|
||||
if (item == null) {
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
try {
|
||||
return SizedBox(
|
||||
return Stack(
|
||||
key: ValueKey(item.id),
|
||||
width: 255,
|
||||
child: Stack(
|
||||
clipBehavior: Clip.none,
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(right: 6, top: 6),
|
||||
child: SuperChatCard(
|
||||
item: item,
|
||||
onRemove: () => _liveRoomController.fsSC.value = null,
|
||||
onReport: () => _liveRoomController.reportSC(item),
|
||||
),
|
||||
clipBehavior: Clip.none,
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(right: 6, top: 6),
|
||||
child: SuperChatCard(
|
||||
item: item,
|
||||
onRemove: () => _liveRoomController.fsSC.value = null,
|
||||
onReport: () => _liveRoomController.reportSC(item),
|
||||
),
|
||||
Positioned(
|
||||
right: 0,
|
||||
top: 0,
|
||||
child: iconButton(
|
||||
size: 24,
|
||||
iconSize: 14,
|
||||
bgColor: const Color(0xEEFFFFFF),
|
||||
iconColor: Colors.black54,
|
||||
icon: const Icon(Icons.clear),
|
||||
onPressed: () =>
|
||||
_liveRoomController.fsSC.value = null,
|
||||
),
|
||||
),
|
||||
Positioned(
|
||||
right: 0,
|
||||
top: 0,
|
||||
child: iconButton(
|
||||
size: 24,
|
||||
iconSize: 14,
|
||||
bgColor: const Color(0xEEFFFFFF),
|
||||
iconColor: Colors.black54,
|
||||
icon: const Icon(Icons.clear),
|
||||
onPressed: () => _liveRoomController.fsSC.value = null,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
} catch (_) {
|
||||
if (kDebugMode) rethrow;
|
||||
@@ -428,7 +426,7 @@ class _LiveRoomPageState extends State<LiveRoomPage>
|
||||
}
|
||||
|
||||
Widget _buildPH(bool isFullScreen) {
|
||||
final height = maxWidth * 9 / 16;
|
||||
final height = maxWidth / StyleString.aspectRatio16x9;
|
||||
final videoHeight = isFullScreen ? maxHeight - padding.top : height;
|
||||
final bottomHeight = maxHeight - padding.top - height - kToolbarHeight;
|
||||
return Column(
|
||||
@@ -476,24 +474,20 @@ class _LiveRoomPageState extends State<LiveRoomPage>
|
||||
left: 0,
|
||||
right: 0,
|
||||
bottom: 55 + bottomHeight,
|
||||
height: maxHeight * 0.32,
|
||||
child: Offstage(
|
||||
offstage: isFullScreen,
|
||||
child: SizedBox(
|
||||
height: maxHeight * 0.32,
|
||||
child: _buildChatWidget(true),
|
||||
),
|
||||
child: _buildChatWidget(true),
|
||||
),
|
||||
),
|
||||
Positioned(
|
||||
left: 0,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
height: bottomHeight,
|
||||
child: Offstage(
|
||||
offstage: isFullScreen,
|
||||
child: SizedBox(
|
||||
height: bottomHeight,
|
||||
child: _buildInputWidget,
|
||||
),
|
||||
child: _buildInputWidget,
|
||||
),
|
||||
),
|
||||
],
|
||||
@@ -998,7 +992,7 @@ class _RenderBorderIndicator extends RenderBox {
|
||||
|
||||
@override
|
||||
void performLayout() {
|
||||
size = constraints.constrain(Size(constraints.maxWidth, _radius.x));
|
||||
size = constraints.constrainDimensions(constraints.maxWidth, _radius.x);
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -1011,7 +1005,7 @@ class _RenderBorderIndicator extends RenderBox {
|
||||
}
|
||||
BoxBorder.paintNonUniformBorder(
|
||||
canvas,
|
||||
Rect.fromLTWH(0, 0, width, size.height),
|
||||
Rect.fromLTRB(0, 0, width, size.height),
|
||||
borderRadius: BorderRadius.only(
|
||||
topLeft: _isLeft ? _radius : .zero,
|
||||
topRight: _isLeft ? .zero : _radius,
|
||||
|
||||
@@ -214,8 +214,9 @@ class VideoCardHMemberVideo extends StatelessWidget {
|
||||
Positioned(
|
||||
bottom: 0,
|
||||
right: 12,
|
||||
width: 29,
|
||||
height: 29,
|
||||
child: VideoPopupMenu(
|
||||
size: 29,
|
||||
iconSize: 17,
|
||||
videoItem: videoItem,
|
||||
),
|
||||
|
||||
@@ -410,7 +410,8 @@ class _SavePanelState extends State<SavePanel> {
|
||||
src: cover!,
|
||||
height: coverSize,
|
||||
width: coverType == _CoverType.def16_9
|
||||
? coverSize * 16 / 9
|
||||
? coverSize *
|
||||
StyleString.aspectRatio16x9
|
||||
: coverSize,
|
||||
quality: 100,
|
||||
borderRadius: const BorderRadius.all(
|
||||
|
||||
@@ -140,17 +140,15 @@ class SubItem extends StatelessWidget {
|
||||
Positioned(
|
||||
bottom: 0,
|
||||
right: 0,
|
||||
child: SizedBox(
|
||||
height: 35,
|
||||
width: 35,
|
||||
child: IconButton(
|
||||
onPressed: cancelSub,
|
||||
style: TextButton.styleFrom(
|
||||
foregroundColor: theme.colorScheme.outline,
|
||||
padding: EdgeInsets.zero,
|
||||
),
|
||||
icon: const Icon(Icons.delete_outline, size: 18),
|
||||
height: 35,
|
||||
width: 35,
|
||||
child: IconButton(
|
||||
onPressed: cancelSub,
|
||||
style: TextButton.styleFrom(
|
||||
foregroundColor: theme.colorScheme.outline,
|
||||
padding: EdgeInsets.zero,
|
||||
),
|
||||
icon: const Icon(Icons.delete_outline, size: 18),
|
||||
),
|
||||
),
|
||||
],
|
||||
|
||||
@@ -478,7 +478,7 @@ class _VideoDetailPageVState extends State<VideoDetailPageV>
|
||||
maxHeight = size.height;
|
||||
|
||||
final shortestSide = size.shortestSide;
|
||||
final minVideoHeight = shortestSide * 9 / 16;
|
||||
final minVideoHeight = shortestSide / StyleString.aspectRatio16x9;
|
||||
final maxVideoHeight = max(size.longestSide * 0.65, shortestSide);
|
||||
videoDetailController
|
||||
..isPortrait = isPortrait = maxHeight >= maxWidth
|
||||
@@ -960,7 +960,7 @@ class _VideoDetailPageVState extends State<VideoDetailPageV>
|
||||
enableVerticalExpand &&
|
||||
!isPortrait) {
|
||||
final double videoHeight = maxHeight - padding.vertical;
|
||||
final double width = videoHeight * 9 / 16;
|
||||
final double width = videoHeight / StyleString.aspectRatio16x9;
|
||||
final videoWidth = isFullScreen ? maxWidth : width;
|
||||
final introWidth = (maxWidth - padding.horizontal - width) / 2;
|
||||
final introHeight = maxHeight - padding.top;
|
||||
@@ -1022,10 +1022,10 @@ class _VideoDetailPageVState extends State<VideoDetailPageV>
|
||||
width = maxWidth - clampDouble(maxWidth - width, 280, 425);
|
||||
}
|
||||
final videoWidth = isFullScreen ? maxWidth : width;
|
||||
final double height = width * 9 / 16;
|
||||
final double height = width / StyleString.aspectRatio16x9;
|
||||
final videoHeight = isFullScreen ? maxHeight - padding.top : height;
|
||||
if (height > maxHeight) {
|
||||
return childSplit(16 / 9);
|
||||
return childSplit(StyleString.aspectRatio16x9);
|
||||
}
|
||||
final introHeight = maxHeight - height - padding.top;
|
||||
final showIntro =
|
||||
@@ -1396,7 +1396,7 @@ class _VideoDetailPageVState extends State<VideoDetailPageV>
|
||||
child = childWhenDisabled;
|
||||
} else if (maxWidth / maxHeight >= kScreenRatio) {
|
||||
child = childWhenDisabledLandscape;
|
||||
} else if (maxWidth * (9 / 16) < (2 / 5) * maxHeight) {
|
||||
} else if (maxWidth / StyleString.aspectRatio16x9 < 0.4 * maxHeight) {
|
||||
child = childWhenDisabled;
|
||||
} else {
|
||||
child = childWhenDisabledAlmostSquare;
|
||||
@@ -1620,21 +1620,19 @@ class _VideoDetailPageVState extends State<VideoDetailPageV>
|
||||
Positioned(
|
||||
left: 16,
|
||||
bottom: isFullScreen ? max(75, maxHeight * 0.25) : 75,
|
||||
child: SizedBox(
|
||||
width: MediaQuery.textScalerOf(context).scale(120),
|
||||
child: AnimatedList(
|
||||
padding: EdgeInsets.zero,
|
||||
key: videoDetailController.listKey,
|
||||
reverse: true,
|
||||
shrinkWrap: true,
|
||||
initialItemCount: videoDetailController.listData.length,
|
||||
itemBuilder: (context, index, animation) {
|
||||
return videoDetailController.buildItem(
|
||||
videoDetailController.listData[index],
|
||||
animation,
|
||||
);
|
||||
},
|
||||
),
|
||||
width: MediaQuery.textScalerOf(context).scale(120),
|
||||
child: AnimatedList(
|
||||
padding: EdgeInsets.zero,
|
||||
key: videoDetailController.listKey,
|
||||
reverse: true,
|
||||
shrinkWrap: true,
|
||||
initialItemCount: videoDetailController.listData.length,
|
||||
itemBuilder: (context, index, animation) {
|
||||
return videoDetailController.buildItem(
|
||||
videoDetailController.listData[index],
|
||||
animation,
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
|
||||
|
||||
@@ -134,10 +134,10 @@ class WhisperDetailController extends CommonListController<RspSessionMsg, Msg> {
|
||||
|
||||
Future<LoadingState> onReport(Msg item, int reasonType, String reasonDesc) {
|
||||
return MsgHttp.imMsgReport(
|
||||
accusedUid: item.senderUid,
|
||||
accusedUid: item.senderUid.toInt(),
|
||||
reasonType: reasonType,
|
||||
reasonDesc: reasonDesc,
|
||||
comment: {'group_id': 0, 'msg_key': item.msgKey},
|
||||
comment: {'group_id': 0, 'msg_key': item.msgKey.toString()},
|
||||
extra: {"msg_keys": []},
|
||||
);
|
||||
}
|
||||
|
||||
@@ -435,7 +435,8 @@ class ChatItem extends StatelessWidget {
|
||||
NetworkImgLayer(
|
||||
type: ImageType.emote,
|
||||
width: constrains.maxWidth,
|
||||
height: constrains.maxWidth * 9 / 16,
|
||||
height:
|
||||
constrains.maxWidth / StyleString.aspectRatio16x9,
|
||||
src: content['cover'],
|
||||
),
|
||||
PBadge(
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import 'package:PiliPlus/common/constants.dart';
|
||||
import 'package:flutter/material.dart' show BoxFit;
|
||||
|
||||
enum VideoFitType {
|
||||
@@ -9,7 +10,7 @@ enum VideoFitType {
|
||||
none('原始', boxFit: BoxFit.none),
|
||||
scaleDown('限制', boxFit: BoxFit.scaleDown),
|
||||
ratio_4x3('4:3', aspectRatio: 4 / 3),
|
||||
ratio_16x9('16:9', aspectRatio: 16 / 9)
|
||||
ratio_16x9('16:9', aspectRatio: StyleString.aspectRatio16x9)
|
||||
;
|
||||
|
||||
final String desc;
|
||||
|
||||
@@ -2459,7 +2459,7 @@ Widget buildDmChart(
|
||||
bottom:
|
||||
videoDetailController.viewPointList.isNotEmpty &&
|
||||
videoDetailController.showVP.value
|
||||
? 20.25 + offset
|
||||
? 19.25 + offset
|
||||
: 4.25 + offset,
|
||||
),
|
||||
child: LineChart(
|
||||
|
||||
Reference in New Issue
Block a user