mirror of
https://github.com/cake-tech/cake_wallet.git
synced 2024-12-23 03:59:23 +00:00
Merge branch 'dashboard-desktop-view' of https://github.com/cake-tech/cake_wallet into CW-321-lock-app-feature-on-mac
This commit is contained in:
commit
a210a1e325
125 changed files with 4594 additions and 1626 deletions
9
.github/pull_request_template.md
vendored
Normal file
9
.github/pull_request_template.md
vendored
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
Issue Number (if Applicable): Fixes #
|
||||||
|
|
||||||
|
# Description
|
||||||
|
|
||||||
|
Please include a summary of the changes and which issue is fixed / feature is added.
|
||||||
|
|
||||||
|
# Pull Request - Checklist
|
||||||
|
|
||||||
|
- [ ] Initial Manual Tests Passed
|
56
.github/workflows/cache_dependencies.yml
vendored
Normal file
56
.github/workflows/cache_dependencies.yml
vendored
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
name: Cache Dependencies
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ main ]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
test:
|
||||||
|
|
||||||
|
runs-on: ubuntu-20.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
|
45
.github/workflows/pr_test_build.yml
vendored
45
.github/workflows/pr_test_build.yml
vendored
|
@ -7,7 +7,10 @@ on:
|
||||||
jobs:
|
jobs:
|
||||||
test:
|
test:
|
||||||
|
|
||||||
runs-on: ubuntu-18.04
|
runs-on: ubuntu-20.04
|
||||||
|
env:
|
||||||
|
STORE_PASS: test@cake_wallet
|
||||||
|
KEY_PASS: test@cake_wallet
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
|
@ -18,7 +21,7 @@ jobs:
|
||||||
- name: Flutter action
|
- name: Flutter action
|
||||||
uses: subosito/flutter-action@v1
|
uses: subosito/flutter-action@v1
|
||||||
with:
|
with:
|
||||||
flutter-version: '3.3.x'
|
flutter-version: '3.7.x'
|
||||||
channel: stable
|
channel: stable
|
||||||
|
|
||||||
- name: Install package dependencies
|
- name: Install package dependencies
|
||||||
|
@ -34,6 +37,24 @@ jobs:
|
||||||
./install_ndk.sh
|
./install_ndk.sh
|
||||||
source ./app_env.sh cakewallet
|
source ./app_env.sh cakewallet
|
||||||
./app_config.sh
|
./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
|
./build_all.sh
|
||||||
./copy_monero_deps.sh
|
./copy_monero_deps.sh
|
||||||
|
|
||||||
|
@ -45,12 +66,12 @@ jobs:
|
||||||
- name: Generate KeyStore
|
- name: Generate KeyStore
|
||||||
run: |
|
run: |
|
||||||
cd /opt/android/cake_wallet/android/app
|
cd /opt/android/cake_wallet/android/app
|
||||||
keytool -genkey -v -keystore key.jks -keyalg RSA -keysize 2048 -validity 10000 -alias testKey -noprompt -dname "CN=CakeWallet, OU=CakeWallet, O=CakeWallet, L=Florida, S=America, C=USA" -storepass ${{ secrets.STORE_PASS }} -keypass ${{ secrets.KEY_PASS }}
|
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
|
- name: Generate key properties
|
||||||
run: |
|
run: |
|
||||||
cd /opt/android/cake_wallet
|
cd /opt/android/cake_wallet
|
||||||
flutter packages pub run tool/generate_android_key_properties.dart keyAlias=testKey storeFile=key.jks storePassword=${{ secrets.STORE_PASS }} keyPassword=${{ secrets.KEY_PASS }}
|
flutter packages pub run tool/generate_android_key_properties.dart keyAlias=testKey storeFile=key.jks storePassword=$STORE_PASS keyPassword=$KEY_PASS
|
||||||
|
|
||||||
- name: Generate localization
|
- name: Generate localization
|
||||||
run: |
|
run: |
|
||||||
|
@ -89,6 +110,7 @@ jobs:
|
||||||
echo "const onramperApiKey = '${{ secrets.ONRAMPER_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 anypayToken = '${{ secrets.ANY_PAY_TOKEN }}';" >> lib/.secrets.g.dart
|
||||||
echo "const ioniaClientId = '${{ secrets.IONIA_CLIENT_ID }}';" >> lib/.secrets.g.dart
|
echo "const ioniaClientId = '${{ secrets.IONIA_CLIENT_ID }}';" >> lib/.secrets.g.dart
|
||||||
|
echo "const twitterBearerToken = '${{ secrets.TWITTER_BEARER_TOKEN }}';" >> lib/.secrets.g.dart
|
||||||
|
|
||||||
- name: Rename app
|
- name: Rename app
|
||||||
run: sed -i -e "s/\${APP_NAME}/$GITHUB_HEAD_REF/g" /opt/android/cake_wallet/android/app/src/main/AndroidManifest.xml
|
run: sed -i -e "s/\${APP_NAME}/$GITHUB_HEAD_REF/g" /opt/android/cake_wallet/android/app/src/main/AndroidManifest.xml
|
||||||
|
@ -111,19 +133,20 @@ jobs:
|
||||||
# --token ${{ secrets.APP_CENTER_TOKEN }} \
|
# --token ${{ secrets.APP_CENTER_TOKEN }} \
|
||||||
# --quiet
|
# --quiet
|
||||||
|
|
||||||
- name: Send Test APK
|
|
||||||
run: |
|
|
||||||
cd /opt/android/cake_wallet
|
|
||||||
var=$(curl --upload-file build/app/outputs/apk/release/app-release.apk https://transfer.sh/$GITHUB_HEAD_REF.apk -H "Max-Days: 10")
|
|
||||||
curl ${{ secrets.SLACK_WEB_HOOK }} -H "Content-Type: application/json" -d '{"apk_link": "'"$var"'","ticket": "'"$GITHUB_HEAD_REF"'"}'
|
|
||||||
|
|
||||||
- name: Rename apk file
|
- name: Rename apk file
|
||||||
run: |
|
run: |
|
||||||
cd /opt/android/cake_wallet/build/app/outputs/apk/release
|
cd /opt/android/cake_wallet/build/app/outputs/apk/release
|
||||||
mkdir test-apk
|
mkdir test-apk
|
||||||
mv app-release.apk test-apk/$GITHUB_HEAD_REF.apk
|
cp app-release.apk test-apk/$GITHUB_HEAD_REF.apk
|
||||||
|
|
||||||
- name: Upload Artifact
|
- name: Upload Artifact
|
||||||
uses: kittaakos/upload-artifact-as-is@v0
|
uses: kittaakos/upload-artifact-as-is@v0
|
||||||
with:
|
with:
|
||||||
path: /opt/android/cake_wallet/build/app/outputs/apk/release/test-apk/
|
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"'"}'
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
MIT License
|
MIT License
|
||||||
|
|
||||||
Copyright (c) 2022 Cake Labs LLC
|
Copyright (c) 2018-2023 Cake Labs LLC
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
|
56
README.md
56
README.md
|
@ -76,3 +76,59 @@ 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
|
||||||
|
- Thai
|
||||||
|
- Arabic
|
||||||
|
- Turkish
|
||||||
|
- Burmese
|
||||||
|
|
||||||
|
## 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 42x26 pixels with a 3 pixels of transparent margin on all 4 sides. You can resize the flag with [paint.net](https://www.getpaint.net/) to 36x20 pixels, expand the canvas to 42x26 pixels with the flag anchored in the middle, and then manually delete the 3 pixels on each side to make transparent. Or you can use another program like Photoshop.
|
||||||
|
|
||||||
|
## 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 42x26 pixels with a 3 pixels of transparent margin on all 4 sides.
|
||||||
|
|
|
@ -18,6 +18,8 @@ analyzer:
|
||||||
linter:
|
linter:
|
||||||
rules:
|
rules:
|
||||||
- cancel_subscriptions
|
- cancel_subscriptions
|
||||||
|
- always_declare_return_types
|
||||||
|
- prefer_final_fields
|
||||||
|
|
||||||
|
|
||||||
# analyzer:
|
# analyzer:
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||||
<uses-permission android:name="android.permission.WRITE_INTERNAL_STORAGE" />
|
<uses-permission android:name="android.permission.WRITE_INTERNAL_STORAGE" />
|
||||||
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
||||||
|
<uses-permission android:name="android.permission.CAMERA" />
|
||||||
|
|
||||||
<application
|
<application
|
||||||
android:name=".Application"
|
android:name=".Application"
|
||||||
|
@ -52,6 +53,15 @@
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="flutterEmbedding"
|
android:name="flutterEmbedding"
|
||||||
android:value="2" />
|
android:value="2" />
|
||||||
|
<provider
|
||||||
|
android:name="com.pichillilorenzo.flutter_inappwebview.InAppWebViewFileProvider"
|
||||||
|
android:authorities="${applicationId}.flutter_inappwebview.fileprovider"
|
||||||
|
android:exported="false"
|
||||||
|
android:grantUriPermissions="true">
|
||||||
|
<meta-data
|
||||||
|
android:name="android.support.FILE_PROVIDER_PATHS"
|
||||||
|
android:resource="@xml/provider_paths" />
|
||||||
|
</provider>
|
||||||
</application>
|
</application>
|
||||||
|
|
||||||
<queries>
|
<queries>
|
||||||
|
|
BIN
assets/images/flags/mmr.png
Normal file
BIN
assets/images/flags/mmr.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 902 B |
BIN
assets/images/flags/sau.png
Normal file
BIN
assets/images/flags/sau.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 476 B |
BIN
assets/images/flags/tur.png
Normal file
BIN
assets/images/flags/tur.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1 KiB |
Binary file not shown.
Before Width: | Height: | Size: 68 KiB |
|
@ -17,7 +17,7 @@ int stringDoubleToBitcoinAmount(String amount) {
|
||||||
int result = 0;
|
int result = 0;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
result = (double.parse(amount) * bitcoinAmountDivider).toInt();
|
result = (double.parse(amount) * bitcoinAmountDivider).round();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
result = 0;
|
result = 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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,117 @@ 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);
|
// title, tag (if applicable), fullName (if unique), raw, name, iconPath
|
||||||
static const xau = CryptoCurrency(title: 'XAU', tag: 'XHV', raw: 18);
|
static const xmr = CryptoCurrency(title: 'XMR', fullName: 'Monero', raw: 0, name: 'xmr', iconPath: 'assets/images/monero_icon.png');
|
||||||
static const xaud = CryptoCurrency(title: 'XAUD', tag: 'XHV', raw: 19);
|
static const ada = CryptoCurrency(title: 'ADA', fullName: 'Cardano', raw: 1, name: 'ada', iconPath: 'assets/images/ada_icon.png');
|
||||||
static const xbtc = CryptoCurrency(title: 'XBTC', tag: 'XHV', raw: 20);
|
static const bch = CryptoCurrency(title: 'BCH', fullName: 'Bitcoin Cash', raw: 2, name: 'bch', iconPath: 'assets/images/bch_icon.png');
|
||||||
static const xcad = CryptoCurrency(title: 'XCAD', tag: 'XHV', raw: 21);
|
static const bnb = CryptoCurrency(title: 'BNB', tag: 'BSC', fullName: 'Binance Coin', raw: 3, name: 'bnb', iconPath: 'assets/images/bnb_icon.png');
|
||||||
static const xchf = CryptoCurrency(title: 'XCHF', tag: 'XHV', raw: 22);
|
static const btc = CryptoCurrency(title: 'BTC', fullName: 'Bitcoin', raw: 4, name: 'btc', iconPath: 'assets/images/btc.png');
|
||||||
static const xcny = CryptoCurrency(title: 'XCNY', tag: 'XHV', raw: 23);
|
static const dai = CryptoCurrency(title: 'DAI', tag: 'ETH', fullName: 'Dai', raw: 5, name: 'dai', iconPath: 'assets/images/dai_icon.png');
|
||||||
static const xeur = CryptoCurrency(title: 'XEUR', tag: 'XHV', raw: 24);
|
static const dash = CryptoCurrency(title: 'DASH', fullName: 'Dash', raw: 6, name: 'dash', iconPath: 'assets/images/dash_icon.png');
|
||||||
static const xgbp = CryptoCurrency(title: 'XGBP', tag: 'XHV', raw: 25);
|
static const eos = CryptoCurrency(title: 'EOS', fullName: 'EOS', raw: 7, name: 'eos', iconPath: 'assets/images/eos_icon.png');
|
||||||
static const xjpy = CryptoCurrency(title: 'XJPY', tag: 'XHV', raw: 26);
|
static const eth = CryptoCurrency(title: 'ETH', fullName: 'Ethereum', raw: 8, name: 'eth', iconPath: 'assets/images/eth_icon.png');
|
||||||
static const xnok = CryptoCurrency(title: 'XNOK', tag: 'XHV', raw: 27);
|
static const ltc = CryptoCurrency(title: 'LTC', fullName: 'Litecoin', raw: 9, name: 'ltc', iconPath: 'assets/images/litecoin-ltc_icon.png');
|
||||||
static const xnzd = CryptoCurrency(title: 'XNZD', tag: 'XHV', raw: 28);
|
static const nano = CryptoCurrency(title: 'NANO', raw: 10, name: 'nano');
|
||||||
static const xusd = CryptoCurrency(title: 'XUSD', tag: 'XHV', raw: 29);
|
static const trx = CryptoCurrency(title: 'TRX', fullName: 'TRON', raw: 11, name: 'trx', iconPath: 'assets/images/trx_icon.png');
|
||||||
|
static const usdt = CryptoCurrency(title: 'USDT', tag: 'OMNI', fullName: 'USDT Tether', raw: 12, name: 'usdt', iconPath: 'assets/images/usdt_icon.png');
|
||||||
|
static const usdterc20 = CryptoCurrency(title: 'USDT', tag: 'ETH', fullName: 'USDT Tether', raw: 13, name: 'usdterc20', iconPath: 'assets/images/usdterc20_icon.png');
|
||||||
|
static const xlm = CryptoCurrency(title: 'XLM', fullName: 'Stellar', raw: 14, name: 'xlm', iconPath: 'assets/images/xlm_icon.png');
|
||||||
|
static const xrp = CryptoCurrency(title: 'XRP', fullName: 'Ripple', raw: 15, name: 'xrp', iconPath: 'assets/images/xrp_icon.png');
|
||||||
|
static const xhv = CryptoCurrency(title: 'XHV', fullName: 'Haven Protocol', raw: 16, name: 'xhv', iconPath: 'assets/images/xhv_logo.png');
|
||||||
|
|
||||||
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', tag: 'ETH', fullName: 'ApeCoin', raw: 30, name: 'ape', iconPath: 'assets/images/ape_icon.png');
|
||||||
static const dcr = CryptoCurrency(title: 'DCR', iconPath: 'assets/images/dcr_icon.png', raw: 47);
|
static const avaxc = CryptoCurrency(title: 'AVAX', tag: 'C-CHAIN', raw: 31, name: 'avaxc', iconPath: 'assets/images/avaxc_icon.png');
|
||||||
static const husd = CryptoCurrency(title: 'HUSD', iconPath: 'assets/images/husd_icon.png', tag: 'ETH', raw: 48);
|
static const btt = CryptoCurrency(title: 'BTT', tag: 'ETH', fullName: 'BitTorrent', raw: 32, name: 'btt', iconPath: 'assets/images/btt_icon.png');
|
||||||
static const kmd = CryptoCurrency(title: 'KMD', iconPath: 'assets/images/kmd_icon.png', raw: 49);
|
static const bttc = CryptoCurrency(title: 'BTTC', tag: 'TRX', fullName: 'BitTorrent-NEW', raw: 33, name: 'bttc', iconPath: 'assets/images/bttbsc_icon.png');
|
||||||
static const mana = CryptoCurrency(title: 'MANA', iconPath: 'assets/images/mana_icon.png', tag: 'ETH', raw: 50);
|
static const doge = CryptoCurrency(title: 'DOGE', fullName: 'Dogecoin', raw: 34, name: 'doge', iconPath: 'assets/images/doge_icon.png');
|
||||||
static const maticpoly = CryptoCurrency(title: 'MATIC', iconPath: 'assets/images/matic_icon.png', tag: 'POLY', raw: 51);
|
static const firo = CryptoCurrency(title: 'FIRO', raw: 35, name: 'firo', iconPath: 'assets/images/firo_icon.png');
|
||||||
static const matic = CryptoCurrency(title: 'MATIC', iconPath: 'assets/images/matic_icon.png', tag: 'ETH', raw: 52);
|
static const usdttrc20 = CryptoCurrency(title: 'USDT', tag: 'TRX', fullName: 'USDT Tether', raw: 36, name: 'usdttrc20', iconPath: 'assets/images/usdttrc20_icon.png');
|
||||||
static const mkr = CryptoCurrency(title: 'MKR', iconPath: 'assets/images/mkr_icon.png', tag: 'ETH', raw: 53);
|
static const hbar = CryptoCurrency(title: 'HBAR', fullName: 'Hedera', raw: 37, name: 'hbar', iconPath: 'assets/images/hbar_icon.png', );
|
||||||
static const near = CryptoCurrency(title: 'NEAR', iconPath: 'assets/images/near_icon.png', raw: 54);
|
static const sc = CryptoCurrency(title: 'SC', fullName: 'Siacoin', raw: 38, name: 'sc', iconPath: 'assets/images/sc_icon.png');
|
||||||
static const oxt = CryptoCurrency(title: 'OXT', iconPath: 'assets/images/oxt_icon.png', tag: 'ETH', raw: 55);
|
static const sol = CryptoCurrency(title: 'SOL', fullName: 'Solana', raw: 39, name: 'sol', iconPath: 'assets/images/sol_icon.png');
|
||||||
static const paxg = CryptoCurrency(title: 'PAXG', iconPath: 'assets/images/paxg_icon.png', tag: 'ETH', raw: 56);
|
static const usdc = CryptoCurrency(title: 'USDC', tag: 'ETH', fullName: 'USD Coin', raw: 40, name: 'usdc', iconPath: 'assets/images/usdc_icon.png');
|
||||||
static const pivx = CryptoCurrency(title: 'PIVX', iconPath: 'assets/images/pivx_icon.png', raw: 57);
|
static const usdcsol = CryptoCurrency(title: 'USDC', tag: 'SOL', fullName: 'USDC Coin', raw: 41, name: 'usdcsol', iconPath: 'assets/images/usdcsol_icon.png');
|
||||||
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', fullName: 'Horizen', raw: 44, name: 'zen', iconPath: 'assets/images/zen_icon.png');
|
||||||
static const uni = CryptoCurrency(title: 'UNI', iconPath: 'assets/images/uni_icon.png', tag: 'ETH', raw: 61);
|
static const xvg = CryptoCurrency(title: 'XVG', fullName: 'Verge', raw: 45, name: 'xvg', iconPath: 'assets/images/xvg_icon.png');
|
||||||
static const stx = CryptoCurrency(title: 'STX', iconPath: 'assets/images/stx_icon.png', raw: 62);
|
|
||||||
|
|
||||||
|
static const usdcpoly = CryptoCurrency(title: 'USDC', tag: 'POLY', fullName: 'USD Coin', raw: 46, name: 'usdcpoly', iconPath: 'assets/images/usdc_icon.png');
|
||||||
|
static const dcr = CryptoCurrency(title: 'DCR', fullName: 'Decred', raw: 47, name: 'dcr', iconPath: 'assets/images/dcr_icon.png');
|
||||||
|
static const kmd = CryptoCurrency(title: 'KMD', fullName: 'Komodo', raw: 48, name: 'kmd', iconPath: 'assets/images/kmd_icon.png');
|
||||||
|
static const mana = CryptoCurrency(title: 'MANA', tag: 'ETH', fullName: 'Decentraland', raw: 49, name: 'mana', iconPath: 'assets/images/mana_icon.png');
|
||||||
|
static const maticpoly = CryptoCurrency(title: 'MATIC', tag: 'POLY', fullName: 'Polygon', raw: 50, name: 'maticpoly', iconPath: 'assets/images/matic_icon.png');
|
||||||
|
static const matic = CryptoCurrency(title: 'MATIC', tag: 'ETH', fullName: 'Polygon', raw: 51, name: 'matic', iconPath: 'assets/images/matic_icon.png');
|
||||||
|
static const mkr = CryptoCurrency(title: 'MKR', tag: 'ETH', fullName: 'Maker', raw: 52, name: 'mkr', iconPath: 'assets/images/mkr_icon.png');
|
||||||
|
static const near = CryptoCurrency(title: 'NEAR', fullName: 'NEAR Protocol', raw: 53, name: 'near', iconPath: 'assets/images/near_icon.png');
|
||||||
|
static const oxt = CryptoCurrency(title: 'OXT', tag: 'ETH', fullName: 'Orchid', raw: 54, name: 'oxt', iconPath: 'assets/images/oxt_icon.png');
|
||||||
|
static const paxg = CryptoCurrency(title: 'PAXG', tag: 'ETH', fullName: 'Pax Gold', raw: 55, name: 'paxg', iconPath: 'assets/images/paxg_icon.png');
|
||||||
|
static const pivx = CryptoCurrency(title: 'PIVX', raw: 56, name: 'pivx', iconPath: 'assets/images/pivx_icon.png');
|
||||||
|
static const rune = CryptoCurrency(title: 'RUNE', fullName: 'Thorchain', raw: 57, name: 'rune', iconPath: 'assets/images/rune_icon.png');
|
||||||
|
static const rvn = CryptoCurrency(title: 'RVN', fullName: 'Ravencoin', raw: 58, name: 'rvn', iconPath: 'assets/images/rvn_icon.png');
|
||||||
|
static const scrt = CryptoCurrency(title: 'SCRT', fullName: 'Secret Network', raw: 59, name: 'scrt', iconPath: 'assets/images/scrt_icon.png');
|
||||||
|
static const uni = CryptoCurrency(title: 'UNI', tag: 'ETH', fullName: 'Uniswap', raw: 60, name: 'uni', iconPath: 'assets/images/uni_icon.png');
|
||||||
|
static const stx = CryptoCurrency(title: 'STX', fullName: 'Stacks', raw: 61, name: 'stx', iconPath: 'assets/images/stx_icon.png');
|
||||||
|
|
||||||
|
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
|
||||||
|
|
|
@ -15,4 +15,4 @@ double moneroAmountToDouble({required int amount}) =>
|
||||||
cryptoAmountToDouble(amount: amount, divider: moneroAmountDivider);
|
cryptoAmountToDouble(amount: amount, divider: moneroAmountDivider);
|
||||||
|
|
||||||
int moneroParseAmount({required String amount}) =>
|
int moneroParseAmount({required String amount}) =>
|
||||||
(double.parse(amount) * moneroAmountDivider).toInt();
|
(double.parse(amount) * moneroAmountDivider).round();
|
||||||
|
|
|
@ -8,7 +8,8 @@ import 'package:cw_haven/api/transaction_history.dart';
|
||||||
|
|
||||||
class HavenTransactionInfo extends TransactionInfo {
|
class HavenTransactionInfo extends TransactionInfo {
|
||||||
HavenTransactionInfo(this.id, this.height, this.direction, this.date,
|
HavenTransactionInfo(this.id, this.height, this.direction, this.date,
|
||||||
this.isPending, this.amount, this.accountIndex, this.addressIndex, this.fee);
|
this.isPending, this.amount, this.accountIndex, this.addressIndex, this.fee,
|
||||||
|
this.confirmations);
|
||||||
|
|
||||||
HavenTransactionInfo.fromMap(Map<String, Object> map)
|
HavenTransactionInfo.fromMap(Map<String, Object> map)
|
||||||
: id = (map['hash'] ?? '') as String,
|
: id = (map['hash'] ?? '') as String,
|
||||||
|
@ -22,6 +23,7 @@ class HavenTransactionInfo extends TransactionInfo {
|
||||||
amount = map['amount'] as int,
|
amount = map['amount'] as int,
|
||||||
accountIndex = int.parse(map['accountIndex'] as String),
|
accountIndex = int.parse(map['accountIndex'] as String),
|
||||||
addressIndex = map['addressIndex'] as int,
|
addressIndex = map['addressIndex'] as int,
|
||||||
|
confirmations = map['confirmations'] as int,
|
||||||
key = getTxKey((map['hash'] ?? '') as String),
|
key = getTxKey((map['hash'] ?? '') as String),
|
||||||
fee = map['fee'] as int? ?? 0;
|
fee = map['fee'] as int? ?? 0;
|
||||||
|
|
||||||
|
@ -35,6 +37,7 @@ class HavenTransactionInfo extends TransactionInfo {
|
||||||
amount = row.getAmount(),
|
amount = row.getAmount(),
|
||||||
accountIndex = row.subaddrAccount,
|
accountIndex = row.subaddrAccount,
|
||||||
addressIndex = row.subaddrIndex,
|
addressIndex = row.subaddrIndex,
|
||||||
|
confirmations = row.confirmations,
|
||||||
key = null, //getTxKey(row.getHash()),
|
key = null, //getTxKey(row.getHash()),
|
||||||
fee = row.fee,
|
fee = row.fee,
|
||||||
assetType = row.getAssetType();
|
assetType = row.getAssetType();
|
||||||
|
@ -48,6 +51,7 @@ class HavenTransactionInfo extends TransactionInfo {
|
||||||
final int amount;
|
final int amount;
|
||||||
final int fee;
|
final int fee;
|
||||||
final int addressIndex;
|
final int addressIndex;
|
||||||
|
final int confirmations;
|
||||||
late String recipientAddress;
|
late String recipientAddress;
|
||||||
late String assetType;
|
late String assetType;
|
||||||
String? _fiatAmount;
|
String? _fiatAmount;
|
||||||
|
|
|
@ -8,7 +8,8 @@ import 'package:cw_monero/api/transaction_history.dart';
|
||||||
|
|
||||||
class MoneroTransactionInfo extends TransactionInfo {
|
class MoneroTransactionInfo extends TransactionInfo {
|
||||||
MoneroTransactionInfo(this.id, this.height, this.direction, this.date,
|
MoneroTransactionInfo(this.id, this.height, this.direction, this.date,
|
||||||
this.isPending, this.amount, this.accountIndex, this.addressIndex, this.fee);
|
this.isPending, this.amount, this.accountIndex, this.addressIndex, this.fee,
|
||||||
|
this.confirmations);
|
||||||
|
|
||||||
MoneroTransactionInfo.fromMap(Map<String, Object?> map)
|
MoneroTransactionInfo.fromMap(Map<String, Object?> map)
|
||||||
: id = (map['hash'] ?? '') as String,
|
: id = (map['hash'] ?? '') as String,
|
||||||
|
@ -22,6 +23,7 @@ class MoneroTransactionInfo extends TransactionInfo {
|
||||||
amount = map['amount'] as int,
|
amount = map['amount'] as int,
|
||||||
accountIndex = int.parse(map['accountIndex'] as String),
|
accountIndex = int.parse(map['accountIndex'] as String),
|
||||||
addressIndex = map['addressIndex'] as int,
|
addressIndex = map['addressIndex'] as int,
|
||||||
|
confirmations = map['confirmations'] as int,
|
||||||
key = getTxKey((map['hash'] ?? '') as String),
|
key = getTxKey((map['hash'] ?? '') as String),
|
||||||
fee = map['fee'] as int ?? 0 {
|
fee = map['fee'] as int ?? 0 {
|
||||||
additionalInfo = <String, dynamic>{
|
additionalInfo = <String, dynamic>{
|
||||||
|
@ -41,6 +43,7 @@ class MoneroTransactionInfo extends TransactionInfo {
|
||||||
amount = row.getAmount(),
|
amount = row.getAmount(),
|
||||||
accountIndex = row.subaddrAccount,
|
accountIndex = row.subaddrAccount,
|
||||||
addressIndex = row.subaddrIndex,
|
addressIndex = row.subaddrIndex,
|
||||||
|
confirmations = row.confirmations,
|
||||||
key = getTxKey(row.getHash()),
|
key = getTxKey(row.getHash()),
|
||||||
fee = row.fee {
|
fee = row.fee {
|
||||||
additionalInfo = <String, dynamic>{
|
additionalInfo = <String, dynamic>{
|
||||||
|
@ -59,6 +62,7 @@ class MoneroTransactionInfo extends TransactionInfo {
|
||||||
final int amount;
|
final int amount;
|
||||||
final int fee;
|
final int fee;
|
||||||
final int addressIndex;
|
final int addressIndex;
|
||||||
|
final int confirmations;
|
||||||
String? recipientAddress;
|
String? recipientAddress;
|
||||||
String? key;
|
String? key;
|
||||||
String? _fiatAmount;
|
String? _fiatAmount;
|
||||||
|
|
|
@ -80,7 +80,7 @@ class AnyPayApi {
|
||||||
final response = await post(Uri.parse(uri), headers: headers, body: utf8.encode(json.encode(body)));
|
final response = await post(Uri.parse(uri), headers: headers, body: utf8.encode(json.encode(body)));
|
||||||
if (response.statusCode == 400) {
|
if (response.statusCode == 400) {
|
||||||
final decodedBody = json.decode(response.body) as Map<String, dynamic>;
|
final decodedBody = json.decode(response.body) as Map<String, dynamic>;
|
||||||
throw Exception(decodedBody['message'] as String);
|
throw Exception(decodedBody['message'] as String? ?? 'Unexpected response\nError code: 400');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (response.statusCode != 200) {
|
if (response.statusCode != 200) {
|
||||||
|
|
|
@ -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:
|
||||||
|
@ -200,4 +198,26 @@ class AddressValidator extends TextValidator {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static String? getAddressFromStringPattern(CryptoCurrency type) {
|
||||||
|
switch (type) {
|
||||||
|
case CryptoCurrency.xmr:
|
||||||
|
return '([^0-9a-zA-Z]|^)4[0-9a-zA-Z]{94}([^0-9a-zA-Z]|\$)'
|
||||||
|
'|([^0-9a-zA-Z]|^)8[0-9a-zA-Z]{94}([^0-9a-zA-Z]|\$)'
|
||||||
|
'|([^0-9a-zA-Z]|^)[0-9a-zA-Z]{106}([^0-9a-zA-Z]|\$)';
|
||||||
|
case CryptoCurrency.btc:
|
||||||
|
return '([^0-9a-zA-Z]|^)1[0-9a-zA-Z]{32}([^0-9a-zA-Z]|\$)'
|
||||||
|
'|([^0-9a-zA-Z]|^)1[0-9a-zA-Z]{33}([^0-9a-zA-Z]|\$)'
|
||||||
|
'|([^0-9a-zA-Z]|^)3[0-9a-zA-Z]{32}([^0-9a-zA-Z]|\$)'
|
||||||
|
'|([^0-9a-zA-Z]|^)3[0-9a-zA-Z]{33}([^0-9a-zA-Z]|\$)'
|
||||||
|
'|([^0-9a-zA-Z]|^)bc1[0-9a-zA-Z]{39}([^0-9a-zA-Z]|\$)'
|
||||||
|
'|([^0-9a-zA-Z]|^)bc1[0-9a-zA-Z]{59}([^0-9a-zA-Z]|\$)';
|
||||||
|
case CryptoCurrency.ltc:
|
||||||
|
return '([^0-9a-zA-Z]|^)^L[a-zA-Z0-9]{26,33}([^0-9a-zA-Z]|\$)'
|
||||||
|
'|([^0-9a-zA-Z]|^)[LM][a-km-zA-HJ-NP-Z1-9]{26,33}([^0-9a-zA-Z]|\$)'
|
||||||
|
'|([^0-9a-zA-Z]|^)ltc[a-zA-Z0-9]{26,45}([^0-9a-zA-Z]|\$)';
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,6 +43,7 @@ import 'package:cake_wallet/view_model/settings/other_settings_view_model.dart';
|
||||||
import 'package:cake_wallet/view_model/settings/privacy_settings_view_model.dart';
|
import 'package:cake_wallet/view_model/settings/privacy_settings_view_model.dart';
|
||||||
import 'package:cake_wallet/view_model/settings/security_settings_view_model.dart';
|
import 'package:cake_wallet/view_model/settings/security_settings_view_model.dart';
|
||||||
import 'package:cake_wallet/view_model/advanced_privacy_settings_view_model.dart';
|
import 'package:cake_wallet/view_model/advanced_privacy_settings_view_model.dart';
|
||||||
|
import 'package:cake_wallet/view_model/wallet_address_list/wallet_address_list_item.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';
|
||||||
|
@ -381,8 +382,8 @@ Future setup(
|
||||||
addressListViewModel: getIt.get<WalletAddressListViewModel>(),
|
addressListViewModel: getIt.get<WalletAddressListViewModel>(),
|
||||||
walletViewModel: getIt.get<DashboardViewModel>()));
|
walletViewModel: getIt.get<DashboardViewModel>()));
|
||||||
|
|
||||||
getIt.registerFactoryParam<WalletAddressEditOrCreateViewModel, dynamic, void>(
|
getIt.registerFactoryParam<WalletAddressEditOrCreateViewModel, WalletAddressListItem?, void>(
|
||||||
(dynamic item, _) => WalletAddressEditOrCreateViewModel(
|
(WalletAddressListItem? item, _) => WalletAddressEditOrCreateViewModel(
|
||||||
wallet: getIt.get<AppStore>().wallet!, item: item));
|
wallet: getIt.get<AppStore>().wallet!, item: item));
|
||||||
|
|
||||||
getIt.registerFactoryParam<AddressEditOrCreatePage, dynamic, void>(
|
getIt.registerFactoryParam<AddressEditOrCreatePage, dynamic, void>(
|
||||||
|
|
|
@ -18,7 +18,11 @@ class LanguageService {
|
||||||
'uk': 'Українська (Ukrainian)',
|
'uk': 'Українська (Ukrainian)',
|
||||||
'zh': '中文 (Chinese)',
|
'zh': '中文 (Chinese)',
|
||||||
'hr': 'Hrvatski (Croatian)',
|
'hr': 'Hrvatski (Croatian)',
|
||||||
'it': 'Italiano (Italian)'
|
'it': 'Italiano (Italian)',
|
||||||
|
'th': 'ภาษาไทย (Thai)',
|
||||||
|
'ar': 'العربية (Arabic)',
|
||||||
|
'tr': 'Türkçe (Turkish)',
|
||||||
|
'my': 'မြန်မာ (Burmese)',
|
||||||
};
|
};
|
||||||
|
|
||||||
static const Map<String, String> localeCountryCode = {
|
static const Map<String, String> localeCountryCode = {
|
||||||
|
@ -36,7 +40,11 @@ class LanguageService {
|
||||||
'uk': 'ukr',
|
'uk': 'ukr',
|
||||||
'zh': 'chn',
|
'zh': 'chn',
|
||||||
'hr': 'hrv',
|
'hr': 'hrv',
|
||||||
'it': 'ita'
|
'it': 'ita',
|
||||||
|
'th': 'tha',
|
||||||
|
'ar': 'sau',
|
||||||
|
'tr': 'tur',
|
||||||
|
'my': 'mmr',
|
||||||
};
|
};
|
||||||
|
|
||||||
static final list = <String, String> {};
|
static final list = <String, String> {};
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import 'package:basic_utils/basic_utils.dart';
|
import 'package:basic_utils/basic_utils.dart';
|
||||||
import 'package:cw_core/wallet_type.dart';
|
|
||||||
|
|
||||||
class OpenaliasRecord {
|
class OpenaliasRecord {
|
||||||
OpenaliasRecord({
|
OpenaliasRecord({
|
||||||
|
@ -22,69 +21,68 @@ class OpenaliasRecord {
|
||||||
return formattedName;
|
return formattedName;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Future<OpenaliasRecord> fetchAddressAndName({
|
static Future<List<RRecord>?> lookupOpenAliasRecord(String name) async {
|
||||||
|
try {
|
||||||
|
final txtRecord = await DnsUtils.lookupRecord(name, RRecordType.TXT, dnssec: true);
|
||||||
|
|
||||||
|
return txtRecord;
|
||||||
|
} catch (e) {
|
||||||
|
print("${e.toString()}");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static OpenaliasRecord fetchAddressAndName({
|
||||||
required String formattedName,
|
required String formattedName,
|
||||||
required String ticker,
|
required String ticker,
|
||||||
}) async {
|
required List<RRecord> txtRecord,
|
||||||
|
}) {
|
||||||
String address = formattedName;
|
String address = formattedName;
|
||||||
String name = formattedName;
|
String name = formattedName;
|
||||||
String note = '';
|
String note = '';
|
||||||
|
|
||||||
if (formattedName.contains(".")) {
|
for (RRecord element in txtRecord) {
|
||||||
try {
|
String record = element.data;
|
||||||
final txtRecord = await DnsUtils.lookupRecord(
|
|
||||||
formattedName, RRecordType.TXT,
|
|
||||||
dnssec: true);
|
|
||||||
|
|
||||||
if (txtRecord != null) {
|
if (record.contains("oa1:$ticker") && record.contains("recipient_address")) {
|
||||||
for (RRecord element in txtRecord) {
|
record = record.replaceAll('\"', "");
|
||||||
String record = element.data;
|
|
||||||
|
|
||||||
if (record.contains("oa1:$ticker") &&
|
final dataList = record.split(";");
|
||||||
record.contains("recipient_address")) {
|
|
||||||
record = record.replaceAll('\"', "");
|
|
||||||
|
|
||||||
final dataList = record.split(";");
|
address = dataList
|
||||||
|
.where((item) => (item.contains("recipient_address")))
|
||||||
|
.toString()
|
||||||
|
.replaceAll("oa1:$ticker recipient_address=", "")
|
||||||
|
.replaceAll("(", "")
|
||||||
|
.replaceAll(")", "")
|
||||||
|
.trim();
|
||||||
|
|
||||||
address = dataList
|
final recipientName = dataList
|
||||||
.where((item) => (item.contains("recipient_address")))
|
.where((item) => (item.contains("recipient_name")))
|
||||||
.toString()
|
.toString()
|
||||||
.replaceAll("oa1:$ticker recipient_address=", "")
|
.replaceAll("(", "")
|
||||||
.replaceAll("(", "")
|
.replaceAll(")", "")
|
||||||
.replaceAll(")", "")
|
.trim();
|
||||||
.trim();
|
|
||||||
|
|
||||||
final recipientName = dataList
|
if (recipientName.isNotEmpty) {
|
||||||
.where((item) => (item.contains("recipient_name")))
|
name = recipientName.replaceAll("recipient_name=", "");
|
||||||
.toString()
|
|
||||||
.replaceAll("(", "")
|
|
||||||
.replaceAll(")", "")
|
|
||||||
.trim();
|
|
||||||
|
|
||||||
if (recipientName.isNotEmpty) {
|
|
||||||
name = recipientName.replaceAll("recipient_name=", "");
|
|
||||||
}
|
|
||||||
|
|
||||||
final description = dataList
|
|
||||||
.where((item) => (item.contains("tx_description")))
|
|
||||||
.toString()
|
|
||||||
.replaceAll("(", "")
|
|
||||||
.replaceAll(")", "")
|
|
||||||
.trim();
|
|
||||||
|
|
||||||
if (description.isNotEmpty) {
|
|
||||||
note = description.replaceAll("tx_description=", "");
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} catch (e) {
|
|
||||||
print("${e.toString()}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return OpenaliasRecord(address: address, name: name, description: note);
|
final description = dataList
|
||||||
|
.where((item) => (item.contains("tx_description")))
|
||||||
|
.toString()
|
||||||
|
.replaceAll("(", "")
|
||||||
|
.replaceAll(")", "")
|
||||||
|
.trim();
|
||||||
|
|
||||||
|
if (description.isNotEmpty) {
|
||||||
|
note = description.replaceAll("tx_description=", "");
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
return OpenaliasRecord(address: address, name: name, description: note);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,40 +1,75 @@
|
||||||
|
import 'package:cake_wallet/core/address_validator.dart';
|
||||||
import 'package:cake_wallet/core/yat_service.dart';
|
import 'package:cake_wallet/core/yat_service.dart';
|
||||||
import 'package:cake_wallet/entities/openalias_record.dart';
|
import 'package:cake_wallet/entities/openalias_record.dart';
|
||||||
import 'package:cake_wallet/entities/parsed_address.dart';
|
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:cake_wallet/twitter/twitter_api.dart';
|
||||||
|
import 'package:cw_core/crypto_currency.dart';
|
||||||
import 'package:cw_core/wallet_type.dart';
|
import 'package:cw_core/wallet_type.dart';
|
||||||
import 'package:cake_wallet/entities/fio_address_provider.dart';
|
import 'package:cake_wallet/entities/fio_address_provider.dart';
|
||||||
|
|
||||||
class AddressResolver {
|
class AddressResolver {
|
||||||
|
|
||||||
AddressResolver({required this.yatService, required this.walletType});
|
AddressResolver({required this.yatService, required this.walletType});
|
||||||
|
|
||||||
final YatService yatService;
|
final YatService yatService;
|
||||||
final WalletType walletType;
|
final WalletType walletType;
|
||||||
|
|
||||||
static const unstoppableDomains = [
|
static const unstoppableDomains = [
|
||||||
'crypto',
|
'crypto',
|
||||||
'zil',
|
'zil',
|
||||||
'x',
|
'x',
|
||||||
'coin',
|
'coin',
|
||||||
'wallet',
|
'wallet',
|
||||||
'bitcoin',
|
'bitcoin',
|
||||||
'888',
|
'888',
|
||||||
'nft',
|
'nft',
|
||||||
'dao',
|
'dao',
|
||||||
'blockchain'
|
'blockchain'
|
||||||
];
|
];
|
||||||
|
|
||||||
|
static String? extractAddressByType({required String raw, required CryptoCurrency type}) {
|
||||||
|
final addressPattern = AddressValidator.getAddressFromStringPattern(type);
|
||||||
|
|
||||||
|
if (addressPattern == null) {
|
||||||
|
throw 'Unexpected token: $type for getAddressFromStringPattern';
|
||||||
|
}
|
||||||
|
|
||||||
|
final match = RegExp(addressPattern).firstMatch(raw);
|
||||||
|
return match?.group(0)?.replaceAll(RegExp('[^0-9a-zA-Z]'), '');
|
||||||
|
}
|
||||||
|
|
||||||
Future<ParsedAddress> resolve(String text, String ticker) async {
|
Future<ParsedAddress> resolve(String text, String ticker) async {
|
||||||
try {
|
try {
|
||||||
if (text.contains('@') && !text.contains('.')) {
|
if (text.startsWith('@') && !text.substring(1).contains('@')) {
|
||||||
|
final formattedName = text.substring(1);
|
||||||
|
final twitterUser = await TwitterApi.lookupUserByName(userName: formattedName);
|
||||||
|
final addressFromBio = extractAddressByType(
|
||||||
|
raw: twitterUser.description, type: CryptoCurrency.fromString(ticker));
|
||||||
|
if (addressFromBio != null) {
|
||||||
|
return ParsedAddress.fetchTwitterAddress(address: addressFromBio, name: text);
|
||||||
|
}
|
||||||
|
final tweets = twitterUser.tweets;
|
||||||
|
if (tweets != null) {
|
||||||
|
var subString = StringBuffer();
|
||||||
|
tweets.forEach((item) {
|
||||||
|
subString.writeln(item.text);
|
||||||
|
});
|
||||||
|
final userTweetsText = subString.toString();
|
||||||
|
final addressFromPinnedTweet =
|
||||||
|
extractAddressByType(raw: userTweetsText, type: CryptoCurrency.fromString(ticker));
|
||||||
|
|
||||||
|
if (addressFromPinnedTweet != null) {
|
||||||
|
return ParsedAddress.fetchTwitterAddress(address: addressFromPinnedTweet, name: text);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!text.startsWith('@') && text.contains('@') && !text.contains('.')) {
|
||||||
final bool isFioRegistered = await FioAddressProvider.checkAvail(text);
|
final bool isFioRegistered = await FioAddressProvider.checkAvail(text);
|
||||||
if (isFioRegistered) {
|
if (isFioRegistered) {
|
||||||
final address = await FioAddressProvider.getPubAddress(text, ticker);
|
final address = await FioAddressProvider.getPubAddress(text, ticker);
|
||||||
return ParsedAddress.fetchFioAddress(address: address, name: text);
|
return ParsedAddress.fetchFioAddress(address: address, name: text);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
if (text.hasOnlyEmojis) {
|
if (text.hasOnlyEmojis) {
|
||||||
if (walletType != WalletType.haven) {
|
if (walletType != WalletType.haven) {
|
||||||
|
@ -55,10 +90,14 @@ class AddressResolver {
|
||||||
return ParsedAddress.fetchUnstoppableDomainAddress(address: address, name: text);
|
return ParsedAddress.fetchUnstoppableDomainAddress(address: address, name: text);
|
||||||
}
|
}
|
||||||
|
|
||||||
final record = await OpenaliasRecord.fetchAddressAndName(
|
if (formattedName.contains(".")) {
|
||||||
formattedName: formattedName, ticker: ticker);
|
final txtRecord = await OpenaliasRecord.lookupOpenAliasRecord(formattedName);
|
||||||
return ParsedAddress.fetchOpenAliasAddress(record: record, name: text);
|
if (txtRecord != null) {
|
||||||
|
final record = await OpenaliasRecord.fetchAddressAndName(
|
||||||
|
formattedName: formattedName, ticker: ticker, txtRecord: txtRecord);
|
||||||
|
return ParsedAddress.fetchOpenAliasAddress(record: record, name: text);
|
||||||
|
}
|
||||||
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print(e.toString());
|
print(e.toString());
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
import 'package:cake_wallet/entities/openalias_record.dart';
|
import 'package:cake_wallet/entities/openalias_record.dart';
|
||||||
import 'package:cake_wallet/entities/yat_record.dart';
|
import 'package:cake_wallet/entities/yat_record.dart';
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
|
|
||||||
enum ParseFrom { unstoppableDomains, openAlias, yatRecord, fio, notParsed }
|
enum ParseFrom { unstoppableDomains, openAlias, yatRecord, fio, notParsed, twitter }
|
||||||
|
|
||||||
class ParsedAddress {
|
class ParsedAddress {
|
||||||
ParsedAddress({
|
ParsedAddress({
|
||||||
|
@ -41,11 +40,7 @@ class ParsedAddress {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
factory ParsedAddress.fetchOpenAliasAddress({OpenaliasRecord? record, required String name}){
|
factory ParsedAddress.fetchOpenAliasAddress({required OpenaliasRecord record, required String name}){
|
||||||
final formattedName = OpenaliasRecord.formatDomainName(name);
|
|
||||||
if (record == null || record.address.contains(formattedName)) {
|
|
||||||
return ParsedAddress(addresses: [name]);
|
|
||||||
}
|
|
||||||
return ParsedAddress(
|
return ParsedAddress(
|
||||||
addresses: [record.address],
|
addresses: [record.address],
|
||||||
name: record.name,
|
name: record.name,
|
||||||
|
@ -62,6 +57,14 @@ class ParsedAddress {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
factory ParsedAddress.fetchTwitterAddress({required String address, required String name}){
|
||||||
|
return ParsedAddress(
|
||||||
|
addresses: [address],
|
||||||
|
name: name,
|
||||||
|
parseFrom: ParseFrom.twitter,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
final List<String> addresses;
|
final List<String> addresses;
|
||||||
final String name;
|
final String name;
|
||||||
final String description;
|
final String description;
|
||||||
|
|
|
@ -29,6 +29,7 @@ class PreferencesKey {
|
||||||
static const moneroWalletPasswordUpdateV1Base = 'monero_wallet_update_v1';
|
static const moneroWalletPasswordUpdateV1Base = 'monero_wallet_update_v1';
|
||||||
static const pinTimeOutDuration = 'pin_timeout_duration';
|
static const pinTimeOutDuration = 'pin_timeout_duration';
|
||||||
static const lastAuthTimeMilliseconds = 'last_auth_time_milliseconds';
|
static const lastAuthTimeMilliseconds = 'last_auth_time_milliseconds';
|
||||||
|
static const lastPopupDate = 'last_popup_date';
|
||||||
|
|
||||||
|
|
||||||
static String moneroWalletUpdateV1Key(String name)
|
static String moneroWalletUpdateV1Key(String name)
|
||||||
|
|
|
@ -7,7 +7,7 @@ Future<String> presentQRScanner() async {
|
||||||
try {
|
try {
|
||||||
final result = await BarcodeScanner.scan();
|
final result = await BarcodeScanner.scan();
|
||||||
isQrScannerShown = false;
|
isQrScannerShown = false;
|
||||||
return result.rawContent;
|
return result.rawContent.trim();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
isQrScannerShown = false;
|
isQrScannerShown = false;
|
||||||
rethrow;
|
rethrow;
|
||||||
|
|
|
@ -143,6 +143,7 @@ class ChangeNowExchangeProvider extends ExchangeProvider {
|
||||||
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?;
|
||||||
|
final payoutAddress = responseJSON['payoutAddress'] as String;
|
||||||
|
|
||||||
return Trade(
|
return Trade(
|
||||||
id: id,
|
id: id,
|
||||||
|
@ -154,7 +155,8 @@ class ChangeNowExchangeProvider extends ExchangeProvider {
|
||||||
extraId: extraId,
|
extraId: extraId,
|
||||||
createdAt: DateTime.now(),
|
createdAt: DateTime.now(),
|
||||||
amount: responseJSON['fromAmount']?.toString() ?? _request.fromAmount,
|
amount: responseJSON['fromAmount']?.toString() ?? _request.fromAmount,
|
||||||
state: TradeState.created);
|
state: TradeState.created,
|
||||||
|
payoutAddress: payoutAddress);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -192,6 +194,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 payoutAddress = responseJSON['payoutAddress'] as String;
|
||||||
final expiredAt = DateTime.tryParse(expiredAtRaw)?.toLocal();
|
final expiredAt = DateTime.tryParse(expiredAtRaw)?.toLocal();
|
||||||
|
|
||||||
return Trade(
|
return Trade(
|
||||||
|
@ -204,7 +207,8 @@ class ChangeNowExchangeProvider extends ExchangeProvider {
|
||||||
state: state,
|
state: state,
|
||||||
extraId: extraId,
|
extraId: extraId,
|
||||||
expiredAt: expiredAt,
|
expiredAt: expiredAt,
|
||||||
outputTransaction: outputTransaction);
|
outputTransaction: outputTransaction,
|
||||||
|
payoutAddress: payoutAddress);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -271,6 +275,10 @@ class ChangeNowExchangeProvider extends ExchangeProvider {
|
||||||
switch(currency) {
|
switch(currency) {
|
||||||
case CryptoCurrency.zec:
|
case CryptoCurrency.zec:
|
||||||
return 'zec';
|
return 'zec';
|
||||||
|
case CryptoCurrency.usdcpoly:
|
||||||
|
return 'usdcmatic';
|
||||||
|
case CryptoCurrency.maticpoly:
|
||||||
|
return 'maticmainnet';
|
||||||
default:
|
default:
|
||||||
return currency.title.toLowerCase();
|
return currency.title.toLowerCase();
|
||||||
}
|
}
|
||||||
|
|
|
@ -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');
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,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,
|
||||||
|
@ -38,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() {
|
||||||
|
@ -150,6 +150,7 @@ class SideShiftExchangeProvider extends ExchangeProvider {
|
||||||
refundAddress: settleAddress,
|
refundAddress: settleAddress,
|
||||||
state: TradeState.created,
|
state: TradeState.created,
|
||||||
amount: _request.depositAmount,
|
amount: _request.depositAmount,
|
||||||
|
payoutAddress: settleAddress,
|
||||||
createdAt: DateTime.now(),
|
createdAt: DateTime.now(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -244,6 +245,7 @@ class SideShiftExchangeProvider extends ExchangeProvider {
|
||||||
final inputAddress = responseJSON['depositAddress']['address'] as String;
|
final inputAddress = responseJSON['depositAddress']['address'] as String;
|
||||||
final expectedSendAmount = responseJSON['depositAmount'].toString();
|
final expectedSendAmount = responseJSON['depositAmount'].toString();
|
||||||
final deposits = responseJSON['deposits'] as List?;
|
final deposits = responseJSON['deposits'] as List?;
|
||||||
|
final settleAddress = responseJSON['settleAddress']['address'] as String;
|
||||||
TradeState? state;
|
TradeState? state;
|
||||||
String? status;
|
String? status;
|
||||||
|
|
||||||
|
@ -264,6 +266,7 @@ class SideShiftExchangeProvider extends ExchangeProvider {
|
||||||
amount: expectedSendAmount,
|
amount: expectedSendAmount,
|
||||||
state: state,
|
state: state,
|
||||||
expiredAt: expiredAt,
|
expiredAt: expiredAt,
|
||||||
|
payoutAddress: settleAddress
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -108,6 +108,7 @@ class SimpleSwapExchangeProvider extends ExchangeProvider {
|
||||||
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
|
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
|
||||||
final id = responseJSON['id'] as String;
|
final id = responseJSON['id'] as String;
|
||||||
final inputAddress = responseJSON['address_from'] as String;
|
final inputAddress = responseJSON['address_from'] as String;
|
||||||
|
final payoutAddress = responseJSON['address_to'] as String;
|
||||||
final settleAddress = responseJSON['user_refund_address'] as String;
|
final settleAddress = responseJSON['user_refund_address'] as String;
|
||||||
final extraId = responseJSON['extra_id_from'] as String?;
|
final extraId = responseJSON['extra_id_from'] as String?;
|
||||||
return Trade(
|
return Trade(
|
||||||
|
@ -120,6 +121,7 @@ class SimpleSwapExchangeProvider extends ExchangeProvider {
|
||||||
extraId: extraId,
|
extraId: extraId,
|
||||||
state: TradeState.created,
|
state: TradeState.created,
|
||||||
amount: _request.amount,
|
amount: _request.amount,
|
||||||
|
payoutAddress: payoutAddress,
|
||||||
createdAt: DateTime.now(),
|
createdAt: DateTime.now(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -189,6 +191,7 @@ class SimpleSwapExchangeProvider extends ExchangeProvider {
|
||||||
final expectedSendAmount = responseJSON['expected_amount'].toString();
|
final expectedSendAmount = responseJSON['expected_amount'].toString();
|
||||||
final extraId = responseJSON['extra_id_from'] as String?;
|
final extraId = responseJSON['extra_id_from'] as String?;
|
||||||
final status = responseJSON['status'] as String;
|
final status = responseJSON['status'] as String;
|
||||||
|
final payoutAddress = responseJSON['address_to'] as String;
|
||||||
final state = TradeState.deserialize(raw: status);
|
final state = TradeState.deserialize(raw: status);
|
||||||
|
|
||||||
return Trade(
|
return Trade(
|
||||||
|
@ -200,6 +203,7 @@ class SimpleSwapExchangeProvider extends ExchangeProvider {
|
||||||
inputAddress: inputAddress,
|
inputAddress: inputAddress,
|
||||||
amount: expectedSendAmount,
|
amount: expectedSendAmount,
|
||||||
state: state,
|
state: state,
|
||||||
|
payoutAddress: payoutAddress,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -231,6 +235,10 @@ class SimpleSwapExchangeProvider extends ExchangeProvider {
|
||||||
return 'usdcpoly';
|
return 'usdcpoly';
|
||||||
case CryptoCurrency.usdcsol:
|
case CryptoCurrency.usdcsol:
|
||||||
return 'usdcspl';
|
return 'usdcspl';
|
||||||
|
case CryptoCurrency.matic:
|
||||||
|
return 'maticerc20';
|
||||||
|
case CryptoCurrency.maticpoly:
|
||||||
|
return 'matic';
|
||||||
default:
|
default:
|
||||||
return currency.title.toLowerCase();
|
return currency.title.toLowerCase();
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,7 +21,8 @@ class Trade extends HiveObject {
|
||||||
this.extraId,
|
this.extraId,
|
||||||
this.outputTransaction,
|
this.outputTransaction,
|
||||||
this.refundAddress,
|
this.refundAddress,
|
||||||
this.walletId}) {
|
this.walletId,
|
||||||
|
this.payoutAddress}) {
|
||||||
if (provider != null) {
|
if (provider != null) {
|
||||||
providerRaw = provider.raw;
|
providerRaw = provider.raw;
|
||||||
}
|
}
|
||||||
|
@ -88,6 +89,9 @@ class Trade extends HiveObject {
|
||||||
@HiveField(12)
|
@HiveField(12)
|
||||||
String? walletId;
|
String? walletId;
|
||||||
|
|
||||||
|
@HiveField(13)
|
||||||
|
String? payoutAddress;
|
||||||
|
|
||||||
static Trade fromMap(Map<String, Object?> map) {
|
static Trade fromMap(Map<String, Object?> map) {
|
||||||
return Trade(
|
return Trade(
|
||||||
id: map['id'] as String,
|
id: map['id'] as String,
|
||||||
|
|
|
@ -1,11 +1,9 @@
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'package:cake_wallet/bitcoin/bitcoin.dart';
|
|
||||||
import 'package:cake_wallet/core/auth_service.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/ionia/ionia_category.dart';
|
|
||||||
import 'package:cake_wallet/ionia/ionia_merchant.dart';
|
|
||||||
import 'package:cake_wallet/store/yat/yat_store.dart';
|
import 'package:cake_wallet/store/yat/yat_store.dart';
|
||||||
|
import 'package:cake_wallet/utils/exception_handler.dart';
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
|
@ -41,11 +39,23 @@ 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 {
|
||||||
try {
|
|
||||||
|
await runZonedGuarded(() async {
|
||||||
WidgetsFlutterBinding.ensureInitialized();
|
WidgetsFlutterBinding.ensureInitialized();
|
||||||
|
|
||||||
|
FlutterError.onError = ExceptionHandler.onError;
|
||||||
|
|
||||||
|
/// A callback that is invoked when an unhandled error occurs in the root
|
||||||
|
/// isolate.
|
||||||
|
PlatformDispatcher.instance.onError = (error, stack) {
|
||||||
|
ExceptionHandler.onError(FlutterErrorDetails(exception: error, stack: stack));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
final appDir = await getApplicationDocumentsDirectory();
|
final appDir = await getApplicationDocumentsDirectory();
|
||||||
await Hive.close();
|
await Hive.close();
|
||||||
Hive.init(appDir.path);
|
Hive.init(appDir.path);
|
||||||
|
@ -131,18 +141,9 @@ Future<void> main() async {
|
||||||
secureStorage: secureStorage,
|
secureStorage: secureStorage,
|
||||||
initialMigrationVersion: 19);
|
initialMigrationVersion: 19);
|
||||||
runApp(App());
|
runApp(App());
|
||||||
} catch (e, stacktrace) {
|
}, (error, stackTrace) async {
|
||||||
runApp(MaterialApp(
|
ExceptionHandler.onError(FlutterErrorDetails(exception: error, stack: stackTrace));
|
||||||
debugShowCheckedModeBanner: true,
|
});
|
||||||
home: Scaffold(
|
|
||||||
body: Container(
|
|
||||||
margin:
|
|
||||||
EdgeInsets.only(top: 50, left: 20, right: 20, bottom: 20),
|
|
||||||
child: Text(
|
|
||||||
'Error:\n${e.toString()}\nStacktrace: $stacktrace',
|
|
||||||
style: TextStyle(fontSize: 22),
|
|
||||||
)))));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> initialSetup(
|
Future<void> initialSetup(
|
||||||
|
@ -279,6 +280,7 @@ class AppState extends State<App> with SingleTickerProviderStateMixin {
|
||||||
navigatorKey: navigatorKey,
|
navigatorKey: navigatorKey,
|
||||||
authService: authService,
|
authService: authService,
|
||||||
child: MaterialApp(
|
child: MaterialApp(
|
||||||
|
navigatorObservers: [routeObserver],
|
||||||
navigatorKey: navigatorKey,
|
navigatorKey: navigatorKey,
|
||||||
debugShowCheckedModeBanner: false,
|
debugShowCheckedModeBanner: false,
|
||||||
theme: settingsStore.theme,
|
theme: settingsStore.theme,
|
||||||
|
|
|
@ -9,11 +9,10 @@ import 'package:cake_wallet/src/screens/base_page.dart';
|
||||||
import 'package:cake_wallet/store/dashboard/orders_store.dart';
|
import 'package:cake_wallet/store/dashboard/orders_store.dart';
|
||||||
import 'package:cake_wallet/view_model/buy/buy_view_model.dart';
|
import 'package:cake_wallet/view_model/buy/buy_view_model.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:webview_flutter/webview_flutter.dart';
|
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
|
||||||
|
|
||||||
class BuyWebViewPage extends BasePage {
|
class BuyWebViewPage extends BasePage {
|
||||||
BuyWebViewPage({required this.buyViewModel,
|
BuyWebViewPage({required this.buyViewModel, required this.ordersStore, required this.url});
|
||||||
required this.ordersStore, required this.url});
|
|
||||||
|
|
||||||
final OrdersStore ordersStore;
|
final OrdersStore ordersStore;
|
||||||
final String url;
|
final String url;
|
||||||
|
@ -46,12 +45,12 @@ class BuyWebViewPageBody extends StatefulWidget {
|
||||||
|
|
||||||
class BuyWebViewPageBodyState extends State<BuyWebViewPageBody> {
|
class BuyWebViewPageBodyState extends State<BuyWebViewPageBody> {
|
||||||
BuyWebViewPageBodyState()
|
BuyWebViewPageBodyState()
|
||||||
: _webViewkey = GlobalKey(),
|
: _webViewkey = GlobalKey(),
|
||||||
_isSaving = false,
|
_isSaving = false,
|
||||||
orderId = '';
|
orderId = '';
|
||||||
|
|
||||||
String orderId;
|
String orderId;
|
||||||
WebViewController? _webViewController;
|
InAppWebViewController? _webViewController;
|
||||||
GlobalKey _webViewkey;
|
GlobalKey _webViewkey;
|
||||||
Timer? _timer;
|
Timer? _timer;
|
||||||
bool _isSaving;
|
bool _isSaving;
|
||||||
|
@ -63,8 +62,6 @@ class BuyWebViewPageBodyState extends State<BuyWebViewPageBody> {
|
||||||
_isSaving = false;
|
_isSaving = false;
|
||||||
widget.ordersStore.orderId = '';
|
widget.ordersStore.orderId = '';
|
||||||
|
|
||||||
if (Platform.isAndroid) WebView.platform = SurfaceAndroidWebView();
|
|
||||||
|
|
||||||
if (widget.buyViewModel.selectedProvider is WyreBuyProvider) {
|
if (widget.buyViewModel.selectedProvider is WyreBuyProvider) {
|
||||||
_saveOrder(keyword: 'completed', splitSymbol: '/');
|
_saveOrder(keyword: 'completed', splitSymbol: '/');
|
||||||
}
|
}
|
||||||
|
@ -76,31 +73,31 @@ class BuyWebViewPageBodyState extends State<BuyWebViewPageBody> {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return WebView(
|
return InAppWebView(
|
||||||
key: _webViewkey,
|
key: _webViewkey,
|
||||||
initialUrl: widget.url,
|
initialOptions: InAppWebViewGroupOptions(
|
||||||
javascriptMode: JavascriptMode.unrestricted,
|
crossPlatform: InAppWebViewOptions(transparentBackground: true),
|
||||||
onWebViewCreated: (WebViewController controller) =>
|
),
|
||||||
|
initialUrlRequest: URLRequest(url: Uri.tryParse(widget.url ?? '')),
|
||||||
|
onWebViewCreated: (InAppWebViewController controller) =>
|
||||||
setState(() => _webViewController = controller));
|
setState(() => _webViewController = controller));
|
||||||
}
|
}
|
||||||
|
|
||||||
void _saveOrder({required String keyword, required String splitSymbol}) {
|
void _saveOrder({required String keyword, required String splitSymbol}) {
|
||||||
_timer?.cancel();
|
_timer?.cancel();
|
||||||
_timer = Timer.periodic(Duration(seconds: 1), (timer) async {
|
_timer = Timer.periodic(Duration(seconds: 1), (timer) async {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (_webViewController == null || _isSaving) {
|
if (_webViewController == null || _isSaving) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
final url = await _webViewController!.currentUrl();
|
final url = (await _webViewController!.getUrl())?.toString();
|
||||||
|
|
||||||
if (url == null) {
|
if (url == null) {
|
||||||
throw Exception('_saveOrder: Url is null');
|
throw Exception('_saveOrder: Url is null');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (url!.contains(keyword)) {
|
if (url.contains(keyword)) {
|
||||||
final urlParts = url!.split(splitSymbol);
|
final urlParts = url.split(splitSymbol);
|
||||||
orderId = urlParts.last;
|
orderId = urlParts.last;
|
||||||
widget.ordersStore.orderId = orderId;
|
widget.ordersStore.orderId = orderId;
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,9 @@ import 'package:cake_wallet/buy/onramper/onramper_buy_provider.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:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:webview_flutter/webview_flutter.dart';
|
import 'package:cake_wallet/.secrets.g.dart' as secrets;
|
||||||
|
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
|
||||||
|
import 'package:permission_handler/permission_handler.dart';
|
||||||
|
|
||||||
class OnRamperPage extends BasePage {
|
class OnRamperPage extends BasePage {
|
||||||
OnRamperPage(this._onRamperBuyProvider);
|
OnRamperPage(this._onRamperBuyProvider);
|
||||||
|
@ -44,17 +46,26 @@ class OnRamperPageBody extends StatefulWidget {
|
||||||
class OnRamperPageBodyState extends State<OnRamperPageBody> {
|
class OnRamperPageBodyState extends State<OnRamperPageBody> {
|
||||||
OnRamperPageBodyState();
|
OnRamperPageBodyState();
|
||||||
|
|
||||||
@override
|
|
||||||
void initState() {
|
|
||||||
super.initState();
|
|
||||||
if (Platform.isAndroid) WebView.platform = SurfaceAndroidWebView();
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return WebView(
|
return InAppWebView(
|
||||||
initialUrl: widget.uri.toString(),
|
initialOptions: InAppWebViewGroupOptions(
|
||||||
backgroundColor: widget.backgroundColor,
|
crossPlatform: InAppWebViewOptions(transparentBackground: true),
|
||||||
javascriptMode: JavascriptMode.unrestricted);
|
),
|
||||||
|
initialUrlRequest: URLRequest(url: widget.uri),
|
||||||
|
androidOnPermissionRequest: (_, __, resources) async {
|
||||||
|
bool permissionGranted = await Permission.camera.status == PermissionStatus.granted;
|
||||||
|
if (!permissionGranted) {
|
||||||
|
permissionGranted = await Permission.camera.request().isGranted;
|
||||||
|
}
|
||||||
|
|
||||||
|
return PermissionRequestResponse(
|
||||||
|
resources: resources,
|
||||||
|
action: permissionGranted
|
||||||
|
? PermissionRequestResponseAction.GRANT
|
||||||
|
: PermissionRequestResponseAction.DENY,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -72,10 +72,10 @@ class ContactListPage extends BasePage {
|
||||||
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(
|
||||||
|
|
|
@ -1,10 +1,8 @@
|
||||||
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_one_action.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/keyboard_done_button.dart';
|
import 'package:cake_wallet/src/widgets/keyboard_done_button.dart';
|
||||||
import 'package:cake_wallet/src/widgets/primary_button.dart';
|
|
||||||
import 'package:cake_wallet/store/settings_store.dart';
|
|
||||||
import 'package:cake_wallet/themes/theme_base.dart';
|
import 'package:cake_wallet/themes/theme_base.dart';
|
||||||
|
import 'package:cake_wallet/utils/share_util.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';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
@ -15,7 +13,6 @@ import 'package:cake_wallet/generated/i18n.dart';
|
||||||
import 'package:flutter_mobx/flutter_mobx.dart';
|
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||||
import 'package:keyboard_actions/keyboard_actions.dart';
|
import 'package:keyboard_actions/keyboard_actions.dart';
|
||||||
import 'package:mobx/mobx.dart';
|
import 'package:mobx/mobx.dart';
|
||||||
import 'package:share_plus/share_plus.dart';
|
|
||||||
|
|
||||||
class AddressPage extends BasePage {
|
class AddressPage extends BasePage {
|
||||||
AddressPage({
|
AddressPage({
|
||||||
|
@ -84,7 +81,12 @@ class AddressPage extends BasePage {
|
||||||
highlightColor: Colors.transparent,
|
highlightColor: Colors.transparent,
|
||||||
splashColor: Colors.transparent,
|
splashColor: Colors.transparent,
|
||||||
iconSize: 25,
|
iconSize: 25,
|
||||||
onPressed: () => Share.share(addressListViewModel.address.address),
|
onPressed: () {
|
||||||
|
ShareUtil.share(
|
||||||
|
text: addressListViewModel.address.address,
|
||||||
|
context: context,
|
||||||
|
);
|
||||||
|
},
|
||||||
icon: shareImage,
|
icon: shareImage,
|
||||||
),
|
),
|
||||||
) : null;
|
) : null;
|
||||||
|
|
|
@ -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,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,127 +28,80 @@ 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)
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
|
@ -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,
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:cw_core/transaction_direction.dart';
|
import 'package:cw_core/transaction_direction.dart';
|
||||||
import 'package:cake_wallet/generated/i18n.dart';
|
|
||||||
|
|
||||||
class TransactionRow extends StatelessWidget {
|
class TransactionRow extends StatelessWidget {
|
||||||
TransactionRow(
|
TransactionRow(
|
||||||
|
@ -9,6 +8,7 @@ class TransactionRow extends StatelessWidget {
|
||||||
required this.formattedAmount,
|
required this.formattedAmount,
|
||||||
required this.formattedFiatAmount,
|
required this.formattedFiatAmount,
|
||||||
required this.isPending,
|
required this.isPending,
|
||||||
|
required this.title,
|
||||||
required this.onTap});
|
required this.onTap});
|
||||||
|
|
||||||
final VoidCallback onTap;
|
final VoidCallback onTap;
|
||||||
|
@ -17,6 +17,7 @@ class TransactionRow extends StatelessWidget {
|
||||||
final String formattedAmount;
|
final String formattedAmount;
|
||||||
final String formattedFiatAmount;
|
final String formattedFiatAmount;
|
||||||
final bool isPending;
|
final bool isPending;
|
||||||
|
final String title;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
@ -49,11 +50,7 @@ class TransactionRow extends StatelessWidget {
|
||||||
Row(
|
Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
Text(
|
Text(title,
|
||||||
(direction == TransactionDirection.incoming
|
|
||||||
? S.of(context).received
|
|
||||||
: S.of(context).sent) +
|
|
||||||
(isPending ? S.of(context).pending : ''),
|
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
fontWeight: FontWeight.w500,
|
fontWeight: FontWeight.w500,
|
||||||
|
|
|
@ -61,7 +61,8 @@ class TransactionsPage extends StatelessWidget {
|
||||||
formattedFiatAmount:
|
formattedFiatAmount:
|
||||||
dashboardViewModel.balanceViewModel.isFiatDisabled
|
dashboardViewModel.balanceViewModel.isFiatDisabled
|
||||||
? '' : item.formattedFiatAmount,
|
? '' : item.formattedFiatAmount,
|
||||||
isPending: transaction.isPending));
|
isPending: transaction.isPending,
|
||||||
|
title: item.formattedTitle + item.formattedStatus));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (item is TradeListItem) {
|
if (item is TradeListItem) {
|
||||||
|
|
|
@ -48,7 +48,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();
|
||||||
|
@ -150,7 +149,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) =>
|
||||||
|
@ -452,12 +450,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);
|
||||||
|
|
||||||
|
|
|
@ -55,7 +55,7 @@ class CurrencyPickerState extends State<CurrencyPicker> {
|
||||||
.where((element) =>
|
.where((element) =>
|
||||||
(element.title.toLowerCase().contains(subString.toLowerCase())) ||
|
(element.title.toLowerCase().contains(subString.toLowerCase())) ||
|
||||||
(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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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';
|
||||||
|
@ -112,7 +112,7 @@ class ExchangeTradeState extends State<ExchangeTradeForm> {
|
||||||
width: 16,
|
width: 16,
|
||||||
color: Theme.of(context).primaryTextTheme!.overline!.color!);
|
color: Theme.of(context).primaryTextTheme!.overline!.color!);
|
||||||
|
|
||||||
_setEffects(context);
|
_setEffects();
|
||||||
|
|
||||||
return Container(
|
return Container(
|
||||||
child: ScrollableWithBottomSection(
|
child: ScrollableWithBottomSection(
|
||||||
|
@ -165,14 +165,7 @@ class ExchangeTradeState extends State<ExchangeTradeForm> {
|
||||||
.color!
|
.color!
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
child: QrImage(
|
child: QrImage(data: trade.inputAddress ?? fetchingLabel),
|
||||||
data: trade.inputAddress ?? fetchingLabel,
|
|
||||||
backgroundColor: Colors.transparent,
|
|
||||||
foregroundColor: Theme.of(context)
|
|
||||||
.accentTextTheme!
|
|
||||||
.subtitle2!
|
|
||||||
.color!,
|
|
||||||
),
|
|
||||||
)))),
|
)))),
|
||||||
Spacer(flex: 3)
|
Spacer(flex: 3)
|
||||||
]),
|
]),
|
||||||
|
@ -194,7 +187,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,
|
||||||
|
@ -241,7 +234,7 @@ class ExchangeTradeState extends State<ExchangeTradeForm> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _setEffects(BuildContext context) {
|
void _setEffects() {
|
||||||
if (_effectsInstalled) {
|
if (_effectsInstalled) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -252,12 +245,12 @@ class ExchangeTradeState extends State<ExchangeTradeForm> {
|
||||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
showPopUp<void>(
|
showPopUp<void>(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (BuildContext context) {
|
builder: (BuildContext popupContext) {
|
||||||
return AlertWithOneAction(
|
return AlertWithOneAction(
|
||||||
alertTitle: S.of(context).error,
|
alertTitle: S.of(popupContext).error,
|
||||||
alertContent: state.error,
|
alertContent: state.error,
|
||||||
buttonText: S.of(context).ok,
|
buttonText: S.of(popupContext).ok,
|
||||||
buttonAction: () => Navigator.of(context).pop());
|
buttonAction: () => Navigator.of(popupContext).pop());
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -266,118 +259,24 @@ class ExchangeTradeState extends State<ExchangeTradeForm> {
|
||||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
showPopUp<void>(
|
showPopUp<void>(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (BuildContext context) {
|
builder: (BuildContext popupContext) {
|
||||||
return ConfirmSendingAlert(
|
return ConfirmSendingAlert(
|
||||||
alertTitle: S.of(context).confirm_sending,
|
alertTitle: S.of(popupContext).confirm_sending,
|
||||||
amount: S.of(context).send_amount,
|
amount: S.of(popupContext).send_amount,
|
||||||
amountValue: widget.exchangeTradeViewModel.sendViewModel
|
amountValue: widget.exchangeTradeViewModel.sendViewModel
|
||||||
.pendingTransaction!.amountFormatted,
|
.pendingTransaction!.amountFormatted,
|
||||||
fee: S.of(context).send_fee,
|
fee: S.of(popupContext).send_fee,
|
||||||
feeValue: widget.exchangeTradeViewModel.sendViewModel
|
feeValue: widget.exchangeTradeViewModel.sendViewModel
|
||||||
.pendingTransaction!.feeFormatted,
|
.pendingTransaction!.feeFormatted,
|
||||||
rightButtonText: S.of(context).ok,
|
rightButtonText: S.of(popupContext).ok,
|
||||||
leftButtonText: S.of(context).cancel,
|
leftButtonText: S.of(popupContext).cancel,
|
||||||
actionRightButton: () async {
|
actionRightButton: () async {
|
||||||
Navigator.of(context).pop();
|
Navigator.of(popupContext).pop();
|
||||||
await widget.exchangeTradeViewModel.sendViewModel
|
await widget.exchangeTradeViewModel.sendViewModel
|
||||||
.commitTransaction();
|
.commitTransaction();
|
||||||
await showPopUp<void>(
|
transactionStatePopup();
|
||||||
context: context,
|
|
||||||
builder: (BuildContext context) {
|
|
||||||
return Observer(builder: (_) {
|
|
||||||
final state = widget
|
|
||||||
.exchangeTradeViewModel.sendViewModel.state;
|
|
||||||
|
|
||||||
if (state is TransactionCommitted) {
|
|
||||||
return Stack(
|
|
||||||
children: <Widget>[
|
|
||||||
Container(
|
|
||||||
color: Theme.of(context).backgroundColor,
|
|
||||||
child: Center(
|
|
||||||
child: Image.asset(
|
|
||||||
'assets/images/birthday_cake.png'),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Center(
|
|
||||||
child: Padding(
|
|
||||||
padding: EdgeInsets.only(
|
|
||||||
top: 220, left: 24, right: 24),
|
|
||||||
child: Text(
|
|
||||||
S.of(context).send_success(widget
|
|
||||||
.exchangeTradeViewModel
|
|
||||||
.wallet
|
|
||||||
.currency
|
|
||||||
.toString()),
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 22,
|
|
||||||
fontWeight: FontWeight.bold,
|
|
||||||
color: Theme.of(context)
|
|
||||||
.primaryTextTheme!
|
|
||||||
.headline6!
|
|
||||||
.color,
|
|
||||||
decoration: TextDecoration.none,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Positioned(
|
|
||||||
left: 24,
|
|
||||||
right: 24,
|
|
||||||
bottom: 24,
|
|
||||||
child: PrimaryButton(
|
|
||||||
onPressed: () =>
|
|
||||||
Navigator.of(context).pop(),
|
|
||||||
text: S.of(context).send_got_it,
|
|
||||||
color: Theme.of(context)
|
|
||||||
.accentTextTheme!
|
|
||||||
.bodyText1!
|
|
||||||
.color!,
|
|
||||||
textColor: Colors.white))
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Stack(
|
|
||||||
children: <Widget>[
|
|
||||||
Container(
|
|
||||||
color: Theme.of(context).backgroundColor,
|
|
||||||
child: Center(
|
|
||||||
child: Image.asset(
|
|
||||||
'assets/images/birthday_cake.png'),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
BackdropFilter(
|
|
||||||
filter: ImageFilter.blur(
|
|
||||||
sigmaX: 3.0, sigmaY: 3.0),
|
|
||||||
child: Container(
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: Theme.of(context)
|
|
||||||
.backgroundColor
|
|
||||||
.withOpacity(0.25)),
|
|
||||||
child: Center(
|
|
||||||
child: Padding(
|
|
||||||
padding: EdgeInsets.only(top: 220),
|
|
||||||
child: Text(
|
|
||||||
S.of(context).send_sending,
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 22,
|
|
||||||
fontWeight: FontWeight.bold,
|
|
||||||
color: Theme.of(context).primaryTextTheme!.headline6!.color!,
|
|
||||||
decoration: TextDecoration.none,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
],
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
actionLeftButton: () => Navigator.of(context).pop(),
|
actionLeftButton: () => Navigator.of(popupContext).pop(),
|
||||||
feeFiatAmount: widget.exchangeTradeViewModel
|
feeFiatAmount: widget.exchangeTradeViewModel
|
||||||
.pendingTransactionFeeFiatAmountFormatted,
|
.pendingTransactionFeeFiatAmountFormatted,
|
||||||
fiatAmountValue: widget.exchangeTradeViewModel
|
fiatAmountValue: widget.exchangeTradeViewModel
|
||||||
|
@ -392,12 +291,12 @@ class ExchangeTradeState extends State<ExchangeTradeForm> {
|
||||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
showPopUp<void>(
|
showPopUp<void>(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (BuildContext context) {
|
builder: (BuildContext popupContext) {
|
||||||
return AlertWithOneAction(
|
return AlertWithOneAction(
|
||||||
alertTitle: S.of(context).sending,
|
alertTitle: S.of(popupContext).sending,
|
||||||
alertContent: S.of(context).transaction_sent,
|
alertContent: S.of(popupContext).transaction_sent,
|
||||||
buttonText: S.of(context).ok,
|
buttonText: S.of(popupContext).ok,
|
||||||
buttonAction: () => Navigator.of(context).pop());
|
buttonAction: () => Navigator.of(popupContext).pop());
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -405,4 +304,102 @@ class ExchangeTradeState extends State<ExchangeTradeForm> {
|
||||||
|
|
||||||
_effectsInstalled = true;
|
_effectsInstalled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void transactionStatePopup() {
|
||||||
|
showPopUp<void>(
|
||||||
|
context: context,
|
||||||
|
builder: (BuildContext popupContext) {
|
||||||
|
return Observer(builder: (_) {
|
||||||
|
final state = widget
|
||||||
|
.exchangeTradeViewModel.sendViewModel.state;
|
||||||
|
|
||||||
|
if (state is TransactionCommitted) {
|
||||||
|
return Stack(
|
||||||
|
children: <Widget>[
|
||||||
|
Container(
|
||||||
|
color: Theme.of(popupContext).backgroundColor,
|
||||||
|
child: Center(
|
||||||
|
child: Image.asset(
|
||||||
|
'assets/images/birthday_cake.png'),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Center(
|
||||||
|
child: Padding(
|
||||||
|
padding: EdgeInsets.only(
|
||||||
|
top: 220, left: 24, right: 24),
|
||||||
|
child: Text(
|
||||||
|
S.of(popupContext).send_success(widget
|
||||||
|
.exchangeTradeViewModel
|
||||||
|
.wallet
|
||||||
|
.currency
|
||||||
|
.toString()),
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 22,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
color: Theme.of(popupContext)
|
||||||
|
.primaryTextTheme!
|
||||||
|
.headline6!
|
||||||
|
.color,
|
||||||
|
decoration: TextDecoration.none,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Positioned(
|
||||||
|
left: 24,
|
||||||
|
right: 24,
|
||||||
|
bottom: 24,
|
||||||
|
child: PrimaryButton(
|
||||||
|
onPressed: () =>
|
||||||
|
Navigator.of(popupContext).pop(),
|
||||||
|
text: S.of(popupContext).send_got_it,
|
||||||
|
color: Theme.of(popupContext)
|
||||||
|
.accentTextTheme!
|
||||||
|
.bodyText1!
|
||||||
|
.color!,
|
||||||
|
textColor: Colors.white))
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Stack(
|
||||||
|
children: <Widget>[
|
||||||
|
Container(
|
||||||
|
color: Theme.of(popupContext).backgroundColor,
|
||||||
|
child: Center(
|
||||||
|
child: Image.asset(
|
||||||
|
'assets/images/birthday_cake.png'),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
BackdropFilter(
|
||||||
|
filter: ImageFilter.blur(
|
||||||
|
sigmaX: 3.0, sigmaY: 3.0),
|
||||||
|
child: Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Theme.of(popupContext)
|
||||||
|
.backgroundColor
|
||||||
|
.withOpacity(0.25)),
|
||||||
|
child: Center(
|
||||||
|
child: Padding(
|
||||||
|
padding: EdgeInsets.only(top: 220),
|
||||||
|
child: Text(
|
||||||
|
S.of(popupContext).send_sending,
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 22,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
color: Theme.of(popupContext).primaryTextTheme!.headline6!.color!,
|
||||||
|
decoration: TextDecoration.none,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,8 +32,8 @@ class IoniaCreateAccountPage extends BasePage {
|
||||||
final FocusNode _emailFocus;
|
final FocusNode _emailFocus;
|
||||||
final TextEditingController _emailController;
|
final TextEditingController _emailController;
|
||||||
|
|
||||||
static const privacyPolicyUrl = 'https://ionia.docsend.com/view/jaqsmbq9w7dzvnqf';
|
static const privacyPolicyUrl = 'https://ionia.docsend.com/view/jhjvdn7qq7k3ukwt';
|
||||||
static const termsAndConditionsUrl = 'https://ionia.docsend.com/view/hi9awnwxr6mqgiqj';
|
static const termsAndConditionsUrl = 'https://ionia.docsend.com/view/uceirymz2ijacq5g';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget middle(BuildContext context) {
|
Widget middle(BuildContext context) {
|
||||||
|
|
|
@ -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';
|
||||||
|
@ -47,10 +48,7 @@ class IoniaGiftCardDetailPage extends BasePage {
|
||||||
//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),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -68,7 +66,6 @@ class IoniaGiftCardDetailPage extends BasePage {
|
||||||
|
|
||||||
@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((_) {
|
||||||
|
@ -85,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: [
|
||||||
|
@ -164,7 +166,7 @@ class IoniaGiftCardDetailPage extends BasePage {
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget buildIoniaTile(BuildContext context, {required String title, required String subTitle}) {
|
Widget buildIoniaTile(BuildContext context, {required String title, required String subTitle}) {
|
||||||
|
|
|
@ -157,7 +157,8 @@ class _IoniaPaymentStatusPageBodyBodyState extends State<_IoniaPaymentStatusPage
|
||||||
Container(
|
Container(
|
||||||
padding: EdgeInsets.only(left: 40, right: 40, bottom: 20),
|
padding: EdgeInsets.only(left: 40, right: 40, bottom: 20),
|
||||||
child: Text(
|
child: Text(
|
||||||
S.of(context).proceed_after_one_minute,
|
widget.viewModel.payingByBitcoin ? S.of(context).bitcoin_payments_require_1_confirmation
|
||||||
|
: S.of(context).proceed_after_one_minute,
|
||||||
style: textMedium(
|
style: textMedium(
|
||||||
color: Theme.of(context).primaryTextTheme!.headline6!.color!,
|
color: Theme.of(context).primaryTextTheme!.headline6!.color!,
|
||||||
).copyWith(fontWeight: FontWeight.w500),
|
).copyWith(fontWeight: FontWeight.w500),
|
||||||
|
|
|
@ -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];
|
||||||
|
|
|
@ -1,9 +1,5 @@
|
||||||
import 'package:cake_wallet/generated/i18n.dart';
|
|
||||||
import 'package:cake_wallet/palette.dart';
|
|
||||||
import 'package:cake_wallet/src/screens/nodes/widgets/node_indicator.dart';
|
import 'package:cake_wallet/src/screens/nodes/widgets/node_indicator.dart';
|
||||||
import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart';
|
|
||||||
import 'package:cake_wallet/src/widgets/standard_list.dart';
|
import 'package:cake_wallet/src/widgets/standard_list.dart';
|
||||||
import 'package:flutter/cupertino.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
class NodeListRow extends StandardListRow {
|
class NodeListRow extends StandardListRow {
|
||||||
|
@ -23,7 +19,7 @@ class NodeListRow extends StandardListRow {
|
||||||
builder: (context, snapshot) {
|
builder: (context, snapshot) {
|
||||||
switch (snapshot.connectionState) {
|
switch (snapshot.connectionState) {
|
||||||
case ConnectionState.done:
|
case ConnectionState.done:
|
||||||
return NodeIndicator(isLive: (snapshot.data as bool)??false);
|
return NodeIndicator(isLive: (snapshot.data as bool?) ?? false);
|
||||||
default:
|
default:
|
||||||
return NodeIndicator(isLive: false);
|
return NodeIndicator(isLive: false);
|
||||||
}
|
}
|
||||||
|
@ -40,7 +36,7 @@ class NodeHeaderListRow extends StandardListRow {
|
||||||
return SizedBox(
|
return SizedBox(
|
||||||
width: 20,
|
width: 20,
|
||||||
child: Icon(Icons.add,
|
child: Icon(Icons.add,
|
||||||
color: Theme.of(context).accentTextTheme!.subtitle1!.color!, size: 24.0),
|
color: Theme.of(context).accentTextTheme.subtitle1?.color, size: 24.0),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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}'));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
import 'package:cake_wallet/src/screens/receive/widgets/qr_image.dart';
|
import 'package:cake_wallet/src/screens/receive/widgets/qr_image.dart';
|
||||||
import 'package:cake_wallet/themes/theme_base.dart';
|
import 'package:cake_wallet/themes/theme_base.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/cupertino.dart';
|
|
||||||
import 'package:cake_wallet/src/screens/base_page.dart';
|
import 'package:cake_wallet/src/screens/base_page.dart';
|
||||||
|
|
||||||
class FullscreenQRPage extends BasePage {
|
class FullscreenQRPage extends BasePage {
|
||||||
|
@ -69,14 +68,10 @@ class FullscreenQRPage extends BasePage {
|
||||||
child: AspectRatio(
|
child: AspectRatio(
|
||||||
aspectRatio: 1.0,
|
aspectRatio: 1.0,
|
||||||
child: Container(
|
child: Container(
|
||||||
padding: EdgeInsets.all(5),
|
padding: EdgeInsets.all(10),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
border: Border.all(width: 3, color: Theme.of(context).accentTextTheme!.headline2!.backgroundColor!)),
|
border: Border.all(width: 3, color: Theme.of(context).accentTextTheme!.headline2!.backgroundColor!)),
|
||||||
child: QrImage(
|
child: QrImage(data: qrData),
|
||||||
data: qrData,
|
|
||||||
backgroundColor: isLight ? Colors.transparent : Colors.black,
|
|
||||||
foregroundColor: Theme.of(context).accentTextTheme!.headline2!.backgroundColor!,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
|
@ -1,12 +1,11 @@
|
||||||
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/share_util.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:cw_core/wallet_type.dart';
|
import 'package:cw_core/wallet_type.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/cupertino.dart';
|
|
||||||
import 'package:flutter_mobx/flutter_mobx.dart';
|
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||||
import 'package:share_plus/share_plus.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/di.dart';
|
import 'package:cake_wallet/di.dart';
|
||||||
|
@ -100,7 +99,12 @@ class ReceivePage extends BasePage {
|
||||||
highlightColor: Colors.transparent,
|
highlightColor: Colors.transparent,
|
||||||
splashColor: Colors.transparent,
|
splashColor: Colors.transparent,
|
||||||
iconSize: 25,
|
iconSize: 25,
|
||||||
onPressed: () => Share.share(addressListViewModel.address.address),
|
onPressed: () {
|
||||||
|
ShareUtil.share(
|
||||||
|
text: addressListViewModel.address.address,
|
||||||
|
context: context,
|
||||||
|
);
|
||||||
|
},
|
||||||
icon: shareImage
|
icon: shareImage
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
@ -135,8 +139,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,
|
||||||
|
|
|
@ -1,30 +1,29 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:qr/qr.dart';
|
import 'package:qr_flutter/qr_flutter.dart' as qr;
|
||||||
import 'package:cake_wallet/src/screens/receive/widgets/qr_painter.dart';
|
|
||||||
|
|
||||||
class QrImage extends StatelessWidget {
|
class QrImage extends StatelessWidget {
|
||||||
QrImage({
|
QrImage({
|
||||||
required String data,
|
required this.data,
|
||||||
this.size = 100.0,
|
this.size = 100.0,
|
||||||
this.backgroundColor,
|
this.version = 9, // Previous value: 7 something happened after flutter upgrade monero wallets addresses are longer than ver. 7 ???
|
||||||
Color foregroundColor = Colors.black,
|
this.errorCorrectionLevel = qr.QrErrorCorrectLevel.L,
|
||||||
int version = 9, // Previous value: 7 something happened after flutter upgrade monero wallets addresses are longer than ver. 7 ???
|
});
|
||||||
int errorCorrectionLevel = QrErrorCorrectLevel.L,
|
|
||||||
}) : _painter = QrPainter(data, foregroundColor, version, errorCorrectionLevel);
|
|
||||||
|
|
||||||
final QrPainter _painter;
|
|
||||||
final Color? backgroundColor;
|
|
||||||
final double size;
|
final double size;
|
||||||
|
final String data;
|
||||||
|
final int version;
|
||||||
|
final int errorCorrectionLevel;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Container(
|
return qr.QrImage(
|
||||||
width: size,
|
data: data,
|
||||||
height: size,
|
errorCorrectionLevel: errorCorrectionLevel,
|
||||||
color: backgroundColor,
|
version: version,
|
||||||
child: CustomPaint(
|
size: size,
|
||||||
painter: _painter,
|
foregroundColor: Colors.black,
|
||||||
),
|
backgroundColor: Colors.white,
|
||||||
|
padding: EdgeInsets.zero,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,47 +0,0 @@
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:qr/qr.dart';
|
|
||||||
|
|
||||||
class QrPainter extends CustomPainter {
|
|
||||||
QrPainter(
|
|
||||||
String data,
|
|
||||||
this.color,
|
|
||||||
this.version,
|
|
||||||
this.errorCorrectionLevel,
|
|
||||||
) : this._qr = QrCode(version, errorCorrectionLevel)..addData(data) {
|
|
||||||
_p.color = this.color;
|
|
||||||
_qrImage = QrImage(_qr);
|
|
||||||
}
|
|
||||||
|
|
||||||
final int version;
|
|
||||||
final int errorCorrectionLevel;
|
|
||||||
final Color color;
|
|
||||||
|
|
||||||
final QrCode _qr;
|
|
||||||
final _p = Paint()..style = PaintingStyle.fill;
|
|
||||||
late QrImage _qrImage;
|
|
||||||
|
|
||||||
@override
|
|
||||||
void paint(Canvas canvas, Size size) {
|
|
||||||
final squareSize = size.shortestSide / _qr.moduleCount;
|
|
||||||
for (int x = 0; x < _qr.moduleCount; x++) {
|
|
||||||
for (int y = 0; y < _qr.moduleCount; y++) {
|
|
||||||
if (_qrImage.isDark(y, x)) {
|
|
||||||
final squareRect = Rect.fromLTWH(
|
|
||||||
x * squareSize, y * squareSize, squareSize, squareSize);
|
|
||||||
canvas.drawRect(squareRect, _p);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
bool shouldRepaint(CustomPainter oldDelegate) {
|
|
||||||
if (oldDelegate is QrPainter) {
|
|
||||||
return this.color != oldDelegate.color ||
|
|
||||||
this.errorCorrectionLevel != oldDelegate.errorCorrectionLevel ||
|
|
||||||
this.version != oldDelegate.version;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -85,11 +85,7 @@ class QRWidget extends StatelessWidget {
|
||||||
color: Theme.of(context).accentTextTheme!.headline2!.backgroundColor!,
|
color: Theme.of(context).accentTextTheme!.headline2!.backgroundColor!,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
child: QrImage(
|
child: QrImage(data: addressListViewModel.uri.toString()),
|
||||||
data: addressListViewModel.uri.toString(),
|
|
||||||
backgroundColor: isLight ? Colors.transparent : Colors.black,
|
|
||||||
foregroundColor: Theme.of(context).accentTextTheme!.headline2!.backgroundColor!,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
import 'package:cake_wallet/palette.dart';
|
import 'package:cake_wallet/palette.dart';
|
||||||
import 'package:cake_wallet/themes/theme_base.dart';
|
import 'package:cake_wallet/themes/theme_base.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/utils/share_util.dart';
|
||||||
import 'package:cake_wallet/utils/responsive_layout_util.dart';
|
import 'package:cake_wallet/utils/responsive_layout_util.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:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
import 'package:share_plus/share_plus.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/widgets/primary_button.dart';
|
import 'package:cake_wallet/src/widgets/primary_button.dart';
|
||||||
|
@ -22,9 +22,6 @@ class WalletSeedPage extends BasePage {
|
||||||
@override
|
@override
|
||||||
String get title => S.current.seed_title;
|
String get title => S.current.seed_title;
|
||||||
|
|
||||||
@override
|
|
||||||
bool get canUseDesktopAppBar => false;
|
|
||||||
|
|
||||||
final bool isNewWalletCreated;
|
final bool isNewWalletCreated;
|
||||||
final WalletSeedViewModel walletSeedViewModel;
|
final WalletSeedViewModel walletSeedViewModel;
|
||||||
|
|
||||||
|
@ -166,8 +163,12 @@ class WalletSeedPage extends BasePage {
|
||||||
child: Container(
|
child: Container(
|
||||||
padding: EdgeInsets.only(right: 8.0),
|
padding: EdgeInsets.only(right: 8.0),
|
||||||
child: PrimaryButton(
|
child: PrimaryButton(
|
||||||
onPressed: () =>
|
onPressed: () {
|
||||||
Share.share(walletSeedViewModel.seed),
|
ShareUtil.share(
|
||||||
|
text: walletSeedViewModel.seed,
|
||||||
|
context: context,
|
||||||
|
);
|
||||||
|
},
|
||||||
text: S.of(context).save,
|
text: S.of(context).save,
|
||||||
color: Colors.green,
|
color: Colors.green,
|
||||||
textColor: Colors.white),
|
textColor: Colors.white),
|
||||||
|
|
|
@ -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];
|
||||||
|
|
||||||
|
|
|
@ -19,13 +19,18 @@ Future<String> extractAddressFromParsed(
|
||||||
address = parsedAddress.addresses.first;
|
address = parsedAddress.addresses.first;
|
||||||
break;
|
break;
|
||||||
case ParseFrom.openAlias:
|
case ParseFrom.openAlias:
|
||||||
title = S.of(context).openalias_alert_title;
|
title = S.of(context).address_detected;
|
||||||
content = S.of(context).openalias_alert_content(parsedAddress.name);
|
content = S.of(context).extracted_address_content('${parsedAddress.name} (OpenAlias)');
|
||||||
address = parsedAddress.addresses.first;
|
address = parsedAddress.addresses.first;
|
||||||
break;
|
break;
|
||||||
case ParseFrom.fio:
|
case ParseFrom.fio:
|
||||||
title = S.of(context).address_detected;
|
title = S.of(context).address_detected;
|
||||||
content = S.of(context).openalias_alert_content(parsedAddress.name);
|
content = S.of(context).extracted_address_content('${parsedAddress.name} (FIO)');
|
||||||
|
address = parsedAddress.addresses.first;
|
||||||
|
break;
|
||||||
|
case ParseFrom.twitter:
|
||||||
|
title = S.of(context).address_detected;
|
||||||
|
content = S.of(context).extracted_address_content('${parsedAddress.name} (Twitter)');
|
||||||
address = parsedAddress.addresses.first;
|
address = parsedAddress.addresses.first;
|
||||||
break;
|
break;
|
||||||
case ParseFrom.yatRecord:
|
case ParseFrom.yatRecord:
|
||||||
|
|
|
@ -2,6 +2,7 @@ import 'package:cake_wallet/src/screens/settings/widgets/settings_cell_with_arro
|
||||||
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';
|
||||||
import 'package:cw_core/node.dart';
|
import 'package:cw_core/node.dart';
|
||||||
|
import 'package:cw_core/wallet_type.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';
|
||||||
|
@ -35,10 +36,11 @@ class ConnectionSyncPage extends BasePage {
|
||||||
handler: (context) => _presentReconnectAlert(context),
|
handler: (context) => _presentReconnectAlert(context),
|
||||||
),
|
),
|
||||||
StandardListSeparator(padding: EdgeInsets.symmetric(horizontal: 24)),
|
StandardListSeparator(padding: EdgeInsets.symmetric(horizontal: 24)),
|
||||||
SettingsCellWithArrow(
|
if (dashboardViewModel.hasRescan)
|
||||||
title: S.current.rescan,
|
SettingsCellWithArrow(
|
||||||
handler: (context) => Navigator.of(context).pushNamed(Routes.rescan),
|
title: S.current.rescan,
|
||||||
),
|
handler: (context) => Navigator.of(context).pushNamed(Routes.rescan),
|
||||||
|
),
|
||||||
StandardListSeparator(padding: EdgeInsets.symmetric(horizontal: 24)),
|
StandardListSeparator(padding: EdgeInsets.symmetric(horizontal: 24)),
|
||||||
NodeHeaderListRow(
|
NodeHeaderListRow(
|
||||||
title: S.of(context).add_new_node,
|
title: S.of(context).add_new_node,
|
||||||
|
@ -73,7 +75,7 @@ class ConnectionSyncPage extends BasePage {
|
||||||
builder: (BuildContext context) {
|
builder: (BuildContext context) {
|
||||||
return AlertWithTwoActions(
|
return AlertWithTwoActions(
|
||||||
alertTitle: S.of(context).change_current_node_title,
|
alertTitle: S.of(context).change_current_node_title,
|
||||||
alertContent: S.of(context).change_current_node(node.uriRaw),
|
alertContent: nodeListViewModel.getAlertContent(node.uriRaw),
|
||||||
leftButtonText: S.of(context).cancel,
|
leftButtonText: S.of(context).cancel,
|
||||||
rightButtonText: S.of(context).change,
|
rightButtonText: S.of(context).change,
|
||||||
actionLeftButton: () => Navigator.of(context).pop(),
|
actionLeftButton: () => Navigator.of(context).pop(),
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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));
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,8 +17,6 @@ class AddressEditOrCreatePage extends BasePage {
|
||||||
_labelController.addListener(
|
_labelController.addListener(
|
||||||
() => addressEditOrCreateViewModel.label = _labelController.text);
|
() => addressEditOrCreateViewModel.label = _labelController.text);
|
||||||
_labelController.text = addressEditOrCreateViewModel.label;
|
_labelController.text = addressEditOrCreateViewModel.label;
|
||||||
print(_labelController.text);
|
|
||||||
print(addressEditOrCreateViewModel.label);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
final WalletAddressEditOrCreateViewModel addressEditOrCreateViewModel;
|
final WalletAddressEditOrCreateViewModel addressEditOrCreateViewModel;
|
||||||
|
|
|
@ -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}'));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -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),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import 'package:cake_wallet/src/widgets/standart_switch.dart';
|
import 'package:cake_wallet/src/widgets/standard_switch.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
class UnspentCoinsSwitchRow extends StatelessWidget {
|
class UnspentCoinsSwitchRow extends StatelessWidget {
|
||||||
|
@ -33,7 +33,7 @@ class UnspentCoinsSwitchRow extends StatelessWidget {
|
||||||
textAlign: TextAlign.left),
|
textAlign: TextAlign.left),
|
||||||
Padding(
|
Padding(
|
||||||
padding: EdgeInsets.only(top: 12),
|
padding: EdgeInsets.only(top: 12),
|
||||||
child: StandartSwitch(
|
child: StandardSwitch(
|
||||||
value: switchValue,
|
value: switchValue,
|
||||||
onTaped: () => onSwitchValueChange(!switchValue))
|
onTaped: () => onSwitchValueChange(!switchValue))
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import 'package:auto_size_text/auto_size_text.dart';
|
import 'package:auto_size_text/auto_size_text.dart';
|
||||||
|
import 'package:cake_wallet/src/widgets/section_divider.dart';
|
||||||
import 'package:cake_wallet/utils/show_bar.dart';
|
import 'package:cake_wallet/utils/show_bar.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/cupertino.dart';
|
import 'package:flutter/cupertino.dart';
|
||||||
|
@ -6,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/view_model/wallet_keys_view_model.dart';
|
import 'package:cake_wallet/view_model/wallet_keys_view_model.dart';
|
||||||
|
|
||||||
class WalletKeysPage extends BasePage {
|
class WalletKeysPage extends BasePage {
|
||||||
|
@ -57,10 +58,7 @@ class WalletKeysPage extends BasePage {
|
||||||
height: 1,
|
height: 1,
|
||||||
padding: EdgeInsets.only(left: 24),
|
padding: EdgeInsets.only(left: 24),
|
||||||
color: Theme.of(context).accentTextTheme!.headline6!.backgroundColor!,
|
color: Theme.of(context).accentTextTheme!.headline6!.backgroundColor!,
|
||||||
child: Container(
|
child: const SectionDivider(),
|
||||||
height: 1,
|
|
||||||
color: Theme.of(context).dividerColor,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
itemCount: walletKeysViewModel.items.length,
|
itemCount: walletKeysViewModel.items.length,
|
||||||
itemBuilder: (BuildContext context, int index) {
|
itemBuilder: (BuildContext context, int index) {
|
||||||
|
@ -71,7 +69,7 @@ class WalletKeysPage extends BasePage {
|
||||||
Clipboard.setData(ClipboardData(text: item.value));
|
Clipboard.setData(ClipboardData(text: item.value));
|
||||||
showBar<void>(context, S.of(context).copied_key_to_clipboard(item.title));
|
showBar<void>(context, S.of(context).copied_key_to_clipboard(item.title));
|
||||||
},
|
},
|
||||||
child: StandartListRow(
|
child: ListRow(
|
||||||
title: item.title + ':',
|
title: item.title + ':',
|
||||||
value: item.value,
|
value: item.value,
|
||||||
),
|
),
|
||||||
|
|
|
@ -1,131 +0,0 @@
|
||||||
import 'package:cake_wallet/src/screens/wallet_list/wallet_menu_item.dart';
|
|
||||||
import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart';
|
|
||||||
import 'package:cake_wallet/utils/show_pop_up.dart';
|
|
||||||
import 'package:cake_wallet/view_model/wallet_list/wallet_list_view_model.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:cake_wallet/routes.dart';
|
|
||||||
import 'package:cake_wallet/generated/i18n.dart';
|
|
||||||
import 'package:cake_wallet/view_model/wallet_list/wallet_list_item.dart';
|
|
||||||
import 'package:cake_wallet/src/screens/auth/auth_page.dart';
|
|
||||||
import 'package:cake_wallet/palette.dart';
|
|
||||||
|
|
||||||
class WalletMenu {
|
|
||||||
WalletMenu(this.context, this.walletListViewModel);
|
|
||||||
|
|
||||||
final WalletListViewModel walletListViewModel;
|
|
||||||
final BuildContext context;
|
|
||||||
|
|
||||||
final List<WalletMenuItem> menuItems = [
|
|
||||||
WalletMenuItem(
|
|
||||||
title: S.current.wallet_list_load_wallet,
|
|
||||||
firstGradientColor: Palette.cornflower,
|
|
||||||
secondGradientColor: Palette.royalBlue,
|
|
||||||
image: Image.asset('assets/images/load.png',
|
|
||||||
height: 24, width: 24, color: Colors.white)),
|
|
||||||
WalletMenuItem(
|
|
||||||
title: S.current.show_seed,
|
|
||||||
firstGradientColor: Palette.moderateOrangeYellow,
|
|
||||||
secondGradientColor: Palette.moderateOrange,
|
|
||||||
image: Image.asset('assets/images/eye_action.png',
|
|
||||||
height: 24, width: 24, color: Colors.white)),
|
|
||||||
WalletMenuItem(
|
|
||||||
title: S.current.remove,
|
|
||||||
firstGradientColor: Palette.lightRed,
|
|
||||||
secondGradientColor: Palette.persianRed,
|
|
||||||
image: Image.asset('assets/images/trash.png',
|
|
||||||
height: 24, width: 24, color: Colors.white)),
|
|
||||||
WalletMenuItem(
|
|
||||||
title: S.current.rescan,
|
|
||||||
firstGradientColor: Palette.shineGreen,
|
|
||||||
secondGradientColor: Palette.moderateGreen,
|
|
||||||
image: Image.asset('assets/images/scanner.png',
|
|
||||||
height: 24, width: 24, color: Colors.white))
|
|
||||||
];
|
|
||||||
|
|
||||||
List<WalletMenuItem> generateItemsForWalletMenu(bool isCurrentWallet) {
|
|
||||||
final items = <WalletMenuItem>[];
|
|
||||||
|
|
||||||
if (!isCurrentWallet) items.add(menuItems[0]);
|
|
||||||
if (isCurrentWallet) items.add(menuItems[1]);
|
|
||||||
if (!isCurrentWallet) items.add(menuItems[2]);
|
|
||||||
if (isCurrentWallet) items.add(menuItems[3]);
|
|
||||||
|
|
||||||
return items;
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> action(
|
|
||||||
int index, WalletListItem wallet) async {
|
|
||||||
switch (index) {
|
|
||||||
case 0:
|
|
||||||
await Navigator.of(context).pushNamed(Routes.auth, arguments:
|
|
||||||
(bool isAuthenticatedSuccessfully, AuthPageState auth) async {
|
|
||||||
if (!isAuthenticatedSuccessfully) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
auth.changeProcessText(
|
|
||||||
S.of(context).wallet_list_loading_wallet(wallet.name));
|
|
||||||
await walletListViewModel.loadWallet(wallet);
|
|
||||||
auth.close();
|
|
||||||
Navigator.of(context).pop();
|
|
||||||
} catch (e) {
|
|
||||||
auth.changeProcessText(S
|
|
||||||
.of(context)
|
|
||||||
.wallet_list_failed_to_load(wallet.name, e.toString()));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
await Navigator.of(context).pushNamed(Routes.auth, arguments:
|
|
||||||
(bool isAuthenticatedSuccessfully, AuthPageState auth) async {
|
|
||||||
if (!isAuthenticatedSuccessfully) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
auth.close();
|
|
||||||
await Navigator.of(context).pushNamed(Routes.seed, arguments: false);
|
|
||||||
});
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
final isComfirmed = await showPopUp<bool>(
|
|
||||||
context: context,
|
|
||||||
builder: (BuildContext context) {
|
|
||||||
return AlertWithTwoActions(
|
|
||||||
alertTitle: 'Remove wallet',
|
|
||||||
alertContent: S.of(context).confirm_delete_wallet,
|
|
||||||
leftButtonText: S.of(context).cancel,
|
|
||||||
rightButtonText: S.of(context).remove,
|
|
||||||
actionLeftButton: () => Navigator.of(context).pop(false),
|
|
||||||
actionRightButton: () => Navigator.of(context).pop(true));
|
|
||||||
});
|
|
||||||
|
|
||||||
if (isComfirmed == null || !isComfirmed) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
await Navigator.of(context).pushNamed(Routes.auth, arguments:
|
|
||||||
(bool isAuthenticatedSuccessfully, AuthPageState auth) async {
|
|
||||||
if (!isAuthenticatedSuccessfully) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
auth.changeProcessText(
|
|
||||||
S.of(context).wallet_list_removing_wallet(wallet.name));
|
|
||||||
await walletListViewModel.remove(wallet);
|
|
||||||
auth.close();
|
|
||||||
} catch (e) {
|
|
||||||
auth.changeProcessText(S
|
|
||||||
.of(context)
|
|
||||||
.wallet_list_failed_to_remove(wallet.name, e.toString()));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
await Navigator.of(context).pushNamed(Routes.rescan);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,16 +0,0 @@
|
||||||
import 'dart:ui';
|
|
||||||
import 'package:flutter/cupertino.dart';
|
|
||||||
|
|
||||||
class WalletMenuItem {
|
|
||||||
WalletMenuItem({
|
|
||||||
required this.title,
|
|
||||||
required this.firstGradientColor,
|
|
||||||
required this.secondGradientColor,
|
|
||||||
required this.image
|
|
||||||
});
|
|
||||||
|
|
||||||
final String title;
|
|
||||||
final Color firstGradientColor;
|
|
||||||
final Color secondGradientColor;
|
|
||||||
final Image image;
|
|
||||||
}
|
|
|
@ -1,112 +0,0 @@
|
||||||
import 'dart:ui';
|
|
||||||
import 'package:cake_wallet/palette.dart';
|
|
||||||
import 'package:cake_wallet/src/screens/wallet_list/wallet_menu.dart';
|
|
||||||
import 'package:cake_wallet/src/screens/wallet_list/wallet_menu_item.dart';
|
|
||||||
import 'package:cake_wallet/view_model/wallet_list/wallet_list_item.dart';
|
|
||||||
import 'package:flutter/cupertino.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:cake_wallet/src/widgets/alert_background.dart';
|
|
||||||
import 'package:cake_wallet/src/widgets/alert_close_button.dart';
|
|
||||||
|
|
||||||
class WalletMenuAlert extends StatelessWidget {
|
|
||||||
WalletMenuAlert({
|
|
||||||
required this.wallet,
|
|
||||||
required this.walletMenu,
|
|
||||||
required this.items
|
|
||||||
});
|
|
||||||
|
|
||||||
final WalletListItem wallet;
|
|
||||||
final WalletMenu walletMenu;
|
|
||||||
final List<WalletMenuItem> items;
|
|
||||||
final closeButton = Image.asset('assets/images/close.png',
|
|
||||||
color: Palette.darkBlueCraiola,
|
|
||||||
);
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return AlertBackground(
|
|
||||||
child: Stack(
|
|
||||||
alignment: Alignment.center,
|
|
||||||
children: <Widget>[
|
|
||||||
Padding(
|
|
||||||
padding: EdgeInsets.only(
|
|
||||||
left: 24,
|
|
||||||
right: 24,
|
|
||||||
),
|
|
||||||
child: ClipRRect(
|
|
||||||
borderRadius: BorderRadius.all(Radius.circular(14)),
|
|
||||||
child: Container(
|
|
||||||
color: Theme.of(context).textTheme!.bodyText1!.decorationColor!,
|
|
||||||
padding: EdgeInsets.only(left: 24),
|
|
||||||
child: ListView.separated(
|
|
||||||
shrinkWrap: true,
|
|
||||||
physics: const NeverScrollableScrollPhysics(),
|
|
||||||
itemCount: items.length,
|
|
||||||
separatorBuilder: (context, _) => Container(
|
|
||||||
height: 1,
|
|
||||||
color: Theme.of(context).accentTextTheme!.subtitle1!.backgroundColor!,
|
|
||||||
),
|
|
||||||
itemBuilder: (_, index) {
|
|
||||||
final item = items[index];
|
|
||||||
|
|
||||||
return GestureDetector(
|
|
||||||
onTap: () {
|
|
||||||
Navigator.of(context).pop();
|
|
||||||
walletMenu.action(
|
|
||||||
walletMenu.menuItems.indexOf(item),
|
|
||||||
wallet);
|
|
||||||
},
|
|
||||||
child: Container(
|
|
||||||
height: 60,
|
|
||||||
child: Row(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
mainAxisAlignment: MainAxisAlignment.start,
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
|
||||||
children: <Widget>[
|
|
||||||
Container(
|
|
||||||
height: 32,
|
|
||||||
width: 32,
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
borderRadius: BorderRadius.all(
|
|
||||||
Radius.circular(4)),
|
|
||||||
gradient: LinearGradient(
|
|
||||||
begin: Alignment.topCenter,
|
|
||||||
end: Alignment.bottomCenter,
|
|
||||||
colors: [
|
|
||||||
item.firstGradientColor,
|
|
||||||
item.secondGradientColor
|
|
||||||
]
|
|
||||||
)
|
|
||||||
),
|
|
||||||
child: Center(
|
|
||||||
child: item.image,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
SizedBox(width: 12),
|
|
||||||
Expanded(
|
|
||||||
child: Text(
|
|
||||||
item.title,
|
|
||||||
style: TextStyle(
|
|
||||||
color: Theme.of(context).primaryTextTheme!.headline6!.color!,
|
|
||||||
fontSize: 18,
|
|
||||||
fontFamily: 'Lato',
|
|
||||||
fontWeight: FontWeight.w500,
|
|
||||||
decoration: TextDecoration.none
|
|
||||||
),
|
|
||||||
)
|
|
||||||
)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
AlertCloseButton(image: closeButton)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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:cake_wallet/palette.dart';
|
import 'package:cake_wallet/palette.dart';
|
||||||
|
|
||||||
|
@ -76,10 +77,7 @@ class BaseAlertDialog extends StatelessWidget {
|
||||||
),
|
),
|
||||||
)),
|
)),
|
||||||
),
|
),
|
||||||
Container(
|
const SectionDivider(),
|
||||||
width: 1,
|
|
||||||
color: Theme.of(context).dividerColor,
|
|
||||||
),
|
|
||||||
Expanded(
|
Expanded(
|
||||||
child: TextButton(
|
child: TextButton(
|
||||||
onPressed: actionRight,
|
onPressed: actionRight,
|
||||||
|
@ -140,10 +138,7 @@ class BaseAlertDialog extends StatelessWidget {
|
||||||
isDividerExists
|
isDividerExists
|
||||||
? Padding(
|
? Padding(
|
||||||
padding: EdgeInsets.only(top: 16, bottom: 8),
|
padding: EdgeInsets.only(top: 16, bottom: 8),
|
||||||
child: Container(
|
child: const SectionDivider(),
|
||||||
height: 1,
|
|
||||||
color: Theme.of(context).dividerColor,
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
: Offstage(),
|
: Offstage(),
|
||||||
Padding(
|
Padding(
|
||||||
|
@ -152,10 +147,7 @@ class BaseAlertDialog extends StatelessWidget {
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
Container(
|
const SectionDivider(),
|
||||||
height: 1,
|
|
||||||
color: Theme.of(context).dividerColor,
|
|
||||||
),
|
|
||||||
actionButtons(context)
|
actionButtons(context)
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|
|
@ -48,6 +48,8 @@ class CollapsibleSectionList extends SectionStandardList {
|
||||||
child: ListTileTheme(
|
child: ListTileTheme(
|
||||||
contentPadding: EdgeInsets.only(right: 16,top:sectionIndex>0?26:0),
|
contentPadding: EdgeInsets.only(right: 16,top:sectionIndex>0?26:0),
|
||||||
child: ExpansionTile(
|
child: ExpansionTile(
|
||||||
|
textColor: themeColor,
|
||||||
|
iconColor: themeColor,
|
||||||
title: sectionTitleBuilder == null
|
title: sectionTitleBuilder == null
|
||||||
? Container()
|
? Container()
|
||||||
: Container(child: buildTitle(items, sectionIndex, context)),
|
: Container(child: buildTitle(items, sectionIndex, context)),
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
import 'package:flutter/cupertino.dart';
|
import 'package:flutter/cupertino.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
class StandartListRow extends StatelessWidget {
|
class ListRow extends StatelessWidget {
|
||||||
StandartListRow(
|
ListRow(
|
||||||
{required this.title,
|
{required this.title,
|
||||||
required this.value,
|
required this.value,
|
||||||
this.titleFontSize = 14,
|
this.titleFontSize = 14,
|
|
@ -5,7 +5,7 @@ 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';
|
||||||
|
|
||||||
class Picker<Item extends Object> extends StatefulWidget {
|
class Picker<Item> extends StatefulWidget {
|
||||||
Picker({
|
Picker({
|
||||||
required this.selectedAtIndex,
|
required this.selectedAtIndex,
|
||||||
required this.items,
|
required this.items,
|
||||||
|
@ -40,7 +40,7 @@ class Picker<Item extends Object> extends StatefulWidget {
|
||||||
_PickerState<Item> createState() => _PickerState<Item>(items, images, onItemSelected);
|
_PickerState<Item> createState() => _PickerState<Item>(items, images, onItemSelected);
|
||||||
}
|
}
|
||||||
|
|
||||||
class _PickerState<Item> extends State<Picker> {
|
class _PickerState<Item> extends State<Picker<Item>> {
|
||||||
_PickerState(this.items, this.images, this.onItemSelected);
|
_PickerState(this.items, this.images, this.onItemSelected);
|
||||||
|
|
||||||
final Function(Item) onItemSelected;
|
final Function(Item) onItemSelected;
|
||||||
|
@ -60,7 +60,7 @@ class _PickerState<Item> extends State<Picker> {
|
||||||
images = [];
|
images = [];
|
||||||
for (int i=0;i<widget.items.length;i++) {
|
for (int i=0;i<widget.items.length;i++) {
|
||||||
if (widget.matchingCriteria?.call(widget.items[i], searchController.text) ?? true) {
|
if (widget.matchingCriteria?.call(widget.items[i], searchController.text) ?? true) {
|
||||||
items.add(widget.items[i] as Item);
|
items.add(widget.items[i]);
|
||||||
images.add(widget.images[i]);
|
images.add(widget.images[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -237,8 +237,7 @@ class _PickerState<Item> extends State<Picker> {
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: EdgeInsets.only(left: image != null ? 12 : 0),
|
padding: EdgeInsets.only(left: image != null ? 12 : 0),
|
||||||
child: Text(
|
child: Text(
|
||||||
// What a hack (item as) ?
|
widget.displayItem?.call(item) ?? item.toString(),
|
||||||
widget.displayItem?.call(item as Object) ?? item.toString(),
|
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
fontFamily: 'Lato',
|
fontFamily: 'Lato',
|
||||||
|
|
13
lib/src/widgets/section_divider.dart
Normal file
13
lib/src/widgets/section_divider.dart
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class SectionDivider extends StatelessWidget {
|
||||||
|
const SectionDivider();
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Container(
|
||||||
|
height: 1,
|
||||||
|
color: Theme.of(context).dividerColor,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,42 +2,42 @@ import 'dart:ui';
|
||||||
import 'package:flutter/cupertino.dart';
|
import 'package:flutter/cupertino.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
class StandardCheckbox extends StatefulWidget {
|
class StandardCheckbox extends StatelessWidget {
|
||||||
StandardCheckbox({
|
StandardCheckbox(
|
||||||
Key? key,
|
{required this.value,
|
||||||
required this.value,
|
this.caption = '',
|
||||||
this.caption = '',
|
this.gradientBackground = false,
|
||||||
required this.onChanged})
|
this.borderColor,
|
||||||
: super(key: key);
|
this.iconColor,
|
||||||
|
required this.onChanged});
|
||||||
|
|
||||||
final bool value;
|
final bool value;
|
||||||
final String caption;
|
final String caption;
|
||||||
|
final bool gradientBackground;
|
||||||
|
final Color? borderColor;
|
||||||
|
final Color? iconColor;
|
||||||
final Function(bool) onChanged;
|
final Function(bool) onChanged;
|
||||||
|
|
||||||
@override
|
|
||||||
StandardCheckboxState createState() =>
|
|
||||||
StandardCheckboxState(value, caption, onChanged);
|
|
||||||
}
|
|
||||||
|
|
||||||
class StandardCheckboxState extends State<StandardCheckbox> {
|
|
||||||
StandardCheckboxState(this.value, this.caption, this.onChanged);
|
|
||||||
|
|
||||||
bool value;
|
|
||||||
String caption;
|
|
||||||
Function(bool) onChanged;
|
|
||||||
|
|
||||||
void changeValue(bool newValue) {
|
|
||||||
setState(() => value = newValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
final baseGradient = LinearGradient(colors: [
|
||||||
|
Theme.of(context).primaryTextTheme.subtitle1!.color!,
|
||||||
|
Theme.of(context).primaryTextTheme.subtitle1!.decorationColor!,
|
||||||
|
], begin: Alignment.centerLeft, end: Alignment.centerRight);
|
||||||
|
|
||||||
|
final boxBorder = Border.all(
|
||||||
|
color: borderColor ?? Theme.of(context).primaryTextTheme.caption!.color!, width: 1.0);
|
||||||
|
|
||||||
|
final checkedBoxDecoration = BoxDecoration(
|
||||||
|
gradient: gradientBackground ? baseGradient : null,
|
||||||
|
border: gradientBackground ? null : boxBorder,
|
||||||
|
borderRadius: BorderRadius.all(Radius.circular(8.0)));
|
||||||
|
|
||||||
|
final uncheckedBoxDecoration =
|
||||||
|
BoxDecoration(border: boxBorder, borderRadius: BorderRadius.all(Radius.circular(8.0)));
|
||||||
|
|
||||||
return GestureDetector(
|
return GestureDetector(
|
||||||
onTap: () {
|
onTap: () => onChanged(!value),
|
||||||
value = !value;
|
|
||||||
onChanged(value);
|
|
||||||
setState(() {});
|
|
||||||
},
|
|
||||||
child: Row(
|
child: Row(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
mainAxisAlignment: MainAxisAlignment.start,
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
|
@ -45,36 +45,23 @@ class StandardCheckboxState extends State<StandardCheckbox> {
|
||||||
Container(
|
Container(
|
||||||
height: 24.0,
|
height: 24.0,
|
||||||
width: 24.0,
|
width: 24.0,
|
||||||
decoration: BoxDecoration(
|
decoration: value ? checkedBoxDecoration : uncheckedBoxDecoration,
|
||||||
border: Border.all(
|
|
||||||
color: Theme.of(context)
|
|
||||||
.primaryTextTheme!
|
|
||||||
.caption!
|
|
||||||
.color!,
|
|
||||||
width: 1.0),
|
|
||||||
borderRadius: BorderRadius.all(
|
|
||||||
Radius.circular(8.0)),
|
|
||||||
color: Theme.of(context).backgroundColor),
|
|
||||||
child: value
|
child: value
|
||||||
? Icon(
|
? Icon(
|
||||||
Icons.check,
|
Icons.check,
|
||||||
color: Colors.blue,
|
color: iconColor ?? Colors.blue,
|
||||||
size: 20.0,
|
size: 20.0,
|
||||||
)
|
)
|
||||||
: Offstage(),
|
: Offstage(),
|
||||||
),
|
),
|
||||||
if (caption.isNotEmpty) Padding(
|
if (caption.isNotEmpty)
|
||||||
padding: EdgeInsets.only(left: 10),
|
Padding(
|
||||||
child: Text(
|
padding: EdgeInsets.only(left: 10),
|
||||||
caption,
|
child: Text(
|
||||||
style: TextStyle(
|
caption,
|
||||||
fontSize: 16.0,
|
style: TextStyle(
|
||||||
color: Theme.of(context)
|
fontSize: 16.0, color: Theme.of(context).primaryTextTheme!.headline6!.color!),
|
||||||
.primaryTextTheme!
|
))
|
||||||
.headline6!
|
|
||||||
.color!),
|
|
||||||
)
|
|
||||||
)
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import 'package:cake_wallet/palette.dart';
|
import 'package:cake_wallet/palette.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:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
class StandardListRow extends StatelessWidget {
|
class StandardListRow extends StatelessWidget {
|
||||||
|
@ -217,7 +217,7 @@ class SectionStandardList extends StatelessWidget {
|
||||||
return Container();
|
return Container();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (row is StandartListStatusRow || row is TradeDatailsStandartListCard) {
|
if (row is StandardListStatusRow || row is TradeDetailsStandardListCard) {
|
||||||
return Container();
|
return Container();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,8 +2,8 @@ import 'package:cake_wallet/palette.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:cake_wallet/themes/theme_base.dart';
|
import 'package:cake_wallet/themes/theme_base.dart';
|
||||||
|
|
||||||
class TradeDatailsStandartListCard extends StatelessWidget {
|
class TradeDetailsStandardListCard extends StatelessWidget {
|
||||||
TradeDatailsStandartListCard(
|
TradeDetailsStandardListCard(
|
||||||
{required this.id,
|
{required this.id,
|
||||||
required this.create,
|
required this.create,
|
||||||
required this.pair,
|
required this.pair,
|
|
@ -3,8 +3,8 @@ import 'package:cake_wallet/src/screens/dashboard/widgets/sync_indicator_icon.da
|
||||||
import 'package:flutter/cupertino.dart';
|
import 'package:flutter/cupertino.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
class StandartListStatusRow extends StatelessWidget {
|
class StandardListStatusRow extends StatelessWidget {
|
||||||
StandartListStatusRow({required this.title, required this.value});
|
StandardListStatusRow({required this.title, required this.value});
|
||||||
|
|
||||||
final String title;
|
final String title;
|
||||||
final String value;
|
final String value;
|
|
@ -1,17 +1,17 @@
|
||||||
import 'package:flutter/cupertino.dart';
|
import 'package:flutter/cupertino.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
class StandartSwitch extends StatefulWidget {
|
class StandardSwitch extends StatefulWidget {
|
||||||
const StandartSwitch({required this.value, required this.onTaped});
|
const StandardSwitch({required this.value, required this.onTaped});
|
||||||
|
|
||||||
final bool value;
|
final bool value;
|
||||||
final VoidCallback onTaped;
|
final VoidCallback onTaped;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
StandartSwitchState createState() => StandartSwitchState();
|
StandardSwitchState createState() => StandardSwitchState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class StandartSwitchState extends State<StandartSwitch> {
|
class StandardSwitchState extends State<StandardSwitch> {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return GestureDetector(
|
return GestureDetector(
|
|
@ -8,12 +8,11 @@ part'trade_filter_store.g.dart';
|
||||||
class TradeFilterStore = TradeFilterStoreBase with _$TradeFilterStore;
|
class TradeFilterStore = TradeFilterStoreBase with _$TradeFilterStore;
|
||||||
|
|
||||||
abstract class TradeFilterStoreBase with Store {
|
abstract class TradeFilterStoreBase with Store {
|
||||||
TradeFilterStoreBase(
|
TradeFilterStoreBase() : displayXMRTO = true,
|
||||||
{this.displayXMRTO = true,
|
displayChangeNow = true,
|
||||||
this.displayChangeNow = true,
|
displaySideShift = true,
|
||||||
this.displayMorphToken = true,
|
displayMorphToken = true,
|
||||||
this.displaySimpleSwap = true,
|
displaySimpleSwap = true;
|
||||||
});
|
|
||||||
|
|
||||||
@observable
|
@observable
|
||||||
bool displayXMRTO;
|
bool displayXMRTO;
|
||||||
|
@ -21,26 +20,50 @@ abstract class TradeFilterStoreBase with Store {
|
||||||
@observable
|
@observable
|
||||||
bool displayChangeNow;
|
bool displayChangeNow;
|
||||||
|
|
||||||
|
@observable
|
||||||
|
bool displaySideShift;
|
||||||
|
|
||||||
@observable
|
@observable
|
||||||
bool displayMorphToken;
|
bool displayMorphToken;
|
||||||
|
|
||||||
@observable
|
@observable
|
||||||
bool displaySimpleSwap;
|
bool displaySimpleSwap;
|
||||||
|
|
||||||
|
@computed
|
||||||
|
bool get displayAllTrades => displayChangeNow && displaySideShift && displaySimpleSwap;
|
||||||
|
|
||||||
@action
|
@action
|
||||||
void toggleDisplayExchange(ExchangeProviderDescription provider) {
|
void toggleDisplayExchange(ExchangeProviderDescription provider) {
|
||||||
switch (provider) {
|
switch (provider) {
|
||||||
case ExchangeProviderDescription.changeNow:
|
case ExchangeProviderDescription.changeNow:
|
||||||
displayChangeNow = !displayChangeNow;
|
displayChangeNow = !displayChangeNow;
|
||||||
break;
|
break;
|
||||||
|
case ExchangeProviderDescription.sideShift:
|
||||||
|
displaySideShift = !displaySideShift;
|
||||||
|
break;
|
||||||
|
case ExchangeProviderDescription.simpleSwap:
|
||||||
|
displaySimpleSwap = !displaySimpleSwap;
|
||||||
|
break;
|
||||||
case ExchangeProviderDescription.xmrto:
|
case ExchangeProviderDescription.xmrto:
|
||||||
displayXMRTO = !displayXMRTO;
|
displayXMRTO = !displayXMRTO;
|
||||||
break;
|
break;
|
||||||
case ExchangeProviderDescription.morphToken:
|
case ExchangeProviderDescription.morphToken:
|
||||||
displayMorphToken = !displayMorphToken;
|
displayMorphToken = !displayMorphToken;
|
||||||
break;
|
break;
|
||||||
case ExchangeProviderDescription.simpleSwap:
|
case ExchangeProviderDescription.all:
|
||||||
displaySimpleSwap = !displaySimpleSwap;
|
if (displayAllTrades) {
|
||||||
|
displayChangeNow = false;
|
||||||
|
displaySideShift = false;
|
||||||
|
displayXMRTO = false;
|
||||||
|
displayMorphToken = false;
|
||||||
|
displaySimpleSwap = false;
|
||||||
|
} else {
|
||||||
|
displayChangeNow = true;
|
||||||
|
displaySideShift = true;
|
||||||
|
displayXMRTO = true;
|
||||||
|
displayMorphToken = true;
|
||||||
|
displaySimpleSwap = true;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -48,13 +71,15 @@ abstract class TradeFilterStoreBase with Store {
|
||||||
List<TradeListItem> filtered({required List<TradeListItem> trades, required WalletBase wallet}) {
|
List<TradeListItem> filtered({required List<TradeListItem> trades, required WalletBase wallet}) {
|
||||||
final _trades =
|
final _trades =
|
||||||
trades.where((item) => item.trade.walletId == wallet.id).toList();
|
trades.where((item) => item.trade.walletId == wallet.id).toList();
|
||||||
final needToFilter = !displayChangeNow || !displayXMRTO || !displayMorphToken || !displaySimpleSwap;
|
final needToFilter = !displayAllTrades;
|
||||||
|
|
||||||
return needToFilter
|
return needToFilter
|
||||||
? _trades
|
? _trades
|
||||||
.where((item) =>
|
.where((item) =>
|
||||||
(displayXMRTO &&
|
(displayXMRTO &&
|
||||||
item.trade.provider == ExchangeProviderDescription.xmrto) ||
|
item.trade.provider == ExchangeProviderDescription.xmrto) ||
|
||||||
|
(displaySideShift &&
|
||||||
|
item.trade.provider == ExchangeProviderDescription.sideShift) ||
|
||||||
(displayChangeNow &&
|
(displayChangeNow &&
|
||||||
item.trade.provider ==
|
item.trade.provider ==
|
||||||
ExchangeProviderDescription.changeNow) ||
|
ExchangeProviderDescription.changeNow) ||
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
import 'package:mobx/mobx.dart';
|
import 'package:mobx/mobx.dart';
|
||||||
import 'package:cw_core/transaction_direction.dart';
|
import 'package:cw_core/transaction_direction.dart';
|
||||||
import 'package:cake_wallet/view_model/dashboard/transaction_list_item.dart';
|
import 'package:cake_wallet/view_model/dashboard/transaction_list_item.dart';
|
||||||
|
import 'package:cake_wallet/view_model/dashboard/filter_item.dart';
|
||||||
|
import 'package:cake_wallet/generated/i18n.dart';
|
||||||
|
|
||||||
part 'transaction_filter_store.g.dart';
|
part 'transaction_filter_store.g.dart';
|
||||||
|
|
||||||
|
@ -8,8 +10,8 @@ class TransactionFilterStore = TransactionFilterStoreBase
|
||||||
with _$TransactionFilterStore;
|
with _$TransactionFilterStore;
|
||||||
|
|
||||||
abstract class TransactionFilterStoreBase with Store {
|
abstract class TransactionFilterStoreBase with Store {
|
||||||
TransactionFilterStoreBase(
|
TransactionFilterStoreBase() : displayIncoming = true,
|
||||||
{this.displayIncoming = true, this.displayOutgoing = true});
|
displayOutgoing = true;
|
||||||
|
|
||||||
@observable
|
@observable
|
||||||
bool displayIncoming;
|
bool displayIncoming;
|
||||||
|
@ -23,11 +25,31 @@ abstract class TransactionFilterStoreBase with Store {
|
||||||
@observable
|
@observable
|
||||||
DateTime? endDate;
|
DateTime? endDate;
|
||||||
|
|
||||||
@action
|
@computed
|
||||||
void toggleIncoming() => displayIncoming = !displayIncoming;
|
bool get displayAll => displayIncoming && displayOutgoing;
|
||||||
|
|
||||||
@action
|
@action
|
||||||
void toggleOutgoing() => displayOutgoing = !displayOutgoing;
|
void toggleAll() {
|
||||||
|
if (displayAll) {
|
||||||
|
displayOutgoing = false;
|
||||||
|
displayIncoming = false;
|
||||||
|
} else {
|
||||||
|
displayOutgoing = true;
|
||||||
|
displayIncoming = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@action
|
||||||
|
void toggleIncoming() {
|
||||||
|
displayIncoming = !displayIncoming;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@action
|
||||||
|
void toggleOutgoing() {
|
||||||
|
displayOutgoing = !displayOutgoing;
|
||||||
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
void changeStartDate(DateTime date) => startDate = date;
|
void changeStartDate(DateTime date) => startDate = date;
|
||||||
|
@ -37,8 +59,7 @@ abstract class TransactionFilterStoreBase with Store {
|
||||||
|
|
||||||
List<TransactionListItem> filtered({required List<TransactionListItem> transactions}) {
|
List<TransactionListItem> filtered({required List<TransactionListItem> transactions}) {
|
||||||
var _transactions = <TransactionListItem>[];
|
var _transactions = <TransactionListItem>[];
|
||||||
final needToFilter = !displayOutgoing ||
|
final needToFilter = !displayAll ||
|
||||||
!displayIncoming ||
|
|
||||||
(startDate != null && endDate != null);
|
(startDate != null && endDate != null);
|
||||||
|
|
||||||
if (needToFilter) {
|
if (needToFilter) {
|
||||||
|
@ -50,7 +71,7 @@ abstract class TransactionFilterStoreBase with Store {
|
||||||
&& (endDate?.isAfter(item.transaction.date) ?? false);
|
&& (endDate?.isAfter(item.transaction.date) ?? false);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (allowed && (!displayOutgoing || !displayIncoming)) {
|
if (allowed && (!displayAll)) {
|
||||||
allowed = (displayOutgoing &&
|
allowed = (displayOutgoing &&
|
||||||
item.transaction.direction ==
|
item.transaction.direction ==
|
||||||
TransactionDirection.outgoing) ||
|
TransactionDirection.outgoing) ||
|
||||||
|
|
37
lib/twitter/twitter_api.dart
Normal file
37
lib/twitter/twitter_api.dart
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
import 'dart:convert';
|
||||||
|
import 'package:cake_wallet/twitter/twitter_user.dart';
|
||||||
|
import 'package:http/http.dart' as http;
|
||||||
|
import 'package:cake_wallet/.secrets.g.dart' as secrets;
|
||||||
|
|
||||||
|
class TwitterApi {
|
||||||
|
static const twitterBearerToken = secrets.twitterBearerToken;
|
||||||
|
static const httpsScheme = 'https';
|
||||||
|
static const apiHost = 'api.twitter.com';
|
||||||
|
static const userPath = '/2/users/by/username/';
|
||||||
|
|
||||||
|
static Future<TwitterUser> lookupUserByName({required String userName}) async {
|
||||||
|
final queryParams = {'user.fields': 'description', 'expansions': 'pinned_tweet_id'};
|
||||||
|
|
||||||
|
final headers = {'authorization': 'Bearer $twitterBearerToken'};
|
||||||
|
|
||||||
|
final uri = Uri(
|
||||||
|
scheme: httpsScheme,
|
||||||
|
host: apiHost,
|
||||||
|
path: userPath + userName,
|
||||||
|
queryParameters: queryParams,
|
||||||
|
);
|
||||||
|
|
||||||
|
var response = await http.get(uri, headers: headers);
|
||||||
|
|
||||||
|
if (response.statusCode != 200) {
|
||||||
|
throw Exception('Unexpected http status: ${response.statusCode}');
|
||||||
|
}
|
||||||
|
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
|
||||||
|
|
||||||
|
if (responseJSON['errors'] != null) {
|
||||||
|
throw Exception(responseJSON['errors'][0]['detail']);
|
||||||
|
}
|
||||||
|
|
||||||
|
return TwitterUser.fromJson(responseJSON);
|
||||||
|
}
|
||||||
|
}
|
45
lib/twitter/twitter_user.dart
Normal file
45
lib/twitter/twitter_user.dart
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
class TwitterUser {
|
||||||
|
TwitterUser(
|
||||||
|
{required this.id,
|
||||||
|
required this.username,
|
||||||
|
required this.name,
|
||||||
|
required this.description,
|
||||||
|
this.tweets});
|
||||||
|
|
||||||
|
final String id;
|
||||||
|
final String username;
|
||||||
|
final String name;
|
||||||
|
final String description;
|
||||||
|
final List<Tweet>? tweets;
|
||||||
|
|
||||||
|
factory TwitterUser.fromJson(Map<String, dynamic> json) {
|
||||||
|
return TwitterUser(
|
||||||
|
id: json['data']['id'] as String,
|
||||||
|
username: json['data']['username'] as String,
|
||||||
|
name: json['data']['name'] as String,
|
||||||
|
description: json['data']['description'] as String? ?? '',
|
||||||
|
tweets: json['includes'] != null
|
||||||
|
? List.from(json['includes']['tweets'] as List)
|
||||||
|
.map((e) => Tweet.fromJson(e as Map<String, dynamic>))
|
||||||
|
.toList()
|
||||||
|
: null,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Tweet {
|
||||||
|
Tweet({
|
||||||
|
required this.id,
|
||||||
|
required this.text,
|
||||||
|
});
|
||||||
|
|
||||||
|
final String id;
|
||||||
|
final String text;
|
||||||
|
|
||||||
|
factory Tweet.fromJson(Map<String, dynamic> json) {
|
||||||
|
return Tweet(
|
||||||
|
id: json['id'] as String,
|
||||||
|
text: json['text'] as String,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
133
lib/utils/exception_handler.dart
Normal file
133
lib/utils/exception_handler.dart
Normal file
|
@ -0,0 +1,133 @@
|
||||||
|
import 'dart:convert';
|
||||||
|
import 'dart:io';
|
||||||
|
|
||||||
|
import 'package:cake_wallet/entities/preferences_key.dart';
|
||||||
|
import 'package:cake_wallet/generated/i18n.dart';
|
||||||
|
import 'package:cake_wallet/main.dart';
|
||||||
|
import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart';
|
||||||
|
import 'package:cake_wallet/utils/show_pop_up.dart';
|
||||||
|
import 'package:flutter/foundation.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_mailer/flutter_mailer.dart';
|
||||||
|
import 'package:path_provider/path_provider.dart';
|
||||||
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
|
|
||||||
|
class ExceptionHandler {
|
||||||
|
static bool _hasError = false;
|
||||||
|
static const _coolDownDurationInDays = 7;
|
||||||
|
|
||||||
|
static void _saveException(String? error, StackTrace? stackTrace) async {
|
||||||
|
final appDocDir = await getApplicationDocumentsDirectory();
|
||||||
|
|
||||||
|
final file = File('${appDocDir.path}/error.txt');
|
||||||
|
final exception = {
|
||||||
|
"${DateTime.now()}": {
|
||||||
|
"Error": error,
|
||||||
|
"StackTrace": stackTrace.toString(),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const String separator = '''\n\n==========================================================
|
||||||
|
==========================================================\n\n''';
|
||||||
|
|
||||||
|
await file.writeAsString(
|
||||||
|
jsonEncode(exception) + separator,
|
||||||
|
mode: FileMode.append,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _sendExceptionFile() async {
|
||||||
|
try {
|
||||||
|
final appDocDir = await getApplicationDocumentsDirectory();
|
||||||
|
|
||||||
|
final file = File('${appDocDir.path}/error.txt');
|
||||||
|
|
||||||
|
final MailOptions mailOptions = MailOptions(
|
||||||
|
subject: 'Mobile App Issue',
|
||||||
|
recipients: ['support@cakewallet.com'],
|
||||||
|
attachments: [file.path],
|
||||||
|
);
|
||||||
|
|
||||||
|
final result = await FlutterMailer.send(mailOptions);
|
||||||
|
|
||||||
|
// Clear file content if the error was sent or saved.
|
||||||
|
// On android we can't know if it was sent or saved
|
||||||
|
if (result.name == MailerResponse.sent.name ||
|
||||||
|
result.name == MailerResponse.saved.name ||
|
||||||
|
result.name == MailerResponse.android.name) {
|
||||||
|
file.writeAsString("", mode: FileMode.write);
|
||||||
|
}
|
||||||
|
} catch (e, s) {
|
||||||
|
_saveException(e.toString(), s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void onError(FlutterErrorDetails errorDetails) async {
|
||||||
|
if (kDebugMode) {
|
||||||
|
FlutterError.presentError(errorDetails);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_ignoreError(errorDetails.exception.toString())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_saveException(errorDetails.exception.toString(), errorDetails.stack);
|
||||||
|
|
||||||
|
final sharedPrefs = await SharedPreferences.getInstance();
|
||||||
|
|
||||||
|
final lastPopupDate =
|
||||||
|
DateTime.tryParse(sharedPrefs.getString(PreferencesKey.lastPopupDate) ?? '') ??
|
||||||
|
DateTime.now().subtract(Duration(days: _coolDownDurationInDays + 1));
|
||||||
|
|
||||||
|
final durationSinceLastReport = DateTime.now().difference(lastPopupDate).inDays;
|
||||||
|
|
||||||
|
if (_hasError || durationSinceLastReport < _coolDownDurationInDays) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_hasError = true;
|
||||||
|
|
||||||
|
sharedPrefs.setString(PreferencesKey.lastPopupDate, DateTime.now().toString());
|
||||||
|
|
||||||
|
WidgetsBinding.instance.addPostFrameCallback(
|
||||||
|
(timeStamp) async {
|
||||||
|
await showPopUp<void>(
|
||||||
|
context: navigatorKey.currentContext!,
|
||||||
|
builder: (context) {
|
||||||
|
return AlertWithTwoActions(
|
||||||
|
isDividerExist: true,
|
||||||
|
alertTitle: S.of(context).error,
|
||||||
|
alertContent: S.of(context).error_dialog_content,
|
||||||
|
rightButtonText: S.of(context).send,
|
||||||
|
leftButtonText: S.of(context).do_not_send,
|
||||||
|
actionRightButton: () {
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
_sendExceptionFile();
|
||||||
|
},
|
||||||
|
actionLeftButton: () {
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
_hasError = false;
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Ignore User related errors or system errors
|
||||||
|
static bool _ignoreError(String error) =>
|
||||||
|
_ignoredErrors.any((element) => error.contains(element));
|
||||||
|
|
||||||
|
static const List<String> _ignoredErrors = const [
|
||||||
|
"errno = 103", // SocketException: Software caused connection abort
|
||||||
|
"errno = 9", // SocketException: Bad file descriptor
|
||||||
|
"errno = 32", // SocketException: Write failed (OS Error: Broken pipe)
|
||||||
|
"errno = 60", // SocketException: Operation timed out
|
||||||
|
"errno = 54", // SocketException: Connection reset by peer
|
||||||
|
"errno = 49", // SocketException: Can't assign requested address
|
||||||
|
"errno = 28", // OS Error: No space left on device
|
||||||
|
"PERMISSION_NOT_GRANTED",
|
||||||
|
];
|
||||||
|
}
|
65
lib/utils/route_aware.dart
Normal file
65
lib/utils/route_aware.dart
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:cake_wallet/main.dart';
|
||||||
|
|
||||||
|
class RouteAwareWidget extends StatefulWidget {
|
||||||
|
RouteAwareWidget(
|
||||||
|
{required this.child,
|
||||||
|
this.pushToWidget,
|
||||||
|
this.pushToNextWidget,
|
||||||
|
this.popWidget,
|
||||||
|
this.popNextWidget});
|
||||||
|
|
||||||
|
final Widget child;
|
||||||
|
final Function()? pushToWidget;
|
||||||
|
final Function()? pushToNextWidget;
|
||||||
|
final Function()? popWidget;
|
||||||
|
final Function()? popNextWidget;
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<RouteAwareWidget> createState() => RouteAwareWidgetState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class RouteAwareWidgetState extends State<RouteAwareWidget> with RouteAware {
|
||||||
|
@override
|
||||||
|
void didChangeDependencies() {
|
||||||
|
super.didChangeDependencies();
|
||||||
|
routeObserver.subscribe(this, ModalRoute.of(context) as PageRoute);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
routeObserver.unsubscribe(this);
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void didPush() {
|
||||||
|
if (widget.pushToWidget != null) {
|
||||||
|
widget.pushToWidget!();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void didPushNext() {
|
||||||
|
if (widget.pushToNextWidget != null) {
|
||||||
|
widget.pushToNextWidget!();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void didPop() {
|
||||||
|
if (widget.popWidget != null) {
|
||||||
|
widget.popWidget!();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void didPopNext() {
|
||||||
|
if (widget.popNextWidget != null) {
|
||||||
|
widget.popNextWidget!();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) => widget.child;
|
||||||
|
}
|
13
lib/utils/share_util.dart
Normal file
13
lib/utils/share_util.dart
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:share_plus/share_plus.dart';
|
||||||
|
|
||||||
|
class ShareUtil {
|
||||||
|
static void share({required String text, required BuildContext context}) {
|
||||||
|
final box = context.findRenderObject() as RenderBox?;
|
||||||
|
|
||||||
|
Share.share(
|
||||||
|
text,
|
||||||
|
sharePositionOrigin: box!.localToGlobal(Offset.zero) & box.size,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -58,25 +58,44 @@ abstract class DashboardViewModelBase with Store {
|
||||||
isShowThirdYatIntroduction = false,
|
isShowThirdYatIntroduction = false,
|
||||||
filterItems = {
|
filterItems = {
|
||||||
S.current.transactions: [
|
S.current.transactions: [
|
||||||
|
FilterItem(
|
||||||
|
value: () => transactionFilterStore.displayAll,
|
||||||
|
caption: S.current.all_transactions,
|
||||||
|
onChanged: transactionFilterStore.toggleAll),
|
||||||
FilterItem(
|
FilterItem(
|
||||||
value: () => transactionFilterStore.displayIncoming,
|
value: () => transactionFilterStore.displayIncoming,
|
||||||
caption: S.current.incoming,
|
caption: S.current.incoming,
|
||||||
onChanged: (value) => transactionFilterStore.toggleIncoming()),
|
onChanged:transactionFilterStore.toggleIncoming),
|
||||||
FilterItem(
|
FilterItem(
|
||||||
value: () => transactionFilterStore.displayOutgoing,
|
value: () => transactionFilterStore.displayOutgoing,
|
||||||
caption: S.current.outgoing,
|
caption: S.current.outgoing,
|
||||||
onChanged: (value) => transactionFilterStore.toggleOutgoing()),
|
onChanged: transactionFilterStore.toggleOutgoing),
|
||||||
// FilterItem(
|
// FilterItem(
|
||||||
// value: () => false,
|
// value: () => false,
|
||||||
// caption: S.current.transactions_by_date,
|
// caption: S.current.transactions_by_date,
|
||||||
// onChanged: null),
|
// onChanged: null),
|
||||||
],
|
],
|
||||||
S.current.trades: [
|
S.current.trades: [
|
||||||
|
FilterItem(
|
||||||
|
value: () => tradeFilterStore.displayAllTrades,
|
||||||
|
caption: S.current.all_trades,
|
||||||
|
onChanged: () => tradeFilterStore
|
||||||
|
.toggleDisplayExchange(ExchangeProviderDescription.all)),
|
||||||
FilterItem(
|
FilterItem(
|
||||||
value: () => tradeFilterStore.displayChangeNow,
|
value: () => tradeFilterStore.displayChangeNow,
|
||||||
caption: 'Change.NOW',
|
caption: ExchangeProviderDescription.changeNow.title,
|
||||||
onChanged: (value) => tradeFilterStore
|
onChanged: () => tradeFilterStore
|
||||||
.toggleDisplayExchange(ExchangeProviderDescription.changeNow)),
|
.toggleDisplayExchange(ExchangeProviderDescription.changeNow)),
|
||||||
|
FilterItem(
|
||||||
|
value: () => tradeFilterStore.displaySideShift,
|
||||||
|
caption: ExchangeProviderDescription.sideShift.title,
|
||||||
|
onChanged: () => tradeFilterStore
|
||||||
|
.toggleDisplayExchange(ExchangeProviderDescription.sideShift)),
|
||||||
|
FilterItem(
|
||||||
|
value: () => tradeFilterStore.displaySimpleSwap,
|
||||||
|
caption: ExchangeProviderDescription.simpleSwap.title,
|
||||||
|
onChanged: () => tradeFilterStore
|
||||||
|
.toggleDisplayExchange(ExchangeProviderDescription.simpleSwap)),
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
subname = '',
|
subname = '',
|
||||||
|
@ -220,7 +239,7 @@ abstract class DashboardViewModelBase with Store {
|
||||||
WalletBase<Balance, TransactionHistoryBase<TransactionInfo>, TransactionInfo>
|
WalletBase<Balance, TransactionHistoryBase<TransactionInfo>, TransactionInfo>
|
||||||
wallet;
|
wallet;
|
||||||
|
|
||||||
bool get hasRescan => wallet.type == WalletType.monero;
|
bool get hasRescan => wallet.type == WalletType.monero || wallet.type == WalletType.haven;
|
||||||
|
|
||||||
BalanceViewModel balanceViewModel;
|
BalanceViewModel balanceViewModel;
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
import 'package:mobx/mobx.dart';
|
||||||
|
|
||||||
class FilterItem {
|
class FilterItem {
|
||||||
FilterItem({
|
FilterItem({
|
||||||
required this.value,
|
required this.value,
|
||||||
|
@ -6,5 +8,5 @@ class FilterItem {
|
||||||
|
|
||||||
bool Function() value;
|
bool Function() value;
|
||||||
String caption;
|
String caption;
|
||||||
Function(bool) onChanged;
|
Function onChanged;
|
||||||
}
|
}
|
|
@ -1,5 +1,7 @@
|
||||||
import 'package:cake_wallet/entities/balance_display_mode.dart';
|
import 'package:cake_wallet/entities/balance_display_mode.dart';
|
||||||
import 'package:cake_wallet/entities/fiat_currency.dart';
|
import 'package:cake_wallet/entities/fiat_currency.dart';
|
||||||
|
import 'package:cake_wallet/generated/i18n.dart';
|
||||||
|
import 'package:cw_core/transaction_direction.dart';
|
||||||
import 'package:cw_core/transaction_info.dart';
|
import 'package:cw_core/transaction_info.dart';
|
||||||
import 'package:cake_wallet/store/settings_store.dart';
|
import 'package:cake_wallet/store/settings_store.dart';
|
||||||
import 'package:cake_wallet/view_model/dashboard/action_list_item.dart';
|
import 'package:cake_wallet/view_model/dashboard/action_list_item.dart';
|
||||||
|
@ -11,6 +13,7 @@ import 'package:cake_wallet/view_model/dashboard/balance_view_model.dart';
|
||||||
import 'package:cw_core/keyable.dart';
|
import 'package:cw_core/keyable.dart';
|
||||||
import 'package:cw_core/wallet_type.dart';
|
import 'package:cw_core/wallet_type.dart';
|
||||||
|
|
||||||
|
|
||||||
class TransactionListItem extends ActionListItem with Keyable {
|
class TransactionListItem extends ActionListItem with Keyable {
|
||||||
TransactionListItem(
|
TransactionListItem(
|
||||||
{required this.transaction,
|
{required this.transaction,
|
||||||
|
@ -35,6 +38,30 @@ class TransactionListItem extends ActionListItem with Keyable {
|
||||||
? '---'
|
? '---'
|
||||||
: transaction.amountFormatted();
|
: transaction.amountFormatted();
|
||||||
}
|
}
|
||||||
|
String get formattedTitle {
|
||||||
|
if (transaction.direction == TransactionDirection.incoming) {
|
||||||
|
return S.current.received;
|
||||||
|
}
|
||||||
|
|
||||||
|
return S.current.sent;
|
||||||
|
}
|
||||||
|
|
||||||
|
String get formattedPendingStatus {
|
||||||
|
if (transaction.confirmations >= 0 && transaction.confirmations < 10) {
|
||||||
|
return ' (${transaction.confirmations}/10)';
|
||||||
|
}
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
String get formattedStatus {
|
||||||
|
if (transaction.direction == TransactionDirection.incoming) {
|
||||||
|
if (balanceViewModel.wallet.type == WalletType.monero ||
|
||||||
|
balanceViewModel.wallet.type == WalletType.haven) {
|
||||||
|
return formattedPendingStatus;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return transaction.isPending ? S.current.pending : '';
|
||||||
|
}
|
||||||
|
|
||||||
String get formattedFiatAmount {
|
String get formattedFiatAmount {
|
||||||
var amount = '';
|
var amount = '';
|
||||||
|
|
|
@ -18,19 +18,18 @@ import 'package:cake_wallet/generated/i18n.dart';
|
||||||
|
|
||||||
part 'exchange_trade_view_model.g.dart';
|
part 'exchange_trade_view_model.g.dart';
|
||||||
|
|
||||||
class ExchangeTradeViewModel = ExchangeTradeViewModelBase
|
class ExchangeTradeViewModel = ExchangeTradeViewModelBase with _$ExchangeTradeViewModel;
|
||||||
with _$ExchangeTradeViewModel;
|
|
||||||
|
|
||||||
abstract class ExchangeTradeViewModelBase with Store {
|
abstract class ExchangeTradeViewModelBase with Store {
|
||||||
ExchangeTradeViewModelBase(
|
ExchangeTradeViewModelBase(
|
||||||
{required this.wallet,
|
{required this.wallet,
|
||||||
required this.trades,
|
required this.trades,
|
||||||
required this.tradesStore,
|
required this.tradesStore,
|
||||||
required this.sendViewModel})
|
required this.sendViewModel})
|
||||||
: trade = tradesStore.trade!,
|
: trade = tradesStore.trade!,
|
||||||
isSendable = tradesStore.trade!.from == wallet.currency ||
|
isSendable = tradesStore.trade!.from == wallet.currency ||
|
||||||
tradesStore.trade!.provider == ExchangeProviderDescription.xmrto,
|
tradesStore.trade!.provider == ExchangeProviderDescription.xmrto,
|
||||||
items = ObservableList<ExchangeTradeItem>() {
|
items = ObservableList<ExchangeTradeItem>() {
|
||||||
switch (trade.provider) {
|
switch (trade.provider) {
|
||||||
case ExchangeProviderDescription.xmrto:
|
case ExchangeProviderDescription.xmrto:
|
||||||
_provider = XMRTOExchangeProvider();
|
_provider = XMRTOExchangeProvider();
|
||||||
|
@ -67,22 +66,20 @@ abstract class ExchangeTradeViewModelBase with Store {
|
||||||
|
|
||||||
@computed
|
@computed
|
||||||
String get extraInfo => trade.from == CryptoCurrency.xlm
|
String get extraInfo => trade.from == CryptoCurrency.xlm
|
||||||
? '\n\n' + S.current.xlm_extra_info
|
? '\n\n' + S.current.xlm_extra_info
|
||||||
: trade.from == CryptoCurrency.xrp
|
: trade.from == CryptoCurrency.xrp
|
||||||
? '\n\n' + S.current.xrp_extra_info
|
? '\n\n' + S.current.xrp_extra_info
|
||||||
: '';
|
: '';
|
||||||
|
|
||||||
@computed
|
@computed
|
||||||
String get pendingTransactionFiatAmountValueFormatted =>
|
String get pendingTransactionFiatAmountValueFormatted => sendViewModel.isFiatDisabled
|
||||||
sendViewModel.isFiatDisabled
|
? ''
|
||||||
? '' : sendViewModel.pendingTransactionFiatAmount
|
: sendViewModel.pendingTransactionFiatAmount + ' ' + sendViewModel.fiat.title;
|
||||||
+ ' ' + sendViewModel.fiat.title;
|
|
||||||
|
|
||||||
@computed
|
@computed
|
||||||
String get pendingTransactionFeeFiatAmountFormatted =>
|
String get pendingTransactionFeeFiatAmountFormatted => sendViewModel.isFiatDisabled
|
||||||
sendViewModel.isFiatDisabled
|
? ''
|
||||||
? '' : sendViewModel.pendingTransactionFeeFiatAmount
|
: sendViewModel.pendingTransactionFeeFiatAmount + ' ' + sendViewModel.fiat.title;
|
||||||
+ ' ' + sendViewModel.fiat.title;
|
|
||||||
|
|
||||||
@observable
|
@observable
|
||||||
ObservableList<ExchangeTradeItem> items;
|
ObservableList<ExchangeTradeItem> items;
|
||||||
|
@ -122,6 +119,8 @@ abstract class ExchangeTradeViewModelBase with Store {
|
||||||
}
|
}
|
||||||
|
|
||||||
void _updateItems() {
|
void _updateItems() {
|
||||||
|
final tagFrom = trade.from.tag != null ? '${trade.from.tag}' + ' ' : '';
|
||||||
|
final tagTo = trade.to.tag != null ? '${trade.to.tag}' + ' ' : '';
|
||||||
items.clear();
|
items.clear();
|
||||||
items.add(ExchangeTradeItem(
|
items.add(ExchangeTradeItem(
|
||||||
title: "${trade.provider.title} ${S.current.id}", data: '${trade.id}', isCopied: true));
|
title: "${trade.provider.title} ${S.current.id}", data: '${trade.id}', isCopied: true));
|
||||||
|
@ -130,22 +129,22 @@ abstract class ExchangeTradeViewModelBase with Store {
|
||||||
final title = trade.from == CryptoCurrency.xrp
|
final title = trade.from == CryptoCurrency.xrp
|
||||||
? S.current.destination_tag
|
? S.current.destination_tag
|
||||||
: trade.from == CryptoCurrency.xlm
|
: trade.from == CryptoCurrency.xlm
|
||||||
? S.current.memo
|
? S.current.memo
|
||||||
: S.current.extra_id;
|
: S.current.extra_id;
|
||||||
|
|
||||||
items.add(ExchangeTradeItem(
|
items.add(ExchangeTradeItem(title: title, data: '${trade.extraId}', isCopied: false));
|
||||||
title: title, data: '${trade.extraId}', isCopied: false));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
items.addAll([
|
items.addAll([
|
||||||
|
ExchangeTradeItem(title: S.current.amount, data: '${trade.amount}', isCopied: false),
|
||||||
ExchangeTradeItem(
|
ExchangeTradeItem(
|
||||||
title: S.current.amount, data: '${trade.amount}', isCopied: false),
|
title: S.current.send_to_this_address('${trade.from}', tagFrom) + ':',
|
||||||
ExchangeTradeItem(
|
|
||||||
title: S.current.status, data: '${trade.state}', isCopied: false),
|
|
||||||
ExchangeTradeItem(
|
|
||||||
title: S.current.widgets_address + ':',
|
|
||||||
data: trade.inputAddress ?? '',
|
data: trade.inputAddress ?? '',
|
||||||
isCopied: true),
|
isCopied: true),
|
||||||
|
ExchangeTradeItem(
|
||||||
|
title: S.current.arrive_in_this_address('${trade.to}', tagTo) + ':',
|
||||||
|
data: trade.payoutAddress ?? '',
|
||||||
|
isCopied: true),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -308,10 +308,11 @@ abstract class ExchangeViewModelBase with Store {
|
||||||
Future<void> _calculateBestRate() async {
|
Future<void> _calculateBestRate() async {
|
||||||
final amount = double.tryParse(isFixedRateMode ? receiveAmount : depositAmount) ?? 1;
|
final amount = double.tryParse(isFixedRateMode ? receiveAmount : depositAmount) ?? 1;
|
||||||
|
|
||||||
|
final _providers = _tradeAvailableProviders
|
||||||
|
.where((element) => !isFixedRateMode || element.supportsFixedRate).toList();
|
||||||
|
|
||||||
final result = await Future.wait<double>(
|
final result = await Future.wait<double>(
|
||||||
_tradeAvailableProviders
|
_providers.map((element) => element.fetchRate(
|
||||||
.where((element) => !isFixedRateMode || element.supportsFixedRate)
|
|
||||||
.map((element) => element.fetchRate(
|
|
||||||
from: depositCurrency,
|
from: depositCurrency,
|
||||||
to: receiveCurrency,
|
to: receiveCurrency,
|
||||||
amount: amount,
|
amount: amount,
|
||||||
|
@ -324,7 +325,12 @@ abstract class ExchangeViewModelBase with Store {
|
||||||
for (int i=0;i<result.length;i++) {
|
for (int i=0;i<result.length;i++) {
|
||||||
if (result[i] != 0) {
|
if (result[i] != 0) {
|
||||||
/// add this provider as its valid for this trade
|
/// add this provider as its valid for this trade
|
||||||
_sortedAvailableProviders[result[i]] = _tradeAvailableProviders[i];
|
try {
|
||||||
|
_sortedAvailableProviders[result[i]] = _providers[i];
|
||||||
|
} catch (e) {
|
||||||
|
// will throw "Concurrent modification during iteration" error if modified at the same
|
||||||
|
// time [createTrade] is called, as this is not a normal map, but a sorted map
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (_sortedAvailableProviders.isNotEmpty) {
|
if (_sortedAvailableProviders.isNotEmpty) {
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
import 'package:cake_wallet/anypay/any_pay_chain.dart';
|
||||||
import 'package:mobx/mobx.dart';
|
import 'package:mobx/mobx.dart';
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:cake_wallet/ionia/ionia_service.dart';
|
import 'package:cake_wallet/ionia/ionia_service.dart';
|
||||||
|
@ -39,6 +40,8 @@ abstract class IoniaPaymentStatusViewModelBase with Store {
|
||||||
|
|
||||||
Timer? get timer => _timer;
|
Timer? get timer => _timer;
|
||||||
|
|
||||||
|
bool get payingByBitcoin => paymentInfo.anyPayPayment.chain == AnyPayChain.btc;
|
||||||
|
|
||||||
Timer? _timer;
|
Timer? _timer;
|
||||||
|
|
||||||
@action
|
@action
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import 'package:cake_wallet/generated/i18n.dart';
|
||||||
import 'package:hive/hive.dart';
|
import 'package:hive/hive.dart';
|
||||||
import 'package:mobx/mobx.dart';
|
import 'package:mobx/mobx.dart';
|
||||||
import 'package:cw_core/wallet_base.dart';
|
import 'package:cw_core/wallet_base.dart';
|
||||||
|
@ -30,6 +31,10 @@ abstract class NodeListViewModelBase with Store {
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String getAlertContent(String uri) =>
|
||||||
|
S.current.change_current_node(uri) +
|
||||||
|
'${uri.endsWith('.onion') || uri.contains('.onion:') ? '\n' + S.current.orbot_running_alert : ''}';
|
||||||
|
|
||||||
final ObservableList<Node> nodes;
|
final ObservableList<Node> nodes;
|
||||||
final SettingsStore settingsStore;
|
final SettingsStore settingsStore;
|
||||||
final WalletBase wallet;
|
final WalletBase wallet;
|
||||||
|
|
|
@ -180,7 +180,8 @@ abstract class SendViewModelBase with Store {
|
||||||
|
|
||||||
WalletType get walletType => _wallet.type;
|
WalletType get walletType => _wallet.type;
|
||||||
|
|
||||||
String? get walletCurrencyName => _wallet.currency.name?.toLowerCase();
|
String? get walletCurrencyName =>
|
||||||
|
_wallet.currency.fullName?.toLowerCase() ?? _wallet.currency.name;
|
||||||
|
|
||||||
bool get hasCurrecyChanger => walletType == WalletType.haven;
|
bool get hasCurrecyChanger => walletType == WalletType.haven;
|
||||||
|
|
||||||
|
|
|
@ -42,7 +42,7 @@ abstract class SupportViewModelBase with Store {
|
||||||
title: 'Telegram',
|
title: 'Telegram',
|
||||||
icon: 'assets/images/Telegram.png',
|
icon: 'assets/images/Telegram.png',
|
||||||
linkTitle: '@cakewallet_bot',
|
linkTitle: '@cakewallet_bot',
|
||||||
link: 'https:t.me/cakewallet_bot'),
|
link: 'https://t.me/cakewallet_bot'),
|
||||||
LinkListItem(
|
LinkListItem(
|
||||||
title: 'Twitter',
|
title: 'Twitter',
|
||||||
icon: 'assets/images/Twitter.png',
|
icon: 'assets/images/Twitter.png',
|
||||||
|
@ -84,7 +84,7 @@ abstract class SupportViewModelBase with Store {
|
||||||
// link: 'mailto:support@y.at')
|
// link: 'mailto:support@y.at')
|
||||||
];
|
];
|
||||||
|
|
||||||
static const url = 'https://cakewallet.com/guide/';
|
static const url = 'https://guides.cakewallet.com';
|
||||||
|
|
||||||
List<SettingsListItem> items;
|
List<SettingsListItem> items;
|
||||||
}
|
}
|
|
@ -142,17 +142,5 @@ abstract class TradeDetailsViewModelBase with Store {
|
||||||
items.add(TrackTradeListItem(
|
items.add(TrackTradeListItem(
|
||||||
title: 'Track', value: buildURL, onTap: () => launch(buildURL)));
|
title: 'Track', value: buildURL, onTap: () => launch(buildURL)));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (trade.createdAt != null) {
|
|
||||||
items.add(StandartListItem(
|
|
||||||
title: S.current.trade_details_created_at,
|
|
||||||
value: trade.createdAt != null ? dateFormat.format(trade.createdAt!).toString() : ''));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (trade.from != null && trade.to != null) {
|
|
||||||
items.add(StandartListItem(
|
|
||||||
title: S.current.trade_details_pair,
|
|
||||||
value: '${trade.from.toString()} → ${trade.to.toString()}'));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import 'package:cake_wallet/view_model/wallet_address_list/wallet_address_list_item.dart';
|
||||||
import 'package:mobx/mobx.dart';
|
import 'package:mobx/mobx.dart';
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:cw_core/wallet_base.dart';
|
import 'package:cw_core/wallet_base.dart';
|
||||||
|
@ -27,10 +28,10 @@ class AddressEditOrCreateStateFailure extends AddressEditOrCreateState {
|
||||||
|
|
||||||
abstract class WalletAddressEditOrCreateViewModelBase with Store {
|
abstract class WalletAddressEditOrCreateViewModelBase with Store {
|
||||||
WalletAddressEditOrCreateViewModelBase(
|
WalletAddressEditOrCreateViewModelBase(
|
||||||
{required WalletBase wallet, dynamic item})
|
{required WalletBase wallet, WalletAddressListItem? item})
|
||||||
: isEdit = item != null,
|
: isEdit = item != null,
|
||||||
state = AddressEditOrCreateStateInitial(),
|
state = AddressEditOrCreateStateInitial(),
|
||||||
label = item?.name as String? ?? '',
|
label = item?.name ?? '',
|
||||||
_item = item,
|
_item = item,
|
||||||
_wallet = wallet;
|
_wallet = wallet;
|
||||||
|
|
||||||
|
@ -42,7 +43,7 @@ abstract class WalletAddressEditOrCreateViewModelBase with Store {
|
||||||
|
|
||||||
bool isEdit;
|
bool isEdit;
|
||||||
|
|
||||||
final dynamic _item;
|
final WalletAddressListItem? _item;
|
||||||
final WalletBase _wallet;
|
final WalletBase _wallet;
|
||||||
|
|
||||||
Future<void> save() async {
|
Future<void> save() async {
|
||||||
|
@ -98,27 +99,20 @@ abstract class WalletAddressEditOrCreateViewModelBase with Store {
|
||||||
await wallet.walletAddresses.updateAddress(_item.address as String);
|
await wallet.walletAddresses.updateAddress(_item.address as String);
|
||||||
await wallet.save();
|
await wallet.save();
|
||||||
}*/
|
}*/
|
||||||
|
final index = _item?.id;
|
||||||
if (wallet.type == WalletType.monero) {
|
if (index != null) {
|
||||||
await monero
|
if (wallet.type == WalletType.monero) {
|
||||||
!.getSubaddressList(wallet)
|
await monero!.getSubaddressList(wallet).setLabelSubaddress(wallet,
|
||||||
.setLabelSubaddress(
|
accountIndex: monero!.getCurrentAccount(wallet).id, addressIndex: index, label: label);
|
||||||
wallet,
|
await wallet.save();
|
||||||
accountIndex: monero!.getCurrentAccount(wallet).id,
|
}
|
||||||
addressIndex: _item.id as int,
|
if (wallet.type == WalletType.haven) {
|
||||||
label: label);
|
await haven!.getSubaddressList(wallet).setLabelSubaddress(wallet,
|
||||||
await wallet.save();
|
accountIndex: haven!.getCurrentAccount(wallet).id,
|
||||||
}
|
addressIndex: index,
|
||||||
|
label: label);
|
||||||
if (wallet.type == WalletType.haven) {
|
await wallet.save();
|
||||||
await haven
|
}
|
||||||
!.getSubaddressList(wallet)
|
|
||||||
.setLabelSubaddress(
|
|
||||||
wallet,
|
|
||||||
accountIndex: haven!.getCurrentAccount(wallet).id,
|
|
||||||
addressIndex: _item.id as int,
|
|
||||||
label: label);
|
|
||||||
await wallet.save();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue