import 'package:cake_wallet/utils/device_info.dart'; import 'package:cake_wallet/themes/extensions/cake_text_theme.dart'; import 'package:cake_wallet/utils/responsive_layout_util.dart'; import 'package:cw_core/currency.dart'; import 'package:flutter/services.dart'; import 'package:flutter/material.dart'; import 'package:cake_wallet/routes.dart'; import 'package:cake_wallet/generated/i18n.dart'; import 'package:cake_wallet/entities/qr_scanner.dart'; import 'package:cake_wallet/entities/contact_base.dart'; import 'package:cake_wallet/themes/extensions/send_page_theme.dart'; import 'package:cake_wallet/utils/permission_handler.dart'; import 'package:permission_handler/permission_handler.dart'; enum AddressTextFieldOption { paste, qrCode, addressBook, walletAddresses } class AddressTextField extends StatelessWidget{ AddressTextField({ required this.controller, this.isActive = true, this.placeholder, this.options = const [AddressTextFieldOption.qrCode, AddressTextFieldOption.addressBook], this.onURIScanned, this.focusNode, this.isBorderExist = true, this.buttonColor, this.borderColor, this.iconColor, this.textStyle, this.hintStyle, this.validator, this.onPushPasteButton, this.onPushAddressBookButton, this.onPushAddressPickerButton, this.onSelectedContact, this.selectedCurrency, this.addressKey, }); static const prefixIconWidth = 34.0; static const prefixIconHeight = 34.0; static const spaceBetweenPrefixIcons = 10.0; final TextEditingController? controller; final bool isActive; final String? placeholder; final Function(Uri)? onURIScanned; final List options; final FormFieldValidator? validator; final bool isBorderExist; final Color? buttonColor; final Color? borderColor; final Color? iconColor; final TextStyle? textStyle; final TextStyle? hintStyle; final FocusNode? focusNode; final Function(BuildContext context)? onPushPasteButton; final Function(BuildContext context)? onPushAddressBookButton; final Function(BuildContext context)? onPushAddressPickerButton; final Function(ContactBase contact)? onSelectedContact; final T? selectedCurrency; final Key? addressKey; @override Widget build(BuildContext context) { return Stack( children: [ TextFormField( key: addressKey, enableIMEPersonalizedLearning: false, keyboardType: TextInputType.visiblePassword, onFieldSubmitted: (_) => FocusScope.of(context).unfocus(), enabled: isActive, controller: controller, focusNode: focusNode, style: textStyle ?? TextStyle( fontSize: 16, color: Theme.of(context).extension()!.titleColor), decoration: InputDecoration( suffixIcon: SizedBox( width: prefixIconWidth * options.length + (spaceBetweenPrefixIcons * options.length), ), hintStyle: hintStyle ?? TextStyle(fontSize: 16, color: Theme.of(context).hintColor), hintText: placeholder ?? S.current.widgets_address, focusedBorder: isBorderExist ? UnderlineInputBorder( borderSide: BorderSide( color: borderColor ?? Theme.of(context).dividerColor, width: 1.0)) : InputBorder.none, disabledBorder: isBorderExist ? UnderlineInputBorder( borderSide: BorderSide( color: borderColor ?? Theme.of(context).dividerColor, width: 1.0)) : InputBorder.none, enabledBorder: isBorderExist ? UnderlineInputBorder( borderSide: BorderSide( color: borderColor ?? Theme.of(context).dividerColor, width: 1.0)) : InputBorder.none, ), validator: validator, ), Positioned( top: 2, right: 0, child: SizedBox( width: (prefixIconWidth * options.length) + (spaceBetweenPrefixIcons * options.length), child: Row( mainAxisAlignment: responsiveLayoutUtil.shouldRenderMobileUI ? MainAxisAlignment.spaceBetween : MainAxisAlignment.end, children: [ if (this.options.contains(AddressTextFieldOption.paste)) ...[ SizedBox(width: 5), Container( width: prefixIconWidth, height: prefixIconHeight, padding: EdgeInsets.only(top: 0), child: Semantics( label: S.of(context).paste, child: InkWell( onTap: () async => _pasteAddress(context), child: Container( padding: EdgeInsets.all(8), decoration: BoxDecoration( color: buttonColor ?? Theme.of(context).dialogTheme.backgroundColor, borderRadius: BorderRadius.all(Radius.circular(6))), child: Image.asset( 'assets/images/paste_ios.png', color: iconColor ?? Theme.of(context) .extension()! .textFieldButtonIconColor, )), ), ), ), ], if (this.options.contains(AddressTextFieldOption.qrCode) && DeviceInfo.instance.isMobile) ...[ SizedBox(width: 5), Container( width: prefixIconWidth, height: prefixIconHeight, padding: EdgeInsets.only(top: 0), child: Semantics( label: S.of(context).scan_qr_code, child: InkWell( onTap: () async => _presentQRScanner(context), child: Container( padding: EdgeInsets.all(8), decoration: BoxDecoration( color: buttonColor ?? Theme.of(context).dialogTheme.backgroundColor, borderRadius: BorderRadius.all(Radius.circular(6))), child: Image.asset( 'assets/images/qr_code_icon.png', color: iconColor ?? Theme.of(context) .extension()! .textFieldButtonIconColor, )), ), ), ), ], if (this.options.contains(AddressTextFieldOption.addressBook)) ...[ SizedBox(width: 5), Container( width: prefixIconWidth, height: prefixIconHeight, padding: EdgeInsets.only(top: 0), child: Semantics( label: S.of(context).address_book, child: InkWell( onTap: () async => _presetAddressBookPicker(context), child: Container( padding: EdgeInsets.all(8), decoration: BoxDecoration( color: buttonColor ?? Theme.of(context).dialogTheme.backgroundColor, borderRadius: BorderRadius.all(Radius.circular(6))), child: Image.asset( 'assets/images/open_book.png', color: iconColor ?? Theme.of(context) .extension()! .textFieldButtonIconColor, )), ), ), ), ], if (this.options.contains(AddressTextFieldOption.walletAddresses)) ...[ SizedBox(width: 5), Container( width: prefixIconWidth, height: prefixIconHeight, padding: EdgeInsets.only(top: 0), child: Semantics( label: S.of(context).address_book, child: InkWell( onTap: () async => _presetWalletAddressPicker(context), child: Container( padding: EdgeInsets.all(8), decoration: BoxDecoration( color: buttonColor ?? Theme.of(context).dialogTheme.backgroundColor, borderRadius: BorderRadius.all(Radius.circular(6))), child: Image.asset( 'assets/images/open_book.png', color: iconColor ?? Theme.of(context) .extension()! .textFieldButtonIconColor, )), ), ), ) ], ], ), )) ], ); } Future _presentQRScanner(BuildContext context) async { bool isCameraPermissionGranted = await PermissionHandler.checkPermission(Permission.camera, context); if (!isCameraPermissionGranted) return; final code = await presentQRScanner(context); if (code == null) return; if (code.isEmpty) { return; } try { final uri = Uri.parse(code); controller?.text = uri.path; onURIScanned?.call(uri); } catch (_) { controller?.text = code; } } Future _presetAddressBookPicker(BuildContext context) async { final contact = await Navigator.of(context) .pushNamed(Routes.pickerAddressBook, arguments: selectedCurrency); if (contact is ContactBase) { controller?.text = contact.address; onPushAddressBookButton?.call(context); onSelectedContact?.call(contact); } } Future _presetWalletAddressPicker(BuildContext context) async { final address = await Navigator.of(context).pushNamed(Routes.pickerWalletAddress); if (address is String) { controller?.text = address; onPushAddressPickerButton?.call(context); } } Future _pasteAddress(BuildContext context) async { final clipboard = await Clipboard.getData('text/plain'); final address = clipboard?.text ?? ''; if (address.isNotEmpty) { controller?.text = address; } onPushPasteButton?.call(context); } }