mirror of
https://github.com/cake-tech/cake_wallet.git
synced 2025-03-21 14:48:53 +00:00
Merge branch 'main' into warning-wording
This commit is contained in:
commit
1fc4f809e5
93 changed files with 1898 additions and 1176 deletions
.github/workflows
android/app
assets
cw_bitcoin/lib
cw_core/lib
cw_haven
cw_monero
howto-build-android.mdlib
core
di.dartentities
default_settings_migration.dartparse_address_from_domain.dartpreferences_key.dartpriority_for_wallet_type.dart
exchange
main.dartreactions
router.dartroutes.dartsrc
screens
contact
dashboard
exchange/widgets
ionia
new_wallet
nodes
receive/widgets
send
settings
widgets
store
view_model
res/values
strings_de.arbstrings_en.arbstrings_es.arbstrings_fr.arbstrings_hi.arbstrings_hr.arbstrings_it.arbstrings_ja.arbstrings_ko.arbstrings_nl.arbstrings_pl.arbstrings_pt.arbstrings_ru.arbstrings_uk.arbstrings_zh.arb
scripts
tool/utils
129
.github/workflows/pr_test_build.yml
vendored
Normal file
129
.github/workflows/pr_test_build.yml
vendored
Normal file
|
@ -0,0 +1,129 @@
|
|||
name: PR Test Build
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches: [ main ]
|
||||
|
||||
jobs:
|
||||
test:
|
||||
|
||||
runs-on: ubuntu-18.04
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-java@v1
|
||||
with:
|
||||
java-version: '8.x'
|
||||
|
||||
- name: Flutter action
|
||||
uses: subosito/flutter-action@v1
|
||||
with:
|
||||
flutter-version: '3.3.x'
|
||||
channel: stable
|
||||
|
||||
- name: Install package dependencies
|
||||
run: sudo apt-get install -y curl unzip automake build-essential file pkg-config git python libtool libtinfo5 cmake clang
|
||||
|
||||
- name: Execute Build and Setup Commands
|
||||
run: |
|
||||
sudo mkdir -p /opt/android
|
||||
sudo chown $USER /opt/android
|
||||
cd /opt/android
|
||||
git clone https://github.com/cake-tech/cake_wallet.git --branch $GITHUB_HEAD_REF
|
||||
cd cake_wallet/scripts/android/
|
||||
./install_ndk.sh
|
||||
source ./app_env.sh cakewallet
|
||||
./app_config.sh
|
||||
./build_all.sh
|
||||
./copy_monero_deps.sh
|
||||
|
||||
- name: Install Flutter dependencies
|
||||
run: |
|
||||
cd /opt/android/cake_wallet
|
||||
flutter pub get
|
||||
|
||||
- name: Generate KeyStore
|
||||
run: |
|
||||
cd /opt/android/cake_wallet/android/app
|
||||
keytool -genkey -v -keystore key.jks -keyalg RSA -keysize 2048 -validity 10000 -alias testKey -noprompt -dname "CN=CakeWallet, OU=CakeWallet, O=CakeWallet, L=Florida, S=America, C=USA" -storepass ${{ secrets.STORE_PASS }} -keypass ${{ secrets.KEY_PASS }}
|
||||
|
||||
- name: Generate key properties
|
||||
run: |
|
||||
cd /opt/android/cake_wallet
|
||||
flutter packages pub run tool/generate_android_key_properties.dart keyAlias=testKey storeFile=key.jks storePassword=${{ secrets.STORE_PASS }} keyPassword=${{ secrets.KEY_PASS }}
|
||||
|
||||
- name: Generate localization
|
||||
run: |
|
||||
cd /opt/android/cake_wallet
|
||||
flutter packages pub run tool/generate_localization.dart
|
||||
|
||||
- name: Build generated code
|
||||
run: |
|
||||
cd /opt/android/cake_wallet
|
||||
cd cw_core && flutter pub get && flutter packages pub run build_runner build --delete-conflicting-outputs && cd ..
|
||||
cd cw_monero && flutter pub get && flutter packages pub run build_runner build --delete-conflicting-outputs && cd ..
|
||||
cd cw_bitcoin && flutter pub get && flutter packages pub run build_runner build --delete-conflicting-outputs && cd ..
|
||||
cd cw_haven && flutter pub get && flutter packages pub run build_runner build --delete-conflicting-outputs && cd ..
|
||||
flutter packages pub run build_runner build --delete-conflicting-outputs
|
||||
|
||||
- name: Add secrets
|
||||
run: |
|
||||
cd /opt/android/cake_wallet
|
||||
touch lib/.secrets.g.dart
|
||||
echo "const salt = '${{ secrets.SALT }}';" > lib/.secrets.g.dart
|
||||
echo "const keychainSalt = '${{ secrets.KEY_CHAIN_SALT }}';" >> lib/.secrets.g.dart
|
||||
echo "const key = '${{ secrets.KEY }}';" >> lib/.secrets.g.dart
|
||||
echo "const walletSalt = '${{ secrets.WALLET_SALT }}';" >> lib/.secrets.g.dart
|
||||
echo "const shortKey = '${{ secrets.SHORT_KEY }}';" >> lib/.secrets.g.dart
|
||||
echo "const backupSalt = '${{ secrets.BACKUP_SALT }}';" >> lib/.secrets.g.dart
|
||||
echo "const backupKeychainSalt = '${{ secrets.BACKUP_KEY_CHAIN_SALT }}';" >> lib/.secrets.g.dart
|
||||
echo "const changeNowApiKey = '${{ secrets.CHANGE_NOW_API_KEY }}';" >> lib/.secrets.g.dart
|
||||
echo "const wyreSecretKey = '${{ secrets.WYRE_SECRET_KEY }}';" >> lib/.secrets.g.dart
|
||||
echo "const wyreApiKey = '${{ secrets.WYRE_API_KEY }}';" >> lib/.secrets.g.dart
|
||||
echo "const wyreAccountId = '${{ secrets.WYRE_ACCOUNT_ID }}';" >> lib/.secrets.g.dart
|
||||
echo "const moonPayApiKey = '${{ secrets.MOON_PAY_API_KEY }}';" >> lib/.secrets.g.dart
|
||||
echo "const moonPaySecretKey = '${{ secrets.MOON_PAY_SECRET_KEY }}';" >> lib/.secrets.g.dart
|
||||
echo "const sideShiftAffiliateId = '${{ secrets.SIDE_SHIFT_AFFILIATE_ID }}';" >> lib/.secrets.g.dart
|
||||
echo "const sideShiftApiKey = '${{ secrets.SIDE_SHIFT_API_KEY }}';" >> lib/.secrets.g.dart
|
||||
echo "const simpleSwapApiKey = '${{ secrets.SIMPLE_SWAP_API_KEY }}';" >> lib/.secrets.g.dart
|
||||
echo "const onramperApiKey = '${{ secrets.ONRAMPER_API_KEY }}';" >> lib/.secrets.g.dart
|
||||
echo "const anypayToken = '${{ secrets.ANY_PAY_TOKEN }}';" >> lib/.secrets.g.dart
|
||||
echo "const ioniaClientId = '${{ secrets.IONIA_CLIENT_ID }}';" >> lib/.secrets.g.dart
|
||||
|
||||
- name: Rename app
|
||||
run: sed -i -e "s/\${APP_NAME}/$GITHUB_HEAD_REF/g" /opt/android/cake_wallet/android/app/src/main/AndroidManifest.xml
|
||||
|
||||
- name: Build
|
||||
run: |
|
||||
cd /opt/android/cake_wallet
|
||||
flutter build apk --release
|
||||
|
||||
# - name: Push to App Center
|
||||
# run: |
|
||||
# echo 'Installing App Center CLI tools'
|
||||
# npm install -g appcenter-cli
|
||||
# echo "Publishing test to App Center"
|
||||
# appcenter distribute release \
|
||||
# --group "Testers" \
|
||||
# --file "/opt/android/cake_wallet/build/app/outputs/apk/release/app-release.apk" \
|
||||
# --release-notes ${GITHUB_HEAD_REF} \
|
||||
# --app Cake-Labs/Cake-Wallet \
|
||||
# --token ${{ secrets.APP_CENTER_TOKEN }} \
|
||||
# --quiet
|
||||
|
||||
- name: Send Test APK
|
||||
run: |
|
||||
cd /opt/android/cake_wallet
|
||||
var=$(curl --upload-file build/app/outputs/apk/release/app-release.apk https://transfer.sh/$GITHUB_HEAD_REF.apk -H "Max-Days: 10")
|
||||
curl ${{ secrets.SLACK_WEB_HOOK }} -H "Content-Type: application/json" -d '{"apk_link": "'"$var"'","ticket": "'"$GITHUB_HEAD_REF"'"}'
|
||||
|
||||
- name: Rename apk file
|
||||
run: |
|
||||
cd /opt/android/cake_wallet/build/app/outputs/apk/release
|
||||
mkdir test-apk
|
||||
mv app-release.apk test-apk/$GITHUB_HEAD_REF.apk
|
||||
|
||||
- name: Upload Artifact
|
||||
uses: kittaakos/upload-artifact-as-is@v0
|
||||
with:
|
||||
path: /opt/android/cake_wallet/build/app/outputs/apk/release/test-apk/
|
|
@ -46,7 +46,7 @@ android {
|
|||
defaultConfig {
|
||||
applicationId appProperties['id']
|
||||
minSdkVersion 21
|
||||
targetSdkVersion 30
|
||||
targetSdkVersion 31
|
||||
versionCode flutterVersionCode.toInteger()
|
||||
versionName flutterVersionName
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
|
|
|
@ -21,7 +21,8 @@
|
|||
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
|
||||
android:hardwareAccelerated="true"
|
||||
android:windowSoftInputMode="adjustResize"
|
||||
android:screenOrientation="portrait">
|
||||
android:screenOrientation="portrait"
|
||||
android:exported="true">
|
||||
<meta-data
|
||||
android:name="io.flutter.embedding.android.SplashScreenDrawable"
|
||||
android:resource="@drawable/launch_background"
|
||||
|
|
|
@ -1,31 +1,24 @@
|
|||
-
|
||||
uri: xmr-node-uk.cakewallet.com:18081
|
||||
uri: xmr-node.cakewallet.com:18081
|
||||
is_default: true
|
||||
-
|
||||
uri: xmr-node-eu.cakewallet.com:18081
|
||||
uri: cakexmrl7bonq7ovjka5kuwuyd3f7qnkz6z6s6dmsy3uckwra7bvggyd.onion:18081
|
||||
is_default: false
|
||||
-
|
||||
uri: xmr-node-usa-east.cakewallet.com:18081
|
||||
uri: node.sethforprivacy.com:18089
|
||||
is_default: false
|
||||
-
|
||||
uri: nodes.hashvault.pro:18081
|
||||
is_default: false
|
||||
-
|
||||
uri: node.c3pool.com:18081
|
||||
is_default: false
|
||||
-
|
||||
uri: node.supportxmr.com:18081
|
||||
is_default: false
|
||||
-
|
||||
uri: node.community.rino.io:18081
|
||||
is_default: false
|
||||
-
|
||||
uri: node.moneroworld.com:18089
|
||||
is_default: false
|
||||
-
|
||||
uri: node.xmr.pt:18081
|
||||
is_default: false
|
||||
-
|
||||
uri: node.monero.net:18081
|
||||
is_default: false
|
||||
-
|
||||
uri: opennode.xmr-tw.org:18089
|
||||
is_default: false
|
||||
-
|
||||
uri: node.imonero.org:18081
|
||||
is_default: false
|
||||
|
||||
uri: node.c3pool.com:18081
|
||||
is_default: false
|
||||
|
||||
uri: xmr.prprpr.icu:18081
|
||||
is_default: false
|
||||
|
||||
|
|
|
@ -129,7 +129,7 @@ abstract class ElectrumWalletBase extends WalletBase<ElectrumBalance,
|
|||
@override
|
||||
Future<void> startSync() async {
|
||||
try {
|
||||
syncStatus = StartingSyncStatus();
|
||||
syncStatus = AttemptingSyncStatus();
|
||||
await walletAddresses.discoverAddresses();
|
||||
await updateTransactions();
|
||||
_subscribeForUpdates();
|
||||
|
|
|
@ -17,6 +17,7 @@ class Node extends HiveObject with Keyable {
|
|||
{this.login,
|
||||
this.password,
|
||||
this.useSSL,
|
||||
this.trusted = false,
|
||||
String? uri,
|
||||
WalletType? type,}) {
|
||||
if (uri != null) {
|
||||
|
@ -31,7 +32,8 @@ class Node extends HiveObject with Keyable {
|
|||
: uriRaw = map['uri'] as String? ?? '',
|
||||
login = map['login'] as String?,
|
||||
password = map['password'] as String?,
|
||||
useSSL = map['useSSL'] as bool?;
|
||||
useSSL = map['useSSL'] as bool?,
|
||||
trusted = map['trusted'] as bool? ?? false;
|
||||
|
||||
static const typeId = 1;
|
||||
static const boxName = 'Nodes';
|
||||
|
@ -51,6 +53,9 @@ class Node extends HiveObject with Keyable {
|
|||
@HiveField(4)
|
||||
bool? useSSL;
|
||||
|
||||
@HiveField(5)
|
||||
bool trusted;
|
||||
|
||||
bool get isSSL => useSSL ?? false;
|
||||
|
||||
Uri get uri {
|
||||
|
@ -104,28 +109,28 @@ class Node extends HiveObject with Keyable {
|
|||
final rpcUri = isSSL ? Uri.https(uri.authority, path) : Uri.http(uri.authority, path);
|
||||
final realm = 'monero-rpc';
|
||||
final body = {
|
||||
'jsonrpc': '2.0',
|
||||
'id': '0',
|
||||
'jsonrpc': '2.0',
|
||||
'id': '0',
|
||||
'method': 'get_info'
|
||||
};
|
||||
|
||||
try {
|
||||
final authenticatingClient = HttpClient();
|
||||
|
||||
|
||||
authenticatingClient.addCredentials(
|
||||
rpcUri,
|
||||
realm,
|
||||
realm,
|
||||
HttpClientDigestCredentials(login ?? '', password ?? ''),
|
||||
);
|
||||
|
||||
|
||||
final http.Client client = ioc.IOClient(authenticatingClient);
|
||||
|
||||
|
||||
final response = await client.post(
|
||||
rpcUri,
|
||||
headers: {'Content-Type': 'application/json'},
|
||||
body: json.encode(body),
|
||||
);
|
||||
|
||||
|
||||
client.close();
|
||||
|
||||
final resBody = json.decode(response.body) as Map<String, dynamic>;
|
||||
|
|
|
@ -28,7 +28,7 @@ class NotConnectedSyncStatus extends SyncStatus {
|
|||
double progress() => 0.0;
|
||||
}
|
||||
|
||||
class StartingSyncStatus extends SyncStatus {
|
||||
class AttemptingSyncStatus extends SyncStatus {
|
||||
@override
|
||||
double progress() => 0.0;
|
||||
}
|
||||
|
|
|
@ -927,6 +927,16 @@ extern "C"
|
|||
return static_cast<int32_t>(rates.size());
|
||||
}
|
||||
|
||||
void set_trusted_daemon(bool arg)
|
||||
{
|
||||
m_wallet->setTrustedDaemon(arg);
|
||||
}
|
||||
|
||||
bool trusted_daemon()
|
||||
{
|
||||
return m_wallet->trustedDaemon();
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -137,4 +137,8 @@ typedef get_rate = Pointer<Int64> Function();
|
|||
|
||||
typedef size_of_rate = Int32 Function();
|
||||
|
||||
typedef update_rate = Void Function();
|
||||
typedef update_rate = Void Function();
|
||||
|
||||
typedef set_trusted_daemon = Void Function(Int8 trusted);
|
||||
|
||||
typedef trusted_daemon = Int8 Function();
|
|
@ -135,4 +135,8 @@ typedef GetRate = Pointer<Int64> Function();
|
|||
|
||||
typedef SizeOfRate = int Function();
|
||||
|
||||
typedef UpdateRate = void Function();
|
||||
typedef UpdateRate = void Function();
|
||||
|
||||
typedef SetTrustedDaemon = void Function(int);
|
||||
|
||||
typedef TrustedDaemon = int Function();
|
|
@ -116,6 +116,14 @@ final rescanBlockchainAsyncNative = havenApi
|
|||
.lookup<NativeFunction<rescan_blockchain>>('rescan_blockchain')
|
||||
.asFunction<RescanBlockchainAsync>();
|
||||
|
||||
final setTrustedDaemonNative = havenApi
|
||||
.lookup<NativeFunction<set_trusted_daemon>>('set_trusted_daemon')
|
||||
.asFunction<SetTrustedDaemon>();
|
||||
|
||||
final trustedDaemonNative = havenApi
|
||||
.lookup<NativeFunction<trusted_daemon>>('trusted_daemon')
|
||||
.asFunction<TrustedDaemon>();
|
||||
|
||||
int getSyncingHeight() => getSyncingHeightNative();
|
||||
|
||||
bool isNeededToRefresh() => isNeededToRefreshNative() != 0;
|
||||
|
@ -351,3 +359,7 @@ Future<bool> isConnected() => compute(_isConnected, 0);
|
|||
Future<int> getNodeHeight() => compute(_getNodeHeight, 0);
|
||||
|
||||
void rescanBlockchainAsync() => rescanBlockchainAsyncNative();
|
||||
|
||||
Future setTrustedDaemon(bool trusted) async => setTrustedDaemonNative(_boolToInt(trusted));
|
||||
|
||||
Future<bool> trustedDaemon() async => trustedDaemonNative() != 0;
|
||||
|
|
|
@ -121,6 +121,8 @@ abstract class HavenWalletBase extends WalletBase<MoneroBalance,
|
|||
password: node.password,
|
||||
useSSL: node.useSSL ?? false,
|
||||
isLightWallet: false); // FIXME: hardcoded value
|
||||
|
||||
haven_wallet.setTrustedDaemon(node.trusted);
|
||||
syncStatus = ConnectedSyncStatus();
|
||||
} catch (e) {
|
||||
syncStatus = FailedSyncStatus();
|
||||
|
@ -135,7 +137,7 @@ abstract class HavenWalletBase extends WalletBase<MoneroBalance,
|
|||
} catch (_) {}
|
||||
|
||||
try {
|
||||
syncStatus = StartingSyncStatus();
|
||||
syncStatus = AttemptingSyncStatus();
|
||||
haven_wallet.startRefresh();
|
||||
_setListeners();
|
||||
_listener?.start();
|
||||
|
|
|
@ -783,6 +783,16 @@ extern "C"
|
|||
return strdup(get_current_wallet()->getSubaddressLabel(accountIndex, addressIndex).c_str());
|
||||
}
|
||||
|
||||
void set_trusted_daemon(bool arg)
|
||||
{
|
||||
m_wallet->setTrustedDaemon(arg);
|
||||
}
|
||||
|
||||
bool trusted_daemon()
|
||||
{
|
||||
return m_wallet->trustedDaemon();
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -30,6 +30,9 @@ void set_refresh_from_block_height(uint64_t height);
|
|||
void set_recovering_from_seed(bool is_recovery);
|
||||
void store(char *path);
|
||||
|
||||
void set_trusted_daemon(bool arg);
|
||||
bool trusted_daemon();
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
|
@ -125,4 +125,8 @@ typedef rescan_blockchain = Void Function();
|
|||
|
||||
typedef get_subaddress_label = Pointer<Utf8> Function(
|
||||
Int32 accountIndex,
|
||||
Int32 addressIndex);
|
||||
Int32 addressIndex);
|
||||
|
||||
typedef set_trusted_daemon = Void Function(Int8 trusted);
|
||||
|
||||
typedef trusted_daemon = Int8 Function();
|
|
@ -123,4 +123,8 @@ typedef RescanBlockchainAsync = void Function();
|
|||
|
||||
typedef GetSubaddressLabel = Pointer<Utf8> Function(
|
||||
int accountIndex,
|
||||
int addressIndex);
|
||||
int addressIndex);
|
||||
|
||||
typedef SetTrustedDaemon = void Function(int);
|
||||
|
||||
typedef TrustedDaemon = int Function();
|
|
@ -120,6 +120,14 @@ final getSubaddressLabelNative = moneroApi
|
|||
.lookup<NativeFunction<get_subaddress_label>>('get_subaddress_label')
|
||||
.asFunction<GetSubaddressLabel>();
|
||||
|
||||
final setTrustedDaemonNative = moneroApi
|
||||
.lookup<NativeFunction<set_trusted_daemon>>('set_trusted_daemon')
|
||||
.asFunction<SetTrustedDaemon>();
|
||||
|
||||
final trustedDaemonNative = moneroApi
|
||||
.lookup<NativeFunction<trusted_daemon>>('trusted_daemon')
|
||||
.asFunction<TrustedDaemon>();
|
||||
|
||||
int getSyncingHeight() => getSyncingHeightNative();
|
||||
|
||||
bool isNeededToRefresh() => isNeededToRefreshNative() != 0;
|
||||
|
@ -359,4 +367,8 @@ void rescanBlockchainAsync() => rescanBlockchainAsyncNative();
|
|||
|
||||
String getSubaddressLabel(int accountIndex, int addressIndex) {
|
||||
return convertUTF8ToString(pointer: getSubaddressLabelNative(accountIndex, addressIndex));
|
||||
}
|
||||
}
|
||||
|
||||
Future setTrustedDaemon(bool trusted) async => setTrustedDaemonNative(_boolToInt(trusted));
|
||||
|
||||
Future<bool> trustedDaemon() async => trustedDaemonNative() != 0;
|
|
@ -136,6 +136,8 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
|
|||
password: node.password,
|
||||
useSSL: node.isSSL,
|
||||
isLightWallet: false); // FIXME: hardcoded value
|
||||
|
||||
monero_wallet.setTrustedDaemon(node.trusted);
|
||||
syncStatus = ConnectedSyncStatus();
|
||||
} catch (e) {
|
||||
syncStatus = FailedSyncStatus();
|
||||
|
@ -150,7 +152,7 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
|
|||
} catch (_) {}
|
||||
|
||||
try {
|
||||
syncStatus = StartingSyncStatus();
|
||||
syncStatus = AttemptingSyncStatus();
|
||||
monero_wallet.startRefresh();
|
||||
_setListeners();
|
||||
_listener?.start();
|
||||
|
|
|
@ -55,7 +55,7 @@ You may download and install the latest version of Android Studio [here](https:/
|
|||
|
||||
### 3. Installing Flutter
|
||||
|
||||
Need to install flutter with version `2.0.4`. For this please check section [Install Flutter manually](https://docs.flutter.dev/get-started/install/linux#install-flutter-manually). When flutter repository is downloaded please open it with `cd <flutter-path>` and checkout version 2.0.4 by `git checkout 2.0.4`.
|
||||
Need to install flutter with version `3.x.x`. For this please check section [Install Flutter manually](https://docs.flutter.dev/get-started/install/linux#install-flutter-manually).
|
||||
|
||||
### 4. Verify Installations
|
||||
|
||||
|
@ -66,7 +66,7 @@ Verify that the Android toolchain, Flutter, and Android Studio have been correct
|
|||
The output of this command will appear like this, indicating successful installations. If there are problems with your installation, they **must** be corrected before proceeding.
|
||||
```
|
||||
Doctor summary (to see all details, run flutter doctor -v):
|
||||
[✓] Flutter (Channel stable, 2.0.4, on Linux, locale en_US.UTF-8)
|
||||
[✓] Flutter (Channel stable, 3.x.x, on Linux, locale en_US.UTF-8)
|
||||
[✓] Android toolchain - develop for Android devices (Android SDK version 28)
|
||||
[✓] Android Studio (version 4.0)
|
||||
```
|
||||
|
@ -156,6 +156,10 @@ Generate mobx models for `cw_bitcoin`:
|
|||
|
||||
`cd cw_bitcoin && flutter pub get && flutter packages pub run build_runner build --delete-conflicting-outputs && cd ..`
|
||||
|
||||
Generate mobx models for `cw_haven`:
|
||||
|
||||
`cd cw_haven && flutter pub get && flutter packages pub run build_runner build --delete-conflicting-outputs && cd ..`
|
||||
|
||||
Finally build mobx models for the app:
|
||||
|
||||
`$ flutter packages pub run build_runner build --delete-conflicting-outputs`
|
||||
|
|
|
@ -14,8 +14,8 @@ String syncStatusTitle(SyncStatus syncStatus) {
|
|||
return S.current.sync_status_not_connected;
|
||||
}
|
||||
|
||||
if (syncStatus is StartingSyncStatus) {
|
||||
return S.current.sync_status_starting_sync;
|
||||
if (syncStatus is AttemptingSyncStatus) {
|
||||
return S.current.sync_status_attempting_sync;
|
||||
}
|
||||
|
||||
if (syncStatus is FailedSyncStatus) {
|
||||
|
|
84
lib/di.dart
84
lib/di.dart
|
@ -5,9 +5,14 @@ import 'package:cake_wallet/ionia/ionia_anypay.dart';
|
|||
import 'package:cake_wallet/ionia/ionia_gift_card.dart';
|
||||
import 'package:cake_wallet/ionia/ionia_tip.dart';
|
||||
import 'package:cake_wallet/src/screens/buy/onramper_page.dart';
|
||||
import 'package:cake_wallet/src/screens/settings/display_settings_page.dart';
|
||||
import 'package:cake_wallet/src/screens/settings/other_settings_page.dart';
|
||||
import 'package:cake_wallet/src/screens/settings/privacy_page.dart';
|
||||
import 'package:cake_wallet/src/screens/settings/security_backup_page.dart';
|
||||
import 'package:cake_wallet/src/screens/ionia/cards/ionia_custom_redeem_page.dart';
|
||||
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/view_model/ionia/ionia_auth_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/ionia/ionia_buy_card_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/ionia/ionia_custom_tip_view_model.dart';
|
||||
|
@ -26,6 +31,11 @@ import 'package:cake_wallet/src/screens/dashboard/widgets/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';
|
||||
import 'package:cake_wallet/view_model/settings/display_settings_view_model.dart';
|
||||
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:cw_core/unspent_coins_info.dart';
|
||||
import 'package:cake_wallet/core/backup_service.dart';
|
||||
import 'package:cw_core/wallet_service.dart';
|
||||
|
@ -49,7 +59,6 @@ import 'package:cake_wallet/src/screens/exchange_trade/exchange_trade_page.dart'
|
|||
import 'package:cake_wallet/src/screens/faq/faq_page.dart';
|
||||
import 'package:cake_wallet/src/screens/new_wallet/new_wallet_type_page.dart';
|
||||
import 'package:cake_wallet/src/screens/nodes/node_create_or_edit_page.dart';
|
||||
import 'package:cake_wallet/src/screens/nodes/nodes_list_page.dart';
|
||||
import 'package:cake_wallet/src/screens/order_details/order_details_page.dart';
|
||||
import 'package:cake_wallet/src/screens/pin_code/pin_code_widget.dart';
|
||||
import 'package:cake_wallet/src/screens/rescan/rescan_page.dart';
|
||||
|
@ -59,7 +68,6 @@ import 'package:cake_wallet/src/screens/restore/wallet_restore_page.dart';
|
|||
import 'package:cake_wallet/src/screens/seed/pre_seed_page.dart';
|
||||
import 'package:cake_wallet/src/screens/seed/wallet_seed_page.dart';
|
||||
import 'package:cake_wallet/src/screens/send/send_template_page.dart';
|
||||
import 'package:cake_wallet/src/screens/settings/settings.dart';
|
||||
import 'package:cake_wallet/src/screens/setup_pin_code/setup_pin_code.dart';
|
||||
import 'package:cake_wallet/src/screens/support/support_page.dart';
|
||||
import 'package:cake_wallet/src/screens/trade_details/trade_details_page.dart';
|
||||
|
@ -115,7 +123,6 @@ import 'package:cake_wallet/view_model/wallet_address_list/wallet_address_list_v
|
|||
import 'package:cake_wallet/view_model/monero_account_list/monero_account_edit_or_create_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/monero_account_list/monero_account_list_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/send/send_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/settings/settings_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/wallet_keys_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/wallet_list/wallet_list_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/wallet_restore_view_model.dart';
|
||||
|
@ -153,6 +160,7 @@ import 'package:cake_wallet/anypay/any_pay_payment_committed_info.dart';
|
|||
import 'package:cake_wallet/ionia/ionia_any_pay_payment_info.dart';
|
||||
import 'package:cake_wallet/src/screens/receive/fullscreen_qr_page.dart';
|
||||
import 'package:cake_wallet/core/wallet_loading_service.dart';
|
||||
import 'package:cw_core/crypto_currency.dart';
|
||||
|
||||
final getIt = GetIt.instance;
|
||||
|
||||
|
@ -343,7 +351,7 @@ Future setup(
|
|||
onAuthenticationFinished: onAuthFinished,
|
||||
closable: closable ?? false));
|
||||
|
||||
getIt.registerFactory(() =>
|
||||
getIt.registerFactory(() =>
|
||||
BalancePage(dashboardViewModel: getIt.get<DashboardViewModel>(), settingsStore: getIt.get<SettingsStore>()));
|
||||
|
||||
getIt.registerFactory<DashboardPage>(() => DashboardPage( balancePage: getIt.get<BalancePage>(), walletViewModel: getIt.get<DashboardViewModel>(), addressListViewModel: getIt.get<WalletAddressListViewModel>()));
|
||||
|
@ -377,8 +385,7 @@ Future setup(
|
|||
_transactionDescriptionBox));
|
||||
|
||||
getIt.registerFactory(
|
||||
() => SendPage(sendViewModel: getIt.get<SendViewModel>(),
|
||||
settingsViewModel: getIt.get<SettingsViewModel>()));
|
||||
() => SendPage(sendViewModel: getIt.get<SendViewModel>()));
|
||||
|
||||
getIt.registerFactory(() => SendTemplatePage(
|
||||
sendTemplateViewModel: getIt.get<SendTemplateViewModel>()));
|
||||
|
@ -434,12 +441,20 @@ Future setup(
|
|||
getIt.get<MoneroAccountEditOrCreateViewModel>(param1: account)));
|
||||
|
||||
getIt.registerFactory(() {
|
||||
final appStore = getIt.get<AppStore>();
|
||||
final yatStore = getIt.get<YatStore>();
|
||||
return SettingsViewModel(appStore.settingsStore, yatStore, appStore.wallet!);
|
||||
return DisplaySettingsViewModel(getIt.get<SettingsStore>());
|
||||
});
|
||||
|
||||
getIt.registerFactory(() => SettingsPage(getIt.get<SettingsViewModel>()));
|
||||
getIt.registerFactory(() {
|
||||
return PrivacySettingsViewModel(getIt.get<SettingsStore>());
|
||||
});
|
||||
|
||||
getIt.registerFactory(() {
|
||||
return OtherSettingsViewModel(getIt.get<SettingsStore>(), getIt.get<AppStore>().wallet!);
|
||||
});
|
||||
|
||||
getIt.registerFactory(() {
|
||||
return SecuritySettingsViewModel(getIt.get<SettingsStore>());
|
||||
});
|
||||
|
||||
getIt
|
||||
.registerFactory(() => WalletSeedViewModel(getIt.get<AppStore>().wallet!));
|
||||
|
@ -458,12 +473,11 @@ Future setup(
|
|||
(ContactRecord? contact, _) =>
|
||||
ContactViewModel(_contactSource, contact: contact));
|
||||
|
||||
getIt.registerFactory(
|
||||
() => ContactListViewModel(_contactSource, _walletInfoSource));
|
||||
getIt.registerFactoryParam<ContactListViewModel, CryptoCurrency?, void>(
|
||||
(CryptoCurrency? cur, _) => ContactListViewModel(_contactSource, _walletInfoSource, cur));
|
||||
|
||||
getIt.registerFactoryParam<ContactListPage, bool, void>(
|
||||
(bool isEditable, _) => ContactListPage(getIt.get<ContactListViewModel>(),
|
||||
isEditable: isEditable));
|
||||
getIt.registerFactoryParam<ContactListPage, CryptoCurrency?, void>((CryptoCurrency? cur, _)
|
||||
=> ContactListPage(getIt.get<ContactListViewModel>(param1: cur)));
|
||||
|
||||
getIt.registerFactoryParam<ContactPage, ContactRecord?, void>(
|
||||
(ContactRecord? contact, _) =>
|
||||
|
@ -475,10 +489,22 @@ Future setup(
|
|||
_nodeSource, appStore.wallet!, appStore.settingsStore);
|
||||
});
|
||||
|
||||
getIt.registerFactory(() => NodeListPage(getIt.get<NodeListViewModel>()));
|
||||
getIt.registerFactory(() => ConnectionSyncPage(getIt.get<NodeListViewModel>(), getIt.get<DashboardViewModel>()));
|
||||
|
||||
getIt.registerFactory(() =>
|
||||
NodeCreateOrEditViewModel(_nodeSource, getIt.get<AppStore>().wallet!));
|
||||
getIt.registerFactory(() => SecurityBackupPage(getIt.get<SecuritySettingsViewModel>()));
|
||||
|
||||
getIt.registerFactory(() => PrivacyPage(getIt.get<PrivacySettingsViewModel>()));
|
||||
|
||||
getIt.registerFactory(() => DisplaySettingsPage(getIt.get<DisplaySettingsViewModel>()));
|
||||
|
||||
getIt.registerFactory(() => OtherSettingsPage(getIt.get<OtherSettingsViewModel>()));
|
||||
|
||||
getIt.registerFactoryParam<NodeCreateOrEditViewModel, WalletType?, void>(
|
||||
(WalletType? type, _) => NodeCreateOrEditViewModel(
|
||||
_nodeSource,
|
||||
type ?? getIt.get<AppStore>().wallet!.type,
|
||||
getIt.get<SettingsStore>(),
|
||||
));
|
||||
|
||||
getIt.registerFactory(
|
||||
() => NodeCreateOrEditPage(getIt.get<NodeCreateOrEditViewModel>()));
|
||||
|
@ -494,7 +520,6 @@ Future setup(
|
|||
getIt.get<TradesStore>(),
|
||||
getIt.get<AppStore>().settingsStore,
|
||||
getIt.get<SharedPreferences>(),
|
||||
getIt.get<SettingsViewModel>(),
|
||||
));
|
||||
|
||||
getIt.registerFactory(() => ExchangeTradeViewModel(
|
||||
|
@ -678,7 +703,7 @@ Future setup(
|
|||
|
||||
getIt.registerFactoryParam<FullscreenQRPage, String, bool>(
|
||||
(String qrData, bool isLight) => FullscreenQRPage(qrData: qrData, isLight: isLight,));
|
||||
|
||||
|
||||
getIt.registerFactory(() => IoniaApi());
|
||||
|
||||
getIt.registerFactory(() => AnyPayApi());
|
||||
|
@ -698,7 +723,7 @@ Future setup(
|
|||
|
||||
getIt.registerFactoryParam<IoniaMerchPurchaseViewModel, double, IoniaMerchant>((double amount, merchant) {
|
||||
return IoniaMerchPurchaseViewModel(
|
||||
ioniaAnyPayService: getIt.get<IoniaAnyPay>(),
|
||||
ioniaAnyPayService: getIt.get<IoniaAnyPay>(),
|
||||
amount: amount,
|
||||
ioniaMerchant: merchant,
|
||||
sendViewModel: getIt.get<SendViewModel>()
|
||||
|
@ -741,31 +766,31 @@ Future setup(
|
|||
ioniaService: getIt.get<IoniaService>(),
|
||||
giftCard: giftCard);
|
||||
});
|
||||
|
||||
|
||||
getIt.registerFactoryParam<IoniaCustomTipViewModel, List, void>((List args, _) {
|
||||
final amount = args[0] as double;
|
||||
final merchant = args[1] as IoniaMerchant;
|
||||
final tip = args[2] as IoniaTip;
|
||||
|
||||
|
||||
return IoniaCustomTipViewModel(amount: amount, tip: tip, ioniaMerchant: merchant);
|
||||
});
|
||||
|
||||
|
||||
getIt.registerFactoryParam<IoniaGiftCardDetailPage, IoniaGiftCard, void>((IoniaGiftCard giftCard, _) {
|
||||
return IoniaGiftCardDetailPage(getIt.get<IoniaGiftCardDetailsViewModel>(param1: giftCard));
|
||||
});
|
||||
|
||||
getIt.registerFactoryParam<IoniaMoreOptionsPage, List, void>((List args, _){
|
||||
final giftCard = args.first as IoniaGiftCard;
|
||||
|
||||
return IoniaMoreOptionsPage(giftCard);
|
||||
|
||||
return IoniaMoreOptionsPage(giftCard);
|
||||
});
|
||||
|
||||
getIt.registerFactoryParam<IoniaCustomRedeemViewModel, IoniaGiftCard, void>((IoniaGiftCard giftCard, _) => IoniaCustomRedeemViewModel(giftCard));
|
||||
|
||||
getIt.registerFactoryParam<IoniaCustomRedeemPage, List, void>((List args, _){
|
||||
final giftCard = args.first as IoniaGiftCard;
|
||||
|
||||
return IoniaCustomRedeemPage(getIt.get<IoniaCustomRedeemViewModel>(param1: giftCard) );
|
||||
|
||||
return IoniaCustomRedeemPage(getIt.get<IoniaCustomRedeemViewModel>(param1: giftCard) );
|
||||
});
|
||||
|
||||
|
||||
|
@ -794,5 +819,8 @@ Future setup(
|
|||
(IoniaAnyPayPaymentInfo paymentInfo, AnyPayPaymentCommittedInfo committedInfo)
|
||||
=> IoniaPaymentStatusPage(getIt.get<IoniaPaymentStatusViewModel>(param1: paymentInfo, param2: committedInfo)));
|
||||
|
||||
getIt.registerFactoryParam<AdvancedPrivacySettingsViewModel, WalletType, void>((type, _) =>
|
||||
AdvancedPrivacySettingsViewModel(type, getIt.get<SettingsStore>()));
|
||||
|
||||
_isSetupFinished = true;
|
||||
}
|
||||
|
|
|
@ -69,6 +69,8 @@ Future defaultSettingsMigration(
|
|||
sharedPreferences: sharedPreferences, nodes: nodes);
|
||||
await changeLitecoinCurrentElectrumServerToDefault(
|
||||
sharedPreferences: sharedPreferences, nodes: nodes);
|
||||
await changeHavenCurrentNodeToDefault(
|
||||
sharedPreferences: sharedPreferences, nodes: nodes);
|
||||
|
||||
break;
|
||||
case 2:
|
||||
|
@ -133,19 +135,32 @@ Future defaultSettingsMigration(
|
|||
await changeDefaultHavenNode(nodes);
|
||||
break;
|
||||
|
||||
case 18:
|
||||
await addOnionNode(nodes);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
await sharedPreferences.setInt(
|
||||
'current_default_settings_migration_version', version);
|
||||
PreferencesKey.currentDefaultSettingsMigrationVersion, version);
|
||||
} catch (e) {
|
||||
print('Migration error: ${e.toString()}');
|
||||
}
|
||||
});
|
||||
|
||||
await sharedPreferences.setInt(
|
||||
'current_default_settings_migration_version', version);
|
||||
PreferencesKey.currentDefaultSettingsMigrationVersion, version);
|
||||
}
|
||||
|
||||
Future<void> addOnionNode(Box<Node> nodes) async {
|
||||
final onionNodeUri = "cakexmrl7bonq7ovjka5kuwuyd3f7qnkz6z6s6dmsy3uckwra7bvggyd.onion:18081";
|
||||
|
||||
// check if the user has this node before (added it manually)
|
||||
if (nodes.values.firstWhereOrNull((element) => element.uriRaw == onionNodeUri) == null) {
|
||||
await nodes.add(Node(uri: onionNodeUri, type: WalletType.monero));
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> replaceNodesMigration({required Box<Node> nodes}) async {
|
||||
|
@ -176,7 +191,7 @@ Future<void> changeMoneroCurrentNodeToDefault(
|
|||
final node = getMoneroDefaultNode(nodes: nodes);
|
||||
final nodeId = node?.key as int ?? 0; // 0 - England
|
||||
|
||||
await sharedPreferences.setInt('current_node_id', nodeId);
|
||||
await sharedPreferences.setInt(PreferencesKey.currentNodeIdKey, nodeId);
|
||||
}
|
||||
|
||||
Node? getBitcoinDefaultElectrumServer({required Box<Node> nodes}) {
|
||||
|
@ -223,7 +238,7 @@ Future<void> changeBitcoinCurrentElectrumServerToDefault(
|
|||
final server = getBitcoinDefaultElectrumServer(nodes: nodes);
|
||||
final serverId = server?.key as int ?? 0;
|
||||
|
||||
await sharedPreferences.setInt('current_node_id_btc', serverId);
|
||||
await sharedPreferences.setInt(PreferencesKey.currentBitcoinElectrumSererIdKey, serverId);
|
||||
}
|
||||
|
||||
Future<void> changeLitecoinCurrentElectrumServerToDefault(
|
||||
|
@ -232,7 +247,7 @@ Future<void> changeLitecoinCurrentElectrumServerToDefault(
|
|||
final server = getLitecoinDefaultElectrumServer(nodes: nodes);
|
||||
final serverId = server?.key as int ?? 0;
|
||||
|
||||
await sharedPreferences.setInt('current_node_id_ltc', serverId);
|
||||
await sharedPreferences.setInt(PreferencesKey.currentLitecoinElectrumSererIdKey, serverId);
|
||||
}
|
||||
|
||||
Future<void> changeHavenCurrentNodeToDefault(
|
||||
|
@ -252,7 +267,7 @@ Future<void> replaceDefaultNode(
|
|||
'eu-node.cakewallet.io:18081',
|
||||
'node.cakewallet.io:18081'
|
||||
];
|
||||
final currentNodeId = sharedPreferences.getInt('current_node_id');
|
||||
final currentNodeId = sharedPreferences.getInt(PreferencesKey.currentNodeIdKey);
|
||||
final currentNode =
|
||||
nodes.values.firstWhereOrNull((Node node) => node.key == currentNodeId);
|
||||
final needToReplace =
|
||||
|
@ -277,17 +292,29 @@ Future<void> updateNodeTypes({required Box<Node> nodes}) async {
|
|||
|
||||
Future<void> addBitcoinElectrumServerList({required Box<Node> nodes}) async {
|
||||
final serverList = await loadBitcoinElectrumServerList();
|
||||
await nodes.addAll(serverList);
|
||||
for (var node in serverList) {
|
||||
if (nodes.values.firstWhereOrNull((element) => element.uriRaw == node.uriRaw) == null) {
|
||||
await nodes.add(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> addLitecoinElectrumServerList({required Box<Node> nodes}) async {
|
||||
final serverList = await loadLitecoinElectrumServerList();
|
||||
await nodes.addAll(serverList);
|
||||
for (var node in serverList) {
|
||||
if (nodes.values.firstWhereOrNull((element) => element.uriRaw == node.uriRaw) == null) {
|
||||
await nodes.add(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> addHavenNodeList({required Box<Node> nodes}) async {
|
||||
final nodeList = await loadDefaultHavenNodes();
|
||||
await nodes.addAll(nodeList);
|
||||
for (var node in nodeList) {
|
||||
if (nodes.values.firstWhereOrNull((element) => element.uriRaw == node.uriRaw) == null) {
|
||||
await nodes.add(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> addAddressesForMoneroWallets(
|
||||
|
@ -431,7 +458,7 @@ Future<void> resetBitcoinElectrumServer(
|
|||
final oldElectrumServer = nodeSource.values.firstWhereOrNull(
|
||||
(node) => node.uri.toString().contains('electrumx.cakewallet.com'));
|
||||
var cakeWalletNode = nodeSource.values.firstWhereOrNull(
|
||||
(node) => node.uri.toString() == cakeWalletBitcoinElectrumUri);
|
||||
(node) => node.uriRaw.toString() == cakeWalletBitcoinElectrumUri);
|
||||
|
||||
if (cakeWalletNode == null) {
|
||||
cakeWalletNode =
|
||||
|
|
|
@ -4,7 +4,6 @@ import 'package:cake_wallet/entities/parsed_address.dart';
|
|||
import 'package:cake_wallet/entities/unstoppable_domain_address.dart';
|
||||
import 'package:cake_wallet/entities/emoji_string_extension.dart';
|
||||
import 'package:cw_core/wallet_type.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:cake_wallet/entities/fio_address_provider.dart';
|
||||
|
||||
class AddressResolver {
|
||||
|
@ -51,7 +50,7 @@ class AddressResolver {
|
|||
return ParsedAddress(addresses: [text]);
|
||||
}
|
||||
|
||||
if (unstoppableDomains.any((domain) => name.contains(domain))) {
|
||||
if (unstoppableDomains.any((domain) => name.trim() == domain)) {
|
||||
final address = await fetchUnstoppableDomainAddress(text, ticker);
|
||||
return ParsedAddress.fetchUnstoppableDomainAddress(address: address, name: text);
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@ class PreferencesKey {
|
|||
static const shouldSaveRecipientAddressKey = 'save_recipient_address';
|
||||
static const allowBiometricalAuthenticationKey =
|
||||
'allow_biometrical_authentication';
|
||||
static const disableExchangeKey = 'disable_exchange';
|
||||
static const currentTheme = 'current_theme';
|
||||
static const isDarkThemeLegacy = 'dark_theme';
|
||||
static const displayActionListModeKey = 'display_list_mode';
|
||||
|
|
21
lib/entities/priority_for_wallet_type.dart
Normal file
21
lib/entities/priority_for_wallet_type.dart
Normal file
|
@ -0,0 +1,21 @@
|
|||
import 'package:cake_wallet/bitcoin/bitcoin.dart';
|
||||
import 'package:cake_wallet/haven/haven.dart';
|
||||
import 'package:cake_wallet/monero/monero.dart';
|
||||
import 'package:cw_core/transaction_priority.dart';
|
||||
import 'package:cw_core/wallet_type.dart';
|
||||
|
||||
List<TransactionPriority> priorityForWalletType(WalletType type) {
|
||||
switch (type) {
|
||||
case WalletType.monero:
|
||||
return monero!.getTransactionPriorities();
|
||||
case WalletType.bitcoin:
|
||||
return bitcoin!.getTransactionPriorities();
|
||||
case WalletType.litecoin:
|
||||
return bitcoin!.getLitecoinTransactionPriorities();
|
||||
case WalletType.haven:
|
||||
return haven!.getTransactionPriorities();
|
||||
default:
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
|
@ -11,7 +11,6 @@ import 'package:cake_wallet/exchange/trade_request.dart';
|
|||
import 'package:cake_wallet/exchange/trade_state.dart';
|
||||
import 'package:cake_wallet/exchange/changenow/changenow_request.dart';
|
||||
import 'package:cake_wallet/exchange/exchange_provider_description.dart';
|
||||
import 'package:cake_wallet/exchange/trade_not_created_exeption.dart';
|
||||
|
||||
class ChangeNowExchangeProvider extends ExchangeProvider {
|
||||
ChangeNowExchangeProvider()
|
||||
|
@ -21,8 +20,7 @@ class ChangeNowExchangeProvider extends ExchangeProvider {
|
|||
.where((i) => i != CryptoCurrency.xhv)
|
||||
.map((i) => CryptoCurrency.all
|
||||
.where((i) => i != CryptoCurrency.xhv)
|
||||
.map((k) => ExchangePair(from: i, to: k, reverse: true))
|
||||
.where((c) => c != null))
|
||||
.map((k) => ExchangePair(from: i, to: k, reverse: true)))
|
||||
.expand((i) => i)
|
||||
.toList());
|
||||
|
||||
|
@ -43,6 +41,9 @@ class ChangeNowExchangeProvider extends ExchangeProvider {
|
|||
@override
|
||||
bool get isEnabled => true;
|
||||
|
||||
@override
|
||||
bool get supportsFixedRate => true;
|
||||
|
||||
@override
|
||||
ExchangeProviderDescription get description =>
|
||||
ExchangeProviderDescription.changeNow;
|
||||
|
@ -96,25 +97,36 @@ class ChangeNowExchangeProvider extends ExchangeProvider {
|
|||
apiHeaderKey: apiKey,
|
||||
'Content-Type': 'application/json'};
|
||||
final flow = getFlow(isFixedRateMode);
|
||||
final type = isFixedRateMode ? 'reverse' : 'direct';
|
||||
final body = <String, String>{
|
||||
'fromCurrency': normalizeCryptoCurrency(_request.from),
|
||||
'toCurrency': normalizeCryptoCurrency(_request.to),
|
||||
'fromNetwork': networkFor(_request.from),
|
||||
'toNetwork': networkFor(_request.to),
|
||||
'fromAmount': _request.fromAmount,
|
||||
'toAmount': _request.toAmount,
|
||||
if (!isFixedRateMode) 'fromAmount': _request.fromAmount,
|
||||
if (isFixedRateMode) 'toAmount': _request.toAmount,
|
||||
'address': _request.address,
|
||||
'flow': flow,
|
||||
'type': type,
|
||||
'refundAddress': _request.refundAddress
|
||||
};
|
||||
|
||||
if (isFixedRateMode) {
|
||||
// since we schedule to calculate the rate every 5 seconds we need to ensure that
|
||||
// we have the latest rate id with the given inputs before creating the trade
|
||||
await fetchRate(
|
||||
from: _request.from,
|
||||
to: _request.to,
|
||||
amount: double.tryParse(_request.toAmount) ?? 0,
|
||||
isFixedRateMode: true,
|
||||
isReceiveAmount: true,
|
||||
);
|
||||
body['rateId'] = _lastUsedRateId;
|
||||
}
|
||||
|
||||
final uri = Uri.https(apiAuthority, createTradePath);
|
||||
final response = await post(uri, headers: headers, body: json.encode(body));
|
||||
|
||||
|
||||
if (response.statusCode == 400) {
|
||||
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
|
||||
final error = responseJSON['error'] as String;
|
||||
|
@ -130,7 +142,7 @@ class ChangeNowExchangeProvider extends ExchangeProvider {
|
|||
final id = responseJSON['id'] as String;
|
||||
final inputAddress = responseJSON['payinAddress'] as String;
|
||||
final refundAddress = responseJSON['refundAddress'] as String;
|
||||
final extraId = responseJSON['payinExtraId'] as String;
|
||||
final extraId = responseJSON['payinExtraId'] as String?;
|
||||
|
||||
return Trade(
|
||||
id: id,
|
||||
|
@ -141,7 +153,7 @@ class ChangeNowExchangeProvider extends ExchangeProvider {
|
|||
refundAddress: refundAddress,
|
||||
extraId: extraId,
|
||||
createdAt: DateTime.now(),
|
||||
amount: _request.fromAmount,
|
||||
amount: responseJSON['fromAmount']?.toString() ?? _request.fromAmount,
|
||||
state: TradeState.created);
|
||||
}
|
||||
|
||||
|
@ -180,9 +192,7 @@ class ChangeNowExchangeProvider extends ExchangeProvider {
|
|||
final extraId = responseJSON['payinExtraId'] as String;
|
||||
final outputTransaction = responseJSON['payoutHash'] as String;
|
||||
final expiredAtRaw = responseJSON['validUntil'] as String;
|
||||
final expiredAt = expiredAtRaw != null
|
||||
? DateTime.parse(expiredAtRaw).toLocal()
|
||||
: null;
|
||||
final expiredAt = DateTime.tryParse(expiredAtRaw)?.toLocal();
|
||||
|
||||
return Trade(
|
||||
id: id,
|
||||
|
@ -198,7 +208,7 @@ class ChangeNowExchangeProvider extends ExchangeProvider {
|
|||
}
|
||||
|
||||
@override
|
||||
Future<double> calculateAmount(
|
||||
Future<double> fetchRate(
|
||||
{required CryptoCurrency from,
|
||||
required CryptoCurrency to,
|
||||
required double amount,
|
||||
|
@ -214,10 +224,10 @@ class ChangeNowExchangeProvider extends ExchangeProvider {
|
|||
final type = isReverse ? 'reverse' : 'direct';
|
||||
final flow = getFlow(isFixedRateMode);
|
||||
final params = <String, String>{
|
||||
'fromCurrency': isReverse ? normalizeCryptoCurrency(to) : normalizeCryptoCurrency(from),
|
||||
'toCurrency': isReverse ? normalizeCryptoCurrency(from) : normalizeCryptoCurrency(to),
|
||||
'fromNetwork': isReverse ? networkFor(to) : networkFor(from),
|
||||
'toNetwork': isReverse ? networkFor(from) : networkFor(to),
|
||||
'fromCurrency': normalizeCryptoCurrency(from),
|
||||
'toCurrency': normalizeCryptoCurrency(to),
|
||||
'fromNetwork': networkFor(from),
|
||||
'toNetwork': networkFor(to),
|
||||
'type': type,
|
||||
'flow': flow};
|
||||
|
||||
|
@ -238,7 +248,7 @@ class ChangeNowExchangeProvider extends ExchangeProvider {
|
|||
_lastUsedRateId = rateId;
|
||||
}
|
||||
|
||||
return isReverse ? fromAmount : toAmount;
|
||||
return isReverse ? (amount / fromAmount) : (toAmount / amount);
|
||||
} catch(e) {
|
||||
print(e.toString());
|
||||
return 0.0;
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
import 'package:flutter/foundation.dart';
|
||||
import 'package:cw_core/crypto_currency.dart';
|
||||
import 'package:cake_wallet/exchange/trade_request.dart';
|
||||
import 'package:cake_wallet/exchange/exchange_pair.dart';
|
||||
|
@ -14,6 +13,7 @@ abstract class ExchangeProvider {
|
|||
ExchangeProviderDescription get description;
|
||||
bool get isAvailable;
|
||||
bool get isEnabled;
|
||||
bool get supportsFixedRate;
|
||||
|
||||
@override
|
||||
String toString() => title;
|
||||
|
@ -26,7 +26,7 @@ abstract class ExchangeProvider {
|
|||
required TradeRequest request,
|
||||
required bool isFixedRateMode});
|
||||
Future<Trade> findTradeById({required String id});
|
||||
Future<double> calculateAmount({
|
||||
Future<double> fetchRate({
|
||||
required CryptoCurrency from,
|
||||
required CryptoCurrency to,
|
||||
required double amount,
|
||||
|
|
|
@ -66,6 +66,9 @@ class MorphTokenExchangeProvider extends ExchangeProvider {
|
|||
@override
|
||||
bool get isEnabled => true;
|
||||
|
||||
@override
|
||||
bool get supportsFixedRate => false;
|
||||
|
||||
@override
|
||||
ExchangeProviderDescription get description =>
|
||||
ExchangeProviderDescription.morphToken;
|
||||
|
@ -200,7 +203,7 @@ class MorphTokenExchangeProvider extends ExchangeProvider {
|
|||
}
|
||||
|
||||
@override
|
||||
Future<double> calculateAmount(
|
||||
Future<double> fetchRate(
|
||||
{required CryptoCurrency from,
|
||||
required CryptoCurrency to,
|
||||
required double amount,
|
||||
|
|
|
@ -12,7 +12,6 @@ import 'package:cw_core/crypto_currency.dart';
|
|||
import 'package:cake_wallet/exchange/trade_request.dart';
|
||||
import 'package:cake_wallet/exchange/trade.dart';
|
||||
import 'package:cake_wallet/exchange/limits.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:http/http.dart';
|
||||
|
||||
class SideShiftExchangeProvider extends ExchangeProvider {
|
||||
|
@ -48,8 +47,7 @@ class SideShiftExchangeProvider extends ExchangeProvider {
|
|||
|
||||
return supportedCurrencies
|
||||
.map((i) => supportedCurrencies
|
||||
.map((k) => ExchangePair(from: i, to: k, reverse: true))
|
||||
.where((c) => c != null))
|
||||
.map((k) => ExchangePair(from: i, to: k, reverse: true)))
|
||||
.expand((i) => i)
|
||||
.toList();
|
||||
}
|
||||
|
@ -59,7 +57,7 @@ class SideShiftExchangeProvider extends ExchangeProvider {
|
|||
ExchangeProviderDescription.sideShift;
|
||||
|
||||
@override
|
||||
Future<double> calculateAmount(
|
||||
Future<double> fetchRate(
|
||||
{required CryptoCurrency from,
|
||||
required CryptoCurrency to,
|
||||
required double amount,
|
||||
|
@ -81,9 +79,7 @@ class SideShiftExchangeProvider extends ExchangeProvider {
|
|||
|
||||
if (amount > max) return 0.00;
|
||||
|
||||
final estimatedAmount = rate * amount;
|
||||
|
||||
return estimatedAmount;
|
||||
return rate;
|
||||
} catch (_) {
|
||||
return 0.00;
|
||||
}
|
||||
|
@ -249,15 +245,15 @@ class SideShiftExchangeProvider extends ExchangeProvider {
|
|||
final expectedSendAmount = responseJSON['depositAmount'].toString();
|
||||
final deposits = responseJSON['deposits'] as List?;
|
||||
TradeState? state;
|
||||
String? status;
|
||||
|
||||
if (deposits != null && deposits.isNotEmpty) {
|
||||
final status = deposits[0]['status'] as String;
|
||||
state = TradeState.deserialize(raw: status);
|
||||
if (deposits?.isNotEmpty ?? false) {
|
||||
status = deposits![0]['status'] as String?;
|
||||
}
|
||||
state = TradeState.deserialize(raw: status ?? 'created');
|
||||
|
||||
final expiredAtRaw = responseJSON['expiresAtISO'] as String;
|
||||
final expiredAt =
|
||||
expiredAtRaw != null ? DateTime.parse(expiredAtRaw).toLocal() : null;
|
||||
final expiredAt = DateTime.tryParse(expiredAtRaw)?.toLocal();
|
||||
|
||||
return Trade(
|
||||
id: id,
|
||||
|
@ -277,6 +273,9 @@ class SideShiftExchangeProvider extends ExchangeProvider {
|
|||
@override
|
||||
bool get isEnabled => true;
|
||||
|
||||
@override
|
||||
bool get supportsFixedRate => true;
|
||||
|
||||
@override
|
||||
String get title => 'SideShift';
|
||||
|
||||
|
|
|
@ -20,8 +20,7 @@ class SimpleSwapExchangeProvider extends ExchangeProvider {
|
|||
.where((i) => i != CryptoCurrency.zaddr)
|
||||
.map((i) => CryptoCurrency.all
|
||||
.where((i) => i != CryptoCurrency.zaddr)
|
||||
.map((k) => ExchangePair(from: i, to: k, reverse: true))
|
||||
.where((c) => c != null))
|
||||
.map((k) => ExchangePair(from: i, to: k, reverse: true)))
|
||||
.expand((i) => i)
|
||||
.toList());
|
||||
|
||||
|
@ -37,7 +36,7 @@ class SimpleSwapExchangeProvider extends ExchangeProvider {
|
|||
ExchangeProviderDescription.simpleSwap;
|
||||
|
||||
@override
|
||||
Future<double> calculateAmount(
|
||||
Future<double> fetchRate(
|
||||
{required CryptoCurrency from,
|
||||
required CryptoCurrency to,
|
||||
required double amount,
|
||||
|
@ -59,9 +58,9 @@ class SimpleSwapExchangeProvider extends ExchangeProvider {
|
|||
final uri = Uri.https(apiAuthority, getEstimatePath, params);
|
||||
final response = await get(uri);
|
||||
|
||||
if (response.body == null || response.body == "null") return 0.00;
|
||||
if (response.body == "null") return 0.00;
|
||||
final data = json.decode(response.body) as String;
|
||||
return double.parse(data);
|
||||
return double.parse(data) / amount;
|
||||
} catch (_) {
|
||||
return 0.00;
|
||||
}
|
||||
|
@ -210,6 +209,9 @@ class SimpleSwapExchangeProvider extends ExchangeProvider {
|
|||
@override
|
||||
bool get isEnabled => true;
|
||||
|
||||
@override
|
||||
bool get supportsFixedRate => false;
|
||||
|
||||
@override
|
||||
String get title => 'SimpleSwap';
|
||||
|
||||
|
|
|
@ -48,6 +48,9 @@ class XMRTOExchangeProvider extends ExchangeProvider {
|
|||
@override
|
||||
bool get isEnabled => true;
|
||||
|
||||
@override
|
||||
bool get supportsFixedRate => false;
|
||||
|
||||
@override
|
||||
ExchangeProviderDescription get description =>
|
||||
ExchangeProviderDescription.xmrto;
|
||||
|
@ -191,7 +194,7 @@ class XMRTOExchangeProvider extends ExchangeProvider {
|
|||
}
|
||||
|
||||
@override
|
||||
Future<double> calculateAmount(
|
||||
Future<double> fetchRate(
|
||||
{required CryptoCurrency from,
|
||||
required CryptoCurrency to,
|
||||
required double amount,
|
||||
|
|
|
@ -128,7 +128,7 @@ Future<void> main() async {
|
|||
exchangeTemplates: exchangeTemplates,
|
||||
transactionDescriptions: transactionDescriptions,
|
||||
secureStorage: secureStorage,
|
||||
initialMigrationVersion: 17);
|
||||
initialMigrationVersion: 18);
|
||||
runApp(App());
|
||||
} catch (e, stacktrace) {
|
||||
runApp(MaterialApp(
|
||||
|
@ -261,7 +261,7 @@ class AppState extends State<App> with SingleTickerProviderStateMixin {
|
|||
final statusBarColor = Colors.transparent;
|
||||
final authenticationStore = getIt.get<AuthenticationStore>();
|
||||
final initialRoute =
|
||||
authenticationStore.state == AuthenticationState.denied
|
||||
authenticationStore.state == AuthenticationState.uninitialized
|
||||
? Routes.disclaimer
|
||||
: Routes.login;
|
||||
final currentTheme = settingsStore.currentTheme;
|
||||
|
|
|
@ -22,9 +22,9 @@ Future<void> bootstrap(GlobalKey<NavigatorState> navigatorKey) async {
|
|||
final currentWalletName = getIt
|
||||
.get<SharedPreferences>()
|
||||
.getString(PreferencesKey.currentWalletName);
|
||||
authenticationStore.state = currentWalletName == null
|
||||
? AuthenticationState.denied
|
||||
: AuthenticationState.installed;
|
||||
if (currentWalletName != null) {
|
||||
authenticationStore.state = AuthenticationState.installed;
|
||||
}
|
||||
|
||||
startAuthenticationStateChange(authenticationStore, navigatorKey);
|
||||
startCurrentWalletChangeReaction(
|
||||
|
|
|
@ -26,10 +26,5 @@ void startAuthenticationStateChange(AuthenticationStore authenticationStore,
|
|||
await navigatorKey.currentState!.pushNamedAndRemoveUntil(Routes.dashboard, (route) => false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (state == AuthenticationState.denied) {
|
||||
await navigatorKey.currentState!.pushNamedAndRemoveUntil(Routes.welcome, (_) => false);
|
||||
return;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -5,21 +5,29 @@ import 'package:cake_wallet/src/screens/backup/edit_backup_password_page.dart';
|
|||
import 'package:cake_wallet/src/screens/buy/buy_webview_page.dart';
|
||||
import 'package:cake_wallet/src/screens/buy/onramper_page.dart';
|
||||
import 'package:cake_wallet/src/screens/buy/pre_order_page.dart';
|
||||
import 'package:cake_wallet/src/screens/settings/display_settings_page.dart';
|
||||
import 'package:cake_wallet/src/screens/settings/other_settings_page.dart';
|
||||
import 'package:cake_wallet/src/screens/settings/privacy_page.dart';
|
||||
import 'package:cake_wallet/src/screens/settings/security_backup_page.dart';
|
||||
import 'package:cake_wallet/src/screens/ionia/cards/ionia_account_cards_page.dart';
|
||||
import 'package:cake_wallet/src/screens/ionia/cards/ionia_account_page.dart';
|
||||
import 'package:cake_wallet/src/screens/ionia/cards/ionia_custom_redeem_page.dart';
|
||||
import 'package:cake_wallet/src/screens/ionia/cards/ionia_custom_tip_page.dart';
|
||||
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/new_wallet/advanced_privacy_settings_page.dart';
|
||||
import 'package:cake_wallet/src/screens/order_details/order_details_page.dart';
|
||||
import 'package:cake_wallet/src/screens/pin_code/pin_code_widget.dart';
|
||||
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/support/support_page.dart';
|
||||
import 'package:cake_wallet/src/screens/unspent_coins/unspent_coins_details_page.dart';
|
||||
import 'package:cake_wallet/src/screens/unspent_coins/unspent_coins_list_page.dart';
|
||||
import 'package:cake_wallet/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';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:cake_wallet/routes.dart';
|
||||
|
@ -36,7 +44,6 @@ import 'package:cake_wallet/src/screens/dashboard/dashboard_page.dart';
|
|||
import 'package:cake_wallet/src/screens/seed/wallet_seed_page.dart';
|
||||
import 'package:cake_wallet/src/screens/auth/auth_page.dart';
|
||||
import 'package:cake_wallet/src/screens/nodes/node_create_or_edit_page.dart';
|
||||
import 'package:cake_wallet/src/screens/nodes/nodes_list_page.dart';
|
||||
import 'package:cake_wallet/src/screens/receive/receive_page.dart';
|
||||
import 'package:cake_wallet/src/screens/subaddress/address_edit_or_create_page.dart';
|
||||
import 'package:cake_wallet/src/screens/wallet_list/wallet_list_page.dart';
|
||||
|
@ -56,7 +63,6 @@ import 'package:cake_wallet/src/screens/contact/contact_page.dart';
|
|||
import 'package:cake_wallet/src/screens/wallet_keys/wallet_keys_page.dart';
|
||||
import 'package:cake_wallet/src/screens/restore/restore_wallet_from_seed_details.dart';
|
||||
import 'package:cake_wallet/src/screens/exchange/exchange_page.dart';
|
||||
import 'package:cake_wallet/src/screens/settings/settings.dart';
|
||||
import 'package:cake_wallet/src/screens/rescan/rescan_page.dart';
|
||||
import 'package:cake_wallet/src/screens/faq/faq_page.dart';
|
||||
import 'package:cake_wallet/src/screens/trade_details/trade_details_page.dart';
|
||||
|
@ -74,6 +80,7 @@ import 'package:cake_wallet/src/screens/ionia/ionia.dart';
|
|||
import 'package:cake_wallet/src/screens/ionia/cards/ionia_payment_status_page.dart';
|
||||
import 'package:cake_wallet/anypay/any_pay_payment_committed_info.dart';
|
||||
import 'package:cake_wallet/ionia/ionia_any_pay_payment_info.dart';
|
||||
import 'package:cw_core/crypto_currency.dart';
|
||||
|
||||
late RouteSettings currentRouteSettings;
|
||||
|
||||
|
@ -274,10 +281,26 @@ Route<dynamic> createRoute(RouteSettings settings) {
|
|||
param2: false),
|
||||
onWillPop: () async => false));
|
||||
|
||||
case Routes.nodeList:
|
||||
case Routes.connectionSync:
|
||||
return CupertinoPageRoute<void>(
|
||||
builder: (_) => getIt.get<NodeListPage>());
|
||||
builder: (_) => getIt.get<ConnectionSyncPage>());
|
||||
|
||||
case Routes.securityBackupPage:
|
||||
return CupertinoPageRoute<void>(
|
||||
builder: (_) => getIt.get<SecurityBackupPage>());
|
||||
|
||||
case Routes.privacyPage:
|
||||
return CupertinoPageRoute<void>(
|
||||
builder: (_) => getIt.get<PrivacyPage>());
|
||||
|
||||
case Routes.displaySettingsPage:
|
||||
return CupertinoPageRoute<void>(
|
||||
builder: (_) => getIt.get<DisplaySettingsPage>());
|
||||
|
||||
case Routes.otherSettingsPage:
|
||||
return CupertinoPageRoute<void>(
|
||||
builder: (_) => getIt.get<OtherSettingsPage>());
|
||||
|
||||
case Routes.newNode:
|
||||
return CupertinoPageRoute<void>(
|
||||
builder: (_) => getIt.get<NodeCreateOrEditPage>());
|
||||
|
@ -298,11 +321,13 @@ Route<dynamic> createRoute(RouteSettings settings) {
|
|||
|
||||
case Routes.addressBook:
|
||||
return MaterialPageRoute<void>(
|
||||
builder: (_) => getIt.get<ContactListPage>(param1: true));
|
||||
builder: (_) =>
|
||||
getIt.get<ContactListPage>());
|
||||
|
||||
case Routes.pickerAddressBook:
|
||||
final selectedCurrency = settings.arguments as CryptoCurrency;
|
||||
return MaterialPageRoute<void>(
|
||||
builder: (_) => getIt.get<ContactListPage>(param1: false));
|
||||
builder: (_) => getIt.get<ContactListPage>(param1: selectedCurrency));
|
||||
|
||||
case Routes.addressBookAddContact:
|
||||
return CupertinoPageRoute<void>(
|
||||
|
@ -360,9 +385,6 @@ Route<dynamic> createRoute(RouteSettings settings) {
|
|||
return CupertinoPageRoute<void>(
|
||||
builder: (_) => getIt.get<ExchangeTemplatePage>());
|
||||
|
||||
case Routes.settings:
|
||||
return MaterialPageRoute<void>(builder: (_) => getIt.get<SettingsPage>());
|
||||
|
||||
case Routes.rescan:
|
||||
return MaterialPageRoute<void>(builder: (_) => getIt.get<RescanPage>());
|
||||
|
||||
|
@ -475,6 +497,15 @@ Route<dynamic> createRoute(RouteSettings settings) {
|
|||
case Routes.onramperPage:
|
||||
return CupertinoPageRoute<void>(builder: (_) => getIt.get<OnRamperPage>());
|
||||
|
||||
case Routes.advancedPrivacySettings:
|
||||
final type = settings.arguments as WalletType;
|
||||
|
||||
return CupertinoPageRoute<void>(
|
||||
builder: (_) => AdvancedPrivacySettingsPage(
|
||||
getIt.get<AdvancedPrivacySettingsViewModel>(param1: type),
|
||||
getIt.get<NodeCreateOrEditViewModel>(param1: type),
|
||||
));
|
||||
|
||||
default:
|
||||
return MaterialPageRoute<void>(
|
||||
builder: (_) => Scaffold(
|
||||
|
|
|
@ -21,7 +21,6 @@ class Routes {
|
|||
static const seedLanguage = '/seed_language';
|
||||
static const walletList = '/view_model.wallet_list';
|
||||
static const auth = '/auth';
|
||||
static const nodeList = '/node_list';
|
||||
static const newNode = '/new_node_list';
|
||||
static const login = '/login';
|
||||
static const splash = '/splash';
|
||||
|
@ -77,4 +76,10 @@ class Routes {
|
|||
static const ioniaMoreOptionsPage = '/ionia_more_options_page';
|
||||
static const ioniaCustomRedeemPage = '/ionia_custom_redeem_page';
|
||||
static const onramperPage = '/onramper';
|
||||
static const connectionSync = '/connection_sync_page';
|
||||
static const securityBackupPage = '/security_and_backup_page';
|
||||
static const privacyPage = '/privacy_page';
|
||||
static const displaySettingsPage = '/display_settings_page';
|
||||
static const otherSettingsPage = '/other_settings_page';
|
||||
static const advancedPrivacySettings = '/advanced_privacy_settings';
|
||||
}
|
||||
|
|
|
@ -9,24 +9,22 @@ import 'package:flutter_mobx/flutter_mobx.dart';
|
|||
import 'package:flutter_slidable/flutter_slidable.dart';
|
||||
import 'package:cake_wallet/routes.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cw_core/crypto_currency.dart';
|
||||
import 'package:cake_wallet/src/screens/base_page.dart';
|
||||
import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart';
|
||||
import 'package:cake_wallet/view_model/contact_list/contact_list_view_model.dart';
|
||||
import 'package:cake_wallet/src/widgets/collapsible_standart_list.dart';
|
||||
|
||||
class ContactListPage extends BasePage {
|
||||
ContactListPage(this.contactListViewModel, {this.isEditable = true});
|
||||
ContactListPage(this.contactListViewModel);
|
||||
|
||||
final ContactListViewModel contactListViewModel;
|
||||
final bool isEditable;
|
||||
|
||||
@override
|
||||
String get title => S.current.address_book;
|
||||
|
||||
@override
|
||||
Widget? trailing(BuildContext context) {
|
||||
if (!isEditable) {
|
||||
if (!contactListViewModel.isEditable) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -60,11 +58,14 @@ class ContactListPage extends BasePage {
|
|||
|
||||
@override
|
||||
Widget body(BuildContext context) {
|
||||
|
||||
return Container(
|
||||
padding: EdgeInsets.only(top: 20.0, bottom: 20.0),
|
||||
child: Observer(
|
||||
builder: (_) {
|
||||
return CollapsibleSectionList(
|
||||
builder: (_) {
|
||||
final contacts = contactListViewModel.contactsToShow;
|
||||
final walletContacts = contactListViewModel.walletContactsToShow;
|
||||
return CollapsibleSectionList(
|
||||
context: context,
|
||||
sectionCount: 2,
|
||||
themeColor: Theme.of(context).primaryTextTheme.headline6!.color!,
|
||||
|
@ -82,35 +83,37 @@ class ContactListPage extends BasePage {
|
|||
child: Text(title, style: TextStyle(fontSize: 36)));
|
||||
},
|
||||
itemCounter: (int sectionIndex) => sectionIndex == 0
|
||||
? contactListViewModel.walletContacts.length
|
||||
: contactListViewModel.contacts.length,
|
||||
? walletContacts.length
|
||||
: contacts.length,
|
||||
itemBuilder: (_, sectionIndex, index) {
|
||||
if (sectionIndex == 0) {
|
||||
final walletInfo = contactListViewModel.walletContacts[index];
|
||||
final walletInfo = walletContacts[index];
|
||||
return generateRaw(context, walletInfo);
|
||||
}
|
||||
|
||||
final contact = contactListViewModel.contacts[index];
|
||||
final contact = contacts[index];
|
||||
final content = generateRaw(context, contact);
|
||||
return !isEditable
|
||||
? content
|
||||
: Slidable(
|
||||
return contactListViewModel.isEditable
|
||||
? Slidable(
|
||||
key: Key('${contact.key}'),
|
||||
endActionPane: _actionPane(context, contact),
|
||||
child: content,
|
||||
);
|
||||
)
|
||||
: content;
|
||||
},
|
||||
);
|
||||
},
|
||||
));
|
||||
);})
|
||||
);
|
||||
}
|
||||
|
||||
Widget generateRaw(BuildContext context, ContactBase contact) {
|
||||
final image = _getCurrencyImage(contact.type);
|
||||
final image = contact.type.iconPath;
|
||||
final currencyIcon = image != null ? Image.asset(image, height: 24, width: 24)
|
||||
: const SizedBox(height: 24, width: 24);
|
||||
|
||||
|
||||
return GestureDetector(
|
||||
onTap: () async {
|
||||
if (!isEditable) {
|
||||
if (!contactListViewModel.isEditable) {
|
||||
Navigator.of(context).pop(contact);
|
||||
return;
|
||||
}
|
||||
|
@ -131,12 +134,10 @@ class ContactListPage extends BasePage {
|
|||
mainAxisSize: MainAxisSize.min,
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
image ?? Offstage(),
|
||||
currencyIcon,
|
||||
Expanded(
|
||||
child: Padding(
|
||||
padding: image != null
|
||||
? EdgeInsets.only(left: 12)
|
||||
: EdgeInsets.only(left: 0),
|
||||
padding: EdgeInsets.only(left: 12),
|
||||
child: Text(
|
||||
contact.name,
|
||||
style: TextStyle(
|
||||
|
@ -152,69 +153,6 @@ class ContactListPage extends BasePage {
|
|||
);
|
||||
}
|
||||
|
||||
Image? _getCurrencyImage(CryptoCurrency currency) {
|
||||
Image? image;
|
||||
|
||||
switch (currency) {
|
||||
case CryptoCurrency.xmr:
|
||||
image =
|
||||
Image.asset('assets/images/monero_logo.png', height: 24, width: 24);
|
||||
break;
|
||||
case CryptoCurrency.ada:
|
||||
image = Image.asset('assets/images/ada.png', height: 24, width: 24);
|
||||
break;
|
||||
case CryptoCurrency.bch:
|
||||
image = Image.asset('assets/images/bch.png', height: 24, width: 24);
|
||||
break;
|
||||
case CryptoCurrency.bnb:
|
||||
image = Image.asset('assets/images/bnb.png', height: 24, width: 24);
|
||||
break;
|
||||
case CryptoCurrency.btc:
|
||||
image = Image.asset('assets/images/bitcoin.png', height: 24, width: 24);
|
||||
break;
|
||||
case CryptoCurrency.dai:
|
||||
image = Image.asset('assets/images/dai.png', height: 24, width: 24);
|
||||
break;
|
||||
case CryptoCurrency.dash:
|
||||
image = Image.asset('assets/images/dash.png', height: 24, width: 24);
|
||||
break;
|
||||
case CryptoCurrency.eos:
|
||||
image = Image.asset('assets/images/eos.png', height: 24, width: 24);
|
||||
break;
|
||||
case CryptoCurrency.eth:
|
||||
image = Image.asset('assets/images/eth.png', height: 24, width: 24);
|
||||
break;
|
||||
case CryptoCurrency.ltc:
|
||||
image =
|
||||
Image.asset('assets/images/litecoin.png', height: 24, width: 24);
|
||||
break;
|
||||
case CryptoCurrency.nano:
|
||||
image = Image.asset('assets/images/nano.png', height: 24, width: 24);
|
||||
break;
|
||||
case CryptoCurrency.trx:
|
||||
image = Image.asset('assets/images/trx.png', height: 24, width: 24);
|
||||
break;
|
||||
case CryptoCurrency.usdt:
|
||||
image = Image.asset('assets/images/usdt.png', height: 24, width: 24);
|
||||
break;
|
||||
case CryptoCurrency.usdterc20:
|
||||
image = Image.asset('assets/images/usdterc.png', height: 24, width: 24);
|
||||
break;
|
||||
case CryptoCurrency.xlm:
|
||||
image = Image.asset('assets/images/xlm.png', height: 24, width: 24);
|
||||
break;
|
||||
case CryptoCurrency.xrp:
|
||||
image = Image.asset('assets/images/xrp.png', height: 24, width: 24);
|
||||
break;
|
||||
case CryptoCurrency.xhv:
|
||||
image = Image.asset('assets/images/haven_logo.png', height: 24, width: 24);
|
||||
break;
|
||||
default:
|
||||
image = null;
|
||||
}
|
||||
return image;
|
||||
}
|
||||
|
||||
Future<bool> showAlertDialog(BuildContext context) async {
|
||||
return await showPopUp<bool>(
|
||||
context: context,
|
||||
|
|
|
@ -60,7 +60,7 @@ class DashboardPage extends BasePage {
|
|||
Widget middle(BuildContext context) {
|
||||
return SyncIndicator(dashboardViewModel: walletViewModel,
|
||||
onTap: () => Navigator.of(context, rootNavigator: true)
|
||||
.pushNamed(Routes.nodeList));
|
||||
.pushNamed(Routes.connectionSync));
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -315,6 +315,8 @@ class DashboardPage extends BasePage {
|
|||
}
|
||||
|
||||
Future<void> _onClickExchangeButton(BuildContext context) async {
|
||||
await Navigator.of(context).pushNamed(Routes.exchange);
|
||||
if (walletViewModel.isEnabledExchangeAction) {
|
||||
await Navigator.of(context).pushNamed(Routes.exchange);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,81 +1,64 @@
|
|||
import 'package:cake_wallet/palette.dart';
|
||||
import 'package:cake_wallet/src/screens/dashboard/wallet_menu_item.dart';
|
||||
import 'package:cake_wallet/utils/show_pop_up.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:cake_wallet/routes.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/src/screens/auth/auth_page.dart';
|
||||
import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart';
|
||||
import 'package:cake_wallet/wallet_type_utils.dart';
|
||||
|
||||
// FIXME: terrible design
|
||||
|
||||
class WalletMenu {
|
||||
WalletMenu(this.context, this.reconnect, this.hasRescan) : items = [] {
|
||||
items.addAll([
|
||||
WalletMenuItem(
|
||||
title: S.current.reconnect,
|
||||
image: Image.asset('assets/images/reconnect_menu.png',
|
||||
height: 16, width: 16),
|
||||
handler: () => _presentReconnectAlert(context)),
|
||||
if (hasRescan)
|
||||
WalletMenuItem(
|
||||
title: S.current.rescan,
|
||||
image: Image.asset('assets/images/filter_icon.png',
|
||||
height: 16, width: 16, color: Palette.darkBlue),
|
||||
handler: () => Navigator.of(context).pushNamed(Routes.rescan)),
|
||||
WalletMenuItem(
|
||||
title: S.current.wallets,
|
||||
image: Image.asset('assets/images/wallet_menu.png',
|
||||
height: 16, width: 16),
|
||||
handler: () => Navigator.of(context).pushNamed(Routes.walletList)),
|
||||
WalletMenuItem(
|
||||
title: S.current.nodes,
|
||||
image: Image.asset('assets/images/nodes_menu.png',
|
||||
height: 16, width: 16),
|
||||
handler: () => Navigator.of(context).pushNamed(Routes.nodeList)),
|
||||
WalletMenuItem(
|
||||
title: S.current.show_keys,
|
||||
image:
|
||||
Image.asset('assets/images/key_menu.png', height: 16, width: 16),
|
||||
handler: () {
|
||||
Navigator.of(context).pushNamed(Routes.auth,
|
||||
arguments: (bool isAuthenticatedSuccessfully, AuthPageState auth) {
|
||||
if (isAuthenticatedSuccessfully) {
|
||||
auth.close(route: Routes.showKeys);
|
||||
}
|
||||
});
|
||||
}),
|
||||
WalletMenuItem(
|
||||
title: S.current.address_book_menu,
|
||||
image: Image.asset('assets/images/open_book_menu.png',
|
||||
height: 16, width: 16),
|
||||
handler: () => Navigator.of(context).pushNamed(Routes.addressBook)),
|
||||
WalletMenuItem(
|
||||
title: S.current.backup,
|
||||
image: Image.asset('assets/images/restore_wallet.png',
|
||||
height: 16,
|
||||
width: 16,
|
||||
color: Palette.darkBlue),
|
||||
handler: () {
|
||||
Navigator.of(context).pushNamed(
|
||||
Routes.auth,
|
||||
arguments: (bool isAuthenticatedSuccessfully, AuthPageState auth) {
|
||||
if (isAuthenticatedSuccessfully) {
|
||||
auth.close(route:Routes.backup);
|
||||
}
|
||||
});
|
||||
}),
|
||||
WalletMenuItem(
|
||||
title: S.current.settings_title,
|
||||
image: Image.asset('assets/images/settings_menu.png',
|
||||
height: 16, width: 16),
|
||||
handler: () => Navigator.of(context).pushNamed(Routes.settings)),
|
||||
WalletMenuItem(
|
||||
title: S.current.settings_support,
|
||||
image: Image.asset('assets/images/question_mark.png',
|
||||
height: 16, width: 16, color: Palette.darkBlue),
|
||||
handler: () => Navigator.of(context).pushNamed(Routes.support)),
|
||||
WalletMenuItem(
|
||||
title: S.current.connection_sync,
|
||||
image: Image.asset('assets/images/nodes_menu.png',
|
||||
height: 16, width: 16),
|
||||
handler: () => Navigator.of(context).pushNamed(Routes.connectionSync),
|
||||
),
|
||||
WalletMenuItem(
|
||||
title: S.current.wallets,
|
||||
image: Image.asset('assets/images/wallet_menu.png',
|
||||
height: 16, width: 16),
|
||||
handler: () => Navigator.of(context).pushNamed(Routes.walletList),
|
||||
),
|
||||
WalletMenuItem(
|
||||
title: S.current.security_and_backup,
|
||||
image:
|
||||
Image.asset('assets/images/key_menu.png', height: 16, width: 16),
|
||||
handler: () {
|
||||
Navigator.of(context).pushNamed(Routes.securityBackupPage);
|
||||
}),
|
||||
WalletMenuItem(
|
||||
title: S.current.privacy,
|
||||
image:
|
||||
Image.asset('assets/images/eye_menu.png', height: 16, width: 16),
|
||||
handler: () {
|
||||
Navigator.of(context).pushNamed(Routes.privacyPage);
|
||||
}),
|
||||
WalletMenuItem(
|
||||
title: S.current.address_book_menu,
|
||||
image: Image.asset('assets/images/open_book_menu.png',
|
||||
height: 16, width: 16),
|
||||
handler: () => Navigator.of(context).pushNamed(Routes.addressBook),
|
||||
),
|
||||
WalletMenuItem(
|
||||
title: S.current.display_settings,
|
||||
image: Image.asset('assets/images/eye_menu.png',
|
||||
height: 16, width: 16),
|
||||
handler: () => Navigator.of(context).pushNamed(Routes.displaySettingsPage),
|
||||
),
|
||||
WalletMenuItem(
|
||||
title: S.current.other_settings,
|
||||
image: Image.asset('assets/images/settings_menu.png',
|
||||
height: 16, width: 16),
|
||||
handler: () => Navigator.of(context).pushNamed(Routes.otherSettingsPage),
|
||||
),
|
||||
WalletMenuItem(
|
||||
title: S.current.settings_support,
|
||||
image: Image.asset('assets/images/question_mark.png',
|
||||
height: 16, width: 16, color: Palette.darkBlue),
|
||||
handler: () => Navigator.of(context).pushNamed(Routes.support),
|
||||
),
|
||||
]);
|
||||
}
|
||||
|
||||
|
@ -86,23 +69,6 @@ class WalletMenu {
|
|||
|
||||
void action(int index) {
|
||||
final item = items[index];
|
||||
item?.handler();
|
||||
}
|
||||
|
||||
Future<void> _presentReconnectAlert(BuildContext context) async {
|
||||
await showPopUp<void>(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return AlertWithTwoActions(
|
||||
alertTitle: S.of(context).reconnection,
|
||||
alertContent: S.of(context).reconnect_alert_text,
|
||||
rightButtonText: S.of(context).ok,
|
||||
leftButtonText: S.of(context).cancel,
|
||||
actionRightButton: () async {
|
||||
Navigator.of(context).pop();
|
||||
await reconnect?.call();
|
||||
},
|
||||
actionLeftButton: () => Navigator.of(context).pop());
|
||||
});
|
||||
item.handler();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -395,7 +395,8 @@ class ExchangeCardState extends State<ExchangeCard> {
|
|||
buttonColor: widget.addressButtonsColor,
|
||||
validator: widget.addressTextFieldValidator,
|
||||
onPushPasteButton: widget.onPushPasteButton,
|
||||
onPushAddressBookButton: widget.onPushAddressBookButton
|
||||
onPushAddressBookButton: widget.onPushAddressBookButton,
|
||||
selectedCurrency: _selectedCurrency
|
||||
),
|
||||
|
||||
)
|
||||
|
|
|
@ -118,7 +118,7 @@ class IoniaManageCardsPage extends BasePage {
|
|||
width: 32,
|
||||
padding: EdgeInsets.all(8),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white.withOpacity(0.15),
|
||||
color: Theme.of(context).textTheme!.headline6!.backgroundColor!,
|
||||
border: Border.all(
|
||||
color: Colors.white.withOpacity(0.2),
|
||||
),
|
||||
|
|
|
@ -20,7 +20,7 @@ class IoniaFilterModal extends StatelessWidget {
|
|||
padding: EdgeInsets.all(10),
|
||||
child: Image.asset(
|
||||
'assets/images/mini_search_icon.png',
|
||||
color: Theme.of(context).accentColor,
|
||||
color: Theme.of(context).textTheme.subtitle2!.color!,
|
||||
),
|
||||
);
|
||||
return Scaffold(
|
||||
|
@ -53,7 +53,7 @@ class IoniaFilterModal extends StatelessWidget {
|
|||
prefixIcon: searchIcon,
|
||||
hintText: S.of(context).search_category,
|
||||
contentPadding: EdgeInsets.only(bottom: 5),
|
||||
fillColor: Theme.of(context).textTheme!.subtitle1!.backgroundColor!,
|
||||
fillColor: Theme.of(context).primaryTextTheme!.caption!.decorationColor!.withOpacity(0.5),
|
||||
border: OutlineInputBorder(
|
||||
borderSide: BorderSide.none,
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
|
|
104
lib/src/screens/new_wallet/advanced_privacy_settings_page.dart
Normal file
104
lib/src/screens/new_wallet/advanced_privacy_settings_page.dart
Normal file
|
@ -0,0 +1,104 @@
|
|||
import 'package:cake_wallet/src/screens/nodes/widgets/node_form.dart';
|
||||
import 'package:cake_wallet/src/screens/settings/widgets/settings_switcher_cell.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';
|
||||
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/src/screens/base_page.dart';
|
||||
import 'package:cake_wallet/src/widgets/primary_button.dart';
|
||||
import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart';
|
||||
|
||||
class AdvancedPrivacySettingsPage extends BasePage {
|
||||
AdvancedPrivacySettingsPage(this.advancedPrivacySettingsViewModel, this.nodeViewModel);
|
||||
|
||||
final AdvancedPrivacySettingsViewModel advancedPrivacySettingsViewModel;
|
||||
final NodeCreateOrEditViewModel nodeViewModel;
|
||||
|
||||
@override
|
||||
String get title => S.current.privacy_settings;
|
||||
|
||||
@override
|
||||
Widget body(BuildContext context) =>
|
||||
AdvancedPrivacySettingsBody(advancedPrivacySettingsViewModel, nodeViewModel);
|
||||
}
|
||||
|
||||
class AdvancedPrivacySettingsBody extends StatefulWidget {
|
||||
const AdvancedPrivacySettingsBody(this.privacySettingsViewModel, this.nodeViewModel, {Key? key})
|
||||
: super(key: key);
|
||||
|
||||
final AdvancedPrivacySettingsViewModel privacySettingsViewModel;
|
||||
final NodeCreateOrEditViewModel nodeViewModel;
|
||||
|
||||
@override
|
||||
_AdvancedPrivacySettingsBodyState createState() => _AdvancedPrivacySettingsBodyState();
|
||||
}
|
||||
|
||||
class _AdvancedPrivacySettingsBodyState extends State<AdvancedPrivacySettingsBody> {
|
||||
_AdvancedPrivacySettingsBodyState();
|
||||
|
||||
final _formKey = GlobalKey<FormState>();
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
padding: EdgeInsets.only(top: 24),
|
||||
child: ScrollableWithBottomSection(
|
||||
contentPadding: EdgeInsets.only(bottom: 24),
|
||||
content: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
...widget.privacySettingsViewModel.settings.map(
|
||||
(item) => Observer(
|
||||
builder: (_) => SettingsSwitcherCell(
|
||||
title: item.title,
|
||||
value: item.value(),
|
||||
onValueChange: item.onValueChange,
|
||||
),
|
||||
),
|
||||
),
|
||||
Observer(
|
||||
builder: (_) {
|
||||
if (widget.privacySettingsViewModel.addCustomNode) {
|
||||
return Padding(
|
||||
padding: EdgeInsets.only(left: 24, right: 24, top: 24),
|
||||
child: NodeForm(
|
||||
formKey: _formKey,
|
||||
nodeViewModel: widget.nodeViewModel,
|
||||
),
|
||||
);
|
||||
}
|
||||
return const SizedBox();
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
bottomSectionPadding: EdgeInsets.all(24),
|
||||
bottomSection: Column(
|
||||
children: [
|
||||
LoadingPrimaryButton(
|
||||
onPressed: () {
|
||||
widget.nodeViewModel.save(saveAsCurrent: true);
|
||||
Navigator.pop(context);
|
||||
},
|
||||
text: S.of(context).continue_text,
|
||||
color: Theme.of(context).accentTextTheme.bodyText1!.color!,
|
||||
textColor: Colors.white,
|
||||
),
|
||||
const SizedBox(height: 25),
|
||||
Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: MediaQuery.of(context).size.width * 0.15),
|
||||
child: Text(
|
||||
S.of(context).settings_can_be_changed_later,
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
color: Theme.of(context).accentTextTheme.headline2?.color,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -200,18 +200,30 @@ class _WalletNameFormState extends State<WalletNameForm> {
|
|||
]
|
||||
]),
|
||||
bottomSectionPadding:
|
||||
EdgeInsets.only(left: 24, right: 24, bottom: 24),
|
||||
bottomSection: Observer(
|
||||
builder: (context) {
|
||||
return LoadingPrimaryButton(
|
||||
onPressed: _confirmForm,
|
||||
text: S.of(context).seed_language_next,
|
||||
color: Colors.green,
|
||||
textColor: Colors.white,
|
||||
isLoading: _walletNewVM.state is IsExecutingState,
|
||||
isDisabled: _walletNewVM.name.isEmpty,
|
||||
);
|
||||
},
|
||||
EdgeInsets.all(24),
|
||||
bottomSection: Column(
|
||||
children: [
|
||||
Observer(
|
||||
builder: (context) {
|
||||
return LoadingPrimaryButton(
|
||||
onPressed: _confirmForm,
|
||||
text: S.of(context).seed_language_next,
|
||||
color: Colors.green,
|
||||
textColor: Colors.white,
|
||||
isLoading: _walletNewVM.state is IsExecutingState,
|
||||
isDisabled: _walletNewVM.name.isEmpty,
|
||||
);
|
||||
},
|
||||
),
|
||||
const SizedBox(height: 25),
|
||||
GestureDetector(
|
||||
onTap: () {
|
||||
Navigator.of(context)
|
||||
.pushNamed(Routes.advancedPrivacySettings, arguments: _walletNewVM.type);
|
||||
},
|
||||
child: Text(S.of(context).advanced_privacy_settings),
|
||||
),
|
||||
],
|
||||
)),
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,16 +1,13 @@
|
|||
import 'package:cake_wallet/core/execution_state.dart';
|
||||
import 'package:cake_wallet/src/screens/nodes/widgets/node_form.dart';
|
||||
import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
|
||||
import 'package:cake_wallet/src/widgets/standard_checkbox.dart';
|
||||
import 'package:cake_wallet/utils/show_pop_up.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||
import 'package:mobx/mobx.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/core/node_address_validator.dart';
|
||||
import 'package:cake_wallet/core/node_port_validator.dart';
|
||||
import 'package:cake_wallet/src/widgets/primary_button.dart';
|
||||
import 'package:cake_wallet/src/widgets/base_text_form_field.dart';
|
||||
import 'package:cake_wallet/src/screens/base_page.dart';
|
||||
import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart';
|
||||
import 'package:cake_wallet/view_model/node_list/node_create_or_edit_view_model.dart';
|
||||
|
@ -108,76 +105,10 @@ class NodeCreateOrEditPage extends BasePage {
|
|||
padding: EdgeInsets.only(left: 24, right: 24),
|
||||
child: ScrollableWithBottomSection(
|
||||
contentPadding: EdgeInsets.only(bottom: 24.0),
|
||||
content: Form(
|
||||
key: _formKey,
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
Row(
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: BaseTextFormField(
|
||||
controller: _addressController,
|
||||
hintText: S.of(context).node_address,
|
||||
validator: NodeAddressValidator(),
|
||||
)
|
||||
)
|
||||
],
|
||||
),
|
||||
SizedBox(height: 10.0),
|
||||
Row(
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: BaseTextFormField(
|
||||
controller: _portController,
|
||||
hintText: S.of(context).node_port,
|
||||
keyboardType: TextInputType.numberWithOptions(
|
||||
signed: false, decimal: false),
|
||||
validator: NodePortValidator(),
|
||||
)
|
||||
)
|
||||
],
|
||||
),
|
||||
SizedBox(height: 10.0),
|
||||
if (nodeCreateOrEditViewModel.hasAuthCredentials) ...[
|
||||
Row(
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: BaseTextFormField(
|
||||
controller: _loginController,
|
||||
hintText: S.of(context).login,
|
||||
)
|
||||
)
|
||||
],
|
||||
),
|
||||
SizedBox(height: 10.0),
|
||||
Row(
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: BaseTextFormField(
|
||||
controller: _passwordController,
|
||||
hintText: S.of(context).password,
|
||||
)
|
||||
)
|
||||
],
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: 20),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
children: [
|
||||
Observer(
|
||||
builder: (_) => StandardCheckbox(
|
||||
value: nodeCreateOrEditViewModel.useSSL,
|
||||
onChanged: (value) =>
|
||||
nodeCreateOrEditViewModel.useSSL = value,
|
||||
caption: S.of(context).use_ssl,
|
||||
))
|
||||
],
|
||||
))
|
||||
]
|
||||
],
|
||||
)),
|
||||
content: NodeForm(
|
||||
formKey: _formKey,
|
||||
nodeViewModel: nodeCreateOrEditViewModel,
|
||||
),
|
||||
bottomSectionPadding: EdgeInsets.only(bottom: 24),
|
||||
bottomSection: Observer(
|
||||
builder: (_) => Row(
|
||||
|
|
|
@ -1,166 +0,0 @@
|
|||
import 'package:cake_wallet/utils/show_pop_up.dart';
|
||||
import 'package:cw_core/node.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||
import 'package:cake_wallet/routes.dart';
|
||||
import 'package:cake_wallet/palette.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/src/screens/base_page.dart';
|
||||
import 'package:cake_wallet/src/screens/nodes/widgets/node_list_row.dart';
|
||||
import 'package:cake_wallet/src/widgets/standard_list.dart';
|
||||
import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart';
|
||||
import 'package:cake_wallet/view_model/node_list/node_list_view_model.dart';
|
||||
import 'package:flutter_slidable/flutter_slidable.dart';
|
||||
|
||||
class NodeListPage extends BasePage {
|
||||
NodeListPage(this.nodeListViewModel);
|
||||
|
||||
@override
|
||||
String get title => S.current.nodes;
|
||||
|
||||
final NodeListViewModel nodeListViewModel;
|
||||
|
||||
@override
|
||||
Widget trailing(context) {
|
||||
return Container(
|
||||
height: 32,
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.all(Radius.circular(16)),
|
||||
color: Theme.of(context).accentTextTheme.caption!.color!),
|
||||
child: ButtonTheme(
|
||||
minWidth: double.minPositive,
|
||||
child: TextButton(
|
||||
onPressed: () async {
|
||||
await showPopUp<void>(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return AlertWithTwoActions(
|
||||
alertTitle: S.of(context).node_reset_settings_title,
|
||||
alertContent:
|
||||
S.of(context).nodes_list_reset_to_default_message,
|
||||
rightButtonText: S.of(context).reset,
|
||||
leftButtonText: S.of(context).cancel,
|
||||
actionRightButton: () async {
|
||||
Navigator.of(context).pop();
|
||||
await nodeListViewModel.reset();
|
||||
},
|
||||
actionLeftButton: () => Navigator.of(context).pop());
|
||||
});
|
||||
},
|
||||
child: Text(
|
||||
S.of(context).reset,
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 14.0,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Palette.blueCraiola),
|
||||
)),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget body(BuildContext context) {
|
||||
return Container(
|
||||
padding: EdgeInsets.only(top: 10),
|
||||
child: Observer(
|
||||
builder: (BuildContext context) {
|
||||
return SectionStandardList(
|
||||
sectionCount: 2,
|
||||
context: context,
|
||||
itemCounter: (int sectionIndex) {
|
||||
if (sectionIndex == 0) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return nodeListViewModel.nodes.length;
|
||||
},
|
||||
itemBuilder: (_, sectionIndex, index) {
|
||||
if (sectionIndex == 0) {
|
||||
return NodeHeaderListRow(
|
||||
title: S.of(context).add_new_node,
|
||||
onTap: (_) async => await Navigator.of(context)
|
||||
.pushNamed(Routes.newNode));
|
||||
}
|
||||
|
||||
final node = nodeListViewModel.nodes[index];
|
||||
final isSelected =
|
||||
node.keyIndex == nodeListViewModel.currentNode.keyIndex;
|
||||
final nodeListRow = NodeListRow(
|
||||
title: node.uriRaw,
|
||||
isSelected: isSelected,
|
||||
isAlive: node.requestNode(),
|
||||
onTap: (_) async {
|
||||
if (isSelected) {
|
||||
return;
|
||||
}
|
||||
|
||||
await showPopUp<void>(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return AlertWithTwoActions(
|
||||
alertTitle:
|
||||
S.of(context).change_current_node_title,
|
||||
alertContent: S
|
||||
.of(context)
|
||||
.change_current_node(node.uriRaw),
|
||||
leftButtonText: S.of(context).cancel,
|
||||
rightButtonText: S.of(context).change,
|
||||
actionLeftButton: () =>
|
||||
Navigator.of(context).pop(),
|
||||
actionRightButton: () async {
|
||||
await nodeListViewModel.setAsCurrent(node);
|
||||
Navigator.of(context).pop();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
final dismissibleRow = Slidable(
|
||||
key: Key('${node.keyIndex}'),
|
||||
startActionPane: _actionPane(context, node),
|
||||
endActionPane: _actionPane(context, node),
|
||||
child: nodeListRow,
|
||||
);
|
||||
|
||||
return isSelected ? nodeListRow : dismissibleRow;
|
||||
});
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
ActionPane _actionPane(BuildContext context, Node node) => ActionPane(
|
||||
motion: const ScrollMotion(),
|
||||
extentRatio: 0.3,
|
||||
children: [
|
||||
SlidableAction(
|
||||
onPressed: (context) 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));
|
||||
}) ??
|
||||
false;
|
||||
|
||||
if (confirmed) {
|
||||
await nodeListViewModel.delete(node);
|
||||
}
|
||||
},
|
||||
backgroundColor: Colors.red,
|
||||
foregroundColor: Colors.white,
|
||||
icon: CupertinoIcons.delete,
|
||||
label: S.of(context).delete,
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
151
lib/src/screens/nodes/widgets/node_form.dart
Normal file
151
lib/src/screens/nodes/widgets/node_form.dart
Normal file
|
@ -0,0 +1,151 @@
|
|||
import 'package:cake_wallet/core/node_address_validator.dart';
|
||||
import 'package:cake_wallet/core/node_port_validator.dart';
|
||||
import 'package:cake_wallet/src/widgets/base_text_form_field.dart';
|
||||
import 'package:cake_wallet/src/widgets/standard_checkbox.dart';
|
||||
import 'package:cake_wallet/view_model/node_list/node_create_or_edit_view_model.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:mobx/mobx.dart';
|
||||
|
||||
class NodeForm extends StatelessWidget {
|
||||
NodeForm({
|
||||
required this.nodeViewModel,
|
||||
required this.formKey,
|
||||
}) : _addressController = TextEditingController(),
|
||||
_portController = TextEditingController(),
|
||||
_loginController = TextEditingController(),
|
||||
_passwordController = TextEditingController() {
|
||||
reaction((_) => nodeViewModel.address, (String address) {
|
||||
if (address != _addressController.text) {
|
||||
_addressController.text = address;
|
||||
}
|
||||
});
|
||||
|
||||
reaction((_) => nodeViewModel.port, (String port) {
|
||||
if (port != _portController.text) {
|
||||
_portController.text = port;
|
||||
}
|
||||
});
|
||||
|
||||
if (nodeViewModel.hasAuthCredentials) {
|
||||
reaction((_) => nodeViewModel.login, (String login) {
|
||||
if (login != _loginController.text) {
|
||||
_loginController.text = login;
|
||||
}
|
||||
});
|
||||
|
||||
reaction((_) => nodeViewModel.password, (String password) {
|
||||
if (password != _passwordController.text) {
|
||||
_passwordController.text = password;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
_addressController
|
||||
.addListener(() => nodeViewModel.address = _addressController.text);
|
||||
_portController
|
||||
.addListener(() => nodeViewModel.port = _portController.text);
|
||||
_loginController
|
||||
.addListener(() => nodeViewModel.login = _loginController.text);
|
||||
_passwordController
|
||||
.addListener(() => nodeViewModel.password = _passwordController.text);
|
||||
}
|
||||
|
||||
final NodeCreateOrEditViewModel nodeViewModel;
|
||||
final GlobalKey<FormState> formKey;
|
||||
|
||||
final TextEditingController _addressController;
|
||||
final TextEditingController _portController;
|
||||
final TextEditingController _loginController;
|
||||
final TextEditingController _passwordController;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Form(
|
||||
key: formKey,
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
Row(
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: BaseTextFormField(
|
||||
controller: _addressController,
|
||||
hintText: S.of(context).node_address,
|
||||
validator: NodeAddressValidator(),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
SizedBox(height: 10.0),
|
||||
Row(
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: BaseTextFormField(
|
||||
controller: _portController,
|
||||
hintText: S.of(context).node_port,
|
||||
keyboardType: TextInputType.numberWithOptions(
|
||||
signed: false, decimal: false),
|
||||
validator: NodePortValidator(),
|
||||
))
|
||||
],
|
||||
),
|
||||
SizedBox(height: 10.0),
|
||||
if (nodeViewModel.hasAuthCredentials) ...[
|
||||
Row(
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: BaseTextFormField(
|
||||
controller: _loginController,
|
||||
hintText: S.of(context).login,
|
||||
))
|
||||
],
|
||||
),
|
||||
SizedBox(height: 10.0),
|
||||
Row(
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: BaseTextFormField(
|
||||
controller: _passwordController,
|
||||
hintText: S.of(context).password,
|
||||
))
|
||||
],
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: 20),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
children: [
|
||||
Observer(
|
||||
builder: (_) => StandardCheckbox(
|
||||
value: nodeViewModel.useSSL,
|
||||
onChanged: (value) => nodeViewModel.useSSL = value,
|
||||
caption: S.of(context).use_ssl,
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: 20),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
children: [
|
||||
Observer(
|
||||
builder: (_) => StandardCheckbox(
|
||||
value: nodeViewModel.trusted,
|
||||
onChanged: (value) => nodeViewModel.trusted = value,
|
||||
caption: S.of(context).trusted,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
]
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -37,7 +37,10 @@ class NodeHeaderListRow extends StandardListRow {
|
|||
|
||||
@override
|
||||
Widget buildTrailing(BuildContext context) {
|
||||
return Icon(Icons.add,
|
||||
color: Theme.of(context).accentTextTheme!.subtitle1!.color!, size: 24.0);
|
||||
return SizedBox(
|
||||
width: 20,
|
||||
child: Icon(Icons.add,
|
||||
color: Theme.of(context).accentTextTheme!.subtitle1!.color!, size: 24.0),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,7 +9,6 @@ class QrPainter extends CustomPainter {
|
|||
this.errorCorrectionLevel,
|
||||
) : this._qr = QrCode(version, errorCorrectionLevel)..addData(data) {
|
||||
_p.color = this.color;
|
||||
_qr.addData(data);
|
||||
_qrImage = QrImage(_qr);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
import 'dart:ui';
|
||||
import 'package:cake_wallet/entities/fiat_currency.dart';
|
||||
import 'package:cake_wallet/src/screens/dashboard/widgets/sync_indicator_icon.dart';
|
||||
import 'package:cake_wallet/src/screens/send/widgets/send_card.dart';
|
||||
|
@ -6,8 +5,6 @@ import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart';
|
|||
import 'package:cake_wallet/src/widgets/picker.dart';
|
||||
import 'package:cake_wallet/src/widgets/template_tile.dart';
|
||||
import 'package:cake_wallet/view_model/send/output.dart';
|
||||
import 'package:cake_wallet/view_model/settings/settings_view_model.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||
import 'package:mobx/mobx.dart';
|
||||
|
@ -28,13 +25,11 @@ import 'package:smooth_page_indicator/smooth_page_indicator.dart';
|
|||
import 'package:cw_core/crypto_currency.dart';
|
||||
|
||||
class SendPage extends BasePage {
|
||||
SendPage({required this.sendViewModel,required this.settingsViewModel }) : _formKey = GlobalKey<FormState>(),fiatFromSettings = settingsViewModel.fiatCurrency;
|
||||
SendPage({required this.sendViewModel}) : _formKey = GlobalKey<FormState>();
|
||||
|
||||
final SendViewModel sendViewModel;
|
||||
final SettingsViewModel settingsViewModel;
|
||||
final GlobalKey<FormState> _formKey;
|
||||
final controller = PageController(initialPage: 0);
|
||||
final FiatCurrency fiatFromSettings ;
|
||||
|
||||
bool _effectsInstalled = false;
|
||||
|
||||
|
@ -55,7 +50,7 @@ class SendPage extends BasePage {
|
|||
|
||||
@override
|
||||
void onClose(BuildContext context) {
|
||||
settingsViewModel.setFiatCurrency(fiatFromSettings);
|
||||
sendViewModel.onClose();
|
||||
Navigator.of(context).pop();
|
||||
}
|
||||
|
||||
|
@ -236,7 +231,7 @@ class SendPage extends BasePage {
|
|||
if(template.isCurrencySelected){
|
||||
output.setCryptoAmount(template.amount);
|
||||
}else{
|
||||
settingsViewModel.setFiatCurrency(fiatFromTemplate);
|
||||
sendViewModel.setFiatCurrency(fiatFromTemplate);
|
||||
output.setFiatAmount(template.amountFiat);
|
||||
}
|
||||
output.resetParsedAddress();
|
||||
|
|
|
@ -1,11 +1,10 @@
|
|||
import 'dart:ui';
|
||||
import 'package:cake_wallet/entities/priority_for_wallet_type.dart';
|
||||
import 'package:cake_wallet/utils/payment_request.dart';
|
||||
import 'package:cw_core/transaction_priority.dart';
|
||||
import 'package:cake_wallet/routes.dart';
|
||||
import 'package:cake_wallet/src/widgets/keyboard_done_button.dart';
|
||||
import 'package:cake_wallet/src/widgets/picker.dart';
|
||||
import 'package:cake_wallet/view_model/send/output.dart';
|
||||
import 'package:cake_wallet/view_model/settings/settings_view_model.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||
|
@ -155,6 +154,7 @@ class SendCardState extends State<SendCard>
|
|||
await output.fetchParsedAddress(context);
|
||||
},
|
||||
validator: validator,
|
||||
selectedCurrency: sendViewModel.currency,
|
||||
);
|
||||
}),
|
||||
if (output.isParsedAddress) Padding(
|
||||
|
|
155
lib/src/screens/settings/connection_sync_page.dart
Normal file
155
lib/src/screens/settings/connection_sync_page.dart
Normal file
|
@ -0,0 +1,155 @@
|
|||
import 'package:cake_wallet/src/screens/settings/widgets/settings_cell_with_arrow.dart';
|
||||
import 'package:cake_wallet/utils/show_pop_up.dart';
|
||||
import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart';
|
||||
import 'package:cw_core/node.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||
import 'package:cake_wallet/routes.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/src/screens/base_page.dart';
|
||||
import 'package:cake_wallet/src/screens/nodes/widgets/node_list_row.dart';
|
||||
import 'package:cake_wallet/src/widgets/standard_list.dart';
|
||||
import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart';
|
||||
import 'package:cake_wallet/view_model/node_list/node_list_view_model.dart';
|
||||
import 'package:flutter_slidable/flutter_slidable.dart';
|
||||
|
||||
class ConnectionSyncPage extends BasePage {
|
||||
ConnectionSyncPage(this.nodeListViewModel, this.dashboardViewModel);
|
||||
|
||||
@override
|
||||
String get title => S.current.connection_sync;
|
||||
|
||||
final NodeListViewModel nodeListViewModel;
|
||||
final DashboardViewModel dashboardViewModel;
|
||||
|
||||
@override
|
||||
Widget body(BuildContext context) {
|
||||
return Container(
|
||||
padding: EdgeInsets.only(top: 10),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
SettingsCellWithArrow(
|
||||
title: S.current.reconnect,
|
||||
handler: (context) => _presentReconnectAlert(context),
|
||||
),
|
||||
StandardListSeparator(padding: EdgeInsets.symmetric(horizontal: 24)),
|
||||
SettingsCellWithArrow(
|
||||
title: S.current.rescan,
|
||||
handler: (context) => Navigator.of(context).pushNamed(Routes.rescan),
|
||||
),
|
||||
StandardListSeparator(padding: EdgeInsets.symmetric(horizontal: 24)),
|
||||
NodeHeaderListRow(
|
||||
title: S.of(context).add_new_node,
|
||||
onTap: (_) async => await Navigator.of(context).pushNamed(Routes.newNode),
|
||||
),
|
||||
StandardListSeparator(padding: EdgeInsets.symmetric(horizontal: 24)),
|
||||
SizedBox(height: 100),
|
||||
Observer(
|
||||
builder: (BuildContext context) {
|
||||
return Flexible(
|
||||
child: SectionStandardList(
|
||||
sectionCount: 1,
|
||||
context: context,
|
||||
dividerPadding: EdgeInsets.symmetric(horizontal: 24),
|
||||
itemCounter: (int sectionIndex) {
|
||||
return nodeListViewModel.nodes.length;
|
||||
},
|
||||
itemBuilder: (_, sectionIndex, index) {
|
||||
final node = nodeListViewModel.nodes[index];
|
||||
final isSelected = node.keyIndex == nodeListViewModel.currentNode.keyIndex;
|
||||
final nodeListRow = NodeListRow(
|
||||
title: node.uriRaw,
|
||||
isSelected: isSelected,
|
||||
isAlive: node.requestNode(),
|
||||
onTap: (_) async {
|
||||
if (isSelected) {
|
||||
return;
|
||||
}
|
||||
|
||||
await showPopUp<void>(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return AlertWithTwoActions(
|
||||
alertTitle: S.of(context).change_current_node_title,
|
||||
alertContent: S.of(context).change_current_node(node.uriRaw),
|
||||
leftButtonText: S.of(context).cancel,
|
||||
rightButtonText: S.of(context).change,
|
||||
actionLeftButton: () => Navigator.of(context).pop(),
|
||||
actionRightButton: () async {
|
||||
await nodeListViewModel.setAsCurrent(node);
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
);
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
final dismissibleRow = Slidable(
|
||||
key: Key('${node.keyIndex}'),
|
||||
startActionPane: _actionPane(context, node),
|
||||
endActionPane: _actionPane(context, node),
|
||||
child: nodeListRow,
|
||||
);
|
||||
|
||||
return isSelected ? nodeListRow : dismissibleRow;
|
||||
},
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _presentReconnectAlert(BuildContext context) async {
|
||||
await showPopUp<void>(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return AlertWithTwoActions(
|
||||
alertTitle: S.of(context).reconnection,
|
||||
alertContent: S.of(context).reconnect_alert_text,
|
||||
rightButtonText: S.of(context).ok,
|
||||
leftButtonText: S.of(context).cancel,
|
||||
actionRightButton: () async {
|
||||
Navigator.of(context).pop();
|
||||
await dashboardViewModel.reconnect();
|
||||
},
|
||||
actionLeftButton: () => Navigator.of(context).pop());
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
ActionPane _actionPane(BuildContext context, Node node) => ActionPane(
|
||||
motion: const ScrollMotion(),
|
||||
extentRatio: 0.3,
|
||||
children: [
|
||||
SlidableAction(
|
||||
onPressed: (context) 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));
|
||||
}) ??
|
||||
false;
|
||||
|
||||
if (confirmed) {
|
||||
await nodeListViewModel.delete(node);
|
||||
}
|
||||
},
|
||||
backgroundColor: Colors.red,
|
||||
foregroundColor: Colors.white,
|
||||
icon: CupertinoIcons.delete,
|
||||
label: S.of(context).delete,
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
80
lib/src/screens/settings/display_settings_page.dart
Normal file
80
lib/src/screens/settings/display_settings_page.dart
Normal file
|
@ -0,0 +1,80 @@
|
|||
import 'package:cake_wallet/entities/fiat_currency.dart';
|
||||
import 'package:cake_wallet/entities/language_service.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/src/screens/base_page.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/theme_base.dart';
|
||||
import 'package:cake_wallet/themes/theme_list.dart';
|
||||
import 'package:cake_wallet/view_model/settings/choices_list_item.dart';
|
||||
import 'package:cake_wallet/view_model/settings/display_settings_view_model.dart';
|
||||
import 'package:cake_wallet/wallet_type_utils.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||
|
||||
class DisplaySettingsPage extends BasePage {
|
||||
DisplaySettingsPage(this._displaySettingsViewModel);
|
||||
|
||||
@override
|
||||
String get title => S.current.display_settings;
|
||||
|
||||
final DisplaySettingsViewModel _displaySettingsViewModel;
|
||||
|
||||
@override
|
||||
Widget body(BuildContext context) {
|
||||
return Observer(builder: (_) {
|
||||
return Container(
|
||||
padding: EdgeInsets.only(top: 10),
|
||||
child: Column(
|
||||
children: [
|
||||
SettingsSwitcherCell(
|
||||
title: S.current.settings_display_balance,
|
||||
value: _displaySettingsViewModel.shouldDisplayBalance,
|
||||
onValueChange: (_, bool value) {
|
||||
_displaySettingsViewModel.setShouldDisplayBalance(value);
|
||||
}),
|
||||
if (!isHaven)
|
||||
SettingsPickerCell<FiatCurrency>(
|
||||
title: S.current.settings_currency,
|
||||
searchHintText: S.current.search_currency,
|
||||
items: FiatCurrency.all,
|
||||
selectedItem: _displaySettingsViewModel.fiatCurrency,
|
||||
onItemSelected: (FiatCurrency currency) => _displaySettingsViewModel.setFiatCurrency(currency),
|
||||
images: FiatCurrency.all.map((e) => Image.asset("assets/images/flags/${e.countryCode}.png")).toList(),
|
||||
isGridView: true,
|
||||
matchingCriteria: (FiatCurrency currency, String searchText) {
|
||||
return currency.title.toLowerCase().contains(searchText) ||
|
||||
currency.fullName.toLowerCase().contains(searchText);
|
||||
},
|
||||
),
|
||||
SettingsPickerCell<String>(
|
||||
title: S.current.settings_change_language,
|
||||
searchHintText: S.current.search_language,
|
||||
items: LanguageService.list.keys.toList(),
|
||||
displayItem: (dynamic code) {
|
||||
return LanguageService.list[code] ?? '';
|
||||
},
|
||||
selectedItem: _displaySettingsViewModel.languageCode,
|
||||
onItemSelected: _displaySettingsViewModel.onLanguageSelected,
|
||||
images: LanguageService.list.keys
|
||||
.map((e) => Image.asset("assets/images/flags/${LanguageService.localeCountryCode[e]}.png"))
|
||||
.toList(),
|
||||
matchingCriteria: (String code, String searchText) {
|
||||
return LanguageService.list[code]?.toLowerCase().contains(searchText) ?? false;
|
||||
},
|
||||
),
|
||||
SettingsChoicesCell(
|
||||
ChoicesListItem<ThemeBase>(
|
||||
title: S.current.color_theme,
|
||||
items: ThemeList.all,
|
||||
selectedItem: _displaySettingsViewModel.theme,
|
||||
onItemSelected: (ThemeBase theme) => _displaySettingsViewModel.setTheme(theme),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
45
lib/src/screens/settings/other_settings_page.dart
Normal file
45
lib/src/screens/settings/other_settings_page.dart
Normal file
|
@ -0,0 +1,45 @@
|
|||
import 'package:cake_wallet/entities/priority_for_wallet_type.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/routes.dart';
|
||||
import 'package:cake_wallet/src/screens/base_page.dart';
|
||||
import 'package:cake_wallet/src/screens/settings/widgets/settings_cell_with_arrow.dart';
|
||||
import 'package:cake_wallet/src/screens/settings/widgets/settings_picker_cell.dart';
|
||||
import 'package:cake_wallet/src/screens/settings/widgets/settings_version_cell.dart';
|
||||
import 'package:cake_wallet/src/widgets/standard_list.dart';
|
||||
import 'package:cake_wallet/view_model/settings/other_settings_view_model.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||
|
||||
class OtherSettingsPage extends BasePage {
|
||||
OtherSettingsPage(this._otherSettingsViewModel);
|
||||
|
||||
@override
|
||||
String get title => S.current.other_settings;
|
||||
|
||||
final OtherSettingsViewModel _otherSettingsViewModel;
|
||||
|
||||
@override
|
||||
Widget body(BuildContext context) {
|
||||
return Observer(builder: (_) {
|
||||
return Container(
|
||||
padding: EdgeInsets.only(top: 10),
|
||||
child: Column(children: [
|
||||
SettingsPickerCell(
|
||||
title: S.current.settings_fee_priority,
|
||||
items: priorityForWalletType(_otherSettingsViewModel.walletType),
|
||||
displayItem: _otherSettingsViewModel.getDisplayPriority,
|
||||
selectedItem: _otherSettingsViewModel.transactionPriority,
|
||||
onItemSelected: _otherSettingsViewModel.onDisplayPrioritySelected,
|
||||
),
|
||||
SettingsCellWithArrow(
|
||||
title: S.current.settings_terms_and_conditions,
|
||||
handler: (BuildContext context) => Navigator.of(context).pushNamed(Routes.readDisclaimer),
|
||||
),
|
||||
StandardListSeparator(padding: EdgeInsets.symmetric(horizontal: 24)),
|
||||
Spacer(),
|
||||
SettingsVersionCell(title: S.of(context).version(_otherSettingsViewModel.currentVersion))
|
||||
]),
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
43
lib/src/screens/settings/privacy_page.dart
Normal file
43
lib/src/screens/settings/privacy_page.dart
Normal file
|
@ -0,0 +1,43 @@
|
|||
import 'package:cake_wallet/generated/i18n.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/privacy_settings_view_model.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||
|
||||
class PrivacyPage extends BasePage {
|
||||
PrivacyPage(this._privacySettingsViewModel);
|
||||
|
||||
@override
|
||||
String get title => S.current.privacy_settings;
|
||||
|
||||
final PrivacySettingsViewModel _privacySettingsViewModel;
|
||||
|
||||
@override
|
||||
Widget body(BuildContext context) {
|
||||
return Container(
|
||||
padding: EdgeInsets.only(top: 10),
|
||||
child: Observer(builder: (_) {
|
||||
return Observer(builder: (_) {
|
||||
return Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
SettingsSwitcherCell(
|
||||
title: S.current.disable_exchange,
|
||||
value: _privacySettingsViewModel.disableExchange,
|
||||
onValueChange: (BuildContext context, bool value) {
|
||||
_privacySettingsViewModel.setEnableExchange(value);
|
||||
}),
|
||||
SettingsSwitcherCell(
|
||||
title: S.current.settings_save_recipient_address,
|
||||
value: _privacySettingsViewModel.shouldSaveRecipientAddress,
|
||||
onValueChange: (BuildContext _, bool value) {
|
||||
_privacySettingsViewModel.setShouldSaveRecipientAddress(value);
|
||||
})
|
||||
],
|
||||
);
|
||||
});
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
84
lib/src/screens/settings/security_backup_page.dart
Normal file
84
lib/src/screens/settings/security_backup_page.dart
Normal file
|
@ -0,0 +1,84 @@
|
|||
import 'package:cake_wallet/routes.dart';
|
||||
import 'package:cake_wallet/src/screens/auth/auth_page.dart';
|
||||
import 'package:cake_wallet/src/screens/base_page.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/src/screens/pin_code/pin_code_widget.dart';
|
||||
import 'package:cake_wallet/src/screens/settings/widgets/settings_cell_with_arrow.dart';
|
||||
import 'package:cake_wallet/src/screens/settings/widgets/settings_switcher_cell.dart';
|
||||
import 'package:cake_wallet/src/widgets/standard_list.dart';
|
||||
import 'package:cake_wallet/view_model/settings/security_settings_view_model.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||
|
||||
class SecurityBackupPage extends BasePage {
|
||||
SecurityBackupPage(this._securitySettingsViewModel);
|
||||
|
||||
@override
|
||||
String get title => S.current.security_and_backup;
|
||||
|
||||
final SecuritySettingsViewModel _securitySettingsViewModel;
|
||||
|
||||
@override
|
||||
Widget body(BuildContext context) {
|
||||
return Container(
|
||||
padding: EdgeInsets.only(top: 10),
|
||||
child: Column(mainAxisSize: MainAxisSize.min, children: [
|
||||
SettingsCellWithArrow(
|
||||
title: S.current.show_keys,
|
||||
handler: (_) => Navigator.of(context).pushNamed(Routes.auth,
|
||||
arguments: (bool isAuthenticatedSuccessfully, AuthPageState auth) {
|
||||
if (isAuthenticatedSuccessfully) {
|
||||
auth.close(route: Routes.showKeys);
|
||||
}
|
||||
}),
|
||||
),
|
||||
StandardListSeparator(padding: EdgeInsets.symmetric(horizontal: 24)),
|
||||
SettingsCellWithArrow(
|
||||
title: S.current.create_backup,
|
||||
handler: (_) => Navigator.of(context).pushNamed(Routes.auth,
|
||||
arguments: (bool isAuthenticatedSuccessfully, AuthPageState auth) {
|
||||
if (isAuthenticatedSuccessfully) {
|
||||
auth.close(route: Routes.backup);
|
||||
}
|
||||
}),
|
||||
),
|
||||
StandardListSeparator(padding: EdgeInsets.symmetric(horizontal: 24)),
|
||||
SettingsCellWithArrow(
|
||||
title: S.current.settings_change_pin,
|
||||
handler: (_) => Navigator.of(context).pushNamed(Routes.auth,
|
||||
arguments: (bool isAuthenticatedSuccessfully, AuthPageState auth) {
|
||||
auth.close(
|
||||
route: isAuthenticatedSuccessfully ? Routes.setupPin : null,
|
||||
arguments: (PinCodeState<PinCodeWidget> setupPinContext, String _) {
|
||||
setupPinContext.close();
|
||||
},
|
||||
);
|
||||
})),
|
||||
StandardListSeparator(padding: EdgeInsets.symmetric(horizontal: 24)),
|
||||
Observer(builder: (_) {
|
||||
return SettingsSwitcherCell(
|
||||
title: S.current.settings_allow_biometrical_authentication,
|
||||
value: _securitySettingsViewModel.allowBiometricalAuthentication,
|
||||
onValueChange: (BuildContext context, bool value) {
|
||||
if (value) {
|
||||
Navigator.of(context).pushNamed(Routes.auth,
|
||||
arguments: (bool isAuthenticatedSuccessfully, AuthPageState auth) async {
|
||||
if (isAuthenticatedSuccessfully) {
|
||||
if (await _securitySettingsViewModel.biometricAuthenticated()) {
|
||||
_securitySettingsViewModel.setAllowBiometricalAuthentication(isAuthenticatedSuccessfully);
|
||||
}
|
||||
} else {
|
||||
_securitySettingsViewModel.setAllowBiometricalAuthentication(isAuthenticatedSuccessfully);
|
||||
}
|
||||
|
||||
auth.close();
|
||||
});
|
||||
} else {
|
||||
_securitySettingsViewModel.setAllowBiometricalAuthentication(value);
|
||||
}
|
||||
});
|
||||
}),
|
||||
]),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -1,98 +0,0 @@
|
|||
import 'package:cake_wallet/src/screens/settings/widgets/settings_choices_cell.dart';
|
||||
import 'package:cake_wallet/src/screens/settings/widgets/settings_version_cell.dart';
|
||||
import 'package:cake_wallet/view_model/settings/choices_list_item.dart';
|
||||
import 'package:cake_wallet/view_model/settings/version_list_item.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/view_model/settings/settings_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/settings/link_list_item.dart';
|
||||
import 'package:cake_wallet/view_model/settings/picker_list_item.dart';
|
||||
import 'package:cake_wallet/view_model/settings/regular_list_item.dart';
|
||||
import 'package:cake_wallet/view_model/settings/switcher_list_item.dart';
|
||||
import 'package:cake_wallet/src/screens/settings/widgets/settings_link_provider_cell.dart';
|
||||
import 'package:cake_wallet/src/screens/settings/widgets/settings_cell_with_arrow.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/src/widgets/standard_list.dart';
|
||||
import 'package:cake_wallet/src/screens/base_page.dart';
|
||||
|
||||
class SettingsPage extends BasePage {
|
||||
SettingsPage(this.settingsViewModel);
|
||||
|
||||
final SettingsViewModel settingsViewModel;
|
||||
|
||||
@override
|
||||
String get title => S.current.settings_title;
|
||||
|
||||
@override
|
||||
Widget body(BuildContext context) {
|
||||
// FIX-ME: Added `context` it was not used here before, maby bug ?
|
||||
return SectionStandardList(
|
||||
context: context,
|
||||
sectionCount: settingsViewModel.sections.length,
|
||||
itemCounter: (int sectionIndex) {
|
||||
if (sectionIndex < settingsViewModel.sections.length) {
|
||||
return settingsViewModel.sections[sectionIndex].length;
|
||||
}
|
||||
|
||||
return 0;
|
||||
},
|
||||
itemBuilder: (_, sectionIndex, itemIndex) {
|
||||
final item = settingsViewModel.sections[sectionIndex][itemIndex];
|
||||
|
||||
if (item is PickerListItem) {
|
||||
return Observer(builder: (_) {
|
||||
return SettingsPickerCell<Object>(
|
||||
displayItem: item.displayItem,
|
||||
title: item.title,
|
||||
selectedItem: item.selectedItem(),
|
||||
items: item.items,
|
||||
onItemSelected: (dynamic value) => item.onItemSelected(value),
|
||||
images: item.images,
|
||||
searchHintText: item.searchHintText,
|
||||
isGridView: item.isGridView,
|
||||
matchingCriteria: (dynamic value, String searchText) => item.matchingCriteria(value, searchText),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
if (item is SwitcherListItem) {
|
||||
return Observer(builder: (_) {
|
||||
return SettingsSwitcherCell(
|
||||
title: item.title,
|
||||
value: item.value(),
|
||||
onValueChange: item.onValueChange);
|
||||
});
|
||||
}
|
||||
|
||||
if (item is RegularListItem) {
|
||||
return SettingsCellWithArrow(
|
||||
title: item.title, handler: item.handler);
|
||||
}
|
||||
|
||||
if (item is LinkListItem) {
|
||||
return SettingsLinkProviderCell(
|
||||
title: item.title,
|
||||
icon: item.icon,
|
||||
link: item.link,
|
||||
linkTitle: item.linkTitle);
|
||||
}
|
||||
|
||||
if (item is VersionListItem) {
|
||||
return Observer(builder: (_) {
|
||||
return SettingsVersionCell(
|
||||
title:
|
||||
S.of(context).version(settingsViewModel.currentVersion));
|
||||
});
|
||||
}
|
||||
|
||||
if (item is ChoicesListItem) {
|
||||
return SettingsChoicesCell(item);
|
||||
}
|
||||
|
||||
return Container();
|
||||
});
|
||||
}
|
||||
}
|
|
@ -4,6 +4,7 @@ import 'package:cake_wallet/routes.dart';
|
|||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/entities/qr_scanner.dart';
|
||||
import 'package:cake_wallet/entities/contact_base.dart';
|
||||
import 'package:cw_core/crypto_currency.dart';
|
||||
|
||||
enum AddressTextFieldOption { paste, qrCode, addressBook }
|
||||
|
||||
|
@ -26,7 +27,8 @@ class AddressTextField extends StatelessWidget {
|
|||
this.hintStyle,
|
||||
this.validator,
|
||||
this.onPushPasteButton,
|
||||
this.onPushAddressBookButton});
|
||||
this.onPushAddressBookButton,
|
||||
this.selectedCurrency});
|
||||
|
||||
static const prefixIconWidth = 34.0;
|
||||
static const prefixIconHeight = 34.0;
|
||||
|
@ -47,6 +49,7 @@ class AddressTextField extends StatelessWidget {
|
|||
final FocusNode? focusNode;
|
||||
final Function(BuildContext context)? onPushPasteButton;
|
||||
final Function(BuildContext context)? onPushAddressBookButton;
|
||||
final CryptoCurrency? selectedCurrency;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
@ -207,7 +210,7 @@ class AddressTextField extends StatelessWidget {
|
|||
|
||||
Future<void> _presetAddressBookPicker(BuildContext context) async {
|
||||
final contact = await Navigator.of(context, rootNavigator: true)
|
||||
.pushNamed(Routes.pickerAddressBook);
|
||||
.pushNamed(Routes.pickerAddressBook,arguments: selectedCurrency);
|
||||
|
||||
if (contact is ContactBase && contact.address != null) {
|
||||
controller?.text = contact.address;
|
||||
|
|
|
@ -123,6 +123,7 @@ class SectionStandardList extends StatelessWidget {
|
|||
required this.itemBuilder,
|
||||
required this.sectionCount,
|
||||
required BuildContext context,
|
||||
this.dividerPadding = const EdgeInsets.only(left: 24),
|
||||
this.themeColor,
|
||||
this.dividerThemeColor,
|
||||
this.sectionTitleBuilder,
|
||||
|
@ -149,6 +150,7 @@ class SectionStandardList extends StatelessWidget {
|
|||
final List<Widget> totalRows;
|
||||
final Color? themeColor;
|
||||
final Color? dividerThemeColor;
|
||||
final EdgeInsets dividerPadding;
|
||||
|
||||
List<Widget> transform(
|
||||
bool hasTopSeparator,
|
||||
|
@ -178,7 +180,7 @@ class SectionStandardList extends StatelessWidget {
|
|||
|
||||
items.add(sectionIndex + 1 != sectionCount
|
||||
? SectionHeaderListRow()
|
||||
: StandardListSeparator(padding: EdgeInsets.only(left: 24)));
|
||||
: StandardListSeparator(padding: dividerPadding));
|
||||
}
|
||||
|
||||
return items;
|
||||
|
|
|
@ -4,7 +4,7 @@ part 'authentication_store.g.dart';
|
|||
|
||||
class AuthenticationStore = AuthenticationStoreBase with _$AuthenticationStore;
|
||||
|
||||
enum AuthenticationState { uninitialized, installed, allowed, denied }
|
||||
enum AuthenticationState { uninitialized, installed, allowed }
|
||||
|
||||
abstract class AuthenticationStoreBase with Store {
|
||||
AuthenticationStoreBase() : state = AuthenticationState.uninitialized;
|
||||
|
@ -17,7 +17,4 @@ abstract class AuthenticationStoreBase with Store {
|
|||
|
||||
@action
|
||||
void allowed() => state = AuthenticationState.allowed;
|
||||
|
||||
@action
|
||||
void denied() => state = AuthenticationState.denied;
|
||||
}
|
||||
|
|
|
@ -30,6 +30,7 @@ abstract class SettingsStoreBase with Store {
|
|||
required BalanceDisplayMode initialBalanceDisplayMode,
|
||||
required bool initialSaveRecipientAddress,
|
||||
required bool initialAllowBiometricalAuthentication,
|
||||
required bool initialExchangeEnabled,
|
||||
required ThemeBase initialTheme,
|
||||
required int initialPinLength,
|
||||
required String initialLanguageCode,
|
||||
|
@ -47,6 +48,7 @@ abstract class SettingsStoreBase with Store {
|
|||
balanceDisplayMode = initialBalanceDisplayMode,
|
||||
shouldSaveRecipientAddress = initialSaveRecipientAddress,
|
||||
allowBiometricalAuthentication = initialAllowBiometricalAuthentication,
|
||||
disableExchange = initialExchangeEnabled,
|
||||
currentTheme = initialTheme,
|
||||
pinCodeLength = initialPinLength,
|
||||
languageCode = initialLanguageCode,
|
||||
|
@ -113,6 +115,11 @@ abstract class SettingsStoreBase with Store {
|
|||
(BalanceDisplayMode mode) => sharedPreferences.setInt(
|
||||
PreferencesKey.currentBalanceDisplayModeKey, mode.serialize()));
|
||||
|
||||
reaction(
|
||||
(_) => disableExchange,
|
||||
(bool disableExchange) => sharedPreferences.setBool(
|
||||
PreferencesKey.disableExchangeKey, disableExchange));
|
||||
|
||||
this
|
||||
.nodes
|
||||
.observe((change) {
|
||||
|
@ -143,6 +150,9 @@ abstract class SettingsStoreBase with Store {
|
|||
@observable
|
||||
bool allowBiometricalAuthentication;
|
||||
|
||||
@observable
|
||||
bool disableExchange;
|
||||
|
||||
@observable
|
||||
ThemeBase currentTheme;
|
||||
|
||||
|
@ -221,6 +231,8 @@ abstract class SettingsStoreBase with Store {
|
|||
final allowBiometricalAuthentication = sharedPreferences
|
||||
.getBool(PreferencesKey.allowBiometricalAuthenticationKey) ??
|
||||
false;
|
||||
final disableExchange = sharedPreferences
|
||||
.getBool(PreferencesKey.disableExchangeKey) ?? false;
|
||||
final legacyTheme =
|
||||
(sharedPreferences.getBool(PreferencesKey.isDarkThemeLegacy) ?? false)
|
||||
? ThemeType.dark.index
|
||||
|
@ -284,6 +296,7 @@ abstract class SettingsStoreBase with Store {
|
|||
initialBalanceDisplayMode: currentBalanceDisplayMode,
|
||||
initialSaveRecipientAddress: shouldSaveRecipientAddress,
|
||||
initialAllowBiometricalAuthentication: allowBiometricalAuthentication,
|
||||
initialExchangeEnabled: disableExchange,
|
||||
initialTheme: savedTheme,
|
||||
actionlistDisplayMode: actionListDisplayMode,
|
||||
initialPinLength: pinLength,
|
||||
|
|
51
lib/view_model/advanced_privacy_settings_view_model.dart
Normal file
51
lib/view_model/advanced_privacy_settings_view_model.dart
Normal file
|
@ -0,0 +1,51 @@
|
|||
import 'package:cake_wallet/store/settings_store.dart';
|
||||
import 'package:cake_wallet/view_model/settings/switcher_list_item.dart';
|
||||
import 'package:cw_core/wallet_type.dart';
|
||||
import 'package:mobx/mobx.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
|
||||
part 'advanced_privacy_settings_view_model.g.dart';
|
||||
|
||||
class AdvancedPrivacySettingsViewModel = AdvancedPrivacySettingsViewModelBase
|
||||
with _$AdvancedPrivacySettingsViewModel;
|
||||
|
||||
abstract class AdvancedPrivacySettingsViewModelBase with Store {
|
||||
AdvancedPrivacySettingsViewModelBase(this.type, this._settingsStore)
|
||||
: _disableFiat = false,
|
||||
_addCustomNode = false {
|
||||
settings = [
|
||||
// TODO: uncomment when Disable Fiat PR is merged
|
||||
// SwitcherListItem(
|
||||
// title: S.current.disable_fiat,
|
||||
// value: () => _disableFiat,
|
||||
// onValueChange: (_, bool value) => _disableFiat = value,
|
||||
// ),
|
||||
SwitcherListItem(
|
||||
title: S.current.disable_exchange,
|
||||
value: () => _settingsStore.disableExchange,
|
||||
onValueChange: (_, bool value) {
|
||||
_settingsStore.disableExchange = value;
|
||||
},
|
||||
),
|
||||
SwitcherListItem(
|
||||
title: S.current.add_custom_node,
|
||||
value: () => _addCustomNode,
|
||||
onValueChange: (_, bool value) => _addCustomNode = value,
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
late List<SwitcherListItem> settings;
|
||||
|
||||
@observable
|
||||
bool _disableFiat = false;
|
||||
|
||||
@observable
|
||||
bool _addCustomNode = false;
|
||||
|
||||
final WalletType type;
|
||||
final SettingsStore _settingsStore;
|
||||
|
||||
@computed
|
||||
bool get addCustomNode => _addCustomNode;
|
||||
}
|
|
@ -7,27 +7,26 @@ import 'package:mobx/mobx.dart';
|
|||
import 'package:cake_wallet/entities/contact_record.dart';
|
||||
import 'package:cake_wallet/entities/contact.dart';
|
||||
import 'package:cake_wallet/utils/mobx.dart';
|
||||
import 'package:cw_core/crypto_currency.dart';
|
||||
|
||||
part 'contact_list_view_model.g.dart';
|
||||
|
||||
class ContactListViewModel = ContactListViewModelBase
|
||||
with _$ContactListViewModel;
|
||||
class ContactListViewModel = ContactListViewModelBase with _$ContactListViewModel;
|
||||
|
||||
abstract class ContactListViewModelBase with Store {
|
||||
ContactListViewModelBase(this.contactSource, this.walletInfoSource)
|
||||
ContactListViewModelBase(this.contactSource, this.walletInfoSource, this._currency)
|
||||
: contacts = ObservableList<ContactRecord>(),
|
||||
walletContacts = [] {
|
||||
walletInfoSource.values.forEach((info) {
|
||||
if (info.addresses?.isNotEmpty ?? false) {
|
||||
info.addresses?.forEach((address, label) {
|
||||
final name = label.isNotEmpty
|
||||
? info.name + ' ($label)'
|
||||
: info.name;
|
||||
final name = label.isNotEmpty ? info.name + ' ($label)' : info.name;
|
||||
|
||||
walletContacts.add(WalletContact(
|
||||
address,
|
||||
name,
|
||||
walletTypeToCryptoCurrency(info.type)));
|
||||
address,
|
||||
name,
|
||||
walletTypeToCryptoCurrency(info.type),
|
||||
));
|
||||
});
|
||||
}
|
||||
});
|
||||
|
@ -41,7 +40,18 @@ abstract class ContactListViewModelBase with Store {
|
|||
final Box<WalletInfo> walletInfoSource;
|
||||
final ObservableList<ContactRecord> contacts;
|
||||
final List<WalletContact> walletContacts;
|
||||
final CryptoCurrency? _currency;
|
||||
StreamSubscription<BoxEvent>? _subscription;
|
||||
|
||||
bool get isEditable => _currency == null;
|
||||
|
||||
Future<void> delete(ContactRecord contact) async => contact.original.delete();
|
||||
|
||||
@computed
|
||||
List<ContactRecord> get contactsToShow =>
|
||||
contacts.where((element) => _currency == null || element.type == _currency).toList();
|
||||
|
||||
@computed
|
||||
List<WalletContact> get walletContactsToShow =>
|
||||
walletContacts.where((element) => _currency == null || element.type == _currency).toList();
|
||||
}
|
||||
|
|
|
@ -53,7 +53,6 @@ abstract class DashboardViewModelBase with Store {
|
|||
hasBuyAction = false,
|
||||
isEnabledBuyAction = false,
|
||||
hasExchangeAction = false,
|
||||
isEnabledExchangeAction = false,
|
||||
isShowFirstYatIntroduction = false,
|
||||
isShowSecondYatIntroduction = false,
|
||||
isShowThirdYatIntroduction = false,
|
||||
|
@ -249,8 +248,8 @@ abstract class DashboardViewModelBase with Store {
|
|||
void furtherShowYatPopup(bool shouldShow) =>
|
||||
settingsStore.shouldShowYatPopup = shouldShow;
|
||||
|
||||
@observable
|
||||
bool isEnabledExchangeAction;
|
||||
@computed
|
||||
bool get isEnabledExchangeAction => !settingsStore.disableExchange;
|
||||
|
||||
@observable
|
||||
bool hasExchangeAction;
|
||||
|
@ -365,7 +364,6 @@ abstract class DashboardViewModelBase with Store {
|
|||
}
|
||||
|
||||
void updateActions() {
|
||||
isEnabledExchangeAction = true;
|
||||
hasExchangeAction = !isHaven;
|
||||
isEnabledBuyAction = wallet.type != WalletType.haven
|
||||
&& wallet.type != WalletType.monero;
|
||||
|
|
|
@ -6,9 +6,8 @@ import 'package:cake_wallet/entities/preferences_key.dart';
|
|||
import 'package:cake_wallet/exchange/sideshift/sideshift_exchange_provider.dart';
|
||||
import 'package:cake_wallet/exchange/sideshift/sideshift_request.dart';
|
||||
import 'package:cake_wallet/exchange/simpleswap/simpleswap_exchange_provider.dart';
|
||||
import 'package:cake_wallet/view_model/settings/settings_view_model.dart';
|
||||
import 'package:cw_core/transaction_priority.dart';
|
||||
import 'package:cake_wallet/exchange/simpleswap/simpleswap_request.dart';
|
||||
import 'package:cw_core/transaction_priority.dart';
|
||||
import 'package:cw_core/wallet_base.dart';
|
||||
import 'package:cw_core/crypto_currency.dart';
|
||||
import 'package:cw_core/sync_status.dart';
|
||||
|
@ -43,9 +42,8 @@ class ExchangeViewModel = ExchangeViewModelBase with _$ExchangeViewModel;
|
|||
|
||||
abstract class ExchangeViewModelBase with Store {
|
||||
ExchangeViewModelBase(this.wallet, this.trades, this._exchangeTemplateStore,
|
||||
this.tradesStore, this._settingsStore, this.sharedPreferences, this._settingsViewModel)
|
||||
this.tradesStore, this._settingsStore, this.sharedPreferences)
|
||||
: _cryptoNumberFormat = NumberFormat(),
|
||||
isReverse = false,
|
||||
isFixedRateMode = false,
|
||||
isReceiveAmountEntered = false,
|
||||
depositAmount = '',
|
||||
|
@ -113,7 +111,11 @@ abstract class ExchangeViewModelBase with Store {
|
|||
loadLimits();
|
||||
reaction(
|
||||
(_) => isFixedRateMode,
|
||||
(Object _) => loadLimits());
|
||||
(Object _) {
|
||||
loadLimits();
|
||||
_bestRate = 0;
|
||||
_calculateBestRate();
|
||||
});
|
||||
}
|
||||
|
||||
final WalletBase wallet;
|
||||
|
@ -190,6 +192,19 @@ abstract class ExchangeViewModelBase with Store {
|
|||
ObservableList<ExchangeTemplate> get templates =>
|
||||
_exchangeTemplateStore.templates;
|
||||
|
||||
|
||||
@computed
|
||||
TransactionPriority get transactionPriority {
|
||||
final priority = _settingsStore.priority[wallet.type];
|
||||
|
||||
if (priority == null) {
|
||||
throw Exception('Unexpected type ${wallet.type.toString()}');
|
||||
}
|
||||
|
||||
return priority;
|
||||
}
|
||||
|
||||
|
||||
bool get hasAllAmount =>
|
||||
wallet.type == WalletType.bitcoin && depositCurrency == wallet.currency;
|
||||
|
||||
|
@ -199,11 +214,11 @@ abstract class ExchangeViewModelBase with Store {
|
|||
switch (wallet.type) {
|
||||
case WalletType.monero:
|
||||
case WalletType.haven:
|
||||
return _settingsViewModel.transactionPriority == monero!.getMoneroTransactionPrioritySlow();
|
||||
return transactionPriority == monero!.getMoneroTransactionPrioritySlow();
|
||||
case WalletType.bitcoin:
|
||||
return _settingsViewModel.transactionPriority == bitcoin!.getBitcoinTransactionPrioritySlow();
|
||||
return transactionPriority == bitcoin!.getBitcoinTransactionPrioritySlow();
|
||||
case WalletType.litecoin:
|
||||
return _settingsViewModel.transactionPriority == bitcoin!.getLitecoinTransactionPrioritySlow();
|
||||
return transactionPriority == bitcoin!.getLitecoinTransactionPrioritySlow();
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
@ -215,14 +230,10 @@ abstract class ExchangeViewModelBase with Store {
|
|||
|
||||
Limits limits;
|
||||
|
||||
bool isReverse;
|
||||
|
||||
NumberFormat _cryptoNumberFormat;
|
||||
|
||||
final SettingsStore _settingsStore;
|
||||
|
||||
final SettingsViewModel _settingsViewModel;
|
||||
|
||||
double _bestRate = 0.0;
|
||||
|
||||
late Timer bestRateSync;
|
||||
|
@ -248,7 +259,6 @@ abstract class ExchangeViewModelBase with Store {
|
|||
@action
|
||||
Future<void> changeReceiveAmount({required String amount}) async {
|
||||
receiveAmount = amount;
|
||||
isReverse = true;
|
||||
|
||||
if (amount.isEmpty) {
|
||||
depositAmount = '';
|
||||
|
@ -273,7 +283,6 @@ abstract class ExchangeViewModelBase with Store {
|
|||
@action
|
||||
Future<void> changeDepositAmount({required String amount}) async {
|
||||
depositAmount = amount;
|
||||
isReverse = false;
|
||||
|
||||
if (amount.isEmpty) {
|
||||
depositAmount = '';
|
||||
|
@ -297,14 +306,17 @@ abstract class ExchangeViewModelBase with Store {
|
|||
}
|
||||
|
||||
Future<void> _calculateBestRate() async {
|
||||
final amount = double.tryParse(isFixedRateMode ? receiveAmount : depositAmount) ?? 1;
|
||||
|
||||
final result = await Future.wait<double>(
|
||||
_tradeAvailableProviders
|
||||
.map((element) => element.calculateAmount(
|
||||
.where((element) => !isFixedRateMode || element.supportsFixedRate)
|
||||
.map((element) => element.fetchRate(
|
||||
from: depositCurrency,
|
||||
to: receiveCurrency,
|
||||
amount: 1,
|
||||
amount: amount,
|
||||
isFixedRateMode: isFixedRateMode,
|
||||
isReceiveAmount: false))
|
||||
isReceiveAmount: isFixedRateMode))
|
||||
);
|
||||
|
||||
_sortedAvailableProviders.clear();
|
||||
|
@ -335,7 +347,7 @@ abstract class ExchangeViewModelBase with Store {
|
|||
? depositCurrency
|
||||
: receiveCurrency;
|
||||
|
||||
double lowestMin = double.maxFinite;
|
||||
double? lowestMin = double.maxFinite;
|
||||
double? highestMax = 0.0;
|
||||
|
||||
for (var provider in selectedProviders) {
|
||||
|
@ -350,8 +362,8 @@ abstract class ExchangeViewModelBase with Store {
|
|||
to: to,
|
||||
isFixedRateMode: isFixedRateMode);
|
||||
|
||||
if (tempLimits.min != null && tempLimits.min! < lowestMin) {
|
||||
lowestMin = tempLimits.min!;
|
||||
if (lowestMin != null && (tempLimits.min ?? -1) < lowestMin) {
|
||||
lowestMin = tempLimits.min;
|
||||
}
|
||||
if (highestMax != null && (tempLimits.max ?? double.maxFinite) > highestMax) {
|
||||
highestMax = tempLimits.max;
|
||||
|
@ -361,7 +373,7 @@ abstract class ExchangeViewModelBase with Store {
|
|||
}
|
||||
}
|
||||
|
||||
if (lowestMin < double.maxFinite) {
|
||||
if (lowestMin != double.maxFinite) {
|
||||
limits = Limits(min: lowestMin, max: highestMax);
|
||||
|
||||
limitsState = LimitsLoadedSuccessfully(limits: limits);
|
||||
|
@ -375,96 +387,105 @@ abstract class ExchangeViewModelBase with Store {
|
|||
TradeRequest? request;
|
||||
String amount = '';
|
||||
|
||||
for (var provider in _sortedAvailableProviders.values) {
|
||||
if (!(await provider.checkIsAvailable())) {
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
for (var provider in _sortedAvailableProviders.values) {
|
||||
if (!(await provider.checkIsAvailable())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (provider is SideShiftExchangeProvider) {
|
||||
request = SideShiftRequest(
|
||||
depositMethod: depositCurrency,
|
||||
settleMethod: receiveCurrency,
|
||||
depositAmount: depositAmount.replaceAll(',', '.'),
|
||||
settleAddress: receiveAddress,
|
||||
refundAddress: depositAddress,
|
||||
);
|
||||
amount = depositAmount;
|
||||
}
|
||||
if (provider is SideShiftExchangeProvider) {
|
||||
request = SideShiftRequest(
|
||||
depositMethod: depositCurrency,
|
||||
settleMethod: receiveCurrency,
|
||||
depositAmount: depositAmount.replaceAll(',', '.'),
|
||||
settleAddress: receiveAddress,
|
||||
refundAddress: depositAddress,
|
||||
);
|
||||
amount = isFixedRateMode ? receiveAmount : depositAmount;
|
||||
}
|
||||
|
||||
if (provider is SimpleSwapExchangeProvider) {
|
||||
request = SimpleSwapRequest(
|
||||
from: depositCurrency,
|
||||
to: receiveCurrency,
|
||||
amount: depositAmount.replaceAll(',', '.'),
|
||||
address: receiveAddress,
|
||||
refundAddress: depositAddress,
|
||||
);
|
||||
amount = depositAmount;
|
||||
}
|
||||
|
||||
if (provider is XMRTOExchangeProvider) {
|
||||
request = XMRTOTradeRequest(
|
||||
if (provider is SimpleSwapExchangeProvider) {
|
||||
request = SimpleSwapRequest(
|
||||
from: depositCurrency,
|
||||
to: receiveCurrency,
|
||||
amount: depositAmount.replaceAll(',', '.'),
|
||||
receiveAmount: receiveAmount.replaceAll(',', '.'),
|
||||
address: receiveAddress,
|
||||
refundAddress: depositAddress,
|
||||
isBTCRequest: isReceiveAmountEntered);
|
||||
amount = depositAmount;
|
||||
}
|
||||
);
|
||||
amount = isFixedRateMode ? receiveAmount : depositAmount;
|
||||
}
|
||||
|
||||
if (provider is ChangeNowExchangeProvider) {
|
||||
request = ChangeNowRequest(
|
||||
from: depositCurrency,
|
||||
to: receiveCurrency,
|
||||
fromAmount: depositAmount.replaceAll(',', '.'),
|
||||
toAmount: receiveAmount.replaceAll(',', '.'),
|
||||
refundAddress: depositAddress,
|
||||
address: receiveAddress,
|
||||
isReverse: isReverse);
|
||||
amount = isReverse ? receiveAmount : depositAmount;
|
||||
}
|
||||
if (provider is XMRTOExchangeProvider) {
|
||||
request = XMRTOTradeRequest(
|
||||
from: depositCurrency,
|
||||
to: receiveCurrency,
|
||||
amount: depositAmount.replaceAll(',', '.'),
|
||||
receiveAmount: receiveAmount.replaceAll(',', '.'),
|
||||
address: receiveAddress,
|
||||
refundAddress: depositAddress,
|
||||
isBTCRequest: isReceiveAmountEntered);
|
||||
amount = isFixedRateMode ? receiveAmount : depositAmount;
|
||||
}
|
||||
|
||||
if (provider is MorphTokenExchangeProvider) {
|
||||
request = MorphTokenRequest(
|
||||
from: depositCurrency,
|
||||
to: receiveCurrency,
|
||||
amount: depositAmount.replaceAll(',', '.'),
|
||||
refundAddress: depositAddress,
|
||||
address: receiveAddress);
|
||||
amount = depositAmount;
|
||||
}
|
||||
if (provider is ChangeNowExchangeProvider) {
|
||||
request = ChangeNowRequest(
|
||||
from: depositCurrency,
|
||||
to: receiveCurrency,
|
||||
fromAmount: depositAmount.replaceAll(',', '.'),
|
||||
toAmount: receiveAmount.replaceAll(',', '.'),
|
||||
refundAddress: depositAddress,
|
||||
address: receiveAddress,
|
||||
isReverse: isFixedRateMode);
|
||||
amount = isFixedRateMode ? receiveAmount : depositAmount;
|
||||
}
|
||||
|
||||
amount = amount.replaceAll(',', '.');
|
||||
if (provider is MorphTokenExchangeProvider) {
|
||||
request = MorphTokenRequest(
|
||||
from: depositCurrency,
|
||||
to: receiveCurrency,
|
||||
amount: depositAmount.replaceAll(',', '.'),
|
||||
refundAddress: depositAddress,
|
||||
address: receiveAddress);
|
||||
amount = isFixedRateMode ? receiveAmount : depositAmount;
|
||||
}
|
||||
|
||||
if (limitsState is LimitsLoadedSuccessfully) {
|
||||
if (double.parse(amount) < limits.min!) {
|
||||
continue;
|
||||
} else if (limits.max != null && double.parse(amount) > limits.max!) {
|
||||
continue;
|
||||
} else {
|
||||
try {
|
||||
tradeState = TradeIsCreating();
|
||||
final trade = await provider.createTrade(
|
||||
request: request!, isFixedRateMode: isFixedRateMode);
|
||||
trade.walletId = wallet.id;
|
||||
tradesStore.setTrade(trade);
|
||||
await trades.add(trade);
|
||||
tradeState = TradeIsCreatedSuccessfully(trade: trade);
|
||||
/// return after the first successful trade
|
||||
return;
|
||||
} catch (e) {
|
||||
amount = amount.replaceAll(',', '.');
|
||||
|
||||
if (limitsState is LimitsLoadedSuccessfully) {
|
||||
if (limits.max != null && double.parse(amount) < limits.min!) {
|
||||
continue;
|
||||
} else if (limits.max != null && double.parse(amount) > limits.max!) {
|
||||
continue;
|
||||
} else {
|
||||
try {
|
||||
tradeState = TradeIsCreating();
|
||||
final trade = await provider.createTrade(
|
||||
request: request!, isFixedRateMode: isFixedRateMode);
|
||||
trade.walletId = wallet.id;
|
||||
tradesStore.setTrade(trade);
|
||||
await trades.add(trade);
|
||||
tradeState = TradeIsCreatedSuccessfully(trade: trade);
|
||||
/// return after the first successful trade
|
||||
return;
|
||||
} catch (e) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// if the code reached here then none of the providers succeeded
|
||||
tradeState = TradeIsCreatedFailure(
|
||||
title: S.current.trade_not_created,
|
||||
error: S.current.none_of_selected_providers_can_exchange);
|
||||
/// if the code reached here then none of the providers succeeded
|
||||
tradeState = TradeIsCreatedFailure(
|
||||
title: S.current.trade_not_created,
|
||||
error: S.current.none_of_selected_providers_can_exchange);
|
||||
} on ConcurrentModificationError {
|
||||
/// if create trade happened at the exact same time of the scheduled rate update
|
||||
/// then delay the create trade a bit and try again
|
||||
///
|
||||
/// this is because the limitation of the SplayTreeMap that
|
||||
/// you can't modify it while iterating through it
|
||||
Future.delayed(Duration(milliseconds: 500), createTrade);
|
||||
}
|
||||
}
|
||||
|
||||
@action
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import 'package:cake_wallet/core/execution_state.dart';
|
||||
import 'package:cake_wallet/store/settings_store.dart';
|
||||
import 'package:hive/hive.dart';
|
||||
import 'package:mobx/mobx.dart';
|
||||
import 'package:cw_core/wallet_base.dart';
|
||||
import 'package:cw_core/node.dart';
|
||||
import 'package:cw_core/wallet_type.dart';
|
||||
|
||||
|
@ -11,14 +11,15 @@ class NodeCreateOrEditViewModel = NodeCreateOrEditViewModelBase
|
|||
with _$NodeCreateOrEditViewModel;
|
||||
|
||||
abstract class NodeCreateOrEditViewModelBase with Store {
|
||||
NodeCreateOrEditViewModelBase(this._nodeSource, this._wallet)
|
||||
NodeCreateOrEditViewModelBase(this._nodeSource, this._walletType, this._settingsStore)
|
||||
: state = InitialExecutionState(),
|
||||
connectionState = InitialExecutionState(),
|
||||
useSSL = false,
|
||||
address = '',
|
||||
port = '',
|
||||
login = '',
|
||||
password = '';
|
||||
password = '',
|
||||
trusted = false;
|
||||
|
||||
@observable
|
||||
ExecutionState state;
|
||||
|
@ -41,12 +42,15 @@ abstract class NodeCreateOrEditViewModelBase with Store {
|
|||
@observable
|
||||
bool useSSL;
|
||||
|
||||
@observable
|
||||
bool trusted;
|
||||
|
||||
@computed
|
||||
bool get isReady =>
|
||||
address.isNotEmpty && port.isNotEmpty;
|
||||
|
||||
bool get hasAuthCredentials => _wallet.type == WalletType.monero ||
|
||||
_wallet.type == WalletType.haven;
|
||||
bool get hasAuthCredentials => _walletType == WalletType.monero ||
|
||||
_walletType == WalletType.haven;
|
||||
|
||||
String get uri {
|
||||
var uri = address;
|
||||
|
@ -58,8 +62,9 @@ abstract class NodeCreateOrEditViewModelBase with Store {
|
|||
return uri;
|
||||
}
|
||||
|
||||
final WalletBase _wallet;
|
||||
final WalletType _walletType;
|
||||
final Box<Node> _nodeSource;
|
||||
final SettingsStore _settingsStore;
|
||||
|
||||
@action
|
||||
void reset() {
|
||||
|
@ -68,16 +73,22 @@ abstract class NodeCreateOrEditViewModelBase with Store {
|
|||
login = '';
|
||||
password = '';
|
||||
useSSL = false;
|
||||
trusted = false;
|
||||
}
|
||||
|
||||
@action
|
||||
Future<void> save() async {
|
||||
Future<void> save({bool saveAsCurrent = false}) async {
|
||||
try {
|
||||
state = IsExecutingState();
|
||||
final node =
|
||||
Node(uri: uri, type: _wallet.type, login: login, password: password,
|
||||
useSSL: useSSL);
|
||||
Node(uri: uri, type: _walletType, login: login, password: password,
|
||||
useSSL: useSSL, trusted: trusted);
|
||||
await _nodeSource.add(node);
|
||||
|
||||
if (saveAsCurrent) {
|
||||
_settingsStore.nodes[_walletType] = node;
|
||||
}
|
||||
|
||||
state = ExecutedSuccessfullyState();
|
||||
} catch (e) {
|
||||
state = FailureState(e.toString());
|
||||
|
@ -89,7 +100,7 @@ abstract class NodeCreateOrEditViewModelBase with Store {
|
|||
try {
|
||||
connectionState = IsExecutingState();
|
||||
final node =
|
||||
Node(uri: uri, type: _wallet.type, login: login, password: password);
|
||||
Node(uri: uri, type: _walletType, login: login, password: password);
|
||||
final isAlive = await node.requestNode();
|
||||
connectionState = ExecutedSuccessfullyState(payload: isAlive);
|
||||
} catch (e) {
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
import 'package:cake_wallet/entities/balance_display_mode.dart';
|
||||
import 'package:cake_wallet/entities/priority_for_wallet_type.dart';
|
||||
import 'package:cake_wallet/entities/transaction_description.dart';
|
||||
import 'package:cake_wallet/view_model/dashboard/balance_view_model.dart';
|
||||
import 'package:cw_core/transaction_priority.dart';
|
||||
import 'package:cake_wallet/view_model/send/output.dart';
|
||||
import 'package:cake_wallet/view_model/send/send_template_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/settings/settings_view_model.dart';
|
||||
import 'package:hive/hive.dart';
|
||||
import 'package:mobx/mobx.dart';
|
||||
import 'package:cake_wallet/entities/template.dart';
|
||||
|
@ -42,7 +42,8 @@ abstract class SendViewModelBase with Store {
|
|||
: state = InitialExecutionState(),
|
||||
currencies = _wallet.balance.keys.toList(),
|
||||
selectedCryptoCurrency = _wallet.currency,
|
||||
outputs = ObservableList<Output>() {
|
||||
outputs = ObservableList<Output>(),
|
||||
fiatFromSettings = _settingsStore.fiatCurrency {
|
||||
final priority = _settingsStore.priority[_wallet.type];
|
||||
final priorities = priorityForWalletType(_wallet.type);
|
||||
|
||||
|
@ -52,7 +53,7 @@ abstract class SendViewModelBase with Store {
|
|||
|
||||
outputs.add(Output(_wallet, _settingsStore, _fiatConversationStore, () => selectedCryptoCurrency));
|
||||
}
|
||||
|
||||
|
||||
@observable
|
||||
ExecutionState state;
|
||||
|
||||
|
@ -133,11 +134,13 @@ abstract class SendViewModelBase with Store {
|
|||
|
||||
Validator get textValidator => TextValidator();
|
||||
|
||||
final FiatCurrency fiatFromSettings;
|
||||
|
||||
@observable
|
||||
PendingTransaction? pendingTransaction;
|
||||
|
||||
@computed
|
||||
String get balance => balanceViewModel.availableBalance ?? '0.0';
|
||||
String get balance => balanceViewModel.availableBalance;
|
||||
|
||||
@computed
|
||||
bool get isReadyForSend => _wallet.syncStatus is SyncedSyncStatus;
|
||||
|
@ -166,6 +169,9 @@ abstract class SendViewModelBase with Store {
|
|||
|
||||
bool get hasCurrecyChanger => walletType == WalletType.haven;
|
||||
|
||||
@computed
|
||||
FiatCurrency get fiatCurrency => _settingsStore.fiatCurrency;
|
||||
|
||||
final WalletBase _wallet;
|
||||
final SettingsStore _settingsStore;
|
||||
final SendTemplateViewModel sendTemplateViewModel;
|
||||
|
@ -208,7 +214,7 @@ abstract class SendViewModelBase with Store {
|
|||
state = TransactionCommitting();
|
||||
await pendingTransaction!.commit();
|
||||
|
||||
if (pendingTransaction!.id?.isNotEmpty ?? false) {
|
||||
if (pendingTransaction!.id.isNotEmpty) {
|
||||
_settingsStore.shouldSaveRecipientAddress
|
||||
? await transactionDescriptionBox.add(TransactionDescription(
|
||||
id: pendingTransaction!.id,
|
||||
|
@ -283,4 +289,12 @@ abstract class SendViewModelBase with Store {
|
|||
|
||||
bool _isEqualCurrency(String currency) =>
|
||||
currency.toLowerCase() == _wallet.currency.title.toLowerCase();
|
||||
|
||||
@action
|
||||
void onClose() =>
|
||||
_settingsStore.fiatCurrency = fiatFromSettings;
|
||||
|
||||
@action
|
||||
void setFiatCurrency(FiatCurrency fiat) =>
|
||||
_settingsStore.fiatCurrency = fiat;
|
||||
}
|
||||
|
|
57
lib/view_model/settings/display_settings_view_model.dart
Normal file
57
lib/view_model/settings/display_settings_view_model.dart
Normal file
|
@ -0,0 +1,57 @@
|
|||
import 'package:cake_wallet/entities/balance_display_mode.dart';
|
||||
import 'package:cake_wallet/entities/fiat_currency.dart';
|
||||
import 'package:cake_wallet/store/settings_store.dart';
|
||||
import 'package:cake_wallet/themes/theme_base.dart';
|
||||
import 'package:mobx/mobx.dart';
|
||||
|
||||
part 'display_settings_view_model.g.dart';
|
||||
|
||||
class DisplaySettingsViewModel = DisplaySettingsViewModelBase with _$DisplaySettingsViewModel;
|
||||
|
||||
abstract class DisplaySettingsViewModelBase with Store {
|
||||
DisplaySettingsViewModelBase(
|
||||
this._settingsStore,
|
||||
);
|
||||
|
||||
final SettingsStore _settingsStore;
|
||||
|
||||
@computed
|
||||
FiatCurrency get fiatCurrency => _settingsStore.fiatCurrency;
|
||||
|
||||
@computed
|
||||
String get languageCode => _settingsStore.languageCode;
|
||||
|
||||
@computed
|
||||
BalanceDisplayMode get balanceDisplayMode => _settingsStore.balanceDisplayMode;
|
||||
|
||||
@computed
|
||||
bool get shouldDisplayBalance => balanceDisplayMode == BalanceDisplayMode.displayableBalance;
|
||||
|
||||
@computed
|
||||
ThemeBase get theme => _settingsStore.currentTheme;
|
||||
|
||||
@action
|
||||
void setBalanceDisplayMode(BalanceDisplayMode value) => _settingsStore.balanceDisplayMode = value;
|
||||
|
||||
@action
|
||||
void setShouldDisplayBalance(bool value) {
|
||||
if (value) {
|
||||
_settingsStore.balanceDisplayMode = BalanceDisplayMode.displayableBalance;
|
||||
} else {
|
||||
_settingsStore.balanceDisplayMode = BalanceDisplayMode.hiddenBalance;
|
||||
}
|
||||
}
|
||||
|
||||
@action
|
||||
void onLanguageSelected(String code) {
|
||||
_settingsStore.languageCode = code;
|
||||
}
|
||||
|
||||
@action
|
||||
void setTheme(ThemeBase newTheme) {
|
||||
_settingsStore.currentTheme = newTheme;
|
||||
}
|
||||
|
||||
@action
|
||||
void setFiatCurrency(FiatCurrency value) => _settingsStore.fiatCurrency = value;
|
||||
}
|
64
lib/view_model/settings/other_settings_view_model.dart
Normal file
64
lib/view_model/settings/other_settings_view_model.dart
Normal file
|
@ -0,0 +1,64 @@
|
|||
import 'package:cake_wallet/bitcoin/bitcoin.dart';
|
||||
import 'package:cake_wallet/entities/priority_for_wallet_type.dart';
|
||||
import 'package:cake_wallet/store/settings_store.dart';
|
||||
import 'package:cw_core/balance.dart';
|
||||
import 'package:cw_core/transaction_history.dart';
|
||||
import 'package:cw_core/transaction_info.dart';
|
||||
import 'package:cw_core/transaction_priority.dart';
|
||||
import 'package:cw_core/wallet_base.dart';
|
||||
import 'package:cw_core/wallet_type.dart';
|
||||
import 'package:mobx/mobx.dart';
|
||||
import 'package:package_info/package_info.dart';
|
||||
|
||||
part 'other_settings_view_model.g.dart';
|
||||
|
||||
class OtherSettingsViewModel = OtherSettingsViewModelBase with _$OtherSettingsViewModel;
|
||||
|
||||
abstract class OtherSettingsViewModelBase with Store {
|
||||
OtherSettingsViewModelBase(this._settingsStore, this._wallet)
|
||||
: walletType = _wallet.type,
|
||||
currentVersion = '' {
|
||||
PackageInfo.fromPlatform()
|
||||
.then((PackageInfo packageInfo) => currentVersion = packageInfo.version);
|
||||
|
||||
final priority = _settingsStore.priority[_wallet.type];
|
||||
final priorities = priorityForWalletType(_wallet.type);
|
||||
|
||||
if (!priorities.contains(priority)) {
|
||||
_settingsStore.priority[_wallet.type] = priorities.first;
|
||||
}
|
||||
}
|
||||
|
||||
final WalletType walletType;
|
||||
final WalletBase<Balance, TransactionHistoryBase<TransactionInfo>, TransactionInfo> _wallet;
|
||||
|
||||
@observable
|
||||
String currentVersion;
|
||||
|
||||
final SettingsStore _settingsStore;
|
||||
|
||||
@computed
|
||||
TransactionPriority get transactionPriority {
|
||||
final priority = _settingsStore.priority[walletType];
|
||||
|
||||
if (priority == null) {
|
||||
throw Exception('Unexpected type ${walletType.toString()}');
|
||||
}
|
||||
|
||||
return priority;
|
||||
}
|
||||
|
||||
String getDisplayPriority(dynamic priority) {
|
||||
final _priority = priority as TransactionPriority;
|
||||
|
||||
if (_wallet.type == WalletType.bitcoin || _wallet.type == WalletType.litecoin) {
|
||||
final rate = bitcoin!.getFeeRate(_wallet, _priority);
|
||||
return bitcoin!.bitcoinTransactionPriorityWithLabel(_priority, rate);
|
||||
}
|
||||
|
||||
return priority.toString();
|
||||
}
|
||||
|
||||
void onDisplayPrioritySelected(TransactionPriority priority) =>
|
||||
_settingsStore.priority[_wallet.type] = priority;
|
||||
}
|
24
lib/view_model/settings/privacy_settings_view_model.dart
Normal file
24
lib/view_model/settings/privacy_settings_view_model.dart
Normal file
|
@ -0,0 +1,24 @@
|
|||
import 'package:cake_wallet/store/settings_store.dart';
|
||||
import 'package:mobx/mobx.dart';
|
||||
|
||||
part 'privacy_settings_view_model.g.dart';
|
||||
|
||||
class PrivacySettingsViewModel = PrivacySettingsViewModelBase with _$PrivacySettingsViewModel;
|
||||
|
||||
abstract class PrivacySettingsViewModelBase with Store {
|
||||
PrivacySettingsViewModelBase(this._settingsStore);
|
||||
|
||||
final SettingsStore _settingsStore;
|
||||
|
||||
@computed
|
||||
bool get disableExchange => _settingsStore.disableExchange;
|
||||
|
||||
@computed
|
||||
bool get shouldSaveRecipientAddress => _settingsStore.shouldSaveRecipientAddress;
|
||||
|
||||
@action
|
||||
void setShouldSaveRecipientAddress(bool value) => _settingsStore.shouldSaveRecipientAddress = value;
|
||||
|
||||
@action
|
||||
void setEnableExchange(bool value) => _settingsStore.disableExchange = value;
|
||||
}
|
25
lib/view_model/settings/security_settings_view_model.dart
Normal file
25
lib/view_model/settings/security_settings_view_model.dart
Normal file
|
@ -0,0 +1,25 @@
|
|||
import 'package:cake_wallet/entities/biometric_auth.dart';
|
||||
import 'package:cake_wallet/store/settings_store.dart';
|
||||
import 'package:mobx/mobx.dart';
|
||||
|
||||
part 'security_settings_view_model.g.dart';
|
||||
|
||||
class SecuritySettingsViewModel = SecuritySettingsViewModelBase with _$SecuritySettingsViewModel;
|
||||
|
||||
abstract class SecuritySettingsViewModelBase with Store {
|
||||
SecuritySettingsViewModelBase(this._settingsStore) : _biometricAuth = BiometricAuth();
|
||||
|
||||
final BiometricAuth _biometricAuth;
|
||||
final SettingsStore _settingsStore;
|
||||
|
||||
@computed
|
||||
bool get allowBiometricalAuthentication => _settingsStore.allowBiometricalAuthentication;
|
||||
|
||||
@action
|
||||
Future<bool> biometricAuthenticated() async {
|
||||
return await _biometricAuth.canCheckBiometrics() && await _biometricAuth.isAuthenticated();
|
||||
}
|
||||
|
||||
@action
|
||||
void setAllowBiometricalAuthentication(bool value) => _settingsStore.allowBiometricalAuthentication = value;
|
||||
}
|
|
@ -1,336 +0,0 @@
|
|||
import 'package:cake_wallet/entities/language_service.dart';
|
||||
import 'package:cake_wallet/store/yat/yat_store.dart';
|
||||
import 'package:cake_wallet/view_model/settings/choices_list_item.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:mobx/mobx.dart';
|
||||
import 'package:package_info/package_info.dart';
|
||||
import 'package:cake_wallet/routes.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cw_core/wallet_base.dart';
|
||||
import 'package:cake_wallet/store/settings_store.dart';
|
||||
import 'package:cake_wallet/entities/biometric_auth.dart';
|
||||
import 'package:cw_core/wallet_type.dart';
|
||||
import 'package:cake_wallet/entities/balance_display_mode.dart';
|
||||
import 'package:cake_wallet/entities/fiat_currency.dart';
|
||||
import 'package:cw_core/node.dart';
|
||||
import 'package:cake_wallet/monero/monero.dart';
|
||||
import 'package:cake_wallet/haven/haven.dart';
|
||||
import 'package:cake_wallet/entities/action_list_display_mode.dart';
|
||||
import 'package:cake_wallet/view_model/settings/version_list_item.dart';
|
||||
import 'package:cake_wallet/view_model/settings/picker_list_item.dart';
|
||||
import 'package:cake_wallet/view_model/settings/regular_list_item.dart';
|
||||
import 'package:cake_wallet/view_model/settings/settings_list_item.dart';
|
||||
import 'package:cake_wallet/view_model/settings/switcher_list_item.dart';
|
||||
import 'package:cake_wallet/src/screens/auth/auth_page.dart';
|
||||
import 'package:cake_wallet/bitcoin/bitcoin.dart';
|
||||
import 'package:cw_core/transaction_history.dart';
|
||||
import 'package:cw_core/balance.dart';
|
||||
import 'package:cw_core/transaction_info.dart';
|
||||
import 'package:cw_core/transaction_priority.dart';
|
||||
import 'package:cake_wallet/themes/theme_base.dart';
|
||||
import 'package:cake_wallet/themes/theme_list.dart';
|
||||
import 'package:cake_wallet/src/screens/pin_code/pin_code_widget.dart';
|
||||
import 'package:cake_wallet/wallet_type_utils.dart';
|
||||
|
||||
part 'settings_view_model.g.dart';
|
||||
|
||||
class SettingsViewModel = SettingsViewModelBase with _$SettingsViewModel;
|
||||
|
||||
List<TransactionPriority> priorityForWalletType(WalletType type) {
|
||||
switch (type) {
|
||||
case WalletType.monero:
|
||||
return monero!.getTransactionPriorities();
|
||||
case WalletType.bitcoin:
|
||||
return bitcoin!.getTransactionPriorities();
|
||||
case WalletType.litecoin:
|
||||
return bitcoin!.getLitecoinTransactionPriorities();
|
||||
case WalletType.haven:
|
||||
return haven!.getTransactionPriorities();
|
||||
default:
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
abstract class SettingsViewModelBase with Store {
|
||||
SettingsViewModelBase(
|
||||
this._settingsStore,
|
||||
this._yatStore,
|
||||
WalletBase<Balance, TransactionHistoryBase<TransactionInfo>,
|
||||
TransactionInfo>
|
||||
wallet)
|
||||
: itemHeaders = {},
|
||||
_walletType = wallet.type,
|
||||
_biometricAuth = BiometricAuth(),
|
||||
sections = <List<SettingsListItem>>[],
|
||||
currentVersion = '' {
|
||||
PackageInfo.fromPlatform().then(
|
||||
(PackageInfo packageInfo) => currentVersion = packageInfo.version);
|
||||
|
||||
final priority = _settingsStore.priority[wallet.type];
|
||||
final priorities = priorityForWalletType(wallet.type);
|
||||
|
||||
if (!priorities.contains(priority)) {
|
||||
_settingsStore.priority[wallet.type] = priorities.first;
|
||||
}
|
||||
|
||||
//var connectYatUrl = YatLink.baseUrl + YatLink.signInSuffix;
|
||||
//final connectYatUrlParameters =
|
||||
// _yatStore.defineQueryParameters();
|
||||
|
||||
//if (connectYatUrlParameters.isNotEmpty) {
|
||||
// connectYatUrl += YatLink.queryParameter + connectYatUrlParameters;
|
||||
//}
|
||||
|
||||
//var manageYatUrl = YatLink.baseUrl + YatLink.managePath;
|
||||
//final manageYatUrlParameters =
|
||||
// _yatStore.defineQueryParameters();
|
||||
|
||||
//if (manageYatUrlParameters.isNotEmpty) {
|
||||
// manageYatUrl += YatLink.queryParameter + manageYatUrlParameters;
|
||||
//}
|
||||
|
||||
//var createNewYatUrl = YatLink.startFlowUrl;
|
||||
//final createNewYatUrlParameters =
|
||||
// _yatStore.defineQueryParameters();
|
||||
|
||||
//if (createNewYatUrlParameters.isNotEmpty) {
|
||||
// createNewYatUrl += '?sub1=' + createNewYatUrlParameters;
|
||||
//}
|
||||
|
||||
|
||||
sections = [
|
||||
[
|
||||
SwitcherListItem(
|
||||
title: S.current.settings_display_balance,
|
||||
value: () => balanceDisplayMode == BalanceDisplayMode.displayableBalance,
|
||||
onValueChange: (_, bool value) {
|
||||
if (value) {
|
||||
_settingsStore.balanceDisplayMode = BalanceDisplayMode.displayableBalance;
|
||||
} else {
|
||||
_settingsStore.balanceDisplayMode = BalanceDisplayMode.hiddenBalance;
|
||||
}
|
||||
},
|
||||
),
|
||||
if (!isHaven)
|
||||
PickerListItem(
|
||||
title: S.current.settings_currency,
|
||||
searchHintText: S.current.search_currency,
|
||||
items: FiatCurrency.all,
|
||||
selectedItem: () => fiatCurrency,
|
||||
onItemSelected: (FiatCurrency currency) =>
|
||||
setFiatCurrency(currency),
|
||||
images: FiatCurrency.all.map(
|
||||
(e) => Image.asset("assets/images/flags/${e.countryCode}.png"))
|
||||
.toList(),
|
||||
isGridView: true,
|
||||
matchingCriteria: (FiatCurrency currency, String searchText) {
|
||||
return currency.title.toLowerCase().contains(searchText) || currency.fullName.toLowerCase().contains(searchText);
|
||||
},
|
||||
),
|
||||
PickerListItem(
|
||||
title: S.current.settings_fee_priority,
|
||||
items: priorityForWalletType(wallet.type),
|
||||
displayItem: (dynamic priority) {
|
||||
final _priority = priority as TransactionPriority;
|
||||
|
||||
if (wallet.type == WalletType.bitcoin
|
||||
|| wallet.type == WalletType.litecoin) {
|
||||
final rate = bitcoin!.getFeeRate(wallet, _priority);
|
||||
return bitcoin!.bitcoinTransactionPriorityWithLabel(_priority, rate);
|
||||
}
|
||||
|
||||
return priority.toString();
|
||||
},
|
||||
selectedItem: () => transactionPriority,
|
||||
onItemSelected: (TransactionPriority priority) =>
|
||||
_settingsStore.priority[wallet.type] = priority),
|
||||
SwitcherListItem(
|
||||
title: S.current.settings_save_recipient_address,
|
||||
value: () => shouldSaveRecipientAddress,
|
||||
onValueChange: (_, bool value) =>
|
||||
setShouldSaveRecipientAddress(value))
|
||||
],
|
||||
[
|
||||
RegularListItem(
|
||||
title: S.current.settings_change_pin,
|
||||
handler: (BuildContext context) {
|
||||
Navigator.of(context).pushNamed(Routes.auth, arguments:
|
||||
(bool isAuthenticatedSuccessfully, AuthPageState auth) {
|
||||
auth.close(
|
||||
route: isAuthenticatedSuccessfully ? Routes.setupPin : null,
|
||||
arguments: (PinCodeState<PinCodeWidget> setupPinContext,
|
||||
String _) {
|
||||
setupPinContext.close();
|
||||
},
|
||||
);
|
||||
});
|
||||
}),
|
||||
PickerListItem(
|
||||
title: S.current.settings_change_language,
|
||||
searchHintText: S.current.search_language,
|
||||
items: LanguageService.list.keys.toList(),
|
||||
displayItem: (dynamic code) {
|
||||
return LanguageService.list[code] ?? '';
|
||||
},
|
||||
selectedItem: () => _settingsStore.languageCode,
|
||||
onItemSelected: (String code) {
|
||||
_settingsStore.languageCode = code;
|
||||
},
|
||||
images: LanguageService.list.keys.map(
|
||||
(e) => Image.asset("assets/images/flags/${LanguageService.localeCountryCode[e]}.png"))
|
||||
.toList(),
|
||||
matchingCriteria: (String code, String searchText) {
|
||||
return LanguageService.list[code]?.toLowerCase().contains(searchText) ?? false;
|
||||
},
|
||||
),
|
||||
SwitcherListItem(
|
||||
title: S.current.settings_allow_biometrical_authentication,
|
||||
value: () => allowBiometricalAuthentication,
|
||||
onValueChange: (BuildContext context, bool value) {
|
||||
if (value) {
|
||||
Navigator.of(context).pushNamed(Routes.auth, arguments:
|
||||
(bool isAuthenticatedSuccessfully,
|
||||
AuthPageState auth) async {
|
||||
if (isAuthenticatedSuccessfully) {
|
||||
if (await _biometricAuth.canCheckBiometrics() &&
|
||||
await _biometricAuth.isAuthenticated()) {
|
||||
setAllowBiometricalAuthentication(
|
||||
isAuthenticatedSuccessfully);
|
||||
}
|
||||
} else {
|
||||
setAllowBiometricalAuthentication(
|
||||
isAuthenticatedSuccessfully);
|
||||
}
|
||||
|
||||
auth.close();
|
||||
});
|
||||
} else {
|
||||
setAllowBiometricalAuthentication(value);
|
||||
}
|
||||
}),
|
||||
ChoicesListItem(
|
||||
title: S.current.color_theme,
|
||||
items: ThemeList.all,
|
||||
selectedItem: theme,
|
||||
onItemSelected: (ThemeBase theme) => _settingsStore.currentTheme = theme,
|
||||
),
|
||||
],
|
||||
//[
|
||||
//if (_yatStore.emoji.isNotEmpty) ...[
|
||||
// LinkListItem(
|
||||
// title: S.current.manage_yats,
|
||||
// link: manageYatUrl,
|
||||
// linkTitle: ''),
|
||||
//] else ...[
|
||||
//LinkListItem(
|
||||
// title: S.current.connect_yats,
|
||||
// link: connectYatUrl,
|
||||
// linkTitle: ''),
|
||||
//LinkListItem(
|
||||
// title: 'Create new Yats',
|
||||
// link: createNewYatUrl,
|
||||
// linkTitle: '')
|
||||
//]
|
||||
//],
|
||||
[
|
||||
RegularListItem(
|
||||
title: S.current.settings_terms_and_conditions,
|
||||
handler: (BuildContext context) =>
|
||||
Navigator.of(context).pushNamed(Routes.readDisclaimer),
|
||||
)
|
||||
],
|
||||
[VersionListItem(title: currentVersion)]
|
||||
];
|
||||
}
|
||||
|
||||
@observable
|
||||
String currentVersion;
|
||||
|
||||
@computed
|
||||
Node get node => _settingsStore.getCurrentNode(_walletType);
|
||||
|
||||
@computed
|
||||
FiatCurrency get fiatCurrency => _settingsStore.fiatCurrency;
|
||||
|
||||
@computed
|
||||
ObservableList<ActionListDisplayMode> get actionlistDisplayMode =>
|
||||
_settingsStore.actionlistDisplayMode;
|
||||
|
||||
@computed
|
||||
TransactionPriority get transactionPriority {
|
||||
final priority = _settingsStore.priority[_walletType];
|
||||
|
||||
if (priority == null) {
|
||||
throw Exception('Unexpected type ${_walletType.toString()}');
|
||||
}
|
||||
|
||||
return priority;
|
||||
}
|
||||
|
||||
@computed
|
||||
BalanceDisplayMode get balanceDisplayMode =>
|
||||
_settingsStore.balanceDisplayMode;
|
||||
|
||||
@computed
|
||||
bool get shouldSaveRecipientAddress =>
|
||||
_settingsStore.shouldSaveRecipientAddress;
|
||||
|
||||
@computed
|
||||
bool get allowBiometricalAuthentication =>
|
||||
_settingsStore.allowBiometricalAuthentication;
|
||||
|
||||
@computed
|
||||
ThemeBase get theme => _settingsStore.currentTheme;
|
||||
|
||||
bool get isBitcoinBuyEnabled => _settingsStore.isBitcoinBuyEnabled;
|
||||
|
||||
final Map<String, String> itemHeaders;
|
||||
List<List<SettingsListItem>> sections;
|
||||
final SettingsStore _settingsStore;
|
||||
final YatStore _yatStore;
|
||||
final WalletType _walletType;
|
||||
final BiometricAuth _biometricAuth;
|
||||
|
||||
@action
|
||||
void setBalanceDisplayMode(BalanceDisplayMode value) =>
|
||||
_settingsStore.balanceDisplayMode = value;
|
||||
|
||||
@action
|
||||
void setFiatCurrency(FiatCurrency value) =>
|
||||
_settingsStore.fiatCurrency = value;
|
||||
|
||||
@action
|
||||
void setShouldSaveRecipientAddress(bool value) =>
|
||||
_settingsStore.shouldSaveRecipientAddress = value;
|
||||
|
||||
@action
|
||||
void setAllowBiometricalAuthentication(bool value) =>
|
||||
_settingsStore.allowBiometricalAuthentication = value;
|
||||
|
||||
@action
|
||||
void toggleTransactionsDisplay() =>
|
||||
actionlistDisplayMode.contains(ActionListDisplayMode.transactions)
|
||||
? _hideTransaction()
|
||||
: _showTransaction();
|
||||
|
||||
@action
|
||||
void toggleTradesDisplay() =>
|
||||
actionlistDisplayMode.contains(ActionListDisplayMode.trades)
|
||||
? _hideTrades()
|
||||
: _showTrades();
|
||||
|
||||
@action
|
||||
void _hideTransaction() =>
|
||||
actionlistDisplayMode.remove(ActionListDisplayMode.transactions);
|
||||
|
||||
@action
|
||||
void _hideTrades() =>
|
||||
actionlistDisplayMode.remove(ActionListDisplayMode.trades);
|
||||
|
||||
@action
|
||||
void _showTransaction() =>
|
||||
actionlistDisplayMode.add(ActionListDisplayMode.transactions);
|
||||
|
||||
@action
|
||||
void _showTrades() => actionlistDisplayMode.add(ActionListDisplayMode.trades);
|
||||
}
|
|
@ -184,7 +184,7 @@ abstract class TransactionDetailsViewModelBase with Store {
|
|||
case WalletType.monero:
|
||||
return 'https://monero.com/tx/${txId}';
|
||||
case WalletType.bitcoin:
|
||||
return 'https://www.blockchain.com/btc/tx/${txId}';
|
||||
return 'https://mempool.space/tx/${txId}';
|
||||
case WalletType.litecoin:
|
||||
return 'https://blockchair.com/litecoin/transaction/${txId}';
|
||||
case WalletType.haven:
|
||||
|
@ -199,7 +199,7 @@ abstract class TransactionDetailsViewModelBase with Store {
|
|||
case WalletType.monero:
|
||||
return S.current.view_transaction_on + 'Monero.com';
|
||||
case WalletType.bitcoin:
|
||||
return S.current.view_transaction_on + 'Blockchain.com';
|
||||
return S.current.view_transaction_on + 'mempool.space';
|
||||
case WalletType.litecoin:
|
||||
return S.current.view_transaction_on + 'Blockchair.com';
|
||||
case WalletType.haven:
|
||||
|
|
5
model_generator.sh
Normal file
5
model_generator.sh
Normal file
|
@ -0,0 +1,5 @@
|
|||
cd cw_core && flutter pub get && flutter packages pub run build_runner build --delete-conflicting-outputs && cd ..
|
||||
cd cw_monero && flutter pub get && flutter packages pub run build_runner build --delete-conflicting-outputs && cd ..
|
||||
cd cw_bitcoin && flutter pub get && flutter packages pub run build_runner build --delete-conflicting-outputs && cd ..
|
||||
cd cw_haven && flutter pub get && flutter packages pub run build_runner build --delete-conflicting-outputs && cd ..
|
||||
flutter packages pub run build_runner build --delete-conflicting-outputs
|
|
@ -34,7 +34,7 @@ dependencies:
|
|||
local_auth: ^2.1.0
|
||||
package_info: ^2.0.0
|
||||
#package_info_plus: ^1.4.2
|
||||
devicelocale: ^0.5.4
|
||||
devicelocale: ^0.4.3
|
||||
auto_size_text: ^3.0.0
|
||||
dotted_border: ^2.0.0+2
|
||||
smooth_page_indicator: ^1.0.0+2
|
||||
|
|
|
@ -356,6 +356,7 @@
|
|||
"sync_status_failed_connect" : "GETRENNT",
|
||||
"sync_status_connecting" : "VERBINDEN",
|
||||
"sync_status_connected" : "VERBUNDEN",
|
||||
"sync_status_attempting_sync" : "SYNC VERSUCHEN",
|
||||
|
||||
|
||||
"transaction_priority_slow" : "Langsam",
|
||||
|
@ -436,6 +437,7 @@
|
|||
"provider_error" : "${provider}-Fehler",
|
||||
|
||||
"use_ssl" : "SSL verwenden",
|
||||
"trusted" : "Vertrauenswürdige",
|
||||
|
||||
"color_theme" : "Farbthema",
|
||||
"light_theme" : "Hell",
|
||||
|
@ -651,5 +653,16 @@
|
|||
"ignor": "Ignorieren",
|
||||
"use_suggested": "Vorgeschlagen verwenden",
|
||||
"do_not_share_warning_text" : "Teilen Sie diese nicht mit anderen, einschließlich Support.\n\nIhr Geld kann und wird gestohlen werden!",
|
||||
"help": "hilfe"
|
||||
"help": "hilfe",
|
||||
"connection_sync": "Verbindung und Synchronisierung",
|
||||
"security_and_backup": "Sicherheit und Datensicherung",
|
||||
"create_backup": "Backup erstellen",
|
||||
"privacy_settings": "Datenschutzeinstellungen",
|
||||
"privacy": "Datenschutz",
|
||||
"display_settings": "Anzeigeeinstellungen",
|
||||
"other_settings": "Andere Einstellungen",
|
||||
"disable_exchange": "Exchange deaktivieren",
|
||||
"advanced_privacy_settings": "Erweiterte Datenschutzeinstellungen",
|
||||
"settings_can_be_changed_later": "Diese Einstellungen können später in den App-Einstellungen geändert werden",
|
||||
"add_custom_node": "Neuen benutzerdefinierten Knoten hinzufügen"
|
||||
}
|
||||
|
|
|
@ -356,6 +356,7 @@
|
|||
"sync_status_failed_connect" : "DISCONNECTED",
|
||||
"sync_status_connecting" : "CONNECTING",
|
||||
"sync_status_connected" : "CONNECTED",
|
||||
"sync_status_attempting_sync" : "ATTEMPTING SYNC",
|
||||
|
||||
|
||||
"transaction_priority_slow" : "Slow",
|
||||
|
@ -436,6 +437,7 @@
|
|||
"provider_error" : "${provider} error",
|
||||
|
||||
"use_ssl" : "Use SSL",
|
||||
"trusted" : "Trusted",
|
||||
|
||||
"color_theme" : "Color theme",
|
||||
"light_theme" : "Light",
|
||||
|
@ -651,5 +653,16 @@
|
|||
"ignor": "Ignore",
|
||||
"use_suggested": "Use Suggested",
|
||||
"do_not_share_warning_text" : "Do not share these with anyone else, including support.\n\nYour funds can and will be stolen!",
|
||||
"help": "help"
|
||||
"help": "help",
|
||||
"connection_sync": "Connection and sync",
|
||||
"security_and_backup": "Security and backup",
|
||||
"create_backup": "Create backup",
|
||||
"privacy_settings": "Privacy settings",
|
||||
"privacy": "Privacy",
|
||||
"display_settings": "Display settings",
|
||||
"other_settings": "Other settings",
|
||||
"disable_exchange": "Disable exchange",
|
||||
"advanced_privacy_settings": "Advanced Privacy Settings",
|
||||
"settings_can_be_changed_later": "These settings can be changed later in the app settings",
|
||||
"add_custom_node": "Add New Custom Node"
|
||||
}
|
||||
|
|
|
@ -356,6 +356,7 @@
|
|||
"sync_status_failed_connect" : "DESCONECTADO",
|
||||
"sync_status_connecting" : "CONECTANDO",
|
||||
"sync_status_connected" : "CONECTADO",
|
||||
"sync_status_attempting_sync" : "INTENTAR SINCRONIZAR",
|
||||
|
||||
|
||||
"transaction_priority_slow" : "Lento",
|
||||
|
@ -436,6 +437,7 @@
|
|||
"provider_error" : "${provider} error",
|
||||
|
||||
"use_ssl" : "Utilice SSL",
|
||||
"trusted" : "de confianza",
|
||||
|
||||
"color_theme" : "Tema de color",
|
||||
"light_theme" : "Ligera",
|
||||
|
@ -651,5 +653,16 @@
|
|||
"ignor": "Pasar por alto",
|
||||
"use_suggested": "Usar sugerido",
|
||||
"do_not_share_warning_text" : "No comparta estos con nadie más, incluido el soporte.\n\n¡Sus fondos pueden ser y serán robados!",
|
||||
"help": "ayuda"
|
||||
"help": "ayuda",
|
||||
"connection_sync": "Conexión y sincronización",
|
||||
"security_and_backup": "Seguridad y respaldo",
|
||||
"create_backup": "Crear copia de seguridad",
|
||||
"privacy_settings": "Configuración de privacidad",
|
||||
"privacy": "Privacidad",
|
||||
"display_settings": "Configuración de pantalla",
|
||||
"other_settings": "Otras configuraciones",
|
||||
"disable_exchange": "Deshabilitar intercambio",
|
||||
"advanced_privacy_settings": "Configuración avanzada de privacidad",
|
||||
"settings_can_be_changed_later": "Estas configuraciones se pueden cambiar más tarde en la configuración de la aplicación",
|
||||
"add_custom_node": "Agregar nuevo nodo personalizado"
|
||||
}
|
||||
|
|
|
@ -354,6 +354,7 @@
|
|||
"sync_status_failed_connect" : "DÉCONNECTÉ",
|
||||
"sync_status_connecting" : "CONNEXION EN COURS",
|
||||
"sync_status_connected" : "CONNECTÉ",
|
||||
"sync_status_attempting_sync" : "TENTATIVE DE SYNCHRONISATION",
|
||||
|
||||
|
||||
"transaction_priority_slow" : "Lent",
|
||||
|
@ -434,6 +435,7 @@
|
|||
"provider_error" : "Erreur de ${provider}",
|
||||
|
||||
"use_ssl" : "Utiliser SSL",
|
||||
"trusted" : "de confiance",
|
||||
|
||||
"color_theme" : "Thème",
|
||||
"light_theme" : "Clair",
|
||||
|
@ -649,5 +651,16 @@
|
|||
"ignor": "Ignorer",
|
||||
"use_suggested": "Utilisation suggérée",
|
||||
"do_not_share_warning_text" : "Ne les partagez avec personne d'autre, y compris avec l'assistance.\n\nVos fonds peuvent et seront volés!",
|
||||
"help": "aider"
|
||||
"help": "aider",
|
||||
"connection_sync": "Connexion et synchronisation",
|
||||
"security_and_backup": "Sécurité et sauvegarde",
|
||||
"create_backup": "Créer une sauvegarde",
|
||||
"privacy_settings": "Paramètres de confidentialité",
|
||||
"privacy": "Confidentialité",
|
||||
"display_settings": "Paramètres d'affichage",
|
||||
"other_settings": "Autres paramètres",
|
||||
"disable_exchange": "Désactiver l'échange",
|
||||
"advanced_privacy_settings": "Paramètres de confidentialité avancés",
|
||||
"settings_can_be_changed_later": "Ces paramètres peuvent être modifiés ultérieurement dans les paramètres de l'application",
|
||||
"add_custom_node": "Ajouter un nouveau nœud personnalisé"
|
||||
}
|
||||
|
|
|
@ -356,6 +356,7 @@
|
|||
"sync_status_failed_connect" : "डिस्कनेक्ट किया गया",
|
||||
"sync_status_connecting" : "कनेक्ट",
|
||||
"sync_status_connected" : "जुड़े हुए",
|
||||
"sync_status_attempting_sync" : "सिंक करने का प्रयास",
|
||||
|
||||
|
||||
"transaction_priority_slow" : "धीरे",
|
||||
|
@ -436,6 +437,7 @@
|
|||
"provider_error" : "${provider} त्रुटि",
|
||||
|
||||
"use_ssl" : "उपयोग SSL",
|
||||
"trusted" : "भरोसा",
|
||||
|
||||
"color_theme" : "रंग विषय",
|
||||
"light_theme" : "रोशनी",
|
||||
|
@ -651,5 +653,16 @@
|
|||
"ignor": "नज़रअंदाज़ करना",
|
||||
"use_suggested": "सुझाए गए का प्रयोग करें",
|
||||
"do_not_share_warning_text" : "समर्थन सहित, इन्हें किसी और के साथ साझा न करें।\n\nआपके धन की चोरी हो सकती है और होगी!",
|
||||
"help": "मदद करना"
|
||||
"help": "मदद करना",
|
||||
"connection_sync": "कनेक्शन और सिंक",
|
||||
"security_and_backup": "सुरक्षा और बैकअप",
|
||||
"create_backup": "बैकअप बनाएँ",
|
||||
"privacy_settings": "गोपनीयता सेटिंग्स",
|
||||
"privacy": "गोपनीयता",
|
||||
"display_settings": "प्रदर्शन सेटिंग्स",
|
||||
"other_settings": "अन्य सेटिंग्स",
|
||||
"disable_exchange": "एक्सचेंज अक्षम करें",
|
||||
"advanced_privacy_settings": "उन्नत गोपनीयता सेटिंग्स",
|
||||
"settings_can_be_changed_later": "इन सेटिंग्स को बाद में ऐप सेटिंग में बदला जा सकता है",
|
||||
"add_custom_node": "नया कस्टम नोड जोड़ें"
|
||||
}
|
||||
|
|
|
@ -356,6 +356,7 @@
|
|||
"sync_status_failed_connect" : "ISKLJUČENO",
|
||||
"sync_status_connecting" : "SPAJANJE",
|
||||
"sync_status_connected" : "SPOJENO",
|
||||
"sync_status_attempting_sync" : "POKUŠAJ SINKRONIZACIJE",
|
||||
|
||||
|
||||
"transaction_priority_slow" : "Sporo",
|
||||
|
@ -436,6 +437,7 @@
|
|||
"provider_error" : "${provider} greška",
|
||||
|
||||
"use_ssl" : "Koristi SSL",
|
||||
"trusted" : "vjerovao",
|
||||
|
||||
"color_theme" : "Shema boja",
|
||||
"light_theme" : "Svijetla",
|
||||
|
@ -651,5 +653,16 @@
|
|||
"ignor": "Zanemariti",
|
||||
"use_suggested": "Koristite predloženo",
|
||||
"do_not_share_warning_text" : "Nemojte ih dijeliti ni s kim, uključujući podršku.\n\nVaša sredstva mogu i bit će ukradena!",
|
||||
"help": "pomozite"
|
||||
"help": "pomozite",
|
||||
"connection_sync": "Povezivanje i sinkronizacija",
|
||||
"security_and_backup": "Sigurnost i sigurnosna kopija",
|
||||
"create_backup": "Stvori sigurnosnu kopiju",
|
||||
"privacy_settings": "Postavke privatnosti",
|
||||
"privacy": "Privatnost",
|
||||
"display_settings": "Postavke zaslona",
|
||||
"other_settings": "Ostale postavke",
|
||||
"disable_exchange": "Onemogući exchange",
|
||||
"advanced_privacy_settings": "Napredne postavke privatnosti",
|
||||
"settings_can_be_changed_later": "Te se postavke mogu promijeniti kasnije u postavkama aplikacije",
|
||||
"add_custom_node": "Dodaj novi prilagođeni čvor"
|
||||
}
|
||||
|
|
|
@ -356,6 +356,7 @@
|
|||
"sync_status_failed_connect" : "DISCONNESSO",
|
||||
"sync_status_connecting" : "CONNESSIONE",
|
||||
"sync_status_connected" : "CONNESSO",
|
||||
"sync_status_attempting_sync" : "TENTATIVO DI SINCRONIZZAZIONE",
|
||||
|
||||
|
||||
"transaction_priority_slow" : "Bassa",
|
||||
|
@ -436,6 +437,7 @@
|
|||
"provider_error" : "${provider} errore",
|
||||
|
||||
"use_ssl" : "Usa SSL",
|
||||
"trusted" : "di fiducia",
|
||||
|
||||
"color_theme" : "Colore tema",
|
||||
"light_theme" : "Bianco",
|
||||
|
@ -651,5 +653,16 @@
|
|||
"ignor": "Ignorare",
|
||||
"use_suggested": "Usa suggerito",
|
||||
"do_not_share_warning_text" : "Non condividerli con nessun altro, incluso il supporto.\n\nI tuoi fondi possono e saranno rubati!",
|
||||
"help": "aiuto"
|
||||
"help": "aiuto",
|
||||
"connection_sync": "Connessione e sincronizzazione",
|
||||
"security_and_backup": "Sicurezza e backup",
|
||||
"create_backup": "Crea backup",
|
||||
"privacy_settings": "Impostazioni privacy",
|
||||
"privacy": "Privacy",
|
||||
"display_settings": "Impostazioni di visualizzazione",
|
||||
"other_settings": "Altre impostazioni",
|
||||
"disable_exchange": "Disabilita scambio",
|
||||
"advanced_privacy_settings": "Impostazioni avanzate sulla privacy",
|
||||
"settings_can_be_changed_later": "Queste impostazioni possono essere modificate in seguito nelle impostazioni dell'app",
|
||||
"add_custom_node": "Aggiungi nuovo nodo personalizzato"
|
||||
}
|
||||
|
|
|
@ -356,6 +356,7 @@
|
|||
"sync_status_failed_connect" : "切断されました",
|
||||
"sync_status_connecting" : "接続中",
|
||||
"sync_status_connected" : "接続済み",
|
||||
"sync_status_attempting_sync" : "同期を試みています",
|
||||
|
||||
|
||||
"transaction_priority_slow" : "スロー",
|
||||
|
@ -436,6 +437,7 @@
|
|||
"provider_error" : "${provider} エラー",
|
||||
|
||||
"use_ssl" : "SSLを使用する",
|
||||
"trusted" : "信頼できる",
|
||||
|
||||
"color_theme" : "カラーテーマ",
|
||||
"light_theme" : "光",
|
||||
|
@ -651,5 +653,16 @@
|
|||
"ignor": "無視",
|
||||
"use_suggested": "推奨を使用",
|
||||
"do_not_share_warning_text" : "サポートを含め、これらを他の誰とも共有しないでください。\n\nあなたの資金は盗まれる可能性があります!",
|
||||
"help": "ヘルプ"
|
||||
"help": "ヘルプ",
|
||||
"connection_sync": "接続と同期",
|
||||
"security_and_backup": "セキュリティとバックアップ",
|
||||
"create_backup": "バックアップを作成",
|
||||
"privacy_settings": "プライバシー設定",
|
||||
"privacy": "プライバシー",
|
||||
"display_settings": "表示設定",
|
||||
"other_settings": "その他の設定",
|
||||
"disable_exchange": "交換を無効にする",
|
||||
"advanced_privacy_settings": "高度なプライバシー設定",
|
||||
"settings_can_be_changed_later": "これらの設定は、後でアプリの設定で変更できます",
|
||||
"add_custom_node": "新しいカスタム ノードを追加"
|
||||
}
|
||||
|
|
|
@ -356,6 +356,7 @@
|
|||
"sync_status_failed_connect" : "연결 해제",
|
||||
"sync_status_connecting" : "연결 중",
|
||||
"sync_status_connected" : "연결됨",
|
||||
"sync_status_attempting_sync" : "동기화 시도 중",
|
||||
|
||||
|
||||
"transaction_priority_slow" : "느린",
|
||||
|
@ -436,6 +437,7 @@
|
|||
"provider_error" : "${provider} 오류",
|
||||
|
||||
"use_ssl" : "SSL 사용",
|
||||
"trusted" : "신뢰할 수 있는",
|
||||
|
||||
"color_theme" : "색상 테마",
|
||||
"light_theme" : "빛",
|
||||
|
@ -651,5 +653,16 @@
|
|||
"ignor": "무시하다",
|
||||
"use_suggested": "추천 사용",
|
||||
"do_not_share_warning_text" : "지원을 포함하여 다른 사람과 이러한 정보를 공유하지 마십시오.\n\n귀하의 자금은 도난당할 수 있고 도난당할 수 있습니다!",
|
||||
"help": "돕다"
|
||||
"help": "돕다",
|
||||
"connection_sync": "연결 및 동기화",
|
||||
"security_and_backup": "보안 및 백업",
|
||||
"create_backup": "백업 생성",
|
||||
"privacy_settings": "개인정보 설정",
|
||||
"privacy": "프라이버시",
|
||||
"display_settings": "디스플레이 설정",
|
||||
"other_settings": "기타 설정",
|
||||
"disable_exchange": "교환 비활성화",
|
||||
"advanced_privacy_settings": "고급 개인 정보 설정",
|
||||
"settings_can_be_changed_later": "이 설정은 나중에 앱 설정에서 변경할 수 있습니다.",
|
||||
"add_custom_node": "새 사용자 정의 노드 추가"
|
||||
}
|
||||
|
|
|
@ -356,6 +356,7 @@
|
|||
"sync_status_failed_connect" : "LOSGEKOPPELD",
|
||||
"sync_status_connecting" : "AANSLUITING",
|
||||
"sync_status_connected" : "VERBONDEN",
|
||||
"sync_status_attempting_sync" : "SYNCHRONISATIE PROBEREN",
|
||||
|
||||
|
||||
"transaction_priority_slow" : "Langzaam",
|
||||
|
@ -436,6 +437,7 @@
|
|||
"provider_error" : "${provider} fout",
|
||||
|
||||
"use_ssl" : "Gebruik SSL",
|
||||
"trusted" : "vertrouwd",
|
||||
|
||||
"color_theme" : "Kleur thema",
|
||||
"light_theme" : "Licht",
|
||||
|
@ -651,5 +653,16 @@
|
|||
"ignor": "Negeren",
|
||||
"use_suggested": "Gebruik aanbevolen",
|
||||
"do_not_share_warning_text" : "Deel deze met niemand anders, ook niet met support.\n\nUw geld kan en zal worden gestolen!",
|
||||
"help": "helpen"
|
||||
"help": "helpen",
|
||||
"connection_sync": "Verbinding en synchronisatie",
|
||||
"security_and_backup": "Beveiliging en back-up",
|
||||
"create_backup": "Maak een back-up",
|
||||
"privacy_settings": "Privacy-instellingen",
|
||||
"privacy": "Privacy",
|
||||
"display_settings": "Weergave-instellingen",
|
||||
"other_settings": "Andere instellingen",
|
||||
"disable_exchange": "Uitwisseling uitschakelen",
|
||||
"advanced_privacy_settings": "Geavanceerde privacy-instellingen",
|
||||
"settings_can_be_changed_later": "Deze instellingen kunnen later worden gewijzigd in de app-instellingen",
|
||||
"add_custom_node": "Voeg een nieuw aangepast knooppunt toe"
|
||||
}
|
||||
|
|
|
@ -356,6 +356,7 @@
|
|||
"sync_status_failed_connect" : "NIEPOWIĄZANY",
|
||||
"sync_status_connecting" : "ZŁĄCZONY",
|
||||
"sync_status_connected" : "POŁĄCZONY",
|
||||
"sync_status_attempting_sync" : "PRÓBA SYNCHRONIZACJI",
|
||||
|
||||
|
||||
"transaction_priority_slow" : "Powolny",
|
||||
|
@ -436,6 +437,7 @@
|
|||
"provider_error" : "${provider} pomyłka",
|
||||
|
||||
"use_ssl" : "Użyj SSL",
|
||||
"trusted" : "zaufany",
|
||||
|
||||
"color_theme" : "Motyw kolorystyczny",
|
||||
"light_theme" : "Lekki",
|
||||
|
@ -651,5 +653,16 @@
|
|||
"ignor": "Ignorować",
|
||||
"use_suggested": "Użyj sugerowane",
|
||||
"do_not_share_warning_text" : "Nie udostępniaj ich nikomu innemu, w tym pomocy.\n\nTwoje środki mogą i zostaną skradzione!",
|
||||
"help": "pomoc"
|
||||
"help": "pomoc",
|
||||
"connection_sync": "Połączenie i synchronizacja",
|
||||
"security_and_backup": "Bezpieczeństwo i kopia zapasowa",
|
||||
"create_backup": "Utwórz kopię zapasową",
|
||||
"privacy_settings": "Ustawienia prywatności",
|
||||
"privacy": "Prywatność",
|
||||
"display_settings": "Ustawienia wyświetlania",
|
||||
"other_settings": "Inne ustawienia",
|
||||
"disable_exchange": "Wyłącz wymianę",
|
||||
"advanced_privacy_settings": "Zaawansowane ustawienia prywatności",
|
||||
"settings_can_be_changed_later": "Te ustawienia można później zmienić w ustawieniach aplikacji",
|
||||
"add_custom_node": "Dodaj nowy węzeł niestandardowy"
|
||||
}
|
||||
|
|
|
@ -356,6 +356,7 @@
|
|||
"sync_status_failed_connect" : "DESCONECTADO",
|
||||
"sync_status_connecting" : "CONECTANDO",
|
||||
"sync_status_connected" : "CONECTADO",
|
||||
"sync_status_attempting_sync" : "TENTANDO SINCRONIZAR",
|
||||
|
||||
|
||||
"transaction_priority_slow" : "Lenta",
|
||||
|
@ -436,6 +437,7 @@
|
|||
"provider_error" : "${provider} erro",
|
||||
|
||||
"use_ssl" : "Use SSL",
|
||||
"trusted" : "confiável",
|
||||
|
||||
"color_theme" : "Tema de cor",
|
||||
"light_theme" : "Luz",
|
||||
|
@ -544,7 +546,6 @@
|
|||
"create_account": "Criar conta",
|
||||
"privacy_policy": "Política de privacidade",
|
||||
"welcome_to_cakepay": "Bem-vindo ao Cake Pay!",
|
||||
"create_account": "Registar-se",
|
||||
"forgot_password": "Esqueci a senha",
|
||||
"reset_password": "Redefinir senha",
|
||||
"gift_cards": "Cartões de presente",
|
||||
|
@ -651,5 +652,16 @@
|
|||
"ignor": "Ignorar",
|
||||
"use_suggested": "Uso sugerido",
|
||||
"do_not_share_warning_text" : "Não os compartilhe com mais ninguém, incluindo suporte.\n\nSeus fundos podem e serão roubados!",
|
||||
"help": "ajuda"
|
||||
"help": "ajuda",
|
||||
"connection_sync": "Conexão e sincronização",
|
||||
"security_and_backup": "Segurança e backup",
|
||||
"create_backup": "Criar backup",
|
||||
"privacy_settings": "Configurações de privacidade",
|
||||
"privacy": "Privacidade",
|
||||
"display_settings": "Configurações de exibição",
|
||||
"other_settings": "Outras configurações",
|
||||
"disable_exchange": "Desativar troca",
|
||||
"advanced_privacy_settings": "Configurações de privacidade avançadas",
|
||||
"settings_can_be_changed_later": "Essas configurações podem ser alteradas posteriormente nas configurações do aplicativo",
|
||||
"add_custom_node": "Adicionar novo nó personalizado"
|
||||
}
|
||||
|
|
|
@ -356,6 +356,7 @@
|
|||
"sync_status_failed_connect" : "ОТКЛЮЧЕНО",
|
||||
"sync_status_connecting" : "ПОДКЛЮЧЕНИЕ",
|
||||
"sync_status_connected" : "ПОДКЛЮЧЕНО",
|
||||
"sync_status_attempting_sync" : "ПОПЫТКА СИНХРОНИЗАЦИИ",
|
||||
|
||||
|
||||
"transaction_priority_slow" : "Медленный",
|
||||
|
@ -436,6 +437,7 @@
|
|||
"provider_error" : "${provider} ошибка",
|
||||
|
||||
"use_ssl" : "Использовать SSL",
|
||||
"trusted" : "доверенный",
|
||||
|
||||
"color_theme" : "Цветовая тема",
|
||||
"light_theme" : "Светлая",
|
||||
|
@ -651,5 +653,16 @@
|
|||
"ignor": "Игнорировать",
|
||||
"use_suggested": "Использовать предложенный",
|
||||
"do_not_share_warning_text" : "Не сообщайте их никому, включая техподдержку.\n\nВаши средства могут и будут украдены!",
|
||||
"help": "помощь"
|
||||
"help": "помощь",
|
||||
"connection_sync": "Подключение и синхронизация",
|
||||
"security_and_backup": "Безопасность и резервное копирование",
|
||||
"create_backup": "Создать резервную копию",
|
||||
"privacy_settings": "Настройки конфиденциальности",
|
||||
"privacy": "Конфиденциальность",
|
||||
"display_settings": "Настройки отображения",
|
||||
"other_settings": "Другие настройки",
|
||||
"disable_exchange": "Отключить обмен",
|
||||
"advanced_privacy_settings": "Расширенные настройки конфиденциальности",
|
||||
"settings_can_be_changed_later": "Эти настройки можно изменить позже в настройках приложения.",
|
||||
"add_custom_node": "Добавить новый пользовательский узел"
|
||||
}
|
||||
|
|
|
@ -355,6 +355,7 @@
|
|||
"sync_status_failed_connect" : "ВІДКЛЮЧЕНО",
|
||||
"sync_status_connecting" : "ПІДКЛЮЧЕННЯ",
|
||||
"sync_status_connected" : "ПІДКЛЮЧЕНО",
|
||||
"sync_status_attempting_sync" : "СПРОБА СИНХРОНІЗАЦІЇ",
|
||||
|
||||
|
||||
"transaction_priority_slow" : "Повільний",
|
||||
|
@ -435,6 +436,7 @@
|
|||
"provider_error" : "${provider} помилка",
|
||||
|
||||
"use_ssl" : "Використати SSL",
|
||||
"trusted" : "довіряють",
|
||||
|
||||
"color_theme" : "Кольорова тема",
|
||||
"light_theme" : "Світла",
|
||||
|
@ -650,5 +652,16 @@
|
|||
"ignor": "Ігнорувати",
|
||||
"use_suggested": "Використати запропоноване",
|
||||
"do_not_share_warning_text" : "Не діліться цим нікому, включно зі службою підтримки.\n\nВаші кошти можуть і будуть вкрадені!",
|
||||
"help": "допомога"
|
||||
"help": "допомога",
|
||||
"connection_sync": "Підключення та синхронізація",
|
||||
"security_and_backup": "Безпека та резервне копіювання",
|
||||
"create_backup": "Створити резервну копію",
|
||||
"privacy_settings": "Налаштування конфіденційності",
|
||||
"privacy": "Конфіденційність",
|
||||
"display_settings": "Налаштування дисплея",
|
||||
"other_settings": "Інші налаштування",
|
||||
"disable_exchange": "Вимкнути exchange",
|
||||
"advanced_privacy_settings": "Розширені налаштування конфіденційності",
|
||||
"settings_can_be_changed_later": "Ці параметри можна змінити пізніше в налаштуваннях програми",
|
||||
"add_custom_node": "Додати новий спеціальний вузол"
|
||||
}
|
||||
|
|
|
@ -356,6 +356,7 @@
|
|||
"sync_status_failed_connect" : "断线",
|
||||
"sync_status_connecting" : "连接中",
|
||||
"sync_status_connected" : "已连接",
|
||||
"sync_status_attempting_sync" : "嘗試同步",
|
||||
|
||||
|
||||
"transaction_priority_slow" : "慢速",
|
||||
|
@ -435,6 +436,7 @@
|
|||
"provider_error" : "${provider} 错误",
|
||||
|
||||
"use_ssl" : "使用SSL",
|
||||
"trusted" : "值得信赖",
|
||||
|
||||
"color_theme" : "主题",
|
||||
"light_theme" : "艳丽",
|
||||
|
@ -649,5 +651,16 @@
|
|||
"ignor": "忽视",
|
||||
"use_suggested": "使用建议",
|
||||
"do_not_share_warning_text" : "请勿与其他任何人分享这些信息,包括支持人员。\n\n您的资金可能而且将会被盗!",
|
||||
"help": "帮助"
|
||||
"help": "帮助",
|
||||
"connection_sync": "连接和同步",
|
||||
"security_and_backup": "安全和备份",
|
||||
"create_backup": "创建备份",
|
||||
"privacy_settings": "隐私设置",
|
||||
"privacy":"隐私",
|
||||
"display_settings": "显示设置",
|
||||
"other_settings": "其他设置",
|
||||
"disable_exchange": "禁用交换",
|
||||
"advanced_privacy_settings": "高级隐私设置",
|
||||
"settings_can_be_changed_later": "稍后可以在应用设置中更改这些设置",
|
||||
"add_custom_node": "添加新的自定义节点"
|
||||
}
|
||||
|
|
|
@ -14,14 +14,14 @@ TYPES=($MONERO_COM $CAKEWALLET $HAVEN)
|
|||
APP_ANDROID_TYPE=$1
|
||||
|
||||
MONERO_COM_NAME="Monero.com"
|
||||
MONERO_COM_VERSION="1.2.0"
|
||||
MONERO_COM_BUILD_NUMBER=28
|
||||
MONERO_COM_VERSION="1.2.1"
|
||||
MONERO_COM_BUILD_NUMBER=32
|
||||
MONERO_COM_BUNDLE_ID="com.monero.app"
|
||||
MONERO_COM_PACKAGE="com.monero.app"
|
||||
|
||||
CAKEWALLET_NAME="Cake Wallet"
|
||||
CAKEWALLET_VERSION="4.5.0"
|
||||
CAKEWALLET_BUILD_NUMBER=132
|
||||
CAKEWALLET_VERSION="4.5.1"
|
||||
CAKEWALLET_BUILD_NUMBER=136
|
||||
CAKEWALLET_BUNDLE_ID="com.cakewallet.cake_wallet"
|
||||
CAKEWALLET_PACKAGE="com.cakewallet.cake_wallet"
|
||||
|
||||
|
|
|
@ -13,13 +13,13 @@ TYPES=($MONERO_COM $CAKEWALLET $HAVEN)
|
|||
APP_IOS_TYPE=$1
|
||||
|
||||
MONERO_COM_NAME="Monero.com"
|
||||
MONERO_COM_VERSION="1.2.0"
|
||||
MONERO_COM_BUILD_NUMBER=28
|
||||
MONERO_COM_VERSION="1.2.1"
|
||||
MONERO_COM_BUILD_NUMBER=29
|
||||
MONERO_COM_BUNDLE_ID="com.cakewallet.monero"
|
||||
|
||||
CAKEWALLET_NAME="Cake Wallet"
|
||||
CAKEWALLET_VERSION="4.5.0"
|
||||
CAKEWALLET_BUILD_NUMBER=132
|
||||
CAKEWALLET_VERSION="4.5.1"
|
||||
CAKEWALLET_BUILD_NUMBER=133
|
||||
CAKEWALLET_BUNDLE_ID="com.fotolockr.cakewallet"
|
||||
|
||||
HAVEN_NAME="Haven"
|
||||
|
|
|
@ -28,6 +28,7 @@ class SecretKey {
|
|||
SecretKey('simpleSwapApiKey', () => ''),
|
||||
SecretKey('anypayToken', () => ''),
|
||||
SecretKey('onramperApiKey', () => ''),
|
||||
SecretKey('ioniaClientId', () => ''),
|
||||
];
|
||||
|
||||
final String name;
|
||||
|
|
Loading…
Reference in a new issue