Merge branch 'main' of github.com:cake-tech/cake_wallet into ionia
|
@ -22,10 +22,11 @@
|
|||
* Select your own custom nodes/servers
|
||||
* Address book
|
||||
* Backup to external location or iCloud
|
||||
* OpenAlias and Unstoppable Domains
|
||||
* Send to OpenAlias, Unstoppable Domains, and Yats
|
||||
* Set custom fee levels
|
||||
* Store local transaction notes
|
||||
* Extremely simple user experience
|
||||
* Convenient exchange and sending templates for recurring payments
|
||||
|
||||
### Monero Specific Features
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
<uses-permission android:name="android.permission.USE_FINGERPRINT"/>
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.WRITE_INTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
||||
|
||||
<application
|
||||
android:name=".Application"
|
||||
|
|
BIN
assets/images/flags/aus.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
assets/images/flags/bgr.png
Normal file
After Width: | Height: | Size: 735 B |
BIN
assets/images/flags/bra.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
assets/images/flags/cad.png
Normal file
After Width: | Height: | Size: 1,005 B |
BIN
assets/images/flags/che.png
Normal file
After Width: | Height: | Size: 855 B |
BIN
assets/images/flags/chn.png
Normal file
After Width: | Height: | Size: 860 B |
BIN
assets/images/flags/czk.png
Normal file
After Width: | Height: | Size: 915 B |
BIN
assets/images/flags/deu.png
Normal file
After Width: | Height: | Size: 703 B |
BIN
assets/images/flags/dnk.png
Normal file
After Width: | Height: | Size: 801 B |
BIN
assets/images/flags/esp.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
assets/images/flags/eur.png
Normal file
After Width: | Height: | Size: 1,005 B |
BIN
assets/images/flags/fra.png
Normal file
After Width: | Height: | Size: 700 B |
BIN
assets/images/flags/gbr.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
assets/images/flags/hkg.png
Normal file
After Width: | Height: | Size: 1,023 B |
BIN
assets/images/flags/hrv.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
assets/images/flags/hun.png
Normal file
After Width: | Height: | Size: 728 B |
BIN
assets/images/flags/idn.png
Normal file
After Width: | Height: | Size: 684 B |
BIN
assets/images/flags/ind.png
Normal file
After Width: | Height: | Size: 845 B |
BIN
assets/images/flags/isl.png
Normal file
After Width: | Height: | Size: 867 B |
BIN
assets/images/flags/isr.png
Normal file
After Width: | Height: | Size: 937 B |
BIN
assets/images/flags/ita.png
Normal file
After Width: | Height: | Size: 705 B |
BIN
assets/images/flags/jpn.png
Normal file
After Width: | Height: | Size: 896 B |
BIN
assets/images/flags/kor.png
Normal file
After Width: | Height: | Size: 997 B |
BIN
assets/images/flags/mex.png
Normal file
After Width: | Height: | Size: 1,013 B |
BIN
assets/images/flags/mys.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
assets/images/flags/nld.png
Normal file
After Width: | Height: | Size: 762 B |
BIN
assets/images/flags/nor.png
Normal file
After Width: | Height: | Size: 898 B |
BIN
assets/images/flags/nzl.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
assets/images/flags/phl.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
assets/images/flags/pol.png
Normal file
After Width: | Height: | Size: 707 B |
BIN
assets/images/flags/prt.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
assets/images/flags/rou.png
Normal file
After Width: | Height: | Size: 705 B |
BIN
assets/images/flags/rus.png
Normal file
After Width: | Height: | Size: 702 B |
BIN
assets/images/flags/saf.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
assets/images/flags/sgp.png
Normal file
After Width: | Height: | Size: 902 B |
BIN
assets/images/flags/swe.png
Normal file
After Width: | Height: | Size: 752 B |
BIN
assets/images/flags/tha.png
Normal file
After Width: | Height: | Size: 774 B |
BIN
assets/images/flags/ukr.png
Normal file
After Width: | Height: | Size: 695 B |
BIN
assets/images/flags/usa.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
assets/images/flags/ven.png
Normal file
After Width: | Height: | Size: 1,009 B |
BIN
assets/images/mini_search_icon.png
Normal file
After Width: | Height: | Size: 536 B |
Before Width: | Height: | Size: 536 B After Width: | Height: | Size: 469 B |
BIN
assets/images/zaddr_icon.png
Normal file
After Width: | Height: | Size: 16 KiB |
BIN
assets/images/zec_icon.png
Normal file
After Width: | Height: | Size: 16 KiB |
|
@ -24,7 +24,7 @@ abstract class ElectrumTransactionHistoryBase
|
|||
}
|
||||
|
||||
final WalletInfo walletInfo;
|
||||
final String _password;
|
||||
String _password;
|
||||
int _height;
|
||||
|
||||
Future<void> init() async => await _load();
|
||||
|
@ -51,6 +51,11 @@ abstract class ElectrumTransactionHistoryBase
|
|||
}
|
||||
}
|
||||
|
||||
Future<void> changePassword(String password) async {
|
||||
_password = password;
|
||||
await save();
|
||||
}
|
||||
|
||||
Future<Map<String, Object>> _read() async {
|
||||
final dirPath =
|
||||
await pathForWalletDir(name: walletInfo.name, type: walletInfo.type);
|
||||
|
|
|
@ -109,7 +109,7 @@ abstract class ElectrumWalletBase extends WalletBase<ElectrumBalance,
|
|||
BitcoinWalletKeys get keys => BitcoinWalletKeys(
|
||||
wif: hd.wif, privateKey: hd.privKey, publicKey: hd.pubKey);
|
||||
|
||||
final String _password;
|
||||
String _password;
|
||||
List<BitcoinUnspent> unspentCoins;
|
||||
List<int> _feeRates;
|
||||
Map<String, BehaviorSubject<Object>> _scripthashesUpdateSubject;
|
||||
|
@ -422,6 +422,13 @@ abstract class ElectrumWalletBase extends WalletBase<ElectrumBalance,
|
|||
await transactionHistory.save();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> changePassword(String password) async {
|
||||
_password = password;
|
||||
await save();
|
||||
await transactionHistory.changePassword(password);
|
||||
}
|
||||
|
||||
bitcoin.ECPair keyPairFor({@required int index}) =>
|
||||
generateKeyPair(hd: hd, index: index, network: networkType);
|
||||
|
||||
|
|
|
@ -5,9 +5,13 @@ part 'crypto_currency.g.dart';
|
|||
|
||||
@HiveType(typeId: 0)
|
||||
class CryptoCurrency extends EnumerableItem<int> with Serializable<int> {
|
||||
const CryptoCurrency({final String title, final int raw})
|
||||
const CryptoCurrency({final String title, this.tag, this.name, this.iconPath, final int raw})
|
||||
: super(title: title, raw: raw);
|
||||
|
||||
final String tag;
|
||||
final String name;
|
||||
final String iconPath;
|
||||
|
||||
static const all = [
|
||||
CryptoCurrency.xmr,
|
||||
CryptoCurrency.ada,
|
||||
|
@ -24,39 +28,44 @@ class CryptoCurrency extends EnumerableItem<int> with Serializable<int> {
|
|||
CryptoCurrency.usdterc20,
|
||||
CryptoCurrency.xlm,
|
||||
CryptoCurrency.xrp,
|
||||
CryptoCurrency.xhv
|
||||
CryptoCurrency.xhv,
|
||||
//CryptoCurrency.zaddr,
|
||||
//CryptoCurrency.zec
|
||||
];
|
||||
static const xmr = CryptoCurrency(title: 'XMR', raw: 0);
|
||||
static const ada = CryptoCurrency(title: 'ADA', raw: 1);
|
||||
static const bch = CryptoCurrency(title: 'BCH', raw: 2);
|
||||
static const bnb = CryptoCurrency(title: 'BNB BEP2', raw: 3);
|
||||
static const btc = CryptoCurrency(title: 'BTC', raw: 4);
|
||||
static const dai = CryptoCurrency(title: 'DAI', raw: 5);
|
||||
static const dash = CryptoCurrency(title: 'DASH', raw: 6);
|
||||
static const eos = CryptoCurrency(title: 'EOS', raw: 7);
|
||||
static const eth = CryptoCurrency(title: 'ETH', raw: 8);
|
||||
static const ltc = CryptoCurrency(title: 'LTC', raw: 9);
|
||||
static const xmr = CryptoCurrency(title: 'XMR', iconPath: 'assets/images/monero_icon.png', name: 'Monero', raw: 0);
|
||||
static const ada = CryptoCurrency(title: 'ADA', iconPath: 'assets/images/ada_icon.png', name: 'Cardano', raw: 1);
|
||||
static const bch = CryptoCurrency(title: 'BCH', iconPath: 'assets/images/bch_icon.png',name: 'Bitcoin Cash', raw: 2);
|
||||
static const bnb = CryptoCurrency(title: 'BNB', iconPath: 'assets/images/bnb_icon.png', tag: 'BSC', name: 'Binance Coin', raw: 3);
|
||||
static const btc = CryptoCurrency(title: 'BTC', iconPath: 'assets/images/btc.png', name: 'Bitcoin', raw: 4);
|
||||
static const dai = CryptoCurrency(title: 'DAI', iconPath: 'assets/images/dai_icon.png', tag: 'ETH', name: 'Dai', raw: 5);
|
||||
static const dash = CryptoCurrency(title: 'DASH', iconPath: 'assets/images/dash_icon.png', name: 'Dash', raw: 6);
|
||||
static const eos = CryptoCurrency(title: 'EOS', iconPath: 'assets/images/eos_icon.png', name: 'EOS', raw: 7);
|
||||
static const eth = CryptoCurrency(title: 'ETH', iconPath: 'assets/images/eth_icon.png', name: 'Ethereum', raw: 8);
|
||||
static const ltc = CryptoCurrency(title: 'LTC', iconPath: 'assets/images/litecoin-ltc_icon.png', name: 'Litecoin',raw: 9);
|
||||
static const nano = CryptoCurrency(title: 'NANO', raw: 10);
|
||||
static const trx = CryptoCurrency(title: 'TRX', raw: 11);
|
||||
static const usdt = CryptoCurrency(title: 'USDT', raw: 12);
|
||||
static const usdterc20 = CryptoCurrency(title: 'USDTERC20', raw: 13);
|
||||
static const xlm = CryptoCurrency(title: 'XLM', raw: 14);
|
||||
static const xrp = CryptoCurrency(title: 'XRP', raw: 15);
|
||||
static const xhv = CryptoCurrency(title: 'XHV', raw: 16);
|
||||
|
||||
static const xag = CryptoCurrency(title: 'XAG', raw: 17);
|
||||
static const xau = CryptoCurrency(title: 'XAU', raw: 18);
|
||||
static const xaud = CryptoCurrency(title: 'XAUD', raw: 19);
|
||||
static const xbtc = CryptoCurrency(title: 'XBTC', raw: 20);
|
||||
static const xcad = CryptoCurrency(title: 'XCAD', raw: 21);
|
||||
static const xchf = CryptoCurrency(title: 'XCHF', raw: 22);
|
||||
static const xcny = CryptoCurrency(title: 'XCNY', raw: 23);
|
||||
static const xeur = CryptoCurrency(title: 'XEUR', raw: 24);
|
||||
static const xgbp = CryptoCurrency(title: 'XGBP', raw: 25);
|
||||
static const xjpy = CryptoCurrency(title: 'XJPY', raw: 26);
|
||||
static const xnok = CryptoCurrency(title: 'XNOK', raw: 27);
|
||||
static const xnzd = CryptoCurrency(title: 'XNZD', raw: 28);
|
||||
static const xusd = CryptoCurrency(title: 'XUSD', raw: 29);
|
||||
static const trx = CryptoCurrency(title: 'TRX', iconPath: 'assets/images/trx_icon.png', name: 'TRON', raw: 11);
|
||||
static const usdt = CryptoCurrency(title: 'USDT', iconPath: 'assets/images/usdt_icon.png', tag: 'OMNI', name: 'USDT', raw: 12);
|
||||
static const usdterc20 = CryptoCurrency(title: 'USDT', iconPath: 'assets/images/usdterc20_icon.png', tag: 'ETH', name: 'USDT', raw: 13);
|
||||
static const xlm = CryptoCurrency(title: 'XLM', iconPath: 'assets/images/xlm_icon.png', name: 'Stellar', raw: 14);
|
||||
static const xrp = CryptoCurrency(title: 'XRP', iconPath: 'assets/images/xrp_icon.png', name: 'Ripple', raw: 15);
|
||||
static const xhv = CryptoCurrency(title: 'XHV', iconPath: 'assets/images/xhv_logo.png', name: 'Haven Protocol', raw: 16);
|
||||
|
||||
static const xag = CryptoCurrency(title: 'XAG', tag: 'XHV', raw: 17);
|
||||
static const xau = CryptoCurrency(title: 'XAU', tag: 'XHV', raw: 18);
|
||||
static const xaud = CryptoCurrency(title: 'XAUD', tag: 'XHV', raw: 19);
|
||||
static const xbtc = CryptoCurrency(title: 'XBTC', tag: 'XHV', raw: 20);
|
||||
static const xcad = CryptoCurrency(title: 'XCAD', tag: 'XHV', raw: 21);
|
||||
static const xchf = CryptoCurrency(title: 'XCHF', tag: 'XHV', raw: 22);
|
||||
static const xcny = CryptoCurrency(title: 'XCNY', tag: 'XHV', raw: 23);
|
||||
static const xeur = CryptoCurrency(title: 'XEUR', tag: 'XHV', raw: 24);
|
||||
static const xgbp = CryptoCurrency(title: 'XGBP', tag: 'XHV', raw: 25);
|
||||
static const xjpy = CryptoCurrency(title: 'XJPY', tag: 'XHV', raw: 26);
|
||||
static const xnok = CryptoCurrency(title: 'XNOK', tag: 'XHV', raw: 27);
|
||||
static const xnzd = CryptoCurrency(title: 'XNZD', tag: 'XHV', raw: 28);
|
||||
static const xusd = CryptoCurrency(title: 'XUSD', tag: 'XHV', raw: 29);
|
||||
|
||||
static const zaddr = CryptoCurrency(title: 'ZZEC', tag: 'ZEC', name: 'Shielded Zcash', iconPath: 'assets/images/zaddr_icon.png', raw: 30);
|
||||
static const zec = CryptoCurrency(title: 'TZEC', tag: 'ZEC', name: 'Transparent Zcash', iconPath: 'assets/images/zec_icon.png', raw: 31);
|
||||
|
||||
static CryptoCurrency deserialize({int raw}) {
|
||||
switch (raw) {
|
||||
|
@ -120,6 +129,10 @@ class CryptoCurrency extends EnumerableItem<int> with Serializable<int> {
|
|||
return CryptoCurrency.xnzd;
|
||||
case 29:
|
||||
return CryptoCurrency.xusd;
|
||||
case 30:
|
||||
return CryptoCurrency.zaddr;
|
||||
case 31:
|
||||
return CryptoCurrency.zec;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
|
@ -187,6 +200,10 @@ class CryptoCurrency extends EnumerableItem<int> with Serializable<int> {
|
|||
return CryptoCurrency.xnzd;
|
||||
case 'xusd':
|
||||
return CryptoCurrency.xusd;
|
||||
case 'zaddr':
|
||||
return CryptoCurrency.zaddr;
|
||||
case 'zec':
|
||||
return CryptoCurrency.zec;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -88,6 +88,8 @@ class Node extends HiveObject with Keyable {
|
|||
return requestElectrumServer();
|
||||
case WalletType.litecoin:
|
||||
return requestElectrumServer();
|
||||
case WalletType.haven:
|
||||
return requestMoneroNode();
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -69,4 +69,6 @@ abstract class WalletBase<
|
|||
Future<void> rescan({int height});
|
||||
|
||||
void close();
|
||||
|
||||
Future<void> changePassword(String password);
|
||||
}
|
||||
|
|
|
@ -565,6 +565,16 @@ extern "C"
|
|||
store_lock.unlock();
|
||||
}
|
||||
|
||||
bool set_password(char *password, Utf8Box &error) {
|
||||
bool is_changed = get_current_wallet()->setPassword(std::string(password));
|
||||
|
||||
if (!is_changed) {
|
||||
error = Utf8Box(strdup(get_current_wallet()->errorString().c_str()));
|
||||
}
|
||||
|
||||
return is_changed;
|
||||
}
|
||||
|
||||
bool transaction_create(char *address, char *asset_type, char *payment_id, char *amount,
|
||||
uint8_t priority_raw, uint32_t subaddr_account, Utf8Box &error, PendingTransactionRaw &pendingTransaction)
|
||||
{
|
||||
|
|
|
@ -51,6 +51,8 @@ typedef set_recovering_from_seed = Void Function(Int8);
|
|||
|
||||
typedef store_c = Void Function(Pointer<Utf8>);
|
||||
|
||||
typedef set_password = Int8 Function(Pointer<Utf8> password, Pointer<Utf8Box> error);
|
||||
|
||||
typedef set_listener = Void Function();
|
||||
|
||||
typedef get_syncing_height = Int64 Function();
|
||||
|
|
|
@ -51,6 +51,8 @@ typedef SetRecoveringFromSeed = void Function(int);
|
|||
|
||||
typedef Store = void Function(Pointer<Utf8>);
|
||||
|
||||
typedef SetPassword = int Function(Pointer<Utf8> password, Pointer<Utf8Box> error);
|
||||
|
||||
typedef SetListener = void Function();
|
||||
|
||||
typedef GetSyncingHeight = int Function();
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import 'dart:async';
|
||||
import 'dart:ffi';
|
||||
import 'package:ffi/ffi.dart';
|
||||
import 'package:cw_haven/api/structs/ut8_box.dart';
|
||||
import 'package:cw_haven/api/convert_utf8_to_string.dart';
|
||||
import 'package:cw_haven/api/signatures.dart';
|
||||
import 'package:cw_haven/api/types.dart';
|
||||
|
@ -67,6 +68,9 @@ final setRecoveringFromSeedNative = havenApi
|
|||
final storeNative =
|
||||
havenApi.lookup<NativeFunction<store_c>>('store').asFunction<Store>();
|
||||
|
||||
final setPasswordNative =
|
||||
havenApi.lookup<NativeFunction<set_password>>('set_password').asFunction<SetPassword>();
|
||||
|
||||
final setListenerNative = havenApi
|
||||
.lookup<NativeFunction<set_listener>>('set_listener')
|
||||
.asFunction<SetListener>();
|
||||
|
@ -193,6 +197,21 @@ void storeSync() {
|
|||
free(pathPointer);
|
||||
}
|
||||
|
||||
void setPasswordSync(String password) {
|
||||
final passwordPointer = Utf8.toUtf8(password);
|
||||
final errorMessagePointer = allocate<Utf8Box>();
|
||||
final changed = setPasswordNative(passwordPointer, errorMessagePointer) != 0;
|
||||
free(passwordPointer);
|
||||
|
||||
if (!changed) {
|
||||
final message = errorMessagePointer.ref.getValue();
|
||||
free(errorMessagePointer);
|
||||
throw Exception(message);
|
||||
}
|
||||
|
||||
free(errorMessagePointer);
|
||||
}
|
||||
|
||||
void closeCurrentWallet() => closeCurrentWalletNative();
|
||||
|
||||
String getSecretViewKey() =>
|
||||
|
|
|
@ -240,6 +240,11 @@ abstract class HavenWalletBase extends WalletBase<MoneroBalance,
|
|||
await haven_wallet.store();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> changePassword(String password) async {
|
||||
haven_wallet.setPasswordSync(password);
|
||||
}
|
||||
|
||||
Future<int> getNodeHeight() async => haven_wallet.getNodeHeight();
|
||||
|
||||
Future<bool> isConnected() async => haven_wallet.isConnected();
|
||||
|
|
|
@ -469,6 +469,16 @@ extern "C"
|
|||
store_lock.unlock();
|
||||
}
|
||||
|
||||
bool set_password(char *password, Utf8Box &error) {
|
||||
bool is_changed = get_current_wallet()->setPassword(std::string(password));
|
||||
|
||||
if (!is_changed) {
|
||||
error = Utf8Box(strdup(get_current_wallet()->errorString().c_str()));
|
||||
}
|
||||
|
||||
return is_changed;
|
||||
}
|
||||
|
||||
bool transaction_create(char *address, char *payment_id, char *amount,
|
||||
uint8_t priority_raw, uint32_t subaddr_account, Utf8Box &error, PendingTransactionRaw &pendingTransaction)
|
||||
{
|
||||
|
|
|
@ -47,6 +47,8 @@ typedef set_recovering_from_seed = Void Function(Int8);
|
|||
|
||||
typedef store_c = Void Function(Pointer<Utf8>);
|
||||
|
||||
typedef set_password = Int8 Function(Pointer<Utf8> password, Pointer<Utf8Box> error);
|
||||
|
||||
typedef set_listener = Void Function();
|
||||
|
||||
typedef get_syncing_height = Int64 Function();
|
||||
|
|
|
@ -47,6 +47,8 @@ typedef SetRecoveringFromSeed = void Function(int);
|
|||
|
||||
typedef Store = void Function(Pointer<Utf8>);
|
||||
|
||||
typedef SetPassword = int Function(Pointer<Utf8> password, Pointer<Utf8Box> error);
|
||||
|
||||
typedef SetListener = void Function();
|
||||
|
||||
typedef GetSyncingHeight = int Function();
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import 'dart:async';
|
||||
import 'dart:ffi';
|
||||
import 'package:ffi/ffi.dart';
|
||||
import 'package:cw_monero/api/structs/ut8_box.dart';
|
||||
import 'package:cw_monero/api/convert_utf8_to_string.dart';
|
||||
import 'package:cw_monero/api/signatures.dart';
|
||||
import 'package:cw_monero/api/types.dart';
|
||||
|
@ -67,6 +68,9 @@ final setRecoveringFromSeedNative = moneroApi
|
|||
final storeNative =
|
||||
moneroApi.lookup<NativeFunction<store_c>>('store').asFunction<Store>();
|
||||
|
||||
final setPasswordNative =
|
||||
moneroApi.lookup<NativeFunction<set_password>>('set_password').asFunction<SetPassword>();
|
||||
|
||||
final setListenerNative = moneroApi
|
||||
.lookup<NativeFunction<set_listener>>('set_listener')
|
||||
.asFunction<SetListener>();
|
||||
|
@ -197,6 +201,21 @@ void storeSync() {
|
|||
free(pathPointer);
|
||||
}
|
||||
|
||||
void setPasswordSync(String password) {
|
||||
final passwordPointer = Utf8.toUtf8(password);
|
||||
final errorMessagePointer = allocate<Utf8Box>();
|
||||
final changed = setPasswordNative(passwordPointer, errorMessagePointer) != 0;
|
||||
free(passwordPointer);
|
||||
|
||||
if (!changed) {
|
||||
final message = errorMessagePointer.ref.getValue();
|
||||
free(errorMessagePointer);
|
||||
throw Exception(message);
|
||||
}
|
||||
|
||||
free(errorMessagePointer);
|
||||
}
|
||||
|
||||
void closeCurrentWallet() => closeCurrentWalletNative();
|
||||
|
||||
String getSecretViewKey() =>
|
||||
|
|
|
@ -258,6 +258,11 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
|
|||
await monero_wallet.store();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> changePassword(String password) async {
|
||||
monero_wallet.setPasswordSync(password);
|
||||
}
|
||||
|
||||
Future<int> getNodeHeight() async => monero_wallet.getNodeHeight();
|
||||
|
||||
Future<bool> isConnected() async => monero_wallet.isConnected();
|
||||
|
|
|
@ -47,7 +47,7 @@ class AddressValidator extends TextValidator {
|
|||
case CryptoCurrency.xrp:
|
||||
return '^[0-9a-zA-Z]{34}\$|^X[0-9a-zA-Z]{46}\$';
|
||||
case CryptoCurrency.xhv:
|
||||
case CryptoCurrency.xhv:
|
||||
return '^hvx|hvi|hvs[0-9a-zA-Z]';
|
||||
case CryptoCurrency.xag:
|
||||
case CryptoCurrency.xau:
|
||||
case CryptoCurrency.xaud:
|
||||
|
@ -102,7 +102,6 @@ class AddressValidator extends TextValidator {
|
|||
case CryptoCurrency.xrp:
|
||||
return null;
|
||||
case CryptoCurrency.xhv:
|
||||
case CryptoCurrency.xhv:
|
||||
case CryptoCurrency.xag:
|
||||
case CryptoCurrency.xau:
|
||||
case CryptoCurrency.xaud:
|
||||
|
|
|
@ -1,12 +1,6 @@
|
|||
import 'package:uuid/uuid.dart';
|
||||
import 'package:cw_core/key.dart';
|
||||
import 'package:cw_core/wallet_type.dart';
|
||||
|
||||
String generateWalletPassword(WalletType type) {
|
||||
switch (type) {
|
||||
case WalletType.monero:
|
||||
return Uuid().v4();
|
||||
default:
|
||||
return generateKey();
|
||||
}
|
||||
String generateWalletPassword() {
|
||||
return generateKey();
|
||||
}
|
||||
|
|
|
@ -40,8 +40,3 @@ class TextValidator extends Validator<String> {
|
|||
|
||||
bool match(String value) => RegExp(pattern).hasMatch(value);
|
||||
}
|
||||
|
||||
class WalletNameValidator extends TextValidator {
|
||||
WalletNameValidator()
|
||||
: super(minLength: 1, maxLength: 15, pattern: '^[a-zA-Z0-9_]\$');
|
||||
}
|
|
@ -1,6 +1,9 @@
|
|||
import 'package:cake_wallet/di.dart';
|
||||
import 'package:cw_core/wallet_info.dart';
|
||||
import 'package:cake_wallet/entities/preferences_key.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
||||
import 'package:hive/hive.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
import 'package:cake_wallet/core/key_service.dart';
|
||||
import 'package:cw_core/wallet_base.dart';
|
||||
|
@ -14,7 +17,8 @@ class WalletCreationService {
|
|||
{WalletType initialType,
|
||||
this.secureStorage,
|
||||
this.keyService,
|
||||
this.sharedPreferences})
|
||||
this.sharedPreferences,
|
||||
this.walletInfoSource})
|
||||
: type = initialType {
|
||||
if (type != null) {
|
||||
changeWalletType(type: type);
|
||||
|
@ -25,34 +29,80 @@ class WalletCreationService {
|
|||
final FlutterSecureStorage secureStorage;
|
||||
final SharedPreferences sharedPreferences;
|
||||
final KeyService keyService;
|
||||
final Box<WalletInfo> walletInfoSource;
|
||||
WalletService _service;
|
||||
|
||||
static const _isNewMoneroWalletPasswordUpdated = true;
|
||||
|
||||
void changeWalletType({@required WalletType type}) {
|
||||
this.type = type;
|
||||
_service = getIt.get<WalletService>(param1: type);
|
||||
}
|
||||
|
||||
bool exists(String name) {
|
||||
final walletName = name.toLowerCase();
|
||||
return walletInfoSource
|
||||
.values
|
||||
.any((walletInfo) => walletInfo.name.toLowerCase() == walletName);
|
||||
}
|
||||
|
||||
void checkIfExists(String name) {
|
||||
if (exists(name)) {
|
||||
throw Exception('Wallet with name ${name} already exists!');
|
||||
}
|
||||
}
|
||||
|
||||
Future<WalletBase> create(WalletCredentials credentials) async {
|
||||
final password = generateWalletPassword(type);
|
||||
checkIfExists(credentials.name);
|
||||
final password = generateWalletPassword();
|
||||
credentials.password = password;
|
||||
await keyService.saveWalletPassword(
|
||||
password: password, walletName: credentials.name);
|
||||
return await _service.create(credentials);
|
||||
final wallet = await _service.create(credentials);
|
||||
|
||||
if (wallet.type == WalletType.monero) {
|
||||
await sharedPreferences
|
||||
.setBool(
|
||||
PreferencesKey.moneroWalletUpdateV1Key(wallet.name),
|
||||
_isNewMoneroWalletPasswordUpdated);
|
||||
}
|
||||
|
||||
return wallet;
|
||||
}
|
||||
|
||||
Future<WalletBase> restoreFromKeys(WalletCredentials credentials) async {
|
||||
final password = generateWalletPassword(type);
|
||||
checkIfExists(credentials.name);
|
||||
final password = generateWalletPassword();
|
||||
credentials.password = password;
|
||||
await keyService.saveWalletPassword(
|
||||
password: password, walletName: credentials.name);
|
||||
return await _service.restoreFromKeys(credentials);
|
||||
final wallet = await _service.restoreFromKeys(credentials);
|
||||
|
||||
if (wallet.type == WalletType.monero) {
|
||||
await sharedPreferences
|
||||
.setBool(
|
||||
PreferencesKey.moneroWalletUpdateV1Key(wallet.name),
|
||||
_isNewMoneroWalletPasswordUpdated);
|
||||
}
|
||||
|
||||
return wallet;
|
||||
}
|
||||
|
||||
Future<WalletBase> restoreFromSeed(WalletCredentials credentials) async {
|
||||
final password = generateWalletPassword(type);
|
||||
checkIfExists(credentials.name);
|
||||
final password = generateWalletPassword();
|
||||
credentials.password = password;
|
||||
await keyService.saveWalletPassword(
|
||||
password: password, walletName: credentials.name);
|
||||
return await _service.restoreFromSeed(credentials);
|
||||
final wallet = await _service.restoreFromSeed(credentials);
|
||||
|
||||
if (wallet.type == WalletType.monero) {
|
||||
await sharedPreferences
|
||||
.setBool(
|
||||
PreferencesKey.moneroWalletUpdateV1Key(wallet.name),
|
||||
_isNewMoneroWalletPasswordUpdated);
|
||||
}
|
||||
|
||||
return wallet;
|
||||
}
|
||||
}
|
||||
|
|
52
lib/core/wallet_loading_service.dart
Normal file
|
@ -0,0 +1,52 @@
|
|||
import 'package:cake_wallet/core/generate_wallet_password.dart';
|
||||
import 'package:cake_wallet/core/key_service.dart';
|
||||
import 'package:cake_wallet/entities/preferences_key.dart';
|
||||
import 'package:cw_core/wallet_base.dart';
|
||||
import 'package:cw_core/wallet_service.dart';
|
||||
import 'package:cw_core/wallet_type.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
|
||||
class WalletLoadingService {
|
||||
WalletLoadingService(
|
||||
this.sharedPreferences,
|
||||
this.keyService,
|
||||
this.walletServiceFactory);
|
||||
|
||||
final SharedPreferences sharedPreferences;
|
||||
final KeyService keyService;
|
||||
final WalletService Function(WalletType type) walletServiceFactory;
|
||||
|
||||
Future<WalletBase> load(WalletType type, String name) async {
|
||||
if (walletServiceFactory == null) {
|
||||
throw Exception('WalletLoadingService.walletServiceFactory is not set');
|
||||
}
|
||||
final walletService = walletServiceFactory?.call(type);
|
||||
final password = await keyService.getWalletPassword(walletName: name);
|
||||
final wallet = await walletService.openWallet(name, password);
|
||||
|
||||
if (type == WalletType.monero) {
|
||||
await upateMoneroWalletPassword(wallet);
|
||||
}
|
||||
|
||||
return wallet;
|
||||
}
|
||||
|
||||
Future<void> upateMoneroWalletPassword(WalletBase wallet) async {
|
||||
final key = PreferencesKey.moneroWalletUpdateV1Key(wallet.name);
|
||||
var isPasswordUpdated = sharedPreferences.getBool(key) ?? false;
|
||||
|
||||
if (isPasswordUpdated) {
|
||||
return;
|
||||
}
|
||||
|
||||
final password = generateWalletPassword();
|
||||
// Save new generated password with backup key for case
|
||||
// if wallet will change password, but it will faild to updated in secure storage
|
||||
final bakWalletName = '#__${wallet.name}_bak__#';
|
||||
await keyService.saveWalletPassword(walletName: bakWalletName, password: password);
|
||||
await wallet.changePassword(password);
|
||||
await keyService.saveWalletPassword(walletName: wallet.name, password: password);
|
||||
isPasswordUpdated = true;
|
||||
await sharedPreferences.setBool(key, isPasswordUpdated);
|
||||
}
|
||||
}
|
11
lib/core/wallet_name_validator.dart
Normal file
|
@ -0,0 +1,11 @@
|
|||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/core/validator.dart';
|
||||
|
||||
class WalletNameValidator extends TextValidator {
|
||||
WalletNameValidator()
|
||||
: super(
|
||||
errorMessage: S.current.error_text_wallet_name,
|
||||
pattern: '^[a-zA-Z0-9\-_ ]+\$',
|
||||
minLength: 1,
|
||||
maxLength: 33);
|
||||
}
|
22
lib/di.dart
|
@ -13,7 +13,6 @@ import 'package:cake_wallet/ionia/ionia_api.dart';
|
|||
import 'package:cake_wallet/ionia/ionia_merchant.dart';
|
||||
import 'package:cake_wallet/monero/monero.dart';
|
||||
import 'package:cake_wallet/haven/haven.dart';
|
||||
import 'package:cake_wallet/haven/haven.dart';
|
||||
import 'package:cake_wallet/bitcoin/bitcoin.dart';
|
||||
import 'package:cake_wallet/src/screens/ionia/cards/ionia_account_cards_page.dart';
|
||||
import 'package:cake_wallet/src/screens/ionia/cards/ionia_account_page.dart';
|
||||
|
@ -56,7 +55,6 @@ import 'package:cake_wallet/src/screens/restore/wallet_restore_page.dart';
|
|||
import 'package:cake_wallet/src/screens/seed/pre_seed_page.dart';
|
||||
import 'package:cake_wallet/src/screens/seed/wallet_seed_page.dart';
|
||||
import 'package:cake_wallet/src/screens/send/send_template_page.dart';
|
||||
import 'package:cake_wallet/src/screens/settings/change_language.dart';
|
||||
import 'package:cake_wallet/src/screens/settings/settings.dart';
|
||||
import 'package:cake_wallet/src/screens/setup_pin_code/setup_pin_code.dart';
|
||||
import 'package:cake_wallet/src/screens/support/support_page.dart';
|
||||
|
@ -150,6 +148,8 @@ import 'package:cake_wallet/src/screens/ionia/cards/ionia_payment_status_page.da
|
|||
import 'package:cake_wallet/view_model/ionia/ionia_payment_status_view_model.dart';
|
||||
import 'package:cake_wallet/anypay/any_pay_payment_committed_info.dart';
|
||||
import 'package:cake_wallet/ionia/ionia_any_pay_payment_info.dart';
|
||||
import 'package:cake_wallet/src/screens/receive/fullscreen_qr_page.dart';
|
||||
import 'package:cake_wallet/core/wallet_loading_service.dart';
|
||||
|
||||
final getIt = GetIt.instance;
|
||||
|
||||
|
@ -241,7 +241,14 @@ Future setup(
|
|||
initialType: type,
|
||||
keyService: getIt.get<KeyService>(),
|
||||
secureStorage: getIt.get<FlutterSecureStorage>(),
|
||||
sharedPreferences: getIt.get<SharedPreferences>()));
|
||||
sharedPreferences: getIt.get<SharedPreferences>(),
|
||||
walletInfoSource: _walletInfoSource));
|
||||
|
||||
getIt.registerFactory<WalletLoadingService>(
|
||||
() => WalletLoadingService(
|
||||
getIt.get<SharedPreferences>(),
|
||||
getIt.get<KeyService>(),
|
||||
(WalletType type) => getIt.get<WalletService>(param1: type)));
|
||||
|
||||
getIt.registerFactory(() => IoniaTokenService(getIt.get<FlutterSecureStorage>()));
|
||||
|
||||
|
@ -378,7 +385,7 @@ Future setup(
|
|||
getIt.registerFactory(() => WalletListViewModel(
|
||||
_walletInfoSource,
|
||||
getIt.get<AppStore>(),
|
||||
getIt.get<KeyService>()));
|
||||
getIt.get<WalletLoadingService>()));
|
||||
|
||||
getIt.registerFactory(() =>
|
||||
WalletListPage(walletListViewModel: getIt.get<WalletListViewModel>()));
|
||||
|
@ -533,8 +540,6 @@ Future setup(
|
|||
|
||||
getIt.registerFactory(() => FaqPage(getIt.get<SettingsStore>()));
|
||||
|
||||
getIt.registerFactory(() => LanguageListPage(getIt.get<SettingsStore>()));
|
||||
|
||||
getIt.registerFactoryParam<WalletRestoreViewModel, WalletType, void>(
|
||||
(type, _) => WalletRestoreViewModel(getIt.get<AppStore>(),
|
||||
getIt.get<WalletCreationService>(param1: type), _walletInfoSource,
|
||||
|
@ -658,6 +663,11 @@ Future setup(
|
|||
|
||||
getIt.registerFactory(() => YatService());
|
||||
|
||||
getIt.registerFactory(() => AddressResolver(yatService: getIt.get<YatService>(),
|
||||
walletType: getIt.get<AppStore>().wallet.type));
|
||||
|
||||
getIt.registerFactoryParam<FullscreenQRPage, String, bool>(
|
||||
(String qrData, bool isLight) => FullscreenQRPage(qrData: qrData, isLight: isLight,));
|
||||
getIt.registerFactory(() => AddressResolver(yatService: getIt.get<YatService>()));
|
||||
|
||||
getIt.registerFactory(() => IoniaApi());
|
||||
|
|
|
@ -1,43 +1,49 @@
|
|||
import 'package:cw_core/enumerable_item.dart';
|
||||
|
||||
class FiatCurrency extends EnumerableItem<String> with Serializable<String> {
|
||||
const FiatCurrency({String symbol}) : super(title: symbol, raw: symbol);
|
||||
const FiatCurrency({String symbol, this.countryCode, this.fullName}) : super(title: symbol, raw: symbol);
|
||||
|
||||
final String countryCode;
|
||||
final String fullName;
|
||||
|
||||
static List<FiatCurrency> get all => _all.values.toList();
|
||||
|
||||
static const aud = FiatCurrency(symbol: 'AUD');
|
||||
static const bgn = FiatCurrency(symbol: 'BGN');
|
||||
static const brl = FiatCurrency(symbol: 'BRL');
|
||||
static const cad = FiatCurrency(symbol: 'CAD');
|
||||
static const chf = FiatCurrency(symbol: 'CHF');
|
||||
static const cny = FiatCurrency(symbol: 'CNY');
|
||||
static const czk = FiatCurrency(symbol: 'CZK');
|
||||
static const eur = FiatCurrency(symbol: 'EUR');
|
||||
static const dkk = FiatCurrency(symbol: 'DKK');
|
||||
static const gbp = FiatCurrency(symbol: 'GBP');
|
||||
static const hkd = FiatCurrency(symbol: 'HKD');
|
||||
static const hrk = FiatCurrency(symbol: 'HRK');
|
||||
static const huf = FiatCurrency(symbol: 'HUF');
|
||||
static const idr = FiatCurrency(symbol: 'IDR');
|
||||
static const ils = FiatCurrency(symbol: 'ILS');
|
||||
static const inr = FiatCurrency(symbol: 'INR');
|
||||
static const isk = FiatCurrency(symbol: 'ISK');
|
||||
static const jpy = FiatCurrency(symbol: 'JPY');
|
||||
static const krw = FiatCurrency(symbol: 'KRW');
|
||||
static const mxn = FiatCurrency(symbol: 'MXN');
|
||||
static const myr = FiatCurrency(symbol: 'MYR');
|
||||
static const nok = FiatCurrency(symbol: 'NOK');
|
||||
static const nzd = FiatCurrency(symbol: 'NZD');
|
||||
static const php = FiatCurrency(symbol: 'PHP');
|
||||
static const pln = FiatCurrency(symbol: 'PLN');
|
||||
static const ron = FiatCurrency(symbol: 'RON');
|
||||
static const rub = FiatCurrency(symbol: 'RUB');
|
||||
static const sek = FiatCurrency(symbol: 'SEK');
|
||||
static const sgd = FiatCurrency(symbol: 'SGD');
|
||||
static const thb = FiatCurrency(symbol: 'THB');
|
||||
static const usd = FiatCurrency(symbol: 'USD');
|
||||
static const zar = FiatCurrency(symbol: 'ZAR');
|
||||
static const vef = FiatCurrency(symbol: 'VEF');
|
||||
static List<FiatCurrency> get currenciesAvailableToBuyWith =>
|
||||
[aud, brl, cad, chf, czk, eur, dkk, gbp, hkd, ils, jpy, krw, mxn, myr, nok, nzd, pln, sek, sgd, thb, usd, zar];
|
||||
|
||||
static const aud = FiatCurrency(symbol: 'AUD', countryCode: "aus", fullName: "Australian Dollar");
|
||||
static const bgn = FiatCurrency(symbol: 'BGN', countryCode: "bgr", fullName: "Bulgarian Lev");
|
||||
static const brl = FiatCurrency(symbol: 'BRL', countryCode: "bra", fullName: "Brazilian Real");
|
||||
static const cad = FiatCurrency(symbol: 'CAD', countryCode: "cad", fullName: "Canadian Dollar");
|
||||
static const chf = FiatCurrency(symbol: 'CHF', countryCode: "che", fullName: "Swiss Franc");
|
||||
static const cny = FiatCurrency(symbol: 'CNY', countryCode: "chn", fullName: "Chinese Yuan");
|
||||
static const czk = FiatCurrency(symbol: 'CZK', countryCode: "czk", fullName: "Czech Koruna");
|
||||
static const eur = FiatCurrency(symbol: 'EUR', countryCode: "eur", fullName: "Euro");
|
||||
static const dkk = FiatCurrency(symbol: 'DKK', countryCode: "dnk", fullName: "Danish Krone");
|
||||
static const gbp = FiatCurrency(symbol: 'GBP', countryCode: "gbr", fullName: "Pound sterling");
|
||||
static const hkd = FiatCurrency(symbol: 'HKD', countryCode: "hkg", fullName: "Hong Kong Dollar");
|
||||
static const hrk = FiatCurrency(symbol: 'HRK', countryCode: "hrv", fullName: "Croatian Kuna");
|
||||
static const huf = FiatCurrency(symbol: 'HUF', countryCode: "hun", fullName: "Hungarian Forint");
|
||||
static const idr = FiatCurrency(symbol: 'IDR', countryCode: "idn", fullName: "Indonesian Rupiah");
|
||||
static const ils = FiatCurrency(symbol: 'ILS', countryCode: "isr", fullName: "Israeli New Shekel");
|
||||
static const inr = FiatCurrency(symbol: 'INR', countryCode: "ind", fullName: "Indian Rupee");
|
||||
static const isk = FiatCurrency(symbol: 'ISK', countryCode: "isl", fullName: "Icelandic Króna");
|
||||
static const jpy = FiatCurrency(symbol: 'JPY', countryCode: "jpn", fullName: "Japanese Yen equals");
|
||||
static const krw = FiatCurrency(symbol: 'KRW', countryCode: "kor", fullName: "South Korean won");
|
||||
static const mxn = FiatCurrency(symbol: 'MXN', countryCode: "mex", fullName: "Mexican Peso");
|
||||
static const myr = FiatCurrency(symbol: 'MYR', countryCode: "mys", fullName: "Malaysian Ringgit");
|
||||
static const nok = FiatCurrency(symbol: 'NOK', countryCode: "nor", fullName: "Norwegian Krone");
|
||||
static const nzd = FiatCurrency(symbol: 'NZD', countryCode: "nzl", fullName: "New Zealand Dollar");
|
||||
static const php = FiatCurrency(symbol: 'PHP', countryCode: "phl", fullName: "Philippine peso");
|
||||
static const pln = FiatCurrency(symbol: 'PLN', countryCode: "pol", fullName: "Poland złoty");
|
||||
static const ron = FiatCurrency(symbol: 'RON', countryCode: "rou", fullName: "Romanian Leu");
|
||||
static const rub = FiatCurrency(symbol: 'RUB', countryCode: "rus", fullName: "Russian Ruble");
|
||||
static const sek = FiatCurrency(symbol: 'SEK', countryCode: "swe", fullName: "Swedish Krona");
|
||||
static const sgd = FiatCurrency(symbol: 'SGD', countryCode: "sgp", fullName: "Singapore Dollar");
|
||||
static const thb = FiatCurrency(symbol: 'THB', countryCode: "tha", fullName: "Thai Baht");
|
||||
static const usd = FiatCurrency(symbol: 'USD', countryCode: "usa", fullName: "United States Dollar");
|
||||
static const zar = FiatCurrency(symbol: 'ZAR', countryCode: "saf", fullName: "South African Rand");
|
||||
static const vef = FiatCurrency(symbol: 'VEF', countryCode: "ven", fullName: "Venezuelan Bolívar");
|
||||
|
||||
static final _all = {
|
||||
FiatCurrency.aud.raw: FiatCurrency.aud,
|
||||
|
|
57
lib/entities/fio_address_provider.dart
Normal file
|
@ -0,0 +1,57 @@
|
|||
import 'dart:convert';
|
||||
|
||||
import 'package:http/http.dart' as http;
|
||||
|
||||
class FioAddressProvider {
|
||||
static const apiAuthority = 'fio.blockpane.com';
|
||||
static const availCheck = '/v1/chain/avail_check';
|
||||
static const getAddress = '/v1/chain/get_pub_address';
|
||||
|
||||
static Future<bool> checkAvail(String fioAddress) async {
|
||||
bool isFioRegistered = false;
|
||||
final headers = {'Content-Type': 'application/json'};
|
||||
final body = <String, String>{"fio_name": fioAddress};
|
||||
|
||||
final uri = Uri.https(apiAuthority, availCheck);
|
||||
final response =
|
||||
await http.post(uri, headers: headers, body: json.encode(body));
|
||||
|
||||
if (response.statusCode != 200) {
|
||||
return isFioRegistered;
|
||||
}
|
||||
|
||||
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
|
||||
isFioRegistered = responseJSON['is_registered'] as int == 1;
|
||||
|
||||
return isFioRegistered;
|
||||
}
|
||||
|
||||
static Future<String> getPubAddress(String fioAddress, String token) async {
|
||||
final headers = {'Content-Type': 'application/json'};
|
||||
final body = <String, String>{
|
||||
"fio_address": fioAddress,
|
||||
"chain_code": token.toUpperCase(),
|
||||
"token_code": token.toUpperCase(),
|
||||
};
|
||||
|
||||
final uri = Uri.https(apiAuthority, getAddress);
|
||||
final response =
|
||||
await http.post(uri, headers: headers, body: json.encode(body));
|
||||
|
||||
if (response.statusCode == 400) {
|
||||
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
|
||||
final error = responseJSON['error'] as String;
|
||||
final message = responseJSON['message'] as String;
|
||||
throw Exception('${error}\n$message');
|
||||
}
|
||||
|
||||
if (response.statusCode != 200) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
|
||||
final String pubAddress = responseJSON['public_address'] as String;
|
||||
|
||||
return pubAddress;
|
||||
}
|
||||
}
|
|
@ -1,3 +1,4 @@
|
|||
import 'dart:convert';
|
||||
import 'dart:math';
|
||||
|
||||
import 'package:flutter/services.dart';
|
||||
|
@ -14,8 +15,11 @@ Future<String> generateName() async {
|
|||
await rootBundle.loadString('assets/text/Wallet_Adjectives.txt');
|
||||
final nounStringRaw =
|
||||
await rootBundle.loadString('assets/text/Wallet_Nouns.txt');
|
||||
final adjectives = List<String>.from(adjectiveStringRaw.split('\n'));
|
||||
final nouns = List<String>.from(nounStringRaw.split('\n'));
|
||||
|
||||
final ls = LineSplitter();
|
||||
final adjectives = ls.convert(adjectiveStringRaw);
|
||||
final nouns = ls.convert(nounStringRaw);
|
||||
|
||||
final chosenAdjective = adjectives[randomThing.nextInt(adjectives.length)];
|
||||
final chosenNoun = nouns[randomThing.nextInt(nouns.length)];
|
||||
final returnString =
|
||||
|
|
|
@ -20,6 +20,25 @@ class LanguageService {
|
|||
'hr': 'Hrvatski (Croatian)',
|
||||
'it': 'Italiano (Italian)'
|
||||
};
|
||||
|
||||
static const Map<String, String> localeCountryCode = {
|
||||
'en': 'usa',
|
||||
'de': 'deu',
|
||||
'es': 'esp',
|
||||
'fr': 'fra',
|
||||
'hi': 'ind',
|
||||
'ja': 'jpn',
|
||||
'ko': 'kor',
|
||||
'nl': 'nld',
|
||||
'pl': 'pol',
|
||||
'pt': 'prt',
|
||||
'ru': 'rus',
|
||||
'uk': 'ukr',
|
||||
'zh': 'chn',
|
||||
'hr': 'hrv',
|
||||
'it': 'ita'
|
||||
};
|
||||
|
||||
static final list = <String, String> {};
|
||||
|
||||
static void loadLocaleList() {
|
||||
|
|
|
@ -5,6 +5,7 @@ import 'package:cake_wallet/core/key_service.dart';
|
|||
import 'package:cw_core/wallet_service.dart';
|
||||
import 'package:cake_wallet/entities/preferences_key.dart';
|
||||
import 'package:cw_core/wallet_type.dart';
|
||||
import 'package:cake_wallet/core/wallet_loading_service.dart';
|
||||
|
||||
Future<void> loadCurrentWallet() async {
|
||||
final appStore = getIt.get<AppStore>();
|
||||
|
@ -15,9 +16,7 @@ Future<void> loadCurrentWallet() async {
|
|||
getIt.get<SharedPreferences>().getInt(PreferencesKey.currentWalletType) ??
|
||||
0;
|
||||
final type = deserializeFromInt(typeRaw);
|
||||
final password =
|
||||
await getIt.get<KeyService>().getWalletPassword(walletName: name);
|
||||
final _service = getIt.get<WalletService>(param1: type);
|
||||
final wallet = await _service.openWallet(name, password);
|
||||
final walletLoadingService = getIt.get<WalletLoadingService>();
|
||||
final wallet = await walletLoadingService.load(type, name);
|
||||
appStore.changeCurrentWallet(wallet);
|
||||
}
|
||||
|
|
|
@ -3,13 +3,16 @@ import 'package:cake_wallet/entities/openalias_record.dart';
|
|||
import 'package:cake_wallet/entities/parsed_address.dart';
|
||||
import 'package:cake_wallet/entities/unstoppable_domain_address.dart';
|
||||
import 'package:cake_wallet/entities/emoji_string_extension.dart';
|
||||
import 'package:cw_core/wallet_type.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:cake_wallet/entities/fio_address_provider.dart';
|
||||
|
||||
class AddressResolver {
|
||||
|
||||
AddressResolver({@required this.yatService});
|
||||
AddressResolver({@required this.yatService, this.walletType});
|
||||
|
||||
final YatService yatService;
|
||||
final WalletType walletType;
|
||||
|
||||
static const unstoppableDomains = [
|
||||
'crypto',
|
||||
|
@ -26,9 +29,19 @@ class AddressResolver {
|
|||
|
||||
Future<ParsedAddress> resolve(String text, String ticker) async {
|
||||
try {
|
||||
if (text.contains('@') && !text.contains('.')) {
|
||||
final bool isFioRegistered = await FioAddressProvider.checkAvail(text);
|
||||
if (isFioRegistered) {
|
||||
final address = await FioAddressProvider.getPubAddress(text, ticker);
|
||||
return ParsedAddress.fetchFioAddress(address: address, name: text);
|
||||
}
|
||||
|
||||
}
|
||||
if (text.hasOnlyEmojis) {
|
||||
final addresses = await yatService.fetchYatAddress(text, ticker);
|
||||
return ParsedAddress.fetchEmojiAddress(addresses: addresses, name: text);
|
||||
if (walletType != WalletType.haven) {
|
||||
final addresses = await yatService.fetchYatAddress(text, ticker);
|
||||
return ParsedAddress.fetchEmojiAddress(addresses: addresses, name: text);
|
||||
}
|
||||
}
|
||||
final formattedName = OpenaliasRecord.formatDomainName(text);
|
||||
final domainParts = formattedName.split('.');
|
||||
|
|
|
@ -2,7 +2,7 @@ import 'package:cake_wallet/entities/openalias_record.dart';
|
|||
import 'package:cake_wallet/entities/yat_record.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
enum ParseFrom { unstoppableDomains, openAlias, yatRecord, notParsed }
|
||||
enum ParseFrom { unstoppableDomains, openAlias, yatRecord, fio, notParsed }
|
||||
|
||||
class ParsedAddress {
|
||||
ParsedAddress({
|
||||
|
@ -58,4 +58,13 @@ class ParsedAddress {
|
|||
parseFrom: ParseFrom.openAlias,
|
||||
);
|
||||
}
|
||||
|
||||
factory ParsedAddress.fetchFioAddress({@required String address, @required String name}){
|
||||
|
||||
return ParsedAddress(
|
||||
addresses: [address],
|
||||
name: name,
|
||||
parseFrom: ParseFrom.fio,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,4 +22,8 @@ class PreferencesKey {
|
|||
static const bitcoinTransactionPriority = 'current_fee_priority_bitcoin';
|
||||
static const shouldShowReceiveWarning = 'should_show_receive_warning';
|
||||
static const shouldShowYatPopup = 'should_show_yat_popup';
|
||||
static const moneroWalletPasswordUpdateV1Base = 'monero_wallet_update_v1';
|
||||
|
||||
static String moneroWalletUpdateV1Key(String name)
|
||||
=> '${PreferencesKey.moneroWalletPasswordUpdateV1Base}_${name}';
|
||||
}
|
||||
|
|
|
@ -240,33 +240,23 @@ class ChangeNowExchangeProvider extends ExchangeProvider {
|
|||
}
|
||||
|
||||
String networkFor(CryptoCurrency currency) {
|
||||
const bnbTitle = 'bnb';
|
||||
|
||||
switch (currency) {
|
||||
case CryptoCurrency.usdt:
|
||||
return CryptoCurrency.btc.title.toLowerCase();
|
||||
case CryptoCurrency.usdterc20:
|
||||
return CryptoCurrency.eth.title.toLowerCase();
|
||||
case CryptoCurrency.bnb:
|
||||
return bnbTitle;
|
||||
case CryptoCurrency.dai:
|
||||
return CryptoCurrency.eth.title.toLowerCase();
|
||||
default:
|
||||
return currency.title.toLowerCase();
|
||||
return currency.tag != null
|
||||
? currency.tag.toLowerCase()
|
||||
: currency.title.toLowerCase();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static String normalizeCryptoCurrency(CryptoCurrency currency) {
|
||||
const bnbTitle = 'bnb';
|
||||
|
||||
switch(currency) {
|
||||
case CryptoCurrency.bnb:
|
||||
return bnbTitle;
|
||||
case CryptoCurrency.usdterc20:
|
||||
return CryptoCurrency.usdt.title.toLowerCase();
|
||||
String normalizeCryptoCurrency(CryptoCurrency currency) {
|
||||
switch(currency) {
|
||||
case CryptoCurrency.zec:
|
||||
return 'zec';
|
||||
default:
|
||||
return currency.title.toLowerCase();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -250,14 +250,15 @@ class SideShiftExchangeProvider extends ExchangeProvider {
|
|||
String get title => 'SideShift';
|
||||
|
||||
static String normalizeCryptoCurrency(CryptoCurrency currency) {
|
||||
const bnbTitle = 'bsc';
|
||||
const usdterc20 = 'usdtErc20';
|
||||
|
||||
switch (currency) {
|
||||
case CryptoCurrency.zaddr:
|
||||
return 'zaddr';
|
||||
case CryptoCurrency.zec:
|
||||
return 'zec';
|
||||
case CryptoCurrency.bnb:
|
||||
return bnbTitle;
|
||||
return currency.tag.toLowerCase();
|
||||
case CryptoCurrency.usdterc20:
|
||||
return usdterc20;
|
||||
return 'usdtErc20';
|
||||
default:
|
||||
return currency.title.toLowerCase();
|
||||
}
|
||||
|
|
|
@ -297,9 +297,9 @@ class CWHaven extends Haven {
|
|||
}
|
||||
|
||||
CryptoCurrency assetOfTransaction(TransactionInfo tx) {
|
||||
final tx = transaction as HavenTransactionInfo;
|
||||
final asset = CryptoCurrency.fromString(tx.assetType);
|
||||
return asset;
|
||||
final transaction = tx as HavenTransactionInfo;
|
||||
final asset = CryptoCurrency.fromString(transaction.assetType);
|
||||
return asset;
|
||||
}
|
||||
|
||||
List<AssetRate> getAssetRate()
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
import 'package:cake_wallet/entities/contact_record.dart';
|
||||
import 'package:cake_wallet/buy/order.dart';
|
||||
import 'package:cake_wallet/entities/transaction_description.dart';
|
||||
import 'package:cake_wallet/src/screens/backup/backup_page.dart';
|
||||
import 'package:cake_wallet/src/screens/backup/edit_backup_password_page.dart';
|
||||
import 'package:cake_wallet/src/screens/buy/buy_webview_page.dart';
|
||||
|
@ -17,10 +16,7 @@ import 'package:cake_wallet/src/screens/seed/pre_seed_page.dart';
|
|||
import 'package:cake_wallet/src/screens/support/support_page.dart';
|
||||
import 'package:cake_wallet/src/screens/unspent_coins/unspent_coins_details_page.dart';
|
||||
import 'package:cake_wallet/src/screens/unspent_coins/unspent_coins_list_page.dart';
|
||||
import 'package:cake_wallet/store/settings_store.dart';
|
||||
import 'package:cake_wallet/view_model/buy/buy_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/monero_account_list/account_list_item.dart';
|
||||
import 'package:cake_wallet/view_model/unspent_coins/unspent_coins_item.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:cake_wallet/routes.dart';
|
||||
|
@ -30,7 +26,6 @@ import 'package:cake_wallet/utils/language_list.dart';
|
|||
import 'package:cake_wallet/view_model/wallet_new_vm.dart';
|
||||
import 'package:cake_wallet/view_model/wallet_restoration_from_seed_vm.dart';
|
||||
import 'package:cake_wallet/view_model/wallet_restoration_from_keys_vm.dart';
|
||||
import 'package:cake_wallet/entities/contact.dart';
|
||||
import 'package:cake_wallet/exchange/trade.dart';
|
||||
import 'package:cw_core/transaction_info.dart';
|
||||
import 'package:cw_core/wallet_type.dart';
|
||||
|
@ -56,7 +51,6 @@ import 'package:cake_wallet/src/screens/monero_accounts/monero_account_edit_or_c
|
|||
import 'package:cake_wallet/src/screens/contact/contact_list_page.dart';
|
||||
import 'package:cake_wallet/src/screens/contact/contact_page.dart';
|
||||
import 'package:cake_wallet/src/screens/wallet_keys/wallet_keys_page.dart';
|
||||
import 'package:cake_wallet/src/screens/settings/change_language.dart';
|
||||
import 'package:cake_wallet/src/screens/restore/restore_wallet_from_seed_details.dart';
|
||||
import 'package:cake_wallet/src/screens/exchange/exchange_page.dart';
|
||||
import 'package:cake_wallet/src/screens/settings/settings.dart';
|
||||
|
@ -70,10 +64,9 @@ import 'package:cake_wallet/src/screens/exchange/exchange_template_page.dart';
|
|||
import 'package:cake_wallet/src/screens/exchange_trade/exchange_confirm_page.dart';
|
||||
import 'package:cake_wallet/src/screens/exchange_trade/exchange_trade_page.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:hive/hive.dart';
|
||||
import 'package:cake_wallet/wallet_type_utils.dart';
|
||||
import 'package:cake_wallet/wallet_types.g.dart';
|
||||
import 'package:cake_wallet/src/screens/dashboard/widgets/address_page.dart';
|
||||
import 'package:cake_wallet/src/screens/receive/fullscreen_qr_page.dart';
|
||||
import 'package:cake_wallet/src/screens/ionia/ionia.dart';
|
||||
import 'package:cake_wallet/src/screens/ionia/cards/ionia_payment_status_page.dart';
|
||||
import 'package:cake_wallet/anypay/any_pay_payment_committed_info.dart';
|
||||
|
@ -83,7 +76,7 @@ RouteSettings currentRouteSettings;
|
|||
|
||||
Route<dynamic> createRoute(RouteSettings settings) {
|
||||
currentRouteSettings = settings;
|
||||
|
||||
|
||||
switch (settings.name) {
|
||||
case Routes.welcome:
|
||||
return MaterialPageRoute<void>(builder: (_) => createWelcomePage());
|
||||
|
@ -92,7 +85,7 @@ Route<dynamic> createRoute(RouteSettings settings) {
|
|||
return CupertinoPageRoute<void>(
|
||||
builder: (_) => getIt.get<SetupPinCodePage>(
|
||||
param1: (PinCodeState<PinCodeWidget> context, dynamic _) {
|
||||
if (availableWalletTypes.length == 1) {
|
||||
if (availableWalletTypes.length == 1) {
|
||||
Navigator.of(context.context).pushNamed(Routes.newWallet, arguments: availableWalletTypes.first);
|
||||
} else {
|
||||
Navigator.of(context.context).pushNamed(Routes.newWalletType);
|
||||
|
@ -373,10 +366,6 @@ Route<dynamic> createRoute(RouteSettings settings) {
|
|||
case Routes.faq:
|
||||
return MaterialPageRoute<void>(builder: (_) => getIt.get<FaqPage>());
|
||||
|
||||
case Routes.changeLanguage:
|
||||
return MaterialPageRoute<void>(
|
||||
builder: (_) => getIt.get<LanguageListPage>());
|
||||
|
||||
case Routes.preSeed:
|
||||
return MaterialPageRoute<void>(
|
||||
builder: (_) =>
|
||||
|
@ -410,6 +399,16 @@ Route<dynamic> createRoute(RouteSettings settings) {
|
|||
getIt.get<UnspentCoinsDetailsPage>(
|
||||
param1: args));
|
||||
|
||||
case Routes.fullscreenQR:
|
||||
final args = settings.arguments as Map<String, dynamic>;
|
||||
|
||||
return MaterialPageRoute<void>(
|
||||
builder: (_) =>
|
||||
getIt.get<FullscreenQRPage>(
|
||||
param1: args['qrData'] as String,
|
||||
param2: args['isLight'] as bool,
|
||||
));
|
||||
|
||||
case Routes.ioniaWelcomePage:
|
||||
return CupertinoPageRoute<void>(builder: (_) => getIt.get<IoniaWelcomePage>());
|
||||
|
||||
|
|
|
@ -41,7 +41,6 @@ class Routes {
|
|||
static const unlock = '/auth_not_closable';
|
||||
static const rescan = '/rescan';
|
||||
static const faq = '/faq';
|
||||
static const changeLanguage = '/change_language';
|
||||
static const newWalletType = '/new_wallet_type';
|
||||
static const sendTemplate = '/send_template';
|
||||
static const exchangeTemplate = '/exchange_template';
|
||||
|
@ -60,6 +59,7 @@ class Routes {
|
|||
static const moneroRestoreWalletFromWelcome = '/monero_restore_wallet';
|
||||
static const moneroNewWalletFromWelcome = '/monero_new_wallet';
|
||||
static const addressPage = '/address_page';
|
||||
static const fullscreenQR = '/fullscreen_qr';
|
||||
static const ioniaWelcomePage = '/cake_pay_welcome_page';
|
||||
static const ioniaCreateAccountPage = '/cake_pay_create_account_page';
|
||||
static const ioniaLoginPage = '/cake_pay_login_page';
|
||||
|
|
|
@ -2,6 +2,8 @@ import 'dart:ui';
|
|||
import 'package:cake_wallet/buy/buy_amount.dart';
|
||||
import 'package:cake_wallet/buy/buy_provider.dart';
|
||||
import 'package:cake_wallet/buy/moonpay/moonpay_buy_provider.dart';
|
||||
import 'package:cake_wallet/entities/fiat_currency.dart';
|
||||
import 'package:cake_wallet/src/widgets/picker.dart';
|
||||
import 'package:cw_core/wallet_type.dart';
|
||||
import 'package:cake_wallet/src/screens/buy/widgets/buy_list_item.dart';
|
||||
import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
|
||||
|
@ -27,7 +29,6 @@ class PreOrderPage extends BasePage {
|
|||
PreOrderPage({@required this.buyViewModel})
|
||||
: _amountFocus = FocusNode(),
|
||||
_amountController = TextEditingController() {
|
||||
|
||||
_amountController.addListener(() {
|
||||
final amount = _amountController.text;
|
||||
|
||||
|
@ -110,52 +111,70 @@ class PreOrderPage extends BasePage {
|
|||
.decorationColor,
|
||||
], begin: Alignment.topLeft, end: Alignment.bottomRight),
|
||||
),
|
||||
child: Padding(
|
||||
padding: EdgeInsets.only(top: 100, bottom: 65),
|
||||
child: Center(
|
||||
child: Container(
|
||||
width: 210,
|
||||
child: BaseTextFormField(
|
||||
focusNode: _amountFocus,
|
||||
controller: _amountController,
|
||||
keyboardType:
|
||||
TextInputType.numberWithOptions(
|
||||
signed: false, decimal: true),
|
||||
inputFormatters: [
|
||||
FilteringTextInputFormatter
|
||||
.allow(RegExp(_amountPattern))
|
||||
],
|
||||
prefixIcon: Padding(
|
||||
padding: EdgeInsets.only(top: 2),
|
||||
child:
|
||||
Text(buyViewModel.fiatCurrency.title + ': ',
|
||||
style: TextStyle(
|
||||
fontSize: 36,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Colors.white,
|
||||
)),
|
||||
),
|
||||
hintText: '0.00',
|
||||
borderColor: Theme.of(context)
|
||||
.primaryTextTheme
|
||||
.body2
|
||||
.decorationColor,
|
||||
borderWidth: 0.5,
|
||||
textStyle: TextStyle(
|
||||
child: Padding(
|
||||
padding: EdgeInsets.only(top: 100, bottom: 65),
|
||||
child: Center(
|
||||
child: Container(
|
||||
width: 210,
|
||||
child: BaseTextFormField(
|
||||
focusNode: _amountFocus,
|
||||
controller: _amountController,
|
||||
keyboardType: TextInputType.numberWithOptions(signed: false, decimal: true),
|
||||
inputFormatters: [FilteringTextInputFormatter.allow(RegExp(_amountPattern))],
|
||||
prefixIcon: GestureDetector(
|
||||
onTap: () {
|
||||
showPopUp<void>(
|
||||
context: context,
|
||||
builder: (_) => Picker(
|
||||
hintText: S.current.search_currency,
|
||||
items: FiatCurrency.currenciesAvailableToBuyWith,
|
||||
selectedAtIndex:
|
||||
FiatCurrency.currenciesAvailableToBuyWith.indexOf(buyViewModel.fiatCurrency),
|
||||
onItemSelected: (FiatCurrency selectedCurrency) {
|
||||
buyViewModel.buyAmountViewModel.fiatCurrency = selectedCurrency;
|
||||
},
|
||||
images: FiatCurrency.currenciesAvailableToBuyWith
|
||||
.map((e) => Image.asset("assets/images/flags/${e.countryCode}.png"))
|
||||
.toList(),
|
||||
isGridView: true,
|
||||
matchingCriteria: (FiatCurrency currency, String searchText) {
|
||||
return currency.title.toLowerCase().contains(searchText) ||
|
||||
currency.fullName.toLowerCase().contains(searchText);
|
||||
},
|
||||
),
|
||||
);
|
||||
},
|
||||
child: Padding(
|
||||
padding: EdgeInsets.only(top: 2),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Icon(Icons.keyboard_arrow_down, color: Colors.white),
|
||||
Text(
|
||||
buyViewModel.fiatCurrency.title + ': ',
|
||||
style: TextStyle(
|
||||
fontSize: 36,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Colors.white),
|
||||
placeholderTextStyle: TextStyle(
|
||||
color: Theme.of(context)
|
||||
.primaryTextTheme
|
||||
.headline
|
||||
.decorationColor,
|
||||
fontWeight: FontWeight.w500,
|
||||
fontSize: 36),
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
hintText: '0.00',
|
||||
borderColor: Theme.of(context).primaryTextTheme.body2.decorationColor,
|
||||
borderWidth: 0.5,
|
||||
textStyle: TextStyle(fontSize: 36, fontWeight: FontWeight.w500, color: Colors.white),
|
||||
placeholderTextStyle: TextStyle(
|
||||
color: Theme.of(context).primaryTextTheme.headline.decorationColor,
|
||||
fontWeight: FontWeight.w500,
|
||||
fontSize: 36,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
if (buyViewModel.isShowProviderButtons) Padding(
|
||||
padding: EdgeInsets.only(top: 38, bottom: 18),
|
||||
|
@ -273,7 +292,7 @@ class PreOrderPage extends BasePage {
|
|||
|
||||
buyViewModel.isRunning = true;
|
||||
final url = await buyViewModel.fetchUrl();
|
||||
|
||||
|
||||
if (url.isNotEmpty) {
|
||||
if (buyViewModel.selectedProvider is MoonPayBuyProvider) {
|
||||
if (await canLaunch(url)) await launch(url);
|
||||
|
@ -287,4 +306,4 @@ class PreOrderPage extends BasePage {
|
|||
buyViewModel.reset();
|
||||
buyViewModel.isRunning = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -94,7 +94,10 @@ class ContactPage extends BasePage {
|
|||
child: Observer(
|
||||
builder: (_) => AddressTextField(
|
||||
controller: _addressController,
|
||||
options: [AddressTextFieldOption.qrCode],
|
||||
options: [
|
||||
AddressTextFieldOption.paste,
|
||||
AddressTextFieldOption.qrCode,
|
||||
],
|
||||
buttonColor: Theme.of(context).accentTextTheme.display2.color,
|
||||
iconColor: PaletteDark.gray,
|
||||
borderColor: Theme.of(context).primaryTextTheme.title.backgroundColor,
|
||||
|
@ -147,6 +150,7 @@ class ContactPage extends BasePage {
|
|||
contactViewModel.currencies.indexOf(contactViewModel.currency),
|
||||
items: contactViewModel.currencies,
|
||||
title: S.of(context).please_select,
|
||||
hintText: S.of(context).search_currency,
|
||||
onItemSelected: (CryptoCurrency item) =>
|
||||
contactViewModel.currency = item),
|
||||
context: context);
|
||||
|
|
|
@ -52,24 +52,6 @@ class WalletMenu {
|
|||
image: Image.asset('assets/images/open_book_menu.png',
|
||||
height: 16, width: 16),
|
||||
handler: () => Navigator.of(context).pushNamed(Routes.addressBook)),
|
||||
WalletMenuItem(
|
||||
title: S.current.backup,
|
||||
image: Image.asset('assets/images/restore_wallet.png',
|
||||
height: 16,
|
||||
width: 16,
|
||||
color: Palette.darkBlue),
|
||||
handler: () {
|
||||
Navigator
|
||||
.of(context)
|
||||
.pushNamed(
|
||||
Routes.auth,
|
||||
arguments: (bool isAuthenticatedSuccessfully, AuthPageState auth) {
|
||||
if (isAuthenticatedSuccessfully) {
|
||||
auth.close();
|
||||
Navigator.of(auth.context).pushNamed(Routes.backup);
|
||||
}
|
||||
});
|
||||
}),
|
||||
WalletMenuItem(
|
||||
title: S.current.settings_title,
|
||||
image: Image.asset('assets/images/settings_menu.png',
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
import 'dart:ui';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/palette.dart';
|
||||
import 'package:cake_wallet/src/screens/exchange/widgets/currency_utils.dart';
|
||||
import 'package:cake_wallet/src/screens/exchange/widgets/currency_picker_item_widget.dart';
|
||||
import 'package:cake_wallet/src/screens/exchange/widgets/picker_item.dart';
|
||||
import 'package:cake_wallet/src/widgets/alert_close_button.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:cw_core/crypto_currency.dart';
|
||||
|
@ -13,8 +12,9 @@ class CurrencyPicker extends StatefulWidget {
|
|||
CurrencyPicker(
|
||||
{@required this.selectedAtIndex,
|
||||
@required this.items,
|
||||
@required this.title,
|
||||
@required this.onItemSelected,
|
||||
this.title,
|
||||
this.hintText,
|
||||
this.isMoneroWallet = false,
|
||||
this.isConvertFrom = false});
|
||||
|
||||
|
@ -24,6 +24,7 @@ class CurrencyPicker extends StatefulWidget {
|
|||
final Function(CryptoCurrency) onItemSelected;
|
||||
final bool isMoneroWallet;
|
||||
final bool isConvertFrom;
|
||||
final String hintText;
|
||||
|
||||
@override
|
||||
CurrencyPickerState createState() => CurrencyPickerState(items);
|
||||
|
@ -33,169 +34,137 @@ class CurrencyPickerState extends State<CurrencyPicker> {
|
|||
CurrencyPickerState(this.items)
|
||||
: isSearchBarActive = false,
|
||||
textFieldValue = '',
|
||||
subPickerItemsList = [],
|
||||
appBarTextStyle = TextStyle(
|
||||
fontSize: 20,
|
||||
fontFamily: 'Lato',
|
||||
backgroundColor: Colors.transparent,
|
||||
color: Colors.white);
|
||||
subPickerItemsList = items,
|
||||
appBarTextStyle =
|
||||
TextStyle(fontSize: 20, fontFamily: 'Lato', backgroundColor: Colors.transparent, color: Colors.white);
|
||||
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
pickerItemsList = CryptoCurrency.all
|
||||
.map((CryptoCurrency cur) => PickerItem<CryptoCurrency>(cur,
|
||||
title: CurrencyUtils.titleForCurrency(cur),
|
||||
iconPath: CurrencyUtils.iconPathForCurrency(cur),
|
||||
tag: CurrencyUtils.tagForCurrency(cur),
|
||||
description: CurrencyUtils.descriptionForCurrency(cur)))
|
||||
.toList();
|
||||
cleanSubPickerItemsList();
|
||||
super.initState();
|
||||
}
|
||||
|
||||
List<PickerItem<CryptoCurrency>> pickerItemsList;
|
||||
List<CryptoCurrency> items;
|
||||
bool isSearchBarActive;
|
||||
String textFieldValue;
|
||||
List<PickerItem<CryptoCurrency>> subPickerItemsList;
|
||||
List<CryptoCurrency> subPickerItemsList;
|
||||
TextStyle appBarTextStyle;
|
||||
|
||||
void cleanSubPickerItemsList() {
|
||||
subPickerItemsList = pickerItemsList
|
||||
.where((element) => items.contains(element.original))
|
||||
.toList();
|
||||
}
|
||||
void cleanSubPickerItemsList() => subPickerItemsList = items;
|
||||
|
||||
void currencySearchBySubstring(
|
||||
String subString, List<PickerItem<CryptoCurrency>> list) {
|
||||
void currencySearchBySubstring(String subString) {
|
||||
setState(() {
|
||||
if (subString.isNotEmpty) {
|
||||
subPickerItemsList = subPickerItemsList
|
||||
subPickerItemsList = items
|
||||
.where((element) =>
|
||||
element.title.contains(subString.toUpperCase()) ||
|
||||
element.description.contains(subString.toLowerCase()))
|
||||
(element.title != null ? element.title.toLowerCase().contains(subString.toLowerCase()) : false) ||
|
||||
(element.tag != null ? element.tag.toLowerCase().contains(subString.toLowerCase()) : false) ||
|
||||
(element.name != null ? element.name.toLowerCase().contains(subString.toLowerCase()) : false))
|
||||
.toList();
|
||||
} else {
|
||||
cleanSubPickerItemsList();
|
||||
return;
|
||||
}
|
||||
cleanSubPickerItemsList();
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return AlertBackground(
|
||||
child: SafeArea(
|
||||
child: Scaffold(
|
||||
resizeToAvoidBottomInset: false,
|
||||
backgroundColor: Colors.transparent,
|
||||
body: Column(
|
||||
children: [
|
||||
Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 26.0, vertical: 0),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
isSearchBarActive
|
||||
? Expanded(
|
||||
child: Row(
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
InkWell(
|
||||
child: Text(
|
||||
S.of(context).cancel,
|
||||
style: appBarTextStyle,
|
||||
),
|
||||
onTap: () {
|
||||
setState(() {
|
||||
isSearchBarActive = false;
|
||||
textFieldValue = '';
|
||||
cleanSubPickerItemsList();
|
||||
});
|
||||
}),
|
||||
Container(
|
||||
width: 100.0,
|
||||
child: CupertinoTextField(
|
||||
autofocus: true,
|
||||
placeholder:
|
||||
S.of(context).search + '...',
|
||||
placeholderStyle: appBarTextStyle,
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.transparent),
|
||||
cursorColor: Colors.white,
|
||||
cursorHeight: 23.0,
|
||||
style: appBarTextStyle,
|
||||
onChanged: (value) {
|
||||
this.textFieldValue = value;
|
||||
cleanSubPickerItemsList();
|
||||
currencySearchBySubstring(
|
||||
textFieldValue,
|
||||
subPickerItemsList);
|
||||
}),
|
||||
)
|
||||
],
|
||||
),
|
||||
)
|
||||
: Text(
|
||||
widget.title,
|
||||
style: appBarTextStyle,
|
||||
),
|
||||
IconButton(
|
||||
splashRadius: 23,
|
||||
icon: Icon(Icons.search, color: Colors.white),
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
isSearchBarActive = true;
|
||||
});
|
||||
},
|
||||
)
|
||||
]),
|
||||
),
|
||||
Expanded(
|
||||
flex: 12,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 26.0, vertical: 26.0),
|
||||
child: Container(
|
||||
child: CurrencyPickerWidget(
|
||||
crossAxisCount: 2,
|
||||
selectedAtIndex: widget.selectedAtIndex,
|
||||
itemsCount: subPickerItemsList.length,
|
||||
pickerItemsList: subPickerItemsList,
|
||||
pickListItem: (int index) {
|
||||
setState(() {
|
||||
widget.selectedAtIndex = index;
|
||||
});
|
||||
widget
|
||||
.onItemSelected(subPickerItemsList[index].original);
|
||||
if (widget.isConvertFrom &&
|
||||
!widget.isMoneroWallet &&
|
||||
(subPickerItemsList[index].original ==
|
||||
CryptoCurrency.xmr)) {
|
||||
} else {
|
||||
Navigator.of(context).pop();
|
||||
}
|
||||
},
|
||||
child: Stack(
|
||||
alignment: Alignment.center,
|
||||
children: [
|
||||
Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: <Widget>[
|
||||
if (widget.title?.isNotEmpty ?? false)
|
||||
Container(
|
||||
padding: EdgeInsets.symmetric(horizontal: 24),
|
||||
child: Text(
|
||||
widget.title,
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
fontFamily: 'Lato',
|
||||
fontWeight: FontWeight.bold,
|
||||
decoration: TextDecoration.none,
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: Container(
|
||||
width: 42.0,
|
||||
alignment: Alignment.topCenter,
|
||||
child: FittedBox(
|
||||
child: FloatingActionButton(
|
||||
elevation: 0,
|
||||
backgroundColor: Colors.white,
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
child: Icon(
|
||||
Icons.close_outlined,
|
||||
color: Palette.darkBlueCraiola,
|
||||
size: 30.0,
|
||||
Padding(
|
||||
padding: EdgeInsets.only(left: 24, right: 24, top: 24),
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.all(Radius.circular(30)),
|
||||
child: Container(
|
||||
color: Theme.of(context).accentTextTheme.title.color,
|
||||
child: ConstrainedBox(
|
||||
constraints: BoxConstraints(
|
||||
maxHeight: MediaQuery.of(context).size.height * 0.65,
|
||||
),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
if (widget.hintText != null)
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: TextFormField(
|
||||
style: TextStyle(color: Theme.of(context).primaryTextTheme.title.color),
|
||||
decoration: InputDecoration(
|
||||
hintText: widget.hintText,
|
||||
prefixIcon: Image.asset("assets/images/search_icon.png"),
|
||||
filled: true,
|
||||
fillColor: const Color(0xffF2F0FA),
|
||||
alignLabelWithHint: false,
|
||||
contentPadding: const EdgeInsets.symmetric(vertical: 4, horizontal: 16),
|
||||
enabledBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(14),
|
||||
borderSide: const BorderSide(
|
||||
color: Colors.transparent,
|
||||
)),
|
||||
focusedBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(14),
|
||||
borderSide: const BorderSide(
|
||||
color: Colors.transparent,
|
||||
)),
|
||||
),
|
||||
onChanged: (value) {
|
||||
this.textFieldValue = value;
|
||||
cleanSubPickerItemsList();
|
||||
currencySearchBySubstring(textFieldValue);
|
||||
},
|
||||
),
|
||||
),
|
||||
Divider(
|
||||
color: Theme.of(context).accentTextTheme.title.backgroundColor,
|
||||
height: 1,
|
||||
),
|
||||
if (widget.selectedAtIndex != -1)
|
||||
AspectRatio(
|
||||
aspectRatio: 6,
|
||||
child: PickerItemWidget(
|
||||
title: items[widget.selectedAtIndex].title,
|
||||
iconPath: items[widget.selectedAtIndex].iconPath,
|
||||
isSelected: true,
|
||||
tag: items[widget.selectedAtIndex].tag,
|
||||
),
|
||||
),
|
||||
Flexible(
|
||||
child: CurrencyPickerWidget(
|
||||
crossAxisCount: 2,
|
||||
selectedAtIndex: widget.selectedAtIndex,
|
||||
pickerItemsList: subPickerItemsList,
|
||||
pickListItem: (int index) {
|
||||
setState(() {
|
||||
widget.selectedAtIndex = index;
|
||||
});
|
||||
widget.onItemSelected(subPickerItemsList[index]);
|
||||
if (widget.isConvertFrom &&
|
||||
!widget.isMoneroWallet &&
|
||||
(subPickerItemsList[index] == CryptoCurrency.xmr)) {
|
||||
} else {
|
||||
Navigator.of(context).pop();
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
|
@ -203,7 +172,8 @@ class CurrencyPickerState extends State<CurrencyPicker> {
|
|||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
AlertCloseButton(),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
|
|
@ -2,8 +2,7 @@ import 'package:flutter/material.dart';
|
|||
import 'package:cake_wallet/palette.dart';
|
||||
|
||||
class PickerItemWidget extends StatelessWidget {
|
||||
const PickerItemWidget(
|
||||
{this.iconPath, this.title, this.isSelected, this.tag, this.onTap});
|
||||
const PickerItemWidget({this.iconPath, this.title, this.isSelected = false, this.tag, this.onTap});
|
||||
|
||||
final String iconPath;
|
||||
final String title;
|
||||
|
@ -16,74 +15,56 @@ class PickerItemWidget extends StatelessWidget {
|
|||
return GestureDetector(
|
||||
onTap: onTap,
|
||||
child: Container(
|
||||
color: isSelected
|
||||
? Theme.of(context).textTheme.bodyText1.color
|
||||
: Theme.of(context).accentTextTheme.headline6.color,
|
||||
child: Center(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Expanded(
|
||||
child: Container(
|
||||
child: Image.asset(
|
||||
iconPath,
|
||||
height: 32.0,
|
||||
width: 32.0,
|
||||
),
|
||||
),
|
||||
color: Theme.of(context).accentTextTheme.headline6.color,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 8.0, horizontal: 24),
|
||||
child: Row(
|
||||
children: [
|
||||
Container(
|
||||
child: Image.asset(
|
||||
iconPath,
|
||||
height: 20.0,
|
||||
width: 20.0,
|
||||
),
|
||||
Expanded(
|
||||
child: Stack(
|
||||
clipBehavior: Clip.none,
|
||||
alignment: Alignment.centerLeft,
|
||||
children: [
|
||||
Text(
|
||||
title,
|
||||
style: TextStyle(
|
||||
color: isSelected
|
||||
? Palette.blueCraiola
|
||||
: Theme.of(context).primaryTextTheme.title.color,
|
||||
fontSize: 18.0,
|
||||
fontFamily: 'Lato',
|
||||
),
|
||||
const SizedBox(width: 6),
|
||||
Expanded(
|
||||
child: Row(
|
||||
children: [
|
||||
Text(
|
||||
title,
|
||||
style: TextStyle(
|
||||
color: isSelected ? Palette.blueCraiola : Theme.of(context).primaryTextTheme.title.color,
|
||||
fontSize: isSelected ? 16 : 14.0,
|
||||
fontFamily: 'Lato',
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
if (tag != null)
|
||||
Align(
|
||||
alignment: Alignment.topCenter,
|
||||
child: Container(
|
||||
width: 35.0,
|
||||
height: 18.0,
|
||||
child: Center(
|
||||
child: Text(
|
||||
tag,
|
||||
style: TextStyle(
|
||||
fontSize: 7.0, fontFamily: 'Lato', color: Theme.of(context).textTheme.body1.color),
|
||||
),
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(6.0),
|
||||
//border: Border.all(color: ),
|
||||
color: Theme.of(context).textTheme.body1.decorationColor,
|
||||
),
|
||||
),
|
||||
),
|
||||
tag != null
|
||||
? Positioned(
|
||||
top: -20.0,
|
||||
right: 7.0,
|
||||
child: Container(
|
||||
width: 35.0,
|
||||
height: 18.0,
|
||||
child: Center(
|
||||
child: Text(
|
||||
tag,
|
||||
style: TextStyle(
|
||||
fontSize: 7.0,
|
||||
fontFamily: 'Lato',
|
||||
color: Theme.of(context)
|
||||
.textTheme
|
||||
.body1
|
||||
.color),
|
||||
),
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(6.0),
|
||||
//border: Border.all(color: ),
|
||||
color: Theme.of(context)
|
||||
.textTheme
|
||||
.body1
|
||||
.decorationColor,
|
||||
),
|
||||
),
|
||||
)
|
||||
: Container(),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
if (isSelected) Icon(Icons.check_circle, color: Theme.of(context).accentTextTheme.body2.color)
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
|
|
|
@ -4,58 +4,47 @@ import 'picker_item.dart';
|
|||
import 'currency_picker_item_widget.dart';
|
||||
|
||||
class CurrencyPickerWidget extends StatelessWidget {
|
||||
const CurrencyPickerWidget({
|
||||
CurrencyPickerWidget({
|
||||
@required this.crossAxisCount,
|
||||
@required this.selectedAtIndex,
|
||||
@required this.itemsCount,
|
||||
@required this.pickerItemsList,
|
||||
@required this.pickListItem,
|
||||
});
|
||||
|
||||
final int crossAxisCount;
|
||||
final int selectedAtIndex;
|
||||
final int itemsCount;
|
||||
final Function pickListItem;
|
||||
final List<PickerItem<CryptoCurrency>> pickerItemsList;
|
||||
final List<CryptoCurrency> pickerItemsList;
|
||||
|
||||
final ScrollController _scrollController = ScrollController();
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return LayoutBuilder(
|
||||
builder: (BuildContext context, BoxConstraints constraints) {
|
||||
return Container(
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context).accentTextTheme.headline6.backgroundColor,
|
||||
borderRadius: BorderRadius.circular(14.0),
|
||||
),
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.circular(14.0),
|
||||
child: Scrollbar(
|
||||
showTrackOnHover: true,
|
||||
isAlwaysShown: true,
|
||||
thickness: 6.0,
|
||||
radius: Radius.circular(3),
|
||||
child: GridView.builder(
|
||||
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
|
||||
crossAxisCount: crossAxisCount,
|
||||
crossAxisSpacing: 1,
|
||||
mainAxisExtent: constraints.maxHeight / 8,
|
||||
mainAxisSpacing: 1),
|
||||
itemCount: pickerItemsList.length,
|
||||
itemBuilder: (BuildContext ctx, index) {
|
||||
return PickerItemWidget(
|
||||
onTap: () {
|
||||
pickListItem(index);
|
||||
},
|
||||
title: pickerItemsList[index].title,
|
||||
iconPath: pickerItemsList[index].iconPath,
|
||||
isSelected: index == selectedAtIndex,
|
||||
tag: pickerItemsList[index].tag,
|
||||
);
|
||||
}),
|
||||
return Container(
|
||||
color: Theme.of(context).accentTextTheme.headline6.backgroundColor,
|
||||
child: Scrollbar(
|
||||
controller: _scrollController,
|
||||
child: GridView.builder(
|
||||
controller: _scrollController,
|
||||
padding: EdgeInsets.zero,
|
||||
shrinkWrap: true,
|
||||
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
|
||||
crossAxisCount: crossAxisCount,
|
||||
crossAxisSpacing: 2,
|
||||
childAspectRatio: 3,
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
itemCount: pickerItemsList.length,
|
||||
itemBuilder: (BuildContext ctx, index) {
|
||||
return PickerItemWidget(
|
||||
onTap: () {
|
||||
pickListItem(index);
|
||||
},
|
||||
title: pickerItemsList[index].title,
|
||||
iconPath: pickerItemsList[index].iconPath,
|
||||
tag: pickerItemsList[index].tag,
|
||||
);
|
||||
}),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,101 +0,0 @@
|
|||
import 'package:cw_core/crypto_currency.dart';
|
||||
|
||||
class CurrencyUtils {
|
||||
static String tagForCurrency(CryptoCurrency cur) {
|
||||
switch (cur) {
|
||||
case CryptoCurrency.bnb:
|
||||
return 'BEP2';
|
||||
case CryptoCurrency.dai:
|
||||
return 'ETH';
|
||||
case CryptoCurrency.usdt:
|
||||
return 'OMNI';
|
||||
case CryptoCurrency.usdterc20:
|
||||
return 'ETH';
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
static String iconPathForCurrency(CryptoCurrency cur) {
|
||||
switch (cur) {
|
||||
case CryptoCurrency.xmr:
|
||||
return 'assets/images/monero_icon.png';
|
||||
case CryptoCurrency.ada:
|
||||
return 'assets/images/ada_icon.png';
|
||||
case CryptoCurrency.bch:
|
||||
return 'assets/images/bch_icon.png';
|
||||
case CryptoCurrency.bnb:
|
||||
return 'assets/images/bnb_icon.png';
|
||||
case CryptoCurrency.btc:
|
||||
return 'assets/images/btc.png';
|
||||
case CryptoCurrency.dai:
|
||||
return 'assets/images/dai_icon.png';
|
||||
case CryptoCurrency.dash:
|
||||
return 'assets/images/dash_icon.png';
|
||||
case CryptoCurrency.eos:
|
||||
return 'assets/images/eos_icon.png';
|
||||
case CryptoCurrency.eth:
|
||||
return 'assets/images/eth_icon.png';
|
||||
case CryptoCurrency.ltc:
|
||||
return 'assets/images/litecoin-ltc_icon.png';
|
||||
case CryptoCurrency.trx:
|
||||
return 'assets/images/trx_icon.png';
|
||||
case CryptoCurrency.usdt:
|
||||
return 'assets/images/usdt_icon.png';
|
||||
case CryptoCurrency.usdterc20:
|
||||
return 'assets/images/usdterc20_icon.png';
|
||||
case CryptoCurrency.xlm:
|
||||
return 'assets/images/xlm_icon.png';
|
||||
case CryptoCurrency.xrp:
|
||||
return 'assets/images/xrp_icon.png';
|
||||
case CryptoCurrency.xhv:
|
||||
return 'assets/images/xhv_logo.png';
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
static String titleForCurrency(CryptoCurrency cur) {
|
||||
switch (cur) {
|
||||
case CryptoCurrency.bnb:
|
||||
return 'BNB';
|
||||
case CryptoCurrency.usdterc20:
|
||||
return 'USDT';
|
||||
default:
|
||||
return cur.title;
|
||||
}
|
||||
}
|
||||
|
||||
static String descriptionForCurrency(CryptoCurrency cur) {
|
||||
switch (cur) {
|
||||
case CryptoCurrency.xmr:
|
||||
return 'monero';
|
||||
case CryptoCurrency.ada:
|
||||
return 'cardano';
|
||||
case CryptoCurrency.bch:
|
||||
return 'bitcoin cash';
|
||||
case CryptoCurrency.bnb:
|
||||
return 'binance bep2';
|
||||
case CryptoCurrency.btc:
|
||||
return 'bitcoin';
|
||||
case CryptoCurrency.dai:
|
||||
return 'dai eth';
|
||||
case CryptoCurrency.eth:
|
||||
return 'ethereum';
|
||||
case CryptoCurrency.ltc:
|
||||
return 'litecoin';
|
||||
case CryptoCurrency.trx:
|
||||
return 'tron';
|
||||
case CryptoCurrency.usdt:
|
||||
return 'usdt omni';
|
||||
case CryptoCurrency.usdterc20:
|
||||
return 'tether ERC20 eth';
|
||||
case CryptoCurrency.xlm:
|
||||
return 'lumens';
|
||||
case CryptoCurrency.xrp:
|
||||
return 'ripple';
|
||||
default:
|
||||
return cur.title;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -176,7 +176,7 @@ class ExchangeCardState extends State<ExchangeCard> {
|
|||
padding: EdgeInsets.only(right: 5),
|
||||
child: widget.imageArrow,
|
||||
),
|
||||
Text(_selectedCurrency.toString() + ':',
|
||||
Text(_selectedCurrency.toString(),
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.w600,
|
||||
fontSize: 16,
|
||||
|
@ -184,6 +184,40 @@ class ExchangeCardState extends State<ExchangeCard> {
|
|||
]),
|
||||
),
|
||||
),
|
||||
_selectedCurrency.tag != null ? Padding(
|
||||
padding: const EdgeInsets.only(right:3.0),
|
||||
child: Container(
|
||||
height: 32,
|
||||
decoration: BoxDecoration(
|
||||
color: widget.addressButtonsColor ?? Theme.of(context)
|
||||
.primaryTextTheme
|
||||
.display1
|
||||
.color,
|
||||
borderRadius:
|
||||
BorderRadius.all(Radius.circular(6))),
|
||||
child: Center(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(6.0),
|
||||
child: Text(_selectedCurrency.tag,
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Theme.of(context)
|
||||
.primaryTextTheme
|
||||
.display1
|
||||
.decorationColor)),
|
||||
),
|
||||
),
|
||||
),
|
||||
) : Container(),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(right: 4.0),
|
||||
child: Text(':',
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.w600,
|
||||
fontSize: 16,
|
||||
color: Colors.white)),
|
||||
),
|
||||
Expanded(
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
|
@ -316,9 +350,10 @@ class ExchangeCardState extends State<ExchangeCard> {
|
|||
|
||||
if (amountController.text.isNotEmpty) {
|
||||
_showAmountPopup(context, paymentRequest);
|
||||
} else {
|
||||
amountController.text = paymentRequest.amount;
|
||||
return;
|
||||
}
|
||||
widget.amountFocusNode.requestFocus();
|
||||
amountController.text = paymentRequest.amount;
|
||||
},
|
||||
placeholder: widget.hasRefundAddress
|
||||
? S.of(context).refund_address
|
||||
|
@ -445,7 +480,7 @@ class ExchangeCardState extends State<ExchangeCard> {
|
|||
builder: (_) => CurrencyPicker(
|
||||
selectedAtIndex: widget.currencies.indexOf(_selectedCurrency),
|
||||
items: widget.currencies,
|
||||
title: S.of(context).change_currency,
|
||||
hintText: S.of(context).search_currency,
|
||||
isMoneroWallet: _isMoneroWallet,
|
||||
isConvertFrom: widget.hasRefundAddress,
|
||||
onItemSelected: (CryptoCurrency item) =>
|
||||
|
@ -465,6 +500,7 @@ class ExchangeCardState extends State<ExchangeCard> {
|
|||
rightButtonText: S.of(context).ok,
|
||||
leftButtonText: S.of(context).cancel,
|
||||
actionRightButton: () {
|
||||
widget.amountFocusNode.requestFocus();
|
||||
amountController.text = paymentRequest.amount;
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
|
|
|
@ -258,7 +258,7 @@ class _SearchWidget extends StatelessWidget {
|
|||
final searchIcon = Padding(
|
||||
padding: EdgeInsets.all(8),
|
||||
child: Image.asset(
|
||||
'assets/images/search_icon.png',
|
||||
'assets/images/mini_search_icon.png',
|
||||
color: Theme.of(context).textTheme.caption.decorationColor,
|
||||
),
|
||||
);
|
||||
|
|
|
@ -23,7 +23,7 @@ class IoniaFilterModal extends StatelessWidget {
|
|||
final searchIcon = Padding(
|
||||
padding: EdgeInsets.all(10),
|
||||
child: Image.asset(
|
||||
'assets/images/search_icon.png',
|
||||
'assets/images/mini_search_icon.png',
|
||||
color: Theme.of(context).accentColor,
|
||||
),
|
||||
);
|
||||
|
|
|
@ -7,7 +7,7 @@ import 'package:flutter_mobx/flutter_mobx.dart';
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/core/validator.dart';
|
||||
import 'package:cake_wallet/core/wallet_name_validator.dart';
|
||||
import 'package:cake_wallet/src/widgets/seed_language_selector.dart';
|
||||
import 'package:cake_wallet/src/screens/base_page.dart';
|
||||
import 'package:cake_wallet/src/widgets/primary_button.dart';
|
||||
|
@ -218,10 +218,21 @@ class _WalletNameFormState extends State<WalletNameForm> {
|
|||
if (!_formKey.currentState.validate()) {
|
||||
return;
|
||||
}
|
||||
|
||||
_walletNewVM.create(
|
||||
options: _walletNewVM.hasLanguageSelector
|
||||
? _languageSelectorKey.currentState.selected
|
||||
: null);
|
||||
if (_walletNewVM.nameExists(_walletNewVM.name)) {
|
||||
showPopUp<void>(
|
||||
context: context,
|
||||
builder: (_) {
|
||||
return AlertWithOneAction(
|
||||
alertTitle: '',
|
||||
alertContent: S.of(context).wallet_name_exists,
|
||||
buttonText: S.of(context).ok,
|
||||
buttonAction: () => Navigator.of(context).pop());
|
||||
});
|
||||
} else {
|
||||
_walletNewVM.create(
|
||||
options: _walletNewVM.hasLanguageSelector
|
||||
? _languageSelectorKey.currentState.selected
|
||||
: null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
85
lib/src/screens/receive/fullscreen_qr_page.dart
Normal file
|
@ -0,0 +1,85 @@
|
|||
import 'package:cake_wallet/src/screens/receive/widgets/qr_image.dart';
|
||||
import 'package:cake_wallet/themes/theme_base.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:cake_wallet/src/screens/base_page.dart';
|
||||
|
||||
class FullscreenQRPage extends BasePage {
|
||||
FullscreenQRPage({@required this.qrData, @required this.isLight});
|
||||
|
||||
final bool isLight;
|
||||
final String qrData;
|
||||
|
||||
@override
|
||||
Color get backgroundLightColor => currentTheme.type == ThemeType.bright ? Colors.transparent : Colors.white;
|
||||
|
||||
@override
|
||||
Color get backgroundDarkColor => Colors.transparent;
|
||||
|
||||
@override
|
||||
bool get resizeToAvoidBottomInset => false;
|
||||
|
||||
@override
|
||||
Widget leading(BuildContext context) {
|
||||
final _backButton = Icon(
|
||||
Icons.arrow_back_ios,
|
||||
color: Theme.of(context).accentTextTheme.display3.backgroundColor,
|
||||
size: 16,
|
||||
);
|
||||
|
||||
return SizedBox(
|
||||
height: 37,
|
||||
width: 37,
|
||||
child: ButtonTheme(
|
||||
minWidth: double.minPositive,
|
||||
child: FlatButton(
|
||||
highlightColor: Colors.transparent,
|
||||
splashColor: Colors.transparent,
|
||||
padding: EdgeInsets.all(0),
|
||||
onPressed: () => onClose(context),
|
||||
child: _backButton,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget Function(BuildContext, Widget) get rootWrapper => (BuildContext context, Widget scaffold) => Container(
|
||||
decoration: BoxDecoration(
|
||||
gradient: LinearGradient(
|
||||
colors: [
|
||||
Theme.of(context).accentColor,
|
||||
Theme.of(context).scaffoldBackgroundColor,
|
||||
Theme.of(context).primaryColor,
|
||||
],
|
||||
begin: Alignment.topRight,
|
||||
end: Alignment.bottomLeft,
|
||||
),
|
||||
),
|
||||
child: scaffold);
|
||||
|
||||
@override
|
||||
Widget body(BuildContext context) {
|
||||
return Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: MediaQuery.of(context).size.width * 0.05),
|
||||
child: Hero(
|
||||
tag: Key(qrData),
|
||||
child: Center(
|
||||
child: AspectRatio(
|
||||
aspectRatio: 1.0,
|
||||
child: Container(
|
||||
padding: EdgeInsets.all(5),
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(width: 3, color: Theme.of(context).accentTextTheme.display3.backgroundColor)),
|
||||
child: QrImage(
|
||||
data: qrData,
|
||||
backgroundColor: isLight ? Colors.transparent : Colors.black,
|
||||
foregroundColor: Theme.of(context).accentTextTheme.display3.backgroundColor,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -1,4 +1,6 @@
|
|||
import 'package:cake_wallet/routes.dart';
|
||||
import 'package:cake_wallet/utils/show_bar.dart';
|
||||
import 'package:device_display_brightness/device_display_brightness.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
|
@ -38,101 +40,134 @@ class QRWidget extends StatelessWidget {
|
|||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
Row(children: <Widget>[
|
||||
Spacer(flex: 3),
|
||||
Observer(
|
||||
builder: (_) => Flexible(
|
||||
flex: 5,
|
||||
child: Center(
|
||||
child: AspectRatio(
|
||||
aspectRatio: 1.0,
|
||||
child: Container(
|
||||
padding: EdgeInsets.all(5),
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(
|
||||
width: 3,
|
||||
color: Theme.of(context).accentTextTheme.
|
||||
display3.backgroundColor
|
||||
)
|
||||
),
|
||||
child: QrImage(
|
||||
data: addressListViewModel.uri.toString(),
|
||||
backgroundColor: isLight ? Colors.transparent : Colors.black,
|
||||
foregroundColor: Theme.of(context).accentTextTheme.
|
||||
display3.backgroundColor,
|
||||
),
|
||||
))))),
|
||||
Spacer(flex: 3)
|
||||
]),
|
||||
if (isAmountFieldShow)
|
||||
Column(
|
||||
children: [
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: 10),
|
||||
child: Row(
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: Form(
|
||||
key: _formKey,
|
||||
child: BaseTextFormField(
|
||||
focusNode: amountTextFieldFocusNode,
|
||||
controller: amountController,
|
||||
keyboardType: TextInputType.numberWithOptions(
|
||||
decimal: true),
|
||||
inputFormatters: [
|
||||
BlacklistingTextInputFormatter(
|
||||
RegExp('[\\-|\\ ]'))
|
||||
],
|
||||
textAlign: TextAlign.center,
|
||||
hintText: S.of(context).receive_amount,
|
||||
textColor: Theme.of(context).accentTextTheme.
|
||||
display3.backgroundColor,
|
||||
borderColor: Theme.of(context)
|
||||
.textTheme
|
||||
.headline
|
||||
.decorationColor,
|
||||
validator: AmountValidator(
|
||||
type: addressListViewModel.type,
|
||||
isAutovalidate: true),
|
||||
autovalidate: true,
|
||||
placeholderTextStyle: TextStyle(
|
||||
color: Theme.of(context).hoverColor,
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.w500))))
|
||||
],
|
||||
),
|
||||
padding: const EdgeInsets.only(bottom: 12),
|
||||
child: Text(
|
||||
S.of(context).qr_fullscreen,
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Theme.of(context).accentTextTheme.display3.backgroundColor),
|
||||
),
|
||||
),
|
||||
Row(
|
||||
children: <Widget>[
|
||||
Spacer(flex: 3),
|
||||
Observer(
|
||||
builder: (_) => Flexible(
|
||||
flex: 5,
|
||||
child: GestureDetector(
|
||||
onTap: () async {
|
||||
// Get the current brightness:
|
||||
final double brightness = await DeviceDisplayBrightness.getBrightness();
|
||||
|
||||
// ignore: unawaited_futures
|
||||
DeviceDisplayBrightness.setBrightness(1.0);
|
||||
await Navigator.pushNamed(
|
||||
context,
|
||||
Routes.fullscreenQR,
|
||||
arguments: {
|
||||
'qrData': addressListViewModel.uri.toString(),
|
||||
'isLight': isLight,
|
||||
},
|
||||
);
|
||||
// ignore: unawaited_futures
|
||||
DeviceDisplayBrightness.setBrightness(brightness);
|
||||
},
|
||||
child: Hero(
|
||||
tag: Key(addressListViewModel.uri.toString()),
|
||||
child: Center(
|
||||
child: AspectRatio(
|
||||
aspectRatio: 1.0,
|
||||
child: Container(
|
||||
padding: EdgeInsets.all(5),
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(
|
||||
width: 3,
|
||||
color: Theme.of(context).accentTextTheme.display3.backgroundColor,
|
||||
),
|
||||
),
|
||||
child: QrImage(
|
||||
data: addressListViewModel.uri.toString(),
|
||||
backgroundColor: isLight ? Colors.transparent : Colors.black,
|
||||
foregroundColor: Theme.of(context).accentTextTheme.display3.backgroundColor,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
Spacer(flex: 3)
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
if (isAmountFieldShow)
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: 10),
|
||||
child: Row(
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: Form(
|
||||
key: _formKey,
|
||||
child: BaseTextFormField(
|
||||
focusNode: amountTextFieldFocusNode,
|
||||
controller: amountController,
|
||||
keyboardType: TextInputType.numberWithOptions(decimal: true),
|
||||
inputFormatters: [BlacklistingTextInputFormatter(RegExp('[\\-|\\ ]'))],
|
||||
textAlign: TextAlign.center,
|
||||
hintText: S.of(context).receive_amount,
|
||||
textColor: Theme.of(context).accentTextTheme.display3.backgroundColor,
|
||||
borderColor: Theme.of(context).textTheme.headline.decorationColor,
|
||||
validator: AmountValidator(type: addressListViewModel.type, isAutovalidate: true),
|
||||
autovalidate: true,
|
||||
placeholderTextStyle: TextStyle(
|
||||
color: Theme.of(context).hoverColor,
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: 8, bottom: 8),
|
||||
child: Builder(
|
||||
builder: (context) => Observer(
|
||||
builder: (context) => GestureDetector(
|
||||
onTap: () {
|
||||
Clipboard.setData(ClipboardData(
|
||||
text: addressListViewModel.address.address));
|
||||
showBar<void>(
|
||||
context, S.of(context).copied_to_clipboard);
|
||||
},
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: Text(
|
||||
addressListViewModel.address.address,
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 15,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Theme.of(context).accentTextTheme.
|
||||
display3.backgroundColor),
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.only(left: 12),
|
||||
child: copyImage,
|
||||
)
|
||||
],
|
||||
),
|
||||
))),
|
||||
builder: (context) => Observer(
|
||||
builder: (context) => GestureDetector(
|
||||
onTap: () {
|
||||
Clipboard.setData(ClipboardData(text: addressListViewModel.address.address));
|
||||
showBar<void>(context, S.of(context).copied_to_clipboard);
|
||||
},
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: Text(
|
||||
addressListViewModel.address.address,
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 15,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Theme.of(context).accentTextTheme.display3.backgroundColor),
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.only(left: 12),
|
||||
child: copyImage,
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import 'package:cake_wallet/core/validator.dart';
|
||||
import 'package:cake_wallet/core/wallet_name_validator.dart';
|
||||
import 'package:cake_wallet/palette.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
|
|
|
@ -3,7 +3,7 @@ import 'package:mobx/mobx.dart';
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/core/validator.dart';
|
||||
import 'package:cake_wallet/core/wallet_name_validator.dart';
|
||||
import 'package:cake_wallet/core/execution_state.dart';
|
||||
import 'package:cake_wallet/src/screens/base_page.dart';
|
||||
import 'package:cake_wallet/src/widgets/blockchain_height_widget.dart';
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
import 'package:cake_wallet/view_model/wallet_restore_view_model.dart';
|
||||
import 'package:cw_core/wallet_type.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
@ -6,14 +8,15 @@ import 'package:cake_wallet/src/widgets/blockchain_height_widget.dart';
|
|||
import 'package:cake_wallet/src/widgets/base_text_form_field.dart';
|
||||
import 'package:cake_wallet/src/widgets/base_text_form_field.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/core/validator.dart';
|
||||
import 'package:cake_wallet/core/wallet_name_validator.dart';
|
||||
import 'package:cake_wallet/entities/generate_name.dart';
|
||||
|
||||
class WalletRestoreFromKeysFrom extends StatefulWidget {
|
||||
WalletRestoreFromKeysFrom({Key key, this.onHeightOrDateEntered})
|
||||
WalletRestoreFromKeysFrom({Key key, this.onHeightOrDateEntered, this.walletRestoreViewModel})
|
||||
: super(key: key);
|
||||
|
||||
final Function(bool) onHeightOrDateEntered;
|
||||
final WalletRestoreViewModel walletRestoreViewModel;
|
||||
|
||||
@override
|
||||
WalletRestoreFromKeysFromState createState() =>
|
||||
|
@ -113,6 +116,7 @@ class WalletRestoreFromKeysFromState extends State<WalletRestoreFromKeysFrom> {
|
|||
maxLines: null)),
|
||||
BlockchainHeightWidget(
|
||||
key: blockchainHeightKey,
|
||||
hasDatePicker: widget.walletRestoreViewModel.type != WalletType.haven,
|
||||
onHeightChange: (_) => null,
|
||||
onHeightOrDateEntered: widget.onHeightOrDateEntered)
|
||||
]),
|
||||
|
|
|
@ -10,7 +10,7 @@ import 'package:cake_wallet/src/widgets/base_text_form_field.dart';
|
|||
import 'package:cake_wallet/src/widgets/blockchain_height_widget.dart';
|
||||
import 'package:cake_wallet/src/widgets/base_text_form_field.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/core/validator.dart';
|
||||
import 'package:cake_wallet/core/wallet_name_validator.dart';
|
||||
|
||||
class WalletRestoreFromSeedForm extends StatefulWidget {
|
||||
WalletRestoreFromSeedForm(
|
||||
|
@ -41,6 +41,7 @@ class WalletRestoreFromSeedFormState extends State<WalletRestoreFromSeedForm> {
|
|||
WalletRestoreFromSeedFormState(this.language)
|
||||
: seedWidgetStateKey = GlobalKey<SeedWidgetState>(),
|
||||
blockchainHeightKey = GlobalKey<BlockchainHeightState>(),
|
||||
formKey = GlobalKey<FormState>(),
|
||||
languageController = TextEditingController(),
|
||||
nameTextEditingController = TextEditingController();
|
||||
|
||||
|
@ -48,6 +49,7 @@ class WalletRestoreFromSeedFormState extends State<WalletRestoreFromSeedForm> {
|
|||
final GlobalKey<BlockchainHeightState> blockchainHeightKey;
|
||||
final TextEditingController languageController;
|
||||
final TextEditingController nameTextEditingController;
|
||||
final GlobalKey<FormState> formKey;
|
||||
String language;
|
||||
|
||||
@override
|
||||
|
@ -61,7 +63,9 @@ class WalletRestoreFromSeedFormState extends State<WalletRestoreFromSeedForm> {
|
|||
return Container(
|
||||
padding: EdgeInsets.only(left: 24, right: 24),
|
||||
child: Column(children: [
|
||||
Stack(
|
||||
Form(
|
||||
key: formKey,
|
||||
child: Stack(
|
||||
alignment: Alignment.centerRight,
|
||||
children: [
|
||||
BaseTextFormField(
|
||||
|
@ -97,7 +101,7 @@ class WalletRestoreFromSeedFormState extends State<WalletRestoreFromSeedForm> {
|
|||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
)),
|
||||
Container(height: 20),
|
||||
SeedWidget(
|
||||
key: seedWidgetStateKey,
|
||||
|
|
|
@ -83,6 +83,7 @@ class WalletRestorePage extends BasePage {
|
|||
case WalletRestoreMode.keys:
|
||||
_pages.add(WalletRestoreFromKeysFrom(
|
||||
key: walletRestoreFromKeysFormKey,
|
||||
walletRestoreViewModel: walletRestoreViewModel,
|
||||
onHeightOrDateEntered: (value) =>
|
||||
walletRestoreViewModel.isButtonEnabled = value));
|
||||
break;
|
||||
|
@ -192,8 +193,7 @@ class WalletRestorePage extends BasePage {
|
|||
child: Observer(
|
||||
builder: (context) {
|
||||
return LoadingPrimaryButton(
|
||||
onPressed: () =>
|
||||
walletRestoreViewModel.create(options: _credentials()),
|
||||
onPressed: _confirmForm,
|
||||
text: S.of(context).restore_recover,
|
||||
color:
|
||||
Theme.of(context).accentTextTheme.subtitle.decorationColor,
|
||||
|
@ -267,4 +267,45 @@ class WalletRestorePage extends BasePage {
|
|||
|
||||
return credentials;
|
||||
}
|
||||
|
||||
void _confirmForm() {
|
||||
final formContext = walletRestoreViewModel.mode == WalletRestoreMode.seed
|
||||
? walletRestoreFromSeedFormKey.currentContext
|
||||
: walletRestoreFromKeysFormKey.currentContext;
|
||||
|
||||
final formKey = walletRestoreViewModel.mode == WalletRestoreMode.seed
|
||||
? walletRestoreFromSeedFormKey.currentState.formKey
|
||||
: walletRestoreFromKeysFormKey.currentState.formKey;
|
||||
|
||||
final name = walletRestoreViewModel.mode == WalletRestoreMode.seed
|
||||
? walletRestoreFromSeedFormKey
|
||||
.currentState.nameTextEditingController.value.text
|
||||
: walletRestoreFromKeysFormKey
|
||||
.currentState.nameTextEditingController.value.text;
|
||||
|
||||
if (!formKey.currentState.validate()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (walletRestoreViewModel.nameExists(name)) {
|
||||
showNameExistsAlert(formContext);
|
||||
return;
|
||||
}
|
||||
|
||||
walletRestoreViewModel.create(options: _credentials());
|
||||
}
|
||||
|
||||
Future<void> showNameExistsAlert(BuildContext context) {
|
||||
return showPopUp<void>(
|
||||
context: context,
|
||||
builder: (_) {
|
||||
return AlertWithOneAction(
|
||||
alertTitle: '',
|
||||
alertContent: S.of(context).wallet_name_exists,
|
||||
buttonText: S.of(context).ok,
|
||||
buttonAction: () => Navigator.of(context).pop());
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -23,6 +23,11 @@ Future<String> extractAddressFromParsed(
|
|||
content = S.of(context).openalias_alert_content(parsedAddress.name);
|
||||
address = parsedAddress.addresses.first;
|
||||
break;
|
||||
case ParseFrom.fio:
|
||||
title = S.of(context).address_detected;
|
||||
content = S.of(context).openalias_alert_content(parsedAddress.name);
|
||||
address = parsedAddress.addresses.first;
|
||||
break;
|
||||
case ParseFrom.yatRecord:
|
||||
if (parsedAddress.name.isEmpty) {
|
||||
title = S.of(context).yat_error;
|
||||
|
|