CAKE-192 | implemented unstoppable domain address to the app

This commit is contained in:
OleksandrSobol 2021-04-20 20:49:53 +03:00
parent 5faf7f5cba
commit ae9efb0ae8
29 changed files with 327 additions and 46 deletions

View file

@ -81,6 +81,7 @@ flutter {
dependencies { dependencies {
testImplementation 'junit:junit:4.12' testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test:runner:1.1.1' androidTestImplementation 'androidx.test:runner:1.3.0'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1' androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
implementation 'com.unstoppabledomains:resolution:1.13.0'
} }

View file

@ -5,11 +5,55 @@ import io.flutter.embedding.android.FlutterFragmentActivity;
import io.flutter.embedding.engine.FlutterEngine; import io.flutter.embedding.engine.FlutterEngine;
import io.flutter.plugins.GeneratedPluginRegistrant; import io.flutter.plugins.GeneratedPluginRegistrant;
import com.unstoppabledomains.resolution.DomainResolution;
import com.unstoppabledomains.resolution.Resolution;
import android.os.AsyncTask;
import android.os.Handler;
import android.os.Looper;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;
public class MainActivity extends FlutterFragmentActivity { public class MainActivity extends FlutterFragmentActivity {
final String UNSTOPPABLE_DOMAIN_CHANNEL = "com.cakewallet.cake_wallet/unstoppable-domain";
@Override @Override
public void configureFlutterEngine(@NonNull FlutterEngine flutterEngine) { public void configureFlutterEngine(@NonNull FlutterEngine flutterEngine) {
GeneratedPluginRegistrant.registerWith(flutterEngine); GeneratedPluginRegistrant.registerWith(flutterEngine);
MethodChannel unstoppableDomainChannel =
new MethodChannel(flutterEngine.getDartExecutor().getBinaryMessenger(),
UNSTOPPABLE_DOMAIN_CHANNEL);
unstoppableDomainChannel.setMethodCallHandler(this::handle);
}
private void handle(@NonNull MethodCall call, @NonNull MethodChannel.Result result) {
try {
if (call.method.equals("getUnstoppableDomainAddress")) {
getUnstoppableDomainAddress(call, result);
} else {
result.notImplemented();
}
} catch (Exception e) {
result.error("UNCAUGHT_ERROR", e.getMessage(), null);
}
}
private void getUnstoppableDomainAddress(@NonNull MethodCall call, @NonNull MethodChannel.Result result) {
DomainResolution resolution = new Resolution();
Handler handler = new Handler(Looper.getMainLooper());
String domain = call.argument("domain");
String ticker = call.argument("ticker");
AsyncTask.execute(() -> {
try {
String address = resolution.getAddress(domain, ticker);
handler.post(() -> result.success(address));
} catch (Exception e) {
handler.post(() -> result.error("INVALID DOMAIN", e.getMessage(), null));
}
});
} }
} }

View file

@ -5,7 +5,7 @@ buildscript {
} }
dependencies { dependencies {
classpath 'com.android.tools.build:gradle:3.5.4' classpath 'com.android.tools.build:gradle:4.1.3'
} }
} }

View file

@ -1,6 +1,6 @@
#Fri Jun 23 08:50:38 CEST 2017 #Mon Apr 19 18:19:26 EEST 2021
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-bin.zip

View file

@ -1,5 +1,5 @@
# Uncomment this line to define a global platform for your project # Uncomment this line to define a global platform for your project
platform :ios, '9.0' platform :ios, '11.0'
source 'https://github.com/CocoaPods/Specs.git' source 'https://github.com/CocoaPods/Specs.git'
# CocoaPods analytics sends network stats synchronously affecting flutter build latency. # CocoaPods analytics sends network stats synchronously affecting flutter build latency.
@ -36,6 +36,7 @@ target 'Runner' do
# Cake Wallet (Legacy) # Cake Wallet (Legacy)
pod 'CryptoSwift' pod 'CryptoSwift'
pod 'UnstoppableDomainsResolution', '~> 0.3.6'
end end
post_install do |installer| post_install do |installer|

View file

@ -3,6 +3,7 @@ PODS:
- Flutter - Flutter
- MTBBarcodeScanner - MTBBarcodeScanner
- SwiftProtobuf - SwiftProtobuf
- BigInt (5.2.0)
- connectivity (0.0.1): - connectivity (0.0.1):
- Flutter - Flutter
- Reachability - Reachability
@ -59,6 +60,8 @@ PODS:
- SwiftyGif - SwiftyGif
- esys_flutter_share (0.0.1): - esys_flutter_share (0.0.1):
- Flutter - Flutter
- EthereumAddress (1.3.0):
- CryptoSwift (~> 1.0)
- file_picker (0.0.1): - file_picker (0.0.1):
- DKImagePickerController/PhotoGallery - DKImagePickerController/PhotoGallery
- Flutter - Flutter
@ -84,6 +87,10 @@ PODS:
- Flutter - Flutter
- SwiftProtobuf (1.12.0) - SwiftProtobuf (1.12.0)
- SwiftyGif (5.3.0) - SwiftyGif (5.3.0)
- UnstoppableDomainsResolution (0.3.6):
- BigInt
- CryptoSwift (~> 1.0)
- EthereumAddress (~> 1.3)
- url_launcher (0.0.1): - url_launcher (0.0.1):
- Flutter - Flutter
- webview_flutter (0.0.1): - webview_flutter (0.0.1):
@ -105,19 +112,23 @@ DEPENDENCIES:
- permission_handler (from `.symlinks/plugins/permission_handler/ios`) - permission_handler (from `.symlinks/plugins/permission_handler/ios`)
- share (from `.symlinks/plugins/share/ios`) - share (from `.symlinks/plugins/share/ios`)
- shared_preferences (from `.symlinks/plugins/shared_preferences/ios`) - shared_preferences (from `.symlinks/plugins/shared_preferences/ios`)
- UnstoppableDomainsResolution (~> 0.3.6)
- url_launcher (from `.symlinks/plugins/url_launcher/ios`) - url_launcher (from `.symlinks/plugins/url_launcher/ios`)
- webview_flutter (from `.symlinks/plugins/webview_flutter/ios`) - webview_flutter (from `.symlinks/plugins/webview_flutter/ios`)
SPEC REPOS: SPEC REPOS:
https://github.com/CocoaPods/Specs.git: https://github.com/CocoaPods/Specs.git:
- BigInt
- CryptoSwift - CryptoSwift
- DKImagePickerController - DKImagePickerController
- DKPhotoGallery - DKPhotoGallery
- EthereumAddress
- MTBBarcodeScanner - MTBBarcodeScanner
- Reachability - Reachability
- SDWebImage - SDWebImage
- SwiftProtobuf - SwiftProtobuf
- SwiftyGif - SwiftyGif
- UnstoppableDomainsResolution
EXTERNAL SOURCES: EXTERNAL SOURCES:
barcode_scan: barcode_scan:
@ -155,6 +166,7 @@ EXTERNAL SOURCES:
SPEC CHECKSUMS: SPEC CHECKSUMS:
barcode_scan: a5c27959edfafaa0c771905bad0b29d6d39e4479 barcode_scan: a5c27959edfafaa0c771905bad0b29d6d39e4479
BigInt: f668a80089607f521586bbe29513d708491ef2f7
connectivity: c4130b2985d4ef6fd26f9702e886bd5260681467 connectivity: c4130b2985d4ef6fd26f9702e886bd5260681467
CryptoSwift: 093499be1a94b0cae36e6c26b70870668cb56060 CryptoSwift: 093499be1a94b0cae36e6c26b70870668cb56060
cw_monero: 2e1f79929880cc2293b5bc1b25e28152e4d84649 cw_monero: 2e1f79929880cc2293b5bc1b25e28152e4d84649
@ -162,6 +174,7 @@ SPEC CHECKSUMS:
DKImagePickerController: b5eb7f7a388e4643264105d648d01f727110fc3d DKImagePickerController: b5eb7f7a388e4643264105d648d01f727110fc3d
DKPhotoGallery: fdfad5125a9fdda9cc57df834d49df790dbb4179 DKPhotoGallery: fdfad5125a9fdda9cc57df834d49df790dbb4179
esys_flutter_share: 403498dab005b36ce1f8d7aff377e81f0621b0b4 esys_flutter_share: 403498dab005b36ce1f8d7aff377e81f0621b0b4
EthereumAddress: 39fe8e11cf04e4e9902b55ae653dbc4e0aee5f30
file_picker: 3e6c3790de664ccf9b882732d9db5eaf6b8d4eb1 file_picker: 3e6c3790de664ccf9b882732d9db5eaf6b8d4eb1
Flutter: 434fef37c0980e73bb6479ef766c45957d4b510c Flutter: 434fef37c0980e73bb6479ef766c45957d4b510c
flutter_secure_storage: 7953c38a04c3fdbb00571bcd87d8e3b5ceb9daec flutter_secure_storage: 7953c38a04c3fdbb00571bcd87d8e3b5ceb9daec
@ -176,9 +189,10 @@ SPEC CHECKSUMS:
shared_preferences: af6bfa751691cdc24be3045c43ec037377ada40d shared_preferences: af6bfa751691cdc24be3045c43ec037377ada40d
SwiftProtobuf: 4ef85479c18ca85b5482b343df9c319c62bda699 SwiftProtobuf: 4ef85479c18ca85b5482b343df9c319c62bda699
SwiftyGif: e466e86c660d343357ab944a819a101c4127cb40 SwiftyGif: e466e86c660d343357ab944a819a101c4127cb40
UnstoppableDomainsResolution: 63abb84858d3e91eb838a5bfa6f7e3c0e0593f24
url_launcher: 6fef411d543ceb26efce54b05a0a40bfd74cbbef url_launcher: 6fef411d543ceb26efce54b05a0a40bfd74cbbef
webview_flutter: 9f491a9b5a66f2573946a389b2677987b0ff8c0b webview_flutter: 9f491a9b5a66f2573946a389b2677987b0ff8c0b
PODFILE CHECKSUM: 5b5f101b119a1b6eb857c967d462832a9062dec4 PODFILE CHECKSUM: 2172f10eb8ff8378f8d6e3e2c1366a0e6cdea018
COCOAPODS: 1.9.3 COCOAPODS: 1.10.1

View file

@ -1,8 +1,13 @@
import UIKit import UIKit
import Flutter import Flutter
import UnstoppableDomainsResolution
@UIApplicationMain @UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate { @objc class AppDelegate: FlutterAppDelegate {
lazy var resolution : Resolution? = {
return try? Resolution()
}()
override func application( override func application(
_ application: UIApplication, _ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
@ -10,6 +15,8 @@ import Flutter
let controller : FlutterViewController = window?.rootViewController as! FlutterViewController let controller : FlutterViewController = window?.rootViewController as! FlutterViewController
let batteryChannel = FlutterMethodChannel(name: "com.cakewallet.cakewallet/legacy_wallet_migration", let batteryChannel = FlutterMethodChannel(name: "com.cakewallet.cakewallet/legacy_wallet_migration",
binaryMessenger: controller.binaryMessenger) binaryMessenger: controller.binaryMessenger)
let unstoppableDomainChannel = FlutterMethodChannel(name: "com.cakewallet.cake_wallet/unstoppable-domain", binaryMessenger: controller.binaryMessenger)
batteryChannel.setMethodCallHandler({ batteryChannel.setMethodCallHandler({
(call: FlutterMethodCall, result: @escaping FlutterResult) -> Void in (call: FlutterMethodCall, result: @escaping FlutterResult) -> Void in
@ -52,6 +59,39 @@ import Flutter
} }
}) })
unstoppableDomainChannel.setMethodCallHandler({ [weak self]
(call: FlutterMethodCall, result: @escaping FlutterResult) -> Void in
switch call.method {
case "getUnstoppableDomainAddress":
guard let args = call.arguments as? Dictionary<String, String>,
let domain = args["domain"],
let ticker = args["ticker"] else {
result(nil)
return
}
guard let resolution = self?.resolution else {
result(nil)
return
}
resolution.addr(domain: domain, ticker: ticker) { addrResult in
var address : String = ""
switch addrResult {
case .success(let returnValue):
address = returnValue
case .failure(let error):
print("Expected Address, but got \(error)")
}
result(address)
}
default:
result(FlutterMethodNotImplemented)
}
})
GeneratedPluginRegistrant.register(with: self) GeneratedPluginRegistrant.register(with: self)
return super.application(application, didFinishLaunchingWithOptions: launchOptions) return super.application(application, didFinishLaunchingWithOptions: launchOptions)
} }

View file

@ -0,0 +1,22 @@
import 'package:flutter/services.dart';
const channel = MethodChannel('com.cakewallet.cake_wallet/unstoppable-domain');
Future<String> fetchUnstoppableDomainAddress(String domain, String ticker) async {
String address;
try {
address = await channel.invokeMethod(
'getUnstoppableDomainAddress',
<String, String> {
'domain' : domain,
'ticker' : ticker
}
);
} catch (e) {
print('Unstoppable domain error: ${e.toString()}');
address = '';
}
return address;
}

View file

@ -1,7 +1,7 @@
import 'dart:ui'; import 'dart:ui';
import 'package:cake_wallet/entities/sync_status.dart'; import 'package:cake_wallet/entities/sync_status.dart';
import 'package:cake_wallet/entities/wallet_type.dart'; import 'package:cake_wallet/entities/wallet_type.dart';
import 'package:cake_wallet/exchange/changenow/changenow_exchange_provider.dart'; import 'package:cake_wallet/src/screens/send/widgets/unstoppable_domain_address_alert.dart';
import 'package:cake_wallet/src/widgets/standard_checkbox.dart'; import 'package:cake_wallet/src/widgets/standard_checkbox.dart';
import 'package:dotted_border/dotted_border.dart'; import 'package:dotted_border/dotted_border.dart';
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
@ -9,8 +9,6 @@ import 'package:flutter/material.dart';
import 'package:flutter_mobx/flutter_mobx.dart'; import 'package:flutter_mobx/flutter_mobx.dart';
import 'package:keyboard_actions/keyboard_actions.dart'; import 'package:keyboard_actions/keyboard_actions.dart';
import 'package:mobx/mobx.dart'; import 'package:mobx/mobx.dart';
import 'package:cake_wallet/exchange/exchange_provider.dart';
import 'package:cake_wallet/core/execution_state.dart';
import 'package:cake_wallet/exchange/exchange_template.dart'; import 'package:cake_wallet/exchange/exchange_template.dart';
import 'package:cake_wallet/exchange/exchange_trade_state.dart'; import 'package:cake_wallet/exchange/exchange_trade_state.dart';
import 'package:cake_wallet/exchange/limits_state.dart'; import 'package:cake_wallet/exchange/limits_state.dart';
@ -23,7 +21,6 @@ import 'package:cake_wallet/utils/show_pop_up.dart';
import 'package:cake_wallet/routes.dart'; import 'package:cake_wallet/routes.dart';
import 'package:cake_wallet/generated/i18n.dart'; import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/entities/crypto_currency.dart'; import 'package:cake_wallet/entities/crypto_currency.dart';
import 'package:cake_wallet/exchange/xmrto/xmrto_exchange_provider.dart';
import 'package:cake_wallet/src/screens/exchange/widgets/exchange_card.dart'; import 'package:cake_wallet/src/screens/exchange/widgets/exchange_card.dart';
import 'package:cake_wallet/src/widgets/primary_button.dart'; import 'package:cake_wallet/src/widgets/primary_button.dart';
import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart'; import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart';
@ -42,7 +39,9 @@ class ExchangePage extends BasePage {
final checkBoxKey = GlobalKey<StandardCheckboxState>(); final checkBoxKey = GlobalKey<StandardCheckboxState>();
final _formKey = GlobalKey<FormState>(); final _formKey = GlobalKey<FormState>();
final _depositAmountFocus = FocusNode(); final _depositAmountFocus = FocusNode();
final _depositAddressFocus = FocusNode();
final _receiveAmountFocus = FocusNode(); final _receiveAmountFocus = FocusNode();
final _receiveAddressFocus = FocusNode();
var _isReactionsSet = false; var _isReactionsSet = false;
@override @override
@ -52,7 +51,7 @@ class ExchangePage extends BasePage {
Color get titleColor => Colors.white; Color get titleColor => Colors.white;
@override @override
bool get resizeToAvoidBottomPadding => false; bool get resizeToAvoidBottomInset => false;
@override @override
bool get extendBodyBehindAppBar => true; bool get extendBodyBehindAppBar => true;
@ -171,6 +170,7 @@ class ExchangePage extends BasePage {
.calculateDepositAllAmount() .calculateDepositAllAmount()
: null, : null,
amountFocusNode: _depositAmountFocus, amountFocusNode: _depositAmountFocus,
addressFocusNode: _depositAddressFocus,
key: depositKey, key: depositKey,
title: S.of(context).you_will_send, title: S.of(context).you_will_send,
initialCurrency: initialCurrency:
@ -223,6 +223,15 @@ class ExchangePage extends BasePage {
type: exchangeViewModel.wallet.type), type: exchangeViewModel.wallet.type),
addressTextFieldValidator: AddressValidator( addressTextFieldValidator: AddressValidator(
type: exchangeViewModel.depositCurrency), type: exchangeViewModel.depositCurrency),
onPushPasteButton: (context) async {
final domain =
exchangeViewModel.depositAddress;
final ticker =
exchangeViewModel.depositCurrency.title;
exchangeViewModel.depositAddress =
await applyUnstoppableDomainAddress(
context, domain, ticker);
},
), ),
), ),
), ),
@ -232,6 +241,7 @@ class ExchangePage extends BasePage {
child: Observer( child: Observer(
builder: (_) => ExchangeCard( builder: (_) => ExchangeCard(
amountFocusNode: _receiveAmountFocus, amountFocusNode: _receiveAmountFocus,
addressFocusNode: _receiveAddressFocus,
key: receiveKey, key: receiveKey,
title: S.of(context).you_will_get, title: S.of(context).you_will_get,
initialCurrency: initialCurrency:
@ -268,6 +278,15 @@ class ExchangePage extends BasePage {
AddressValidator( AddressValidator(
type: exchangeViewModel type: exchangeViewModel
.receiveCurrency), .receiveCurrency),
onPushPasteButton: (context) async {
final domain =
exchangeViewModel.receiveAddress;
final ticker =
exchangeViewModel.receiveCurrency.title;
exchangeViewModel.receiveAddress =
await applyUnstoppableDomainAddress(
context, domain, ticker);
},
)), )),
) )
], ],
@ -371,7 +390,7 @@ class ExchangePage extends BasePage {
from: template.depositCurrency, from: template.depositCurrency,
to: template.receiveCurrency, to: template.receiveCurrency,
onTap: () { onTap: () {
applyTemplate( applyTemplate(context,
exchangeViewModel, template); exchangeViewModel, template);
}, },
onRemove: () { onRemove: () {
@ -472,8 +491,8 @@ class ExchangePage extends BasePage {
)); ));
} }
void applyTemplate( void applyTemplate(BuildContext context,
ExchangeViewModel exchangeViewModel, ExchangeTemplate template) { ExchangeViewModel exchangeViewModel, ExchangeTemplate template) async {
exchangeViewModel.changeDepositCurrency( exchangeViewModel.changeDepositCurrency(
currency: CryptoCurrency.fromString(template.depositCurrency)); currency: CryptoCurrency.fromString(template.depositCurrency));
exchangeViewModel.changeReceiveCurrency( exchangeViewModel.changeReceiveCurrency(
@ -491,6 +510,16 @@ class ExchangePage extends BasePage {
exchangeViewModel.receiveAddress = template.receiveAddress; exchangeViewModel.receiveAddress = template.receiveAddress;
exchangeViewModel.isReceiveAmountEntered = false; exchangeViewModel.isReceiveAmountEntered = false;
exchangeViewModel.isFixedRateMode = false; exchangeViewModel.isFixedRateMode = false;
var domain = template.depositAddress;
var ticker = template.depositCurrency;
exchangeViewModel.depositAddress =
await applyUnstoppableDomainAddress(context, domain, ticker);
domain = template.receiveAddress;
ticker = template.receiveCurrency;
exchangeViewModel.receiveAddress =
await applyUnstoppableDomainAddress(context, domain, ticker);
} }
void _setReactions( void _setReactions(
@ -656,6 +685,26 @@ class ExchangePage extends BasePage {
} }
}); });
_depositAddressFocus.addListener(() async {
if (!_depositAddressFocus.hasFocus &&
depositAddressController.text.isNotEmpty) {
final domain = depositAddressController.text;
final ticker = exchangeViewModel.depositCurrency.title;
exchangeViewModel.depositAddress =
await applyUnstoppableDomainAddress(context, domain, ticker);
}
});
_receiveAddressFocus.addListener(() async {
if (!_receiveAddressFocus.hasFocus &&
receiveAddressController.text.isNotEmpty) {
final domain = receiveAddressController.text;
final ticker = exchangeViewModel.receiveCurrency.title;
exchangeViewModel.receiveAddress =
await applyUnstoppableDomainAddress(context, domain, ticker);
}
});
_receiveAmountFocus.addListener(() { _receiveAmountFocus.addListener(() {
if (_receiveAmountFocus.hasFocus && !exchangeViewModel.isFixedRateMode) { if (_receiveAmountFocus.hasFocus && !exchangeViewModel.isFixedRateMode) {
showPopUp<void>( showPopUp<void>(
@ -726,4 +775,20 @@ class ExchangePage extends BasePage {
key.currentState.addressController.text = null; key.currentState.addressController.text = null;
} }
} }
Future<String> applyUnstoppableDomainAddress(BuildContext context,
String domain, String ticker) async {
try {
final address =
await exchangeViewModel.getUnstoppableDomainAddress(domain, ticker);
if ((address != null)&&address.isNotEmpty) {
unstoppableDomainAddressAlert(context, domain);
return address;
}
} catch (e) {
print(e.toString());
}
return domain;
}
} }

View file

@ -37,7 +37,7 @@ class ExchangeTemplatePage extends BasePage {
Color get titleColor => Colors.white; Color get titleColor => Colors.white;
@override @override
bool get resizeToAvoidBottomPadding => false; bool get resizeToAvoidBottomInset => false;
@override @override
bool get extendBodyBehindAppBar => true; bool get extendBodyBehindAppBar => true;
@ -150,9 +150,8 @@ class ExchangeTemplatePage extends BasePage {
.color, .color,
currencyValueValidator: AmountValidator( currencyValueValidator: AmountValidator(
type: exchangeViewModel.wallet.type), type: exchangeViewModel.wallet.type),
addressTextFieldValidator: AddressValidator( //addressTextFieldValidator: AddressValidator(
type: // type: exchangeViewModel.depositCurrency),
exchangeViewModel.depositCurrency),
), ),
), ),
), ),
@ -190,8 +189,8 @@ class ExchangeTemplatePage extends BasePage {
.decorationColor, .decorationColor,
currencyValueValidator: AmountValidator( currencyValueValidator: AmountValidator(
type: exchangeViewModel.wallet.type), type: exchangeViewModel.wallet.type),
addressTextFieldValidator: AddressValidator( //addressTextFieldValidator: AddressValidator(
type: exchangeViewModel.receiveCurrency), // type: exchangeViewModel.receiveCurrency),
)), )),
) )
], ],

View file

@ -28,8 +28,10 @@ class ExchangeCard extends StatefulWidget {
this.currencyValueValidator, this.currencyValueValidator,
this.addressTextFieldValidator, this.addressTextFieldValidator,
this.amountFocusNode, this.amountFocusNode,
this.addressFocusNode,
this.hasAllAmount = false, this.hasAllAmount = false,
this.allAmount}) this.allAmount,
this.onPushPasteButton})
: super(key: key); : super(key: key);
final List<CryptoCurrency> currencies; final List<CryptoCurrency> currencies;
@ -49,8 +51,10 @@ class ExchangeCard extends StatefulWidget {
final FormFieldValidator<String> currencyValueValidator; final FormFieldValidator<String> currencyValueValidator;
final FormFieldValidator<String> addressTextFieldValidator; final FormFieldValidator<String> addressTextFieldValidator;
final FocusNode amountFocusNode; final FocusNode amountFocusNode;
final FocusNode addressFocusNode;
final bool hasAllAmount; final bool hasAllAmount;
Function allAmount; final Function allAmount;
final Function(BuildContext context) onPushPasteButton;
@override @override
ExchangeCardState createState() => ExchangeCardState(); ExchangeCardState createState() => ExchangeCardState();
@ -288,6 +292,7 @@ class ExchangeCardState extends State<ExchangeCard> {
? Padding( ? Padding(
padding: EdgeInsets.only(top: 20), padding: EdgeInsets.only(top: 20),
child: AddressTextField( child: AddressTextField(
focusNode: widget.addressFocusNode,
controller: addressController, controller: addressController,
placeholder: widget.hasRefundAddress placeholder: widget.hasRefundAddress
? S.of(context).refund_address ? S.of(context).refund_address
@ -311,6 +316,7 @@ class ExchangeCardState extends State<ExchangeCard> {
.decorationColor), .decorationColor),
buttonColor: widget.addressButtonsColor, buttonColor: widget.addressButtonsColor,
validator: widget.addressTextFieldValidator, validator: widget.addressTextFieldValidator,
onPushPasteButton: widget.onPushPasteButton,
), ),
) )
: Padding( : Padding(

View file

@ -1,6 +1,6 @@
import 'dart:ui'; import 'dart:ui';
import 'package:cake_wallet/entities/monero_transaction_priority.dart';
import 'package:cake_wallet/entities/transaction_priority.dart'; import 'package:cake_wallet/entities/transaction_priority.dart';
import 'package:cake_wallet/src/screens/send/widgets/unstoppable_domain_address_alert.dart';
import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart'; import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart';
import 'package:cake_wallet/src/widgets/keyboard_done_button.dart'; import 'package:cake_wallet/src/widgets/keyboard_done_button.dart';
import 'package:cake_wallet/src/widgets/picker.dart'; import 'package:cake_wallet/src/widgets/picker.dart';
@ -38,9 +38,10 @@ class SendPage extends BasePage {
_cryptoAmountFocus = FocusNode(), _cryptoAmountFocus = FocusNode(),
_fiatAmountFocus = FocusNode(), _fiatAmountFocus = FocusNode(),
_addressFocusNode = FocusNode() { _addressFocusNode = FocusNode() {
_addressFocusNode.addListener(() { _addressFocusNode.addListener(() async {
if (!_addressFocusNode.hasFocus && _addressController.text.isNotEmpty) { if (!_addressFocusNode.hasFocus && _addressController.text.isNotEmpty) {
getOpenaliasRecord(_addressFocusNode.context); await getOpenaliasRecord(_addressFocusNode.context);
await applyUnstoppableDomainAddress(_addressFocusNode.context);
} }
}); });
} }
@ -67,7 +68,7 @@ class SendPage extends BasePage {
Color get titleColor => Colors.white; Color get titleColor => Colors.white;
@override @override
bool get resizeToAvoidBottomPadding => false; bool get resizeToAvoidBottomInset => false;
@override @override
bool get extendBodyBehindAppBar => true; bool get extendBodyBehindAppBar => true;
@ -173,6 +174,10 @@ class SendPage extends BasePage {
.headline .headline
.decorationColor), .decorationColor),
validator: sendViewModel.addressValidator, validator: sendViewModel.addressValidator,
onPushPasteButton: (context) async {
await getOpenaliasRecord(context);
await applyUnstoppableDomainAddress(context);
},
), ),
Observer( Observer(
builder: (_) => Padding( builder: (_) => Padding(
@ -513,12 +518,13 @@ class SendPage extends BasePage {
to: template.name, to: template.name,
amount: template.amount, amount: template.amount,
from: template.cryptoCurrency, from: template.cryptoCurrency,
onTap: () { onTap: () async {
_addressController.text = _addressController.text =
template.address; template.address;
_cryptoAmountController.text = _cryptoAmountController.text =
template.amount; template.amount;
getOpenaliasRecord(context); await getOpenaliasRecord(context);
await applyUnstoppableDomainAddress(context);
}, },
onRemove: () { onRemove: () {
showPopUp<void>( showPopUp<void>(
@ -770,4 +776,20 @@ class SendPage extends BasePage {
), ),
context: context); context: context);
} }
Future<void> applyUnstoppableDomainAddress(BuildContext context) async {
try {
final address = await sendViewModel
.getUnstoppableDomainAddress(
_addressController.text);
if ((address != null)&&address.isNotEmpty) {
unstoppableDomainAddressAlert(
context, _addressController.text);
_addressController.text = address;
}
} catch (e) {
print(e.toString());
}
}
} }

View file

@ -34,7 +34,7 @@ class SendTemplatePage extends BasePage {
Color get titleColor => Colors.white; Color get titleColor => Colors.white;
@override @override
bool get resizeToAvoidBottomPadding => false; bool get resizeToAvoidBottomInset => false;
@override @override
bool get extendBodyBehindAppBar => true; bool get extendBodyBehindAppBar => true;
@ -145,7 +145,7 @@ class SendTemplatePage extends BasePage {
.primaryTextTheme .primaryTextTheme
.headline .headline
.decorationColor), .decorationColor),
validator: sendViewModel.addressValidator, //validator: sendViewModel.addressValidator,
), ),
), ),
Observer(builder: (_) { Observer(builder: (_) {

View file

@ -0,0 +1,17 @@
import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
import 'package:cake_wallet/utils/show_pop_up.dart';
import 'package:flutter/material.dart';
import 'package:cake_wallet/generated/i18n.dart';
void unstoppableDomainAddressAlert(BuildContext context, String domain) async {
await showPopUp<void>(
context: context,
builder: (BuildContext context) {
return AlertWithOneAction(
alertTitle: S.of(context).address_detected,
alertContent: S.of(context).address_from_domain(domain),
buttonText: S.of(context).ok,
buttonAction: () => Navigator.of(context).pop());
});
}

View file

@ -24,7 +24,8 @@ class AddressTextField extends StatelessWidget {
this.iconColor, this.iconColor,
this.textStyle, this.textStyle,
this.hintStyle, this.hintStyle,
this.validator}); this.validator,
this.onPushPasteButton});
static const prefixIconWidth = 34.0; static const prefixIconWidth = 34.0;
static const prefixIconHeight = 34.0; static const prefixIconHeight = 34.0;
@ -43,6 +44,7 @@ class AddressTextField extends StatelessWidget {
final TextStyle textStyle; final TextStyle textStyle;
final TextStyle hintStyle; final TextStyle hintStyle;
final FocusNode focusNode; final FocusNode focusNode;
final Function(BuildContext context) onPushPasteButton;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -225,5 +227,7 @@ class AddressTextField extends StatelessWidget {
if (address?.isNotEmpty ?? false) { if (address?.isNotEmpty ?? false) {
controller.text = address; controller.text = address;
} }
onPushPasteButton?.call(context);
} }
} }

View file

@ -4,6 +4,7 @@ import 'package:cake_wallet/bitcoin/bitcoin_wallet.dart';
import 'package:cake_wallet/core/wallet_base.dart'; import 'package:cake_wallet/core/wallet_base.dart';
import 'package:cake_wallet/entities/crypto_currency.dart'; import 'package:cake_wallet/entities/crypto_currency.dart';
import 'package:cake_wallet/entities/sync_status.dart'; import 'package:cake_wallet/entities/sync_status.dart';
import 'package:cake_wallet/entities/unstoppable_domain_address.dart';
import 'package:cake_wallet/entities/wallet_type.dart'; import 'package:cake_wallet/entities/wallet_type.dart';
import 'package:cake_wallet/exchange/exchange_provider.dart'; import 'package:cake_wallet/exchange/exchange_provider.dart';
import 'package:cake_wallet/exchange/limits.dart'; import 'package:cake_wallet/exchange/limits.dart';
@ -417,4 +418,8 @@ abstract class ExchangeViewModelBase with Store {
}*/ }*/
isReceiveAmountEditable = false; isReceiveAmountEditable = false;
} }
Future<String> getUnstoppableDomainAddress(String domain, String ticker) async {
return await fetchUnstoppableDomainAddress(domain, ticker.toLowerCase());
}
} }

View file

@ -4,6 +4,7 @@ import 'package:cake_wallet/entities/balance_display_mode.dart';
import 'package:cake_wallet/entities/calculate_fiat_amount_raw.dart'; import 'package:cake_wallet/entities/calculate_fiat_amount_raw.dart';
import 'package:cake_wallet/entities/transaction_description.dart'; import 'package:cake_wallet/entities/transaction_description.dart';
import 'package:cake_wallet/entities/transaction_priority.dart'; import 'package:cake_wallet/entities/transaction_priority.dart';
import 'package:cake_wallet/entities/unstoppable_domain_address.dart';
import 'package:cake_wallet/monero/monero_amount_format.dart'; import 'package:cake_wallet/monero/monero_amount_format.dart';
import 'package:cake_wallet/view_model/settings/settings_view_model.dart'; import 'package:cake_wallet/view_model/settings/settings_view_model.dart';
import 'package:hive/hive.dart'; import 'package:hive/hive.dart';
@ -267,6 +268,10 @@ abstract class SendViewModelBase with Store {
return record.name != name ? record : null; return record.name != name ? record : null;
} }
Future<String> getUnstoppableDomainAddress(String domain) async {
return await fetchUnstoppableDomainAddress(domain, currency.title.toLowerCase());
}
@action @action
void _updateFiatAmount() { void _updateFiatAmount() {
try { try {

View file

@ -469,5 +469,8 @@
"unconfirmed" : "Unbestätigt", "unconfirmed" : "Unbestätigt",
"displayable" : "Anzeigebar", "displayable" : "Anzeigebar",
"submit_request" : "Einen Antrag stellen" "submit_request" : "Einen Antrag stellen",
"address_detected" : "Adresse erkannt",
"address_from_domain" : "Sie haben die Adresse von der unaufhaltsamen Domain ${domain} erhalten"
} }

View file

@ -469,5 +469,8 @@
"unconfirmed" : "Unconfirmed", "unconfirmed" : "Unconfirmed",
"displayable" : "Displayable", "displayable" : "Displayable",
"submit_request" : "submit a request" "submit_request" : "submit a request",
"address_detected" : "Address detected",
"address_from_domain" : "You got address from unstoppable domain ${domain}"
} }

View file

@ -469,5 +469,8 @@
"unconfirmed" : "Inconfirmado", "unconfirmed" : "Inconfirmado",
"displayable" : "Visualizable", "displayable" : "Visualizable",
"submit_request" : "presentar una solicitud" "submit_request" : "presentar una solicitud",
"address_detected" : "Dirección detectada",
"address_from_domain" : "Tienes la dirección de unstoppable domain ${domain}"
} }

View file

@ -469,5 +469,8 @@
"unconfirmed" : "अपुष्ट", "unconfirmed" : "अपुष्ट",
"displayable" : "प्रदर्शन योग्य", "displayable" : "प्रदर्शन योग्य",
"submit_request" : "एक अनुरोध सबमिट करें" "submit_request" : "एक अनुरोध सबमिट करें",
"address_detected" : "पता लग गया",
"address_from_domain" : "आपको अजेय डोमेन ${domain} से पता मिला है"
} }

View file

@ -469,5 +469,8 @@
"unconfirmed" : "未確認", "unconfirmed" : "未確認",
"displayable" : "表示可能", "displayable" : "表示可能",
"submit_request" : "リクエストを送信する" "submit_request" : "リクエストを送信する",
"address_detected" : "アドレスが検出されました",
"address_from_domain" : "あなたはからアドレスを得ました unstoppable domain ${domain}"
} }

View file

@ -469,5 +469,8 @@
"unconfirmed" : "미확인", "unconfirmed" : "미확인",
"displayable" : "표시 가능", "displayable" : "표시 가능",
"submit_request" : "요청을 제출" "submit_request" : "요청을 제출",
"address_detected" : "주소 감지",
"address_from_domain" : "주소는 unstoppable domain ${domain}"
} }

View file

@ -469,5 +469,8 @@
"unconfirmed" : "Niet bevestigd", "unconfirmed" : "Niet bevestigd",
"displayable" : "Weer te geven", "displayable" : "Weer te geven",
"submit_request" : "een verzoek indienen" "submit_request" : "een verzoek indienen",
"address_detected" : "Adres gedetecteerd",
"address_from_domain" : "Je adres is van unstoppable domain ${domain}"
} }

View file

@ -469,5 +469,8 @@
"unconfirmed" : "Niepotwierdzony", "unconfirmed" : "Niepotwierdzony",
"displayable" : "Wyświetlane", "displayable" : "Wyświetlane",
"submit_request" : "złożyć wniosek" "submit_request" : "złożyć wniosek",
"address_detected" : "Wykryto adres",
"address_from_domain" : "Dostałeś adres od unstoppable domain ${domain}"
} }

View file

@ -469,5 +469,8 @@
"unconfirmed" : "Não confirmado", "unconfirmed" : "Não confirmado",
"displayable" : "Exibível", "displayable" : "Exibível",
"submit_request" : "enviar um pedido" "submit_request" : "enviar um pedido",
"address_detected" : "Endereço detectado",
"address_from_domain" : "Você obteve o endereço de unstoppable domain ${domain}"
} }

View file

@ -469,5 +469,8 @@
"unconfirmed" : "Неподтвержденный", "unconfirmed" : "Неподтвержденный",
"displayable" : "Отображаемый", "displayable" : "Отображаемый",
"submit_request" : "отправить запрос" "submit_request" : "отправить запрос",
"address_detected" : "Обнаружен адрес",
"address_from_domain" : "Вы получили адрес из unstoppable domain ${domain}"
} }

View file

@ -469,5 +469,8 @@
"unconfirmed" : "Непідтверджений", "unconfirmed" : "Непідтверджений",
"displayable" : "Відображуваний", "displayable" : "Відображуваний",
"submit_request" : "надіслати запит" "submit_request" : "надіслати запит",
"address_detected" : "Виявлено адресу",
"address_from_domain" : "Ви отримали адресу від unstoppable domain ${domain}"
} }

View file

@ -469,5 +469,8 @@
"unconfirmed" : "未经证实", "unconfirmed" : "未经证实",
"displayable" : "可显示", "displayable" : "可显示",
"submit_request" : "提交請求" "submit_request" : "提交請求",
"address_detected" : "檢測到地址",
"address_from_domain" : "您有以下地址 unstoppable domain ${domain}"
} }