flutter/lib/components/my_qrcode.dart

139 lines
4.4 KiB
Dart
Raw Normal View History

2025-09-17 15:32:18 +08:00
import 'dart:typed_data';
import 'dart:ui' as ui;
import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:get/get.dart';
import 'package:image_gallery_saver_plus/image_gallery_saver_plus.dart';
import 'package:loopin/IM/controller/im_user_info_controller.dart';
import 'package:loopin/IM/im_friend_listeners.dart';
import 'package:loopin/components/my_toast.dart';
import 'package:loopin/styles/index.dart';
import 'package:loopin/utils/scan_code_type.dart';
import 'package:pretty_qr_code/pretty_qr_code.dart';
class MyQrcode extends StatelessWidget {
2025-09-18 16:13:37 +08:00
MyQrcode({
super.key,
this.prefix,
});
final String? prefix;
2025-09-17 15:32:18 +08:00
final controller = Get.find<ImUserInfoController>();
// GlobalKey 用于截图 Widget
final GlobalKey _qrKey = GlobalKey();
/// 将 Widget 渲染为 Uint8List
2025-09-18 16:13:37 +08:00
Future<Uint8List?> capturePng(BuildContext context) async {
2025-09-17 15:32:18 +08:00
try {
final boundary = _qrKey.currentContext?.findRenderObject() as RenderRepaintBoundary?;
if (boundary == null) return null;
2025-09-18 16:13:37 +08:00
// final image = await boundary.toImage(pixelRatio: ui.window.devicePixelRatio);
final pixelRatio = View.of(context).devicePixelRatio;
final image = await boundary.toImage(pixelRatio: pixelRatio);
2025-09-17 15:32:18 +08:00
final byteData = await image.toByteData(format: ui.ImageByteFormat.png);
return byteData?.buffer.asUint8List();
} catch (e) {
logger.e("截图失败: $e");
}
return null;
}
/// 保存二维码到相册
Future<void> saveQrToGallery() async {
logger.w('长安了');
2025-09-18 16:13:37 +08:00
final pngBytes = await capturePng(Get.context!);
2025-09-17 15:32:18 +08:00
if (pngBytes == null) return;
final result = await ImageGallerySaverPlus.saveImage(
pngBytes,
quality: 100,
name: "my_qr_${DateTime.now().millisecondsSinceEpoch}",
);
logger.w("保存结果: $result");
MyToast().tip(
title: '图片已保存',
position: 'top',
type: 'success',
);
}
@override
Widget build(BuildContext context) {
final userID = controller.userID.value;
final faceUrl = controller.faceUrl.value;
ImageProvider face;
if (faceUrl.isEmpty) {
face = AssetImage('assets/images/logo/logo.png');
} else {
face = CachedNetworkImageProvider(faceUrl);
}
2025-09-18 16:13:37 +08:00
final data = '${prefix ?? QrTypeCode.hym}$userID';
2025-09-17 15:32:18 +08:00
return GestureDetector(
onLongPress: () {
showModalBottomSheet(
context: Get.context!,
backgroundColor: Colors.white,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.vertical(top: Radius.circular(16)),
),
builder: (context) {
return SafeArea(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
ListTile(
leading: const Icon(Icons.save, color: Colors.black),
title: const Text('保存到相册', style: TextStyle(color: Colors.black)),
onTap: () async {
await saveQrToGallery();
Get.back();
},
),
],
),
);
},
);
},
child: Center(
child: Container(
alignment: Alignment.topCenter,
decoration: BoxDecoration(
color: Colors.transparent,
),
child: RepaintBoundary(
key: _qrKey,
child: PrettyQrView.data(
errorCorrectLevel: QrErrorCorrectLevel.H, // 高容错
2025-09-18 16:13:37 +08:00
data: data, // 二维码内容
2025-09-17 15:32:18 +08:00
decoration: PrettyQrDecoration(
background: Colors.transparent,
shape: const PrettyQrShape.custom(
PrettyQrSmoothSymbol(color: FStyle.primaryColor),
finderPattern: PrettyQrSmoothSymbol(color: FStyle.primaryColor),
alignmentPatterns: PrettyQrSmoothSymbol(color: FStyle.primaryColor),
),
image: PrettyQrDecorationImage(
image: face,
scale: 0.3, // 默认
opacity: 1,
padding: EdgeInsets.all(8.0), // 图片与二维码的边距
),
quietZone: const PrettyQrQuietZone.modules(2),
),
),
),
),
),
);
}
}