diff --git a/assets/images/lost-poster-bg.png b/assets/images/lost-poster-bg.png new file mode 100644 index 0000000..089067f Binary files /dev/null and b/assets/images/lost-poster-bg.png differ diff --git a/assets/images/lost-poster-logo-white.png b/assets/images/lost-poster-logo-white.png new file mode 100644 index 0000000..3417562 Binary files /dev/null and b/assets/images/lost-poster-logo-white.png differ diff --git a/ios/Podfile.lock b/ios/Podfile.lock index e9485f1..a390ad3 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -24,6 +24,9 @@ PODS: - flutter_udid (0.0.1): - Flutter - SAMKeychain + - gal (1.0.0): + - Flutter + - FlutterMacOS - in_app_purchase_storekit (0.0.1): - Flutter - FlutterMacOS @@ -51,6 +54,7 @@ DEPENDENCIES: - flutter_inappwebview_ios (from `.symlinks/plugins/flutter_inappwebview_ios/ios`) - flutter_keychain (from `.symlinks/plugins/flutter_keychain/ios`) - flutter_udid (from `.symlinks/plugins/flutter_udid/ios`) + - gal (from `.symlinks/plugins/gal/darwin`) - in_app_purchase_storekit (from `.symlinks/plugins/in_app_purchase_storekit/darwin`) - package_info_plus (from `.symlinks/plugins/package_info_plus/ios`) - path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`) @@ -81,6 +85,8 @@ EXTERNAL SOURCES: :path: ".symlinks/plugins/flutter_keychain/ios" flutter_udid: :path: ".symlinks/plugins/flutter_udid/ios" + gal: + :path: ".symlinks/plugins/gal/darwin" in_app_purchase_storekit: :path: ".symlinks/plugins/in_app_purchase_storekit/darwin" package_info_plus: @@ -104,6 +110,7 @@ SPEC CHECKSUMS: flutter_inappwebview_ios: 6f63631e2c62a7c350263b13fa5427aedefe81d4 flutter_keychain: 01aabf894ffe8b01adfda1d9df21c210c1b4b452 flutter_udid: b2417673f287ee62817a1de3d1643f47b9f508ab + gal: 6a522c75909f1244732d4596d11d6a2f86ff37a5 in_app_purchase_storekit: a1ce04056e23eecc666b086040239da7619cd783 OrderedSet: e539b66b644ff081c73a262d24ad552a69be3a94 package_info_plus: c0502532a26c7662a62a356cebe2692ec5fe4ec4 diff --git a/lib/app/modules/hi_anti_lost/controllers/hi_anti_lost_controller.dart b/lib/app/modules/hi_anti_lost/controllers/hi_anti_lost_controller.dart index 9ba4b63..e52a1a7 100644 --- a/lib/app/modules/hi_anti_lost/controllers/hi_anti_lost_controller.dart +++ b/lib/app/modules/hi_anti_lost/controllers/hi_anti_lost_controller.dart @@ -1,3 +1,4 @@ +import 'dart:io'; import 'dart:typed_data'; import 'dart:ui' as ui; import 'package:flutter/material.dart'; @@ -5,6 +6,7 @@ import 'package:flutter/rendering.dart'; import 'package:get/get.dart'; import 'package:gal/gal.dart'; import 'package:kaer_with_panels/app/utils/kr_common_util.dart'; +import 'package:kaer_with_panels/app/widgets/dialogs/hi_dialog.dart'; import 'package:url_launcher/url_launcher.dart'; class HIAntiLostController extends GetxController { @@ -20,9 +22,9 @@ class HIAntiLostController extends GetxController { } // Capture image - RenderRepaintBoundary? boundary = - repaintKey.currentContext?.findRenderObject() as RenderRepaintBoundary?; - + RenderRepaintBoundary? boundary = repaintKey.currentContext + ?.findRenderObject() as RenderRepaintBoundary?; + if (boundary == null) { throw Exception("Cannot find boundary"); } @@ -30,26 +32,38 @@ class HIAntiLostController extends GetxController { // Check if the boundary needs layout (sometimes Offstage needs a frame) if (boundary.debugNeedsPaint) { await Future.delayed(const Duration(milliseconds: 20)); - boundary = repaintKey.currentContext?.findRenderObject() as RenderRepaintBoundary?; + boundary = repaintKey.currentContext?.findRenderObject() + as RenderRepaintBoundary?; } ui.Image image = await boundary!.toImage(pixelRatio: 3.0); ByteData? byteData = await image.toByteData(format: ui.ImageByteFormat.png); - + if (byteData != null) { final Uint8List pngBytes = byteData.buffer.asUint8List(); await Gal.putImageBytes(pngBytes); - KRCommonUtil.kr_showToast("保存成功"); + // KRCommonUtil.kr_showToast("保存成功"); + + String message = "已保存至系统相册"; + if (Platform.isMacOS) { + message = "已保存至系统【照片】应用"; + } else if (Platform.isWindows) { + message = "已保存至系统【图片】文件夹"; + } + + HIDialog.show( + message: message, + ); } else { KRCommonUtil.kr_showToast("生成图片失败"); } } catch (e) { debugPrint("Save image error: $e"); if (e is GalException) { - KRCommonUtil.kr_showToast("保存失败: No Permission"); + KRCommonUtil.kr_showToast("保存失败: No Permission"); } else { - KRCommonUtil.kr_showToast("保存失败"); + KRCommonUtil.kr_showToast("保存失败"); } } finally { KRCommonUtil.kr_hideLoading(); @@ -67,7 +81,7 @@ class HIAntiLostController extends GetxController { } else { // Fallback to web if (!await launchUrl(webUrl, mode: LaunchMode.externalApplication)) { - KRCommonUtil.kr_showToast("无法打开链接"); + KRCommonUtil.kr_showToast("无法打开链接"); } } } catch (e) { @@ -75,7 +89,7 @@ class HIAntiLostController extends GetxController { // Fallback to web if anything goes wrong try { if (!await launchUrl(webUrl, mode: LaunchMode.externalApplication)) { - KRCommonUtil.kr_showToast("无法打开链接"); + KRCommonUtil.kr_showToast("无法打开链接"); } } catch (e) { KRCommonUtil.kr_showToast("无法打开链接"); diff --git a/lib/app/modules/hi_anti_lost/views/hi_anti_lost_view.dart b/lib/app/modules/hi_anti_lost/views/hi_anti_lost_view.dart index ad8c498..b56e1ce 100644 --- a/lib/app/modules/hi_anti_lost/views/hi_anti_lost_view.dart +++ b/lib/app/modules/hi_anti_lost/views/hi_anti_lost_view.dart @@ -13,18 +13,11 @@ class HIAntiLostView extends GetView { @override Widget build(BuildContext context) { return HIBaseScaffold( - showBack: true, - title: null, - topContentAreaHeight: 0, - backgroundColor: Colors.black, // Dark background child: Stack( fit: StackFit.expand, children: [ - // 1. Visible Content Column( children: [ - SizedBox(height: 60.h), - // Card Container Container( width: double.infinity, margin: EdgeInsets.symmetric(horizontal: 40.w), @@ -46,7 +39,7 @@ class HIAntiLostView extends GetView { fontWeight: FontWeight.bold, ), ), - SizedBox(height: 25.h), + SizedBox(height: 25.w), Text( '建议保存Hi快VPN防丢二维码到相册\n永久保障您的互联网自由', textAlign: TextAlign.center, @@ -56,7 +49,7 @@ class HIAntiLostView extends GetView { height: 1.5, ), ), - SizedBox(height: 10.h), + SizedBox(height: 10.w), // QR Code LayoutBuilder(builder: (context, constraints) { // Use a reasonable size for the QR code @@ -76,9 +69,8 @@ class HIAntiLostView extends GetView { dataModuleShape: QrDataModuleShape.square, color: Theme.of(context).primaryColor, ), - // center image - embeddedImage: - const AssetImage('assets/images/kr-logo.png'), + embeddedImage: const AssetImage( + 'assets/images/lost-poster-logo-white.png'), embeddedImageStyle: QrEmbeddedImageStyle( size: Size(36.w, 36.w), ), @@ -89,7 +81,7 @@ class HIAntiLostView extends GetView { ), ), - SizedBox(height: 30.h), + SizedBox(height: 10.w), // Save Button GestureDetector( @@ -101,7 +93,7 @@ class HIAntiLostView extends GetView { alignment: Alignment.center, decoration: BoxDecoration( color: Theme.of(context).primaryColor, - borderRadius: BorderRadius.circular(22.h), + borderRadius: BorderRadius.circular(22.w), ), child: Text( '保存到本地', @@ -120,7 +112,7 @@ class HIAntiLostView extends GetView { // 2. Bottom Button (Follow us on X) Positioned( - bottom: 40.h, + bottom: 40.w, left: 0, right: 0, child: Center( diff --git a/lib/app/modules/hi_anti_lost/widgets/hi_anti_lost_share_card.dart b/lib/app/modules/hi_anti_lost/widgets/hi_anti_lost_share_card.dart index e8bfa17..52ccdae 100644 --- a/lib/app/modules/hi_anti_lost/widgets/hi_anti_lost_share_card.dart +++ b/lib/app/modules/hi_anti_lost/widgets/hi_anti_lost_share_card.dart @@ -8,80 +8,50 @@ class HIAntiLostShareCard extends StatelessWidget { @override Widget build(BuildContext context) { - // Fixed width for the generated image, independent of screen size - final double cardWidth = 375.0; - final double cardHeight = 600.0; // Approx height + // Fixed dimensions for the generated image + final double cardWidth = 375.0; + final double cardHeight = 812.0; return Container( width: cardWidth, - // minimal height or let it expand - padding: EdgeInsets.all(20), - color: Colors.black, // Dark background - child: Column( - mainAxisSize: MainAxisSize.min, + height: cardHeight, + decoration: const BoxDecoration( + image: DecorationImage( + image: AssetImage('assets/images/lost-poster-bg.png'), + fit: BoxFit.cover, + ), + ), + child: Stack( children: [ - SizedBox(height: 40), - // Title - Text( - '保存二维码,防止失联', - style: TextStyle( - color: const Color(0xFFCCFF00), - fontSize: 24, - fontWeight: FontWeight.bold, - fontFamily: 'AlibabaPuHuiTi-Medium', - ), - ), - SizedBox(height: 20), - // Description - Text( - '建议保存Hi快VPN防丢二维码到相册\n永久保障您的互联网自由', - textAlign: TextAlign.center, - style: TextStyle( - color: const Color(0xFFCCFF00), - fontSize: 14, - height: 1.5, - fontFamily: 'AlibabaPuHuiTi-Regular', - ), - ), - SizedBox(height: 40), - // QR Code Card - Container( - padding: EdgeInsets.all(20), - decoration: BoxDecoration( - color: Colors.black, - border: Border.all(color: const Color(0xFFCCFF00), width: 3), - borderRadius: BorderRadius.circular(20), - ), - child: QrImageView( - data: 'https://github.com/hi-vpn/hi-client', // Replace with actual URL - version: QrVersions.auto, - size: 200, - backgroundColor: Colors.transparent, - eyeStyle: const QrEyeStyle( - eyeShape: QrEyeShape.square, - color: Color(0xFFCCFF00), - ), - dataModuleStyle: const QrDataModuleStyle( - dataModuleShape: QrDataModuleShape.square, - color: Color(0xFFCCFF00), - ), - embeddedImage: const AssetImage('assets/images/kr-logo.png'), - embeddedImageStyle: const QrEmbeddedImageStyle( - size: Size(50, 50), + Positioned( + top: 32, + right: 30, + child: SizedBox( + width: 108, + height: 108, + child: QrImageView( + data: + 'https://github.com/hi-vpn/hi-client', // Replace with actual URL + version: QrVersions.auto, + size: 108, + padding: EdgeInsets.zero, + backgroundColor: Colors.transparent, + eyeStyle: const QrEyeStyle( + eyeShape: QrEyeShape.square, + color: Colors.white, ), - ), - ), - SizedBox(height: 40), - // Footer branding - Text( - 'HiVPN', - style: TextStyle( - color: Colors.white.withOpacity(0.5), - fontSize: 12, - letterSpacing: 2, - ), - ), - SizedBox(height: 20), + dataModuleStyle: const QrDataModuleStyle( + dataModuleShape: QrDataModuleShape.square, + color: Colors.white, + ), + embeddedImage: const AssetImage( + 'assets/images/lost-poster-logo-white.png'), + embeddedImageStyle: const QrEmbeddedImageStyle( + size: Size(42, 42), + ), + ), + ), + ), ], ), ); diff --git a/lib/app/modules/kr_invite/views/kr_invite_view.dart b/lib/app/modules/kr_invite/views/kr_invite_view.dart index 3b604b6..5fec251 100755 --- a/lib/app/modules/kr_invite/views/kr_invite_view.dart +++ b/lib/app/modules/kr_invite/views/kr_invite_view.dart @@ -43,7 +43,7 @@ class KRInviteView extends GetView { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - SizedBox(height: 20.w), + // SizedBox(height: 20.w), // 🟢 第一行:奖励说明 Container( width: double.infinity, diff --git a/lib/app/widgets/dialogs/hi_dialog.dart b/lib/app/widgets/dialogs/hi_dialog.dart index 13025db..7d68cc8 100755 --- a/lib/app/widgets/dialogs/hi_dialog.dart +++ b/lib/app/widgets/dialogs/hi_dialog.dart @@ -113,7 +113,7 @@ class _HIDialogState extends State { shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(23.r), ), - minimumSize: Size(85.w, 40.w), + minimumSize: Size(85.w, 40), padding: EdgeInsets.zero, tapTargetSize: MaterialTapTargetSize.shrinkWrap, ), diff --git a/lib/app/widgets/kr_local_image.dart b/lib/app/widgets/kr_local_image.dart index 6d3b9cb..645da25 100755 --- a/lib/app/widgets/kr_local_image.dart +++ b/lib/app/widgets/kr_local_image.dart @@ -34,6 +34,9 @@ class KrLocalImage extends StatelessWidget { colorFilter: color != null ? ColorFilter.mode(color!, BlendMode.srcIn) : null, + // theme: SvgTheme( + // currentColor: color ?? Colors.transparent, + // ), ); case ImageType.png: case ImageType.jpg: