Peg in and peg out flow (#1745)

* version 4.20.0

* update build numbers

* UI updates and script fix for ios bundle identifier

* disable mweb for desktop

* change hardcoded ltc server ip address
electrum connection enhancement

* additional logging and minor fixes

* additional logging and minor fixes

* addresses pt.1

* logs of fixes and experimental changes, close wallet before opening next

* save

* fix icon

* fixes

* [skip ci] updates

* [skip ci] updates

* updates

* minor optimizations

* fix for when switching between wallets

* [skip ci] updates

* [skip ci] updates

* Update cw_bitcoin/lib/litecoin_wallet.dart

Co-authored-by: Omar Hatem <omarh.ismail1@gmail.com>

* Update cw_bitcoin/lib/litecoin_wallet.dart

Co-authored-by: Omar Hatem <omarh.ismail1@gmail.com>

* mobx

* mostly logging

* stream fix pt.1 [skip ci]

* updates

* some fixes and enhancements

* [skip ci] minor

* potential partial fix for streamsink closed

* fix stream sink closed errors

* fix mweb logo colors

* add initial whitelisting for coin types on send screen

* MWEB enhancements 2.0 (#1735)

* additional logging and minor fixes

* additional logging and minor fixes

* addresses pt.1

* Allow Wallet Group Names to be the same as Wallet Names (#1730)

* fix: Issues with imaging

* fix: Allow group names to be the same as wallet names

* fix: Bug with wallet grouping when a wallet is minimized

* fix: Bug with wallet grouping when a wallet is minimized

* logs of fixes and experimental changes, close wallet before opening next

* save

* fix icon

* fixes

* [skip ci] updates

* [skip ci] updates

* updates

* minor optimizations

* fix for when switching between wallets

* [skip ci] updates

* [skip ci] updates

* Update cw_bitcoin/lib/litecoin_wallet.dart

Co-authored-by: Omar Hatem <omarh.ismail1@gmail.com>

* Update cw_bitcoin/lib/litecoin_wallet.dart

Co-authored-by: Omar Hatem <omarh.ismail1@gmail.com>

* mobx

* mostly logging

* stream fix pt.1 [skip ci]

* updates

* some fixes and enhancements

* [skip ci] minor

* potential partial fix for streamsink closed

* fix stream sink closed errors

* fix mweb logo colors

* save

* minor enhancements [skip ci]

* save

* experimental

* minor

* minor [skip ci]

---------

Co-authored-by: David Adegoke <64401859+Blazebrain@users.noreply.github.com>
Co-authored-by: Omar Hatem <omarh.ismail1@gmail.com>

* fix menu list removing from original list

* handle pegin and pegout

* fix text color

* fix import

* pegin/out button ui updates

* update spacing + tx creation fix

* add correct args for link view model [skip ci]

---------

Co-authored-by: Matthew Fosse <matt@fosse.co>
Co-authored-by: fossephate <matt.cfosse@gmail.com>
Co-authored-by: David Adegoke <64401859+Blazebrain@users.noreply.github.com>
This commit is contained in:
Omar Hatem
2024-10-15 00:28:38 +03:00
committed by GitHub
co-authored by David Adegoke Matthew Fosse fossephate
parent 380f7653b2
commit ebe8c65407
14 changed files with 428 additions and 253 deletions
+35 -25
View File
@@ -106,34 +106,33 @@ class CWBitcoin extends Bitcoin {
}
@override
Object createBitcoinTransactionCredentials(List<Output> outputs,
{required TransactionPriority priority, int? feeRate}) {
Object createBitcoinTransactionCredentials(
List<Output> outputs, {
required TransactionPriority priority,
int? feeRate,
UnspentCoinType coinTypeToSpendFrom = UnspentCoinType.any,
}) {
final bitcoinFeeRate =
priority == BitcoinTransactionPriority.custom && feeRate != null ? feeRate : null;
return BitcoinTransactionCredentials(
outputs
.map((out) => OutputInfo(
fiatAmount: out.fiatAmount,
cryptoAmount: out.cryptoAmount,
address: out.address,
note: out.note,
sendAll: out.sendAll,
extractedAddress: out.extractedAddress,
isParsedAddress: out.isParsedAddress,
formattedCryptoAmount: out.formattedCryptoAmount,
memo: out.memo))
.toList(),
priority: priority as BitcoinTransactionPriority,
feeRate: bitcoinFeeRate);
outputs
.map((out) => OutputInfo(
fiatAmount: out.fiatAmount,
cryptoAmount: out.cryptoAmount,
address: out.address,
note: out.note,
sendAll: out.sendAll,
extractedAddress: out.extractedAddress,
isParsedAddress: out.isParsedAddress,
formattedCryptoAmount: out.formattedCryptoAmount,
memo: out.memo))
.toList(),
priority: priority as BitcoinTransactionPriority,
feeRate: bitcoinFeeRate,
coinTypeToSpendFrom: coinTypeToSpendFrom,
);
}
@override
Object createBitcoinTransactionCredentialsRaw(List<OutputInfo> outputs,
{TransactionPriority? priority, required int feeRate}) =>
BitcoinTransactionCredentials(outputs,
priority: priority != null ? priority as BitcoinTransactionPriority : null,
feeRate: feeRate);
@override
@computed
List<ElectrumSubAddress> getSubAddresses(Object wallet) {
@@ -205,9 +204,20 @@ class CWBitcoin extends Bitcoin {
(priority as BitcoinTransactionPriority).labelWithRate(rate, customRate);
@override
List<BitcoinUnspent> getUnspents(Object wallet) {
List<BitcoinUnspent> getUnspents(Object wallet,
{UnspentCoinType coinTypeToSpendFrom = UnspentCoinType.any}) {
final bitcoinWallet = wallet as ElectrumWallet;
return bitcoinWallet.unspentCoins;
return bitcoinWallet.unspentCoins.where((element) {
switch(coinTypeToSpendFrom) {
case UnspentCoinType.mweb:
return element.bitcoinAddressRecord.type == SegwitAddresType.mweb;
case UnspentCoinType.nonMweb:
return element.bitcoinAddressRecord.type != SegwitAddresType.mweb;
case UnspentCoinType.any:
return true;
}
}).toList();
}
Future<void> updateUnspents(Object wallet) async {
+18 -9
View File
@@ -167,6 +167,7 @@ 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_restore_choose_derivation_view_model.dart';
import 'package:cw_core/nano_account.dart';
import 'package:cw_core/unspent_coin_type.dart';
import 'package:cw_core/unspent_coins_info.dart';
import 'package:cw_core/wallet_service.dart';
import 'package:cw_core/transaction_info.dart';
@@ -725,8 +726,8 @@ Future<void> setup({
getIt.get<SendTemplateStore>(),
getIt.get<FiatConversionStore>()));
getIt.registerFactory<SendViewModel>(
() => SendViewModel(
getIt.registerFactoryParam<SendViewModel, UnspentCoinType?, void>(
(coinTypeToSpendFrom, _) => SendViewModel(
getIt.get<AppStore>(),
getIt.get<SendTemplateViewModel>(),
getIt.get<FiatConversionStore>(),
@@ -734,12 +735,13 @@ Future<void> setup({
getIt.get<ContactListViewModel>(),
_transactionDescriptionBox,
getIt.get<AppStore>().wallet!.isHardwareWallet ? getIt.get<LedgerViewModel>() : null,
coinTypeToSpendFrom: coinTypeToSpendFrom ?? UnspentCoinType.any,
),
);
getIt.registerFactoryParam<SendPage, PaymentRequest?, void>(
(PaymentRequest? initialPaymentRequest, _) => SendPage(
sendViewModel: getIt.get<SendViewModel>(),
getIt.registerFactoryParam<SendPage, PaymentRequest?, UnspentCoinType?>(
(PaymentRequest? initialPaymentRequest, coinTypeToSpendFrom) => SendPage(
sendViewModel: getIt.get<SendViewModel>(param1: coinTypeToSpendFrom),
authService: getIt.get<AuthService>(),
initialPaymentRequest: initialPaymentRequest,
));
@@ -1215,14 +1217,21 @@ Future<void> setup({
getIt.registerFactory(() => SupportOtherLinksPage(getIt.get<SupportViewModel>()));
getIt.registerFactory(() {
getIt.registerFactoryParam<UnspentCoinsListViewModel, UnspentCoinType?, void>(
(coinTypeToSpendFrom, _) {
final wallet = getIt.get<AppStore>().wallet;
return UnspentCoinsListViewModel(wallet: wallet!, unspentCoinsInfo: _unspentCoinsInfoSource);
return UnspentCoinsListViewModel(
wallet: wallet!,
unspentCoinsInfo: _unspentCoinsInfoSource,
coinTypeToSpendFrom: coinTypeToSpendFrom ?? UnspentCoinType.any,
);
});
getIt.registerFactory(() =>
UnspentCoinsListPage(unspentCoinsListViewModel: getIt.get<UnspentCoinsListViewModel>()));
getIt.registerFactoryParam<UnspentCoinsListPage, UnspentCoinType?, void>(
(coinTypeToSpendFrom, _) => UnspentCoinsListPage(
unspentCoinsListViewModel:
getIt.get<UnspentCoinsListViewModel>(param1: coinTypeToSpendFrom)));
getIt.registerFactoryParam<UnspentCoinsDetailsViewModel, UnspentCoinsItem,
UnspentCoinsListViewModel>(
+16 -8
View File
@@ -120,6 +120,7 @@ import 'package:cw_core/crypto_currency.dart';
import 'package:cw_core/nano_account.dart';
import 'package:cw_core/node.dart';
import 'package:cw_core/transaction_info.dart';
import 'package:cw_core/unspent_coin_type.dart';
import 'package:cw_core/wallet_info.dart';
import 'package:cw_core/wallet_type.dart';
import 'package:flutter/cupertino.dart';
@@ -184,7 +185,8 @@ Route<dynamic> createRoute(RouteSettings settings) {
final type = settings.arguments as WalletType;
final walletGroupsDisplayVM = getIt.get<WalletGroupsDisplayViewModel>(param1: type);
return CupertinoPageRoute<void>(builder: (_) => WalletGroupsDisplayPage(walletGroupsDisplayVM));
return CupertinoPageRoute<void>(
builder: (_) => WalletGroupsDisplayPage(walletGroupsDisplayVM));
case Routes.newWallet:
final args = settings.arguments as NewWalletArguments;
@@ -348,13 +350,17 @@ Route<dynamic> createRoute(RouteSettings settings) {
settings: settings, builder: (_) => getIt.get<DashboardPage>());
case Routes.send:
final initialPaymentRequest = settings.arguments as PaymentRequest?;
final args = settings.arguments as Map<String, dynamic>?;
final initialPaymentRequest = args?['paymentRequest'] as PaymentRequest?;
final coinTypeToSpendFrom = args?['coinTypeToSpendFrom'] as UnspentCoinType?;
return CupertinoPageRoute<void>(
fullscreenDialog: true,
builder: (_) => getIt.get<SendPage>(
param1: initialPaymentRequest,
));
fullscreenDialog: true,
builder: (_) => getIt.get<SendPage>(
param1: initialPaymentRequest,
param2: coinTypeToSpendFrom,
),
);
case Routes.sendTemplate:
return CupertinoPageRoute<void>(
@@ -604,7 +610,9 @@ Route<dynamic> createRoute(RouteSettings settings) {
fullscreenDialog: true, builder: (_) => getIt.get<SupportOtherLinksPage>());
case Routes.unspentCoinsList:
return MaterialPageRoute<void>(builder: (_) => getIt.get<UnspentCoinsListPage>());
final coinTypeToSpendFrom = settings.arguments as UnspentCoinType?;
return MaterialPageRoute<void>(
builder: (_) => getIt.get<UnspentCoinsListPage>(param1: coinTypeToSpendFrom));
case Routes.unspentCoinsDetails:
final args = settings.arguments as List;
@@ -778,7 +786,7 @@ Route<dynamic> createRoute(RouteSettings settings) {
case Routes.walletGroupDescription:
final walletType = settings.arguments as WalletType;
return MaterialPageRoute<void>(
builder: (_) => WalletGroupDescriptionPage(
selectedWalletType: walletType,
+265 -179
View File
@@ -17,13 +17,15 @@ import 'package:cake_wallet/src/widgets/standard_switch.dart';
import 'package:cake_wallet/store/settings_store.dart';
import 'package:cake_wallet/themes/extensions/balance_page_theme.dart';
import 'package:cake_wallet/themes/extensions/dashboard_page_theme.dart';
import 'package:cake_wallet/themes/extensions/send_page_theme.dart';
import 'package:cake_wallet/themes/extensions/sync_indicator_theme.dart';
import 'package:cake_wallet/utils/feature_flag.dart';
import 'package:cake_wallet/utils/payment_request.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/nft_view_model.dart';
import 'package:cw_core/crypto_currency.dart';
import 'package:flutter/cupertino.dart';
import 'package:cw_core/unspent_coin_type.dart';
import 'package:flutter/material.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
import 'package:url_launcher/url_launcher.dart';
@@ -837,216 +839,300 @@ class BalanceRowWidget extends StatelessWidget {
color: Theme.of(context).extension<SyncIndicatorTheme>()!.syncedBackgroundColor,
),
child: Container(
margin: const EdgeInsets.only(top: 0, left: 24, right: 8, bottom: 16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Stack(
children: [
if (currency == CryptoCurrency.ltc)
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
Container(
padding: EdgeInsets.only(right: 16, top: 16),
child: Column(
children: [
Container(
decoration: BoxDecoration(
color: Colors.white,
shape: BoxShape.circle,
Container(
margin: const EdgeInsets.only(top: 0, left: 24, right: 8, bottom: 16),
child: Stack(
children: [
if (currency == CryptoCurrency.ltc)
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
Container(
padding: EdgeInsets.only(right: 16, top: 16),
child: Column(
children: [
Container(
decoration: BoxDecoration(
color: Colors.white,
shape: BoxShape.circle,
),
child: ImageIcon(
AssetImage('assets/images/mweb_logo.png'),
color: Color.fromARGB(255, 11, 70, 129),
size: 40,
),
),
child: ImageIcon(
AssetImage('assets/images/mweb_logo.png'),
color: Color.fromARGB(255, 11, 70, 129),
size: 40,
const SizedBox(height: 10),
Text(
'MWEB',
style: TextStyle(
fontSize: 15,
fontFamily: 'Lato',
fontWeight: FontWeight.w800,
color: Theme.of(context)
.extension<BalancePageTheme>()!
.assetTitleColor,
height: 1,
),
),
],
),
),
],
),
if (hasSecondAvailableBalance)
Row(
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(height: 24),
Text(
'${secondAvailableBalanceLabel}',
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 12,
fontFamily: 'Lato',
fontWeight: FontWeight.w400,
color: Theme.of(context)
.extension<BalancePageTheme>()!
.labelTextColor,
height: 1,
),
),
const SizedBox(height: 10),
Text(
'MWEB',
SizedBox(height: 8),
AutoSizeText(
secondAvailableBalance,
style: TextStyle(
fontSize: 15,
fontSize: 20,
fontFamily: 'Lato',
fontWeight: FontWeight.w800,
fontWeight: FontWeight.w400,
color: Theme.of(context)
.extension<BalancePageTheme>()!
.assetTitleColor,
height: 1,
),
maxLines: 1,
textAlign: TextAlign.center,
),
SizedBox(height: 4),
if (!isTestnet)
Text(
'${secondAvailableFiatBalance}',
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 12,
fontFamily: 'Lato',
fontWeight: FontWeight.w400,
color: Theme.of(context)
.extension<BalancePageTheme>()!
.textColor,
height: 1,
),
),
],
),
),
],
),
if (hasSecondAvailableBalance)
Row(
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(height: 24),
Text(
'${secondAvailableBalanceLabel}',
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 12,
fontFamily: 'Lato',
fontWeight: FontWeight.w400,
color: Theme.of(context)
.extension<BalancePageTheme>()!
.labelTextColor,
height: 1,
),
),
SizedBox(height: 8),
AutoSizeText(
secondAvailableBalance,
style: TextStyle(
fontSize: 20,
fontFamily: 'Lato',
fontWeight: FontWeight.w400,
color: Theme.of(context)
.extension<BalancePageTheme>()!
.assetTitleColor,
height: 1,
),
maxLines: 1,
textAlign: TextAlign.center,
),
SizedBox(height: 4),
if (!isTestnet)
],
),
],
),
),
Container(
margin: const EdgeInsets.only(top: 0, left: 24, right: 8, bottom: 16),
child: Stack(
children: [
if (hasSecondAdditionalBalance)
Row(
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(height: 24),
Text(
'${secondAvailableFiatBalance}',
'${secondAdditionalBalanceLabel}',
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 12,
fontFamily: 'Lato',
fontWeight: FontWeight.w400,
color:
Theme.of(context).extension<BalancePageTheme>()!.textColor,
color: Theme.of(context)
.extension<BalancePageTheme>()!
.labelTextColor,
height: 1,
),
),
],
),
],
),
],
),
Stack(
children: [
if (hasSecondAdditionalBalance)
Row(
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(height: 24),
Text(
'${secondAdditionalBalanceLabel}',
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 12,
fontFamily: 'Lato',
fontWeight: FontWeight.w400,
color: Theme.of(context)
.extension<BalancePageTheme>()!
.labelTextColor,
height: 1,
),
),
SizedBox(height: 8),
AutoSizeText(
secondAdditionalBalance,
style: TextStyle(
fontSize: 20,
fontFamily: 'Lato',
fontWeight: FontWeight.w400,
color: Theme.of(context)
.extension<BalancePageTheme>()!
.assetTitleColor,
height: 1,
),
maxLines: 1,
textAlign: TextAlign.center,
),
SizedBox(height: 4),
if (!isTestnet)
Text(
'${secondAdditionalFiatBalance}',
textAlign: TextAlign.center,
SizedBox(height: 8),
AutoSizeText(
secondAdditionalBalance,
style: TextStyle(
fontSize: 12,
fontSize: 20,
fontFamily: 'Lato',
fontWeight: FontWeight.w400,
color:
Theme.of(context).extension<BalancePageTheme>()!.textColor,
color: Theme.of(context)
.extension<BalancePageTheme>()!
.assetTitleColor,
height: 1,
),
maxLines: 1,
textAlign: TextAlign.center,
),
],
),
],
),
// TODO: smarter peg in / out buttons
// if (currency == CryptoCurrency.ltc)
// Row(
// mainAxisAlignment: MainAxisAlignment.end,
// children: [
// Container(
// margin: EdgeInsets.only(top: 24, right: 8),
// child: ElevatedButton(
// style: ElevatedButton.styleFrom(
// backgroundColor: Theme.of(context).highlightColor,
// ),
// onPressed: () {
// final mwebAddress =
// bitcoin!.getUnusedMwebAddress(dashboardViewModel.wallet);
// if (mwebAddress == null) return;
// final paymentRequest =
// PaymentRequest.fromUri(Uri.parse("litecoin:${mwebAddress}"));
// Navigator.of(context)
// .pushNamed(Routes.send, arguments: paymentRequest);
// },
// child: Container(
// color: Colors.transparent,
// margin: EdgeInsets.all(4),
// child: Column(
// mainAxisSize: MainAxisSize.max,
// crossAxisAlignment: CrossAxisAlignment.center,
// children: <Widget>[
// Container(
// alignment: Alignment.center,
// decoration: BoxDecoration(shape: BoxShape.circle),
// child: Image.asset(
// 'assets/images/received.png',
// color: Theme.of(context)
// .extension<BalancePageTheme>()!
// .balanceAmountColor,
// width: 64,
// height: 32,
// ),
// ),
// SizedBox(height: 4),
// Text(
// S.of(context).litecoin_mweb_pegin,
// style: TextStyle(
// fontSize: 10,
// color: Theme.of(context)
// .extension<DashboardPageTheme>()!
// .cardTextColor),
// )
// ],
// ),
// ),
// ),
// ),
// ],
// ),
],
SizedBox(height: 4),
if (!isTestnet)
Text(
'${secondAdditionalFiatBalance}',
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 12,
fontFamily: 'Lato',
fontWeight: FontWeight.w400,
color: Theme.of(context)
.extension<BalancePageTheme>()!
.textColor,
height: 1,
),
),
],
),
],
),
],
),
),
IntrinsicHeight(
child: Container(
padding: EdgeInsets.symmetric(horizontal: 24),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: Semantics(
label: S.of(context).litecoin_mweb_pegin,
child: OutlinedButton(
onPressed: () {
final mwebAddress =
bitcoin!.getUnusedMwebAddress(dashboardViewModel.wallet);
PaymentRequest? paymentRequest = null;
if ((mwebAddress?.isNotEmpty ?? false)) {
paymentRequest =
PaymentRequest.fromUri(Uri.parse("litecoin:${mwebAddress}"));
}
Navigator.pushNamed(
context,
Routes.send,
arguments: {
'paymentRequest': paymentRequest,
'coinTypeToSpendFrom': UnspentCoinType.nonMweb,
},
);
},
style: OutlinedButton.styleFrom(
backgroundColor: Theme.of(context)
.extension<SendPageTheme>()!
.textFieldButtonIconColor
.withAlpha(50),
side: BorderSide(color: Colors.grey.shade400, width: 0),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20),
),
),
child: Container(
padding: EdgeInsets.symmetric(vertical: 12),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Image.asset(
height: 30,
width: 30,
'assets/images/received.png',
color: Theme.of(context)
.extension<BalancePageTheme>()!
.balanceAmountColor,
),
const SizedBox(width: 8),
Text(
S.of(context).litecoin_mweb_pegin,
style: TextStyle(
color: Theme.of(context)
.extension<BalancePageTheme>()!
.assetTitleColor,
),
),
],
),
),
),
),
),
SizedBox(width: 32),
Expanded(
child: Semantics(
label: S.of(context).litecoin_mweb_pegout,
child: OutlinedButton(
onPressed: () {
final litecoinAddress =
bitcoin!.getAddress(dashboardViewModel.wallet);
PaymentRequest? paymentRequest = null;
if (litecoinAddress.isNotEmpty) {
paymentRequest = PaymentRequest.fromUri(
Uri.parse("litecoin:${litecoinAddress}"));
}
Navigator.pushNamed(
context,
Routes.send,
arguments: {
'paymentRequest': paymentRequest,
'coinTypeToSpendFrom': UnspentCoinType.mweb,
},
);
},
style: OutlinedButton.styleFrom(
backgroundColor: Theme.of(context)
.extension<SendPageTheme>()!
.textFieldButtonIconColor
.withAlpha(50),
side: BorderSide(color: Colors.grey.shade400, width: 0),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20),
),
),
child: Container(
padding: EdgeInsets.symmetric(vertical: 12),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Image.asset(
height: 30,
width: 30,
'assets/images/upload.png',
color: Theme.of(context)
.extension<BalancePageTheme>()!
.balanceAmountColor,
),
const SizedBox(width: 8),
Text(
S.of(context).litecoin_mweb_pegout,
style: TextStyle(
color: Theme.of(context)
.extension<BalancePageTheme>()!
.assetTitleColor,
),
),
],
),
),
),
),
),
],
),
),
),
SizedBox(height: 16),
],
),
),
+4 -2
View File
@@ -14,7 +14,6 @@ import 'package:cake_wallet/view_model/send/output.dart';
import 'package:cw_core/transaction_priority.dart';
import 'package:cw_core/wallet_type.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
import 'package:mobx/mobx.dart';
import 'package:keyboard_actions/keyboard_actions.dart';
@@ -373,7 +372,10 @@ class SendCardState extends State<SendCard> with AutomaticKeepAliveClientMixin<S
padding: EdgeInsets.only(top: 6),
child: GestureDetector(
key: ValueKey('send_page_unspent_coin_button_key'),
onTap: () => Navigator.of(context).pushNamed(Routes.unspentCoinsList),
onTap: () => Navigator.of(context).pushNamed(
Routes.unspentCoinsList,
arguments: widget.sendViewModel.coinTypeToSpendFrom,
),
child: Container(
color: Colors.transparent,
child: Row(
+3 -2
View File
@@ -65,15 +65,16 @@ class LinkViewModel {
if (isNanoGptLink) {
switch (currentLink?.authority ?? '') {
case "exchange":
case "send":
return PaymentRequest.fromUri(currentLink);
case "send":
return {"paymentRequest": PaymentRequest.fromUri(currentLink)};
case "buy":
return true;
}
}
if (_isValidPaymentUri) {
return PaymentRequest.fromUri(currentLink);
return {"paymentRequest": PaymentRequest.fromUri(currentLink)};
}
return null;
+20 -5
View File
@@ -20,6 +20,7 @@ import 'package:cake_wallet/wownero/wownero.dart';
import 'package:cw_core/exceptions.dart';
import 'package:cw_core/transaction_info.dart';
import 'package:cw_core/transaction_priority.dart';
import 'package:cw_core/unspent_coin_type.dart';
import 'package:cake_wallet/view_model/send/output.dart';
import 'package:cake_wallet/view_model/send/send_template_view_model.dart';
import 'package:hive/hive.dart';
@@ -67,8 +68,9 @@ abstract class SendViewModelBase extends WalletChangeListenerViewModel with Stor
this.balanceViewModel,
this.contactListViewModel,
this.transactionDescriptionBox,
this.ledgerViewModel,
) : state = InitialExecutionState(),
this.ledgerViewModel, {
this.coinTypeToSpendFrom = UnspentCoinType.any,
}) : state = InitialExecutionState(),
currencies = appStore.wallet!.balance.keys.toList(),
selectedCryptoCurrency = appStore.wallet!.currency,
hasMultipleTokens = isEVMCompatibleChain(appStore.wallet!.type) ||
@@ -97,6 +99,8 @@ abstract class SendViewModelBase extends WalletChangeListenerViewModel with Stor
ObservableList<Output> outputs;
final UnspentCoinType coinTypeToSpendFrom;
@action
void addOutput() {
outputs
@@ -217,7 +221,14 @@ abstract class SendViewModelBase extends WalletChangeListenerViewModel with Stor
PendingTransaction? pendingTransaction;
@computed
String get balance => wallet.balance[selectedCryptoCurrency]!.formattedFullAvailableBalance;
String get balance {
if (coinTypeToSpendFrom == UnspentCoinType.mweb) {
return balanceViewModel.balances.values.first.secondAvailableBalance;
} else if (coinTypeToSpendFrom == UnspentCoinType.nonMweb) {
return balanceViewModel.balances.values.first.availableBalance;
}
return wallet.balance[selectedCryptoCurrency]!.formattedFullAvailableBalance;
}
@computed
bool get isFiatDisabled => balanceViewModel.isFiatDisabled;
@@ -494,8 +505,12 @@ abstract class SendViewModelBase extends WalletChangeListenerViewModel with Stor
case WalletType.bitcoin:
case WalletType.litecoin:
case WalletType.bitcoinCash:
return bitcoin!.createBitcoinTransactionCredentials(outputs,
priority: priority!, feeRate: customBitcoinFeeRate);
return bitcoin!.createBitcoinTransactionCredentials(
outputs,
priority: priority!,
feeRate: customBitcoinFeeRate,
coinTypeToSpendFrom: coinTypeToSpendFrom,
);
case WalletType.monero:
return monero!
@@ -3,6 +3,7 @@ import 'package:cake_wallet/monero/monero.dart';
import 'package:cake_wallet/utils/exception_handler.dart';
import 'package:cake_wallet/view_model/unspent_coins/unspent_coins_item.dart';
import 'package:cake_wallet/wownero/wownero.dart';
import 'package:cw_core/unspent_coin_type.dart';
import 'package:cw_core/unspent_coins_info.dart';
import 'package:cw_core/unspent_transaction_output.dart';
import 'package:cw_core/wallet_base.dart';
@@ -16,9 +17,11 @@ part 'unspent_coins_list_view_model.g.dart';
class UnspentCoinsListViewModel = UnspentCoinsListViewModelBase with _$UnspentCoinsListViewModel;
abstract class UnspentCoinsListViewModelBase with Store {
UnspentCoinsListViewModelBase(
{required this.wallet, required Box<UnspentCoinsInfo> unspentCoinsInfo})
: _unspentCoinsInfo = unspentCoinsInfo,
UnspentCoinsListViewModelBase({
required this.wallet,
required Box<UnspentCoinsInfo> unspentCoinsInfo,
this.coinTypeToSpendFrom = UnspentCoinType.any,
}) : _unspentCoinsInfo = unspentCoinsInfo,
_items = ObservableList<UnspentCoinsItem>() {
_updateUnspentCoinsInfo();
_updateUnspents();
@@ -26,6 +29,7 @@ abstract class UnspentCoinsListViewModelBase with Store {
WalletBase wallet;
final Box<UnspentCoinsInfo> _unspentCoinsInfo;
final UnspentCoinType coinTypeToSpendFrom;
@observable
ObservableList<UnspentCoinsItem> _items;
@@ -103,7 +107,7 @@ abstract class UnspentCoinsListViewModelBase with Store {
case WalletType.bitcoin:
case WalletType.litecoin:
case WalletType.bitcoinCash:
return bitcoin!.getUnspents(wallet);
return bitcoin!.getUnspents(wallet, coinTypeToSpendFrom: coinTypeToSpendFrom);
default:
return List.empty();
}