CAKE-192 | implemented unstoppable domain address to the app

OleksandrSobol committed Apr 20, 2021 at 20:49 UTC ae9efb0ae8ae35e0c33bcfe7ba3473ddc9b4d0ae
29 files changed +327 -46
android/app/build.gradle
+3 -2
@@ -81,6 +81,7 @@ flutter {
81
82 dependencies {
83 testImplementation 'junit:junit:4.12'
84 - androidTestImplementation 'androidx.test:runner:1.1.1'
85 - androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1'
84 + androidTestImplementation 'androidx.test:runner:1.3.0'
85 + androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
86 + implementation 'com.unstoppabledomains:resolution:1.13.0'
87 }
android/app/src/main/java/com/cakewallet/cake_wallet/MainActivity.java
+45 -1
@@ -5,11 +5,55 @@ import io.flutter.embedding.android.FlutterFragmentActivity;
5 import io.flutter.embedding.engine.FlutterEngine;
6 import io.flutter.plugins.GeneratedPluginRegistrant;
7
8 +import com.unstoppabledomains.resolution.DomainResolution;
9 +import com.unstoppabledomains.resolution.Resolution;
10 +
11 +import android.os.AsyncTask;
12 +import android.os.Handler;
13 +import android.os.Looper;
14 +
15 +import io.flutter.plugin.common.MethodCall;
16 +import io.flutter.plugin.common.MethodChannel;
17
18 public class MainActivity extends FlutterFragmentActivity {
10 -
19 + final String UNSTOPPABLE_DOMAIN_CHANNEL = "com.cakewallet.cake_wallet/unstoppable-domain";
20 +
21 @Override
22 public void configureFlutterEngine(@NonNull FlutterEngine flutterEngine) {
23 GeneratedPluginRegistrant.registerWith(flutterEngine);
24 +
25 + MethodChannel unstoppableDomainChannel =
26 + new MethodChannel(flutterEngine.getDartExecutor().getBinaryMessenger(),
27 + UNSTOPPABLE_DOMAIN_CHANNEL);
28 +
29 + unstoppableDomainChannel.setMethodCallHandler(this::handle);
30 + }
31 +
32 + private void handle(@NonNull MethodCall call, @NonNull MethodChannel.Result result) {
33 + try {
34 + if (call.method.equals("getUnstoppableDomainAddress")) {
35 + getUnstoppableDomainAddress(call, result);
36 + } else {
37 + result.notImplemented();
38 + }
39 + } catch (Exception e) {
40 + result.error("UNCAUGHT_ERROR", e.getMessage(), null);
41 + }
42 + }
43 +
44 + private void getUnstoppableDomainAddress(@NonNull MethodCall call, @NonNull MethodChannel.Result result) {
45 + DomainResolution resolution = new Resolution();
46 + Handler handler = new Handler(Looper.getMainLooper());
47 + String domain = call.argument("domain");
48 + String ticker = call.argument("ticker");
49 +
50 + AsyncTask.execute(() -> {
51 + try {
52 + String address = resolution.getAddress(domain, ticker);
53 + handler.post(() -> result.success(address));
54 + } catch (Exception e) {
55 + handler.post(() -> result.error("INVALID DOMAIN", e.getMessage(), null));
56 + }
57 + });
58 }
59 }
android/build.gradle
+1 -1
@@ -5,7 +5,7 @@ buildscript {
5 }
6
7 dependencies {
8 - classpath 'com.android.tools.build:gradle:3.5.4'
8 + classpath 'com.android.tools.build:gradle:4.1.3'
9 }
10 }
11
android/gradle/wrapper/gradle-wrapper.properties
+2 -2
@@ -1,6 +1,6 @@
1 -#Fri Jun 23 08:50:38 CEST 2017
1 +#Mon Apr 19 18:19:26 EEST 2021
2 distributionBase=GRADLE_USER_HOME
3 distributionPath=wrapper/dists
4 zipStoreBase=GRADLE_USER_HOME
5 zipStorePath=wrapper/dists
6 -distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip
6 +distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-bin.zip
ios/Podfile
+2 -1
@@ -1,5 +1,5 @@
1 # Uncomment this line to define a global platform for your project
2 -platform :ios, '9.0'
2 +platform :ios, '11.0'
3 source 'https://github.com/CocoaPods/Specs.git'
4
5 # CocoaPods analytics sends network stats synchronously affecting flutter build latency.
@@ -36,6 +36,7 @@ target 'Runner' do
36
37 # Cake Wallet (Legacy)
38 pod 'CryptoSwift'
39 + pod 'UnstoppableDomainsResolution', '~> 0.3.6'
40 end
41
42 post_install do |installer|
ios/Podfile.lock
+16 -2
@@ -3,6 +3,7 @@ PODS:
3 - Flutter
4 - MTBBarcodeScanner
5 - SwiftProtobuf
6 + - BigInt (5.2.0)
7 - connectivity (0.0.1):
8 - Flutter
9 - Reachability
@@ -59,6 +60,8 @@ PODS:
60 - SwiftyGif
61 - esys_flutter_share (0.0.1):
62 - Flutter
63 + - EthereumAddress (1.3.0):
64 + - CryptoSwift (~> 1.0)
65 - file_picker (0.0.1):
66 - DKImagePickerController/PhotoGallery
67 - Flutter
@@ -84,6 +87,10 @@ PODS:
87 - Flutter
88 - SwiftProtobuf (1.12.0)
89 - SwiftyGif (5.3.0)
90 + - UnstoppableDomainsResolution (0.3.6):
91 + - BigInt
92 + - CryptoSwift (~> 1.0)
93 + - EthereumAddress (~> 1.3)
94 - url_launcher (0.0.1):
95 - Flutter
96 - webview_flutter (0.0.1):
@@ -105,19 +112,23 @@ DEPENDENCIES:
112 - permission_handler (from `.symlinks/plugins/permission_handler/ios`)
113 - share (from `.symlinks/plugins/share/ios`)
114 - shared_preferences (from `.symlinks/plugins/shared_preferences/ios`)
115 + - UnstoppableDomainsResolution (~> 0.3.6)
116 - url_launcher (from `.symlinks/plugins/url_launcher/ios`)
117 - webview_flutter (from `.symlinks/plugins/webview_flutter/ios`)
118
119 SPEC REPOS:
120 https://github.com/CocoaPods/Specs.git:
121 + - BigInt
122 - CryptoSwift
123 - DKImagePickerController
124 - DKPhotoGallery
125 + - EthereumAddress
126 - MTBBarcodeScanner
127 - Reachability
128 - SDWebImage
129 - SwiftProtobuf
130 - SwiftyGif
131 + - UnstoppableDomainsResolution
132
133 EXTERNAL SOURCES:
134 barcode_scan:
@@ -155,6 +166,7 @@ EXTERNAL SOURCES:
166
167 SPEC CHECKSUMS:
168 barcode_scan: a5c27959edfafaa0c771905bad0b29d6d39e4479
169 + BigInt: f668a80089607f521586bbe29513d708491ef2f7
170 connectivity: c4130b2985d4ef6fd26f9702e886bd5260681467
171 CryptoSwift: 093499be1a94b0cae36e6c26b70870668cb56060
172 cw_monero: 2e1f79929880cc2293b5bc1b25e28152e4d84649
@@ -162,6 +174,7 @@ SPEC CHECKSUMS:
174 DKImagePickerController: b5eb7f7a388e4643264105d648d01f727110fc3d
175 DKPhotoGallery: fdfad5125a9fdda9cc57df834d49df790dbb4179
176 esys_flutter_share: 403498dab005b36ce1f8d7aff377e81f0621b0b4
177 + EthereumAddress: 39fe8e11cf04e4e9902b55ae653dbc4e0aee5f30
178 file_picker: 3e6c3790de664ccf9b882732d9db5eaf6b8d4eb1
179 Flutter: 434fef37c0980e73bb6479ef766c45957d4b510c
180 flutter_secure_storage: 7953c38a04c3fdbb00571bcd87d8e3b5ceb9daec
@@ -176,9 +189,10 @@ SPEC CHECKSUMS:
189 shared_preferences: af6bfa751691cdc24be3045c43ec037377ada40d
190 SwiftProtobuf: 4ef85479c18ca85b5482b343df9c319c62bda699
191 SwiftyGif: e466e86c660d343357ab944a819a101c4127cb40
192 + UnstoppableDomainsResolution: 63abb84858d3e91eb838a5bfa6f7e3c0e0593f24
193 url_launcher: 6fef411d543ceb26efce54b05a0a40bfd74cbbef
194 webview_flutter: 9f491a9b5a66f2573946a389b2677987b0ff8c0b
195
182 -PODFILE CHECKSUM: 5b5f101b119a1b6eb857c967d462832a9062dec4
196 +PODFILE CHECKSUM: 2172f10eb8ff8378f8d6e3e2c1366a0e6cdea018
197
184 -COCOAPODS: 1.9.3
198 +COCOAPODS: 1.10.1
ios/Runner/AppDelegate.swift
+40
@@ -1,8 +1,13 @@
1 import UIKit
2 import Flutter
3 +import UnstoppableDomainsResolution
4
5 @UIApplicationMain
6 @objc class AppDelegate: FlutterAppDelegate {
7 + lazy var resolution : Resolution? = {
8 + return try? Resolution()
9 + }()
10 +
11 override func application(
12 _ application: UIApplication,
13 didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
@@ -10,6 +15,8 @@ import Flutter
15 let controller : FlutterViewController = window?.rootViewController as! FlutterViewController
16 let batteryChannel = FlutterMethodChannel(name: "com.cakewallet.cakewallet/legacy_wallet_migration",
17 binaryMessenger: controller.binaryMessenger)
18 + let unstoppableDomainChannel = FlutterMethodChannel(name: "com.cakewallet.cake_wallet/unstoppable-domain", binaryMessenger: controller.binaryMessenger)
19 +
20 batteryChannel.setMethodCallHandler({
21 (call: FlutterMethodCall, result: @escaping FlutterResult) -> Void in
22
@@ -52,6 +59,39 @@ import Flutter
59 }
60 })
61
62 + unstoppableDomainChannel.setMethodCallHandler({ [weak self]
63 + (call: FlutterMethodCall, result: @escaping FlutterResult) -> Void in
64 + switch call.method {
65 + case "getUnstoppableDomainAddress":
66 + guard let args = call.arguments as? Dictionary<String, String>,
67 + let domain = args["domain"],
68 + let ticker = args["ticker"] else {
69 + result(nil)
70 + return
71 + }
72 +
73 + guard let resolution = self?.resolution else {
74 + result(nil)
75 + return
76 + }
77 +
78 + resolution.addr(domain: domain, ticker: ticker) { addrResult in
79 + var address : String = ""
80 +
81 + switch addrResult {
82 + case .success(let returnValue):
83 + address = returnValue
84 + case .failure(let error):
85 + print("Expected Address, but got \(error)")
86 + }
87 +
88 + result(address)
89 + }
90 + default:
91 + result(FlutterMethodNotImplemented)
92 + }
93 + })
94 +
95 GeneratedPluginRegistrant.register(with: self)
96 return super.application(application, didFinishLaunchingWithOptions: launchOptions)
97 }
lib/entities/unstoppable_domain_address.dart new
+22
@@ -0,0 +1,22 @@
1 +import 'package:flutter/services.dart';
2 +
3 +const channel = MethodChannel('com.cakewallet.cake_wallet/unstoppable-domain');
4 +
5 +Future<String> fetchUnstoppableDomainAddress(String domain, String ticker) async {
6 + String address;
7 +
8 + try {
9 + address = await channel.invokeMethod(
10 + 'getUnstoppableDomainAddress',
11 + <String, String> {
12 + 'domain' : domain,
13 + 'ticker' : ticker
14 + }
15 + );
16 + } catch (e) {
17 + print('Unstoppable domain error: ${e.toString()}');
18 + address = '';
19 + }
20 +
21 + return address;
22 +}
\ No newline at end of file
lib/src/screens/exchange/exchange_page.dart
+73 -8
@@ -1,7 +1,7 @@
1 import 'dart:ui';
2 import 'package:cake_wallet/entities/sync_status.dart';
3 import 'package:cake_wallet/entities/wallet_type.dart';
4 -import 'package:cake_wallet/exchange/changenow/changenow_exchange_provider.dart';
4 +import 'package:cake_wallet/src/screens/send/widgets/unstoppable_domain_address_alert.dart';
5 import 'package:cake_wallet/src/widgets/standard_checkbox.dart';
6 import 'package:dotted_border/dotted_border.dart';
7 import 'package:flutter/cupertino.dart';
@@ -9,8 +9,6 @@ import 'package:flutter/material.dart';
9 import 'package:flutter_mobx/flutter_mobx.dart';
10 import 'package:keyboard_actions/keyboard_actions.dart';
11 import 'package:mobx/mobx.dart';
12 -import 'package:cake_wallet/exchange/exchange_provider.dart';
13 -import 'package:cake_wallet/core/execution_state.dart';
12 import 'package:cake_wallet/exchange/exchange_template.dart';
13 import 'package:cake_wallet/exchange/exchange_trade_state.dart';
14 import 'package:cake_wallet/exchange/limits_state.dart';
@@ -23,7 +21,6 @@ import 'package:cake_wallet/utils/show_pop_up.dart';
21 import 'package:cake_wallet/routes.dart';
22 import 'package:cake_wallet/generated/i18n.dart';
23 import 'package:cake_wallet/entities/crypto_currency.dart';
26 -import 'package:cake_wallet/exchange/xmrto/xmrto_exchange_provider.dart';
24 import 'package:cake_wallet/src/screens/exchange/widgets/exchange_card.dart';
25 import 'package:cake_wallet/src/widgets/primary_button.dart';
26 import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart';
@@ -42,7 +39,9 @@ class ExchangePage extends BasePage {
39 final checkBoxKey = GlobalKey<StandardCheckboxState>();
40 final _formKey = GlobalKey<FormState>();
41 final _depositAmountFocus = FocusNode();
42 + final _depositAddressFocus = FocusNode();
43 final _receiveAmountFocus = FocusNode();
44 + final _receiveAddressFocus = FocusNode();
45 var _isReactionsSet = false;
46
47 @override
@@ -52,7 +51,7 @@ class ExchangePage extends BasePage {
51 Color get titleColor => Colors.white;
52
53 @override
55 - bool get resizeToAvoidBottomPadding => false;
54 + bool get resizeToAvoidBottomInset => false;
55
56 @override
57 bool get extendBodyBehindAppBar => true;
@@ -171,6 +170,7 @@ class ExchangePage extends BasePage {
170 .calculateDepositAllAmount()
171 : null,
172 amountFocusNode: _depositAmountFocus,
173 + addressFocusNode: _depositAddressFocus,
174 key: depositKey,
175 title: S.of(context).you_will_send,
176 initialCurrency:
@@ -223,6 +223,15 @@ class ExchangePage extends BasePage {
223 type: exchangeViewModel.wallet.type),
224 addressTextFieldValidator: AddressValidator(
225 type: exchangeViewModel.depositCurrency),
226 + onPushPasteButton: (context) async {
227 + final domain =
228 + exchangeViewModel.depositAddress;
229 + final ticker =
230 + exchangeViewModel.depositCurrency.title;
231 + exchangeViewModel.depositAddress =
232 + await applyUnstoppableDomainAddress(
233 + context, domain, ticker);
234 + },
235 ),
236 ),
237 ),
@@ -232,6 +241,7 @@ class ExchangePage extends BasePage {
241 child: Observer(
242 builder: (_) => ExchangeCard(
243 amountFocusNode: _receiveAmountFocus,
244 + addressFocusNode: _receiveAddressFocus,
245 key: receiveKey,
246 title: S.of(context).you_will_get,
247 initialCurrency:
@@ -268,6 +278,15 @@ class ExchangePage extends BasePage {
278 AddressValidator(
279 type: exchangeViewModel
280 .receiveCurrency),
281 + onPushPasteButton: (context) async {
282 + final domain =
283 + exchangeViewModel.receiveAddress;
284 + final ticker =
285 + exchangeViewModel.receiveCurrency.title;
286 + exchangeViewModel.receiveAddress =
287 + await applyUnstoppableDomainAddress(
288 + context, domain, ticker);
289 + },
290 )),
291 )
292 ],
@@ -371,7 +390,7 @@ class ExchangePage extends BasePage {
390 from: template.depositCurrency,
391 to: template.receiveCurrency,
392 onTap: () {
374 - applyTemplate(
393 + applyTemplate(context,
394 exchangeViewModel, template);
395 },
396 onRemove: () {
@@ -472,8 +491,8 @@ class ExchangePage extends BasePage {
491 ));
492 }
493
475 - void applyTemplate(
476 - ExchangeViewModel exchangeViewModel, ExchangeTemplate template) {
494 + void applyTemplate(BuildContext context,
495 + ExchangeViewModel exchangeViewModel, ExchangeTemplate template) async {
496 exchangeViewModel.changeDepositCurrency(
497 currency: CryptoCurrency.fromString(template.depositCurrency));
498 exchangeViewModel.changeReceiveCurrency(
@@ -491,6 +510,16 @@ class ExchangePage extends BasePage {
510 exchangeViewModel.receiveAddress = template.receiveAddress;
511 exchangeViewModel.isReceiveAmountEntered = false;
512 exchangeViewModel.isFixedRateMode = false;
513 +
514 + var domain = template.depositAddress;
515 + var ticker = template.depositCurrency;
516 + exchangeViewModel.depositAddress =
517 + await applyUnstoppableDomainAddress(context, domain, ticker);
518 +
519 + domain = template.receiveAddress;
520 + ticker = template.receiveCurrency;
521 + exchangeViewModel.receiveAddress =
522 + await applyUnstoppableDomainAddress(context, domain, ticker);
523 }
524
525 void _setReactions(
@@ -656,6 +685,26 @@ class ExchangePage extends BasePage {
685 }
686 });
687
688 + _depositAddressFocus.addListener(() async {
689 + if (!_depositAddressFocus.hasFocus &&
690 + depositAddressController.text.isNotEmpty) {
691 + final domain = depositAddressController.text;
692 + final ticker = exchangeViewModel.depositCurrency.title;
693 + exchangeViewModel.depositAddress =
694 + await applyUnstoppableDomainAddress(context, domain, ticker);
695 + }
696 + });
697 +
698 + _receiveAddressFocus.addListener(() async {
699 + if (!_receiveAddressFocus.hasFocus &&
700 + receiveAddressController.text.isNotEmpty) {
701 + final domain = receiveAddressController.text;
702 + final ticker = exchangeViewModel.receiveCurrency.title;
703 + exchangeViewModel.receiveAddress =
704 + await applyUnstoppableDomainAddress(context, domain, ticker);
705 + }
706 + });
707 +
708 _receiveAmountFocus.addListener(() {
709 if (_receiveAmountFocus.hasFocus && !exchangeViewModel.isFixedRateMode) {
710 showPopUp<void>(
@@ -726,4 +775,20 @@ class ExchangePage extends BasePage {
775 key.currentState.addressController.text = null;
776 }
777 }
778 +
779 + Future<String> applyUnstoppableDomainAddress(BuildContext context,
780 + String domain, String ticker) async {
781 + try {
782 + final address =
783 + await exchangeViewModel.getUnstoppableDomainAddress(domain, ticker);
784 + if ((address != null)&&address.isNotEmpty) {
785 + unstoppableDomainAddressAlert(context, domain);
786 + return address;
787 + }
788 + } catch (e) {
789 + print(e.toString());
790 + }
791 +
792 + return domain;
793 + }
794 }
lib/src/screens/exchange/exchange_template_page.dart
+5 -6
@@ -37,7 +37,7 @@ class ExchangeTemplatePage extends BasePage {
37 Color get titleColor => Colors.white;
38
39 @override
40 - bool get resizeToAvoidBottomPadding => false;
40 + bool get resizeToAvoidBottomInset => false;
41
42 @override
43 bool get extendBodyBehindAppBar => true;
@@ -150,9 +150,8 @@ class ExchangeTemplatePage extends BasePage {
150 .color,
151 currencyValueValidator: AmountValidator(
152 type: exchangeViewModel.wallet.type),
153 - addressTextFieldValidator: AddressValidator(
154 - type:
155 - exchangeViewModel.depositCurrency),
153 + //addressTextFieldValidator: AddressValidator(
154 + // type: exchangeViewModel.depositCurrency),
155 ),
156 ),
157 ),
@@ -190,8 +189,8 @@ class ExchangeTemplatePage extends BasePage {
189 .decorationColor,
190 currencyValueValidator: AmountValidator(
191 type: exchangeViewModel.wallet.type),
193 - addressTextFieldValidator: AddressValidator(
194 - type: exchangeViewModel.receiveCurrency),
192 + //addressTextFieldValidator: AddressValidator(
193 + // type: exchangeViewModel.receiveCurrency),
194 )),
195 )
196 ],
lib/src/screens/exchange/widgets/exchange_card.dart
+8 -2
@@ -28,8 +28,10 @@ class ExchangeCard extends StatefulWidget {
28 this.currencyValueValidator,
29 this.addressTextFieldValidator,
30 this.amountFocusNode,
31 + this.addressFocusNode,
32 this.hasAllAmount = false,
32 - this.allAmount})
33 + this.allAmount,
34 + this.onPushPasteButton})
35 : super(key: key);
36
37 final List<CryptoCurrency> currencies;
@@ -49,8 +51,10 @@ class ExchangeCard extends StatefulWidget {
51 final FormFieldValidator<String> currencyValueValidator;
52 final FormFieldValidator<String> addressTextFieldValidator;
53 final FocusNode amountFocusNode;
54 + final FocusNode addressFocusNode;
55 final bool hasAllAmount;
53 - Function allAmount;
56 + final Function allAmount;
57 + final Function(BuildContext context) onPushPasteButton;
58
59 @override
60 ExchangeCardState createState() => ExchangeCardState();
@@ -288,6 +292,7 @@ class ExchangeCardState extends State<ExchangeCard> {
292 ? Padding(
293 padding: EdgeInsets.only(top: 20),
294 child: AddressTextField(
295 + focusNode: widget.addressFocusNode,
296 controller: addressController,
297 placeholder: widget.hasRefundAddress
298 ? S.of(context).refund_address
@@ -311,6 +316,7 @@ class ExchangeCardState extends State<ExchangeCard> {
316 .decorationColor),
317 buttonColor: widget.addressButtonsColor,
318 validator: widget.addressTextFieldValidator,
319 + onPushPasteButton: widget.onPushPasteButton,
320 ),
321 )
322 : Padding(
lib/src/screens/send/send_page.dart
+28 -6
@@ -1,6 +1,6 @@
1 import 'dart:ui';
2 -import 'package:cake_wallet/entities/monero_transaction_priority.dart';
2 import 'package:cake_wallet/entities/transaction_priority.dart';
3 +import 'package:cake_wallet/src/screens/send/widgets/unstoppable_domain_address_alert.dart';
4 import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart';
5 import 'package:cake_wallet/src/widgets/keyboard_done_button.dart';
6 import 'package:cake_wallet/src/widgets/picker.dart';
@@ -38,9 +38,10 @@ class SendPage extends BasePage {
38 _cryptoAmountFocus = FocusNode(),
39 _fiatAmountFocus = FocusNode(),
40 _addressFocusNode = FocusNode() {
41 - _addressFocusNode.addListener(() {
41 + _addressFocusNode.addListener(() async {
42 if (!_addressFocusNode.hasFocus && _addressController.text.isNotEmpty) {
43 - getOpenaliasRecord(_addressFocusNode.context);
43 + await getOpenaliasRecord(_addressFocusNode.context);
44 + await applyUnstoppableDomainAddress(_addressFocusNode.context);
45 }
46 });
47 }
@@ -67,7 +68,7 @@ class SendPage extends BasePage {
68 Color get titleColor => Colors.white;
69
70 @override
70 - bool get resizeToAvoidBottomPadding => false;
71 + bool get resizeToAvoidBottomInset => false;
72
73 @override
74 bool get extendBodyBehindAppBar => true;
@@ -173,6 +174,10 @@ class SendPage extends BasePage {
174 .headline
175 .decorationColor),
176 validator: sendViewModel.addressValidator,
177 + onPushPasteButton: (context) async {
178 + await getOpenaliasRecord(context);
179 + await applyUnstoppableDomainAddress(context);
180 + },
181 ),
182 Observer(
183 builder: (_) => Padding(
@@ -513,12 +518,13 @@ class SendPage extends BasePage {
518 to: template.name,
519 amount: template.amount,
520 from: template.cryptoCurrency,
516 - onTap: () {
521 + onTap: () async {
522 _addressController.text =
523 template.address;
524 _cryptoAmountController.text =
525 template.amount;
521 - getOpenaliasRecord(context);
526 + await getOpenaliasRecord(context);
527 + await applyUnstoppableDomainAddress(context);
528 },
529 onRemove: () {
530 showPopUp<void>(
@@ -770,4 +776,20 @@ class SendPage extends BasePage {
776 ),
777 context: context);
778 }
779 +
780 + Future<void> applyUnstoppableDomainAddress(BuildContext context) async {
781 + try {
782 + final address = await sendViewModel
783 + .getUnstoppableDomainAddress(
784 + _addressController.text);
785 +
786 + if ((address != null)&&address.isNotEmpty) {
787 + unstoppableDomainAddressAlert(
788 + context, _addressController.text);
789 + _addressController.text = address;
790 + }
791 + } catch (e) {
792 + print(e.toString());
793 + }
794 + }
795 }
lib/src/screens/send/send_template_page.dart
+2 -2
@@ -34,7 +34,7 @@ class SendTemplatePage extends BasePage {
34 Color get titleColor => Colors.white;
35
36 @override
37 - bool get resizeToAvoidBottomPadding => false;
37 + bool get resizeToAvoidBottomInset => false;
38
39 @override
40 bool get extendBodyBehindAppBar => true;
@@ -145,7 +145,7 @@ class SendTemplatePage extends BasePage {
145 .primaryTextTheme
146 .headline
147 .decorationColor),
148 - validator: sendViewModel.addressValidator,
148 + //validator: sendViewModel.addressValidator,
149 ),
150 ),
151 Observer(builder: (_) {
lib/src/screens/send/widgets/unstoppable_domain_address_alert.dart new
+17
@@ -0,0 +1,17 @@
1 +import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
2 +import 'package:cake_wallet/utils/show_pop_up.dart';
3 +import 'package:flutter/material.dart';
4 +import 'package:cake_wallet/generated/i18n.dart';
5 +
6 +void unstoppableDomainAddressAlert(BuildContext context, String domain) async {
7 + await showPopUp<void>(
8 + context: context,
9 + builder: (BuildContext context) {
10 +
11 + return AlertWithOneAction(
12 + alertTitle: S.of(context).address_detected,
13 + alertContent: S.of(context).address_from_domain(domain),
14 + buttonText: S.of(context).ok,
15 + buttonAction: () => Navigator.of(context).pop());
16 + });
17 +}
\ No newline at end of file
lib/src/widgets/address_text_field.dart
+5 -1
@@ -24,7 +24,8 @@ class AddressTextField extends StatelessWidget {
24 this.iconColor,
25 this.textStyle,
26 this.hintStyle,
27 - this.validator});
27 + this.validator,
28 + this.onPushPasteButton});
29
30 static const prefixIconWidth = 34.0;
31 static const prefixIconHeight = 34.0;
@@ -43,6 +44,7 @@ class AddressTextField extends StatelessWidget {
44 final TextStyle textStyle;
45 final TextStyle hintStyle;
46 final FocusNode focusNode;
47 + final Function(BuildContext context) onPushPasteButton;
48
49 @override
50 Widget build(BuildContext context) {
@@ -225,5 +227,7 @@ class AddressTextField extends StatelessWidget {
227 if (address?.isNotEmpty ?? false) {
228 controller.text = address;
229 }
230 +
231 + onPushPasteButton?.call(context);
232 }
233 }
lib/view_model/exchange/exchange_view_model.dart
+5
@@ -4,6 +4,7 @@ import 'package:cake_wallet/bitcoin/bitcoin_wallet.dart';
4 import 'package:cake_wallet/core/wallet_base.dart';
5 import 'package:cake_wallet/entities/crypto_currency.dart';
6 import 'package:cake_wallet/entities/sync_status.dart';
7 +import 'package:cake_wallet/entities/unstoppable_domain_address.dart';
8 import 'package:cake_wallet/entities/wallet_type.dart';
9 import 'package:cake_wallet/exchange/exchange_provider.dart';
10 import 'package:cake_wallet/exchange/limits.dart';
@@ -417,4 +418,8 @@ abstract class ExchangeViewModelBase with Store {
418 }*/
419 isReceiveAmountEditable = false;
420 }
421 +
422 + Future<String> getUnstoppableDomainAddress(String domain, String ticker) async {
423 + return await fetchUnstoppableDomainAddress(domain, ticker.toLowerCase());
424 + }
425 }
lib/view_model/send/send_view_model.dart
+5
@@ -4,6 +4,7 @@ import 'package:cake_wallet/entities/balance_display_mode.dart';
4 import 'package:cake_wallet/entities/calculate_fiat_amount_raw.dart';
5 import 'package:cake_wallet/entities/transaction_description.dart';
6 import 'package:cake_wallet/entities/transaction_priority.dart';
7 +import 'package:cake_wallet/entities/unstoppable_domain_address.dart';
8 import 'package:cake_wallet/monero/monero_amount_format.dart';
9 import 'package:cake_wallet/view_model/settings/settings_view_model.dart';
10 import 'package:hive/hive.dart';
@@ -267,6 +268,10 @@ abstract class SendViewModelBase with Store {
268 return record.name != name ? record : null;
269 }
270
271 + Future<String> getUnstoppableDomainAddress(String domain) async {
272 + return await fetchUnstoppableDomainAddress(domain, currency.title.toLowerCase());
273 + }
274 +
275 @action
276 void _updateFiatAmount() {
277 try {
res/values/strings_de.arb
+4 -1
@@ -469,5 +469,8 @@
469 "unconfirmed" : "Unbestätigt",
470 "displayable" : "Anzeigebar",
471
472 - "submit_request" : "Einen Antrag stellen"
472 + "submit_request" : "Einen Antrag stellen",
473 +
474 + "address_detected" : "Adresse erkannt",
475 + "address_from_domain" : "Sie haben die Adresse von der unaufhaltsamen Domain ${domain} erhalten"
476 }
\ No newline at end of file
res/values/strings_en.arb
+4 -1
@@ -469,5 +469,8 @@
469 "unconfirmed" : "Unconfirmed",
470 "displayable" : "Displayable",
471
472 - "submit_request" : "submit a request"
472 + "submit_request" : "submit a request",
473 +
474 + "address_detected" : "Address detected",
475 + "address_from_domain" : "You got address from unstoppable domain ${domain}"
476 }
\ No newline at end of file
res/values/strings_es.arb
+4 -1
@@ -469,5 +469,8 @@
469 "unconfirmed" : "Inconfirmado",
470 "displayable" : "Visualizable",
471
472 - "submit_request" : "presentar una solicitud"
472 + "submit_request" : "presentar una solicitud",
473 +
474 + "address_detected" : "Dirección detectada",
475 + "address_from_domain" : "Tienes la dirección de unstoppable domain ${domain}"
476 }
\ No newline at end of file
res/values/strings_hi.arb
+4 -1
@@ -469,5 +469,8 @@
469 "unconfirmed" : "अपुष्ट",
470 "displayable" : "प्रदर्शन योग्य",
471
472 - "submit_request" : "एक अनुरोध सबमिट करें"
472 + "submit_request" : "एक अनुरोध सबमिट करें",
473 +
474 + "address_detected" : "पता लग गया",
475 + "address_from_domain" : "आपको अजेय डोमेन ${domain} से पता मिला है"
476 }
\ No newline at end of file
res/values/strings_ja.arb
+4 -1
@@ -469,5 +469,8 @@
469 "unconfirmed" : "未確認",
470 "displayable" : "表示可能",
471
472 - "submit_request" : "リクエストを送信する"
472 + "submit_request" : "リクエストを送信する",
473 +
474 + "address_detected" : "アドレスが検出されました",
475 + "address_from_domain" : "あなたはからアドレスを得ました unstoppable domain ${domain}"
476 }
\ No newline at end of file
res/values/strings_ko.arb
+4 -1
@@ -469,5 +469,8 @@
469 "unconfirmed" : "미확인",
470 "displayable" : "표시 가능",
471
472 - "submit_request" : "요청을 제출"
472 + "submit_request" : "요청을 제출",
473 +
474 + "address_detected" : "주소 감지",
475 + "address_from_domain" : "주소는 unstoppable domain ${domain}"
476 }
\ No newline at end of file
res/values/strings_nl.arb
+4 -1
@@ -469,5 +469,8 @@
469 "unconfirmed" : "Niet bevestigd",
470 "displayable" : "Weer te geven",
471
472 - "submit_request" : "een verzoek indienen"
472 + "submit_request" : "een verzoek indienen",
473 +
474 + "address_detected" : "Adres gedetecteerd",
475 + "address_from_domain" : "Je adres is van unstoppable domain ${domain}"
476 }
\ No newline at end of file
res/values/strings_pl.arb
+4 -1
@@ -469,5 +469,8 @@
469 "unconfirmed" : "Niepotwierdzony",
470 "displayable" : "Wyświetlane",
471
472 - "submit_request" : "złożyć wniosek"
472 + "submit_request" : "złożyć wniosek",
473 +
474 + "address_detected" : "Wykryto adres",
475 + "address_from_domain" : "Dostałeś adres od unstoppable domain ${domain}"
476 }
\ No newline at end of file
res/values/strings_pt.arb
+4 -1
@@ -469,5 +469,8 @@
469 "unconfirmed" : "Não confirmado",
470 "displayable" : "Exibível",
471
472 - "submit_request" : "enviar um pedido"
472 + "submit_request" : "enviar um pedido",
473 +
474 + "address_detected" : "Endereço detectado",
475 + "address_from_domain" : "Você obteve o endereço de unstoppable domain ${domain}"
476 }
\ No newline at end of file
res/values/strings_ru.arb
+4 -1
@@ -469,5 +469,8 @@
469 "unconfirmed" : "Неподтвержденный",
470 "displayable" : "Отображаемый",
471
472 - "submit_request" : "отправить запрос"
472 + "submit_request" : "отправить запрос",
473 +
474 + "address_detected" : "Обнаружен адрес",
475 + "address_from_domain" : "Вы получили адрес из unstoppable domain ${domain}"
476 }
\ No newline at end of file
res/values/strings_uk.arb
+4 -1
@@ -469,5 +469,8 @@
469 "unconfirmed" : "Непідтверджений",
470 "displayable" : "Відображуваний",
471
472 - "submit_request" : "надіслати запит"
472 + "submit_request" : "надіслати запит",
473 +
474 + "address_detected" : "Виявлено адресу",
475 + "address_from_domain" : "Ви отримали адресу від unstoppable domain ${domain}"
476 }
\ No newline at end of file
res/values/strings_zh.arb
+4 -1
@@ -469,5 +469,8 @@
469 "unconfirmed" : "未经证实",
470 "displayable" : "可显示",
471
472 - "submit_request" : "提交請求"
472 + "submit_request" : "提交請求",
473 +
474 + "address_detected" : "檢測到地址",
475 + "address_from_domain" : "您有以下地址 unstoppable domain ${domain}"
476 }
\ No newline at end of file