mod: image save dialog

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
This commit is contained in:
bggRGjQaUbCoE
2024-12-29 10:31:13 +08:00
parent eca69f3d6d
commit e9945ab63c
21 changed files with 160 additions and 141 deletions

View File

@@ -0,0 +1,91 @@
import 'package:PiliPalaX/common/constants.dart';
import 'package:PiliPalaX/common/widgets/network_img_layer.dart';
import 'package:PiliPalaX/utils/download.dart';
import 'package:flutter/material.dart';
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
void imageSaveDialog({
required BuildContext context,
required String? title,
required String? cover,
}) {
final double imgWidth =
MediaQuery.sizeOf(context).width - StyleString.safeSpace * 2;
SmartDialog.show(
animationType: SmartAnimationType.centerScale_otherSlide,
builder: (context) => Container(
margin: const EdgeInsets.symmetric(horizontal: StyleString.safeSpace),
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.surface,
borderRadius: BorderRadius.circular(10.0),
),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Stack(
children: [
NetworkImgLayer(
width: imgWidth,
height: imgWidth / StyleString.aspectRatio,
src: cover,
quality: 100,
),
Positioned(
right: 8,
top: 8,
child: Container(
width: 30,
height: 30,
decoration: BoxDecoration(
color: Colors.black.withOpacity(0.3),
borderRadius:
const BorderRadius.all(Radius.circular(20))),
child: IconButton(
style: ButtonStyle(
padding: WidgetStateProperty.all(EdgeInsets.zero),
),
onPressed: SmartDialog.dismiss,
icon: const Icon(
Icons.close,
size: 18,
color: Colors.white,
),
),
),
),
],
),
Padding(
padding: const EdgeInsets.fromLTRB(12, 10, 8, 10),
child: Row(
children: [
Expanded(
child: SelectableText(
title ?? '',
style: Theme.of(context).textTheme.titleSmall,
),
),
const SizedBox(width: 4),
IconButton(
tooltip: '保存封面图',
onPressed: () async {
bool saveStatus = await DownloadUtils.downloadImg(
context,
[cover ?? ''],
);
// 保存成功,自动关闭弹窗
if (saveStatus) {
SmartDialog.dismiss();
}
},
icon: const Icon(Icons.download, size: 20),
)
],
),
),
],
),
),
);
}

View File

@@ -1,3 +1,4 @@
import 'package:PiliPalaX/common/widgets/image_save.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
@@ -16,24 +17,22 @@ class VideoCardH extends StatelessWidget {
const VideoCardH({
super.key,
required this.videoItem,
this.longPress,
this.longPressEnd,
this.source = 'normal',
this.showOwner = true,
this.showView = true,
this.showDanmaku = true,
this.showPubdate = false,
this.onTap,
this.onLongPress,
});
final dynamic videoItem;
final Function()? longPress;
final Function()? longPressEnd;
final String source;
final bool showOwner;
final bool showView;
final bool showDanmaku;
final bool showPubdate;
final GestureTapCallback? onTap;
final VoidCallback? onTap;
final VoidCallback? onLongPress;
@override
Widget build(BuildContext context) {
@@ -56,7 +55,23 @@ class VideoCardH extends StatelessWidget {
label: item.title.isEmpty ? 'label' : item.title): item.onTap!,
},
child: InkWell(
onLongPress: longPress,
onLongPress: () {
if (onLongPress != null) {
onLongPress!();
} else {
imageSaveDialog(
context: context,
title: videoItem.title is String
? videoItem.title
: videoItem.title is List
? (videoItem.title as List)
.map((item) => item['text'])
.join()
: '',
cover: videoItem.pic,
);
}
},
onTap: () async {
if (onTap != null) {
onTap?.call();
@@ -154,7 +169,7 @@ class VideoCardH extends StatelessWidget {
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (videoItem.title is String) ...[
if (videoItem.title is String)
Expanded(
child: Text(
videoItem.title as String,
@@ -167,8 +182,8 @@ class VideoCardH extends StatelessWidget {
maxLines: 2,
overflow: TextOverflow.ellipsis,
),
),
] else ...[
)
else
Expanded(
child: RichText(
overflow: TextOverflow.ellipsis,
@@ -194,7 +209,6 @@ class VideoCardH extends StatelessWidget {
),
),
),
],
// const Spacer(),
// if (videoItem.rcmdReason != null &&
// videoItem.rcmdReason.content != '')

View File

@@ -1,3 +1,4 @@
import 'package:PiliPalaX/common/widgets/image_save.dart';
import 'package:PiliPalaX/grpc/app/card/v1/card.pb.dart' as card;
import 'package:PiliPalaX/utils/app_scheme.dart';
import 'package:flutter/material.dart';
@@ -12,8 +13,6 @@ class VideoCardHGrpc extends StatelessWidget {
const VideoCardHGrpc({
super.key,
required this.videoItem,
this.longPress,
this.longPressEnd,
this.source = 'normal',
this.showOwner = true,
this.showView = true,
@@ -21,8 +20,6 @@ class VideoCardHGrpc extends StatelessWidget {
this.showPubdate = false,
});
final card.Card videoItem;
final Function()? longPress;
final Function()? longPressEnd;
final String source;
final bool showOwner;
final bool showView;
@@ -50,7 +47,11 @@ class VideoCardHGrpc extends StatelessWidget {
// },
child: InkWell(
borderRadius: BorderRadius.circular(12),
onLongPress: longPress,
onLongPress: () => imageSaveDialog(
context: context,
title: videoItem.smallCoverV5.base.title,
cover: videoItem.smallCoverV5.base.cover,
),
onTap: () async {
if (type == 'ketang') {
SmartDialog.showToast('课堂视频暂不支持播放');

View File

@@ -1,3 +1,4 @@
import 'package:PiliPalaX/common/widgets/image_save.dart';
import 'package:PiliPalaX/common/widgets/stat/danmu.dart';
import 'package:PiliPalaX/common/widgets/stat/view.dart';
import 'package:PiliPalaX/common/widgets/video_popup_menu.dart';
@@ -15,14 +16,10 @@ class VideoCardHMemberVideo extends StatelessWidget {
const VideoCardHMemberVideo({
super.key,
required this.videoItem,
this.longPress,
this.longPressEnd,
this.onTap,
this.bvid,
});
final Item videoItem;
final Function()? longPress;
final Function()? longPressEnd;
final VoidCallback? onTap;
final dynamic bvid;
@@ -34,7 +31,11 @@ class VideoCardHMemberVideo extends StatelessWidget {
return Stack(
children: [
InkWell(
onLongPress: longPress,
onLongPress: () => imageSaveDialog(
context: context,
title: videoItem.title,
cover: videoItem.cover,
),
onTap: () async {
if (onTap != null) {
onTap!();

View File

@@ -1,3 +1,4 @@
import 'package:PiliPalaX/common/widgets/image_save.dart';
import 'package:PiliPalaX/http/search.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
@@ -18,14 +19,10 @@ import 'video_popup_menu.dart';
// 视频卡片 - 垂直布局
class VideoCardV extends StatelessWidget {
final dynamic videoItem;
final Function()? longPress;
final Function()? longPressEnd;
const VideoCardV({
super.key,
required this.videoItem,
this.longPress,
this.longPressEnd,
});
bool isStringNumeric(String str) {
@@ -163,7 +160,11 @@ class VideoCardV extends StatelessWidget {
margin: EdgeInsets.zero,
child: InkWell(
onTap: () async => onPushDetail(heroTag),
onLongPress: longPress,
onLongPress: () => imageSaveDialog(
context: context,
title: videoItem.title,
cover: videoItem.pic,
),
child: Column(
children: [
AspectRatio(

View File

@@ -1,3 +1,4 @@
import 'package:PiliPalaX/common/widgets/image_save.dart';
import 'package:PiliPalaX/models/space/item.dart';
import 'package:flutter/material.dart';
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
@@ -10,14 +11,10 @@ import 'network_img_layer.dart';
// 视频卡片 - 垂直布局
class VideoCardVMemberHome extends StatelessWidget {
final Item videoItem;
final Function()? longPress;
final Function()? longPressEnd;
const VideoCardVMemberHome({
super.key,
required this.videoItem,
this.longPress,
this.longPressEnd,
});
void onPushDetail(heroTag) async {
@@ -147,7 +144,11 @@ class VideoCardVMemberHome extends StatelessWidget {
margin: EdgeInsets.zero,
child: InkWell(
onTap: () async => onPushDetail(heroTag),
onLongPress: longPress,
onLongPress: () => imageSaveDialog(
context: context,
title: videoItem.title,
cover: videoItem.cover,
),
child: Column(
children: [
AspectRatio(