mirror of
https://github.com/cake-tech/cake_wallet.git
synced 2025-03-12 09:32:33 +00:00
Merge branch 'breez' of https://github.com/cake-tech/cake_wallet into wownero_breez
Conflicts: configure_cake_wallet.sh cw_core/lib/amount_converter.dart cw_core/lib/wallet_type.dart cw_monero/lib/monero_wallet.dart lib/view_model/unspent_coins/unspent_coins_list_view_model.dart scripts/android/pubspec_gen.sh scripts/ios/app_config.sh scripts/macos/app_config.sh tool/configure.dart
This commit is contained in:
commit
90508b8726
133 changed files with 4714 additions and 459 deletions
3
.github/workflows/pr_test_build.yml
vendored
3
.github/workflows/pr_test_build.yml
vendored
|
@ -158,6 +158,9 @@ jobs:
|
||||||
echo "const walletConnectProjectId = '${{ secrets.WALLET_CONNECT_PROJECT_ID }}';" >> lib/.secrets.g.dart
|
echo "const walletConnectProjectId = '${{ secrets.WALLET_CONNECT_PROJECT_ID }}';" >> lib/.secrets.g.dart
|
||||||
echo "const moralisApiKey = '${{ secrets.MORALIS_API_KEY }}';" >> lib/.secrets.g.dart
|
echo "const moralisApiKey = '${{ secrets.MORALIS_API_KEY }}';" >> lib/.secrets.g.dart
|
||||||
echo "const polygonScanApiKey = '${{ secrets.POLYGON_SCAN_API_KEY }}';" >> cw_evm/lib/.secrets.g.dart
|
echo "const polygonScanApiKey = '${{ secrets.POLYGON_SCAN_API_KEY }}';" >> cw_evm/lib/.secrets.g.dart
|
||||||
|
echo "const breezApiKey = '${{ secrets.BREEZ_API_KEY }}';" >> cw_lightning/lib/.secrets.g.dart
|
||||||
|
echo "const greenlightCert = '${{ secrets.GREENLIGHT_CERTIFICATE }}';" >> cw_lightning/lib/.secrets.g.dart
|
||||||
|
echo "const greenlightKey = '${{ secrets.GREENLIGHT_KEY }}';" >> cw_lightning/lib/.secrets.g.dart
|
||||||
echo "const ankrApiKey = '${{ secrets.ANKR_API_KEY }}';" >> cw_solana/lib/.secrets.g.dart
|
echo "const ankrApiKey = '${{ secrets.ANKR_API_KEY }}';" >> cw_solana/lib/.secrets.g.dart
|
||||||
echo "const testCakePayApiKey = '${{ secrets.TEST_CAKE_PAY_API_KEY }}';" >> lib/.secrets.g.dart
|
echo "const testCakePayApiKey = '${{ secrets.TEST_CAKE_PAY_API_KEY }}';" >> lib/.secrets.g.dart
|
||||||
echo "const cakePayApiKey = '${{ secrets.CAKE_PAY_API_KEY }}';" >> lib/.secrets.g.dart
|
echo "const cakePayApiKey = '${{ secrets.CAKE_PAY_API_KEY }}';" >> lib/.secrets.g.dart
|
||||||
|
|
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -128,6 +128,7 @@ cw_haven/android/.externalNativeBuild/
|
||||||
cw_haven/android/.cxx/
|
cw_haven/android/.cxx/
|
||||||
|
|
||||||
lib/bitcoin/bitcoin.dart
|
lib/bitcoin/bitcoin.dart
|
||||||
|
lib/lightning/lightning.dart
|
||||||
lib/monero/monero.dart
|
lib/monero/monero.dart
|
||||||
lib/haven/haven.dart
|
lib/haven/haven.dart
|
||||||
lib/ethereum/ethereum.dart
|
lib/ethereum/ethereum.dart
|
||||||
|
|
|
@ -23,6 +23,7 @@ if (flutterVersionName == null) {
|
||||||
|
|
||||||
apply plugin: 'com.android.application'
|
apply plugin: 'com.android.application'
|
||||||
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
|
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
|
||||||
|
apply plugin: 'kotlinx-serialization'
|
||||||
|
|
||||||
def keystoreProperties = new Properties()
|
def keystoreProperties = new Properties()
|
||||||
def keystorePropertiesFile = rootProject.file('key.properties')
|
def keystorePropertiesFile = rootProject.file('key.properties')
|
||||||
|
|
|
@ -9,6 +9,8 @@
|
||||||
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
||||||
<uses-permission android:name="android.permission.CAMERA" />
|
<uses-permission android:name="android.permission.CAMERA" />
|
||||||
<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS"/>
|
<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS"/>
|
||||||
|
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
|
||||||
|
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
||||||
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
|
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
|
||||||
|
|
||||||
<!--bibo01 : hardware option-->
|
<!--bibo01 : hardware option-->
|
||||||
|
@ -69,6 +71,9 @@
|
||||||
<data android:scheme="bitcoin" />
|
<data android:scheme="bitcoin" />
|
||||||
<data android:scheme="bitcoin-wallet" />
|
<data android:scheme="bitcoin-wallet" />
|
||||||
<data android:scheme="bitcoin_wallet" />
|
<data android:scheme="bitcoin_wallet" />
|
||||||
|
<data android:scheme="lightning" />
|
||||||
|
<data android:scheme="lightning-wallet" />
|
||||||
|
<data android:scheme="lightning_wallet" />
|
||||||
<data android:scheme="monero" />
|
<data android:scheme="monero" />
|
||||||
<data android:scheme="monero-wallet" />
|
<data android:scheme="monero-wallet" />
|
||||||
<data android:scheme="monero_wallet" />
|
<data android:scheme="monero_wallet" />
|
||||||
|
@ -115,6 +120,24 @@
|
||||||
android:name="android.support.FILE_PROVIDER_PATHS"
|
android:name="android.support.FILE_PROVIDER_PATHS"
|
||||||
android:resource="@xml/provider_paths" />
|
android:resource="@xml/provider_paths" />
|
||||||
</provider>
|
</provider>
|
||||||
|
|
||||||
|
<!-- service to handle messaging events -->
|
||||||
|
<!-- commented out until we decide what to do -->
|
||||||
|
<!-- <service
|
||||||
|
android:name=".NotificationFcmService"
|
||||||
|
android:exported="false">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="com.google.firebase.MESSAGING_EVENT" />
|
||||||
|
</intent-filter>
|
||||||
|
</service> -->
|
||||||
|
|
||||||
|
<!-- service to handle the foreground service -->
|
||||||
|
<service
|
||||||
|
android:name=".NotificationForegroundService"
|
||||||
|
android:foregroundServiceType="shortService"
|
||||||
|
android:exported="false"
|
||||||
|
android:stopWithTask="false">
|
||||||
|
</service>
|
||||||
</application>
|
</application>
|
||||||
|
|
||||||
<queries>
|
<queries>
|
||||||
|
|
|
@ -9,6 +9,7 @@ buildscript {
|
||||||
classpath 'com.android.tools.build:gradle:7.3.0'
|
classpath 'com.android.tools.build:gradle:7.3.0'
|
||||||
classpath 'com.google.gms:google-services:4.3.8'
|
classpath 'com.google.gms:google-services:4.3.8'
|
||||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||||
|
classpath "org.jetbrains.kotlin:kotlin-serialization:$kotlin_version"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
BIN
assets/images/lightning_logo.png
Normal file
BIN
assets/images/lightning_logo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 9.4 KiB |
10
assets/images/lightning_logo.svg
Normal file
10
assets/images/lightning_logo.svg
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
<?xml version="1.0" standalone="no"?>
|
||||||
|
<!-- Generator: Adobe Fireworks 10, Export SVG Extension by Aaron Beall (http://fireworks.abeall.com) . Version: 0.6.1 -->
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||||
|
<svg id="bitcoin_lightning_icon.fw-Page%201" viewBox="0 0 280 280" style="background-color:#ffffff00" version="1.1"
|
||||||
|
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve"
|
||||||
|
x="0px" y="0px" width="280px" height="280px"
|
||||||
|
>
|
||||||
|
<path id="Ellipse" d="M 7 140.5 C 7 66.769 66.769 7 140.5 7 C 214.231 7 274 66.769 274 140.5 C 274 214.231 214.231 274 140.5 274 C 66.769 274 7 214.231 7 140.5 Z" fill="#f7931a"/>
|
||||||
|
<path d="M 161.1943 51.5 C 153.2349 72.1607 145.2756 94.4107 135.7244 116.6607 C 135.7244 116.6607 135.7244 119.8393 138.9081 119.8393 L 204.1747 119.8393 C 204.1747 119.8393 204.1747 121.4286 205.7667 123.0179 L 110.2545 229.5 C 108.6626 227.9107 108.6626 226.3214 108.6626 224.7321 L 142.0919 153.2143 L 142.0919 146.8571 L 75.2333 146.8571 L 75.2333 140.5 L 156.4187 51.5 L 161.1943 51.5 Z" fill="#ffffff"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.1 KiB |
BIN
assets/images/warning.png
Normal file
BIN
assets/images/warning.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 28 KiB |
|
@ -31,5 +31,4 @@ source ./app_env.sh cakewallet
|
||||||
./app_config.sh
|
./app_config.sh
|
||||||
cd ../.. && flutter pub get
|
cd ../.. && flutter pub get
|
||||||
#flutter packages pub run tool/generate_localization.dart
|
#flutter packages pub run tool/generate_localization.dart
|
||||||
./model_generator.sh
|
./model_generator.sh
|
||||||
#cd macos && pod install
|
|
|
@ -3,12 +3,13 @@ import 'package:cw_core/crypto_amount_format.dart';
|
||||||
|
|
||||||
const bitcoinAmountLength = 8;
|
const bitcoinAmountLength = 8;
|
||||||
const bitcoinAmountDivider = 100000000;
|
const bitcoinAmountDivider = 100000000;
|
||||||
|
const lightningAmountDivider = 1;
|
||||||
final bitcoinAmountFormat = NumberFormat()
|
final bitcoinAmountFormat = NumberFormat()
|
||||||
..maximumFractionDigits = bitcoinAmountLength
|
..maximumFractionDigits = bitcoinAmountLength
|
||||||
..minimumFractionDigits = 1;
|
..minimumFractionDigits = 1;
|
||||||
|
|
||||||
String bitcoinAmountToString({required int amount}) => bitcoinAmountFormat.format(
|
String bitcoinAmountToString({required int amount}) =>
|
||||||
cryptoAmountToDouble(amount: amount, divider: bitcoinAmountDivider));
|
bitcoinAmountFormat.format(cryptoAmountToDouble(amount: amount, divider: bitcoinAmountDivider));
|
||||||
|
|
||||||
double bitcoinAmountToDouble({required int amount}) =>
|
double bitcoinAmountToDouble({required int amount}) =>
|
||||||
cryptoAmountToDouble(amount: amount, divider: bitcoinAmountDivider);
|
cryptoAmountToDouble(amount: amount, divider: bitcoinAmountDivider);
|
||||||
|
@ -24,3 +25,9 @@ int stringDoubleToBitcoinAmount(String amount) {
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String bitcoinAmountToLightningString({required int amount}) {
|
||||||
|
String formattedAmount = bitcoinAmountFormat
|
||||||
|
.format(cryptoAmountToDouble(amount: amount, divider: lightningAmountDivider));
|
||||||
|
return formattedAmount.substring(0, formattedAmount.length - 2);
|
||||||
|
}
|
||||||
|
|
|
@ -73,6 +73,7 @@ abstract class ElectrumWalletBase
|
||||||
getAccountHDWallet(currency, networkType, seedBytes, xpub, walletInfo.derivationInfo),
|
getAccountHDWallet(currency, networkType, seedBytes, xpub, walletInfo.derivationInfo),
|
||||||
syncStatus = NotConnectedSyncStatus(),
|
syncStatus = NotConnectedSyncStatus(),
|
||||||
_password = password,
|
_password = password,
|
||||||
|
_mnemonic = mnemonic,
|
||||||
_feeRates = <int>[],
|
_feeRates = <int>[],
|
||||||
_isTransactionUpdating = false,
|
_isTransactionUpdating = false,
|
||||||
isEnabledAutoGenerateSubaddress = true,
|
isEnabledAutoGenerateSubaddress = true,
|
||||||
|
@ -91,7 +92,6 @@ abstract class ElectrumWalletBase
|
||||||
this.unspentCoinsInfo = unspentCoinsInfo,
|
this.unspentCoinsInfo = unspentCoinsInfo,
|
||||||
this.network = _getNetwork(networkType, currency),
|
this.network = _getNetwork(networkType, currency),
|
||||||
this.isTestnet = networkType == bitcoin.testnet,
|
this.isTestnet = networkType == bitcoin.testnet,
|
||||||
this._mnemonic = mnemonic,
|
|
||||||
super(walletInfo) {
|
super(walletInfo) {
|
||||||
this.electrumClient = electrumClient ?? ElectrumClient();
|
this.electrumClient = electrumClient ?? ElectrumClient();
|
||||||
this.walletInfo = walletInfo;
|
this.walletInfo = walletInfo;
|
||||||
|
@ -1138,7 +1138,7 @@ abstract class ElectrumWalletBase
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<void> close() async {
|
Future<void> close({bool? switchingToSameWalletType}) async {
|
||||||
try {
|
try {
|
||||||
await electrumClient.close();
|
await electrumClient.close();
|
||||||
} catch (_) {}
|
} catch (_) {}
|
||||||
|
|
|
@ -33,15 +33,16 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store {
|
||||||
Map<String, int>? initialRegularAddressIndex,
|
Map<String, int>? initialRegularAddressIndex,
|
||||||
Map<String, int>? initialChangeAddressIndex,
|
Map<String, int>? initialChangeAddressIndex,
|
||||||
}) : super(
|
}) : super(
|
||||||
mnemonic: mnemonic,
|
mnemonic: mnemonic,
|
||||||
password: password,
|
password: password,
|
||||||
walletInfo: walletInfo,
|
walletInfo: walletInfo,
|
||||||
unspentCoinsInfo: unspentCoinsInfo,
|
unspentCoinsInfo: unspentCoinsInfo,
|
||||||
networkType: litecoinNetwork,
|
networkType: litecoinNetwork,
|
||||||
initialAddresses: initialAddresses,
|
initialAddresses: initialAddresses,
|
||||||
initialBalance: initialBalance,
|
initialBalance: initialBalance,
|
||||||
seedBytes: seedBytes,
|
seedBytes: seedBytes,
|
||||||
currency: CryptoCurrency.ltc) {
|
currency: CryptoCurrency.ltc,
|
||||||
|
) {
|
||||||
walletAddresses = LitecoinWalletAddresses(
|
walletAddresses = LitecoinWalletAddresses(
|
||||||
walletInfo,
|
walletInfo,
|
||||||
initialAddresses: initialAddresses,
|
initialAddresses: initialAddresses,
|
||||||
|
|
|
@ -27,7 +27,7 @@ dependencies:
|
||||||
git:
|
git:
|
||||||
url: https://github.com/cake-tech/bitbox-flutter.git
|
url: https://github.com/cake-tech/bitbox-flutter.git
|
||||||
ref: Add-Support-For-OP-Return-data
|
ref: Add-Support-For-OP-Return-data
|
||||||
rxdart: ^0.27.5
|
rxdart: ^0.28.0
|
||||||
cryptography: ^2.0.5
|
cryptography: ^2.0.5
|
||||||
bitcoin_base:
|
bitcoin_base:
|
||||||
git:
|
git:
|
||||||
|
@ -53,7 +53,7 @@ dev_dependencies:
|
||||||
build_runner: ^2.4.7
|
build_runner: ^2.4.7
|
||||||
build_resolvers: ^2.0.9
|
build_resolvers: ^2.0.9
|
||||||
mobx_codegen: ^2.0.7
|
mobx_codegen: ^2.0.7
|
||||||
hive_generator: ^1.1.3
|
hive_generator: ^2.0.1
|
||||||
|
|
||||||
dependency_overrides:
|
dependency_overrides:
|
||||||
watcher: ^1.1.0
|
watcher: ^1.1.0
|
||||||
|
|
|
@ -35,15 +35,16 @@ abstract class BitcoinCashWalletBase extends ElectrumWallet with Store {
|
||||||
Map<String, int>? initialRegularAddressIndex,
|
Map<String, int>? initialRegularAddressIndex,
|
||||||
Map<String, int>? initialChangeAddressIndex,
|
Map<String, int>? initialChangeAddressIndex,
|
||||||
}) : super(
|
}) : super(
|
||||||
mnemonic: mnemonic,
|
mnemonic: mnemonic,
|
||||||
password: password,
|
password: password,
|
||||||
walletInfo: walletInfo,
|
walletInfo: walletInfo,
|
||||||
unspentCoinsInfo: unspentCoinsInfo,
|
unspentCoinsInfo: unspentCoinsInfo,
|
||||||
networkType: bitcoin.bitcoin,
|
networkType: bitcoin.bitcoin,
|
||||||
initialAddresses: initialAddresses,
|
initialAddresses: initialAddresses,
|
||||||
initialBalance: initialBalance,
|
initialBalance: initialBalance,
|
||||||
seedBytes: seedBytes,
|
seedBytes: seedBytes,
|
||||||
currency: CryptoCurrency.bch) {
|
currency: CryptoCurrency.bch,
|
||||||
|
) {
|
||||||
walletAddresses = BitcoinCashWalletAddresses(
|
walletAddresses = BitcoinCashWalletAddresses(
|
||||||
walletInfo,
|
walletInfo,
|
||||||
initialAddresses: initialAddresses,
|
initialAddresses: initialAddresses,
|
||||||
|
|
|
@ -43,7 +43,7 @@ dev_dependencies:
|
||||||
sdk: flutter
|
sdk: flutter
|
||||||
build_runner: ^2.4.7
|
build_runner: ^2.4.7
|
||||||
mobx_codegen: ^2.0.7
|
mobx_codegen: ^2.0.7
|
||||||
hive_generator: ^1.1.3
|
hive_generator: ^2.0.1
|
||||||
|
|
||||||
dependency_overrides:
|
dependency_overrides:
|
||||||
watcher: ^1.1.0
|
watcher: ^1.1.0
|
||||||
|
|
|
@ -6,6 +6,7 @@ class AmountConverter {
|
||||||
static const _moneroAmountDivider = 1000000000000;
|
static const _moneroAmountDivider = 1000000000000;
|
||||||
static const _wowneroAmountLength = 11;
|
static const _wowneroAmountLength = 11;
|
||||||
static const _wowneroAmountDivider = 100000000000;
|
static const _wowneroAmountDivider = 100000000000;
|
||||||
|
static const _ethereumAmountDivider = 1000000000000000000;
|
||||||
static const _bitcoinAmountDivider = 100000000;
|
static const _bitcoinAmountDivider = 100000000;
|
||||||
static const _bitcoinAmountLength = 8;
|
static const _bitcoinAmountLength = 8;
|
||||||
static final _bitcoinAmountFormat = NumberFormat()
|
static final _bitcoinAmountFormat = NumberFormat()
|
||||||
|
@ -18,6 +19,30 @@ class AmountConverter {
|
||||||
..maximumFractionDigits = _wowneroAmountLength
|
..maximumFractionDigits = _wowneroAmountLength
|
||||||
..minimumFractionDigits = 1;
|
..minimumFractionDigits = 1;
|
||||||
|
|
||||||
|
static int amountStringToInt(CryptoCurrency cryptoCurrency, String amount) {
|
||||||
|
switch (cryptoCurrency) {
|
||||||
|
case CryptoCurrency.xmr:
|
||||||
|
return _moneroParseAmount(amount);
|
||||||
|
case CryptoCurrency.xhv:
|
||||||
|
case CryptoCurrency.xag:
|
||||||
|
case CryptoCurrency.xau:
|
||||||
|
case CryptoCurrency.xaud:
|
||||||
|
case CryptoCurrency.xbtc:
|
||||||
|
case CryptoCurrency.xcad:
|
||||||
|
case CryptoCurrency.xchf:
|
||||||
|
case CryptoCurrency.xcny:
|
||||||
|
case CryptoCurrency.xeur:
|
||||||
|
case CryptoCurrency.xgbp:
|
||||||
|
case CryptoCurrency.xjpy:
|
||||||
|
case CryptoCurrency.xnok:
|
||||||
|
case CryptoCurrency.xnzd:
|
||||||
|
case CryptoCurrency.xusd:
|
||||||
|
return _moneroParseAmount(amount);
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static String amountIntToString(CryptoCurrency cryptoCurrency, int amount) {
|
static String amountIntToString(CryptoCurrency cryptoCurrency, int amount) {
|
||||||
switch (cryptoCurrency) {
|
switch (cryptoCurrency) {
|
||||||
case CryptoCurrency.xmr:
|
case CryptoCurrency.xmr:
|
||||||
|
@ -28,6 +53,8 @@ class AmountConverter {
|
||||||
case CryptoCurrency.bch:
|
case CryptoCurrency.bch:
|
||||||
case CryptoCurrency.ltc:
|
case CryptoCurrency.ltc:
|
||||||
return _bitcoinAmountToString(amount);
|
return _bitcoinAmountToString(amount);
|
||||||
|
case CryptoCurrency.btcln:
|
||||||
|
return _lightningAmountToString(amount);
|
||||||
case CryptoCurrency.xhv:
|
case CryptoCurrency.xhv:
|
||||||
case CryptoCurrency.xag:
|
case CryptoCurrency.xag:
|
||||||
case CryptoCurrency.xau:
|
case CryptoCurrency.xau:
|
||||||
|
@ -57,6 +84,11 @@ class AmountConverter {
|
||||||
static String _bitcoinAmountToString(int amount) => _bitcoinAmountFormat
|
static String _bitcoinAmountToString(int amount) => _bitcoinAmountFormat
|
||||||
.format(cryptoAmountToDouble(amount: amount, divider: _bitcoinAmountDivider));
|
.format(cryptoAmountToDouble(amount: amount, divider: _bitcoinAmountDivider));
|
||||||
|
|
||||||
|
static String _lightningAmountToString(int amount) {
|
||||||
|
String formattedAmount = _bitcoinAmountFormat.format(amount);
|
||||||
|
return formattedAmount.substring(0, formattedAmount.length - 2);
|
||||||
|
}
|
||||||
|
|
||||||
static String _wowneroAmountToString(int amount) => _wowneroAmountFormat
|
static String _wowneroAmountToString(int amount) => _wowneroAmountFormat
|
||||||
.format(cryptoAmountToDouble(amount: amount, divider: _wowneroAmountDivider));
|
.format(cryptoAmountToDouble(amount: amount, divider: _wowneroAmountDivider));
|
||||||
}
|
}
|
||||||
|
|
|
@ -103,6 +103,7 @@ class CryptoCurrency extends EnumerableItem<int> with Serializable<int> implemen
|
||||||
CryptoCurrency.kaspa,
|
CryptoCurrency.kaspa,
|
||||||
CryptoCurrency.digibyte,
|
CryptoCurrency.digibyte,
|
||||||
CryptoCurrency.usdtSol,
|
CryptoCurrency.usdtSol,
|
||||||
|
CryptoCurrency.btcln,
|
||||||
CryptoCurrency.usdcTrc20,
|
CryptoCurrency.usdcTrc20,
|
||||||
CryptoCurrency.tbtc,
|
CryptoCurrency.tbtc,
|
||||||
CryptoCurrency.wow,
|
CryptoCurrency.wow,
|
||||||
|
@ -190,7 +191,7 @@ class CryptoCurrency extends EnumerableItem<int> with Serializable<int> implemen
|
||||||
static const scrt = CryptoCurrency(title: 'SCRT', fullName: 'Secret Network', raw: 59, name: 'scrt', iconPath: 'assets/images/scrt_icon.png', decimals: 6);
|
static const scrt = CryptoCurrency(title: 'SCRT', fullName: 'Secret Network', raw: 59, name: 'scrt', iconPath: 'assets/images/scrt_icon.png', decimals: 6);
|
||||||
static const uni = CryptoCurrency(title: 'UNI', tag: 'ETH', fullName: 'Uniswap', raw: 60, name: 'uni', iconPath: 'assets/images/uni_icon.png', decimals: 18);
|
static const uni = CryptoCurrency(title: 'UNI', tag: 'ETH', fullName: 'Uniswap', raw: 60, name: 'uni', iconPath: 'assets/images/uni_icon.png', decimals: 18);
|
||||||
static const stx = CryptoCurrency(title: 'STX', fullName: 'Stacks', raw: 61, name: 'stx', iconPath: 'assets/images/stx_icon.png', decimals: 8);
|
static const stx = CryptoCurrency(title: 'STX', fullName: 'Stacks', raw: 61, name: 'stx', iconPath: 'assets/images/stx_icon.png', decimals: 8);
|
||||||
static const btcln = CryptoCurrency(title: 'BTC', tag: 'LN', fullName: 'Bitcoin Lightning Network', raw: 62, name: 'btcln', iconPath: 'assets/images/btc.png', decimals: 8);
|
static const btcln = CryptoCurrency(title: 'sats', tag: 'LN', fullName: 'Bitcoin Lightning Network', raw: 62, name: 'sats', iconPath: 'assets/images/lightning_logo.png', decimals: 8);
|
||||||
static const shib = CryptoCurrency(title: 'SHIB', tag: 'ETH', fullName: 'Shiba Inu', raw: 63, name: 'shib', iconPath: 'assets/images/shib_icon.png', decimals: 18);
|
static const shib = CryptoCurrency(title: 'SHIB', tag: 'ETH', fullName: 'Shiba Inu', raw: 63, name: 'shib', iconPath: 'assets/images/shib_icon.png', decimals: 18);
|
||||||
static const aave = CryptoCurrency(title: 'AAVE', tag: 'ETH', fullName: 'Aave', raw: 64, name: 'aave', iconPath: 'assets/images/aave_icon.png', decimals: 18);
|
static const aave = CryptoCurrency(title: 'AAVE', tag: 'ETH', fullName: 'Aave', raw: 64, name: 'aave', iconPath: 'assets/images/aave_icon.png', decimals: 18);
|
||||||
static const arb = CryptoCurrency(title: 'ARB', fullName: 'Arbitrum', raw: 65, name: 'arb', iconPath: 'assets/images/arb_icon.png', decimals: 18);
|
static const arb = CryptoCurrency(title: 'ARB', fullName: 'Arbitrum', raw: 65, name: 'arb', iconPath: 'assets/images/arb_icon.png', decimals: 18);
|
||||||
|
@ -224,7 +225,6 @@ class CryptoCurrency extends EnumerableItem<int> with Serializable<int> implemen
|
||||||
static const tbtc = CryptoCurrency(title: 'tBTC', fullName: 'Testnet Bitcoin', raw: 93, name: 'tbtc', iconPath: 'assets/images/tbtc.png', decimals: 8);
|
static const tbtc = CryptoCurrency(title: 'tBTC', fullName: 'Testnet Bitcoin', raw: 93, name: 'tbtc', iconPath: 'assets/images/tbtc.png', decimals: 8);
|
||||||
static const wow = CryptoCurrency(title: 'WOW', fullName: 'Wownero', raw: 94, name: 'wow', iconPath: 'assets/images/wownero_icon.png', decimals: 11);
|
static const wow = CryptoCurrency(title: 'WOW', fullName: 'Wownero', raw: 94, name: 'wow', iconPath: 'assets/images/wownero_icon.png', decimals: 11);
|
||||||
|
|
||||||
|
|
||||||
static final Map<int, CryptoCurrency> _rawCurrencyMap =
|
static final Map<int, CryptoCurrency> _rawCurrencyMap =
|
||||||
[...all, ...havenCurrencies].fold<Map<int, CryptoCurrency>>(<int, CryptoCurrency>{}, (acc, item) {
|
[...all, ...havenCurrencies].fold<Map<int, CryptoCurrency>>(<int, CryptoCurrency>{}, (acc, item) {
|
||||||
acc.addAll({item.raw: item});
|
acc.addAll({item.raw: item});
|
||||||
|
|
|
@ -8,6 +8,8 @@ CryptoCurrency currencyForWalletType(WalletType type, {bool? isTestnet}) {
|
||||||
return CryptoCurrency.tbtc;
|
return CryptoCurrency.tbtc;
|
||||||
}
|
}
|
||||||
return CryptoCurrency.btc;
|
return CryptoCurrency.btc;
|
||||||
|
case WalletType.lightning:
|
||||||
|
return CryptoCurrency.btcln;
|
||||||
case WalletType.monero:
|
case WalletType.monero:
|
||||||
return CryptoCurrency.xmr;
|
return CryptoCurrency.xmr;
|
||||||
case WalletType.litecoin:
|
case WalletType.litecoin:
|
||||||
|
|
|
@ -80,7 +80,7 @@ abstract class WalletBase<BalanceType extends Balance, HistoryType extends Trans
|
||||||
|
|
||||||
Future<void> rescan({required int height});
|
Future<void> rescan({required int height});
|
||||||
|
|
||||||
void close();
|
void close({bool? switchingToSameWalletType});
|
||||||
|
|
||||||
Future<void> changePassword(String password);
|
Future<void> changePassword(String password);
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@ part 'wallet_type.g.dart';
|
||||||
const walletTypes = [
|
const walletTypes = [
|
||||||
WalletType.monero,
|
WalletType.monero,
|
||||||
WalletType.bitcoin,
|
WalletType.bitcoin,
|
||||||
|
WalletType.lightning,
|
||||||
WalletType.litecoin,
|
WalletType.litecoin,
|
||||||
WalletType.haven,
|
WalletType.haven,
|
||||||
WalletType.ethereum,
|
WalletType.ethereum,
|
||||||
|
@ -16,6 +17,7 @@ const walletTypes = [
|
||||||
WalletType.polygon,
|
WalletType.polygon,
|
||||||
WalletType.solana,
|
WalletType.solana,
|
||||||
WalletType.tron,
|
WalletType.tron,
|
||||||
|
WalletType.wownero,
|
||||||
];
|
];
|
||||||
|
|
||||||
@HiveType(typeId: WALLET_TYPE_TYPE_ID)
|
@HiveType(typeId: WALLET_TYPE_TYPE_ID)
|
||||||
|
@ -58,6 +60,9 @@ enum WalletType {
|
||||||
|
|
||||||
@HiveField(12)
|
@HiveField(12)
|
||||||
wownero,
|
wownero,
|
||||||
|
|
||||||
|
@HiveField(13)
|
||||||
|
lightning,
|
||||||
}
|
}
|
||||||
|
|
||||||
int serializeToInt(WalletType type) {
|
int serializeToInt(WalletType type) {
|
||||||
|
@ -86,6 +91,8 @@ int serializeToInt(WalletType type) {
|
||||||
return 10;
|
return 10;
|
||||||
case WalletType.wownero:
|
case WalletType.wownero:
|
||||||
return 11;
|
return 11;
|
||||||
|
case WalletType.lightning:
|
||||||
|
return 12;
|
||||||
case WalletType.none:
|
case WalletType.none:
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -117,6 +124,8 @@ WalletType deserializeFromInt(int raw) {
|
||||||
return WalletType.tron;
|
return WalletType.tron;
|
||||||
case 11:
|
case 11:
|
||||||
return WalletType.wownero;
|
return WalletType.wownero;
|
||||||
|
case 12:
|
||||||
|
return WalletType.lightning;
|
||||||
default:
|
default:
|
||||||
throw Exception('Unexpected token: $raw for WalletType deserializeFromInt');
|
throw Exception('Unexpected token: $raw for WalletType deserializeFromInt');
|
||||||
}
|
}
|
||||||
|
@ -142,6 +151,8 @@ String walletTypeToString(WalletType type) {
|
||||||
return 'Banano';
|
return 'Banano';
|
||||||
case WalletType.polygon:
|
case WalletType.polygon:
|
||||||
return 'Polygon';
|
return 'Polygon';
|
||||||
|
case WalletType.lightning:
|
||||||
|
return 'Lightning';
|
||||||
case WalletType.solana:
|
case WalletType.solana:
|
||||||
return 'Solana';
|
return 'Solana';
|
||||||
case WalletType.tron:
|
case WalletType.tron:
|
||||||
|
@ -173,6 +184,8 @@ String walletTypeToDisplayName(WalletType type) {
|
||||||
return 'Banano (BAN)';
|
return 'Banano (BAN)';
|
||||||
case WalletType.polygon:
|
case WalletType.polygon:
|
||||||
return 'Polygon (MATIC)';
|
return 'Polygon (MATIC)';
|
||||||
|
case WalletType.lightning:
|
||||||
|
return 'Bitcoin (Lightning)';
|
||||||
case WalletType.solana:
|
case WalletType.solana:
|
||||||
return 'Solana (SOL)';
|
return 'Solana (SOL)';
|
||||||
case WalletType.tron:
|
case WalletType.tron:
|
||||||
|
@ -207,6 +220,8 @@ CryptoCurrency walletTypeToCryptoCurrency(WalletType type, {bool isTestnet = fal
|
||||||
return CryptoCurrency.banano;
|
return CryptoCurrency.banano;
|
||||||
case WalletType.polygon:
|
case WalletType.polygon:
|
||||||
return CryptoCurrency.maticpoly;
|
return CryptoCurrency.maticpoly;
|
||||||
|
case WalletType.lightning:
|
||||||
|
return CryptoCurrency.btcln;
|
||||||
case WalletType.solana:
|
case WalletType.solana:
|
||||||
return CryptoCurrency.sol;
|
return CryptoCurrency.sol;
|
||||||
case WalletType.tron:
|
case WalletType.tron:
|
||||||
|
|
|
@ -191,7 +191,7 @@ abstract class EVMChainWalletBase
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void close() {
|
void close({bool? switchingToSameWalletType}) {
|
||||||
_client.stop();
|
_client.stop();
|
||||||
_transactionsUpdateTimer?.cancel();
|
_transactionsUpdateTimer?.cancel();
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,7 +43,7 @@ dev_dependencies:
|
||||||
sdk: flutter
|
sdk: flutter
|
||||||
build_runner: ^2.4.7
|
build_runner: ^2.4.7
|
||||||
mobx_codegen: ^2.0.7
|
mobx_codegen: ^2.0.7
|
||||||
hive_generator: ^1.1.3
|
hive_generator: ^2.0.1
|
||||||
flutter_lints: ^2.0.0
|
flutter_lints: ^2.0.0
|
||||||
|
|
||||||
flutter:
|
flutter:
|
||||||
|
|
|
@ -106,7 +106,7 @@ abstract class HavenWalletBase
|
||||||
Future<void>? updateBalance() => null;
|
Future<void>? updateBalance() => null;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void close() {
|
void close({bool? switchingToSameWalletType}) {
|
||||||
_listener?.stop();
|
_listener?.stop();
|
||||||
_onAccountChangeReaction?.reaction.dispose();
|
_onAccountChangeReaction?.reaction.dispose();
|
||||||
_autoSaveTimer?.cancel();
|
_autoSaveTimer?.cancel();
|
||||||
|
|
|
@ -27,7 +27,7 @@ dev_dependencies:
|
||||||
build_runner: ^2.4.7
|
build_runner: ^2.4.7
|
||||||
mobx_codegen: ^2.0.7
|
mobx_codegen: ^2.0.7
|
||||||
build_resolvers: ^2.0.9
|
build_resolvers: ^2.0.9
|
||||||
hive_generator: ^1.1.3
|
hive_generator: ^2.0.1
|
||||||
|
|
||||||
dependency_overrides:
|
dependency_overrides:
|
||||||
watcher: ^1.1.0
|
watcher: ^1.1.0
|
||||||
|
|
74
cw_lightning/.gitignore
vendored
Normal file
74
cw_lightning/.gitignore
vendored
Normal file
|
@ -0,0 +1,74 @@
|
||||||
|
# Miscellaneous
|
||||||
|
*.class
|
||||||
|
*.log
|
||||||
|
*.pyc
|
||||||
|
*.swp
|
||||||
|
.DS_Store
|
||||||
|
.atom/
|
||||||
|
.buildlog/
|
||||||
|
.history
|
||||||
|
.svn/
|
||||||
|
|
||||||
|
# IntelliJ related
|
||||||
|
*.iml
|
||||||
|
*.ipr
|
||||||
|
*.iws
|
||||||
|
.idea/
|
||||||
|
|
||||||
|
# The .vscode folder contains launch configuration and tasks you configure in
|
||||||
|
# VS Code which you may wish to be included in version control, so this line
|
||||||
|
# is commented out by default.
|
||||||
|
#.vscode/
|
||||||
|
|
||||||
|
# Flutter/Dart/Pub related
|
||||||
|
**/doc/api/
|
||||||
|
.dart_tool/
|
||||||
|
.flutter-plugins
|
||||||
|
.flutter-plugins-dependencies
|
||||||
|
.packages
|
||||||
|
.pub-cache/
|
||||||
|
.pub/
|
||||||
|
build/
|
||||||
|
|
||||||
|
# Android related
|
||||||
|
**/android/**/gradle-wrapper.jar
|
||||||
|
**/android/.gradle
|
||||||
|
**/android/captures/
|
||||||
|
**/android/gradlew
|
||||||
|
**/android/gradlew.bat
|
||||||
|
**/android/local.properties
|
||||||
|
**/android/**/GeneratedPluginRegistrant.java
|
||||||
|
|
||||||
|
# iOS/XCode related
|
||||||
|
**/ios/**/*.mode1v3
|
||||||
|
**/ios/**/*.mode2v3
|
||||||
|
**/ios/**/*.moved-aside
|
||||||
|
**/ios/**/*.pbxuser
|
||||||
|
**/ios/**/*.perspectivev3
|
||||||
|
**/ios/**/*sync/
|
||||||
|
**/ios/**/.sconsign.dblite
|
||||||
|
**/ios/**/.tags*
|
||||||
|
**/ios/**/.vagrant/
|
||||||
|
**/ios/**/DerivedData/
|
||||||
|
**/ios/**/Icon?
|
||||||
|
**/ios/**/Pods/
|
||||||
|
**/ios/**/.symlinks/
|
||||||
|
**/ios/**/profile
|
||||||
|
**/ios/**/xcuserdata
|
||||||
|
**/ios/.generated/
|
||||||
|
**/ios/Flutter/App.framework
|
||||||
|
**/ios/Flutter/Flutter.framework
|
||||||
|
**/ios/Flutter/Flutter.podspec
|
||||||
|
**/ios/Flutter/Generated.xcconfig
|
||||||
|
**/ios/Flutter/app.flx
|
||||||
|
**/ios/Flutter/app.zip
|
||||||
|
**/ios/Flutter/flutter_assets/
|
||||||
|
**/ios/Flutter/flutter_export_environment.sh
|
||||||
|
**/ios/ServiceDefinitions.json
|
||||||
|
**/ios/Runner/GeneratedPluginRegistrant.*
|
||||||
|
|
||||||
|
# Exceptions to above rules.
|
||||||
|
!**/ios/**/default.mode1v3
|
||||||
|
!**/ios/**/default.mode2v3
|
||||||
|
!**/ios/**/default.pbxuser
|
||||||
|
!**/ios/**/default.perspectivev3
|
10
cw_lightning/.metadata
Normal file
10
cw_lightning/.metadata
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
# This file tracks properties of this Flutter project.
|
||||||
|
# Used by Flutter tool to assess capabilities and perform upgrades etc.
|
||||||
|
#
|
||||||
|
# This file should be version controlled and should not be manually edited.
|
||||||
|
|
||||||
|
version:
|
||||||
|
revision: b1395592de68cc8ac4522094ae59956dd21a91db
|
||||||
|
channel: stable
|
||||||
|
|
||||||
|
project_type: package
|
3
cw_lightning/CHANGELOG.md
Normal file
3
cw_lightning/CHANGELOG.md
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
## [0.0.1] - TODO: Add release date.
|
||||||
|
|
||||||
|
* TODO: Describe initial release.
|
1
cw_lightning/LICENSE
Normal file
1
cw_lightning/LICENSE
Normal file
|
@ -0,0 +1 @@
|
||||||
|
TODO: Add your license here.
|
14
cw_lightning/README.md
Normal file
14
cw_lightning/README.md
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
# cw_bitcoin
|
||||||
|
|
||||||
|
A new Flutter package project.
|
||||||
|
|
||||||
|
## Getting Started
|
||||||
|
|
||||||
|
This project is a starting point for a Dart
|
||||||
|
[package](https://flutter.dev/developing-packages/),
|
||||||
|
a library module containing code that can be shared easily across
|
||||||
|
multiple Flutter or Dart projects.
|
||||||
|
|
||||||
|
For help getting started with Flutter, view our
|
||||||
|
[online documentation](https://flutter.dev/docs), which offers tutorials,
|
||||||
|
samples, guidance on mobile development, and a full API reference.
|
7
cw_lightning/lib/cw_lightning.dart
Normal file
7
cw_lightning/lib/cw_lightning.dart
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
library cw_lightning;
|
||||||
|
|
||||||
|
/// A Calculator.
|
||||||
|
class Calculator {
|
||||||
|
/// Returns [value] plus 1.
|
||||||
|
int addOne(int value) => value + 1;
|
||||||
|
}
|
45
cw_lightning/lib/lightning_balance.dart
Normal file
45
cw_lightning/lib/lightning_balance.dart
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
import 'dart:convert';
|
||||||
|
import 'package:cw_bitcoin/bitcoin_amount_format.dart';
|
||||||
|
import 'package:cw_bitcoin/electrum_balance.dart';
|
||||||
|
import 'package:cw_core/balance.dart';
|
||||||
|
|
||||||
|
class LightningBalance extends ElectrumBalance {
|
||||||
|
LightningBalance({required this.confirmed, required this.unconfirmed, required this.frozen})
|
||||||
|
: super(
|
||||||
|
confirmed: confirmed,
|
||||||
|
unconfirmed: unconfirmed,
|
||||||
|
frozen: frozen,
|
||||||
|
);
|
||||||
|
|
||||||
|
static LightningBalance? fromJSON(String? jsonSource) {
|
||||||
|
if (jsonSource == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
final decoded = json.decode(jsonSource) as Map;
|
||||||
|
|
||||||
|
return LightningBalance(
|
||||||
|
confirmed: decoded['confirmed'] as int? ?? 0,
|
||||||
|
unconfirmed: decoded['unconfirmed'] as int? ?? 0,
|
||||||
|
frozen: decoded['frozen'] as int? ?? 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
final int confirmed;
|
||||||
|
final int unconfirmed;
|
||||||
|
final int frozen;
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get formattedAvailableBalance => bitcoinAmountToLightningString(amount: confirmed);
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get formattedAdditionalBalance => bitcoinAmountToLightningString(amount: unconfirmed);
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get formattedUnAvailableBalance {
|
||||||
|
final frozenFormatted = bitcoinAmountToLightningString(amount: frozen);
|
||||||
|
return frozenFormatted == '0.0' ? '' : frozenFormatted;
|
||||||
|
}
|
||||||
|
|
||||||
|
String toJSON() =>
|
||||||
|
json.encode({'confirmed': confirmed, 'unconfirmed': unconfirmed, 'frozen': frozen});
|
||||||
|
}
|
19
cw_lightning/lib/lightning_receive_page_option.dart
Normal file
19
cw_lightning/lib/lightning_receive_page_option.dart
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
import 'package:cw_core/receive_page_option.dart';
|
||||||
|
|
||||||
|
class LightningReceivePageOption implements ReceivePageOption {
|
||||||
|
static const lightningOnchain = LightningReceivePageOption._('lightningOnchain');
|
||||||
|
static const lightningInvoice = LightningReceivePageOption._('lightningInvoice');
|
||||||
|
|
||||||
|
const LightningReceivePageOption._(this.value);
|
||||||
|
|
||||||
|
final String value;
|
||||||
|
|
||||||
|
String toString() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const all = [
|
||||||
|
LightningReceivePageOption.lightningInvoice,
|
||||||
|
LightningReceivePageOption.lightningOnchain
|
||||||
|
];
|
||||||
|
}
|
57
cw_lightning/lib/lightning_transaction_info.dart
Normal file
57
cw_lightning/lib/lightning_transaction_info.dart
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
import 'package:cw_bitcoin/bitcoin_amount_format.dart';
|
||||||
|
import 'package:cw_bitcoin/electrum_transaction_info.dart';
|
||||||
|
import 'package:cw_core/transaction_direction.dart';
|
||||||
|
import 'package:cw_core/format_amount.dart';
|
||||||
|
import 'package:cw_core/wallet_type.dart';
|
||||||
|
|
||||||
|
class LightningTransactionInfo extends ElectrumTransactionInfo {
|
||||||
|
LightningTransactionInfo({
|
||||||
|
required String id,
|
||||||
|
required int amount,
|
||||||
|
int? fee,
|
||||||
|
required TransactionDirection direction,
|
||||||
|
required bool isPending,
|
||||||
|
required DateTime date,
|
||||||
|
}) : super(
|
||||||
|
WalletType.lightning,
|
||||||
|
amount: amount,
|
||||||
|
fee: fee,
|
||||||
|
direction: direction,
|
||||||
|
date: date,
|
||||||
|
isPending: isPending,
|
||||||
|
id: id,
|
||||||
|
confirmations: 0,
|
||||||
|
height: 0,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String amountFormatted() =>
|
||||||
|
'${formatAmount(bitcoinAmountToLightningString(amount: amount))} ${walletTypeToCryptoCurrency(type).title}';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String? feeFormatted() => fee != null
|
||||||
|
? '${formatAmount(bitcoinAmountToLightningString(amount: fee!))} ${walletTypeToCryptoCurrency(type).title}'
|
||||||
|
: '';
|
||||||
|
|
||||||
|
factory LightningTransactionInfo.fromJson(Map<String, dynamic> data, WalletType type) {
|
||||||
|
return LightningTransactionInfo(
|
||||||
|
id: data['id'] as String,
|
||||||
|
amount: data['amount'] as int,
|
||||||
|
fee: data['fee'] as int,
|
||||||
|
direction: parseTransactionDirectionFromInt(data['direction'] as int),
|
||||||
|
date: DateTime.fromMillisecondsSinceEpoch(data['date'] as int),
|
||||||
|
isPending: data['isPending'] as bool,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
final m = <String, dynamic>{};
|
||||||
|
m['id'] = id;
|
||||||
|
m['amount'] = amount;
|
||||||
|
m['direction'] = direction.index;
|
||||||
|
m['date'] = date.millisecondsSinceEpoch;
|
||||||
|
m['isPending'] = isPending;
|
||||||
|
m['fee'] = fee;
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
}
|
422
cw_lightning/lib/lightning_wallet.dart
Normal file
422
cw_lightning/lib/lightning_wallet.dart
Normal file
|
@ -0,0 +1,422 @@
|
||||||
|
import 'dart:async';
|
||||||
|
import 'dart:convert';
|
||||||
|
import 'dart:io';
|
||||||
|
|
||||||
|
import 'package:bitbox/bitbox.dart';
|
||||||
|
import 'package:bitcoin_base/bitcoin_base.dart';
|
||||||
|
import 'package:breez_sdk/breez_sdk.dart';
|
||||||
|
import 'package:breez_sdk/bridge_generated.dart';
|
||||||
|
import 'package:cw_bitcoin/bitcoin_mnemonic.dart';
|
||||||
|
import 'package:cw_bitcoin/electrum_wallet_snapshot.dart';
|
||||||
|
import 'package:cw_core/crypto_currency.dart';
|
||||||
|
import 'package:cw_core/node.dart';
|
||||||
|
import 'package:cw_core/pathForWallet.dart';
|
||||||
|
import 'package:cw_core/pending_transaction.dart';
|
||||||
|
import 'package:cw_core/sync_status.dart';
|
||||||
|
import 'package:cw_core/transaction_direction.dart';
|
||||||
|
import 'package:cw_core/unspent_coins_info.dart';
|
||||||
|
import 'package:cw_lightning/lightning_balance.dart';
|
||||||
|
import 'package:cw_lightning/lightning_transaction_info.dart';
|
||||||
|
import 'package:hive/hive.dart';
|
||||||
|
import 'package:mobx/mobx.dart';
|
||||||
|
import 'package:flutter/foundation.dart';
|
||||||
|
import 'package:bitcoin_flutter/bitcoin_flutter.dart' as bitcoin;
|
||||||
|
import 'package:cw_core/wallet_info.dart';
|
||||||
|
import 'package:cw_bitcoin/bitcoin_address_record.dart';
|
||||||
|
import 'package:cw_bitcoin/bitcoin_wallet_addresses.dart';
|
||||||
|
import 'package:path_provider/path_provider.dart';
|
||||||
|
import 'package:cw_lightning/.secrets.g.dart' as secrets;
|
||||||
|
import 'package:cw_bitcoin/electrum_wallet.dart';
|
||||||
|
import 'package:bip39/bip39.dart' as bip39;
|
||||||
|
|
||||||
|
part 'lightning_wallet.g.dart';
|
||||||
|
|
||||||
|
class LightningWallet = LightningWalletBase with _$LightningWallet;
|
||||||
|
|
||||||
|
abstract class LightningWalletBase extends ElectrumWallet with Store {
|
||||||
|
bool _isTransactionUpdating;
|
||||||
|
|
||||||
|
@override
|
||||||
|
@observable
|
||||||
|
SyncStatus syncStatus;
|
||||||
|
|
||||||
|
LightningWalletBase({
|
||||||
|
required String mnemonic,
|
||||||
|
required String password,
|
||||||
|
required WalletInfo walletInfo,
|
||||||
|
required Box<UnspentCoinsInfo> unspentCoinsInfo,
|
||||||
|
required Uint8List seedBytes,
|
||||||
|
String? addressPageType,
|
||||||
|
List<BitcoinAddressRecord>? initialAddresses,
|
||||||
|
LightningBalance? initialBalance,
|
||||||
|
Map<String, int>? initialRegularAddressIndex,
|
||||||
|
Map<String, int>? initialChangeAddressIndex,
|
||||||
|
}) : _isTransactionUpdating = false,
|
||||||
|
syncStatus = NotConnectedSyncStatus(),
|
||||||
|
_balance = ObservableMap<CryptoCurrency, LightningBalance>(),
|
||||||
|
mnemonic = mnemonic,
|
||||||
|
super(
|
||||||
|
password: password,
|
||||||
|
walletInfo: walletInfo,
|
||||||
|
unspentCoinsInfo: unspentCoinsInfo,
|
||||||
|
networkType: bitcoin.bitcoin,
|
||||||
|
initialAddresses: initialAddresses,
|
||||||
|
initialBalance: initialBalance,
|
||||||
|
seedBytes: seedBytes,
|
||||||
|
currency: CryptoCurrency.btcln,
|
||||||
|
) {
|
||||||
|
_balance[CryptoCurrency.btcln] =
|
||||||
|
initialBalance ?? LightningBalance(confirmed: 0, unconfirmed: 0, frozen: 0);
|
||||||
|
String derivationPath = walletInfo.derivationInfo!.derivationPath!;
|
||||||
|
String sideDerivationPath = derivationPath.substring(0, derivationPath.length - 1) + "1";
|
||||||
|
final hd = bitcoin.HDWallet.fromSeed(seedBytes, network: networkType);
|
||||||
|
walletAddresses = BitcoinWalletAddresses(
|
||||||
|
walletInfo,
|
||||||
|
initialAddresses: initialAddresses,
|
||||||
|
initialRegularAddressIndex: initialRegularAddressIndex,
|
||||||
|
initialChangeAddressIndex: initialChangeAddressIndex,
|
||||||
|
mainHd: hd.derivePath(derivationPath),
|
||||||
|
sideHd: hd.derivePath(sideDerivationPath),
|
||||||
|
network: network,
|
||||||
|
);
|
||||||
|
|
||||||
|
// initialize breez:
|
||||||
|
try {
|
||||||
|
setupBreez(seedBytes);
|
||||||
|
} catch (e) {
|
||||||
|
print("Error initializing Breez: $e");
|
||||||
|
}
|
||||||
|
|
||||||
|
autorun((_) {
|
||||||
|
this.walletAddresses.isEnabledAutoGenerateSubaddress = this.isEnabledAutoGenerateSubaddress;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
late final ObservableMap<CryptoCurrency, LightningBalance> _balance;
|
||||||
|
StreamSubscription<List<Payment>>? _paymentsSub;
|
||||||
|
StreamSubscription<NodeState?>? _nodeStateSub;
|
||||||
|
StreamSubscription<LogEntry>? _logStream;
|
||||||
|
|
||||||
|
@override
|
||||||
|
@computed
|
||||||
|
ObservableMap<CryptoCurrency, LightningBalance> get balance => _balance;
|
||||||
|
|
||||||
|
static Future<LightningWallet> create(
|
||||||
|
{required String mnemonic,
|
||||||
|
required String password,
|
||||||
|
required WalletInfo walletInfo,
|
||||||
|
required Box<UnspentCoinsInfo> unspentCoinsInfo,
|
||||||
|
String? addressPageType,
|
||||||
|
List<BitcoinAddressRecord>? initialAddresses,
|
||||||
|
LightningBalance? initialBalance,
|
||||||
|
Map<String, int>? initialRegularAddressIndex,
|
||||||
|
Map<String, int>? initialChangeAddressIndex}) async {
|
||||||
|
late final Uint8List seedBytes;
|
||||||
|
// electrum:
|
||||||
|
if (validateMnemonic(mnemonic)) {
|
||||||
|
seedBytes = await mnemonicToSeedBytes(mnemonic);
|
||||||
|
// bip39:
|
||||||
|
} else if (bip39.validateMnemonic(mnemonic)) {
|
||||||
|
seedBytes = await bip39.mnemonicToSeed(mnemonic);
|
||||||
|
} else {
|
||||||
|
throw Exception("Invalid mnemonic!");
|
||||||
|
}
|
||||||
|
return LightningWallet(
|
||||||
|
mnemonic: mnemonic,
|
||||||
|
password: password,
|
||||||
|
walletInfo: walletInfo,
|
||||||
|
unspentCoinsInfo: unspentCoinsInfo,
|
||||||
|
initialAddresses: initialAddresses,
|
||||||
|
initialBalance: initialBalance,
|
||||||
|
seedBytes: seedBytes,
|
||||||
|
initialRegularAddressIndex: initialRegularAddressIndex,
|
||||||
|
initialChangeAddressIndex: initialChangeAddressIndex,
|
||||||
|
addressPageType: addressPageType,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Future<LightningWallet> open({
|
||||||
|
required String name,
|
||||||
|
required WalletInfo walletInfo,
|
||||||
|
required Box<UnspentCoinsInfo> unspentCoinsInfo,
|
||||||
|
required String password,
|
||||||
|
}) async {
|
||||||
|
final snp =
|
||||||
|
await ElectrumWalletSnapshot.load(name, walletInfo.type, password, BitcoinNetwork.mainnet);
|
||||||
|
|
||||||
|
print("OPENING!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
|
||||||
|
return LightningWallet(
|
||||||
|
mnemonic: snp.mnemonic!,
|
||||||
|
password: password,
|
||||||
|
walletInfo: walletInfo,
|
||||||
|
unspentCoinsInfo: unspentCoinsInfo,
|
||||||
|
initialAddresses: snp.addresses,
|
||||||
|
initialBalance: LightningBalance(
|
||||||
|
confirmed: snp.balance.confirmed,
|
||||||
|
unconfirmed: snp.balance.unconfirmed,
|
||||||
|
frozen: snp.balance.frozen,
|
||||||
|
),
|
||||||
|
seedBytes: await Mnemonic.toSeed(snp.mnemonic!),
|
||||||
|
initialRegularAddressIndex: snp.regularAddressIndex,
|
||||||
|
initialChangeAddressIndex: snp.changeAddressIndex,
|
||||||
|
addressPageType: snp.addressPageType,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _handleNodeState(NodeState? nodeState) async {
|
||||||
|
if (nodeState == null) return;
|
||||||
|
_balance[CryptoCurrency.btcln] = LightningBalance(
|
||||||
|
confirmed: nodeState.maxPayableMsat ~/ 1000,
|
||||||
|
unconfirmed: nodeState.maxReceivableMsat ~/ 1000,
|
||||||
|
frozen: 0,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _handlePayments(List<Payment> payments) async {
|
||||||
|
_isTransactionUpdating = true;
|
||||||
|
final txs = convertToTxInfo(payments);
|
||||||
|
transactionHistory.addMany(txs);
|
||||||
|
_isTransactionUpdating = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> renameWalletFiles(String newWalletName) async {
|
||||||
|
await stopBreez(true);
|
||||||
|
await super.renameWalletFiles(newWalletName);
|
||||||
|
await setupBreez(await Mnemonic.toSeed(mnemonic));
|
||||||
|
}
|
||||||
|
|
||||||
|
void _logSdkEntries(LogEntry entry) {
|
||||||
|
switch (entry.level) {
|
||||||
|
case "ERROR":
|
||||||
|
case "WARN":
|
||||||
|
case "INFO":
|
||||||
|
// case "DEBUG":
|
||||||
|
// case "TRACE":
|
||||||
|
print("BREEZ:${entry.level}: ${entry.line}");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> setupBreez(Uint8List seedBytes) async {
|
||||||
|
final sdk = await BreezSDK();
|
||||||
|
_logStream?.cancel();
|
||||||
|
_logStream = sdk.logStream.listen(_logSdkEntries);
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (!(await sdk.isInitialized())) {
|
||||||
|
sdk.initialize();
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
print("Error initializing Breez: $e");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
GreenlightCredentials greenlightCredentials = GreenlightCredentials(
|
||||||
|
developerKey: base64.decode(secrets.greenlightKey),
|
||||||
|
developerCert: base64.decode(secrets.greenlightCert),
|
||||||
|
);
|
||||||
|
|
||||||
|
NodeConfig breezNodeConfig = NodeConfig.greenlight(
|
||||||
|
config: GreenlightNodeConfig(
|
||||||
|
partnerCredentials: greenlightCredentials,
|
||||||
|
inviteCode: null,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
Config breezConfig = await sdk.defaultConfig(
|
||||||
|
envType: EnvironmentType.Production,
|
||||||
|
apiKey: secrets.breezApiKey,
|
||||||
|
nodeConfig: breezNodeConfig,
|
||||||
|
);
|
||||||
|
|
||||||
|
String workingDir = await pathForWalletDir(name: walletInfo.name, type: type);
|
||||||
|
workingDir = "$workingDir/breez/";
|
||||||
|
|
||||||
|
new Directory(workingDir).createSync(recursive: true);
|
||||||
|
breezConfig = breezConfig.copyWith(workingDir: workingDir);
|
||||||
|
|
||||||
|
// disconnect if already connected
|
||||||
|
try {
|
||||||
|
if (await sdk.isInitialized()) {
|
||||||
|
await sdk.disconnect();
|
||||||
|
}
|
||||||
|
} catch (e, s) {
|
||||||
|
print("ERROR disconnecting from Breez: $e\n$s");
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
await sdk.connect(
|
||||||
|
req: ConnectRequest(
|
||||||
|
config: breezConfig,
|
||||||
|
seed: seedBytes,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
} catch (e, s) {
|
||||||
|
print("Error connecting to Breez: $e\n$s");
|
||||||
|
}
|
||||||
|
|
||||||
|
await _nodeStateSub?.cancel();
|
||||||
|
_nodeStateSub = sdk.nodeStateStream.listen((event) {
|
||||||
|
_handleNodeState(event);
|
||||||
|
});
|
||||||
|
await _handleNodeState(await sdk.nodeInfo());
|
||||||
|
|
||||||
|
await _paymentsSub?.cancel();
|
||||||
|
_paymentsSub = sdk.paymentsStream.listen((List<Payment> payments) {
|
||||||
|
_handlePayments(payments);
|
||||||
|
});
|
||||||
|
await _handlePayments(await sdk.listPayments(req: ListPaymentsRequest()));
|
||||||
|
|
||||||
|
print("initialized breez: ${(await sdk.isInitialized())}");
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> stopBreez(bool disconnect) async {
|
||||||
|
if (disconnect) {
|
||||||
|
final sdk = await BreezSDK();
|
||||||
|
if (await sdk.isInitialized()) {
|
||||||
|
await sdk.disconnect();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
await _nodeStateSub?.cancel();
|
||||||
|
await _paymentsSub?.cancel();
|
||||||
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
@override
|
||||||
|
Future<void> startSync() async {
|
||||||
|
try {
|
||||||
|
syncStatus = AttemptingSyncStatus();
|
||||||
|
await updateTransactions();
|
||||||
|
syncStatus = SyncedSyncStatus();
|
||||||
|
} catch (e) {
|
||||||
|
print(e);
|
||||||
|
syncStatus = FailedSyncStatus();
|
||||||
|
rethrow;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> changePassword(String password) {
|
||||||
|
throw UnimplementedError("changePassword");
|
||||||
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
@override
|
||||||
|
Future<void> connectToNode({required Node node}) async {
|
||||||
|
try {
|
||||||
|
syncStatus = ConnectingSyncStatus();
|
||||||
|
await updateTransactions();
|
||||||
|
syncStatus = ConnectedSyncStatus();
|
||||||
|
} catch (e) {
|
||||||
|
print(e);
|
||||||
|
syncStatus = FailedSyncStatus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<PendingTransaction> createTransaction(Object credentials) async {
|
||||||
|
throw UnimplementedError("createTransaction");
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<bool> updateTransactions() async {
|
||||||
|
try {
|
||||||
|
if (_isTransactionUpdating) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
_isTransactionUpdating = true;
|
||||||
|
final transactions = await fetchTransactions();
|
||||||
|
transactionHistory.addMany(transactions);
|
||||||
|
await transactionHistory.save();
|
||||||
|
_isTransactionUpdating = false;
|
||||||
|
return true;
|
||||||
|
} catch (_) {
|
||||||
|
_isTransactionUpdating = false;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, LightningTransactionInfo> convertToTxInfo(List<Payment> payments) {
|
||||||
|
Map<String, LightningTransactionInfo> transactions = {};
|
||||||
|
|
||||||
|
for (Payment tx in payments) {
|
||||||
|
if (tx.paymentType == PaymentType.ClosedChannel) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
bool isSend = tx.paymentType == PaymentType.Sent;
|
||||||
|
transactions[tx.id] = LightningTransactionInfo(
|
||||||
|
isPending: false,
|
||||||
|
id: tx.id,
|
||||||
|
amount: tx.amountMsat ~/ 1000,
|
||||||
|
fee: tx.feeMsat ~/ 1000,
|
||||||
|
date: DateTime.fromMillisecondsSinceEpoch(tx.paymentTime * 1000),
|
||||||
|
direction: isSend ? TransactionDirection.outgoing : TransactionDirection.incoming,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return transactions;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<Map<String, LightningTransactionInfo>> fetchTransactions() async {
|
||||||
|
final sdk = await BreezSDK();
|
||||||
|
|
||||||
|
final payments = await sdk.listPayments(req: ListPaymentsRequest());
|
||||||
|
final transactions = convertToTxInfo(payments);
|
||||||
|
|
||||||
|
return transactions;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> rescan({
|
||||||
|
required int height,
|
||||||
|
int? chainTip,
|
||||||
|
ScanData? scanData,
|
||||||
|
bool? doSingleScan,
|
||||||
|
bool? usingElectrs,
|
||||||
|
}) async {
|
||||||
|
updateTransactions();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> init() async {
|
||||||
|
await walletAddresses.init();
|
||||||
|
await transactionHistory.init();
|
||||||
|
await save();
|
||||||
|
}
|
||||||
|
|
||||||
|
String toJSON() => json.encode({
|
||||||
|
'mnemonic': mnemonic,
|
||||||
|
'account_index': walletAddresses.currentReceiveAddressIndexByType,
|
||||||
|
'change_address_index': walletAddresses.currentChangeAddressIndexByType,
|
||||||
|
'addresses': walletAddresses.allAddresses.map((addr) => addr.toJSON()).toList(),
|
||||||
|
'address_page_type': walletInfo.addressPageType == null
|
||||||
|
? SegwitAddresType.p2wpkh.toString()
|
||||||
|
: walletInfo.addressPageType.toString(),
|
||||||
|
'balance': balance[currency]?.toJSON(),
|
||||||
|
'network_type': network == BitcoinNetwork.testnet ? 'testnet' : 'mainnet',
|
||||||
|
});
|
||||||
|
|
||||||
|
Future<void> updateBalance() async {
|
||||||
|
// balance is updated automatically
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String mnemonic;
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get seed => mnemonic;
|
||||||
|
|
||||||
|
Future<String> makePath() async => pathForWallet(name: walletInfo.name, type: walletInfo.type);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> close({bool? switchingToSameWalletType}) async {
|
||||||
|
try {
|
||||||
|
await electrumClient.close();
|
||||||
|
} catch (_) {}
|
||||||
|
try {
|
||||||
|
bool shouldDisconnect = switchingToSameWalletType == null || !switchingToSameWalletType;
|
||||||
|
await stopBreez(shouldDisconnect);
|
||||||
|
} catch (e, s) {
|
||||||
|
print("Error stopping breez: $e\n$s");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
134
cw_lightning/lib/lightning_wallet_service.dart
Normal file
134
cw_lightning/lib/lightning_wallet_service.dart
Normal file
|
@ -0,0 +1,134 @@
|
||||||
|
import 'dart:io';
|
||||||
|
import 'package:bitcoin_base/bitcoin_base.dart';
|
||||||
|
import 'package:cw_bitcoin/bitcoin_mnemonic.dart';
|
||||||
|
import 'package:cw_bitcoin/mnemonic_is_incorrect_exception.dart';
|
||||||
|
import 'package:cw_bitcoin/bitcoin_wallet_creation_credentials.dart';
|
||||||
|
import 'package:cw_core/unspent_coins_info.dart';
|
||||||
|
import 'package:cw_core/wallet_base.dart';
|
||||||
|
import 'package:cw_core/wallet_service.dart';
|
||||||
|
import 'package:cw_core/pathForWallet.dart';
|
||||||
|
import 'package:cw_core/wallet_info.dart';
|
||||||
|
import 'package:cw_core/wallet_type.dart';
|
||||||
|
import 'package:cw_lightning/lightning_wallet.dart';
|
||||||
|
import 'package:hive/hive.dart';
|
||||||
|
import 'package:collection/collection.dart';
|
||||||
|
import 'package:bip39/bip39.dart' as bip39;
|
||||||
|
|
||||||
|
class LightningWalletService extends WalletService<
|
||||||
|
BitcoinNewWalletCredentials,
|
||||||
|
BitcoinRestoreWalletFromSeedCredentials,
|
||||||
|
BitcoinRestoreWalletFromWIFCredentials,
|
||||||
|
BitcoinRestoreWalletFromHardware> {
|
||||||
|
LightningWalletService(this.walletInfoSource, this.unspentCoinsInfoSource);
|
||||||
|
|
||||||
|
final Box<WalletInfo> walletInfoSource;
|
||||||
|
final Box<UnspentCoinsInfo> unspentCoinsInfoSource;
|
||||||
|
|
||||||
|
@override
|
||||||
|
WalletType getType() => WalletType.lightning;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<LightningWallet> create(BitcoinNewWalletCredentials credentials, {bool? isTestnet}) async {
|
||||||
|
final wallet = await LightningWalletBase.create(
|
||||||
|
mnemonic: bip39.generateMnemonic(),
|
||||||
|
password: credentials.password!,
|
||||||
|
walletInfo: credentials.walletInfo!,
|
||||||
|
unspentCoinsInfo: unspentCoinsInfoSource,
|
||||||
|
);
|
||||||
|
await wallet.save();
|
||||||
|
await wallet.init();
|
||||||
|
return wallet;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<bool> isWalletExit(String name) async =>
|
||||||
|
File(await pathForWallet(name: name, type: getType())).existsSync();
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<LightningWallet> openWallet(String name, String password) async {
|
||||||
|
final walletInfo = walletInfoSource.values
|
||||||
|
.firstWhereOrNull((info) => info.id == WalletBase.idFor(name, getType()))!;
|
||||||
|
try {
|
||||||
|
final wallet = await LightningWalletBase.open(
|
||||||
|
password: password,
|
||||||
|
name: name,
|
||||||
|
walletInfo: walletInfo,
|
||||||
|
unspentCoinsInfo: unspentCoinsInfoSource,
|
||||||
|
);
|
||||||
|
await wallet.init();
|
||||||
|
saveBackup(name);
|
||||||
|
return wallet;
|
||||||
|
} catch (_) {
|
||||||
|
await restoreWalletFilesFromBackup(name);
|
||||||
|
final wallet = await LightningWalletBase.open(
|
||||||
|
password: password,
|
||||||
|
name: name,
|
||||||
|
walletInfo: walletInfo,
|
||||||
|
unspentCoinsInfo: unspentCoinsInfoSource,
|
||||||
|
);
|
||||||
|
await wallet.init();
|
||||||
|
return wallet;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<LightningWallet> restoreFromHardwareWallet(BitcoinRestoreWalletFromHardware credentials,
|
||||||
|
{bool? isTestnet}) {
|
||||||
|
throw UnimplementedError(
|
||||||
|
"Restoring a Lightning wallet from a hardware wallet is not yet supported!");
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> remove(String wallet) async {
|
||||||
|
File(await pathForWalletDir(name: wallet, type: getType())).delete(recursive: true);
|
||||||
|
final walletInfo = walletInfoSource.values
|
||||||
|
.firstWhereOrNull((info) => info.id == WalletBase.idFor(wallet, getType()))!;
|
||||||
|
await walletInfoSource.delete(walletInfo.key);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> rename(String currentName, String password, String newName) async {
|
||||||
|
final currentWalletInfo = walletInfoSource.values
|
||||||
|
.firstWhereOrNull((info) => info.id == WalletBase.idFor(currentName, getType()))!;
|
||||||
|
final currentWallet = await LightningWalletBase.open(
|
||||||
|
password: password,
|
||||||
|
name: currentName,
|
||||||
|
walletInfo: currentWalletInfo,
|
||||||
|
unspentCoinsInfo: unspentCoinsInfoSource);
|
||||||
|
|
||||||
|
await currentWallet.renameWalletFiles(newName);
|
||||||
|
await saveBackup(newName);
|
||||||
|
|
||||||
|
final newWalletInfo = currentWalletInfo;
|
||||||
|
newWalletInfo.id = WalletBase.idFor(newName, getType());
|
||||||
|
newWalletInfo.name = newName;
|
||||||
|
|
||||||
|
await walletInfoSource.put(currentWalletInfo.key, newWalletInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<LightningWallet> restoreFromKeys(BitcoinRestoreWalletFromWIFCredentials credentials,
|
||||||
|
{bool? isTestnet}) async =>
|
||||||
|
throw UnimplementedError();
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<LightningWallet> restoreFromSeed(BitcoinRestoreWalletFromSeedCredentials credentials,
|
||||||
|
{bool? isTestnet}) async {
|
||||||
|
if (!bip39.validateMnemonic(credentials.mnemonic) && !validateMnemonic(credentials.mnemonic)) {
|
||||||
|
throw BitcoinMnemonicIsIncorrectException();
|
||||||
|
}
|
||||||
|
|
||||||
|
final network = isTestnet == true ? BitcoinNetwork.testnet : BitcoinNetwork.mainnet;
|
||||||
|
credentials.walletInfo?.network = network.value;
|
||||||
|
|
||||||
|
final wallet = await LightningWalletBase.create(
|
||||||
|
password: credentials.password!,
|
||||||
|
mnemonic: credentials.mnemonic,
|
||||||
|
walletInfo: credentials.walletInfo!,
|
||||||
|
unspentCoinsInfo: unspentCoinsInfoSource,
|
||||||
|
);
|
||||||
|
await wallet.save();
|
||||||
|
await wallet.init();
|
||||||
|
return wallet;
|
||||||
|
}
|
||||||
|
}
|
920
cw_lightning/pubspec.lock
Normal file
920
cw_lightning/pubspec.lock
Normal file
|
@ -0,0 +1,920 @@
|
||||||
|
# Generated by pub
|
||||||
|
# See https://dart.dev/tools/pub/glossary#lockfile
|
||||||
|
packages:
|
||||||
|
_fe_analyzer_shared:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: _fe_analyzer_shared
|
||||||
|
sha256: ae92f5d747aee634b87f89d9946000c2de774be1d6ac3e58268224348cd0101a
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "61.0.0"
|
||||||
|
analyzer:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: analyzer
|
||||||
|
sha256: ea3d8652bda62982addfd92fdc2d0214e5f82e43325104990d4f4c4a2a313562
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "5.13.0"
|
||||||
|
archive:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: archive
|
||||||
|
sha256: "20071638cbe4e5964a427cfa0e86dce55d060bc7d82d56f3554095d7239a8765"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "3.4.2"
|
||||||
|
args:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: args
|
||||||
|
sha256: "139d809800a412ebb26a3892da228b2d0ba36f0ef5d9a82166e5e52ec8d61611"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.3.2"
|
||||||
|
asn1lib:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: asn1lib
|
||||||
|
sha256: ab96a1cb3beeccf8145c52e449233fe68364c9641623acd3adad66f8184f1039
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.4.0"
|
||||||
|
async:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: async
|
||||||
|
sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.11.0"
|
||||||
|
bech32:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
path: "."
|
||||||
|
ref: "cake-0.2.2"
|
||||||
|
resolved-ref: "05755063b593aa6cca0a4820a318e0ce17de6192"
|
||||||
|
url: "https://github.com/cake-tech/bech32.git"
|
||||||
|
source: git
|
||||||
|
version: "0.2.2"
|
||||||
|
bip32:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: bip32
|
||||||
|
sha256: "54787cd7a111e9d37394aabbf53d1fc5e2e0e0af2cd01c459147a97c0e3f8a97"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.0.0"
|
||||||
|
bip39:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: bip39
|
||||||
|
sha256: de1ee27ebe7d96b84bb3a04a4132a0a3007dcdd5ad27dd14aa87a29d97c45edc
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.0.6"
|
||||||
|
bitbox:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
path: "."
|
||||||
|
ref: Add-Support-For-OP-Return-data
|
||||||
|
resolved-ref: "57b78afb85bd2c30d3cdb9f7884f3878a62be442"
|
||||||
|
url: "https://github.com/cake-tech/bitbox-flutter.git"
|
||||||
|
source: git
|
||||||
|
version: "1.0.1"
|
||||||
|
bitcoin_base:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
path: "."
|
||||||
|
ref: cake-update-v2
|
||||||
|
resolved-ref: "3fd81d238b990bb767fc7a4fdd5053a22a142e2e"
|
||||||
|
url: "https://github.com/cake-tech/bitcoin_base.git"
|
||||||
|
source: git
|
||||||
|
version: "4.2.0"
|
||||||
|
bitcoin_flutter:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
path: "."
|
||||||
|
ref: cake-update-v4
|
||||||
|
resolved-ref: e19ffb7e7977278a75b27e0479b3c6f4034223b3
|
||||||
|
url: "https://github.com/cake-tech/bitcoin_flutter.git"
|
||||||
|
source: git
|
||||||
|
version: "2.1.0"
|
||||||
|
blockchain_utils:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: blockchain_utils
|
||||||
|
sha256: "38ef5f4a22441ac4370aed9071dc71c460acffc37c79b344533f67d15f24c13c"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.1.1"
|
||||||
|
boolean_selector:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: boolean_selector
|
||||||
|
sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.1.1"
|
||||||
|
breez_sdk:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
path: "."
|
||||||
|
ref: "v0.4.0-rc2"
|
||||||
|
resolved-ref: "8762a59b1f823d3c37ee04b95bfe4eb88ea4eb6c"
|
||||||
|
url: "https://github.com/breez/breez-sdk-flutter.git"
|
||||||
|
source: git
|
||||||
|
version: "0.4.0-rc2"
|
||||||
|
bs58check:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: bs58check
|
||||||
|
sha256: c4a164d42b25c2f6bc88a8beccb9fc7d01440f3c60ba23663a20a70faf484ea9
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.0.2"
|
||||||
|
build:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: build
|
||||||
|
sha256: "3fbda25365741f8251b39f3917fb3c8e286a96fd068a5a242e11c2012d495777"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.3.1"
|
||||||
|
build_cli_annotations:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: build_cli_annotations
|
||||||
|
sha256: b59d2769769efd6c9ff6d4c4cede0be115a566afc591705c2040b707534b1172
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.1.0"
|
||||||
|
build_config:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: build_config
|
||||||
|
sha256: bf80fcfb46a29945b423bd9aad884590fb1dc69b330a4d4700cac476af1708d1
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.1.1"
|
||||||
|
build_daemon:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: build_daemon
|
||||||
|
sha256: "6bc5544ea6ce4428266e7ea680e945c68806c4aae2da0eb5e9ccf38df8d6acbf"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "3.1.0"
|
||||||
|
build_resolvers:
|
||||||
|
dependency: "direct dev"
|
||||||
|
description:
|
||||||
|
name: build_resolvers
|
||||||
|
sha256: "687cf90a3951affac1bd5f9ecb5e3e90b60487f3d9cdc359bb310f8876bb02a6"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.0.10"
|
||||||
|
build_runner:
|
||||||
|
dependency: "direct dev"
|
||||||
|
description:
|
||||||
|
name: build_runner
|
||||||
|
sha256: b0a8a7b8a76c493e85f1b84bffa0588859a06197863dba8c9036b15581fd9727
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.3.3"
|
||||||
|
build_runner_core:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: build_runner_core
|
||||||
|
sha256: "14febe0f5bac5ae474117a36099b4de6f1dbc52df6c5e55534b3da9591bf4292"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "7.2.7"
|
||||||
|
built_collection:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: built_collection
|
||||||
|
sha256: "376e3dd27b51ea877c28d525560790aee2e6fbb5f20e2f85d5081027d94e2100"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "5.1.1"
|
||||||
|
built_value:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: built_value
|
||||||
|
sha256: "169565c8ad06adb760c3645bf71f00bff161b00002cace266cad42c5d22a7725"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "8.4.3"
|
||||||
|
characters:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: characters
|
||||||
|
sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.3.0"
|
||||||
|
checked_yaml:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: checked_yaml
|
||||||
|
sha256: "3d1505d91afa809d177efd4eed5bb0eb65805097a1463abdd2add076effae311"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.0.2"
|
||||||
|
clock:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: clock
|
||||||
|
sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.1.1"
|
||||||
|
code_builder:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: code_builder
|
||||||
|
sha256: "0d43dd1288fd145de1ecc9a3948ad4a6d5a82f0a14c4fdd0892260787d975cbe"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "4.4.0"
|
||||||
|
collection:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: collection
|
||||||
|
sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.18.0"
|
||||||
|
convert:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: convert
|
||||||
|
sha256: "0f08b14755d163f6e2134cb58222dd25ea2a2ee8a195e53983d57c075324d592"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "3.1.1"
|
||||||
|
crypto:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: crypto
|
||||||
|
sha256: aa274aa7774f8964e4f4f38cc994db7b6158dd36e9187aaceaddc994b35c6c67
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "3.0.2"
|
||||||
|
cryptography:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: cryptography
|
||||||
|
sha256: e0e37f79665cd5c86e8897f9abe1accfe813c0cc5299dab22256e22fddc1fef8
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.0.5"
|
||||||
|
cw_bitcoin:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
path: "../cw_bitcoin"
|
||||||
|
relative: true
|
||||||
|
source: path
|
||||||
|
version: "0.0.1"
|
||||||
|
cw_core:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
path: "../cw_core"
|
||||||
|
relative: true
|
||||||
|
source: path
|
||||||
|
version: "0.0.1"
|
||||||
|
dart_style:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: dart_style
|
||||||
|
sha256: "7a03456c3490394c8e7665890333e91ae8a49be43542b616e414449ac358acd4"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.2.4"
|
||||||
|
encrypt:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: encrypt
|
||||||
|
sha256: "4fd4e4fdc21b9d7d4141823e1e6515cd94e7b8d84749504c232999fba25d9bbb"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "5.0.1"
|
||||||
|
fake_async:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: fake_async
|
||||||
|
sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.3.1"
|
||||||
|
ffi:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: ffi
|
||||||
|
sha256: "493f37e7df1804778ff3a53bd691d8692ddf69702cf4c1c1096a2e41b4779e21"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.1.2"
|
||||||
|
file:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: file
|
||||||
|
sha256: "1b92bec4fc2a72f59a8e15af5f52cd441e4a7860b49499d69dfa817af20e925d"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "6.1.4"
|
||||||
|
fixnum:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: fixnum
|
||||||
|
sha256: "25517a4deb0c03aa0f32fd12db525856438902d9c16536311e76cdc57b31d7d1"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.1.0"
|
||||||
|
flutter:
|
||||||
|
dependency: "direct main"
|
||||||
|
description: flutter
|
||||||
|
source: sdk
|
||||||
|
version: "0.0.0"
|
||||||
|
flutter_mobx:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: flutter_mobx
|
||||||
|
sha256: "0da4add0016387a7bf309a0d0c41d36c6b3ae25ed7a176409267f166509e723e"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.0.6+5"
|
||||||
|
flutter_rust_bridge:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: flutter_rust_bridge
|
||||||
|
sha256: "02720226035257ad0b571c1256f43df3e1556a499f6bcb004849a0faaa0e87f0"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.82.6"
|
||||||
|
flutter_test:
|
||||||
|
dependency: "direct dev"
|
||||||
|
description: flutter
|
||||||
|
source: sdk
|
||||||
|
version: "0.0.0"
|
||||||
|
freezed:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: freezed
|
||||||
|
sha256: "57247f692f35f068cae297549a46a9a097100685c6780fe67177503eea5ed4e5"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.4.7"
|
||||||
|
freezed_annotation:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: freezed_annotation
|
||||||
|
sha256: c3fd9336eb55a38cc1bbd79ab17573113a8deccd0ecbbf926cca3c62803b5c2d
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.4.1"
|
||||||
|
frontend_server_client:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: frontend_server_client
|
||||||
|
sha256: "408e3ca148b31c20282ad6f37ebfa6f4bdc8fede5b74bc2f08d9d92b55db3612"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "3.2.0"
|
||||||
|
glob:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: glob
|
||||||
|
sha256: "4515b5b6ddb505ebdd242a5f2cc5d22d3d6a80013789debfbda7777f47ea308c"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.1.1"
|
||||||
|
graphs:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: graphs
|
||||||
|
sha256: f9e130f3259f52d26f0cfc0e964513796dafed572fa52e45d2f8d6ca14db39b2
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.2.0"
|
||||||
|
hex:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: hex
|
||||||
|
sha256: "4e7cd54e4b59ba026432a6be2dd9d96e4c5205725194997193bf871703b82c4a"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.2.0"
|
||||||
|
hive:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: hive
|
||||||
|
sha256: "8dcf6db979d7933da8217edcec84e9df1bdb4e4edc7fc77dbd5aa74356d6d941"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.2.3"
|
||||||
|
hive_generator:
|
||||||
|
dependency: "direct dev"
|
||||||
|
description:
|
||||||
|
name: hive_generator
|
||||||
|
sha256: "06cb8f58ace74de61f63500564931f9505368f45f98958bd7a6c35ba24159db4"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.0.1"
|
||||||
|
http:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: http
|
||||||
|
sha256: "759d1a329847dd0f39226c688d3e06a6b8679668e350e2891a6474f8b4bb8525"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.1.0"
|
||||||
|
http_multi_server:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: http_multi_server
|
||||||
|
sha256: "97486f20f9c2f7be8f514851703d0119c3596d14ea63227af6f7a481ef2b2f8b"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "3.2.1"
|
||||||
|
http_parser:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: http_parser
|
||||||
|
sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "4.0.2"
|
||||||
|
intl:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: intl
|
||||||
|
sha256: "3bc132a9dbce73a7e4a21a17d06e1878839ffbf975568bc875c60537824b0c4d"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.18.1"
|
||||||
|
io:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: io
|
||||||
|
sha256: "2ec25704aba361659e10e3e5f5d672068d332fc8ac516421d483a11e5cbd061e"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.0.4"
|
||||||
|
js:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: js
|
||||||
|
sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.6.7"
|
||||||
|
json_annotation:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: json_annotation
|
||||||
|
sha256: c33da08e136c3df0190bd5bbe51ae1df4a7d96e7954d1d7249fea2968a72d317
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "4.8.0"
|
||||||
|
leak_tracker:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: leak_tracker
|
||||||
|
sha256: "78eb209deea09858f5269f5a5b02be4049535f568c07b275096836f01ea323fa"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "10.0.0"
|
||||||
|
leak_tracker_flutter_testing:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: leak_tracker_flutter_testing
|
||||||
|
sha256: b46c5e37c19120a8a01918cfaf293547f47269f7cb4b0058f21531c2465d6ef0
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.0.1"
|
||||||
|
leak_tracker_testing:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: leak_tracker_testing
|
||||||
|
sha256: a597f72a664dbd293f3bfc51f9ba69816f84dcd403cdac7066cb3f6003f3ab47
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.0.1"
|
||||||
|
logging:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: logging
|
||||||
|
sha256: "04094f2eb032cbb06c6f6e8d3607edcfcb0455e2bb6cbc010cb01171dcb64e6d"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.1.1"
|
||||||
|
matcher:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: matcher
|
||||||
|
sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.12.16+1"
|
||||||
|
material_color_utilities:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: material_color_utilities
|
||||||
|
sha256: "0e0a020085b65b6083975e499759762399b4475f766c21668c4ecca34ea74e5a"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.8.0"
|
||||||
|
meta:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: meta
|
||||||
|
sha256: d584fa6707a52763a52446f02cc621b077888fb63b93bbcb1143a7be5a0c0c04
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.11.0"
|
||||||
|
mime:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: mime
|
||||||
|
sha256: e4ff8e8564c03f255408decd16e7899da1733852a9110a58fe6d1b817684a63e
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.0.4"
|
||||||
|
mobx:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: mobx
|
||||||
|
sha256: f1862bd92c6a903fab67338f27e2f731117c3cb9ea37cee1a487f9e4e0de314a
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.1.3+1"
|
||||||
|
mobx_codegen:
|
||||||
|
dependency: "direct dev"
|
||||||
|
description:
|
||||||
|
name: mobx_codegen
|
||||||
|
sha256: "86122e410d8ea24dda0c69adb5c2a6ccadd5ce02ad46e144764e0d0184a06181"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.1.1"
|
||||||
|
package_config:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: package_config
|
||||||
|
sha256: "1c5b77ccc91e4823a5af61ee74e6b972db1ef98c2ff5a18d3161c982a55448bd"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.1.0"
|
||||||
|
path:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: path
|
||||||
|
sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.9.0"
|
||||||
|
path_provider:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: path_provider
|
||||||
|
sha256: a1aa8aaa2542a6bc57e381f132af822420216c80d4781f7aa085ca3229208aaa
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.1.1"
|
||||||
|
path_provider_android:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: path_provider_android
|
||||||
|
sha256: e595b98692943b4881b219f0a9e3945118d3c16bd7e2813f98ec6e532d905f72
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.2.1"
|
||||||
|
path_provider_foundation:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: path_provider_foundation
|
||||||
|
sha256: "19314d595120f82aca0ba62787d58dde2cc6b5df7d2f0daf72489e38d1b57f2d"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.3.1"
|
||||||
|
path_provider_linux:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: path_provider_linux
|
||||||
|
sha256: f7a1fe3a634fe7734c8d3f2766ad746ae2a2884abe22e241a8b301bf5cac3279
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.2.1"
|
||||||
|
path_provider_platform_interface:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: path_provider_platform_interface
|
||||||
|
sha256: "94b1e0dd80970c1ce43d5d4e050a9918fce4f4a775e6142424c30a29a363265c"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.1.1"
|
||||||
|
path_provider_windows:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: path_provider_windows
|
||||||
|
sha256: "8bc9f22eee8690981c22aa7fc602f5c85b497a6fb2ceb35ee5a5e5ed85ad8170"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.2.1"
|
||||||
|
petitparser:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: petitparser
|
||||||
|
sha256: cb3798bef7fc021ac45b308f4b51208a152792445cce0448c9a4ba5879dd8750
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "5.4.0"
|
||||||
|
platform:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: platform
|
||||||
|
sha256: "4a451831508d7d6ca779f7ac6e212b4023dd5a7d08a27a63da33756410e32b76"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "3.1.0"
|
||||||
|
plugin_platform_interface:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: plugin_platform_interface
|
||||||
|
sha256: dbf0f707c78beedc9200146ad3cb0ab4d5da13c246336987be6940f026500d3a
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.1.3"
|
||||||
|
pointycastle:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: pointycastle
|
||||||
|
sha256: db7306cf0249f838d1a24af52b5a5887c5bf7f31d8bb4e827d071dc0939ad346
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "3.6.2"
|
||||||
|
pool:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: pool
|
||||||
|
sha256: "20fe868b6314b322ea036ba325e6fc0711a22948856475e2c2b6306e8ab39c2a"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.5.1"
|
||||||
|
process:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: process
|
||||||
|
sha256: "53fd8db9cec1d37b0574e12f07520d582019cb6c44abf5479a01505099a34a09"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "4.2.4"
|
||||||
|
pub_semver:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: pub_semver
|
||||||
|
sha256: "307de764d305289ff24ad257ad5c5793ce56d04947599ad68b3baa124105fc17"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.1.3"
|
||||||
|
pubspec_parse:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: pubspec_parse
|
||||||
|
sha256: "75f6614d6dde2dc68948dffbaa4fe5dae32cd700eb9fb763fe11dfb45a3c4d0a"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.2.1"
|
||||||
|
puppeteer:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: puppeteer
|
||||||
|
sha256: "59e723cc5b69537159a7c34efd645dc08a6a1ac4647d7d7823606802c0f93cdb"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "3.2.0"
|
||||||
|
rxdart:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: rxdart
|
||||||
|
sha256: "0c7c0cedd93788d996e33041ffecda924cc54389199cde4e6a34b440f50044cb"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.27.7"
|
||||||
|
shelf:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: shelf
|
||||||
|
sha256: c24a96135a2ccd62c64b69315a14adc5c3419df63b4d7c05832a346fdb73682c
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.4.0"
|
||||||
|
shelf_static:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: shelf_static
|
||||||
|
sha256: a41d3f53c4adf0f57480578c1d61d90342cd617de7fc8077b1304643c2d85c1e
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.1.2"
|
||||||
|
shelf_web_socket:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: shelf_web_socket
|
||||||
|
sha256: a988c0e8d8ffbdb8a28aa7ec8e449c260f3deb808781fe1284d22c5bba7156e8
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.0.3"
|
||||||
|
sky_engine:
|
||||||
|
dependency: transitive
|
||||||
|
description: flutter
|
||||||
|
source: sdk
|
||||||
|
version: "0.0.99"
|
||||||
|
socks5_proxy:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: socks5_proxy
|
||||||
|
sha256: "1d21b5606169654bbf4cfb904e8e6ed897e9f763358709f87310c757096d909a"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.0.4"
|
||||||
|
source_gen:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: source_gen
|
||||||
|
sha256: "2d79738b6bbf38a43920e2b8d189e9a3ce6cc201f4b8fc76be5e4fe377b1c38d"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.2.6"
|
||||||
|
source_helper:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: source_helper
|
||||||
|
sha256: "3b67aade1d52416149c633ba1bb36df44d97c6b51830c2198e934e3fca87ca1f"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.3.3"
|
||||||
|
source_span:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: source_span
|
||||||
|
sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.10.0"
|
||||||
|
sprintf:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: sprintf
|
||||||
|
sha256: "1fc9ffe69d4df602376b52949af107d8f5703b77cda567c4d7d86a0693120f23"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "7.0.0"
|
||||||
|
stack_trace:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: stack_trace
|
||||||
|
sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.11.1"
|
||||||
|
stream_channel:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: stream_channel
|
||||||
|
sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.1.2"
|
||||||
|
stream_transform:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: stream_transform
|
||||||
|
sha256: "14a00e794c7c11aa145a170587321aedce29769c08d7f58b1d141da75e3b1c6f"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.1.0"
|
||||||
|
string_scanner:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: string_scanner
|
||||||
|
sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.2.0"
|
||||||
|
term_glyph:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: term_glyph
|
||||||
|
sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.2.1"
|
||||||
|
test_api:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: test_api
|
||||||
|
sha256: "5c2f730018264d276c20e4f1503fd1308dfbbae39ec8ee63c5236311ac06954b"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.6.1"
|
||||||
|
timing:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: timing
|
||||||
|
sha256: "70a3b636575d4163c477e6de42f247a23b315ae20e86442bebe32d3cabf61c32"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.0.1"
|
||||||
|
tuple:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: tuple
|
||||||
|
sha256: a97ce2013f240b2f3807bcbaf218765b6f301c3eff91092bcfa23a039e7dd151
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.0.2"
|
||||||
|
typed_data:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: typed_data
|
||||||
|
sha256: "26f87ade979c47a150c9eaab93ccd2bebe70a27dc0b4b29517f2904f04eb11a5"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.3.1"
|
||||||
|
unorm_dart:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: unorm_dart
|
||||||
|
sha256: "5b35bff83fce4d76467641438f9e867dc9bcfdb8c1694854f230579d68cd8f4b"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.2.0"
|
||||||
|
uuid:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: uuid
|
||||||
|
sha256: "22c94e5ad1e75f9934b766b53c742572ee2677c56bc871d850a57dad0f82127f"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "4.2.2"
|
||||||
|
vector_math:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: vector_math
|
||||||
|
sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.1.4"
|
||||||
|
vm_service:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: vm_service
|
||||||
|
sha256: b3d56ff4341b8f182b96aceb2fa20e3dcb336b9f867bc0eafc0de10f1048e957
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "13.0.0"
|
||||||
|
watcher:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: watcher
|
||||||
|
sha256: "6a7f46926b01ce81bfc339da6a7f20afbe7733eff9846f6d6a5466aa4c6667c0"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.0.2"
|
||||||
|
web_socket_channel:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: web_socket_channel
|
||||||
|
sha256: ca49c0bc209c687b887f30527fb6a9d80040b072cc2990f34b9bec3e7663101b
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.3.0"
|
||||||
|
win32:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: win32
|
||||||
|
sha256: c9ebe7ee4ab0c2194e65d3a07d8c54c5d00bb001b76081c4a04cdb8448b59e46
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "3.1.3"
|
||||||
|
xdg_directories:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: xdg_directories
|
||||||
|
sha256: bd512f03919aac5f1313eb8249f223bacf4927031bf60b02601f81f687689e86
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.2.0+3"
|
||||||
|
yaml:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: yaml
|
||||||
|
sha256: "23812a9b125b48d4007117254bca50abb6c712352927eece9e155207b1db2370"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "3.1.1"
|
||||||
|
sdks:
|
||||||
|
dart: ">=3.3.0 <4.0.0"
|
||||||
|
flutter: ">=3.19.0"
|
88
cw_lightning/pubspec.yaml
Normal file
88
cw_lightning/pubspec.yaml
Normal file
|
@ -0,0 +1,88 @@
|
||||||
|
name: cw_lightning
|
||||||
|
description: A new Flutter package project.
|
||||||
|
version: 0.0.1
|
||||||
|
publish_to: none
|
||||||
|
author: Cake Wallet
|
||||||
|
homepage: https://cakewallet.com
|
||||||
|
|
||||||
|
environment:
|
||||||
|
sdk: ">=2.17.5 <3.0.0"
|
||||||
|
flutter: ">=1.20.0"
|
||||||
|
|
||||||
|
dependencies:
|
||||||
|
flutter:
|
||||||
|
sdk: flutter
|
||||||
|
path_provider: ^2.0.11
|
||||||
|
http: ^1.1.0
|
||||||
|
mobx: ^2.0.7+4
|
||||||
|
flutter_mobx: ^2.0.6+1
|
||||||
|
intl: ^0.18.0
|
||||||
|
cw_core:
|
||||||
|
path: ../cw_core
|
||||||
|
cw_bitcoin:
|
||||||
|
path: ../cw_bitcoin
|
||||||
|
bitcoin_flutter:
|
||||||
|
git:
|
||||||
|
url: https://github.com/cake-tech/bitcoin_flutter.git
|
||||||
|
ref: cake-update-v4
|
||||||
|
bitbox:
|
||||||
|
git:
|
||||||
|
url: https://github.com/cake-tech/bitbox-flutter.git
|
||||||
|
ref: Add-Support-For-OP-Return-data
|
||||||
|
breez_sdk:
|
||||||
|
git:
|
||||||
|
url: https://github.com/breez/breez-sdk-flutter.git
|
||||||
|
ref: v0.4.3-rc1
|
||||||
|
cryptography: ^2.0.5
|
||||||
|
bitcoin_base:
|
||||||
|
git:
|
||||||
|
url: https://github.com/cake-tech/bitcoin_base
|
||||||
|
ref: cake-update-v3
|
||||||
|
|
||||||
|
dev_dependencies:
|
||||||
|
flutter_test:
|
||||||
|
sdk: flutter
|
||||||
|
build_runner: ^2.1.11
|
||||||
|
build_resolvers: ^2.0.9
|
||||||
|
mobx_codegen: ^2.0.7
|
||||||
|
hive_generator: ^2.0.1
|
||||||
|
|
||||||
|
dependency_overrides:
|
||||||
|
watcher: ^1.1.0
|
||||||
|
|
||||||
|
# For information on the generic Dart part of this file, see the
|
||||||
|
# following page: https://dart.dev/tools/pub/pubspec
|
||||||
|
|
||||||
|
# The following section is specific to Flutter.
|
||||||
|
flutter:
|
||||||
|
|
||||||
|
# To add assets to your package, add an assets section, like this:
|
||||||
|
# assets:
|
||||||
|
# - images/a_dot_burr.jpeg
|
||||||
|
# - images/a_dot_ham.jpeg
|
||||||
|
#
|
||||||
|
# For details regarding assets in packages, see
|
||||||
|
# https://flutter.dev/assets-and-images/#from-packages
|
||||||
|
#
|
||||||
|
# An image asset can refer to one or more resolution-specific "variants", see
|
||||||
|
# https://flutter.dev/assets-and-images/#resolution-aware.
|
||||||
|
|
||||||
|
# To add custom fonts to your package, add a fonts section here,
|
||||||
|
# in this "flutter" section. Each entry in this list should have a
|
||||||
|
# "family" key with the font family name, and a "fonts" key with a
|
||||||
|
# list giving the asset and other descriptors for the font. For
|
||||||
|
# example:
|
||||||
|
# fonts:
|
||||||
|
# - family: Schyler
|
||||||
|
# fonts:
|
||||||
|
# - asset: fonts/Schyler-Regular.ttf
|
||||||
|
# - asset: fonts/Schyler-Italic.ttf
|
||||||
|
# style: italic
|
||||||
|
# - family: Trajan Pro
|
||||||
|
# fonts:
|
||||||
|
# - asset: fonts/TrajanPro.ttf
|
||||||
|
# - asset: fonts/TrajanPro_Bold.ttf
|
||||||
|
# weight: 700
|
||||||
|
#
|
||||||
|
# For details regarding fonts in packages, see
|
||||||
|
# https://flutter.dev/custom-fonts/#from-packages
|
12
cw_lightning/test/cw_lightning_test.dart
Normal file
12
cw_lightning/test/cw_lightning_test.dart
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
|
||||||
|
import 'package:cw_lightning/cw_lightning.dart';
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
test('adds one to input values', () {
|
||||||
|
final calculator = Calculator();
|
||||||
|
expect(calculator.addOne(2), 3);
|
||||||
|
expect(calculator.addOne(-7), -6);
|
||||||
|
expect(calculator.addOne(0), 1);
|
||||||
|
});
|
||||||
|
}
|
|
@ -161,7 +161,7 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
|
||||||
Future<void>? updateBalance() => null;
|
Future<void>? updateBalance() => null;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void close() async {
|
void close({bool? switchingToSameWalletType}) {
|
||||||
_listener?.stop();
|
_listener?.stop();
|
||||||
_onAccountChangeReaction?.reaction.dispose();
|
_onAccountChangeReaction?.reaction.dispose();
|
||||||
_autoSaveTimer?.cancel();
|
_autoSaveTimer?.cancel();
|
||||||
|
|
|
@ -34,7 +34,7 @@ dev_dependencies:
|
||||||
build_runner: ^2.4.7
|
build_runner: ^2.4.7
|
||||||
build_resolvers: ^2.0.9
|
build_resolvers: ^2.0.9
|
||||||
mobx_codegen: ^2.0.7
|
mobx_codegen: ^2.0.7
|
||||||
hive_generator: ^1.1.3
|
hive_generator: ^2.0.1
|
||||||
|
|
||||||
dependency_overrides:
|
dependency_overrides:
|
||||||
watcher: ^1.1.0
|
watcher: ^1.1.0
|
||||||
|
|
|
@ -138,7 +138,7 @@ abstract class NanoWalletBase
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void close() {
|
void close({bool? switchingToSameWalletType}) {
|
||||||
_client.stop();
|
_client.stop();
|
||||||
_receiveTimer?.cancel();
|
_receiveTimer?.cancel();
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,7 +34,7 @@ dev_dependencies:
|
||||||
sdk: flutter
|
sdk: flutter
|
||||||
build_runner: ^2.4.7
|
build_runner: ^2.4.7
|
||||||
mobx_codegen: ^2.0.7
|
mobx_codegen: ^2.0.7
|
||||||
hive_generator: ^1.1.3
|
hive_generator: ^2.0.1
|
||||||
|
|
||||||
dependency_overrides:
|
dependency_overrides:
|
||||||
watcher: ^1.1.0
|
watcher: ^1.1.0
|
||||||
|
|
|
@ -165,7 +165,7 @@ abstract class SolanaWalletBase
|
||||||
Future<void> changePassword(String password) => throw UnimplementedError("changePassword");
|
Future<void> changePassword(String password) => throw UnimplementedError("changePassword");
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void close() {
|
void close({bool? switchingToSameWalletType}) {
|
||||||
_client.stop();
|
_client.stop();
|
||||||
_transactionsUpdateTimer?.cancel();
|
_transactionsUpdateTimer?.cancel();
|
||||||
}
|
}
|
||||||
|
|
|
@ -186,7 +186,7 @@ abstract class TronWalletBase
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void close() {
|
void close({bool? switchingToSameWalletType}) {
|
||||||
_transactionsUpdateTimer?.cancel();
|
_transactionsUpdateTimer?.cancel();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -60,6 +60,26 @@
|
||||||
<string>bitcoin-wallet</string>
|
<string>bitcoin-wallet</string>
|
||||||
</array>
|
</array>
|
||||||
</dict>
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>CFBundleTypeRole</key>
|
||||||
|
<string>Editor</string>
|
||||||
|
<key>CFBundleURLName</key>
|
||||||
|
<string>lightning</string>
|
||||||
|
<key>CFBundleURLSchemes</key>
|
||||||
|
<array>
|
||||||
|
<string>lightning</string>
|
||||||
|
</array>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>CFBundleTypeRole</key>
|
||||||
|
<string>Editor</string>
|
||||||
|
<key>CFBundleURLName</key>
|
||||||
|
<string>lightning-wallet</string>
|
||||||
|
<key>CFBundleURLSchemes</key>
|
||||||
|
<array>
|
||||||
|
<string>lightning-wallet</string>
|
||||||
|
</array>
|
||||||
|
</dict>
|
||||||
<dict>
|
<dict>
|
||||||
<key>CFBundleTypeRole</key>
|
<key>CFBundleTypeRole</key>
|
||||||
<string>Editor</string>
|
<string>Editor</string>
|
||||||
|
|
|
@ -36,4 +36,10 @@ class CWBitcoinCash extends BitcoinCash {
|
||||||
@override
|
@override
|
||||||
TransactionPriority getBitcoinCashTransactionPrioritySlow() =>
|
TransactionPriority getBitcoinCashTransactionPrioritySlow() =>
|
||||||
BitcoinCashTransactionPriority.slow;
|
BitcoinCashTransactionPriority.slow;
|
||||||
|
|
||||||
|
@override
|
||||||
|
String getMnemonic(int? strength) => throw UnimplementedError();
|
||||||
|
|
||||||
|
@override
|
||||||
|
Uint8List getSeedFromMnemonic(String seed) => throw UnimplementedError();
|
||||||
}
|
}
|
||||||
|
|
|
@ -279,7 +279,8 @@ class AddressValidator extends TextValidator {
|
||||||
'|([^0-9a-zA-Z]|^)((bc|tb)1q[ac-hj-np-z02-9]{40,80})([^0-9a-zA-Z]|\$)' //P2wshAddress type
|
'|([^0-9a-zA-Z]|^)((bc|tb)1q[ac-hj-np-z02-9]{40,80})([^0-9a-zA-Z]|\$)' //P2wshAddress type
|
||||||
'|([^0-9a-zA-Z]|^)((bc|tb)1p([ac-hj-np-z02-9]{39}|[ac-hj-np-z02-9]{59}|[ac-hj-np-z02-9]{8,89}))([^0-9a-zA-Z]|\$)' //P2trAddress type
|
'|([^0-9a-zA-Z]|^)((bc|tb)1p([ac-hj-np-z02-9]{39}|[ac-hj-np-z02-9]{59}|[ac-hj-np-z02-9]{8,89}))([^0-9a-zA-Z]|\$)' //P2trAddress type
|
||||||
'|${SilentPaymentAddress.regex.pattern}\$';
|
'|${SilentPaymentAddress.regex.pattern}\$';
|
||||||
|
case CryptoCurrency.btcln:
|
||||||
|
return '(lnbc|LNBC)([0-9]{1,}[a-zA-Z0-9]+)([^0-9a-zA-Z]|\$)';
|
||||||
case CryptoCurrency.ltc:
|
case CryptoCurrency.ltc:
|
||||||
return '([^0-9a-zA-Z]|^)^L[a-zA-Z0-9]{26,33}([^0-9a-zA-Z]|\$)'
|
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]|^)[LM][a-km-zA-HJ-NP-Z1-9]{26,33}([^0-9a-zA-Z]|\$)'
|
||||||
|
|
|
@ -24,7 +24,7 @@ class SeedValidator extends Validator<MnemonicItem> {
|
||||||
static List<String> getWordList({required WalletType type, required String language}) {
|
static List<String> getWordList({required WalletType type, required String language}) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case WalletType.bitcoin:
|
case WalletType.bitcoin:
|
||||||
return getBitcoinWordList(language);
|
case WalletType.lightning:
|
||||||
case WalletType.litecoin:
|
case WalletType.litecoin:
|
||||||
return getBitcoinWordList(language);
|
return getBitcoinWordList(language);
|
||||||
case WalletType.monero:
|
case WalletType.monero:
|
||||||
|
|
|
@ -79,6 +79,7 @@ class WalletCreationService {
|
||||||
case WalletType.polygon:
|
case WalletType.polygon:
|
||||||
case WalletType.solana:
|
case WalletType.solana:
|
||||||
case WalletType.tron:
|
case WalletType.tron:
|
||||||
|
case WalletType.lightning:
|
||||||
return true;
|
return true;
|
||||||
case WalletType.monero:
|
case WalletType.monero:
|
||||||
case WalletType.wownero:
|
case WalletType.wownero:
|
||||||
|
|
112
lib/di.dart
112
lib/di.dart
|
@ -1,3 +1,4 @@
|
||||||
|
import 'package:breez_sdk/bridge_generated.dart';
|
||||||
import 'package:cake_wallet/.secrets.g.dart' as secrets;
|
import 'package:cake_wallet/.secrets.g.dart' as secrets;
|
||||||
import 'package:cake_wallet/anonpay/anonpay_api.dart';
|
import 'package:cake_wallet/anonpay/anonpay_api.dart';
|
||||||
import 'package:cake_wallet/anonpay/anonpay_info_base.dart';
|
import 'package:cake_wallet/anonpay/anonpay_info_base.dart';
|
||||||
|
@ -28,16 +29,24 @@ import 'package:cake_wallet/entities/contact.dart';
|
||||||
import 'package:cake_wallet/entities/contact_record.dart';
|
import 'package:cake_wallet/entities/contact_record.dart';
|
||||||
import 'package:cake_wallet/entities/exchange_api_mode.dart';
|
import 'package:cake_wallet/entities/exchange_api_mode.dart';
|
||||||
import 'package:cake_wallet/entities/parse_address_from_domain.dart';
|
import 'package:cake_wallet/entities/parse_address_from_domain.dart';
|
||||||
|
import 'package:cake_wallet/src/screens/cake_pay/cake_pay.dart';
|
||||||
|
import 'package:cake_wallet/view_model/lightning_send_view_model.dart';
|
||||||
|
import 'package:cake_wallet/view_model/link_view_model.dart';
|
||||||
|
import 'package:cake_wallet/tron/tron.dart';
|
||||||
|
import 'package:cake_wallet/src/screens/transaction_details/rbf_details_page.dart';
|
||||||
|
import 'package:cw_core/nano_account.dart';
|
||||||
|
import 'package:cw_core/receive_page_option.dart';
|
||||||
import 'package:cake_wallet/entities/qr_view_data.dart';
|
import 'package:cake_wallet/entities/qr_view_data.dart';
|
||||||
import 'package:cake_wallet/entities/template.dart';
|
import 'package:cake_wallet/entities/template.dart';
|
||||||
import 'package:cake_wallet/entities/transaction_description.dart';
|
import 'package:cake_wallet/entities/transaction_description.dart';
|
||||||
import 'package:cake_wallet/ethereum/ethereum.dart';
|
import 'package:cake_wallet/ethereum/ethereum.dart';
|
||||||
|
import 'package:cake_wallet/lightning/lightning.dart';
|
||||||
|
import 'package:cake_wallet/nano/nano.dart';
|
||||||
import 'package:cake_wallet/cake_pay/cake_pay_card.dart';
|
import 'package:cake_wallet/cake_pay/cake_pay_card.dart';
|
||||||
import 'package:cake_wallet/exchange/exchange_template.dart';
|
import 'package:cake_wallet/exchange/exchange_template.dart';
|
||||||
import 'package:cake_wallet/exchange/trade.dart';
|
import 'package:cake_wallet/exchange/trade.dart';
|
||||||
import 'package:cake_wallet/haven/haven.dart';
|
import 'package:cake_wallet/haven/haven.dart';
|
||||||
import 'package:cake_wallet/monero/monero.dart';
|
import 'package:cake_wallet/monero/monero.dart';
|
||||||
import 'package:cake_wallet/nano/nano.dart';
|
|
||||||
import 'package:cake_wallet/polygon/polygon.dart';
|
import 'package:cake_wallet/polygon/polygon.dart';
|
||||||
import 'package:cake_wallet/reactions/on_authentication_state_change.dart';
|
import 'package:cake_wallet/reactions/on_authentication_state_change.dart';
|
||||||
import 'package:cake_wallet/routes.dart';
|
import 'package:cake_wallet/routes.dart';
|
||||||
|
@ -77,12 +86,16 @@ import 'package:cake_wallet/src/screens/order_details/order_details_page.dart';
|
||||||
import 'package:cake_wallet/src/screens/pin_code/pin_code_widget.dart';
|
import 'package:cake_wallet/src/screens/pin_code/pin_code_widget.dart';
|
||||||
import 'package:cake_wallet/src/screens/receive/anonpay_invoice_page.dart';
|
import 'package:cake_wallet/src/screens/receive/anonpay_invoice_page.dart';
|
||||||
import 'package:cake_wallet/src/screens/receive/anonpay_receive_page.dart';
|
import 'package:cake_wallet/src/screens/receive/anonpay_receive_page.dart';
|
||||||
|
import 'package:cake_wallet/src/screens/receive/lightning_invoice_page.dart';
|
||||||
|
import 'package:cake_wallet/src/screens/receive/lightning_receive_page.dart';
|
||||||
|
import 'package:cake_wallet/src/screens/restore/wallet_restore_choose_derivation.dart';
|
||||||
|
import 'package:cake_wallet/src/screens/send/lightning_send_confirm_page.dart';
|
||||||
|
import 'package:cake_wallet/src/screens/send/lightning_send_page.dart';
|
||||||
import 'package:cake_wallet/src/screens/receive/fullscreen_qr_page.dart';
|
import 'package:cake_wallet/src/screens/receive/fullscreen_qr_page.dart';
|
||||||
import 'package:cake_wallet/src/screens/receive/receive_page.dart';
|
import 'package:cake_wallet/src/screens/receive/receive_page.dart';
|
||||||
import 'package:cake_wallet/src/screens/rescan/rescan_page.dart';
|
import 'package:cake_wallet/src/screens/rescan/rescan_page.dart';
|
||||||
import 'package:cake_wallet/src/screens/restore/restore_from_backup_page.dart';
|
import 'package:cake_wallet/src/screens/restore/restore_from_backup_page.dart';
|
||||||
import 'package:cake_wallet/src/screens/restore/restore_options_page.dart';
|
import 'package:cake_wallet/src/screens/restore/restore_options_page.dart';
|
||||||
import 'package:cake_wallet/src/screens/restore/wallet_restore_choose_derivation.dart';
|
|
||||||
import 'package:cake_wallet/src/screens/restore/wallet_restore_page.dart';
|
import 'package:cake_wallet/src/screens/restore/wallet_restore_page.dart';
|
||||||
import 'package:cake_wallet/src/screens/seed/pre_seed_page.dart';
|
import 'package:cake_wallet/src/screens/seed/pre_seed_page.dart';
|
||||||
import 'package:cake_wallet/src/screens/seed/wallet_seed_page.dart';
|
import 'package:cake_wallet/src/screens/seed/wallet_seed_page.dart';
|
||||||
|
@ -122,13 +135,14 @@ import 'package:cake_wallet/view_model/anonpay_details_view_model.dart';
|
||||||
import 'package:cake_wallet/view_model/dashboard/home_settings_view_model.dart';
|
import 'package:cake_wallet/view_model/dashboard/home_settings_view_model.dart';
|
||||||
import 'package:cake_wallet/view_model/dashboard/nft_view_model.dart';
|
import 'package:cake_wallet/view_model/dashboard/nft_view_model.dart';
|
||||||
import 'package:cake_wallet/view_model/dashboard/receive_option_view_model.dart';
|
import 'package:cake_wallet/view_model/dashboard/receive_option_view_model.dart';
|
||||||
|
import 'package:cake_wallet/view_model/lightning_invoice_page_view_model.dart';
|
||||||
|
import 'package:cake_wallet/view_model/lightning_view_model.dart';
|
||||||
import 'package:cake_wallet/view_model/cake_pay/cake_pay_auth_view_model.dart';
|
import 'package:cake_wallet/view_model/cake_pay/cake_pay_auth_view_model.dart';
|
||||||
import 'package:cake_wallet/view_model/cake_pay/cake_pay_buy_card_view_model.dart';
|
import 'package:cake_wallet/view_model/cake_pay/cake_pay_buy_card_view_model.dart';
|
||||||
import 'package:cake_wallet/cake_pay/cake_pay_service.dart';
|
import 'package:cake_wallet/cake_pay/cake_pay_service.dart';
|
||||||
import 'package:cake_wallet/cake_pay/cake_pay_api.dart';
|
import 'package:cake_wallet/cake_pay/cake_pay_api.dart';
|
||||||
import 'package:cake_wallet/cake_pay/cake_pay_vendor.dart';
|
import 'package:cake_wallet/cake_pay/cake_pay_vendor.dart';
|
||||||
import 'package:cake_wallet/src/screens/cake_pay/auth/cake_pay_account_page.dart';
|
import 'package:cake_wallet/src/screens/cake_pay/auth/cake_pay_account_page.dart';
|
||||||
import 'package:cake_wallet/src/screens/cake_pay/cake_pay.dart';
|
|
||||||
import 'package:cake_wallet/view_model/cake_pay/cake_pay_account_view_model.dart';
|
import 'package:cake_wallet/view_model/cake_pay/cake_pay_account_view_model.dart';
|
||||||
import 'package:cake_wallet/view_model/cake_pay/cake_pay_cards_list_view_model.dart';
|
import 'package:cake_wallet/view_model/cake_pay/cake_pay_cards_list_view_model.dart';
|
||||||
import 'package:cake_wallet/view_model/cake_pay/cake_pay_purchase_view_model.dart';
|
import 'package:cake_wallet/view_model/cake_pay/cake_pay_purchase_view_model.dart';
|
||||||
|
@ -136,6 +150,7 @@ import 'package:cake_wallet/view_model/nano_account_list/nano_account_edit_or_cr
|
||||||
import 'package:cake_wallet/view_model/nano_account_list/nano_account_list_view_model.dart';
|
import 'package:cake_wallet/view_model/nano_account_list/nano_account_list_view_model.dart';
|
||||||
import 'package:cake_wallet/view_model/node_list/pow_node_list_view_model.dart';
|
import 'package:cake_wallet/view_model/node_list/pow_node_list_view_model.dart';
|
||||||
import 'package:cake_wallet/view_model/seed_type_view_model.dart';
|
import 'package:cake_wallet/view_model/seed_type_view_model.dart';
|
||||||
|
import 'package:cake_wallet/view_model/send/output.dart';
|
||||||
import 'package:cake_wallet/view_model/set_up_2fa_viewmodel.dart';
|
import 'package:cake_wallet/view_model/set_up_2fa_viewmodel.dart';
|
||||||
import 'package:cake_wallet/view_model/restore/restore_from_qr_vm.dart';
|
import 'package:cake_wallet/view_model/restore/restore_from_qr_vm.dart';
|
||||||
import 'package:cake_wallet/view_model/settings/display_settings_view_model.dart';
|
import 'package:cake_wallet/view_model/settings/display_settings_view_model.dart';
|
||||||
|
@ -148,13 +163,12 @@ import 'package:cake_wallet/view_model/wallet_address_list/wallet_address_list_i
|
||||||
import 'package:cake_wallet/view_model/wallet_list/wallet_edit_view_model.dart';
|
import 'package:cake_wallet/view_model/wallet_list/wallet_edit_view_model.dart';
|
||||||
import 'package:cake_wallet/view_model/wallet_list/wallet_list_item.dart';
|
import 'package:cake_wallet/view_model/wallet_list/wallet_list_item.dart';
|
||||||
import 'package:cake_wallet/view_model/wallet_restore_choose_derivation_view_model.dart';
|
import 'package:cake_wallet/view_model/wallet_restore_choose_derivation_view_model.dart';
|
||||||
import 'package:cw_core/nano_account.dart';
|
|
||||||
import 'package:cw_core/unspent_coins_info.dart';
|
import 'package:cw_core/unspent_coins_info.dart';
|
||||||
|
import 'package:cw_core/wallet_info.dart';
|
||||||
import 'package:cw_core/wallet_service.dart';
|
import 'package:cw_core/wallet_service.dart';
|
||||||
import 'package:cw_core/transaction_info.dart';
|
import 'package:cw_core/transaction_info.dart';
|
||||||
import 'package:cw_core/node.dart';
|
import 'package:cw_core/node.dart';
|
||||||
import 'package:cake_wallet/src/screens/trade_details/trade_details_page.dart';
|
import 'package:cake_wallet/src/screens/trade_details/trade_details_page.dart';
|
||||||
import 'package:cake_wallet/src/screens/transaction_details/rbf_details_page.dart';
|
|
||||||
import 'package:cake_wallet/src/screens/transaction_details/transaction_details_page.dart';
|
import 'package:cake_wallet/src/screens/transaction_details/transaction_details_page.dart';
|
||||||
import 'package:cake_wallet/src/screens/unspent_coins/unspent_coins_details_page.dart';
|
import 'package:cake_wallet/src/screens/unspent_coins/unspent_coins_details_page.dart';
|
||||||
import 'package:cake_wallet/src/screens/unspent_coins/unspent_coins_list_page.dart';
|
import 'package:cake_wallet/src/screens/unspent_coins/unspent_coins_list_page.dart';
|
||||||
|
@ -174,7 +188,6 @@ import 'package:cake_wallet/store/templates/exchange_template_store.dart';
|
||||||
import 'package:cake_wallet/store/templates/send_template_store.dart';
|
import 'package:cake_wallet/store/templates/send_template_store.dart';
|
||||||
import 'package:cake_wallet/store/wallet_list_store.dart';
|
import 'package:cake_wallet/store/wallet_list_store.dart';
|
||||||
import 'package:cake_wallet/store/yat/yat_store.dart';
|
import 'package:cake_wallet/store/yat/yat_store.dart';
|
||||||
import 'package:cake_wallet/tron/tron.dart';
|
|
||||||
import 'package:cake_wallet/view_model/auth_view_model.dart';
|
import 'package:cake_wallet/view_model/auth_view_model.dart';
|
||||||
import 'package:cake_wallet/view_model/backup_view_model.dart';
|
import 'package:cake_wallet/view_model/backup_view_model.dart';
|
||||||
import 'package:cake_wallet/view_model/buy/buy_amount_view_model.dart';
|
import 'package:cake_wallet/view_model/buy/buy_amount_view_model.dart';
|
||||||
|
@ -188,7 +201,6 @@ import 'package:cake_wallet/view_model/edit_backup_password_view_model.dart';
|
||||||
import 'package:cake_wallet/view_model/exchange/exchange_trade_view_model.dart';
|
import 'package:cake_wallet/view_model/exchange/exchange_trade_view_model.dart';
|
||||||
import 'package:cake_wallet/view_model/exchange/exchange_view_model.dart';
|
import 'package:cake_wallet/view_model/exchange/exchange_view_model.dart';
|
||||||
import 'package:cake_wallet/view_model/hardware_wallet/ledger_view_model.dart';
|
import 'package:cake_wallet/view_model/hardware_wallet/ledger_view_model.dart';
|
||||||
import 'package:cake_wallet/view_model/link_view_model.dart';
|
|
||||||
import 'package:cake_wallet/view_model/monero_account_list/account_list_item.dart';
|
import 'package:cake_wallet/view_model/monero_account_list/account_list_item.dart';
|
||||||
import 'package:cake_wallet/view_model/monero_account_list/monero_account_edit_or_create_view_model.dart';
|
import 'package:cake_wallet/view_model/monero_account_list/monero_account_edit_or_create_view_model.dart';
|
||||||
import 'package:cake_wallet/view_model/monero_account_list/monero_account_list_view_model.dart';
|
import 'package:cake_wallet/view_model/monero_account_list/monero_account_list_view_model.dart';
|
||||||
|
@ -217,8 +229,6 @@ import 'package:cake_wallet/view_model/wallet_restore_view_model.dart';
|
||||||
import 'package:cake_wallet/view_model/wallet_seed_view_model.dart';
|
import 'package:cake_wallet/view_model/wallet_seed_view_model.dart';
|
||||||
import 'package:cake_wallet/wownero/wownero.dart';
|
import 'package:cake_wallet/wownero/wownero.dart';
|
||||||
import 'package:cw_core/crypto_currency.dart';
|
import 'package:cw_core/crypto_currency.dart';
|
||||||
import 'package:cw_core/receive_page_option.dart';
|
|
||||||
import 'package:cw_core/wallet_info.dart';
|
|
||||||
import 'package:cw_core/wallet_type.dart';
|
import 'package:cw_core/wallet_type.dart';
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/widgets.dart';
|
import 'package:flutter/widgets.dart';
|
||||||
|
@ -376,17 +386,19 @@ Future<void> setup({
|
||||||
fiatConvertationStore: getIt.get<FiatConversionStore>()));
|
fiatConvertationStore: getIt.get<FiatConversionStore>()));
|
||||||
|
|
||||||
getIt.registerFactory(() => DashboardViewModel(
|
getIt.registerFactory(() => DashboardViewModel(
|
||||||
balanceViewModel: getIt.get<BalanceViewModel>(),
|
balanceViewModel: getIt.get<BalanceViewModel>(),
|
||||||
appStore: getIt.get<AppStore>(),
|
appStore: getIt.get<AppStore>(),
|
||||||
tradesStore: getIt.get<TradesStore>(),
|
tradesStore: getIt.get<TradesStore>(),
|
||||||
tradeFilterStore: getIt.get<TradeFilterStore>(),
|
tradeFilterStore: getIt.get<TradeFilterStore>(),
|
||||||
transactionFilterStore: getIt.get<TransactionFilterStore>(),
|
transactionFilterStore: getIt.get<TransactionFilterStore>(),
|
||||||
settingsStore: settingsStore,
|
settingsStore: settingsStore,
|
||||||
yatStore: getIt.get<YatStore>(),
|
yatStore: getIt.get<YatStore>(),
|
||||||
ordersStore: getIt.get<OrdersStore>(),
|
ordersStore: getIt.get<OrdersStore>(),
|
||||||
anonpayTransactionsStore: getIt.get<AnonpayTransactionsStore>(),
|
anonpayTransactionsStore: getIt.get<AnonpayTransactionsStore>(),
|
||||||
sharedPreferences: getIt.get<SharedPreferences>(),
|
sharedPreferences: getIt.get<SharedPreferences>(),
|
||||||
keyService: getIt.get<KeyService>()));
|
keyService: getIt.get<KeyService>(),
|
||||||
|
lightningViewModel: getIt.get<LightningViewModel>(),
|
||||||
|
));
|
||||||
|
|
||||||
getIt.registerFactory<AuthService>(
|
getIt.registerFactory<AuthService>(
|
||||||
() => AuthService(
|
() => AuthService(
|
||||||
|
@ -624,7 +636,6 @@ Future<void> setup({
|
||||||
authService: getIt.get<AuthService>(),
|
authService: getIt.get<AuthService>(),
|
||||||
initialPaymentRequest: initialPaymentRequest,
|
initialPaymentRequest: initialPaymentRequest,
|
||||||
));
|
));
|
||||||
|
|
||||||
getIt.registerFactory(
|
getIt.registerFactory(
|
||||||
() => SendTemplatePage(sendTemplateViewModel: getIt.get<SendTemplateViewModel>()));
|
() => SendTemplatePage(sendTemplateViewModel: getIt.get<SendTemplateViewModel>()));
|
||||||
|
|
||||||
|
@ -905,6 +916,8 @@ Future<void> setup({
|
||||||
return nano!.createNanoWalletService(_walletInfoSource);
|
return nano!.createNanoWalletService(_walletInfoSource);
|
||||||
case WalletType.polygon:
|
case WalletType.polygon:
|
||||||
return polygon!.createPolygonWalletService(_walletInfoSource);
|
return polygon!.createPolygonWalletService(_walletInfoSource);
|
||||||
|
case WalletType.lightning:
|
||||||
|
return lightning!.createLightningWalletService(_walletInfoSource, _unspentCoinsInfoSource);
|
||||||
case WalletType.solana:
|
case WalletType.solana:
|
||||||
return solana!.createSolanaWalletService(_walletInfoSource);
|
return solana!.createSolanaWalletService(_walletInfoSource);
|
||||||
case WalletType.tron:
|
case WalletType.tron:
|
||||||
|
@ -1192,5 +1205,62 @@ Future<void> setup({
|
||||||
getIt.registerFactory(() => NFTViewModel(appStore, getIt.get<BottomSheetService>()));
|
getIt.registerFactory(() => NFTViewModel(appStore, getIt.get<BottomSheetService>()));
|
||||||
getIt.registerFactory<TorPage>(() => TorPage(getIt.get<AppStore>()));
|
getIt.registerFactory<TorPage>(() => TorPage(getIt.get<AppStore>()));
|
||||||
|
|
||||||
|
getIt.registerFactory<LightningViewModel>(
|
||||||
|
() => LightningViewModel(),
|
||||||
|
);
|
||||||
|
|
||||||
|
getIt.registerFactory<LightningSendViewModel>(
|
||||||
|
() => LightningSendViewModel(
|
||||||
|
settingsStore: getIt.get<SettingsStore>(),
|
||||||
|
fiatConversionStore: getIt.get<FiatConversionStore>(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
getIt.registerFactoryParam<LightningInvoicePageViewModel, void, void>((_, __) {
|
||||||
|
return LightningInvoicePageViewModel(
|
||||||
|
getIt.get<SettingsStore>(),
|
||||||
|
getIt.get<AppStore>().wallet!,
|
||||||
|
getIt.get<SharedPreferences>(),
|
||||||
|
getIt.get<LightningViewModel>(),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
getIt.registerFactoryParam<LightningReceiveOnchainPage, void, void>((_, __) {
|
||||||
|
return LightningReceiveOnchainPage(
|
||||||
|
addressListViewModel: getIt.get<WalletAddressListViewModel>(),
|
||||||
|
lightningViewModel: getIt.get<LightningViewModel>(),
|
||||||
|
receiveOptionViewModel:
|
||||||
|
getIt.get<ReceiveOptionViewModel>(param1: lightning!.getOptionOnchain()),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
getIt.registerFactoryParam<LightningInvoicePage, void, void>((_, __) {
|
||||||
|
return LightningInvoicePage(
|
||||||
|
lightningInvoicePageViewModel: getIt.get<LightningInvoicePageViewModel>(),
|
||||||
|
receiveOptionViewModel:
|
||||||
|
getIt.get<ReceiveOptionViewModel>(param1: lightning!.getOptionInvoice()),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
getIt.registerFactory<LightningSendPage>(() {
|
||||||
|
return LightningSendPage(
|
||||||
|
output: Output(
|
||||||
|
getIt.get<AppStore>().wallet!,
|
||||||
|
getIt.get<SettingsStore>(),
|
||||||
|
getIt.get<FiatConversionStore>(),
|
||||||
|
() => CryptoCurrency.btcln,
|
||||||
|
),
|
||||||
|
authService: getIt.get<AuthService>(),
|
||||||
|
lightningSendViewModel: getIt.get<LightningSendViewModel>(),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
getIt.registerFactoryParam<LightningSendConfirmPage, LNInvoice, void>((LNInvoice invoice, _) {
|
||||||
|
return LightningSendConfirmPage(
|
||||||
|
invoice: invoice,
|
||||||
|
lightningSendViewModel: getIt.get<LightningSendViewModel>(),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
_isSetupFinished = true;
|
_isSetupFinished = true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
import 'package:cake_wallet/generated/i18n.dart';
|
import 'package:cake_wallet/generated/i18n.dart';
|
||||||
|
import 'package:cake_wallet/lightning/lightning.dart';
|
||||||
import 'package:cake_wallet/routes.dart';
|
import 'package:cake_wallet/routes.dart';
|
||||||
import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
|
import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
|
||||||
import 'package:cake_wallet/utils/show_pop_up.dart';
|
import 'package:cake_wallet/utils/show_pop_up.dart';
|
||||||
import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart';
|
import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart';
|
||||||
|
import 'package:cw_core/wallet_type.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
class MainActions {
|
class MainActions {
|
||||||
|
@ -11,8 +13,7 @@ class MainActions {
|
||||||
|
|
||||||
final bool Function(DashboardViewModel viewModel)? isEnabled;
|
final bool Function(DashboardViewModel viewModel)? isEnabled;
|
||||||
final bool Function(DashboardViewModel viewModel)? canShow;
|
final bool Function(DashboardViewModel viewModel)? canShow;
|
||||||
final Future<void> Function(
|
final Future<void> Function(BuildContext context, DashboardViewModel viewModel) onTap;
|
||||||
BuildContext context, DashboardViewModel viewModel) onTap;
|
|
||||||
|
|
||||||
MainActions._({
|
MainActions._({
|
||||||
required this.name,
|
required this.name,
|
||||||
|
@ -55,6 +56,10 @@ class MainActions {
|
||||||
name: (context) => S.of(context).receive,
|
name: (context) => S.of(context).receive,
|
||||||
image: 'assets/images/received.png',
|
image: 'assets/images/received.png',
|
||||||
onTap: (BuildContext context, DashboardViewModel viewModel) async {
|
onTap: (BuildContext context, DashboardViewModel viewModel) async {
|
||||||
|
if (viewModel.wallet.type == WalletType.lightning) {
|
||||||
|
Navigator.pushNamed(context, Routes.lightningInvoice);
|
||||||
|
return;
|
||||||
|
}
|
||||||
Navigator.pushNamed(context, Routes.addressPage);
|
Navigator.pushNamed(context, Routes.addressPage);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
@ -75,6 +80,10 @@ class MainActions {
|
||||||
name: (context) => S.of(context).send,
|
name: (context) => S.of(context).send,
|
||||||
image: 'assets/images/upload.png',
|
image: 'assets/images/upload.png',
|
||||||
onTap: (BuildContext context, DashboardViewModel viewModel) async {
|
onTap: (BuildContext context, DashboardViewModel viewModel) async {
|
||||||
|
if (viewModel.wallet.type == WalletType.lightning) {
|
||||||
|
Navigator.pushNamed(context, Routes.lightningSend);
|
||||||
|
return;
|
||||||
|
}
|
||||||
Navigator.pushNamed(context, Routes.send);
|
Navigator.pushNamed(context, Routes.send);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
@ -114,4 +123,4 @@ class MainActions {
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -78,6 +78,7 @@ class ProvidersHelper {
|
||||||
ProviderType.moonpay,
|
ProviderType.moonpay,
|
||||||
];
|
];
|
||||||
case WalletType.none:
|
case WalletType.none:
|
||||||
|
case WalletType.lightning:
|
||||||
case WalletType.haven:
|
case WalletType.haven:
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
@ -113,6 +114,7 @@ class ProvidersHelper {
|
||||||
case WalletType.monero:
|
case WalletType.monero:
|
||||||
case WalletType.nano:
|
case WalletType.nano:
|
||||||
case WalletType.banano:
|
case WalletType.banano:
|
||||||
|
case WalletType.lightning:
|
||||||
case WalletType.none:
|
case WalletType.none:
|
||||||
case WalletType.haven:
|
case WalletType.haven:
|
||||||
case WalletType.wownero:
|
case WalletType.wownero:
|
||||||
|
|
|
@ -11,6 +11,14 @@ import 'package:cake_wallet/exchange/utils/currency_pairs_utils.dart';
|
||||||
import 'package:cw_core/crypto_currency.dart';
|
import 'package:cw_core/crypto_currency.dart';
|
||||||
import 'package:http/http.dart';
|
import 'package:http/http.dart';
|
||||||
|
|
||||||
|
double lightningDoubleToBitcoinDouble({required double amount}) {
|
||||||
|
return amount / 100000000;
|
||||||
|
}
|
||||||
|
|
||||||
|
double bitcoinDoubleToLightningDouble({required double amount}) {
|
||||||
|
return amount * 100000000;
|
||||||
|
}
|
||||||
|
|
||||||
class TrocadorExchangeProvider extends ExchangeProvider {
|
class TrocadorExchangeProvider extends ExchangeProvider {
|
||||||
TrocadorExchangeProvider({this.useTorOnly = false, this.providerStates = const {}})
|
TrocadorExchangeProvider({this.useTorOnly = false, this.providerStates = const {}})
|
||||||
: _lastUsedRateId = '',
|
: _lastUsedRateId = '',
|
||||||
|
@ -106,6 +114,14 @@ class TrocadorExchangeProvider extends ExchangeProvider {
|
||||||
|
|
||||||
final coinJson = responseJSON.first as Map<String, dynamic>;
|
final coinJson = responseJSON.first as Map<String, dynamic>;
|
||||||
|
|
||||||
|
// trocador treats btcln as just bitcoin amounts:
|
||||||
|
if (from == CryptoCurrency.btcln) {
|
||||||
|
return Limits(
|
||||||
|
min: bitcoinDoubleToLightningDouble(amount: (coinJson['minimum'] as double)),
|
||||||
|
max: bitcoinDoubleToLightningDouble(amount: (coinJson['maximum'] as double)),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return Limits(
|
return Limits(
|
||||||
min: coinJson['minimum'] as double,
|
min: coinJson['minimum'] as double,
|
||||||
max: coinJson['maximum'] as double,
|
max: coinJson['maximum'] as double,
|
||||||
|
@ -122,14 +138,20 @@ class TrocadorExchangeProvider extends ExchangeProvider {
|
||||||
try {
|
try {
|
||||||
if (amount == 0) return 0.0;
|
if (amount == 0) return 0.0;
|
||||||
|
|
||||||
|
double amt = amount;
|
||||||
|
|
||||||
|
if (from == CryptoCurrency.btcln) {
|
||||||
|
amt = lightningDoubleToBitcoinDouble(amount: amount);
|
||||||
|
}
|
||||||
|
|
||||||
final params = <String, String>{
|
final params = <String, String>{
|
||||||
'api_key': apiKey,
|
'api_key': apiKey,
|
||||||
'ticker_from': _normalizeCurrency(from),
|
'ticker_from': _normalizeCurrency(from),
|
||||||
'ticker_to': _normalizeCurrency(to),
|
'ticker_to': _normalizeCurrency(to),
|
||||||
'network_from': _networkFor(from),
|
'network_from': _networkFor(from),
|
||||||
'network_to': _networkFor(to),
|
'network_to': _networkFor(to),
|
||||||
if (!isFixedRateMode) 'amount_from': amount.toString(),
|
if (!isFixedRateMode) 'amount_from': amt.toString(),
|
||||||
if (isFixedRateMode) 'amount_to': amount.toString(),
|
if (isFixedRateMode) 'amount_to': amt.toString(),
|
||||||
'payment': isFixedRateMode ? 'True' : 'False',
|
'payment': isFixedRateMode ? 'True' : 'False',
|
||||||
'min_kycrating': 'C',
|
'min_kycrating': 'C',
|
||||||
'markup': markup,
|
'markup': markup,
|
||||||
|
@ -160,6 +182,14 @@ class TrocadorExchangeProvider extends ExchangeProvider {
|
||||||
required bool isFixedRateMode,
|
required bool isFixedRateMode,
|
||||||
required bool isSendAll,
|
required bool isSendAll,
|
||||||
}) async {
|
}) async {
|
||||||
|
double fromAmt = double.parse(request.fromAmount);
|
||||||
|
double toAmt = double.parse(request.toAmount);
|
||||||
|
if (request.fromCurrency == CryptoCurrency.btcln) {
|
||||||
|
fromAmt = lightningDoubleToBitcoinDouble(amount: fromAmt);
|
||||||
|
}
|
||||||
|
if (request.toCurrency == CryptoCurrency.btcln) {
|
||||||
|
toAmt = lightningDoubleToBitcoinDouble(amount: toAmt);
|
||||||
|
}
|
||||||
final params = {
|
final params = {
|
||||||
'api_key': apiKey,
|
'api_key': apiKey,
|
||||||
'ticker_from': _normalizeCurrency(request.fromCurrency),
|
'ticker_from': _normalizeCurrency(request.fromCurrency),
|
||||||
|
@ -169,17 +199,22 @@ class TrocadorExchangeProvider extends ExchangeProvider {
|
||||||
'payment': isFixedRateMode ? 'True' : 'False',
|
'payment': isFixedRateMode ? 'True' : 'False',
|
||||||
'min_kycrating': 'C',
|
'min_kycrating': 'C',
|
||||||
'markup': markup,
|
'markup': markup,
|
||||||
if (!isFixedRateMode) 'amount_from': request.fromAmount,
|
if (!isFixedRateMode) 'amount_from': fromAmt.toString(),
|
||||||
if (isFixedRateMode) 'amount_to': request.toAmount,
|
if (isFixedRateMode) 'amount_to': toAmt.toString(),
|
||||||
'address': request.toAddress,
|
'address': request.toAddress,
|
||||||
'refund': request.refundAddress
|
'refund': request.refundAddress
|
||||||
};
|
};
|
||||||
|
|
||||||
|
double amt = double.tryParse(request.toAmount) ?? 0;
|
||||||
|
if (request.fromCurrency == CryptoCurrency.btcln) {
|
||||||
|
amt = lightningDoubleToBitcoinDouble(amount: amt);
|
||||||
|
}
|
||||||
|
|
||||||
if (isFixedRateMode) {
|
if (isFixedRateMode) {
|
||||||
await fetchRate(
|
await fetchRate(
|
||||||
from: request.fromCurrency,
|
from: request.fromCurrency,
|
||||||
to: request.toCurrency,
|
to: request.toCurrency,
|
||||||
amount: double.tryParse(request.toAmount) ?? 0,
|
amount: amt,
|
||||||
isFixedRateMode: true,
|
isFixedRateMode: true,
|
||||||
isReceiveAmount: true,
|
isReceiveAmount: true,
|
||||||
);
|
);
|
||||||
|
@ -225,6 +260,13 @@ class TrocadorExchangeProvider extends ExchangeProvider {
|
||||||
final providerId = responseJSON['id_provider'] as String;
|
final providerId = responseJSON['id_provider'] as String;
|
||||||
final providerName = responseJSON['provider'] as String;
|
final providerName = responseJSON['provider'] as String;
|
||||||
|
|
||||||
|
String? responseAmount = responseJSON['amount_from']?.toString();
|
||||||
|
if (request.fromCurrency == CryptoCurrency.btcln && responseAmount != null) {
|
||||||
|
responseAmount =
|
||||||
|
bitcoinDoubleToLightningDouble(amount: double.parse(responseAmount)).toString();
|
||||||
|
}
|
||||||
|
responseAmount ??= fromAmt.toString();
|
||||||
|
|
||||||
return Trade(
|
return Trade(
|
||||||
id: id,
|
id: id,
|
||||||
from: request.fromCurrency,
|
from: request.fromCurrency,
|
||||||
|
@ -237,7 +279,7 @@ class TrocadorExchangeProvider extends ExchangeProvider {
|
||||||
providerId: providerId,
|
providerId: providerId,
|
||||||
providerName: providerName,
|
providerName: providerName,
|
||||||
createdAt: DateTime.tryParse(date)?.toLocal(),
|
createdAt: DateTime.tryParse(date)?.toLocal(),
|
||||||
amount: responseJSON['amount_from']?.toString() ?? request.fromAmount,
|
amount: responseAmount,
|
||||||
payoutAddress: payoutAddress,
|
payoutAddress: payoutAddress,
|
||||||
isSendAll: isSendAll);
|
isSendAll: isSendAll);
|
||||||
}
|
}
|
||||||
|
@ -290,6 +332,8 @@ class TrocadorExchangeProvider extends ExchangeProvider {
|
||||||
return 'MATIC';
|
return 'MATIC';
|
||||||
case CryptoCurrency.zec:
|
case CryptoCurrency.zec:
|
||||||
return 'Mainnet';
|
return 'Mainnet';
|
||||||
|
case CryptoCurrency.btcln:
|
||||||
|
return 'Lightning';
|
||||||
default:
|
default:
|
||||||
return currency.tag != null ? _normalizeTag(currency.tag!) : 'Mainnet';
|
return currency.tag != null ? _normalizeTag(currency.tag!) : 'Mainnet';
|
||||||
}
|
}
|
||||||
|
@ -301,6 +345,8 @@ class TrocadorExchangeProvider extends ExchangeProvider {
|
||||||
return 'zec';
|
return 'zec';
|
||||||
case CryptoCurrency.usdcEPoly:
|
case CryptoCurrency.usdcEPoly:
|
||||||
return 'usdce';
|
return 'usdce';
|
||||||
|
case CryptoCurrency.btcln:
|
||||||
|
return 'btc';
|
||||||
default:
|
default:
|
||||||
return currency.title.toLowerCase();
|
return currency.title.toLowerCase();
|
||||||
}
|
}
|
||||||
|
|
69
lib/lightning/cw_lightning.dart
Normal file
69
lib/lightning/cw_lightning.dart
Normal file
|
@ -0,0 +1,69 @@
|
||||||
|
part of 'lightning.dart';
|
||||||
|
|
||||||
|
class CWLightning extends Lightning {
|
||||||
|
|
||||||
|
@override
|
||||||
|
String formatterLightningAmountToString({required int amount}) =>
|
||||||
|
bitcoinAmountToString(amount: amount * 100000000);
|
||||||
|
|
||||||
|
@override
|
||||||
|
double formatterLightningAmountToDouble({required int amount}) =>
|
||||||
|
bitcoinAmountToDouble(amount: amount * 100000000);
|
||||||
|
|
||||||
|
@override
|
||||||
|
int formatterStringDoubleToLightningAmount(String amount) =>
|
||||||
|
stringDoubleToBitcoinAmount(amount * 100000000);
|
||||||
|
|
||||||
|
WalletService createLightningWalletService(
|
||||||
|
Box<WalletInfo> walletInfoSource, Box<UnspentCoinsInfo> unspentCoinSource) {
|
||||||
|
return LightningWalletService(walletInfoSource, unspentCoinSource);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<LightningReceivePageOption> getLightningReceivePageOptions() =>
|
||||||
|
LightningReceivePageOption.all;
|
||||||
|
|
||||||
|
@override
|
||||||
|
ReceivePageOption getOptionInvoice() => LightningReceivePageOption.lightningInvoice;
|
||||||
|
|
||||||
|
@override
|
||||||
|
ReceivePageOption getOptionOnchain() => LightningReceivePageOption.lightningOnchain;
|
||||||
|
|
||||||
|
@override
|
||||||
|
String satsToLightningString(int sats) {
|
||||||
|
const bitcoinAmountLength = 8;
|
||||||
|
const bitcoinAmountDivider = 100000000;
|
||||||
|
const lightningAmountDivider = 1;
|
||||||
|
final bitcoinAmountFormat = NumberFormat()
|
||||||
|
..maximumFractionDigits = bitcoinAmountLength
|
||||||
|
..minimumFractionDigits = 1;
|
||||||
|
|
||||||
|
String formattedAmount = bitcoinAmountFormat.format(sats);
|
||||||
|
return formattedAmount.substring(0, formattedAmount.length - 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String bitcoinAmountToLightningString({required int amount}) {
|
||||||
|
final bitcoinAmountFormat = NumberFormat()
|
||||||
|
..maximumFractionDigits = bitcoinAmountLength
|
||||||
|
..minimumFractionDigits = 1;
|
||||||
|
String formattedAmount =
|
||||||
|
bitcoinAmountFormat.format(cryptoAmountToDouble(amount: amount, divider: 1));
|
||||||
|
return formattedAmount.substring(0, formattedAmount.length - 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
int bitcoinAmountToLightningAmount({required int amount}) {
|
||||||
|
return amount * 100000000;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
double bitcoinDoubleToLightningDouble({required double amount}) {
|
||||||
|
return amount * 100000000;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
double lightningDoubleToBitcoinDouble({required double amount}) {
|
||||||
|
return amount / 100000000;
|
||||||
|
}
|
||||||
|
}
|
|
@ -30,46 +30,49 @@ Future<void> startFiatRateUpdate(
|
||||||
|
|
||||||
if (appStore.wallet!.type == WalletType.haven) {
|
if (appStore.wallet!.type == WalletType.haven) {
|
||||||
await updateHavenRate(fiatConversionStore);
|
await updateHavenRate(fiatConversionStore);
|
||||||
} else {
|
return;
|
||||||
fiatConversionStore.prices[appStore.wallet!.currency] =
|
|
||||||
await FiatConversionService.fetchPrice(
|
|
||||||
crypto: appStore.wallet!.currency,
|
|
||||||
fiat: settingsStore.fiatCurrency,
|
|
||||||
torOnly: settingsStore.fiatApiMode == FiatApiMode.torOnly);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Iterable<CryptoCurrency>? currencies;
|
Iterable<CryptoCurrency>? currencies = [];
|
||||||
if (appStore.wallet!.type == WalletType.ethereum) {
|
switch (appStore.wallet!.type) {
|
||||||
currencies =
|
case WalletType.ethereum:
|
||||||
ethereum!.getERC20Currencies(appStore.wallet!).where((element) => element.enabled);
|
currencies =
|
||||||
|
ethereum!.getERC20Currencies(appStore.wallet!).where((element) => element.enabled);
|
||||||
|
break;
|
||||||
|
case WalletType.polygon:
|
||||||
|
currencies =
|
||||||
|
polygon!.getERC20Currencies(appStore.wallet!).where((element) => element.enabled);
|
||||||
|
break;
|
||||||
|
case WalletType.solana:
|
||||||
|
currencies =
|
||||||
|
solana!.getSPLTokenCurrencies(appStore.wallet!).where((element) => element.enabled);
|
||||||
|
break;
|
||||||
|
case WalletType.tron:
|
||||||
|
currencies =
|
||||||
|
tron!.getTronTokenCurrencies(appStore.wallet!).where((element) => element.enabled);
|
||||||
|
break;
|
||||||
|
case WalletType.lightning:
|
||||||
|
currencies = [CryptoCurrency.btc];
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
currencies = [appStore.wallet!.currency];
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (appStore.wallet!.type == WalletType.polygon) {
|
for (final currency in currencies) {
|
||||||
currencies =
|
() async {
|
||||||
polygon!.getERC20Currencies(appStore.wallet!).where((element) => element.enabled);
|
fiatConversionStore.prices[currency] = await FiatConversionService.fetchPrice(
|
||||||
|
crypto: currency,
|
||||||
|
fiat: settingsStore.fiatCurrency,
|
||||||
|
torOnly: settingsStore.fiatApiMode == FiatApiMode.torOnly,
|
||||||
|
);
|
||||||
|
}.call();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (appStore.wallet!.type == WalletType.solana) {
|
// keep btcln price in sync with btc (since the fiat api only returns btc and not btcln)
|
||||||
currencies =
|
// (btcln price is just the btc price divided by 100000000)
|
||||||
solana!.getSPLTokenCurrencies(appStore.wallet!).where((element) => element.enabled);
|
fiatConversionStore.prices[CryptoCurrency.btcln] =
|
||||||
}
|
(fiatConversionStore.prices[CryptoCurrency.btc] ?? 0) / 100000000;
|
||||||
|
|
||||||
if (appStore.wallet!.type == WalletType.tron) {
|
|
||||||
currencies =
|
|
||||||
tron!.getTronTokenCurrencies(appStore.wallet!).where((element) => element.enabled);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (currencies != null) {
|
|
||||||
for (final currency in currencies) {
|
|
||||||
() async {
|
|
||||||
fiatConversionStore.prices[currency] = await FiatConversionService.fetchPrice(
|
|
||||||
crypto: currency,
|
|
||||||
fiat: settingsStore.fiatCurrency,
|
|
||||||
torOnly: settingsStore.fiatApiMode == FiatApiMode.torOnly);
|
|
||||||
}.call();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print(e);
|
print(e);
|
||||||
}
|
}
|
||||||
|
|
|
@ -73,7 +73,8 @@ void startCurrentWalletChangeReaction(
|
||||||
if (wallet.type == WalletType.monero ||
|
if (wallet.type == WalletType.monero ||
|
||||||
wallet.type == WalletType.bitcoin ||
|
wallet.type == WalletType.bitcoin ||
|
||||||
wallet.type == WalletType.litecoin ||
|
wallet.type == WalletType.litecoin ||
|
||||||
wallet.type == WalletType.bitcoinCash) {
|
wallet.type == WalletType.bitcoinCash ||
|
||||||
|
wallet.type == WalletType.lightning) {
|
||||||
_setAutoGenerateSubaddressStatus(wallet, settingsStore);
|
_setAutoGenerateSubaddressStatus(wallet, settingsStore);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -42,6 +42,9 @@ import 'package:cake_wallet/src/screens/new_wallet/new_wallet_page.dart';
|
||||||
import 'package:cake_wallet/src/screens/new_wallet/new_wallet_type_page.dart';
|
import 'package:cake_wallet/src/screens/new_wallet/new_wallet_type_page.dart';
|
||||||
import 'package:cake_wallet/src/screens/nodes/node_create_or_edit_page.dart';
|
import 'package:cake_wallet/src/screens/nodes/node_create_or_edit_page.dart';
|
||||||
import 'package:cake_wallet/src/screens/nodes/pow_node_create_or_edit_page.dart';
|
import 'package:cake_wallet/src/screens/nodes/pow_node_create_or_edit_page.dart';
|
||||||
|
import 'package:cake_wallet/src/screens/receive/lightning_invoice_page.dart';
|
||||||
|
import 'package:cake_wallet/src/screens/receive/lightning_receive_page.dart';
|
||||||
|
import 'package:cake_wallet/src/screens/restore/sweeping_wallet_page.dart';
|
||||||
import 'package:cake_wallet/src/screens/order_details/order_details_page.dart';
|
import 'package:cake_wallet/src/screens/order_details/order_details_page.dart';
|
||||||
import 'package:cake_wallet/src/screens/pin_code/pin_code_widget.dart';
|
import 'package:cake_wallet/src/screens/pin_code/pin_code_widget.dart';
|
||||||
import 'package:cake_wallet/src/screens/receive/anonpay_invoice_page.dart';
|
import 'package:cake_wallet/src/screens/receive/anonpay_invoice_page.dart';
|
||||||
|
@ -53,6 +56,8 @@ import 'package:cake_wallet/src/screens/restore/restore_from_backup_page.dart';
|
||||||
import 'package:cake_wallet/src/screens/restore/restore_options_page.dart';
|
import 'package:cake_wallet/src/screens/restore/restore_options_page.dart';
|
||||||
import 'package:cake_wallet/src/screens/restore/sweeping_wallet_page.dart';
|
import 'package:cake_wallet/src/screens/restore/sweeping_wallet_page.dart';
|
||||||
import 'package:cake_wallet/src/screens/restore/wallet_restore_choose_derivation.dart';
|
import 'package:cake_wallet/src/screens/restore/wallet_restore_choose_derivation.dart';
|
||||||
|
import 'package:cake_wallet/src/screens/send/lightning_send_confirm_page.dart';
|
||||||
|
import 'package:cake_wallet/src/screens/send/lightning_send_page.dart';
|
||||||
import 'package:cake_wallet/src/screens/restore/wallet_restore_page.dart';
|
import 'package:cake_wallet/src/screens/restore/wallet_restore_page.dart';
|
||||||
import 'package:cake_wallet/src/screens/seed/pre_seed_page.dart';
|
import 'package:cake_wallet/src/screens/seed/pre_seed_page.dart';
|
||||||
import 'package:cake_wallet/src/screens/seed/wallet_seed_page.dart';
|
import 'package:cake_wallet/src/screens/seed/wallet_seed_page.dart';
|
||||||
|
@ -651,6 +656,25 @@ Route<dynamic> createRoute(RouteSettings settings) {
|
||||||
case Routes.torPage:
|
case Routes.torPage:
|
||||||
return MaterialPageRoute<void>(builder: (_) => getIt.get<TorPage>());
|
return MaterialPageRoute<void>(builder: (_) => getIt.get<TorPage>());
|
||||||
|
|
||||||
|
case Routes.lightningSend:
|
||||||
|
return CupertinoPageRoute<void>(
|
||||||
|
fullscreenDialog: true, builder: (_) => getIt.get<LightningSendPage>());
|
||||||
|
|
||||||
|
case Routes.lightningSendConfirm:
|
||||||
|
return CupertinoPageRoute<void>(
|
||||||
|
fullscreenDialog: true,
|
||||||
|
builder: (_) => getIt.get<LightningSendConfirmPage>(param1: settings.arguments));
|
||||||
|
|
||||||
|
case Routes.lightningReceiveOnchain:
|
||||||
|
final args = settings.arguments as List;
|
||||||
|
return CupertinoPageRoute<void>(
|
||||||
|
fullscreenDialog: true,
|
||||||
|
builder: (_) => getIt.get<LightningReceiveOnchainPage>(param1: args));
|
||||||
|
|
||||||
|
case Routes.lightningInvoice:
|
||||||
|
return CupertinoPageRoute<void>(
|
||||||
|
fullscreenDialog: true, builder: (_) => getIt.get<LightningInvoicePage>());
|
||||||
|
|
||||||
case Routes.connectDevices:
|
case Routes.connectDevices:
|
||||||
final params = settings.arguments as ConnectDevicePageParams;
|
final params = settings.arguments as ConnectDevicePageParams;
|
||||||
return MaterialPageRoute<void>(
|
return MaterialPageRoute<void>(
|
||||||
|
|
|
@ -101,5 +101,10 @@ class Routes {
|
||||||
static const nftDetailsPage = '/nft_details_page';
|
static const nftDetailsPage = '/nft_details_page';
|
||||||
static const importNFTPage = '/import_nft_page';
|
static const importNFTPage = '/import_nft_page';
|
||||||
static const torPage = '/tor_page';
|
static const torPage = '/tor_page';
|
||||||
|
static const lightningSend = '/lightning_send';
|
||||||
|
static const lightningSendConfirm = '/lightning_send_confirm';
|
||||||
|
static const lightningInvoice = '/lightning_invoice';
|
||||||
|
static const lightningReceiveOnchain = '/lightning_receive_onchain';
|
||||||
|
static const lightningSettings = '/lightning_settings';
|
||||||
static const connectDevices = '/device/connect';
|
static const connectDevices = '/device/connect';
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,6 +30,7 @@ class DesktopWalletSelectionDropDown extends StatefulWidget {
|
||||||
class _DesktopWalletSelectionDropDownState extends State<DesktopWalletSelectionDropDown> {
|
class _DesktopWalletSelectionDropDownState extends State<DesktopWalletSelectionDropDown> {
|
||||||
final moneroIcon = Image.asset('assets/images/monero_logo.png', height: 24, width: 24);
|
final moneroIcon = Image.asset('assets/images/monero_logo.png', height: 24, width: 24);
|
||||||
final bitcoinIcon = Image.asset('assets/images/bitcoin.png', height: 24, width: 24);
|
final bitcoinIcon = Image.asset('assets/images/bitcoin.png', height: 24, width: 24);
|
||||||
|
final lightningIcon = Image.asset('assets/images/lightning_logo.png', height: 24, width: 24);
|
||||||
final tBitcoinIcon = Image.asset('assets/images/tbtc.png', height: 24, width: 24);
|
final tBitcoinIcon = Image.asset('assets/images/tbtc.png', height: 24, width: 24);
|
||||||
final litecoinIcon = Image.asset('assets/images/litecoin_icon.png', height: 24, width: 24);
|
final litecoinIcon = Image.asset('assets/images/litecoin_icon.png', height: 24, width: 24);
|
||||||
final havenIcon = Image.asset('assets/images/haven_logo.png', height: 24, width: 24);
|
final havenIcon = Image.asset('assets/images/haven_logo.png', height: 24, width: 24);
|
||||||
|
@ -150,6 +151,8 @@ class _DesktopWalletSelectionDropDownState extends State<DesktopWalletSelectionD
|
||||||
return tBitcoinIcon;
|
return tBitcoinIcon;
|
||||||
}
|
}
|
||||||
return bitcoinIcon;
|
return bitcoinIcon;
|
||||||
|
case WalletType.lightning:
|
||||||
|
return lightningIcon;
|
||||||
case WalletType.monero:
|
case WalletType.monero:
|
||||||
return moneroIcon;
|
return moneroIcon;
|
||||||
case WalletType.litecoin:
|
case WalletType.litecoin:
|
||||||
|
|
|
@ -186,6 +186,20 @@ class CryptoBalanceWidget extends StatelessWidget {
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
)),
|
)),
|
||||||
|
Observer(builder: (_) {
|
||||||
|
final serviceMessage = dashboardViewModel.serviceMessage;
|
||||||
|
if (serviceMessage.isEmpty) {
|
||||||
|
return const SizedBox();
|
||||||
|
}
|
||||||
|
return Padding(
|
||||||
|
padding: const EdgeInsets.fromLTRB(16, 0, 16, 8),
|
||||||
|
child: DashBoardRoundedCardWidget(
|
||||||
|
onTap: () => null,
|
||||||
|
title: S.of(context).warning,
|
||||||
|
subTitle: serviceMessage,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}),
|
||||||
Observer(
|
Observer(
|
||||||
builder: (_) {
|
builder: (_) {
|
||||||
if (dashboardViewModel.balanceViewModel.isShowCard &&
|
if (dashboardViewModel.balanceViewModel.isShowCard &&
|
||||||
|
|
|
@ -28,6 +28,7 @@ class MenuWidgetState extends State<MenuWidget> {
|
||||||
this.fromBottomEdge = 25,
|
this.fromBottomEdge = 25,
|
||||||
this.moneroIcon = Image.asset('assets/images/monero_menu.png'),
|
this.moneroIcon = Image.asset('assets/images/monero_menu.png'),
|
||||||
this.bitcoinIcon = Image.asset('assets/images/bitcoin_menu.png'),
|
this.bitcoinIcon = Image.asset('assets/images/bitcoin_menu.png'),
|
||||||
|
this.lightningIcon = Image.asset('assets/images/lightning_logo.png'),
|
||||||
this.litecoinIcon = Image.asset('assets/images/litecoin_menu.png'),
|
this.litecoinIcon = Image.asset('assets/images/litecoin_menu.png'),
|
||||||
this.havenIcon = Image.asset('assets/images/haven_menu.png'),
|
this.havenIcon = Image.asset('assets/images/haven_menu.png'),
|
||||||
this.ethereumIcon = Image.asset('assets/images/eth_icon.png'),
|
this.ethereumIcon = Image.asset('assets/images/eth_icon.png'),
|
||||||
|
@ -52,6 +53,7 @@ class MenuWidgetState extends State<MenuWidget> {
|
||||||
|
|
||||||
Image moneroIcon;
|
Image moneroIcon;
|
||||||
Image bitcoinIcon;
|
Image bitcoinIcon;
|
||||||
|
Image lightningIcon;
|
||||||
Image litecoinIcon;
|
Image litecoinIcon;
|
||||||
Image havenIcon;
|
Image havenIcon;
|
||||||
Image ethereumIcon;
|
Image ethereumIcon;
|
||||||
|
@ -103,6 +105,7 @@ class MenuWidgetState extends State<MenuWidget> {
|
||||||
color: Theme.of(context).extension<CakeMenuTheme>()!.iconColor);
|
color: Theme.of(context).extension<CakeMenuTheme>()!.iconColor);
|
||||||
bitcoinIcon = Image.asset('assets/images/bitcoin_menu.png',
|
bitcoinIcon = Image.asset('assets/images/bitcoin_menu.png',
|
||||||
color: Theme.of(context).extension<CakeMenuTheme>()!.iconColor);
|
color: Theme.of(context).extension<CakeMenuTheme>()!.iconColor);
|
||||||
|
lightningIcon = Image.asset('assets/images/lightning_logo.png');
|
||||||
|
|
||||||
return Row(
|
return Row(
|
||||||
mainAxisSize: MainAxisSize.max,
|
mainAxisSize: MainAxisSize.max,
|
||||||
|
@ -220,6 +223,8 @@ class MenuWidgetState extends State<MenuWidget> {
|
||||||
return moneroIcon;
|
return moneroIcon;
|
||||||
case WalletType.bitcoin:
|
case WalletType.bitcoin:
|
||||||
return bitcoinIcon;
|
return bitcoinIcon;
|
||||||
|
case WalletType.lightning:
|
||||||
|
return lightningIcon;
|
||||||
case WalletType.litecoin:
|
case WalletType.litecoin:
|
||||||
return litecoinIcon;
|
return litecoinIcon;
|
||||||
case WalletType.haven:
|
case WalletType.haven:
|
||||||
|
|
|
@ -638,6 +638,7 @@ class ExchangePage extends BasePage {
|
||||||
initialIsAddressEditable: exchangeViewModel.isDepositAddressEnabled,
|
initialIsAddressEditable: exchangeViewModel.isDepositAddressEnabled,
|
||||||
isAmountEstimated: false,
|
isAmountEstimated: false,
|
||||||
hasRefundAddress: true,
|
hasRefundAddress: true,
|
||||||
|
hasAddress: exchangeViewModel.hasAddress,
|
||||||
isMoneroWallet: exchangeViewModel.isMoneroWallet,
|
isMoneroWallet: exchangeViewModel.isMoneroWallet,
|
||||||
currencies: exchangeViewModel.depositCurrencies,
|
currencies: exchangeViewModel.depositCurrencies,
|
||||||
onCurrencySelected: (currency) {
|
onCurrencySelected: (currency) {
|
||||||
|
|
|
@ -33,6 +33,7 @@ class ExchangeCard extends StatefulWidget {
|
||||||
this.title = '',
|
this.title = '',
|
||||||
this.initialIsAddressEditable = true,
|
this.initialIsAddressEditable = true,
|
||||||
this.hasRefundAddress = false,
|
this.hasRefundAddress = false,
|
||||||
|
this.hasAddress = true,
|
||||||
this.isMoneroWallet = false,
|
this.isMoneroWallet = false,
|
||||||
this.currencyButtonColor = Colors.transparent,
|
this.currencyButtonColor = Colors.transparent,
|
||||||
this.addressButtonsColor = Colors.transparent,
|
this.addressButtonsColor = Colors.transparent,
|
||||||
|
@ -57,6 +58,7 @@ class ExchangeCard extends StatefulWidget {
|
||||||
final bool initialIsAddressEditable;
|
final bool initialIsAddressEditable;
|
||||||
final bool isAmountEstimated;
|
final bool isAmountEstimated;
|
||||||
final bool hasRefundAddress;
|
final bool hasRefundAddress;
|
||||||
|
final bool hasAddress;
|
||||||
final bool isMoneroWallet;
|
final bool isMoneroWallet;
|
||||||
final Image imageArrow;
|
final Image imageArrow;
|
||||||
final Color currencyButtonColor;
|
final Color currencyButtonColor;
|
||||||
|
@ -272,9 +274,7 @@ class ExchangeCardState extends State<ExchangeCard> {
|
||||||
color: Theme.of(context)
|
color: Theme.of(context)
|
||||||
.extension<ExchangePageTheme>()!
|
.extension<ExchangePageTheme>()!
|
||||||
.hintTextColor),
|
.hintTextColor),
|
||||||
validator: _isAmountEditable
|
validator: _isAmountEditable ? widget.currencyValueValidator : null),
|
||||||
? widget.currencyValueValidator
|
|
||||||
: null),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
if (widget.hasAllAmount)
|
if (widget.hasAllAmount)
|
||||||
|
@ -330,138 +330,142 @@ class ExchangeCardState extends State<ExchangeCard> {
|
||||||
: Offstage(),
|
: Offstage(),
|
||||||
])),
|
])),
|
||||||
),
|
),
|
||||||
!_isAddressEditable && widget.hasRefundAddress
|
if (widget.hasAddress) ...[
|
||||||
? Padding(
|
!_isAddressEditable && widget.hasRefundAddress
|
||||||
padding: EdgeInsets.only(top: 20),
|
? Padding(
|
||||||
child: Text(
|
|
||||||
S.of(context).refund_address,
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 14,
|
|
||||||
fontWeight: FontWeight.w500,
|
|
||||||
color: Theme.of(context).extension<ExchangePageTheme>()!.hintTextColor),
|
|
||||||
))
|
|
||||||
: Offstage(),
|
|
||||||
_isAddressEditable
|
|
||||||
? FocusTraversalOrder(
|
|
||||||
order: NumericFocusOrder(2),
|
|
||||||
child: Padding(
|
|
||||||
padding: EdgeInsets.only(top: 20),
|
padding: EdgeInsets.only(top: 20),
|
||||||
child: AddressTextField(
|
child: Text(
|
||||||
focusNode: widget.addressFocusNode,
|
S.of(context).refund_address,
|
||||||
controller: addressController,
|
style: TextStyle(
|
||||||
onURIScanned: (uri) {
|
fontSize: 14,
|
||||||
final paymentRequest = PaymentRequest.fromUri(uri);
|
fontWeight: FontWeight.w500,
|
||||||
addressController.text = paymentRequest.address;
|
color: Theme.of(context).extension<ExchangePageTheme>()!.hintTextColor),
|
||||||
|
))
|
||||||
|
: Offstage(),
|
||||||
|
_isAddressEditable
|
||||||
|
? FocusTraversalOrder(
|
||||||
|
order: NumericFocusOrder(2),
|
||||||
|
child: Padding(
|
||||||
|
padding: EdgeInsets.only(top: 20),
|
||||||
|
child: AddressTextField(
|
||||||
|
focusNode: widget.addressFocusNode,
|
||||||
|
controller: addressController,
|
||||||
|
onURIScanned: (uri) {
|
||||||
|
final paymentRequest = PaymentRequest.fromUri(uri);
|
||||||
|
addressController.text = paymentRequest.address;
|
||||||
|
|
||||||
if (amountController.text.isNotEmpty) {
|
if (amountController.text.isNotEmpty) {
|
||||||
_showAmountPopup(context, paymentRequest);
|
_showAmountPopup(context, paymentRequest);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
widget.amountFocusNode?.requestFocus();
|
widget.amountFocusNode?.requestFocus();
|
||||||
amountController.text = paymentRequest.amount;
|
amountController.text = paymentRequest.amount;
|
||||||
},
|
},
|
||||||
placeholder: widget.hasRefundAddress ? S.of(context).refund_address : null,
|
placeholder: widget.hasRefundAddress ? S.of(context).refund_address : null,
|
||||||
options: [
|
options: [
|
||||||
AddressTextFieldOption.paste,
|
AddressTextFieldOption.paste,
|
||||||
AddressTextFieldOption.qrCode,
|
AddressTextFieldOption.qrCode,
|
||||||
AddressTextFieldOption.addressBook,
|
AddressTextFieldOption.addressBook,
|
||||||
],
|
],
|
||||||
isBorderExist: false,
|
isBorderExist: false,
|
||||||
textStyle:
|
textStyle: TextStyle(
|
||||||
TextStyle(fontSize: 16, fontWeight: FontWeight.w600, color: Colors.white),
|
fontSize: 16, fontWeight: FontWeight.w600, color: Colors.white),
|
||||||
hintStyle: TextStyle(
|
hintStyle: TextStyle(
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
fontWeight: FontWeight.w600,
|
fontWeight: FontWeight.w600,
|
||||||
color: Theme.of(context).extension<ExchangePageTheme>()!.hintTextColor),
|
color: Theme.of(context).extension<ExchangePageTheme>()!.hintTextColor),
|
||||||
buttonColor: widget.addressButtonsColor,
|
buttonColor: widget.addressButtonsColor,
|
||||||
validator: widget.addressTextFieldValidator,
|
validator: widget.addressTextFieldValidator,
|
||||||
onPushPasteButton: widget.onPushPasteButton,
|
onPushPasteButton: widget.onPushPasteButton,
|
||||||
onPushAddressBookButton: widget.onPushAddressBookButton,
|
onPushAddressBookButton: widget.onPushAddressBookButton,
|
||||||
selectedCurrency: _selectedCurrency),
|
selectedCurrency: _selectedCurrency),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
: Padding(
|
: Padding(
|
||||||
padding: EdgeInsets.only(top: 10),
|
padding: EdgeInsets.only(top: 10),
|
||||||
child: Builder(
|
child: Builder(
|
||||||
builder: (context) => Stack(children: <Widget>[
|
builder: (context) => Stack(children: <Widget>[
|
||||||
FocusTraversalOrder(
|
FocusTraversalOrder(
|
||||||
order: NumericFocusOrder(3),
|
order: NumericFocusOrder(3),
|
||||||
child: BaseTextFormField(
|
child: BaseTextFormField(
|
||||||
controller: addressController,
|
controller: addressController,
|
||||||
borderColor: Colors.transparent,
|
borderColor: Colors.transparent,
|
||||||
suffixIcon: SizedBox(width: _isMoneroWallet ? 80 : 36),
|
suffixIcon: SizedBox(width: _isMoneroWallet ? 80 : 36),
|
||||||
textStyle: TextStyle(
|
textStyle: TextStyle(
|
||||||
fontSize: 16, fontWeight: FontWeight.w600, color: Colors.white),
|
fontSize: 16,
|
||||||
validator: widget.addressTextFieldValidator),
|
fontWeight: FontWeight.w600,
|
||||||
),
|
color: Colors.white),
|
||||||
Positioned(
|
validator: widget.addressTextFieldValidator),
|
||||||
top: 2,
|
),
|
||||||
right: 0,
|
Positioned(
|
||||||
child: SizedBox(
|
top: 2,
|
||||||
width: _isMoneroWallet ? 80 : 36,
|
right: 0,
|
||||||
child: Row(children: <Widget>[
|
child: SizedBox(
|
||||||
if (_isMoneroWallet)
|
width: _isMoneroWallet ? 80 : 36,
|
||||||
|
child: Row(children: <Widget>[
|
||||||
|
if (_isMoneroWallet)
|
||||||
|
Padding(
|
||||||
|
padding: EdgeInsets.only(left: 10),
|
||||||
|
child: Container(
|
||||||
|
width: 34,
|
||||||
|
height: 34,
|
||||||
|
padding: EdgeInsets.only(top: 0),
|
||||||
|
child: Semantics(
|
||||||
|
label: S.of(context).address_book,
|
||||||
|
child: InkWell(
|
||||||
|
onTap: () async {
|
||||||
|
final contact =
|
||||||
|
await Navigator.of(context).pushNamed(
|
||||||
|
Routes.pickerAddressBook,
|
||||||
|
arguments: widget.initialCurrency,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (contact is ContactBase) {
|
||||||
|
setState(() =>
|
||||||
|
addressController.text = contact.address);
|
||||||
|
widget.onPushAddressBookButton?.call(context);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
child: Container(
|
||||||
|
padding: EdgeInsets.all(8),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: widget.addressButtonsColor,
|
||||||
|
borderRadius:
|
||||||
|
BorderRadius.all(Radius.circular(6))),
|
||||||
|
child: Image.asset(
|
||||||
|
'assets/images/open_book.png',
|
||||||
|
color: Theme.of(context)
|
||||||
|
.extension<SendPageTheme>()!
|
||||||
|
.textFieldButtonIconColor,
|
||||||
|
)),
|
||||||
|
),
|
||||||
|
)),
|
||||||
|
),
|
||||||
Padding(
|
Padding(
|
||||||
padding: EdgeInsets.only(left: 10),
|
padding: EdgeInsets.only(left: 2),
|
||||||
child: Container(
|
child: Container(
|
||||||
width: 34,
|
width: 34,
|
||||||
height: 34,
|
height: 34,
|
||||||
padding: EdgeInsets.only(top: 0),
|
padding: EdgeInsets.only(top: 0),
|
||||||
child: Semantics(
|
child: Semantics(
|
||||||
label: S.of(context).address_book,
|
label: S.of(context).copy_address,
|
||||||
child: InkWell(
|
child: InkWell(
|
||||||
onTap: () async {
|
onTap: () {
|
||||||
final contact =
|
Clipboard.setData(ClipboardData(
|
||||||
await Navigator.of(context).pushNamed(
|
text: addressController.text));
|
||||||
Routes.pickerAddressBook,
|
showBar<void>(
|
||||||
arguments: widget.initialCurrency,
|
context, S.of(context).copied_to_clipboard);
|
||||||
);
|
},
|
||||||
|
child: Container(
|
||||||
if (contact is ContactBase) {
|
padding: EdgeInsets.fromLTRB(8, 8, 0, 8),
|
||||||
setState(() =>
|
color: Colors.transparent,
|
||||||
addressController.text = contact.address);
|
child: copyImage),
|
||||||
widget.onPushAddressBookButton?.call(context);
|
),
|
||||||
}
|
)))
|
||||||
},
|
])))
|
||||||
child: Container(
|
])),
|
||||||
padding: EdgeInsets.all(8),
|
),
|
||||||
decoration: BoxDecoration(
|
],
|
||||||
color: widget.addressButtonsColor,
|
|
||||||
borderRadius:
|
|
||||||
BorderRadius.all(Radius.circular(6))),
|
|
||||||
child: Image.asset(
|
|
||||||
'assets/images/open_book.png',
|
|
||||||
color: Theme.of(context)
|
|
||||||
.extension<SendPageTheme>()!
|
|
||||||
.textFieldButtonIconColor,
|
|
||||||
)),
|
|
||||||
),
|
|
||||||
)),
|
|
||||||
),
|
|
||||||
Padding(
|
|
||||||
padding: EdgeInsets.only(left: 2),
|
|
||||||
child: Container(
|
|
||||||
width: 34,
|
|
||||||
height: 34,
|
|
||||||
padding: EdgeInsets.only(top: 0),
|
|
||||||
child: Semantics(
|
|
||||||
label: S.of(context).copy_address,
|
|
||||||
child: InkWell(
|
|
||||||
onTap: () {
|
|
||||||
Clipboard.setData(
|
|
||||||
ClipboardData(text: addressController.text));
|
|
||||||
showBar<void>(
|
|
||||||
context, S.of(context).copied_to_clipboard);
|
|
||||||
},
|
|
||||||
child: Container(
|
|
||||||
padding: EdgeInsets.fromLTRB(8, 8, 0, 8),
|
|
||||||
color: Colors.transparent,
|
|
||||||
child: copyImage),
|
|
||||||
),
|
|
||||||
)))
|
|
||||||
])))
|
|
||||||
])),
|
|
||||||
),
|
|
||||||
]),
|
]),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,22 +24,17 @@ import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart';
|
||||||
import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
|
import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
|
||||||
import 'package:cake_wallet/themes/extensions/transaction_trade_theme.dart';
|
import 'package:cake_wallet/themes/extensions/transaction_trade_theme.dart';
|
||||||
|
|
||||||
void showInformation(
|
void showInformation(ExchangeTradeViewModel exchangeTradeViewModel, BuildContext context) {
|
||||||
ExchangeTradeViewModel exchangeTradeViewModel, BuildContext context) {
|
|
||||||
final trade = exchangeTradeViewModel.trade;
|
final trade = exchangeTradeViewModel.trade;
|
||||||
final walletName = exchangeTradeViewModel.wallet.name;
|
final walletName = exchangeTradeViewModel.wallet.name;
|
||||||
|
|
||||||
final information = exchangeTradeViewModel.isSendable
|
final information = exchangeTradeViewModel.isSendable
|
||||||
? S.current.exchange_result_confirm(
|
? S.current.exchange_result_confirm(trade.amount, trade.from.toString(), walletName) +
|
||||||
trade.amount, trade.from.toString(), walletName) +
|
exchangeTradeViewModel.extraInfo
|
||||||
exchangeTradeViewModel.extraInfo
|
: S.current.exchange_result_description(trade.amount, trade.from.toString()) +
|
||||||
: S.current.exchange_result_description(
|
exchangeTradeViewModel.extraInfo;
|
||||||
trade.amount, trade.from.toString()) +
|
|
||||||
exchangeTradeViewModel.extraInfo;
|
|
||||||
|
|
||||||
showPopUp<void>(
|
showPopUp<void>(context: context, builder: (_) => InformationPage(information: information));
|
||||||
context: context,
|
|
||||||
builder: (_) => InformationPage(information: information));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class ExchangeTradePage extends BasePage {
|
class ExchangeTradePage extends BasePage {
|
||||||
|
@ -72,8 +67,7 @@ class ExchangeTradePage extends BasePage {
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget body(BuildContext context) =>
|
Widget body(BuildContext context) => ExchangeTradeForm(exchangeTradeViewModel);
|
||||||
ExchangeTradeForm(exchangeTradeViewModel);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class ExchangeTradeForm extends StatefulWidget {
|
class ExchangeTradeForm extends StatefulWidget {
|
||||||
|
@ -138,7 +132,9 @@ class ExchangeTradeState extends State<ExchangeTradeForm> {
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 14.0,
|
fontSize: 14.0,
|
||||||
fontWeight: FontWeight.w500,
|
fontWeight: FontWeight.w500,
|
||||||
color: Theme.of(context).extension<TransactionTradeTheme>()!.detailsTitlesColor),
|
color: Theme.of(context)
|
||||||
|
.extension<TransactionTradeTheme>()!
|
||||||
|
.detailsTitlesColor),
|
||||||
),
|
),
|
||||||
if (trade.expiredAt != null)
|
if (trade.expiredAt != null)
|
||||||
TimerWidget(trade.expiredAt!,
|
TimerWidget(trade.expiredAt!,
|
||||||
|
@ -159,9 +155,9 @@ class ExchangeTradeState extends State<ExchangeTradeForm> {
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
border: Border.all(
|
border: Border.all(
|
||||||
width: 3,
|
width: 3,
|
||||||
color: Theme.of(context).extension<ExchangePageTheme>()!.qrCodeColor
|
color: Theme.of(context)
|
||||||
)
|
.extension<ExchangePageTheme>()!
|
||||||
),
|
.qrCodeColor)),
|
||||||
child: QrImage(data: trade.inputAddress ?? fetchingLabel),
|
child: QrImage(data: trade.inputAddress ?? fetchingLabel),
|
||||||
)))),
|
)))),
|
||||||
Spacer(flex: 3)
|
Spacer(flex: 3)
|
||||||
|
@ -192,10 +188,8 @@ class ExchangeTradeState extends State<ExchangeTradeForm> {
|
||||||
? Builder(
|
? Builder(
|
||||||
builder: (context) => GestureDetector(
|
builder: (context) => GestureDetector(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
Clipboard.setData(
|
Clipboard.setData(ClipboardData(text: value));
|
||||||
ClipboardData(text: value));
|
showBar<void>(context, S.of(context).copied_to_clipboard);
|
||||||
showBar<void>(context,
|
|
||||||
S.of(context).copied_to_clipboard);
|
|
||||||
},
|
},
|
||||||
child: content,
|
child: content,
|
||||||
))
|
))
|
||||||
|
@ -209,17 +203,14 @@ class ExchangeTradeState extends State<ExchangeTradeForm> {
|
||||||
bottomSectionPadding: EdgeInsets.fromLTRB(24, 0, 24, 24),
|
bottomSectionPadding: EdgeInsets.fromLTRB(24, 0, 24, 24),
|
||||||
bottomSection: Observer(builder: (_) {
|
bottomSection: Observer(builder: (_) {
|
||||||
final trade = widget.exchangeTradeViewModel.trade;
|
final trade = widget.exchangeTradeViewModel.trade;
|
||||||
final sendingState =
|
final sendingState = widget.exchangeTradeViewModel.sendViewModel.state;
|
||||||
widget.exchangeTradeViewModel.sendViewModel.state;
|
|
||||||
|
|
||||||
return widget.exchangeTradeViewModel.isSendable &&
|
return widget.exchangeTradeViewModel.isSendable &&
|
||||||
!(sendingState is TransactionCommitted)
|
!(sendingState is TransactionCommitted)
|
||||||
? LoadingPrimaryButton(
|
? LoadingPrimaryButton(
|
||||||
isDisabled: trade.inputAddress == null ||
|
isDisabled: trade.inputAddress == null || trade.inputAddress!.isEmpty,
|
||||||
trade.inputAddress!.isEmpty,
|
|
||||||
isLoading: sendingState is IsExecutingState,
|
isLoading: sendingState is IsExecutingState,
|
||||||
onPressed: () =>
|
onPressed: () => widget.exchangeTradeViewModel.confirmSending(),
|
||||||
widget.exchangeTradeViewModel.confirmSending(),
|
|
||||||
text: S.of(context).confirm,
|
text: S.of(context).confirm,
|
||||||
color: Theme.of(context).primaryColor,
|
color: Theme.of(context).primaryColor,
|
||||||
textColor: Colors.white)
|
textColor: Colors.white)
|
||||||
|
@ -257,27 +248,26 @@ class ExchangeTradeState extends State<ExchangeTradeForm> {
|
||||||
return ConfirmSendingAlert(
|
return ConfirmSendingAlert(
|
||||||
alertTitle: S.of(popupContext).confirm_sending,
|
alertTitle: S.of(popupContext).confirm_sending,
|
||||||
amount: S.of(popupContext).send_amount,
|
amount: S.of(popupContext).send_amount,
|
||||||
amountValue: widget.exchangeTradeViewModel.sendViewModel
|
amountValue: widget
|
||||||
.pendingTransaction!.amountFormatted,
|
.exchangeTradeViewModel.sendViewModel.pendingTransaction!.amountFormatted,
|
||||||
fee: S.of(popupContext).send_fee,
|
fee: S.of(popupContext).send_fee,
|
||||||
feeValue: widget.exchangeTradeViewModel.sendViewModel
|
feeValue: widget
|
||||||
.pendingTransaction!.feeFormatted,
|
.exchangeTradeViewModel.sendViewModel.pendingTransaction!.feeFormatted,
|
||||||
feeRate: widget.exchangeTradeViewModel.sendViewModel.pendingTransaction!.feeRate,
|
feeRate:
|
||||||
|
widget.exchangeTradeViewModel.sendViewModel.pendingTransaction!.feeRate,
|
||||||
rightButtonText: S.of(popupContext).send,
|
rightButtonText: S.of(popupContext).send,
|
||||||
leftButtonText: S.of(popupContext).cancel,
|
leftButtonText: S.of(popupContext).cancel,
|
||||||
actionRightButton: () async {
|
actionRightButton: () async {
|
||||||
Navigator.of(popupContext).pop();
|
Navigator.of(popupContext).pop();
|
||||||
await widget.exchangeTradeViewModel.sendViewModel
|
await widget.exchangeTradeViewModel.sendViewModel.commitTransaction();
|
||||||
.commitTransaction();
|
|
||||||
transactionStatePopup();
|
transactionStatePopup();
|
||||||
},
|
},
|
||||||
actionLeftButton: () => Navigator.of(popupContext).pop(),
|
actionLeftButton: () => Navigator.of(popupContext).pop(),
|
||||||
feeFiatAmount: widget.exchangeTradeViewModel
|
feeFiatAmount:
|
||||||
.pendingTransactionFeeFiatAmountFormatted,
|
widget.exchangeTradeViewModel.pendingTransactionFeeFiatAmountFormatted,
|
||||||
fiatAmountValue: widget.exchangeTradeViewModel
|
fiatAmountValue:
|
||||||
.pendingTransactionFiatAmountValueFormatted,
|
widget.exchangeTradeViewModel.pendingTransactionFiatAmountValueFormatted,
|
||||||
outputs: widget.exchangeTradeViewModel.sendViewModel
|
outputs: widget.exchangeTradeViewModel.sendViewModel.outputs);
|
||||||
.outputs);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -305,85 +295,26 @@ class ExchangeTradeState extends State<ExchangeTradeForm> {
|
||||||
void transactionStatePopup() {
|
void transactionStatePopup() {
|
||||||
if (this.mounted) {
|
if (this.mounted) {
|
||||||
showPopUp<void>(
|
showPopUp<void>(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (BuildContext popupContext) {
|
builder: (BuildContext popupContext) {
|
||||||
return Observer(builder: (_) {
|
return Observer(builder: (_) {
|
||||||
final state = widget
|
final state = widget.exchangeTradeViewModel.sendViewModel.state;
|
||||||
.exchangeTradeViewModel.sendViewModel.state;
|
|
||||||
|
|
||||||
if (state is TransactionCommitted) {
|
if (state is TransactionCommitted) {
|
||||||
return Stack(
|
return Stack(
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
Container(
|
Container(
|
||||||
color: Theme.of(popupContext).colorScheme.background,
|
color: Theme.of(popupContext).colorScheme.background,
|
||||||
child: Center(
|
child: Center(
|
||||||
child: Image.asset(
|
child: Image.asset('assets/images/birthday_cake.png'),
|
||||||
'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).extension<CakeTextTheme>()!.titleColor,
|
|
||||||
decoration: TextDecoration.none,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
Center(
|
||||||
Positioned(
|
|
||||||
left: 24,
|
|
||||||
right: 24,
|
|
||||||
bottom: 24,
|
|
||||||
child: PrimaryButton(
|
|
||||||
onPressed: () {
|
|
||||||
Navigator.pushNamedAndRemoveUntil(
|
|
||||||
popupContext,
|
|
||||||
Routes.dashboard,
|
|
||||||
(route) => false,
|
|
||||||
);
|
|
||||||
RequestReviewHandler.requestReview();
|
|
||||||
},
|
|
||||||
text: S.of(popupContext).got_it,
|
|
||||||
color: Theme.of(popupContext).primaryColor,
|
|
||||||
textColor: Colors.white))
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Stack(
|
|
||||||
children: <Widget>[
|
|
||||||
Container(
|
|
||||||
color: Theme.of(popupContext).colorScheme.background,
|
|
||||||
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)
|
|
||||||
.colorScheme
|
|
||||||
.background
|
|
||||||
.withOpacity(0.25)),
|
|
||||||
child: Center(
|
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: EdgeInsets.only(top: 220),
|
padding: EdgeInsets.only(top: 220, left: 24, right: 24),
|
||||||
child: Text(
|
child: Text(
|
||||||
S.of(popupContext).send_sending,
|
S.of(popupContext).send_success(
|
||||||
|
widget.exchangeTradeViewModel.wallet.currency.toString()),
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 22,
|
fontSize: 22,
|
||||||
|
@ -394,12 +325,60 @@ class ExchangeTradeState extends State<ExchangeTradeForm> {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
Positioned(
|
||||||
|
left: 24,
|
||||||
|
right: 24,
|
||||||
|
bottom: 24,
|
||||||
|
child: PrimaryButton(
|
||||||
|
onPressed: () {
|
||||||
|
Navigator.pushNamedAndRemoveUntil(
|
||||||
|
popupContext,
|
||||||
|
Routes.dashboard,
|
||||||
|
(route) => false,
|
||||||
|
);
|
||||||
|
RequestReviewHandler.requestReview();
|
||||||
|
},
|
||||||
|
text: S.of(popupContext).got_it,
|
||||||
|
color: Theme.of(popupContext).primaryColor,
|
||||||
|
textColor: Colors.white))
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Stack(
|
||||||
|
children: <Widget>[
|
||||||
|
Container(
|
||||||
|
color: Theme.of(popupContext).colorScheme.background,
|
||||||
|
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).colorScheme.background.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).extension<CakeTextTheme>()!.titleColor,
|
||||||
|
decoration: TextDecoration.none,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
340
lib/src/screens/receive/lightning_invoice_page.dart
Normal file
340
lib/src/screens/receive/lightning_invoice_page.dart
Normal file
|
@ -0,0 +1,340 @@
|
||||||
|
import 'package:cake_wallet/lightning/lightning.dart';
|
||||||
|
import 'package:cake_wallet/src/screens/receive/widgets/lightning_input_form.dart';
|
||||||
|
import 'package:cake_wallet/src/screens/receive/widgets/qr_image.dart';
|
||||||
|
import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart';
|
||||||
|
import 'package:cake_wallet/themes/extensions/dashboard_page_theme.dart';
|
||||||
|
import 'package:cake_wallet/themes/extensions/exchange_page_theme.dart';
|
||||||
|
import 'package:cake_wallet/themes/extensions/keyboard_theme.dart';
|
||||||
|
import 'package:cake_wallet/core/execution_state.dart';
|
||||||
|
import 'package:cake_wallet/routes.dart';
|
||||||
|
import 'package:cake_wallet/src/screens/dashboard/widgets/present_receive_option_picker.dart';
|
||||||
|
import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
|
||||||
|
import 'package:cake_wallet/src/widgets/keyboard_done_button.dart';
|
||||||
|
import 'package:cake_wallet/utils/responsive_layout_util.dart';
|
||||||
|
import 'package:cake_wallet/utils/show_bar.dart';
|
||||||
|
import 'package:cake_wallet/view_model/dashboard/receive_option_view_model.dart';
|
||||||
|
import 'package:cake_wallet/view_model/lightning_invoice_page_view_model.dart';
|
||||||
|
import 'package:cake_wallet/view_model/lightning_view_model.dart';
|
||||||
|
import 'package:cw_core/receive_page_option.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
|
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||||
|
import 'package:keyboard_actions/keyboard_actions.dart';
|
||||||
|
import 'package:cake_wallet/src/screens/base_page.dart';
|
||||||
|
import 'package:cake_wallet/src/widgets/trail_button.dart';
|
||||||
|
import 'package:cake_wallet/utils/show_pop_up.dart';
|
||||||
|
import 'package:cake_wallet/generated/i18n.dart';
|
||||||
|
import 'package:cake_wallet/src/widgets/primary_button.dart';
|
||||||
|
import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart';
|
||||||
|
import 'package:mobx/mobx.dart';
|
||||||
|
import 'package:qr_flutter/qr_flutter.dart' as qr;
|
||||||
|
|
||||||
|
class LightningInvoicePage extends BasePage {
|
||||||
|
LightningInvoicePage({
|
||||||
|
required this.lightningInvoicePageViewModel,
|
||||||
|
required this.receiveOptionViewModel,
|
||||||
|
}) : _amountFocusNode = FocusNode() {}
|
||||||
|
|
||||||
|
final _descriptionController = TextEditingController();
|
||||||
|
final _amountController = TextEditingController();
|
||||||
|
final FocusNode _amountFocusNode;
|
||||||
|
|
||||||
|
final LightningInvoicePageViewModel lightningInvoicePageViewModel;
|
||||||
|
final ReceiveOptionViewModel receiveOptionViewModel;
|
||||||
|
final _formKey = GlobalKey<FormState>();
|
||||||
|
|
||||||
|
bool effectsInstalled = false;
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool get gradientAll => true;
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool get resizeToAvoidBottomInset => false;
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool get extendBodyBehindAppBar => true;
|
||||||
|
|
||||||
|
@override
|
||||||
|
AppBarStyle get appBarStyle => AppBarStyle.transparent;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void onClose(BuildContext context) => Navigator.popUntil(context, (route) => route.isFirst);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget middle(BuildContext context) => PresentReceiveOptionPicker(
|
||||||
|
receiveOptionViewModel: receiveOptionViewModel, color: titleColor(context));
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget trailing(BuildContext context) => TrailButton(
|
||||||
|
caption: S.of(context).clear,
|
||||||
|
onPressed: () {
|
||||||
|
_formKey.currentState?.reset();
|
||||||
|
});
|
||||||
|
|
||||||
|
Future<bool> _onNavigateBack(BuildContext context) async {
|
||||||
|
onClose(context);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget body(BuildContext context) {
|
||||||
|
WidgetsBinding.instance.addPostFrameCallback((_) => _setReactions(context));
|
||||||
|
|
||||||
|
return WillPopScope(
|
||||||
|
onWillPop: () => _onNavigateBack(context),
|
||||||
|
child: KeyboardActions(
|
||||||
|
disableScroll: true,
|
||||||
|
config: KeyboardActionsConfig(
|
||||||
|
keyboardActionsPlatform: KeyboardActionsPlatform.IOS,
|
||||||
|
keyboardBarColor: Theme.of(context).extension<KeyboardTheme>()!.keyboardBarColor,
|
||||||
|
nextFocus: false,
|
||||||
|
actions: [
|
||||||
|
KeyboardActionsItem(
|
||||||
|
focusNode: _amountFocusNode,
|
||||||
|
toolbarButtons: [(_) => KeyboardDoneButton()],
|
||||||
|
),
|
||||||
|
]),
|
||||||
|
child: Container(
|
||||||
|
color: Theme.of(context).colorScheme.background,
|
||||||
|
child: ScrollableWithBottomSection(
|
||||||
|
contentPadding: EdgeInsets.only(bottom: 24),
|
||||||
|
content: Container(
|
||||||
|
decoration: responsiveLayoutUtil.shouldRenderMobileUI
|
||||||
|
? BoxDecoration(
|
||||||
|
borderRadius: BorderRadius.only(
|
||||||
|
bottomLeft: Radius.circular(24), bottomRight: Radius.circular(24)),
|
||||||
|
gradient: LinearGradient(
|
||||||
|
colors: [
|
||||||
|
Theme.of(context)
|
||||||
|
.extension<ExchangePageTheme>()!
|
||||||
|
.firstGradientTopPanelColor,
|
||||||
|
Theme.of(context)
|
||||||
|
.extension<ExchangePageTheme>()!
|
||||||
|
.secondGradientTopPanelColor,
|
||||||
|
],
|
||||||
|
begin: Alignment.topLeft,
|
||||||
|
end: Alignment.bottomRight,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
: null,
|
||||||
|
child: Padding(
|
||||||
|
padding: EdgeInsets.fromLTRB(24, 120, 24, 0),
|
||||||
|
child: LightningInvoiceForm(
|
||||||
|
descriptionController: _descriptionController,
|
||||||
|
amountController: _amountController,
|
||||||
|
depositAmountFocus: _amountFocusNode,
|
||||||
|
formKey: _formKey,
|
||||||
|
lightningInvoicePageViewModel: lightningInvoicePageViewModel,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
bottomSectionPadding: EdgeInsets.only(left: 24, right: 24, bottom: 24),
|
||||||
|
bottomSection: Column(
|
||||||
|
children: <Widget>[
|
||||||
|
Container(
|
||||||
|
padding: const EdgeInsets.only(top: 12, bottom: 12, right: 6),
|
||||||
|
margin: const EdgeInsets.only(left: 24, right: 24, bottom: 48),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
borderRadius: BorderRadius.all(Radius.circular(15)),
|
||||||
|
color: Color.fromARGB(255, 170, 147, 30),
|
||||||
|
border: Border.all(
|
||||||
|
color: Color.fromARGB(178, 223, 214, 0),
|
||||||
|
width: 2,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
width: 48,
|
||||||
|
height: 48,
|
||||||
|
margin: EdgeInsets.only(left: 12, bottom: 48, right: 20),
|
||||||
|
child: Image.asset(
|
||||||
|
"assets/images/warning.png",
|
||||||
|
color: Color.fromARGB(128, 255, 255, 255),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
FutureBuilder(
|
||||||
|
future: lightningInvoicePageViewModel.lightningViewModel
|
||||||
|
.invoiceSoftLimitsSats(),
|
||||||
|
builder: (context, snapshot) {
|
||||||
|
if (snapshot.data == null) {
|
||||||
|
return Expanded(
|
||||||
|
child:
|
||||||
|
Container(child: Center(child: CircularProgressIndicator())));
|
||||||
|
}
|
||||||
|
late String finalText;
|
||||||
|
InvoiceSoftLimitsResult limits = snapshot.data as InvoiceSoftLimitsResult;
|
||||||
|
if (limits.inboundLiquidity == 0) {
|
||||||
|
finalText = S.of(context).lightning_invoice_min(
|
||||||
|
limits.feePercent.toString(),
|
||||||
|
lightning!.satsToLightningString(limits.minFee));
|
||||||
|
} else {
|
||||||
|
finalText = S.of(context).lightning_invoice_min_max(
|
||||||
|
limits.feePercent.toString(),
|
||||||
|
lightning!.satsToLightningString(limits.minFee),
|
||||||
|
lightning!.satsToLightningString(limits.inboundLiquidity),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Expanded(
|
||||||
|
child: Text(
|
||||||
|
finalText,
|
||||||
|
maxLines: 5,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 14,
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
|
color: Theme.of(context).extension<DashboardPageTheme>()!.textColor,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Observer(builder: (_) {
|
||||||
|
return LoadingPrimaryButton(
|
||||||
|
text: S.of(context).create_invoice,
|
||||||
|
onPressed: () {
|
||||||
|
FocusScope.of(context).unfocus();
|
||||||
|
lightningInvoicePageViewModel.setRequestParams(
|
||||||
|
inputAmount: _amountController.text,
|
||||||
|
inputDescription: _descriptionController.text,
|
||||||
|
);
|
||||||
|
lightningInvoicePageViewModel.createInvoice();
|
||||||
|
},
|
||||||
|
color: Theme.of(context).primaryColor,
|
||||||
|
textColor: Colors.white,
|
||||||
|
isLoading: lightningInvoicePageViewModel.state is IsExecutingState,
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _setReactions(BuildContext context) {
|
||||||
|
if (effectsInstalled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
reaction((_) => receiveOptionViewModel.selectedReceiveOption, (ReceivePageOption option) async {
|
||||||
|
if (option == lightning!.getOptionOnchain()) {
|
||||||
|
Navigator.popAndPushNamed(
|
||||||
|
context,
|
||||||
|
Routes.lightningReceiveOnchain,
|
||||||
|
arguments: [lightning!.getOptionOnchain()],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
reaction((_) => lightningInvoicePageViewModel.state, (ExecutionState state) {
|
||||||
|
if (state is ExecutedSuccessfullyState) {
|
||||||
|
showPopUp<void>(
|
||||||
|
context: context,
|
||||||
|
builder: (BuildContext context) {
|
||||||
|
return AlertWithTwoActions(
|
||||||
|
alertTitle: S.of(context).invoice_created,
|
||||||
|
alertContent: '',
|
||||||
|
contentWidget: Column(
|
||||||
|
children: [
|
||||||
|
Center(
|
||||||
|
child: AspectRatio(
|
||||||
|
aspectRatio: 1.0,
|
||||||
|
child: Container(
|
||||||
|
padding: EdgeInsets.all(5),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
border: Border.all(
|
||||||
|
width: 3,
|
||||||
|
color: Theme.of(context).extension<DashboardPageTheme>()!.textColor,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
border: Border.all(
|
||||||
|
width: 3,
|
||||||
|
color: Colors.white,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: QrImage(
|
||||||
|
data: state.payload as String,
|
||||||
|
version: 14,
|
||||||
|
errorCorrectionLevel: qr.QrErrorCorrectLevel.L,
|
||||||
|
)),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
padding: const EdgeInsets.only(top: 12, bottom: 12, right: 6),
|
||||||
|
margin: const EdgeInsets.only(top: 32),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
borderRadius: BorderRadius.all(Radius.circular(15)),
|
||||||
|
color: Color.fromARGB(255, 170, 147, 30),
|
||||||
|
border: Border.all(
|
||||||
|
color: Color.fromARGB(178, 223, 214, 0),
|
||||||
|
width: 2,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
width: 32,
|
||||||
|
height: 32,
|
||||||
|
margin: EdgeInsets.only(left: 12, bottom: 48, right: 12),
|
||||||
|
child: Image.asset(
|
||||||
|
"assets/images/warning.png",
|
||||||
|
color: Color.fromARGB(128, 255, 255, 255),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: Material(
|
||||||
|
color: Colors.transparent,
|
||||||
|
child: Text(
|
||||||
|
S.of(context).lightning_invoice_warning,
|
||||||
|
maxLines: 5,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 12,
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
|
color:
|
||||||
|
Theme.of(context).extension<DashboardPageTheme>()!.textColor,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
rightButtonText: S.of(context).ok,
|
||||||
|
actionRightButton: () => Navigator.of(context).pop(),
|
||||||
|
actionLeftButton: () async {
|
||||||
|
Clipboard.setData(ClipboardData(text: state.payload as String));
|
||||||
|
showBar<void>(context, S.of(context).copied_to_clipboard);
|
||||||
|
},
|
||||||
|
leftButtonText: S.of(context).copy,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state is FailureState) {
|
||||||
|
showPopUp<void>(
|
||||||
|
context: context,
|
||||||
|
builder: (BuildContext context) {
|
||||||
|
return AlertWithOneAction(
|
||||||
|
alertTitle: S.of(context).error,
|
||||||
|
alertContent: state.error.toString(),
|
||||||
|
buttonText: S.of(context).ok,
|
||||||
|
buttonAction: () => Navigator.of(context).pop());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
effectsInstalled = true;
|
||||||
|
}
|
||||||
|
}
|
252
lib/src/screens/receive/lightning_receive_page.dart
Normal file
252
lib/src/screens/receive/lightning_receive_page.dart
Normal file
|
@ -0,0 +1,252 @@
|
||||||
|
import 'package:cake_wallet/entities/qr_view_data.dart';
|
||||||
|
import 'package:cake_wallet/lightning/lightning.dart';
|
||||||
|
import 'package:cake_wallet/routes.dart';
|
||||||
|
import 'package:cake_wallet/src/screens/dashboard/widgets/present_receive_option_picker.dart';
|
||||||
|
import 'package:cake_wallet/src/screens/receive/widgets/qr_image.dart';
|
||||||
|
import 'package:cake_wallet/src/widgets/gradient_background.dart';
|
||||||
|
import 'package:cake_wallet/themes/extensions/dashboard_page_theme.dart';
|
||||||
|
import 'package:cake_wallet/themes/extensions/qr_code_theme.dart';
|
||||||
|
import 'package:cake_wallet/utils/brightness_util.dart';
|
||||||
|
import 'package:cake_wallet/utils/show_bar.dart';
|
||||||
|
import 'package:cake_wallet/view_model/dashboard/receive_option_view_model.dart';
|
||||||
|
import 'package:cake_wallet/view_model/lightning_view_model.dart';
|
||||||
|
import 'package:cw_core/receive_page_option.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:cake_wallet/generated/i18n.dart';
|
||||||
|
import 'package:cake_wallet/src/screens/base_page.dart';
|
||||||
|
import 'package:cake_wallet/view_model/wallet_address_list/wallet_address_list_view_model.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
|
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||||
|
import 'package:mobx/mobx.dart';
|
||||||
|
|
||||||
|
class LightningReceiveOnchainPage extends BasePage {
|
||||||
|
LightningReceiveOnchainPage(
|
||||||
|
{required this.addressListViewModel,
|
||||||
|
required this.receiveOptionViewModel,
|
||||||
|
required this.lightningViewModel})
|
||||||
|
: _amountController = TextEditingController(),
|
||||||
|
_formKey = GlobalKey<FormState>() {
|
||||||
|
_amountController.addListener(() {
|
||||||
|
if (_formKey.currentState!.validate()) {
|
||||||
|
addressListViewModel.changeAmount(_amountController.text);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
final WalletAddressListViewModel addressListViewModel;
|
||||||
|
final ReceiveOptionViewModel receiveOptionViewModel;
|
||||||
|
final LightningViewModel lightningViewModel;
|
||||||
|
final TextEditingController _amountController;
|
||||||
|
final GlobalKey<FormState> _formKey;
|
||||||
|
|
||||||
|
bool effectsInstalled = false;
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get title => S.current.receive;
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool get gradientBackground => true;
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool get resizeToAvoidBottomInset => true;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget middle(BuildContext context) => PresentReceiveOptionPicker(
|
||||||
|
color: titleColor(context), receiveOptionViewModel: receiveOptionViewModel);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget Function(BuildContext, Widget) get rootWrapper =>
|
||||||
|
(BuildContext context, Widget scaffold) => GradientBackground(scaffold: scaffold);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget body(BuildContext context) {
|
||||||
|
WidgetsBinding.instance.addPostFrameCallback((_) => _setReactions(context));
|
||||||
|
final copyImage = Image.asset('assets/images/copy_address.png',
|
||||||
|
color: Theme.of(context).extension<QRCodeTheme>()!.qrWidgetCopyButtonColor);
|
||||||
|
String heroTag = "lightning_receive";
|
||||||
|
return Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||||
|
children: [
|
||||||
|
FutureBuilder(
|
||||||
|
future: lightningViewModel.receiveOnchain(),
|
||||||
|
builder: ((context, snapshot) {
|
||||||
|
if (snapshot.data == null) {
|
||||||
|
return CircularProgressIndicator();
|
||||||
|
}
|
||||||
|
ReceiveOnchainResult results = snapshot.data as ReceiveOnchainResult;
|
||||||
|
return Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.only(bottom: 12),
|
||||||
|
child: Text(
|
||||||
|
S.of(context).qr_fullscreen,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 14,
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
|
color: Theme.of(context).extension<DashboardPageTheme>()!.textColor),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Row(
|
||||||
|
children: <Widget>[
|
||||||
|
Spacer(flex: 3),
|
||||||
|
Observer(
|
||||||
|
builder: (_) => Flexible(
|
||||||
|
flex: 5,
|
||||||
|
child: GestureDetector(
|
||||||
|
onTap: () {
|
||||||
|
BrightnessUtil.changeBrightnessForFunction(
|
||||||
|
() async {
|
||||||
|
await Navigator.pushNamed(context, Routes.fullscreenQR,
|
||||||
|
arguments: QrViewData(
|
||||||
|
data: results.bitcoinAddress,
|
||||||
|
heroTag: heroTag,
|
||||||
|
));
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
child: Hero(
|
||||||
|
tag: Key(heroTag),
|
||||||
|
child: Center(
|
||||||
|
child: AspectRatio(
|
||||||
|
aspectRatio: 1.0,
|
||||||
|
child: Container(
|
||||||
|
padding: EdgeInsets.all(5),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
border: Border.all(
|
||||||
|
width: 3,
|
||||||
|
color: Theme.of(context)
|
||||||
|
.extension<DashboardPageTheme>()!
|
||||||
|
.textColor,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
border: Border.all(
|
||||||
|
width: 3,
|
||||||
|
color: Colors.white,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: QrImage(data: results.bitcoinAddress)),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Spacer(flex: 3)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding: EdgeInsets.only(top: 20, bottom: 8, left: 24, right: 24),
|
||||||
|
child: Builder(
|
||||||
|
builder: (context) => Observer(
|
||||||
|
builder: (context) => GestureDetector(
|
||||||
|
onTap: () {
|
||||||
|
Clipboard.setData(ClipboardData(text: results.bitcoinAddress));
|
||||||
|
showBar<void>(context, S.of(context).copied_to_clipboard);
|
||||||
|
},
|
||||||
|
child: Row(
|
||||||
|
mainAxisSize: MainAxisSize.max,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: <Widget>[
|
||||||
|
Expanded(
|
||||||
|
child: Text(
|
||||||
|
results.bitcoinAddress,
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 15,
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
|
color: Theme.of(context)
|
||||||
|
.extension<DashboardPageTheme>()!
|
||||||
|
.textColor),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding: EdgeInsets.only(left: 12),
|
||||||
|
child: copyImage,
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
padding: const EdgeInsets.only(top: 24, bottom: 24, right: 6),
|
||||||
|
margin: const EdgeInsets.symmetric(horizontal: 24),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
borderRadius: BorderRadius.all(Radius.circular(15)),
|
||||||
|
color: Color.fromARGB(255, 170, 147, 30),
|
||||||
|
border: Border.all(
|
||||||
|
color: Color.fromARGB(178, 223, 214, 0),
|
||||||
|
width: 2,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
width: 48,
|
||||||
|
height: 48,
|
||||||
|
margin: EdgeInsets.only(left: 12, bottom: 48, right: 20),
|
||||||
|
child: Image.asset(
|
||||||
|
"assets/images/warning.png",
|
||||||
|
color: Color.fromARGB(128, 255, 255, 255),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
FutureBuilder(
|
||||||
|
future: lightningViewModel.receiveOnchain(),
|
||||||
|
builder: (context, snapshot) {
|
||||||
|
if (snapshot.data == null) {
|
||||||
|
return Expanded(
|
||||||
|
child: Container(child: Center(child: CircularProgressIndicator())));
|
||||||
|
}
|
||||||
|
ReceiveOnchainResult results = snapshot.data as ReceiveOnchainResult;
|
||||||
|
return Expanded(
|
||||||
|
child: Text(
|
||||||
|
S.of(context).lightning_receive_limits(
|
||||||
|
lightning!.satsToLightningString(results.minAllowedDeposit),
|
||||||
|
lightning!.satsToLightningString(results.maxAllowedDeposit),
|
||||||
|
results.feePercent.toString(),
|
||||||
|
lightning!.satsToLightningString(results.fee),
|
||||||
|
),
|
||||||
|
maxLines: 10,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 14,
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
|
color: Theme.of(context).extension<DashboardPageTheme>()!.textColor,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _setReactions(BuildContext context) {
|
||||||
|
if (effectsInstalled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
reaction((_) => receiveOptionViewModel.selectedReceiveOption, (ReceivePageOption option) async {
|
||||||
|
if (option == lightning!.getOptionInvoice()) {
|
||||||
|
Navigator.popAndPushNamed(
|
||||||
|
context,
|
||||||
|
Routes.lightningInvoice,
|
||||||
|
arguments: [lightning!.getOptionInvoice()],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
effectsInstalled = true;
|
||||||
|
}
|
||||||
|
}
|
|
@ -7,15 +7,16 @@ import 'package:flutter/services.dart';
|
||||||
import 'package:cake_wallet/themes/extensions/send_page_theme.dart';
|
import 'package:cake_wallet/themes/extensions/send_page_theme.dart';
|
||||||
|
|
||||||
class AnonpayCurrencyInputField extends StatelessWidget {
|
class AnonpayCurrencyInputField extends StatelessWidget {
|
||||||
const AnonpayCurrencyInputField(
|
const AnonpayCurrencyInputField({
|
||||||
{super.key,
|
super.key,
|
||||||
required this.onTapPicker,
|
this.onTapPicker,
|
||||||
required this.selectedCurrency,
|
required this.selectedCurrency,
|
||||||
required this.focusNode,
|
required this.focusNode,
|
||||||
required this.controller,
|
required this.controller,
|
||||||
required this.minAmount,
|
required this.minAmount,
|
||||||
required this.maxAmount});
|
required this.maxAmount,
|
||||||
final Function() onTapPicker;
|
});
|
||||||
|
final Function()? onTapPicker;
|
||||||
final Currency selectedCurrency;
|
final Currency selectedCurrency;
|
||||||
final FocusNode focusNode;
|
final FocusNode focusNode;
|
||||||
final TextEditingController controller;
|
final TextEditingController controller;
|
||||||
|
@ -23,6 +24,7 @@ class AnonpayCurrencyInputField extends StatelessWidget {
|
||||||
final String maxAmount;
|
final String maxAmount;
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
bool hasDecimals = selectedCurrency.name.toLowerCase() != "sats";
|
||||||
final arrowBottomPurple = Image.asset(
|
final arrowBottomPurple = Image.asset(
|
||||||
'assets/images/arrow_bottom_purple_icon.png',
|
'assets/images/arrow_bottom_purple_icon.png',
|
||||||
color: Colors.white,
|
color: Colors.white,
|
||||||
|
@ -34,40 +36,50 @@ class AnonpayCurrencyInputField extends StatelessWidget {
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
border: Border(
|
border: Border(
|
||||||
bottom: BorderSide(
|
bottom: BorderSide(
|
||||||
color:
|
color: Theme.of(context)
|
||||||
Theme.of(context).extension<ExchangePageTheme>()!.textFieldBorderBottomPanelColor,
|
.extension<ExchangePageTheme>()!
|
||||||
|
.textFieldBorderBottomPanelColor,
|
||||||
width: 1)),
|
width: 1)),
|
||||||
),
|
),
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: EdgeInsets.only(top: 20),
|
padding: EdgeInsets.only(top: 20),
|
||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
Container(
|
if (onTapPicker != null)
|
||||||
padding: EdgeInsets.only(right: 8),
|
Container(
|
||||||
height: 32,
|
padding: EdgeInsets.only(right: 8),
|
||||||
child: InkWell(
|
height: 32,
|
||||||
onTap: onTapPicker,
|
child: InkWell(
|
||||||
child: Row(
|
onTap: onTapPicker,
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
child: Row(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
children: <Widget>[
|
mainAxisSize: MainAxisSize.min,
|
||||||
Padding(
|
children: <Widget>[
|
||||||
padding: EdgeInsets.only(right: 5),
|
Padding(
|
||||||
child: arrowBottomPurple,
|
padding: EdgeInsets.only(right: 5),
|
||||||
),
|
child: arrowBottomPurple,
|
||||||
Text(selectedCurrency.name.toUpperCase(),
|
),
|
||||||
style: TextStyle(
|
Text(selectedCurrency.name.toUpperCase(),
|
||||||
fontWeight: FontWeight.w600, fontSize: 16, color: Colors.white))
|
style: TextStyle(
|
||||||
]),
|
fontWeight: FontWeight.w600,
|
||||||
),
|
fontSize: 16,
|
||||||
),
|
color: Colors.white))
|
||||||
|
]),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
else
|
||||||
|
Text(selectedCurrency.name.toUpperCase(),
|
||||||
|
style: TextStyle(
|
||||||
|
fontWeight: FontWeight.w600, fontSize: 16, color: Colors.white)),
|
||||||
selectedCurrency.tag != null
|
selectedCurrency.tag != null
|
||||||
? Padding(
|
? Padding(
|
||||||
padding: const EdgeInsets.only(right: 3.0),
|
padding: const EdgeInsets.only(right: 3.0),
|
||||||
child: Container(
|
child: Container(
|
||||||
height: 32,
|
height: 32,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: Theme.of(context).extension<SendPageTheme>()!.textFieldButtonColor,
|
color: Theme.of(context)
|
||||||
|
.extension<SendPageTheme>()!
|
||||||
|
.textFieldButtonColor,
|
||||||
borderRadius: BorderRadius.all(Radius.circular(6))),
|
borderRadius: BorderRadius.all(Radius.circular(6))),
|
||||||
child: Center(
|
child: Center(
|
||||||
child: Padding(
|
child: Padding(
|
||||||
|
@ -77,7 +89,9 @@ class AnonpayCurrencyInputField extends StatelessWidget {
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
color: Theme.of(context).extension<SendPageTheme>()!.textFieldButtonIconColor,
|
color: Theme.of(context)
|
||||||
|
.extension<SendPageTheme>()!
|
||||||
|
.textFieldButtonIconColor,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -102,20 +116,21 @@ class AnonpayCurrencyInputField extends StatelessWidget {
|
||||||
textInputAction: TextInputAction.next,
|
textInputAction: TextInputAction.next,
|
||||||
enabled: true,
|
enabled: true,
|
||||||
textAlign: TextAlign.left,
|
textAlign: TextAlign.left,
|
||||||
keyboardType:
|
keyboardType: TextInputType.numberWithOptions(
|
||||||
TextInputType.numberWithOptions(signed: false, decimal: true),
|
signed: false, decimal: hasDecimals),
|
||||||
inputFormatters: [
|
inputFormatters: [
|
||||||
FilteringTextInputFormatter.deny(RegExp('[\\-|\\ ]'))
|
FilteringTextInputFormatter.deny(RegExp('[\\-|\\ ]')),
|
||||||
|
if (!hasDecimals) FilteringTextInputFormatter.deny(RegExp('[\.,]')),
|
||||||
],
|
],
|
||||||
hintText: '0.0000',
|
hintText: hasDecimals ? '0.0000' : '0',
|
||||||
borderColor: Colors.transparent,
|
borderColor: Colors.transparent,
|
||||||
//widget.borderColor,
|
|
||||||
textStyle: TextStyle(
|
textStyle: TextStyle(
|
||||||
fontSize: 16, fontWeight: FontWeight.w600, color: Colors.white),
|
fontSize: 16, fontWeight: FontWeight.w600, color: Colors.white),
|
||||||
placeholderTextStyle: TextStyle(
|
placeholderTextStyle: TextStyle(
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
fontWeight: FontWeight.w600,
|
fontWeight: FontWeight.w600,
|
||||||
color: Theme.of(context).extension<ExchangePageTheme>()!.hintTextColor,
|
color:
|
||||||
|
Theme.of(context).extension<ExchangePageTheme>()!.hintTextColor,
|
||||||
),
|
),
|
||||||
validator: null,
|
validator: null,
|
||||||
),
|
),
|
||||||
|
@ -131,19 +146,23 @@ class AnonpayCurrencyInputField extends StatelessWidget {
|
||||||
child: Row(
|
child: Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.start,
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
Text(
|
if (minAmount.isNotEmpty) ...[
|
||||||
S.of(context).min_value(minAmount, selectedCurrency.toString()),
|
Text(
|
||||||
style: TextStyle(
|
S.of(context).min_value(minAmount, selectedCurrency.toString()),
|
||||||
fontSize: 10,
|
|
||||||
height: 1.2,
|
|
||||||
color: Theme.of(context).extension<ExchangePageTheme>()!.hintTextColor),
|
|
||||||
),
|
|
||||||
SizedBox(width: 10),
|
|
||||||
Text(S.of(context).max_value(maxAmount, selectedCurrency.toString()),
|
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 10,
|
fontSize: 10,
|
||||||
height: 1.2,
|
height: 1.2,
|
||||||
color: Theme.of(context).extension<ExchangePageTheme>()!.hintTextColor)),
|
color: Theme.of(context).extension<ExchangePageTheme>()!.hintTextColor),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
SizedBox(width: 10),
|
||||||
|
if (maxAmount.isNotEmpty) ...[
|
||||||
|
Text(S.of(context).max_value(maxAmount, selectedCurrency.toString()),
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 10,
|
||||||
|
height: 1.2,
|
||||||
|
color: Theme.of(context).extension<ExchangePageTheme>()!.hintTextColor))
|
||||||
|
],
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
81
lib/src/screens/receive/widgets/lightning_input_form.dart
Normal file
81
lib/src/screens/receive/widgets/lightning_input_form.dart
Normal file
|
@ -0,0 +1,81 @@
|
||||||
|
import 'package:cake_wallet/generated/i18n.dart';
|
||||||
|
import 'package:cake_wallet/lightning/lightning.dart';
|
||||||
|
import 'package:cake_wallet/src/screens/receive/widgets/anonpay_currency_input_field.dart';
|
||||||
|
import 'package:cake_wallet/src/widgets/base_text_form_field.dart';
|
||||||
|
import 'package:cake_wallet/themes/extensions/exchange_page_theme.dart';
|
||||||
|
import 'package:cake_wallet/typography.dart';
|
||||||
|
import 'package:cake_wallet/view_model/lightning_invoice_page_view_model.dart';
|
||||||
|
import 'package:cw_core/crypto_currency.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||||
|
import 'package:cake_wallet/lightning/lightning.dart';
|
||||||
|
|
||||||
|
class LightningInvoiceForm extends StatelessWidget {
|
||||||
|
LightningInvoiceForm({
|
||||||
|
super.key,
|
||||||
|
required this.formKey,
|
||||||
|
required this.lightningInvoicePageViewModel,
|
||||||
|
required this.amountController,
|
||||||
|
required this.descriptionController,
|
||||||
|
required this.depositAmountFocus,
|
||||||
|
}) : _descriptionFocusNode = FocusNode() {
|
||||||
|
amountController.text = lightningInvoicePageViewModel.amount;
|
||||||
|
descriptionController.text = lightningInvoicePageViewModel.description;
|
||||||
|
}
|
||||||
|
|
||||||
|
final TextEditingController amountController;
|
||||||
|
final TextEditingController descriptionController;
|
||||||
|
final LightningInvoicePageViewModel lightningInvoicePageViewModel;
|
||||||
|
final FocusNode depositAmountFocus;
|
||||||
|
final FocusNode _descriptionFocusNode;
|
||||||
|
final GlobalKey<FormState> formKey;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Form(
|
||||||
|
key: formKey,
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: <Widget>[
|
||||||
|
Text(
|
||||||
|
S.of(context).invoice_details,
|
||||||
|
style: textMediumSemiBold(),
|
||||||
|
),
|
||||||
|
Observer(builder: (_) {
|
||||||
|
return AnonpayCurrencyInputField(
|
||||||
|
controller: amountController,
|
||||||
|
focusNode: depositAmountFocus,
|
||||||
|
maxAmount: '',
|
||||||
|
minAmount: (lightningInvoicePageViewModel.minimum != null)
|
||||||
|
? lightning!
|
||||||
|
.satsToLightningString(lightningInvoicePageViewModel.minimum!.round())
|
||||||
|
: '...',
|
||||||
|
selectedCurrency: CryptoCurrency.btcln,
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
SizedBox(
|
||||||
|
height: 24,
|
||||||
|
),
|
||||||
|
BaseTextFormField(
|
||||||
|
controller: descriptionController,
|
||||||
|
focusNode: _descriptionFocusNode,
|
||||||
|
textInputAction: TextInputAction.next,
|
||||||
|
borderColor:
|
||||||
|
Theme.of(context).extension<ExchangePageTheme>()!.textFieldBorderTopPanelColor,
|
||||||
|
suffixIcon: SizedBox(width: 36),
|
||||||
|
hintText: S.of(context).optional_description,
|
||||||
|
placeholderTextStyle: TextStyle(
|
||||||
|
fontSize: 16,
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
color: Theme.of(context).extension<ExchangePageTheme>()!.hintTextColor,
|
||||||
|
),
|
||||||
|
textStyle: TextStyle(fontSize: 16, fontWeight: FontWeight.w600, color: Colors.white),
|
||||||
|
validator: null,
|
||||||
|
),
|
||||||
|
SizedBox(
|
||||||
|
height: 52,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +1,6 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:qr_flutter/qr_flutter.dart' as qr;
|
import 'package:qr_flutter/qr_flutter.dart' as qr;
|
||||||
|
import 'package:qr_flutter/qr_flutter.dart';
|
||||||
|
|
||||||
class QrImage extends StatelessWidget {
|
class QrImage extends StatelessWidget {
|
||||||
QrImage({
|
QrImage({
|
||||||
|
@ -23,7 +24,9 @@ class QrImage extends StatelessWidget {
|
||||||
return qr.QrImageView(
|
return qr.QrImageView(
|
||||||
data: data,
|
data: data,
|
||||||
errorCorrectionLevel: errorCorrectionLevel,
|
errorCorrectionLevel: errorCorrectionLevel,
|
||||||
version: version ?? 9, // Previous value: 7 something happened after flutter upgrade monero wallets addresses are longer than ver. 7 ???
|
// Previous value: 7 something happened after flutter upgrade monero wallets addresses are longer than ver. 7 ???
|
||||||
|
// changed from 9 to auto
|
||||||
|
version: version ?? QrVersions.auto,
|
||||||
size: size,
|
size: size,
|
||||||
foregroundColor: foregroundColor,
|
foregroundColor: foregroundColor,
|
||||||
backgroundColor: backgroundColor,
|
backgroundColor: backgroundColor,
|
||||||
|
|
|
@ -270,7 +270,8 @@ class WalletRestorePage extends BasePage {
|
||||||
|
|
||||||
// bip39:
|
// bip39:
|
||||||
const validSeedLengths = [12, 18, 24];
|
const validSeedLengths = [12, 18, 24];
|
||||||
if (walletRestoreViewModel.type == WalletType.bitcoin &&
|
final type = walletRestoreViewModel.type;
|
||||||
|
if ((type == WalletType.bitcoin || type == WalletType.lightning) &&
|
||||||
!(validSeedLengths.contains(seedWords.length))) {
|
!(validSeedLengths.contains(seedWords.length))) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
311
lib/src/screens/send/lightning_send_confirm_page.dart
Normal file
311
lib/src/screens/send/lightning_send_confirm_page.dart
Normal file
|
@ -0,0 +1,311 @@
|
||||||
|
import 'package:breez_sdk/breez_sdk.dart';
|
||||||
|
import 'package:breez_sdk/bridge_generated.dart' as BZG;
|
||||||
|
import 'package:cake_wallet/entities/fiat_currency.dart';
|
||||||
|
import 'package:cake_wallet/lightning/lightning.dart';
|
||||||
|
import 'package:cake_wallet/src/screens/receive/widgets/anonpay_currency_input_field.dart';
|
||||||
|
import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
|
||||||
|
import 'package:cake_wallet/src/widgets/base_text_form_field.dart';
|
||||||
|
import 'package:cake_wallet/src/widgets/keyboard_done_button.dart';
|
||||||
|
import 'package:cake_wallet/themes/extensions/exchange_page_theme.dart';
|
||||||
|
import 'package:cake_wallet/themes/extensions/keyboard_theme.dart';
|
||||||
|
import 'package:cake_wallet/themes/theme_base.dart';
|
||||||
|
import 'package:cake_wallet/utils/responsive_layout_util.dart';
|
||||||
|
import 'package:cake_wallet/utils/show_pop_up.dart';
|
||||||
|
import 'package:cake_wallet/view_model/lightning_send_view_model.dart';
|
||||||
|
import 'package:cake_wallet/view_model/lightning_view_model.dart';
|
||||||
|
import 'package:cw_core/crypto_currency.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||||
|
import 'package:keyboard_actions/keyboard_actions.dart';
|
||||||
|
import 'package:cake_wallet/src/screens/base_page.dart';
|
||||||
|
import 'package:cake_wallet/src/widgets/primary_button.dart';
|
||||||
|
import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart';
|
||||||
|
import 'package:cake_wallet/generated/i18n.dart';
|
||||||
|
|
||||||
|
class LightningSendConfirmPage extends BasePage {
|
||||||
|
LightningSendConfirmPage({required this.invoice, required this.lightningSendViewModel})
|
||||||
|
: _formKey = GlobalKey<FormState>() {
|
||||||
|
initialSatAmount = ((invoice.amountMsat ?? 0) ~/ 1000);
|
||||||
|
_amountController = TextEditingController();
|
||||||
|
_fiatAmountController = TextEditingController();
|
||||||
|
_amountController.text = initialSatAmount.toString();
|
||||||
|
_fiatAmountController.text = lightningSendViewModel.formattedFiatAmount(initialSatAmount);
|
||||||
|
}
|
||||||
|
|
||||||
|
final GlobalKey<FormState> _formKey;
|
||||||
|
final controller = PageController(initialPage: 0);
|
||||||
|
|
||||||
|
BZG.LNInvoice invoice;
|
||||||
|
late int initialSatAmount;
|
||||||
|
late TextEditingController _amountController;
|
||||||
|
late TextEditingController _fiatAmountController;
|
||||||
|
final FocusNode _depositAmountFocus = FocusNode();
|
||||||
|
final LightningSendViewModel lightningSendViewModel;
|
||||||
|
|
||||||
|
bool _effectsInstalled = false;
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get title => S.current.send;
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool get gradientAll => true;
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool get resizeToAvoidBottomInset => false;
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool get extendBodyBehindAppBar => true;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget? leading(BuildContext context) {
|
||||||
|
final _backButton = Icon(
|
||||||
|
Icons.arrow_back_ios,
|
||||||
|
color: titleColor(context),
|
||||||
|
size: 16,
|
||||||
|
);
|
||||||
|
final _closeButton =
|
||||||
|
currentTheme.type == ThemeType.dark ? closeButtonImageDarkTheme : closeButtonImage;
|
||||||
|
|
||||||
|
bool isMobileView = responsiveLayoutUtil.shouldRenderMobileUI;
|
||||||
|
|
||||||
|
return MergeSemantics(
|
||||||
|
child: SizedBox(
|
||||||
|
height: isMobileView ? 37 : 45,
|
||||||
|
width: isMobileView ? 37 : 45,
|
||||||
|
child: ButtonTheme(
|
||||||
|
minWidth: double.minPositive,
|
||||||
|
child: Semantics(
|
||||||
|
label: !isMobileView ? S.of(context).close : S.of(context).seed_alert_back,
|
||||||
|
child: TextButton(
|
||||||
|
style: ButtonStyle(
|
||||||
|
overlayColor: MaterialStateColor.resolveWith((states) => Colors.transparent),
|
||||||
|
),
|
||||||
|
onPressed: () => onClose(context),
|
||||||
|
child: !isMobileView ? _closeButton : _backButton,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
AppBarStyle get appBarStyle => AppBarStyle.transparent;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void onClose(BuildContext context) {
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget body(BuildContext context) {
|
||||||
|
_setEffects(context);
|
||||||
|
|
||||||
|
return WillPopScope(
|
||||||
|
onWillPop: () => _onNavigateBack(context),
|
||||||
|
child: KeyboardActions(
|
||||||
|
disableScroll: true,
|
||||||
|
config: KeyboardActionsConfig(
|
||||||
|
keyboardActionsPlatform: KeyboardActionsPlatform.IOS,
|
||||||
|
keyboardBarColor: Theme.of(context).extension<KeyboardTheme>()!.keyboardBarColor,
|
||||||
|
nextFocus: false,
|
||||||
|
actions: [
|
||||||
|
KeyboardActionsItem(
|
||||||
|
focusNode: FocusNode(),
|
||||||
|
toolbarButtons: [(_) => KeyboardDoneButton()],
|
||||||
|
),
|
||||||
|
]),
|
||||||
|
child: Container(
|
||||||
|
color: Theme.of(context).colorScheme.background,
|
||||||
|
child: ScrollableWithBottomSection(
|
||||||
|
contentPadding: EdgeInsets.only(bottom: 24),
|
||||||
|
content: Container(
|
||||||
|
decoration: responsiveLayoutUtil.shouldRenderMobileUI
|
||||||
|
? BoxDecoration(
|
||||||
|
borderRadius: BorderRadius.only(
|
||||||
|
bottomLeft: Radius.circular(24), bottomRight: Radius.circular(24)),
|
||||||
|
gradient: LinearGradient(
|
||||||
|
colors: [
|
||||||
|
Theme.of(context)
|
||||||
|
.extension<ExchangePageTheme>()!
|
||||||
|
.firstGradientTopPanelColor,
|
||||||
|
Theme.of(context)
|
||||||
|
.extension<ExchangePageTheme>()!
|
||||||
|
.secondGradientTopPanelColor,
|
||||||
|
],
|
||||||
|
begin: Alignment.topLeft,
|
||||||
|
end: Alignment.bottomRight,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
: null,
|
||||||
|
child: Observer(builder: (_) {
|
||||||
|
return Padding(
|
||||||
|
padding: EdgeInsets.fromLTRB(24, 120, 24, 0),
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
BaseTextFormField(
|
||||||
|
enabled: false,
|
||||||
|
borderColor: Theme.of(context)
|
||||||
|
.extension<ExchangePageTheme>()!
|
||||||
|
.textFieldBorderTopPanelColor,
|
||||||
|
suffixIcon: SizedBox(width: 36),
|
||||||
|
initialValue: "${S.of(context).invoice}: ${invoice.bolt11}",
|
||||||
|
placeholderTextStyle: TextStyle(
|
||||||
|
fontSize: 16,
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
color: Theme.of(context).extension<ExchangePageTheme>()!.hintTextColor,
|
||||||
|
),
|
||||||
|
textStyle: TextStyle(
|
||||||
|
fontSize: 16, fontWeight: FontWeight.w600, color: Colors.white),
|
||||||
|
validator: null,
|
||||||
|
),
|
||||||
|
SizedBox(height: 24),
|
||||||
|
if (invoice.amountMsat == null)
|
||||||
|
Observer(builder: (_) {
|
||||||
|
return AnonpayCurrencyInputField(
|
||||||
|
controller: _amountController,
|
||||||
|
focusNode: _depositAmountFocus,
|
||||||
|
maxAmount: '',
|
||||||
|
minAmount: '',
|
||||||
|
selectedCurrency: CryptoCurrency.btcln,
|
||||||
|
);
|
||||||
|
})
|
||||||
|
else
|
||||||
|
BaseTextFormField(
|
||||||
|
enabled: false,
|
||||||
|
borderColor: Theme.of(context)
|
||||||
|
.extension<ExchangePageTheme>()!
|
||||||
|
.textFieldBorderTopPanelColor,
|
||||||
|
suffixIcon: SizedBox(width: 36),
|
||||||
|
initialValue:
|
||||||
|
"sats: ${lightning!.bitcoinAmountToLightningString(amount: initialSatAmount)}",
|
||||||
|
placeholderTextStyle: TextStyle(
|
||||||
|
fontSize: 16,
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
color: Theme.of(context).extension<ExchangePageTheme>()!.hintTextColor,
|
||||||
|
),
|
||||||
|
textStyle: TextStyle(
|
||||||
|
fontSize: 16, fontWeight: FontWeight.w600, color: Colors.white),
|
||||||
|
validator: null,
|
||||||
|
),
|
||||||
|
SizedBox(height: 24),
|
||||||
|
BaseTextFormField(
|
||||||
|
enabled: false,
|
||||||
|
controller: _fiatAmountController,
|
||||||
|
prefixIcon: Padding(
|
||||||
|
padding: EdgeInsets.only(top: 9),
|
||||||
|
child: Text(
|
||||||
|
lightningSendViewModel.fiat.title + ':',
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 16,
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
color: Colors.white,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
borderColor: Theme.of(context)
|
||||||
|
.extension<ExchangePageTheme>()!
|
||||||
|
.textFieldBorderTopPanelColor,
|
||||||
|
suffixIcon: SizedBox(width: 36),
|
||||||
|
placeholderTextStyle: TextStyle(
|
||||||
|
fontSize: 16,
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
color: Theme.of(context).extension<ExchangePageTheme>()!.hintTextColor,
|
||||||
|
),
|
||||||
|
textStyle: TextStyle(
|
||||||
|
fontSize: 16, fontWeight: FontWeight.w600, color: Colors.white),
|
||||||
|
validator: null,
|
||||||
|
),
|
||||||
|
SizedBox(height: 24),
|
||||||
|
if (invoice.description?.isNotEmpty ?? false) ...[
|
||||||
|
BaseTextFormField(
|
||||||
|
enabled: false,
|
||||||
|
initialValue: "${S.of(context).description}: ${invoice.description}",
|
||||||
|
textInputAction: TextInputAction.next,
|
||||||
|
borderColor: Theme.of(context)
|
||||||
|
.extension<ExchangePageTheme>()!
|
||||||
|
.textFieldBorderTopPanelColor,
|
||||||
|
suffixIcon: SizedBox(width: 36),
|
||||||
|
placeholderTextStyle: TextStyle(
|
||||||
|
fontSize: 16,
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
color: Theme.of(context).extension<ExchangePageTheme>()!.hintTextColor,
|
||||||
|
),
|
||||||
|
textStyle: TextStyle(
|
||||||
|
fontSize: 16, fontWeight: FontWeight.w600, color: Colors.white),
|
||||||
|
validator: null,
|
||||||
|
),
|
||||||
|
SizedBox(height: 24),
|
||||||
|
],
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
bottomSectionPadding: EdgeInsets.only(left: 24, right: 24, bottom: 24),
|
||||||
|
bottomSection: Observer(builder: (_) {
|
||||||
|
return Column(
|
||||||
|
children: <Widget>[
|
||||||
|
LoadingPrimaryButton(
|
||||||
|
text: S.of(context).send,
|
||||||
|
onPressed: () async {
|
||||||
|
try {
|
||||||
|
await lightningSendViewModel.send(
|
||||||
|
invoice,
|
||||||
|
int.parse(_amountController.text)
|
||||||
|
);
|
||||||
|
showPopUp<void>(
|
||||||
|
context: context,
|
||||||
|
builder: (BuildContext context) {
|
||||||
|
return AlertWithOneAction(
|
||||||
|
alertTitle: '',
|
||||||
|
alertContent:
|
||||||
|
S.of(context).send_success(CryptoCurrency.btc.toString()),
|
||||||
|
buttonText: S.of(context).ok,
|
||||||
|
buttonAction: () {
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
showPopUp<void>(
|
||||||
|
context: context,
|
||||||
|
builder: (BuildContext context) {
|
||||||
|
return AlertWithOneAction(
|
||||||
|
alertTitle: S.of(context).error,
|
||||||
|
alertContent: e.toString(),
|
||||||
|
buttonText: S.of(context).ok,
|
||||||
|
buttonAction: () => Navigator.of(context).pop());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
color: Theme.of(context).primaryColor,
|
||||||
|
textColor: Colors.white,
|
||||||
|
isLoading: lightningSendViewModel.loading,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<bool> _onNavigateBack(BuildContext context) async {
|
||||||
|
onClose(context);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void _setEffects(BuildContext context) {
|
||||||
|
if (_effectsInstalled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_amountController.addListener(() {
|
||||||
|
final amount = _amountController.text;
|
||||||
|
_fiatAmountController.text = lightningSendViewModel.formattedFiatAmount(int.parse(amount));
|
||||||
|
});
|
||||||
|
|
||||||
|
_effectsInstalled = true;
|
||||||
|
}
|
||||||
|
}
|
233
lib/src/screens/send/lightning_send_page.dart
Normal file
233
lib/src/screens/send/lightning_send_page.dart
Normal file
|
@ -0,0 +1,233 @@
|
||||||
|
import 'package:breez_sdk/breez_sdk.dart';
|
||||||
|
import 'package:breez_sdk/bridge_generated.dart';
|
||||||
|
import 'package:cake_wallet/core/auth_service.dart';
|
||||||
|
import 'package:cake_wallet/src/widgets/address_text_field.dart';
|
||||||
|
import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
|
||||||
|
import 'package:cake_wallet/src/widgets/keyboard_done_button.dart';
|
||||||
|
import 'package:cake_wallet/themes/extensions/exchange_page_theme.dart';
|
||||||
|
import 'package:cake_wallet/themes/extensions/keyboard_theme.dart';
|
||||||
|
import 'package:cake_wallet/themes/extensions/send_page_theme.dart';
|
||||||
|
import 'package:cake_wallet/themes/theme_base.dart';
|
||||||
|
import 'package:cake_wallet/utils/payment_request.dart';
|
||||||
|
import 'package:cake_wallet/utils/responsive_layout_util.dart';
|
||||||
|
import 'package:cake_wallet/utils/show_pop_up.dart';
|
||||||
|
import 'package:cake_wallet/view_model/lightning_send_view_model.dart';
|
||||||
|
import 'package:cake_wallet/view_model/send/output.dart';
|
||||||
|
import 'package:cw_core/crypto_currency.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:keyboard_actions/keyboard_actions.dart';
|
||||||
|
import 'package:cake_wallet/routes.dart';
|
||||||
|
import 'package:cake_wallet/src/screens/base_page.dart';
|
||||||
|
import 'package:cake_wallet/src/widgets/primary_button.dart';
|
||||||
|
import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart';
|
||||||
|
import 'package:cake_wallet/src/widgets/trail_button.dart';
|
||||||
|
import 'package:cake_wallet/generated/i18n.dart';
|
||||||
|
|
||||||
|
class LightningSendPage extends BasePage {
|
||||||
|
LightningSendPage({
|
||||||
|
required this.output,
|
||||||
|
required this.authService,
|
||||||
|
required this.lightningSendViewModel,
|
||||||
|
}) : _formKey = GlobalKey<FormState>();
|
||||||
|
|
||||||
|
final Output output;
|
||||||
|
final AuthService authService;
|
||||||
|
final LightningSendViewModel lightningSendViewModel;
|
||||||
|
final GlobalKey<FormState> _formKey;
|
||||||
|
|
||||||
|
final bolt11Controller = TextEditingController();
|
||||||
|
final bolt11FocusNode = FocusNode();
|
||||||
|
|
||||||
|
bool _effectsInstalled = false;
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get title => S.current.send;
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool get gradientAll => true;
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool get resizeToAvoidBottomInset => false;
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool get extendBodyBehindAppBar => true;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget? leading(BuildContext context) {
|
||||||
|
final _backButton = Icon(
|
||||||
|
Icons.arrow_back_ios,
|
||||||
|
color: titleColor(context),
|
||||||
|
size: 16,
|
||||||
|
);
|
||||||
|
final _closeButton =
|
||||||
|
currentTheme.type == ThemeType.dark ? closeButtonImageDarkTheme : closeButtonImage;
|
||||||
|
|
||||||
|
bool isMobileView = responsiveLayoutUtil.shouldRenderMobileUI;
|
||||||
|
|
||||||
|
return MergeSemantics(
|
||||||
|
child: SizedBox(
|
||||||
|
height: isMobileView ? 37 : 45,
|
||||||
|
width: isMobileView ? 37 : 45,
|
||||||
|
child: ButtonTheme(
|
||||||
|
minWidth: double.minPositive,
|
||||||
|
child: Semantics(
|
||||||
|
label: !isMobileView ? S.of(context).close : S.of(context).seed_alert_back,
|
||||||
|
child: TextButton(
|
||||||
|
style: ButtonStyle(
|
||||||
|
overlayColor: MaterialStateColor.resolveWith((states) => Colors.transparent),
|
||||||
|
),
|
||||||
|
onPressed: () => onClose(context),
|
||||||
|
child: !isMobileView ? _closeButton : _backButton,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
AppBarStyle get appBarStyle => AppBarStyle.transparent;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void onClose(BuildContext context) {
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget trailing(context) => TrailButton(
|
||||||
|
caption: S.of(context).clear,
|
||||||
|
onPressed: () {
|
||||||
|
_formKey.currentState?.reset();
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget body(BuildContext context) {
|
||||||
|
_setEffects(context);
|
||||||
|
|
||||||
|
return WillPopScope(
|
||||||
|
onWillPop: () => _onNavigateBack(context),
|
||||||
|
child: KeyboardActions(
|
||||||
|
disableScroll: true,
|
||||||
|
config: KeyboardActionsConfig(
|
||||||
|
keyboardActionsPlatform: KeyboardActionsPlatform.IOS,
|
||||||
|
keyboardBarColor: Theme.of(context).extension<KeyboardTheme>()!.keyboardBarColor,
|
||||||
|
nextFocus: false,
|
||||||
|
actions: [
|
||||||
|
KeyboardActionsItem(
|
||||||
|
focusNode: FocusNode(),
|
||||||
|
toolbarButtons: [(_) => KeyboardDoneButton()],
|
||||||
|
),
|
||||||
|
]),
|
||||||
|
child: Container(
|
||||||
|
color: Theme.of(context).colorScheme.background,
|
||||||
|
child: ScrollableWithBottomSection(
|
||||||
|
contentPadding: EdgeInsets.only(bottom: 24),
|
||||||
|
content: Container(
|
||||||
|
decoration: responsiveLayoutUtil.shouldRenderMobileUI
|
||||||
|
? BoxDecoration(
|
||||||
|
borderRadius: BorderRadius.only(
|
||||||
|
bottomLeft: Radius.circular(24), bottomRight: Radius.circular(24)),
|
||||||
|
gradient: LinearGradient(
|
||||||
|
colors: [
|
||||||
|
Theme.of(context)
|
||||||
|
.extension<ExchangePageTheme>()!
|
||||||
|
.firstGradientTopPanelColor,
|
||||||
|
Theme.of(context)
|
||||||
|
.extension<ExchangePageTheme>()!
|
||||||
|
.secondGradientTopPanelColor,
|
||||||
|
],
|
||||||
|
begin: Alignment.topLeft,
|
||||||
|
end: Alignment.bottomRight,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
: null,
|
||||||
|
child: Padding(
|
||||||
|
padding: EdgeInsets.fromLTRB(24, 120, 24, 0),
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
AddressTextField(
|
||||||
|
focusNode: bolt11FocusNode,
|
||||||
|
controller: bolt11Controller,
|
||||||
|
onURIScanned: (uri) {
|
||||||
|
final paymentRequest = PaymentRequest.fromUri(uri);
|
||||||
|
bolt11Controller.text = paymentRequest.address;
|
||||||
|
},
|
||||||
|
options: [
|
||||||
|
AddressTextFieldOption.paste,
|
||||||
|
AddressTextFieldOption.qrCode,
|
||||||
|
AddressTextFieldOption.addressBook
|
||||||
|
],
|
||||||
|
buttonColor:
|
||||||
|
Theme.of(context).extension<SendPageTheme>()!.textFieldButtonColor,
|
||||||
|
borderColor:
|
||||||
|
Theme.of(context).extension<SendPageTheme>()!.textFieldBorderColor,
|
||||||
|
textStyle:
|
||||||
|
TextStyle(fontSize: 14, fontWeight: FontWeight.w500, color: Colors.white),
|
||||||
|
hintStyle: TextStyle(
|
||||||
|
fontSize: 14,
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
|
color: Theme.of(context).extension<SendPageTheme>()!.textFieldHintColor),
|
||||||
|
onPushPasteButton: (context) async {
|
||||||
|
output.resetParsedAddress();
|
||||||
|
await output.fetchParsedAddress(context);
|
||||||
|
await send(context);
|
||||||
|
},
|
||||||
|
onPushAddressBookButton: (context) async {
|
||||||
|
output.resetParsedAddress();
|
||||||
|
},
|
||||||
|
onSelectedContact: (contact) {
|
||||||
|
output.loadContact(contact);
|
||||||
|
},
|
||||||
|
selectedCurrency: CryptoCurrency.btc,
|
||||||
|
),
|
||||||
|
SizedBox(height: 24),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
bottomSectionPadding: EdgeInsets.only(left: 24, right: 24, bottom: 24),
|
||||||
|
bottomSection: Column(
|
||||||
|
children: <Widget>[
|
||||||
|
PrimaryButton(
|
||||||
|
text: S.of(context).send,
|
||||||
|
color: Theme.of(context).primaryColor,
|
||||||
|
textColor: Colors.white,
|
||||||
|
onPressed: () => send(context),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> send(BuildContext context) async {
|
||||||
|
try {
|
||||||
|
await lightningSendViewModel.processInput(context, bolt11Controller.text);
|
||||||
|
} catch (e) {
|
||||||
|
showPopUp<void>(
|
||||||
|
context: context,
|
||||||
|
builder: (BuildContext context) {
|
||||||
|
return AlertWithOneAction(
|
||||||
|
alertTitle: S.of(context).error,
|
||||||
|
alertContent: e.toString(),
|
||||||
|
buttonText: S.of(context).ok,
|
||||||
|
buttonAction: () => Navigator.of(context).pop());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<bool> _onNavigateBack(BuildContext context) async {
|
||||||
|
onClose(context);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void _setEffects(BuildContext context) {
|
||||||
|
if (_effectsInstalled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_effectsInstalled = true;
|
||||||
|
}
|
||||||
|
}
|
|
@ -90,14 +90,22 @@ class ConnectionSyncPage extends BasePage {
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
SettingsCellWithArrow(
|
Observer(
|
||||||
title: S.current.manage_nodes,
|
builder: (context) {
|
||||||
handler: (context) => Navigator.of(context).pushNamed(Routes.manageNodes),
|
if (!dashboardViewModel.hasNodes) return const SizedBox();
|
||||||
|
return Column(
|
||||||
|
children: [
|
||||||
|
SettingsCellWithArrow(
|
||||||
|
title: S.current.manage_nodes,
|
||||||
|
handler: (context) => Navigator.of(context).pushNamed(Routes.manageNodes),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
},
|
||||||
),
|
),
|
||||||
Observer(
|
Observer(
|
||||||
builder: (context) {
|
builder: (context) {
|
||||||
if (!dashboardViewModel.hasPowNodes) return const SizedBox();
|
if (!dashboardViewModel.hasPowNodes) return const SizedBox();
|
||||||
|
|
||||||
return Column(
|
return Column(
|
||||||
children: [
|
children: [
|
||||||
SettingsCellWithArrow(
|
SettingsCellWithArrow(
|
||||||
|
|
|
@ -96,6 +96,7 @@ class WalletListBody extends StatefulWidget {
|
||||||
class WalletListBodyState extends State<WalletListBody> {
|
class WalletListBodyState extends State<WalletListBody> {
|
||||||
final moneroIcon = Image.asset('assets/images/monero_logo.png', height: 24, width: 24);
|
final moneroIcon = Image.asset('assets/images/monero_logo.png', height: 24, width: 24);
|
||||||
final bitcoinIcon = Image.asset('assets/images/bitcoin.png', height: 24, width: 24);
|
final bitcoinIcon = Image.asset('assets/images/bitcoin.png', height: 24, width: 24);
|
||||||
|
final lightningIcon = Image.asset('assets/images/lightning_logo.png', height: 24, width: 24);
|
||||||
final tBitcoinIcon = Image.asset('assets/images/tbtc.png', height: 24, width: 24);
|
final tBitcoinIcon = Image.asset('assets/images/tbtc.png', height: 24, width: 24);
|
||||||
final litecoinIcon = Image.asset('assets/images/litecoin_icon.png', height: 24, width: 24);
|
final litecoinIcon = Image.asset('assets/images/litecoin_icon.png', height: 24, width: 24);
|
||||||
final nonWalletTypeIcon = Image.asset('assets/images/close.png', height: 24, width: 24);
|
final nonWalletTypeIcon = Image.asset('assets/images/close.png', height: 24, width: 24);
|
||||||
|
@ -309,6 +310,8 @@ class WalletListBodyState extends State<WalletListBody> {
|
||||||
return tBitcoinIcon;
|
return tBitcoinIcon;
|
||||||
}
|
}
|
||||||
return bitcoinIcon;
|
return bitcoinIcon;
|
||||||
|
case WalletType.lightning:
|
||||||
|
return lightningIcon;
|
||||||
case WalletType.monero:
|
case WalletType.monero:
|
||||||
return moneroIcon;
|
return moneroIcon;
|
||||||
case WalletType.litecoin:
|
case WalletType.litecoin:
|
||||||
|
|
|
@ -10,6 +10,7 @@ class AlertWithTwoActions extends BaseAlertDialog {
|
||||||
required this.rightButtonText,
|
required this.rightButtonText,
|
||||||
required this.actionLeftButton,
|
required this.actionLeftButton,
|
||||||
required this.actionRightButton,
|
required this.actionRightButton,
|
||||||
|
this.contentWidget,
|
||||||
this.alertBarrierDismissible = true,
|
this.alertBarrierDismissible = true,
|
||||||
this.isDividerExist = false,
|
this.isDividerExist = false,
|
||||||
// this.leftActionColor,
|
// this.leftActionColor,
|
||||||
|
@ -20,6 +21,7 @@ class AlertWithTwoActions extends BaseAlertDialog {
|
||||||
final String alertContent;
|
final String alertContent;
|
||||||
final String leftButtonText;
|
final String leftButtonText;
|
||||||
final String rightButtonText;
|
final String rightButtonText;
|
||||||
|
final Widget? contentWidget;
|
||||||
final VoidCallback actionLeftButton;
|
final VoidCallback actionLeftButton;
|
||||||
final VoidCallback actionRightButton;
|
final VoidCallback actionRightButton;
|
||||||
final bool alertBarrierDismissible;
|
final bool alertBarrierDismissible;
|
||||||
|
@ -47,4 +49,9 @@ class AlertWithTwoActions extends BaseAlertDialog {
|
||||||
// Color get rightButtonColor => rightActionColor;
|
// Color get rightButtonColor => rightActionColor;
|
||||||
@override
|
@override
|
||||||
bool get isDividerExists => isDividerExist;
|
bool get isDividerExists => isDividerExist;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget content(BuildContext context) {
|
||||||
|
return contentWidget ?? super.content(context);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ import 'package:cake_wallet/di.dart';
|
||||||
import 'package:cake_wallet/reactions/wallet_connect.dart';
|
import 'package:cake_wallet/reactions/wallet_connect.dart';
|
||||||
import 'package:cake_wallet/utils/exception_handler.dart';
|
import 'package:cake_wallet/utils/exception_handler.dart';
|
||||||
import 'package:cw_core/transaction_info.dart';
|
import 'package:cw_core/transaction_info.dart';
|
||||||
|
import 'package:cw_core/wallet_type.dart';
|
||||||
import 'package:mobx/mobx.dart';
|
import 'package:mobx/mobx.dart';
|
||||||
import 'package:cw_core/balance.dart';
|
import 'package:cw_core/balance.dart';
|
||||||
import 'package:cw_core/wallet_base.dart';
|
import 'package:cw_core/wallet_base.dart';
|
||||||
|
@ -37,7 +38,8 @@ abstract class AppStoreBase with Store {
|
||||||
@action
|
@action
|
||||||
Future<void> changeCurrentWallet(
|
Future<void> changeCurrentWallet(
|
||||||
WalletBase<Balance, TransactionHistoryBase<TransactionInfo>, TransactionInfo> wallet) async {
|
WalletBase<Balance, TransactionHistoryBase<TransactionInfo>, TransactionInfo> wallet) async {
|
||||||
this.wallet?.close();
|
bool switchingToSameWalletType = this.wallet?.type == wallet.type;
|
||||||
|
this.wallet?.close(switchingToSameWalletType: switchingToSameWalletType);
|
||||||
this.wallet = wallet;
|
this.wallet = wallet;
|
||||||
this.wallet!.setExceptionHandler(ExceptionHandler.onError);
|
this.wallet!.setExceptionHandler(ExceptionHandler.onError);
|
||||||
|
|
||||||
|
|
|
@ -956,6 +956,7 @@ abstract class SettingsStoreBase with Store {
|
||||||
|
|
||||||
if (bitcoinElectrumServer != null) {
|
if (bitcoinElectrumServer != null) {
|
||||||
nodes[WalletType.bitcoin] = bitcoinElectrumServer;
|
nodes[WalletType.bitcoin] = bitcoinElectrumServer;
|
||||||
|
nodes[WalletType.lightning] = bitcoinElectrumServer;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (litecoinElectrumServer != null) {
|
if (litecoinElectrumServer != null) {
|
||||||
|
@ -1320,6 +1321,7 @@ abstract class SettingsStoreBase with Store {
|
||||||
|
|
||||||
if (bitcoinElectrumServer != null) {
|
if (bitcoinElectrumServer != null) {
|
||||||
nodes[WalletType.bitcoin] = bitcoinElectrumServer;
|
nodes[WalletType.bitcoin] = bitcoinElectrumServer;
|
||||||
|
nodes[WalletType.lightning] = bitcoinElectrumServer;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (litecoinElectrumServer != null) {
|
if (litecoinElectrumServer != null) {
|
||||||
|
|
|
@ -48,6 +48,7 @@ abstract class AdvancedPrivacySettingsViewModelBase with Store {
|
||||||
case WalletType.haven:
|
case WalletType.haven:
|
||||||
case WalletType.nano:
|
case WalletType.nano:
|
||||||
case WalletType.banano:
|
case WalletType.banano:
|
||||||
|
case WalletType.lightning:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -65,7 +65,9 @@ abstract class BalanceViewModelBase with Store {
|
||||||
|
|
||||||
@computed
|
@computed
|
||||||
double get price {
|
double get price {
|
||||||
final price = fiatConvertationStore.prices[appStore.wallet!.currency];
|
CryptoCurrency currency = appStore.wallet!.currency;
|
||||||
|
|
||||||
|
final price = fiatConvertationStore.prices[currency];
|
||||||
|
|
||||||
if (price == null) {
|
if (price == null) {
|
||||||
// price should update on next fetch:
|
// price should update on next fetch:
|
||||||
|
@ -153,6 +155,8 @@ abstract class BalanceViewModelBase with Store {
|
||||||
case WalletType.nano:
|
case WalletType.nano:
|
||||||
case WalletType.banano:
|
case WalletType.banano:
|
||||||
return S.current.receivable_balance;
|
return S.current.receivable_balance;
|
||||||
|
case WalletType.lightning:
|
||||||
|
return S.current.max_receivable;
|
||||||
default:
|
default:
|
||||||
return S.current.unconfirmed;
|
return S.current.unconfirmed;
|
||||||
}
|
}
|
||||||
|
@ -249,6 +253,7 @@ abstract class BalanceViewModelBase with Store {
|
||||||
asset: key,
|
asset: key,
|
||||||
formattedAssetTitle: _formatterAsset(key)));
|
formattedAssetTitle: _formatterAsset(key)));
|
||||||
}
|
}
|
||||||
|
|
||||||
final fiatCurrency = settingsStore.fiatCurrency;
|
final fiatCurrency = settingsStore.fiatCurrency;
|
||||||
final price = fiatConvertationStore.prices[key] ?? 0;
|
final price = fiatConvertationStore.prices[key] ?? 0;
|
||||||
|
|
||||||
|
@ -262,7 +267,7 @@ abstract class BalanceViewModelBase with Store {
|
||||||
' ' +
|
' ' +
|
||||||
_getFiatBalance(price: price, cryptoAmount: value.formattedAdditionalBalance));
|
_getFiatBalance(price: price, cryptoAmount: value.formattedAdditionalBalance));
|
||||||
|
|
||||||
final availableFiatBalance = isFiatDisabled
|
var availableFiatBalance = isFiatDisabled
|
||||||
? ''
|
? ''
|
||||||
: (fiatCurrency.toString() +
|
: (fiatCurrency.toString() +
|
||||||
' ' +
|
' ' +
|
||||||
|
@ -397,6 +402,7 @@ abstract class BalanceViewModelBase with Store {
|
||||||
}
|
}
|
||||||
|
|
||||||
String _getFiatBalance({required double price, String? cryptoAmount}) {
|
String _getFiatBalance({required double price, String? cryptoAmount}) {
|
||||||
|
cryptoAmount = cryptoAmount?.replaceAll(',', '');// fix for amounts > 1000
|
||||||
if (cryptoAmount == null || cryptoAmount.isEmpty || double.tryParse(cryptoAmount) == null) {
|
if (cryptoAmount == null || cryptoAmount.isEmpty || double.tryParse(cryptoAmount) == null) {
|
||||||
return '0.00';
|
return '0.00';
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
|
|
||||||
|
import 'package:breez_sdk/bridge_generated.dart';
|
||||||
import 'package:cake_wallet/buy/buy_provider.dart';
|
import 'package:cake_wallet/buy/buy_provider.dart';
|
||||||
import 'package:cake_wallet/core/key_service.dart';
|
import 'package:cake_wallet/core/key_service.dart';
|
||||||
import 'package:cake_wallet/entities/auto_generate_subaddress_status.dart';
|
import 'package:cake_wallet/entities/auto_generate_subaddress_status.dart';
|
||||||
|
@ -29,6 +30,7 @@ import 'package:cake_wallet/view_model/dashboard/formatted_item_list.dart';
|
||||||
import 'package:cake_wallet/view_model/dashboard/order_list_item.dart';
|
import 'package:cake_wallet/view_model/dashboard/order_list_item.dart';
|
||||||
import 'package:cake_wallet/view_model/dashboard/trade_list_item.dart';
|
import 'package:cake_wallet/view_model/dashboard/trade_list_item.dart';
|
||||||
import 'package:cake_wallet/view_model/dashboard/transaction_list_item.dart';
|
import 'package:cake_wallet/view_model/dashboard/transaction_list_item.dart';
|
||||||
|
import 'package:cake_wallet/view_model/lightning_view_model.dart';
|
||||||
import 'package:cake_wallet/view_model/settings/sync_mode.dart';
|
import 'package:cake_wallet/view_model/settings/sync_mode.dart';
|
||||||
import 'package:cake_wallet/wallet_type_utils.dart';
|
import 'package:cake_wallet/wallet_type_utils.dart';
|
||||||
import 'package:cryptography/cryptography.dart';
|
import 'package:cryptography/cryptography.dart';
|
||||||
|
@ -54,19 +56,20 @@ part 'dashboard_view_model.g.dart';
|
||||||
class DashboardViewModel = DashboardViewModelBase with _$DashboardViewModel;
|
class DashboardViewModel = DashboardViewModelBase with _$DashboardViewModel;
|
||||||
|
|
||||||
abstract class DashboardViewModelBase with Store {
|
abstract class DashboardViewModelBase with Store {
|
||||||
DashboardViewModelBase(
|
DashboardViewModelBase({
|
||||||
{required this.balanceViewModel,
|
required this.balanceViewModel,
|
||||||
required this.appStore,
|
required this.appStore,
|
||||||
required this.tradesStore,
|
required this.tradesStore,
|
||||||
required this.tradeFilterStore,
|
required this.tradeFilterStore,
|
||||||
required this.transactionFilterStore,
|
required this.transactionFilterStore,
|
||||||
required this.settingsStore,
|
required this.settingsStore,
|
||||||
required this.yatStore,
|
required this.yatStore,
|
||||||
required this.ordersStore,
|
required this.ordersStore,
|
||||||
required this.anonpayTransactionsStore,
|
required this.anonpayTransactionsStore,
|
||||||
required this.sharedPreferences,
|
required this.sharedPreferences,
|
||||||
required this.keyService})
|
required this.keyService,
|
||||||
: hasSellAction = false,
|
required this.lightningViewModel,
|
||||||
|
}) : hasSellAction = false,
|
||||||
hasBuyAction = false,
|
hasBuyAction = false,
|
||||||
hasExchangeAction = false,
|
hasExchangeAction = false,
|
||||||
isShowFirstYatIntroduction = false,
|
isShowFirstYatIntroduction = false,
|
||||||
|
@ -345,6 +348,8 @@ abstract class DashboardViewModelBase with Store {
|
||||||
|
|
||||||
TransactionFilterStore transactionFilterStore;
|
TransactionFilterStore transactionFilterStore;
|
||||||
|
|
||||||
|
LightningViewModel lightningViewModel;
|
||||||
|
|
||||||
Map<String, List<FilterItem>> filterItems;
|
Map<String, List<FilterItem>> filterItems;
|
||||||
|
|
||||||
BuyProvider? get defaultBuyProvider => ProvidersHelper.getProviderByType(
|
BuyProvider? get defaultBuyProvider => ProvidersHelper.getProviderByType(
|
||||||
|
@ -383,7 +388,12 @@ abstract class DashboardViewModelBase with Store {
|
||||||
void furtherShowYatPopup(bool shouldShow) => settingsStore.shouldShowYatPopup = shouldShow;
|
void furtherShowYatPopup(bool shouldShow) => settingsStore.shouldShowYatPopup = shouldShow;
|
||||||
|
|
||||||
@computed
|
@computed
|
||||||
bool get isEnabledExchangeAction => settingsStore.exchangeStatus != ExchangeApiMode.disabled;
|
bool get isEnabledExchangeAction {
|
||||||
|
if (wallet.type == WalletType.lightning) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return settingsStore.exchangeStatus != ExchangeApiMode.disabled;
|
||||||
|
}
|
||||||
|
|
||||||
@observable
|
@observable
|
||||||
bool hasExchangeAction;
|
bool hasExchangeAction;
|
||||||
|
@ -407,9 +417,26 @@ abstract class DashboardViewModelBase with Store {
|
||||||
|
|
||||||
ReactionDisposer? _onMoneroBalanceChangeReaction;
|
ReactionDisposer? _onMoneroBalanceChangeReaction;
|
||||||
|
|
||||||
|
@computed
|
||||||
|
bool get hasNodes => wallet.type != WalletType.lightning;
|
||||||
|
|
||||||
@computed
|
@computed
|
||||||
bool get hasPowNodes => wallet.type == WalletType.nano || wallet.type == WalletType.banano;
|
bool get hasPowNodes => wallet.type == WalletType.nano || wallet.type == WalletType.banano;
|
||||||
|
|
||||||
|
String get serviceMessage {
|
||||||
|
if (wallet.type == WalletType.lightning) {
|
||||||
|
final serviceStatus = lightningViewModel.serviceHealthCheck();
|
||||||
|
if (serviceStatus == HealthCheckStatus.ServiceDisruption) {
|
||||||
|
return S.current.breez_warning_disruption;
|
||||||
|
} else if (serviceStatus == HealthCheckStatus.Maintenance) {
|
||||||
|
return S.current.breez_warning_maintenance;
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
bool get showRepWarning {
|
bool get showRepWarning {
|
||||||
if (wallet.type != WalletType.nano) {
|
if (wallet.type != WalletType.nano) {
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import 'package:cake_wallet/bitcoin/bitcoin.dart';
|
import 'package:cake_wallet/bitcoin/bitcoin.dart';
|
||||||
|
import 'package:cake_wallet/lightning/lightning.dart';
|
||||||
import 'package:cw_core/receive_page_option.dart';
|
import 'package:cw_core/receive_page_option.dart';
|
||||||
import 'package:cw_core/wallet_base.dart';
|
import 'package:cw_core/wallet_base.dart';
|
||||||
import 'package:cw_core/wallet_type.dart';
|
import 'package:cw_core/wallet_type.dart';
|
||||||
|
@ -16,14 +17,28 @@ abstract class ReceiveOptionViewModelBase with Store {
|
||||||
: ReceivePageOption.mainnet),
|
: ReceivePageOption.mainnet),
|
||||||
_options = [] {
|
_options = [] {
|
||||||
final walletType = _wallet.type;
|
final walletType = _wallet.type;
|
||||||
_options = walletType == WalletType.haven
|
|
||||||
? [ReceivePageOption.mainnet]
|
switch (walletType) {
|
||||||
: walletType == WalletType.bitcoin
|
case WalletType.haven:
|
||||||
? [
|
_options = [ReceivePageOption.mainnet];
|
||||||
...bitcoin!.getBitcoinReceivePageOptions(),
|
break;
|
||||||
...ReceivePageOptions.where((element) => element != ReceivePageOption.mainnet)
|
case WalletType.lightning:
|
||||||
]
|
_options = [...lightning!.getLightningReceivePageOptions()];
|
||||||
: ReceivePageOptions;
|
break;
|
||||||
|
case WalletType.bitcoin:
|
||||||
|
_options = [
|
||||||
|
...bitcoin!.getBitcoinReceivePageOptions(),
|
||||||
|
...ReceivePageOptions.where((element) => element != ReceivePageOption.mainnet)
|
||||||
|
];
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
_options = [
|
||||||
|
ReceivePageOption.mainnet,
|
||||||
|
ReceivePageOption.anonPayDonationLink,
|
||||||
|
ReceivePageOption.anonPayInvoice
|
||||||
|
];
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
final WalletBase _wallet;
|
final WalletBase _wallet;
|
||||||
|
|
|
@ -2,6 +2,7 @@ import 'package:cake_wallet/entities/balance_display_mode.dart';
|
||||||
import 'package:cake_wallet/entities/fiat_currency.dart';
|
import 'package:cake_wallet/entities/fiat_currency.dart';
|
||||||
import 'package:cake_wallet/ethereum/ethereum.dart';
|
import 'package:cake_wallet/ethereum/ethereum.dart';
|
||||||
import 'package:cake_wallet/generated/i18n.dart';
|
import 'package:cake_wallet/generated/i18n.dart';
|
||||||
|
import 'package:cake_wallet/lightning/lightning.dart';
|
||||||
import 'package:cake_wallet/nano/nano.dart';
|
import 'package:cake_wallet/nano/nano.dart';
|
||||||
import 'package:cake_wallet/polygon/polygon.dart';
|
import 'package:cake_wallet/polygon/polygon.dart';
|
||||||
import 'package:cake_wallet/reactions/wallet_connect.dart';
|
import 'package:cake_wallet/reactions/wallet_connect.dart';
|
||||||
|
@ -122,6 +123,11 @@ class TransactionListItem extends ActionListItem with Keyable {
|
||||||
cryptoAmount: bitcoin!.formatterBitcoinAmountToDouble(amount: transaction.amount),
|
cryptoAmount: bitcoin!.formatterBitcoinAmountToDouble(amount: transaction.amount),
|
||||||
price: price);
|
price: price);
|
||||||
break;
|
break;
|
||||||
|
case WalletType.lightning:
|
||||||
|
amount = calculateFiatAmountRaw(
|
||||||
|
cryptoAmount: lightning!.formatterLightningAmountToDouble(amount: transaction.amount),
|
||||||
|
price: price);
|
||||||
|
break;
|
||||||
case WalletType.haven:
|
case WalletType.haven:
|
||||||
final asset = haven!.assetOfTransaction(transaction);
|
final asset = haven!.assetOfTransaction(transaction);
|
||||||
final price = balanceViewModel.fiatConvertationStore.prices[asset];
|
final price = balanceViewModel.fiatConvertationStore.prices[asset];
|
||||||
|
|
|
@ -174,6 +174,11 @@ abstract class ExchangeTradeViewModelBase with Store {
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool _checkIfCanSend(TradesStore tradesStore, WalletBase wallet) {
|
static bool _checkIfCanSend(TradesStore tradesStore, WalletBase wallet) {
|
||||||
|
|
||||||
|
if (wallet.currency == CryptoCurrency.btcln) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool _isEthToken() =>
|
bool _isEthToken() =>
|
||||||
wallet.currency == CryptoCurrency.eth &&
|
wallet.currency == CryptoCurrency.eth &&
|
||||||
tradesStore.trade!.from.tag == CryptoCurrency.eth.title;
|
tradesStore.trade!.from.tag == CryptoCurrency.eth.title;
|
||||||
|
|
|
@ -278,12 +278,16 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with
|
||||||
|
|
||||||
bool get hasAllAmount =>
|
bool get hasAllAmount =>
|
||||||
(wallet.type == WalletType.bitcoin ||
|
(wallet.type == WalletType.bitcoin ||
|
||||||
|
wallet.type == WalletType.lightning ||
|
||||||
wallet.type == WalletType.litecoin ||
|
wallet.type == WalletType.litecoin ||
|
||||||
wallet.type == WalletType.bitcoinCash) &&
|
wallet.type == WalletType.bitcoinCash) &&
|
||||||
depositCurrency == wallet.currency;
|
depositCurrency == wallet.currency;
|
||||||
|
|
||||||
bool get isMoneroWallet => wallet.type == WalletType.monero;
|
bool get isMoneroWallet => wallet.type == WalletType.monero;
|
||||||
|
|
||||||
|
// lightning doesn't have the same concept of "addresses" (since it uses invoices)
|
||||||
|
bool get hasAddress => wallet.type != WalletType.lightning;
|
||||||
|
|
||||||
bool get isLowFee {
|
bool get isLowFee {
|
||||||
switch (wallet.type) {
|
switch (wallet.type) {
|
||||||
case WalletType.monero:
|
case WalletType.monero:
|
||||||
|
@ -539,6 +543,7 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with
|
||||||
/// return after the first successful trade
|
/// return after the first successful trade
|
||||||
return;
|
return;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
print(e);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -651,6 +656,10 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with
|
||||||
depositCurrency = CryptoCurrency.btc;
|
depositCurrency = CryptoCurrency.btc;
|
||||||
receiveCurrency = CryptoCurrency.xmr;
|
receiveCurrency = CryptoCurrency.xmr;
|
||||||
break;
|
break;
|
||||||
|
case WalletType.lightning:
|
||||||
|
depositCurrency = CryptoCurrency.btcln;
|
||||||
|
receiveCurrency = CryptoCurrency.xmr;
|
||||||
|
break;
|
||||||
case WalletType.litecoin:
|
case WalletType.litecoin:
|
||||||
depositCurrency = CryptoCurrency.ltc;
|
depositCurrency = CryptoCurrency.ltc;
|
||||||
receiveCurrency = CryptoCurrency.xmr;
|
receiveCurrency = CryptoCurrency.xmr;
|
||||||
|
|
130
lib/view_model/lightning_invoice_page_view_model.dart
Normal file
130
lib/view_model/lightning_invoice_page_view_model.dart
Normal file
|
@ -0,0 +1,130 @@
|
||||||
|
import 'package:cake_wallet/core/execution_state.dart';
|
||||||
|
import 'package:cake_wallet/entities/fiat_currency.dart';
|
||||||
|
import 'package:cake_wallet/store/settings_store.dart';
|
||||||
|
import 'package:cake_wallet/view_model/lightning_view_model.dart';
|
||||||
|
import 'package:cw_core/crypto_currency.dart';
|
||||||
|
import 'package:cw_core/currency.dart';
|
||||||
|
import 'package:cw_core/receive_page_option.dart';
|
||||||
|
import 'package:cw_core/wallet_base.dart';
|
||||||
|
import 'package:cw_core/wallet_type.dart';
|
||||||
|
import 'package:mobx/mobx.dart';
|
||||||
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
|
|
||||||
|
part 'lightning_invoice_page_view_model.g.dart';
|
||||||
|
|
||||||
|
class LightningInvoicePageViewModel = LightningInvoicePageViewModelBase
|
||||||
|
with _$LightningInvoicePageViewModel;
|
||||||
|
|
||||||
|
abstract class LightningInvoicePageViewModelBase with Store {
|
||||||
|
LightningInvoicePageViewModelBase(
|
||||||
|
this.settingsStore,
|
||||||
|
this._wallet,
|
||||||
|
this.sharedPreferences,
|
||||||
|
this.lightningViewModel,
|
||||||
|
) : description = '',
|
||||||
|
amount = '',
|
||||||
|
state = InitialExecutionState(),
|
||||||
|
selectedCurrency = walletTypeToCryptoCurrency(_wallet.type),
|
||||||
|
cryptoCurrency = walletTypeToCryptoCurrency(_wallet.type) {
|
||||||
|
_fetchLimits();
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Currency> get currencies => [walletTypeToCryptoCurrency(_wallet.type), ...FiatCurrency.all];
|
||||||
|
final SettingsStore settingsStore;
|
||||||
|
final WalletBase _wallet;
|
||||||
|
final SharedPreferences sharedPreferences;
|
||||||
|
final LightningViewModel lightningViewModel;
|
||||||
|
|
||||||
|
@observable
|
||||||
|
Currency selectedCurrency;
|
||||||
|
|
||||||
|
CryptoCurrency cryptoCurrency;
|
||||||
|
|
||||||
|
@observable
|
||||||
|
String description;
|
||||||
|
|
||||||
|
@observable
|
||||||
|
String amount;
|
||||||
|
|
||||||
|
@observable
|
||||||
|
ExecutionState state;
|
||||||
|
|
||||||
|
@computed
|
||||||
|
int get selectedCurrencyIndex => currencies.indexOf(selectedCurrency);
|
||||||
|
|
||||||
|
@observable
|
||||||
|
double? minimum;
|
||||||
|
|
||||||
|
@observable
|
||||||
|
double? maximum;
|
||||||
|
|
||||||
|
@action
|
||||||
|
void selectCurrency(Currency currency) {
|
||||||
|
selectedCurrency = currency;
|
||||||
|
maximum = minimum = null;
|
||||||
|
if (currency is CryptoCurrency) {
|
||||||
|
cryptoCurrency = currency;
|
||||||
|
} else {
|
||||||
|
cryptoCurrency = walletTypeToCryptoCurrency(_wallet.type);
|
||||||
|
}
|
||||||
|
|
||||||
|
_fetchLimits();
|
||||||
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
Future<void> createInvoice() async {
|
||||||
|
state = IsExecutingState();
|
||||||
|
if (amount.isNotEmpty) {
|
||||||
|
final amountInCrypto = double.tryParse(amount);
|
||||||
|
if (amountInCrypto == null) {
|
||||||
|
state = FailureState('Amount is invalid');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (minimum != null && amountInCrypto < minimum!) {
|
||||||
|
state = FailureState('Amount is too small');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (amountInCrypto > 4000000) {
|
||||||
|
state = FailureState('Amount is too big');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
String bolt11 = await lightningViewModel.createInvoice(
|
||||||
|
amountSats: amount,
|
||||||
|
description: description,
|
||||||
|
);
|
||||||
|
state = ExecutedSuccessfullyState(payload: bolt11);
|
||||||
|
} catch (e) {
|
||||||
|
state = FailureState(e.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
void setRequestParams({
|
||||||
|
required String inputAmount,
|
||||||
|
required String inputDescription,
|
||||||
|
}) {
|
||||||
|
description = inputDescription;
|
||||||
|
amount = inputAmount;
|
||||||
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
Future<void> _fetchLimits() async {
|
||||||
|
final limits = await lightningViewModel.invoiceSoftLimitsSats();
|
||||||
|
minimum = limits.minFee.toDouble();
|
||||||
|
maximum = limits.inboundLiquidity.toDouble();
|
||||||
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
void reset() {
|
||||||
|
selectedCurrency = walletTypeToCryptoCurrency(_wallet.type);
|
||||||
|
cryptoCurrency = walletTypeToCryptoCurrency(_wallet.type);
|
||||||
|
description = '';
|
||||||
|
amount = '';
|
||||||
|
try {
|
||||||
|
_fetchLimits();
|
||||||
|
} catch (_) {}
|
||||||
|
}
|
||||||
|
}
|
93
lib/view_model/lightning_send_view_model.dart
Normal file
93
lib/view_model/lightning_send_view_model.dart
Normal file
|
@ -0,0 +1,93 @@
|
||||||
|
import 'dart:async';
|
||||||
|
import 'package:breez_sdk/breez_sdk.dart';
|
||||||
|
import 'package:breez_sdk/bridge_generated.dart' as BZG;
|
||||||
|
import 'package:cake_wallet/entities/calculate_fiat_amount_raw.dart';
|
||||||
|
import 'package:cake_wallet/entities/fiat_currency.dart';
|
||||||
|
import 'package:cake_wallet/lightning/lightning.dart';
|
||||||
|
import 'package:cake_wallet/routes.dart';
|
||||||
|
import 'package:cake_wallet/store/dashboard/fiat_conversion_store.dart';
|
||||||
|
import 'package:cake_wallet/store/settings_store.dart';
|
||||||
|
import 'package:cw_core/crypto_currency.dart';
|
||||||
|
import 'package:flutter/widgets.dart';
|
||||||
|
import 'package:mobx/mobx.dart';
|
||||||
|
|
||||||
|
part 'lightning_send_view_model.g.dart';
|
||||||
|
|
||||||
|
class LightningSendViewModel = LightningSendViewModelBase with _$LightningSendViewModel;
|
||||||
|
|
||||||
|
abstract class LightningSendViewModelBase with Store {
|
||||||
|
LightningSendViewModelBase({
|
||||||
|
required this.settingsStore,
|
||||||
|
required this.fiatConversionStore,
|
||||||
|
}) {}
|
||||||
|
|
||||||
|
final SettingsStore settingsStore;
|
||||||
|
final FiatConversionStore fiatConversionStore;
|
||||||
|
|
||||||
|
@observable
|
||||||
|
bool loading = false;
|
||||||
|
|
||||||
|
@action
|
||||||
|
void setLoading(bool value) {
|
||||||
|
loading = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
FiatCurrency get fiat => settingsStore.fiatCurrency;
|
||||||
|
|
||||||
|
String formattedFiatAmount(int sats) {
|
||||||
|
String amount = calculateFiatAmountRaw(
|
||||||
|
cryptoAmount: lightning!.formatterLightningAmountToDouble(amount: sats),
|
||||||
|
price: fiatConversionStore.prices[CryptoCurrency.btcln],
|
||||||
|
);
|
||||||
|
return amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
Future<void> send(BZG.LNInvoice invoice, int satAmount) async {
|
||||||
|
try {
|
||||||
|
setLoading(true);
|
||||||
|
|
||||||
|
final sdk = await BreezSDK();
|
||||||
|
late BZG.SendPaymentRequest req;
|
||||||
|
|
||||||
|
if (invoice.amountMsat == null) {
|
||||||
|
req = BZG.SendPaymentRequest(
|
||||||
|
bolt11: invoice.bolt11,
|
||||||
|
amountMsat: satAmount * 1000,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
req = BZG.SendPaymentRequest(bolt11: invoice.bolt11);
|
||||||
|
}
|
||||||
|
|
||||||
|
await sdk.sendPayment(req: req);
|
||||||
|
|
||||||
|
setLoading(false);
|
||||||
|
} catch (e) {
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
Future<void> processInput(BuildContext context, String input) async {
|
||||||
|
FocusScope.of(context).unfocus();
|
||||||
|
|
||||||
|
final sdk = await BreezSDK();
|
||||||
|
|
||||||
|
late BZG.InputType inputType;
|
||||||
|
|
||||||
|
try {
|
||||||
|
inputType = await sdk.parseInput(input: input);
|
||||||
|
} catch (_) {
|
||||||
|
throw Exception("Unknown input type");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (inputType is BZG.InputType_Bolt11) {
|
||||||
|
final bolt11 = await sdk.parseInvoice(input);
|
||||||
|
Navigator.of(context).pushNamed(Routes.lightningSendConfirm, arguments: bolt11);
|
||||||
|
} else if (inputType is BZG.InputType_LnUrlPay) {
|
||||||
|
throw Exception("Unsupported input type");
|
||||||
|
} else {
|
||||||
|
throw Exception("Unknown input type");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
130
lib/view_model/lightning_view_model.dart
Normal file
130
lib/view_model/lightning_view_model.dart
Normal file
|
@ -0,0 +1,130 @@
|
||||||
|
import 'dart:async';
|
||||||
|
import 'package:breez_sdk/breez_sdk.dart';
|
||||||
|
import 'package:breez_sdk/bridge_generated.dart' as BZG;
|
||||||
|
import 'package:mobx/mobx.dart';
|
||||||
|
import 'package:cw_lightning/.secrets.g.dart' as secrets;
|
||||||
|
|
||||||
|
part 'lightning_view_model.g.dart';
|
||||||
|
|
||||||
|
class LightningViewModel = LightningViewModelBase with _$LightningViewModel;
|
||||||
|
|
||||||
|
abstract class LightningViewModelBase with Store {
|
||||||
|
LightningViewModelBase() {}
|
||||||
|
|
||||||
|
Future<ReceiveOnchainResult> receiveOnchain() async {
|
||||||
|
final sdk = await BreezSDK();
|
||||||
|
|
||||||
|
BZG.ReceiveOnchainRequest req = const BZG.ReceiveOnchainRequest();
|
||||||
|
BZG.SwapInfo swapInfo = await sdk.receiveOnchain(req: req);
|
||||||
|
print("Minimum amount allowed to deposit in sats: ${swapInfo.minAllowedDeposit}");
|
||||||
|
print("Maximum amount allowed to deposit in sats: ${swapInfo.maxAllowedDeposit}");
|
||||||
|
|
||||||
|
int fee = 0;
|
||||||
|
double feePercent = 0;
|
||||||
|
|
||||||
|
try {
|
||||||
|
final nodeState = (await sdk.nodeInfo())!;
|
||||||
|
int inboundLiquidity = nodeState.inboundLiquidityMsats ~/ 1000;
|
||||||
|
final openingFees = await sdk.openChannelFee(
|
||||||
|
req: BZG.OpenChannelFeeRequest(amountMsat: inboundLiquidity + 1));
|
||||||
|
feePercent = (openingFees.feeParams.proportional * 100) / 1000000;
|
||||||
|
fee = openingFees.feeParams.minMsat ~/ 1000;
|
||||||
|
} catch (_) {}
|
||||||
|
|
||||||
|
return ReceiveOnchainResult(
|
||||||
|
bitcoinAddress: swapInfo.bitcoinAddress,
|
||||||
|
minAllowedDeposit: swapInfo.minAllowedDeposit,
|
||||||
|
maxAllowedDeposit: swapInfo.maxAllowedDeposit,
|
||||||
|
feePercent: feePercent,
|
||||||
|
fee: fee,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<String> createInvoice({required String amountSats, String? description}) async {
|
||||||
|
final sdk = await BreezSDK();
|
||||||
|
final req = BZG.ReceivePaymentRequest(
|
||||||
|
amountMsat: (double.parse(amountSats) * 1000).round(),
|
||||||
|
description: description ?? '',
|
||||||
|
);
|
||||||
|
final res = await sdk.receivePayment(req: req);
|
||||||
|
return res.lnInvoice.bolt11;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<InvoiceSoftLimitsResult> invoiceSoftLimitsSats() async {
|
||||||
|
double feePercent = 0.4;
|
||||||
|
int minFee = (2500 * 1000) ~/ 1000; // 2500 sats
|
||||||
|
int inboundLiquidity = 1000000000 * 1000 * 10; // 10 BTC
|
||||||
|
int balance = 0;
|
||||||
|
|
||||||
|
final sdk = await BreezSDK();
|
||||||
|
|
||||||
|
try {
|
||||||
|
final nodeState = (await sdk.nodeInfo())!;
|
||||||
|
inboundLiquidity = nodeState.inboundLiquidityMsats ~/ 1000;
|
||||||
|
|
||||||
|
final openingFees = await sdk.openChannelFee(
|
||||||
|
req: BZG.OpenChannelFeeRequest(amountMsat: inboundLiquidity + 1));
|
||||||
|
|
||||||
|
feePercent = (openingFees.feeParams.proportional * 100) / 1000000;
|
||||||
|
minFee = openingFees.feeParams.minMsat ~/ 1000;
|
||||||
|
balance = nodeState.channelsBalanceMsat ~/ 1000;
|
||||||
|
} catch (_) {}
|
||||||
|
return InvoiceSoftLimitsResult(
|
||||||
|
minFee: minFee,
|
||||||
|
inboundLiquidity: inboundLiquidity,
|
||||||
|
feePercent: feePercent,
|
||||||
|
balance: balance,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<int> getBalanceSats() async {
|
||||||
|
try {
|
||||||
|
final sdk = await BreezSDK();
|
||||||
|
final nodeState = (await sdk.nodeInfo())!;
|
||||||
|
return nodeState.channelsBalanceMsat ~/ 1000;
|
||||||
|
} catch (_) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<BZG.HealthCheckStatus> serviceHealthCheck() async {
|
||||||
|
try {
|
||||||
|
final sdk = await BreezSDK();
|
||||||
|
BZG.ServiceHealthCheckResponse response =
|
||||||
|
await sdk.serviceHealthCheck(apiKey: secrets.breezApiKey);
|
||||||
|
return response.status;
|
||||||
|
} catch (_) {
|
||||||
|
return BZG.HealthCheckStatus.ServiceDisruption;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ReceiveOnchainResult {
|
||||||
|
final String bitcoinAddress;
|
||||||
|
final int minAllowedDeposit;
|
||||||
|
final int maxAllowedDeposit;
|
||||||
|
final int fee;
|
||||||
|
final double feePercent;
|
||||||
|
|
||||||
|
ReceiveOnchainResult({
|
||||||
|
required this.bitcoinAddress,
|
||||||
|
required this.minAllowedDeposit,
|
||||||
|
required this.maxAllowedDeposit,
|
||||||
|
required this.fee,
|
||||||
|
required this.feePercent,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
class InvoiceSoftLimitsResult {
|
||||||
|
final double feePercent;
|
||||||
|
final int minFee;
|
||||||
|
final int inboundLiquidity;
|
||||||
|
final int balance;
|
||||||
|
|
||||||
|
InvoiceSoftLimitsResult({
|
||||||
|
required this.inboundLiquidity,
|
||||||
|
required this.feePercent,
|
||||||
|
required this.minFee,
|
||||||
|
required this.balance,
|
||||||
|
});
|
||||||
|
}
|
|
@ -85,6 +85,7 @@ abstract class NodeCreateOrEditViewModelBase with Store {
|
||||||
case WalletType.litecoin:
|
case WalletType.litecoin:
|
||||||
case WalletType.bitcoinCash:
|
case WalletType.bitcoinCash:
|
||||||
case WalletType.bitcoin:
|
case WalletType.bitcoin:
|
||||||
|
case WalletType.lightning:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -58,6 +58,9 @@ abstract class NodeListViewModelBase with Store {
|
||||||
node = getBitcoinDefaultElectrumServer(nodes: _nodeSource)!;
|
node = getBitcoinDefaultElectrumServer(nodes: _nodeSource)!;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case WalletType.lightning:
|
||||||
|
node = getBitcoinDefaultElectrumServer(nodes: _nodeSource)!;
|
||||||
|
break;
|
||||||
case WalletType.monero:
|
case WalletType.monero:
|
||||||
node = getMoneroDefaultNode(nodes: _nodeSource);
|
node = getMoneroDefaultNode(nodes: _nodeSource);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -85,6 +85,7 @@ abstract class WalletRestorationFromQRVMBase extends WalletCreationVM with Store
|
||||||
spendKey: restoreWallet.spendKey ?? '',
|
spendKey: restoreWallet.spendKey ?? '',
|
||||||
height: restoreWallet.height ?? 0);
|
height: restoreWallet.height ?? 0);
|
||||||
case WalletType.bitcoin:
|
case WalletType.bitcoin:
|
||||||
|
case WalletType.lightning:
|
||||||
case WalletType.litecoin:
|
case WalletType.litecoin:
|
||||||
return bitcoin!.createBitcoinRestoreWalletFromWIFCredentials(
|
return bitcoin!.createBitcoinRestoreWalletFromWIFCredentials(
|
||||||
name: name, password: password, wif: wif);
|
name: name, password: password, wif: wif);
|
||||||
|
|
|
@ -22,6 +22,9 @@ class WalletRestoreFromQRCode {
|
||||||
'bitcoin': WalletType.bitcoin,
|
'bitcoin': WalletType.bitcoin,
|
||||||
'bitcoin-wallet': WalletType.bitcoin,
|
'bitcoin-wallet': WalletType.bitcoin,
|
||||||
'bitcoin_wallet': WalletType.bitcoin,
|
'bitcoin_wallet': WalletType.bitcoin,
|
||||||
|
'lightning': WalletType.lightning,
|
||||||
|
'lightning-wallet': WalletType.lightning,
|
||||||
|
'lightning_wallet': WalletType.lightning,
|
||||||
'litecoin': WalletType.litecoin,
|
'litecoin': WalletType.litecoin,
|
||||||
'litecoin-wallet': WalletType.litecoin,
|
'litecoin-wallet': WalletType.litecoin,
|
||||||
'litecoin_wallet': WalletType.litecoin,
|
'litecoin_wallet': WalletType.litecoin,
|
||||||
|
|
|
@ -58,6 +58,9 @@ abstract class TransactionDetailsViewModelBase with Store {
|
||||||
case WalletType.bitcoinCash:
|
case WalletType.bitcoinCash:
|
||||||
_addElectrumListItems(tx, dateFormat);
|
_addElectrumListItems(tx, dateFormat);
|
||||||
break;
|
break;
|
||||||
|
case WalletType.lightning:
|
||||||
|
_addLightningListItems(tx, dateFormat);
|
||||||
|
break;
|
||||||
case WalletType.haven:
|
case WalletType.haven:
|
||||||
_addHavenListItems(tx, dateFormat);
|
_addHavenListItems(tx, dateFormat);
|
||||||
break;
|
break;
|
||||||
|
@ -100,14 +103,16 @@ abstract class TransactionDetailsViewModelBase with Store {
|
||||||
|
|
||||||
final type = wallet.type;
|
final type = wallet.type;
|
||||||
|
|
||||||
items.add(BlockExplorerListItem(
|
if (_explorerDescription(type) != '') {
|
||||||
title: S.current.view_in_block_explorer,
|
items.add(BlockExplorerListItem(
|
||||||
value: _explorerDescription(type),
|
title: S.current.view_in_block_explorer,
|
||||||
onTap: () {
|
value: _explorerDescription(type),
|
||||||
try {
|
onTap: () {
|
||||||
launch(_explorerUrl(type, tx.id));
|
try {
|
||||||
} catch (e) {}
|
launch(_explorerUrl(type, tx.id));
|
||||||
}));
|
} catch (e) {}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
final description = transactionDescriptionBox.values.firstWhere(
|
final description = transactionDescriptionBox.values.firstWhere(
|
||||||
(val) => val.id == transactionInfo.id,
|
(val) => val.id == transactionInfo.id,
|
||||||
|
@ -262,6 +267,19 @@ abstract class TransactionDetailsViewModelBase with Store {
|
||||||
items.addAll(_items);
|
items.addAll(_items);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _addLightningListItems(TransactionInfo tx, DateFormat dateFormat) {
|
||||||
|
final _items = [
|
||||||
|
StandartListItem(title: S.current.transaction_details_transaction_id, value: tx.id),
|
||||||
|
StandartListItem(
|
||||||
|
title: S.current.transaction_details_date, value: dateFormat.format(tx.date)),
|
||||||
|
StandartListItem(title: S.current.transaction_details_amount, value: tx.amountFormatted()),
|
||||||
|
if (tx.feeFormatted()?.isNotEmpty ?? false)
|
||||||
|
StandartListItem(title: S.current.transaction_details_fee, value: tx.feeFormatted()!),
|
||||||
|
];
|
||||||
|
|
||||||
|
items.addAll(_items);
|
||||||
|
}
|
||||||
|
|
||||||
void _addHavenListItems(TransactionInfo tx, DateFormat dateFormat) {
|
void _addHavenListItems(TransactionInfo tx, DateFormat dateFormat) {
|
||||||
items.addAll([
|
items.addAll([
|
||||||
StandartListItem(title: S.current.transaction_details_transaction_id, value: tx.id),
|
StandartListItem(title: S.current.transaction_details_transaction_id, value: tx.id),
|
||||||
|
|
|
@ -83,6 +83,16 @@ class BitcoinURI extends PaymentURI {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class LightningURI extends PaymentURI {
|
||||||
|
LightningURI({required String amount, required String address})
|
||||||
|
: super(amount: amount, address: address);
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
throw Exception('N/A for lightning wallets (need to make a bolt11 invoice).');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class LitecoinURI extends PaymentURI {
|
class LitecoinURI extends PaymentURI {
|
||||||
LitecoinURI({required String amount, required String address})
|
LitecoinURI({required String amount, required String address})
|
||||||
: super(amount: amount, address: address);
|
: super(amount: amount, address: address);
|
||||||
|
@ -282,6 +292,10 @@ abstract class WalletAddressListViewModelBase extends WalletChangeListenerViewMo
|
||||||
return BitcoinURI(amount: amount, address: address.address);
|
return BitcoinURI(amount: amount, address: address.address);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (wallet.type == WalletType.lightning) {
|
||||||
|
return LightningURI(amount: amount, address: address.address);
|
||||||
|
}
|
||||||
|
|
||||||
if (wallet.type == WalletType.litecoin) {
|
if (wallet.type == WalletType.litecoin) {
|
||||||
return LitecoinURI(amount: amount, address: address.address);
|
return LitecoinURI(amount: amount, address: address.address);
|
||||||
}
|
}
|
||||||
|
|
|
@ -104,6 +104,7 @@ abstract class WalletCreationVMBase with Store {
|
||||||
derivationType: DerivationType.nano,
|
derivationType: DerivationType.nano,
|
||||||
);
|
);
|
||||||
case WalletType.bitcoin:
|
case WalletType.bitcoin:
|
||||||
|
case WalletType.lightning:
|
||||||
case WalletType.litecoin:
|
case WalletType.litecoin:
|
||||||
return bitcoin!.getElectrumDerivations()[DerivationType.electrum]!.first;
|
return bitcoin!.getElectrumDerivations()[DerivationType.electrum]!.first;
|
||||||
default:
|
default:
|
||||||
|
@ -118,6 +119,7 @@ abstract class WalletCreationVMBase with Store {
|
||||||
derivationType: DerivationType.nano,
|
derivationType: DerivationType.nano,
|
||||||
);
|
);
|
||||||
case WalletType.bitcoin:
|
case WalletType.bitcoin:
|
||||||
|
case WalletType.lightning:
|
||||||
return DerivationInfo(
|
return DerivationInfo(
|
||||||
derivationType: DerivationType.bip39,
|
derivationType: DerivationType.bip39,
|
||||||
derivationPath: "m/84'/0'/0'/0",
|
derivationPath: "m/84'/0'/0'/0",
|
||||||
|
|
|
@ -21,6 +21,7 @@ class WalletKeysViewModel = WalletKeysViewModelBase with _$WalletKeysViewModel;
|
||||||
abstract class WalletKeysViewModelBase with Store {
|
abstract class WalletKeysViewModelBase with Store {
|
||||||
WalletKeysViewModelBase(this._appStore)
|
WalletKeysViewModelBase(this._appStore)
|
||||||
: title = _appStore.wallet!.type == WalletType.bitcoin ||
|
: title = _appStore.wallet!.type == WalletType.bitcoin ||
|
||||||
|
_appStore.wallet!.type == WalletType.lightning ||
|
||||||
_appStore.wallet!.type == WalletType.litecoin ||
|
_appStore.wallet!.type == WalletType.litecoin ||
|
||||||
_appStore.wallet!.type == WalletType.bitcoinCash
|
_appStore.wallet!.type == WalletType.bitcoinCash
|
||||||
? S.current.wallet_seed
|
? S.current.wallet_seed
|
||||||
|
@ -163,6 +164,7 @@ abstract class WalletKeysViewModelBase with Store {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_appStore.wallet!.type == WalletType.bitcoin ||
|
if (_appStore.wallet!.type == WalletType.bitcoin ||
|
||||||
|
_appStore.wallet!.type == WalletType.lightning ||
|
||||||
_appStore.wallet!.type == WalletType.litecoin ||
|
_appStore.wallet!.type == WalletType.litecoin ||
|
||||||
_appStore.wallet!.type == WalletType.bitcoinCash) {
|
_appStore.wallet!.type == WalletType.bitcoinCash) {
|
||||||
// final keys = bitcoin!.getWalletKeys(_appStore.wallet!);
|
// final keys = bitcoin!.getWalletKeys(_appStore.wallet!);
|
||||||
|
@ -247,6 +249,8 @@ abstract class WalletKeysViewModelBase with Store {
|
||||||
return 'banano-wallet';
|
return 'banano-wallet';
|
||||||
case WalletType.polygon:
|
case WalletType.polygon:
|
||||||
return 'polygon-wallet';
|
return 'polygon-wallet';
|
||||||
|
case WalletType.lightning:
|
||||||
|
return 'lightning-wallet';
|
||||||
case WalletType.solana:
|
case WalletType.solana:
|
||||||
return 'solana-wallet';
|
return 'solana-wallet';
|
||||||
case WalletType.tron:
|
case WalletType.tron:
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import 'package:cake_wallet/ethereum/ethereum.dart';
|
import 'package:cake_wallet/ethereum/ethereum.dart';
|
||||||
import 'package:cake_wallet/bitcoin_cash/bitcoin_cash.dart';
|
import 'package:cake_wallet/bitcoin_cash/bitcoin_cash.dart';
|
||||||
|
import 'package:cake_wallet/lightning/lightning.dart';
|
||||||
import 'package:cake_wallet/solana/solana.dart';
|
import 'package:cake_wallet/solana/solana.dart';
|
||||||
import 'package:cake_wallet/tron/tron.dart';
|
import 'package:cake_wallet/tron/tron.dart';
|
||||||
import 'package:cake_wallet/wownero/wownero.dart';
|
import 'package:cake_wallet/wownero/wownero.dart';
|
||||||
|
@ -69,6 +70,8 @@ abstract class WalletNewVMBase extends WalletCreationVM with Store {
|
||||||
name: name, language: options!.first as String, isPolyseed: options.last as bool);
|
name: name, language: options!.first as String, isPolyseed: options.last as bool);
|
||||||
case WalletType.bitcoin:
|
case WalletType.bitcoin:
|
||||||
return bitcoin!.createBitcoinNewWalletCredentials(name: name);
|
return bitcoin!.createBitcoinNewWalletCredentials(name: name);
|
||||||
|
case WalletType.lightning:
|
||||||
|
return bitcoin!.createBitcoinNewWalletCredentials(name: name);
|
||||||
case WalletType.litecoin:
|
case WalletType.litecoin:
|
||||||
return bitcoin!.createBitcoinNewWalletCredentials(name: name);
|
return bitcoin!.createBitcoinNewWalletCredentials(name: name);
|
||||||
case WalletType.haven:
|
case WalletType.haven:
|
||||||
|
|
|
@ -108,6 +108,14 @@ abstract class WalletRestoreViewModelBase extends WalletCreationVM with Store {
|
||||||
derivationType: derivationInfo!.derivationType!,
|
derivationType: derivationInfo!.derivationType!,
|
||||||
derivationPath: derivationInfo.derivationPath!,
|
derivationPath: derivationInfo.derivationPath!,
|
||||||
);
|
);
|
||||||
|
case WalletType.lightning:
|
||||||
|
return bitcoin!.createBitcoinRestoreWalletFromSeedCredentials(
|
||||||
|
name: name,
|
||||||
|
mnemonic: seed,
|
||||||
|
password: password,
|
||||||
|
derivationType: derivationInfo!.derivationType!,
|
||||||
|
derivationPath: derivationInfo.derivationPath!,
|
||||||
|
);
|
||||||
case WalletType.haven:
|
case WalletType.haven:
|
||||||
return haven!.createHavenRestoreWalletFromSeedCredentials(
|
return haven!.createHavenRestoreWalletFromSeedCredentials(
|
||||||
name: name, height: height, mnemonic: seed, password: password);
|
name: name, height: height, mnemonic: seed, password: password);
|
||||||
|
|
|
@ -2,6 +2,7 @@ cd cw_core; flutter pub get; flutter packages pub run build_runner build --delet
|
||||||
cd cw_evm; flutter pub get; flutter packages pub run build_runner build --delete-conflicting-outputs; cd ..
|
cd cw_evm; flutter pub get; flutter packages pub run build_runner build --delete-conflicting-outputs; cd ..
|
||||||
cd cw_monero; flutter pub get; flutter packages pub run build_runner build --delete-conflicting-outputs; cd ..
|
cd cw_monero; flutter pub get; flutter packages pub run build_runner build --delete-conflicting-outputs; cd ..
|
||||||
cd cw_bitcoin; flutter pub get; flutter packages pub run build_runner build --delete-conflicting-outputs; cd ..
|
cd cw_bitcoin; flutter pub get; flutter packages pub run build_runner build --delete-conflicting-outputs; cd ..
|
||||||
|
cd cw_lightning && flutter pub get && flutter packages pub run build_runner build --delete-conflicting-outputs && cd ..
|
||||||
cd cw_haven; flutter pub get; flutter packages pub run build_runner build --delete-conflicting-outputs; cd ..
|
cd cw_haven; flutter pub get; flutter packages pub run build_runner build --delete-conflicting-outputs; cd ..
|
||||||
cd cw_nano; flutter pub get; flutter packages pub run build_runner build --delete-conflicting-outputs; cd ..
|
cd cw_nano; flutter pub get; flutter packages pub run build_runner build --delete-conflicting-outputs; cd ..
|
||||||
cd cw_bitcoin_cash; flutter pub get; flutter packages pub run build_runner build --delete-conflicting-outputs; cd ..
|
cd cw_bitcoin_cash; flutter pub get; flutter packages pub run build_runner build --delete-conflicting-outputs; cd ..
|
||||||
|
|
|
@ -12,7 +12,7 @@ dependencies:
|
||||||
version: 4.0.2
|
version: 4.0.2
|
||||||
shared_preferences: ^2.0.15
|
shared_preferences: ^2.0.15
|
||||||
# provider: ^6.0.3
|
# provider: ^6.0.3
|
||||||
rxdart: ^0.27.4
|
rxdart: ^0.28.0
|
||||||
yaml: ^3.1.1
|
yaml: ^3.1.1
|
||||||
#barcode_scan: any
|
#barcode_scan: any
|
||||||
barcode_scan2: ^4.2.1
|
barcode_scan2: ^4.2.1
|
||||||
|
@ -107,14 +107,20 @@ dependencies:
|
||||||
ref: cake-update-v3
|
ref: cake-update-v3
|
||||||
ledger_flutter: ^1.0.1
|
ledger_flutter: ^1.0.1
|
||||||
|
|
||||||
|
breez_sdk:
|
||||||
|
git:
|
||||||
|
url: https://github.com/breez/breez-sdk-flutter.git
|
||||||
|
ref: v0.4.3-rc1
|
||||||
|
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
sdk: flutter
|
sdk: flutter
|
||||||
build_runner: ^2.3.3
|
build_runner: ^2.4.7
|
||||||
logging: ^1.2.0
|
logging: ^1.2.0
|
||||||
mobx_codegen: ^2.1.1
|
mobx_codegen: ^2.1.1
|
||||||
build_resolvers: ^2.0.9
|
build_resolvers: ^2.0.9
|
||||||
hive_generator: ^1.1.3
|
hive_generator: ^2.0.1
|
||||||
# flutter_launcher_icons: ^0.11.0
|
# flutter_launcher_icons: ^0.11.0
|
||||||
# check flutter_launcher_icons for usage
|
# check flutter_launcher_icons for usage
|
||||||
pedantic: ^1.8.0
|
pedantic: ^1.8.0
|
||||||
|
@ -128,6 +134,8 @@ dependency_overrides:
|
||||||
bech32:
|
bech32:
|
||||||
git:
|
git:
|
||||||
url: https://github.com/cake-tech/bech32.git
|
url: https://github.com/cake-tech/bech32.git
|
||||||
|
flutter_rust_bridge: ^1.82.6
|
||||||
|
uuid: ^4.1.0
|
||||||
ledger_flutter:
|
ledger_flutter:
|
||||||
git:
|
git:
|
||||||
url: https://github.com/cake-tech/ledger-flutter.git
|
url: https://github.com/cake-tech/ledger-flutter.git
|
||||||
|
|
|
@ -81,6 +81,8 @@
|
||||||
"bitcoin_payments_require_1_confirmation": "تتطلب مدفوعات Bitcoin تأكيدًا واحدًا ، والذي قد يستغرق 20 دقيقة أو أكثر. شكرا لصبرك! سيتم إرسال بريد إلكتروني إليك عند تأكيد الدفع.",
|
"bitcoin_payments_require_1_confirmation": "تتطلب مدفوعات Bitcoin تأكيدًا واحدًا ، والذي قد يستغرق 20 دقيقة أو أكثر. شكرا لصبرك! سيتم إرسال بريد إلكتروني إليك عند تأكيد الدفع.",
|
||||||
"block_remaining": "1 كتلة متبقية",
|
"block_remaining": "1 كتلة متبقية",
|
||||||
"Blocks_remaining": "بلوك متبقي ${status}",
|
"Blocks_remaining": "بلوك متبقي ${status}",
|
||||||
|
"breez_warning_disruption": "خدمة Breez تواجه حاليًا قضايا. الرجاء معاودة المحاولة في وقت لاحق.",
|
||||||
|
"breez_warning_maintenance": "تمر خدمة Breez حاليًا بالصيانة. الرجاء معاودة المحاولة في وقت لاحق.",
|
||||||
"bluetooth": "بلوتوث",
|
"bluetooth": "بلوتوث",
|
||||||
"bright_theme": "مشرق",
|
"bright_theme": "مشرق",
|
||||||
"bump_fee": "رسوم عثرة",
|
"bump_fee": "رسوم عثرة",
|
||||||
|
@ -337,6 +339,8 @@
|
||||||
"inputs": "المدخلات",
|
"inputs": "المدخلات",
|
||||||
"introducing_cake_pay": "نقدم لكم Cake Pay!",
|
"introducing_cake_pay": "نقدم لكم Cake Pay!",
|
||||||
"invalid_input": "مدخل غير صالح",
|
"invalid_input": "مدخل غير صالح",
|
||||||
|
"invoice": "فاتورة",
|
||||||
|
"invoice_created": "الفاتورة التي تم إنشاؤها",
|
||||||
"invoice_details": "تفاصيل الفاتورة",
|
"invoice_details": "تفاصيل الفاتورة",
|
||||||
"is_percentage": "يكون",
|
"is_percentage": "يكون",
|
||||||
"last_30_days": "آخر 30 يومًا",
|
"last_30_days": "آخر 30 يومًا",
|
||||||
|
@ -347,6 +351,10 @@
|
||||||
"ledger_error_wrong_app": "يرجى التأكد",
|
"ledger_error_wrong_app": "يرجى التأكد",
|
||||||
"ledger_please_enable_bluetooth": "يرجى تمكين البلوتوث للكشف عن دفتر الأستاذ الخاص بك",
|
"ledger_please_enable_bluetooth": "يرجى تمكين البلوتوث للكشف عن دفتر الأستاذ الخاص بك",
|
||||||
"light_theme": "فاتح",
|
"light_theme": "فاتح",
|
||||||
|
"lightning_invoice_min": "<سيتم تطبيق رسوم الإعداد ${feePercent} ٪ مع ما لا يقل عن ${min} SATs عند تلقي هذه الفاتورة",
|
||||||
|
"lightning_invoice_min_max": "سيتم تطبيق رسوم إعداد ${feePercent} ٪ مع ما لا يقل عن ${min} SATs لتلقي أكثر من ${max} SATs",
|
||||||
|
"lightning_invoice_warning": "يجب أن تبقي التطبيق مفتوحًا حتى يتم الانتهاء من الدفع أو تفشل المعاملة",
|
||||||
|
"lightning_receive_limits": "أرسل أكثر من ${min} SATs وحتى ${max} SATs إلى هذا العنوان. سيتم تطبيق رسوم إعداد ${feePercent} ٪ مع ما لا يقل عن ${fee} SATs عند تلقي هذه الفاتورة. سيؤدي ذلك إلى تحويل أي Bitcoin المستلم إلى Lightning. سيتم تطبيق رسوم على السلسلة. لا يمكن استخدام هذا العنوان إلا مرة واحدة.",
|
||||||
"load_more": "تحميل المزيد",
|
"load_more": "تحميل المزيد",
|
||||||
"loading_your_wallet": "يتم تحميل محفظتك",
|
"loading_your_wallet": "يتم تحميل محفظتك",
|
||||||
"login": "تسجيل الدخول",
|
"login": "تسجيل الدخول",
|
||||||
|
@ -360,6 +368,7 @@
|
||||||
"market_place": "منصة التجارة",
|
"market_place": "منصة التجارة",
|
||||||
"matrix_green_dark_theme": "موضوع ماتريكس الأخضر الداكن",
|
"matrix_green_dark_theme": "موضوع ماتريكس الأخضر الداكن",
|
||||||
"max_amount": "الحد الأقصى: ${value}",
|
"max_amount": "الحد الأقصى: ${value}",
|
||||||
|
"max_receivable": "ماكس القبض",
|
||||||
"max_value": "الحد الأقصى: ${value} ${currency}",
|
"max_value": "الحد الأقصى: ${value} ${currency}",
|
||||||
"memo": "مذكرة:",
|
"memo": "مذكرة:",
|
||||||
"message": "ﺔﻟﺎﺳﺭ",
|
"message": "ﺔﻟﺎﺳﺭ",
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue