Merge branch 'main' of https://github.com/cake-tech/cake_wallet into CW-237-enhance-error-catching-reporting

This commit is contained in:
OmarHatem 2023-01-06 16:18:21 +02:00
commit baeff1ea14
166 changed files with 4306 additions and 2203 deletions

View file

@ -0,0 +1,56 @@
name: Cache Dependencies
on:
push:
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 main
cd cake_wallet/scripts/android/
./install_ndk.sh
source ./app_env.sh cakewallet
./app_config.sh
- name: Cache Externals
id: cache-externals
uses: actions/cache@v3
with:
path: |
/opt/android/cake_wallet/cw_haven/android/.cxx
/opt/android/cake_wallet/cw_haven/ios/External
/opt/android/cake_wallet/cw_monero/android/.cxx
/opt/android/cake_wallet/cw_monero/ios/External
/opt/android/cake_wallet/cw_shared_external/ios/External
key: ${{ hashFiles('**/build_monero.sh', '**/build_haven.sh') }}
- if: ${{ steps.cache-externals.outputs.cache-hit != 'true' }}
name: Generate Externals
run: |
cd /opt/android/cake_wallet/scripts/android/
source ./app_env.sh cakewallet
./build_all.sh
./copy_monero_deps.sh

151
.github/workflows/pr_test_build.yml vendored Normal file
View file

@ -0,0 +1,151 @@
name: PR Test Build
on:
pull_request:
branches: [ main ]
jobs:
test:
runs-on: ubuntu-18.04
env:
STORE_PASS: test@cake_wallet
KEY_PASS: test@cake_wallet
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
- name: Cache Externals
id: cache-externals
uses: actions/cache@v3
with:
path: |
/opt/android/cake_wallet/cw_haven/android/.cxx
/opt/android/cake_wallet/cw_haven/ios/External
/opt/android/cake_wallet/cw_monero/android/.cxx
/opt/android/cake_wallet/cw_monero/ios/External
/opt/android/cake_wallet/cw_shared_external/ios/External
key: ${{ hashFiles('**/build_monero.sh', '**/build_haven.sh') }}
- if: ${{ steps.cache-externals.outputs.cache-hit != 'true' }}
name: Generate Externals
run: |
cd /opt/android/cake_wallet/scripts/android/
source ./app_env.sh cakewallet
./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 $STORE_PASS -keypass $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=$STORE_PASS keyPassword=$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: Rename apk file
run: |
cd /opt/android/cake_wallet/build/app/outputs/apk/release
mkdir test-apk
cp 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/
- name: Send Test APK
continue-on-error: true
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"'"}'

View file

@ -76,3 +76,55 @@ We have 24/7 free support. Please contact support@cakewallet.com
More instructions to follow More instructions to follow
For instructions on how to build for Android: please view file `howto-build-android.md` For instructions on how to build for Android: please view file `howto-build-android.md`
# Contributing
## Improving translations
Edit the applicable `strings_XX.arb` file in `res/values/` and open a pull request with the changes.
## Current list of language files:
- English
- Spanish
- French
- German
- Italian
- Portugese
- Dutch
- Polish
- Croatian
- Russian
- Ukranian
- Hindi
- Japanese
- Chinese
- Korean
## Add a new language
1. Create a new `strings_XX.arb` file in `res/values/`, replacing XX with the language's [ISO 639-1 code](https://en.wikipedia.org/wiki/ISO_639-1).
2. Edit the strings in this file, replacing XXX below with the translation for each string.
`"welcome" : "Welcome to",` -> `"welcome" : "XXX",`
3. For strings where there is a variable, denoted by a $ symbol and braces, such as ${status}, the string in braces should not be translated. For example, when editing line 106:
"time" : "${minutes}m ${seconds}s"
The only parts to be translated, if needed, are the values m and s after the variables.
4. Add the language to `lib/entities/language_service.dart` under both `supportedLocales` and `localeCountryCode`. Use the name of the language in the local language and in English in parentheses after for `supportedLocales`. Use the [ISO 3166-1 alpha-3 code](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-3) for `localeCountryCode`. You must choose one country, so choose the country with the most native speakers of this language or is otherwise best associated with this language.
5. Add a relevant flag to `assets/images/flags/XXXX.png`, replacing XXXX with the 3 digit localeCountryCode. The image must be 42x36 pizxels with a 3 pixels of transparent margin on all 4 sides.
## Add a new fiat currency
1. Check with [Cake Wallet support](https://guides.cakewallet.com) to see if the desired new fiat currency is available through our fiat API. Not all fiat currencies are.
2. If the currency is associated strongly with a specific issuing country, map the [ISO 4217](https://en.wikipedia.org/wiki/ISO_4217) currency code with the applicable [ISO 3166-1 alpha-3 code](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-3) in `lib/entities/fiat_currency.dart`. If the currency is used in a whole region or organization, then map with a reasonable interpretation of this (eg: eur countryCode for EUR symbol).
3. Add the raw mapping underneath in `lib/entities/fiat_currency.dart` following the same format as the others.
4. Add a flag of the issuing country or organization to `assets/images/flags/XXXX.png`, replacing XXXX with the ISO 3166-1 alpha-3 code used above (eg: `usa.png`, `eur.png`). Do not add this if the flag with the same name already exists. The image must be 42x36 pizxels with a 3 pixels of transparent margin on all 4 sides.

View file

@ -16,7 +16,7 @@
android:requestLegacyExternalStorage="true"> android:requestLegacyExternalStorage="true">
<activity <activity
android:name=".MainActivity" android:name=".MainActivity"
android:launchMode="singleTop" android:launchMode="singleInstance"
android:theme="@style/LaunchTheme" android:theme="@style/LaunchTheme"
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"
@ -39,6 +39,15 @@
android:scheme="cakewallet" android:scheme="cakewallet"
android:host="y.at" /> android:host="y.at" />
</intent-filter> </intent-filter>
<!-- currencies qr code scheme -->
<intent-filter android:autoVerify="true">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="bitcoin" />
<data android:scheme="monero" />
<data android:scheme="litecoin" />
</intent-filter>
</activity> </activity>
<meta-data <meta-data
android:name="flutterEmbedding" android:name="flutterEmbedding"

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 548 B

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

@ -303,7 +303,7 @@ class ElectrumClient {
Future<List<int>> feeRates() async { Future<List<int>> feeRates() async {
try { try {
final topDoubleString = await estimatefee(p: 1); final topDoubleString = await estimatefee(p: 1);
final middleDoubleString = await estimatefee(p: 20); final middleDoubleString = await estimatefee(p: 5);
final bottomDoubleString = await estimatefee(p: 100); final bottomDoubleString = await estimatefee(p: 100);
final top = final top =
(stringDoubleToBitcoinAmount(topDoubleString.toString()) / 1000) (stringDoubleToBitcoinAmount(topDoubleString.toString()) / 1000)

View file

@ -72,7 +72,7 @@ abstract class ElectrumTransactionHistoryBase
txs.entries.forEach((entry) { txs.entries.forEach((entry) {
final val = entry.value; final val = entry.value;
if (val is Map<String, Object>) { if (val is Map<String, dynamic>) {
final tx = ElectrumTransactionInfo.fromJson(val, walletInfo.type); final tx = ElectrumTransactionInfo.fromJson(val, walletInfo.type);
_updateOrInsert(tx); _updateOrInsert(tx);
} }
@ -85,9 +85,6 @@ abstract class ElectrumTransactionHistoryBase
} }
void _updateOrInsert(ElectrumTransactionInfo transaction) { void _updateOrInsert(ElectrumTransactionInfo transaction) {
if (transaction.id == null) {
return;
}
if (transactions[transaction.id] == null) { if (transactions[transaction.id] == null) {
transactions[transaction.id] = transaction; transactions[transaction.id] = transaction;
@ -98,6 +95,7 @@ abstract class ElectrumTransactionHistoryBase
originalTx?.height = transaction.height; originalTx?.height = transaction.height;
originalTx?.date ??= transaction.date; originalTx?.date ??= transaction.date;
originalTx?.isPending = transaction.isPending; originalTx?.isPending = transaction.isPending;
originalTx?.direction = transaction.direction;
} }
} }
} }

View file

@ -228,9 +228,7 @@ class ElectrumTransactionInfo extends TransactionInfo {
m['id'] = id; m['id'] = id;
m['height'] = height; m['height'] = height;
m['amount'] = amount; m['amount'] = amount;
// FIX-ME: Hardcoded value m['direction'] = direction.index;
// m['direction'] = direction.index;
m['direction'] = 0;
m['date'] = date.millisecondsSinceEpoch; m['date'] = date.millisecondsSinceEpoch;
m['isPending'] = isPending; m['isPending'] = isPending;
m['confirmations'] = confirmations; m['confirmations'] = confirmations;

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();
@ -191,8 +191,10 @@ abstract class ElectrumWalletBase extends WalletBase<ElectrumBalance,
throw BitcoinTransactionNoInputsException(); throw BitcoinTransactionNoInputsException();
} }
final allAmountFee = feeAmountForPriority( final allAmountFee = transactionCredentials.feeRate != null
transactionCredentials.priority!, inputs.length, outputs.length); ? feeAmountWithFeeRate(transactionCredentials.feeRate!, inputs.length, outputs.length)
: feeAmountForPriority(transactionCredentials.priority!, inputs.length, outputs.length);
final allAmount = allInputsAmount - allAmountFee; final allAmount = allInputsAmount - allAmountFee;
var credentialsAmount = 0; var credentialsAmount = 0;

View file

@ -1,20 +1,18 @@
import 'package:cw_core/enumerable_item.dart'; import 'package:cw_core/enumerable_item.dart';
import 'package:hive/hive.dart';
part 'crypto_currency.g.dart';
@HiveType(typeId: 0)
class CryptoCurrency extends EnumerableItem<int> with Serializable<int> { class CryptoCurrency extends EnumerableItem<int> with Serializable<int> {
const CryptoCurrency({ const CryptoCurrency({
String title = '', String title = '',
int raw = -1, int raw = -1,
this.name, required this.name,
this.fullName,
this.iconPath, this.iconPath,
this.tag,}) this.tag})
: super(title: title, raw: raw); : super(title: title, raw: raw);
final String name;
final String? tag; final String? tag;
final String? name; final String? fullName;
final String? iconPath; final String? iconPath;
static const all = [ static const all = [
@ -38,7 +36,7 @@ class CryptoCurrency extends EnumerableItem<int> with Serializable<int> {
CryptoCurrency.ape, CryptoCurrency.ape,
CryptoCurrency.avaxc, CryptoCurrency.avaxc,
CryptoCurrency.btt, CryptoCurrency.btt,
CryptoCurrency.bttbsc, CryptoCurrency.bttc,
CryptoCurrency.doge, CryptoCurrency.doge,
CryptoCurrency.firo, CryptoCurrency.firo,
CryptoCurrency.usdttrc20, CryptoCurrency.usdttrc20,
@ -53,7 +51,6 @@ class CryptoCurrency extends EnumerableItem<int> with Serializable<int> {
CryptoCurrency.xvg, CryptoCurrency.xvg,
CryptoCurrency.usdcpoly, CryptoCurrency.usdcpoly,
CryptoCurrency.dcr, CryptoCurrency.dcr,
CryptoCurrency.husd,
CryptoCurrency.kmd, CryptoCurrency.kmd,
CryptoCurrency.mana, CryptoCurrency.mana,
CryptoCurrency.maticpoly, CryptoCurrency.maticpoly,
@ -70,339 +67,116 @@ class CryptoCurrency extends EnumerableItem<int> with Serializable<int> {
CryptoCurrency.stx, CryptoCurrency.stx,
]; ];
static const xmr = CryptoCurrency(title: 'XMR', iconPath: 'assets/images/monero_icon.png', name: 'Monero', raw: 0); static const havenCurrencies = [
static const ada = CryptoCurrency(title: 'ADA', iconPath: 'assets/images/ada_icon.png', name: 'Cardano', raw: 1); xag,
static const bch = CryptoCurrency(title: 'BCH', iconPath: 'assets/images/bch_icon.png',name: 'Bitcoin Cash', raw: 2); xau,
static const bnb = CryptoCurrency(title: 'BNB', iconPath: 'assets/images/bnb_icon.png', tag: 'BSC', name: 'Binance Coin', raw: 3); xaud,
static const btc = CryptoCurrency(title: 'BTC', iconPath: 'assets/images/btc.png', name: 'Bitcoin', raw: 4); xbtc,
static const dai = CryptoCurrency(title: 'DAI', iconPath: 'assets/images/dai_icon.png', tag: 'ETH', name: 'Dai', raw: 5); xcad,
static const dash = CryptoCurrency(title: 'DASH', iconPath: 'assets/images/dash_icon.png', name: 'Dash', raw: 6); xchf,
static const eos = CryptoCurrency(title: 'EOS', iconPath: 'assets/images/eos_icon.png', name: 'EOS', raw: 7); xcny,
static const eth = CryptoCurrency(title: 'ETH', iconPath: 'assets/images/eth_icon.png', name: 'Ethereum', raw: 8); xeur,
static const ltc = CryptoCurrency(title: 'LTC', iconPath: 'assets/images/litecoin-ltc_icon.png', name: 'Litecoin', raw: 9); xgbp,
static const nano = CryptoCurrency(title: 'NANO', raw: 10); xjpy,
static const trx = CryptoCurrency(title: 'TRX', iconPath: 'assets/images/trx_icon.png', name: 'TRON', raw: 11); xnok,
static const usdt = CryptoCurrency(title: 'USDT', iconPath: 'assets/images/usdt_icon.png', tag: 'OMNI', name: 'USDT', raw: 12); xnzd,
static const usdterc20 = CryptoCurrency(title: 'USDT', iconPath: 'assets/images/usdterc20_icon.png', tag: 'ETH', name: 'USDT', raw: 13); xusd,
static const xlm = CryptoCurrency(title: 'XLM', iconPath: 'assets/images/xlm_icon.png', name: 'Stellar', raw: 14); ];
static const xrp = CryptoCurrency(title: 'XRP', iconPath: 'assets/images/xrp_icon.png', name: 'Ripple', raw: 15);
static const xhv = CryptoCurrency(title: 'XHV', iconPath: 'assets/images/xhv_logo.png', name: 'Haven Protocol', raw: 16);
static const xag = CryptoCurrency(title: 'XAG', tag: 'XHV', raw: 17); static const xmr = CryptoCurrency(title: 'XMR', iconPath: 'assets/images/monero_icon.png', fullName: 'Monero', raw: 0, name: 'xmr');
static const xau = CryptoCurrency(title: 'XAU', tag: 'XHV', raw: 18); static const ada = CryptoCurrency(title: 'ADA', iconPath: 'assets/images/ada_icon.png', fullName: 'Cardano', raw: 1, name: 'ada');
static const xaud = CryptoCurrency(title: 'XAUD', tag: 'XHV', raw: 19); static const bch = CryptoCurrency(title: 'BCH', iconPath: 'assets/images/bch_icon.png',fullName: 'Bitcoin Cash', raw: 2, name: 'bch');
static const xbtc = CryptoCurrency(title: 'XBTC', tag: 'XHV', raw: 20); static const bnb = CryptoCurrency(title: 'BNB', iconPath: 'assets/images/bnb_icon.png', tag: 'BSC', fullName: 'Binance Coin', raw: 3, name: 'bnb');
static const xcad = CryptoCurrency(title: 'XCAD', tag: 'XHV', raw: 21); static const btc = CryptoCurrency(title: 'BTC', iconPath: 'assets/images/btc.png', fullName: 'Bitcoin', raw: 4, name: 'btc');
static const xchf = CryptoCurrency(title: 'XCHF', tag: 'XHV', raw: 22); static const dai = CryptoCurrency(title: 'DAI', iconPath: 'assets/images/dai_icon.png', tag: 'ETH', fullName: 'Dai', raw: 5, name: 'dai');
static const xcny = CryptoCurrency(title: 'XCNY', tag: 'XHV', raw: 23); static const dash = CryptoCurrency(title: 'DASH', iconPath: 'assets/images/dash_icon.png', fullName: 'Dash', raw: 6, name: 'dash');
static const xeur = CryptoCurrency(title: 'XEUR', tag: 'XHV', raw: 24); static const eos = CryptoCurrency(title: 'EOS', iconPath: 'assets/images/eos_icon.png', fullName: 'EOS', raw: 7, name: 'eos');
static const xgbp = CryptoCurrency(title: 'XGBP', tag: 'XHV', raw: 25); static const eth = CryptoCurrency(title: 'ETH', iconPath: 'assets/images/eth_icon.png', fullName: 'Ethereum', raw: 8, name: 'eth');
static const xjpy = CryptoCurrency(title: 'XJPY', tag: 'XHV', raw: 26); static const ltc = CryptoCurrency(title: 'LTC', iconPath: 'assets/images/litecoin-ltc_icon.png', fullName: 'Litecoin', raw: 9, name: 'ltc');
static const xnok = CryptoCurrency(title: 'XNOK', tag: 'XHV', raw: 27); static const nano = CryptoCurrency(title: 'NANO', raw: 10, name: 'nano');
static const xnzd = CryptoCurrency(title: 'XNZD', tag: 'XHV', raw: 28); static const trx = CryptoCurrency(title: 'TRX', iconPath: 'assets/images/trx_icon.png', fullName: 'TRON', raw: 11, name: 'trx');
static const xusd = CryptoCurrency(title: 'XUSD', tag: 'XHV', raw: 29); static const usdt = CryptoCurrency(title: 'USDT', iconPath: 'assets/images/usdt_icon.png', tag: 'OMNI', fullName: 'USDT', raw: 12, name: 'usdt');
static const usdterc20 = CryptoCurrency(title: 'USDT', iconPath: 'assets/images/usdterc20_icon.png', tag: 'ETH', fullName: 'USDT', raw: 13, name: 'usdterc20');
static const xlm = CryptoCurrency(title: 'XLM', iconPath: 'assets/images/xlm_icon.png', fullName: 'Stellar', raw: 14, name: 'xlm');
static const xrp = CryptoCurrency(title: 'XRP', iconPath: 'assets/images/xrp_icon.png', fullName: 'Ripple', raw: 15, name: 'xrp');
static const xhv = CryptoCurrency(title: 'XHV', iconPath: 'assets/images/xhv_logo.png', fullName: 'Haven Protocol', raw: 16, name: 'xhv');
static const ape = CryptoCurrency(title: 'APE', iconPath: 'assets/images/ape_icon.png', tag: 'ETH', raw: 30); static const xag = CryptoCurrency(title: 'XAG', tag: 'XHV', raw: 17, name: 'xag');
static const avaxc = CryptoCurrency(title: 'AVAX', iconPath: 'assets/images/avaxc_icon.png', tag: 'C-CHAIN', raw: 31); static const xau = CryptoCurrency(title: 'XAU', tag: 'XHV', raw: 18, name: 'xau');
static const btt = CryptoCurrency(title: 'BTT', iconPath: 'assets/images/btt_icon.png', raw: 32); static const xaud = CryptoCurrency(title: 'XAUD', tag: 'XHV', raw: 19, name: 'xaud');
static const bttbsc = CryptoCurrency(title: 'BTT', iconPath: 'assets/images/bttbsc_icon.png', tag: 'BSC', raw: 33); static const xbtc = CryptoCurrency(title: 'XBTC', tag: 'XHV', raw: 20, name: 'xbtc');
static const doge = CryptoCurrency(title: 'DOGE', iconPath: 'assets/images/doge_icon.png', raw: 34); static const xcad = CryptoCurrency(title: 'XCAD', tag: 'XHV', raw: 21, name: 'xcad');
static const firo = CryptoCurrency(title: 'FIRO', iconPath: 'assets/images/firo_icon.png', raw: 35); static const xchf = CryptoCurrency(title: 'XCHF', tag: 'XHV', raw: 22, name: 'xchf');
static const usdttrc20 = CryptoCurrency(title: 'USDT', iconPath: 'assets/images/usdttrc20_icon.png', tag: 'TRX', raw: 36); static const xcny = CryptoCurrency(title: 'XCNY', tag: 'XHV', raw: 23, name: 'xcny');
static const hbar = CryptoCurrency(title: 'HBAR', iconPath: 'assets/images/hbar_icon.png', raw: 37); static const xeur = CryptoCurrency(title: 'XEUR', tag: 'XHV', raw: 24, name: 'xeur');
static const sc = CryptoCurrency(title: 'SC', iconPath: 'assets/images/sc_icon.png', raw: 38); static const xgbp = CryptoCurrency(title: 'XGBP', tag: 'XHV', raw: 25, name: 'xgbp');
static const sol = CryptoCurrency(title: 'SOL', iconPath: 'assets/images/sol_icon.png', raw: 39); static const xjpy = CryptoCurrency(title: 'XJPY', tag: 'XHV', raw: 26, name: 'xjpy');
static const usdc = CryptoCurrency(title: 'USDC', iconPath: 'assets/images/usdc_icon.png', tag: 'ETH', raw: 40); static const xnok = CryptoCurrency(title: 'XNOK', tag: 'XHV', raw: 27, name: 'xnok');
static const usdcsol = CryptoCurrency(title: 'USDC', iconPath: 'assets/images/usdcsol_icon.png', tag: 'SOL', raw: 41); static const xnzd = CryptoCurrency(title: 'XNZD', tag: 'XHV', raw: 28, name: 'xnzd');
static const zaddr = CryptoCurrency(title: 'ZZEC', tag: 'ZEC', name: 'Shielded Zcash', iconPath: 'assets/images/zaddr_icon.png', raw: 42); static const xusd = CryptoCurrency(title: 'XUSD', tag: 'XHV', raw: 29, name: 'xusd');
static const zec = CryptoCurrency(title: 'TZEC', tag: 'ZEC', name: 'Transparent Zcash', iconPath: 'assets/images/zec_icon.png', raw: 43);
static const zen = CryptoCurrency(title: 'ZEN', iconPath: 'assets/images/zen_icon.png', raw: 44);
static const xvg = CryptoCurrency(title: 'XVG', name: 'Verge', iconPath: 'assets/images/xvg_icon.png', raw: 45);
static const usdcpoly = CryptoCurrency(title: 'USDC', iconPath: 'assets/images/usdc_icon.png', tag: 'POLY', raw: 46); static const ape = CryptoCurrency(title: 'APE', iconPath: 'assets/images/ape_icon.png', tag: 'ETH', raw: 30, name: 'ape');
static const dcr = CryptoCurrency(title: 'DCR', iconPath: 'assets/images/dcr_icon.png', raw: 47); static const avaxc = CryptoCurrency(title: 'AVAX', iconPath: 'assets/images/avaxc_icon.png', tag: 'C-CHAIN', raw: 31, name: 'avaxc');
static const husd = CryptoCurrency(title: 'HUSD', iconPath: 'assets/images/husd_icon.png', tag: 'ETH', raw: 48); static const btt = CryptoCurrency(title: 'BTT', iconPath: 'assets/images/btt_icon.png', raw: 32, name: 'btt');
static const kmd = CryptoCurrency(title: 'KMD', iconPath: 'assets/images/kmd_icon.png', raw: 49); static const bttc = CryptoCurrency(title: 'BTTC', iconPath: 'assets/images/bttbsc_icon.png',fullName: 'BitTorrent-NEW (Binance Smart Chain)', tag: 'BSC', raw: 33, name: 'bttc');
static const mana = CryptoCurrency(title: 'MANA', iconPath: 'assets/images/mana_icon.png', tag: 'ETH', raw: 50); static const doge = CryptoCurrency(title: 'DOGE', iconPath: 'assets/images/doge_icon.png', raw: 34, name: 'doge');
static const maticpoly = CryptoCurrency(title: 'MATIC', iconPath: 'assets/images/matic_icon.png', tag: 'POLY', raw: 51); static const firo = CryptoCurrency(title: 'FIRO', iconPath: 'assets/images/firo_icon.png', raw: 35, name: 'firo');
static const matic = CryptoCurrency(title: 'MATIC', iconPath: 'assets/images/matic_icon.png', tag: 'ETH', raw: 52); static const usdttrc20 = CryptoCurrency(title: 'USDT', iconPath: 'assets/images/usdttrc20_icon.png', tag: 'TRX', raw: 36, name: 'usdttrc20');
static const mkr = CryptoCurrency(title: 'MKR', iconPath: 'assets/images/mkr_icon.png', tag: 'ETH', raw: 53); static const hbar = CryptoCurrency(title: 'HBAR', iconPath: 'assets/images/hbar_icon.png', raw: 37, name: 'hbar');
static const near = CryptoCurrency(title: 'NEAR', iconPath: 'assets/images/near_icon.png', raw: 54); static const sc = CryptoCurrency(title: 'SC', iconPath: 'assets/images/sc_icon.png', raw: 38, name: 'sc');
static const oxt = CryptoCurrency(title: 'OXT', iconPath: 'assets/images/oxt_icon.png', tag: 'ETH', raw: 55); static const sol = CryptoCurrency(title: 'SOL', iconPath: 'assets/images/sol_icon.png', raw: 39, name: 'sol');
static const paxg = CryptoCurrency(title: 'PAXG', iconPath: 'assets/images/paxg_icon.png', tag: 'ETH', raw: 56); static const usdc = CryptoCurrency(title: 'USDC', iconPath: 'assets/images/usdc_icon.png', tag: 'ETH', raw: 40, name: 'usdc');
static const pivx = CryptoCurrency(title: 'PIVX', iconPath: 'assets/images/pivx_icon.png', raw: 57); static const usdcsol = CryptoCurrency(title: 'USDC', iconPath: 'assets/images/usdcsol_icon.png', tag: 'SOL', raw: 41, name: 'usdcsol');
static const rune = CryptoCurrency(title: 'RUNE', iconPath: 'assets/images/rune_icon.png', raw: 58); static const zaddr = CryptoCurrency(title: 'ZZEC', tag: 'ZEC', fullName: 'Shielded Zcash', iconPath: 'assets/images/zaddr_icon.png', raw: 42, name: 'zaddr');
static const rvn = CryptoCurrency(title: 'RVN', iconPath: 'assets/images/rvn_icon.png', raw: 59); static const zec = CryptoCurrency(title: 'TZEC', tag: 'ZEC', fullName: 'Transparent Zcash', iconPath: 'assets/images/zec_icon.png', raw: 43, name: 'zec');
static const scrt = CryptoCurrency(title: 'SCRT', iconPath: 'assets/images/scrt_icon.png', raw: 60); static const zen = CryptoCurrency(title: 'ZEN', iconPath: 'assets/images/zen_icon.png', raw: 44, name: 'zen');
static const uni = CryptoCurrency(title: 'UNI', iconPath: 'assets/images/uni_icon.png', tag: 'ETH', raw: 61); static const xvg = CryptoCurrency(title: 'XVG', fullName: 'Verge', iconPath: 'assets/images/xvg_icon.png', raw: 45, name: 'xvg');
static const stx = CryptoCurrency(title: 'STX', iconPath: 'assets/images/stx_icon.png', raw: 62);
static const usdcpoly = CryptoCurrency(title: 'USDC', iconPath: 'assets/images/usdc_icon.png', tag: 'POLY', raw: 46, name: 'usdcpoly');
static const dcr = CryptoCurrency(title: 'DCR', iconPath: 'assets/images/dcr_icon.png', raw: 47, name: 'dcr');
static const kmd = CryptoCurrency(title: 'KMD', iconPath: 'assets/images/kmd_icon.png', raw: 48, name: 'kmd');
static const mana = CryptoCurrency(title: 'MANA', iconPath: 'assets/images/mana_icon.png', tag: 'ETH', raw: 49, name: 'mana');
static const maticpoly = CryptoCurrency(title: 'MATIC', iconPath: 'assets/images/matic_icon.png', tag: 'POLY', raw: 50, name: 'maticpoly');
static const matic = CryptoCurrency(title: 'MATIC', iconPath: 'assets/images/matic_icon.png', tag: 'ETH', raw: 51, name: 'matic');
static const mkr = CryptoCurrency(title: 'MKR', iconPath: 'assets/images/mkr_icon.png', tag: 'ETH', raw: 52, name: 'mkr');
static const near = CryptoCurrency(title: 'NEAR', iconPath: 'assets/images/near_icon.png', raw: 53, name: 'near');
static const oxt = CryptoCurrency(title: 'OXT', iconPath: 'assets/images/oxt_icon.png', tag: 'ETH', raw: 54, name: 'oxt');
static const paxg = CryptoCurrency(title: 'PAXG', iconPath: 'assets/images/paxg_icon.png', tag: 'ETH', raw: 55, name: 'paxg');
static const pivx = CryptoCurrency(title: 'PIVX', iconPath: 'assets/images/pivx_icon.png', raw: 56, name: 'pivx');
static const rune = CryptoCurrency(title: 'RUNE', iconPath: 'assets/images/rune_icon.png', raw: 57, name: 'rune');
static const rvn = CryptoCurrency(title: 'RVN', iconPath: 'assets/images/rvn_icon.png', raw: 58, name: 'rvn');
static const scrt = CryptoCurrency(title: 'SCRT', iconPath: 'assets/images/scrt_icon.png', raw: 59, name: 'scrt');
static const uni = CryptoCurrency(title: 'UNI', iconPath: 'assets/images/uni_icon.png', tag: 'ETH', raw: 60, name: 'uni');
static const stx = CryptoCurrency(title: 'STX', iconPath: 'assets/images/stx_icon.png', raw: 61, name: 'stx');
static final Map<int, CryptoCurrency> _rawCurrencyMap =
[...all, ...havenCurrencies].fold<Map<int, CryptoCurrency>>(<int, CryptoCurrency>{}, (acc, item) {
acc.addAll({item.raw: item});
return acc;
});
static final Map<String, CryptoCurrency> _nameCurrencyMap =
[...all, ...havenCurrencies].fold<Map<String, CryptoCurrency>>(<String, CryptoCurrency>{}, (acc, item) {
acc.addAll({item.name: item});
return acc;
});
static CryptoCurrency deserialize({required int raw}) { static CryptoCurrency deserialize({required int raw}) {
switch (raw) {
case 0: if (CryptoCurrency._rawCurrencyMap[raw] == null) {
return CryptoCurrency.xmr; final s = 'Unexpected token: $raw for CryptoCurrency deserialize';
case 1: throw ArgumentError.value(raw, 'raw', s);
return CryptoCurrency.ada;
case 2:
return CryptoCurrency.bch;
case 3:
return CryptoCurrency.bnb;
case 4:
return CryptoCurrency.btc;
case 5:
return CryptoCurrency.dai;
case 6:
return CryptoCurrency.dash;
case 7:
return CryptoCurrency.eos;
case 8:
return CryptoCurrency.eth;
case 9:
return CryptoCurrency.ltc;
case 10:
return CryptoCurrency.nano;
case 11:
return CryptoCurrency.trx;
case 12:
return CryptoCurrency.usdt;
case 13:
return CryptoCurrency.usdterc20;
case 14:
return CryptoCurrency.xlm;
case 15:
return CryptoCurrency.xrp;
case 16:
return CryptoCurrency.xhv;
case 17:
return CryptoCurrency.xag;
case 18:
return CryptoCurrency.xau;
case 19:
return CryptoCurrency.xaud;
case 20:
return CryptoCurrency.xbtc;
case 21:
return CryptoCurrency.xcad;
case 22:
return CryptoCurrency.xchf;
case 23:
return CryptoCurrency.xcny;
case 24:
return CryptoCurrency.xeur;
case 25:
return CryptoCurrency.xgbp;
case 26:
return CryptoCurrency.xjpy;
case 27:
return CryptoCurrency.xnok;
case 28:
return CryptoCurrency.xnzd;
case 29:
return CryptoCurrency.xusd;
case 30:
return CryptoCurrency.ape;
case 31:
return CryptoCurrency.avaxc;
case 32:
return CryptoCurrency.btt;
case 33:
return CryptoCurrency.bttbsc;
case 34:
return CryptoCurrency.doge;
case 35:
return CryptoCurrency.firo;
case 36:
return CryptoCurrency.usdttrc20;
case 37:
return CryptoCurrency.hbar;
case 38:
return CryptoCurrency.sc;
case 39:
return CryptoCurrency.sol;
case 40:
return CryptoCurrency.usdc;
case 41:
return CryptoCurrency.usdcsol;
case 42:
return CryptoCurrency.zaddr;
case 43:
return CryptoCurrency.zec;
case 44:
return CryptoCurrency.zen;
case 45:
return CryptoCurrency.xvg;
case 46:
return CryptoCurrency.usdcpoly;
case 47:
return CryptoCurrency.dcr;
case 48:
return CryptoCurrency.husd;
case 49:
return CryptoCurrency.kmd;
case 50:
return CryptoCurrency.mana;
case 51:
return CryptoCurrency.maticpoly;
case 52:
return CryptoCurrency.matic;
case 53:
return CryptoCurrency.mkr;
case 54:
return CryptoCurrency.near;
case 55:
return CryptoCurrency.oxt;
case 56:
return CryptoCurrency.paxg;
case 57:
return CryptoCurrency.pivx;
case 58:
return CryptoCurrency.rune;
case 59:
return CryptoCurrency.rvn;
case 60:
return CryptoCurrency.scrt;
case 61:
return CryptoCurrency.uni;
case 62:
return CryptoCurrency.stx;
default:
throw Exception('Unexpected token: $raw for CryptoCurrency deserialize');
} }
return CryptoCurrency._rawCurrencyMap[raw]!;
} }
static CryptoCurrency fromString(String raw) { static CryptoCurrency fromString(String name) {
switch (raw.toLowerCase()) {
case 'xmr': if (CryptoCurrency._nameCurrencyMap[name.toLowerCase()] == null) {
return CryptoCurrency.xmr; final s = 'Unexpected token: $name for CryptoCurrency fromString';
case 'ada': throw ArgumentError.value(name, 'name', s);
return CryptoCurrency.ada;
case 'bch':
return CryptoCurrency.bch;
case 'bnbmainnet':
return CryptoCurrency.bnb;
case 'btc':
return CryptoCurrency.btc;
case 'dai':
return CryptoCurrency.dai;
case 'dash':
return CryptoCurrency.dash;
case 'eos':
return CryptoCurrency.eos;
case 'eth':
return CryptoCurrency.eth;
case 'ltc':
return CryptoCurrency.ltc;
case 'nano':
return CryptoCurrency.nano;
case 'trx':
return CryptoCurrency.trx;
case 'usdc':
return CryptoCurrency.usdc;
case 'usdterc20':
return CryptoCurrency.usdterc20;
case 'xlm':
return CryptoCurrency.xlm;
case 'xrp':
return CryptoCurrency.xrp;
case 'xhv':
return CryptoCurrency.xhv;
case 'xag':
return CryptoCurrency.xag;
case 'xau':
return CryptoCurrency.xau;
case 'xaud':
return CryptoCurrency.xaud;
case 'xbtc':
return CryptoCurrency.xbtc;
case 'xcad':
return CryptoCurrency.xcad;
case 'xchf':
return CryptoCurrency.xchf;
case 'xcny':
return CryptoCurrency.xcny;
case 'xeur':
return CryptoCurrency.xeur;
case 'xgbp':
return CryptoCurrency.xgbp;
case 'xjpy':
return CryptoCurrency.xjpy;
case 'xnok':
return CryptoCurrency.xnok;
case 'xnzd':
return CryptoCurrency.xnzd;
case 'xusd':
return CryptoCurrency.xusd;
case 'ape':
return CryptoCurrency.ape;
case 'avax':
return CryptoCurrency.avaxc;
case 'btt':
return CryptoCurrency.btt;
case 'bttbsc':
return CryptoCurrency.bttbsc;
case 'doge':
return CryptoCurrency.doge;
case 'firo':
return CryptoCurrency.firo;
case 'usdttrc20':
return CryptoCurrency.usdttrc20;
case 'hbar':
return CryptoCurrency.hbar;
case 'sc':
return CryptoCurrency.sc;
case 'sol':
return CryptoCurrency.sol;
case 'usdt':
return CryptoCurrency.usdt;
case 'usdcsol':
return CryptoCurrency.usdcsol;
case 'zaddr':
return CryptoCurrency.zaddr;
case 'zec':
return CryptoCurrency.zec;
case 'zen':
return CryptoCurrency.zen;
case 'xvg':
return CryptoCurrency.xvg;
case 'usdcpoly':
return CryptoCurrency.usdcpoly;
case 'dcr':
return CryptoCurrency.dcr;
case 'husd':
return CryptoCurrency.husd;
case 'kmd':
return CryptoCurrency.kmd;
case 'mana':
return CryptoCurrency.mana;
case 'maticpoly':
return CryptoCurrency.maticpoly;
case 'matic':
return CryptoCurrency.matic;
case 'mkr':
return CryptoCurrency.mkr;
case 'near':
return CryptoCurrency.near;
case 'oxt':
return CryptoCurrency.oxt;
case 'paxg':
return CryptoCurrency.paxg;
case 'pivx':
return CryptoCurrency.pivx;
case 'rune':
return CryptoCurrency.rune;
case 'rvn':
return CryptoCurrency.rvn;
case 'scrt':
return CryptoCurrency.scrt;
case 'uni':
return CryptoCurrency.uni;
case 'stx':
return CryptoCurrency.stx;
default:
throw Exception('Unexpected token: $raw for CryptoCurrency fromString');
} }
return CryptoCurrency._nameCurrencyMap[name.toLowerCase()]!;
} }
@override @override

View file

@ -21,22 +21,6 @@ class MoneroTransactionPriority extends TransactionPriority {
static const fastest = MoneroTransactionPriority(title: 'Fastest', raw: 4); static const fastest = MoneroTransactionPriority(title: 'Fastest', raw: 4);
static const standard = slow; static const standard = slow;
static List<MoneroTransactionPriority> forWalletType(WalletType type) {
switch (type) {
case WalletType.monero:
return MoneroTransactionPriority.all;
case WalletType.bitcoin:
return [
MoneroTransactionPriority.slow,
MoneroTransactionPriority.automatic,
MoneroTransactionPriority.fast
];
default:
return [];
}
}
static MoneroTransactionPriority deserialize({required int raw}) { static MoneroTransactionPriority deserialize({required int raw}) {
switch (raw) { switch (raw) {
case 0: case 0:

View file

@ -17,6 +17,7 @@ class Node extends HiveObject with Keyable {
{this.login, {this.login,
this.password, this.password,
this.useSSL, this.useSSL,
this.trusted = false,
String? uri, String? uri,
WalletType? type,}) { WalletType? type,}) {
if (uri != null) { if (uri != null) {
@ -31,7 +32,8 @@ class Node extends HiveObject with Keyable {
: uriRaw = map['uri'] as String? ?? '', : uriRaw = map['uri'] as String? ?? '',
login = map['login'] as String?, login = map['login'] as String?,
password = map['password'] as String?, password = map['password'] as String?,
useSSL = map['useSSL'] as bool?; useSSL = map['useSSL'] as bool?,
trusted = map['trusted'] as bool? ?? false;
static const typeId = 1; static const typeId = 1;
static const boxName = 'Nodes'; static const boxName = 'Nodes';
@ -51,6 +53,9 @@ class Node extends HiveObject with Keyable {
@HiveField(4) @HiveField(4)
bool? useSSL; bool? useSSL;
@HiveField(5, defaultValue: false)
bool trusted;
bool get isSSL => useSSL ?? false; bool get isSSL => useSSL ?? false;
Uri get uri { Uri get uri {
@ -104,28 +109,28 @@ class Node extends HiveObject with Keyable {
final rpcUri = isSSL ? Uri.https(uri.authority, path) : Uri.http(uri.authority, path); final 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

@ -21,18 +21,48 @@
<key>CFBundleSignature</key> <key>CFBundleSignature</key>
<string>????</string> <string>????</string>
<key>CFBundleURLTypes</key> <key>CFBundleURLTypes</key>
<array> <array>
<dict> <dict>
<key>CFBundleTypeRole</key> <key>CFBundleTypeRole</key>
<string>Editor</string> <string>Editor</string>
<key>CFBundleURLName</key> <key>CFBundleURLName</key>
<string>y.at</string> <string>y.at</string>
<key>CFBundleURLSchemes</key> <key>CFBundleURLSchemes</key>
<array> <array>
<string>cakewallet</string> <string>cakewallet</string>
</array> </array>
</dict> </dict>
</array> <dict>
<key>CFBundleTypeRole</key>
<string>Editor</string>
<key>CFBundleURLName</key>
<string>bitcoin</string>
<key>CFBundleURLSchemes</key>
<array>
<string>bitcoin</string>
</array>
</dict>
<dict>
<key>CFBundleTypeRole</key>
<string>Editor</string>
<key>CFBundleURLName</key>
<string>monero</string>
<key>CFBundleURLSchemes</key>
<array>
<string>monero</string>
</array>
</dict>
<dict>
<key>CFBundleTypeRole</key>
<string>Editor</string>
<key>CFBundleURLName</key>
<string>litecoin</string>
<key>CFBundleURLSchemes</key>
<array>
<string>litecoin</string>
</array>
</dict>
</array>
<key>CFBundleVersion</key> <key>CFBundleVersion</key>
<string>$(CURRENT_PROJECT_VERSION)</string> <string>$(CURRENT_PROJECT_VERSION)</string>
<key>LSRequiresIPhoneOS</key> <key>LSRequiresIPhoneOS</key>

View file

@ -51,6 +51,10 @@ class CWBitcoin extends Bitcoin {
TransactionPriority deserializeBitcoinTransactionPriority(int raw) TransactionPriority deserializeBitcoinTransactionPriority(int raw)
=> BitcoinTransactionPriority.deserialize(raw: raw); => BitcoinTransactionPriority.deserialize(raw: raw);
@override
TransactionPriority deserializeLitecoinTransactionPriority(int raw)
=> LitecoinTransactionPriority.deserialize(raw: raw);
@override @override
int getFeeRate(Object wallet, TransactionPriority priority) { int getFeeRate(Object wallet, TransactionPriority priority) {
final bitcoinWallet = wallet as ElectrumWallet; final bitcoinWallet = wallet as ElectrumWallet;

View file

@ -24,7 +24,6 @@ class AddressValidator extends TextValidator {
return '[0-9a-zA-Z_]'; return '[0-9a-zA-Z_]';
case CryptoCurrency.usdc: case CryptoCurrency.usdc:
case CryptoCurrency.usdcpoly: case CryptoCurrency.usdcpoly:
case CryptoCurrency.husd:
case CryptoCurrency.ape: case CryptoCurrency.ape:
case CryptoCurrency.avaxc: case CryptoCurrency.avaxc:
case CryptoCurrency.eth: case CryptoCurrency.eth:
@ -156,7 +155,7 @@ class AddressValidator extends TextValidator {
return [98, 99, 106]; return [98, 99, 106];
case CryptoCurrency.btt: case CryptoCurrency.btt:
return [34]; return [34];
case CryptoCurrency.bttbsc: case CryptoCurrency.bttc:
return [34]; return [34];
case CryptoCurrency.doge: case CryptoCurrency.doge:
return [34]; return [34];
@ -181,7 +180,6 @@ class AddressValidator extends TextValidator {
case CryptoCurrency.stx: case CryptoCurrency.stx:
return [40, 41, 42]; return [40, 41, 42];
case CryptoCurrency.usdcpoly: case CryptoCurrency.usdcpoly:
case CryptoCurrency.husd:
case CryptoCurrency.mana: case CryptoCurrency.mana:
case CryptoCurrency.matic: case CryptoCurrency.matic:
case CryptoCurrency.maticpoly: case CryptoCurrency.maticpoly:

View file

@ -4,12 +4,19 @@ import 'package:shared_preferences/shared_preferences.dart';
import 'package:cake_wallet/entities/preferences_key.dart'; import 'package:cake_wallet/entities/preferences_key.dart';
import 'package:cake_wallet/entities/secret_store_key.dart'; import 'package:cake_wallet/entities/secret_store_key.dart';
import 'package:cake_wallet/entities/encrypt.dart'; import 'package:cake_wallet/entities/encrypt.dart';
import 'package:cake_wallet/di.dart';
import 'package:cake_wallet/store/settings_store.dart';
class AuthService with Store { class AuthService with Store {
AuthService({required this.secureStorage, required this.sharedPreferences}); AuthService({
required this.secureStorage,
required this.sharedPreferences,
required this.settingsStore,
});
final FlutterSecureStorage secureStorage; final FlutterSecureStorage secureStorage;
final SharedPreferences sharedPreferences; final SharedPreferences sharedPreferences;
final SettingsStore settingsStore;
Future<void> setPassword(String password) async { Future<void> setPassword(String password) async {
final key = generateStoreKeyFor(key: SecretStoreKey.pinCodePassword); final key = generateStoreKeyFor(key: SecretStoreKey.pinCodePassword);
@ -19,8 +26,7 @@ class AuthService with Store {
Future<bool> canAuthenticate() async { Future<bool> canAuthenticate() async {
final key = generateStoreKeyFor(key: SecretStoreKey.pinCodePassword); final key = generateStoreKeyFor(key: SecretStoreKey.pinCodePassword);
final walletName = final walletName = sharedPreferences.getString(PreferencesKey.currentWalletName) ?? '';
sharedPreferences.getString(PreferencesKey.currentWalletName) ?? '';
var password = ''; var password = '';
try { try {
@ -39,4 +45,25 @@ class AuthService with Store {
return decodedPin == pin; return decodedPin == pin;
} }
void saveLastAuthTime() {
int timestamp = DateTime.now().millisecondsSinceEpoch;
sharedPreferences.setInt(PreferencesKey.lastAuthTimeMilliseconds, timestamp);
}
bool requireAuth() {
final timestamp = sharedPreferences.getInt(PreferencesKey.lastAuthTimeMilliseconds);
final duration = _durationToRequireAuth(timestamp ?? 0);
final requiredPinInterval = settingsStore.pinTimeOutDuration;
return duration >= requiredPinInterval.value;
}
int _durationToRequireAuth(int timestamp) {
DateTime before = DateTime.fromMillisecondsSinceEpoch(timestamp);
DateTime now = DateTime.now();
Duration timeDifference = now.difference(before);
return timeDifference.inMinutes;
}
} }

View file

@ -214,8 +214,10 @@ class BackupService {
final currentBitcoinElectrumSererId = data[PreferencesKey.currentBitcoinElectrumSererIdKey] as int?; final currentBitcoinElectrumSererId = data[PreferencesKey.currentBitcoinElectrumSererIdKey] as int?;
final currentLanguageCode = data[PreferencesKey.currentLanguageCode] as String?; final currentLanguageCode = data[PreferencesKey.currentLanguageCode] as String?;
final displayActionListMode = data[PreferencesKey.displayActionListModeKey] as int?; final displayActionListMode = data[PreferencesKey.displayActionListModeKey] as int?;
final fiatApiMode = data[PreferencesKey.currentFiatApiModeKey] as int?;
final currentPinLength = data[PreferencesKey.currentPinLength] as int?; final currentPinLength = data[PreferencesKey.currentPinLength] as int?;
final currentTheme = data[PreferencesKey.currentTheme] as int?; final currentTheme = data[PreferencesKey.currentTheme] as int?;
final disableExchange = data[PreferencesKey.disableExchangeKey] as bool?;
final currentDefaultSettingsMigrationVersion = data[PreferencesKey.currentDefaultSettingsMigrationVersion] as int?; final currentDefaultSettingsMigrationVersion = data[PreferencesKey.currentDefaultSettingsMigrationVersion] as int?;
final moneroTransactionPriority = data[PreferencesKey.moneroTransactionPriority] as int?; final moneroTransactionPriority = data[PreferencesKey.moneroTransactionPriority] as int?;
final bitcoinTransactionPriority = data[PreferencesKey.bitcoinTransactionPriority] as int?; final bitcoinTransactionPriority = data[PreferencesKey.bitcoinTransactionPriority] as int?;
@ -266,6 +268,10 @@ class BackupService {
await _sharedPreferences.setInt(PreferencesKey.displayActionListModeKey, await _sharedPreferences.setInt(PreferencesKey.displayActionListModeKey,
displayActionListMode); displayActionListMode);
if (fiatApiMode != null)
await _sharedPreferences.setInt(PreferencesKey.currentFiatApiModeKey,
fiatApiMode);
if (currentPinLength != null) if (currentPinLength != null)
await _sharedPreferences.setInt(PreferencesKey.currentPinLength, await _sharedPreferences.setInt(PreferencesKey.currentPinLength,
currentPinLength); currentPinLength);
@ -274,6 +280,10 @@ class BackupService {
await _sharedPreferences.setInt( await _sharedPreferences.setInt(
PreferencesKey.currentTheme, currentTheme); PreferencesKey.currentTheme, currentTheme);
if (disableExchange != null)
await _sharedPreferences.setBool(
PreferencesKey.disableExchangeKey, disableExchange);
if (currentDefaultSettingsMigrationVersion != null) if (currentDefaultSettingsMigrationVersion != null)
await _sharedPreferences.setInt( await _sharedPreferences.setInt(
PreferencesKey.currentDefaultSettingsMigrationVersion, PreferencesKey.currentDefaultSettingsMigrationVersion,
@ -421,12 +431,16 @@ class BackupService {
_sharedPreferences.getInt(PreferencesKey.displayActionListModeKey), _sharedPreferences.getInt(PreferencesKey.displayActionListModeKey),
PreferencesKey.currentTheme: PreferencesKey.currentTheme:
_sharedPreferences.getInt(PreferencesKey.currentTheme), _sharedPreferences.getInt(PreferencesKey.currentTheme),
PreferencesKey.disableExchangeKey:
_sharedPreferences.getBool(PreferencesKey.disableExchangeKey),
PreferencesKey.currentDefaultSettingsMigrationVersion: _sharedPreferences PreferencesKey.currentDefaultSettingsMigrationVersion: _sharedPreferences
.getInt(PreferencesKey.currentDefaultSettingsMigrationVersion), .getInt(PreferencesKey.currentDefaultSettingsMigrationVersion),
PreferencesKey.bitcoinTransactionPriority: PreferencesKey.bitcoinTransactionPriority:
_sharedPreferences.getInt(PreferencesKey.bitcoinTransactionPriority), _sharedPreferences.getInt(PreferencesKey.bitcoinTransactionPriority),
PreferencesKey.moneroTransactionPriority: PreferencesKey.moneroTransactionPriority:
_sharedPreferences.getInt(PreferencesKey.moneroTransactionPriority), _sharedPreferences.getInt(PreferencesKey.moneroTransactionPriority),
PreferencesKey.currentFiatApiModeKey:
_sharedPreferences.getInt(PreferencesKey.currentFiatApiModeKey),
}; };
return json.encode(preferences); return json.encode(preferences);

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,15 @@ 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/utils/payment_request.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,6 +32,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/settings/display_settings_view_model.dart';
import 'package:cake_wallet/view_model/settings/other_settings_view_model.dart';
import 'package:cake_wallet/view_model/settings/privacy_settings_view_model.dart';
import 'package:cake_wallet/view_model/settings/security_settings_view_model.dart';
import 'package:cake_wallet/view_model/advanced_privacy_settings_view_model.dart';
import 'package:cw_core/unspent_coins_info.dart'; import 'package: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';
@ -49,7 +60,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';
@ -59,7 +69,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';
@ -115,7 +124,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';
@ -153,6 +161,7 @@ import 'package:cake_wallet/anypay/any_pay_payment_committed_info.dart';
import 'package:cake_wallet/ionia/ionia_any_pay_payment_info.dart'; import 'package:cake_wallet/ionia/ionia_any_pay_payment_info.dart';
import 'package:cake_wallet/src/screens/receive/fullscreen_qr_page.dart'; import 'package:cake_wallet/src/screens/receive/fullscreen_qr_page.dart';
import 'package:cake_wallet/core/wallet_loading_service.dart'; import 'package:cake_wallet/core/wallet_loading_service.dart';
import 'package:cw_core/crypto_currency.dart';
final getIt = GetIt.instance; final getIt = GetIt.instance;
@ -300,7 +309,10 @@ Future setup(
getIt.registerFactory<AuthService>(() => AuthService( getIt.registerFactory<AuthService>(() => AuthService(
secureStorage: getIt.get<FlutterSecureStorage>(), secureStorage: getIt.get<FlutterSecureStorage>(),
sharedPreferences: getIt.get<SharedPreferences>())); sharedPreferences: getIt.get<SharedPreferences>(),
settingsStore: getIt.get<SettingsStore>(),
),
);
getIt.registerFactory<AuthViewModel>(() => AuthViewModel( getIt.registerFactory<AuthViewModel>(() => AuthViewModel(
getIt.get<AuthService>(), getIt.get<AuthService>(),
@ -343,7 +355,7 @@ Future setup(
onAuthenticationFinished: onAuthFinished, onAuthenticationFinished: onAuthFinished,
closable: closable ?? false)); closable: closable ?? false));
getIt.registerFactory(() => getIt.registerFactory(() =>
BalancePage(dashboardViewModel: getIt.get<DashboardViewModel>(), settingsStore: getIt.get<SettingsStore>())); BalancePage(dashboardViewModel: getIt.get<DashboardViewModel>(), settingsStore: getIt.get<SettingsStore>()));
getIt.registerFactory<DashboardPage>(() => DashboardPage( balancePage: getIt.get<BalancePage>(), walletViewModel: getIt.get<DashboardViewModel>(), addressListViewModel: getIt.get<WalletAddressListViewModel>())); getIt.registerFactory<DashboardPage>(() => DashboardPage( balancePage: getIt.get<BalancePage>(), walletViewModel: getIt.get<DashboardViewModel>(), addressListViewModel: getIt.get<WalletAddressListViewModel>()));
@ -376,9 +388,11 @@ Future setup(
getIt.get<BalanceViewModel>(), getIt.get<BalanceViewModel>(),
_transactionDescriptionBox)); _transactionDescriptionBox));
getIt.registerFactory( getIt.registerFactoryParam<SendPage, PaymentRequest?, void>(
() => SendPage(sendViewModel: getIt.get<SendViewModel>(), (PaymentRequest? initialPaymentRequest, _) => SendPage(
settingsViewModel: getIt.get<SettingsViewModel>())); sendViewModel: getIt.get<SendViewModel>(),
initialPaymentRequest: initialPaymentRequest,
));
getIt.registerFactory(() => SendTemplatePage( getIt.registerFactory(() => SendTemplatePage(
sendTemplateViewModel: getIt.get<SendTemplateViewModel>())); sendTemplateViewModel: getIt.get<SendTemplateViewModel>()));
@ -386,7 +400,10 @@ Future setup(
getIt.registerFactory(() => WalletListViewModel( getIt.registerFactory(() => WalletListViewModel(
_walletInfoSource, _walletInfoSource,
getIt.get<AppStore>(), getIt.get<AppStore>(),
getIt.get<WalletLoadingService>())); getIt.get<WalletLoadingService>(),
getIt.get<AuthService>(),
),
);
getIt.registerFactory(() => getIt.registerFactory(() =>
WalletListPage(walletListViewModel: getIt.get<WalletListViewModel>())); WalletListPage(walletListViewModel: getIt.get<WalletListViewModel>()));
@ -434,12 +451,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.get<AuthService>());
});
getIt getIt
.registerFactory(() => WalletSeedViewModel(getIt.get<AppStore>().wallet!)); .registerFactory(() => WalletSeedViewModel(getIt.get<AppStore>().wallet!));
@ -458,12 +483,11 @@ Future setup(
(ContactRecord? contact, _) => (ContactRecord? contact, _) =>
ContactViewModel(_contactSource, contact: contact)); ContactViewModel(_contactSource, contact: contact));
getIt.registerFactory( getIt.registerFactoryParam<ContactListViewModel, CryptoCurrency?, void>(
() => ContactListViewModel(_contactSource, _walletInfoSource)); (CryptoCurrency? cur, _) => ContactListViewModel(_contactSource, _walletInfoSource, cur));
getIt.registerFactoryParam<ContactListPage, bool, void>( getIt.registerFactoryParam<ContactListPage, CryptoCurrency?, void>((CryptoCurrency? cur, _)
(bool isEditable, _) => ContactListPage(getIt.get<ContactListViewModel>(), => ContactListPage(getIt.get<ContactListViewModel>(param1: cur)));
isEditable: isEditable));
getIt.registerFactoryParam<ContactPage, ContactRecord?, void>( getIt.registerFactoryParam<ContactPage, ContactRecord?, void>(
(ContactRecord? contact, _) => (ContactRecord? contact, _) =>
@ -475,10 +499,22 @@ 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(() => getIt.registerFactory(() => SecurityBackupPage(getIt.get<SecuritySettingsViewModel>()));
NodeCreateOrEditViewModel(_nodeSource, getIt.get<AppStore>().wallet!));
getIt.registerFactory(() => PrivacyPage(getIt.get<PrivacySettingsViewModel>()));
getIt.registerFactory(() => DisplaySettingsPage(getIt.get<DisplaySettingsViewModel>()));
getIt.registerFactory(() => OtherSettingsPage(getIt.get<OtherSettingsViewModel>()));
getIt.registerFactoryParam<NodeCreateOrEditViewModel, WalletType?, void>(
(WalletType? type, _) => NodeCreateOrEditViewModel(
_nodeSource,
type ?? getIt.get<AppStore>().wallet!.type,
getIt.get<SettingsStore>(),
));
getIt.registerFactory( getIt.registerFactory(
() => NodeCreateOrEditPage(getIt.get<NodeCreateOrEditViewModel>())); () => NodeCreateOrEditPage(getIt.get<NodeCreateOrEditViewModel>()));
@ -494,7 +530,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(
@ -678,7 +713,7 @@ Future setup(
getIt.registerFactoryParam<FullscreenQRPage, String, bool>( getIt.registerFactoryParam<FullscreenQRPage, String, bool>(
(String qrData, bool isLight) => FullscreenQRPage(qrData: qrData, isLight: isLight,)); (String qrData, bool isLight) => FullscreenQRPage(qrData: qrData, isLight: isLight,));
getIt.registerFactory(() => IoniaApi()); getIt.registerFactory(() => IoniaApi());
getIt.registerFactory(() => AnyPayApi()); getIt.registerFactory(() => AnyPayApi());
@ -698,7 +733,7 @@ Future setup(
getIt.registerFactoryParam<IoniaMerchPurchaseViewModel, double, IoniaMerchant>((double amount, merchant) { getIt.registerFactoryParam<IoniaMerchPurchaseViewModel, double, IoniaMerchant>((double amount, merchant) {
return IoniaMerchPurchaseViewModel( return IoniaMerchPurchaseViewModel(
ioniaAnyPayService: getIt.get<IoniaAnyPay>(), ioniaAnyPayService: getIt.get<IoniaAnyPay>(),
amount: amount, amount: amount,
ioniaMerchant: merchant, ioniaMerchant: merchant,
sendViewModel: getIt.get<SendViewModel>() sendViewModel: getIt.get<SendViewModel>()
@ -741,31 +776,32 @@ Future setup(
ioniaService: getIt.get<IoniaService>(), ioniaService: getIt.get<IoniaService>(),
giftCard: giftCard); giftCard: giftCard);
}); });
getIt.registerFactoryParam<IoniaCustomTipViewModel, List, void>((List args, _) { getIt.registerFactoryParam<IoniaCustomTipViewModel, List, void>((List args, _) {
final amount = args[0] as double; final amount = args[0] as double;
final merchant = args[1] as IoniaMerchant; final merchant = args[1] as IoniaMerchant;
final tip = args[2] as IoniaTip; final tip = args[2] as IoniaTip;
return IoniaCustomTipViewModel(amount: amount, tip: tip, ioniaMerchant: merchant); return IoniaCustomTipViewModel(amount: amount, tip: tip, ioniaMerchant: merchant);
}); });
getIt.registerFactoryParam<IoniaGiftCardDetailPage, IoniaGiftCard, void>((IoniaGiftCard giftCard, _) { getIt.registerFactoryParam<IoniaGiftCardDetailPage, IoniaGiftCard, void>((IoniaGiftCard giftCard, _) {
return IoniaGiftCardDetailPage(getIt.get<IoniaGiftCardDetailsViewModel>(param1: giftCard)); return IoniaGiftCardDetailPage(getIt.get<IoniaGiftCardDetailsViewModel>(param1: giftCard));
}); });
getIt.registerFactoryParam<IoniaMoreOptionsPage, List, void>((List args, _){ getIt.registerFactoryParam<IoniaMoreOptionsPage, List, void>((List args, _){
final giftCard = args.first as IoniaGiftCard; final giftCard = args.first as IoniaGiftCard;
return IoniaMoreOptionsPage(giftCard); return IoniaMoreOptionsPage(giftCard);
}); });
getIt.registerFactoryParam<IoniaCustomRedeemViewModel, IoniaGiftCard, void>((IoniaGiftCard giftCard, _) => IoniaCustomRedeemViewModel(giftCard)); getIt.registerFactoryParam<IoniaCustomRedeemViewModel, IoniaGiftCard, void>((IoniaGiftCard giftCard, _)
=> IoniaCustomRedeemViewModel(giftCard: giftCard, ioniaService: getIt.get<IoniaService>()));
getIt.registerFactoryParam<IoniaCustomRedeemPage, List, void>((List args, _){ getIt.registerFactoryParam<IoniaCustomRedeemPage, List, void>((List args, _){
final giftCard = args.first as IoniaGiftCard; final giftCard = args.first as IoniaGiftCard;
return IoniaCustomRedeemPage(getIt.get<IoniaCustomRedeemViewModel>(param1: giftCard) ); return IoniaCustomRedeemPage(getIt.get<IoniaCustomRedeemViewModel>(param1: giftCard) );
}); });
@ -794,5 +830,8 @@ Future setup(
(IoniaAnyPayPaymentInfo paymentInfo, AnyPayPaymentCommittedInfo committedInfo) (IoniaAnyPayPaymentInfo paymentInfo, AnyPayPaymentCommittedInfo committedInfo)
=> IoniaPaymentStatusPage(getIt.get<IoniaPaymentStatusViewModel>(param1: paymentInfo, param2: committedInfo))); => IoniaPaymentStatusPage(getIt.get<IoniaPaymentStatusViewModel>(param1: paymentInfo, param2: committedInfo)));
getIt.registerFactoryParam<AdvancedPrivacySettingsViewModel, WalletType, void>((type, _) =>
AdvancedPrivacySettingsViewModel(type, getIt.get<SettingsStore>()));
_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,48 @@ Future defaultSettingsMigration(
await changeDefaultHavenNode(nodes); await changeDefaultHavenNode(nodes);
break; break;
case 18:
await addOnionNode(nodes);
break;
case 19:
await validateBitcoinSavedTransactionPriority(sharedPreferences);
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> validateBitcoinSavedTransactionPriority(SharedPreferences sharedPreferences) async {
if (bitcoin == null) {
return;
}
final int? savedBitcoinPriority =
sharedPreferences.getInt(PreferencesKey.bitcoinTransactionPriority);
if (!bitcoin!.getTransactionPriorities().any((element) => element.raw == savedBitcoinPriority)) {
await sharedPreferences.setInt(
PreferencesKey.bitcoinTransactionPriority, bitcoin!.getMediumTransactionPriority().serialize());
}
}
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 +207,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 +254,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 +263,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 +283,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 +308,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 +474,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

@ -0,0 +1,39 @@
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cw_core/enumerable_item.dart';
class FiatApiMode extends EnumerableItem<int> with Serializable<int> {
const FiatApiMode({required String title, required int raw}) : super(title: title, raw: raw);
static const all = [FiatApiMode.enabled, FiatApiMode.torOnly, FiatApiMode.disabled];
static const enabled = FiatApiMode(raw: 0, title: 'Enabled');
static const torOnly = FiatApiMode(raw: 1, title: 'Tor only');
static const disabled = FiatApiMode(raw: 2, title: 'Disabled');
static FiatApiMode deserialize({required int raw}) {
switch (raw) {
case 0:
return enabled;
case 1:
return torOnly;
case 2:
return disabled;
default:
throw Exception('Unexpected token: $raw for FiatApiMode deserialize');
}
}
@override
String toString() {
switch (this) {
case FiatApiMode.enabled:
return S.current.enabled;
case FiatApiMode.torOnly:
return S.current.tor_only;
case FiatApiMode.disabled:
return S.current.disabled;
default:
return '';
}
}
}

View file

@ -18,7 +18,8 @@ class LanguageService {
'uk': 'Українська (Ukrainian)', 'uk': 'Українська (Ukrainian)',
'zh': '中文 (Chinese)', 'zh': '中文 (Chinese)',
'hr': 'Hrvatski (Croatian)', 'hr': 'Hrvatski (Croatian)',
'it': 'Italiano (Italian)' 'it': 'Italiano (Italian)',
'th': 'ภาษาไทย (Thai)'
}; };
static const Map<String, String> localeCountryCode = { static const Map<String, String> localeCountryCode = {
@ -36,7 +37,8 @@ class LanguageService {
'uk': 'ukr', 'uk': 'ukr',
'zh': 'chn', 'zh': 'chn',
'hr': 'hrv', 'hr': 'hrv',
'it': 'ita' 'it': 'ita',
'th': 'tha'
}; };
static final list = <String, String> {}; static final list = <String, String> {};

View file

@ -4,7 +4,6 @@ import 'package:cake_wallet/entities/parsed_address.dart';
import 'package:cake_wallet/entities/unstoppable_domain_address.dart'; import 'package:cake_wallet/entities/unstoppable_domain_address.dart';
import 'package:cake_wallet/entities/emoji_string_extension.dart'; import 'package:cake_wallet/entities/emoji_string_extension.dart';
import 'package:cw_core/wallet_type.dart'; import 'package:cw_core/wallet_type.dart';
import 'package:flutter/foundation.dart';
import 'package:cake_wallet/entities/fio_address_provider.dart'; import 'package:cake_wallet/entities/fio_address_provider.dart';
class AddressResolver { class AddressResolver {
@ -51,7 +50,7 @@ class AddressResolver {
return ParsedAddress(addresses: [text]); return ParsedAddress(addresses: [text]);
} }
if (unstoppableDomains.any((domain) => name.contains(domain))) { if (unstoppableDomains.any((domain) => name.trim() == domain)) {
final address = await fetchUnstoppableDomainAddress(text, ticker); final address = await fetchUnstoppableDomainAddress(text, ticker);
return ParsedAddress.fetchUnstoppableDomainAddress(address: address, name: text); return ParsedAddress.fetchUnstoppableDomainAddress(address: address, name: text);
} }

View file

@ -0,0 +1,32 @@
import 'package:cake_wallet/generated/i18n.dart';
enum PinCodeRequiredDuration {
always(0),
tenminutes(10),
onehour(60);
const PinCodeRequiredDuration(this.value);
final int value;
static PinCodeRequiredDuration deserialize({required int raw}) =>
PinCodeRequiredDuration.values.firstWhere((e) => e.value == raw);
@override
String toString(){
String label = '';
switch (this) {
case PinCodeRequiredDuration.always:
label = S.current.always;
break;
case PinCodeRequiredDuration.tenminutes:
label = S.current.minutes_to_pin_code('10');
break;
case PinCodeRequiredDuration.onehour:
label = S.current.minutes_to_pin_code('60');
break;
}
return label;
}
}

View file

@ -9,6 +9,7 @@ class PreferencesKey {
static const currentTransactionPriorityKeyLegacy = 'current_fee_priority'; static const currentTransactionPriorityKeyLegacy = 'current_fee_priority';
static const currentBalanceDisplayModeKey = 'current_balance_display_mode'; static const currentBalanceDisplayModeKey = 'current_balance_display_mode';
static const shouldSaveRecipientAddressKey = 'save_recipient_address'; static const shouldSaveRecipientAddressKey = 'save_recipient_address';
static const currentFiatApiModeKey = 'current_fiat_api_mode';
static const allowBiometricalAuthenticationKey = static const allowBiometricalAuthenticationKey =
'allow_biometrical_authentication'; 'allow_biometrical_authentication';
static const disableExchangeKey = 'disable_exchange'; static const disableExchangeKey = 'disable_exchange';
@ -21,9 +22,14 @@ class PreferencesKey {
'current_default_settings_migration_version'; 'current_default_settings_migration_version';
static const moneroTransactionPriority = 'current_fee_priority_monero'; static const moneroTransactionPriority = 'current_fee_priority_monero';
static const bitcoinTransactionPriority = 'current_fee_priority_bitcoin'; static const bitcoinTransactionPriority = 'current_fee_priority_bitcoin';
static const havenTransactionPriority = 'current_fee_priority_haven';
static const litecoinTransactionPriority = 'current_fee_priority_litecoin';
static const shouldShowReceiveWarning = 'should_show_receive_warning'; static const shouldShowReceiveWarning = 'should_show_receive_warning';
static const shouldShowYatPopup = 'should_show_yat_popup'; static const shouldShowYatPopup = 'should_show_yat_popup';
static const moneroWalletPasswordUpdateV1Base = 'monero_wallet_update_v1'; static const moneroWalletPasswordUpdateV1Base = 'monero_wallet_update_v1';
static const pinTimeOutDuration = 'pin_timeout_duration';
static const lastAuthTimeMilliseconds = 'last_auth_time_milliseconds';
static String moneroWalletUpdateV1Key(String name) static String moneroWalletUpdateV1Key(String name)
=> '${PreferencesKey.moneroWalletPasswordUpdateV1Base}_${name}'; => '${PreferencesKey.moneroWalletPasswordUpdateV1Base}_${name}';

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

@ -11,7 +11,6 @@ import 'package:cake_wallet/exchange/trade_request.dart';
import 'package:cake_wallet/exchange/trade_state.dart'; import 'package:cake_wallet/exchange/trade_state.dart';
import 'package:cake_wallet/exchange/changenow/changenow_request.dart'; import 'package:cake_wallet/exchange/changenow/changenow_request.dart';
import 'package:cake_wallet/exchange/exchange_provider_description.dart'; import 'package:cake_wallet/exchange/exchange_provider_description.dart';
import 'package:cake_wallet/exchange/trade_not_created_exeption.dart';
class ChangeNowExchangeProvider extends ExchangeProvider { class ChangeNowExchangeProvider extends ExchangeProvider {
ChangeNowExchangeProvider() ChangeNowExchangeProvider()
@ -21,8 +20,7 @@ class ChangeNowExchangeProvider extends ExchangeProvider {
.where((i) => i != CryptoCurrency.xhv) .where((i) => i != CryptoCurrency.xhv)
.map((i) => CryptoCurrency.all .map((i) => CryptoCurrency.all
.where((i) => i != CryptoCurrency.xhv) .where((i) => i != CryptoCurrency.xhv)
.map((k) => ExchangePair(from: i, to: k, reverse: true)) .map((k) => ExchangePair(from: i, to: k, reverse: true)))
.where((c) => c != null))
.expand((i) => i) .expand((i) => i)
.toList()); .toList());
@ -43,6 +41,9 @@ class ChangeNowExchangeProvider extends ExchangeProvider {
@override @override
bool get isEnabled => true; bool get isEnabled => true;
@override
bool get supportsFixedRate => true;
@override @override
ExchangeProviderDescription get description => ExchangeProviderDescription get description =>
ExchangeProviderDescription.changeNow; ExchangeProviderDescription.changeNow;
@ -96,25 +97,36 @@ class ChangeNowExchangeProvider extends ExchangeProvider {
apiHeaderKey: apiKey, apiHeaderKey: apiKey,
'Content-Type': 'application/json'}; 'Content-Type': 'application/json'};
final flow = getFlow(isFixedRateMode); final flow = getFlow(isFixedRateMode);
final type = isFixedRateMode ? 'reverse' : 'direct';
final body = <String, String>{ final body = <String, String>{
'fromCurrency': normalizeCryptoCurrency(_request.from), 'fromCurrency': normalizeCryptoCurrency(_request.from),
'toCurrency': normalizeCryptoCurrency(_request.to), 'toCurrency': normalizeCryptoCurrency(_request.to),
'fromNetwork': networkFor(_request.from), 'fromNetwork': networkFor(_request.from),
'toNetwork': networkFor(_request.to), 'toNetwork': networkFor(_request.to),
'fromAmount': _request.fromAmount, if (!isFixedRateMode) 'fromAmount': _request.fromAmount,
'toAmount': _request.toAmount, if (isFixedRateMode) 'toAmount': _request.toAmount,
'address': _request.address, 'address': _request.address,
'flow': flow, 'flow': flow,
'type': type,
'refundAddress': _request.refundAddress 'refundAddress': _request.refundAddress
}; };
if (isFixedRateMode) { if (isFixedRateMode) {
// since we schedule to calculate the rate every 5 seconds we need to ensure that
// we have the latest rate id with the given inputs before creating the trade
await fetchRate(
from: _request.from,
to: _request.to,
amount: double.tryParse(_request.toAmount) ?? 0,
isFixedRateMode: true,
isReceiveAmount: true,
);
body['rateId'] = _lastUsedRateId; body['rateId'] = _lastUsedRateId;
} }
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 +142,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,
@ -141,7 +153,7 @@ class ChangeNowExchangeProvider extends ExchangeProvider {
refundAddress: refundAddress, refundAddress: refundAddress,
extraId: extraId, extraId: extraId,
createdAt: DateTime.now(), createdAt: DateTime.now(),
amount: _request.fromAmount, amount: responseJSON['fromAmount']?.toString() ?? _request.fromAmount,
state: TradeState.created); state: TradeState.created);
} }
@ -180,9 +192,7 @@ class ChangeNowExchangeProvider extends ExchangeProvider {
final extraId = responseJSON['payinExtraId'] as String; final extraId = responseJSON['payinExtraId'] as String;
final outputTransaction = responseJSON['payoutHash'] as String; final outputTransaction = responseJSON['payoutHash'] as String;
final expiredAtRaw = responseJSON['validUntil'] as String; final expiredAtRaw = responseJSON['validUntil'] as String;
final expiredAt = expiredAtRaw != null final expiredAt = DateTime.tryParse(expiredAtRaw)?.toLocal();
? DateTime.parse(expiredAtRaw).toLocal()
: null;
return Trade( return Trade(
id: id, id: id,
@ -198,7 +208,7 @@ class ChangeNowExchangeProvider extends ExchangeProvider {
} }
@override @override
Future<double> calculateAmount( Future<double> fetchRate(
{required CryptoCurrency from, {required CryptoCurrency from,
required CryptoCurrency to, required CryptoCurrency to,
required double amount, required double amount,
@ -214,10 +224,10 @@ class ChangeNowExchangeProvider extends ExchangeProvider {
final type = isReverse ? 'reverse' : 'direct'; final type = isReverse ? 'reverse' : 'direct';
final flow = getFlow(isFixedRateMode); final flow = getFlow(isFixedRateMode);
final params = <String, String>{ final params = <String, String>{
'fromCurrency': isReverse ? normalizeCryptoCurrency(to) : normalizeCryptoCurrency(from), 'fromCurrency': normalizeCryptoCurrency(from),
'toCurrency': isReverse ? normalizeCryptoCurrency(from) : normalizeCryptoCurrency(to), 'toCurrency': normalizeCryptoCurrency(to),
'fromNetwork': isReverse ? networkFor(to) : networkFor(from), 'fromNetwork': networkFor(from),
'toNetwork': isReverse ? networkFor(from) : networkFor(to), 'toNetwork': networkFor(to),
'type': type, 'type': type,
'flow': flow}; 'flow': flow};
@ -238,7 +248,7 @@ class ChangeNowExchangeProvider extends ExchangeProvider {
_lastUsedRateId = rateId; _lastUsedRateId = rateId;
} }
return isReverse ? fromAmount : toAmount; return isReverse ? (amount / fromAmount) : (toAmount / amount);
} catch(e) { } catch(e) {
print(e.toString()); print(e.toString());
return 0.0; return 0.0;

View file

@ -1,4 +1,3 @@
import 'package:flutter/foundation.dart';
import 'package:cw_core/crypto_currency.dart'; import 'package:cw_core/crypto_currency.dart';
import 'package:cake_wallet/exchange/trade_request.dart'; import 'package:cake_wallet/exchange/trade_request.dart';
import 'package:cake_wallet/exchange/exchange_pair.dart'; import 'package:cake_wallet/exchange/exchange_pair.dart';
@ -14,6 +13,7 @@ abstract class ExchangeProvider {
ExchangeProviderDescription get description; ExchangeProviderDescription get description;
bool get isAvailable; bool get isAvailable;
bool get isEnabled; bool get isEnabled;
bool get supportsFixedRate;
@override @override
String toString() => title; String toString() => title;
@ -26,7 +26,7 @@ abstract class ExchangeProvider {
required TradeRequest request, required TradeRequest request,
required bool isFixedRateMode}); required bool isFixedRateMode});
Future<Trade> findTradeById({required String id}); Future<Trade> findTradeById({required String id});
Future<double> calculateAmount({ Future<double> fetchRate({
required CryptoCurrency from, required CryptoCurrency from,
required CryptoCurrency to, required CryptoCurrency to,
required double amount, required double amount,

View file

@ -24,6 +24,9 @@ class ExchangeProviderDescription extends EnumerableItem<int>
static const simpleSwap = static const simpleSwap =
ExchangeProviderDescription(title: 'SimpleSwap', raw: 4, image: 'assets/images/simpleSwap.png'); ExchangeProviderDescription(title: 'SimpleSwap', raw: 4, image: 'assets/images/simpleSwap.png');
static const all =
ExchangeProviderDescription(title: 'All trades', raw: 5, image:'');
static ExchangeProviderDescription deserialize({required int raw}) { static ExchangeProviderDescription deserialize({required int raw}) {
switch (raw) { switch (raw) {
case 0: case 0:
@ -36,6 +39,8 @@ class ExchangeProviderDescription extends EnumerableItem<int>
return sideShift; return sideShift;
case 4: case 4:
return simpleSwap; return simpleSwap;
case 5:
return all;
default: default:
throw Exception('Unexpected token: $raw for ExchangeProviderDescription deserialize'); throw Exception('Unexpected token: $raw for ExchangeProviderDescription deserialize');
} }

View file

@ -66,6 +66,9 @@ class MorphTokenExchangeProvider extends ExchangeProvider {
@override @override
bool get isEnabled => true; bool get isEnabled => true;
@override
bool get supportsFixedRate => false;
@override @override
ExchangeProviderDescription get description => ExchangeProviderDescription get description =>
ExchangeProviderDescription.morphToken; ExchangeProviderDescription.morphToken;
@ -200,7 +203,7 @@ class MorphTokenExchangeProvider extends ExchangeProvider {
} }
@override @override
Future<double> calculateAmount( Future<double> fetchRate(
{required CryptoCurrency from, {required CryptoCurrency from,
required CryptoCurrency to, required CryptoCurrency to,
required double amount, required double amount,

View file

@ -12,7 +12,6 @@ import 'package:cw_core/crypto_currency.dart';
import 'package:cake_wallet/exchange/trade_request.dart'; import 'package:cake_wallet/exchange/trade_request.dart';
import 'package:cake_wallet/exchange/trade.dart'; import 'package:cake_wallet/exchange/trade.dart';
import 'package:cake_wallet/exchange/limits.dart'; import 'package:cake_wallet/exchange/limits.dart';
import 'package:flutter/foundation.dart';
import 'package:http/http.dart'; import 'package:http/http.dart';
class SideShiftExchangeProvider extends ExchangeProvider { class SideShiftExchangeProvider extends ExchangeProvider {
@ -28,7 +27,6 @@ class SideShiftExchangeProvider extends ExchangeProvider {
static const List<CryptoCurrency> _notSupported = [ static const List<CryptoCurrency> _notSupported = [
CryptoCurrency.xhv, CryptoCurrency.xhv,
CryptoCurrency.dcr, CryptoCurrency.dcr,
CryptoCurrency.husd,
CryptoCurrency.kmd, CryptoCurrency.kmd,
CryptoCurrency.mkr, CryptoCurrency.mkr,
CryptoCurrency.near, CryptoCurrency.near,
@ -39,6 +37,7 @@ class SideShiftExchangeProvider extends ExchangeProvider {
CryptoCurrency.rvn, CryptoCurrency.rvn,
CryptoCurrency.scrt, CryptoCurrency.scrt,
CryptoCurrency.stx, CryptoCurrency.stx,
CryptoCurrency.bttc,
]; ];
static List<ExchangePair> _supportedPairs() { static List<ExchangePair> _supportedPairs() {
@ -48,8 +47,7 @@ class SideShiftExchangeProvider extends ExchangeProvider {
return supportedCurrencies return supportedCurrencies
.map((i) => supportedCurrencies .map((i) => supportedCurrencies
.map((k) => ExchangePair(from: i, to: k, reverse: true)) .map((k) => ExchangePair(from: i, to: k, reverse: true)))
.where((c) => c != null))
.expand((i) => i) .expand((i) => i)
.toList(); .toList();
} }
@ -59,7 +57,7 @@ class SideShiftExchangeProvider extends ExchangeProvider {
ExchangeProviderDescription.sideShift; ExchangeProviderDescription.sideShift;
@override @override
Future<double> calculateAmount( Future<double> fetchRate(
{required CryptoCurrency from, {required CryptoCurrency from,
required CryptoCurrency to, required CryptoCurrency to,
required double amount, required double amount,
@ -81,9 +79,7 @@ class SideShiftExchangeProvider extends ExchangeProvider {
if (amount > max) return 0.00; if (amount > max) return 0.00;
final estimatedAmount = rate * amount; return rate;
return estimatedAmount;
} catch (_) { } catch (_) {
return 0.00; return 0.00;
} }
@ -249,15 +245,15 @@ class SideShiftExchangeProvider extends ExchangeProvider {
final expectedSendAmount = responseJSON['depositAmount'].toString(); final expectedSendAmount = responseJSON['depositAmount'].toString();
final deposits = responseJSON['deposits'] as List?; final deposits = responseJSON['deposits'] as List?;
TradeState? state; TradeState? state;
String? status;
if (deposits != null && deposits.isNotEmpty) { if (deposits?.isNotEmpty ?? false) {
final status = deposits[0]['status'] as String; status = deposits![0]['status'] as String?;
state = TradeState.deserialize(raw: status);
} }
state = TradeState.deserialize(raw: status ?? 'created');
final expiredAtRaw = responseJSON['expiresAtISO'] as String; final expiredAtRaw = responseJSON['expiresAtISO'] as String;
final expiredAt = final expiredAt = DateTime.tryParse(expiredAtRaw)?.toLocal();
expiredAtRaw != null ? DateTime.parse(expiredAtRaw).toLocal() : null;
return Trade( return Trade(
id: id, id: id,
@ -277,6 +273,9 @@ class SideShiftExchangeProvider extends ExchangeProvider {
@override @override
bool get isEnabled => true; bool get isEnabled => true;
@override
bool get supportsFixedRate => true;
@override @override
String get title => 'SideShift'; String get title => 'SideShift';

View file

@ -20,8 +20,7 @@ class SimpleSwapExchangeProvider extends ExchangeProvider {
.where((i) => i != CryptoCurrency.zaddr) .where((i) => i != CryptoCurrency.zaddr)
.map((i) => CryptoCurrency.all .map((i) => CryptoCurrency.all
.where((i) => i != CryptoCurrency.zaddr) .where((i) => i != CryptoCurrency.zaddr)
.map((k) => ExchangePair(from: i, to: k, reverse: true)) .map((k) => ExchangePair(from: i, to: k, reverse: true)))
.where((c) => c != null))
.expand((i) => i) .expand((i) => i)
.toList()); .toList());
@ -37,7 +36,7 @@ class SimpleSwapExchangeProvider extends ExchangeProvider {
ExchangeProviderDescription.simpleSwap; ExchangeProviderDescription.simpleSwap;
@override @override
Future<double> calculateAmount( Future<double> fetchRate(
{required CryptoCurrency from, {required CryptoCurrency from,
required CryptoCurrency to, required CryptoCurrency to,
required double amount, required double amount,
@ -59,9 +58,9 @@ class SimpleSwapExchangeProvider extends ExchangeProvider {
final uri = Uri.https(apiAuthority, getEstimatePath, params); final uri = Uri.https(apiAuthority, getEstimatePath, params);
final response = await get(uri); final response = await get(uri);
if (response.body == null || response.body == "null") return 0.00; if (response.body == "null") return 0.00;
final data = json.decode(response.body) as String; final data = json.decode(response.body) as String;
return double.parse(data); return double.parse(data) / amount;
} catch (_) { } catch (_) {
return 0.00; return 0.00;
} }
@ -210,6 +209,9 @@ class SimpleSwapExchangeProvider extends ExchangeProvider {
@override @override
bool get isEnabled => true; bool get isEnabled => true;
@override
bool get supportsFixedRate => false;
@override @override
String get title => 'SimpleSwap'; String get title => 'SimpleSwap';

View file

@ -48,6 +48,9 @@ class XMRTOExchangeProvider extends ExchangeProvider {
@override @override
bool get isEnabled => true; bool get isEnabled => true;
@override
bool get supportsFixedRate => false;
@override @override
ExchangeProviderDescription get description => ExchangeProviderDescription get description =>
ExchangeProviderDescription.xmrto; ExchangeProviderDescription.xmrto;
@ -191,7 +194,7 @@ class XMRTOExchangeProvider extends ExchangeProvider {
} }
@override @override
Future<double> calculateAmount( Future<double> fetchRate(
{required CryptoCurrency from, {required CryptoCurrency from,
required CryptoCurrency to, required CryptoCurrency to,
required double amount, required double amount,

View file

@ -37,7 +37,7 @@ class IoniaGiftCard {
purchaseAmount: element['PurchaseAmount'] as double, purchaseAmount: element['PurchaseAmount'] as double,
actualAmount: element['ActualAmount'] as double, actualAmount: element['ActualAmount'] as double,
totalTransactionAmount: element['TotalTransactionAmount'] as double, totalTransactionAmount: element['TotalTransactionAmount'] as double,
totalDashTransactionAmount: element['TotalDashTransactionAmount'] as double, totalDashTransactionAmount: (element['TotalDashTransactionAmount'] as double?) ?? 0.0,
remainingAmount: element['RemainingAmount'] as double, remainingAmount: element['RemainingAmount'] as double,
isActive: element['IsActive'] as bool, isActive: element['IsActive'] as bool,
isEmpty: element['IsEmpty'] as bool, isEmpty: element['IsEmpty'] as bool,

View file

@ -148,8 +148,8 @@ class IoniaService {
// Redeem // Redeem
Future<void> redeem(IoniaGiftCard giftCard) async { Future<void> redeem({required int giftCardId, required double amount}) async {
await chargeGiftCard(giftCardId: giftCard.id, amount: giftCard.remainingAmount); await chargeGiftCard(giftCardId: giftCardId, amount: amount);
} }
// Get Gift Card // Get Gift Card

View file

@ -3,6 +3,7 @@ import 'dart:convert';
import 'dart:io'; import 'dart:io';
import 'dart:isolate'; import 'dart:isolate';
import 'package:cake_wallet/bitcoin/bitcoin.dart'; import 'package:cake_wallet/bitcoin/bitcoin.dart';
import 'package:cake_wallet/core/auth_service.dart';
import 'package:cake_wallet/entities/language_service.dart'; import 'package:cake_wallet/entities/language_service.dart';
import 'package:cake_wallet/buy/order.dart'; import 'package:cake_wallet/buy/order.dart';
import 'package:cake_wallet/entities/preferences_key.dart'; import 'package:cake_wallet/entities/preferences_key.dart';
@ -48,6 +49,7 @@ import 'package:cake_wallet/wallet_type_utils.dart';
final navigatorKey = GlobalKey<NavigatorState>(); final navigatorKey = GlobalKey<NavigatorState>();
final rootKey = GlobalKey<RootState>(); final rootKey = GlobalKey<RootState>();
final RouteObserver<PageRoute> routeObserver = RouteObserver<PageRoute>();
Future<void> main() async { Future<void> main() async {
@ -166,7 +168,7 @@ Future<void> main() async {
exchangeTemplates: exchangeTemplates, exchangeTemplates: exchangeTemplates,
transactionDescriptions: transactionDescriptions, transactionDescriptions: transactionDescriptions,
secureStorage: secureStorage, secureStorage: secureStorage,
initialMigrationVersion: 17); initialMigrationVersion: 19);
runApp(App()); runApp(App());
}, (error, stackTrace) async { }, (error, stackTrace) async {
print("@@@@@@@@@@@@@@@@ in run zone guard"); print("@@@@@@@@@@@@@@@@ in run zone guard");
@ -276,12 +278,6 @@ class AppState extends State<App> with SingleTickerProviderStateMixin {
//_handleInitialUri(); //_handleInitialUri();
} }
@override
void dispose() {
stream?.cancel();
super.dispose();
}
Future<void> _handleInitialUri() async { Future<void> _handleInitialUri() async {
try { try {
final uri = await getInitialUri(); final uri = await getInitialUri();
@ -329,11 +325,12 @@ class AppState extends State<App> with SingleTickerProviderStateMixin {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Observer(builder: (BuildContext context) { return Observer(builder: (BuildContext context) {
final appStore = getIt.get<AppStore>(); final appStore = getIt.get<AppStore>();
final authService = getIt.get<AuthService>();
final settingsStore = appStore.settingsStore; final settingsStore = appStore.settingsStore;
final statusBarColor = Colors.transparent; final statusBarColor = Colors.transparent;
final authenticationStore = getIt.get<AuthenticationStore>(); final authenticationStore = getIt.get<AuthenticationStore>();
final initialRoute = final initialRoute =
authenticationStore.state == AuthenticationState.denied authenticationStore.state == AuthenticationState.uninitialized
? Routes.disclaimer ? Routes.disclaimer
: Routes.login; : Routes.login;
final currentTheme = settingsStore.currentTheme; final currentTheme = settingsStore.currentTheme;
@ -353,7 +350,9 @@ class AppState extends State<App> with SingleTickerProviderStateMixin {
appStore: appStore, appStore: appStore,
authenticationStore: authenticationStore, authenticationStore: authenticationStore,
navigatorKey: navigatorKey, navigatorKey: navigatorKey,
authService: authService,
child: MaterialApp( child: MaterialApp(
navigatorObservers: [routeObserver],
navigatorKey: navigatorKey, navigatorKey: navigatorKey,
debugShowCheckedModeBanner: false, debugShowCheckedModeBanner: false,
theme: settingsStore.theme, theme: settingsStore.theme,

View file

@ -1,4 +1,5 @@
import 'dart:async'; import 'dart:async';
import 'package:cake_wallet/reactions/fiat_rate_update.dart';
import 'package:cake_wallet/reactions/on_current_node_change.dart'; import 'package:cake_wallet/reactions/on_current_node_change.dart';
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
@ -22,13 +23,14 @@ Future<void> bootstrap(GlobalKey<NavigatorState> navigatorKey) async {
final currentWalletName = getIt final currentWalletName = getIt
.get<SharedPreferences>() .get<SharedPreferences>()
.getString(PreferencesKey.currentWalletName); .getString(PreferencesKey.currentWalletName);
authenticationStore.state = currentWalletName == null if (currentWalletName != null) {
? AuthenticationState.denied authenticationStore.state = AuthenticationState.installed;
: AuthenticationState.installed; }
startAuthenticationStateChange(authenticationStore, navigatorKey); startAuthenticationStateChange(authenticationStore, navigatorKey);
startCurrentWalletChangeReaction( startCurrentWalletChangeReaction(
appStore, settingsStore, fiatConversionStore); appStore, settingsStore, fiatConversionStore);
startCurrentFiatChangeReaction(appStore, settingsStore, fiatConversionStore); startCurrentFiatChangeReaction(appStore, settingsStore, fiatConversionStore);
startOnCurrentNodeChangeReaction(appStore); startOnCurrentNodeChangeReaction(appStore);
startFiatRateUpdate(appStore, settingsStore, fiatConversionStore);
} }

View file

@ -1,5 +1,6 @@
import 'dart:async'; import 'dart:async';
import 'package:cake_wallet/core/fiat_conversion_service.dart'; import 'package:cake_wallet/core/fiat_conversion_service.dart';
import 'package:cake_wallet/entities/fiat_api_mode.dart';
import 'package:cake_wallet/entities/update_haven_rate.dart'; import 'package:cake_wallet/entities/update_haven_rate.dart';
import 'package:cake_wallet/store/app_store.dart'; import 'package:cake_wallet/store/app_store.dart';
import 'package:cake_wallet/store/dashboard/fiat_conversion_store.dart'; import 'package:cake_wallet/store/dashboard/fiat_conversion_store.dart';
@ -8,30 +9,27 @@ import 'package:cw_core/wallet_type.dart';
Timer? _timer; Timer? _timer;
Future<void> startFiatRateUpdate(AppStore appStore, SettingsStore settingsStore, Future<void> startFiatRateUpdate(
FiatConversionStore fiatConversionStore) async { AppStore appStore, SettingsStore settingsStore, FiatConversionStore fiatConversionStore) async {
if (_timer != null) { if (_timer != null) {
return; return;
} }
if (appStore.wallet != null) { _timer = Timer.periodic(Duration(seconds: 30), (_) async {
fiatConversionStore.prices[appStore.wallet!.currency] = try {
await FiatConversionService.fetchPrice( if (appStore.wallet == null || settingsStore.fiatApiMode == FiatApiMode.disabled) {
appStore.wallet!.currency, settingsStore.fiatCurrency); return;
} }
_timer = Timer.periodic( if (appStore.wallet!.type == WalletType.haven) {
Duration(seconds: 30), await updateHavenRate(fiatConversionStore);
(_) async { } else {
try { fiatConversionStore.prices[appStore.wallet!.currency] =
if (appStore.wallet!.type == WalletType.haven) { await FiatConversionService.fetchPrice(
await updateHavenRate(fiatConversionStore); appStore.wallet!.currency, settingsStore.fiatCurrency);
} else { }
fiatConversionStore.prices[appStore.wallet!.currency] = await FiatConversionService.fetchPrice( } catch (e) {
appStore.wallet!.currency, settingsStore.fiatCurrency); print(e);
} }
} catch(e) { });
print(e);
}
});
} }

View file

@ -26,10 +26,5 @@ void startAuthenticationStateChange(AuthenticationStore authenticationStore,
await navigatorKey.currentState!.pushNamedAndRemoveUntil(Routes.dashboard, (route) => false); await navigatorKey.currentState!.pushNamedAndRemoveUntil(Routes.dashboard, (route) => false);
return; return;
} }
if (state == AuthenticationState.denied) {
await navigatorKey.currentState!.pushNamedAndRemoveUntil(Routes.welcome, (_) => false);
return;
}
}); });
} }

View file

@ -1,3 +1,4 @@
import 'package:cake_wallet/entities/fiat_api_mode.dart';
import 'package:mobx/mobx.dart'; import 'package:mobx/mobx.dart';
import 'package:cake_wallet/core/fiat_conversion_service.dart'; import 'package:cake_wallet/core/fiat_conversion_service.dart';
import 'package:cake_wallet/store/dashboard/fiat_conversion_store.dart'; import 'package:cake_wallet/store/dashboard/fiat_conversion_store.dart';
@ -12,7 +13,7 @@ void startCurrentFiatChangeReaction(AppStore appStore,
_onCurrentFiatCurrencyChangeDisposer?.reaction.dispose(); _onCurrentFiatCurrencyChangeDisposer?.reaction.dispose();
_onCurrentFiatCurrencyChangeDisposer = reaction( _onCurrentFiatCurrencyChangeDisposer = reaction(
(_) => settingsStore.fiatCurrency, (FiatCurrency fiatCurrency) async { (_) => settingsStore.fiatCurrency, (FiatCurrency fiatCurrency) async {
if (appStore.wallet == null) { if (appStore.wallet == null || settingsStore.fiatApiMode == FiatApiMode.disabled) {
return; return;
} }

View file

@ -1,3 +1,4 @@
import 'package:cake_wallet/entities/fiat_api_mode.dart';
import 'package:cake_wallet/entities/fiat_currency.dart'; import 'package:cake_wallet/entities/fiat_currency.dart';
import 'package:cake_wallet/entities/update_haven_rate.dart'; import 'package:cake_wallet/entities/update_haven_rate.dart';
import 'package:cw_core/transaction_history.dart'; import 'package:cw_core/transaction_history.dart';
@ -87,7 +88,7 @@ void startCurrentWalletChangeReaction(AppStore appStore,
TransactionHistoryBase<TransactionInfo>, TransactionInfo>? TransactionHistoryBase<TransactionInfo>, TransactionInfo>?
wallet) async { wallet) async {
try { try {
if (wallet == null) { if (wallet == null || settingsStore.fiatApiMode == FiatApiMode.disabled) {
return; return;
} }

View file

@ -5,21 +5,30 @@ 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';
import 'package:cake_wallet/src/screens/ionia/cards/ionia_custom_tip_page.dart'; import 'package:cake_wallet/src/screens/ionia/cards/ionia_custom_tip_page.dart';
import 'package:cake_wallet/src/screens/ionia/cards/ionia_gift_card_detail_page.dart'; import 'package:cake_wallet/src/screens/ionia/cards/ionia_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/new_wallet/advanced_privacy_settings_page.dart';
import 'package:cake_wallet/src/screens/order_details/order_details_page.dart'; import 'package:cake_wallet/src/screens/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/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';
import 'package:cake_wallet/utils/payment_request.dart';
import 'package:cake_wallet/view_model/monero_account_list/account_list_item.dart'; import 'package:cake_wallet/view_model/monero_account_list/account_list_item.dart';
import 'package:cake_wallet/view_model/node_list/node_create_or_edit_view_model.dart';
import 'package:cake_wallet/view_model/advanced_privacy_settings_view_model.dart';
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:cake_wallet/routes.dart'; import 'package:cake_wallet/routes.dart';
@ -36,7 +45,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';
@ -56,7 +64,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';
@ -74,6 +81,7 @@ import 'package:cake_wallet/src/screens/ionia/ionia.dart';
import 'package:cake_wallet/src/screens/ionia/cards/ionia_payment_status_page.dart'; import 'package:cake_wallet/src/screens/ionia/cards/ionia_payment_status_page.dart';
import 'package:cake_wallet/anypay/any_pay_payment_committed_info.dart'; import 'package:cake_wallet/anypay/any_pay_payment_committed_info.dart';
import 'package:cake_wallet/ionia/ionia_any_pay_payment_info.dart'; import 'package:cake_wallet/ionia/ionia_any_pay_payment_info.dart';
import 'package:cw_core/crypto_currency.dart';
late RouteSettings currentRouteSettings; late RouteSettings currentRouteSettings;
@ -209,8 +217,12 @@ Route<dynamic> createRoute(RouteSettings settings) {
builder: (_) => getIt.get<DashboardPage>()); builder: (_) => getIt.get<DashboardPage>());
case Routes.send: case Routes.send:
final initialPaymentRequest = settings.arguments as PaymentRequest?;
return CupertinoPageRoute<void>( return CupertinoPageRoute<void>(
fullscreenDialog: true, builder: (_) => getIt.get<SendPage>()); fullscreenDialog: true, builder: (_) => getIt.get<SendPage>(
param1: initialPaymentRequest,
));
case Routes.sendTemplate: case Routes.sendTemplate:
return CupertinoPageRoute<void>( return CupertinoPageRoute<void>(
@ -274,10 +286,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>());
@ -298,11 +326,13 @@ Route<dynamic> createRoute(RouteSettings settings) {
case Routes.addressBook: case Routes.addressBook:
return MaterialPageRoute<void>( return MaterialPageRoute<void>(
builder: (_) => getIt.get<ContactListPage>(param1: true)); builder: (_) =>
getIt.get<ContactListPage>());
case Routes.pickerAddressBook: case Routes.pickerAddressBook:
final selectedCurrency = settings.arguments as CryptoCurrency;
return MaterialPageRoute<void>( return MaterialPageRoute<void>(
builder: (_) => getIt.get<ContactListPage>(param1: false)); builder: (_) => getIt.get<ContactListPage>(param1: selectedCurrency));
case Routes.addressBookAddContact: case Routes.addressBookAddContact:
return CupertinoPageRoute<void>( return CupertinoPageRoute<void>(
@ -360,9 +390,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>());
@ -475,6 +502,15 @@ Route<dynamic> createRoute(RouteSettings settings) {
case Routes.onramperPage: case Routes.onramperPage:
return CupertinoPageRoute<void>(builder: (_) => getIt.get<OnRamperPage>()); return CupertinoPageRoute<void>(builder: (_) => getIt.get<OnRamperPage>());
case Routes.advancedPrivacySettings:
final type = settings.arguments as WalletType;
return CupertinoPageRoute<void>(
builder: (_) => AdvancedPrivacySettingsPage(
getIt.get<AdvancedPrivacySettingsViewModel>(param1: type),
getIt.get<NodeCreateOrEditViewModel>(param1: type),
));
default: default:
return MaterialPageRoute<void>( return MaterialPageRoute<void>(
builder: (_) => Scaffold( builder: (_) => Scaffold(

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,4 +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 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

@ -9,24 +9,22 @@ import 'package:flutter_mobx/flutter_mobx.dart';
import 'package:flutter_slidable/flutter_slidable.dart'; import 'package:flutter_slidable/flutter_slidable.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:cw_core/crypto_currency.dart';
import 'package:cake_wallet/src/screens/base_page.dart'; import 'package:cake_wallet/src/screens/base_page.dart';
import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart'; import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart';
import 'package:cake_wallet/view_model/contact_list/contact_list_view_model.dart'; import 'package:cake_wallet/view_model/contact_list/contact_list_view_model.dart';
import 'package:cake_wallet/src/widgets/collapsible_standart_list.dart'; import 'package:cake_wallet/src/widgets/collapsible_standart_list.dart';
class ContactListPage extends BasePage { class ContactListPage extends BasePage {
ContactListPage(this.contactListViewModel, {this.isEditable = true}); ContactListPage(this.contactListViewModel);
final ContactListViewModel contactListViewModel; final ContactListViewModel contactListViewModel;
final bool isEditable;
@override @override
String get title => S.current.address_book; String get title => S.current.address_book;
@override @override
Widget? trailing(BuildContext context) { Widget? trailing(BuildContext context) {
if (!isEditable) { if (!contactListViewModel.isEditable) {
return null; return null;
} }
@ -60,21 +58,24 @@ class ContactListPage extends BasePage {
@override @override
Widget body(BuildContext context) { Widget body(BuildContext context) {
return Container( return Container(
padding: EdgeInsets.only(top: 20.0, bottom: 20.0), padding: EdgeInsets.only(top: 20.0, bottom: 20.0),
child: Observer( child: Observer(
builder: (_) { builder: (_) {
return CollapsibleSectionList( final contacts = contactListViewModel.contactsToShow;
final walletContacts = contactListViewModel.walletContactsToShow;
return CollapsibleSectionList(
context: context, context: context,
sectionCount: 2, sectionCount: 2,
themeColor: Theme.of(context).primaryTextTheme.headline6!.color!, themeColor: Theme.of(context).primaryTextTheme.headline6!.color!,
dividerThemeColor: dividerThemeColor:
Theme.of(context).primaryTextTheme.caption!.decorationColor!, Theme.of(context).primaryTextTheme.caption!.decorationColor!,
sectionTitleBuilder: (_, int sectionIndex) { sectionTitleBuilder: (_, int sectionIndex) {
var title = 'Contacts'; var title = S.current.contact_list_contacts;
if (sectionIndex == 0) { if (sectionIndex == 0) {
title = 'My wallets'; title = S.current.contact_list_wallets;
} }
return Container( return Container(
@ -82,35 +83,37 @@ class ContactListPage extends BasePage {
child: Text(title, style: TextStyle(fontSize: 36))); child: Text(title, style: TextStyle(fontSize: 36)));
}, },
itemCounter: (int sectionIndex) => sectionIndex == 0 itemCounter: (int sectionIndex) => sectionIndex == 0
? contactListViewModel.walletContacts.length ? walletContacts.length
: contactListViewModel.contacts.length, : contacts.length,
itemBuilder: (_, sectionIndex, index) { itemBuilder: (_, sectionIndex, index) {
if (sectionIndex == 0) { if (sectionIndex == 0) {
final walletInfo = contactListViewModel.walletContacts[index]; final walletInfo = walletContacts[index];
return generateRaw(context, walletInfo); return generateRaw(context, walletInfo);
} }
final contact = contactListViewModel.contacts[index]; final contact = contacts[index];
final content = generateRaw(context, contact); final content = generateRaw(context, contact);
return !isEditable return contactListViewModel.isEditable
? content ? Slidable(
: Slidable(
key: Key('${contact.key}'), key: Key('${contact.key}'),
endActionPane: _actionPane(context, contact), endActionPane: _actionPane(context, contact),
child: content, child: content,
); )
: content;
}, },
); );})
}, );
));
} }
Widget generateRaw(BuildContext context, ContactBase contact) { Widget generateRaw(BuildContext context, ContactBase contact) {
final image = _getCurrencyImage(contact.type); final image = contact.type.iconPath;
final currencyIcon = image != null ? Image.asset(image, height: 24, width: 24)
: const SizedBox(height: 24, width: 24);
return GestureDetector( return GestureDetector(
onTap: () async { onTap: () async {
if (!isEditable) { if (!contactListViewModel.isEditable) {
Navigator.of(context).pop(contact); Navigator.of(context).pop(contact);
return; return;
} }
@ -131,12 +134,10 @@ class ContactListPage extends BasePage {
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[ children: <Widget>[
image ?? Offstage(), currencyIcon,
Expanded( Expanded(
child: Padding( child: Padding(
padding: image != null padding: EdgeInsets.only(left: 12),
? EdgeInsets.only(left: 12)
: EdgeInsets.only(left: 0),
child: Text( child: Text(
contact.name, contact.name,
style: TextStyle( style: TextStyle(
@ -152,69 +153,6 @@ class ContactListPage extends BasePage {
); );
} }
Image? _getCurrencyImage(CryptoCurrency currency) {
Image? image;
switch (currency) {
case CryptoCurrency.xmr:
image =
Image.asset('assets/images/monero_logo.png', height: 24, width: 24);
break;
case CryptoCurrency.ada:
image = Image.asset('assets/images/ada.png', height: 24, width: 24);
break;
case CryptoCurrency.bch:
image = Image.asset('assets/images/bch.png', height: 24, width: 24);
break;
case CryptoCurrency.bnb:
image = Image.asset('assets/images/bnb.png', height: 24, width: 24);
break;
case CryptoCurrency.btc:
image = Image.asset('assets/images/bitcoin.png', height: 24, width: 24);
break;
case CryptoCurrency.dai:
image = Image.asset('assets/images/dai.png', height: 24, width: 24);
break;
case CryptoCurrency.dash:
image = Image.asset('assets/images/dash.png', height: 24, width: 24);
break;
case CryptoCurrency.eos:
image = Image.asset('assets/images/eos.png', height: 24, width: 24);
break;
case CryptoCurrency.eth:
image = Image.asset('assets/images/eth.png', height: 24, width: 24);
break;
case CryptoCurrency.ltc:
image =
Image.asset('assets/images/litecoin.png', height: 24, width: 24);
break;
case CryptoCurrency.nano:
image = Image.asset('assets/images/nano.png', height: 24, width: 24);
break;
case CryptoCurrency.trx:
image = Image.asset('assets/images/trx.png', height: 24, width: 24);
break;
case CryptoCurrency.usdt:
image = Image.asset('assets/images/usdt.png', height: 24, width: 24);
break;
case CryptoCurrency.usdterc20:
image = Image.asset('assets/images/usdterc.png', height: 24, width: 24);
break;
case CryptoCurrency.xlm:
image = Image.asset('assets/images/xlm.png', height: 24, width: 24);
break;
case CryptoCurrency.xrp:
image = Image.asset('assets/images/xrp.png', height: 24, width: 24);
break;
case CryptoCurrency.xhv:
image = Image.asset('assets/images/haven_logo.png', height: 24, width: 24);
break;
default:
image = null;
}
return image;
}
Future<bool> showAlertDialog(BuildContext context) async { Future<bool> showAlertDialog(BuildContext context) async {
return await showPopUp<bool>( return await showPopUp<bool>(
context: context, context: context,

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

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.address_book_menu,
height: 16, width: 16), image: Image.asset('assets/images/open_book_menu.png',
handler: () => Navigator.of(context).pushNamed(Routes.walletList)), height: 16, width: 16),
WalletMenuItem( handler: () => Navigator.of(context).pushNamed(Routes.addressBook),
title: S.current.nodes, ),
image: Image.asset('assets/images/nodes_menu.png', WalletMenuItem(
height: 16, width: 16), title: S.current.security_and_backup,
handler: () => Navigator.of(context).pushNamed(Routes.nodeList)), image:
WalletMenuItem( Image.asset('assets/images/key_menu.png', height: 16, width: 16),
title: S.current.show_keys, handler: () {
image: Navigator.of(context).pushNamed(Routes.securityBackupPage);
Image.asset('assets/images/key_menu.png', height: 16, width: 16), }),
handler: () { WalletMenuItem(
Navigator.of(context).pushNamed(Routes.auth, title: S.current.privacy_settings,
arguments: (bool isAuthenticatedSuccessfully, AuthPageState auth) { image:
if (isAuthenticatedSuccessfully) { Image.asset('assets/images/privacy_menu.png', height: 16, width: 16),
auth.close(route: Routes.showKeys); handler: () {
} Navigator.of(context).pushNamed(Routes.privacyPage);
}); }),
}), 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

@ -9,12 +9,7 @@ class FilterTile extends StatelessWidget {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Container( return Container(
width: double.infinity, width: double.infinity,
padding: EdgeInsets.only( padding: EdgeInsets.symmetric(vertical: 8.0, horizontal: 24.0),
top: 18,
bottom: 18,
left: 24,
right: 24
),
child: child, child: child,
); );
} }

View file

@ -1,25 +1,26 @@
import 'dart:ui'; import 'dart:ui';
import 'package:cake_wallet/palette.dart'; import 'package:cake_wallet/palette.dart';
import 'package:cake_wallet/src/screens/dashboard/widgets/filter_tile.dart'; import 'package:cake_wallet/src/screens/dashboard/widgets/filter_tile.dart';
import 'package:cake_wallet/src/widgets/section_divider.dart';
import 'package:cake_wallet/src/widgets/standard_checkbox.dart';
import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart'; import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart';
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:cake_wallet/src/widgets/alert_background.dart'; import 'package:cake_wallet/src/widgets/alert_background.dart';
import 'package:cake_wallet/src/widgets/alert_close_button.dart'; import 'package:cake_wallet/src/widgets/alert_close_button.dart';
import 'package:cake_wallet/src/widgets/checkbox_widget.dart';
import 'package:cake_wallet/generated/i18n.dart'; import 'package:cake_wallet/generated/i18n.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
//import 'package:date_range_picker/date_range_picker.dart' as date_rage_picker; //import 'package:date_range_picker/date_range_picker.dart' as date_rage_picker;
class FilterWidget extends StatelessWidget { class FilterWidget extends StatelessWidget {
FilterWidget({required this.dashboardViewModel}); FilterWidget({required this.dashboardViewModel});
final DashboardViewModel dashboardViewModel; final DashboardViewModel dashboardViewModel;
final backVector = Image.asset('assets/images/back_vector.png', final closeIcon = Image.asset('assets/images/close.png', color: Palette.darkBlueCraiola);
color: Palette.darkBlueCraiola
);
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
const sectionDivider = const SectionDivider();
return AlertBackground( return AlertBackground(
child: Stack( child: Stack(
alignment: Alignment.center, alignment: Alignment.center,
@ -27,129 +28,82 @@ class FilterWidget extends StatelessWidget {
Column( Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: <Widget>[ children: <Widget>[
Text(
S.of(context).filters,
style: TextStyle(
color: Colors.white,
fontSize: 18,
fontWeight: FontWeight.bold,
fontFamily: 'Lato',
decoration: TextDecoration.none,
),
),
Padding( Padding(
padding: EdgeInsets.only( padding: EdgeInsets.only(left: 24, right: 24, top: 24),
left: 24,
right: 24,
top: 24
),
child: ClipRRect( child: ClipRRect(
borderRadius: BorderRadius.all(Radius.circular(14)), borderRadius: BorderRadius.all(Radius.circular(24)),
child: Container( child: Container(
color: Theme.of(context).textTheme!.bodyText1!.decorationColor!, color: Theme.of(context).textTheme!.bodyText1!.decorationColor!,
child: ListView.separated( child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
shrinkWrap: true, Padding(
physics: const NeverScrollableScrollPhysics(), padding: EdgeInsets.all(24.0),
itemCount: dashboardViewModel.filterItems.length, child: Text(
separatorBuilder: (context, _) => Container( S.of(context).filter_by,
height: 1, style: TextStyle(
color: Theme.of(context).accentTextTheme!.subtitle1!.backgroundColor!, color: Theme.of(context).primaryTextTheme.overline!.color!,
fontSize: 16,
fontFamily: 'Lato',
decoration: TextDecoration.none,
),
),
), ),
itemBuilder: (_, index1) { sectionDivider,
final title = dashboardViewModel.filterItems.keys.elementAt(index1); ListView.separated(
final section = dashboardViewModel.filterItems.values.elementAt(index1); padding: EdgeInsets.zero,
shrinkWrap: true,
return Column( physics: const NeverScrollableScrollPhysics(),
crossAxisAlignment: CrossAxisAlignment.start, itemCount: dashboardViewModel.filterItems.length,
children: <Widget>[ separatorBuilder: (context, _) => sectionDivider,
Padding( itemBuilder: (_, index1) {
padding: EdgeInsets.only( final title = dashboardViewModel.filterItems.keys.elementAt(index1);
top: 20, final section = dashboardViewModel.filterItems.values.elementAt(index1);
left: 24, return Column(
right: 24 crossAxisAlignment: CrossAxisAlignment.start,
), children: <Widget>[
child: Text( Padding(
title, padding: EdgeInsets.only(top: 20, left: 24, right: 24),
style: TextStyle( child: Text(
color: Theme.of(context).accentTextTheme!.subtitle1!.color!, title,
fontSize: 16, style: TextStyle(
fontWeight: FontWeight.w500, color: Theme.of(context).primaryTextTheme!.headline6!.color!,
fontFamily: 'Lato', fontSize: 16,
decoration: TextDecoration.none fontFamily: 'Lato',
fontWeight: FontWeight.bold,
decoration: TextDecoration.none),
), ),
), ),
), ListView.builder(
ListView.separated( padding: EdgeInsets.symmetric(vertical: 8.0),
shrinkWrap: true, shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(), physics: const NeverScrollableScrollPhysics(),
itemCount: section.length, itemCount: section.length,
separatorBuilder: (context, _) => Container( itemBuilder: (_, index2) {
height: 1, final item = section[index2];
padding: EdgeInsets.only(left: 24), final content = Observer(
color: Theme.of(context).textTheme!.bodyText1!.decorationColor!, builder: (_) => StandardCheckbox(
child: Container( value: item.value(),
height: 1, caption: item.caption,
color: Theme.of(context).accentTextTheme!.subtitle1!.backgroundColor!, gradientBackground: true,
), borderColor: Theme.of(context).dividerColor,
), iconColor: Colors.white,
itemBuilder: (_, index2) { onChanged: (value) => item.onChanged(),
));
final item = section[index2]; return FilterTile(child: content);
final content = item.onChanged != null },
? CheckboxWidget( )
value: item.value(), ],
caption: item.caption, );
onChanged: item.onChanged },
) ),
: GestureDetector( ]),
onTap: () async {
//final List<DateTime> picked =
//await date_rage_picker.showDatePicker(
// context: context,
// initialFirstDate: DateTime.now()
// .subtract(Duration(days: 1)),
// initialLastDate: (DateTime.now()),
// firstDate: DateTime(2015),
// lastDate: DateTime.now()
// .add(Duration(days: 1)));
//if (picked != null && picked.length == 2) {
// dashboardViewModel.transactionFilterStore
// .changeStartDate(picked.first);
// dashboardViewModel.transactionFilterStore
// .changeEndDate(picked.last);
//}
},
child: Padding(
padding: EdgeInsets.only(left: 32),
child: Text(
item.caption,
style: TextStyle(
color: Theme.of(context).primaryTextTheme!.headline6!.color!,
fontSize: 18,
fontFamily: 'Lato',
fontWeight: FontWeight.w500,
decoration: TextDecoration.none
),
),
),
);
return FilterTile(child: content);
},
)
],
);
},
),
), ),
), ),
), ),
], ],
), ),
AlertCloseButton(image: backVector) AlertCloseButton(image: closeIcon)
], ],
), ),
); );
} }
} }

View file

@ -6,6 +6,7 @@ import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart';
import 'package:cw_core/wallet_type.dart'; import 'package:cw_core/wallet_type.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:cake_wallet/generated/i18n.dart'; import 'package:cake_wallet/generated/i18n.dart';
import 'package:url_launcher/url_launcher.dart';
class MarketPlacePage extends StatelessWidget { class MarketPlacePage extends StatelessWidget {
@ -48,6 +49,15 @@ class MarketPlacePage extends StatelessWidget {
title: S.of(context).cake_pay_title, title: S.of(context).cake_pay_title,
subTitle: S.of(context).cake_pay_subtitle, subTitle: S.of(context).cake_pay_subtitle,
), ),
SizedBox(height: 20),
MarketPlaceItem(
onTap: () => launchUrl(
Uri.https("buy.cakepay.com"),
mode: LaunchMode.externalApplication,
),
title: S.of(context).cake_pay_web_cards_title,
subTitle: S.of(context).cake_pay_web_cards_subtitle,
),
], ],
), ),
), ),
@ -72,7 +82,7 @@ class MarketPlacePage extends StatelessWidget {
buttonAction: () => Navigator.of(context).pop()); buttonAction: () => Navigator.of(context).pop());
}); });
break; break;
default: default:
Navigator.of(context).pushNamed(Routes.ioniaWelcomePage); Navigator.of(context).pushNamed(Routes.ioniaWelcomePage);
} }
} }

View file

@ -57,7 +57,9 @@ class TransactionsPage extends StatelessWidget {
formattedDate: DateFormat('HH:mm') formattedDate: DateFormat('HH:mm')
.format(transaction.date), .format(transaction.date),
formattedAmount: item.formattedCryptoAmount, formattedAmount: item.formattedCryptoAmount,
formattedFiatAmount: item.formattedFiatAmount, formattedFiatAmount:
dashboardViewModel.balanceViewModel.isFiatDisabled
? '' : item.formattedFiatAmount,
isPending: transaction.isPending)); isPending: transaction.isPending));
} }

View file

@ -40,7 +40,6 @@ class ExchangePage extends BasePage {
final ExchangeViewModel exchangeViewModel; final ExchangeViewModel exchangeViewModel;
final depositKey = GlobalKey<ExchangeCardState>(); final depositKey = GlobalKey<ExchangeCardState>();
final receiveKey = GlobalKey<ExchangeCardState>(); final receiveKey = GlobalKey<ExchangeCardState>();
final checkBoxKey = GlobalKey<StandardCheckboxState>();
final _formKey = GlobalKey<FormState>(); final _formKey = GlobalKey<FormState>();
final _depositAmountFocus = FocusNode(); final _depositAmountFocus = FocusNode();
final _depositAddressFocus = FocusNode(); final _depositAddressFocus = FocusNode();
@ -339,7 +338,6 @@ class ExchangePage extends BasePage {
mainAxisAlignment: MainAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.start,
children: [ children: [
StandardCheckbox( StandardCheckbox(
key: checkBoxKey,
value: exchangeViewModel.isFixedRateMode, value: exchangeViewModel.isFixedRateMode,
caption: S.of(context).fixed_rate, caption: S.of(context).fixed_rate,
onChanged: (value) => onChanged: (value) =>
@ -682,12 +680,6 @@ class ExchangePage extends BasePage {
} }
}); });
reaction((_) => exchangeViewModel.isFixedRateMode, (bool value) {
if (checkBoxKey.currentState!.value != exchangeViewModel.isFixedRateMode) {
checkBoxKey.currentState!.value = exchangeViewModel.isFixedRateMode;
}
});
depositAddressController.addListener( depositAddressController.addListener(
() => exchangeViewModel.depositAddress = depositAddressController.text); () => exchangeViewModel.depositAddress = depositAddressController.text);

View file

@ -56,7 +56,7 @@ class CurrencyPickerState extends State<CurrencyPicker> {
.where((element) => .where((element) =>
(element.title != null ? element.title.toLowerCase().contains(subString.toLowerCase()) : false) || (element.title != null ? element.title.toLowerCase().contains(subString.toLowerCase()) : false) ||
(element.tag != null ? element.tag!.toLowerCase().contains(subString.toLowerCase()) : false) || (element.tag != null ? element.tag!.toLowerCase().contains(subString.toLowerCase()) : false) ||
(element.name != null ? element.name!.toLowerCase().contains(subString.toLowerCase()) : false)) (element.fullName != null ? element.fullName!.toLowerCase().contains(subString.toLowerCase()) : false))
.toList(); .toList();
return; return;
} }

View file

@ -395,7 +395,8 @@ class ExchangeCardState extends State<ExchangeCard> {
buttonColor: widget.addressButtonsColor, buttonColor: widget.addressButtonsColor,
validator: widget.addressTextFieldValidator, validator: widget.addressTextFieldValidator,
onPushPasteButton: widget.onPushPasteButton, onPushPasteButton: widget.onPushPasteButton,
onPushAddressBookButton: widget.onPushAddressBookButton onPushAddressBookButton: widget.onPushAddressBookButton,
selectedCurrency: _selectedCurrency
), ),
) )

View file

@ -8,7 +8,7 @@ import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/core/execution_state.dart'; import 'package:cake_wallet/core/execution_state.dart';
import 'package:cake_wallet/src/screens/exchange_trade/information_page.dart'; import 'package:cake_wallet/src/screens/exchange_trade/information_page.dart';
import 'package:cake_wallet/src/screens/send/widgets/confirm_sending_alert.dart'; import 'package:cake_wallet/src/screens/send/widgets/confirm_sending_alert.dart';
import 'package:cake_wallet/src/widgets/standart_list_row.dart'; import 'package:cake_wallet/src/widgets/list_row.dart';
import 'package:cake_wallet/utils/show_bar.dart'; import 'package:cake_wallet/utils/show_bar.dart';
import 'package:cake_wallet/utils/show_pop_up.dart'; import 'package:cake_wallet/utils/show_pop_up.dart';
import 'package:cake_wallet/view_model/exchange/exchange_trade_view_model.dart'; import 'package:cake_wallet/view_model/exchange/exchange_trade_view_model.dart';
@ -194,7 +194,7 @@ class ExchangeTradeState extends State<ExchangeTradeForm> {
final item = widget.exchangeTradeViewModel.items[index]; final item = widget.exchangeTradeViewModel.items[index];
final value = item.data ?? fetchingLabel; final value = item.data ?? fetchingLabel;
final content = StandartListRow( final content = ListRow(
title: item.title, title: item.title,
value: value, value: value,
valueFontSize: 14, valueFontSize: 14,
@ -378,12 +378,10 @@ class ExchangeTradeState extends State<ExchangeTradeForm> {
}); });
}, },
actionLeftButton: () => Navigator.of(context).pop(), actionLeftButton: () => Navigator.of(context).pop(),
feeFiatAmount: widget.exchangeTradeViewModel.sendViewModel.pendingTransactionFeeFiatAmount feeFiatAmount: widget.exchangeTradeViewModel
+ ' ' + widget.exchangeTradeViewModel.sendViewModel.fiat.title, .pendingTransactionFeeFiatAmountFormatted,
fiatAmountValue: widget.exchangeTradeViewModel.sendViewModel fiatAmountValue: widget.exchangeTradeViewModel
.pendingTransactionFiatAmount + .pendingTransactionFiatAmountValueFormatted,
' ' +
widget.exchangeTradeViewModel.sendViewModel.fiat.title,
outputs: widget.exchangeTradeViewModel.sendViewModel outputs: widget.exchangeTradeViewModel.sendViewModel
.outputs); .outputs);
}); });

View file

@ -1,3 +1,4 @@
import 'package:cake_wallet/core/execution_state.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/ionia/widgets/card_item.dart'; import 'package:cake_wallet/src/screens/ionia/widgets/card_item.dart';
import 'package:cake_wallet/src/widgets/base_text_form_field.dart'; import 'package:cake_wallet/src/widgets/base_text_form_field.dart';
@ -18,12 +19,11 @@ class IoniaCustomRedeemPage extends BasePage {
) : _amountFieldFocus = FocusNode(), ) : _amountFieldFocus = FocusNode(),
_amountController = TextEditingController() { _amountController = TextEditingController() {
_amountController.addListener(() { _amountController.addListener(() {
ioniaCustomRedeemViewModel.updateAmount(_amountController.text); ioniaCustomRedeemViewModel.updateAmount(_amountController.text);
}); });
} }
final IoniaCustomRedeemViewModel ioniaCustomRedeemViewModel; final IoniaCustomRedeemViewModel ioniaCustomRedeemViewModel;
@override @override
String get title => S.current.custom_redeem_amount; String get title => S.current.custom_redeem_amount;
@ -50,7 +50,7 @@ class IoniaCustomRedeemPage extends BasePage {
disableScroll: true, disableScroll: true,
config: KeyboardActionsConfig( config: KeyboardActionsConfig(
keyboardActionsPlatform: KeyboardActionsPlatform.IOS, keyboardActionsPlatform: KeyboardActionsPlatform.IOS,
keyboardBarColor: Theme.of(context).accentTextTheme!.bodyText1!.backgroundColor!, keyboardBarColor: Theme.of(context).accentTextTheme.bodyText1!.backgroundColor!,
nextFocus: false, nextFocus: false,
actions: [ actions: [
KeyboardActionsItem( KeyboardActionsItem(
@ -67,10 +67,11 @@ class IoniaCustomRedeemPage extends BasePage {
Container( Container(
padding: EdgeInsets.symmetric(horizontal: 25), padding: EdgeInsets.symmetric(horizontal: 25),
decoration: BoxDecoration( decoration: BoxDecoration(
borderRadius: BorderRadius.only(bottomLeft: Radius.circular(24), bottomRight: Radius.circular(24)), borderRadius: BorderRadius.only(
bottomLeft: Radius.circular(24), bottomRight: Radius.circular(24)),
gradient: LinearGradient(colors: [ gradient: LinearGradient(colors: [
Theme.of(context).primaryTextTheme!.subtitle1!.color!, Theme.of(context).primaryTextTheme.subtitle1!.color!,
Theme.of(context).primaryTextTheme!.subtitle1!.decorationColor!, Theme.of(context).primaryTextTheme.subtitle1!.decorationColor!,
], begin: Alignment.topLeft, end: Alignment.bottomRight), ], begin: Alignment.topLeft, end: Alignment.bottomRight),
), ),
child: Column( child: Column(
@ -85,11 +86,11 @@ class IoniaCustomRedeemPage extends BasePage {
inputFormatters: [FilteringTextInputFormatter.deny(RegExp('[\-|\ ]'))], inputFormatters: [FilteringTextInputFormatter.deny(RegExp('[\-|\ ]'))],
hintText: '1000', hintText: '1000',
placeholderTextStyle: TextStyle( placeholderTextStyle: TextStyle(
color: Theme.of(context).primaryTextTheme!.headline5!.color!, color: Theme.of(context).primaryTextTheme.headline5!.color!,
fontWeight: FontWeight.w500, fontWeight: FontWeight.w500,
fontSize: 36, fontSize: 36,
), ),
borderColor: Theme.of(context).primaryTextTheme!.headline5!.color!, borderColor: Theme.of(context).primaryTextTheme.headline5!.color!,
textColor: Colors.white, textColor: Colors.white,
textStyle: TextStyle( textStyle: TextStyle(
color: Colors.white, color: Colors.white,
@ -114,14 +115,17 @@ class IoniaCustomRedeemPage extends BasePage {
), ),
), ),
SizedBox(height: 8), SizedBox(height: 8),
Observer(builder: (_)=> Observer(
!ioniaCustomRedeemViewModel.disableRedeem ? builder: (_) => !ioniaCustomRedeemViewModel.disableRedeem
Center( ? Center(
child: Text('\$${giftCard.remainingAmount} - \$${ioniaCustomRedeemViewModel.amount} = \$${ioniaCustomRedeemViewModel.formattedRemaining} ${S.of(context).remaining}', child: Text(
style: TextStyle( '\$${giftCard.remainingAmount} - \$${ioniaCustomRedeemViewModel.amount} = \$${ioniaCustomRedeemViewModel.formattedRemaining} ${S.of(context).remaining}',
color: Theme.of(context).primaryTextTheme!.headline5!.color!, style: TextStyle(
),), color: Theme.of(context).primaryTextTheme.headline5!.color!,
) : SizedBox.shrink(), ),
),
)
: SizedBox.shrink(),
), ),
SizedBox(height: 24), SizedBox(height: 24),
], ],
@ -131,30 +135,37 @@ class IoniaCustomRedeemPage extends BasePage {
padding: const EdgeInsets.all(24.0), padding: const EdgeInsets.all(24.0),
child: CardItem( child: CardItem(
title: giftCard.legalName, title: giftCard.legalName,
backgroundColor: Theme.of(context).accentTextTheme!.headline1!.backgroundColor!.withOpacity(0.1), backgroundColor: Theme.of(context)
.accentTextTheme
.headline1!
.backgroundColor!
.withOpacity(0.1),
discount: giftCard.remainingAmount, discount: giftCard.remainingAmount,
isAmount: true, isAmount: true,
discountBackground: AssetImage('assets/images/red_badge_discount.png'), discountBackground: AssetImage('assets/images/red_badge_discount.png'),
titleColor: Theme.of(context).accentTextTheme!.headline1!.backgroundColor!, titleColor: Theme.of(context).accentTextTheme.headline1!.backgroundColor!,
subtitleColor: Theme.of(context).hintColor, subtitleColor: Theme.of(context).hintColor,
subTitle: S.of(context).online, subTitle: S.of(context).online,
logoUrl: giftCard.logoUrl, logoUrl: giftCard.logoUrl,
), ),
), ),
], ],
), ),
bottomSection: Column( bottomSection: Column(
children: [ children: [
Padding( Observer(
padding: EdgeInsets.only(bottom: 12), builder: (_) => Padding(
child: PrimaryButton( padding: EdgeInsets.only(bottom: 12),
onPressed: () { child: LoadingPrimaryButton(
Navigator.of(context).pop(_amountController.text); isLoading: ioniaCustomRedeemViewModel.redeemState is IsExecutingState,
}, isDisabled: ioniaCustomRedeemViewModel.disableRedeem,
isDisabled: ioniaCustomRedeemViewModel.disableRedeem, text: S.of(context).add_custom_redemption,
text: S.of(context).add_custom_redemption, color: Theme.of(context).accentTextTheme.bodyText1!.color!,
color: Theme.of(context).accentTextTheme!.bodyText1!.color!, textColor: Colors.white,
textColor: Colors.white, onPressed: () => ioniaCustomRedeemViewModel.addCustomRedeem().then((value) {
Navigator.of(context).pop(ioniaCustomRedeemViewModel.remaining.toString());
}),
),
), ),
), ),
SizedBox(height: 30), SizedBox(height: 30),

View file

@ -11,6 +11,7 @@ import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart';
import 'package:cake_wallet/typography.dart'; import 'package:cake_wallet/typography.dart';
import 'package:cake_wallet/utils/show_bar.dart'; import 'package:cake_wallet/utils/show_bar.dart';
import 'package:cake_wallet/utils/show_pop_up.dart'; import 'package:cake_wallet/utils/show_pop_up.dart';
import 'package:cake_wallet/utils/route_aware.dart';
import 'package:cake_wallet/view_model/ionia/ionia_gift_card_details_view_model.dart'; import 'package:cake_wallet/view_model/ionia/ionia_gift_card_details_view_model.dart';
import 'package:device_display_brightness/device_display_brightness.dart'; import 'package:device_display_brightness/device_display_brightness.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
@ -32,7 +33,7 @@ class IoniaGiftCardDetailPage extends BasePage {
final _backButton = Icon( final _backButton = Icon(
Icons.arrow_back_ios, Icons.arrow_back_ios,
color: Theme.of(context).primaryTextTheme!.headline6!.color!, color: Theme.of(context).primaryTextTheme.headline6!.color!,
size: 16, size: 16,
); );
return Padding( return Padding(
@ -43,14 +44,11 @@ class IoniaGiftCardDetailPage extends BasePage {
child: ButtonTheme( child: ButtonTheme(
minWidth: double.minPositive, minWidth: double.minPositive,
child: TextButton( child: TextButton(
// FIX-ME: Style // FIX-ME: Style
//highlightColor: Colors.transparent, //highlightColor: Colors.transparent,
//splashColor: Colors.transparent, //splashColor: Colors.transparent,
//padding: EdgeInsets.all(0), //padding: EdgeInsets.all(0),
onPressed: () { onPressed: ()=> onClose(context),
onClose(context);
DeviceDisplayBrightness.setBrightness(viewModel.brightness);
},
child: _backButton), child: _backButton),
), ),
), ),
@ -61,13 +59,13 @@ class IoniaGiftCardDetailPage extends BasePage {
Widget middle(BuildContext context) { Widget middle(BuildContext context) {
return Text( return Text(
viewModel.giftCard.legalName, viewModel.giftCard.legalName,
style: textMediumSemiBold(color: Theme.of(context).accentTextTheme!.headline1!.backgroundColor!), style:
textMediumSemiBold(color: Theme.of(context).accentTextTheme.headline1!.backgroundColor!),
); );
} }
@override @override
Widget body(BuildContext context) { Widget body(BuildContext context) {
viewModel.increaseBrightness();
reaction((_) => viewModel.redeemState, (ExecutionState state) { reaction((_) => viewModel.redeemState, (ExecutionState state) {
if (state is FailureState) { if (state is FailureState) {
WidgetsBinding.instance.addPostFrameCallback((_) { WidgetsBinding.instance.addPostFrameCallback((_) {
@ -84,7 +82,12 @@ class IoniaGiftCardDetailPage extends BasePage {
} }
}); });
return ScrollableWithBottomSection( return RouteAwareWidget(
pushToWidget: ()=> viewModel.increaseBrightness(),
pushToNextWidget: ()=> DeviceDisplayBrightness.setBrightness(viewModel.brightness),
popNextWidget: ()=> viewModel.increaseBrightness(),
popWidget: ()=> DeviceDisplayBrightness.setBrightness(viewModel.brightness),
child: ScrollableWithBottomSection(
contentPadding: EdgeInsets.all(24), contentPadding: EdgeInsets.all(24),
content: Column( content: Column(
children: [ children: [
@ -102,20 +105,21 @@ class IoniaGiftCardDetailPage extends BasePage {
title: S.of(context).gift_card_number, title: S.of(context).gift_card_number,
subTitle: viewModel.giftCard.cardNumber, subTitle: viewModel.giftCard.cardNumber,
), ),
if (viewModel.giftCard.cardPin?.isNotEmpty ?? false) if (viewModel.giftCard.cardPin.isNotEmpty) ...[
...[Divider(height: 30), Divider(height: 30),
buildIoniaTile( buildIoniaTile(
context, context,
title: S.of(context).pin_number, title: S.of(context).pin_number,
subTitle: viewModel.giftCard.cardPin, subTitle: viewModel.giftCard.cardPin,
)], )
],
Divider(height: 30), Divider(height: 30),
Observer(builder: (_) => Observer(
buildIoniaTile( builder: (_) => buildIoniaTile(
context, context,
title: S.of(context).amount, title: S.of(context).amount,
subTitle: viewModel.remainingAmount.toStringAsFixed(2) ?? '0.00', subTitle: viewModel.remainingAmount.toStringAsFixed(2),
)), )),
Divider(height: 50), Divider(height: 50),
TextIconButton( TextIconButton(
label: S.of(context).how_to_use_card, label: S.of(context).how_to_use_card,
@ -130,29 +134,28 @@ class IoniaGiftCardDetailPage extends BasePage {
if (!viewModel.giftCard.isEmpty) { if (!viewModel.giftCard.isEmpty) {
return Column( return Column(
children: [ children: [
//PrimaryButton( PrimaryButton(
// onPressed: () async { onPressed: () async {
// final amount = await Navigator.of(context) await Navigator.of(context).pushNamed(
// .pushNamed(Routes.ioniaMoreOptionsPage, arguments: [viewModel.giftCard]) as String; Routes.ioniaMoreOptionsPage,
// if (amount != null) { arguments: [viewModel.giftCard]) as String?;
// viewModel.updateRemaining(double.parse(amount)); viewModel.refeshCard();
// } },
// }, text: S.of(context).more_options,
// text: S.of(context).more_options, color: Theme.of(context).accentTextTheme.caption!.color!,
// color: Theme.of(context).accentTextTheme!.caption!.color!, textColor: Theme.of(context).primaryTextTheme.headline6!.color!,
// textColor: Theme.of(context).primaryTextTheme!.headline6!.color!, ),
//), SizedBox(height: 12),
//SizedBox(height: 12),
LoadingPrimaryButton( LoadingPrimaryButton(
isLoading: viewModel.redeemState is IsExecutingState, isLoading: viewModel.redeemState is IsExecutingState,
onPressed: () => viewModel.redeem().then( onPressed: () => viewModel.redeem().then(
(_) { (_) {
Navigator.of(context) Navigator.of(context).pushNamedAndRemoveUntil(
.pushNamedAndRemoveUntil(Routes.ioniaManageCardsPage, (route) => route.isFirst); Routes.ioniaManageCardsPage, (route) => route.isFirst);
}, },
), ),
text: S.of(context).mark_as_redeemed, text: S.of(context).mark_as_redeemed,
color: Theme.of(context).accentTextTheme!.bodyText1!.color!, color: Theme.of(context).accentTextTheme.bodyText1!.color!,
textColor: Colors.white, textColor: Colors.white,
), ),
], ],
@ -163,17 +166,16 @@ class IoniaGiftCardDetailPage extends BasePage {
}, },
), ),
), ),
); ));
} }
Widget buildIoniaTile(BuildContext context, {required String title, required String subTitle}) { Widget buildIoniaTile(BuildContext context, {required String title, required String subTitle}) {
return IoniaTile( return IoniaTile(
title: title, title: title,
subTitle: subTitle, subTitle: subTitle,
onTap: () { onTap: () {
Clipboard.setData(ClipboardData(text: subTitle)); Clipboard.setData(ClipboardData(text: subTitle));
showBar<void>(context, showBar<void>(context, S.of(context).transaction_details_copied(title));
S.of(context).transaction_details_copied(title));
}); });
} }
@ -184,10 +186,10 @@ class IoniaGiftCardDetailPage extends BasePage {
showPopUp<void>( showPopUp<void>(
context: context, context: context,
builder: (BuildContext context) { builder: (BuildContext context) {
return IoniaAlertModal( return IoniaAlertModal(
title: S.of(context).how_to_use_card, title: S.of(context).how_to_use_card,
content: Column( content: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: viewModel.giftCard.instructions children: viewModel.giftCard.instructions
.map((instruction) { .map((instruction) {
return [ return [
@ -196,13 +198,13 @@ class IoniaGiftCardDetailPage extends BasePage {
child: Text( child: Text(
instruction.header, instruction.header,
style: textLargeSemiBold( style: textLargeSemiBold(
color: Theme.of(context).textTheme!.headline3!.color!, color: Theme.of(context).textTheme.headline3!.color!,
), ),
)), )),
Text( Text(
instruction.body, instruction.body,
style: textMedium( style: textMedium(
color: Theme.of(context).textTheme!.headline3!.color!, color: Theme.of(context).textTheme.headline3!.color!,
), ),
) )
]; ];
@ -210,7 +212,7 @@ class IoniaGiftCardDetailPage extends BasePage {
.expand((e) => e) .expand((e) => e)
.toList()), .toList()),
actionTitle: S.of(context).send_got_it, actionTitle: S.of(context).send_got_it,
); );
}); });
} }
} }

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

@ -5,7 +5,6 @@ import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/typography.dart'; import 'package:cake_wallet/typography.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
class IoniaMoreOptionsPage extends BasePage { class IoniaMoreOptionsPage extends BasePage {
IoniaMoreOptionsPage(this.giftCard); IoniaMoreOptionsPage(this.giftCard);
@ -16,7 +15,7 @@ class IoniaMoreOptionsPage extends BasePage {
return Text( return Text(
S.current.more_options, S.current.more_options,
style: textMediumSemiBold( style: textMediumSemiBold(
color: Theme.of(context).accentTextTheme!.headline1!.backgroundColor!, color: Theme.of(context).accentTextTheme.headline1!.backgroundColor!,
), ),
); );
} }
@ -27,40 +26,45 @@ class IoniaMoreOptionsPage extends BasePage {
padding: const EdgeInsets.all(16.0), padding: const EdgeInsets.all(16.0),
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch, crossAxisAlignment: CrossAxisAlignment.stretch,
children: [ children: [
SizedBox(height: 10,), SizedBox(
Center(child: Text(S.of(context).choose_from_available_options, style: textMedium( height: 10,
color: Theme.of(context).primaryTextTheme!.headline6!.color!, ),
),)), Center(
SizedBox(height: 40,), child: Text(
InkWell( S.of(context).choose_from_available_options,
onTap: () async { style: textMedium(
final amount = await Navigator.of(context).pushNamed(Routes.ioniaCustomRedeemPage, arguments: [giftCard]) as String; color: Theme.of(context).primaryTextTheme.headline6!.color!,
if(amount.isNotEmpty){ ),
Navigator.pop(context, amount); ),
} ),
}, SizedBox(height: 40),
child: _GradiantContainer( InkWell(
content: Padding( onTap: () async {
padding: const EdgeInsets.only(top: 24, left: 20, right: 24, bottom: 50), final amount = await Navigator.of(context)
child: Text( .pushNamed(Routes.ioniaCustomRedeemPage, arguments: [giftCard]) as String?;
S.of(context).custom_redeem_amount, if (amount != null && amount.isNotEmpty) {
style: textXLargeSemiBold(), Navigator.pop(context);
), }
), },
), child: _GradiantContainer(
) content: Padding(
], padding: const EdgeInsets.only(top: 24, left: 20, right: 24, bottom: 50),
), child: Text(
S.of(context).custom_redeem_amount,
style: textXLargeSemiBold(),
),
),
),
)
],
),
); );
} }
} }
class _GradiantContainer extends StatelessWidget { class _GradiantContainer extends StatelessWidget {
const _GradiantContainer({ const _GradiantContainer({Key? key, required this.content}) : super(key: key);
Key? key,
required this.content
}) : super(key: key);
final Widget content; final Widget content;

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,4 +1,5 @@
import 'dart:ui'; import 'dart:ui';
import 'package:cake_wallet/src/widgets/section_divider.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:flutter_mobx/flutter_mobx.dart'; import 'package:flutter_mobx/flutter_mobx.dart';
@ -84,10 +85,7 @@ class MoneroAccountListPage extends StatelessWidget {
padding: EdgeInsets.zero, padding: EdgeInsets.zero,
controller: controller, controller: controller,
separatorBuilder: (context, index) => separatorBuilder: (context, index) =>
Container( const SectionDivider(),
height: 1,
color: Theme.of(context).dividerColor,
),
itemCount: accounts.length ?? 0, itemCount: accounts.length ?? 0,
itemBuilder: (context, index) { itemBuilder: (context, index) {
final account = accounts[index]; final account = accounts[index];

View file

@ -0,0 +1,111 @@
import 'package:cake_wallet/src/screens/nodes/widgets/node_form.dart';
import 'package:cake_wallet/src/screens/settings/widgets/settings_switcher_cell.dart';
import 'package:cake_wallet/view_model/node_list/node_create_or_edit_view_model.dart';
import 'package:cake_wallet/view_model/advanced_privacy_settings_view_model.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
import 'package:flutter/material.dart';
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/src/screens/base_page.dart';
import 'package:cake_wallet/src/widgets/primary_button.dart';
import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart';
class AdvancedPrivacySettingsPage extends BasePage {
AdvancedPrivacySettingsPage(this.advancedPrivacySettingsViewModel, this.nodeViewModel);
final AdvancedPrivacySettingsViewModel advancedPrivacySettingsViewModel;
final NodeCreateOrEditViewModel nodeViewModel;
@override
String get title => S.current.privacy_settings;
@override
Widget body(BuildContext context) =>
AdvancedPrivacySettingsBody(advancedPrivacySettingsViewModel, nodeViewModel);
}
class AdvancedPrivacySettingsBody extends StatefulWidget {
const AdvancedPrivacySettingsBody(this.privacySettingsViewModel, this.nodeViewModel, {Key? key})
: super(key: key);
final AdvancedPrivacySettingsViewModel privacySettingsViewModel;
final NodeCreateOrEditViewModel nodeViewModel;
@override
_AdvancedPrivacySettingsBodyState createState() => _AdvancedPrivacySettingsBodyState();
}
class _AdvancedPrivacySettingsBodyState extends State<AdvancedPrivacySettingsBody> {
_AdvancedPrivacySettingsBodyState();
final _formKey = GlobalKey<FormState>();
@override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.only(top: 24),
child: ScrollableWithBottomSection(
contentPadding: EdgeInsets.only(bottom: 24),
content: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
...widget.privacySettingsViewModel.settings.map(
(item) => Observer(
builder: (_) => SettingsSwitcherCell(
title: item.title,
value: item.value(),
onValueChange: item.onValueChange,
),
),
),
Observer(
builder: (_) {
if (widget.privacySettingsViewModel.addCustomNode) {
return Padding(
padding: EdgeInsets.only(left: 24, right: 24, top: 24),
child: NodeForm(
formKey: _formKey,
nodeViewModel: widget.nodeViewModel,
),
);
}
return const SizedBox();
},
),
],
),
bottomSectionPadding: EdgeInsets.all(24),
bottomSection: Column(
children: [
LoadingPrimaryButton(
onPressed: () {
if (widget.privacySettingsViewModel.addCustomNode) {
if (_formKey.currentState != null && !_formKey.currentState!.validate()) {
return;
}
widget.nodeViewModel.save(saveAsCurrent: true);
}
Navigator.pop(context);
},
text: S.of(context).continue_text,
color: Theme.of(context).accentTextTheme.bodyText1!.color!,
textColor: Colors.white,
),
const SizedBox(height: 25),
Padding(
padding: EdgeInsets.symmetric(horizontal: MediaQuery.of(context).size.width * 0.15),
child: Text(
S.of(context).settings_can_be_changed_later,
textAlign: TextAlign.center,
style: TextStyle(
color: Theme.of(context).accentTextTheme.headline2?.color,
),
),
),
],
),
),
);
}
}

View file

@ -200,18 +200,30 @@ class _WalletNameFormState extends State<WalletNameForm> {
] ]
]), ]),
bottomSectionPadding: bottomSectionPadding:
EdgeInsets.only(left: 24, right: 24, bottom: 24), EdgeInsets.all(24),
bottomSection: Observer( bottomSection: Column(
builder: (context) { children: [
return LoadingPrimaryButton( Observer(
onPressed: _confirmForm, builder: (context) {
text: S.of(context).seed_language_next, return LoadingPrimaryButton(
color: Colors.green, onPressed: _confirmForm,
textColor: Colors.white, text: S.of(context).seed_language_next,
isLoading: _walletNewVM.state is IsExecutingState, color: Colors.green,
isDisabled: _walletNewVM.name.isEmpty, textColor: Colors.white,
); isLoading: _walletNewVM.state is IsExecutingState,
}, isDisabled: _walletNewVM.name.isEmpty,
);
},
),
const SizedBox(height: 25),
GestureDetector(
onTap: () {
Navigator.of(context)
.pushNamed(Routes.advancedPrivacySettings, arguments: _walletNewVM.type);
},
child: Text(S.of(context).advanced_privacy_settings),
),
],
)), )),
); );
} }

View file

@ -1,16 +1,13 @@
import 'package:cake_wallet/core/execution_state.dart'; import 'package:cake_wallet/core/execution_state.dart';
import 'package:cake_wallet/src/screens/nodes/widgets/node_form.dart';
import 'package:cake_wallet/src/widgets/alert_with_one_action.dart'; import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
import 'package:cake_wallet/src/widgets/standard_checkbox.dart';
import 'package:cake_wallet/utils/show_pop_up.dart'; import 'package:cake_wallet/utils/show_pop_up.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.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/generated/i18n.dart'; import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/core/node_address_validator.dart';
import 'package:cake_wallet/core/node_port_validator.dart';
import 'package:cake_wallet/src/widgets/primary_button.dart'; import 'package:cake_wallet/src/widgets/primary_button.dart';
import 'package:cake_wallet/src/widgets/base_text_form_field.dart';
import 'package:cake_wallet/src/screens/base_page.dart'; import 'package:cake_wallet/src/screens/base_page.dart';
import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart'; import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart';
import 'package:cake_wallet/view_model/node_list/node_create_or_edit_view_model.dart'; import 'package:cake_wallet/view_model/node_list/node_create_or_edit_view_model.dart';
@ -108,76 +105,10 @@ class NodeCreateOrEditPage extends BasePage {
padding: EdgeInsets.only(left: 24, right: 24), padding: EdgeInsets.only(left: 24, right: 24),
child: ScrollableWithBottomSection( child: ScrollableWithBottomSection(
contentPadding: EdgeInsets.only(bottom: 24.0), contentPadding: EdgeInsets.only(bottom: 24.0),
content: Form( content: NodeForm(
key: _formKey, formKey: _formKey,
child: Column( nodeViewModel: nodeCreateOrEditViewModel,
children: <Widget>[ ),
Row(
children: <Widget>[
Expanded(
child: BaseTextFormField(
controller: _addressController,
hintText: S.of(context).node_address,
validator: NodeAddressValidator(),
)
)
],
),
SizedBox(height: 10.0),
Row(
children: <Widget>[
Expanded(
child: BaseTextFormField(
controller: _portController,
hintText: S.of(context).node_port,
keyboardType: TextInputType.numberWithOptions(
signed: false, decimal: false),
validator: NodePortValidator(),
)
)
],
),
SizedBox(height: 10.0),
if (nodeCreateOrEditViewModel.hasAuthCredentials) ...[
Row(
children: <Widget>[
Expanded(
child: BaseTextFormField(
controller: _loginController,
hintText: S.of(context).login,
)
)
],
),
SizedBox(height: 10.0),
Row(
children: <Widget>[
Expanded(
child: BaseTextFormField(
controller: _passwordController,
hintText: S.of(context).password,
)
)
],
),
Padding(
padding: EdgeInsets.only(top: 20),
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
mainAxisSize: MainAxisSize.max,
children: [
Observer(
builder: (_) => StandardCheckbox(
value: nodeCreateOrEditViewModel.useSSL,
onChanged: (value) =>
nodeCreateOrEditViewModel.useSSL = value,
caption: S.of(context).use_ssl,
))
],
))
]
],
)),
bottomSectionPadding: EdgeInsets.only(bottom: 24), bottomSectionPadding: EdgeInsets.only(bottom: 24),
bottomSection: Observer( bottomSection: Observer(
builder: (_) => Row( builder: (_) => Row(

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

@ -0,0 +1,151 @@
import 'package:cake_wallet/core/node_address_validator.dart';
import 'package:cake_wallet/core/node_port_validator.dart';
import 'package:cake_wallet/src/widgets/base_text_form_field.dart';
import 'package:cake_wallet/src/widgets/standard_checkbox.dart';
import 'package:cake_wallet/view_model/node_list/node_create_or_edit_view_model.dart';
import 'package:flutter/material.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
import 'package:cake_wallet/generated/i18n.dart';
import 'package:mobx/mobx.dart';
class NodeForm extends StatelessWidget {
NodeForm({
required this.nodeViewModel,
required this.formKey,
}) : _addressController = TextEditingController(),
_portController = TextEditingController(),
_loginController = TextEditingController(),
_passwordController = TextEditingController() {
reaction((_) => nodeViewModel.address, (String address) {
if (address != _addressController.text) {
_addressController.text = address;
}
});
reaction((_) => nodeViewModel.port, (String port) {
if (port != _portController.text) {
_portController.text = port;
}
});
if (nodeViewModel.hasAuthCredentials) {
reaction((_) => nodeViewModel.login, (String login) {
if (login != _loginController.text) {
_loginController.text = login;
}
});
reaction((_) => nodeViewModel.password, (String password) {
if (password != _passwordController.text) {
_passwordController.text = password;
}
});
}
_addressController
.addListener(() => nodeViewModel.address = _addressController.text);
_portController
.addListener(() => nodeViewModel.port = _portController.text);
_loginController
.addListener(() => nodeViewModel.login = _loginController.text);
_passwordController
.addListener(() => nodeViewModel.password = _passwordController.text);
}
final NodeCreateOrEditViewModel nodeViewModel;
final GlobalKey<FormState> formKey;
final TextEditingController _addressController;
final TextEditingController _portController;
final TextEditingController _loginController;
final TextEditingController _passwordController;
@override
Widget build(BuildContext context) {
return Form(
key: formKey,
child: Column(
children: <Widget>[
Row(
children: <Widget>[
Expanded(
child: BaseTextFormField(
controller: _addressController,
hintText: S.of(context).node_address,
validator: NodeAddressValidator(),
),
)
],
),
SizedBox(height: 10.0),
Row(
children: <Widget>[
Expanded(
child: BaseTextFormField(
controller: _portController,
hintText: S.of(context).node_port,
keyboardType: TextInputType.numberWithOptions(
signed: false, decimal: false),
validator: NodePortValidator(),
))
],
),
SizedBox(height: 10.0),
if (nodeViewModel.hasAuthCredentials) ...[
Row(
children: <Widget>[
Expanded(
child: BaseTextFormField(
controller: _loginController,
hintText: S.of(context).login,
))
],
),
SizedBox(height: 10.0),
Row(
children: <Widget>[
Expanded(
child: BaseTextFormField(
controller: _passwordController,
hintText: S.of(context).password,
))
],
),
Padding(
padding: EdgeInsets.only(top: 20),
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
mainAxisSize: MainAxisSize.max,
children: [
Observer(
builder: (_) => StandardCheckbox(
value: nodeViewModel.useSSL,
onChanged: (value) => nodeViewModel.useSSL = value,
caption: S.of(context).use_ssl,
),
)
],
),
),
Padding(
padding: EdgeInsets.only(top: 20),
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
mainAxisSize: MainAxisSize.max,
children: [
Observer(
builder: (_) => StandardCheckbox(
value: nodeViewModel.trusted,
onChanged: (value) => nodeViewModel.trusted = value,
caption: S.of(context).trusted,
),
),
],
),
),
]
],
),
);
}
}

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

@ -7,7 +7,7 @@ import 'package:flutter/services.dart';
import 'package:flutter_mobx/flutter_mobx.dart'; import 'package:flutter_mobx/flutter_mobx.dart';
import 'package:cake_wallet/generated/i18n.dart'; import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/src/screens/base_page.dart'; import 'package:cake_wallet/src/screens/base_page.dart';
import 'package:cake_wallet/src/widgets/standart_list_row.dart'; import 'package:cake_wallet/src/widgets/list_row.dart';
import 'package:cake_wallet/src/screens/trade_details/track_trade_list_item.dart'; import 'package:cake_wallet/src/screens/trade_details/track_trade_list_item.dart';
class OrderDetailsPage extends BasePage { class OrderDetailsPage extends BasePage {
@ -57,7 +57,7 @@ class OrderDetailsPageBodyState extends State<OrderDetailsPageBody> {
if (item is TrackTradeListItem) { if (item is TrackTradeListItem) {
return GestureDetector( return GestureDetector(
onTap: item.onTap, onTap: item.onTap,
child: StandartListRow( child: ListRow(
title: '${item.title}', value: '${item.value}')); title: '${item.title}', value: '${item.value}'));
} else { } else {
return GestureDetector( return GestureDetector(
@ -65,7 +65,7 @@ class OrderDetailsPageBodyState extends State<OrderDetailsPageBody> {
Clipboard.setData(ClipboardData(text: '${item.value}')); Clipboard.setData(ClipboardData(text: '${item.value}'));
showBar<void>(context, S.of(context).copied_to_clipboard); showBar<void>(context, S.of(context).copied_to_clipboard);
}, },
child: StandartListRow( child: ListRow(
title: '${item.title}', value: '${item.value}')); title: '${item.title}', value: '${item.value}'));
} }
}); });

View file

@ -1,4 +1,5 @@
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/section_divider.dart';
import 'package:cake_wallet/themes/theme_base.dart'; import 'package:cake_wallet/themes/theme_base.dart';
import 'package:cake_wallet/utils/show_pop_up.dart'; import 'package:cake_wallet/utils/show_pop_up.dart';
import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart'; import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart';
@ -135,8 +136,7 @@ class ReceivePage extends BasePage {
Observer( Observer(
builder: (_) => ListView.separated( builder: (_) => ListView.separated(
padding: EdgeInsets.all(0), padding: EdgeInsets.all(0),
separatorBuilder: (context, _) => Container( separatorBuilder: (context, _) => const SectionDivider(),
height: 1, color: Theme.of(context).dividerColor),
shrinkWrap: true, shrinkWrap: true,
physics: NeverScrollableScrollPhysics(), physics: NeverScrollableScrollPhysics(),
itemCount: addressListViewModel.items.length, itemCount: addressListViewModel.items.length,

View file

@ -1,23 +1,28 @@
import 'dart:async'; import 'dart:async';
import 'package:cake_wallet/core/auth_service.dart';
import 'package:cake_wallet/utils/payment_request.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/src/screens/auth/auth_page.dart'; import 'package:cake_wallet/src/screens/auth/auth_page.dart';
import 'package:cake_wallet/store/app_store.dart'; import 'package:cake_wallet/store/app_store.dart';
import 'package:cake_wallet/store/authentication_store.dart'; import 'package:cake_wallet/store/authentication_store.dart';
import 'package:cake_wallet/entities/qr_scanner.dart'; import 'package:cake_wallet/entities/qr_scanner.dart';
import 'package:uni_links/uni_links.dart';
class Root extends StatefulWidget { class Root extends StatefulWidget {
Root( Root({
{required Key key, required Key key,
required this.authenticationStore, required this.authenticationStore,
required this.appStore, required this.appStore,
required this.child, required this.child,
required this.navigatorKey}) required this.navigatorKey,
: super(key: key); required this.authService,
}) : super(key: key);
final AuthenticationStore authenticationStore; final AuthenticationStore authenticationStore;
final AppStore appStore; final AppStore appStore;
final GlobalKey<NavigatorState> navigatorKey; final GlobalKey<NavigatorState> navigatorKey;
final AuthService authService;
final Widget child; final Widget child;
@override @override
@ -26,22 +31,56 @@ class Root extends StatefulWidget {
class RootState extends State<Root> with WidgetsBindingObserver { class RootState extends State<Root> with WidgetsBindingObserver {
RootState() RootState()
: _isInactiveController = StreamController<bool>.broadcast(), : _isInactiveController = StreamController<bool>.broadcast(),
_isInactive = false, _isInactive = false,
_postFrameCallback = false; _requestAuth = true,
_postFrameCallback = false;
Stream<bool> get isInactive => _isInactiveController.stream; Stream<bool> get isInactive => _isInactiveController.stream;
StreamController<bool> _isInactiveController; StreamController<bool> _isInactiveController;
bool _isInactive; bool _isInactive;
bool _postFrameCallback; bool _postFrameCallback;
bool _requestAuth;
StreamSubscription<Uri?>? stream;
Uri? launchUri;
@override @override
void initState() { void initState() {
_requestAuth = widget.authService.requireAuth();
_isInactiveController = StreamController<bool>.broadcast(); _isInactiveController = StreamController<bool>.broadcast();
_isInactive = false; _isInactive = false;
_postFrameCallback = false; _postFrameCallback = false;
WidgetsBinding.instance.addObserver(this); WidgetsBinding.instance.addObserver(this);
super.initState(); super.initState();
initUniLinks();
}
@override
void dispose() {
stream?.cancel();
super.dispose();
}
/// handle app links while the app is already started
/// whether its in the foreground or in the background.
Future<void> initUniLinks() async {
try {
stream = uriLinkStream.listen((Uri? uri) {
handleDeepLinking(uri);
});
handleDeepLinking(await getInitialUri());
} catch (e) {
print(e);
}
}
void handleDeepLinking(Uri? uri) {
if (uri == null || !mounted) return;
launchUri = uri;
} }
@override @override
@ -52,11 +91,15 @@ class RootState extends State<Root> with WidgetsBindingObserver {
return; return;
} }
if (!_isInactive && if (!_isInactive && widget.authenticationStore.state == AuthenticationState.allowed) {
widget.authenticationStore.state == AuthenticationState.allowed) {
setState(() => _setInactive(true)); setState(() => _setInactive(true));
} }
break;
case AppLifecycleState.resumed:
setState(() {
_requestAuth = widget.authService.requireAuth();
});
break; break;
default: default:
break; break;
@ -65,7 +108,7 @@ class RootState extends State<Root> with WidgetsBindingObserver {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
if (_isInactive && !_postFrameCallback) { if (_isInactive && !_postFrameCallback && _requestAuth) {
_postFrameCallback = true; _postFrameCallback = true;
WidgetsBinding.instance.addPostFrameCallback((_) { WidgetsBinding.instance.addPostFrameCallback((_) {
widget.navigatorKey.currentState?.pushNamed(Routes.unlock, widget.navigatorKey.currentState?.pushNamed(Routes.unlock,
@ -75,9 +118,19 @@ class RootState extends State<Root> with WidgetsBindingObserver {
} }
_reset(); _reset();
auth.close(); auth.close(
route: launchUri != null ? Routes.send : null,
arguments: PaymentRequest.fromUri(launchUri),
);
launchUri = null;
}); });
}); });
} else if (launchUri != null) {
widget.navigatorKey.currentState?.pushNamed(
Routes.send,
arguments: PaymentRequest.fromUri(launchUri),
);
launchUri = null;
} }
return WillPopScope(onWillPop: () async => false, child: widget.child); return WillPopScope(onWillPop: () async => false, child: widget.child);

View file

@ -1,13 +1,11 @@
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';
import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart'; import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart';
import 'package:cake_wallet/src/widgets/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/utils/payment_request.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 +26,15 @@ 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,
this.initialPaymentRequest,
}) : _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 ; final PaymentRequest? initialPaymentRequest;
bool _effectsInstalled = false; bool _effectsInstalled = false;
@ -55,7 +55,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();
} }
@ -121,6 +121,7 @@ class SendPage extends BasePage {
key: output.key, key: output.key,
output: output, output: output,
sendViewModel: sendViewModel, sendViewModel: sendViewModel,
initialPaymentRequest: initialPaymentRequest,
); );
}); });
}, },
@ -236,7 +237,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();
@ -386,16 +387,10 @@ class SendPage extends BasePage {
amount: S.of(context).send_amount, amount: S.of(context).send_amount,
amountValue: amountValue:
sendViewModel.pendingTransaction!.amountFormatted, sendViewModel.pendingTransaction!.amountFormatted,
fiatAmountValue: fiatAmountValue: sendViewModel.pendingTransactionFiatAmountFormatted,
sendViewModel.pendingTransactionFiatAmount +
' ' +
sendViewModel.fiat.title,
fee: S.of(context).send_fee, fee: S.of(context).send_fee,
feeValue: sendViewModel.pendingTransaction!.feeFormatted, feeValue: sendViewModel.pendingTransaction!.feeFormatted,
feeFiatAmount: feeFiatAmount: sendViewModel.pendingTransactionFeeFiatAmountFormatted,
sendViewModel.pendingTransactionFeeFiatAmount +
' ' +
sendViewModel.fiat.title,
outputs: sendViewModel.outputs, outputs: sendViewModel.outputs,
rightButtonText: S.of(context).ok, rightButtonText: S.of(context).ok,
leftButtonText: S.of(context).cancel, leftButtonText: S.of(context).cancel,

View file

@ -1,4 +1,5 @@
import 'package:cake_wallet/src/widgets/cake_scrollbar.dart'; import 'package:cake_wallet/src/widgets/cake_scrollbar.dart';
import 'package:cake_wallet/src/widgets/section_divider.dart';
import 'package:flutter/material.dart'; 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';
@ -70,10 +71,7 @@ class ChooseYatAddressButtonsState extends State<ChooseYatAddressButtons> {
controller: controller, controller: controller,
padding: EdgeInsets.all(0), padding: EdgeInsets.all(0),
itemCount: itemCount, itemCount: itemCount,
separatorBuilder: (_, __) => Container( separatorBuilder: (_, __) => const SectionDivider(),
height: 1,
color: Theme.of(context).dividerColor,
),
itemBuilder: (context, index) { itemBuilder: (context, index) {
final address = addresses[index]; final address = addresses[index];

View file

@ -1,11 +1,11 @@
import 'dart:ui'; import 'package:cake_wallet/entities/priority_for_wallet_type.dart';
import 'package:cake_wallet/src/widgets/alert_with_one_action.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';
@ -21,21 +21,28 @@ class SendCard extends StatefulWidget {
SendCard({ SendCard({
Key? key, Key? key,
required this.output, required this.output,
required this.sendViewModel}) : super(key: key); required this.sendViewModel,
this.initialPaymentRequest,
}) : super(key: key);
final Output output; final Output output;
final SendViewModel sendViewModel; final SendViewModel sendViewModel;
final PaymentRequest? initialPaymentRequest;
@override @override
SendCardState createState() => SendCardState( SendCardState createState() => SendCardState(
output: output, output: output,
sendViewModel: sendViewModel sendViewModel: sendViewModel,
initialPaymentRequest: initialPaymentRequest,
); );
} }
class SendCardState extends State<SendCard> class SendCardState extends State<SendCard>
with AutomaticKeepAliveClientMixin<SendCard> { with AutomaticKeepAliveClientMixin<SendCard> {
SendCardState({required this.output, required this.sendViewModel}) SendCardState({
required this.output,
required this.sendViewModel,
this.initialPaymentRequest})
: addressController = TextEditingController(), : addressController = TextEditingController(),
cryptoAmountController = TextEditingController(), cryptoAmountController = TextEditingController(),
fiatAmountController = TextEditingController(), fiatAmountController = TextEditingController(),
@ -50,6 +57,7 @@ class SendCardState extends State<SendCard>
final Output output; final Output output;
final SendViewModel sendViewModel; final SendViewModel sendViewModel;
final PaymentRequest? initialPaymentRequest;
final TextEditingController addressController; final TextEditingController addressController;
final TextEditingController cryptoAmountController; final TextEditingController cryptoAmountController;
@ -62,6 +70,27 @@ class SendCardState extends State<SendCard>
bool _effectsInstalled = false; bool _effectsInstalled = false;
@override
void initState() {
super.initState();
/// if the current wallet doesn't match the one in the qr code
if (initialPaymentRequest != null &&
sendViewModel.walletCurrencyName != initialPaymentRequest!.scheme.toLowerCase()) {
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
showPopUp<void>(
context: context,
builder: (BuildContext context) {
return AlertWithOneAction(
alertTitle: S.of(context).error,
alertContent: S.of(context).unmatched_currencies,
buttonText: S.of(context).ok,
buttonAction: () => Navigator.of(context).pop());
});
});
}
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
super.build(context); super.build(context);
@ -155,6 +184,7 @@ class SendCardState extends State<SendCard>
await output.fetchParsedAddress(context); await output.fetchParsedAddress(context);
}, },
validator: validator, validator: validator,
selectedCurrency: sendViewModel.currency,
); );
}), }),
if (output.isParsedAddress) Padding( if (output.isParsedAddress) Padding(
@ -332,7 +362,8 @@ class SendCardState extends State<SendCard>
], ],
), ),
)), )),
Padding( if (!sendViewModel.isFiatDisabled)
Padding(
padding: const EdgeInsets.only(top: 20), padding: const EdgeInsets.only(top: 20),
child: BaseTextFormField( child: BaseTextFormField(
focusNode: fiatAmountFocus, focusNode: fiatAmountFocus,
@ -438,8 +469,9 @@ class SendCardState extends State<SendCard>
Padding( Padding(
padding: padding:
EdgeInsets.only(top: 5), EdgeInsets.only(top: 5),
child: Text( child: sendViewModel.isFiatDisabled
output ? const SizedBox(height: 14)
: Text(output
.estimatedFeeFiatAmount .estimatedFeeFiatAmount
+ ' ' + + ' ' +
sendViewModel sendViewModel
@ -510,8 +542,12 @@ class SendCardState extends State<SendCard>
} }
void _setEffects(BuildContext context) { void _setEffects(BuildContext context) {
addressController.text = output.address; if (output.address.isNotEmpty) {
cryptoAmountController.text = output.cryptoAmount; addressController.text = output.address;
}
if (output.cryptoAmount.isNotEmpty) {
cryptoAmountController.text = output.cryptoAmount;
}
fiatAmountController.text = output.fiatAmount; fiatAmountController.text = output.fiatAmount;
noteController.text = output.note; noteController.text = output.note;
extractedAddressController.text = output.extractedAddress; extractedAddressController.text = output.extractedAddress;
@ -603,6 +639,13 @@ class SendCardState extends State<SendCard>
extractedAddressController.text = extractedAddress; extractedAddressController.text = extractedAddress;
}); });
if (initialPaymentRequest != null &&
sendViewModel.walletCurrencyName == initialPaymentRequest!.scheme.toLowerCase()) {
addressController.text = initialPaymentRequest!.address;
cryptoAmountController.text = initialPaymentRequest!.amount;
noteController.text = initialPaymentRequest!.note;
}
_effectsInstalled = true; _effectsInstalled = true;
} }

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,81 @@
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) it does not work correctly
if(!_displaySettingsViewModel.disabledFiatApiMode)
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,47 @@
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 Column(
mainAxisSize: MainAxisSize.min,
children: [
SettingsSwitcherCell(
title: S.current.disable_fiat,
value: _privacySettingsViewModel.isFiatDisabled,
onValueChange: (BuildContext context, bool value) {
_privacySettingsViewModel.setFiatMode(value);
}),
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,102 @@
import 'package:cake_wallet/entities/pin_code_required_duration.dart';
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_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/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: (_) => _securitySettingsViewModel.checkPinCodeRiquired()
? Navigator.of(context).pushNamed(Routes.auth,
arguments: (bool isAuthenticatedSuccessfully, AuthPageState auth) {
if (isAuthenticatedSuccessfully) {
auth.close(route: Routes.showKeys);
}
})
: Navigator.of(context).pushNamed(Routes.showKeys),
),
StandardListSeparator(padding: EdgeInsets.symmetric(horizontal: 24)),
SettingsCellWithArrow(
title: S.current.create_backup,
handler: (_) => _securitySettingsViewModel.checkPinCodeRiquired()
? Navigator.of(context).pushNamed(Routes.auth,
arguments: (bool isAuthenticatedSuccessfully, AuthPageState auth) {
if (isAuthenticatedSuccessfully) {
auth.close(route: Routes.backup);
}
})
: Navigator.of(context).pushNamed(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);
}
});
}),
Observer(builder: (_) {
return SettingsPickerCell<PinCodeRequiredDuration>(
title: S.current.require_pin_after,
items: PinCodeRequiredDuration.values,
selectedItem: _securitySettingsViewModel.pinCodeRequiredDuration,
onItemSelected: (PinCodeRequiredDuration code) {
_securitySettingsViewModel.setPinCodeRequiredDuration(code);
},
);
}),
]),
);
}
}

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

@ -3,7 +3,7 @@ import 'package:flutter/material.dart';
import 'package:cake_wallet/src/widgets/picker.dart'; import 'package:cake_wallet/src/widgets/picker.dart';
import 'package:cake_wallet/src/widgets/standard_list.dart'; import 'package:cake_wallet/src/widgets/standard_list.dart';
class SettingsPickerCell<ItemType extends Object> extends StandardListRow { class SettingsPickerCell<ItemType> extends StandardListRow {
SettingsPickerCell( SettingsPickerCell(
{required String title, {required String title,
required this.selectedItem, required this.selectedItem,

View file

@ -1,6 +1,6 @@
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:cake_wallet/src/widgets/standard_list.dart'; import 'package:cake_wallet/src/widgets/standard_list.dart';
import 'package:cake_wallet/src/widgets/standart_switch.dart'; import 'package:cake_wallet/src/widgets/standard_switch.dart';
class SettingsSwitcherCell extends StandardListRow { class SettingsSwitcherCell extends StandardListRow {
SettingsSwitcherCell( SettingsSwitcherCell(
@ -11,6 +11,6 @@ class SettingsSwitcherCell extends StandardListRow {
final void Function(BuildContext context, bool value)? onValueChange; final void Function(BuildContext context, bool value)? onValueChange;
@override @override
Widget buildTrailing(BuildContext context) => StandartSwitch( Widget buildTrailing(BuildContext context) => StandardSwitch(
value: value, onTaped: () => onValueChange?.call(context, !value)); value: value, onTaped: () => onValueChange?.call(context, !value));
} }

View file

@ -1,6 +1,6 @@
import 'package:cake_wallet/src/widgets/standard_list.dart'; import 'package:cake_wallet/src/widgets/standard_list.dart';
import 'package:cake_wallet/src/widgets/standart_list_card.dart'; import 'package:cake_wallet/src/widgets/standard_list_card.dart';
import 'package:cake_wallet/src/widgets/standart_list_status_row.dart'; import 'package:cake_wallet/src/widgets/standard_list_status_row.dart';
import 'package:cake_wallet/utils/show_bar.dart'; import 'package:cake_wallet/utils/show_bar.dart';
import 'package:cake_wallet/view_model/trade_details_view_model.dart'; import 'package:cake_wallet/view_model/trade_details_view_model.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
@ -9,7 +9,7 @@ import 'package:flutter/services.dart';
import 'package:flutter_mobx/flutter_mobx.dart'; import 'package:flutter_mobx/flutter_mobx.dart';
import 'package:cake_wallet/generated/i18n.dart'; import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/src/screens/base_page.dart'; import 'package:cake_wallet/src/screens/base_page.dart';
import 'package:cake_wallet/src/widgets/standart_list_row.dart'; import 'package:cake_wallet/src/widgets/list_row.dart';
import 'package:cake_wallet/src/screens/trade_details/track_trade_list_item.dart'; import 'package:cake_wallet/src/screens/trade_details/track_trade_list_item.dart';
import 'package:cake_wallet/src/screens/trade_details/trade_details_list_card.dart'; import 'package:cake_wallet/src/screens/trade_details/trade_details_list_card.dart';
import 'package:cake_wallet/src/screens/trade_details/trade_details_status_item.dart'; import 'package:cake_wallet/src/screens/trade_details/trade_details_status_item.dart';
@ -62,18 +62,18 @@ class TradeDetailsPageBodyState extends State<TradeDetailsPageBody> {
if (item is TrackTradeListItem) { if (item is TrackTradeListItem) {
return GestureDetector( return GestureDetector(
onTap: item.onTap, onTap: item.onTap,
child: StandartListRow( child: ListRow(
title: '${item.title}', value: '${item.value}')); title: '${item.title}', value: '${item.value}'));
} }
if (item is DetailsListStatusItem) { if (item is DetailsListStatusItem) {
return StandartListStatusRow( return StandardListStatusRow(
title: item.title, title: item.title,
value: item.value); value: item.value);
} }
if (item is TradeDetailsListCardItem) { if (item is TradeDetailsListCardItem) {
return TradeDatailsStandartListCard( return TradeDetailsStandardListCard(
id: item.id, id: item.id,
create: item.createdAt, create: item.createdAt,
pair: item.pair, pair: item.pair,
@ -86,7 +86,7 @@ class TradeDetailsPageBodyState extends State<TradeDetailsPageBody> {
Clipboard.setData(ClipboardData(text: '${item.value}')); Clipboard.setData(ClipboardData(text: '${item.value}'));
showBar<void>(context, S.of(context).copied_to_clipboard); showBar<void>(context, S.of(context).copied_to_clipboard);
}, },
child: StandartListRow( child: ListRow(
title: '${item.title}', value: '${item.value}')); title: '${item.title}', value: '${item.value}'));
}); });
}); });

View file

@ -6,7 +6,7 @@ import 'package:cake_wallet/view_model/transaction_details_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:cake_wallet/generated/i18n.dart'; import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/src/widgets/standart_list_row.dart'; import 'package:cake_wallet/src/widgets/list_row.dart';
import 'package:cake_wallet/src/screens/transaction_details/blockexplorer_list_item.dart'; import 'package:cake_wallet/src/screens/transaction_details/blockexplorer_list_item.dart';
import 'package:cake_wallet/src/screens/transaction_details/standart_list_item.dart'; import 'package:cake_wallet/src/screens/transaction_details/standart_list_item.dart';
import 'package:cake_wallet/src/screens/base_page.dart'; import 'package:cake_wallet/src/screens/base_page.dart';
@ -42,7 +42,7 @@ class TransactionDetailsPage extends BasePage {
S.of(context).transaction_details_copied(item.title)); S.of(context).transaction_details_copied(item.title));
}, },
child: child:
StandartListRow(title: '${item.title}:', value: item.value), ListRow(title: '${item.title}:', value: item.value),
); );
} }
@ -50,7 +50,7 @@ class TransactionDetailsPage extends BasePage {
return GestureDetector( return GestureDetector(
onTap: item.onTap, onTap: item.onTap,
child: child:
StandartListRow(title: '${item.title}:', value: item.value), ListRow(title: '${item.title}:', value: item.value),
); );
} }

View file

@ -5,7 +5,7 @@ import 'package:cake_wallet/src/widgets/standard_list.dart';
import 'package:cake_wallet/view_model/unspent_coins/unspent_coins_details_view_model.dart'; import 'package:cake_wallet/view_model/unspent_coins/unspent_coins_details_view_model.dart';
import 'package:cake_wallet/view_model/unspent_coins/unspent_coins_switch_item.dart'; import 'package:cake_wallet/view_model/unspent_coins/unspent_coins_switch_item.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:cake_wallet/src/widgets/standart_list_row.dart'; import 'package:cake_wallet/src/widgets/list_row.dart';
import 'package:cake_wallet/src/screens/transaction_details/standart_list_item.dart'; import 'package:cake_wallet/src/screens/transaction_details/standart_list_item.dart';
import 'package:cake_wallet/src/screens/base_page.dart'; import 'package:cake_wallet/src/screens/base_page.dart';
import 'package:flutter_mobx/flutter_mobx.dart'; import 'package:flutter_mobx/flutter_mobx.dart';
@ -30,7 +30,7 @@ class UnspentCoinsDetailsPage extends BasePage {
final item = unspentCoinsDetailsViewModel.items[index]; final item = unspentCoinsDetailsViewModel.items[index];
if (item is StandartListItem) { if (item is StandartListItem) {
return StandartListRow( return ListRow(
title: '${item.title}:', title: '${item.title}:',
value: item.value); value: item.value);
} }

Some files were not shown because too many files have changed in this diff Show more