mirror of
https://github.com/cake-tech/cake_wallet.git
synced 2025-02-26 04:50:28 +00:00
Merge branch 'main' of https://github.com/cake-tech/cake_wallet into CW-492-moonpay
This commit is contained in:
commit
b369b4514d
119 changed files with 2722 additions and 661 deletions
.github/workflows
android
assets/text
cw_bitcoin
cw_bitcoin_cash
lib/src
linux/flutter
cw_core
cw_ethereum/lib
cw_haven
cw_monero
cw_nano
cw_shared_external/android
ios
lib
buy/robinhood
core
di.dartentities
exchange/provider
ionia
nano
reactions
router.dartroutes.dartsrc
screens
backup
buy
dashboard
dashboard_page.dartdesktop_dashboard_page.dart
desktop_widgets
pages
address_page.dartbalance_page.dartmarket_place_page.dartnft_details_page.dartnft_import_page.dartnft_listing_page.darttransactions_page.dart
widgets
monero_accounts
nano
new_wallet
nodes
restore
seed
settings
widgets
store
utils
view_model
macos
pubspec_base.yamlres/values
2
.github/workflows/cache_dependencies.yml
vendored
2
.github/workflows/cache_dependencies.yml
vendored
|
@ -14,7 +14,7 @@ jobs:
|
|||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-java@v1
|
||||
with:
|
||||
java-version: '8.x'
|
||||
java-version: '11.x'
|
||||
|
||||
- name: Flutter action
|
||||
uses: subosito/flutter-action@v1
|
||||
|
|
5
.github/workflows/pr_test_build.yml
vendored
5
.github/workflows/pr_test_build.yml
vendored
|
@ -22,7 +22,7 @@ jobs:
|
|||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-java@v1
|
||||
with:
|
||||
java-version: "8.x"
|
||||
java-version: "11.x"
|
||||
|
||||
- name: Flutter action
|
||||
uses: subosito/flutter-action@v1
|
||||
|
@ -38,6 +38,8 @@ jobs:
|
|||
sudo mkdir -p /opt/android
|
||||
sudo chown $USER /opt/android
|
||||
cd /opt/android
|
||||
-y curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
|
||||
cargo install cargo-ndk
|
||||
git clone https://github.com/cake-tech/cake_wallet.git --branch $GITHUB_HEAD_REF
|
||||
cd cake_wallet/scripts/android/
|
||||
./install_ndk.sh
|
||||
|
@ -134,6 +136,7 @@ jobs:
|
|||
echo "const robinhoodApplicationId = '${{ secrets.ROBINHOOD_APPLICATION_ID }}';" >> lib/.secrets.g.dart
|
||||
echo "const robinhoodCIdApiSecret = '${{ secrets.ROBINHOOD_CID_CLIENT_SECRET }}';" >> lib/.secrets.g.dart
|
||||
echo "const walletConnectProjectId = '${{ secrets.WALLET_CONNECT_PROJECT_ID }}';" >> lib/.secrets.g.dart
|
||||
echo "const moralisApiKey = '${{ secrets.MORALIS_API_KEY }}';" >> lib/.secrets.g.dart
|
||||
|
||||
- name: Rename app
|
||||
run: echo -e "id=com.cakewallet.test\nname=$GITHUB_HEAD_REF" > /opt/android/cake_wallet/android/app.properties
|
||||
|
|
|
@ -75,7 +75,6 @@ android {
|
|||
|
||||
shrinkResources false
|
||||
minifyEnabled false
|
||||
useProguard false
|
||||
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
<uses-permission android:name="android.permission.INTERNET"/>
|
||||
<uses-permission android:name="android.permission.USE_FINGERPRINT"/>
|
||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
||||
<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" />
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
buildscript {
|
||||
ext.kotlin_version = '1.6.21'
|
||||
ext.kotlin_version = '1.7.10'
|
||||
repositories {
|
||||
google()
|
||||
jcenter()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:4.1.3'
|
||||
classpath 'com.android.tools.build:gradle:7.3.0'
|
||||
classpath 'com.google.gms:google-services:4.3.8'
|
||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||
}
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
UI enhancements
|
||||
Coin control fixes and enhancements
|
||||
In-app Tor connection
|
||||
Accessibility enhancements
|
||||
Privacy settings enhancements
|
||||
Tablet/iPad fixes
|
||||
UI enhancements
|
||||
Backup flow fixes
|
||||
Bug fixes
|
|
@ -1,5 +1,7 @@
|
|||
WalletConnect enhancements
|
||||
UI enhancements
|
||||
Coin control fixes and enhancements
|
||||
In-app Tor connection
|
||||
Accessibility enhancements
|
||||
Privacy settings enhancements
|
||||
Tablet/iPad fixes
|
||||
UI enhancements
|
||||
Backup flow fixes
|
||||
Bug fixes
|
|
@ -481,50 +481,50 @@ packages:
|
|||
dependency: "direct main"
|
||||
description:
|
||||
name: path_provider
|
||||
sha256: dcea5feb97d8abf90cab9e9030b497fb7c3cbf26b7a1fe9e3ef7dcb0a1ddec95
|
||||
sha256: a1aa8aaa2542a6bc57e381f132af822420216c80d4781f7aa085ca3229208aaa
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.12"
|
||||
version: "2.1.1"
|
||||
path_provider_android:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: path_provider_android
|
||||
sha256: a776c088d671b27f6e3aa8881d64b87b3e80201c64e8869b811325de7a76c15e
|
||||
sha256: e595b98692943b4881b219f0a9e3945118d3c16bd7e2813f98ec6e532d905f72
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.22"
|
||||
version: "2.2.1"
|
||||
path_provider_foundation:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: path_provider_foundation
|
||||
sha256: "62a68e7e1c6c459f9289859e2fae58290c981ce21d1697faf54910fe1faa4c74"
|
||||
sha256: "19314d595120f82aca0ba62787d58dde2cc6b5df7d2f0daf72489e38d1b57f2d"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.1"
|
||||
version: "2.3.1"
|
||||
path_provider_linux:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: path_provider_linux
|
||||
sha256: ab0987bf95bc591da42dffb38c77398fc43309f0b9b894dcc5d6f40c4b26c379
|
||||
sha256: f7a1fe3a634fe7734c8d3f2766ad746ae2a2884abe22e241a8b301bf5cac3279
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.7"
|
||||
version: "2.2.1"
|
||||
path_provider_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: path_provider_platform_interface
|
||||
sha256: f0abc8ebd7253741f05488b4813d936b4d07c6bae3e86148a09e342ee4b08e76
|
||||
sha256: "94b1e0dd80970c1ce43d5d4e050a9918fce4f4a775e6142424c30a29a363265c"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.5"
|
||||
version: "2.1.1"
|
||||
path_provider_windows:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: path_provider_windows
|
||||
sha256: bcabbe399d4042b8ee687e17548d5d3f527255253b4a639f5f8d2094a9c2b45c
|
||||
sha256: "8bc9f22eee8690981c22aa7fc602f5c85b497a6fb2ceb35ee5a5e5ed85ad8170"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.3"
|
||||
version: "2.2.1"
|
||||
platform:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -610,6 +610,14 @@ packages:
|
|||
description: flutter
|
||||
source: sdk
|
||||
version: "0.0.99"
|
||||
socks5_proxy:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: socks5_proxy
|
||||
sha256: "1d21b5606169654bbf4cfb904e8e6ed897e9f763358709f87310c757096d909a"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.4"
|
||||
source_gen:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -690,6 +698,15 @@ packages:
|
|||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.1"
|
||||
tor:
|
||||
dependency: transitive
|
||||
description:
|
||||
path: "."
|
||||
ref: main
|
||||
resolved-ref: "09ba92cb11d4e3cacf97256e57863b805f79f2e5"
|
||||
url: "https://github.com/cake-tech/tor.git"
|
||||
source: git
|
||||
version: "0.0.1"
|
||||
typed_data:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -756,4 +773,4 @@ packages:
|
|||
version: "3.1.1"
|
||||
sdks:
|
||||
dart: ">=3.0.0 <4.0.0"
|
||||
flutter: ">=3.0.0"
|
||||
flutter: ">=3.7.0"
|
||||
|
|
|
@ -2,4 +2,5 @@ import 'package:bitbox/bitbox.dart' as bitbox;
|
|||
|
||||
class AddressUtils {
|
||||
static String getCashAddrFormat(String address) => bitbox.Address.toCashAddress(address);
|
||||
static String toLegacyAddress(String address) => bitbox.Address.toLegacyAddress(address);
|
||||
}
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
import 'dart:convert';
|
||||
|
||||
import 'package:bitbox/bitbox.dart' as bitbox;
|
||||
import 'package:bitcoin_flutter/bitcoin_flutter.dart' as bitcoin;
|
||||
import 'package:cw_bitcoin/bitcoin_address_record.dart';
|
||||
|
@ -294,4 +296,16 @@ abstract class BitcoinCashWalletBase extends ElectrumWallet with Store {
|
|||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@override
|
||||
String signMessage(String message, {String? address = null}) {
|
||||
final index = address != null
|
||||
? walletAddresses.addresses
|
||||
.firstWhere((element) => element.address == AddressUtils.toLegacyAddress(address))
|
||||
.index
|
||||
: null;
|
||||
return index == null
|
||||
? base64Encode(hd.sign(message))
|
||||
: base64Encode(hd.derive(index).sign(message));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -32,8 +32,13 @@ class BitcoinCashWalletService extends WalletService<BitcoinCashNewWalletCredent
|
|||
@override
|
||||
Future<BitcoinCashWallet> create(
|
||||
credentials) async {
|
||||
final strength = (credentials.seedPhraseLength == 12)
|
||||
? 128
|
||||
: (credentials.seedPhraseLength == 24)
|
||||
? 256
|
||||
: 128;
|
||||
final wallet = await BitcoinCashWalletBase.create(
|
||||
mnemonic: await Mnemonic.generate(),
|
||||
mnemonic: await Mnemonic.generate(strength: strength),
|
||||
password: credentials.password!,
|
||||
walletInfo: credentials.walletInfo!,
|
||||
unspentCoinsInfo: unspentCoinsInfoSource);
|
||||
|
|
1
cw_bitcoin_cash/linux/flutter/ephemeral/.plugin_symlinks/tor
Symbolic link
1
cw_bitcoin_cash/linux/flutter/ephemeral/.plugin_symlinks/tor
Symbolic link
|
@ -0,0 +1 @@
|
|||
/Users/blazebrain/.pub-cache/git/tor-09ba92cb11d4e3cacf97256e57863b805f79f2e5/
|
|
@ -6,6 +6,7 @@ list(APPEND FLUTTER_PLUGIN_LIST
|
|||
)
|
||||
|
||||
list(APPEND FLUTTER_FFI_PLUGIN_LIST
|
||||
tor
|
||||
)
|
||||
|
||||
set(PLUGIN_BUNDLED_LIBRARIES)
|
||||
|
|
|
@ -9,5 +9,5 @@ abstract class Balance {
|
|||
|
||||
String get formattedAdditionalBalance;
|
||||
|
||||
String get formattedFrozenBalance => '';
|
||||
String get formattedUnAvailableBalance => '';
|
||||
}
|
||||
|
|
|
@ -4,17 +4,18 @@ import 'package:cw_core/monero_amount_format.dart';
|
|||
class MoneroBalance extends Balance {
|
||||
MoneroBalance({required this.fullBalance, required this.unlockedBalance, this.frozenBalance = 0})
|
||||
: formattedFullBalance = moneroAmountToString(amount: fullBalance),
|
||||
formattedUnlockedBalance = moneroAmountToString(amount: unlockedBalance),
|
||||
frozenFormatted = moneroAmountToString(amount: frozenBalance),
|
||||
formattedUnlockedBalance = moneroAmountToString(amount: unlockedBalance - frozenBalance),
|
||||
formattedLockedBalance =
|
||||
moneroAmountToString(amount: frozenBalance + fullBalance - unlockedBalance),
|
||||
super(unlockedBalance, fullBalance);
|
||||
|
||||
MoneroBalance.fromString(
|
||||
{required this.formattedFullBalance,
|
||||
required this.formattedUnlockedBalance,
|
||||
this.frozenFormatted = '0.0'})
|
||||
this.formattedLockedBalance = '0.0'})
|
||||
: fullBalance = moneroParseAmount(amount: formattedFullBalance),
|
||||
unlockedBalance = moneroParseAmount(amount: formattedUnlockedBalance),
|
||||
frozenBalance = moneroParseAmount(amount: frozenFormatted),
|
||||
frozenBalance = moneroParseAmount(amount: formattedLockedBalance),
|
||||
super(moneroParseAmount(amount: formattedUnlockedBalance),
|
||||
moneroParseAmount(amount: formattedFullBalance));
|
||||
|
||||
|
@ -23,10 +24,11 @@ class MoneroBalance extends Balance {
|
|||
final int frozenBalance;
|
||||
final String formattedFullBalance;
|
||||
final String formattedUnlockedBalance;
|
||||
final String frozenFormatted;
|
||||
final String formattedLockedBalance;
|
||||
|
||||
@override
|
||||
String get formattedFrozenBalance => frozenFormatted == '0.0' ? '' : frozenFormatted;
|
||||
String get formattedUnAvailableBalance =>
|
||||
formattedLockedBalance == '0.0' ? '' : formattedLockedBalance;
|
||||
|
||||
@override
|
||||
String get formattedAvailableBalance => formattedUnlockedBalance;
|
||||
|
|
|
@ -6,6 +6,7 @@ import 'package:hive/hive.dart';
|
|||
import 'package:cw_core/hive_type_ids.dart';
|
||||
import 'package:cw_core/wallet_type.dart';
|
||||
import 'package:http/io_client.dart' as ioc;
|
||||
import 'package:tor/tor.dart';
|
||||
|
||||
part 'node.g.dart';
|
||||
|
||||
|
@ -92,6 +93,8 @@ class Node extends HiveObject with Keyable {
|
|||
}
|
||||
}
|
||||
|
||||
bool get isValidProxyAddress => socksProxyAddress?.contains(':') ?? false;
|
||||
|
||||
@override
|
||||
bool operator ==(other) =>
|
||||
other is Node &&
|
||||
|
@ -129,9 +132,7 @@ class Node extends HiveObject with Keyable {
|
|||
try {
|
||||
switch (type) {
|
||||
case WalletType.monero:
|
||||
return useSocksProxy
|
||||
? requestNodeWithProxy(socksProxyAddress ?? '')
|
||||
: requestMoneroNode();
|
||||
return requestMoneroNode();
|
||||
case WalletType.bitcoin:
|
||||
return requestElectrumServer();
|
||||
case WalletType.litecoin:
|
||||
|
@ -154,6 +155,9 @@ class Node extends HiveObject with Keyable {
|
|||
}
|
||||
|
||||
Future<bool> requestMoneroNode() async {
|
||||
if (uri.toString().contains(".onion") || useSocksProxy) {
|
||||
return await requestNodeWithProxy();
|
||||
}
|
||||
final path = '/json_rpc';
|
||||
final rpcUri = isSSL ? Uri.https(uri.authority, path) : Uri.http(uri.authority, path);
|
||||
final realm = 'monero-rpc';
|
||||
|
@ -205,11 +209,17 @@ class Node extends HiveObject with Keyable {
|
|||
}
|
||||
}
|
||||
|
||||
Future<bool> requestNodeWithProxy(String proxy) async {
|
||||
if (proxy.isEmpty || !proxy.contains(':')) {
|
||||
Future<bool> requestNodeWithProxy() async {
|
||||
if (!isValidProxyAddress && !Tor.instance.enabled) {
|
||||
return false;
|
||||
}
|
||||
final proxyAddress = proxy.split(':')[0];
|
||||
|
||||
String? proxy = socksProxyAddress;
|
||||
|
||||
if ((proxy?.isEmpty ?? true) && Tor.instance.enabled) {
|
||||
proxy = "${InternetAddress.loopbackIPv4.address}:${Tor.instance.port}";
|
||||
}
|
||||
final proxyAddress = proxy!.split(':')[0];
|
||||
final proxyPort = int.parse(proxy.split(':')[1]);
|
||||
try {
|
||||
final socket = await Socket.connect(proxyAddress, proxyPort, timeout: Duration(seconds: 5));
|
||||
|
|
|
@ -4,6 +4,7 @@ abstract class WalletCredentials {
|
|||
WalletCredentials({
|
||||
required this.name,
|
||||
this.height,
|
||||
this.seedPhraseLength,
|
||||
this.walletInfo,
|
||||
this.password,
|
||||
this.derivationType,
|
||||
|
@ -12,6 +13,7 @@ abstract class WalletCredentials {
|
|||
|
||||
final String name;
|
||||
final int? height;
|
||||
int? seedPhraseLength;
|
||||
String? password;
|
||||
DerivationType? derivationType;
|
||||
String? derivationPath;
|
||||
|
|
|
@ -407,50 +407,50 @@ packages:
|
|||
dependency: "direct main"
|
||||
description:
|
||||
name: path_provider
|
||||
sha256: dcea5feb97d8abf90cab9e9030b497fb7c3cbf26b7a1fe9e3ef7dcb0a1ddec95
|
||||
sha256: a1aa8aaa2542a6bc57e381f132af822420216c80d4781f7aa085ca3229208aaa
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.12"
|
||||
version: "2.1.1"
|
||||
path_provider_android:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: path_provider_android
|
||||
sha256: a776c088d671b27f6e3aa8881d64b87b3e80201c64e8869b811325de7a76c15e
|
||||
sha256: e595b98692943b4881b219f0a9e3945118d3c16bd7e2813f98ec6e532d905f72
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.22"
|
||||
version: "2.2.1"
|
||||
path_provider_foundation:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: path_provider_foundation
|
||||
sha256: "62a68e7e1c6c459f9289859e2fae58290c981ce21d1697faf54910fe1faa4c74"
|
||||
sha256: "19314d595120f82aca0ba62787d58dde2cc6b5df7d2f0daf72489e38d1b57f2d"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.1"
|
||||
version: "2.3.1"
|
||||
path_provider_linux:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: path_provider_linux
|
||||
sha256: ab0987bf95bc591da42dffb38c77398fc43309f0b9b894dcc5d6f40c4b26c379
|
||||
sha256: f7a1fe3a634fe7734c8d3f2766ad746ae2a2884abe22e241a8b301bf5cac3279
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.7"
|
||||
version: "2.2.1"
|
||||
path_provider_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: path_provider_platform_interface
|
||||
sha256: f0abc8ebd7253741f05488b4813d936b4d07c6bae3e86148a09e342ee4b08e76
|
||||
sha256: "94b1e0dd80970c1ce43d5d4e050a9918fce4f4a775e6142424c30a29a363265c"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.5"
|
||||
version: "2.1.1"
|
||||
path_provider_windows:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: path_provider_windows
|
||||
sha256: bcabbe399d4042b8ee687e17548d5d3f527255253b4a639f5f8d2094a9c2b45c
|
||||
sha256: "8bc9f22eee8690981c22aa7fc602f5c85b497a6fb2ceb35ee5a5e5ed85ad8170"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.3"
|
||||
version: "2.2.1"
|
||||
platform:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -528,6 +528,14 @@ packages:
|
|||
description: flutter
|
||||
source: sdk
|
||||
version: "0.0.99"
|
||||
socks5_proxy:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: socks5_proxy
|
||||
sha256: "1d21b5606169654bbf4cfb904e8e6ed897e9f763358709f87310c757096d909a"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.4"
|
||||
source_gen:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -608,6 +616,15 @@ packages:
|
|||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.1"
|
||||
tor:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
path: "."
|
||||
ref: main
|
||||
resolved-ref: "09ba92cb11d4e3cacf97256e57863b805f79f2e5"
|
||||
url: "https://github.com/cake-tech/tor.git"
|
||||
source: git
|
||||
version: "0.0.1"
|
||||
typed_data:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -666,4 +683,4 @@ packages:
|
|||
version: "3.1.1"
|
||||
sdks:
|
||||
dart: ">=3.0.0 <4.0.0"
|
||||
flutter: ">=3.0.0"
|
||||
flutter: ">=3.7.0"
|
||||
|
|
|
@ -19,6 +19,11 @@ dependencies:
|
|||
flutter_mobx: ^2.0.6+1
|
||||
intl: ^0.18.0
|
||||
encrypt: ^5.0.1
|
||||
socks5_proxy: ^1.0.4
|
||||
tor:
|
||||
git:
|
||||
url: https://github.com/cake-tech/tor.git
|
||||
ref: main
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
|
|
|
@ -38,8 +38,13 @@ class EthereumClient {
|
|||
// });
|
||||
}
|
||||
|
||||
Future<EtherAmount> getBalance(EthereumAddress address) async =>
|
||||
await _client!.getBalance(address);
|
||||
Future<EtherAmount> getBalance(EthereumAddress address) async {
|
||||
try {
|
||||
return await _client!.getBalance(address);
|
||||
} catch (_) {
|
||||
return EtherAmount.zero();
|
||||
}
|
||||
}
|
||||
|
||||
Future<int> getGasUnitPrice() async {
|
||||
try {
|
||||
|
|
|
@ -20,7 +20,14 @@ class EthereumWalletService extends WalletService<EthereumNewWalletCredentials,
|
|||
|
||||
@override
|
||||
Future<EthereumWallet> create(EthereumNewWalletCredentials credentials) async {
|
||||
final mnemonic = bip39.generateMnemonic();
|
||||
|
||||
final strength = (credentials.seedPhraseLength == 12)
|
||||
? 128
|
||||
: (credentials.seedPhraseLength == 24)
|
||||
? 256
|
||||
: 128;
|
||||
|
||||
final mnemonic = bip39.generateMnemonic(strength: strength);
|
||||
final wallet = EthereumWallet(
|
||||
walletInfo: credentials.walletInfo!,
|
||||
mnemonic: mnemonic,
|
||||
|
|
|
@ -2,14 +2,14 @@ group 'com.cakewallet.cw_haven'
|
|||
version '1.0-SNAPSHOT'
|
||||
|
||||
buildscript {
|
||||
ext.kotlin_version = '1.3.50'
|
||||
ext.kotlin_version = '1.7.10'
|
||||
repositories {
|
||||
google()
|
||||
jcenter()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:4.1.0'
|
||||
classpath 'com.android.tools.build:gradle:7.3.0'
|
||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -414,50 +414,50 @@ packages:
|
|||
dependency: "direct main"
|
||||
description:
|
||||
name: path_provider
|
||||
sha256: dcea5feb97d8abf90cab9e9030b497fb7c3cbf26b7a1fe9e3ef7dcb0a1ddec95
|
||||
sha256: a1aa8aaa2542a6bc57e381f132af822420216c80d4781f7aa085ca3229208aaa
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.12"
|
||||
version: "2.1.1"
|
||||
path_provider_android:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: path_provider_android
|
||||
sha256: a776c088d671b27f6e3aa8881d64b87b3e80201c64e8869b811325de7a76c15e
|
||||
sha256: e595b98692943b4881b219f0a9e3945118d3c16bd7e2813f98ec6e532d905f72
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.22"
|
||||
version: "2.2.1"
|
||||
path_provider_foundation:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: path_provider_foundation
|
||||
sha256: "62a68e7e1c6c459f9289859e2fae58290c981ce21d1697faf54910fe1faa4c74"
|
||||
sha256: "19314d595120f82aca0ba62787d58dde2cc6b5df7d2f0daf72489e38d1b57f2d"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.1"
|
||||
version: "2.3.1"
|
||||
path_provider_linux:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: path_provider_linux
|
||||
sha256: ab0987bf95bc591da42dffb38c77398fc43309f0b9b894dcc5d6f40c4b26c379
|
||||
sha256: f7a1fe3a634fe7734c8d3f2766ad746ae2a2884abe22e241a8b301bf5cac3279
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.7"
|
||||
version: "2.2.1"
|
||||
path_provider_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: path_provider_platform_interface
|
||||
sha256: f0abc8ebd7253741f05488b4813d936b4d07c6bae3e86148a09e342ee4b08e76
|
||||
sha256: "94b1e0dd80970c1ce43d5d4e050a9918fce4f4a775e6142424c30a29a363265c"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.5"
|
||||
version: "2.1.1"
|
||||
path_provider_windows:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: path_provider_windows
|
||||
sha256: f53720498d5a543f9607db4b0e997c4b5438884de25b0f73098cc2671a51b130
|
||||
sha256: "8bc9f22eee8690981c22aa7fc602f5c85b497a6fb2ceb35ee5a5e5ed85ad8170"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.5"
|
||||
version: "2.2.1"
|
||||
platform:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -535,6 +535,14 @@ packages:
|
|||
description: flutter
|
||||
source: sdk
|
||||
version: "0.0.99"
|
||||
socks5_proxy:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: socks5_proxy
|
||||
sha256: "1d21b5606169654bbf4cfb904e8e6ed897e9f763358709f87310c757096d909a"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.4"
|
||||
source_gen:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -615,6 +623,15 @@ packages:
|
|||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.1"
|
||||
tor:
|
||||
dependency: transitive
|
||||
description:
|
||||
path: "."
|
||||
ref: main
|
||||
resolved-ref: "09ba92cb11d4e3cacf97256e57863b805f79f2e5"
|
||||
url: "https://github.com/cake-tech/tor.git"
|
||||
source: git
|
||||
version: "0.0.1"
|
||||
typed_data:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -673,4 +690,4 @@ packages:
|
|||
version: "3.1.1"
|
||||
sdks:
|
||||
dart: ">=3.0.0 <4.0.0"
|
||||
flutter: ">=3.0.0"
|
||||
flutter: ">=3.7.0"
|
||||
|
|
|
@ -2,14 +2,14 @@ group 'com.cakewallet.monero'
|
|||
version '1.0-SNAPSHOT'
|
||||
|
||||
buildscript {
|
||||
ext.kotlin_version = '1.3.50'
|
||||
ext.kotlin_version = '1.7.10'
|
||||
repositories {
|
||||
google()
|
||||
jcenter()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:3.5.4'
|
||||
classpath 'com.android.tools.build:gradle:7.3.0'
|
||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -237,50 +237,50 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: path_provider
|
||||
sha256: dcea5feb97d8abf90cab9e9030b497fb7c3cbf26b7a1fe9e3ef7dcb0a1ddec95
|
||||
sha256: a1aa8aaa2542a6bc57e381f132af822420216c80d4781f7aa085ca3229208aaa
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.12"
|
||||
version: "2.1.1"
|
||||
path_provider_android:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: path_provider_android
|
||||
sha256: a776c088d671b27f6e3aa8881d64b87b3e80201c64e8869b811325de7a76c15e
|
||||
sha256: e595b98692943b4881b219f0a9e3945118d3c16bd7e2813f98ec6e532d905f72
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.22"
|
||||
version: "2.2.1"
|
||||
path_provider_foundation:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: path_provider_foundation
|
||||
sha256: "62a68e7e1c6c459f9289859e2fae58290c981ce21d1697faf54910fe1faa4c74"
|
||||
sha256: "19314d595120f82aca0ba62787d58dde2cc6b5df7d2f0daf72489e38d1b57f2d"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.1"
|
||||
version: "2.3.1"
|
||||
path_provider_linux:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: path_provider_linux
|
||||
sha256: ab0987bf95bc591da42dffb38c77398fc43309f0b9b894dcc5d6f40c4b26c379
|
||||
sha256: f7a1fe3a634fe7734c8d3f2766ad746ae2a2884abe22e241a8b301bf5cac3279
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.7"
|
||||
version: "2.2.1"
|
||||
path_provider_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: path_provider_platform_interface
|
||||
sha256: f0abc8ebd7253741f05488b4813d936b4d07c6bae3e86148a09e342ee4b08e76
|
||||
sha256: "94b1e0dd80970c1ce43d5d4e050a9918fce4f4a775e6142424c30a29a363265c"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.5"
|
||||
version: "2.1.1"
|
||||
path_provider_windows:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: path_provider_windows
|
||||
sha256: f53720498d5a543f9607db4b0e997c4b5438884de25b0f73098cc2671a51b130
|
||||
sha256: "8bc9f22eee8690981c22aa7fc602f5c85b497a6fb2ceb35ee5a5e5ed85ad8170"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.5"
|
||||
version: "2.2.1"
|
||||
platform:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -318,6 +318,14 @@ packages:
|
|||
description: flutter
|
||||
source: sdk
|
||||
version: "0.0.99"
|
||||
socks5_proxy:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: socks5_proxy
|
||||
sha256: "1d21b5606169654bbf4cfb904e8e6ed897e9f763358709f87310c757096d909a"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.4"
|
||||
source_span:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -366,6 +374,15 @@ packages:
|
|||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.5.1"
|
||||
tor:
|
||||
dependency: transitive
|
||||
description:
|
||||
path: "."
|
||||
ref: main
|
||||
resolved-ref: "09ba92cb11d4e3cacf97256e57863b805f79f2e5"
|
||||
url: "https://github.com/cake-tech/tor.git"
|
||||
source: git
|
||||
version: "0.0.1"
|
||||
typed_data:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -400,4 +417,4 @@ packages:
|
|||
version: "0.2.0+3"
|
||||
sdks:
|
||||
dart: ">=3.0.0 <4.0.0"
|
||||
flutter: ">=3.0.0"
|
||||
flutter: ">=3.7.0"
|
||||
|
|
|
@ -414,50 +414,50 @@ packages:
|
|||
dependency: "direct main"
|
||||
description:
|
||||
name: path_provider
|
||||
sha256: dcea5feb97d8abf90cab9e9030b497fb7c3cbf26b7a1fe9e3ef7dcb0a1ddec95
|
||||
sha256: a1aa8aaa2542a6bc57e381f132af822420216c80d4781f7aa085ca3229208aaa
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.12"
|
||||
version: "2.1.1"
|
||||
path_provider_android:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: path_provider_android
|
||||
sha256: a776c088d671b27f6e3aa8881d64b87b3e80201c64e8869b811325de7a76c15e
|
||||
sha256: e595b98692943b4881b219f0a9e3945118d3c16bd7e2813f98ec6e532d905f72
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.22"
|
||||
version: "2.2.1"
|
||||
path_provider_foundation:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: path_provider_foundation
|
||||
sha256: "62a68e7e1c6c459f9289859e2fae58290c981ce21d1697faf54910fe1faa4c74"
|
||||
sha256: "19314d595120f82aca0ba62787d58dde2cc6b5df7d2f0daf72489e38d1b57f2d"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.1"
|
||||
version: "2.3.1"
|
||||
path_provider_linux:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: path_provider_linux
|
||||
sha256: ab0987bf95bc591da42dffb38c77398fc43309f0b9b894dcc5d6f40c4b26c379
|
||||
sha256: f7a1fe3a634fe7734c8d3f2766ad746ae2a2884abe22e241a8b301bf5cac3279
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.7"
|
||||
version: "2.2.1"
|
||||
path_provider_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: path_provider_platform_interface
|
||||
sha256: f0abc8ebd7253741f05488b4813d936b4d07c6bae3e86148a09e342ee4b08e76
|
||||
sha256: "94b1e0dd80970c1ce43d5d4e050a9918fce4f4a775e6142424c30a29a363265c"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.5"
|
||||
version: "2.1.1"
|
||||
path_provider_windows:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: path_provider_windows
|
||||
sha256: f53720498d5a543f9607db4b0e997c4b5438884de25b0f73098cc2671a51b130
|
||||
sha256: "8bc9f22eee8690981c22aa7fc602f5c85b497a6fb2ceb35ee5a5e5ed85ad8170"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.5"
|
||||
version: "2.2.1"
|
||||
platform:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -535,6 +535,14 @@ packages:
|
|||
description: flutter
|
||||
source: sdk
|
||||
version: "0.0.99"
|
||||
socks5_proxy:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: socks5_proxy
|
||||
sha256: "1d21b5606169654bbf4cfb904e8e6ed897e9f763358709f87310c757096d909a"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.4"
|
||||
source_gen:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -615,6 +623,15 @@ packages:
|
|||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.1"
|
||||
tor:
|
||||
dependency: transitive
|
||||
description:
|
||||
path: "."
|
||||
ref: main
|
||||
resolved-ref: "09ba92cb11d4e3cacf97256e57863b805f79f2e5"
|
||||
url: "https://github.com/cake-tech/tor.git"
|
||||
source: git
|
||||
version: "0.0.1"
|
||||
typed_data:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -673,4 +690,4 @@ packages:
|
|||
version: "3.1.1"
|
||||
sdks:
|
||||
dart: ">=3.0.0 <4.0.0"
|
||||
flutter: ">=3.0.0"
|
||||
flutter: ">=3.7.0"
|
||||
|
|
|
@ -8,18 +8,28 @@ import 'package:cw_nano/nano_util.dart';
|
|||
import 'package:http/http.dart' as http;
|
||||
import 'package:nanodart/nanodart.dart';
|
||||
import 'package:cw_core/node.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
|
||||
class NanoClient {
|
||||
static const String DEFAULT_REPRESENTATIVE =
|
||||
"nano_38713x95zyjsqzx6nm1dsom1jmm668owkeb9913ax6nfgj15az3nu8xkx579";
|
||||
|
||||
static const Map<String, String> CAKE_HEADERS = {
|
||||
"Content-Type": "application/json",
|
||||
"nano-app": "cake-wallet"
|
||||
};
|
||||
|
||||
NanoClient() {
|
||||
SharedPreferences.getInstance().then((value) => prefs = value);
|
||||
}
|
||||
|
||||
late SharedPreferences prefs;
|
||||
Node? _node;
|
||||
Node? _powNode;
|
||||
static const String _defaultDefaultRepresentative =
|
||||
"nano_38713x95zyjsqzx6nm1dsom1jmm668owkeb9913ax6nfgj15az3nu8xkx579";
|
||||
|
||||
String getRepFromPrefs() {
|
||||
// from preferences_key.dart "defaultNanoRep" key:
|
||||
return prefs.getString("default_nano_representative") ?? _defaultDefaultRepresentative;
|
||||
}
|
||||
|
||||
bool connect(Node node) {
|
||||
try {
|
||||
|
@ -84,44 +94,45 @@ class NanoClient {
|
|||
required String repAddress,
|
||||
required String ourAddress,
|
||||
}) async {
|
||||
AccountInfoResponse? accountInfo = await getAccountInfo(ourAddress);
|
||||
|
||||
if (accountInfo == null) {
|
||||
throw Exception(
|
||||
"error while getting account info, you can't change the rep of an unopened account");
|
||||
}
|
||||
|
||||
// construct the change block:
|
||||
Map<String, String> changeBlock = {
|
||||
"type": "state",
|
||||
"account": ourAddress,
|
||||
"previous": accountInfo.frontier,
|
||||
"representative": repAddress,
|
||||
"balance": accountInfo.balance,
|
||||
"link": "0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"link_as_account": "nano_1111111111111111111111111111111111111111111111111111hifc8npp",
|
||||
};
|
||||
|
||||
// sign the change block:
|
||||
final String hash = NanoBlocks.computeStateHash(
|
||||
NanoAccountType.NANO,
|
||||
changeBlock["account"]!,
|
||||
changeBlock["previous"]!,
|
||||
changeBlock["representative"]!,
|
||||
BigInt.parse(changeBlock["balance"]!),
|
||||
changeBlock["link"]!,
|
||||
);
|
||||
final String signature = NanoSignatures.signBlock(hash, privateKey);
|
||||
|
||||
// get PoW for the send block:
|
||||
final String work = await requestWork(accountInfo.frontier);
|
||||
|
||||
changeBlock["signature"] = signature;
|
||||
changeBlock["work"] = work;
|
||||
|
||||
try {
|
||||
AccountInfoResponse? accountInfo = await getAccountInfo(ourAddress);
|
||||
|
||||
if (accountInfo == null) {
|
||||
throw Exception("error while getting account info");
|
||||
}
|
||||
|
||||
// construct the change block:
|
||||
Map<String, String> changeBlock = {
|
||||
"type": "state",
|
||||
"account": ourAddress,
|
||||
"previous": accountInfo.frontier,
|
||||
"representative": repAddress,
|
||||
"balance": accountInfo.balance,
|
||||
"link": "0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"link_as_account": "nano_1111111111111111111111111111111111111111111111111111hifc8npp",
|
||||
};
|
||||
|
||||
// sign the change block:
|
||||
final String hash = NanoBlocks.computeStateHash(
|
||||
NanoAccountType.NANO,
|
||||
changeBlock["account"]!,
|
||||
changeBlock["previous"]!,
|
||||
changeBlock["representative"]!,
|
||||
BigInt.parse(changeBlock["balance"]!),
|
||||
changeBlock["link"]!,
|
||||
);
|
||||
final String signature = NanoSignatures.signBlock(hash, privateKey);
|
||||
|
||||
// get PoW for the send block:
|
||||
final String work = await requestWork(accountInfo.frontier);
|
||||
|
||||
changeBlock["signature"] = signature;
|
||||
changeBlock["work"] = work;
|
||||
|
||||
return await processBlock(changeBlock, "change");
|
||||
} catch (e) {
|
||||
throw Exception("error while changing representative");
|
||||
throw Exception("error while changing representative: $e");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -191,68 +202,63 @@ class NanoClient {
|
|||
BigInt? balanceAfterTx,
|
||||
String? previousHash,
|
||||
}) async {
|
||||
try {
|
||||
// our address:
|
||||
final String publicAddress = NanoUtil.privateKeyToAddress(privateKey);
|
||||
// our address:
|
||||
final String publicAddress = NanoUtil.privateKeyToAddress(privateKey);
|
||||
|
||||
// first get the current account balance:
|
||||
if (balanceAfterTx == null) {
|
||||
final BigInt currentBalance = (await getBalance(publicAddress)).currentBalance;
|
||||
final BigInt txAmount = BigInt.parse(amountRaw);
|
||||
balanceAfterTx = currentBalance - txAmount;
|
||||
}
|
||||
|
||||
// get the account info (we need the frontier and representative):
|
||||
AccountInfoResponse? infoResponse = await getAccountInfo(publicAddress);
|
||||
if (infoResponse == null) {
|
||||
throw Exception(
|
||||
"error while getting account info! (we probably don't have an open account yet)");
|
||||
}
|
||||
|
||||
String frontier = infoResponse.frontier;
|
||||
// override if provided:
|
||||
if (previousHash != null) {
|
||||
frontier = previousHash;
|
||||
}
|
||||
final String representative = infoResponse.representative;
|
||||
// link = destination address:
|
||||
final String link = NanoAccounts.extractPublicKey(destinationAddress);
|
||||
final String linkAsAccount = destinationAddress;
|
||||
|
||||
// construct the send block:
|
||||
Map<String, String> sendBlock = {
|
||||
"type": "state",
|
||||
"account": publicAddress,
|
||||
"previous": frontier,
|
||||
"representative": representative,
|
||||
"balance": balanceAfterTx.toString(),
|
||||
"link": link,
|
||||
};
|
||||
|
||||
// sign the send block:
|
||||
final String hash = NanoBlocks.computeStateHash(
|
||||
NanoAccountType.NANO,
|
||||
sendBlock["account"]!,
|
||||
sendBlock["previous"]!,
|
||||
sendBlock["representative"]!,
|
||||
BigInt.parse(sendBlock["balance"]!),
|
||||
sendBlock["link"]!,
|
||||
);
|
||||
final String signature = NanoSignatures.signBlock(hash, privateKey);
|
||||
|
||||
// get PoW for the send block:
|
||||
final String work = await requestWork(frontier);
|
||||
|
||||
sendBlock["link_as_account"] = linkAsAccount;
|
||||
sendBlock["signature"] = signature;
|
||||
sendBlock["work"] = work;
|
||||
|
||||
// ready to post send block:
|
||||
return sendBlock;
|
||||
} catch (e) {
|
||||
print(e);
|
||||
rethrow;
|
||||
// first get the current account balance:
|
||||
if (balanceAfterTx == null) {
|
||||
final BigInt currentBalance = (await getBalance(publicAddress)).currentBalance;
|
||||
final BigInt txAmount = BigInt.parse(amountRaw);
|
||||
balanceAfterTx = currentBalance - txAmount;
|
||||
}
|
||||
|
||||
// get the account info (we need the frontier and representative):
|
||||
AccountInfoResponse? infoResponse = await getAccountInfo(publicAddress);
|
||||
if (infoResponse == null) {
|
||||
throw Exception(
|
||||
"error while getting account info! (we probably don't have an open account yet)");
|
||||
}
|
||||
|
||||
String frontier = infoResponse.frontier;
|
||||
// override if provided:
|
||||
if (previousHash != null) {
|
||||
frontier = previousHash;
|
||||
}
|
||||
final String representative = infoResponse.representative;
|
||||
// link = destination address:
|
||||
final String link = NanoAccounts.extractPublicKey(destinationAddress);
|
||||
final String linkAsAccount = destinationAddress;
|
||||
|
||||
// construct the send block:
|
||||
Map<String, String> sendBlock = {
|
||||
"type": "state",
|
||||
"account": publicAddress,
|
||||
"previous": frontier,
|
||||
"representative": representative,
|
||||
"balance": balanceAfterTx.toString(),
|
||||
"link": link,
|
||||
};
|
||||
|
||||
// sign the send block:
|
||||
final String hash = NanoBlocks.computeStateHash(
|
||||
NanoAccountType.NANO,
|
||||
sendBlock["account"]!,
|
||||
sendBlock["previous"]!,
|
||||
sendBlock["representative"]!,
|
||||
BigInt.parse(sendBlock["balance"]!),
|
||||
sendBlock["link"]!,
|
||||
);
|
||||
final String signature = NanoSignatures.signBlock(hash, privateKey);
|
||||
|
||||
// get PoW for the send block:
|
||||
final String work = await requestWork(frontier);
|
||||
|
||||
sendBlock["link_as_account"] = linkAsAccount;
|
||||
sendBlock["signature"] = signature;
|
||||
sendBlock["work"] = work;
|
||||
|
||||
// ready to post send block:
|
||||
return sendBlock;
|
||||
}
|
||||
|
||||
Future<void> receiveBlock({
|
||||
|
@ -274,7 +280,7 @@ class NanoClient {
|
|||
// account is not open yet, we need to create an open block:
|
||||
openBlock = true;
|
||||
// we don't have a representative set yet:
|
||||
representative = DEFAULT_REPRESENTATIVE;
|
||||
representative = await getRepFromPrefs();
|
||||
// we don't have a frontier yet:
|
||||
frontier = "0000000000000000000000000000000000000000000000000000000000000000";
|
||||
} else {
|
||||
|
|
|
@ -382,7 +382,7 @@ abstract class NanoWalletBase
|
|||
_representativeAddress = accountInfo.representative;
|
||||
} catch (e) {
|
||||
// account not found:
|
||||
_representativeAddress = NanoClient.DEFAULT_REPRESENTATIVE;
|
||||
_representativeAddress = await _client.getRepFromPrefs();
|
||||
throw Exception("Failed to get representative address $e");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -290,6 +290,11 @@ packages:
|
|||
description: flutter
|
||||
source: sdk
|
||||
version: "0.0.0"
|
||||
flutter_web_plugins:
|
||||
dependency: transitive
|
||||
description: flutter
|
||||
source: sdk
|
||||
version: "0.0.0"
|
||||
frontend_server_client:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -486,50 +491,50 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: path_provider
|
||||
sha256: "3087813781ab814e4157b172f1a11c46be20179fcc9bea043e0fba36bc0acaa2"
|
||||
sha256: a1aa8aaa2542a6bc57e381f132af822420216c80d4781f7aa085ca3229208aaa
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.15"
|
||||
version: "2.1.1"
|
||||
path_provider_android:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: path_provider_android
|
||||
sha256: "2cec049d282c7f13c594b4a73976b0b4f2d7a1838a6dd5aaf7bd9719196bee86"
|
||||
sha256: e595b98692943b4881b219f0a9e3945118d3c16bd7e2813f98ec6e532d905f72
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.27"
|
||||
version: "2.2.1"
|
||||
path_provider_foundation:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: path_provider_foundation
|
||||
sha256: "916731ccbdce44d545414dd9961f26ba5fbaa74bcbb55237d8e65a623a8c7297"
|
||||
sha256: "19314d595120f82aca0ba62787d58dde2cc6b5df7d2f0daf72489e38d1b57f2d"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.2.4"
|
||||
version: "2.3.1"
|
||||
path_provider_linux:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: path_provider_linux
|
||||
sha256: ffbb8cc9ed2c9ec0e4b7a541e56fd79b138e8f47d2fb86815f15358a349b3b57
|
||||
sha256: f7a1fe3a634fe7734c8d3f2766ad746ae2a2884abe22e241a8b301bf5cac3279
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.11"
|
||||
version: "2.2.1"
|
||||
path_provider_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: path_provider_platform_interface
|
||||
sha256: "57585299a729335f1298b43245842678cb9f43a6310351b18fb577d6e33165ec"
|
||||
sha256: "94b1e0dd80970c1ce43d5d4e050a9918fce4f4a775e6142424c30a29a363265c"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.6"
|
||||
version: "2.1.1"
|
||||
path_provider_windows:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: path_provider_windows
|
||||
sha256: "1cb68ba4cd3a795033de62ba1b7b4564dace301f952de6bfb3cd91b202b6ee96"
|
||||
sha256: "8bc9f22eee8690981c22aa7fc602f5c85b497a6fb2ceb35ee5a5e5ed85ad8170"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.7"
|
||||
version: "2.2.1"
|
||||
pinenacl:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -594,6 +599,62 @@ packages:
|
|||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.2.2"
|
||||
shared_preferences:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: shared_preferences
|
||||
sha256: "81429e4481e1ccfb51ede496e916348668fd0921627779233bd24cc3ff6abd02"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.2.2"
|
||||
shared_preferences_android:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shared_preferences_android
|
||||
sha256: "8568a389334b6e83415b6aae55378e158fbc2314e074983362d20c562780fb06"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.2.1"
|
||||
shared_preferences_foundation:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shared_preferences_foundation
|
||||
sha256: "7bf53a9f2d007329ee6f3df7268fd498f8373602f943c975598bbb34649b62a7"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.3.4"
|
||||
shared_preferences_linux:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shared_preferences_linux
|
||||
sha256: "9f2cbcf46d4270ea8be39fa156d86379077c8a5228d9dfdb1164ae0bb93f1faa"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.3.2"
|
||||
shared_preferences_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shared_preferences_platform_interface
|
||||
sha256: d4ec5fc9ebb2f2e056c617112aa75dcf92fc2e4faaf2ae999caa297473f75d8a
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.3.1"
|
||||
shared_preferences_web:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shared_preferences_web
|
||||
sha256: d762709c2bbe80626ecc819143013cc820fa49ca5e363620ee20a8b15a3e3daf
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.2.1"
|
||||
shared_preferences_windows:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shared_preferences_windows
|
||||
sha256: "841ad54f3c8381c480d0c9b508b89a34036f512482c407e6df7a9c4aa2ef8f59"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.3.2"
|
||||
shelf:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -615,6 +676,14 @@ packages:
|
|||
description: flutter
|
||||
source: sdk
|
||||
version: "0.0.99"
|
||||
socks5_proxy:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: socks5_proxy
|
||||
sha256: "1d21b5606169654bbf4cfb904e8e6ed897e9f763358709f87310c757096d909a"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.4"
|
||||
source_gen:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -695,6 +764,15 @@ packages:
|
|||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.1"
|
||||
tor:
|
||||
dependency: transitive
|
||||
description:
|
||||
path: "."
|
||||
ref: main
|
||||
resolved-ref: "09ba92cb11d4e3cacf97256e57863b805f79f2e5"
|
||||
url: "https://github.com/cake-tech/tor.git"
|
||||
source: git
|
||||
version: "0.0.1"
|
||||
typed_data:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -753,4 +831,4 @@ packages:
|
|||
version: "3.1.2"
|
||||
sdks:
|
||||
dart: ">=3.0.0 <4.0.0"
|
||||
flutter: ">=3.3.0"
|
||||
flutter: ">=3.7.0"
|
||||
|
|
|
@ -21,6 +21,7 @@ dependencies:
|
|||
ed25519_hd_key: ^2.2.0
|
||||
hex: ^0.2.0
|
||||
http: ^1.1.0
|
||||
shared_preferences: ^2.0.15
|
||||
cw_core:
|
||||
path: ../cw_core
|
||||
|
||||
|
|
|
@ -2,14 +2,14 @@ group 'com.cakewallet.cw_shared_external'
|
|||
version '1.0-SNAPSHOT'
|
||||
|
||||
buildscript {
|
||||
ext.kotlin_version = '1.3.50'
|
||||
ext.kotlin_version = '1.7.10'
|
||||
repositories {
|
||||
google()
|
||||
jcenter()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:4.1.0'
|
||||
classpath 'com.android.tools.build:gradle:7.3.0'
|
||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -63,8 +63,6 @@ PODS:
|
|||
- Flutter
|
||||
- device_display_brightness (0.0.1):
|
||||
- Flutter
|
||||
- device_info (0.0.1):
|
||||
- Flutter
|
||||
- device_info_plus (0.0.1):
|
||||
- Flutter
|
||||
- devicelocale (0.0.1):
|
||||
|
@ -126,13 +124,13 @@ PODS:
|
|||
- OrderedSet (5.0.0)
|
||||
- package_info (0.0.1):
|
||||
- Flutter
|
||||
- package_info_plus (0.4.5):
|
||||
- Flutter
|
||||
- path_provider_foundation (0.0.1):
|
||||
- Flutter
|
||||
- FlutterMacOS
|
||||
- permission_handler_apple (9.1.1):
|
||||
- Flutter
|
||||
- platform_device_id (0.0.1):
|
||||
- Flutter
|
||||
- ReachabilitySwift (5.0.0)
|
||||
- SDWebImage (5.16.0):
|
||||
- SDWebImage/Core (= 5.16.0)
|
||||
|
@ -147,6 +145,8 @@ PODS:
|
|||
- SwiftProtobuf (1.22.0)
|
||||
- SwiftyGif (5.4.4)
|
||||
- Toast (4.0.0)
|
||||
- tor (0.0.1):
|
||||
- Flutter
|
||||
- uni_links (0.0.1):
|
||||
- Flutter
|
||||
- UnstoppableDomainsResolution (4.0.0):
|
||||
|
@ -154,7 +154,7 @@ PODS:
|
|||
- CryptoSwift
|
||||
- url_launcher_ios (0.0.1):
|
||||
- Flutter
|
||||
- wakelock (0.0.1):
|
||||
- wakelock_plus (0.0.1):
|
||||
- Flutter
|
||||
- workmanager (0.0.1):
|
||||
- Flutter
|
||||
|
@ -167,7 +167,6 @@ DEPENDENCIES:
|
|||
- cw_monero (from `.symlinks/plugins/cw_monero/ios`)
|
||||
- cw_shared_external (from `.symlinks/plugins/cw_shared_external/ios`)
|
||||
- device_display_brightness (from `.symlinks/plugins/device_display_brightness/ios`)
|
||||
- device_info (from `.symlinks/plugins/device_info/ios`)
|
||||
- device_info_plus (from `.symlinks/plugins/device_info_plus/ios`)
|
||||
- devicelocale (from `.symlinks/plugins/devicelocale/ios`)
|
||||
- file_picker (from `.symlinks/plugins/file_picker/ios`)
|
||||
|
@ -179,16 +178,17 @@ DEPENDENCIES:
|
|||
- in_app_review (from `.symlinks/plugins/in_app_review/ios`)
|
||||
- local_auth_ios (from `.symlinks/plugins/local_auth_ios/ios`)
|
||||
- package_info (from `.symlinks/plugins/package_info/ios`)
|
||||
- package_info_plus (from `.symlinks/plugins/package_info_plus/ios`)
|
||||
- path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`)
|
||||
- permission_handler_apple (from `.symlinks/plugins/permission_handler_apple/ios`)
|
||||
- platform_device_id (from `.symlinks/plugins/platform_device_id/ios`)
|
||||
- sensitive_clipboard (from `.symlinks/plugins/sensitive_clipboard/ios`)
|
||||
- share_plus (from `.symlinks/plugins/share_plus/ios`)
|
||||
- shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`)
|
||||
- tor (from `.symlinks/plugins/tor/ios`)
|
||||
- uni_links (from `.symlinks/plugins/uni_links/ios`)
|
||||
- UnstoppableDomainsResolution (~> 4.0.0)
|
||||
- url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`)
|
||||
- wakelock (from `.symlinks/plugins/wakelock/ios`)
|
||||
- wakelock_plus (from `.symlinks/plugins/wakelock_plus/ios`)
|
||||
- workmanager (from `.symlinks/plugins/workmanager/ios`)
|
||||
|
||||
SPEC REPOS:
|
||||
|
@ -219,8 +219,6 @@ EXTERNAL SOURCES:
|
|||
:path: ".symlinks/plugins/cw_shared_external/ios"
|
||||
device_display_brightness:
|
||||
:path: ".symlinks/plugins/device_display_brightness/ios"
|
||||
device_info:
|
||||
:path: ".symlinks/plugins/device_info/ios"
|
||||
device_info_plus:
|
||||
:path: ".symlinks/plugins/device_info_plus/ios"
|
||||
devicelocale:
|
||||
|
@ -243,24 +241,26 @@ EXTERNAL SOURCES:
|
|||
:path: ".symlinks/plugins/local_auth_ios/ios"
|
||||
package_info:
|
||||
:path: ".symlinks/plugins/package_info/ios"
|
||||
package_info_plus:
|
||||
:path: ".symlinks/plugins/package_info_plus/ios"
|
||||
path_provider_foundation:
|
||||
:path: ".symlinks/plugins/path_provider_foundation/darwin"
|
||||
permission_handler_apple:
|
||||
:path: ".symlinks/plugins/permission_handler_apple/ios"
|
||||
platform_device_id:
|
||||
:path: ".symlinks/plugins/platform_device_id/ios"
|
||||
sensitive_clipboard:
|
||||
:path: ".symlinks/plugins/sensitive_clipboard/ios"
|
||||
share_plus:
|
||||
:path: ".symlinks/plugins/share_plus/ios"
|
||||
shared_preferences_foundation:
|
||||
:path: ".symlinks/plugins/shared_preferences_foundation/darwin"
|
||||
tor:
|
||||
:path: ".symlinks/plugins/tor/ios"
|
||||
uni_links:
|
||||
:path: ".symlinks/plugins/uni_links/ios"
|
||||
url_launcher_ios:
|
||||
:path: ".symlinks/plugins/url_launcher_ios/ios"
|
||||
wakelock:
|
||||
:path: ".symlinks/plugins/wakelock/ios"
|
||||
wakelock_plus:
|
||||
:path: ".symlinks/plugins/wakelock_plus/ios"
|
||||
workmanager:
|
||||
:path: ".symlinks/plugins/workmanager/ios"
|
||||
|
||||
|
@ -273,12 +273,11 @@ SPEC CHECKSUMS:
|
|||
cw_monero: 4cf3b96f2da8e95e2ef7d6703dd4d2c509127b7d
|
||||
cw_shared_external: 2972d872b8917603478117c9957dfca611845a92
|
||||
device_display_brightness: 1510e72c567a1f6ce6ffe393dcd9afd1426034f7
|
||||
device_info: d7d233b645a32c40dfdc212de5cf646ca482f175
|
||||
device_info_plus: e5c5da33f982a436e103237c0c85f9031142abed
|
||||
device_info_plus: c6fb39579d0f423935b0c9ce7ee2f44b71b9fce6
|
||||
devicelocale: b22617f40038496deffba44747101255cee005b0
|
||||
DKImagePickerController: b512c28220a2b8ac7419f21c491fc8534b7601ac
|
||||
DKPhotoGallery: fdfad5125a9fdda9cc57df834d49df790dbb4179
|
||||
file_picker: ce3938a0df3cc1ef404671531facef740d03f920
|
||||
file_picker: 15fd9539e4eb735dc54bae8c0534a7a9511a03de
|
||||
Flutter: f04841e97a9d0b0a8025694d0796dd46242b2854
|
||||
flutter_inappwebview: 3d32228f1304635e7c028b0d4252937730bbc6cf
|
||||
flutter_mailer: 2ef5a67087bc8c6c4cefd04a178bf1ae2c94cd83
|
||||
|
@ -289,9 +288,9 @@ SPEC CHECKSUMS:
|
|||
MTBBarcodeScanner: f453b33c4b7dfe545d8c6484ed744d55671788cb
|
||||
OrderedSet: aaeb196f7fef5a9edf55d89760da9176ad40b93c
|
||||
package_info: 873975fc26034f0b863a300ad47e7f1ac6c7ec62
|
||||
package_info_plus: 115f4ad11e0698c8c1c5d8a689390df880f47e85
|
||||
path_provider_foundation: 29f094ae23ebbca9d3d0cec13889cd9060c0e943
|
||||
permission_handler_apple: e76247795d700c14ea09e3a2d8855d41ee80a2e6
|
||||
platform_device_id: 81b3e2993881f87d0c82ef151dc274df4869aef5
|
||||
ReachabilitySwift: 985039c6f7b23a1da463388634119492ff86c825
|
||||
SDWebImage: 2aea163b50bfcb569a2726b6a754c54a4506fcf6
|
||||
sensitive_clipboard: d4866e5d176581536c27bb1618642ee83adca986
|
||||
|
@ -300,10 +299,11 @@ SPEC CHECKSUMS:
|
|||
SwiftProtobuf: 40bd808372cb8706108f22d28f8ab4a6b9bc6989
|
||||
SwiftyGif: 93a1cc87bf3a51916001cf8f3d63835fb64c819f
|
||||
Toast: 91b396c56ee72a5790816f40d3a94dd357abc196
|
||||
tor: 662a9f5b980b5c86decb8ba611de9bcd4c8286eb
|
||||
uni_links: d97da20c7701486ba192624d99bffaaffcfc298a
|
||||
UnstoppableDomainsResolution: c3c67f4d0a5e2437cb00d4bd50c2e00d6e743841
|
||||
url_launcher_ios: 68d46cc9766d0c41dbdc884310529557e3cd7a86
|
||||
wakelock: d0fc7c864128eac40eba1617cb5264d9c940b46f
|
||||
url_launcher_ios: bf5ce03e0e2088bad9cc378ea97fa0ed5b49673b
|
||||
wakelock_plus: 8b09852c8876491e4b6d179e17dfe2a0b5f60d47
|
||||
workmanager: 0afdcf5628bbde6924c21af7836fed07b42e30e6
|
||||
|
||||
PODFILE CHECKSUM: 09df1114e7c360f55770d35a79356bf5446e0100
|
||||
|
|
|
@ -3,7 +3,6 @@ import 'dart:convert';
|
|||
import 'package:cake_wallet/.secrets.g.dart' as secrets;
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
|
||||
import 'package:cake_wallet/utils/exception_handler.dart';
|
||||
import 'package:cake_wallet/utils/show_pop_up.dart';
|
||||
import 'package:cw_core/wallet_base.dart';
|
||||
import 'package:cw_core/wallet_type.dart';
|
||||
|
@ -12,8 +11,7 @@ import 'package:http/http.dart' as http;
|
|||
import 'package:url_launcher/url_launcher.dart';
|
||||
|
||||
class RobinhoodBuyProvider {
|
||||
RobinhoodBuyProvider({required WalletBase wallet})
|
||||
: this._wallet = wallet;
|
||||
RobinhoodBuyProvider({required WalletBase wallet}) : this._wallet = wallet;
|
||||
|
||||
final WalletBase _wallet;
|
||||
|
||||
|
@ -21,10 +19,15 @@ class RobinhoodBuyProvider {
|
|||
static const _cIdBaseUrl = 'exchange-helper.cakewallet.com';
|
||||
|
||||
String get _applicationId => secrets.robinhoodApplicationId;
|
||||
|
||||
String get _apiSecret => secrets.robinhoodCIdApiSecret;
|
||||
|
||||
bool get isAvailable =>
|
||||
[WalletType.bitcoin, WalletType.litecoin, WalletType.ethereum].contains(_wallet.type);
|
||||
bool get isAvailable => [
|
||||
WalletType.bitcoin,
|
||||
WalletType.bitcoinCash,
|
||||
WalletType.litecoin,
|
||||
WalletType.ethereum
|
||||
].contains(_wallet.type);
|
||||
|
||||
String getSignature(String message) {
|
||||
switch (_wallet.type) {
|
||||
|
@ -32,6 +35,7 @@ class RobinhoodBuyProvider {
|
|||
return _wallet.signMessage(message);
|
||||
case WalletType.litecoin:
|
||||
case WalletType.bitcoin:
|
||||
case WalletType.bitcoinCash:
|
||||
return _wallet.signMessage(message, address: _wallet.walletAddresses.address);
|
||||
default:
|
||||
throw Exception("WalletType is not available for Robinhood ${_wallet.type}");
|
||||
|
@ -55,7 +59,8 @@ class RobinhoodBuyProvider {
|
|||
if (response.statusCode == 200) {
|
||||
return (jsonDecode(response.body) as Map<String, dynamic>)['connectId'] as String;
|
||||
} else {
|
||||
throw Exception('Provider currently unavailable. Status: ${response.statusCode} ${response.body}');
|
||||
throw Exception(
|
||||
'Provider currently unavailable. Status: ${response.statusCode} ${response.body}');
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -76,8 +81,7 @@ class RobinhoodBuyProvider {
|
|||
try {
|
||||
final uri = await requestUrl();
|
||||
await launchUrl(uri, mode: LaunchMode.externalApplication);
|
||||
} catch (e, s) {
|
||||
ExceptionHandler.onError(FlutterErrorDetails(exception: e, stack: s));
|
||||
} catch (_) {
|
||||
await showPopUp<void>(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
import 'dart:io';
|
||||
|
||||
import 'package:cake_wallet/core/totp_request_details.dart';
|
||||
import 'package:cake_wallet/routes.dart';
|
||||
import 'package:cake_wallet/src/screens/auth/auth_page.dart';
|
||||
|
@ -40,7 +42,9 @@ class AuthService with Store {
|
|||
final encodedPassword = encodedPinCode(pin: password);
|
||||
// secure storage has a weird bug on macOS, where overwriting a key doesn't work, unless
|
||||
// we delete what's there first:
|
||||
await secureStorage.delete(key: key);
|
||||
if (Platform.isMacOS) {
|
||||
await secureStorage.delete(key: key);
|
||||
}
|
||||
await secureStorage.write(key: key, value: encodedPassword);
|
||||
}
|
||||
|
||||
|
|
|
@ -247,6 +247,8 @@ class BackupService {
|
|||
final sortBalanceTokensBy = data[PreferencesKey.sortBalanceBy] as int?;
|
||||
final pinNativeTokenAtTop = data[PreferencesKey.pinNativeTokenAtTop] as bool?;
|
||||
final useEtherscan = data[PreferencesKey.useEtherscan] as bool?;
|
||||
final defaultNanoRep = data[PreferencesKey.defaultNanoRep] as String?;
|
||||
final defaultBananoRep = data[PreferencesKey.defaultBananoRep] as String?;
|
||||
final lookupsTwitter = data[PreferencesKey.lookupsTwitter] as bool?;
|
||||
final lookupsMastodon = data[PreferencesKey.lookupsMastodon] as bool?;
|
||||
final lookupsYatService = data[PreferencesKey.lookupsYatService] as bool?;
|
||||
|
@ -293,7 +295,7 @@ class BackupService {
|
|||
await _sharedPreferences.setInt(
|
||||
PreferencesKey.currentTransactionPriorityKeyLegacy, currentTransactionPriorityKeyLegacy);
|
||||
|
||||
if (Platform.isMacOS || Platform.isLinux) {
|
||||
if (DeviceInfo.instance.isDesktop) {
|
||||
await _sharedPreferences.setBool(PreferencesKey.allowBiometricalAuthenticationKey, false);
|
||||
} else if (allowBiometricalAuthentication != null) {
|
||||
await _sharedPreferences.setBool(
|
||||
|
@ -322,11 +324,10 @@ class BackupService {
|
|||
|
||||
if (currentTheme != null && DeviceInfo.instance.isMobile) {
|
||||
await _sharedPreferences.setInt(PreferencesKey.currentTheme, currentTheme);
|
||||
// enforce dark theme on desktop platforms until the design is ready:
|
||||
// enforce dark theme on desktop platforms until the design is ready:
|
||||
} else if (DeviceInfo.instance.isDesktop) {
|
||||
await _sharedPreferences.setInt(PreferencesKey.currentTheme, ThemeList.darkTheme.raw);
|
||||
}
|
||||
|
||||
|
||||
if (exchangeStatus != null)
|
||||
await _sharedPreferences.setInt(PreferencesKey.exchangeStatusKey, exchangeStatus);
|
||||
|
@ -389,6 +390,13 @@ class BackupService {
|
|||
if (useEtherscan != null)
|
||||
await _sharedPreferences.setBool(PreferencesKey.useEtherscan, useEtherscan);
|
||||
|
||||
if (defaultNanoRep != null)
|
||||
await _sharedPreferences.setString(PreferencesKey.defaultNanoRep, defaultNanoRep);
|
||||
|
||||
if (defaultBananoRep != null)
|
||||
await _sharedPreferences.setString(PreferencesKey.defaultBananoRep, defaultBananoRep);
|
||||
|
||||
if (syncAll != null) await _sharedPreferences.setBool(PreferencesKey.syncAllKey, syncAll);
|
||||
if (lookupsTwitter != null)
|
||||
await _sharedPreferences.setBool(PreferencesKey.lookupsTwitter, lookupsTwitter);
|
||||
|
||||
|
@ -560,6 +568,9 @@ class BackupService {
|
|||
PreferencesKey.pinNativeTokenAtTop:
|
||||
_sharedPreferences.getBool(PreferencesKey.pinNativeTokenAtTop),
|
||||
PreferencesKey.useEtherscan: _sharedPreferences.getBool(PreferencesKey.useEtherscan),
|
||||
PreferencesKey.defaultNanoRep: _sharedPreferences.getString(PreferencesKey.defaultNanoRep),
|
||||
PreferencesKey.defaultBananoRep:
|
||||
_sharedPreferences.getString(PreferencesKey.defaultBananoRep),
|
||||
PreferencesKey.lookupsTwitter: _sharedPreferences.getBool(PreferencesKey.lookupsTwitter),
|
||||
PreferencesKey.lookupsMastodon: _sharedPreferences.getBool(PreferencesKey.lookupsMastodon),
|
||||
PreferencesKey.lookupsYatService:
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import 'package:cake_wallet/di.dart';
|
||||
import 'package:cake_wallet/store/settings_store.dart';
|
||||
import 'package:cw_core/wallet_info.dart';
|
||||
import 'package:cake_wallet/entities/preferences_key.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
|
@ -18,6 +19,7 @@ class WalletCreationService {
|
|||
required this.secureStorage,
|
||||
required this.keyService,
|
||||
required this.sharedPreferences,
|
||||
required this.settingsStore,
|
||||
required this.walletInfoSource})
|
||||
: type = initialType {
|
||||
changeWalletType(type: type);
|
||||
|
@ -26,6 +28,7 @@ class WalletCreationService {
|
|||
WalletType type;
|
||||
final FlutterSecureStorage secureStorage;
|
||||
final SharedPreferences sharedPreferences;
|
||||
final SettingsStore settingsStore;
|
||||
final KeyService keyService;
|
||||
final Box<WalletInfo> walletInfoSource;
|
||||
WalletService? _service;
|
||||
|
@ -56,6 +59,9 @@ class WalletCreationService {
|
|||
checkIfExists(credentials.name);
|
||||
final password = generateWalletPassword();
|
||||
credentials.password = password;
|
||||
if (type == WalletType.bitcoinCash || type == WalletType.ethereum) {
|
||||
credentials.seedPhraseLength = settingsStore.seedPhraseLength.value;
|
||||
}
|
||||
await keyService.saveWalletPassword(password: password, walletName: credentials.name);
|
||||
final wallet = await _service!.create(credentials);
|
||||
|
||||
|
|
29
lib/di.dart
29
lib/di.dart
|
@ -28,8 +28,8 @@ import 'package:cake_wallet/src/screens/dashboard/desktop_widgets/desktop_sideba
|
|||
import 'package:cake_wallet/src/screens/dashboard/desktop_widgets/desktop_wallet_selection_dropdown.dart';
|
||||
import 'package:cake_wallet/src/screens/dashboard/edit_token_page.dart';
|
||||
import 'package:cake_wallet/src/screens/dashboard/home_settings_page.dart';
|
||||
import 'package:cake_wallet/src/screens/dashboard/widgets/transactions_page.dart';
|
||||
import 'package:cake_wallet/src/screens/exchange/exchange_options_page.dart';
|
||||
import 'package:cake_wallet/src/screens/dashboard/pages/transactions_page.dart';
|
||||
import 'package:cake_wallet/src/screens/nano/nano_change_rep_page.dart';
|
||||
import 'package:cake_wallet/src/screens/nano_accounts/nano_account_edit_or_create_page.dart';
|
||||
import 'package:cake_wallet/src/screens/nano_accounts/nano_account_list_page.dart';
|
||||
|
@ -47,6 +47,8 @@ import 'package:cake_wallet/src/screens/ionia/cards/ionia_custom_redeem_page.dar
|
|||
import 'package:cake_wallet/src/screens/ionia/cards/ionia_gift_card_detail_page.dart';
|
||||
import 'package:cake_wallet/src/screens/ionia/cards/ionia_more_options_page.dart';
|
||||
import 'package:cake_wallet/src/screens/settings/connection_sync_page.dart';
|
||||
import 'package:cake_wallet/src/screens/settings/trocador_providers_page.dart';
|
||||
import 'package:cake_wallet/src/screens/settings/tor_page.dart';
|
||||
import 'package:cake_wallet/src/screens/setup_2fa/modify_2fa_page.dart';
|
||||
import 'package:cake_wallet/src/screens/setup_2fa/setup_2fa_qr_page.dart';
|
||||
import 'package:cake_wallet/src/screens/setup_2fa/setup_2fa.dart';
|
||||
|
@ -65,6 +67,7 @@ import 'package:cake_wallet/view_model/anon_invoice_page_view_model.dart';
|
|||
import 'package:cake_wallet/view_model/anonpay_details_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/dashboard/home_settings_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/dashboard/market_place_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/dashboard/nft_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/dashboard/receive_option_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/ionia/ionia_auth_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/ionia/ionia_buy_card_view_model.dart';
|
||||
|
@ -80,7 +83,7 @@ import 'package:cake_wallet/src/screens/ionia/cards/ionia_account_cards_page.dar
|
|||
import 'package:cake_wallet/src/screens/ionia/cards/ionia_account_page.dart';
|
||||
import 'package:cake_wallet/src/screens/ionia/cards/ionia_custom_tip_page.dart';
|
||||
import 'package:cake_wallet/src/screens/ionia/ionia.dart';
|
||||
import 'package:cake_wallet/src/screens/dashboard/widgets/balance_page.dart';
|
||||
import 'package:cake_wallet/src/screens/dashboard/pages/balance_page.dart';
|
||||
import 'package:cake_wallet/view_model/ionia/ionia_account_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/ionia/ionia_gift_cards_list_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/ionia/ionia_purchase_merch_view_model.dart';
|
||||
|
@ -94,6 +97,7 @@ import 'package:cake_wallet/view_model/settings/other_settings_view_model.dart';
|
|||
import 'package:cake_wallet/view_model/settings/privacy_settings_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/settings/security_settings_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/advanced_privacy_settings_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/settings/trocador_providers_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/wallet_address_list/wallet_address_list_item.dart';
|
||||
import 'package:cake_wallet/view_model/wallet_list/wallet_edit_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/wallet_list/wallet_list_item.dart';
|
||||
|
@ -211,7 +215,7 @@ import 'package:cake_wallet/store/templates/exchange_template_store.dart';
|
|||
import 'package:cake_wallet/entities/template.dart';
|
||||
import 'package:cake_wallet/exchange/exchange_template.dart';
|
||||
import 'package:cake_wallet/.secrets.g.dart' as secrets;
|
||||
import 'package:cake_wallet/src/screens/dashboard/widgets/address_page.dart';
|
||||
import 'package:cake_wallet/src/screens/dashboard/pages/address_page.dart';
|
||||
import 'package:cake_wallet/anypay/anypay_api.dart';
|
||||
import 'package:cake_wallet/view_model/ionia/ionia_gift_card_details_view_model.dart';
|
||||
import 'package:cake_wallet/src/screens/ionia/cards/ionia_payment_status_page.dart';
|
||||
|
@ -333,6 +337,7 @@ Future<void> setup({
|
|||
keyService: getIt.get<KeyService>(),
|
||||
secureStorage: getIt.get<FlutterSecureStorage>(),
|
||||
sharedPreferences: getIt.get<SharedPreferences>(),
|
||||
settingsStore: getIt.get<SettingsStore>(),
|
||||
walletInfoSource: _walletInfoSource));
|
||||
|
||||
getIt.registerFactory<WalletLoadingService>(() => WalletLoadingService(
|
||||
|
@ -480,6 +485,7 @@ Future<void> setup({
|
|||
});
|
||||
|
||||
getIt.registerFactory(() => BalancePage(
|
||||
nftViewModel: getIt.get<NFTViewModel>(),
|
||||
dashboardViewModel: getIt.get<DashboardViewModel>(),
|
||||
settingsStore: getIt.get<SettingsStore>()));
|
||||
|
||||
|
@ -700,6 +706,8 @@ Future<void> setup({
|
|||
return PrivacySettingsViewModel(getIt.get<SettingsStore>(), getIt.get<AppStore>().wallet!);
|
||||
});
|
||||
|
||||
getIt.registerFactory(() => TrocadorProvidersViewModel(getIt.get<SettingsStore>()));
|
||||
|
||||
getIt.registerFactory(() {
|
||||
return OtherSettingsViewModel(getIt.get<SettingsStore>(), getIt.get<AppStore>().wallet!);
|
||||
});
|
||||
|
@ -753,13 +761,18 @@ Future<void> setup({
|
|||
|
||||
getIt.registerFactory(() => PrivacyPage(getIt.get<PrivacySettingsViewModel>()));
|
||||
|
||||
getIt.registerFactory(() => TrocadorProvidersPage(getIt.get<TrocadorProvidersViewModel>()));
|
||||
|
||||
getIt.registerFactory(() => DomainLookupsPage(getIt.get<PrivacySettingsViewModel>()));
|
||||
|
||||
getIt.registerFactory(() => DisplaySettingsPage(getIt.get<DisplaySettingsViewModel>()));
|
||||
|
||||
getIt.registerFactory(() => OtherSettingsPage(getIt.get<OtherSettingsViewModel>()));
|
||||
|
||||
getIt.registerFactory(() => NanoChangeRepPage(getIt.get<AppStore>().wallet!));
|
||||
getIt.registerFactory(() => NanoChangeRepPage(
|
||||
settingsStore: getIt.get<AppStore>().settingsStore,
|
||||
wallet: getIt.get<AppStore>().wallet!,
|
||||
));
|
||||
|
||||
getIt.registerFactoryParam<NodeCreateOrEditViewModel, WalletType?, bool?>(
|
||||
(WalletType? type, bool? isPow) => NodeCreateOrEditViewModel(
|
||||
|
@ -895,8 +908,9 @@ Future<void> setup({
|
|||
getIt.registerFactoryParam<NewWalletTypePage, void Function(BuildContext, WalletType), bool?>(
|
||||
(param1, isCreate) => NewWalletTypePage(onTypeSelected: param1, isCreate: isCreate ?? true));
|
||||
|
||||
getIt.registerFactoryParam<PreSeedPage, WalletType, void>(
|
||||
(WalletType type, _) => PreSeedPage(type));
|
||||
getIt.registerFactoryParam<PreSeedPage, WalletType, AdvancedPrivacySettingsViewModel>(
|
||||
(WalletType type, AdvancedPrivacySettingsViewModel advancedPrivacySettingsViewModel) =>
|
||||
PreSeedPage(type, advancedPrivacySettingsViewModel));
|
||||
|
||||
getIt.registerFactoryParam<TradeDetailsViewModel, Trade, void>((trade, _) =>
|
||||
TradeDetailsViewModel(
|
||||
|
@ -1171,5 +1185,8 @@ Future<void> setup({
|
|||
getIt.registerFactory(
|
||||
() => WalletConnectConnectionsView(web3walletService: getIt.get<Web3WalletService>()));
|
||||
|
||||
getIt.registerFactory(() => NFTViewModel(appStore, getIt.get<BottomSheetService>()));
|
||||
getIt.registerFactory<TorPage>(() => TorPage(getIt.get<AppStore>()));
|
||||
|
||||
_isSetupFinished = true;
|
||||
}
|
||||
|
|
|
@ -53,7 +53,7 @@ class MainActions {
|
|||
case WalletType.bitcoin:
|
||||
case WalletType.litecoin:
|
||||
case WalletType.ethereum:
|
||||
// case WalletType.bitcoinCash: // TODO: add sign message function to BCH first
|
||||
case WalletType.bitcoinCash:
|
||||
switch (defaultBuyProvider) {
|
||||
case BuyProviderType.AskEachTime:
|
||||
Navigator.pushNamed(context, Routes.buy);
|
||||
|
|
|
@ -51,6 +51,8 @@ class PreferencesKey {
|
|||
static const sortBalanceBy = 'sort_balance_by';
|
||||
static const pinNativeTokenAtTop = 'pin_native_token_at_top';
|
||||
static const useEtherscan = 'use_etherscan';
|
||||
static const defaultNanoRep = 'default_nano_representative';
|
||||
static const defaultBananoRep = 'default_banano_representative';
|
||||
static const lookupsTwitter = 'looks_up_twitter';
|
||||
static const lookupsMastodon = 'looks_up_mastodon';
|
||||
static const lookupsYatService = 'looks_up_mastodon';
|
||||
|
@ -88,4 +90,5 @@ class PreferencesKey {
|
|||
'should_require_totp_2fa_for_all_security_and_backup_settings';
|
||||
static const selectedCake2FAPreset = 'selected_cake_2fa_preset';
|
||||
static const totpSecretKey = 'totp_secret_key';
|
||||
static const currentSeedPhraseLength = 'current_seed_phrase_length';
|
||||
}
|
||||
|
|
26
lib/entities/seed_phrase_length.dart
Normal file
26
lib/entities/seed_phrase_length.dart
Normal file
|
@ -0,0 +1,26 @@
|
|||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
|
||||
enum SeedPhraseLength {
|
||||
twelveWords(12),
|
||||
twentyFourWords(24);
|
||||
|
||||
const SeedPhraseLength(this.value);
|
||||
final int value;
|
||||
|
||||
static SeedPhraseLength deserialize({required int raw}) =>
|
||||
SeedPhraseLength.values.firstWhere((e) => e.value == raw);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
String label = '';
|
||||
switch (this) {
|
||||
case SeedPhraseLength.twelveWords:
|
||||
label = '12 Words';
|
||||
break;
|
||||
case SeedPhraseLength.twentyFourWords:
|
||||
label = '24 Words';
|
||||
break;
|
||||
}
|
||||
return label;
|
||||
}
|
||||
}
|
95
lib/entities/wallet_nft_response.dart
Normal file
95
lib/entities/wallet_nft_response.dart
Normal file
|
@ -0,0 +1,95 @@
|
|||
class WalletNFTsResponseModel {
|
||||
final int? page;
|
||||
final int? pageSize;
|
||||
|
||||
final List<NFTAssetModel>? result;
|
||||
final String? status;
|
||||
|
||||
WalletNFTsResponseModel({this.page, this.pageSize, this.result, this.status});
|
||||
|
||||
factory WalletNFTsResponseModel.fromJson(Map<String, dynamic> json) {
|
||||
return WalletNFTsResponseModel(
|
||||
page: json['page'] as int?,
|
||||
pageSize: json['page_size'] as int?,
|
||||
result: (json['result'] as List?)
|
||||
?.map((x) => NFTAssetModel.fromJson(x as Map<String, dynamic>))
|
||||
.toList(),
|
||||
status: json['status'] as String?,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class NFTAssetModel {
|
||||
final String? tokenAddress;
|
||||
final String? tokenId;
|
||||
final String? contractType;
|
||||
final String? name;
|
||||
final String? symbol;
|
||||
NormalizedMetadata? normalizedMetadata;
|
||||
|
||||
NFTAssetModel(
|
||||
{this.tokenAddress,
|
||||
this.tokenId,
|
||||
this.contractType,
|
||||
this.name,
|
||||
this.symbol,
|
||||
this.normalizedMetadata});
|
||||
|
||||
factory NFTAssetModel.fromJson(Map<String, dynamic> json) {
|
||||
return NFTAssetModel(
|
||||
tokenAddress: json['token_address'] as String?,
|
||||
tokenId: json['token_id'] as String?,
|
||||
contractType: json['contract_type'] as String?,
|
||||
name: json['name'] as String?,
|
||||
symbol: json['symbol'] as String?,
|
||||
normalizedMetadata: json['normalized_metadata'] != null
|
||||
? new NormalizedMetadata.fromJson(
|
||||
json['normalized_metadata'] as Map<String, dynamic>)
|
||||
: null,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class NormalizedMetadata {
|
||||
final String? name;
|
||||
final String? description;
|
||||
final String? image;
|
||||
NormalizedMetadata({
|
||||
this.name,
|
||||
this.description,
|
||||
this.image,
|
||||
});
|
||||
|
||||
factory NormalizedMetadata.fromJson(Map<String, dynamic> json) {
|
||||
return NormalizedMetadata(
|
||||
name: json['name'] as String?,
|
||||
description: json['description'] as String?,
|
||||
image: json['image'] as String?,
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
String? get imageUrl {
|
||||
if (image == null) return image;
|
||||
|
||||
if (image!.contains('ipfs.io')) return image;
|
||||
|
||||
if (!image!.contains('ipfs')) return image;
|
||||
|
||||
// IPFS public gateway provided by Cloudflare is https://cloudflare-ipfs.com/ipfs/
|
||||
//
|
||||
// Here is an example of an ipfs image link:
|
||||
//
|
||||
// [ipfs://bafkreia2i2ctfexpovgzfff66wqhbmwwpvqjvozan7ioifzcnq76jharwu]
|
||||
|
||||
//https://ipfs.io/ipfs/QmTRcRXo6cXByjHYHTVxGpag6vpocrG3rxjPC9PxKAArR9/1620.png
|
||||
|
||||
const String ipfsPublicGateway = 'https://cloudflare-ipfs.com/ipfs/';
|
||||
|
||||
final ipfsPath = image?.split('//')[1];
|
||||
|
||||
final imageLink = '$ipfsPublicGateway$ipfsPath';
|
||||
|
||||
return imageLink;
|
||||
}
|
||||
}
|
|
@ -12,11 +12,27 @@ import 'package:cw_core/crypto_currency.dart';
|
|||
import 'package:http/http.dart';
|
||||
|
||||
class TrocadorExchangeProvider extends ExchangeProvider {
|
||||
TrocadorExchangeProvider({this.useTorOnly = false})
|
||||
: _lastUsedRateId = '',
|
||||
TrocadorExchangeProvider({this.useTorOnly = false, this.providerStates = const {}})
|
||||
: _lastUsedRateId = '', _provider = [],
|
||||
super(pairList: supportedPairs(_notSupported));
|
||||
|
||||
bool useTorOnly;
|
||||
final Map<String, bool> providerStates;
|
||||
|
||||
static const List<String> availableProviders = [
|
||||
'Swapter',
|
||||
'StealthEx',
|
||||
'Simpleswap',
|
||||
'Swapuz'
|
||||
'ChangeNow',
|
||||
'Changehero',
|
||||
'FixedFloat',
|
||||
'LetsExchange',
|
||||
'Exolix',
|
||||
'Godex',
|
||||
'Exch',
|
||||
'CoinCraddle'
|
||||
];
|
||||
|
||||
static const List<CryptoCurrency> _notSupported = [
|
||||
CryptoCurrency.stx,
|
||||
|
@ -33,6 +49,7 @@ class TrocadorExchangeProvider extends ExchangeProvider {
|
|||
static const coinPath = 'api/coin';
|
||||
|
||||
String _lastUsedRateId;
|
||||
List<dynamic> _provider;
|
||||
|
||||
@override
|
||||
String get title => 'Trocador';
|
||||
|
@ -105,7 +122,6 @@ class TrocadorExchangeProvider extends ExchangeProvider {
|
|||
'payment': isFixedRateMode ? 'True' : 'False',
|
||||
'min_kycrating': 'C',
|
||||
'markup': markup,
|
||||
'best_only': 'True',
|
||||
};
|
||||
|
||||
final uri = await _getUri(newRatePath, params);
|
||||
|
@ -115,6 +131,9 @@ class TrocadorExchangeProvider extends ExchangeProvider {
|
|||
final toAmount = double.parse(responseJSON['amount_to'].toString());
|
||||
final rateId = responseJSON['trade_id'] as String? ?? '';
|
||||
|
||||
var quotes = responseJSON['quotes']['quotes'] as List;
|
||||
_provider = quotes.map((quote) => quote['provider']).toList();
|
||||
|
||||
if (rateId.isNotEmpty) _lastUsedRateId = rateId;
|
||||
|
||||
return isReceiveAmount ? (amount / fromAmount) : (toAmount / amount);
|
||||
|
@ -126,6 +145,7 @@ class TrocadorExchangeProvider extends ExchangeProvider {
|
|||
|
||||
@override
|
||||
Future<Trade> createTrade({required TradeRequest request, required bool isFixedRateMode}) async {
|
||||
|
||||
final params = {
|
||||
'api_key': apiKey,
|
||||
'ticker_from': _normalizeCurrency(request.fromCurrency),
|
||||
|
@ -135,7 +155,6 @@ class TrocadorExchangeProvider extends ExchangeProvider {
|
|||
'payment': isFixedRateMode ? 'True' : 'False',
|
||||
'min_kycrating': 'C',
|
||||
'markup': markup,
|
||||
'best_only': 'True',
|
||||
if (!isFixedRateMode) 'amount_from': request.fromAmount,
|
||||
if (isFixedRateMode) 'amount_to': request.toAmount,
|
||||
'address': request.toAddress,
|
||||
|
@ -153,6 +172,22 @@ class TrocadorExchangeProvider extends ExchangeProvider {
|
|||
params['id'] = _lastUsedRateId;
|
||||
}
|
||||
|
||||
|
||||
String firstAvailableProvider = '';
|
||||
|
||||
for (var provider in _provider) {
|
||||
if (providerStates.containsKey(provider) && providerStates[provider] == true) {
|
||||
firstAvailableProvider = provider as String;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (firstAvailableProvider.isEmpty) {
|
||||
throw Exception('No available provider is enabled');
|
||||
}
|
||||
|
||||
params['provider'] = firstAvailableProvider;
|
||||
|
||||
final uri = await _getUri(createTradePath, params);
|
||||
final response = await get(uri);
|
||||
|
||||
|
|
|
@ -6,7 +6,6 @@ import 'package:cake_wallet/.secrets.g.dart' as secrets;
|
|||
import 'package:cake_wallet/ionia/ionia_api.dart';
|
||||
import 'package:cake_wallet/ionia/ionia_gift_card.dart';
|
||||
import 'package:cake_wallet/ionia/ionia_category.dart';
|
||||
import 'package:platform_device_id/platform_device_id.dart';
|
||||
|
||||
class IoniaService {
|
||||
IoniaService(this.secureStorage, this.ioniaApi);
|
||||
|
@ -112,9 +111,9 @@ class IoniaService {
|
|||
required String currency}) async {
|
||||
final username = (await secureStorage.read(key: ioniaUsernameStorageKey))!;
|
||||
final password = (await secureStorage.read(key: ioniaPasswordStorageKey))!;
|
||||
final deviceId = await PlatformDeviceId.getDeviceId;
|
||||
final deviceId = '';
|
||||
return ioniaApi.purchaseGiftCard(
|
||||
requestedUUID: deviceId!,
|
||||
requestedUUID: deviceId,
|
||||
merchId: merchId,
|
||||
amount: amount,
|
||||
currency: currency,
|
||||
|
|
|
@ -166,7 +166,10 @@ class CWNano extends Nano {
|
|||
|
||||
@override
|
||||
Future<void> changeRep(Object wallet, String address) async {
|
||||
return (wallet as NanoWallet).changeRep(address);
|
||||
if ((wallet as NanoWallet).transactionHistory.transactions.isEmpty) {
|
||||
throw Exception("Can't change representative without an existing transaction history");
|
||||
}
|
||||
return wallet.changeRep(address);
|
||||
}
|
||||
|
||||
@override
|
||||
|
|
|
@ -2,6 +2,7 @@ import 'package:cake_wallet/entities/auto_generate_subaddress_status.dart';
|
|||
import 'package:cake_wallet/entities/fiat_api_mode.dart';
|
||||
import 'package:cake_wallet/entities/update_haven_rate.dart';
|
||||
import 'package:cake_wallet/ethereum/ethereum.dart';
|
||||
import 'package:cake_wallet/nano/nano.dart';
|
||||
import 'package:cw_core/transaction_history.dart';
|
||||
import 'package:cw_core/balance.dart';
|
||||
import 'package:cw_core/transaction_info.dart';
|
||||
|
|
|
@ -7,7 +7,7 @@ import 'package:cw_core/wallet_base.dart';
|
|||
import 'package:cw_core/balance.dart';
|
||||
import 'package:cw_core/transaction_info.dart';
|
||||
import 'package:cw_core/sync_status.dart';
|
||||
import 'package:wakelock/wakelock.dart';
|
||||
import 'package:wakelock_plus/wakelock_plus.dart';
|
||||
|
||||
ReactionDisposer? _onWalletSyncStatusChangeReaction;
|
||||
|
||||
|
@ -27,10 +27,10 @@ void startWalletSyncStatusChangeReaction(
|
|||
}
|
||||
}
|
||||
if (status is SyncingSyncStatus) {
|
||||
await Wakelock.enable();
|
||||
await WakelockPlus.enable();
|
||||
}
|
||||
if (status is SyncedSyncStatus || status is FailedSyncStatus) {
|
||||
await Wakelock.disable();
|
||||
await WakelockPlus.disable();
|
||||
}
|
||||
} catch(e) {
|
||||
print(e.toString());
|
||||
|
|
|
@ -5,6 +5,7 @@ import 'package:cake_wallet/core/wallet_connect/web3wallet_service.dart';
|
|||
import 'package:cake_wallet/entities/contact_record.dart';
|
||||
import 'package:cake_wallet/buy/order.dart';
|
||||
import 'package:cake_wallet/entities/qr_view_data.dart';
|
||||
import 'package:cake_wallet/entities/wallet_nft_response.dart';
|
||||
import 'package:cake_wallet/src/screens/anonpay_details/anonpay_details_page.dart';
|
||||
import 'package:cake_wallet/src/screens/backup/backup_page.dart';
|
||||
import 'package:cake_wallet/src/screens/backup/edit_backup_password_page.dart';
|
||||
|
@ -14,6 +15,7 @@ import 'package:cake_wallet/src/screens/buy/webview_page.dart';
|
|||
import 'package:cake_wallet/src/screens/dashboard/edit_token_page.dart';
|
||||
import 'package:cake_wallet/src/screens/dashboard/home_settings_page.dart';
|
||||
import 'package:cake_wallet/src/screens/exchange/exchange_options_page.dart';
|
||||
import 'package:cake_wallet/src/screens/dashboard/pages/nft_details_page.dart';
|
||||
import 'package:cake_wallet/src/screens/nano/nano_change_rep_page.dart';
|
||||
import 'package:cake_wallet/src/screens/nano_accounts/nano_account_edit_or_create_page.dart';
|
||||
import 'package:cake_wallet/src/screens/nodes/pow_node_create_or_edit_page.dart';
|
||||
|
@ -21,7 +23,7 @@ import 'package:cake_wallet/src/screens/restore/sweeping_wallet_page.dart';
|
|||
import 'package:cake_wallet/src/screens/receive/anonpay_invoice_page.dart';
|
||||
import 'package:cake_wallet/src/screens/receive/anonpay_receive_page.dart';
|
||||
import 'package:cake_wallet/src/screens/dashboard/desktop_widgets/desktop_dashboard_actions.dart';
|
||||
import 'package:cake_wallet/src/screens/dashboard/widgets/transactions_page.dart';
|
||||
import 'package:cake_wallet/src/screens/dashboard/pages/transactions_page.dart';
|
||||
import 'package:cake_wallet/src/screens/restore/wallet_restore_choose_derivation.dart';
|
||||
import 'package:cake_wallet/src/screens/settings/desktop_settings/desktop_settings_page.dart';
|
||||
import 'package:cake_wallet/src/screens/settings/display_settings_page.dart';
|
||||
|
@ -43,6 +45,8 @@ import 'package:cake_wallet/src/screens/restore/restore_from_backup_page.dart';
|
|||
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/settings/connection_sync_page.dart';
|
||||
import 'package:cake_wallet/src/screens/settings/trocador_providers_page.dart';
|
||||
import 'package:cake_wallet/src/screens/settings/tor_page.dart';
|
||||
import 'package:cake_wallet/src/screens/setup_2fa/modify_2fa_page.dart';
|
||||
import 'package:cake_wallet/src/screens/setup_2fa/setup_2fa_qr_page.dart';
|
||||
import 'package:cake_wallet/src/screens/setup_2fa/setup_2fa.dart';
|
||||
|
@ -55,6 +59,7 @@ import 'package:cake_wallet/src/screens/unspent_coins/unspent_coins_list_page.da
|
|||
import 'package:cake_wallet/src/screens/wallet_connect/wc_connections_listing_view.dart';
|
||||
import 'package:cake_wallet/utils/payment_request.dart';
|
||||
import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/dashboard/nft_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/monero_account_list/account_list_item.dart';
|
||||
import 'package:cake_wallet/view_model/node_list/node_create_or_edit_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/advanced_privacy_settings_view_model.dart';
|
||||
|
@ -101,7 +106,7 @@ import 'package:cake_wallet/src/screens/exchange_trade/exchange_confirm_page.dar
|
|||
import 'package:cake_wallet/src/screens/exchange_trade/exchange_trade_page.dart';
|
||||
import 'package:flutter/services.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/dashboard/pages/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';
|
||||
|
@ -110,6 +115,8 @@ import 'package:cake_wallet/ionia/ionia_any_pay_payment_info.dart';
|
|||
import 'package:cw_core/crypto_currency.dart';
|
||||
import 'package:cw_core/node.dart';
|
||||
|
||||
import 'src/screens/dashboard/pages/nft_import_page.dart';
|
||||
|
||||
late RouteSettings currentRouteSettings;
|
||||
|
||||
Route<dynamic> createRoute(RouteSettings settings) {
|
||||
|
@ -324,6 +331,10 @@ Route<dynamic> createRoute(RouteSettings settings) {
|
|||
return CupertinoPageRoute<void>(
|
||||
fullscreenDialog: true, builder: (_) => getIt.get<PrivacyPage>());
|
||||
|
||||
case Routes.trocadorProvidersPage:
|
||||
return CupertinoPageRoute<void>(
|
||||
fullscreenDialog: true, builder: (_) => getIt.get<TrocadorProvidersPage>());
|
||||
|
||||
case Routes.domainLookupsPage:
|
||||
return CupertinoPageRoute<void>(
|
||||
fullscreenDialog: true, builder: (_) => getIt.get<DomainLookupsPage>());
|
||||
|
@ -417,7 +428,10 @@ Route<dynamic> createRoute(RouteSettings settings) {
|
|||
|
||||
case Routes.preSeed:
|
||||
return MaterialPageRoute<void>(
|
||||
builder: (_) => getIt.get<PreSeedPage>(param1: settings.arguments as WalletType));
|
||||
builder: (_) => getIt.get<PreSeedPage>(
|
||||
param1: settings.arguments as WalletType,
|
||||
param2: getIt.get<AdvancedPrivacySettingsViewModel>(
|
||||
param1: settings.arguments as WalletType)));
|
||||
|
||||
case Routes.backup:
|
||||
return CupertinoPageRoute<void>(
|
||||
|
@ -611,6 +625,25 @@ Route<dynamic> createRoute(RouteSettings settings) {
|
|||
web3walletService: getIt.get<Web3WalletService>(),
|
||||
launchUri: settings.arguments as Uri?,
|
||||
));
|
||||
|
||||
case Routes.nftDetailsPage:
|
||||
return MaterialPageRoute<void>(
|
||||
builder: (_) => NFTDetailsPage(
|
||||
nftAsset: settings.arguments as NFTAssetModel,
|
||||
dashboardViewModel: getIt.get<DashboardViewModel>(),
|
||||
),
|
||||
);
|
||||
|
||||
case Routes.importNFTPage:
|
||||
return MaterialPageRoute<void>(
|
||||
builder: (_) => ImportNFTPage(
|
||||
nftViewModel: settings.arguments as NFTViewModel,
|
||||
),
|
||||
);
|
||||
|
||||
case Routes.torPage:
|
||||
return MaterialPageRoute<void>(builder: (_) => getIt.get<TorPage>());
|
||||
|
||||
default:
|
||||
return MaterialPageRoute<void>(
|
||||
builder: (_) => Scaffold(
|
||||
|
|
|
@ -7,7 +7,8 @@ class Routes {
|
|||
static const restoreOptions = '/restore_options';
|
||||
static const restoreWalletFromSeedKeys = '/restore_wallet_from_seeds_keys';
|
||||
static const restoreWalletTypeFromQR = '/restore_wallet_from_qr_code';
|
||||
static const restoreWalletChooseDerivation = '/restore_wallet_choose_derivation';
|
||||
static const restoreWalletChooseDerivation =
|
||||
'/restore_wallet_choose_derivation';
|
||||
static const dashboard = '/dashboard';
|
||||
static const send = '/send';
|
||||
static const transactionDetails = '/transaction_info';
|
||||
|
@ -82,6 +83,7 @@ class Routes {
|
|||
static const connectionSync = '/connection_sync_page';
|
||||
static const securityBackupPage = '/security_and_backup_page';
|
||||
static const privacyPage = '/privacy_page';
|
||||
static const trocadorProvidersPage = '/trocador_providers_page';
|
||||
static const domainLookupsPage = '/domain_lookups_page';
|
||||
static const displaySettingsPage = '/display_settings_page';
|
||||
static const otherSettingsPage = '/other_settings_page';
|
||||
|
@ -100,5 +102,9 @@ class Routes {
|
|||
static const editToken = '/edit_token';
|
||||
static const manageNodes = '/manage_nodes';
|
||||
static const managePowNodes = '/manage_pow_nodes';
|
||||
static const walletConnectConnectionsListing = '/wallet-connect-connections-listing';
|
||||
static const walletConnectConnectionsListing =
|
||||
'/wallet-connect-connections-listing';
|
||||
static const nftDetailsPage = '/nft_details_page';
|
||||
static const importNFTPage = '/import_nft_page';
|
||||
static const torPage = '/tor_page';
|
||||
}
|
||||
|
|
|
@ -17,7 +17,6 @@ import 'package:file_picker/file_picker.dart';
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||
import 'package:permission_handler/permission_handler.dart';
|
||||
|
||||
class BackupPage extends BasePage {
|
||||
BackupPage(this.backupViewModelBase);
|
||||
|
@ -129,15 +128,8 @@ class BackupPage extends BasePage {
|
|||
alertTitle: S.of(context).export_backup,
|
||||
alertContent: S.of(context).select_destination,
|
||||
rightButtonText: S.of(context).save_to_downloads,
|
||||
leftButtonText:S.of(context).share,
|
||||
leftButtonText: S.of(context).share,
|
||||
actionRightButton: () async {
|
||||
final permission = await Permission.storage.request();
|
||||
|
||||
if (permission.isDenied) {
|
||||
Navigator.of(dialogContext).pop();
|
||||
return;
|
||||
}
|
||||
|
||||
await backupViewModelBase.saveToDownload(backup.name, backup.content);
|
||||
Navigator.of(dialogContext).pop();
|
||||
},
|
||||
|
|
|
@ -34,16 +34,6 @@ class BuyOptionsPage extends BasePage {
|
|||
constraints: BoxConstraints(maxWidth: 330),
|
||||
child: Column(
|
||||
children: [
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: 24),
|
||||
child: OptionTile(
|
||||
image: iconRobinhood,
|
||||
title: "Robinhood Connect",
|
||||
description: S.of(context).robinhood_option_description,
|
||||
onPressed: () async =>
|
||||
await getIt.get<RobinhoodBuyProvider>().launchProvider(context),
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: 24),
|
||||
child: OptionTile(
|
||||
|
@ -54,6 +44,16 @@ class BuyOptionsPage extends BasePage {
|
|||
await getIt.get<OnRamperBuyProvider>().launchProvider(context),
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: 24),
|
||||
child: OptionTile(
|
||||
image: iconRobinhood,
|
||||
title: "Robinhood Connect",
|
||||
description: S.of(context).robinhood_option_description,
|
||||
onPressed: () async =>
|
||||
await getIt.get<RobinhoodBuyProvider>().launchProvider(context),
|
||||
),
|
||||
),
|
||||
Spacer(),
|
||||
Padding(
|
||||
padding: EdgeInsets.fromLTRB(24, 24, 24, 32),
|
||||
|
|
|
@ -1,11 +1,10 @@
|
|||
import 'dart:async';
|
||||
import 'package:cake_wallet/core/wallet_connect/wc_bottom_sheet_service.dart';
|
||||
import 'package:cake_wallet/core/wallet_connect/web3wallet_service.dart';
|
||||
import 'package:cake_wallet/entities/preferences_key.dart';
|
||||
import 'package:cake_wallet/di.dart';
|
||||
import 'package:cake_wallet/entities/main_actions.dart';
|
||||
import 'package:cake_wallet/src/screens/dashboard/desktop_widgets/desktop_sidebar_wrapper.dart';
|
||||
import 'package:cake_wallet/src/screens/dashboard/widgets/market_place_page.dart';
|
||||
import 'package:cake_wallet/src/screens/dashboard/pages/market_place_page.dart';
|
||||
import 'package:cake_wallet/src/screens/wallet_connect/widgets/modals/bottom_sheet_listener.dart';
|
||||
import 'package:cake_wallet/src/widgets/gradient_background.dart';
|
||||
import 'package:cake_wallet/themes/extensions/sync_indicator_theme.dart';
|
||||
|
@ -15,7 +14,6 @@ import 'package:cake_wallet/view_model/dashboard/market_place_view_model.dart';
|
|||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/routes.dart';
|
||||
import 'package:cake_wallet/src/screens/yat_emoji_id.dart';
|
||||
import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
|
||||
import 'package:cake_wallet/utils/responsive_layout_util.dart';
|
||||
import 'package:cake_wallet/utils/show_pop_up.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
@ -23,8 +21,8 @@ import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart';
|
|||
import 'package:cake_wallet/src/screens/base_page.dart';
|
||||
import 'package:cake_wallet/src/screens/dashboard/widgets/menu_widget.dart';
|
||||
import 'package:cake_wallet/src/screens/dashboard/widgets/action_button.dart';
|
||||
import 'package:cake_wallet/src/screens/dashboard/widgets/balance_page.dart';
|
||||
import 'package:cake_wallet/src/screens/dashboard/widgets/transactions_page.dart';
|
||||
import 'package:cake_wallet/src/screens/dashboard/pages/balance_page.dart';
|
||||
import 'package:cake_wallet/src/screens/dashboard/pages/transactions_page.dart';
|
||||
import 'package:cake_wallet/src/screens/dashboard/widgets/sync_indicator.dart';
|
||||
import 'package:cake_wallet/view_model/wallet_address_list/wallet_address_list_view_model.dart';
|
||||
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||
|
|
|
@ -1,17 +1,14 @@
|
|||
import 'dart:async';
|
||||
import 'package:cake_wallet/entities/preferences_key.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/routes.dart';
|
||||
import 'package:cake_wallet/src/screens/release_notes/release_notes_screen.dart';
|
||||
import 'package:cake_wallet/src/screens/yat_emoji_id.dart';
|
||||
import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
|
||||
import 'package:cake_wallet/utils/show_pop_up.dart';
|
||||
import 'package:cake_wallet/utils/version_comparator.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart';
|
||||
import 'package:cake_wallet/src/screens/dashboard/widgets/balance_page.dart';
|
||||
import 'package:cake_wallet/src/screens/dashboard/pages/balance_page.dart';
|
||||
import 'package:cake_wallet/view_model/wallet_address_list/wallet_address_list_view_model.dart';
|
||||
import 'package:mobx/mobx.dart';
|
||||
import 'package:cake_wallet/main.dart';
|
||||
import 'package:cake_wallet/router.dart' as Router;
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import 'package:cake_wallet/di.dart';
|
||||
import 'package:cake_wallet/entities/main_actions.dart';
|
||||
import 'package:cake_wallet/src/screens/dashboard/desktop_widgets/desktop_action_button.dart';
|
||||
import 'package:cake_wallet/src/screens/dashboard/widgets/market_place_page.dart';
|
||||
import 'package:cake_wallet/src/screens/dashboard/pages/market_place_page.dart';
|
||||
import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/dashboard/market_place_view_model.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
|
|
@ -6,10 +6,8 @@ import 'package:cake_wallet/anonpay/anonpay_donation_link_info.dart';
|
|||
import 'package:cake_wallet/entities/preferences_key.dart';
|
||||
import 'package:cake_wallet/entities/receive_page_option.dart';
|
||||
import 'package:cake_wallet/src/screens/dashboard/widgets/present_receive_option_picker.dart';
|
||||
import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart';
|
||||
import 'package:cake_wallet/src/widgets/gradient_background.dart';
|
||||
import 'package:cake_wallet/src/widgets/keyboard_done_button.dart';
|
||||
import 'package:cake_wallet/themes/extensions/receive_page_theme.dart';
|
||||
import 'package:cake_wallet/themes/extensions/sync_indicator_theme.dart';
|
||||
import 'package:cake_wallet/themes/theme_base.dart';
|
||||
import 'package:cake_wallet/utils/responsive_layout_util.dart';
|
||||
|
@ -26,7 +24,6 @@ import 'package:flutter_mobx/flutter_mobx.dart';
|
|||
import 'package:keyboard_actions/keyboard_actions.dart';
|
||||
import 'package:mobx/mobx.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
import 'package:cake_wallet/themes/extensions/dashboard_page_theme.dart';
|
||||
import 'package:cake_wallet/themes/extensions/balance_page_theme.dart';
|
||||
|
||||
class AddressPage extends BasePage {
|
||||
|
@ -163,8 +160,7 @@ class AddressPage extends BasePage {
|
|||
return GestureDetector(
|
||||
onTap: () async => dashboardViewModel.isAutoGenerateSubaddressesEnabled
|
||||
? await showPopUp<void>(
|
||||
context: context,
|
||||
builder: (_) => getIt.get<MoneroAccountListPage>())
|
||||
context: context, builder: (_) => getIt.get<MoneroAccountListPage>())
|
||||
: Navigator.of(context).pushNamed(Routes.receive),
|
||||
child: Container(
|
||||
height: 50,
|
||||
|
@ -184,26 +180,27 @@ class AddressPage extends BasePage {
|
|||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: <Widget>[
|
||||
Observer(
|
||||
builder: (_) {
|
||||
String label = addressListViewModel.hasAccounts
|
||||
? S.of(context).accounts_subaddresses
|
||||
: S.of(context).addresses;
|
||||
builder: (_) {
|
||||
String label = addressListViewModel.hasAccounts
|
||||
? S.of(context).accounts_subaddresses
|
||||
: S.of(context).addresses;
|
||||
|
||||
if (dashboardViewModel.isAutoGenerateSubaddressesEnabled) {
|
||||
label = addressListViewModel.hasAccounts
|
||||
? S.of(context).accounts
|
||||
: S.of(context).account;
|
||||
}
|
||||
return Text(
|
||||
label,
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Theme.of(context)
|
||||
.extension<SyncIndicatorTheme>()!
|
||||
.textColor),
|
||||
);
|
||||
},),
|
||||
if (dashboardViewModel.isAutoGenerateSubaddressesEnabled) {
|
||||
label = addressListViewModel.hasAccounts
|
||||
? S.of(context).accounts
|
||||
: S.of(context).account;
|
||||
}
|
||||
return Text(
|
||||
label,
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Theme.of(context)
|
||||
.extension<SyncIndicatorTheme>()!
|
||||
.textColor),
|
||||
);
|
||||
},
|
||||
),
|
||||
Icon(
|
||||
Icons.arrow_forward_ios,
|
||||
size: 14,
|
||||
|
@ -213,7 +210,8 @@ class AddressPage extends BasePage {
|
|||
),
|
||||
),
|
||||
);
|
||||
} else if (dashboardViewModel.isAutoGenerateSubaddressesEnabled || addressListViewModel.showElectrumAddressDisclaimer) {
|
||||
} else if (dashboardViewModel.isAutoGenerateSubaddressesEnabled ||
|
||||
addressListViewModel.showElectrumAddressDisclaimer) {
|
||||
return Text(S.of(context).electrum_address_disclaimer,
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
|
@ -1,6 +1,7 @@
|
|||
import 'package:auto_size_text/auto_size_text.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/routes.dart';
|
||||
import 'package:cake_wallet/src/screens/dashboard/pages/nft_listing_page.dart';
|
||||
import 'package:cake_wallet/src/screens/dashboard/widgets/home_screen_account_widget.dart';
|
||||
import 'package:cake_wallet/src/screens/exchange_trade/information_page.dart';
|
||||
import 'package:cake_wallet/src/widgets/introducing_card.dart';
|
||||
|
@ -11,15 +12,80 @@ import 'package:cake_wallet/themes/extensions/sync_indicator_theme.dart';
|
|||
import 'package:cake_wallet/utils/feature_flag.dart';
|
||||
import 'package:cake_wallet/utils/show_pop_up.dart';
|
||||
import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/dashboard/nft_view_model.dart';
|
||||
import 'package:cw_core/wallet_type.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||
|
||||
class BalancePage extends StatelessWidget {
|
||||
BalancePage({required this.dashboardViewModel, required this.settingsStore});
|
||||
BalancePage({
|
||||
required this.dashboardViewModel,
|
||||
required this.settingsStore,
|
||||
required this.nftViewModel,
|
||||
});
|
||||
|
||||
final DashboardViewModel dashboardViewModel;
|
||||
final NFTViewModel nftViewModel;
|
||||
final SettingsStore settingsStore;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Observer(
|
||||
builder: (context) {
|
||||
final isEthereumWallet = dashboardViewModel.type == WalletType.ethereum;
|
||||
return DefaultTabController(
|
||||
length: isEthereumWallet ? 2 : 1,
|
||||
child: Column(
|
||||
children: [
|
||||
if (isEthereumWallet)
|
||||
Align(
|
||||
alignment: Alignment.centerLeft,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(left: 8),
|
||||
child: TabBar(
|
||||
indicatorSize: TabBarIndicatorSize.label,
|
||||
isScrollable: true,
|
||||
physics: NeverScrollableScrollPhysics(),
|
||||
labelStyle: TextStyle(
|
||||
fontSize: 18,
|
||||
fontFamily: 'Lato',
|
||||
fontWeight: FontWeight.w600,
|
||||
color:
|
||||
Theme.of(context).extension<DashboardPageTheme>()!.pageTitleTextColor,
|
||||
height: 1,
|
||||
),
|
||||
tabs: [
|
||||
Tab(text: 'My Crypto'),
|
||||
Tab(text: 'My NFTs'),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: TabBarView(
|
||||
physics: NeverScrollableScrollPhysics(),
|
||||
children: [
|
||||
CryptoBalanceWidget(dashboardViewModel: dashboardViewModel),
|
||||
if (isEthereumWallet) NFTListingPage(nftViewModel: nftViewModel)
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class CryptoBalanceWidget extends StatelessWidget {
|
||||
const CryptoBalanceWidget({
|
||||
super.key,
|
||||
required this.dashboardViewModel,
|
||||
});
|
||||
|
||||
final DashboardViewModel dashboardViewModel;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return GestureDetector(
|
||||
|
@ -38,7 +104,7 @@ class BalancePage extends StatelessWidget {
|
|||
accountName: dashboardViewModel.subname)
|
||||
: Column(
|
||||
children: [
|
||||
SizedBox(height: 56),
|
||||
SizedBox(height: 16),
|
||||
Container(
|
||||
margin: const EdgeInsets.only(left: 24, bottom: 16),
|
||||
child: Observer(
|
||||
|
@ -105,8 +171,7 @@ class BalancePage extends StatelessWidget {
|
|||
itemBuilder: (__, index) {
|
||||
final balance =
|
||||
dashboardViewModel.balanceViewModel.formattedBalances.elementAt(index);
|
||||
return buildBalanceRow(
|
||||
context,
|
||||
return BalanceRowWidget(
|
||||
availableBalanceLabel:
|
||||
'${dashboardViewModel.balanceViewModel.availableBalanceLabel}',
|
||||
availableBalance: balance.availableBalance,
|
||||
|
@ -130,20 +195,44 @@ class BalancePage extends StatelessWidget {
|
|||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Widget buildBalanceRow(
|
||||
BuildContext context, {
|
||||
required String availableBalanceLabel,
|
||||
required String availableBalance,
|
||||
required String availableFiatBalance,
|
||||
required String additionalBalanceLabel,
|
||||
required String additionalBalance,
|
||||
required String additionalFiatBalance,
|
||||
required String frozenBalance,
|
||||
required String frozenFiatBalance,
|
||||
required String currency,
|
||||
required bool hasAdditionalBalance,
|
||||
}) {
|
||||
class BalanceRowWidget extends StatelessWidget {
|
||||
const BalanceRowWidget({
|
||||
required this.availableBalanceLabel,
|
||||
required this.availableBalance,
|
||||
required this.availableFiatBalance,
|
||||
required this.additionalBalanceLabel,
|
||||
required this.additionalBalance,
|
||||
required this.additionalFiatBalance,
|
||||
required this.frozenBalance,
|
||||
required this.frozenFiatBalance,
|
||||
required this.currency,
|
||||
required this.hasAdditionalBalance,
|
||||
super.key,
|
||||
});
|
||||
|
||||
final String availableBalanceLabel;
|
||||
final String availableBalance;
|
||||
final String availableFiatBalance;
|
||||
final String additionalBalanceLabel;
|
||||
final String additionalBalance;
|
||||
final String additionalFiatBalance;
|
||||
final String frozenBalance;
|
||||
final String frozenFiatBalance;
|
||||
final String currency;
|
||||
final bool hasAdditionalBalance;
|
||||
|
||||
// void _showBalanceDescription(BuildContext context) {
|
||||
// showPopUp<void>(
|
||||
// context: context,
|
||||
// builder: (_) =>
|
||||
// InformationPage(information: S.current.available_balance_description),
|
||||
// );
|
||||
// }
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
margin: const EdgeInsets.only(left: 16, right: 16),
|
||||
decoration: BoxDecoration(
|
||||
|
@ -165,7 +254,10 @@ class BalancePage extends StatelessWidget {
|
|||
children: [
|
||||
GestureDetector(
|
||||
behavior: HitTestBehavior.opaque,
|
||||
onTap: hasAdditionalBalance ? () => _showBalanceDescription(context) : null,
|
||||
onTap: hasAdditionalBalance
|
||||
? () =>
|
||||
_showBalanceDescription(context, S.current.available_balance_description)
|
||||
: null,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
|
@ -225,47 +317,65 @@ class BalancePage extends StatelessWidget {
|
|||
],
|
||||
),
|
||||
if (frozenBalance.isNotEmpty)
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
SizedBox(height: 26),
|
||||
Text(
|
||||
S.current.frozen_balance,
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontFamily: 'Lato',
|
||||
fontWeight: FontWeight.w400,
|
||||
color: Theme.of(context).extension<BalancePageTheme>()!.labelTextColor,
|
||||
height: 1,
|
||||
GestureDetector(
|
||||
behavior: HitTestBehavior.opaque,
|
||||
onTap: hasAdditionalBalance
|
||||
? () =>
|
||||
_showBalanceDescription(context, S.current.unavailable_balance_description)
|
||||
: null,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
SizedBox(height: 26),
|
||||
Row(
|
||||
children: [
|
||||
Text(
|
||||
S.current.unavailable_balance,
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontFamily: 'Lato',
|
||||
fontWeight: FontWeight.w400,
|
||||
color: Theme.of(context).extension<BalancePageTheme>()!.labelTextColor,
|
||||
height: 1,
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 4),
|
||||
child: Icon(Icons.help_outline,
|
||||
size: 16,
|
||||
color:
|
||||
Theme.of(context).extension<BalancePageTheme>()!.labelTextColor),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
SizedBox(height: 8),
|
||||
AutoSizeText(
|
||||
frozenBalance,
|
||||
style: TextStyle(
|
||||
fontSize: 20,
|
||||
fontFamily: 'Lato',
|
||||
fontWeight: FontWeight.w400,
|
||||
color: Theme.of(context).extension<DashboardPageTheme>()!.textColor,
|
||||
height: 1,
|
||||
SizedBox(height: 8),
|
||||
AutoSizeText(
|
||||
frozenBalance,
|
||||
style: TextStyle(
|
||||
fontSize: 20,
|
||||
fontFamily: 'Lato',
|
||||
fontWeight: FontWeight.w400,
|
||||
color: Theme.of(context).extension<DashboardPageTheme>()!.textColor,
|
||||
height: 1,
|
||||
),
|
||||
maxLines: 1,
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
maxLines: 1,
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
SizedBox(height: 4),
|
||||
Text(
|
||||
frozenFiatBalance,
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontFamily: 'Lato',
|
||||
fontWeight: FontWeight.w400,
|
||||
color: Theme.of(context).extension<DashboardPageTheme>()!.textColor,
|
||||
height: 1,
|
||||
SizedBox(height: 4),
|
||||
Text(
|
||||
frozenFiatBalance,
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontFamily: 'Lato',
|
||||
fontWeight: FontWeight.w400,
|
||||
color: Theme.of(context).extension<DashboardPageTheme>()!.textColor,
|
||||
height: 1,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
),
|
||||
if (hasAdditionalBalance)
|
||||
Column(
|
||||
|
@ -316,9 +426,7 @@ class BalancePage extends StatelessWidget {
|
|||
);
|
||||
}
|
||||
|
||||
void _showBalanceDescription(BuildContext context) {
|
||||
showPopUp<void>(
|
||||
context: context,
|
||||
builder: (_) => InformationPage(information: S.current.available_balance_description));
|
||||
void _showBalanceDescription(BuildContext context, String content) {
|
||||
showPopUp<void>(context: context, builder: (_) => InformationPage(information: content));
|
||||
}
|
||||
}
|
178
lib/src/screens/dashboard/pages/nft_details_page.dart
Normal file
178
lib/src/screens/dashboard/pages/nft_details_page.dart
Normal file
|
@ -0,0 +1,178 @@
|
|||
import 'package:cake_wallet/entities/wallet_nft_response.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/src/screens/base_page.dart';
|
||||
import 'package:cake_wallet/src/screens/dashboard/widgets/menu_widget.dart';
|
||||
import 'package:cake_wallet/src/screens/dashboard/widgets/nft_image_tile_widget.dart';
|
||||
import 'package:cake_wallet/src/widgets/gradient_background.dart';
|
||||
import 'package:cake_wallet/themes/extensions/balance_page_theme.dart';
|
||||
import 'package:cake_wallet/themes/extensions/dashboard_page_theme.dart';
|
||||
import 'package:cake_wallet/themes/extensions/sync_indicator_theme.dart';
|
||||
import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class NFTDetailsPage extends BasePage {
|
||||
NFTDetailsPage({required this.dashboardViewModel, required this.nftAsset});
|
||||
|
||||
final DashboardViewModel dashboardViewModel;
|
||||
final NFTAssetModel nftAsset;
|
||||
|
||||
@override
|
||||
bool get gradientBackground => true;
|
||||
|
||||
@override
|
||||
Widget Function(BuildContext, Widget) get rootWrapper =>
|
||||
(BuildContext context, Widget scaffold) =>
|
||||
GradientBackground(scaffold: scaffold);
|
||||
|
||||
@override
|
||||
bool get resizeToAvoidBottomInset => false;
|
||||
|
||||
@override
|
||||
Widget get endDrawer => MenuWidget(dashboardViewModel);
|
||||
|
||||
@override
|
||||
Widget trailing(BuildContext context) {
|
||||
final menuButton = Image.asset(
|
||||
'assets/images/menu.png',
|
||||
color:
|
||||
Theme.of(context).extension<DashboardPageTheme>()!.pageTitleTextColor,
|
||||
);
|
||||
|
||||
return Container(
|
||||
alignment: Alignment.centerRight,
|
||||
width: 40,
|
||||
child: TextButton(
|
||||
// FIX-ME: Style
|
||||
//highlightColor: Colors.transparent,
|
||||
//splashColor: Colors.transparent,
|
||||
//padding: EdgeInsets.all(0),
|
||||
onPressed: () => onOpenEndDrawer(),
|
||||
child: Semantics(label: S.of(context).wallet_menu, child: menuButton),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget body(BuildContext context) {
|
||||
return SingleChildScrollView(
|
||||
child: Column(
|
||||
children: [
|
||||
Container(
|
||||
width: double.infinity,
|
||||
margin: const EdgeInsets.all(16),
|
||||
padding: const EdgeInsets.symmetric(vertical: 16),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(30.0),
|
||||
border: Border.all(
|
||||
color: Theme.of(context)
|
||||
.extension<BalancePageTheme>()!
|
||||
.cardBorderColor,
|
||||
width: 1,
|
||||
),
|
||||
color: Theme.of(context)
|
||||
.extension<SyncIndicatorTheme>()!
|
||||
.syncedBackgroundColor,
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Container(
|
||||
height: MediaQuery.sizeOf(context).height / 2.5,
|
||||
width: double.infinity,
|
||||
clipBehavior: Clip.hardEdge,
|
||||
margin: const EdgeInsets.all(8),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(16.0),
|
||||
border: Border.all(
|
||||
color: Theme.of(context)
|
||||
.extension<BalancePageTheme>()!
|
||||
.cardBorderColor,
|
||||
width: 1,
|
||||
),
|
||||
color: Theme.of(context)
|
||||
.extension<SyncIndicatorTheme>()!
|
||||
.syncedBackgroundColor,
|
||||
|
||||
),
|
||||
child: NFTImageWidget(
|
||||
imageUrl: nftAsset.normalizedMetadata?.imageUrl,
|
||||
),
|
||||
),
|
||||
SizedBox(height: 16),
|
||||
_NFTSingleInfoTile(
|
||||
infoType: S.current.name,
|
||||
infoValue: nftAsset.normalizedMetadata?.name ?? '',
|
||||
),
|
||||
|
||||
if (nftAsset.normalizedMetadata?.description != null) ...[
|
||||
SizedBox(height: 16),
|
||||
_NFTSingleInfoTile(
|
||||
infoType: 'Description',
|
||||
infoValue: nftAsset.normalizedMetadata?.description ?? '',
|
||||
),
|
||||
],
|
||||
|
||||
SizedBox(height: 16),
|
||||
_NFTSingleInfoTile(
|
||||
infoType: 'Contract Name',
|
||||
infoValue: nftAsset.name ?? '',
|
||||
),
|
||||
SizedBox(height: 8),
|
||||
_NFTSingleInfoTile(
|
||||
infoType: 'Contract Symbol',
|
||||
infoValue: nftAsset.symbol ?? '',
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _NFTSingleInfoTile extends StatelessWidget {
|
||||
const _NFTSingleInfoTile({
|
||||
required this.infoType,
|
||||
required this.infoValue,
|
||||
});
|
||||
|
||||
final String infoType;
|
||||
final String infoValue;
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 24),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
infoType,
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontFamily: 'Lato',
|
||||
fontWeight: FontWeight.w400,
|
||||
color: Theme.of(context)
|
||||
.extension<BalancePageTheme>()!
|
||||
.labelTextColor,
|
||||
height: 1,
|
||||
),
|
||||
),
|
||||
SizedBox(height: 8),
|
||||
Text(
|
||||
infoValue,
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontFamily: 'Lato',
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Theme.of(context)
|
||||
.extension<BalancePageTheme>()!
|
||||
.assetTitleColor,
|
||||
height: 1,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
168
lib/src/screens/dashboard/pages/nft_import_page.dart
Normal file
168
lib/src/screens/dashboard/pages/nft_import_page.dart
Normal file
|
@ -0,0 +1,168 @@
|
|||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/palette.dart';
|
||||
import 'package:cake_wallet/src/screens/base_page.dart';
|
||||
import 'package:cake_wallet/src/widgets/address_text_field.dart';
|
||||
import 'package:cake_wallet/src/widgets/primary_button.dart';
|
||||
import 'package:cake_wallet/themes/extensions/cake_text_theme.dart';
|
||||
import 'package:cake_wallet/themes/extensions/seed_widget_theme.dart';
|
||||
import 'package:cake_wallet/view_model/dashboard/nft_view_model.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||
|
||||
class ImportNFTPage extends StatefulWidget {
|
||||
const ImportNFTPage({required this.nftViewModel, super.key});
|
||||
|
||||
final NFTViewModel nftViewModel;
|
||||
|
||||
@override
|
||||
State<ImportNFTPage> createState() => _ImportNFTPageState();
|
||||
}
|
||||
|
||||
class _ImportNFTPageState extends State<ImportNFTPage> {
|
||||
late TextEditingController tokenAddressController;
|
||||
late TextEditingController tokenIDController;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
tokenAddressController = TextEditingController();
|
||||
tokenIDController = TextEditingController();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
tokenAddressController.dispose();
|
||||
tokenIDController.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return _ImportNFTPage(
|
||||
nftViewModel: widget.nftViewModel,
|
||||
tokenAddressController: tokenAddressController,
|
||||
tokenIDController: tokenIDController,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _ImportNFTPage extends BasePage {
|
||||
_ImportNFTPage({
|
||||
required this.tokenIDController,
|
||||
required this.tokenAddressController,
|
||||
required this.nftViewModel,
|
||||
});
|
||||
|
||||
final NFTViewModel nftViewModel;
|
||||
final TextEditingController tokenIDController;
|
||||
final TextEditingController tokenAddressController;
|
||||
|
||||
@override
|
||||
String? get title => S.current.import;
|
||||
|
||||
@override
|
||||
Widget body(BuildContext context) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 16),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
|
||||
Text(
|
||||
S.current.address,
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontFamily: 'Lato',
|
||||
fontWeight: FontWeight.w800,
|
||||
color:
|
||||
Theme.of(context).extension<SeedWidgetTheme>()!.hintTextColor,
|
||||
height: 1,
|
||||
),
|
||||
),
|
||||
AddressTextField(
|
||||
controller: tokenAddressController,
|
||||
options: [AddressTextFieldOption.paste],
|
||||
onPushPasteButton: (context) async {
|
||||
final clipboard = await Clipboard.getData('text/plain');
|
||||
final tokenAddress = clipboard?.text ?? '';
|
||||
|
||||
if (tokenAddress.isNotEmpty) {
|
||||
tokenAddressController.text = tokenAddress;
|
||||
}
|
||||
},
|
||||
borderColor: Theme.of(context)
|
||||
.extension<CakeTextTheme>()!
|
||||
.textfieldUnderlineColor,
|
||||
iconColor: Theme.of(context).primaryColor,
|
||||
placeholder: '0x...',
|
||||
textStyle: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w400,
|
||||
color: PaletteDark.darkCyanBlue,
|
||||
),
|
||||
hintStyle: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w400,
|
||||
color: PaletteDark.darkCyanBlue,
|
||||
),
|
||||
),
|
||||
|
||||
SizedBox(height: 48),
|
||||
Text(
|
||||
S.current.tokenID,
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontFamily: 'Lato',
|
||||
fontWeight: FontWeight.w800,
|
||||
color: Theme.of(context).extension<SeedWidgetTheme>()!.hintTextColor,
|
||||
height: 1,
|
||||
),
|
||||
),
|
||||
AddressTextField(
|
||||
controller: tokenIDController,
|
||||
options: [AddressTextFieldOption.paste],
|
||||
onPushPasteButton: (context) async {
|
||||
final clipboard = await Clipboard.getData('text/plain');
|
||||
final tokenID = clipboard?.text ?? '';
|
||||
|
||||
if (tokenID.isNotEmpty) {
|
||||
tokenIDController.text = tokenID;
|
||||
}
|
||||
},
|
||||
borderColor: Theme.of(context)
|
||||
.extension<CakeTextTheme>()!
|
||||
.textfieldUnderlineColor,
|
||||
iconColor: Theme.of(context).primaryColor,
|
||||
placeholder: S.current.enterTokenID,
|
||||
textStyle: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w400,
|
||||
color: PaletteDark.darkCyanBlue,
|
||||
),
|
||||
hintStyle: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w400,
|
||||
color: PaletteDark.darkCyanBlue,
|
||||
),
|
||||
),
|
||||
Spacer(),
|
||||
Observer(builder: (context) {
|
||||
return LoadingPrimaryButton(
|
||||
isLoading: nftViewModel.isImportNFTLoading,
|
||||
text: S.current.import,
|
||||
color: Theme.of(context).primaryColor,
|
||||
textColor: Colors.white,
|
||||
onPressed: () async {
|
||||
await nftViewModel.importNFT(tokenAddressController.text, tokenIDController.text);
|
||||
Navigator.pop(context);
|
||||
},
|
||||
);
|
||||
}),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
84
lib/src/screens/dashboard/pages/nft_listing_page.dart
Normal file
84
lib/src/screens/dashboard/pages/nft_listing_page.dart
Normal file
|
@ -0,0 +1,84 @@
|
|||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/routes.dart';
|
||||
import 'package:cake_wallet/src/screens/dashboard/widgets/nft_tile_widget.dart';
|
||||
import 'package:cake_wallet/src/widgets/primary_button.dart';
|
||||
import 'package:cake_wallet/themes/extensions/dashboard_page_theme.dart';
|
||||
import 'package:cake_wallet/themes/extensions/exchange_page_theme.dart';
|
||||
import 'package:cake_wallet/themes/extensions/sync_indicator_theme.dart';
|
||||
import 'package:cake_wallet/view_model/dashboard/nft_view_model.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||
|
||||
class NFTListingPage extends StatelessWidget {
|
||||
final NFTViewModel nftViewModel;
|
||||
|
||||
const NFTListingPage({super.key, required this.nftViewModel});
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Observer(
|
||||
builder: (context) {
|
||||
return Column(
|
||||
children: [
|
||||
SizedBox(height: 16),
|
||||
Padding(
|
||||
padding: EdgeInsets.only(left: 16, right: 16, bottom: 16),
|
||||
child: PrimaryButton(
|
||||
text: S.current.import,
|
||||
color: Theme.of(context)
|
||||
.extension<SyncIndicatorTheme>()!
|
||||
.syncedBackgroundColor,
|
||||
textColor: Colors.white,
|
||||
onPressed: () => Navigator.pushNamed(
|
||||
context,
|
||||
Routes.importNFTPage,
|
||||
arguments: nftViewModel,
|
||||
),
|
||||
),
|
||||
),
|
||||
if (nftViewModel.isLoading)
|
||||
Expanded(
|
||||
child: Center(
|
||||
child: CircularProgressIndicator(
|
||||
backgroundColor: Theme.of(context).extension<DashboardPageTheme>()!.textColor,
|
||||
valueColor: AlwaysStoppedAnimation<Color>(
|
||||
Theme.of(context)
|
||||
.extension<ExchangePageTheme>()!
|
||||
.firstGradientBottomPanelColor,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
if (!nftViewModel.isLoading)
|
||||
Expanded(
|
||||
child: nftViewModel.nftAssetByWalletModels.isEmpty
|
||||
? Center(
|
||||
child: Text(
|
||||
S.current.noNFTYet,
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 20,
|
||||
fontFamily: 'Lato',
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Theme.of(context)
|
||||
.extension<DashboardPageTheme>()!
|
||||
.pageTitleTextColor,
|
||||
height: 1,
|
||||
),
|
||||
),
|
||||
)
|
||||
: ListView.separated(
|
||||
padding: EdgeInsets.symmetric(horizontal: 4, vertical: 16),
|
||||
separatorBuilder: (context, index) => SizedBox(height: 8),
|
||||
itemCount: nftViewModel.nftAssetByWalletModels.length,
|
||||
itemBuilder: (context, index) {
|
||||
final nftAsset = nftViewModel.nftAssetByWalletModels[index];
|
||||
return NFTTileWidget(nftAsset: nftAsset);
|
||||
},
|
||||
),
|
||||
)
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
|
@ -46,9 +46,11 @@ class TransactionsPage extends StatelessWidget {
|
|||
return Padding(
|
||||
padding: const EdgeInsets.fromLTRB(24, 0, 24, 8),
|
||||
child: DashBoardRoundedCardWidget(
|
||||
onTap: () => Navigator.of(context).pushNamed(
|
||||
Routes.webViewPage,
|
||||
arguments: ['', Uri.parse('https://guides.cakewallet.com/docs/bugs-service-status/why_are_my_funds_not_appearing/')]),
|
||||
onTap: () => Navigator.of(context).pushNamed(Routes.webViewPage, arguments: [
|
||||
'',
|
||||
Uri.parse(
|
||||
'https://guides.cakewallet.com/docs/bugs-service-status/why_are_my_funds_not_appearing/')
|
||||
]),
|
||||
title: S.of(context).syncing_wallet_alert_title,
|
||||
subTitle: S.of(context).syncing_wallet_alert_content,
|
||||
),
|
||||
|
@ -76,40 +78,34 @@ class TransactionsPage extends StatelessWidget {
|
|||
|
||||
return Observer(
|
||||
builder: (_) => TransactionRow(
|
||||
onTap: () => Navigator.of(context).pushNamed(
|
||||
Routes.transactionDetails,
|
||||
arguments: transaction),
|
||||
onTap: () => Navigator.of(context)
|
||||
.pushNamed(Routes.transactionDetails, arguments: transaction),
|
||||
direction: transaction.direction,
|
||||
formattedDate: DateFormat('HH:mm')
|
||||
.format(transaction.date),
|
||||
formattedDate: DateFormat('HH:mm').format(transaction.date),
|
||||
formattedAmount: item.formattedCryptoAmount,
|
||||
formattedFiatAmount: dashboardViewModel
|
||||
.balanceViewModel.isFiatDisabled
|
||||
? ''
|
||||
: item.formattedFiatAmount,
|
||||
formattedFiatAmount:
|
||||
dashboardViewModel.balanceViewModel.isFiatDisabled
|
||||
? ''
|
||||
: item.formattedFiatAmount,
|
||||
isPending: transaction.isPending,
|
||||
title: item.formattedTitle +
|
||||
item.formattedStatus));
|
||||
title: item.formattedTitle + item.formattedStatus));
|
||||
}
|
||||
|
||||
if (item is AnonpayTransactionListItem) {
|
||||
final transactionInfo = item.transaction;
|
||||
|
||||
return AnonpayTransactionRow(
|
||||
onTap: () => Navigator.of(context).pushNamed(
|
||||
Routes.anonPayDetailsPage,
|
||||
arguments: transactionInfo),
|
||||
onTap: () => Navigator.of(context)
|
||||
.pushNamed(Routes.anonPayDetailsPage, arguments: transactionInfo),
|
||||
currency: transactionInfo.fiatAmount != null
|
||||
? transactionInfo.fiatEquiv ?? ''
|
||||
: CryptoCurrency.fromFullName(
|
||||
transactionInfo.coinTo)
|
||||
: CryptoCurrency.fromFullName(transactionInfo.coinTo)
|
||||
.name
|
||||
.toUpperCase(),
|
||||
provider: transactionInfo.provider,
|
||||
amount: transactionInfo.fiatAmount?.toString() ??
|
||||
(transactionInfo.amountTo?.toString() ?? ''),
|
||||
createdAt: DateFormat('HH:mm')
|
||||
.format(transactionInfo.createdAt),
|
||||
createdAt: DateFormat('HH:mm').format(transactionInfo.createdAt),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -118,17 +114,14 @@ class TransactionsPage extends StatelessWidget {
|
|||
|
||||
return Observer(
|
||||
builder: (_) => TradeRow(
|
||||
onTap: () => Navigator.of(context).pushNamed(
|
||||
Routes.tradeDetails,
|
||||
arguments: trade),
|
||||
onTap: () => Navigator.of(context)
|
||||
.pushNamed(Routes.tradeDetails, arguments: trade),
|
||||
provider: trade.provider,
|
||||
from: trade.from,
|
||||
to: trade.to,
|
||||
createdAtFormattedDate:
|
||||
trade.createdAt != null
|
||||
? DateFormat('HH:mm')
|
||||
.format(trade.createdAt!)
|
||||
: null,
|
||||
createdAtFormattedDate: trade.createdAt != null
|
||||
? DateFormat('HH:mm').format(trade.createdAt!)
|
||||
: null,
|
||||
formattedAmount: item.tradeFormattedAmount));
|
||||
}
|
||||
|
||||
|
@ -138,13 +131,12 @@ class TransactionsPage extends StatelessWidget {
|
|||
return Observer(
|
||||
builder: (_) => OrderRow(
|
||||
onTap: () => Navigator.of(context)
|
||||
.pushNamed(Routes.orderDetails,
|
||||
arguments: order),
|
||||
.pushNamed(Routes.orderDetails, arguments: order),
|
||||
provider: order.provider,
|
||||
from: order.from!,
|
||||
to: order.to!,
|
||||
createdAtFormattedDate: DateFormat('HH:mm')
|
||||
.format(order.createdAt),
|
||||
createdAtFormattedDate:
|
||||
DateFormat('HH:mm').format(order.createdAt),
|
||||
formattedAmount: item.orderFormattedAmount,
|
||||
));
|
||||
}
|
37
lib/src/screens/dashboard/widgets/nft_image_tile_widget.dart
Normal file
37
lib/src/screens/dashboard/widgets/nft_image_tile_widget.dart
Normal file
|
@ -0,0 +1,37 @@
|
|||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
|
||||
class NFTImageWidget extends StatelessWidget {
|
||||
const NFTImageWidget({
|
||||
required this.imageUrl,
|
||||
});
|
||||
|
||||
final String? imageUrl;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
try {
|
||||
if (imageUrl == null) return Icon(Icons.error);
|
||||
|
||||
if (imageUrl!.contains('.svg')) {
|
||||
return SvgPicture.network(imageUrl!);
|
||||
}
|
||||
|
||||
return Image.network(
|
||||
imageUrl!,
|
||||
fit: BoxFit.cover,
|
||||
loadingBuilder: (BuildContext _, Widget child, ImageChunkEvent? loadingProgress) {
|
||||
if (loadingProgress == null) {
|
||||
return child;
|
||||
} else {
|
||||
return CupertinoActivityIndicator(animating: true);
|
||||
}
|
||||
},
|
||||
errorBuilder: (_, __, ___) => Icon(Icons.error),
|
||||
);
|
||||
} catch (_) {
|
||||
return Icon(Icons.error);
|
||||
}
|
||||
}
|
||||
}
|
95
lib/src/screens/dashboard/widgets/nft_tile_widget.dart
Normal file
95
lib/src/screens/dashboard/widgets/nft_tile_widget.dart
Normal file
|
@ -0,0 +1,95 @@
|
|||
import 'package:cake_wallet/entities/wallet_nft_response.dart';
|
||||
import 'package:cake_wallet/routes.dart';
|
||||
import 'package:cake_wallet/src/screens/dashboard/widgets/nft_image_tile_widget.dart';
|
||||
import 'package:cake_wallet/themes/extensions/balance_page_theme.dart';
|
||||
import 'package:cake_wallet/themes/extensions/sync_indicator_theme.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class NFTTileWidget extends StatelessWidget {
|
||||
const NFTTileWidget({super.key, required this.nftAsset});
|
||||
|
||||
final NFTAssetModel nftAsset;
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return InkWell(
|
||||
onTap: () => Navigator.pushNamed(context, Routes.nftDetailsPage,
|
||||
arguments: nftAsset),
|
||||
child: Container(
|
||||
width: double.infinity,
|
||||
margin: const EdgeInsets.only(left: 16, right: 16),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(30.0),
|
||||
border: Border.all(
|
||||
color: Theme.of(context)
|
||||
.extension<BalancePageTheme>()!
|
||||
.cardBorderColor,
|
||||
width: 1,
|
||||
),
|
||||
color: Theme.of(context)
|
||||
.extension<SyncIndicatorTheme>()!
|
||||
.syncedBackgroundColor,
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
Container(
|
||||
height: 100,
|
||||
width: 100,
|
||||
clipBehavior: Clip.hardEdge,
|
||||
margin: const EdgeInsets.all(8),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(16.0),
|
||||
border: Border.all(
|
||||
color: Theme.of(context)
|
||||
.extension<BalancePageTheme>()!
|
||||
.cardBorderColor,
|
||||
width: 1,
|
||||
),
|
||||
color: Theme.of(context)
|
||||
.extension<SyncIndicatorTheme>()!
|
||||
.syncedBackgroundColor,
|
||||
),
|
||||
child: NFTImageWidget(
|
||||
imageUrl: nftAsset.normalizedMetadata?.imageUrl,
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
'${nftAsset.name ?? ''} - ${nftAsset.symbol ?? ''}',
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontFamily: 'Lato',
|
||||
fontWeight: FontWeight.w400,
|
||||
color: Theme.of(context)
|
||||
.extension<BalancePageTheme>()!
|
||||
.labelTextColor,
|
||||
height: 1,
|
||||
),
|
||||
),
|
||||
SizedBox(height: 8),
|
||||
Text(
|
||||
nftAsset.normalizedMetadata?.name ?? nftAsset.name ?? "",
|
||||
style: TextStyle(
|
||||
fontSize: 20,
|
||||
fontFamily: 'Lato',
|
||||
fontWeight: FontWeight.w900,
|
||||
color: Theme.of(context)
|
||||
.extension<BalancePageTheme>()!
|
||||
.assetTitleColor,
|
||||
height: 1,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -15,7 +15,7 @@ class MoneroAccountListPage extends StatelessWidget {
|
|||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
double itemHeight = 80;
|
||||
double itemHeight = 65;
|
||||
double buttonHeight = 62;
|
||||
|
||||
return Observer(builder: (_) {
|
||||
|
@ -31,7 +31,7 @@ class MoneroAccountListPage extends StatelessWidget {
|
|||
child: ListView.separated(
|
||||
padding: EdgeInsets.zero,
|
||||
controller: controller,
|
||||
separatorBuilder: (context, index) => const VerticalSectionDivider(),
|
||||
separatorBuilder: (context, index) => const HorizontalSectionDivider(),
|
||||
itemCount: accounts.length,
|
||||
itemBuilder: (context, index) {
|
||||
final account = accounts[index];
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import 'package:cake_wallet/themes/extensions/account_list_theme.dart';
|
||||
import 'package:cake_wallet/themes/extensions/receive_page_theme.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_slidable/flutter_slidable.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
|
@ -33,7 +32,7 @@ class AccountTile extends StatelessWidget {
|
|||
final Widget cell = GestureDetector(
|
||||
onTap: onTap,
|
||||
child: Container(
|
||||
height: 77,
|
||||
height: 60,
|
||||
width: double.infinity,
|
||||
padding: EdgeInsets.only(left: 24, right: 24),
|
||||
color: color,
|
||||
|
|
|
@ -1,8 +1,11 @@
|
|||
import 'package:cake_wallet/core/address_validator.dart';
|
||||
import 'package:cake_wallet/nano/nano.dart';
|
||||
import 'package:cake_wallet/src/widgets/address_text_field.dart';
|
||||
import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
|
||||
import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart';
|
||||
import 'package:cake_wallet/src/widgets/base_text_form_field.dart';
|
||||
import 'package:cake_wallet/store/settings_store.dart';
|
||||
import 'package:cake_wallet/themes/extensions/address_theme.dart';
|
||||
import 'package:cake_wallet/utils/payment_request.dart';
|
||||
import 'package:cake_wallet/utils/show_pop_up.dart';
|
||||
import 'package:cw_core/crypto_currency.dart';
|
||||
import 'package:cw_core/wallet_base.dart';
|
||||
|
@ -14,21 +17,28 @@ import 'package:cake_wallet/src/screens/base_page.dart';
|
|||
import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart';
|
||||
|
||||
class NanoChangeRepPage extends BasePage {
|
||||
NanoChangeRepPage(WalletBase wallet)
|
||||
NanoChangeRepPage({required SettingsStore settingsStore, required WalletBase wallet})
|
||||
: _wallet = wallet,
|
||||
_addressController = TextEditingController() {
|
||||
_settingsStore = settingsStore,
|
||||
_addressController = TextEditingController(),
|
||||
_formKey = GlobalKey<FormState>() {
|
||||
_addressController.text = nano!.getRepresentative(wallet);
|
||||
}
|
||||
|
||||
final TextEditingController _addressController;
|
||||
final WalletBase _wallet;
|
||||
final SettingsStore _settingsStore;
|
||||
|
||||
final GlobalKey<FormState> _formKey;
|
||||
|
||||
@override
|
||||
String get title => S.current.change_rep;
|
||||
|
||||
@override
|
||||
Widget body(BuildContext context) {
|
||||
return Container(
|
||||
return Form(
|
||||
key: _formKey,
|
||||
child: Container(
|
||||
padding: EdgeInsets.only(left: 24, right: 24),
|
||||
child: ScrollableWithBottomSection(
|
||||
contentPadding: EdgeInsets.only(bottom: 24.0),
|
||||
|
@ -38,9 +48,17 @@ class NanoChangeRepPage extends BasePage {
|
|||
Row(
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: BaseTextFormField(
|
||||
child: AddressTextField(
|
||||
controller: _addressController,
|
||||
hintText: S.of(context).node_address,
|
||||
onURIScanned: (uri) {
|
||||
final paymentRequest = PaymentRequest.fromUri(uri);
|
||||
_addressController.text = paymentRequest.address;
|
||||
},
|
||||
options: [
|
||||
AddressTextFieldOption.paste,
|
||||
AddressTextFieldOption.qrCode,
|
||||
],
|
||||
buttonColor: Theme.of(context).extension<AddressTheme>()!.actionButtonColor,
|
||||
validator: AddressValidator(type: CryptoCurrency.nano),
|
||||
),
|
||||
)
|
||||
|
@ -59,6 +77,11 @@ class NanoChangeRepPage extends BasePage {
|
|||
padding: EdgeInsets.only(right: 8.0),
|
||||
child: LoadingPrimaryButton(
|
||||
onPressed: () async {
|
||||
if (_formKey.currentState != null &&
|
||||
!_formKey.currentState!.validate()) {
|
||||
return;
|
||||
}
|
||||
|
||||
final confirmed = await showPopUp<bool>(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
|
@ -74,8 +97,19 @@ class NanoChangeRepPage extends BasePage {
|
|||
|
||||
if (confirmed) {
|
||||
try {
|
||||
_settingsStore.defaultNanoRep = _addressController.text;
|
||||
|
||||
await nano!.changeRep(_wallet, _addressController.text);
|
||||
Navigator.of(context).pop();
|
||||
|
||||
await showPopUp<void>(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return AlertWithOneAction(
|
||||
alertTitle: S.of(context).successful,
|
||||
alertContent: S.of(context).change_rep_successful,
|
||||
buttonText: S.of(context).ok,
|
||||
buttonAction: () => Navigator.pop(context));
|
||||
});
|
||||
} catch (e) {
|
||||
await showPopUp<void>(
|
||||
context: context,
|
||||
|
@ -97,6 +131,8 @@ class NanoChangeRepPage extends BasePage {
|
|||
)),
|
||||
],
|
||||
)),
|
||||
));
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
import 'package:cake_wallet/entities/exchange_api_mode.dart';
|
||||
import 'package:cake_wallet/entities/fiat_api_mode.dart';
|
||||
import 'package:cake_wallet/entities/seed_phrase_length.dart';
|
||||
import 'package:cake_wallet/src/screens/nodes/widgets/node_form.dart';
|
||||
import 'package:cake_wallet/src/screens/settings/widgets/settings_choices_cell.dart';
|
||||
import 'package:cake_wallet/src/screens/settings/widgets/settings_picker_cell.dart';
|
||||
import 'package:cake_wallet/src/screens/settings/widgets/settings_switcher_cell.dart';
|
||||
import 'package:cake_wallet/themes/extensions/new_wallet_theme.dart';
|
||||
import 'package:cake_wallet/view_model/node_list/node_create_or_edit_view_model.dart';
|
||||
|
@ -94,6 +96,17 @@ class _AdvancedPrivacySettingsBodyState extends State<AdvancedPrivacySettingsBod
|
|||
],
|
||||
);
|
||||
}),
|
||||
if (widget.privacySettingsViewModel.hasSeedPhraseLengthOption)
|
||||
Observer(builder: (_) {
|
||||
return SettingsPickerCell<SeedPhraseLength>(
|
||||
title: S.current.seed_phrase_length,
|
||||
items: SeedPhraseLength.values,
|
||||
selectedItem: widget.privacySettingsViewModel.seedPhraseLength,
|
||||
onItemSelected: (SeedPhraseLength length) {
|
||||
widget.privacySettingsViewModel.setSeedPhraseLength(length);
|
||||
},
|
||||
);
|
||||
}),
|
||||
],
|
||||
),
|
||||
bottomSectionPadding: EdgeInsets.all(24),
|
||||
|
|
|
@ -78,7 +78,7 @@ class NodeCreateOrEditPage extends BasePage {
|
|||
'assets/images/qr_code_icon.png',
|
||||
),
|
||||
);
|
||||
|
||||
|
||||
final NodeCreateOrEditViewModel nodeCreateOrEditViewModel;
|
||||
final Node? editingNode;
|
||||
final bool? isSelected;
|
||||
|
@ -133,27 +133,20 @@ class NodeCreateOrEditPage extends BasePage {
|
|||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
Flexible(
|
||||
child: Container(
|
||||
padding: EdgeInsets.only(right: 8.0),
|
||||
child: LoadingPrimaryButton(
|
||||
child: Container(
|
||||
padding: EdgeInsets.only(right: 8.0),
|
||||
child: LoadingPrimaryButton(
|
||||
onPressed: () async {
|
||||
final confirmed = await showPopUp<bool>(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return AlertWithTwoActions(
|
||||
alertTitle:
|
||||
S.of(context).remove_node,
|
||||
alertContent: S
|
||||
.of(context)
|
||||
.remove_node_message,
|
||||
rightButtonText:
|
||||
S.of(context).remove,
|
||||
leftButtonText:
|
||||
S.of(context).cancel,
|
||||
actionRightButton: () =>
|
||||
Navigator.pop(context, true),
|
||||
actionLeftButton: () =>
|
||||
Navigator.pop(context, false));
|
||||
alertTitle: S.of(context).remove_node,
|
||||
alertContent: S.of(context).remove_node_message,
|
||||
rightButtonText: S.of(context).remove,
|
||||
leftButtonText: S.of(context).cancel,
|
||||
actionRightButton: () => Navigator.pop(context, true),
|
||||
actionLeftButton: () => Navigator.pop(context, false));
|
||||
}) ??
|
||||
false;
|
||||
|
||||
|
@ -163,11 +156,14 @@ class NodeCreateOrEditPage extends BasePage {
|
|||
}
|
||||
},
|
||||
text: S.of(context).delete,
|
||||
isDisabled: !nodeCreateOrEditViewModel.isReady ||
|
||||
isDisabled: editingNode == null ||
|
||||
!nodeCreateOrEditViewModel.isReady ||
|
||||
(isSelected ?? false),
|
||||
color: Palette.red,
|
||||
textColor: Colors.white),
|
||||
)),
|
||||
textColor: Colors.white,
|
||||
),
|
||||
),
|
||||
),
|
||||
Flexible(
|
||||
child: Container(
|
||||
padding: EdgeInsets.only(left: 8.0),
|
||||
|
|
|
@ -4,7 +4,6 @@ import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
|
|||
import 'package:cake_wallet/utils/responsive_layout_util.dart';
|
||||
import 'package:cake_wallet/utils/show_pop_up.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/src/widgets/framework.dart';
|
||||
import 'package:cake_wallet/src/widgets/primary_button.dart';
|
||||
import 'package:cake_wallet/view_model/restore_from_backup_view_model.dart';
|
||||
import 'package:cake_wallet/src/screens/base_page.dart';
|
||||
|
@ -31,10 +30,11 @@ class RestoreFromBackupPage extends BasePage {
|
|||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return AlertWithOneAction(
|
||||
alertTitle: S.of(context).error,
|
||||
alertContent: state.error,
|
||||
buttonText: S.of(context).ok,
|
||||
buttonAction: () => Navigator.of(context).pop());
|
||||
alertTitle: S.of(context).error,
|
||||
alertContent: state.error,
|
||||
buttonText: S.of(context).ok,
|
||||
buttonAction: () => Navigator.of(context).pop(),
|
||||
);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
@ -44,42 +44,97 @@ class RestoreFromBackupPage extends BasePage {
|
|||
child: ConstrainedBox(
|
||||
constraints: BoxConstraints(maxWidth: ResponsiveLayoutUtilBase.kDesktopMaxWidthConstraint),
|
||||
child: Padding(
|
||||
padding: EdgeInsets.only(bottom: 24, left: 24, right: 24),
|
||||
child: Column(children: [
|
||||
padding: EdgeInsets.only(bottom: 24, left: 24, right: 24),
|
||||
child: Column(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Container(
|
||||
child: Center(
|
||||
child: TextFormField(
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
TextFormField(
|
||||
obscureText: true,
|
||||
enableSuggestions: false,
|
||||
autocorrect: false,
|
||||
decoration: InputDecoration(
|
||||
hintText: S.of(context).enter_backup_password),
|
||||
decoration:
|
||||
InputDecoration(hintText: S.of(context).enter_backup_password),
|
||||
keyboardType: TextInputType.visiblePassword,
|
||||
controller: textEditingController,
|
||||
style: TextStyle(fontSize: 26, color: Colors.black))),
|
||||
style: TextStyle(fontSize: 26, color: Colors.black),
|
||||
),
|
||||
Observer(
|
||||
builder: (_) {
|
||||
if (restoreFromBackupViewModel.filePath.isNotEmpty) {
|
||||
return Column(
|
||||
children: [
|
||||
const SizedBox(height: 100),
|
||||
Row(
|
||||
children: [
|
||||
Text(
|
||||
"File Name: ",
|
||||
style: TextStyle(
|
||||
fontSize: 18.0,
|
||||
fontWeight: FontWeight.bold,
|
||||
fontFamily: 'Lato',
|
||||
color: titleColor(context),
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: Text(
|
||||
restoreFromBackupViewModel.filePath.split("/").last,
|
||||
style: TextStyle(
|
||||
fontSize: 18.0,
|
||||
fontWeight: FontWeight.bold,
|
||||
fontFamily: 'Lato',
|
||||
color: titleColor(context),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
return const SizedBox();
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
Container(
|
||||
child: Row(children: [
|
||||
Expanded(
|
||||
child: PrimaryButton(
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: PrimaryButton(
|
||||
onPressed: () => presentFilePicker(),
|
||||
text: S.of(context).select_backup_file,
|
||||
color: Colors.grey,
|
||||
textColor: Colors.white)),
|
||||
SizedBox(width: 20),
|
||||
Expanded(child: Observer(builder: (_) {
|
||||
return LoadingPrimaryButton(
|
||||
isLoading:
|
||||
restoreFromBackupViewModel.state is IsExecutingState,
|
||||
onPressed: () => onImportHandler(context),
|
||||
text: S.of(context).import,
|
||||
color: Theme.of(context).primaryColor,
|
||||
textColor: Colors.white);
|
||||
}))
|
||||
])),
|
||||
])),
|
||||
textColor: Colors.white,
|
||||
),
|
||||
),
|
||||
SizedBox(width: 20),
|
||||
Expanded(
|
||||
child: Observer(
|
||||
builder: (_) {
|
||||
return LoadingPrimaryButton(
|
||||
isLoading: restoreFromBackupViewModel.state is IsExecutingState,
|
||||
onPressed: () => onImportHandler(context),
|
||||
text: S.of(context).import,
|
||||
color: Theme.of(context).primaryColor,
|
||||
textColor: Colors.white);
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
@ -87,7 +142,7 @@ class RestoreFromBackupPage extends BasePage {
|
|||
Future<void> presentFilePicker() async {
|
||||
final result = await FilePicker.platform.pickFiles();
|
||||
|
||||
if (result?.files?.isEmpty ?? true) {
|
||||
if (result?.files.isEmpty ?? true) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -95,8 +150,7 @@ class RestoreFromBackupPage extends BasePage {
|
|||
}
|
||||
|
||||
Future<void> onImportHandler(BuildContext context) async {
|
||||
if (textEditingController.text.isEmpty ||
|
||||
(restoreFromBackupViewModel.filePath.isEmpty ?? true)) {
|
||||
if (textEditingController.text.isEmpty || (restoreFromBackupViewModel.filePath.isEmpty)) {
|
||||
await showPopUp<void>(
|
||||
context: context,
|
||||
builder: (_) {
|
||||
|
|
|
@ -21,7 +21,6 @@ class RestoreOptionsPage extends BasePage {
|
|||
@override
|
||||
String get title => S.current.restore_restore_wallet;
|
||||
|
||||
|
||||
final bool isNewInstall;
|
||||
final imageSeedKeys = Image.asset('assets/images/restore_wallet_image.png');
|
||||
final imageBackup = Image.asset('assets/images/backup.png');
|
||||
|
@ -38,8 +37,7 @@ class RestoreOptionsPage extends BasePage {
|
|||
child: Column(
|
||||
children: <Widget>[
|
||||
OptionTile(
|
||||
onPressed: () => Navigator.pushNamed(
|
||||
context, Routes.restoreWalletFromSeedKeys,
|
||||
onPressed: () => Navigator.pushNamed(context, Routes.restoreWalletFromSeedKeys,
|
||||
arguments: isNewInstall),
|
||||
image: imageSeedKeys,
|
||||
title: S.of(context).restore_title_from_seed_keys,
|
||||
|
@ -58,7 +56,7 @@ class RestoreOptionsPage extends BasePage {
|
|||
child: OptionTile(
|
||||
onPressed: () async {
|
||||
bool isCameraPermissionGranted =
|
||||
await PermissionHandler.checkPermission(Permission.camera, context);
|
||||
await PermissionHandler.checkPermission(Permission.camera, context);
|
||||
if (!isCameraPermissionGranted) return;
|
||||
bool isPinSet = false;
|
||||
if (isNewInstall) {
|
||||
|
@ -73,7 +71,8 @@ class RestoreOptionsPage extends BasePage {
|
|||
final restoreWallet =
|
||||
await WalletRestoreFromQRCode.scanQRCodeForRestoring(context);
|
||||
|
||||
final restoreFromQRViewModel = getIt.get<WalletRestorationFromQRVM>(param1: restoreWallet.type);
|
||||
final restoreFromQRViewModel =
|
||||
getIt.get<WalletRestorationFromQRVM>(param1: restoreWallet.type);
|
||||
|
||||
await restoreFromQRViewModel.create(restoreWallet: restoreWallet);
|
||||
if (restoreFromQRViewModel.state is FailureState) {
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import 'package:cake_wallet/utils/responsive_layout_util.dart';
|
||||
import 'package:cake_wallet/themes/extensions/cake_text_theme.dart';
|
||||
import 'package:cake_wallet/view_model/advanced_privacy_settings_view_model.dart';
|
||||
import 'package:cw_core/wallet_type.dart';
|
||||
import 'package:cake_wallet/src/screens/base_page.dart';
|
||||
import 'package:cake_wallet/src/widgets/primary_button.dart';
|
||||
|
@ -9,15 +10,19 @@ import 'package:cake_wallet/themes/theme_base.dart';
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
class PreSeedPage extends BasePage {
|
||||
PreSeedPage(this.type)
|
||||
PreSeedPage(this.type, this.advancedPrivacySettingsViewModel)
|
||||
: imageLight = Image.asset('assets/images/pre_seed_light.png'),
|
||||
imageDark = Image.asset('assets/images/pre_seed_dark.png'),
|
||||
wordsCount = _wordsCount(type);
|
||||
seedPhraseLength = advancedPrivacySettingsViewModel.seedPhraseLength.value {
|
||||
wordsCount = _wordsCount(type, seedPhraseLength);
|
||||
}
|
||||
|
||||
final Image imageDark;
|
||||
final Image imageLight;
|
||||
final WalletType type;
|
||||
final int wordsCount;
|
||||
final AdvancedPrivacySettingsViewModel advancedPrivacySettingsViewModel;
|
||||
final int seedPhraseLength;
|
||||
late final int wordsCount;
|
||||
|
||||
@override
|
||||
Widget? leading(BuildContext context) => null;
|
||||
|
@ -68,13 +73,13 @@ class PreSeedPage extends BasePage {
|
|||
));
|
||||
}
|
||||
|
||||
static int _wordsCount(WalletType type) {
|
||||
static int _wordsCount(WalletType type, int seedPhraseLength) {
|
||||
switch (type) {
|
||||
case WalletType.monero:
|
||||
return 25;
|
||||
case WalletType.ethereum:
|
||||
case WalletType.bitcoinCash:
|
||||
return 12;
|
||||
return seedPhraseLength;
|
||||
default:
|
||||
return 24;
|
||||
}
|
||||
|
|
|
@ -3,8 +3,8 @@ import 'package:cake_wallet/src/screens/settings/widgets/settings_cell_with_arro
|
|||
import 'package:cake_wallet/src/screens/settings/widgets/settings_picker_cell.dart';
|
||||
import 'package:cake_wallet/src/screens/settings/widgets/settings_switcher_cell.dart';
|
||||
import 'package:cake_wallet/src/screens/settings/widgets/wallet_connect_button.dart';
|
||||
import 'package:cake_wallet/src/screens/wallet_connect/wc_connections_listing_view.dart';
|
||||
import 'package:cake_wallet/utils/device_info.dart';
|
||||
import 'package:cake_wallet/utils/feature_flag.dart';
|
||||
import 'package:cake_wallet/utils/show_pop_up.dart';
|
||||
import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/settings/sync_mode.dart';
|
||||
|
@ -90,7 +90,12 @@ class ConnectionSyncPage extends BasePage {
|
|||
onTap: () => Navigator.of(context).pushNamed(Routes.walletConnectConnectionsListing),
|
||||
),
|
||||
const StandardListSeparator(padding: EdgeInsets.symmetric(horizontal: 24)),
|
||||
]
|
||||
],
|
||||
if (FeatureFlag.isInAppTorEnabled)
|
||||
SettingsCellWithArrow(
|
||||
title: S.current.tor_connection,
|
||||
handler: (context) => Navigator.of(context).pushNamed(Routes.torPage),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
|
|
|
@ -22,77 +22,83 @@ class PrivacyPage extends BasePage {
|
|||
|
||||
@override
|
||||
Widget body(BuildContext context) {
|
||||
return Container(
|
||||
padding: EdgeInsets.only(top: 10),
|
||||
child: Observer(builder: (_) {
|
||||
return Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
SettingsChoicesCell(
|
||||
ChoicesListItem<FiatApiMode>(
|
||||
title: S.current.fiat_api,
|
||||
items: FiatApiMode.all,
|
||||
selectedItem: _privacySettingsViewModel.fiatApiMode,
|
||||
onItemSelected: (FiatApiMode fiatApiMode) =>
|
||||
_privacySettingsViewModel.setFiatMode(fiatApiMode),
|
||||
return SingleChildScrollView(
|
||||
child: Container(
|
||||
padding: EdgeInsets.only(top: 10),
|
||||
child: Observer(builder: (_) {
|
||||
return Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
SettingsChoicesCell(
|
||||
ChoicesListItem<FiatApiMode>(
|
||||
title: S.current.fiat_api,
|
||||
items: FiatApiMode.all,
|
||||
selectedItem: _privacySettingsViewModel.fiatApiMode,
|
||||
onItemSelected: (FiatApiMode fiatApiMode) =>
|
||||
_privacySettingsViewModel.setFiatMode(fiatApiMode),
|
||||
),
|
||||
),
|
||||
),
|
||||
SettingsChoicesCell(
|
||||
ChoicesListItem<ExchangeApiMode>(
|
||||
title: S.current.exchange,
|
||||
items: ExchangeApiMode.all,
|
||||
selectedItem: _privacySettingsViewModel.exchangeStatus,
|
||||
onItemSelected: (ExchangeApiMode mode) =>
|
||||
_privacySettingsViewModel.setExchangeApiMode(mode),
|
||||
SettingsChoicesCell(
|
||||
ChoicesListItem<ExchangeApiMode>(
|
||||
title: S.current.exchange,
|
||||
items: ExchangeApiMode.all,
|
||||
selectedItem: _privacySettingsViewModel.exchangeStatus,
|
||||
onItemSelected: (ExchangeApiMode mode) =>
|
||||
_privacySettingsViewModel.setExchangeApiMode(mode),
|
||||
),
|
||||
),
|
||||
),
|
||||
SettingsSwitcherCell(
|
||||
title: S.current.settings_save_recipient_address,
|
||||
value: _privacySettingsViewModel.shouldSaveRecipientAddress,
|
||||
onValueChange: (BuildContext _, bool value) {
|
||||
_privacySettingsViewModel.setShouldSaveRecipientAddress(value);
|
||||
}),
|
||||
if (_privacySettingsViewModel.isAutoGenerateSubaddressesVisible)
|
||||
SettingsSwitcherCell(
|
||||
title: S.current.auto_generate_subaddresses,
|
||||
value: _privacySettingsViewModel.isAutoGenerateSubaddressesEnabled,
|
||||
onValueChange: (BuildContext _, bool value) {
|
||||
_privacySettingsViewModel.setAutoGenerateSubaddresses(value);
|
||||
},
|
||||
),
|
||||
if (DeviceInfo.instance.isMobile)
|
||||
SettingsSwitcherCell(
|
||||
title: S.current.prevent_screenshots,
|
||||
value: _privacySettingsViewModel.isAppSecure,
|
||||
title: S.current.settings_save_recipient_address,
|
||||
value: _privacySettingsViewModel.shouldSaveRecipientAddress,
|
||||
onValueChange: (BuildContext _, bool value) {
|
||||
_privacySettingsViewModel.setIsAppSecure(value);
|
||||
_privacySettingsViewModel.setShouldSaveRecipientAddress(value);
|
||||
}),
|
||||
SettingsSwitcherCell(
|
||||
title: S.current.disable_buy,
|
||||
value: _privacySettingsViewModel.disableBuy,
|
||||
onValueChange: (BuildContext _, bool value) {
|
||||
_privacySettingsViewModel.setDisableBuy(value);
|
||||
}),
|
||||
SettingsSwitcherCell(
|
||||
title: S.current.disable_sell,
|
||||
value: _privacySettingsViewModel.disableSell,
|
||||
onValueChange: (BuildContext _, bool value) {
|
||||
_privacySettingsViewModel.setDisableSell(value);
|
||||
}),
|
||||
if (_privacySettingsViewModel.canUseEtherscan)
|
||||
SettingsSwitcherCell(
|
||||
title: S.current.etherscan_history,
|
||||
value: _privacySettingsViewModel.useEtherscan,
|
||||
if (_privacySettingsViewModel.isAutoGenerateSubaddressesVisible)
|
||||
SettingsSwitcherCell(
|
||||
title: S.current.auto_generate_subaddresses,
|
||||
value: _privacySettingsViewModel.isAutoGenerateSubaddressesEnabled,
|
||||
onValueChange: (BuildContext _, bool value) {
|
||||
_privacySettingsViewModel.setUseEtherscan(value);
|
||||
_privacySettingsViewModel.setAutoGenerateSubaddresses(value);
|
||||
},
|
||||
),
|
||||
if (DeviceInfo.instance.isMobile)
|
||||
SettingsSwitcherCell(
|
||||
title: S.current.prevent_screenshots,
|
||||
value: _privacySettingsViewModel.isAppSecure,
|
||||
onValueChange: (BuildContext _, bool value) {
|
||||
_privacySettingsViewModel.setIsAppSecure(value);
|
||||
}),
|
||||
SettingsSwitcherCell(
|
||||
title: S.current.disable_buy,
|
||||
value: _privacySettingsViewModel.disableBuy,
|
||||
onValueChange: (BuildContext _, bool value) {
|
||||
_privacySettingsViewModel.setDisableBuy(value);
|
||||
}),
|
||||
SettingsCellWithArrow(
|
||||
title: S.current.domain_looks_up,
|
||||
handler: (context) => Navigator.of(context).pushNamed(Routes.domainLookupsPage),
|
||||
),
|
||||
],
|
||||
);
|
||||
}),
|
||||
SettingsSwitcherCell(
|
||||
title: S.current.disable_sell,
|
||||
value: _privacySettingsViewModel.disableSell,
|
||||
onValueChange: (BuildContext _, bool value) {
|
||||
_privacySettingsViewModel.setDisableSell(value);
|
||||
}),
|
||||
if (_privacySettingsViewModel.canUseEtherscan)
|
||||
SettingsSwitcherCell(
|
||||
title: S.current.etherscan_history,
|
||||
value: _privacySettingsViewModel.useEtherscan,
|
||||
onValueChange: (BuildContext _, bool value) {
|
||||
_privacySettingsViewModel.setUseEtherscan(value);
|
||||
}),
|
||||
SettingsCellWithArrow(
|
||||
title: S.current.domain_looks_up,
|
||||
handler: (context) => Navigator.of(context).pushNamed(Routes.domainLookupsPage),
|
||||
),
|
||||
SettingsCellWithArrow(
|
||||
title: 'Trocador providers',
|
||||
handler: (context) => Navigator.of(context).pushNamed(Routes.trocadorProvidersPage),
|
||||
),
|
||||
],
|
||||
);
|
||||
}),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
267
lib/src/screens/settings/tor_page.dart
Normal file
267
lib/src/screens/settings/tor_page.dart
Normal file
|
@ -0,0 +1,267 @@
|
|||
import 'dart:async';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:cake_wallet/src/screens/base_page.dart';
|
||||
import 'package:cake_wallet/store/app_store.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:tor/tor.dart';
|
||||
|
||||
class TorPage extends BasePage {
|
||||
final AppStore appStore;
|
||||
|
||||
TorPage(this.appStore);
|
||||
|
||||
@override
|
||||
Widget body(BuildContext context) {
|
||||
return TorPageBody(appStore);
|
||||
}
|
||||
}
|
||||
|
||||
class TorPageBody extends StatefulWidget {
|
||||
final AppStore appStore;
|
||||
|
||||
const TorPageBody(this.appStore, {Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
State<TorPageBody> createState() => _TorPageBodyState();
|
||||
}
|
||||
|
||||
class _TorPageBodyState extends State<TorPageBody> {
|
||||
bool torEnabled = false;
|
||||
bool connecting = false;
|
||||
|
||||
// Set the default text for the host input field.
|
||||
final hostController = TextEditingController(text: 'https://icanhazip.com/');
|
||||
|
||||
// https://check.torproject.org is another good option.
|
||||
|
||||
Future<void> startTor() async {
|
||||
setState(() {
|
||||
connecting = true; // Update flag
|
||||
});
|
||||
|
||||
await Tor.init();
|
||||
|
||||
// Start the proxy
|
||||
await Tor.instance.start();
|
||||
|
||||
// Toggle started flag.
|
||||
setState(() {
|
||||
torEnabled = Tor.instance.enabled; // Update flag
|
||||
connecting = false;
|
||||
});
|
||||
|
||||
final node = widget.appStore.settingsStore.getCurrentNode(widget.appStore.wallet!.type);
|
||||
if (node.socksProxyAddress?.isEmpty ?? true) {
|
||||
node.socksProxyAddress = "${InternetAddress.loopbackIPv4.address}:${Tor.instance.port}";
|
||||
}
|
||||
widget.appStore.wallet!.connectToNode(node: node);
|
||||
|
||||
print('Done awaiting; tor should be running');
|
||||
}
|
||||
|
||||
Future<void> endTor() async {
|
||||
// Start the proxy
|
||||
Tor.instance.disable();
|
||||
|
||||
// Toggle started flag.
|
||||
setState(() {
|
||||
torEnabled = Tor.instance.enabled; // Update flag
|
||||
});
|
||||
|
||||
print('Done awaiting; tor should be stopped');
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
|
||||
torEnabled = Tor.instance.enabled;
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
// Clean up the controller when the widget is disposed.
|
||||
hostController.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return SingleChildScrollView(
|
||||
child: Container(
|
||||
padding: const EdgeInsets.all(10),
|
||||
child: connecting
|
||||
? ConnectingScreen()
|
||||
: torEnabled
|
||||
? DisconnectScreen(disconnect: endTor)
|
||||
: ConnectScreen(connect: startTor),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class ConnectScreen extends StatelessWidget {
|
||||
final Function() connect;
|
||||
|
||||
const ConnectScreen({super.key, required this.connect});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Center(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
Container(
|
||||
width: 200,
|
||||
height: 200,
|
||||
decoration: BoxDecoration(
|
||||
shape: BoxShape.circle,
|
||||
color: Colors.blue,
|
||||
),
|
||||
child: Icon(
|
||||
Icons.lock,
|
||||
color: Colors.white,
|
||||
size: 100,
|
||||
),
|
||||
),
|
||||
SizedBox(height: 20),
|
||||
Text(
|
||||
'Connect to Tor',
|
||||
style: TextStyle(
|
||||
fontSize: 24,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
SizedBox(height: 10),
|
||||
Text(
|
||||
'Your connection to the Tor network ensures privacy and security.',
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
color: Colors.grey,
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
SizedBox(height: 30),
|
||||
ElevatedButton(
|
||||
onPressed: connect,
|
||||
style: ElevatedButton.styleFrom(
|
||||
primary: Colors.blue,
|
||||
padding: EdgeInsets.symmetric(horizontal: 40, vertical: 15),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(30),
|
||||
),
|
||||
),
|
||||
child: Text(
|
||||
'Connect',
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class DisconnectScreen extends StatelessWidget {
|
||||
final Function() disconnect;
|
||||
|
||||
const DisconnectScreen({super.key, required this.disconnect});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Center(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
Container(
|
||||
width: 200,
|
||||
height: 200,
|
||||
decoration: BoxDecoration(
|
||||
shape: BoxShape.circle,
|
||||
color: Colors.green,
|
||||
),
|
||||
child: Icon(
|
||||
Icons.check,
|
||||
color: Colors.white,
|
||||
size: 100,
|
||||
),
|
||||
),
|
||||
SizedBox(height: 20),
|
||||
Text(
|
||||
'Connected to Tor',
|
||||
style: TextStyle(
|
||||
fontSize: 24,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
SizedBox(height: 10),
|
||||
Text(
|
||||
'You are currently connected to the Tor network.',
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
color: Colors.grey,
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
SizedBox(height: 30),
|
||||
ElevatedButton(
|
||||
onPressed: disconnect,
|
||||
style: ElevatedButton.styleFrom(
|
||||
primary: Colors.red,
|
||||
padding: EdgeInsets.symmetric(horizontal: 40, vertical: 15),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(30),
|
||||
),
|
||||
),
|
||||
child: Text(
|
||||
'Disconnect',
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class ConnectingScreen extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Center(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
Container(
|
||||
width: 200,
|
||||
height: 200,
|
||||
decoration: BoxDecoration(
|
||||
shape: BoxShape.circle,
|
||||
color: Colors.yellow,
|
||||
),
|
||||
child: Icon(
|
||||
Icons.hourglass_bottom,
|
||||
color: Colors.white,
|
||||
size: 100,
|
||||
),
|
||||
),
|
||||
SizedBox(height: 20),
|
||||
Text(
|
||||
'Connecting...',
|
||||
style: TextStyle(
|
||||
fontSize: 24,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
SizedBox(height: 10),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
37
lib/src/screens/settings/trocador_providers_page.dart
Normal file
37
lib/src/screens/settings/trocador_providers_page.dart
Normal file
|
@ -0,0 +1,37 @@
|
|||
import 'package:cake_wallet/exchange/provider/trocador_exchange_provider.dart';
|
||||
import 'package:cake_wallet/src/screens/base_page.dart';
|
||||
import 'package:cake_wallet/src/screens/settings/widgets/settings_switcher_cell.dart';
|
||||
import 'package:cake_wallet/view_model/settings/trocador_providers_view_model.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||
|
||||
class TrocadorProvidersPage extends BasePage {
|
||||
TrocadorProvidersPage(this.trocadorProvidersViewModel);
|
||||
|
||||
@override
|
||||
String get title => 'Trocador Providers';
|
||||
|
||||
final TrocadorProvidersViewModel trocadorProvidersViewModel;
|
||||
|
||||
@override
|
||||
Widget body(BuildContext context) {
|
||||
final availableProviders = TrocadorExchangeProvider.availableProviders;
|
||||
final providerStates = trocadorProvidersViewModel.providerStates;
|
||||
return Container(
|
||||
padding: EdgeInsets.only(top: 10),
|
||||
child: ListView.builder(
|
||||
itemCount: availableProviders.length,
|
||||
itemBuilder: (_, index) {
|
||||
String provider = availableProviders[index];
|
||||
return Observer(
|
||||
builder: (_) => SettingsSwitcherCell(
|
||||
title: provider,
|
||||
value: providerStates[provider] ?? false,
|
||||
onValueChange: (BuildContext _, bool value) {
|
||||
trocadorProvidersViewModel.toggleProviderState(provider);
|
||||
}));
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -67,13 +67,16 @@ class AddressTextField extends StatelessWidget {
|
|||
enabled: isActive,
|
||||
controller: controller,
|
||||
focusNode: focusNode,
|
||||
|
||||
style: textStyle ??
|
||||
TextStyle(
|
||||
fontSize: 16, color: Theme.of(context).extension<CakeTextTheme>()!.titleColor),
|
||||
decoration: InputDecoration(
|
||||
|
||||
suffixIcon: SizedBox(
|
||||
width: prefixIconWidth * options.length + (spaceBetweenPrefixIcons * options.length),
|
||||
),
|
||||
|
||||
hintStyle: hintStyle ?? TextStyle(fontSize: 16, color: Theme.of(context).hintColor),
|
||||
hintText: placeholder ?? S.current.widgets_address,
|
||||
focusedBorder: isBorderExist
|
||||
|
|
|
@ -3,7 +3,6 @@ import 'dart:ui';
|
|||
import 'package:cake_wallet/src/widgets/section_divider.dart';
|
||||
import 'package:cake_wallet/themes/extensions/alert_theme.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:cake_wallet/palette.dart';
|
||||
|
||||
class BaseAlertDialog extends StatelessWidget {
|
||||
String get titleText => '';
|
||||
|
@ -49,7 +48,7 @@ class BaseAlertDialog extends StatelessWidget {
|
|||
|
||||
Widget actionButtons(BuildContext context) {
|
||||
return Container(
|
||||
height: 52,
|
||||
height: 60,
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
|
|
|
@ -52,7 +52,7 @@ class OptionTile extends StatelessWidget {
|
|||
child: Text(
|
||||
description,
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.normal,
|
||||
color: Theme.of(context).extension<OptionTileTheme>()!.descriptionColor,
|
||||
),
|
||||
|
|
|
@ -10,7 +10,9 @@ import 'package:cake_wallet/entities/exchange_api_mode.dart';
|
|||
import 'package:cake_wallet/entities/exchange_provider_types.dart';
|
||||
import 'package:cake_wallet/entities/pin_code_required_duration.dart';
|
||||
import 'package:cake_wallet/entities/preferences_key.dart';
|
||||
import 'package:cake_wallet/entities/seed_phrase_length.dart';
|
||||
import 'package:cake_wallet/entities/sort_balance_types.dart';
|
||||
import 'package:cake_wallet/exchange/provider/trocador_exchange_provider.dart';
|
||||
import 'package:cake_wallet/view_model/settings/sync_mode.dart';
|
||||
import 'package:cake_wallet/utils/device_info.dart';
|
||||
import 'package:cake_wallet/ethereum/ethereum.dart';
|
||||
|
@ -72,6 +74,7 @@ abstract class SettingsStoreBase with Store {
|
|||
required this.isBitcoinBuyEnabled,
|
||||
required this.actionlistDisplayMode,
|
||||
required this.pinTimeOutDuration,
|
||||
required this.seedPhraseLength,
|
||||
required Cake2FAPresetsOptions initialCake2FAPresetOptions,
|
||||
required bool initialShouldRequireTOTP2FAForAccessingWallet,
|
||||
required bool initialShouldRequireTOTP2FAForSendsToContact,
|
||||
|
@ -85,6 +88,8 @@ abstract class SettingsStoreBase with Store {
|
|||
required this.sortBalanceBy,
|
||||
required this.pinNativeTokenAtTop,
|
||||
required this.useEtherscan,
|
||||
required this.defaultNanoRep,
|
||||
required this.defaultBananoRep,
|
||||
required this.lookupsTwitter,
|
||||
required this.lookupsMastodon,
|
||||
required this.lookupsYatService,
|
||||
|
@ -164,6 +169,8 @@ abstract class SettingsStoreBase with Store {
|
|||
priority[WalletType.bitcoinCash] = initialBitcoinCashTransactionPriority;
|
||||
}
|
||||
|
||||
initializeTrocadorProviderStates();
|
||||
|
||||
reaction(
|
||||
(_) => fiatCurrency,
|
||||
(FiatCurrency fiatCurrency) => sharedPreferences.setString(
|
||||
|
@ -334,6 +341,11 @@ abstract class SettingsStoreBase with Store {
|
|||
(String languageCode) =>
|
||||
sharedPreferences.setString(PreferencesKey.currentLanguageCode, languageCode));
|
||||
|
||||
reaction(
|
||||
(_) => seedPhraseLength,
|
||||
(SeedPhraseLength seedPhraseWordCount) =>
|
||||
sharedPreferences.setInt(PreferencesKey.currentSeedPhraseLength, seedPhraseWordCount.value));
|
||||
|
||||
reaction(
|
||||
(_) => pinTimeOutDuration,
|
||||
(PinCodeRequiredDuration pinCodeInterval) =>
|
||||
|
@ -376,6 +388,13 @@ abstract class SettingsStoreBase with Store {
|
|||
(bool useEtherscan) =>
|
||||
_sharedPreferences.setBool(PreferencesKey.useEtherscan, useEtherscan));
|
||||
|
||||
reaction((_) => defaultNanoRep,
|
||||
(String nanoRep) => _sharedPreferences.setString(PreferencesKey.defaultNanoRep, nanoRep));
|
||||
|
||||
reaction(
|
||||
(_) => defaultBananoRep,
|
||||
(String bananoRep) =>
|
||||
_sharedPreferences.setString(PreferencesKey.defaultBananoRep, bananoRep));
|
||||
reaction(
|
||||
(_) => lookupsTwitter,
|
||||
(bool looksUpTwitter) =>
|
||||
|
@ -423,6 +442,7 @@ abstract class SettingsStoreBase with Store {
|
|||
static const defaultActionsMode = 11;
|
||||
static const defaultPinCodeTimeOutDuration = PinCodeRequiredDuration.tenminutes;
|
||||
static const defaultAutoGenerateSubaddressStatus = AutoGenerateSubaddressStatus.initialized;
|
||||
static const defaultSeedPhraseLength = SeedPhraseLength.twelveWords;
|
||||
|
||||
@observable
|
||||
FiatCurrency fiatCurrency;
|
||||
|
@ -517,6 +537,9 @@ abstract class SettingsStoreBase with Store {
|
|||
@observable
|
||||
PinCodeRequiredDuration pinTimeOutDuration;
|
||||
|
||||
@observable
|
||||
SeedPhraseLength seedPhraseLength;
|
||||
|
||||
@computed
|
||||
ThemeData get theme => currentTheme.themeData;
|
||||
|
||||
|
@ -526,6 +549,9 @@ abstract class SettingsStoreBase with Store {
|
|||
@observable
|
||||
ObservableMap<WalletType, TransactionPriority> priority;
|
||||
|
||||
@observable
|
||||
ObservableMap<String, bool> trocadorProviderStates = ObservableMap<String, bool>();
|
||||
|
||||
@observable
|
||||
SortBalanceBy sortBalanceBy;
|
||||
|
||||
|
@ -535,6 +561,12 @@ abstract class SettingsStoreBase with Store {
|
|||
@observable
|
||||
bool useEtherscan;
|
||||
|
||||
@observable
|
||||
String defaultNanoRep;
|
||||
|
||||
@observable
|
||||
String defaultBananoRep;
|
||||
|
||||
@observable
|
||||
bool lookupsTwitter;
|
||||
|
||||
|
@ -706,14 +738,20 @@ abstract class SettingsStoreBase with Store {
|
|||
sharedPreferences.getInt(PreferencesKey.displayActionListModeKey) ?? defaultActionsMode));
|
||||
var pinLength = sharedPreferences.getInt(PreferencesKey.currentPinLength);
|
||||
final timeOutDuration = sharedPreferences.getInt(PreferencesKey.pinTimeOutDuration);
|
||||
final seedPhraseCount = sharedPreferences.getInt(PreferencesKey.currentSeedPhraseLength);
|
||||
final pinCodeTimeOutDuration = timeOutDuration != null
|
||||
? PinCodeRequiredDuration.deserialize(raw: timeOutDuration)
|
||||
: defaultPinCodeTimeOutDuration;
|
||||
final seedPhraseWordCount = seedPhraseCount != null
|
||||
? SeedPhraseLength.deserialize(raw: seedPhraseCount)
|
||||
: defaultSeedPhraseLength;
|
||||
final sortBalanceBy =
|
||||
SortBalanceBy.values[sharedPreferences.getInt(PreferencesKey.sortBalanceBy) ?? 0];
|
||||
final pinNativeTokenAtTop =
|
||||
sharedPreferences.getBool(PreferencesKey.pinNativeTokenAtTop) ?? true;
|
||||
final useEtherscan = sharedPreferences.getBool(PreferencesKey.useEtherscan) ?? true;
|
||||
final defaultNanoRep = sharedPreferences.getString(PreferencesKey.defaultNanoRep) ?? "";
|
||||
final defaultBananoRep = sharedPreferences.getString(PreferencesKey.defaultBananoRep) ?? "";
|
||||
final lookupsTwitter = sharedPreferences.getBool(PreferencesKey.lookupsTwitter) ?? true;
|
||||
final lookupsMastodon = sharedPreferences.getBool(PreferencesKey.lookupsMastodon) ?? true;
|
||||
final lookupsYatService = sharedPreferences.getBool(PreferencesKey.lookupsYatService) ?? true;
|
||||
|
@ -824,10 +862,13 @@ abstract class SettingsStoreBase with Store {
|
|||
actionlistDisplayMode: actionListDisplayMode,
|
||||
initialPinLength: pinLength,
|
||||
pinTimeOutDuration: pinCodeTimeOutDuration,
|
||||
seedPhraseLength: seedPhraseWordCount,
|
||||
initialLanguageCode: savedLanguageCode,
|
||||
sortBalanceBy: sortBalanceBy,
|
||||
pinNativeTokenAtTop: pinNativeTokenAtTop,
|
||||
useEtherscan: useEtherscan,
|
||||
defaultNanoRep: defaultNanoRep,
|
||||
defaultBananoRep: defaultBananoRep,
|
||||
lookupsTwitter: lookupsTwitter,
|
||||
lookupsMastodon: lookupsMastodon,
|
||||
lookupsYatService: lookupsYatService,
|
||||
|
@ -974,6 +1015,8 @@ abstract class SettingsStoreBase with Store {
|
|||
.values[sharedPreferences.getInt(PreferencesKey.sortBalanceBy) ?? sortBalanceBy.index];
|
||||
pinNativeTokenAtTop = sharedPreferences.getBool(PreferencesKey.pinNativeTokenAtTop) ?? true;
|
||||
useEtherscan = sharedPreferences.getBool(PreferencesKey.useEtherscan) ?? true;
|
||||
defaultNanoRep = sharedPreferences.getString(PreferencesKey.defaultNanoRep) ?? "";
|
||||
defaultBananoRep = sharedPreferences.getString(PreferencesKey.defaultBananoRep) ?? "";
|
||||
lookupsTwitter = sharedPreferences.getBool(PreferencesKey.lookupsTwitter) ?? true;
|
||||
lookupsMastodon = sharedPreferences.getBool(PreferencesKey.lookupsMastodon) ?? true;
|
||||
lookupsYatService = sharedPreferences.getBool(PreferencesKey.lookupsYatService) ?? true;
|
||||
|
@ -1074,6 +1117,19 @@ abstract class SettingsStoreBase with Store {
|
|||
powNodes[walletType] = node;
|
||||
}
|
||||
|
||||
void initializeTrocadorProviderStates() {
|
||||
for (var provider in TrocadorExchangeProvider.availableProviders) {
|
||||
final savedState = _sharedPreferences.getBool(provider) ?? true;
|
||||
trocadorProviderStates[provider] = savedState;
|
||||
}
|
||||
}
|
||||
|
||||
void saveTrocadorProviderState(String providerName, bool state) {
|
||||
_sharedPreferences.setBool(providerName, state);
|
||||
trocadorProviderStates[providerName] = state;
|
||||
}
|
||||
|
||||
|
||||
static Future<String?> _getDeviceName() async {
|
||||
String? deviceName = '';
|
||||
final deviceInfoPlugin = DeviceInfoPlugin();
|
||||
|
|
|
@ -162,6 +162,7 @@ class ExceptionHandler {
|
|||
"Error while launching http",
|
||||
"OS Error: Network is unreachable",
|
||||
"ClientException: Write failed, uri=http",
|
||||
"Connection terminated during handshake",
|
||||
];
|
||||
|
||||
static Future<void> _addDeviceInfo(File file) async {
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
class FeatureFlag {
|
||||
static const bool isCakePayEnabled = false;
|
||||
static const bool isExolixEnabled = false;
|
||||
static const bool isInAppTorEnabled = false;
|
||||
}
|
|
@ -17,7 +17,9 @@ class PermissionHandler {
|
|||
var status = await permission.status;
|
||||
|
||||
if (status.isDenied) {
|
||||
status = await permission.request();
|
||||
try {
|
||||
status = await permission.request();
|
||||
} catch (_) {}
|
||||
}
|
||||
|
||||
if (status.isPermanentlyDenied || status.isDenied) {
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import 'package:cake_wallet/entities/exchange_api_mode.dart';
|
||||
import 'package:cake_wallet/entities/fiat_api_mode.dart';
|
||||
import 'package:cake_wallet/entities/seed_phrase_length.dart';
|
||||
import 'package:cake_wallet/store/settings_store.dart';
|
||||
import 'package:cw_core/wallet_type.dart';
|
||||
import 'package:mobx/mobx.dart';
|
||||
|
@ -25,9 +26,15 @@ abstract class AdvancedPrivacySettingsViewModelBase with Store {
|
|||
|
||||
final SettingsStore _settingsStore;
|
||||
|
||||
bool get hasSeedPhraseLengthOption =>
|
||||
type == WalletType.bitcoinCash || type == WalletType.ethereum;
|
||||
|
||||
@computed
|
||||
bool get addCustomNode => _addCustomNode;
|
||||
|
||||
@computed
|
||||
SeedPhraseLength get seedPhraseLength => _settingsStore.seedPhraseLength;
|
||||
|
||||
@action
|
||||
void setFiatApiMode(FiatApiMode fiatApiMode) => _settingsStore.fiatApiMode = fiatApiMode;
|
||||
|
||||
|
@ -36,4 +43,7 @@ abstract class AdvancedPrivacySettingsViewModelBase with Store {
|
|||
|
||||
@action
|
||||
void toggleAddCustomNode() => _addCustomNode = !_addCustomNode;
|
||||
|
||||
@action
|
||||
void setSeedPhraseLength(SeedPhraseLength length) => _settingsStore.seedPhraseLength = length;
|
||||
}
|
||||
|
|
|
@ -392,6 +392,6 @@ abstract class BalanceViewModelBase with Store {
|
|||
}
|
||||
}
|
||||
|
||||
String getFormattedFrozenBalance(Balance walletBalance) => walletBalance.formattedFrozenBalance;
|
||||
String getFormattedFrozenBalance(Balance walletBalance) => walletBalance.formattedUnAvailableBalance;
|
||||
}
|
||||
|
||||
|
|
139
lib/view_model/dashboard/nft_view_model.dart
Normal file
139
lib/view_model/dashboard/nft_view_model.dart
Normal file
|
@ -0,0 +1,139 @@
|
|||
// ignore_for_file: public_member_api_docs, sort_constructors_first
|
||||
import 'dart:convert';
|
||||
import 'dart:developer';
|
||||
|
||||
import 'package:cake_wallet/core/wallet_connect/wc_bottom_sheet_service.dart';
|
||||
import 'package:cake_wallet/src/screens/wallet_connect/widgets/message_display_widget.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'package:mobx/mobx.dart';
|
||||
import 'package:cake_wallet/.secrets.g.dart' as secrets;
|
||||
|
||||
import 'package:cake_wallet/entities/wallet_nft_response.dart';
|
||||
import 'package:cake_wallet/store/app_store.dart';
|
||||
|
||||
part 'nft_view_model.g.dart';
|
||||
|
||||
class NFTViewModel = NFTViewModelBase with _$NFTViewModel;
|
||||
|
||||
abstract class NFTViewModelBase with Store {
|
||||
NFTViewModelBase(this.appStore, this.bottomSheetService)
|
||||
: isLoading = false,
|
||||
isImportNFTLoading = false,
|
||||
nftAssetByWalletModels = ObservableList() {
|
||||
getNFTAssetByWallet();
|
||||
|
||||
reaction((_) => appStore.wallet, (_) => getNFTAssetByWallet());
|
||||
}
|
||||
|
||||
final AppStore appStore;
|
||||
final BottomSheetService bottomSheetService;
|
||||
|
||||
@observable
|
||||
bool isLoading;
|
||||
|
||||
@observable
|
||||
bool isImportNFTLoading;
|
||||
|
||||
ObservableList<NFTAssetModel> nftAssetByWalletModels;
|
||||
|
||||
@action
|
||||
Future<void> getNFTAssetByWallet() async {
|
||||
final walletAddress = appStore.wallet!.walletInfo.address;
|
||||
log('Fetching wallet NFTs for $walletAddress');
|
||||
|
||||
// the [chain] refers to the chain network that the nft is on
|
||||
// the [format] refers to the number format type of the responses
|
||||
// the [normalizedMetadata] field is a boolean that determines if
|
||||
// the response would include a json string of the NFT Metadata that can be decoded
|
||||
// and used within the wallet
|
||||
final uri = Uri.https(
|
||||
'deep-index.moralis.io',
|
||||
'/api/v2.2/$walletAddress/nft',
|
||||
{
|
||||
"chain": "eth",
|
||||
"format": "decimal",
|
||||
"media_items": "false",
|
||||
"normalizeMetadata": "true",
|
||||
},
|
||||
);
|
||||
|
||||
try {
|
||||
isLoading = true;
|
||||
|
||||
final response = await http.get(
|
||||
uri,
|
||||
headers: {
|
||||
"Accept": "application/json",
|
||||
"X-API-Key": secrets.moralisApiKey,
|
||||
},
|
||||
);
|
||||
|
||||
final decodedResponse = jsonDecode(response.body) as Map<String, dynamic>;
|
||||
|
||||
final result = WalletNFTsResponseModel.fromJson(decodedResponse).result ?? [];
|
||||
|
||||
nftAssetByWalletModels.clear();
|
||||
|
||||
nftAssetByWalletModels.addAll(result);
|
||||
|
||||
isLoading = false;
|
||||
} catch (e) {
|
||||
isLoading = false;
|
||||
log(e.toString());
|
||||
bottomSheetService.queueBottomSheet(
|
||||
isModalDismissible: true,
|
||||
widget: BottomSheetMessageDisplayWidget(
|
||||
message: e.toString(),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@action
|
||||
Future<void> importNFT(String tokenAddress, String tokenId) async {
|
||||
|
||||
// the [chain] refers to the chain network that the nft is on
|
||||
// the [format] refers to the number format type of the responses
|
||||
// the [normalizedMetadata] field is a boolean that determines if
|
||||
// the response would include a json string of the NFT Metadata that can be decoded
|
||||
// and used within the wallet
|
||||
final uri = Uri.https(
|
||||
'deep-index.moralis.io',
|
||||
'/api/v2.2/nft/$tokenAddress/$tokenId',
|
||||
{
|
||||
"chain": "eth",
|
||||
"format": "decimal",
|
||||
"media_items": "false",
|
||||
"normalizeMetadata": "true",
|
||||
},
|
||||
);
|
||||
|
||||
try {
|
||||
isImportNFTLoading = true;
|
||||
|
||||
final response = await http.get(
|
||||
uri,
|
||||
headers: {
|
||||
"Accept": "application/json",
|
||||
"X-API-Key": secrets.moralisApiKey,
|
||||
},
|
||||
);
|
||||
|
||||
final decodedResponse = jsonDecode(response.body) as Map<String, dynamic>;
|
||||
|
||||
final nftAsset = NFTAssetModel.fromJson(decodedResponse);
|
||||
|
||||
nftAssetByWalletModels.add(nftAsset);
|
||||
|
||||
isImportNFTLoading = false;
|
||||
} catch (e) {
|
||||
isImportNFTLoading = false;
|
||||
bottomSheetService.queueBottomSheet(
|
||||
isModalDismissible: true,
|
||||
widget: BottomSheetMessageDisplayWidget(
|
||||
message: e.toString(),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -146,7 +146,8 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with
|
|||
ChangeNowExchangeProvider(settingsStore: _settingsStore),
|
||||
SideShiftExchangeProvider(),
|
||||
SimpleSwapExchangeProvider(),
|
||||
TrocadorExchangeProvider(useTorOnly: _useTorOnly),
|
||||
TrocadorExchangeProvider(useTorOnly: _useTorOnly,
|
||||
providerStates: _settingsStore.trocadorProviderStates),
|
||||
if (FeatureFlag.isExolixEnabled) ExolixExchangeProvider(),
|
||||
];
|
||||
|
||||
|
|
21
lib/view_model/settings/trocador_providers_view_model.dart
Normal file
21
lib/view_model/settings/trocador_providers_view_model.dart
Normal file
|
@ -0,0 +1,21 @@
|
|||
import 'package:cake_wallet/store/settings_store.dart';
|
||||
import 'package:mobx/mobx.dart';
|
||||
|
||||
part 'trocador_providers_view_model.g.dart';
|
||||
|
||||
class TrocadorProvidersViewModel = TrocadorProvidersViewModelBase with _$TrocadorProvidersViewModel;
|
||||
|
||||
abstract class TrocadorProvidersViewModelBase with Store {
|
||||
TrocadorProvidersViewModelBase(this._settingsStore);
|
||||
|
||||
final SettingsStore _settingsStore;
|
||||
|
||||
@computed
|
||||
Map<String, bool> get providerStates => _settingsStore.trocadorProviderStates;
|
||||
|
||||
@action
|
||||
void toggleProviderState(String providerName) {
|
||||
final currentState = providerStates[providerName] ?? false;
|
||||
_settingsStore.saveTrocadorProviderState(providerName, !currentState);
|
||||
}
|
||||
}
|
|
@ -12,13 +12,12 @@ import devicelocale
|
|||
import flutter_secure_storage_macos
|
||||
import in_app_review
|
||||
import package_info
|
||||
import package_info_plus
|
||||
import path_provider_foundation
|
||||
import platform_device_id
|
||||
import platform_device_id_macos
|
||||
import share_plus_macos
|
||||
import shared_preferences_foundation
|
||||
import url_launcher_macos
|
||||
import wakelock_macos
|
||||
import wakelock_plus
|
||||
|
||||
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
||||
ConnectivityPlugin.register(with: registry.registrar(forPlugin: "ConnectivityPlugin"))
|
||||
|
@ -28,11 +27,10 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
|||
FlutterSecureStoragePlugin.register(with: registry.registrar(forPlugin: "FlutterSecureStoragePlugin"))
|
||||
InAppReviewPlugin.register(with: registry.registrar(forPlugin: "InAppReviewPlugin"))
|
||||
FLTPackageInfoPlugin.register(with: registry.registrar(forPlugin: "FLTPackageInfoPlugin"))
|
||||
FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FPPPackageInfoPlusPlugin"))
|
||||
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
|
||||
PlatformDeviceIdMacosPlugin.register(with: registry.registrar(forPlugin: "PlatformDeviceIdMacosPlugin"))
|
||||
PlatformDeviceIdMacosPlugin.register(with: registry.registrar(forPlugin: "PlatformDeviceIdMacosPlugin"))
|
||||
SharePlusMacosPlugin.register(with: registry.registrar(forPlugin: "SharePlusMacosPlugin"))
|
||||
SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
|
||||
UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin"))
|
||||
WakelockMacosPlugin.register(with: registry.registrar(forPlugin: "WakelockMacosPlugin"))
|
||||
WakelockPlusMacosPlugin.register(with: registry.registrar(forPlugin: "WakelockPlusMacosPlugin"))
|
||||
}
|
||||
|
|
|
@ -30,13 +30,11 @@ PODS:
|
|||
- FlutterMacOS
|
||||
- package_info (0.0.1):
|
||||
- FlutterMacOS
|
||||
- package_info_plus (0.0.1):
|
||||
- FlutterMacOS
|
||||
- path_provider_foundation (0.0.1):
|
||||
- Flutter
|
||||
- FlutterMacOS
|
||||
- platform_device_id (0.0.1):
|
||||
- FlutterMacOS
|
||||
- platform_device_id_macos (0.0.1):
|
||||
- FlutterMacOS
|
||||
- ReachabilitySwift (5.0.0)
|
||||
- share_plus_macos (0.0.1):
|
||||
- FlutterMacOS
|
||||
|
@ -45,7 +43,7 @@ PODS:
|
|||
- FlutterMacOS
|
||||
- url_launcher_macos (0.0.1):
|
||||
- FlutterMacOS
|
||||
- wakelock_macos (0.0.1):
|
||||
- wakelock_plus (0.0.1):
|
||||
- FlutterMacOS
|
||||
|
||||
DEPENDENCIES:
|
||||
|
@ -57,13 +55,12 @@ DEPENDENCIES:
|
|||
- FlutterMacOS (from `Flutter/ephemeral`)
|
||||
- in_app_review (from `Flutter/ephemeral/.symlinks/plugins/in_app_review/macos`)
|
||||
- package_info (from `Flutter/ephemeral/.symlinks/plugins/package_info/macos`)
|
||||
- package_info_plus (from `Flutter/ephemeral/.symlinks/plugins/package_info_plus/macos`)
|
||||
- path_provider_foundation (from `Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin`)
|
||||
- platform_device_id (from `Flutter/ephemeral/.symlinks/plugins/platform_device_id/macos`)
|
||||
- platform_device_id_macos (from `Flutter/ephemeral/.symlinks/plugins/platform_device_id_macos/macos`)
|
||||
- share_plus_macos (from `Flutter/ephemeral/.symlinks/plugins/share_plus_macos/macos`)
|
||||
- shared_preferences_foundation (from `Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin`)
|
||||
- url_launcher_macos (from `Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos`)
|
||||
- wakelock_macos (from `Flutter/ephemeral/.symlinks/plugins/wakelock_macos/macos`)
|
||||
- wakelock_plus (from `Flutter/ephemeral/.symlinks/plugins/wakelock_plus/macos`)
|
||||
|
||||
SPEC REPOS:
|
||||
trunk:
|
||||
|
@ -86,20 +83,18 @@ EXTERNAL SOURCES:
|
|||
:path: Flutter/ephemeral/.symlinks/plugins/in_app_review/macos
|
||||
package_info:
|
||||
:path: Flutter/ephemeral/.symlinks/plugins/package_info/macos
|
||||
package_info_plus:
|
||||
:path: Flutter/ephemeral/.symlinks/plugins/package_info_plus/macos
|
||||
path_provider_foundation:
|
||||
:path: Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin
|
||||
platform_device_id:
|
||||
:path: Flutter/ephemeral/.symlinks/plugins/platform_device_id/macos
|
||||
platform_device_id_macos:
|
||||
:path: Flutter/ephemeral/.symlinks/plugins/platform_device_id_macos/macos
|
||||
share_plus_macos:
|
||||
:path: Flutter/ephemeral/.symlinks/plugins/share_plus_macos/macos
|
||||
shared_preferences_foundation:
|
||||
:path: Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin
|
||||
url_launcher_macos:
|
||||
:path: Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos
|
||||
wakelock_macos:
|
||||
:path: Flutter/ephemeral/.symlinks/plugins/wakelock_macos/macos
|
||||
wakelock_plus:
|
||||
:path: Flutter/ephemeral/.symlinks/plugins/wakelock_plus/macos
|
||||
|
||||
SPEC CHECKSUMS:
|
||||
connectivity_plus_macos: f6e86fd000e971d361e54b5afcadc8c8fa773308
|
||||
|
@ -110,14 +105,13 @@ SPEC CHECKSUMS:
|
|||
FlutterMacOS: 8f6f14fa908a6fb3fba0cd85dbd81ec4b251fb24
|
||||
in_app_review: a850789fad746e89bce03d4aeee8078b45a53fd0
|
||||
package_info: 6eba2fd8d3371dda2d85c8db6fe97488f24b74b2
|
||||
package_info_plus: 02d7a575e80f194102bef286361c6c326e4c29ce
|
||||
path_provider_foundation: 29f094ae23ebbca9d3d0cec13889cd9060c0e943
|
||||
platform_device_id: 3e414428f45df149bbbfb623e2c0ca27c545b763
|
||||
platform_device_id_macos: f763bb55f088be804d61b96eb4710b8ab6598e94
|
||||
ReachabilitySwift: 985039c6f7b23a1da463388634119492ff86c825
|
||||
share_plus_macos: 853ee48e7dce06b633998ca0735d482dd671ade4
|
||||
shared_preferences_foundation: 5b919d13b803cadd15ed2dc053125c68730e5126
|
||||
url_launcher_macos: d2691c7dd33ed713bf3544850a623080ec693d95
|
||||
wakelock_macos: bc3f2a9bd8d2e6c89fee1e1822e7ddac3bd004a9
|
||||
wakelock_plus: 4783562c9a43d209c458cb9b30692134af456269
|
||||
|
||||
PODFILE CHECKSUM: 5107934592df7813b33d744aebc8ddc6b5a5445f
|
||||
|
||||
|
|
|
@ -60,16 +60,21 @@ dependencies:
|
|||
another_flushbar: ^1.12.29
|
||||
archive: ^3.3.0
|
||||
cryptography: ^2.0.5
|
||||
file_picker: ^5.2.5
|
||||
file_picker:
|
||||
git:
|
||||
url: https://github.com/cake-tech/flutter_file_picker.git
|
||||
ref: master
|
||||
unorm_dart: ^0.2.0
|
||||
# check unorm_dart for usage and for replace
|
||||
permission_handler: ^10.0.0
|
||||
device_display_brightness: ^0.0.6
|
||||
device_display_brightness:
|
||||
git:
|
||||
url: https://github.com/cake-tech/device_display_brightness.git
|
||||
ref: master
|
||||
workmanager: ^0.5.1
|
||||
platform_device_id: ^1.0.1
|
||||
wakelock: ^0.6.2
|
||||
wakelock_plus: ^1.1.3
|
||||
flutter_mailer: ^2.0.2
|
||||
device_info_plus: 8.1.0
|
||||
device_info_plus: ^9.1.0
|
||||
base32: 2.1.3
|
||||
in_app_review: ^2.0.6
|
||||
cake_backup:
|
||||
|
@ -78,7 +83,7 @@ dependencies:
|
|||
ref: main
|
||||
version: 1.0.0
|
||||
flutter_plugin_android_lifecycle: 2.0.9
|
||||
path_provider_android: 2.0.24
|
||||
path_provider_android: ^2.2.1
|
||||
shared_preferences_android: 2.0.17
|
||||
url_launcher_android: 6.0.24
|
||||
sensitive_clipboard: ^1.0.0
|
||||
|
@ -93,6 +98,12 @@ dependencies:
|
|||
url: https://github.com/cake-tech/bitcoin_flutter.git
|
||||
ref: cake-update-v3
|
||||
fluttertoast: 8.1.4
|
||||
tor:
|
||||
git:
|
||||
url: https://github.com/cake-tech/tor.git
|
||||
ref: main
|
||||
socks5_proxy: ^1.0.4
|
||||
flutter_svg: ^2.0.9
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
|
|
|
@ -383,7 +383,7 @@
|
|||
"change_backup_password_alert": "لن تكون ملفات النسخ الاحتياطي السابقة متاحة للاستيراد بكلمة مرور نسخ احتياطي جديدة. سيتم استخدام كلمة مرور النسخ الاحتياطي الجديدة لملفات النسخ الاحتياطي الجديدة فقط. هل أنت متأكد أنك تريد تغيير كلمة المرور الاحتياطية؟",
|
||||
"enter_backup_password": "أدخل كلمة المرور الاحتياطية هنا",
|
||||
"select_backup_file": "حدد ملف النسخ الاحتياطي",
|
||||
"import": "اختيار ملف",
|
||||
"import": "ﺩﺭﻮﺘﺴﻳ",
|
||||
"please_select_backup_file": "الرجاء تحديد ملف النسخ الاحتياطي وإدخال كلمة مرور النسخ الاحتياطي.",
|
||||
"fixed_rate": "السعر الثابت",
|
||||
"fixed_rate_alert": "ستتمكن من إدخال مبلغ الاستلام عند تشغيل وضع السعر الثابت. هل تريد التبديل إلى وضع السعر الثابت؟",
|
||||
|
@ -591,7 +591,6 @@
|
|||
"sweeping_wallet_alert": "لن يستغرق هذا وقتًا طويلاً. لا تترك هذه الشاشة وإلا فقد يتم فقد أموال سويبت",
|
||||
"decimal_places_error": "عدد كبير جدًا من المنازل العشرية",
|
||||
"edit_node": "تحرير العقدة",
|
||||
"frozen_balance": "الرصيد المجمد",
|
||||
"invoice_details": "تفاصيل الفاتورة",
|
||||
"donation_link_details": "تفاصيل رابط التبرع",
|
||||
"anonpay_description": "توليد ${type}. يمكن للمستلم ${method} بأي عملة مشفرة مدعومة ، وستتلقى أموالاً في هذه",
|
||||
|
@ -724,6 +723,7 @@
|
|||
"enterWalletConnectURI": "WalletConnect ـﻟ URI ﻞﺧﺩﺃ",
|
||||
"seed_key": "مفتاح البذور",
|
||||
"enter_seed_phrase": "أدخل عبارة البذور الخاصة بك",
|
||||
"change_rep_successful": "تم تغيير ممثل بنجاح",
|
||||
"add_contact": "ﻝﺎﺼﺗﺍ ﺔﻬﺟ ﺔﻓﺎﺿﺇ",
|
||||
"exchange_provider_unsupported": "${providerName} لم يعد مدعومًا!",
|
||||
"domain_looks_up": "ﻝﺎﺠﻤﻟﺍ ﺚﺤﺑ ﺕﺎﻴﻠﻤﻋ",
|
||||
|
@ -732,5 +732,16 @@
|
|||
"switchToETHWallet": "ﻯﺮﺧﺃ ﺓﺮﻣ ﺔﻟﻭﺎﺤﻤﻟﺍﻭ Ethereum ﺔﻈﻔﺤﻣ ﻰﻟﺇ ﻞﻳﺪﺒﺘﻟﺍ ﻰﺟﺮﻳ",
|
||||
"moonpay_exchange_description": "تبديل العملة المشفرة سلسة.",
|
||||
"kyc_required": "الحساب و KYC مطلوب",
|
||||
"unspent_change": "يتغير"
|
||||
"importNFTs": "NFTs ﺩﺍﺮﻴﺘﺳﺍ",
|
||||
"noNFTYet": "ﻥﻵﺍ ﻰﺘﺣ NFTs ﺪﺟﻮﻳ ﻻ",
|
||||
"address": " ﻥﺍﻮﻨﻋ",
|
||||
"enterTokenID": "ﺰﻴﻤﻤﻟﺍ ﺰﻣﺮﻟﺍ ﻑﺮﻌﻣ ﻞﺧﺩﺃ",
|
||||
"tokenID": "ﻒﻳﺮﻌﺗ ﺔﻗﺎﻄﺑ",
|
||||
"name": "ﻢﺳﺍ",
|
||||
"symbol": "ﺰﻣﺭ",
|
||||
"seed_phrase_length": "ﺭﻭﺬﺒﻟﺍ ﺓﺭﺎﺒﻌﻟﺍ ﻝﻮﻃ",
|
||||
"unavailable_balance": "ﺮﻓﻮﺘﻣ ﺮﻴﻏ ﺪﻴﺻﺭ",
|
||||
"unavailable_balance_description": ".ﺎﻫﺪﻴﻤﺠﺗ ءﺎﻐﻟﺇ ﺭﺮﻘﺗ ﻰﺘﺣ ﺕﻼﻣﺎﻌﻤﻠﻟ ﻝﻮﺻﻮﻠﻟ ﺔﻠﺑﺎﻗ ﺮﻴﻏ ﺓﺪﻤﺠﻤﻟﺍ ﺓﺪﺻﺭﻷﺍ ﻞﻈﺗ ﺎﻤﻨﻴﺑ ،ﺎﻬﺑ ﺔﺻﺎﺨﻟﺍ ﺕﻼﻣﺎﻌﻤﻟﺍ ﻝﺎﻤﺘﻛﺍ ﺩﺮﺠﻤﺑ ﺔﺣﺎﺘﻣ ﺔﻠﻔﻘﻤﻟﺍ ﺓﺪﺻﺭﻷﺍ ﺢﺒﺼﺘﺳ .ﻚﺑ ﺔﺻﺎﺨﻟﺍ ﺕﻼﻤﻌﻟﺍ ﻲﻓ ﻢﻜﺤﺘﻟﺍ ﺕﺍﺩﺍﺪﻋﺇ ﻲﻓ ﻂﺸﻧ ﻞﻜﺸﺑ ﺎﻫﺪﻴﻤﺠﺘﺑ ﺖﻤﻗ",
|
||||
"unspent_change": "يتغير",
|
||||
"tor_connection": "ﺭﻮﺗ ﻝﺎﺼﺗﺍ"
|
||||
}
|
||||
|
|
|
@ -588,7 +588,6 @@
|
|||
"error_dialog_content": "Получихме грешка.\n\nМоля, изпратете доклада до нашия отдел поддръжка, за да подобрим приложението.",
|
||||
"decimal_places_error": "Твърде много знаци след десетичната запетая",
|
||||
"edit_node": "Редактиране на възел",
|
||||
"frozen_balance": "Замразен баланс",
|
||||
"invoice_details": "IДанни за фактура",
|
||||
"donation_link_details": "Подробности за връзката за дарение",
|
||||
"anonpay_description": "Генерирайте ${type}. Получателят може да ${method} с всяка поддържана криптовалута и вие ще получите средства в този портфейл.",
|
||||
|
@ -720,6 +719,7 @@
|
|||
"enterWalletConnectURI": "Въведете URI на WalletConnect",
|
||||
"seed_key": "Ключ за семена",
|
||||
"enter_seed_phrase": "Въведете вашата фраза за семена",
|
||||
"change_rep_successful": "Успешно промени представител",
|
||||
"add_contact": "Добави контакт",
|
||||
"exchange_provider_unsupported": "${providerName} вече не се поддържа!",
|
||||
"domain_looks_up": "Търсене на домейни",
|
||||
|
@ -728,5 +728,16 @@
|
|||
"switchToETHWallet": "Моля, преминете към портфейл Ethereum и опитайте отново",
|
||||
"moonpay_exchange_description": "Безпроблемна размяна на криптовалута.",
|
||||
"kyc_required": "Изисква се акаунт и KYC",
|
||||
"unspent_change": "Промяна"
|
||||
"importNFTs": "Импортирайте NFT",
|
||||
"noNFTYet": "Все още няма NFT",
|
||||
"address": "Адрес",
|
||||
"enterTokenID": "Въведете идентификатора на токена",
|
||||
"tokenID": "документ за самоличност",
|
||||
"name": "Име",
|
||||
"symbol": "Символ",
|
||||
"seed_phrase_length": "Дължина на началната фраза",
|
||||
"unavailable_balance": "Неналично салдо",
|
||||
"unavailable_balance_description": "Неналично салдо: Тази обща сума включва средства, които са заключени в чакащи транзакции и тези, които сте замразили активно в настройките за контрол на монетите. Заключените баланси ще станат достъпни, след като съответните им транзакции бъдат завършени, докато замразените баланси остават недостъпни за транзакции, докато не решите да ги размразите.",
|
||||
"unspent_change": "Промяна",
|
||||
"tor_connection": "Tor връзка"
|
||||
}
|
||||
|
|
|
@ -383,7 +383,7 @@
|
|||
"change_backup_password_alert": "Vaše předchozí soubory se zálohami nebude možné naimportovat s novým heslem. Nové heslo bude použito pouze pro nové zálohy. Opravdu chcete změnit heslo pro zálohy?",
|
||||
"enter_backup_password": "Zde zadejte své heslo pro zálohy",
|
||||
"select_backup_file": "Vybrat soubor se zálohou",
|
||||
"import": "Importovat",
|
||||
"import": "Import",
|
||||
"please_select_backup_file": "Prosím vyberte soubor se zálohou a zadejte heslo pro zálohy.",
|
||||
"fixed_rate": "Pevný kurz",
|
||||
"fixed_rate_alert": "Když je zvolený pevný kurz, můžete zadat konkrétní částku, kterou chcete dostat. Chcete se přepnout do režimu s pevným kurzem?",
|
||||
|
@ -588,7 +588,6 @@
|
|||
"error_dialog_content": "Nastala chyba.\n\nProsím odešlete zprávu o chybě naší podpoře, aby mohli zajistit opravu.",
|
||||
"decimal_places_error": "Příliš mnoho desetinných míst",
|
||||
"edit_node": "Upravit uzel",
|
||||
"frozen_balance": "Zmrazená bilance",
|
||||
"invoice_details": "detaily faktury",
|
||||
"donation_link_details": "Podrobnosti odkazu na darování",
|
||||
"anonpay_description": "Vygenerujte ${type}. Příjemce může ${method} s jakoukoli podporovanou kryptoměnou a vy obdržíte prostředky v této peněžence.",
|
||||
|
@ -720,6 +719,7 @@
|
|||
"enterWalletConnectURI": "Zadejte identifikátor URI WalletConnect",
|
||||
"seed_key": "Klíč semen",
|
||||
"enter_seed_phrase": "Zadejte svou frázi semen",
|
||||
"change_rep_successful": "Úspěšně změnil zástupce",
|
||||
"add_contact": "Přidat kontakt",
|
||||
"exchange_provider_unsupported": "${providerName} již není podporováno!",
|
||||
"domain_looks_up": "Vyhledávání domén",
|
||||
|
@ -728,5 +728,16 @@
|
|||
"switchToETHWallet": "Přejděte na peněženku Ethereum a zkuste to znovu",
|
||||
"moonpay_exchange_description": "Bezproblémové výměny kryptoměny.",
|
||||
"kyc_required": "Účet a KYC vyžadoval",
|
||||
"unspent_change": "Změna"
|
||||
"importNFTs": "Importujte NFT",
|
||||
"noNFTYet": "Zatím žádné NFT",
|
||||
"address": "Adresa",
|
||||
"enterTokenID": "Zadejte ID tokenu",
|
||||
"tokenID": "ID",
|
||||
"name": "název",
|
||||
"symbol": "Symbol",
|
||||
"seed_phrase_length": "Délka fráze semene",
|
||||
"unavailable_balance": "Nedostupný zůstatek",
|
||||
"unavailable_balance_description": "Nedostupný zůstatek: Tento součet zahrnuje prostředky, které jsou uzamčeny v nevyřízených transakcích a ty, které jste aktivně zmrazili v nastavení kontroly mincí. Uzamčené zůstatky budou k dispozici po dokončení příslušných transakcí, zatímco zmrazené zůstatky zůstanou pro transakce nepřístupné, dokud se nerozhodnete je uvolnit.",
|
||||
"unspent_change": "Změna",
|
||||
"tor_connection": "Připojení Tor"
|
||||
}
|
||||
|
|
|
@ -595,7 +595,6 @@
|
|||
"sweeping_wallet_alert": "Das sollte nicht lange dauern. VERLASSEN SIE DIESEN BILDSCHIRM NICHT, ANDERNFALLS KÖNNEN DIE GELDER VERLOREN GEHEN",
|
||||
"decimal_places_error": "Zu viele Nachkommastellen",
|
||||
"edit_node": "Knoten bearbeiten",
|
||||
"frozen_balance": "Gefrorenes Guthaben",
|
||||
"invoice_details": "Rechnungs-Details",
|
||||
"donation_link_details": "Details zum Spendenlink",
|
||||
"anonpay_description": "Generieren Sie ${type}. Der Empfänger kann ${method} mit jeder unterstützten Kryptowährung verwenden, und Sie erhalten Geld in dieser Wallet.",
|
||||
|
@ -726,8 +725,9 @@
|
|||
"default_exchange_provider": "Standard -Austauschanbieter",
|
||||
"copyWalletConnectLink": "Kopieren Sie den WalletConnect-Link von dApp und fügen Sie ihn hier ein",
|
||||
"enterWalletConnectURI": "Geben Sie den WalletConnect-URI ein",
|
||||
"seed_key": "Seed-Schlüssel",
|
||||
"enter_seed_phrase": "Geben Sie Ihre Seed-Phrase ein",
|
||||
"seed_key": "Samenschlüssel",
|
||||
"enter_seed_phrase": "Geben Sie Ihre Samenphrase ein",
|
||||
"change_rep_successful": "Erfolgreich veränderte Vertreter",
|
||||
"add_contact": "Kontakt hinzufügen",
|
||||
"exchange_provider_unsupported": "${providerName} wird nicht mehr unterstützt!",
|
||||
"domain_looks_up": "Domain-Suchen",
|
||||
|
@ -736,5 +736,16 @@
|
|||
"switchToETHWallet": "Bitte wechseln Sie zu einem Ethereum-Wallet und versuchen Sie es erneut",
|
||||
"moonpay_exchange_description": "Nahtloser Kryptowährungstausch.",
|
||||
"kyc_required": "Konto und KYC erforderlich",
|
||||
"unspent_change": "Wechselgeld"
|
||||
"importNFTs": "NFTs importieren",
|
||||
"noNFTYet": "Noch keine NFTs",
|
||||
"address": "Adresse",
|
||||
"enterTokenID": "Geben Sie die Token-ID ein",
|
||||
"tokenID": "AUSWEIS",
|
||||
"name": "Name",
|
||||
"symbol": "Symbol",
|
||||
"seed_phrase_length": "Länge der Seed-Phrase",
|
||||
"unavailable_balance": "Nicht verfügbares Guthaben",
|
||||
"unavailable_balance_description": "Nicht verfügbares Guthaben: Diese Summe umfasst Gelder, die in ausstehenden Transaktionen gesperrt sind, und solche, die Sie in Ihren Münzkontrolleinstellungen aktiv eingefroren haben. Gesperrte Guthaben werden verfügbar, sobald die entsprechenden Transaktionen abgeschlossen sind, während eingefrorene Guthaben für Transaktionen nicht zugänglich bleiben, bis Sie sich dazu entschließen, sie wieder freizugeben.",
|
||||
"unspent_change": "Wechselgeld",
|
||||
"tor_connection": "Tor-Verbindung"
|
||||
}
|
||||
|
|
|
@ -606,7 +606,6 @@
|
|||
"onion_link": "Onion link",
|
||||
"decimal_places_error": "Too many decimal places",
|
||||
"edit_node": "Edit Node",
|
||||
"frozen_balance": "Frozen Balance",
|
||||
"settings": "Settings",
|
||||
"sell_monero_com_alert_content": "Selling Monero is not supported yet",
|
||||
"error_text_input_below_minimum_limit": "Amount is less than the minimum",
|
||||
|
@ -729,6 +728,7 @@
|
|||
"enterWalletConnectURI": "Enter WalletConnect URI",
|
||||
"seed_key": "Seed key",
|
||||
"enter_seed_phrase": "Enter your seed phrase",
|
||||
"change_rep_successful": "Successfully changed representative",
|
||||
"add_contact": "Add contact",
|
||||
"exchange_provider_unsupported": "${providerName} is no longer supported!",
|
||||
"domain_looks_up": "Domain lookups",
|
||||
|
@ -737,5 +737,16 @@
|
|||
"switchToETHWallet": "Please switch to an Ethereum wallet and try again",
|
||||
"moonpay_exchange_description": "Seamless cryptocurrency swapping.",
|
||||
"kyc_required": "Account and KYC required",
|
||||
"unspent_change": "Change"
|
||||
"importNFTs": "Import NFTs",
|
||||
"noNFTYet": "No NFTs yet",
|
||||
"address": "Address",
|
||||
"enterTokenID": "Enter the token ID",
|
||||
"tokenID": "ID",
|
||||
"name": "Name",
|
||||
"symbol": "Symbol",
|
||||
"seed_phrase_length": "Seed phrase length",
|
||||
"unavailable_balance": "Unavailable balance",
|
||||
"unavailable_balance_description": "Unavailable Balance: This total includes funds that are locked in pending transactions and those you have actively frozen in your coin control settings. Locked balances will become available once their respective transactions are completed, while frozen balances remain inaccessible for transactions until you decide to unfreeze them.",
|
||||
"unspent_change": "Change",
|
||||
"tor_connection": "Tor connection"
|
||||
}
|
||||
|
|
|
@ -595,7 +595,6 @@
|
|||
"sweeping_wallet_alert": "Esto no debería llevar mucho tiempo. NO DEJES ESTA PANTALLA O SE PUEDEN PERDER LOS FONDOS BARRIDOS",
|
||||
"decimal_places_error": "Demasiados lugares decimales",
|
||||
"edit_node": "Editar nodo",
|
||||
"frozen_balance": "Balance congelado",
|
||||
"invoice_details": "Detalles de la factura",
|
||||
"donation_link_details": "Detalles del enlace de donación",
|
||||
"anonpay_description": "Genera ${type}. El destinatario puede ${method} con cualquier criptomoneda admitida, y recibirá fondos en esta billetera.",
|
||||
|
@ -728,6 +727,7 @@
|
|||
"enterWalletConnectURI": "Ingrese el URI de WalletConnect",
|
||||
"seed_key": "Llave de semilla",
|
||||
"enter_seed_phrase": "Ingrese su frase de semillas",
|
||||
"change_rep_successful": "Representante cambiado con éxito",
|
||||
"add_contact": "Agregar contacto",
|
||||
"exchange_provider_unsupported": "¡${providerName} ya no es compatible!",
|
||||
"domain_looks_up": "Búsquedas de dominio",
|
||||
|
@ -736,5 +736,16 @@
|
|||
"switchToETHWallet": "Cambie a una billetera Ethereum e inténtelo nuevamente.",
|
||||
"moonpay_exchange_description": "Cambio de criptomonedas sin costuras.",
|
||||
"kyc_required": "Cuenta y KYC requerido",
|
||||
"unspent_change": "Cambiar"
|
||||
"importNFTs": "Importar NFT",
|
||||
"noNFTYet": "Aún no hay NFT",
|
||||
"address": "DIRECCIÓN",
|
||||
"enterTokenID": "Ingrese el ID del token",
|
||||
"tokenID": "IDENTIFICACIÓN",
|
||||
"name": "Nombre",
|
||||
"symbol": "Símbolo",
|
||||
"seed_phrase_length": "Longitud de la frase inicial",
|
||||
"unavailable_balance": "Saldo no disponible",
|
||||
"unavailable_balance_description": "Saldo no disponible: este total incluye fondos que están bloqueados en transacciones pendientes y aquellos que usted ha congelado activamente en su configuración de control de monedas. Los saldos bloqueados estarán disponibles una vez que se completen sus respectivas transacciones, mientras que los saldos congelados permanecerán inaccesibles para las transacciones hasta que usted decida descongelarlos.",
|
||||
"unspent_change": "Cambiar",
|
||||
"tor_connection": "conexión tor"
|
||||
}
|
||||
|
|
|
@ -595,7 +595,6 @@
|
|||
"sweeping_wallet_alert": "Cette opération ne devrait pas prendre longtemps. NE QUITTEZ PAS CET ÉCRAN OU LES FONDS CONSOLIDÉS POURRAIENT ÊTRE PERDUS",
|
||||
"decimal_places_error": "Trop de décimales",
|
||||
"edit_node": "Modifier le nœud",
|
||||
"frozen_balance": "Solde gelé",
|
||||
"invoice_details": "Détails de la facture",
|
||||
"donation_link_details": "Détails du lien de don",
|
||||
"anonpay_description": "Générez ${type}. Le destinataire peut ${method} avec n'importe quelle crypto-monnaie prise en charge, et vous recevrez des fonds dans ce portefeuille (wallet).",
|
||||
|
@ -728,13 +727,25 @@
|
|||
"enterWalletConnectURI": "Saisissez l'URI de WalletConnect.",
|
||||
"seed_key": "Clé secrète (seed key)",
|
||||
"enter_seed_phrase": "Entrez votre phrase secrète (seed)",
|
||||
"change_rep_successful": "Représentant changé avec succès",
|
||||
"add_contact": "Ajouter le contact",
|
||||
"exchange_provider_unsupported": "${providerName} n'est plus pris en charge !",
|
||||
"domain_looks_up": "Résolution de nom",
|
||||
"require_for_exchanges_to_external_wallets": "Exiger pour les échanges vers des portefeuilles externes",
|
||||
"moonpay_exchange_description": "Échange de crypto-monnaie sans couture.",
|
||||
"kyc_required": "Compte et KYC requis",
|
||||
"importNFTs": "Importer des NFT",
|
||||
"noNFTYet": "Pas encore de NFT",
|
||||
"address": "Adresse",
|
||||
"enterTokenID": "Entrez l'ID du jeton",
|
||||
"tokenID": "IDENTIFIANT",
|
||||
"name": "Nom",
|
||||
"symbol": "Symbole",
|
||||
"seed_phrase_length": "Longueur de la phrase de départ",
|
||||
"unavailable_balance": "Solde indisponible",
|
||||
"unavailable_balance_description": "Solde indisponible : ce total comprend les fonds bloqués dans les transactions en attente et ceux que vous avez activement gelés dans vos paramètres de contrôle des pièces. Les soldes bloqués deviendront disponibles une fois leurs transactions respectives terminées, tandis que les soldes gelés resteront inaccessibles aux transactions jusqu'à ce que vous décidiez de les débloquer.",
|
||||
"camera_permission_is_required": "L'autorisation d'accès à la caméra est requise.\nVeuillez l'activer depuis les paramètres de l'application.",
|
||||
"switchToETHWallet": "Veuillez passer à un portefeuille (wallet) Ethereum et réessayer",
|
||||
"unspent_change": "Changement"
|
||||
"unspent_change": "Changement",
|
||||
"tor_connection": "Connexion Tor"
|
||||
}
|
||||
|
|
|
@ -602,7 +602,6 @@
|
|||
"onion_link": "Lambar onion",
|
||||
"decimal_places_error": "Wadannan suna da tsawon harsuna",
|
||||
"edit_node": "Shirya Node",
|
||||
"frozen_balance": "Falin kuma maɓallin",
|
||||
"settings": "Saiti",
|
||||
"sell_monero_com_alert_content": "Selling Monero bai sami ƙarshen mai bukatar samun ba",
|
||||
"error_text_input_below_minimum_limit": "Kudin ba a kamai",
|
||||
|
@ -706,6 +705,7 @@
|
|||
"enterWalletConnectURI": "Shigar da WalletConnect URI",
|
||||
"seed_key": "Maɓallin iri",
|
||||
"enter_seed_phrase": "Shigar da Sert Sentarku",
|
||||
"change_rep_successful": "An samu nasarar canzawa wakilin",
|
||||
"add_contact": "Ƙara lamba",
|
||||
"exchange_provider_unsupported": "${providerName}",
|
||||
"domain_looks_up": "Binciken yanki",
|
||||
|
@ -714,5 +714,16 @@
|
|||
"switchToETHWallet": "Da fatan za a canza zuwa walat ɗin Ethereum kuma a sake gwadawa",
|
||||
"moonpay_exchange_description": "Sumba crypptocurrency.",
|
||||
"kyc_required": "Asusun da KyKC da ake buƙata",
|
||||
"unspent_change": "Canza"
|
||||
"importNFTs": "Shigo da NFTs",
|
||||
"noNFTYet": "Babu NFTs tukuna",
|
||||
"address": "Adireshi",
|
||||
"enterTokenID": "Shigar da alamar alama",
|
||||
"tokenID": "ID",
|
||||
"name": "Suna",
|
||||
"symbol": "Alama",
|
||||
"seed_phrase_length": "Tsawon jimlar iri",
|
||||
"unavailable_balance": "Ma'aunin da ba ya samuwa",
|
||||
"unavailable_balance_description": "Ma'auni Babu: Wannan jimlar ya haɗa da kuɗi waɗanda ke kulle a cikin ma'amaloli da ke jiran aiki da waɗanda kuka daskare sosai a cikin saitunan sarrafa kuɗin ku. Ma'auni da aka kulle za su kasance da zarar an kammala ma'amalolinsu, yayin da daskararrun ma'auni ba za su iya samun damar yin ciniki ba har sai kun yanke shawarar cire su.",
|
||||
"unspent_change": "Canza",
|
||||
"tor_connection": "Tor haɗin gwiwa"
|
||||
}
|
||||
|
|
|
@ -595,7 +595,6 @@
|
|||
"sweeping_wallet_alert": "इसमें अधिक समय नहीं लगना चाहिए। इस स्क्रीन को न छोड़ें या स्वैप्ट फंड खो सकते हैं",
|
||||
"decimal_places_error": "बहुत अधिक दशमलव स्थान",
|
||||
"edit_node": "नोड संपादित करें",
|
||||
"frozen_balance": "जमे हुए संतुलन",
|
||||
"invoice_details": "चालान विवरण",
|
||||
"donation_link_details": "दान लिंक विवरण",
|
||||
"anonpay_description": "${type} उत्पन्न करें। प्राप्तकर्ता किसी भी समर्थित क्रिप्टोकरेंसी के साथ ${method} कर सकता है, और आपको इस वॉलेट में धन प्राप्त होगा।",
|
||||
|
@ -728,6 +727,7 @@
|
|||
"enterWalletConnectURI": "वॉलेटकनेक्ट यूआरआई दर्ज करें",
|
||||
"seed_key": "बीज कुंजी",
|
||||
"enter_seed_phrase": "अपना बीज वाक्यांश दर्ज करें",
|
||||
"change_rep_successful": "सफलतापूर्वक बदलकर प्रतिनिधि",
|
||||
"add_contact": "संपर्क जोड़ें",
|
||||
"exchange_provider_unsupported": "${providerName} अब समर्थित नहीं है!",
|
||||
"domain_looks_up": "डोमेन लुकअप",
|
||||
|
@ -736,5 +736,16 @@
|
|||
"switchToETHWallet": "कृपया एथेरियम वॉलेट पर स्विच करें और पुनः प्रयास करें",
|
||||
"moonpay_exchange_description": "सीमलेस क्रिप्टोक्यूरेंसी स्वैपिंग।",
|
||||
"kyc_required": "खाता और KYC की आवश्यकता है",
|
||||
"unspent_change": "परिवर्तन"
|
||||
"importNFTs": "एनएफटी आयात करें",
|
||||
"noNFTYet": "अभी तक कोई एनएफटी नहीं",
|
||||
"address": "पता",
|
||||
"enterTokenID": "टोकन आईडी दर्ज करें",
|
||||
"tokenID": "पहचान",
|
||||
"name": "नाम",
|
||||
"symbol": "प्रतीक",
|
||||
"seed_phrase_length": "बीज वाक्यांश की लंबाई",
|
||||
"unavailable_balance": "अनुपलब्ध शेष",
|
||||
"unavailable_balance_description": "अनुपलब्ध शेष राशि: इस कुल में वे धनराशि शामिल हैं जो लंबित लेनदेन में बंद हैं और जिन्हें आपने अपनी सिक्का नियंत्रण सेटिंग्स में सक्रिय रूप से जमा कर रखा है। लॉक किए गए शेष उनके संबंधित लेन-देन पूरे होने के बाद उपलब्ध हो जाएंगे, जबकि जमे हुए शेष लेन-देन के लिए अप्राप्य रहेंगे जब तक कि आप उन्हें अनफ्रीज करने का निर्णय नहीं लेते।",
|
||||
"unspent_change": "परिवर्तन",
|
||||
"tor_connection": "टोर कनेक्शन"
|
||||
}
|
||||
|
|
|
@ -383,7 +383,7 @@
|
|||
"change_backup_password_alert": "Nećemo moći uvesti Vaše prethodne datoteke sigurnosne kopije s novom lozinkom za sigurnosnu kopiju. Novu lozinku za sigurnosnu kopiju moći ćete koristiti samo za nove datoteke sigurnosne kopije. Jeste li sigurni da želite promijeniti lozinku za sigurnosnu kopiju?",
|
||||
"enter_backup_password": "Unesite svoju lozinku za sigurnosnu kopiju ovdje",
|
||||
"select_backup_file": "Odaberite datoteku sigurnosne kopije",
|
||||
"import": "Uvezi",
|
||||
"import": "Uvoz",
|
||||
"please_select_backup_file": "Molimo odaberite datoteku sigurnosne kopije i unesite lozinku za sigurnosnu kopiju.",
|
||||
"fixed_rate": "Fiksna stopa",
|
||||
"fixed_rate_alert": "Moći ćete unijeti iznos koji želite primiti nakon što označite način rada fiksne stope. Želite li se prebaciti na način rada fiksne stope?",
|
||||
|
@ -595,7 +595,6 @@
|
|||
"sweeping_wallet_alert": "Ovo ne bi trebalo dugo trajati. NE NAPUŠTAJTE OVAJ ZASLON INAČE SE POBREŠENA SREDSTVA MOGU IZGUBITI",
|
||||
"decimal_places_error": "Previše decimalnih mjesta",
|
||||
"edit_node": "Uredi čvor",
|
||||
"frozen_balance": "Zamrznuti saldo",
|
||||
"invoice_details": "Podaci o fakturi",
|
||||
"donation_link_details": "Detalji veza za donacije",
|
||||
"anonpay_description": "Generiraj ${type}. Primatelj može ${method} s bilo kojom podržanom kriptovalutom, a vi ćete primiti sredstva u ovaj novčanik.",
|
||||
|
@ -726,6 +725,7 @@
|
|||
"enterWalletConnectURI": "Unesite WalletConnect URI",
|
||||
"seed_key": "Sjemenski ključ",
|
||||
"enter_seed_phrase": "Unesite svoju sjemensku frazu",
|
||||
"change_rep_successful": "Uspješno promijenjena reprezentativna",
|
||||
"add_contact": "Dodaj kontakt",
|
||||
"exchange_provider_unsupported": "${providerName} više nije podržan!",
|
||||
"domain_looks_up": "Pretraga domena",
|
||||
|
@ -734,5 +734,16 @@
|
|||
"switchToETHWallet": "Prijeđite na Ethereum novčanik i pokušajte ponovno",
|
||||
"moonpay_exchange_description": "Bešavna zamjena kriptovaluta.",
|
||||
"kyc_required": "Potrebni su račun i KYC",
|
||||
"unspent_change": "Promijeniti"
|
||||
"importNFTs": "Uvoz NFT-ova",
|
||||
"noNFTYet": "Još nema NFT-ova",
|
||||
"address": "Adresa",
|
||||
"enterTokenID": "Unesite ID tokena",
|
||||
"tokenID": "iskaznica",
|
||||
"name": "Ime",
|
||||
"symbol": "Simbol",
|
||||
"seed_phrase_length": "Duljina početne fraze",
|
||||
"unavailable_balance": "Nedostupno stanje",
|
||||
"unavailable_balance_description": "Nedostupno stanje: Ovaj ukupni iznos uključuje sredstva koja su zaključana u transakcijama na čekanju i ona koja ste aktivno zamrznuli u postavkama kontrole novčića. Zaključani saldi postat će dostupni kada se dovrše njihove transakcije, dok zamrznuti saldi ostaju nedostupni za transakcije sve dok ih ne odlučite odmrznuti.",
|
||||
"unspent_change": "Promijeniti",
|
||||
"tor_connection": "Tor veza"
|
||||
}
|
||||
|
|
|
@ -584,7 +584,6 @@
|
|||
"contact_list_wallets": "Dompet Saya",
|
||||
"decimal_places_error": "Terlalu banyak tempat desimal",
|
||||
"edit_node": "Sunting Node",
|
||||
"frozen_balance": "Saldo Beku",
|
||||
"invoice_details": "Detail faktur",
|
||||
"donation_link_details": "Detail tautan donasi",
|
||||
"anonpay_description": "Hasilkan ${type}. Penerima dapat ${method} dengan cryptocurrency apa pun yang didukung, dan Anda akan menerima dana di dompet ini.",
|
||||
|
@ -716,6 +715,7 @@
|
|||
"enterWalletConnectURI": "Masukkan URI WalletConnect",
|
||||
"seed_key": "Kunci benih",
|
||||
"enter_seed_phrase": "Masukkan frasa benih Anda",
|
||||
"change_rep_successful": "Berhasil mengubah perwakilan",
|
||||
"add_contact": "Tambah kontak",
|
||||
"exchange_provider_unsupported": "${providerName} tidak lagi didukung!",
|
||||
"domain_looks_up": "Pencarian domain",
|
||||
|
@ -724,5 +724,16 @@
|
|||
"switchToETHWallet": "Silakan beralih ke dompet Ethereum dan coba lagi",
|
||||
"moonpay_exchange_description": "Pertukaran cryptocurrency yang mulus.",
|
||||
"kyc_required": "Akun dan KYC diperlukan",
|
||||
"unspent_change": "Mengubah"
|
||||
"importNFTs": "Impor NFT",
|
||||
"noNFTYet": "Belum ada NFT",
|
||||
"address": "Alamat",
|
||||
"enterTokenID": "Masukkan ID tokennya",
|
||||
"tokenID": "PENGENAL",
|
||||
"name": "Nama",
|
||||
"symbol": "Simbol",
|
||||
"seed_phrase_length": "Panjang frase benih",
|
||||
"unavailable_balance": "Saldo tidak tersedia",
|
||||
"unavailable_balance_description": "Saldo Tidak Tersedia: Total ini termasuk dana yang terkunci dalam transaksi yang tertunda dan dana yang telah Anda bekukan secara aktif di pengaturan kontrol koin Anda. Saldo yang terkunci akan tersedia setelah transaksi masing-masing selesai, sedangkan saldo yang dibekukan tetap tidak dapat diakses untuk transaksi sampai Anda memutuskan untuk mencairkannya.",
|
||||
"unspent_change": "Mengubah",
|
||||
"tor_connection": "koneksi Tor"
|
||||
}
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue