Merge branch 'main' of https://github.com/cake-tech/cake_wallet into CW-180-advanced-startup-privacy-settings

 Conflicts:
	lib/di.dart
	lib/routes.dart
	lib/view_model/node_list/node_create_or_edit_view_model.dart
	res/values/strings_de.arb
	res/values/strings_en.arb
	res/values/strings_es.arb
	res/values/strings_fr.arb
	res/values/strings_hi.arb
	res/values/strings_hr.arb
	res/values/strings_it.arb
	res/values/strings_ja.arb
	res/values/strings_ko.arb
	res/values/strings_nl.arb
	res/values/strings_pl.arb
	res/values/strings_pt.arb
	res/values/strings_ru.arb
	res/values/strings_uk.arb
	res/values/strings_zh.arb
This commit is contained in:
OmarHatem 2022-12-04 04:34:32 +02:00
commit f792b58338
80 changed files with 1470 additions and 1161 deletions
.github/workflows
android/app
assets
cw_bitcoin/lib
cw_core/lib
cw_haven
cw_monero
howto-build-android.md
lib
model_generator.shpubspec_base.yaml
res/values
scripts
tool/utils

129
.github/workflows/pr_test_build.yml vendored Normal file
View 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/

View file

@ -46,7 +46,7 @@ android {
defaultConfig { defaultConfig {
applicationId appProperties['id'] applicationId appProperties['id']
minSdkVersion 21 minSdkVersion 21
targetSdkVersion 30 targetSdkVersion 31
versionCode flutterVersionCode.toInteger() versionCode flutterVersionCode.toInteger()
versionName flutterVersionName versionName flutterVersionName
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"

View file

@ -21,7 +21,8 @@
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode" android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="true" android:hardwareAccelerated="true"
android:windowSoftInputMode="adjustResize" android:windowSoftInputMode="adjustResize"
android:screenOrientation="portrait"> android:screenOrientation="portrait"
android:exported="true">
<meta-data <meta-data
android:name="io.flutter.embedding.android.SplashScreenDrawable" android:name="io.flutter.embedding.android.SplashScreenDrawable"
android:resource="@drawable/launch_background" android:resource="@drawable/launch_background"

View file

@ -1,31 +1,24 @@
- -
uri: xmr-node-uk.cakewallet.com:18081 uri: xmr-node.cakewallet.com:18081
is_default: true is_default: true
- -
uri: xmr-node-eu.cakewallet.com:18081 uri: cakexmrl7bonq7ovjka5kuwuyd3f7qnkz6z6s6dmsy3uckwra7bvggyd.onion:18081
is_default: false 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 is_default: false
- -
uri: node.moneroworld.com:18089 uri: node.moneroworld.com:18089
is_default: false 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

View file

@ -129,7 +129,7 @@ abstract class ElectrumWalletBase extends WalletBase<ElectrumBalance,
@override @override
Future<void> startSync() async { Future<void> startSync() async {
try { try {
syncStatus = StartingSyncStatus(); syncStatus = AttemptingSyncStatus();
await walletAddresses.discoverAddresses(); await walletAddresses.discoverAddresses();
await updateTransactions(); await updateTransactions();
_subscribeForUpdates(); _subscribeForUpdates();

View file

@ -109,28 +109,28 @@ class Node extends HiveObject with Keyable {
final rpcUri = isSSL ? Uri.https(uri.authority, path) : Uri.http(uri.authority, path); final rpcUri = isSSL ? Uri.https(uri.authority, path) : Uri.http(uri.authority, path);
final realm = 'monero-rpc'; final realm = 'monero-rpc';
final body = { final body = {
'jsonrpc': '2.0', 'jsonrpc': '2.0',
'id': '0', 'id': '0',
'method': 'get_info' 'method': 'get_info'
}; };
try { try {
final authenticatingClient = HttpClient(); final authenticatingClient = HttpClient();
authenticatingClient.addCredentials( authenticatingClient.addCredentials(
rpcUri, rpcUri,
realm, realm,
HttpClientDigestCredentials(login ?? '', password ?? ''), HttpClientDigestCredentials(login ?? '', password ?? ''),
); );
final http.Client client = ioc.IOClient(authenticatingClient); final http.Client client = ioc.IOClient(authenticatingClient);
final response = await client.post( final response = await client.post(
rpcUri, rpcUri,
headers: {'Content-Type': 'application/json'}, headers: {'Content-Type': 'application/json'},
body: json.encode(body), body: json.encode(body),
); );
client.close(); client.close();
final resBody = json.decode(response.body) as Map<String, dynamic>; final resBody = json.decode(response.body) as Map<String, dynamic>;

View file

@ -28,7 +28,7 @@ class NotConnectedSyncStatus extends SyncStatus {
double progress() => 0.0; double progress() => 0.0;
} }
class StartingSyncStatus extends SyncStatus { class AttemptingSyncStatus extends SyncStatus {
@override @override
double progress() => 0.0; double progress() => 0.0;
} }

View file

@ -927,6 +927,16 @@ extern "C"
return static_cast<int32_t>(rates.size()); 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 #ifdef __cplusplus
} }
#endif #endif

View file

@ -137,4 +137,8 @@ typedef get_rate = Pointer<Int64> Function();
typedef size_of_rate = Int32 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();

View file

@ -135,4 +135,8 @@ typedef GetRate = Pointer<Int64> Function();
typedef SizeOfRate = int Function(); typedef SizeOfRate = int Function();
typedef UpdateRate = void Function(); typedef UpdateRate = void Function();
typedef SetTrustedDaemon = void Function(int);
typedef TrustedDaemon = int Function();

View file

@ -116,6 +116,14 @@ final rescanBlockchainAsyncNative = havenApi
.lookup<NativeFunction<rescan_blockchain>>('rescan_blockchain') .lookup<NativeFunction<rescan_blockchain>>('rescan_blockchain')
.asFunction<RescanBlockchainAsync>(); .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(); int getSyncingHeight() => getSyncingHeightNative();
bool isNeededToRefresh() => isNeededToRefreshNative() != 0; bool isNeededToRefresh() => isNeededToRefreshNative() != 0;
@ -351,3 +359,7 @@ Future<bool> isConnected() => compute(_isConnected, 0);
Future<int> getNodeHeight() => compute(_getNodeHeight, 0); Future<int> getNodeHeight() => compute(_getNodeHeight, 0);
void rescanBlockchainAsync() => rescanBlockchainAsyncNative(); void rescanBlockchainAsync() => rescanBlockchainAsyncNative();
Future setTrustedDaemon(bool trusted) async => setTrustedDaemonNative(_boolToInt(trusted));
Future<bool> trustedDaemon() async => trustedDaemonNative() != 0;

View file

@ -121,6 +121,8 @@ abstract class HavenWalletBase extends WalletBase<MoneroBalance,
password: node.password, password: node.password,
useSSL: node.useSSL ?? false, useSSL: node.useSSL ?? false,
isLightWallet: false); // FIXME: hardcoded value isLightWallet: false); // FIXME: hardcoded value
haven_wallet.setTrustedDaemon(node.trusted);
syncStatus = ConnectedSyncStatus(); syncStatus = ConnectedSyncStatus();
} catch (e) { } catch (e) {
syncStatus = FailedSyncStatus(); syncStatus = FailedSyncStatus();
@ -135,7 +137,7 @@ abstract class HavenWalletBase extends WalletBase<MoneroBalance,
} catch (_) {} } catch (_) {}
try { try {
syncStatus = StartingSyncStatus(); syncStatus = AttemptingSyncStatus();
haven_wallet.startRefresh(); haven_wallet.startRefresh();
_setListeners(); _setListeners();
_listener?.start(); _listener?.start();

View file

@ -783,6 +783,16 @@ extern "C"
return strdup(get_current_wallet()->getSubaddressLabel(accountIndex, addressIndex).c_str()); 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 #ifdef __cplusplus
} }
#endif #endif

View file

@ -30,6 +30,9 @@ void set_refresh_from_block_height(uint64_t height);
void set_recovering_from_seed(bool is_recovery); void set_recovering_from_seed(bool is_recovery);
void store(char *path); void store(char *path);
void set_trusted_daemon(bool arg);
bool trusted_daemon();
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View file

@ -125,4 +125,8 @@ typedef rescan_blockchain = Void Function();
typedef get_subaddress_label = Pointer<Utf8> Function( typedef get_subaddress_label = Pointer<Utf8> Function(
Int32 accountIndex, Int32 accountIndex,
Int32 addressIndex); Int32 addressIndex);
typedef set_trusted_daemon = Void Function(Int8 trusted);
typedef trusted_daemon = Int8 Function();

View file

@ -123,4 +123,8 @@ typedef RescanBlockchainAsync = void Function();
typedef GetSubaddressLabel = Pointer<Utf8> Function( typedef GetSubaddressLabel = Pointer<Utf8> Function(
int accountIndex, int accountIndex,
int addressIndex); int addressIndex);
typedef SetTrustedDaemon = void Function(int);
typedef TrustedDaemon = int Function();

View file

@ -120,6 +120,14 @@ final getSubaddressLabelNative = moneroApi
.lookup<NativeFunction<get_subaddress_label>>('get_subaddress_label') .lookup<NativeFunction<get_subaddress_label>>('get_subaddress_label')
.asFunction<GetSubaddressLabel>(); .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(); int getSyncingHeight() => getSyncingHeightNative();
bool isNeededToRefresh() => isNeededToRefreshNative() != 0; bool isNeededToRefresh() => isNeededToRefreshNative() != 0;
@ -359,4 +367,8 @@ void rescanBlockchainAsync() => rescanBlockchainAsyncNative();
String getSubaddressLabel(int accountIndex, int addressIndex) { String getSubaddressLabel(int accountIndex, int addressIndex) {
return convertUTF8ToString(pointer: getSubaddressLabelNative(accountIndex, addressIndex)); return convertUTF8ToString(pointer: getSubaddressLabelNative(accountIndex, addressIndex));
} }
Future setTrustedDaemon(bool trusted) async => setTrustedDaemonNative(_boolToInt(trusted));
Future<bool> trustedDaemon() async => trustedDaemonNative() != 0;

View file

@ -136,6 +136,8 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
password: node.password, password: node.password,
useSSL: node.isSSL, useSSL: node.isSSL,
isLightWallet: false); // FIXME: hardcoded value isLightWallet: false); // FIXME: hardcoded value
monero_wallet.setTrustedDaemon(node.trusted);
syncStatus = ConnectedSyncStatus(); syncStatus = ConnectedSyncStatus();
} catch (e) { } catch (e) {
syncStatus = FailedSyncStatus(); syncStatus = FailedSyncStatus();
@ -150,7 +152,7 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
} catch (_) {} } catch (_) {}
try { try {
syncStatus = StartingSyncStatus(); syncStatus = AttemptingSyncStatus();
monero_wallet.startRefresh(); monero_wallet.startRefresh();
_setListeners(); _setListeners();
_listener?.start(); _listener?.start();

View file

@ -55,7 +55,7 @@ You may download and install the latest version of Android Studio [here](https:/
### 3. Installing Flutter ### 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 ### 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. 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): 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 toolchain - develop for Android devices (Android SDK version 28)
[✓] Android Studio (version 4.0) [✓] 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 ..` `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: Finally build mobx models for the app:
`$ flutter packages pub run build_runner build --delete-conflicting-outputs` `$ flutter packages pub run build_runner build --delete-conflicting-outputs`

View file

@ -14,8 +14,8 @@ String syncStatusTitle(SyncStatus syncStatus) {
return S.current.sync_status_not_connected; return S.current.sync_status_not_connected;
} }
if (syncStatus is StartingSyncStatus) { if (syncStatus is AttemptingSyncStatus) {
return S.current.sync_status_starting_sync; return S.current.sync_status_attempting_sync;
} }
if (syncStatus is FailedSyncStatus) { if (syncStatus is FailedSyncStatus) {

View file

@ -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_gift_card.dart';
import 'package:cake_wallet/ionia/ionia_tip.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/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_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_gift_card_detail_page.dart';
import 'package:cake_wallet/src/screens/ionia/cards/ionia_more_options_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_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_buy_card_view_model.dart';
import 'package:cake_wallet/view_model/ionia/ionia_custom_tip_view_model.dart'; import 'package:cake_wallet/view_model/ionia/ionia_custom_tip_view_model.dart';
@ -26,7 +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_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_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/ionia/ionia_purchase_merch_view_model.dart';
import 'package:cake_wallet/view_model/privacy_settings_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/privacy_settings_view_model.dart'
import 'package:cw_core/unspent_coins_info.dart'; import 'package:cw_core/unspent_coins_info.dart';
import 'package:cake_wallet/core/backup_service.dart'; import 'package:cake_wallet/core/backup_service.dart';
import 'package:cw_core/wallet_service.dart'; import 'package:cw_core/wallet_service.dart';
@ -50,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/faq/faq_page.dart';
import 'package:cake_wallet/src/screens/new_wallet/new_wallet_type_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/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/order_details/order_details_page.dart';
import 'package:cake_wallet/src/screens/pin_code/pin_code_widget.dart'; import 'package:cake_wallet/src/screens/pin_code/pin_code_widget.dart';
import 'package:cake_wallet/src/screens/rescan/rescan_page.dart'; import 'package:cake_wallet/src/screens/rescan/rescan_page.dart';
@ -60,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/pre_seed_page.dart';
import 'package:cake_wallet/src/screens/seed/wallet_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/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/setup_pin_code/setup_pin_code.dart';
import 'package:cake_wallet/src/screens/support/support_page.dart'; import 'package:cake_wallet/src/screens/support/support_page.dart';
import 'package:cake_wallet/src/screens/trade_details/trade_details_page.dart'; import 'package:cake_wallet/src/screens/trade_details/trade_details_page.dart';
@ -116,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_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/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/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_keys_view_model.dart';
import 'package:cake_wallet/view_model/wallet_list/wallet_list_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'; import 'package:cake_wallet/view_model/wallet_restore_view_model.dart';
@ -378,8 +384,7 @@ Future setup(
_transactionDescriptionBox)); _transactionDescriptionBox));
getIt.registerFactory( getIt.registerFactory(
() => SendPage(sendViewModel: getIt.get<SendViewModel>(), () => SendPage(sendViewModel: getIt.get<SendViewModel>()));
settingsViewModel: getIt.get<SettingsViewModel>()));
getIt.registerFactory(() => SendTemplatePage( getIt.registerFactory(() => SendTemplatePage(
sendTemplateViewModel: getIt.get<SendTemplateViewModel>())); sendTemplateViewModel: getIt.get<SendTemplateViewModel>()));
@ -435,12 +440,20 @@ Future setup(
getIt.get<MoneroAccountEditOrCreateViewModel>(param1: account))); getIt.get<MoneroAccountEditOrCreateViewModel>(param1: account)));
getIt.registerFactory(() { getIt.registerFactory(() {
final appStore = getIt.get<AppStore>(); return DisplaySettingsViewModel(getIt.get<SettingsStore>());
final yatStore = getIt.get<YatStore>();
return SettingsViewModel(appStore.settingsStore, yatStore, appStore.wallet!);
}); });
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 getIt
.registerFactory(() => WalletSeedViewModel(getIt.get<AppStore>().wallet!)); .registerFactory(() => WalletSeedViewModel(getIt.get<AppStore>().wallet!));
@ -476,7 +489,15 @@ Future setup(
_nodeSource, appStore.wallet!, appStore.settingsStore); _nodeSource, appStore.wallet!, appStore.settingsStore);
}); });
getIt.registerFactory(() => NodeListPage(getIt.get<NodeListViewModel>())); getIt.registerFactory(() => ConnectionSyncPage(getIt.get<NodeListViewModel>(), getIt.get<DashboardViewModel>()));
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>( getIt.registerFactoryParam<NodeCreateOrEditViewModel, WalletType?, void>(
(WalletType? type, _) => (WalletType? type, _) =>
@ -496,7 +517,6 @@ Future setup(
getIt.get<TradesStore>(), getIt.get<TradesStore>(),
getIt.get<AppStore>().settingsStore, getIt.get<AppStore>().settingsStore,
getIt.get<SharedPreferences>(), getIt.get<SharedPreferences>(),
getIt.get<SettingsViewModel>(),
)); ));
getIt.registerFactory(() => ExchangeTradeViewModel( getIt.registerFactory(() => ExchangeTradeViewModel(
@ -703,6 +723,7 @@ Future setup(
ioniaAnyPayService: getIt.get<IoniaAnyPay>(), ioniaAnyPayService: getIt.get<IoniaAnyPay>(),
amount: amount, amount: amount,
ioniaMerchant: merchant, ioniaMerchant: merchant,
sendViewModel: getIt.get<SendViewModel>()
); );
}); });
@ -796,7 +817,7 @@ Future setup(
=> IoniaPaymentStatusPage(getIt.get<IoniaPaymentStatusViewModel>(param1: paymentInfo, param2: committedInfo))); => IoniaPaymentStatusPage(getIt.get<IoniaPaymentStatusViewModel>(param1: paymentInfo, param2: committedInfo)));
getIt.registerFactoryParam<PrivacySettingsViewModel, WalletType, void>((type, _) => getIt.registerFactoryParam<PrivacySettingsViewModel, WalletType, void>((type, _) =>
PrivacySettingsViewModel(type)); PrivacySettingsViewModel(type))
_isSetupFinished = true; _isSetupFinished = true;
} }

View file

@ -69,6 +69,8 @@ Future defaultSettingsMigration(
sharedPreferences: sharedPreferences, nodes: nodes); sharedPreferences: sharedPreferences, nodes: nodes);
await changeLitecoinCurrentElectrumServerToDefault( await changeLitecoinCurrentElectrumServerToDefault(
sharedPreferences: sharedPreferences, nodes: nodes); sharedPreferences: sharedPreferences, nodes: nodes);
await changeHavenCurrentNodeToDefault(
sharedPreferences: sharedPreferences, nodes: nodes);
break; break;
case 2: case 2:
@ -133,19 +135,32 @@ Future defaultSettingsMigration(
await changeDefaultHavenNode(nodes); await changeDefaultHavenNode(nodes);
break; break;
case 18:
await addOnionNode(nodes);
break;
default: default:
break; break;
} }
await sharedPreferences.setInt( await sharedPreferences.setInt(
'current_default_settings_migration_version', version); PreferencesKey.currentDefaultSettingsMigrationVersion, version);
} catch (e) { } catch (e) {
print('Migration error: ${e.toString()}'); print('Migration error: ${e.toString()}');
} }
}); });
await sharedPreferences.setInt( 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 { Future<void> replaceNodesMigration({required Box<Node> nodes}) async {
@ -176,7 +191,7 @@ Future<void> changeMoneroCurrentNodeToDefault(
final node = getMoneroDefaultNode(nodes: nodes); final node = getMoneroDefaultNode(nodes: nodes);
final nodeId = node?.key as int ?? 0; // 0 - England 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}) { Node? getBitcoinDefaultElectrumServer({required Box<Node> nodes}) {
@ -223,7 +238,7 @@ Future<void> changeBitcoinCurrentElectrumServerToDefault(
final server = getBitcoinDefaultElectrumServer(nodes: nodes); final server = getBitcoinDefaultElectrumServer(nodes: nodes);
final serverId = server?.key as int ?? 0; final serverId = server?.key as int ?? 0;
await sharedPreferences.setInt('current_node_id_btc', serverId); await sharedPreferences.setInt(PreferencesKey.currentBitcoinElectrumSererIdKey, serverId);
} }
Future<void> changeLitecoinCurrentElectrumServerToDefault( Future<void> changeLitecoinCurrentElectrumServerToDefault(
@ -232,7 +247,7 @@ Future<void> changeLitecoinCurrentElectrumServerToDefault(
final server = getLitecoinDefaultElectrumServer(nodes: nodes); final server = getLitecoinDefaultElectrumServer(nodes: nodes);
final serverId = server?.key as int ?? 0; final serverId = server?.key as int ?? 0;
await sharedPreferences.setInt('current_node_id_ltc', serverId); await sharedPreferences.setInt(PreferencesKey.currentLitecoinElectrumSererIdKey, serverId);
} }
Future<void> changeHavenCurrentNodeToDefault( Future<void> changeHavenCurrentNodeToDefault(
@ -252,7 +267,7 @@ Future<void> replaceDefaultNode(
'eu-node.cakewallet.io:18081', 'eu-node.cakewallet.io:18081',
'node.cakewallet.io:18081' 'node.cakewallet.io:18081'
]; ];
final currentNodeId = sharedPreferences.getInt('current_node_id'); final currentNodeId = sharedPreferences.getInt(PreferencesKey.currentNodeIdKey);
final currentNode = final currentNode =
nodes.values.firstWhereOrNull((Node node) => node.key == currentNodeId); nodes.values.firstWhereOrNull((Node node) => node.key == currentNodeId);
final needToReplace = final needToReplace =
@ -277,17 +292,29 @@ Future<void> updateNodeTypes({required Box<Node> nodes}) async {
Future<void> addBitcoinElectrumServerList({required Box<Node> nodes}) async { Future<void> addBitcoinElectrumServerList({required Box<Node> nodes}) async {
final serverList = await loadBitcoinElectrumServerList(); 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 { Future<void> addLitecoinElectrumServerList({required Box<Node> nodes}) async {
final serverList = await loadLitecoinElectrumServerList(); 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 { Future<void> addHavenNodeList({required Box<Node> nodes}) async {
final nodeList = await loadDefaultHavenNodes(); 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( Future<void> addAddressesForMoneroWallets(
@ -431,7 +458,7 @@ Future<void> resetBitcoinElectrumServer(
final oldElectrumServer = nodeSource.values.firstWhereOrNull( final oldElectrumServer = nodeSource.values.firstWhereOrNull(
(node) => node.uri.toString().contains('electrumx.cakewallet.com')); (node) => node.uri.toString().contains('electrumx.cakewallet.com'));
var cakeWalletNode = nodeSource.values.firstWhereOrNull( var cakeWalletNode = nodeSource.values.firstWhereOrNull(
(node) => node.uri.toString() == cakeWalletBitcoinElectrumUri); (node) => node.uriRaw.toString() == cakeWalletBitcoinElectrumUri);
if (cakeWalletNode == null) { if (cakeWalletNode == null) {
cakeWalletNode = cakeWalletNode =

View file

@ -11,6 +11,7 @@ class PreferencesKey {
static const shouldSaveRecipientAddressKey = 'save_recipient_address'; static const shouldSaveRecipientAddressKey = 'save_recipient_address';
static const allowBiometricalAuthenticationKey = static const allowBiometricalAuthenticationKey =
'allow_biometrical_authentication'; 'allow_biometrical_authentication';
static const disableExchangeKey = 'disable_exchange';
static const currentTheme = 'current_theme'; static const currentTheme = 'current_theme';
static const isDarkThemeLegacy = 'dark_theme'; static const isDarkThemeLegacy = 'dark_theme';
static const displayActionListModeKey = 'display_list_mode'; static const displayActionListModeKey = 'display_list_mode';

View 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 [];
}
}

View file

@ -114,7 +114,7 @@ class ChangeNowExchangeProvider extends ExchangeProvider {
final uri = Uri.https(apiAuthority, createTradePath); final uri = Uri.https(apiAuthority, createTradePath);
final response = await post(uri, headers: headers, body: json.encode(body)); final response = await post(uri, headers: headers, body: json.encode(body));
if (response.statusCode == 400) { if (response.statusCode == 400) {
final responseJSON = json.decode(response.body) as Map<String, dynamic>; final responseJSON = json.decode(response.body) as Map<String, dynamic>;
final error = responseJSON['error'] as String; final error = responseJSON['error'] as String;
@ -130,7 +130,7 @@ class ChangeNowExchangeProvider extends ExchangeProvider {
final id = responseJSON['id'] as String; final id = responseJSON['id'] as String;
final inputAddress = responseJSON['payinAddress'] as String; final inputAddress = responseJSON['payinAddress'] as String;
final refundAddress = responseJSON['refundAddress'] as String; final refundAddress = responseJSON['refundAddress'] as String;
final extraId = responseJSON['payinExtraId'] as String; final extraId = responseJSON['payinExtraId'] as String?;
return Trade( return Trade(
id: id, id: id,

View file

@ -128,7 +128,7 @@ Future<void> main() async {
exchangeTemplates: exchangeTemplates, exchangeTemplates: exchangeTemplates,
transactionDescriptions: transactionDescriptions, transactionDescriptions: transactionDescriptions,
secureStorage: secureStorage, secureStorage: secureStorage,
initialMigrationVersion: 17); initialMigrationVersion: 18);
runApp(App()); runApp(App());
} catch (e, stacktrace) { } catch (e, stacktrace) {
runApp(MaterialApp( runApp(MaterialApp(

View file

@ -5,6 +5,10 @@ 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/buy_webview_page.dart';
import 'package:cake_wallet/src/screens/buy/onramper_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/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_cards_page.dart';
import 'package:cake_wallet/src/screens/ionia/cards/ionia_account_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_redeem_page.dart';
@ -17,6 +21,7 @@ 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/restore_from_backup_page.dart';
import 'package:cake_wallet/src/screens/restore/wallet_restore_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/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/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_details_page.dart';
import 'package:cake_wallet/src/screens/unspent_coins/unspent_coins_list_page.dart'; import 'package:cake_wallet/src/screens/unspent_coins/unspent_coins_list_page.dart';
@ -39,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/seed/wallet_seed_page.dart';
import 'package:cake_wallet/src/screens/auth/auth_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/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/receive/receive_page.dart';
import 'package:cake_wallet/src/screens/subaddress/address_edit_or_create_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'; import 'package:cake_wallet/src/screens/wallet_list/wallet_list_page.dart';
@ -59,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/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/restore/restore_wallet_from_seed_details.dart';
import 'package:cake_wallet/src/screens/exchange/exchange_page.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/rescan/rescan_page.dart';
import 'package:cake_wallet/src/screens/faq/faq_page.dart'; import 'package:cake_wallet/src/screens/faq/faq_page.dart';
import 'package:cake_wallet/src/screens/trade_details/trade_details_page.dart'; import 'package:cake_wallet/src/screens/trade_details/trade_details_page.dart';
@ -277,10 +280,26 @@ Route<dynamic> createRoute(RouteSettings settings) {
param2: false), param2: false),
onWillPop: () async => false)); onWillPop: () async => false));
case Routes.nodeList: case Routes.connectionSync:
return CupertinoPageRoute<void>( 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: case Routes.newNode:
return CupertinoPageRoute<void>( return CupertinoPageRoute<void>(
builder: (_) => getIt.get<NodeCreateOrEditPage>()); builder: (_) => getIt.get<NodeCreateOrEditPage>());
@ -363,9 +382,6 @@ Route<dynamic> createRoute(RouteSettings settings) {
return CupertinoPageRoute<void>( return CupertinoPageRoute<void>(
builder: (_) => getIt.get<ExchangeTemplatePage>()); builder: (_) => getIt.get<ExchangeTemplatePage>());
case Routes.settings:
return MaterialPageRoute<void>(builder: (_) => getIt.get<SettingsPage>());
case Routes.rescan: case Routes.rescan:
return MaterialPageRoute<void>(builder: (_) => getIt.get<RescanPage>()); return MaterialPageRoute<void>(builder: (_) => getIt.get<RescanPage>());

View file

@ -21,7 +21,6 @@ class Routes {
static const seedLanguage = '/seed_language'; static const seedLanguage = '/seed_language';
static const walletList = '/view_model.wallet_list'; static const walletList = '/view_model.wallet_list';
static const auth = '/auth'; static const auth = '/auth';
static const nodeList = '/node_list';
static const newNode = '/new_node_list'; static const newNode = '/new_node_list';
static const login = '/login'; static const login = '/login';
static const splash = '/splash'; static const splash = '/splash';
@ -77,5 +76,10 @@ class Routes {
static const ioniaMoreOptionsPage = '/ionia_more_options_page'; static const ioniaMoreOptionsPage = '/ionia_more_options_page';
static const ioniaCustomRedeemPage = '/ionia_custom_redeem_page'; static const ioniaCustomRedeemPage = '/ionia_custom_redeem_page';
static const onramperPage = '/onramper'; static const onramperPage = '/onramper';
static const privacySettings = '/privacy_settings'; 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';
} }

View file

@ -60,7 +60,7 @@ class DashboardPage extends BasePage {
Widget middle(BuildContext context) { Widget middle(BuildContext context) {
return SyncIndicator(dashboardViewModel: walletViewModel, return SyncIndicator(dashboardViewModel: walletViewModel,
onTap: () => Navigator.of(context, rootNavigator: true) onTap: () => Navigator.of(context, rootNavigator: true)
.pushNamed(Routes.nodeList)); .pushNamed(Routes.connectionSync));
} }
@override @override
@ -315,6 +315,8 @@ class DashboardPage extends BasePage {
} }
Future<void> _onClickExchangeButton(BuildContext context) async { Future<void> _onClickExchangeButton(BuildContext context) async {
await Navigator.of(context).pushNamed(Routes.exchange); if (walletViewModel.isEnabledExchangeAction) {
await Navigator.of(context).pushNamed(Routes.exchange);
}
} }
} }

View file

@ -1,81 +1,64 @@
import 'package:cake_wallet/palette.dart'; import 'package:cake_wallet/palette.dart';
import 'package:cake_wallet/src/screens/dashboard/wallet_menu_item.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:flutter/material.dart';
import 'package:cake_wallet/routes.dart'; import 'package:cake_wallet/routes.dart';
import 'package:cake_wallet/generated/i18n.dart'; import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/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 // FIXME: terrible design
class WalletMenu { class WalletMenu {
WalletMenu(this.context, this.reconnect, this.hasRescan) : items = [] { WalletMenu(this.context, this.reconnect, this.hasRescan) : items = [] {
items.addAll([ items.addAll([
WalletMenuItem( WalletMenuItem(
title: S.current.reconnect, title: S.current.connection_sync,
image: Image.asset('assets/images/reconnect_menu.png', image: Image.asset('assets/images/nodes_menu.png',
height: 16, width: 16), height: 16, width: 16),
handler: () => _presentReconnectAlert(context)), handler: () => Navigator.of(context).pushNamed(Routes.connectionSync),
if (hasRescan) ),
WalletMenuItem( WalletMenuItem(
title: S.current.rescan, title: S.current.wallets,
image: Image.asset('assets/images/filter_icon.png', image: Image.asset('assets/images/wallet_menu.png',
height: 16, width: 16, color: Palette.darkBlue), height: 16, width: 16),
handler: () => Navigator.of(context).pushNamed(Routes.rescan)), handler: () => Navigator.of(context).pushNamed(Routes.walletList),
WalletMenuItem( ),
title: S.current.wallets, WalletMenuItem(
image: Image.asset('assets/images/wallet_menu.png', title: S.current.security_and_backup,
height: 16, width: 16), image:
handler: () => Navigator.of(context).pushNamed(Routes.walletList)), Image.asset('assets/images/key_menu.png', height: 16, width: 16),
WalletMenuItem( handler: () {
title: S.current.nodes, Navigator.of(context).pushNamed(Routes.securityBackupPage);
image: Image.asset('assets/images/nodes_menu.png', }),
height: 16, width: 16), WalletMenuItem(
handler: () => Navigator.of(context).pushNamed(Routes.nodeList)), title: S.current.privacy,
WalletMenuItem( image:
title: S.current.show_keys, Image.asset('assets/images/eye_menu.png', height: 16, width: 16),
image: handler: () {
Image.asset('assets/images/key_menu.png', height: 16, width: 16), Navigator.of(context).pushNamed(Routes.privacyPage);
handler: () { }),
Navigator.of(context).pushNamed(Routes.auth, WalletMenuItem(
arguments: (bool isAuthenticatedSuccessfully, AuthPageState auth) { title: S.current.address_book_menu,
if (isAuthenticatedSuccessfully) { image: Image.asset('assets/images/open_book_menu.png',
auth.close(route: Routes.showKeys); height: 16, width: 16),
} handler: () => Navigator.of(context).pushNamed(Routes.addressBook),
}); ),
}), WalletMenuItem(
WalletMenuItem( title: S.current.display_settings,
title: S.current.address_book_menu, image: Image.asset('assets/images/eye_menu.png',
image: Image.asset('assets/images/open_book_menu.png', height: 16, width: 16),
height: 16, width: 16), handler: () => Navigator.of(context).pushNamed(Routes.displaySettingsPage),
handler: () => Navigator.of(context).pushNamed(Routes.addressBook)), ),
WalletMenuItem( WalletMenuItem(
title: S.current.backup, title: S.current.other_settings,
image: Image.asset('assets/images/restore_wallet.png', image: Image.asset('assets/images/settings_menu.png',
height: 16, height: 16, width: 16),
width: 16, handler: () => Navigator.of(context).pushNamed(Routes.otherSettingsPage),
color: Palette.darkBlue), ),
handler: () { WalletMenuItem(
Navigator.of(context).pushNamed( title: S.current.settings_support,
Routes.auth, image: Image.asset('assets/images/question_mark.png',
arguments: (bool isAuthenticatedSuccessfully, AuthPageState auth) { height: 16, width: 16, color: Palette.darkBlue),
if (isAuthenticatedSuccessfully) { handler: () => Navigator.of(context).pushNamed(Routes.support),
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)),
]); ]);
} }
@ -86,23 +69,6 @@ class WalletMenu {
void action(int index) { void action(int index) {
final item = items[index]; final item = items[index];
item?.handler(); 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());
});
} }
} }

View file

@ -3,7 +3,6 @@ import 'package:cake_wallet/ionia/ionia_merchant.dart';
import 'package:cake_wallet/ionia/ionia_tip.dart'; import 'package:cake_wallet/ionia/ionia_tip.dart';
import 'package:cake_wallet/palette.dart'; import 'package:cake_wallet/palette.dart';
import 'package:cake_wallet/routes.dart'; import 'package:cake_wallet/routes.dart';
import 'package:cake_wallet/src/screens/ionia/widgets/confirm_modal.dart';
import 'package:cake_wallet/src/screens/ionia/widgets/ionia_alert_model.dart'; import 'package:cake_wallet/src/screens/ionia/widgets/ionia_alert_model.dart';
import 'package:cake_wallet/src/screens/ionia/widgets/text_icon_button.dart'; import 'package:cake_wallet/src/screens/ionia/widgets/text_icon_button.dart';
import 'package:cake_wallet/src/widgets/alert_with_one_action.dart'; import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
@ -18,6 +17,7 @@ import 'package:cake_wallet/generated/i18n.dart';
import 'package:flutter_mobx/flutter_mobx.dart'; import 'package:flutter_mobx/flutter_mobx.dart';
import 'package:mobx/mobx.dart'; import 'package:mobx/mobx.dart';
import 'package:cake_wallet/src/screens/base_page.dart'; import 'package:cake_wallet/src/screens/base_page.dart';
import 'package:cake_wallet/src/screens/send/widgets/confirm_sending_alert.dart';
class IoniaBuyGiftCardDetailPage extends BasePage { class IoniaBuyGiftCardDetailPage extends BasePage {
IoniaBuyGiftCardDetailPage(this.ioniaPurchaseViewModel); IoniaBuyGiftCardDetailPage(this.ioniaPurchaseViewModel);
@ -295,73 +295,35 @@ class IoniaBuyGiftCardDetailPage extends BasePage {
final amount = ioniaPurchaseViewModel.invoice!.totalAmount; final amount = ioniaPurchaseViewModel.invoice!.totalAmount;
final addresses = ioniaPurchaseViewModel.invoice!.outAddresses; final addresses = ioniaPurchaseViewModel.invoice!.outAddresses;
ioniaPurchaseViewModel.sendViewModel.outputs.first.setCryptoAmount(amount);
ioniaPurchaseViewModel.sendViewModel.outputs.first.address = addresses.first;
await showPopUp<void>( await showPopUp<void>(
context: context, context: context,
builder: (_) { builder: (_) {
return IoniaConfirmModal( return ConfirmSendingAlert(
alertTitle: S.of(context).confirm_sending, alertTitle: S.of(context).confirm_sending,
alertContent: Container( paymentId: S.of(context).payment_id,
height: 200, paymentIdValue: ioniaPurchaseViewModel.invoice!.paymentId,
padding: EdgeInsets.all(15), amount: S.of(context).send_amount,
child: Column(children: [ amountValue: '$amount ${ioniaPurchaseViewModel.invoice!.chain}',
Row(children: [ fiatAmountValue:
Text(S.of(context).payment_id, '~ ${ioniaPurchaseViewModel.sendViewModel.outputs.first.fiatAmount} '
textAlign: TextAlign.center, '${ioniaPurchaseViewModel.sendViewModel.fiat.title}',
style: TextStyle( fee: S.of(context).send_fee,
fontSize: 16, feeValue:
fontWeight: FontWeight.w400, '${ioniaPurchaseViewModel.sendViewModel.outputs.first.estimatedFee} '
color: PaletteDark.pigeonBlue, '${ioniaPurchaseViewModel.invoice!.chain}',
decoration: TextDecoration.none)), feeFiatAmount:
Text(ioniaPurchaseViewModel.invoice!.paymentId, '${ioniaPurchaseViewModel.sendViewModel.outputs.first.estimatedFeeFiatAmount} '
style: TextStyle( '${ioniaPurchaseViewModel.sendViewModel.fiat.title}',
fontSize: 16, outputs: ioniaPurchaseViewModel.sendViewModel.outputs,
fontWeight: FontWeight.w400,
color: PaletteDark.pigeonBlue,
decoration: TextDecoration.none))
], mainAxisAlignment: MainAxisAlignment.spaceBetween),
SizedBox(height: 10),
Row(children: [
Text(S.of(context).amount,
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w400,
color: PaletteDark.pigeonBlue,
decoration: TextDecoration.none)),
Text('$amount ${ioniaPurchaseViewModel.invoice!.chain}',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w400,
color: PaletteDark.pigeonBlue,
decoration: TextDecoration.none))
], mainAxisAlignment: MainAxisAlignment.spaceBetween),
SizedBox(height: 25),
Row(children: [
Text(S.of(context).recipient_address,
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w400,
color: PaletteDark.pigeonBlue,
decoration: TextDecoration.none))
], mainAxisAlignment: MainAxisAlignment.center),
Expanded(
child: ListView.builder(
itemBuilder: (_, int index) {
return Text(addresses[index],
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.w400,
color: PaletteDark.pigeonBlue,
decoration: TextDecoration.none));
},
itemCount: addresses.length,
physics: NeverScrollableScrollPhysics()))
])),
rightButtonText: S.of(context).ok, rightButtonText: S.of(context).ok,
leftButtonText: S.of(context).cancel, leftButtonText: S.of(context).cancel,
leftActionColor: Color(0xffFF6600), alertLeftActionButtonTextColor: Colors.white,
rightActionColor: Theme.of(context).accentTextTheme!.bodyText1!.color!, alertRightActionButtonTextColor: Colors.white,
alertLeftActionButtonColor: Palette.brightOrange,
alertRightActionButtonColor: Theme.of(context).textTheme!.subtitle2!.color,
actionRightButton: () async { actionRightButton: () async {
Navigator.of(context).pop(); Navigator.of(context).pop();
await ioniaPurchaseViewModel.commitPaymentInvoice(); await ioniaPurchaseViewModel.commitPaymentInvoice();

View file

@ -118,7 +118,7 @@ class IoniaManageCardsPage extends BasePage {
width: 32, width: 32,
padding: EdgeInsets.all(8), padding: EdgeInsets.all(8),
decoration: BoxDecoration( decoration: BoxDecoration(
color: Colors.white.withOpacity(0.15), color: Theme.of(context).textTheme!.headline6!.backgroundColor!,
border: Border.all( border: Border.all(
color: Colors.white.withOpacity(0.2), color: Colors.white.withOpacity(0.2),
), ),

View file

@ -1,149 +0,0 @@
import 'dart:ui';
import 'package:cake_wallet/palette.dart';
import 'package:flutter/material.dart';
class IoniaConfirmModal extends StatelessWidget {
IoniaConfirmModal({
required this.alertTitle,
required this.alertContent,
required this.leftButtonText,
required this.rightButtonText,
required this.actionLeftButton,
required this.actionRightButton,
required this.leftActionColor,
required this.rightActionColor,
this.hideActions = false,
});
final String alertTitle;
final Widget alertContent;
final String leftButtonText;
final String rightButtonText;
final VoidCallback actionLeftButton;
final VoidCallback actionRightButton;
final Color leftActionColor;
final Color rightActionColor;
final bool hideActions;
Widget actionButtons(BuildContext context) {
return Row(
mainAxisSize: MainAxisSize.max,
children: <Widget>[
IoniaActionButton(
buttonText: leftButtonText,
action: actionLeftButton,
backgoundColor: leftActionColor,
),
Container(
width: 1,
height: 52,
color: Theme.of(context).dividerColor,
),
IoniaActionButton(
buttonText: rightButtonText,
action: actionRightButton,
backgoundColor: rightActionColor,
),
],
);
}
Widget title(BuildContext context) {
return Text(
alertTitle,
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 20,
fontFamily: 'Lato',
fontWeight: FontWeight.w600,
color: Theme.of(context).primaryTextTheme!.headline6!.color!,
decoration: TextDecoration.none,
),
);
}
@override
Widget build(BuildContext context) {
return Container(
color: Colors.transparent,
child: BackdropFilter(
filter: ImageFilter.blur(sigmaX: 3.0, sigmaY: 3.0),
child: Container(
decoration: BoxDecoration(color: PaletteDark.darkNightBlue.withOpacity(0.75)),
child: Center(
child: GestureDetector(
onTap: () => null,
child: ClipRRect(
borderRadius: BorderRadius.all(Radius.circular(30)),
child: Container(
width: 327,
color: Theme.of(context).accentTextTheme!.headline6!.decorationColor!,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Padding(
padding: EdgeInsets.fromLTRB(24, 20, 24, 0),
child: title(context),
),
Padding(
padding: EdgeInsets.only(top: 16, bottom: 8),
child: Container(
height: 1,
color: Theme.of(context).dividerColor,
),
),
alertContent,
actionButtons(context),
],
),
),
),
),
),
),
),
);
}
}
class IoniaActionButton extends StatelessWidget {
const IoniaActionButton({
required this.buttonText,
required this.action,
required this.backgoundColor,
});
final String buttonText;
final VoidCallback action;
final Color backgoundColor;
@override
Widget build(BuildContext context) {
return Flexible(
child: Container(
height: 52,
padding: EdgeInsets.only(left: 6, right: 6),
color: backgoundColor,
child: ButtonTheme(
minWidth: double.infinity,
child: TextButton(
onPressed: action,
// FIX-ME: ignored highlightColor and splashColor
//highlightColor: Colors.transparent,
//splashColor: Colors.transparent,
child: Text(
buttonText,
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 15,
fontFamily: 'Lato',
fontWeight: FontWeight.w600,
color: backgoundColor != null ? Colors.white : Theme.of(context).primaryTextTheme!.bodyText2!.backgroundColor!,
decoration: TextDecoration.none,
),
)),
),
));
}
}

View file

@ -20,7 +20,7 @@ class IoniaFilterModal extends StatelessWidget {
padding: EdgeInsets.all(10), padding: EdgeInsets.all(10),
child: Image.asset( child: Image.asset(
'assets/images/mini_search_icon.png', 'assets/images/mini_search_icon.png',
color: Theme.of(context).accentColor, color: Theme.of(context).textTheme.subtitle2!.color!,
), ),
); );
return Scaffold( return Scaffold(
@ -53,7 +53,7 @@ class IoniaFilterModal extends StatelessWidget {
prefixIcon: searchIcon, prefixIcon: searchIcon,
hintText: S.of(context).search_category, hintText: S.of(context).search_category,
contentPadding: EdgeInsets.only(bottom: 5), contentPadding: EdgeInsets.only(bottom: 5),
fillColor: Theme.of(context).textTheme!.subtitle1!.backgroundColor!, fillColor: Theme.of(context).primaryTextTheme!.caption!.decorationColor!.withOpacity(0.5),
border: OutlineInputBorder( border: OutlineInputBorder(
borderSide: BorderSide.none, borderSide: BorderSide.none,
borderRadius: BorderRadius.circular(8), borderRadius: BorderRadius.circular(8),

View file

@ -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,
),
],
);
}

View file

@ -37,7 +37,10 @@ class NodeHeaderListRow extends StandardListRow {
@override @override
Widget buildTrailing(BuildContext context) { Widget buildTrailing(BuildContext context) {
return Icon(Icons.add, return SizedBox(
color: Theme.of(context).accentTextTheme!.subtitle1!.color!, size: 24.0); width: 20,
child: Icon(Icons.add,
color: Theme.of(context).accentTextTheme!.subtitle1!.color!, size: 24.0),
);
} }
} }

View file

@ -9,7 +9,6 @@ class QrPainter extends CustomPainter {
this.errorCorrectionLevel, this.errorCorrectionLevel,
) : this._qr = QrCode(version, errorCorrectionLevel)..addData(data) { ) : this._qr = QrCode(version, errorCorrectionLevel)..addData(data) {
_p.color = this.color; _p.color = this.color;
_qr.addData(data);
_qrImage = QrImage(_qr); _qrImage = QrImage(_qr);
} }

View file

@ -1,4 +1,3 @@
import 'dart:ui';
import 'package:cake_wallet/entities/fiat_currency.dart'; 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/dashboard/widgets/sync_indicator_icon.dart';
import 'package:cake_wallet/src/screens/send/widgets/send_card.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/picker.dart';
import 'package:cake_wallet/src/widgets/template_tile.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/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/material.dart';
import 'package:flutter_mobx/flutter_mobx.dart'; import 'package:flutter_mobx/flutter_mobx.dart';
import 'package:mobx/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'; import 'package:cw_core/crypto_currency.dart';
class SendPage extends BasePage { 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 SendViewModel sendViewModel;
final SettingsViewModel settingsViewModel;
final GlobalKey<FormState> _formKey; final GlobalKey<FormState> _formKey;
final controller = PageController(initialPage: 0); final controller = PageController(initialPage: 0);
final FiatCurrency fiatFromSettings ;
bool _effectsInstalled = false; bool _effectsInstalled = false;
@ -55,7 +50,7 @@ class SendPage extends BasePage {
@override @override
void onClose(BuildContext context) { void onClose(BuildContext context) {
settingsViewModel.setFiatCurrency(fiatFromSettings); sendViewModel.onClose();
Navigator.of(context).pop(); Navigator.of(context).pop();
} }
@ -236,7 +231,7 @@ class SendPage extends BasePage {
if(template.isCurrencySelected){ if(template.isCurrencySelected){
output.setCryptoAmount(template.amount); output.setCryptoAmount(template.amount);
}else{ }else{
settingsViewModel.setFiatCurrency(fiatFromTemplate); sendViewModel.setFiatCurrency(fiatFromTemplate);
output.setFiatAmount(template.amountFiat); output.setFiatAmount(template.amountFiat);
} }
output.resetParsedAddress(); output.resetParsedAddress();

View file

@ -4,10 +4,13 @@ import 'package:flutter/material.dart';
import 'package:cake_wallet/src/widgets/base_alert_dialog.dart'; import 'package:cake_wallet/src/widgets/base_alert_dialog.dart';
import 'package:cake_wallet/generated/i18n.dart'; import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/src/widgets/cake_scrollbar.dart'; import 'package:cake_wallet/src/widgets/cake_scrollbar.dart';
import 'package:flutter/scheduler.dart';
class ConfirmSendingAlert extends BaseAlertDialog { class ConfirmSendingAlert extends BaseAlertDialog {
ConfirmSendingAlert({ ConfirmSendingAlert({
required this.alertTitle, required this.alertTitle,
this.paymentId,
this.paymentIdValue,
required this.amount, required this.amount,
required this.amountValue, required this.amountValue,
required this.fiatAmountValue, required this.fiatAmountValue,
@ -19,9 +22,15 @@ class ConfirmSendingAlert extends BaseAlertDialog {
required this.rightButtonText, required this.rightButtonText,
required this.actionLeftButton, required this.actionLeftButton,
required this.actionRightButton, required this.actionRightButton,
this.alertBarrierDismissible = true}); this.alertBarrierDismissible = true,
this.alertLeftActionButtonTextColor,
this.alertRightActionButtonTextColor,
this.alertLeftActionButtonColor,
this.alertRightActionButtonColor});
final String alertTitle; final String alertTitle;
final String? paymentId;
final String? paymentIdValue;
final String amount; final String amount;
final String amountValue; final String amountValue;
final String fiatAmountValue; final String fiatAmountValue;
@ -34,6 +43,10 @@ class ConfirmSendingAlert extends BaseAlertDialog {
final VoidCallback actionLeftButton; final VoidCallback actionLeftButton;
final VoidCallback actionRightButton; final VoidCallback actionRightButton;
final bool alertBarrierDismissible; final bool alertBarrierDismissible;
final Color? alertLeftActionButtonTextColor;
final Color? alertRightActionButtonTextColor;
final Color? alertLeftActionButtonColor;
final Color? alertRightActionButtonColor;
@override @override
String get titleText => alertTitle; String get titleText => alertTitle;
@ -56,8 +69,22 @@ class ConfirmSendingAlert extends BaseAlertDialog {
@override @override
bool get barrierDismissible => alertBarrierDismissible; bool get barrierDismissible => alertBarrierDismissible;
@override
Color? get leftActionButtonTextColor => alertLeftActionButtonTextColor;
@override
Color? get rightActionButtonTextColor => alertRightActionButtonTextColor;
@override
Color? get leftActionButtonColor => alertLeftActionButtonColor;
@override
Color? get rightActionButtonColor => alertRightActionButtonColor;
@override @override
Widget content(BuildContext context) => ConfirmSendingAlertContent( Widget content(BuildContext context) => ConfirmSendingAlertContent(
paymentId: paymentId,
paymentIdValue: paymentIdValue,
amount: amount, amount: amount,
amountValue: amountValue, amountValue: amountValue,
fiatAmountValue: fiatAmountValue, fiatAmountValue: fiatAmountValue,
@ -70,6 +97,8 @@ class ConfirmSendingAlert extends BaseAlertDialog {
class ConfirmSendingAlertContent extends StatefulWidget { class ConfirmSendingAlertContent extends StatefulWidget {
ConfirmSendingAlertContent({ ConfirmSendingAlertContent({
this.paymentId,
this.paymentIdValue,
required this.amount, required this.amount,
required this.amountValue, required this.amountValue,
required this.fiatAmountValue, required this.fiatAmountValue,
@ -78,6 +107,8 @@ class ConfirmSendingAlertContent extends StatefulWidget {
required this.feeFiatAmount, required this.feeFiatAmount,
required this.outputs}); required this.outputs});
final String? paymentId;
final String? paymentIdValue;
final String amount; final String amount;
final String amountValue; final String amountValue;
final String fiatAmountValue; final String fiatAmountValue;
@ -88,6 +119,8 @@ class ConfirmSendingAlertContent extends StatefulWidget {
@override @override
ConfirmSendingAlertContentState createState() => ConfirmSendingAlertContentState( ConfirmSendingAlertContentState createState() => ConfirmSendingAlertContentState(
paymentId: paymentId,
paymentIdValue: paymentIdValue,
amount: amount, amount: amount,
amountValue: amountValue, amountValue: amountValue,
fiatAmountValue: fiatAmountValue, fiatAmountValue: fiatAmountValue,
@ -100,6 +133,8 @@ class ConfirmSendingAlertContent extends StatefulWidget {
class ConfirmSendingAlertContentState extends State<ConfirmSendingAlertContent> { class ConfirmSendingAlertContentState extends State<ConfirmSendingAlertContent> {
ConfirmSendingAlertContentState({ ConfirmSendingAlertContentState({
this.paymentId,
this.paymentIdValue,
required this.amount, required this.amount,
required this.amountValue, required this.amountValue,
required this.fiatAmountValue, required this.fiatAmountValue,
@ -115,6 +150,8 @@ class ConfirmSendingAlertContentState extends State<ConfirmSendingAlertContent>
: S.current.recipient_address; : S.current.recipient_address;
} }
final String? paymentId;
final String? paymentIdValue;
final String amount; final String amount;
final String amountValue; final String amountValue;
final String fiatAmountValue; final String fiatAmountValue;
@ -129,6 +166,7 @@ class ConfirmSendingAlertContentState extends State<ConfirmSendingAlertContent>
double fromTop = 0; double fromTop = 0;
String recipientTitle; String recipientTitle;
int itemCount; int itemCount;
bool showScrollbar = false;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -140,6 +178,12 @@ class ConfirmSendingAlertContentState extends State<ConfirmSendingAlertContent>
setState(() {}); setState(() {});
}); });
SchedulerBinding.instance.addPostFrameCallback((_) {
setState(() {
showScrollbar = controller.position.maxScrollExtent > 0;
});
});
return Stack( return Stack(
alignment: Alignment.center, alignment: Alignment.center,
clipBehavior: Clip.none, clipBehavior: Clip.none,
@ -150,6 +194,44 @@ class ConfirmSendingAlertContentState extends State<ConfirmSendingAlertContent>
controller: controller, controller: controller,
child: Column( child: Column(
children: <Widget>[ children: <Widget>[
if (paymentIdValue != null && paymentId != null)
Padding(
padding: EdgeInsets.only(bottom: 32),
child: Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
paymentId!,
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.normal,
fontFamily: 'Lato',
color: Theme.of(context).primaryTextTheme!
.headline6!.color!,
decoration: TextDecoration.none,
),
),
Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Text(
paymentIdValue!,
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.w600,
fontFamily: 'Lato',
color: Theme.of(context).primaryTextTheme!
.headline6!.color!,
decoration: TextDecoration.none,
),
),
],
)
],
),
),
Row( Row(
mainAxisSize: MainAxisSize.max, mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
@ -365,7 +447,7 @@ class ConfirmSendingAlertContentState extends State<ConfirmSendingAlertContent>
) )
) )
), ),
if (itemCount > 1) CakeScrollbar( if (showScrollbar) CakeScrollbar(
backgroundHeight: backgroundHeight, backgroundHeight: backgroundHeight,
thumbHeight: thumbHeight, thumbHeight: thumbHeight,
fromTop: fromTop, fromTop: fromTop,

View file

@ -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:cake_wallet/utils/payment_request.dart';
import 'package:cw_core/transaction_priority.dart'; import 'package:cw_core/transaction_priority.dart';
import 'package:cake_wallet/routes.dart'; import 'package:cake_wallet/routes.dart';
import 'package:cake_wallet/src/widgets/keyboard_done_button.dart'; import 'package:cake_wallet/src/widgets/keyboard_done_button.dart';
import 'package:cake_wallet/src/widgets/picker.dart'; import 'package:cake_wallet/src/widgets/picker.dart';
import 'package:cake_wallet/view_model/send/output.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/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:flutter_mobx/flutter_mobx.dart'; import 'package:flutter_mobx/flutter_mobx.dart';

View 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,
),
],
);
}

View 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),
),
),
],
),
);
});
}
}

View 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))
]),
);
});
}
}

View 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);
})
],
);
});
}),
);
}
}

View 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);
}
});
}),
]),
);
}
}

View file

@ -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();
});
}
}

View file

@ -11,6 +11,10 @@ class BaseAlertDialog extends StatelessWidget {
VoidCallback get actionLeft => () {}; VoidCallback get actionLeft => () {};
VoidCallback get actionRight => () {}; VoidCallback get actionRight => () {};
bool get barrierDismissible => true; bool get barrierDismissible => true;
Color? get leftActionButtonTextColor => null;
Color? get rightActionButtonTextColor => null;
Color? get leftActionButtonColor => null;
Color? get rightActionButtonColor => null;
Widget title(BuildContext context) { Widget title(BuildContext context) {
return Text( return Text(
@ -45,52 +49,64 @@ class BaseAlertDialog extends StatelessWidget {
height: 52, height: 52,
child: Row( child: Row(
mainAxisSize: MainAxisSize.max, mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[ children: <Widget>[
Flexible( Expanded(
child: Container( child: TextButton(
width: double.infinity, onPressed: actionLeft,
color: Theme.of(context).accentTextTheme!.bodyText1!.decorationColor!, style: TextButton.styleFrom(
child: TextButton( backgroundColor: leftActionButtonColor ??
onPressed: actionLeft, Theme.of(context)
child: Text( .accentTextTheme!
leftActionButtonText, .bodyText1!
textAlign: TextAlign.center, .decorationColor!,
style: TextStyle( shape: const RoundedRectangleBorder(
fontSize: 15, borderRadius: BorderRadius.all(Radius.zero))),
fontFamily: 'Lato', child: Text(
fontWeight: FontWeight.w600, leftActionButtonText,
color: Theme.of(context).primaryTextTheme!.bodyText1!.backgroundColor!, textAlign: TextAlign.center,
decoration: TextDecoration.none, style: TextStyle(
), fontSize: 15,
)), fontFamily: 'Lato',
), fontWeight: FontWeight.w600,
), color: leftActionButtonTextColor ??
Theme.of(context).primaryTextTheme!
.bodyText1!.backgroundColor!,
decoration: TextDecoration.none,
),
)),
),
Container( Container(
width: 1, width: 1,
color: Theme.of(context).dividerColor, color: Theme.of(context).dividerColor,
), ),
Flexible( Expanded(
child: Container( child: TextButton(
width: double.infinity, onPressed: actionRight,
color: Theme.of(context).accentTextTheme!.bodyText2!.backgroundColor!, style: TextButton.styleFrom(
child: TextButton( backgroundColor: rightActionButtonColor ??
onPressed: actionRight, Theme.of(context).accentTextTheme!
child: Text( .bodyText2!.backgroundColor!,
rightActionButtonText, shape: const RoundedRectangleBorder(
textAlign: TextAlign.center, borderRadius: BorderRadius.all(Radius.zero))),
style: TextStyle( child: Text(
fontSize: 15, rightActionButtonText,
fontFamily: 'Lato', textAlign: TextAlign.center,
fontWeight: FontWeight.w600, style: TextStyle(
color: Theme.of(context).primaryTextTheme!.bodyText2!.backgroundColor!, fontSize: 15,
decoration: TextDecoration.none, fontFamily: 'Lato',
), fontWeight: FontWeight.w600,
)), color: rightActionButtonTextColor ??
), Theme.of(context)
), .primaryTextTheme!
], .bodyText2!
)); .backgroundColor!,
decoration: TextDecoration.none,
),
)),
),
],
));
} }
@override @override

View file

@ -123,6 +123,7 @@ class SectionStandardList extends StatelessWidget {
required this.itemBuilder, required this.itemBuilder,
required this.sectionCount, required this.sectionCount,
required BuildContext context, required BuildContext context,
this.dividerPadding = const EdgeInsets.only(left: 24),
this.themeColor, this.themeColor,
this.dividerThemeColor, this.dividerThemeColor,
this.sectionTitleBuilder, this.sectionTitleBuilder,
@ -149,6 +150,7 @@ class SectionStandardList extends StatelessWidget {
final List<Widget> totalRows; final List<Widget> totalRows;
final Color? themeColor; final Color? themeColor;
final Color? dividerThemeColor; final Color? dividerThemeColor;
final EdgeInsets dividerPadding;
List<Widget> transform( List<Widget> transform(
bool hasTopSeparator, bool hasTopSeparator,
@ -178,7 +180,7 @@ class SectionStandardList extends StatelessWidget {
items.add(sectionIndex + 1 != sectionCount items.add(sectionIndex + 1 != sectionCount
? SectionHeaderListRow() ? SectionHeaderListRow()
: StandardListSeparator(padding: EdgeInsets.only(left: 24))); : StandardListSeparator(padding: dividerPadding));
} }
return items; return items;

View file

@ -30,6 +30,7 @@ abstract class SettingsStoreBase with Store {
required BalanceDisplayMode initialBalanceDisplayMode, required BalanceDisplayMode initialBalanceDisplayMode,
required bool initialSaveRecipientAddress, required bool initialSaveRecipientAddress,
required bool initialAllowBiometricalAuthentication, required bool initialAllowBiometricalAuthentication,
required bool initialExchangeEnabled,
required ThemeBase initialTheme, required ThemeBase initialTheme,
required int initialPinLength, required int initialPinLength,
required String initialLanguageCode, required String initialLanguageCode,
@ -47,6 +48,7 @@ abstract class SettingsStoreBase with Store {
balanceDisplayMode = initialBalanceDisplayMode, balanceDisplayMode = initialBalanceDisplayMode,
shouldSaveRecipientAddress = initialSaveRecipientAddress, shouldSaveRecipientAddress = initialSaveRecipientAddress,
allowBiometricalAuthentication = initialAllowBiometricalAuthentication, allowBiometricalAuthentication = initialAllowBiometricalAuthentication,
disableExchange = initialExchangeEnabled,
currentTheme = initialTheme, currentTheme = initialTheme,
pinCodeLength = initialPinLength, pinCodeLength = initialPinLength,
languageCode = initialLanguageCode, languageCode = initialLanguageCode,
@ -143,6 +145,9 @@ abstract class SettingsStoreBase with Store {
@observable @observable
bool allowBiometricalAuthentication; bool allowBiometricalAuthentication;
@observable
bool disableExchange;
@observable @observable
ThemeBase currentTheme; ThemeBase currentTheme;
@ -221,6 +226,8 @@ abstract class SettingsStoreBase with Store {
final allowBiometricalAuthentication = sharedPreferences final allowBiometricalAuthentication = sharedPreferences
.getBool(PreferencesKey.allowBiometricalAuthenticationKey) ?? .getBool(PreferencesKey.allowBiometricalAuthenticationKey) ??
false; false;
final disableExchange = sharedPreferences
.getBool(PreferencesKey.disableExchangeKey) ?? false;
final legacyTheme = final legacyTheme =
(sharedPreferences.getBool(PreferencesKey.isDarkThemeLegacy) ?? false) (sharedPreferences.getBool(PreferencesKey.isDarkThemeLegacy) ?? false)
? ThemeType.dark.index ? ThemeType.dark.index
@ -284,6 +291,7 @@ abstract class SettingsStoreBase with Store {
initialBalanceDisplayMode: currentBalanceDisplayMode, initialBalanceDisplayMode: currentBalanceDisplayMode,
initialSaveRecipientAddress: shouldSaveRecipientAddress, initialSaveRecipientAddress: shouldSaveRecipientAddress,
initialAllowBiometricalAuthentication: allowBiometricalAuthentication, initialAllowBiometricalAuthentication: allowBiometricalAuthentication,
initialExchangeEnabled: disableExchange,
initialTheme: savedTheme, initialTheme: savedTheme,
actionlistDisplayMode: actionListDisplayMode, actionlistDisplayMode: actionListDisplayMode,
initialPinLength: pinLength, initialPinLength: pinLength,

View file

@ -53,7 +53,6 @@ abstract class DashboardViewModelBase with Store {
hasBuyAction = false, hasBuyAction = false,
isEnabledBuyAction = false, isEnabledBuyAction = false,
hasExchangeAction = false, hasExchangeAction = false,
isEnabledExchangeAction = false,
isShowFirstYatIntroduction = false, isShowFirstYatIntroduction = false,
isShowSecondYatIntroduction = false, isShowSecondYatIntroduction = false,
isShowThirdYatIntroduction = false, isShowThirdYatIntroduction = false,
@ -249,8 +248,8 @@ abstract class DashboardViewModelBase with Store {
void furtherShowYatPopup(bool shouldShow) => void furtherShowYatPopup(bool shouldShow) =>
settingsStore.shouldShowYatPopup = shouldShow; settingsStore.shouldShowYatPopup = shouldShow;
@observable @computed
bool isEnabledExchangeAction; bool get isEnabledExchangeAction => !settingsStore.disableExchange;
@observable @observable
bool hasExchangeAction; bool hasExchangeAction;
@ -365,7 +364,6 @@ abstract class DashboardViewModelBase with Store {
} }
void updateActions() { void updateActions() {
isEnabledExchangeAction = true;
hasExchangeAction = !isHaven; hasExchangeAction = !isHaven;
isEnabledBuyAction = wallet.type != WalletType.haven isEnabledBuyAction = wallet.type != WalletType.haven
&& wallet.type != WalletType.monero; && wallet.type != WalletType.monero;

View file

@ -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_exchange_provider.dart';
import 'package:cake_wallet/exchange/sideshift/sideshift_request.dart'; import 'package:cake_wallet/exchange/sideshift/sideshift_request.dart';
import 'package:cake_wallet/exchange/simpleswap/simpleswap_exchange_provider.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: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/wallet_base.dart';
import 'package:cw_core/crypto_currency.dart'; import 'package:cw_core/crypto_currency.dart';
import 'package:cw_core/sync_status.dart'; import 'package:cw_core/sync_status.dart';
@ -43,7 +42,7 @@ class ExchangeViewModel = ExchangeViewModelBase with _$ExchangeViewModel;
abstract class ExchangeViewModelBase with Store { abstract class ExchangeViewModelBase with Store {
ExchangeViewModelBase(this.wallet, this.trades, this._exchangeTemplateStore, ExchangeViewModelBase(this.wallet, this.trades, this._exchangeTemplateStore,
this.tradesStore, this._settingsStore, this.sharedPreferences, this._settingsViewModel) this.tradesStore, this._settingsStore, this.sharedPreferences)
: _cryptoNumberFormat = NumberFormat(), : _cryptoNumberFormat = NumberFormat(),
isReverse = false, isReverse = false,
isFixedRateMode = false, isFixedRateMode = false,
@ -190,6 +189,19 @@ abstract class ExchangeViewModelBase with Store {
ObservableList<ExchangeTemplate> get templates => ObservableList<ExchangeTemplate> get templates =>
_exchangeTemplateStore.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 => bool get hasAllAmount =>
wallet.type == WalletType.bitcoin && depositCurrency == wallet.currency; wallet.type == WalletType.bitcoin && depositCurrency == wallet.currency;
@ -199,11 +211,11 @@ abstract class ExchangeViewModelBase with Store {
switch (wallet.type) { switch (wallet.type) {
case WalletType.monero: case WalletType.monero:
case WalletType.haven: case WalletType.haven:
return _settingsViewModel.transactionPriority == monero!.getMoneroTransactionPrioritySlow(); return transactionPriority == monero!.getMoneroTransactionPrioritySlow();
case WalletType.bitcoin: case WalletType.bitcoin:
return _settingsViewModel.transactionPriority == bitcoin!.getBitcoinTransactionPrioritySlow(); return transactionPriority == bitcoin!.getBitcoinTransactionPrioritySlow();
case WalletType.litecoin: case WalletType.litecoin:
return _settingsViewModel.transactionPriority == bitcoin!.getLitecoinTransactionPrioritySlow(); return transactionPriority == bitcoin!.getLitecoinTransactionPrioritySlow();
default: default:
return false; return false;
} }
@ -221,8 +233,6 @@ abstract class ExchangeViewModelBase with Store {
final SettingsStore _settingsStore; final SettingsStore _settingsStore;
final SettingsViewModel _settingsViewModel;
double _bestRate = 0.0; double _bestRate = 0.0;
late Timer bestRateSync; late Timer bestRateSync;
@ -297,12 +307,14 @@ abstract class ExchangeViewModelBase with Store {
} }
Future<void> _calculateBestRate() async { Future<void> _calculateBestRate() async {
final amount = double.tryParse(isFixedRateMode ? receiveAmount : depositAmount) ?? 1;
final result = await Future.wait<double>( final result = await Future.wait<double>(
_tradeAvailableProviders _tradeAvailableProviders
.map((element) => element.calculateAmount( .map((element) => element.calculateAmount(
from: depositCurrency, from: depositCurrency,
to: receiveCurrency, to: receiveCurrency,
amount: 1, amount: amount,
isFixedRateMode: isFixedRateMode, isFixedRateMode: isFixedRateMode,
isReceiveAmount: false)) isReceiveAmount: false))
); );
@ -312,7 +324,7 @@ abstract class ExchangeViewModelBase with Store {
for (int i=0;i<result.length;i++) { for (int i=0;i<result.length;i++) {
if (result[i] != 0) { if (result[i] != 0) {
/// add this provider as its valid for this trade /// add this provider as its valid for this trade
_sortedAvailableProviders[result[i]] = _tradeAvailableProviders[i]; _sortedAvailableProviders[result[i] / amount] = _tradeAvailableProviders[i];
} }
} }
if (_sortedAvailableProviders.isNotEmpty) { if (_sortedAvailableProviders.isNotEmpty) {
@ -335,7 +347,7 @@ abstract class ExchangeViewModelBase with Store {
? depositCurrency ? depositCurrency
: receiveCurrency; : receiveCurrency;
double lowestMin = double.maxFinite; double? lowestMin = double.maxFinite;
double? highestMax = 0.0; double? highestMax = 0.0;
for (var provider in selectedProviders) { for (var provider in selectedProviders) {
@ -350,8 +362,8 @@ abstract class ExchangeViewModelBase with Store {
to: to, to: to,
isFixedRateMode: isFixedRateMode); isFixedRateMode: isFixedRateMode);
if (tempLimits.min != null && tempLimits.min! < lowestMin) { if (lowestMin != null && (tempLimits.min ?? -1) < lowestMin) {
lowestMin = tempLimits.min!; lowestMin = tempLimits.min;
} }
if (highestMax != null && (tempLimits.max ?? double.maxFinite) > highestMax) { if (highestMax != null && (tempLimits.max ?? double.maxFinite) > highestMax) {
highestMax = tempLimits.max; 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); limits = Limits(min: lowestMin, max: highestMax);
limitsState = LimitsLoadedSuccessfully(limits: limits); limitsState = LimitsLoadedSuccessfully(limits: limits);
@ -375,96 +387,105 @@ abstract class ExchangeViewModelBase with Store {
TradeRequest? request; TradeRequest? request;
String amount = ''; String amount = '';
for (var provider in _sortedAvailableProviders.values) { try {
if (!(await provider.checkIsAvailable())) { for (var provider in _sortedAvailableProviders.values) {
continue; if (!(await provider.checkIsAvailable())) {
} continue;
}
if (provider is SideShiftExchangeProvider) { if (provider is SideShiftExchangeProvider) {
request = SideShiftRequest( request = SideShiftRequest(
depositMethod: depositCurrency, depositMethod: depositCurrency,
settleMethod: receiveCurrency, settleMethod: receiveCurrency,
depositAmount: depositAmount.replaceAll(',', '.'), depositAmount: depositAmount.replaceAll(',', '.'),
settleAddress: receiveAddress, settleAddress: receiveAddress,
refundAddress: depositAddress, refundAddress: depositAddress,
); );
amount = depositAmount; amount = depositAmount;
} }
if (provider is SimpleSwapExchangeProvider) { if (provider is SimpleSwapExchangeProvider) {
request = SimpleSwapRequest( request = SimpleSwapRequest(
from: depositCurrency,
to: receiveCurrency,
amount: depositAmount.replaceAll(',', '.'),
address: receiveAddress,
refundAddress: depositAddress,
);
amount = depositAmount;
}
if (provider is XMRTOExchangeProvider) {
request = XMRTOTradeRequest(
from: depositCurrency, from: depositCurrency,
to: receiveCurrency, to: receiveCurrency,
amount: depositAmount.replaceAll(',', '.'), amount: depositAmount.replaceAll(',', '.'),
receiveAmount: receiveAmount.replaceAll(',', '.'),
address: receiveAddress, address: receiveAddress,
refundAddress: depositAddress, refundAddress: depositAddress,
isBTCRequest: isReceiveAmountEntered); );
amount = depositAmount; amount = depositAmount;
} }
if (provider is ChangeNowExchangeProvider) { if (provider is XMRTOExchangeProvider) {
request = ChangeNowRequest( request = XMRTOTradeRequest(
from: depositCurrency, from: depositCurrency,
to: receiveCurrency, to: receiveCurrency,
fromAmount: depositAmount.replaceAll(',', '.'), amount: depositAmount.replaceAll(',', '.'),
toAmount: receiveAmount.replaceAll(',', '.'), receiveAmount: receiveAmount.replaceAll(',', '.'),
refundAddress: depositAddress, address: receiveAddress,
address: receiveAddress, refundAddress: depositAddress,
isReverse: isReverse); isBTCRequest: isReceiveAmountEntered);
amount = isReverse ? receiveAmount : depositAmount; amount = depositAmount;
} }
if (provider is MorphTokenExchangeProvider) { if (provider is ChangeNowExchangeProvider) {
request = MorphTokenRequest( request = ChangeNowRequest(
from: depositCurrency, from: depositCurrency,
to: receiveCurrency, to: receiveCurrency,
amount: depositAmount.replaceAll(',', '.'), fromAmount: depositAmount.replaceAll(',', '.'),
refundAddress: depositAddress, toAmount: receiveAmount.replaceAll(',', '.'),
address: receiveAddress); refundAddress: depositAddress,
amount = depositAmount; address: receiveAddress,
} isReverse: isReverse);
amount = isReverse ? receiveAmount : depositAmount;
}
amount = amount.replaceAll(',', '.'); if (provider is MorphTokenExchangeProvider) {
request = MorphTokenRequest(
from: depositCurrency,
to: receiveCurrency,
amount: depositAmount.replaceAll(',', '.'),
refundAddress: depositAddress,
address: receiveAddress);
amount = depositAmount;
}
if (limitsState is LimitsLoadedSuccessfully) { amount = amount.replaceAll(',', '.');
if (double.parse(amount) < limits.min!) {
continue; if (limitsState is LimitsLoadedSuccessfully) {
} else if (limits.max != null && double.parse(amount) > limits.max!) { if (double.parse(amount) < limits.min!) {
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; 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 /// if the code reached here then none of the providers succeeded
tradeState = TradeIsCreatedFailure( tradeState = TradeIsCreatedFailure(
title: S.current.trade_not_created, title: S.current.trade_not_created,
error: S.current.none_of_selected_providers_can_exchange); 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 @action

View file

@ -7,6 +7,7 @@ import 'package:cake_wallet/ionia/ionia_anypay.dart';
import 'package:cake_wallet/ionia/ionia_merchant.dart'; import 'package:cake_wallet/ionia/ionia_merchant.dart';
import 'package:cake_wallet/ionia/ionia_tip.dart'; import 'package:cake_wallet/ionia/ionia_tip.dart';
import 'package:cake_wallet/ionia/ionia_any_pay_payment_info.dart'; import 'package:cake_wallet/ionia/ionia_any_pay_payment_info.dart';
import 'package:cake_wallet/view_model/send/send_view_model.dart';
part 'ionia_purchase_merch_view_model.g.dart'; part 'ionia_purchase_merch_view_model.g.dart';
@ -17,6 +18,7 @@ abstract class IoniaMerchPurchaseViewModelBase with Store {
required this.ioniaAnyPayService, required this.ioniaAnyPayService,
required this.amount, required this.amount,
required this.ioniaMerchant, required this.ioniaMerchant,
required this.sendViewModel,
}) : tipAmount = 0.0, }) : tipAmount = 0.0,
percentage = 0.0, percentage = 0.0,
invoiceCreationState = InitialExecutionState(), invoiceCreationState = InitialExecutionState(),
@ -40,6 +42,8 @@ abstract class IoniaMerchPurchaseViewModelBase with Store {
final IoniaMerchant ioniaMerchant; final IoniaMerchant ioniaMerchant;
final SendViewModel sendViewModel;
final IoniaAnyPay ioniaAnyPayService; final IoniaAnyPay ioniaAnyPayService;
IoniaAnyPayPaymentInfo? paymentInfo; IoniaAnyPayPaymentInfo? paymentInfo;

View file

@ -14,11 +14,11 @@ abstract class NodeCreateOrEditViewModelBase with Store {
: state = InitialExecutionState(), : state = InitialExecutionState(),
connectionState = InitialExecutionState(), connectionState = InitialExecutionState(),
useSSL = false, useSSL = false,
trusted = false,
address = '', address = '',
port = '', port = '',
login = '', login = '',
password = ''; password = '',
trusted = false;
@observable @observable
ExecutionState state; ExecutionState state;

View file

@ -1,10 +1,10 @@
import 'package:cake_wallet/entities/balance_display_mode.dart'; 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/entities/transaction_description.dart';
import 'package:cake_wallet/view_model/dashboard/balance_view_model.dart'; import 'package:cake_wallet/view_model/dashboard/balance_view_model.dart';
import 'package:cw_core/transaction_priority.dart'; import 'package:cw_core/transaction_priority.dart';
import 'package:cake_wallet/view_model/send/output.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/send/send_template_view_model.dart';
import 'package:cake_wallet/view_model/settings/settings_view_model.dart';
import 'package:hive/hive.dart'; import 'package:hive/hive.dart';
import 'package:mobx/mobx.dart'; import 'package:mobx/mobx.dart';
import 'package:cake_wallet/entities/template.dart'; import 'package:cake_wallet/entities/template.dart';
@ -42,7 +42,8 @@ abstract class SendViewModelBase with Store {
: state = InitialExecutionState(), : state = InitialExecutionState(),
currencies = _wallet.balance.keys.toList(), currencies = _wallet.balance.keys.toList(),
selectedCryptoCurrency = _wallet.currency, selectedCryptoCurrency = _wallet.currency,
outputs = ObservableList<Output>() { outputs = ObservableList<Output>(),
fiatFromSettings = _settingsStore.fiatCurrency {
final priority = _settingsStore.priority[_wallet.type]; final priority = _settingsStore.priority[_wallet.type];
final priorities = priorityForWalletType(_wallet.type); final priorities = priorityForWalletType(_wallet.type);
@ -52,7 +53,7 @@ abstract class SendViewModelBase with Store {
outputs.add(Output(_wallet, _settingsStore, _fiatConversationStore, () => selectedCryptoCurrency)); outputs.add(Output(_wallet, _settingsStore, _fiatConversationStore, () => selectedCryptoCurrency));
} }
@observable @observable
ExecutionState state; ExecutionState state;
@ -133,11 +134,13 @@ abstract class SendViewModelBase with Store {
Validator get textValidator => TextValidator(); Validator get textValidator => TextValidator();
final FiatCurrency fiatFromSettings;
@observable @observable
PendingTransaction? pendingTransaction; PendingTransaction? pendingTransaction;
@computed @computed
String get balance => balanceViewModel.availableBalance ?? '0.0'; String get balance => balanceViewModel.availableBalance;
@computed @computed
bool get isReadyForSend => _wallet.syncStatus is SyncedSyncStatus; bool get isReadyForSend => _wallet.syncStatus is SyncedSyncStatus;
@ -166,6 +169,9 @@ abstract class SendViewModelBase with Store {
bool get hasCurrecyChanger => walletType == WalletType.haven; bool get hasCurrecyChanger => walletType == WalletType.haven;
@computed
FiatCurrency get fiatCurrency => _settingsStore.fiatCurrency;
final WalletBase _wallet; final WalletBase _wallet;
final SettingsStore _settingsStore; final SettingsStore _settingsStore;
final SendTemplateViewModel sendTemplateViewModel; final SendTemplateViewModel sendTemplateViewModel;
@ -208,7 +214,7 @@ abstract class SendViewModelBase with Store {
state = TransactionCommitting(); state = TransactionCommitting();
await pendingTransaction!.commit(); await pendingTransaction!.commit();
if (pendingTransaction!.id?.isNotEmpty ?? false) { if (pendingTransaction!.id.isNotEmpty) {
_settingsStore.shouldSaveRecipientAddress _settingsStore.shouldSaveRecipientAddress
? await transactionDescriptionBox.add(TransactionDescription( ? await transactionDescriptionBox.add(TransactionDescription(
id: pendingTransaction!.id, id: pendingTransaction!.id,
@ -283,4 +289,12 @@ abstract class SendViewModelBase with Store {
bool _isEqualCurrency(String currency) => bool _isEqualCurrency(String currency) =>
currency.toLowerCase() == _wallet.currency.title.toLowerCase(); currency.toLowerCase() == _wallet.currency.title.toLowerCase();
@action
void onClose() =>
_settingsStore.fiatCurrency = fiatFromSettings;
@action
void setFiatCurrency(FiatCurrency fiat) =>
_settingsStore.fiatCurrency = fiat;
} }

View 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;
}

View 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;
}

View 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;
}

View 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;
}

View file

@ -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);
}

View file

@ -184,7 +184,7 @@ abstract class TransactionDetailsViewModelBase with Store {
case WalletType.monero: case WalletType.monero:
return 'https://monero.com/tx/${txId}'; return 'https://monero.com/tx/${txId}';
case WalletType.bitcoin: case WalletType.bitcoin:
return 'https://www.blockchain.com/btc/tx/${txId}'; return 'https://mempool.space/tx/${txId}';
case WalletType.litecoin: case WalletType.litecoin:
return 'https://blockchair.com/litecoin/transaction/${txId}'; return 'https://blockchair.com/litecoin/transaction/${txId}';
case WalletType.haven: case WalletType.haven:
@ -199,7 +199,7 @@ abstract class TransactionDetailsViewModelBase with Store {
case WalletType.monero: case WalletType.monero:
return S.current.view_transaction_on + 'Monero.com'; return S.current.view_transaction_on + 'Monero.com';
case WalletType.bitcoin: case WalletType.bitcoin:
return S.current.view_transaction_on + 'Blockchain.com'; return S.current.view_transaction_on + 'mempool.space';
case WalletType.litecoin: case WalletType.litecoin:
return S.current.view_transaction_on + 'Blockchair.com'; return S.current.view_transaction_on + 'Blockchair.com';
case WalletType.haven: case WalletType.haven:

5
model_generator.sh Normal file
View 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

View file

@ -34,7 +34,7 @@ dependencies:
local_auth: ^2.1.0 local_auth: ^2.1.0
package_info: ^2.0.0 package_info: ^2.0.0
#package_info_plus: ^1.4.2 #package_info_plus: ^1.4.2
devicelocale: ^0.5.4 devicelocale: ^0.4.3
auto_size_text: ^3.0.0 auto_size_text: ^3.0.0
dotted_border: ^2.0.0+2 dotted_border: ^2.0.0+2
smooth_page_indicator: ^1.0.0+2 smooth_page_indicator: ^1.0.0+2

View file

@ -356,6 +356,7 @@
"sync_status_failed_connect" : "GETRENNT", "sync_status_failed_connect" : "GETRENNT",
"sync_status_connecting" : "VERBINDEN", "sync_status_connecting" : "VERBINDEN",
"sync_status_connected" : "VERBUNDEN", "sync_status_connected" : "VERBUNDEN",
"sync_status_attempting_sync" : "SYNC VERSUCHEN",
"transaction_priority_slow" : "Langsam", "transaction_priority_slow" : "Langsam",
@ -653,7 +654,14 @@
"use_suggested": "Vorgeschlagen verwenden", "use_suggested": "Vorgeschlagen verwenden",
"do_not_share_warning_text" : "Teilen Sie diese nicht mit anderen, einschließlich des Supports.\n\nSie werden Ihr Geld stehlen!", "do_not_share_warning_text" : "Teilen Sie diese nicht mit anderen, einschließlich des Supports.\n\nSie werden Ihr Geld stehlen!",
"help": "hilfe", "help": "hilfe",
"advanced_privacy_settings": "Erweiterte Datenschutzeinstellungen", "connection_sync": "Verbindung und Synchronisierung",
"security_and_backup": "Sicherheit und Datensicherung",
"create_backup": "Backup erstellen",
"privacy_settings": "Datenschutzeinstellungen", "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" "settings_can_be_changed_later": "Diese Einstellungen können später in den App-Einstellungen geändert werden"
} }

View file

@ -356,6 +356,7 @@
"sync_status_failed_connect" : "DISCONNECTED", "sync_status_failed_connect" : "DISCONNECTED",
"sync_status_connecting" : "CONNECTING", "sync_status_connecting" : "CONNECTING",
"sync_status_connected" : "CONNECTED", "sync_status_connected" : "CONNECTED",
"sync_status_attempting_sync" : "ATTEMPTING SYNC",
"transaction_priority_slow" : "Slow", "transaction_priority_slow" : "Slow",
@ -653,7 +654,14 @@
"use_suggested": "Use Suggested", "use_suggested": "Use Suggested",
"do_not_share_warning_text" : "Do not share these with anyone else, including support.\n\nThey will steal your money!", "do_not_share_warning_text" : "Do not share these with anyone else, including support.\n\nThey will steal your money!",
"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", "advanced_privacy_settings": "Advanced Privacy Settings",
"privacy_settings": "Privacy Settings",
"settings_can_be_changed_later": "These settings can be changed later in the app settings" "settings_can_be_changed_later": "These settings can be changed later in the app settings"
} }

View file

@ -356,6 +356,7 @@
"sync_status_failed_connect" : "DESCONECTADO", "sync_status_failed_connect" : "DESCONECTADO",
"sync_status_connecting" : "CONECTANDO", "sync_status_connecting" : "CONECTANDO",
"sync_status_connected" : "CONECTADO", "sync_status_connected" : "CONECTADO",
"sync_status_attempting_sync" : "INTENTAR SINCRONIZAR",
"transaction_priority_slow" : "Lento", "transaction_priority_slow" : "Lento",
@ -653,7 +654,14 @@
"use_suggested": "Usar sugerido", "use_suggested": "Usar sugerido",
"do_not_share_warning_text" : "No comparta estos con nadie más, incluido el soporte.\n\n¡Te robarán tu dinero!", "do_not_share_warning_text" : "No comparta estos con nadie más, incluido el soporte.\n\n¡Te robarán tu dinero!",
"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", "advanced_privacy_settings": "Configuración avanzada de privacidad",
"privacy_settings": "La configuración de privacidad",
"settings_can_be_changed_later": "Estas configuraciones se pueden cambiar más tarde en la configuración de la aplicación" "settings_can_be_changed_later": "Estas configuraciones se pueden cambiar más tarde en la configuración de la aplicación"
} }

View file

@ -354,6 +354,7 @@
"sync_status_failed_connect" : "DÉCONNECTÉ", "sync_status_failed_connect" : "DÉCONNECTÉ",
"sync_status_connecting" : "CONNEXION EN COURS", "sync_status_connecting" : "CONNEXION EN COURS",
"sync_status_connected" : "CONNECTÉ", "sync_status_connected" : "CONNECTÉ",
"sync_status_attempting_sync" : "TENTATIVE DE SYNCHRONISATION",
"transaction_priority_slow" : "Lent", "transaction_priority_slow" : "Lent",
@ -651,7 +652,14 @@
"use_suggested": "Utilisation suggérée", "use_suggested": "Utilisation suggérée",
"do_not_share_warning_text" : "Ne les partagez avec personne d'autre, y compris avec l'assistance.\n\nIls vont voler votre argent!", "do_not_share_warning_text" : "Ne les partagez avec personne d'autre, y compris avec l'assistance.\n\nIls vont voler votre argent!",
"help": "aider", "help": "aider",
"advanced_privacy_settings": "Paramètres de confidentialité avancés", "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_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" "settings_can_be_changed_later": "Ces paramètres peuvent être modifiés ultérieurement dans les paramètres de l'application"
} }

View file

@ -356,6 +356,7 @@
"sync_status_failed_connect" : "डिस्कनेक्ट किया गया", "sync_status_failed_connect" : "डिस्कनेक्ट किया गया",
"sync_status_connecting" : "कनेक्ट", "sync_status_connecting" : "कनेक्ट",
"sync_status_connected" : "जुड़े हुए", "sync_status_connected" : "जुड़े हुए",
"sync_status_attempting_sync" : "सिंक करने का प्रयास",
"transaction_priority_slow" : "धीरे", "transaction_priority_slow" : "धीरे",
@ -653,7 +654,14 @@
"use_suggested": "सुझाए गए का प्रयोग करें", "use_suggested": "सुझाए गए का प्रयोग करें",
"do_not_share_warning_text" : "इन्हें समर्थन सहित किसी और के साथ साझा न करें।\n\nवे आपका पैसा चुरा लेंगे!", "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": "उन्नत गोपनीयता सेटिंग्स", "advanced_privacy_settings": "उन्नत गोपनीयता सेटिंग्स",
"privacy_settings": "गोपनीय सेटिंग",
"settings_can_be_changed_later": "इन सेटिंग्स को बाद में ऐप सेटिंग में बदला जा सकता है" "settings_can_be_changed_later": "इन सेटिंग्स को बाद में ऐप सेटिंग में बदला जा सकता है"
} }

View file

@ -356,6 +356,7 @@
"sync_status_failed_connect" : "ISKLJUČENO", "sync_status_failed_connect" : "ISKLJUČENO",
"sync_status_connecting" : "SPAJANJE", "sync_status_connecting" : "SPAJANJE",
"sync_status_connected" : "SPOJENO", "sync_status_connected" : "SPOJENO",
"sync_status_attempting_sync" : "POKUŠAJ SINKRONIZACIJE",
"transaction_priority_slow" : "Sporo", "transaction_priority_slow" : "Sporo",
@ -653,7 +654,14 @@
"use_suggested": "Koristite predloženo", "use_suggested": "Koristite predloženo",
"do_not_share_warning_text" : "Nemojte ih dijeliti ni s kim, uključujući podršku.\n\nUkrast će vam novac!", "do_not_share_warning_text" : "Nemojte ih dijeliti ni s kim, uključujući podršku.\n\nUkrast će vam novac!",
"help": "pomozite", "help": "pomozite",
"advanced_privacy_settings": "Napredne postavke privatnosti", "connection_sync": "Povezivanje i sinkronizacija",
"security_and_backup": "Sigurnost i sigurnosna kopija",
"create_backup": "Stvori sigurnosnu kopiju",
"privacy_settings": "Postavke privatnosti", "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" "settings_can_be_changed_later": "Te se postavke mogu promijeniti kasnije u postavkama aplikacije"
} }

View file

@ -356,6 +356,7 @@
"sync_status_failed_connect" : "DISCONNESSO", "sync_status_failed_connect" : "DISCONNESSO",
"sync_status_connecting" : "CONNESSIONE", "sync_status_connecting" : "CONNESSIONE",
"sync_status_connected" : "CONNESSO", "sync_status_connected" : "CONNESSO",
"sync_status_attempting_sync" : "TENTATIVO DI SINCRONIZZAZIONE",
"transaction_priority_slow" : "Bassa", "transaction_priority_slow" : "Bassa",
@ -653,7 +654,14 @@
"use_suggested": "Usa suggerito", "use_suggested": "Usa suggerito",
"do_not_share_warning_text" : "Non condividerli con nessun altro, incluso il supporto.\n\nTi ruberanno i soldi!", "do_not_share_warning_text" : "Non condividerli con nessun altro, incluso il supporto.\n\nTi ruberanno i soldi!",
"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", "advanced_privacy_settings": "Impostazioni avanzate sulla privacy",
"privacy_settings": "Impostazioni della privacy",
"settings_can_be_changed_later": "Queste impostazioni possono essere modificate in seguito nelle impostazioni dell'app" "settings_can_be_changed_later": "Queste impostazioni possono essere modificate in seguito nelle impostazioni dell'app"
} }

View file

@ -356,6 +356,7 @@
"sync_status_failed_connect" : "切断されました", "sync_status_failed_connect" : "切断されました",
"sync_status_connecting" : "接続中", "sync_status_connecting" : "接続中",
"sync_status_connected" : "接続済み", "sync_status_connected" : "接続済み",
"sync_status_attempting_sync" : "同期を試みています",
"transaction_priority_slow" : "スロー", "transaction_priority_slow" : "スロー",
@ -653,7 +654,14 @@
"use_suggested": "推奨を使用", "use_suggested": "推奨を使用",
"do_not_share_warning_text" : "サポートを含め、これらを他の誰とも共有しないでください。\n\n彼らはあなたのお金を盗みます", "do_not_share_warning_text" : "サポートを含め、これらを他の誰とも共有しないでください。\n\n彼らはあなたのお金を盗みます",
"help": "ヘルプ", "help": "ヘルプ",
"advanced_privacy_settings": "高度なプライバシー設定", "connection_sync": "接続と同期",
"security_and_backup": "セキュリティとバックアップ",
"create_backup": "バックアップを作成",
"privacy_settings": "プライバシー設定", "privacy_settings": "プライバシー設定",
"privacy": "プライバシー",
"display_settings": "表示設定",
"other_settings": "その他の設定",
"disable_exchange": "交換を無効にする",
"advanced_privacy_settings": "高度なプライバシー設定",
"settings_can_be_changed_later": "これらの設定は、後でアプリの設定で変更できます" "settings_can_be_changed_later": "これらの設定は、後でアプリの設定で変更できます"
} }

View file

@ -356,6 +356,7 @@
"sync_status_failed_connect" : "연결 해제", "sync_status_failed_connect" : "연결 해제",
"sync_status_connecting" : "연결 중", "sync_status_connecting" : "연결 중",
"sync_status_connected" : "연결됨", "sync_status_connected" : "연결됨",
"sync_status_attempting_sync" : "동기화 시도 중",
"transaction_priority_slow" : "느린", "transaction_priority_slow" : "느린",
@ -653,7 +654,14 @@
"use_suggested": "추천 사용", "use_suggested": "추천 사용",
"do_not_share_warning_text" : "지원을 포함하여 다른 사람과 이러한 정보를 공유하지 마십시오.\n\n그들은 당신의 돈을 훔칠 것입니다!", "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": "고급 개인 정보 설정", "advanced_privacy_settings": "고급 개인 정보 설정",
"privacy_settings": "개인 정보 설정",
"settings_can_be_changed_later": "이 설정은 나중에 앱 설정에서 변경할 수 있습니다." "settings_can_be_changed_later": "이 설정은 나중에 앱 설정에서 변경할 수 있습니다."
} }

View file

@ -356,6 +356,7 @@
"sync_status_failed_connect" : "LOSGEKOPPELD", "sync_status_failed_connect" : "LOSGEKOPPELD",
"sync_status_connecting" : "AANSLUITING", "sync_status_connecting" : "AANSLUITING",
"sync_status_connected" : "VERBONDEN", "sync_status_connected" : "VERBONDEN",
"sync_status_attempting_sync" : "SYNCHRONISATIE PROBEREN",
"transaction_priority_slow" : "Langzaam", "transaction_priority_slow" : "Langzaam",
@ -653,7 +654,14 @@
"use_suggested": "Gebruik aanbevolen", "use_suggested": "Gebruik aanbevolen",
"do_not_share_warning_text" : "Deel deze met niemand anders, ook niet met support.\n\nZe zullen je geld stelen!", "do_not_share_warning_text" : "Deel deze met niemand anders, ook niet met support.\n\nZe zullen je geld stelen!",
"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", "advanced_privacy_settings": "Geavanceerde privacy-instellingen",
"privacy_settings": "Privacy instellingen",
"settings_can_be_changed_later": "Deze instellingen kunnen later worden gewijzigd in de app-instellingen" "settings_can_be_changed_later": "Deze instellingen kunnen later worden gewijzigd in de app-instellingen"
} }

View file

@ -356,6 +356,7 @@
"sync_status_failed_connect" : "NIEPOWIĄZANY", "sync_status_failed_connect" : "NIEPOWIĄZANY",
"sync_status_connecting" : "ZŁĄCZONY", "sync_status_connecting" : "ZŁĄCZONY",
"sync_status_connected" : "POŁĄCZONY", "sync_status_connected" : "POŁĄCZONY",
"sync_status_attempting_sync" : "PRÓBA SYNCHRONIZACJI",
"transaction_priority_slow" : "Powolny", "transaction_priority_slow" : "Powolny",
@ -653,7 +654,14 @@
"use_suggested": "Użyj sugerowane", "use_suggested": "Użyj sugerowane",
"do_not_share_warning_text" : "Nie udostępniaj ich nikomu innemu, w tym wsparcia.\n\nUkradną twoje pieniądze!", "do_not_share_warning_text" : "Nie udostępniaj ich nikomu innemu, w tym wsparcia.\n\nUkradną twoje pieniądze!",
"help": "pomoc", "help": "pomoc",
"advanced_privacy_settings": "Zaawansowane ustawienia prywatności", "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_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" "settings_can_be_changed_later": "Te ustawienia można później zmienić w ustawieniach aplikacji"
} }

View file

@ -356,6 +356,7 @@
"sync_status_failed_connect" : "DESCONECTADO", "sync_status_failed_connect" : "DESCONECTADO",
"sync_status_connecting" : "CONECTANDO", "sync_status_connecting" : "CONECTANDO",
"sync_status_connected" : "CONECTADO", "sync_status_connected" : "CONECTADO",
"sync_status_attempting_sync" : "TENTANDO SINCRONIZAR",
"transaction_priority_slow" : "Lenta", "transaction_priority_slow" : "Lenta",
@ -652,7 +653,14 @@
"use_suggested": "Uso sugerido", "use_suggested": "Uso sugerido",
"do_not_share_warning_text" : "Não os compartilhe com mais ninguém, incluindo suporte.\n\nEles vão roubar seu dinheiro!", "do_not_share_warning_text" : "Não os compartilhe com mais ninguém, incluindo suporte.\n\nEles vão roubar seu dinheiro!",
"help": "ajuda", "help": "ajuda",
"advanced_privacy_settings": "Configurações de privacidade avançadas", "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_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" "settings_can_be_changed_later": "Essas configurações podem ser alteradas posteriormente nas configurações do aplicativo"
} }

View file

@ -356,6 +356,7 @@
"sync_status_failed_connect" : "ОТКЛЮЧЕНО", "sync_status_failed_connect" : "ОТКЛЮЧЕНО",
"sync_status_connecting" : "ПОДКЛЮЧЕНИЕ", "sync_status_connecting" : "ПОДКЛЮЧЕНИЕ",
"sync_status_connected" : "ПОДКЛЮЧЕНО", "sync_status_connected" : "ПОДКЛЮЧЕНО",
"sync_status_attempting_sync" : "ПОПЫТКА СИНХРОНИЗАЦИИ",
"transaction_priority_slow" : "Медленный", "transaction_priority_slow" : "Медленный",
@ -653,7 +654,14 @@
"use_suggested": "Использовать предложенный", "use_suggested": "Использовать предложенный",
"do_not_share_warning_text" : "Не делитесь ими с кем-либо еще, в том числе со службой поддержки.\n\nОни украдут ваши деньги!", "do_not_share_warning_text" : "Не делитесь ими с кем-либо еще, в том числе со службой поддержки.\n\nОни украдут ваши деньги!",
"help": "помощь", "help": "помощь",
"advanced_privacy_settings": "Расширенные настройки конфиденциальности", "connection_sync": "Подключение и синхронизация",
"security_and_backup": "Безопасность и резервное копирование",
"create_backup": "Создать резервную копию",
"privacy_settings": "Настройки конфиденциальности", "privacy_settings": "Настройки конфиденциальности",
"privacy": "Конфиденциальность",
"display_settings": "Настройки отображения",
"other_settings": "Другие настройки",
"disable_exchange": "Отключить обмен",
"advanced_privacy_settings": "Расширенные настройки конфиденциальности",
"settings_can_be_changed_later": "Эти настройки можно изменить позже в настройках приложения." "settings_can_be_changed_later": "Эти настройки можно изменить позже в настройках приложения."
} }

View file

@ -355,6 +355,7 @@
"sync_status_failed_connect" : "ВІДКЛЮЧЕНО", "sync_status_failed_connect" : "ВІДКЛЮЧЕНО",
"sync_status_connecting" : "ПІДКЛЮЧЕННЯ", "sync_status_connecting" : "ПІДКЛЮЧЕННЯ",
"sync_status_connected" : "ПІДКЛЮЧЕНО", "sync_status_connected" : "ПІДКЛЮЧЕНО",
"sync_status_attempting_sync" : "СПРОБА СИНХРОНІЗАЦІЇ",
"transaction_priority_slow" : "Повільний", "transaction_priority_slow" : "Повільний",
@ -652,7 +653,14 @@
"use_suggested": "Використати запропоноване", "use_suggested": "Використати запропоноване",
"do_not_share_warning_text" : "Не повідомляйте їх нікому, включно зі службою підтримки.\n\nВони вкрадуть ваші гроші!", "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": "Розширені налаштування конфіденційності", "advanced_privacy_settings": "Розширені налаштування конфіденційності",
"privacy_settings": "Параметри конфіденційності",
"settings_can_be_changed_later": "Ці параметри можна змінити пізніше в налаштуваннях програми" "settings_can_be_changed_later": "Ці параметри можна змінити пізніше в налаштуваннях програми"
} }

View file

@ -356,6 +356,7 @@
"sync_status_failed_connect" : "断线", "sync_status_failed_connect" : "断线",
"sync_status_connecting" : "连接中", "sync_status_connecting" : "连接中",
"sync_status_connected" : "已连接", "sync_status_connected" : "已连接",
"sync_status_attempting_sync" : "嘗試同步",
"transaction_priority_slow" : "慢速", "transaction_priority_slow" : "慢速",
@ -651,7 +652,14 @@
"use_suggested": "使用建议", "use_suggested": "使用建议",
"do_not_share_warning_text" : "不要與其他任何人分享這些內容,包括支持。\n\n他們會偷你的錢", "do_not_share_warning_text" : "不要與其他任何人分享這些內容,包括支持。\n\n他們會偷你的錢",
"help": "帮助", "help": "帮助",
"advanced_privacy_settings": "高级隐私设置", "connection_sync": "连接和同步",
"security_and_backup": "安全和备份",
"create_backup": "创建备份",
"privacy_settings": "隐私设置", "privacy_settings": "隐私设置",
"privacy":"隐私",
"display_settings": "显示设置",
"other_settings": "其他设置",
"disable_exchange": "禁用交换",
"advanced_privacy_settings": "高级隐私设置",
"settings_can_be_changed_later": "稍后可以在应用设置中更改这些设置" "settings_can_be_changed_later": "稍后可以在应用设置中更改这些设置"
} }

View file

@ -14,14 +14,14 @@ TYPES=($MONERO_COM $CAKEWALLET $HAVEN)
APP_ANDROID_TYPE=$1 APP_ANDROID_TYPE=$1
MONERO_COM_NAME="Monero.com" MONERO_COM_NAME="Monero.com"
MONERO_COM_VERSION="1.2.0" MONERO_COM_VERSION="1.2.1"
MONERO_COM_BUILD_NUMBER=26 MONERO_COM_BUILD_NUMBER=32
MONERO_COM_BUNDLE_ID="com.monero.app" MONERO_COM_BUNDLE_ID="com.monero.app"
MONERO_COM_PACKAGE="com.monero.app" MONERO_COM_PACKAGE="com.monero.app"
CAKEWALLET_NAME="Cake Wallet" CAKEWALLET_NAME="Cake Wallet"
CAKEWALLET_VERSION="4.5.0" CAKEWALLET_VERSION="4.5.1"
CAKEWALLET_BUILD_NUMBER=130 CAKEWALLET_BUILD_NUMBER=136
CAKEWALLET_BUNDLE_ID="com.cakewallet.cake_wallet" CAKEWALLET_BUNDLE_ID="com.cakewallet.cake_wallet"
CAKEWALLET_PACKAGE="com.cakewallet.cake_wallet" CAKEWALLET_PACKAGE="com.cakewallet.cake_wallet"

View file

@ -13,13 +13,13 @@ TYPES=($MONERO_COM $CAKEWALLET $HAVEN)
APP_IOS_TYPE=$1 APP_IOS_TYPE=$1
MONERO_COM_NAME="Monero.com" MONERO_COM_NAME="Monero.com"
MONERO_COM_VERSION="1.2.0" MONERO_COM_VERSION="1.2.1"
MONERO_COM_BUILD_NUMBER=26 MONERO_COM_BUILD_NUMBER=29
MONERO_COM_BUNDLE_ID="com.cakewallet.monero" MONERO_COM_BUNDLE_ID="com.cakewallet.monero"
CAKEWALLET_NAME="Cake Wallet" CAKEWALLET_NAME="Cake Wallet"
CAKEWALLET_VERSION="4.5.0" CAKEWALLET_VERSION="4.5.1"
CAKEWALLET_BUILD_NUMBER=130 CAKEWALLET_BUILD_NUMBER=133
CAKEWALLET_BUNDLE_ID="com.fotolockr.cakewallet" CAKEWALLET_BUNDLE_ID="com.fotolockr.cakewallet"
HAVEN_NAME="Haven" HAVEN_NAME="Haven"

View file

@ -28,6 +28,7 @@ class SecretKey {
SecretKey('simpleSwapApiKey', () => ''), SecretKey('simpleSwapApiKey', () => ''),
SecretKey('anypayToken', () => ''), SecretKey('anypayToken', () => ''),
SecretKey('onramperApiKey', () => ''), SecretKey('onramperApiKey', () => ''),
SecretKey('ioniaClientId', () => ''),
]; ];
final String name; final String name;