/* * This file is part of Stack Wallet. * * Copyright (c) 2023 Cypher Stack * All Rights Reserved. * The code is distributed under GPLv3 license, see LICENSE file for details. * Generated by Cypher Stack on 2023-05-26 * */ import 'dart:async'; import 'dart:io'; import 'dart:ui' as ui; import 'package:file_picker/file_picker.dart'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter/services.dart'; import 'package:flutter_svg/svg.dart'; import 'package:path_provider/path_provider.dart'; import 'package:share_plus/share_plus.dart'; import '../../../notifications/show_flush_bar.dart'; import '../../../themes/stack_colors.dart'; import '../../../utilities/address_utils.dart'; import '../../../utilities/assets.dart'; import '../../../utilities/clipboard_interface.dart'; import '../../../utilities/text_styles.dart'; import '../../../utilities/util.dart'; import '../../../wallets/crypto_currency/crypto_currency.dart'; import '../../../widgets/desktop/primary_button.dart'; import '../../../widgets/desktop/secondary_button.dart'; import '../../../widgets/qr.dart'; import '../../../widgets/stack_dialog.dart'; class AddressQrPopup extends StatefulWidget { const AddressQrPopup({ super.key, required this.addressString, required this.coin, this.clipboard = const ClipboardWrapper(), }); final String addressString; final CryptoCurrency coin; final ClipboardInterface clipboard; @override State createState() => _AddressQrPopupState(); } class _AddressQrPopupState extends State { final _qrKey = GlobalKey(); final isDesktop = Util.isDesktop; Future _capturePng(bool shouldSaveInsteadOfShare) async { try { final RenderRepaintBoundary boundary = _qrKey.currentContext?.findRenderObject() as RenderRepaintBoundary; final ui.Image image = await boundary.toImage(); final ByteData? byteData = await image.toByteData(format: ui.ImageByteFormat.png); final Uint8List pngBytes = byteData!.buffer.asUint8List(); if (shouldSaveInsteadOfShare) { if (isDesktop) { final dir = Directory("${Platform.environment['HOME']}"); if (!dir.existsSync()) { throw Exception( "Home dir not found while trying to open filepicker on QR image save", ); } final path = await FilePicker.platform.saveFile( fileName: "qrcode.png", initialDirectory: dir.path, ); if (path != null) { final file = File(path); if (file.existsSync()) { unawaited( showFloatingFlushBar( type: FlushBarType.warning, message: "$path already exists!", context: context, ), ); } else { await file.writeAsBytes(pngBytes); unawaited( showFloatingFlushBar( type: FlushBarType.success, message: "$path saved!", context: context, ), ); } } } else { // await DocumentFileSavePlus.saveFile( // pngBytes, // "receive_qr_code_${DateTime.now().toLocal().toIso8601String()}.png", // "image/png"); } } else { final tempDir = await getTemporaryDirectory(); final file = await File("${tempDir.path}/qrcode.png").create(); await file.writeAsBytes(pngBytes); await Share.shareFiles( ["${tempDir.path}/qrcode.png"], text: "Receive URI QR Code", ); } } catch (e) { //todo: comeback to this debugPrint(e.toString()); } } @override Widget build(BuildContext context) { return StackDialogBase( child: Column( children: [ Text( "todo: custom label", style: STextStyles.pageTitleH2(context), ), const SizedBox( height: 8, ), Text( widget.addressString, style: STextStyles.itemSubtitle(context), ), const SizedBox( height: 16, ), Center( child: RepaintBoundary( key: _qrKey, child: QR( data: AddressUtils.buildUriString( widget.coin, widget.addressString, {}, ), size: 220, ), ), ), const SizedBox( height: 16, ), Row( children: [ Expanded( child: SecondaryButton( width: 170, buttonHeight: isDesktop ? ButtonHeight.l : null, onPressed: () async { await _capturePng(false); }, label: "Share", icon: SvgPicture.asset( Assets.svg.share, width: 20, height: 20, color: Theme.of(context) .extension()! .buttonTextSecondary, ), ), ), const SizedBox( width: 16, ), Expanded( child: PrimaryButton( width: 170, onPressed: () async { await _capturePng(true); }, label: "Save", icon: SvgPicture.asset( Assets.svg.arrowDown, width: 20, height: 20, color: Theme.of(context) .extension()! .buttonTextPrimary, ), ), ), ], ), ], ), ); } }