mirror of
https://github.com/cake-tech/cake_wallet.git
synced 2024-12-22 19:49:22 +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:
|
||||
test:
|
||||
|
||||
runs-on: ubuntu-18.04
|
||||
runs-on: ubuntu-20.04
|
||||
env:
|
||||
STORE_PASS: test@cake_wallet
|
||||
KEY_PASS: test@cake_wallet
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
@ -18,7 +21,7 @@ jobs:
|
|||
- name: Flutter action
|
||||
uses: subosito/flutter-action@v1
|
||||
with:
|
||||
flutter-version: '3.3.x'
|
||||
flutter-version: '3.7.x'
|
||||
channel: stable
|
||||
|
||||
- name: Install package dependencies
|
||||
|
@ -34,6 +37,24 @@ jobs:
|
|||
./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,12 +66,12 @@ jobs:
|
|||
- name: Generate KeyStore
|
||||
run: |
|
||||
cd /opt/android/cake_wallet/android/app
|
||||
keytool -genkey -v -keystore key.jks -keyalg RSA -keysize 2048 -validity 10000 -alias testKey -noprompt -dname "CN=CakeWallet, OU=CakeWallet, O=CakeWallet, L=Florida, S=America, C=USA" -storepass ${{ secrets.STORE_PASS }} -keypass ${{ secrets.KEY_PASS }}
|
||||
keytool -genkey -v -keystore key.jks -keyalg RSA -keysize 2048 -validity 10000 -alias testKey -noprompt -dname "CN=CakeWallet, OU=CakeWallet, O=CakeWallet, L=Florida, S=America, C=USA" -storepass $STORE_PASS -keypass $KEY_PASS
|
||||
|
||||
- name: Generate key properties
|
||||
run: |
|
||||
cd /opt/android/cake_wallet
|
||||
flutter packages pub run tool/generate_android_key_properties.dart keyAlias=testKey storeFile=key.jks storePassword=${{ 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
|
||||
run: |
|
||||
|
@ -89,6 +110,7 @@ jobs:
|
|||
echo "const onramperApiKey = '${{ secrets.ONRAMPER_API_KEY }}';" >> lib/.secrets.g.dart
|
||||
echo "const anypayToken = '${{ secrets.ANY_PAY_TOKEN }}';" >> lib/.secrets.g.dart
|
||||
echo "const ioniaClientId = '${{ secrets.IONIA_CLIENT_ID }}';" >> lib/.secrets.g.dart
|
||||
echo "const twitterBearerToken = '${{ secrets.TWITTER_BEARER_TOKEN }}';" >> lib/.secrets.g.dart
|
||||
|
||||
- name: Rename app
|
||||
run: sed -i -e "s/\${APP_NAME}/$GITHUB_HEAD_REF/g" /opt/android/cake_wallet/android/app/src/main/AndroidManifest.xml
|
||||
|
@ -111,19 +133,20 @@ jobs:
|
|||
# --token ${{ secrets.APP_CENTER_TOKEN }} \
|
||||
# --quiet
|
||||
|
||||
- name: Send Test APK
|
||||
run: |
|
||||
cd /opt/android/cake_wallet
|
||||
var=$(curl --upload-file build/app/outputs/apk/release/app-release.apk https://transfer.sh/$GITHUB_HEAD_REF.apk -H "Max-Days: 10")
|
||||
curl ${{ secrets.SLACK_WEB_HOOK }} -H "Content-Type: application/json" -d '{"apk_link": "'"$var"'","ticket": "'"$GITHUB_HEAD_REF"'"}'
|
||||
|
||||
- name: Rename apk file
|
||||
run: |
|
||||
cd /opt/android/cake_wallet/build/app/outputs/apk/release
|
||||
mkdir test-apk
|
||||
mv app-release.apk test-apk/$GITHUB_HEAD_REF.apk
|
||||
cp app-release.apk test-apk/$GITHUB_HEAD_REF.apk
|
||||
|
||||
- name: Upload Artifact
|
||||
uses: kittaakos/upload-artifact-as-is@v0
|
||||
with:
|
||||
path: /opt/android/cake_wallet/build/app/outputs/apk/release/test-apk/
|
||||
|
||||
- name: Send Test APK
|
||||
continue-on-error: true
|
||||
run: |
|
||||
cd /opt/android/cake_wallet
|
||||
var=$(curl --upload-file build/app/outputs/apk/release/app-release.apk https://transfer.sh/$GITHUB_HEAD_REF.apk -H "Max-Days: 10")
|
||||
curl ${{ secrets.SLACK_WEB_HOOK }} -H "Content-Type: application/json" -d '{"apk_link": "'"$var"'","ticket": "'"$GITHUB_HEAD_REF"'"}'
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
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
|
||||
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
|
||||
|
||||
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:
|
||||
rules:
|
||||
- cancel_subscriptions
|
||||
- always_declare_return_types
|
||||
- prefer_final_fields
|
||||
|
||||
|
||||
# analyzer:
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.WRITE_INTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
||||
<uses-permission android:name="android.permission.CAMERA" />
|
||||
|
||||
<application
|
||||
android:name=".Application"
|
||||
|
@ -52,6 +53,15 @@
|
|||
<meta-data
|
||||
android:name="flutterEmbedding"
|
||||
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>
|
||||
|
||||
<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;
|
||||
|
||||
try {
|
||||
result = (double.parse(amount) * bitcoinAmountDivider).toInt();
|
||||
result = (double.parse(amount) * bitcoinAmountDivider).round();
|
||||
} catch (e) {
|
||||
result = 0;
|
||||
}
|
||||
|
|
|
@ -72,7 +72,7 @@ abstract class ElectrumTransactionHistoryBase
|
|||
txs.entries.forEach((entry) {
|
||||
final val = entry.value;
|
||||
|
||||
if (val is Map<String, Object>) {
|
||||
if (val is Map<String, dynamic>) {
|
||||
final tx = ElectrumTransactionInfo.fromJson(val, walletInfo.type);
|
||||
_updateOrInsert(tx);
|
||||
}
|
||||
|
@ -85,9 +85,6 @@ abstract class ElectrumTransactionHistoryBase
|
|||
}
|
||||
|
||||
void _updateOrInsert(ElectrumTransactionInfo transaction) {
|
||||
if (transaction.id == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (transactions[transaction.id] == null) {
|
||||
transactions[transaction.id] = transaction;
|
||||
|
@ -98,6 +95,7 @@ abstract class ElectrumTransactionHistoryBase
|
|||
originalTx?.height = transaction.height;
|
||||
originalTx?.date ??= transaction.date;
|
||||
originalTx?.isPending = transaction.isPending;
|
||||
originalTx?.direction = transaction.direction;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -228,9 +228,7 @@ class ElectrumTransactionInfo extends TransactionInfo {
|
|||
m['id'] = id;
|
||||
m['height'] = height;
|
||||
m['amount'] = amount;
|
||||
// FIX-ME: Hardcoded value
|
||||
// m['direction'] = direction.index;
|
||||
m['direction'] = 0;
|
||||
m['direction'] = direction.index;
|
||||
m['date'] = date.millisecondsSinceEpoch;
|
||||
m['isPending'] = isPending;
|
||||
m['confirmations'] = confirmations;
|
||||
|
|
|
@ -191,8 +191,10 @@ abstract class ElectrumWalletBase extends WalletBase<ElectrumBalance,
|
|||
throw BitcoinTransactionNoInputsException();
|
||||
}
|
||||
|
||||
final allAmountFee = feeAmountForPriority(
|
||||
transactionCredentials.priority!, inputs.length, outputs.length);
|
||||
final allAmountFee = transactionCredentials.feeRate != null
|
||||
? feeAmountWithFeeRate(transactionCredentials.feeRate!, inputs.length, outputs.length)
|
||||
: feeAmountForPriority(transactionCredentials.priority!, inputs.length, outputs.length);
|
||||
|
||||
final allAmount = allInputsAmount - allAmountFee;
|
||||
|
||||
var credentialsAmount = 0;
|
||||
|
|
|
@ -1,20 +1,18 @@
|
|||
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> {
|
||||
const CryptoCurrency({
|
||||
String title = '',
|
||||
int raw = -1,
|
||||
this.name,
|
||||
required this.name,
|
||||
this.fullName,
|
||||
this.iconPath,
|
||||
this.tag,})
|
||||
this.tag})
|
||||
: super(title: title, raw: raw);
|
||||
|
||||
final String name;
|
||||
final String? tag;
|
||||
final String? name;
|
||||
final String? fullName;
|
||||
final String? iconPath;
|
||||
|
||||
static const all = [
|
||||
|
@ -38,7 +36,7 @@ class CryptoCurrency extends EnumerableItem<int> with Serializable<int> {
|
|||
CryptoCurrency.ape,
|
||||
CryptoCurrency.avaxc,
|
||||
CryptoCurrency.btt,
|
||||
CryptoCurrency.bttbsc,
|
||||
CryptoCurrency.bttc,
|
||||
CryptoCurrency.doge,
|
||||
CryptoCurrency.firo,
|
||||
CryptoCurrency.usdttrc20,
|
||||
|
@ -53,7 +51,6 @@ class CryptoCurrency extends EnumerableItem<int> with Serializable<int> {
|
|||
CryptoCurrency.xvg,
|
||||
CryptoCurrency.usdcpoly,
|
||||
CryptoCurrency.dcr,
|
||||
CryptoCurrency.husd,
|
||||
CryptoCurrency.kmd,
|
||||
CryptoCurrency.mana,
|
||||
CryptoCurrency.maticpoly,
|
||||
|
@ -70,339 +67,117 @@ class CryptoCurrency extends EnumerableItem<int> with Serializable<int> {
|
|||
CryptoCurrency.stx,
|
||||
];
|
||||
|
||||
static const xmr = CryptoCurrency(title: 'XMR', iconPath: 'assets/images/monero_icon.png', name: 'Monero', raw: 0);
|
||||
static const ada = CryptoCurrency(title: 'ADA', iconPath: 'assets/images/ada_icon.png', name: 'Cardano', raw: 1);
|
||||
static const bch = CryptoCurrency(title: 'BCH', iconPath: 'assets/images/bch_icon.png',name: 'Bitcoin Cash', raw: 2);
|
||||
static const bnb = CryptoCurrency(title: 'BNB', iconPath: 'assets/images/bnb_icon.png', tag: 'BSC', name: 'Binance Coin', raw: 3);
|
||||
static const btc = CryptoCurrency(title: 'BTC', iconPath: 'assets/images/btc.png', name: 'Bitcoin', raw: 4);
|
||||
static const dai = CryptoCurrency(title: 'DAI', iconPath: 'assets/images/dai_icon.png', tag: 'ETH', name: 'Dai', raw: 5);
|
||||
static const dash = CryptoCurrency(title: 'DASH', iconPath: 'assets/images/dash_icon.png', name: 'Dash', raw: 6);
|
||||
static const eos = CryptoCurrency(title: 'EOS', iconPath: 'assets/images/eos_icon.png', name: 'EOS', raw: 7);
|
||||
static const eth = CryptoCurrency(title: 'ETH', iconPath: 'assets/images/eth_icon.png', name: 'Ethereum', raw: 8);
|
||||
static const ltc = CryptoCurrency(title: 'LTC', iconPath: 'assets/images/litecoin-ltc_icon.png', name: 'Litecoin', raw: 9);
|
||||
static const nano = CryptoCurrency(title: 'NANO', raw: 10);
|
||||
static const trx = CryptoCurrency(title: 'TRX', iconPath: 'assets/images/trx_icon.png', name: 'TRON', raw: 11);
|
||||
static const usdt = CryptoCurrency(title: 'USDT', iconPath: 'assets/images/usdt_icon.png', tag: 'OMNI', name: 'USDT', raw: 12);
|
||||
static const usdterc20 = CryptoCurrency(title: 'USDT', iconPath: 'assets/images/usdterc20_icon.png', tag: 'ETH', name: 'USDT', raw: 13);
|
||||
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 havenCurrencies = [
|
||||
xag,
|
||||
xau,
|
||||
xaud,
|
||||
xbtc,
|
||||
xcad,
|
||||
xchf,
|
||||
xcny,
|
||||
xeur,
|
||||
xgbp,
|
||||
xjpy,
|
||||
xnok,
|
||||
xnzd,
|
||||
xusd,
|
||||
];
|
||||
|
||||
static const xag = CryptoCurrency(title: 'XAG', tag: 'XHV', raw: 17);
|
||||
static const xau = CryptoCurrency(title: 'XAU', tag: 'XHV', raw: 18);
|
||||
static const xaud = CryptoCurrency(title: 'XAUD', tag: 'XHV', raw: 19);
|
||||
static const xbtc = CryptoCurrency(title: 'XBTC', tag: 'XHV', raw: 20);
|
||||
static const xcad = CryptoCurrency(title: 'XCAD', tag: 'XHV', raw: 21);
|
||||
static const xchf = CryptoCurrency(title: 'XCHF', tag: 'XHV', raw: 22);
|
||||
static const xcny = CryptoCurrency(title: 'XCNY', tag: 'XHV', raw: 23);
|
||||
static const xeur = CryptoCurrency(title: 'XEUR', tag: 'XHV', raw: 24);
|
||||
static const xgbp = CryptoCurrency(title: 'XGBP', tag: 'XHV', raw: 25);
|
||||
static const xjpy = CryptoCurrency(title: 'XJPY', tag: 'XHV', raw: 26);
|
||||
static const xnok = CryptoCurrency(title: 'XNOK', tag: 'XHV', raw: 27);
|
||||
static const xnzd = CryptoCurrency(title: 'XNZD', tag: 'XHV', raw: 28);
|
||||
static const xusd = CryptoCurrency(title: 'XUSD', tag: 'XHV', raw: 29);
|
||||
// title, tag (if applicable), fullName (if unique), raw, name, iconPath
|
||||
static const xmr = CryptoCurrency(title: 'XMR', fullName: 'Monero', raw: 0, name: 'xmr', iconPath: 'assets/images/monero_icon.png');
|
||||
static const ada = CryptoCurrency(title: 'ADA', fullName: 'Cardano', raw: 1, name: 'ada', iconPath: 'assets/images/ada_icon.png');
|
||||
static const bch = CryptoCurrency(title: 'BCH', fullName: 'Bitcoin Cash', raw: 2, name: 'bch', iconPath: 'assets/images/bch_icon.png');
|
||||
static const bnb = CryptoCurrency(title: 'BNB', tag: 'BSC', fullName: 'Binance Coin', raw: 3, name: 'bnb', iconPath: 'assets/images/bnb_icon.png');
|
||||
static const btc = CryptoCurrency(title: 'BTC', fullName: 'Bitcoin', raw: 4, name: 'btc', iconPath: 'assets/images/btc.png');
|
||||
static const dai = CryptoCurrency(title: 'DAI', tag: 'ETH', fullName: 'Dai', raw: 5, name: 'dai', iconPath: 'assets/images/dai_icon.png');
|
||||
static const dash = CryptoCurrency(title: 'DASH', fullName: 'Dash', raw: 6, name: 'dash', iconPath: 'assets/images/dash_icon.png');
|
||||
static const eos = CryptoCurrency(title: 'EOS', fullName: 'EOS', raw: 7, name: 'eos', iconPath: 'assets/images/eos_icon.png');
|
||||
static const eth = CryptoCurrency(title: 'ETH', fullName: 'Ethereum', raw: 8, name: 'eth', iconPath: 'assets/images/eth_icon.png');
|
||||
static const ltc = CryptoCurrency(title: 'LTC', fullName: 'Litecoin', raw: 9, name: 'ltc', iconPath: 'assets/images/litecoin-ltc_icon.png');
|
||||
static const nano = CryptoCurrency(title: 'NANO', raw: 10, name: 'nano');
|
||||
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 avaxc = CryptoCurrency(title: 'AVAX', iconPath: 'assets/images/avaxc_icon.png', tag: 'C-CHAIN', raw: 31);
|
||||
static const btt = CryptoCurrency(title: 'BTT', iconPath: 'assets/images/btt_icon.png', raw: 32);
|
||||
static const bttbsc = CryptoCurrency(title: 'BTT', iconPath: 'assets/images/bttbsc_icon.png', tag: 'BSC', raw: 33);
|
||||
static const doge = CryptoCurrency(title: 'DOGE', iconPath: 'assets/images/doge_icon.png', raw: 34);
|
||||
static const firo = CryptoCurrency(title: 'FIRO', iconPath: 'assets/images/firo_icon.png', raw: 35);
|
||||
static const usdttrc20 = CryptoCurrency(title: 'USDT', iconPath: 'assets/images/usdttrc20_icon.png', tag: 'TRX', raw: 36);
|
||||
static const hbar = CryptoCurrency(title: 'HBAR', iconPath: 'assets/images/hbar_icon.png', raw: 37);
|
||||
static const sc = CryptoCurrency(title: 'SC', iconPath: 'assets/images/sc_icon.png', raw: 38);
|
||||
static const sol = CryptoCurrency(title: 'SOL', iconPath: 'assets/images/sol_icon.png', raw: 39);
|
||||
static const usdc = CryptoCurrency(title: 'USDC', iconPath: 'assets/images/usdc_icon.png', tag: 'ETH', raw: 40);
|
||||
static const usdcsol = CryptoCurrency(title: 'USDC', iconPath: 'assets/images/usdcsol_icon.png', tag: 'SOL', raw: 41);
|
||||
static const zaddr = CryptoCurrency(title: 'ZZEC', tag: 'ZEC', name: 'Shielded Zcash', iconPath: 'assets/images/zaddr_icon.png', raw: 42);
|
||||
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 xag = CryptoCurrency(title: 'XAG', tag: 'XHV', raw: 17, name: 'xag');
|
||||
static const xau = CryptoCurrency(title: 'XAU', tag: 'XHV', raw: 18, name: 'xau');
|
||||
static const xaud = CryptoCurrency(title: 'XAUD', tag: 'XHV', raw: 19, name: 'xaud');
|
||||
static const xbtc = CryptoCurrency(title: 'XBTC', tag: 'XHV', raw: 20, name: 'xbtc');
|
||||
static const xcad = CryptoCurrency(title: 'XCAD', tag: 'XHV', raw: 21, name: 'xcad');
|
||||
static const xchf = CryptoCurrency(title: 'XCHF', tag: 'XHV', raw: 22, name: 'xchf');
|
||||
static const xcny = CryptoCurrency(title: 'XCNY', tag: 'XHV', raw: 23, name: 'xcny');
|
||||
static const xeur = CryptoCurrency(title: 'XEUR', tag: 'XHV', raw: 24, name: 'xeur');
|
||||
static const xgbp = CryptoCurrency(title: 'XGBP', tag: 'XHV', raw: 25, name: 'xgbp');
|
||||
static const xjpy = CryptoCurrency(title: 'XJPY', tag: 'XHV', raw: 26, name: 'xjpy');
|
||||
static const xnok = CryptoCurrency(title: 'XNOK', tag: 'XHV', raw: 27, name: 'xnok');
|
||||
static const xnzd = CryptoCurrency(title: 'XNZD', tag: 'XHV', raw: 28, name: 'xnzd');
|
||||
static const xusd = CryptoCurrency(title: 'XUSD', tag: 'XHV', raw: 29, name: 'xusd');
|
||||
|
||||
static const usdcpoly = CryptoCurrency(title: 'USDC', iconPath: 'assets/images/usdc_icon.png', tag: 'POLY', raw: 46);
|
||||
static const dcr = CryptoCurrency(title: 'DCR', iconPath: 'assets/images/dcr_icon.png', raw: 47);
|
||||
static const husd = CryptoCurrency(title: 'HUSD', iconPath: 'assets/images/husd_icon.png', tag: 'ETH', raw: 48);
|
||||
static const kmd = CryptoCurrency(title: 'KMD', iconPath: 'assets/images/kmd_icon.png', raw: 49);
|
||||
static const mana = CryptoCurrency(title: 'MANA', iconPath: 'assets/images/mana_icon.png', tag: 'ETH', raw: 50);
|
||||
static const maticpoly = CryptoCurrency(title: 'MATIC', iconPath: 'assets/images/matic_icon.png', tag: 'POLY', raw: 51);
|
||||
static const matic = CryptoCurrency(title: 'MATIC', iconPath: 'assets/images/matic_icon.png', tag: 'ETH', raw: 52);
|
||||
static const mkr = CryptoCurrency(title: 'MKR', iconPath: 'assets/images/mkr_icon.png', tag: 'ETH', raw: 53);
|
||||
static const near = CryptoCurrency(title: 'NEAR', iconPath: 'assets/images/near_icon.png', raw: 54);
|
||||
static const oxt = CryptoCurrency(title: 'OXT', iconPath: 'assets/images/oxt_icon.png', tag: 'ETH', raw: 55);
|
||||
static const paxg = CryptoCurrency(title: 'PAXG', iconPath: 'assets/images/paxg_icon.png', tag: 'ETH', raw: 56);
|
||||
static const pivx = CryptoCurrency(title: 'PIVX', iconPath: 'assets/images/pivx_icon.png', raw: 57);
|
||||
static const rune = CryptoCurrency(title: 'RUNE', iconPath: 'assets/images/rune_icon.png', raw: 58);
|
||||
static const rvn = CryptoCurrency(title: 'RVN', iconPath: 'assets/images/rvn_icon.png', raw: 59);
|
||||
static const scrt = CryptoCurrency(title: 'SCRT', iconPath: 'assets/images/scrt_icon.png', raw: 60);
|
||||
static const uni = CryptoCurrency(title: 'UNI', iconPath: 'assets/images/uni_icon.png', tag: 'ETH', raw: 61);
|
||||
static const stx = CryptoCurrency(title: 'STX', iconPath: 'assets/images/stx_icon.png', raw: 62);
|
||||
static const ape = CryptoCurrency(title: 'APE', tag: 'ETH', fullName: 'ApeCoin', raw: 30, name: 'ape', iconPath: 'assets/images/ape_icon.png');
|
||||
static const avaxc = CryptoCurrency(title: 'AVAX', tag: 'C-CHAIN', raw: 31, name: 'avaxc', iconPath: 'assets/images/avaxc_icon.png');
|
||||
static const btt = CryptoCurrency(title: 'BTT', tag: 'ETH', fullName: 'BitTorrent', raw: 32, name: 'btt', iconPath: 'assets/images/btt_icon.png');
|
||||
static const bttc = CryptoCurrency(title: 'BTTC', tag: 'TRX', fullName: 'BitTorrent-NEW', raw: 33, name: 'bttc', iconPath: 'assets/images/bttbsc_icon.png');
|
||||
static const doge = CryptoCurrency(title: 'DOGE', fullName: 'Dogecoin', raw: 34, name: 'doge', iconPath: 'assets/images/doge_icon.png');
|
||||
static const firo = CryptoCurrency(title: 'FIRO', raw: 35, name: 'firo', iconPath: 'assets/images/firo_icon.png');
|
||||
static const usdttrc20 = CryptoCurrency(title: 'USDT', tag: 'TRX', fullName: 'USDT Tether', raw: 36, name: 'usdttrc20', iconPath: 'assets/images/usdttrc20_icon.png');
|
||||
static const hbar = CryptoCurrency(title: 'HBAR', fullName: 'Hedera', raw: 37, name: 'hbar', iconPath: 'assets/images/hbar_icon.png', );
|
||||
static const sc = CryptoCurrency(title: 'SC', fullName: 'Siacoin', raw: 38, name: 'sc', iconPath: 'assets/images/sc_icon.png');
|
||||
static const sol = CryptoCurrency(title: 'SOL', fullName: 'Solana', raw: 39, name: 'sol', iconPath: 'assets/images/sol_icon.png');
|
||||
static const usdc = CryptoCurrency(title: 'USDC', tag: 'ETH', fullName: 'USD Coin', raw: 40, name: 'usdc', iconPath: 'assets/images/usdc_icon.png');
|
||||
static const usdcsol = CryptoCurrency(title: 'USDC', tag: 'SOL', fullName: 'USDC Coin', raw: 41, name: 'usdcsol', iconPath: 'assets/images/usdcsol_icon.png');
|
||||
static const zaddr = CryptoCurrency(title: 'ZZEC', tag: 'ZEC', fullName: 'Shielded Zcash', iconPath: 'assets/images/zaddr_icon.png', raw: 42, name: 'zaddr');
|
||||
static const zec = CryptoCurrency(title: 'TZEC', tag: 'ZEC', fullName: 'Transparent Zcash', iconPath: 'assets/images/zec_icon.png', raw: 43, name: 'zec');
|
||||
static const zen = CryptoCurrency(title: 'ZEN', fullName: 'Horizen', raw: 44, name: 'zen', iconPath: 'assets/images/zen_icon.png');
|
||||
static const xvg = CryptoCurrency(title: 'XVG', fullName: 'Verge', raw: 45, name: 'xvg', iconPath: 'assets/images/xvg_icon.png');
|
||||
|
||||
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}) {
|
||||
switch (raw) {
|
||||
case 0:
|
||||
return CryptoCurrency.xmr;
|
||||
case 1:
|
||||
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');
|
||||
|
||||
if (CryptoCurrency._rawCurrencyMap[raw] == null) {
|
||||
final s = 'Unexpected token: $raw for CryptoCurrency deserialize';
|
||||
throw ArgumentError.value(raw, 'raw', s);
|
||||
}
|
||||
return CryptoCurrency._rawCurrencyMap[raw]!;
|
||||
}
|
||||
|
||||
static CryptoCurrency fromString(String raw) {
|
||||
switch (raw.toLowerCase()) {
|
||||
case 'xmr':
|
||||
return CryptoCurrency.xmr;
|
||||
case 'ada':
|
||||
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');
|
||||
static CryptoCurrency fromString(String name) {
|
||||
|
||||
if (CryptoCurrency._nameCurrencyMap[name.toLowerCase()] == null) {
|
||||
final s = 'Unexpected token: $name for CryptoCurrency fromString';
|
||||
throw ArgumentError.value(name, 'name', s);
|
||||
}
|
||||
return CryptoCurrency._nameCurrencyMap[name.toLowerCase()]!;
|
||||
}
|
||||
|
||||
@override
|
||||
|
|
|
@ -15,4 +15,4 @@ double moneroAmountToDouble({required int amount}) =>
|
|||
cryptoAmountToDouble(amount: amount, divider: moneroAmountDivider);
|
||||
|
||||
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 {
|
||||
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)
|
||||
: id = (map['hash'] ?? '') as String,
|
||||
|
@ -22,6 +23,7 @@ class HavenTransactionInfo extends TransactionInfo {
|
|||
amount = map['amount'] as int,
|
||||
accountIndex = int.parse(map['accountIndex'] as String),
|
||||
addressIndex = map['addressIndex'] as int,
|
||||
confirmations = map['confirmations'] as int,
|
||||
key = getTxKey((map['hash'] ?? '') as String),
|
||||
fee = map['fee'] as int? ?? 0;
|
||||
|
||||
|
@ -35,6 +37,7 @@ class HavenTransactionInfo extends TransactionInfo {
|
|||
amount = row.getAmount(),
|
||||
accountIndex = row.subaddrAccount,
|
||||
addressIndex = row.subaddrIndex,
|
||||
confirmations = row.confirmations,
|
||||
key = null, //getTxKey(row.getHash()),
|
||||
fee = row.fee,
|
||||
assetType = row.getAssetType();
|
||||
|
@ -48,6 +51,7 @@ class HavenTransactionInfo extends TransactionInfo {
|
|||
final int amount;
|
||||
final int fee;
|
||||
final int addressIndex;
|
||||
final int confirmations;
|
||||
late String recipientAddress;
|
||||
late String assetType;
|
||||
String? _fiatAmount;
|
||||
|
|
|
@ -8,7 +8,8 @@ import 'package:cw_monero/api/transaction_history.dart';
|
|||
|
||||
class MoneroTransactionInfo extends TransactionInfo {
|
||||
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)
|
||||
: id = (map['hash'] ?? '') as String,
|
||||
|
@ -22,6 +23,7 @@ class MoneroTransactionInfo extends TransactionInfo {
|
|||
amount = map['amount'] as int,
|
||||
accountIndex = int.parse(map['accountIndex'] as String),
|
||||
addressIndex = map['addressIndex'] as int,
|
||||
confirmations = map['confirmations'] as int,
|
||||
key = getTxKey((map['hash'] ?? '') as String),
|
||||
fee = map['fee'] as int ?? 0 {
|
||||
additionalInfo = <String, dynamic>{
|
||||
|
@ -41,6 +43,7 @@ class MoneroTransactionInfo extends TransactionInfo {
|
|||
amount = row.getAmount(),
|
||||
accountIndex = row.subaddrAccount,
|
||||
addressIndex = row.subaddrIndex,
|
||||
confirmations = row.confirmations,
|
||||
key = getTxKey(row.getHash()),
|
||||
fee = row.fee {
|
||||
additionalInfo = <String, dynamic>{
|
||||
|
@ -59,6 +62,7 @@ class MoneroTransactionInfo extends TransactionInfo {
|
|||
final int amount;
|
||||
final int fee;
|
||||
final int addressIndex;
|
||||
final int confirmations;
|
||||
String? recipientAddress;
|
||||
String? key;
|
||||
String? _fiatAmount;
|
||||
|
|
|
@ -80,7 +80,7 @@ class AnyPayApi {
|
|||
final response = await post(Uri.parse(uri), headers: headers, body: utf8.encode(json.encode(body)));
|
||||
if (response.statusCode == 400) {
|
||||
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) {
|
||||
|
|
|
@ -24,7 +24,6 @@ class AddressValidator extends TextValidator {
|
|||
return '[0-9a-zA-Z_]';
|
||||
case CryptoCurrency.usdc:
|
||||
case CryptoCurrency.usdcpoly:
|
||||
case CryptoCurrency.husd:
|
||||
case CryptoCurrency.ape:
|
||||
case CryptoCurrency.avaxc:
|
||||
case CryptoCurrency.eth:
|
||||
|
@ -156,7 +155,7 @@ class AddressValidator extends TextValidator {
|
|||
return [98, 99, 106];
|
||||
case CryptoCurrency.btt:
|
||||
return [34];
|
||||
case CryptoCurrency.bttbsc:
|
||||
case CryptoCurrency.bttc:
|
||||
return [34];
|
||||
case CryptoCurrency.doge:
|
||||
return [34];
|
||||
|
@ -181,7 +180,6 @@ class AddressValidator extends TextValidator {
|
|||
case CryptoCurrency.stx:
|
||||
return [40, 41, 42];
|
||||
case CryptoCurrency.usdcpoly:
|
||||
case CryptoCurrency.husd:
|
||||
case CryptoCurrency.mana:
|
||||
case CryptoCurrency.matic:
|
||||
case CryptoCurrency.maticpoly:
|
||||
|
@ -200,4 +198,26 @@ class AddressValidator extends TextValidator {
|
|||
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/security_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:cake_wallet/core/backup_service.dart';
|
||||
import 'package:cw_core/wallet_service.dart';
|
||||
|
@ -381,8 +382,8 @@ Future setup(
|
|||
addressListViewModel: getIt.get<WalletAddressListViewModel>(),
|
||||
walletViewModel: getIt.get<DashboardViewModel>()));
|
||||
|
||||
getIt.registerFactoryParam<WalletAddressEditOrCreateViewModel, dynamic, void>(
|
||||
(dynamic item, _) => WalletAddressEditOrCreateViewModel(
|
||||
getIt.registerFactoryParam<WalletAddressEditOrCreateViewModel, WalletAddressListItem?, void>(
|
||||
(WalletAddressListItem? item, _) => WalletAddressEditOrCreateViewModel(
|
||||
wallet: getIt.get<AppStore>().wallet!, item: item));
|
||||
|
||||
getIt.registerFactoryParam<AddressEditOrCreatePage, dynamic, void>(
|
||||
|
|
|
@ -18,7 +18,11 @@ class LanguageService {
|
|||
'uk': 'Українська (Ukrainian)',
|
||||
'zh': '中文 (Chinese)',
|
||||
'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 = {
|
||||
|
@ -36,7 +40,11 @@ class LanguageService {
|
|||
'uk': 'ukr',
|
||||
'zh': 'chn',
|
||||
'hr': 'hrv',
|
||||
'it': 'ita'
|
||||
'it': 'ita',
|
||||
'th': 'tha',
|
||||
'ar': 'sau',
|
||||
'tr': 'tur',
|
||||
'my': 'mmr',
|
||||
};
|
||||
|
||||
static final list = <String, String> {};
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import 'package:basic_utils/basic_utils.dart';
|
||||
import 'package:cw_core/wallet_type.dart';
|
||||
|
||||
class OpenaliasRecord {
|
||||
OpenaliasRecord({
|
||||
|
@ -22,69 +21,68 @@ class OpenaliasRecord {
|
|||
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 ticker,
|
||||
}) async {
|
||||
required List<RRecord> txtRecord,
|
||||
}) {
|
||||
String address = formattedName;
|
||||
String name = formattedName;
|
||||
String note = '';
|
||||
|
||||
if (formattedName.contains(".")) {
|
||||
try {
|
||||
final txtRecord = await DnsUtils.lookupRecord(
|
||||
formattedName, RRecordType.TXT,
|
||||
dnssec: true);
|
||||
for (RRecord element in txtRecord) {
|
||||
String record = element.data;
|
||||
|
||||
if (txtRecord != null) {
|
||||
for (RRecord element in txtRecord) {
|
||||
String record = element.data;
|
||||
if (record.contains("oa1:$ticker") && record.contains("recipient_address")) {
|
||||
record = record.replaceAll('\"', "");
|
||||
|
||||
if (record.contains("oa1:$ticker") &&
|
||||
record.contains("recipient_address")) {
|
||||
record = record.replaceAll('\"', "");
|
||||
final dataList = record.split(";");
|
||||
|
||||
final dataList = record.split(";");
|
||||
address = dataList
|
||||
.where((item) => (item.contains("recipient_address")))
|
||||
.toString()
|
||||
.replaceAll("oa1:$ticker recipient_address=", "")
|
||||
.replaceAll("(", "")
|
||||
.replaceAll(")", "")
|
||||
.trim();
|
||||
|
||||
address = dataList
|
||||
.where((item) => (item.contains("recipient_address")))
|
||||
.toString()
|
||||
.replaceAll("oa1:$ticker recipient_address=", "")
|
||||
.replaceAll("(", "")
|
||||
.replaceAll(")", "")
|
||||
.trim();
|
||||
final recipientName = dataList
|
||||
.where((item) => (item.contains("recipient_name")))
|
||||
.toString()
|
||||
.replaceAll("(", "")
|
||||
.replaceAll(")", "")
|
||||
.trim();
|
||||
|
||||
final recipientName = dataList
|
||||
.where((item) => (item.contains("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;
|
||||
}
|
||||
}
|
||||
if (recipientName.isNotEmpty) {
|
||||
name = recipientName.replaceAll("recipient_name=", "");
|
||||
}
|
||||
} 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/entities/openalias_record.dart';
|
||||
import 'package:cake_wallet/entities/parsed_address.dart';
|
||||
import 'package:cake_wallet/entities/unstoppable_domain_address.dart';
|
||||
import 'package:cake_wallet/entities/emoji_string_extension.dart';
|
||||
import 'package:cake_wallet/twitter/twitter_api.dart';
|
||||
import 'package:cw_core/crypto_currency.dart';
|
||||
import 'package:cw_core/wallet_type.dart';
|
||||
import 'package:cake_wallet/entities/fio_address_provider.dart';
|
||||
|
||||
class AddressResolver {
|
||||
|
||||
AddressResolver({required this.yatService, required this.walletType});
|
||||
|
||||
|
||||
final YatService yatService;
|
||||
final WalletType walletType;
|
||||
|
||||
|
||||
static const unstoppableDomains = [
|
||||
'crypto',
|
||||
'zil',
|
||||
'x',
|
||||
'coin',
|
||||
'wallet',
|
||||
'bitcoin',
|
||||
'888',
|
||||
'nft',
|
||||
'dao',
|
||||
'blockchain'
|
||||
];
|
||||
'crypto',
|
||||
'zil',
|
||||
'x',
|
||||
'coin',
|
||||
'wallet',
|
||||
'bitcoin',
|
||||
'888',
|
||||
'nft',
|
||||
'dao',
|
||||
'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 {
|
||||
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);
|
||||
if (isFioRegistered) {
|
||||
final address = await FioAddressProvider.getPubAddress(text, ticker);
|
||||
return ParsedAddress.fetchFioAddress(address: address, name: text);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
if (text.hasOnlyEmojis) {
|
||||
if (walletType != WalletType.haven) {
|
||||
|
@ -55,10 +90,14 @@ class AddressResolver {
|
|||
return ParsedAddress.fetchUnstoppableDomainAddress(address: address, name: text);
|
||||
}
|
||||
|
||||
final record = await OpenaliasRecord.fetchAddressAndName(
|
||||
formattedName: formattedName, ticker: ticker);
|
||||
return ParsedAddress.fetchOpenAliasAddress(record: record, name: text);
|
||||
|
||||
if (formattedName.contains(".")) {
|
||||
final txtRecord = await OpenaliasRecord.lookupOpenAliasRecord(formattedName);
|
||||
if (txtRecord != null) {
|
||||
final record = await OpenaliasRecord.fetchAddressAndName(
|
||||
formattedName: formattedName, ticker: ticker, txtRecord: txtRecord);
|
||||
return ParsedAddress.fetchOpenAliasAddress(record: record, name: text);
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
print(e.toString());
|
||||
}
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
import 'package:cake_wallet/entities/openalias_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 {
|
||||
ParsedAddress({
|
||||
|
@ -41,11 +40,7 @@ class ParsedAddress {
|
|||
);
|
||||
}
|
||||
|
||||
factory ParsedAddress.fetchOpenAliasAddress({OpenaliasRecord? record, required String name}){
|
||||
final formattedName = OpenaliasRecord.formatDomainName(name);
|
||||
if (record == null || record.address.contains(formattedName)) {
|
||||
return ParsedAddress(addresses: [name]);
|
||||
}
|
||||
factory ParsedAddress.fetchOpenAliasAddress({required OpenaliasRecord record, required String name}){
|
||||
return ParsedAddress(
|
||||
addresses: [record.address],
|
||||
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 String name;
|
||||
final String description;
|
||||
|
|
|
@ -29,6 +29,7 @@ class PreferencesKey {
|
|||
static const moneroWalletPasswordUpdateV1Base = 'monero_wallet_update_v1';
|
||||
static const pinTimeOutDuration = 'pin_timeout_duration';
|
||||
static const lastAuthTimeMilliseconds = 'last_auth_time_milliseconds';
|
||||
static const lastPopupDate = 'last_popup_date';
|
||||
|
||||
|
||||
static String moneroWalletUpdateV1Key(String name)
|
||||
|
|
|
@ -7,7 +7,7 @@ Future<String> presentQRScanner() async {
|
|||
try {
|
||||
final result = await BarcodeScanner.scan();
|
||||
isQrScannerShown = false;
|
||||
return result.rawContent;
|
||||
return result.rawContent.trim();
|
||||
} catch (e) {
|
||||
isQrScannerShown = false;
|
||||
rethrow;
|
||||
|
|
|
@ -143,6 +143,7 @@ class ChangeNowExchangeProvider extends ExchangeProvider {
|
|||
final inputAddress = responseJSON['payinAddress'] as String;
|
||||
final refundAddress = responseJSON['refundAddress'] as String;
|
||||
final extraId = responseJSON['payinExtraId'] as String?;
|
||||
final payoutAddress = responseJSON['payoutAddress'] as String;
|
||||
|
||||
return Trade(
|
||||
id: id,
|
||||
|
@ -154,7 +155,8 @@ class ChangeNowExchangeProvider extends ExchangeProvider {
|
|||
extraId: extraId,
|
||||
createdAt: DateTime.now(),
|
||||
amount: responseJSON['fromAmount']?.toString() ?? _request.fromAmount,
|
||||
state: TradeState.created);
|
||||
state: TradeState.created,
|
||||
payoutAddress: payoutAddress);
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -192,6 +194,7 @@ class ChangeNowExchangeProvider extends ExchangeProvider {
|
|||
final extraId = responseJSON['payinExtraId'] as String;
|
||||
final outputTransaction = responseJSON['payoutHash'] as String;
|
||||
final expiredAtRaw = responseJSON['validUntil'] as String;
|
||||
final payoutAddress = responseJSON['payoutAddress'] as String;
|
||||
final expiredAt = DateTime.tryParse(expiredAtRaw)?.toLocal();
|
||||
|
||||
return Trade(
|
||||
|
@ -204,7 +207,8 @@ class ChangeNowExchangeProvider extends ExchangeProvider {
|
|||
state: state,
|
||||
extraId: extraId,
|
||||
expiredAt: expiredAt,
|
||||
outputTransaction: outputTransaction);
|
||||
outputTransaction: outputTransaction,
|
||||
payoutAddress: payoutAddress);
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -271,6 +275,10 @@ class ChangeNowExchangeProvider extends ExchangeProvider {
|
|||
switch(currency) {
|
||||
case CryptoCurrency.zec:
|
||||
return 'zec';
|
||||
case CryptoCurrency.usdcpoly:
|
||||
return 'usdcmatic';
|
||||
case CryptoCurrency.maticpoly:
|
||||
return 'maticmainnet';
|
||||
default:
|
||||
return currency.title.toLowerCase();
|
||||
}
|
||||
|
|
|
@ -24,6 +24,9 @@ class ExchangeProviderDescription extends EnumerableItem<int>
|
|||
static const simpleSwap =
|
||||
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}) {
|
||||
switch (raw) {
|
||||
case 0:
|
||||
|
@ -36,6 +39,8 @@ class ExchangeProviderDescription extends EnumerableItem<int>
|
|||
return sideShift;
|
||||
case 4:
|
||||
return simpleSwap;
|
||||
case 5:
|
||||
return all;
|
||||
default:
|
||||
throw Exception('Unexpected token: $raw for ExchangeProviderDescription deserialize');
|
||||
}
|
||||
|
|
|
@ -27,7 +27,6 @@ class SideShiftExchangeProvider extends ExchangeProvider {
|
|||
static const List<CryptoCurrency> _notSupported = [
|
||||
CryptoCurrency.xhv,
|
||||
CryptoCurrency.dcr,
|
||||
CryptoCurrency.husd,
|
||||
CryptoCurrency.kmd,
|
||||
CryptoCurrency.mkr,
|
||||
CryptoCurrency.near,
|
||||
|
@ -38,6 +37,7 @@ class SideShiftExchangeProvider extends ExchangeProvider {
|
|||
CryptoCurrency.rvn,
|
||||
CryptoCurrency.scrt,
|
||||
CryptoCurrency.stx,
|
||||
CryptoCurrency.bttc,
|
||||
];
|
||||
|
||||
static List<ExchangePair> _supportedPairs() {
|
||||
|
@ -150,6 +150,7 @@ class SideShiftExchangeProvider extends ExchangeProvider {
|
|||
refundAddress: settleAddress,
|
||||
state: TradeState.created,
|
||||
amount: _request.depositAmount,
|
||||
payoutAddress: settleAddress,
|
||||
createdAt: DateTime.now(),
|
||||
);
|
||||
}
|
||||
|
@ -244,6 +245,7 @@ class SideShiftExchangeProvider extends ExchangeProvider {
|
|||
final inputAddress = responseJSON['depositAddress']['address'] as String;
|
||||
final expectedSendAmount = responseJSON['depositAmount'].toString();
|
||||
final deposits = responseJSON['deposits'] as List?;
|
||||
final settleAddress = responseJSON['settleAddress']['address'] as String;
|
||||
TradeState? state;
|
||||
String? status;
|
||||
|
||||
|
@ -264,6 +266,7 @@ class SideShiftExchangeProvider extends ExchangeProvider {
|
|||
amount: expectedSendAmount,
|
||||
state: state,
|
||||
expiredAt: expiredAt,
|
||||
payoutAddress: settleAddress
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -108,6 +108,7 @@ class SimpleSwapExchangeProvider extends ExchangeProvider {
|
|||
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
|
||||
final id = responseJSON['id'] 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 extraId = responseJSON['extra_id_from'] as String?;
|
||||
return Trade(
|
||||
|
@ -120,6 +121,7 @@ class SimpleSwapExchangeProvider extends ExchangeProvider {
|
|||
extraId: extraId,
|
||||
state: TradeState.created,
|
||||
amount: _request.amount,
|
||||
payoutAddress: payoutAddress,
|
||||
createdAt: DateTime.now(),
|
||||
);
|
||||
}
|
||||
|
@ -189,6 +191,7 @@ class SimpleSwapExchangeProvider extends ExchangeProvider {
|
|||
final expectedSendAmount = responseJSON['expected_amount'].toString();
|
||||
final extraId = responseJSON['extra_id_from'] as String?;
|
||||
final status = responseJSON['status'] as String;
|
||||
final payoutAddress = responseJSON['address_to'] as String;
|
||||
final state = TradeState.deserialize(raw: status);
|
||||
|
||||
return Trade(
|
||||
|
@ -200,6 +203,7 @@ class SimpleSwapExchangeProvider extends ExchangeProvider {
|
|||
inputAddress: inputAddress,
|
||||
amount: expectedSendAmount,
|
||||
state: state,
|
||||
payoutAddress: payoutAddress,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -231,6 +235,10 @@ class SimpleSwapExchangeProvider extends ExchangeProvider {
|
|||
return 'usdcpoly';
|
||||
case CryptoCurrency.usdcsol:
|
||||
return 'usdcspl';
|
||||
case CryptoCurrency.matic:
|
||||
return 'maticerc20';
|
||||
case CryptoCurrency.maticpoly:
|
||||
return 'matic';
|
||||
default:
|
||||
return currency.title.toLowerCase();
|
||||
}
|
||||
|
|
|
@ -21,7 +21,8 @@ class Trade extends HiveObject {
|
|||
this.extraId,
|
||||
this.outputTransaction,
|
||||
this.refundAddress,
|
||||
this.walletId}) {
|
||||
this.walletId,
|
||||
this.payoutAddress}) {
|
||||
if (provider != null) {
|
||||
providerRaw = provider.raw;
|
||||
}
|
||||
|
@ -88,6 +89,9 @@ class Trade extends HiveObject {
|
|||
@HiveField(12)
|
||||
String? walletId;
|
||||
|
||||
@HiveField(13)
|
||||
String? payoutAddress;
|
||||
|
||||
static Trade fromMap(Map<String, Object?> map) {
|
||||
return Trade(
|
||||
id: map['id'] as String,
|
||||
|
|
|
@ -1,11 +1,9 @@
|
|||
import 'dart:async';
|
||||
import 'package:cake_wallet/bitcoin/bitcoin.dart';
|
||||
import 'package:cake_wallet/core/auth_service.dart';
|
||||
import 'package:cake_wallet/entities/language_service.dart';
|
||||
import 'package:cake_wallet/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/utils/exception_handler.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
|
@ -41,11 +39,23 @@ import 'package:cake_wallet/wallet_type_utils.dart';
|
|||
|
||||
final navigatorKey = GlobalKey<NavigatorState>();
|
||||
final rootKey = GlobalKey<RootState>();
|
||||
final RouteObserver<PageRoute> routeObserver = RouteObserver<PageRoute>();
|
||||
|
||||
Future<void> main() async {
|
||||
try {
|
||||
|
||||
await runZonedGuarded(() async {
|
||||
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();
|
||||
await Hive.close();
|
||||
Hive.init(appDir.path);
|
||||
|
@ -131,18 +141,9 @@ Future<void> main() async {
|
|||
secureStorage: secureStorage,
|
||||
initialMigrationVersion: 19);
|
||||
runApp(App());
|
||||
} catch (e, stacktrace) {
|
||||
runApp(MaterialApp(
|
||||
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),
|
||||
)))));
|
||||
}
|
||||
}, (error, stackTrace) async {
|
||||
ExceptionHandler.onError(FlutterErrorDetails(exception: error, stack: stackTrace));
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> initialSetup(
|
||||
|
@ -279,6 +280,7 @@ class AppState extends State<App> with SingleTickerProviderStateMixin {
|
|||
navigatorKey: navigatorKey,
|
||||
authService: authService,
|
||||
child: MaterialApp(
|
||||
navigatorObservers: [routeObserver],
|
||||
navigatorKey: navigatorKey,
|
||||
debugShowCheckedModeBanner: false,
|
||||
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/view_model/buy/buy_view_model.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:webview_flutter/webview_flutter.dart';
|
||||
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
|
||||
|
||||
class BuyWebViewPage extends BasePage {
|
||||
BuyWebViewPage({required this.buyViewModel,
|
||||
required this.ordersStore, required this.url});
|
||||
BuyWebViewPage({required this.buyViewModel, required this.ordersStore, required this.url});
|
||||
|
||||
final OrdersStore ordersStore;
|
||||
final String url;
|
||||
|
@ -46,12 +45,12 @@ class BuyWebViewPageBody extends StatefulWidget {
|
|||
|
||||
class BuyWebViewPageBodyState extends State<BuyWebViewPageBody> {
|
||||
BuyWebViewPageBodyState()
|
||||
: _webViewkey = GlobalKey(),
|
||||
_isSaving = false,
|
||||
orderId = '';
|
||||
: _webViewkey = GlobalKey(),
|
||||
_isSaving = false,
|
||||
orderId = '';
|
||||
|
||||
String orderId;
|
||||
WebViewController? _webViewController;
|
||||
InAppWebViewController? _webViewController;
|
||||
GlobalKey _webViewkey;
|
||||
Timer? _timer;
|
||||
bool _isSaving;
|
||||
|
@ -63,8 +62,6 @@ class BuyWebViewPageBodyState extends State<BuyWebViewPageBody> {
|
|||
_isSaving = false;
|
||||
widget.ordersStore.orderId = '';
|
||||
|
||||
if (Platform.isAndroid) WebView.platform = SurfaceAndroidWebView();
|
||||
|
||||
if (widget.buyViewModel.selectedProvider is WyreBuyProvider) {
|
||||
_saveOrder(keyword: 'completed', splitSymbol: '/');
|
||||
}
|
||||
|
@ -76,31 +73,31 @@ class BuyWebViewPageBodyState extends State<BuyWebViewPageBody> {
|
|||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return WebView(
|
||||
return InAppWebView(
|
||||
key: _webViewkey,
|
||||
initialUrl: widget.url,
|
||||
javascriptMode: JavascriptMode.unrestricted,
|
||||
onWebViewCreated: (WebViewController controller) =>
|
||||
initialOptions: InAppWebViewGroupOptions(
|
||||
crossPlatform: InAppWebViewOptions(transparentBackground: true),
|
||||
),
|
||||
initialUrlRequest: URLRequest(url: Uri.tryParse(widget.url ?? '')),
|
||||
onWebViewCreated: (InAppWebViewController controller) =>
|
||||
setState(() => _webViewController = controller));
|
||||
}
|
||||
|
||||
void _saveOrder({required String keyword, required String splitSymbol}) {
|
||||
_timer?.cancel();
|
||||
_timer = Timer.periodic(Duration(seconds: 1), (timer) async {
|
||||
|
||||
try {
|
||||
if (_webViewController == null || _isSaving) {
|
||||
return;
|
||||
}
|
||||
|
||||
final url = await _webViewController!.currentUrl();
|
||||
|
||||
final url = (await _webViewController!.getUrl())?.toString();
|
||||
if (url == null) {
|
||||
throw Exception('_saveOrder: Url is null');
|
||||
}
|
||||
|
||||
if (url!.contains(keyword)) {
|
||||
final urlParts = url!.split(splitSymbol);
|
||||
if (url.contains(keyword)) {
|
||||
final urlParts = url.split(splitSymbol);
|
||||
orderId = urlParts.last;
|
||||
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/src/screens/base_page.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 {
|
||||
OnRamperPage(this._onRamperBuyProvider);
|
||||
|
@ -44,17 +46,26 @@ class OnRamperPageBody extends StatefulWidget {
|
|||
class OnRamperPageBodyState extends State<OnRamperPageBody> {
|
||||
OnRamperPageBodyState();
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
if (Platform.isAndroid) WebView.platform = SurfaceAndroidWebView();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return WebView(
|
||||
initialUrl: widget.uri.toString(),
|
||||
backgroundColor: widget.backgroundColor,
|
||||
javascriptMode: JavascriptMode.unrestricted);
|
||||
return InAppWebView(
|
||||
initialOptions: InAppWebViewGroupOptions(
|
||||
crossPlatform: InAppWebViewOptions(transparentBackground: true),
|
||||
),
|
||||
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:
|
||||
Theme.of(context).primaryTextTheme.caption!.decorationColor!,
|
||||
sectionTitleBuilder: (_, int sectionIndex) {
|
||||
var title = 'Contacts';
|
||||
var title = S.current.contact_list_contacts;
|
||||
|
||||
if (sectionIndex == 0) {
|
||||
title = 'My wallets';
|
||||
title = S.current.contact_list_wallets;
|
||||
}
|
||||
|
||||
return Container(
|
||||
|
|
|
@ -1,10 +1,8 @@
|
|||
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/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/utils/share_util.dart';
|
||||
import 'package:cake_wallet/utils/show_pop_up.dart';
|
||||
import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.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:keyboard_actions/keyboard_actions.dart';
|
||||
import 'package:mobx/mobx.dart';
|
||||
import 'package:share_plus/share_plus.dart';
|
||||
|
||||
class AddressPage extends BasePage {
|
||||
AddressPage({
|
||||
|
@ -84,7 +81,12 @@ class AddressPage extends BasePage {
|
|||
highlightColor: Colors.transparent,
|
||||
splashColor: Colors.transparent,
|
||||
iconSize: 25,
|
||||
onPressed: () => Share.share(addressListViewModel.address.address),
|
||||
onPressed: () {
|
||||
ShareUtil.share(
|
||||
text: addressListViewModel.address.address,
|
||||
context: context,
|
||||
);
|
||||
},
|
||||
icon: shareImage,
|
||||
),
|
||||
) : null;
|
||||
|
|
|
@ -9,12 +9,7 @@ class FilterTile extends StatelessWidget {
|
|||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
width: double.infinity,
|
||||
padding: EdgeInsets.only(
|
||||
top: 18,
|
||||
bottom: 18,
|
||||
left: 24,
|
||||
right: 24
|
||||
),
|
||||
padding: EdgeInsets.symmetric(vertical: 8.0, horizontal: 24.0),
|
||||
child: child,
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,25 +1,26 @@
|
|||
import 'dart:ui';
|
||||
import 'package:cake_wallet/palette.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: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';
|
||||
import 'package:cake_wallet/src/widgets/checkbox_widget.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;
|
||||
|
||||
class FilterWidget extends StatelessWidget {
|
||||
FilterWidget({required this.dashboardViewModel});
|
||||
|
||||
final DashboardViewModel dashboardViewModel;
|
||||
final backVector = Image.asset('assets/images/back_vector.png',
|
||||
color: Palette.darkBlueCraiola
|
||||
);
|
||||
final closeIcon = Image.asset('assets/images/close.png', color: Palette.darkBlueCraiola);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
const sectionDivider = const SectionDivider();
|
||||
return AlertBackground(
|
||||
child: Stack(
|
||||
alignment: Alignment.center,
|
||||
|
@ -27,129 +28,82 @@ class FilterWidget extends StatelessWidget {
|
|||
Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: <Widget>[
|
||||
Text(
|
||||
S.of(context).filters,
|
||||
style: TextStyle(
|
||||
color: Colors.white,
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.bold,
|
||||
fontFamily: 'Lato',
|
||||
decoration: TextDecoration.none,
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.only(
|
||||
left: 24,
|
||||
right: 24,
|
||||
top: 24
|
||||
),
|
||||
padding: EdgeInsets.only(left: 24, right: 24, top: 24),
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.all(Radius.circular(14)),
|
||||
borderRadius: BorderRadius.all(Radius.circular(24)),
|
||||
child: Container(
|
||||
color: Theme.of(context).textTheme!.bodyText1!.decorationColor!,
|
||||
child: ListView.separated(
|
||||
shrinkWrap: true,
|
||||
physics: const NeverScrollableScrollPhysics(),
|
||||
itemCount: dashboardViewModel.filterItems.length,
|
||||
separatorBuilder: (context, _) => Container(
|
||||
height: 1,
|
||||
color: Theme.of(context).accentTextTheme!.subtitle1!.backgroundColor!,
|
||||
child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
|
||||
Padding(
|
||||
padding: EdgeInsets.all(24.0),
|
||||
child: Text(
|
||||
S.of(context).filter_by,
|
||||
style: TextStyle(
|
||||
color: Theme.of(context).primaryTextTheme.overline!.color!,
|
||||
fontSize: 16,
|
||||
fontFamily: 'Lato',
|
||||
decoration: TextDecoration.none,
|
||||
),
|
||||
),
|
||||
),
|
||||
itemBuilder: (_, index1) {
|
||||
final title = dashboardViewModel.filterItems.keys.elementAt(index1);
|
||||
final section = dashboardViewModel.filterItems.values.elementAt(index1);
|
||||
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
Padding(
|
||||
padding: EdgeInsets.only(
|
||||
top: 20,
|
||||
left: 24,
|
||||
right: 24
|
||||
),
|
||||
child: Text(
|
||||
title,
|
||||
style: TextStyle(
|
||||
color: Theme.of(context).accentTextTheme!.subtitle1!.color!,
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w500,
|
||||
fontFamily: 'Lato',
|
||||
decoration: TextDecoration.none
|
||||
sectionDivider,
|
||||
ListView.separated(
|
||||
padding: EdgeInsets.zero,
|
||||
shrinkWrap: true,
|
||||
physics: const NeverScrollableScrollPhysics(),
|
||||
itemCount: dashboardViewModel.filterItems.length,
|
||||
separatorBuilder: (context, _) => sectionDivider,
|
||||
itemBuilder: (_, index1) {
|
||||
final title = dashboardViewModel.filterItems.keys.elementAt(index1);
|
||||
final section = dashboardViewModel.filterItems.values.elementAt(index1);
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: 20, left: 24, right: 24),
|
||||
child: Text(
|
||||
title,
|
||||
style: TextStyle(
|
||||
color: Theme.of(context).primaryTextTheme!.headline6!.color!,
|
||||
fontSize: 16,
|
||||
fontFamily: 'Lato',
|
||||
fontWeight: FontWeight.bold,
|
||||
decoration: TextDecoration.none),
|
||||
),
|
||||
),
|
||||
),
|
||||
ListView.separated(
|
||||
shrinkWrap: true,
|
||||
physics: const NeverScrollableScrollPhysics(),
|
||||
itemCount: section.length,
|
||||
separatorBuilder: (context, _) => Container(
|
||||
height: 1,
|
||||
padding: EdgeInsets.only(left: 24),
|
||||
color: Theme.of(context).textTheme!.bodyText1!.decorationColor!,
|
||||
child: Container(
|
||||
height: 1,
|
||||
color: Theme.of(context).accentTextTheme!.subtitle1!.backgroundColor!,
|
||||
),
|
||||
),
|
||||
itemBuilder: (_, index2) {
|
||||
|
||||
final item = section[index2];
|
||||
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);
|
||||
},
|
||||
)
|
||||
],
|
||||
);
|
||||
},
|
||||
),
|
||||
ListView.builder(
|
||||
padding: EdgeInsets.symmetric(vertical: 8.0),
|
||||
shrinkWrap: true,
|
||||
physics: const NeverScrollableScrollPhysics(),
|
||||
itemCount: section.length,
|
||||
itemBuilder: (_, index2) {
|
||||
final item = section[index2];
|
||||
final content = Observer(
|
||||
builder: (_) => StandardCheckbox(
|
||||
value: item.value(),
|
||||
caption: item.caption,
|
||||
gradientBackground: true,
|
||||
borderColor: Theme.of(context).dividerColor,
|
||||
iconColor: Colors.white,
|
||||
onChanged: (value) => item.onChanged(),
|
||||
));
|
||||
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:flutter/material.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:url_launcher/url_launcher.dart';
|
||||
|
||||
class MarketPlacePage extends StatelessWidget {
|
||||
|
||||
|
@ -48,6 +49,15 @@ class MarketPlacePage extends StatelessWidget {
|
|||
title: S.of(context).cake_pay_title,
|
||||
subTitle: S.of(context).cake_pay_subtitle,
|
||||
),
|
||||
SizedBox(height: 20),
|
||||
MarketPlaceItem(
|
||||
onTap: () => launchUrl(
|
||||
Uri.https("buy.cakepay.com"),
|
||||
mode: LaunchMode.externalApplication,
|
||||
),
|
||||
title: S.of(context).cake_pay_web_cards_title,
|
||||
subTitle: S.of(context).cake_pay_web_cards_subtitle,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
@ -72,7 +82,7 @@ class MarketPlacePage extends StatelessWidget {
|
|||
buttonAction: () => Navigator.of(context).pop());
|
||||
});
|
||||
break;
|
||||
default:
|
||||
default:
|
||||
Navigator.of(context).pushNamed(Routes.ioniaWelcomePage);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:cw_core/transaction_direction.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
|
||||
class TransactionRow extends StatelessWidget {
|
||||
TransactionRow(
|
||||
|
@ -9,6 +8,7 @@ class TransactionRow extends StatelessWidget {
|
|||
required this.formattedAmount,
|
||||
required this.formattedFiatAmount,
|
||||
required this.isPending,
|
||||
required this.title,
|
||||
required this.onTap});
|
||||
|
||||
final VoidCallback onTap;
|
||||
|
@ -17,6 +17,7 @@ class TransactionRow extends StatelessWidget {
|
|||
final String formattedAmount;
|
||||
final String formattedFiatAmount;
|
||||
final bool isPending;
|
||||
final String title;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
@ -49,11 +50,7 @@ class TransactionRow extends StatelessWidget {
|
|||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: <Widget>[
|
||||
Text(
|
||||
(direction == TransactionDirection.incoming
|
||||
? S.of(context).received
|
||||
: S.of(context).sent) +
|
||||
(isPending ? S.of(context).pending : ''),
|
||||
Text(title,
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w500,
|
||||
|
|
|
@ -61,7 +61,8 @@ class TransactionsPage extends StatelessWidget {
|
|||
formattedFiatAmount:
|
||||
dashboardViewModel.balanceViewModel.isFiatDisabled
|
||||
? '' : item.formattedFiatAmount,
|
||||
isPending: transaction.isPending));
|
||||
isPending: transaction.isPending,
|
||||
title: item.formattedTitle + item.formattedStatus));
|
||||
}
|
||||
|
||||
if (item is TradeListItem) {
|
||||
|
|
|
@ -48,7 +48,6 @@ class ExchangePage extends BasePage {
|
|||
final ExchangeViewModel exchangeViewModel;
|
||||
final depositKey = GlobalKey<ExchangeCardState>();
|
||||
final receiveKey = GlobalKey<ExchangeCardState>();
|
||||
final checkBoxKey = GlobalKey<StandardCheckboxState>();
|
||||
final _formKey = GlobalKey<FormState>();
|
||||
final _depositAmountFocus = FocusNode();
|
||||
final _depositAddressFocus = FocusNode();
|
||||
|
@ -150,7 +149,6 @@ class ExchangePage extends BasePage {
|
|||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
StandardCheckbox(
|
||||
key: checkBoxKey,
|
||||
value: exchangeViewModel.isFixedRateMode,
|
||||
caption: S.of(context).fixed_rate,
|
||||
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(
|
||||
() => exchangeViewModel.depositAddress = depositAddressController.text);
|
||||
|
||||
|
|
|
@ -55,7 +55,7 @@ class CurrencyPickerState extends State<CurrencyPicker> {
|
|||
.where((element) =>
|
||||
(element.title.toLowerCase().contains(subString.toLowerCase())) ||
|
||||
(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();
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ import 'package:cake_wallet/generated/i18n.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/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_pop_up.dart';
|
||||
import 'package:cake_wallet/view_model/exchange/exchange_trade_view_model.dart';
|
||||
|
@ -112,7 +112,7 @@ class ExchangeTradeState extends State<ExchangeTradeForm> {
|
|||
width: 16,
|
||||
color: Theme.of(context).primaryTextTheme!.overline!.color!);
|
||||
|
||||
_setEffects(context);
|
||||
_setEffects();
|
||||
|
||||
return Container(
|
||||
child: ScrollableWithBottomSection(
|
||||
|
@ -165,14 +165,7 @@ class ExchangeTradeState extends State<ExchangeTradeForm> {
|
|||
.color!
|
||||
)
|
||||
),
|
||||
child: QrImage(
|
||||
data: trade.inputAddress ?? fetchingLabel,
|
||||
backgroundColor: Colors.transparent,
|
||||
foregroundColor: Theme.of(context)
|
||||
.accentTextTheme!
|
||||
.subtitle2!
|
||||
.color!,
|
||||
),
|
||||
child: QrImage(data: trade.inputAddress ?? fetchingLabel),
|
||||
)))),
|
||||
Spacer(flex: 3)
|
||||
]),
|
||||
|
@ -194,7 +187,7 @@ class ExchangeTradeState extends State<ExchangeTradeForm> {
|
|||
final item = widget.exchangeTradeViewModel.items[index];
|
||||
final value = item.data ?? fetchingLabel;
|
||||
|
||||
final content = StandartListRow(
|
||||
final content = ListRow(
|
||||
title: item.title,
|
||||
value: value,
|
||||
valueFontSize: 14,
|
||||
|
@ -241,7 +234,7 @@ class ExchangeTradeState extends State<ExchangeTradeForm> {
|
|||
);
|
||||
}
|
||||
|
||||
void _setEffects(BuildContext context) {
|
||||
void _setEffects() {
|
||||
if (_effectsInstalled) {
|
||||
return;
|
||||
}
|
||||
|
@ -252,12 +245,12 @@ class ExchangeTradeState extends State<ExchangeTradeForm> {
|
|||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
showPopUp<void>(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
builder: (BuildContext popupContext) {
|
||||
return AlertWithOneAction(
|
||||
alertTitle: S.of(context).error,
|
||||
alertTitle: S.of(popupContext).error,
|
||||
alertContent: state.error,
|
||||
buttonText: S.of(context).ok,
|
||||
buttonAction: () => Navigator.of(context).pop());
|
||||
buttonText: S.of(popupContext).ok,
|
||||
buttonAction: () => Navigator.of(popupContext).pop());
|
||||
});
|
||||
});
|
||||
}
|
||||
|
@ -266,118 +259,24 @@ class ExchangeTradeState extends State<ExchangeTradeForm> {
|
|||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
showPopUp<void>(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
builder: (BuildContext popupContext) {
|
||||
return ConfirmSendingAlert(
|
||||
alertTitle: S.of(context).confirm_sending,
|
||||
amount: S.of(context).send_amount,
|
||||
alertTitle: S.of(popupContext).confirm_sending,
|
||||
amount: S.of(popupContext).send_amount,
|
||||
amountValue: widget.exchangeTradeViewModel.sendViewModel
|
||||
.pendingTransaction!.amountFormatted,
|
||||
fee: S.of(context).send_fee,
|
||||
fee: S.of(popupContext).send_fee,
|
||||
feeValue: widget.exchangeTradeViewModel.sendViewModel
|
||||
.pendingTransaction!.feeFormatted,
|
||||
rightButtonText: S.of(context).ok,
|
||||
leftButtonText: S.of(context).cancel,
|
||||
rightButtonText: S.of(popupContext).ok,
|
||||
leftButtonText: S.of(popupContext).cancel,
|
||||
actionRightButton: () async {
|
||||
Navigator.of(context).pop();
|
||||
Navigator.of(popupContext).pop();
|
||||
await widget.exchangeTradeViewModel.sendViewModel
|
||||
.commitTransaction();
|
||||
await showPopUp<void>(
|
||||
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,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
);
|
||||
});
|
||||
});
|
||||
transactionStatePopup();
|
||||
},
|
||||
actionLeftButton: () => Navigator.of(context).pop(),
|
||||
actionLeftButton: () => Navigator.of(popupContext).pop(),
|
||||
feeFiatAmount: widget.exchangeTradeViewModel
|
||||
.pendingTransactionFeeFiatAmountFormatted,
|
||||
fiatAmountValue: widget.exchangeTradeViewModel
|
||||
|
@ -392,12 +291,12 @@ class ExchangeTradeState extends State<ExchangeTradeForm> {
|
|||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
showPopUp<void>(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
builder: (BuildContext popupContext) {
|
||||
return AlertWithOneAction(
|
||||
alertTitle: S.of(context).sending,
|
||||
alertContent: S.of(context).transaction_sent,
|
||||
buttonText: S.of(context).ok,
|
||||
buttonAction: () => Navigator.of(context).pop());
|
||||
alertTitle: S.of(popupContext).sending,
|
||||
alertContent: S.of(popupContext).transaction_sent,
|
||||
buttonText: S.of(popupContext).ok,
|
||||
buttonAction: () => Navigator.of(popupContext).pop());
|
||||
});
|
||||
});
|
||||
}
|
||||
|
@ -405,4 +304,102 @@ class ExchangeTradeState extends State<ExchangeTradeForm> {
|
|||
|
||||
_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 TextEditingController _emailController;
|
||||
|
||||
static const privacyPolicyUrl = 'https://ionia.docsend.com/view/jaqsmbq9w7dzvnqf';
|
||||
static const termsAndConditionsUrl = 'https://ionia.docsend.com/view/hi9awnwxr6mqgiqj';
|
||||
static const privacyPolicyUrl = 'https://ionia.docsend.com/view/jhjvdn7qq7k3ukwt';
|
||||
static const termsAndConditionsUrl = 'https://ionia.docsend.com/view/uceirymz2ijacq5g';
|
||||
|
||||
@override
|
||||
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/utils/show_bar.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:device_display_brightness/device_display_brightness.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
@ -47,10 +48,7 @@ class IoniaGiftCardDetailPage extends BasePage {
|
|||
//highlightColor: Colors.transparent,
|
||||
//splashColor: Colors.transparent,
|
||||
//padding: EdgeInsets.all(0),
|
||||
onPressed: () {
|
||||
onClose(context);
|
||||
DeviceDisplayBrightness.setBrightness(viewModel.brightness);
|
||||
},
|
||||
onPressed: ()=> onClose(context),
|
||||
child: _backButton),
|
||||
),
|
||||
),
|
||||
|
@ -68,7 +66,6 @@ class IoniaGiftCardDetailPage extends BasePage {
|
|||
|
||||
@override
|
||||
Widget body(BuildContext context) {
|
||||
viewModel.increaseBrightness();
|
||||
reaction((_) => viewModel.redeemState, (ExecutionState state) {
|
||||
if (state is FailureState) {
|
||||
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),
|
||||
content: Column(
|
||||
children: [
|
||||
|
@ -164,7 +166,7 @@ class IoniaGiftCardDetailPage extends BasePage {
|
|||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
));
|
||||
}
|
||||
|
||||
Widget buildIoniaTile(BuildContext context, {required String title, required String subTitle}) {
|
||||
|
|
|
@ -157,7 +157,8 @@ class _IoniaPaymentStatusPageBodyBodyState extends State<_IoniaPaymentStatusPage
|
|||
Container(
|
||||
padding: EdgeInsets.only(left: 40, right: 40, bottom: 20),
|
||||
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(
|
||||
color: Theme.of(context).primaryTextTheme!.headline6!.color!,
|
||||
).copyWith(fontWeight: FontWeight.w500),
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import 'dart:ui';
|
||||
import 'package:cake_wallet/src/widgets/section_divider.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||
|
@ -84,10 +85,7 @@ class MoneroAccountListPage extends StatelessWidget {
|
|||
padding: EdgeInsets.zero,
|
||||
controller: controller,
|
||||
separatorBuilder: (context, index) =>
|
||||
Container(
|
||||
height: 1,
|
||||
color: Theme.of(context).dividerColor,
|
||||
),
|
||||
const SectionDivider(),
|
||||
itemCount: accounts.length ?? 0,
|
||||
itemBuilder: (context, 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/widgets/alert_with_two_actions.dart';
|
||||
import 'package:cake_wallet/src/widgets/standard_list.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class NodeListRow extends StandardListRow {
|
||||
|
@ -23,7 +19,7 @@ class NodeListRow extends StandardListRow {
|
|||
builder: (context, snapshot) {
|
||||
switch (snapshot.connectionState) {
|
||||
case ConnectionState.done:
|
||||
return NodeIndicator(isLive: (snapshot.data as bool)??false);
|
||||
return NodeIndicator(isLive: (snapshot.data as bool?) ?? false);
|
||||
default:
|
||||
return NodeIndicator(isLive: false);
|
||||
}
|
||||
|
@ -40,7 +36,7 @@ class NodeHeaderListRow extends StandardListRow {
|
|||
return SizedBox(
|
||||
width: 20,
|
||||
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:cake_wallet/generated/i18n.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';
|
||||
|
||||
class OrderDetailsPage extends BasePage {
|
||||
|
@ -57,7 +57,7 @@ class OrderDetailsPageBodyState extends State<OrderDetailsPageBody> {
|
|||
if (item is TrackTradeListItem) {
|
||||
return GestureDetector(
|
||||
onTap: item.onTap,
|
||||
child: StandartListRow(
|
||||
child: ListRow(
|
||||
title: '${item.title}', value: '${item.value}'));
|
||||
} else {
|
||||
return GestureDetector(
|
||||
|
@ -65,7 +65,7 @@ class OrderDetailsPageBodyState extends State<OrderDetailsPageBody> {
|
|||
Clipboard.setData(ClipboardData(text: '${item.value}'));
|
||||
showBar<void>(context, S.of(context).copied_to_clipboard);
|
||||
},
|
||||
child: StandartListRow(
|
||||
child: ListRow(
|
||||
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/themes/theme_base.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:cake_wallet/src/screens/base_page.dart';
|
||||
|
||||
class FullscreenQRPage extends BasePage {
|
||||
|
@ -69,14 +68,10 @@ class FullscreenQRPage extends BasePage {
|
|||
child: AspectRatio(
|
||||
aspectRatio: 1.0,
|
||||
child: Container(
|
||||
padding: EdgeInsets.all(5),
|
||||
padding: EdgeInsets.all(10),
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(width: 3, color: Theme.of(context).accentTextTheme!.headline2!.backgroundColor!)),
|
||||
child: QrImage(
|
||||
data: qrData,
|
||||
backgroundColor: isLight ? Colors.transparent : Colors.black,
|
||||
foregroundColor: Theme.of(context).accentTextTheme!.headline2!.backgroundColor!,
|
||||
),
|
||||
child: QrImage(data: qrData),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
|
|
@ -1,12 +1,11 @@
|
|||
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/utils/share_util.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:flutter/material.dart';
|
||||
import 'package:flutter/cupertino.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/generated/i18n.dart';
|
||||
import 'package:cake_wallet/di.dart';
|
||||
|
@ -100,7 +99,12 @@ class ReceivePage extends BasePage {
|
|||
highlightColor: Colors.transparent,
|
||||
splashColor: Colors.transparent,
|
||||
iconSize: 25,
|
||||
onPressed: () => Share.share(addressListViewModel.address.address),
|
||||
onPressed: () {
|
||||
ShareUtil.share(
|
||||
text: addressListViewModel.address.address,
|
||||
context: context,
|
||||
);
|
||||
},
|
||||
icon: shareImage
|
||||
)
|
||||
);
|
||||
|
@ -135,8 +139,7 @@ class ReceivePage extends BasePage {
|
|||
Observer(
|
||||
builder: (_) => ListView.separated(
|
||||
padding: EdgeInsets.all(0),
|
||||
separatorBuilder: (context, _) => Container(
|
||||
height: 1, color: Theme.of(context).dividerColor),
|
||||
separatorBuilder: (context, _) => const SectionDivider(),
|
||||
shrinkWrap: true,
|
||||
physics: NeverScrollableScrollPhysics(),
|
||||
itemCount: addressListViewModel.items.length,
|
||||
|
|
|
@ -1,30 +1,29 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:qr/qr.dart';
|
||||
import 'package:cake_wallet/src/screens/receive/widgets/qr_painter.dart';
|
||||
import 'package:qr_flutter/qr_flutter.dart' as qr;
|
||||
|
||||
class QrImage extends StatelessWidget {
|
||||
QrImage({
|
||||
required String data,
|
||||
required this.data,
|
||||
this.size = 100.0,
|
||||
this.backgroundColor,
|
||||
Color foregroundColor = Colors.black,
|
||||
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);
|
||||
this.version = 9, // Previous value: 7 something happened after flutter upgrade monero wallets addresses are longer than ver. 7 ???
|
||||
this.errorCorrectionLevel = qr.QrErrorCorrectLevel.L,
|
||||
});
|
||||
|
||||
final QrPainter _painter;
|
||||
final Color? backgroundColor;
|
||||
final double size;
|
||||
final String data;
|
||||
final int version;
|
||||
final int errorCorrectionLevel;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
width: size,
|
||||
height: size,
|
||||
color: backgroundColor,
|
||||
child: CustomPaint(
|
||||
painter: _painter,
|
||||
),
|
||||
return qr.QrImage(
|
||||
data: data,
|
||||
errorCorrectionLevel: errorCorrectionLevel,
|
||||
version: version,
|
||||
size: size,
|
||||
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!,
|
||||
),
|
||||
),
|
||||
child: QrImage(
|
||||
data: addressListViewModel.uri.toString(),
|
||||
backgroundColor: isLight ? Colors.transparent : Colors.black,
|
||||
foregroundColor: Theme.of(context).accentTextTheme!.headline2!.backgroundColor!,
|
||||
),
|
||||
child: QrImage(data: addressListViewModel.uri.toString()),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
import 'package:cake_wallet/palette.dart';
|
||||
import 'package:cake_wallet/themes/theme_base.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/show_bar.dart';
|
||||
import 'package:cake_wallet/utils/show_pop_up.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:share_plus/share_plus.dart';
|
||||
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/src/widgets/primary_button.dart';
|
||||
|
@ -22,9 +22,6 @@ class WalletSeedPage extends BasePage {
|
|||
@override
|
||||
String get title => S.current.seed_title;
|
||||
|
||||
@override
|
||||
bool get canUseDesktopAppBar => false;
|
||||
|
||||
final bool isNewWalletCreated;
|
||||
final WalletSeedViewModel walletSeedViewModel;
|
||||
|
||||
|
@ -166,8 +163,12 @@ class WalletSeedPage extends BasePage {
|
|||
child: Container(
|
||||
padding: EdgeInsets.only(right: 8.0),
|
||||
child: PrimaryButton(
|
||||
onPressed: () =>
|
||||
Share.share(walletSeedViewModel.seed),
|
||||
onPressed: () {
|
||||
ShareUtil.share(
|
||||
text: walletSeedViewModel.seed,
|
||||
context: context,
|
||||
);
|
||||
},
|
||||
text: S.of(context).save,
|
||||
color: Colors.green,
|
||||
textColor: Colors.white),
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
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:cake_wallet/src/widgets/base_alert_dialog.dart';
|
||||
|
||||
|
@ -70,10 +71,7 @@ class ChooseYatAddressButtonsState extends State<ChooseYatAddressButtons> {
|
|||
controller: controller,
|
||||
padding: EdgeInsets.all(0),
|
||||
itemCount: itemCount,
|
||||
separatorBuilder: (_, __) => Container(
|
||||
height: 1,
|
||||
color: Theme.of(context).dividerColor,
|
||||
),
|
||||
separatorBuilder: (_, __) => const SectionDivider(),
|
||||
itemBuilder: (context, index) {
|
||||
final address = addresses[index];
|
||||
|
||||
|
|
|
@ -19,13 +19,18 @@ Future<String> extractAddressFromParsed(
|
|||
address = parsedAddress.addresses.first;
|
||||
break;
|
||||
case ParseFrom.openAlias:
|
||||
title = S.of(context).openalias_alert_title;
|
||||
content = S.of(context).openalias_alert_content(parsedAddress.name);
|
||||
title = S.of(context).address_detected;
|
||||
content = S.of(context).extracted_address_content('${parsedAddress.name} (OpenAlias)');
|
||||
address = parsedAddress.addresses.first;
|
||||
break;
|
||||
case ParseFrom.fio:
|
||||
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;
|
||||
break;
|
||||
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/view_model/dashboard/dashboard_view_model.dart';
|
||||
import 'package:cw_core/node.dart';
|
||||
import 'package:cw_core/wallet_type.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||
|
@ -35,10 +36,11 @@ class ConnectionSyncPage extends BasePage {
|
|||
handler: (context) => _presentReconnectAlert(context),
|
||||
),
|
||||
StandardListSeparator(padding: EdgeInsets.symmetric(horizontal: 24)),
|
||||
SettingsCellWithArrow(
|
||||
title: S.current.rescan,
|
||||
handler: (context) => Navigator.of(context).pushNamed(Routes.rescan),
|
||||
),
|
||||
if (dashboardViewModel.hasRescan)
|
||||
SettingsCellWithArrow(
|
||||
title: S.current.rescan,
|
||||
handler: (context) => Navigator.of(context).pushNamed(Routes.rescan),
|
||||
),
|
||||
StandardListSeparator(padding: EdgeInsets.symmetric(horizontal: 24)),
|
||||
NodeHeaderListRow(
|
||||
title: S.of(context).add_new_node,
|
||||
|
@ -73,7 +75,7 @@ class ConnectionSyncPage extends BasePage {
|
|||
builder: (BuildContext context) {
|
||||
return AlertWithTwoActions(
|
||||
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,
|
||||
rightButtonText: S.of(context).change,
|
||||
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/standard_list.dart';
|
||||
|
||||
class SettingsPickerCell<ItemType extends Object> extends StandardListRow {
|
||||
class SettingsPickerCell<ItemType> extends StandardListRow {
|
||||
SettingsPickerCell(
|
||||
{required String title,
|
||||
required this.selectedItem,
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import 'package:flutter/cupertino.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 {
|
||||
SettingsSwitcherCell(
|
||||
|
@ -11,6 +11,6 @@ class SettingsSwitcherCell extends StandardListRow {
|
|||
final void Function(BuildContext context, bool value)? onValueChange;
|
||||
|
||||
@override
|
||||
Widget buildTrailing(BuildContext context) => StandartSwitch(
|
||||
Widget buildTrailing(BuildContext context) => StandardSwitch(
|
||||
value: value, onTaped: () => onValueChange?.call(context, !value));
|
||||
}
|
||||
|
|
|
@ -17,8 +17,6 @@ class AddressEditOrCreatePage extends BasePage {
|
|||
_labelController.addListener(
|
||||
() => addressEditOrCreateViewModel.label = _labelController.text);
|
||||
_labelController.text = addressEditOrCreateViewModel.label;
|
||||
print(_labelController.text);
|
||||
print(addressEditOrCreateViewModel.label);
|
||||
}
|
||||
|
||||
final WalletAddressEditOrCreateViewModel addressEditOrCreateViewModel;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
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/standart_list_status_row.dart';
|
||||
import 'package:cake_wallet/src/widgets/standard_list_card.dart';
|
||||
import 'package:cake_wallet/src/widgets/standard_list_status_row.dart';
|
||||
import 'package:cake_wallet/utils/show_bar.dart';
|
||||
import 'package:cake_wallet/view_model/trade_details_view_model.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
@ -9,7 +9,7 @@ import 'package:flutter/services.dart';
|
|||
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||
import 'package:cake_wallet/generated/i18n.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/trade_details_list_card.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) {
|
||||
return GestureDetector(
|
||||
onTap: item.onTap,
|
||||
child: StandartListRow(
|
||||
child: ListRow(
|
||||
title: '${item.title}', value: '${item.value}'));
|
||||
}
|
||||
|
||||
if (item is DetailsListStatusItem) {
|
||||
return StandartListStatusRow(
|
||||
return StandardListStatusRow(
|
||||
title: item.title,
|
||||
value: item.value);
|
||||
}
|
||||
|
||||
if (item is TradeDetailsListCardItem) {
|
||||
return TradeDatailsStandartListCard(
|
||||
return TradeDetailsStandardListCard(
|
||||
id: item.id,
|
||||
create: item.createdAt,
|
||||
pair: item.pair,
|
||||
|
@ -86,7 +86,7 @@ class TradeDetailsPageBodyState extends State<TradeDetailsPageBody> {
|
|||
Clipboard.setData(ClipboardData(text: '${item.value}'));
|
||||
showBar<void>(context, S.of(context).copied_to_clipboard);
|
||||
},
|
||||
child: StandartListRow(
|
||||
child: ListRow(
|
||||
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/services.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/standart_list_item.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));
|
||||
},
|
||||
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(
|
||||
onTap: item.onTap,
|
||||
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_switch_item.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/base_page.dart';
|
||||
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||
|
@ -30,7 +30,7 @@ class UnspentCoinsDetailsPage extends BasePage {
|
|||
final item = unspentCoinsDetailsViewModel.items[index];
|
||||
|
||||
if (item is StandartListItem) {
|
||||
return StandartListRow(
|
||||
return ListRow(
|
||||
title: '${item.title}:',
|
||||
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';
|
||||
|
||||
class UnspentCoinsSwitchRow extends StatelessWidget {
|
||||
|
@ -33,7 +33,7 @@ class UnspentCoinsSwitchRow extends StatelessWidget {
|
|||
textAlign: TextAlign.left),
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: 12),
|
||||
child: StandartSwitch(
|
||||
child: StandardSwitch(
|
||||
value: switchValue,
|
||||
onTaped: () => onSwitchValueChange(!switchValue))
|
||||
)
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
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:flutter/material.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
|
@ -6,7 +7,7 @@ import 'package:flutter/services.dart';
|
|||
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||
import 'package:cake_wallet/generated/i18n.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';
|
||||
|
||||
class WalletKeysPage extends BasePage {
|
||||
|
@ -57,10 +58,7 @@ class WalletKeysPage extends BasePage {
|
|||
height: 1,
|
||||
padding: EdgeInsets.only(left: 24),
|
||||
color: Theme.of(context).accentTextTheme!.headline6!.backgroundColor!,
|
||||
child: Container(
|
||||
height: 1,
|
||||
color: Theme.of(context).dividerColor,
|
||||
),
|
||||
child: const SectionDivider(),
|
||||
),
|
||||
itemCount: walletKeysViewModel.items.length,
|
||||
itemBuilder: (BuildContext context, int index) {
|
||||
|
@ -71,7 +69,7 @@ class WalletKeysPage extends BasePage {
|
|||
Clipboard.setData(ClipboardData(text: item.value));
|
||||
showBar<void>(context, S.of(context).copied_key_to_clipboard(item.title));
|
||||
},
|
||||
child: StandartListRow(
|
||||
child: ListRow(
|
||||
title: item.title + ':',
|
||||
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 'package:cake_wallet/src/widgets/section_divider.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:cake_wallet/palette.dart';
|
||||
|
||||
|
@ -76,10 +77,7 @@ class BaseAlertDialog extends StatelessWidget {
|
|||
),
|
||||
)),
|
||||
),
|
||||
Container(
|
||||
width: 1,
|
||||
color: Theme.of(context).dividerColor,
|
||||
),
|
||||
const SectionDivider(),
|
||||
Expanded(
|
||||
child: TextButton(
|
||||
onPressed: actionRight,
|
||||
|
@ -140,10 +138,7 @@ class BaseAlertDialog extends StatelessWidget {
|
|||
isDividerExists
|
||||
? Padding(
|
||||
padding: EdgeInsets.only(top: 16, bottom: 8),
|
||||
child: Container(
|
||||
height: 1,
|
||||
color: Theme.of(context).dividerColor,
|
||||
),
|
||||
child: const SectionDivider(),
|
||||
)
|
||||
: Offstage(),
|
||||
Padding(
|
||||
|
@ -152,10 +147,7 @@ class BaseAlertDialog extends StatelessWidget {
|
|||
)
|
||||
],
|
||||
),
|
||||
Container(
|
||||
height: 1,
|
||||
color: Theme.of(context).dividerColor,
|
||||
),
|
||||
const SectionDivider(),
|
||||
actionButtons(context)
|
||||
],
|
||||
),
|
||||
|
|
|
@ -48,6 +48,8 @@ class CollapsibleSectionList extends SectionStandardList {
|
|||
child: ListTileTheme(
|
||||
contentPadding: EdgeInsets.only(right: 16,top:sectionIndex>0?26:0),
|
||||
child: ExpansionTile(
|
||||
textColor: themeColor,
|
||||
iconColor: themeColor,
|
||||
title: sectionTitleBuilder == null
|
||||
? Container()
|
||||
: Container(child: buildTitle(items, sectionIndex, context)),
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class StandartListRow extends StatelessWidget {
|
||||
StandartListRow(
|
||||
class ListRow extends StatelessWidget {
|
||||
ListRow(
|
||||
{required this.title,
|
||||
required this.value,
|
||||
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_close_button.dart';
|
||||
|
||||
class Picker<Item extends Object> extends StatefulWidget {
|
||||
class Picker<Item> extends StatefulWidget {
|
||||
Picker({
|
||||
required this.selectedAtIndex,
|
||||
required this.items,
|
||||
|
@ -40,7 +40,7 @@ class Picker<Item extends Object> extends StatefulWidget {
|
|||
_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);
|
||||
|
||||
final Function(Item) onItemSelected;
|
||||
|
@ -60,7 +60,7 @@ class _PickerState<Item> extends State<Picker> {
|
|||
images = [];
|
||||
for (int i=0;i<widget.items.length;i++) {
|
||||
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]);
|
||||
}
|
||||
}
|
||||
|
@ -237,8 +237,7 @@ class _PickerState<Item> extends State<Picker> {
|
|||
child: Padding(
|
||||
padding: EdgeInsets.only(left: image != null ? 12 : 0),
|
||||
child: Text(
|
||||
// What a hack (item as) ?
|
||||
widget.displayItem?.call(item as Object) ?? item.toString(),
|
||||
widget.displayItem?.call(item) ?? item.toString(),
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
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/material.dart';
|
||||
|
||||
class StandardCheckbox extends StatefulWidget {
|
||||
StandardCheckbox({
|
||||
Key? key,
|
||||
required this.value,
|
||||
this.caption = '',
|
||||
required this.onChanged})
|
||||
: super(key: key);
|
||||
class StandardCheckbox extends StatelessWidget {
|
||||
StandardCheckbox(
|
||||
{required this.value,
|
||||
this.caption = '',
|
||||
this.gradientBackground = false,
|
||||
this.borderColor,
|
||||
this.iconColor,
|
||||
required this.onChanged});
|
||||
|
||||
final bool value;
|
||||
final String caption;
|
||||
final bool gradientBackground;
|
||||
final Color? borderColor;
|
||||
final Color? iconColor;
|
||||
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
|
||||
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(
|
||||
onTap: () {
|
||||
value = !value;
|
||||
onChanged(value);
|
||||
setState(() {});
|
||||
},
|
||||
onTap: () => onChanged(!value),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
|
@ -45,38 +45,25 @@ class StandardCheckboxState extends State<StandardCheckbox> {
|
|||
Container(
|
||||
height: 24.0,
|
||||
width: 24.0,
|
||||
decoration: BoxDecoration(
|
||||
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),
|
||||
decoration: value ? checkedBoxDecoration : uncheckedBoxDecoration,
|
||||
child: value
|
||||
? Icon(
|
||||
Icons.check,
|
||||
color: Colors.blue,
|
||||
size: 20.0,
|
||||
)
|
||||
: Offstage(),
|
||||
? Icon(
|
||||
Icons.check,
|
||||
color: iconColor ?? Colors.blue,
|
||||
size: 20.0,
|
||||
)
|
||||
: Offstage(),
|
||||
),
|
||||
if (caption.isNotEmpty) Padding(
|
||||
padding: EdgeInsets.only(left: 10),
|
||||
child: Text(
|
||||
caption,
|
||||
style: TextStyle(
|
||||
fontSize: 16.0,
|
||||
color: Theme.of(context)
|
||||
.primaryTextTheme!
|
||||
.headline6!
|
||||
.color!),
|
||||
)
|
||||
)
|
||||
if (caption.isNotEmpty)
|
||||
Padding(
|
||||
padding: EdgeInsets.only(left: 10),
|
||||
child: Text(
|
||||
caption,
|
||||
style: TextStyle(
|
||||
fontSize: 16.0, color: Theme.of(context).primaryTextTheme!.headline6!.color!),
|
||||
))
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import 'package:cake_wallet/palette.dart';
|
||||
import 'package:cake_wallet/src/widgets/standart_list_card.dart';
|
||||
import 'package:cake_wallet/src/widgets/standart_list_status_row.dart';
|
||||
import 'package:cake_wallet/src/widgets/standard_list_card.dart';
|
||||
import 'package:cake_wallet/src/widgets/standard_list_status_row.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class StandardListRow extends StatelessWidget {
|
||||
|
@ -217,7 +217,7 @@ class SectionStandardList extends StatelessWidget {
|
|||
return Container();
|
||||
}
|
||||
|
||||
if (row is StandartListStatusRow || row is TradeDatailsStandartListCard) {
|
||||
if (row is StandardListStatusRow || row is TradeDetailsStandardListCard) {
|
||||
return Container();
|
||||
}
|
||||
|
||||
|
|
|
@ -2,8 +2,8 @@ import 'package:cake_wallet/palette.dart';
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:cake_wallet/themes/theme_base.dart';
|
||||
|
||||
class TradeDatailsStandartListCard extends StatelessWidget {
|
||||
TradeDatailsStandartListCard(
|
||||
class TradeDetailsStandardListCard extends StatelessWidget {
|
||||
TradeDetailsStandardListCard(
|
||||
{required this.id,
|
||||
required this.create,
|
||||
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/material.dart';
|
||||
|
||||
class StandartListStatusRow extends StatelessWidget {
|
||||
StandartListStatusRow({required this.title, required this.value});
|
||||
class StandardListStatusRow extends StatelessWidget {
|
||||
StandardListStatusRow({required this.title, required this.value});
|
||||
|
||||
final String title;
|
||||
final String value;
|
|
@ -1,17 +1,17 @@
|
|||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class StandartSwitch extends StatefulWidget {
|
||||
const StandartSwitch({required this.value, required this.onTaped});
|
||||
class StandardSwitch extends StatefulWidget {
|
||||
const StandardSwitch({required this.value, required this.onTaped});
|
||||
|
||||
final bool value;
|
||||
final VoidCallback onTaped;
|
||||
|
||||
@override
|
||||
StandartSwitchState createState() => StandartSwitchState();
|
||||
StandardSwitchState createState() => StandardSwitchState();
|
||||
}
|
||||
|
||||
class StandartSwitchState extends State<StandartSwitch> {
|
||||
class StandardSwitchState extends State<StandardSwitch> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return GestureDetector(
|
|
@ -8,12 +8,11 @@ part'trade_filter_store.g.dart';
|
|||
class TradeFilterStore = TradeFilterStoreBase with _$TradeFilterStore;
|
||||
|
||||
abstract class TradeFilterStoreBase with Store {
|
||||
TradeFilterStoreBase(
|
||||
{this.displayXMRTO = true,
|
||||
this.displayChangeNow = true,
|
||||
this.displayMorphToken = true,
|
||||
this.displaySimpleSwap = true,
|
||||
});
|
||||
TradeFilterStoreBase() : displayXMRTO = true,
|
||||
displayChangeNow = true,
|
||||
displaySideShift = true,
|
||||
displayMorphToken = true,
|
||||
displaySimpleSwap = true;
|
||||
|
||||
@observable
|
||||
bool displayXMRTO;
|
||||
|
@ -21,26 +20,50 @@ abstract class TradeFilterStoreBase with Store {
|
|||
@observable
|
||||
bool displayChangeNow;
|
||||
|
||||
@observable
|
||||
bool displaySideShift;
|
||||
|
||||
@observable
|
||||
bool displayMorphToken;
|
||||
|
||||
@observable
|
||||
bool displaySimpleSwap;
|
||||
|
||||
@computed
|
||||
bool get displayAllTrades => displayChangeNow && displaySideShift && displaySimpleSwap;
|
||||
|
||||
@action
|
||||
void toggleDisplayExchange(ExchangeProviderDescription provider) {
|
||||
switch (provider) {
|
||||
case ExchangeProviderDescription.changeNow:
|
||||
displayChangeNow = !displayChangeNow;
|
||||
break;
|
||||
case ExchangeProviderDescription.sideShift:
|
||||
displaySideShift = !displaySideShift;
|
||||
break;
|
||||
case ExchangeProviderDescription.simpleSwap:
|
||||
displaySimpleSwap = !displaySimpleSwap;
|
||||
break;
|
||||
case ExchangeProviderDescription.xmrto:
|
||||
displayXMRTO = !displayXMRTO;
|
||||
break;
|
||||
case ExchangeProviderDescription.morphToken:
|
||||
displayMorphToken = !displayMorphToken;
|
||||
break;
|
||||
case ExchangeProviderDescription.simpleSwap:
|
||||
displaySimpleSwap = !displaySimpleSwap;
|
||||
case ExchangeProviderDescription.all:
|
||||
if (displayAllTrades) {
|
||||
displayChangeNow = false;
|
||||
displaySideShift = false;
|
||||
displayXMRTO = false;
|
||||
displayMorphToken = false;
|
||||
displaySimpleSwap = false;
|
||||
} else {
|
||||
displayChangeNow = true;
|
||||
displaySideShift = true;
|
||||
displayXMRTO = true;
|
||||
displayMorphToken = true;
|
||||
displaySimpleSwap = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -48,13 +71,15 @@ abstract class TradeFilterStoreBase with Store {
|
|||
List<TradeListItem> filtered({required List<TradeListItem> trades, required WalletBase wallet}) {
|
||||
final _trades =
|
||||
trades.where((item) => item.trade.walletId == wallet.id).toList();
|
||||
final needToFilter = !displayChangeNow || !displayXMRTO || !displayMorphToken || !displaySimpleSwap;
|
||||
final needToFilter = !displayAllTrades;
|
||||
|
||||
return needToFilter
|
||||
? _trades
|
||||
.where((item) =>
|
||||
(displayXMRTO &&
|
||||
item.trade.provider == ExchangeProviderDescription.xmrto) ||
|
||||
(displaySideShift &&
|
||||
item.trade.provider == ExchangeProviderDescription.sideShift) ||
|
||||
(displayChangeNow &&
|
||||
item.trade.provider ==
|
||||
ExchangeProviderDescription.changeNow) ||
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
import 'package:mobx/mobx.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/filter_item.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
|
||||
part 'transaction_filter_store.g.dart';
|
||||
|
||||
|
@ -8,8 +10,8 @@ class TransactionFilterStore = TransactionFilterStoreBase
|
|||
with _$TransactionFilterStore;
|
||||
|
||||
abstract class TransactionFilterStoreBase with Store {
|
||||
TransactionFilterStoreBase(
|
||||
{this.displayIncoming = true, this.displayOutgoing = true});
|
||||
TransactionFilterStoreBase() : displayIncoming = true,
|
||||
displayOutgoing = true;
|
||||
|
||||
@observable
|
||||
bool displayIncoming;
|
||||
|
@ -23,11 +25,31 @@ abstract class TransactionFilterStoreBase with Store {
|
|||
@observable
|
||||
DateTime? endDate;
|
||||
|
||||
@action
|
||||
void toggleIncoming() => displayIncoming = !displayIncoming;
|
||||
@computed
|
||||
bool get displayAll => displayIncoming && displayOutgoing;
|
||||
|
||||
@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
|
||||
void changeStartDate(DateTime date) => startDate = date;
|
||||
|
@ -37,8 +59,7 @@ abstract class TransactionFilterStoreBase with Store {
|
|||
|
||||
List<TransactionListItem> filtered({required List<TransactionListItem> transactions}) {
|
||||
var _transactions = <TransactionListItem>[];
|
||||
final needToFilter = !displayOutgoing ||
|
||||
!displayIncoming ||
|
||||
final needToFilter = !displayAll ||
|
||||
(startDate != null && endDate != null);
|
||||
|
||||
if (needToFilter) {
|
||||
|
@ -50,7 +71,7 @@ abstract class TransactionFilterStoreBase with Store {
|
|||
&& (endDate?.isAfter(item.transaction.date) ?? false);
|
||||
}
|
||||
|
||||
if (allowed && (!displayOutgoing || !displayIncoming)) {
|
||||
if (allowed && (!displayAll)) {
|
||||
allowed = (displayOutgoing &&
|
||||
item.transaction.direction ==
|
||||
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,
|
||||
filterItems = {
|
||||
S.current.transactions: [
|
||||
FilterItem(
|
||||
value: () => transactionFilterStore.displayAll,
|
||||
caption: S.current.all_transactions,
|
||||
onChanged: transactionFilterStore.toggleAll),
|
||||
FilterItem(
|
||||
value: () => transactionFilterStore.displayIncoming,
|
||||
caption: S.current.incoming,
|
||||
onChanged: (value) => transactionFilterStore.toggleIncoming()),
|
||||
onChanged:transactionFilterStore.toggleIncoming),
|
||||
FilterItem(
|
||||
value: () => transactionFilterStore.displayOutgoing,
|
||||
caption: S.current.outgoing,
|
||||
onChanged: (value) => transactionFilterStore.toggleOutgoing()),
|
||||
onChanged: transactionFilterStore.toggleOutgoing),
|
||||
// FilterItem(
|
||||
// value: () => false,
|
||||
// caption: S.current.transactions_by_date,
|
||||
// onChanged: null),
|
||||
],
|
||||
S.current.trades: [
|
||||
FilterItem(
|
||||
value: () => tradeFilterStore.displayAllTrades,
|
||||
caption: S.current.all_trades,
|
||||
onChanged: () => tradeFilterStore
|
||||
.toggleDisplayExchange(ExchangeProviderDescription.all)),
|
||||
FilterItem(
|
||||
value: () => tradeFilterStore.displayChangeNow,
|
||||
caption: 'Change.NOW',
|
||||
onChanged: (value) => tradeFilterStore
|
||||
caption: ExchangeProviderDescription.changeNow.title,
|
||||
onChanged: () => tradeFilterStore
|
||||
.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 = '',
|
||||
|
@ -220,7 +239,7 @@ abstract class DashboardViewModelBase with Store {
|
|||
WalletBase<Balance, TransactionHistoryBase<TransactionInfo>, TransactionInfo>
|
||||
wallet;
|
||||
|
||||
bool get hasRescan => wallet.type == WalletType.monero;
|
||||
bool get hasRescan => wallet.type == WalletType.monero || wallet.type == WalletType.haven;
|
||||
|
||||
BalanceViewModel balanceViewModel;
|
||||
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
import 'package:mobx/mobx.dart';
|
||||
|
||||
class FilterItem {
|
||||
FilterItem({
|
||||
required this.value,
|
||||
|
@ -6,5 +8,5 @@ class FilterItem {
|
|||
|
||||
bool Function() value;
|
||||
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/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:cake_wallet/store/settings_store.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/wallet_type.dart';
|
||||
|
||||
|
||||
class TransactionListItem extends ActionListItem with Keyable {
|
||||
TransactionListItem(
|
||||
{required this.transaction,
|
||||
|
@ -35,6 +38,30 @@ class TransactionListItem extends ActionListItem with Keyable {
|
|||
? '---'
|
||||
: 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 {
|
||||
var amount = '';
|
||||
|
|
|
@ -18,19 +18,18 @@ import 'package:cake_wallet/generated/i18n.dart';
|
|||
|
||||
part 'exchange_trade_view_model.g.dart';
|
||||
|
||||
class ExchangeTradeViewModel = ExchangeTradeViewModelBase
|
||||
with _$ExchangeTradeViewModel;
|
||||
class ExchangeTradeViewModel = ExchangeTradeViewModelBase with _$ExchangeTradeViewModel;
|
||||
|
||||
abstract class ExchangeTradeViewModelBase with Store {
|
||||
ExchangeTradeViewModelBase(
|
||||
{required this.wallet,
|
||||
required this.trades,
|
||||
required this.tradesStore,
|
||||
required this.sendViewModel})
|
||||
: trade = tradesStore.trade!,
|
||||
isSendable = tradesStore.trade!.from == wallet.currency ||
|
||||
tradesStore.trade!.provider == ExchangeProviderDescription.xmrto,
|
||||
items = ObservableList<ExchangeTradeItem>() {
|
||||
required this.trades,
|
||||
required this.tradesStore,
|
||||
required this.sendViewModel})
|
||||
: trade = tradesStore.trade!,
|
||||
isSendable = tradesStore.trade!.from == wallet.currency ||
|
||||
tradesStore.trade!.provider == ExchangeProviderDescription.xmrto,
|
||||
items = ObservableList<ExchangeTradeItem>() {
|
||||
switch (trade.provider) {
|
||||
case ExchangeProviderDescription.xmrto:
|
||||
_provider = XMRTOExchangeProvider();
|
||||
|
@ -67,22 +66,20 @@ abstract class ExchangeTradeViewModelBase with Store {
|
|||
|
||||
@computed
|
||||
String get extraInfo => trade.from == CryptoCurrency.xlm
|
||||
? '\n\n' + S.current.xlm_extra_info
|
||||
: trade.from == CryptoCurrency.xrp
|
||||
? '\n\n' + S.current.xrp_extra_info
|
||||
: '';
|
||||
? '\n\n' + S.current.xlm_extra_info
|
||||
: trade.from == CryptoCurrency.xrp
|
||||
? '\n\n' + S.current.xrp_extra_info
|
||||
: '';
|
||||
|
||||
@computed
|
||||
String get pendingTransactionFiatAmountValueFormatted =>
|
||||
sendViewModel.isFiatDisabled
|
||||
? '' : sendViewModel.pendingTransactionFiatAmount
|
||||
+ ' ' + sendViewModel.fiat.title;
|
||||
String get pendingTransactionFiatAmountValueFormatted => sendViewModel.isFiatDisabled
|
||||
? ''
|
||||
: sendViewModel.pendingTransactionFiatAmount + ' ' + sendViewModel.fiat.title;
|
||||
|
||||
@computed
|
||||
String get pendingTransactionFeeFiatAmountFormatted =>
|
||||
sendViewModel.isFiatDisabled
|
||||
? '' : sendViewModel.pendingTransactionFeeFiatAmount
|
||||
+ ' ' + sendViewModel.fiat.title;
|
||||
String get pendingTransactionFeeFiatAmountFormatted => sendViewModel.isFiatDisabled
|
||||
? ''
|
||||
: sendViewModel.pendingTransactionFeeFiatAmount + ' ' + sendViewModel.fiat.title;
|
||||
|
||||
@observable
|
||||
ObservableList<ExchangeTradeItem> items;
|
||||
|
@ -122,6 +119,8 @@ abstract class ExchangeTradeViewModelBase with Store {
|
|||
}
|
||||
|
||||
void _updateItems() {
|
||||
final tagFrom = trade.from.tag != null ? '${trade.from.tag}' + ' ' : '';
|
||||
final tagTo = trade.to.tag != null ? '${trade.to.tag}' + ' ' : '';
|
||||
items.clear();
|
||||
items.add(ExchangeTradeItem(
|
||||
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
|
||||
? S.current.destination_tag
|
||||
: trade.from == CryptoCurrency.xlm
|
||||
? S.current.memo
|
||||
: S.current.extra_id;
|
||||
? S.current.memo
|
||||
: S.current.extra_id;
|
||||
|
||||
items.add(ExchangeTradeItem(
|
||||
title: title, data: '${trade.extraId}', isCopied: false));
|
||||
items.add(ExchangeTradeItem(title: title, data: '${trade.extraId}', isCopied: false));
|
||||
}
|
||||
|
||||
items.addAll([
|
||||
ExchangeTradeItem(title: S.current.amount, data: '${trade.amount}', isCopied: false),
|
||||
ExchangeTradeItem(
|
||||
title: S.current.amount, data: '${trade.amount}', isCopied: false),
|
||||
ExchangeTradeItem(
|
||||
title: S.current.status, data: '${trade.state}', isCopied: false),
|
||||
ExchangeTradeItem(
|
||||
title: S.current.widgets_address + ':',
|
||||
title: S.current.send_to_this_address('${trade.from}', tagFrom) + ':',
|
||||
data: trade.inputAddress ?? '',
|
||||
isCopied: true),
|
||||
ExchangeTradeItem(
|
||||
title: S.current.arrive_in_this_address('${trade.to}', tagTo) + ':',
|
||||
data: trade.payoutAddress ?? '',
|
||||
isCopied: true),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -192,7 +192,7 @@ abstract class ExchangeViewModelBase with Store {
|
|||
ObservableList<ExchangeTemplate> get templates =>
|
||||
_exchangeTemplateStore.templates;
|
||||
|
||||
|
||||
|
||||
@computed
|
||||
TransactionPriority get transactionPriority {
|
||||
final priority = _settingsStore.priority[wallet.type];
|
||||
|
@ -308,10 +308,11 @@ abstract class ExchangeViewModelBase with Store {
|
|||
Future<void> _calculateBestRate() async {
|
||||
final amount = double.tryParse(isFixedRateMode ? receiveAmount : depositAmount) ?? 1;
|
||||
|
||||
final _providers = _tradeAvailableProviders
|
||||
.where((element) => !isFixedRateMode || element.supportsFixedRate).toList();
|
||||
|
||||
final result = await Future.wait<double>(
|
||||
_tradeAvailableProviders
|
||||
.where((element) => !isFixedRateMode || element.supportsFixedRate)
|
||||
.map((element) => element.fetchRate(
|
||||
_providers.map((element) => element.fetchRate(
|
||||
from: depositCurrency,
|
||||
to: receiveCurrency,
|
||||
amount: amount,
|
||||
|
@ -324,7 +325,12 @@ abstract class ExchangeViewModelBase with Store {
|
|||
for (int i=0;i<result.length;i++) {
|
||||
if (result[i] != 0) {
|
||||
/// 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) {
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import 'dart:async';
|
||||
import 'package:cake_wallet/anypay/any_pay_chain.dart';
|
||||
import 'package:mobx/mobx.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:cake_wallet/ionia/ionia_service.dart';
|
||||
|
@ -39,6 +40,8 @@ abstract class IoniaPaymentStatusViewModelBase with Store {
|
|||
|
||||
Timer? get timer => _timer;
|
||||
|
||||
bool get payingByBitcoin => paymentInfo.anyPayPayment.chain == AnyPayChain.btc;
|
||||
|
||||
Timer? _timer;
|
||||
|
||||
@action
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:hive/hive.dart';
|
||||
import 'package:mobx/mobx.dart';
|
||||
import 'package:cw_core/wallet_base.dart';
|
||||
|
@ -30,6 +31,10 @@ abstract class NodeListViewModelBase with Store {
|
|||
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 SettingsStore settingsStore;
|
||||
final WalletBase wallet;
|
||||
|
|
|
@ -180,7 +180,8 @@ abstract class SendViewModelBase with Store {
|
|||
|
||||
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;
|
||||
|
||||
|
|
|
@ -42,7 +42,7 @@ abstract class SupportViewModelBase with Store {
|
|||
title: 'Telegram',
|
||||
icon: 'assets/images/Telegram.png',
|
||||
linkTitle: '@cakewallet_bot',
|
||||
link: 'https:t.me/cakewallet_bot'),
|
||||
link: 'https://t.me/cakewallet_bot'),
|
||||
LinkListItem(
|
||||
title: 'Twitter',
|
||||
icon: 'assets/images/Twitter.png',
|
||||
|
@ -84,7 +84,7 @@ abstract class SupportViewModelBase with Store {
|
|||
// link: 'mailto:support@y.at')
|
||||
];
|
||||
|
||||
static const url = 'https://cakewallet.com/guide/';
|
||||
static const url = 'https://guides.cakewallet.com';
|
||||
|
||||
List<SettingsListItem> items;
|
||||
}
|
|
@ -142,17 +142,5 @@ abstract class TradeDetailsViewModelBase with Store {
|
|||
items.add(TrackTradeListItem(
|
||||
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:flutter/foundation.dart';
|
||||
import 'package:cw_core/wallet_base.dart';
|
||||
|
@ -27,10 +28,10 @@ class AddressEditOrCreateStateFailure extends AddressEditOrCreateState {
|
|||
|
||||
abstract class WalletAddressEditOrCreateViewModelBase with Store {
|
||||
WalletAddressEditOrCreateViewModelBase(
|
||||
{required WalletBase wallet, dynamic item})
|
||||
{required WalletBase wallet, WalletAddressListItem? item})
|
||||
: isEdit = item != null,
|
||||
state = AddressEditOrCreateStateInitial(),
|
||||
label = item?.name as String? ?? '',
|
||||
label = item?.name ?? '',
|
||||
_item = item,
|
||||
_wallet = wallet;
|
||||
|
||||
|
@ -42,7 +43,7 @@ abstract class WalletAddressEditOrCreateViewModelBase with Store {
|
|||
|
||||
bool isEdit;
|
||||
|
||||
final dynamic _item;
|
||||
final WalletAddressListItem? _item;
|
||||
final WalletBase _wallet;
|
||||
|
||||
Future<void> save() async {
|
||||
|
@ -98,27 +99,20 @@ abstract class WalletAddressEditOrCreateViewModelBase with Store {
|
|||
await wallet.walletAddresses.updateAddress(_item.address as String);
|
||||
await wallet.save();
|
||||
}*/
|
||||
|
||||
if (wallet.type == WalletType.monero) {
|
||||
await monero
|
||||
!.getSubaddressList(wallet)
|
||||
.setLabelSubaddress(
|
||||
wallet,
|
||||
accountIndex: monero!.getCurrentAccount(wallet).id,
|
||||
addressIndex: _item.id as int,
|
||||
label: label);
|
||||
await wallet.save();
|
||||
}
|
||||
|
||||
if (wallet.type == WalletType.haven) {
|
||||
await haven
|
||||
!.getSubaddressList(wallet)
|
||||
.setLabelSubaddress(
|
||||
wallet,
|
||||
accountIndex: haven!.getCurrentAccount(wallet).id,
|
||||
addressIndex: _item.id as int,
|
||||
label: label);
|
||||
await wallet.save();
|
||||
final index = _item?.id;
|
||||
if (index != null) {
|
||||
if (wallet.type == WalletType.monero) {
|
||||
await monero!.getSubaddressList(wallet).setLabelSubaddress(wallet,
|
||||
accountIndex: monero!.getCurrentAccount(wallet).id, addressIndex: index, label: label);
|
||||
await wallet.save();
|
||||
}
|
||||
if (wallet.type == WalletType.haven) {
|
||||
await haven!.getSubaddressList(wallet).setLabelSubaddress(wallet,
|
||||
accountIndex: haven!.getCurrentAccount(wallet).id,
|
||||
addressIndex: index,
|
||||
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