mirror of
https://github.com/cypherstack/stack_wallet.git
synced 2025-01-29 21:55:58 +00:00
firo pub/priv balance send from choice on exchange flow
This commit is contained in:
parent
bb260e3a23
commit
c88971ebd6
2 changed files with 404 additions and 168 deletions
|
@ -10,6 +10,7 @@ import 'package:stackwallet/pages/wallet_view/wallet_view.dart';
|
|||
import 'package:stackwallet/providers/exchange/trade_sent_from_stack_lookup_provider.dart';
|
||||
import 'package:stackwallet/providers/providers.dart';
|
||||
import 'package:stackwallet/route_generator.dart';
|
||||
import 'package:stackwallet/services/coins/firo/firo_wallet.dart';
|
||||
import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
||||
import 'package:stackwallet/utilities/format.dart';
|
||||
import 'package:stackwallet/utilities/text_styles.dart';
|
||||
|
@ -27,6 +28,7 @@ class ConfirmChangeNowSendView extends ConsumerStatefulWidget {
|
|||
required this.walletId,
|
||||
this.routeOnSuccessName = WalletView.routeName,
|
||||
required this.trade,
|
||||
this.shouldSendPublicFiroFunds,
|
||||
}) : super(key: key);
|
||||
|
||||
static const String routeName = "/confirmChangeNowSend";
|
||||
|
@ -35,6 +37,7 @@ class ConfirmChangeNowSendView extends ConsumerStatefulWidget {
|
|||
final String walletId;
|
||||
final String routeOnSuccessName;
|
||||
final Trade trade;
|
||||
final bool? shouldSendPublicFiroFunds;
|
||||
|
||||
@override
|
||||
ConsumerState<ConfirmChangeNowSendView> createState() =>
|
||||
|
@ -63,7 +66,15 @@ class _ConfirmChangeNowSendViewState
|
|||
ref.read(walletsChangeNotifierProvider).getManager(walletId);
|
||||
|
||||
try {
|
||||
final txid = await manager.confirmSend(txData: transactionInfo);
|
||||
late final String txid;
|
||||
|
||||
if (widget.shouldSendPublicFiroFunds == true) {
|
||||
txid = await (manager.wallet as FiroWallet)
|
||||
.confirmSendPublic(txData: transactionInfo);
|
||||
} else {
|
||||
txid = await manager.confirmSend(txData: transactionInfo);
|
||||
}
|
||||
|
||||
unawaited(manager.refresh());
|
||||
|
||||
// save note
|
||||
|
|
|
@ -10,6 +10,8 @@ import 'package:stackwallet/pages/home_view/home_view.dart';
|
|||
import 'package:stackwallet/pages/send_view/sub_widgets/building_transaction_dialog.dart';
|
||||
import 'package:stackwallet/providers/providers.dart';
|
||||
import 'package:stackwallet/route_generator.dart';
|
||||
import 'package:stackwallet/services/coins/firo/firo_wallet.dart';
|
||||
import 'package:stackwallet/services/coins/manager.dart';
|
||||
import 'package:stackwallet/utilities/assets.dart';
|
||||
import 'package:stackwallet/utilities/constants.dart';
|
||||
import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
||||
|
@ -18,7 +20,9 @@ import 'package:stackwallet/utilities/format.dart';
|
|||
import 'package:stackwallet/utilities/text_styles.dart';
|
||||
import 'package:stackwallet/utilities/theme/stack_colors.dart';
|
||||
import 'package:stackwallet/widgets/animated_text.dart';
|
||||
import 'package:stackwallet/widgets/conditional_parent.dart';
|
||||
import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart';
|
||||
import 'package:stackwallet/widgets/expandable.dart';
|
||||
import 'package:stackwallet/widgets/rounded_white_container.dart';
|
||||
import 'package:stackwallet/widgets/stack_dialog.dart';
|
||||
|
||||
|
@ -162,6 +166,130 @@ class _SendFromCardState extends ConsumerState<SendFromCard> {
|
|||
late final String address;
|
||||
late final Trade trade;
|
||||
|
||||
Future<void> _send(Manager manager, {bool? shouldSendPublicFiroFunds}) async {
|
||||
final _amount = Format.decimalAmountToSatoshis(amount);
|
||||
|
||||
try {
|
||||
bool wasCancelled = false;
|
||||
|
||||
unawaited(
|
||||
showDialog<dynamic>(
|
||||
context: context,
|
||||
useSafeArea: false,
|
||||
barrierDismissible: false,
|
||||
builder: (context) {
|
||||
return BuildingTransactionDialog(
|
||||
onCancel: () {
|
||||
wasCancelled = true;
|
||||
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
|
||||
late Map<String, dynamic> txData;
|
||||
|
||||
// if not firo then do normal send
|
||||
if (shouldSendPublicFiroFunds == null) {
|
||||
txData = await manager.prepareSend(
|
||||
address: address,
|
||||
satoshiAmount: _amount,
|
||||
args: {
|
||||
"feeRate": FeeRateType.average,
|
||||
// ref.read(feeRateTypeStateProvider)
|
||||
},
|
||||
);
|
||||
} else {
|
||||
final firoWallet = manager.wallet as FiroWallet;
|
||||
// otherwise do firo send based on balance selected
|
||||
if (shouldSendPublicFiroFunds) {
|
||||
txData = await firoWallet.prepareSendPublic(
|
||||
address: address,
|
||||
satoshiAmount: _amount,
|
||||
args: {
|
||||
"feeRate": FeeRateType.average,
|
||||
// ref.read(feeRateTypeStateProvider)
|
||||
},
|
||||
);
|
||||
} else {
|
||||
txData = await firoWallet.prepareSend(
|
||||
address: address,
|
||||
satoshiAmount: _amount,
|
||||
args: {
|
||||
"feeRate": FeeRateType.average,
|
||||
// ref.read(feeRateTypeStateProvider)
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (!wasCancelled) {
|
||||
// pop building dialog
|
||||
|
||||
if (mounted) {
|
||||
Navigator.of(context).pop();
|
||||
}
|
||||
|
||||
txData["note"] =
|
||||
"${trade.payInCurrency.toUpperCase()}/${trade.payOutCurrency.toUpperCase()} exchange";
|
||||
txData["address"] = address;
|
||||
|
||||
if (mounted) {
|
||||
await Navigator.of(context).push(
|
||||
RouteGenerator.getRoute(
|
||||
shouldUseMaterialRoute: RouteGenerator.useMaterialPageRoute,
|
||||
builder: (_) => ConfirmChangeNowSendView(
|
||||
transactionInfo: txData,
|
||||
walletId: walletId,
|
||||
routeOnSuccessName: HomeView.routeName,
|
||||
trade: trade,
|
||||
shouldSendPublicFiroFunds: shouldSendPublicFiroFunds,
|
||||
),
|
||||
settings: const RouteSettings(
|
||||
name: ConfirmChangeNowSendView.routeName,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
// if (mounted) {
|
||||
// pop building dialog
|
||||
Navigator.of(context).pop();
|
||||
|
||||
await showDialog<dynamic>(
|
||||
context: context,
|
||||
useSafeArea: false,
|
||||
barrierDismissible: true,
|
||||
builder: (context) {
|
||||
return StackDialog(
|
||||
title: "Transaction failed",
|
||||
message: e.toString(),
|
||||
rightButton: TextButton(
|
||||
style: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.getSecondaryEnabledButtonColor(context),
|
||||
child: Text(
|
||||
"Ok",
|
||||
style: STextStyles.button(context).copyWith(
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.buttonTextSecondary,
|
||||
),
|
||||
),
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
walletId = widget.walletId;
|
||||
|
@ -182,181 +310,278 @@ class _SendFromCardState extends ConsumerState<SendFromCard> {
|
|||
|
||||
final coin = manager.coin;
|
||||
|
||||
final isFiro = coin == Coin.firoTestNet || coin == Coin.firo;
|
||||
|
||||
return RoundedWhiteContainer(
|
||||
padding: const EdgeInsets.all(0),
|
||||
child: MaterialButton(
|
||||
splashColor: Theme.of(context).extension<StackColors>()!.highlight,
|
||||
key: Key("walletsSheetItemButtonKey_$walletId"),
|
||||
padding: const EdgeInsets.all(8),
|
||||
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(
|
||||
Constants.size.circularBorderRadius,
|
||||
child: ConditionalParent(
|
||||
condition: isFiro,
|
||||
builder: (child) => Expandable(
|
||||
header: Container(
|
||||
color: Colors.transparent,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(12),
|
||||
child: child,
|
||||
),
|
||||
),
|
||||
body: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
MaterialButton(
|
||||
splashColor:
|
||||
Theme.of(context).extension<StackColors>()!.highlight,
|
||||
key: Key("walletsSheetItemButtonFiroPrivateKey_$walletId"),
|
||||
padding: const EdgeInsets.all(0),
|
||||
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(
|
||||
Constants.size.circularBorderRadius,
|
||||
),
|
||||
),
|
||||
onPressed: () => _send(
|
||||
manager,
|
||||
shouldSendPublicFiroFunds: false,
|
||||
),
|
||||
child: Container(
|
||||
color: Colors.transparent,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(
|
||||
top: 6,
|
||||
left: 16,
|
||||
right: 16,
|
||||
bottom: 6,
|
||||
),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
"Use private balance",
|
||||
style: STextStyles.itemSubtitle(context),
|
||||
),
|
||||
FutureBuilder(
|
||||
future: (manager.wallet as FiroWallet)
|
||||
.availablePrivateBalance(),
|
||||
builder: (builderContext,
|
||||
AsyncSnapshot<Decimal> snapshot) {
|
||||
if (snapshot.connectionState ==
|
||||
ConnectionState.done &&
|
||||
snapshot.hasData) {
|
||||
return Text(
|
||||
"${Format.localizedStringAsFixed(
|
||||
value: snapshot.data!,
|
||||
locale: locale,
|
||||
decimalPlaces: Constants.decimalPlaces,
|
||||
)} ${coin.ticker}",
|
||||
style: STextStyles.itemSubtitle(context),
|
||||
);
|
||||
} else {
|
||||
return AnimatedText(
|
||||
stringsToLoopThrough: const [
|
||||
"Loading balance",
|
||||
"Loading balance.",
|
||||
"Loading balance..",
|
||||
"Loading balance..."
|
||||
],
|
||||
style: STextStyles.itemSubtitle(context),
|
||||
);
|
||||
}
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
SvgPicture.asset(
|
||||
Assets.svg.chevronRight,
|
||||
height: 14,
|
||||
width: 7,
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.infoItemLabel,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
MaterialButton(
|
||||
splashColor:
|
||||
Theme.of(context).extension<StackColors>()!.highlight,
|
||||
key: Key("walletsSheetItemButtonFiroPublicKey_$walletId"),
|
||||
padding: const EdgeInsets.all(0),
|
||||
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(
|
||||
Constants.size.circularBorderRadius,
|
||||
),
|
||||
),
|
||||
onPressed: () => _send(
|
||||
manager,
|
||||
shouldSendPublicFiroFunds: true,
|
||||
),
|
||||
child: Container(
|
||||
color: Colors.transparent,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(
|
||||
top: 6,
|
||||
left: 16,
|
||||
right: 16,
|
||||
bottom: 6,
|
||||
),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
"Use public balance",
|
||||
style: STextStyles.itemSubtitle(context),
|
||||
),
|
||||
FutureBuilder(
|
||||
future: (manager.wallet as FiroWallet)
|
||||
.availablePublicBalance(),
|
||||
builder: (builderContext,
|
||||
AsyncSnapshot<Decimal> snapshot) {
|
||||
if (snapshot.connectionState ==
|
||||
ConnectionState.done &&
|
||||
snapshot.hasData) {
|
||||
return Text(
|
||||
"${Format.localizedStringAsFixed(
|
||||
value: snapshot.data!,
|
||||
locale: locale,
|
||||
decimalPlaces: Constants.decimalPlaces,
|
||||
)} ${coin.ticker}",
|
||||
style: STextStyles.itemSubtitle(context),
|
||||
);
|
||||
} else {
|
||||
return AnimatedText(
|
||||
stringsToLoopThrough: const [
|
||||
"Loading balance",
|
||||
"Loading balance.",
|
||||
"Loading balance..",
|
||||
"Loading balance..."
|
||||
],
|
||||
style: STextStyles.itemSubtitle(context),
|
||||
);
|
||||
}
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
SvgPicture.asset(
|
||||
Assets.svg.chevronRight,
|
||||
height: 14,
|
||||
width: 7,
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.infoItemLabel,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 6,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
onPressed: () async {
|
||||
final _amount = Format.decimalAmountToSatoshis(amount);
|
||||
|
||||
try {
|
||||
bool wasCancelled = false;
|
||||
|
||||
unawaited(showDialog<dynamic>(
|
||||
context: context,
|
||||
useSafeArea: false,
|
||||
barrierDismissible: false,
|
||||
builder: (context) {
|
||||
return BuildingTransactionDialog(
|
||||
onCancel: () {
|
||||
wasCancelled = true;
|
||||
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
);
|
||||
},
|
||||
));
|
||||
|
||||
final txData = await manager.prepareSend(
|
||||
address: address,
|
||||
satoshiAmount: _amount,
|
||||
args: {
|
||||
"feeRate": FeeRateType.average,
|
||||
// ref.read(feeRateTypeStateProvider)
|
||||
},
|
||||
);
|
||||
|
||||
if (!wasCancelled) {
|
||||
// pop building dialog
|
||||
|
||||
if (mounted) {
|
||||
Navigator.of(context).pop();
|
||||
}
|
||||
|
||||
txData["note"] =
|
||||
"${trade.payInCurrency.toUpperCase()}/${trade.payOutCurrency.toUpperCase()} exchange";
|
||||
txData["address"] = address;
|
||||
|
||||
if (mounted) {
|
||||
await Navigator.of(context).push(
|
||||
RouteGenerator.getRoute(
|
||||
shouldUseMaterialRoute: RouteGenerator.useMaterialPageRoute,
|
||||
builder: (_) => ConfirmChangeNowSendView(
|
||||
transactionInfo: txData,
|
||||
walletId: walletId,
|
||||
routeOnSuccessName: HomeView.routeName,
|
||||
trade: trade,
|
||||
),
|
||||
settings: const RouteSettings(
|
||||
name: ConfirmChangeNowSendView.routeName,
|
||||
),
|
||||
child: ConditionalParent(
|
||||
condition: !isFiro,
|
||||
builder: (child) => MaterialButton(
|
||||
splashColor: Theme.of(context).extension<StackColors>()!.highlight,
|
||||
key: Key("walletsSheetItemButtonKey_$walletId"),
|
||||
padding: const EdgeInsets.all(8),
|
||||
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(
|
||||
Constants.size.circularBorderRadius,
|
||||
),
|
||||
),
|
||||
onPressed: () => _send(manager),
|
||||
child: child,
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
Container(
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.colorForCoin(manager.coin)
|
||||
.withOpacity(0.5),
|
||||
borderRadius: BorderRadius.circular(
|
||||
Constants.size.circularBorderRadius,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
// if (mounted) {
|
||||
// pop building dialog
|
||||
Navigator.of(context).pop();
|
||||
|
||||
await showDialog<dynamic>(
|
||||
context: context,
|
||||
useSafeArea: false,
|
||||
barrierDismissible: true,
|
||||
builder: (context) {
|
||||
return StackDialog(
|
||||
title: "Transaction failed",
|
||||
message: e.toString(),
|
||||
rightButton: TextButton(
|
||||
style: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.getSecondaryEnabledButtonColor(context),
|
||||
child: Text(
|
||||
"Ok",
|
||||
style: STextStyles.button(context).copyWith(
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.buttonTextSecondary,
|
||||
),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(6),
|
||||
child: SvgPicture.asset(
|
||||
Assets.svg.iconFor(coin: coin),
|
||||
width: 24,
|
||||
height: 24,
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
width: 12,
|
||||
),
|
||||
Expanded(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
manager.walletName,
|
||||
style: STextStyles.titleBold12(context),
|
||||
),
|
||||
if (!isFiro)
|
||||
const SizedBox(
|
||||
height: 2,
|
||||
),
|
||||
),
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
// }
|
||||
}
|
||||
},
|
||||
child: Row(
|
||||
children: [
|
||||
Container(
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.colorForCoin(manager.coin)
|
||||
.withOpacity(0.5),
|
||||
borderRadius: BorderRadius.circular(
|
||||
Constants.size.circularBorderRadius,
|
||||
if (!isFiro)
|
||||
FutureBuilder(
|
||||
future: manager.totalBalance,
|
||||
builder:
|
||||
(builderContext, AsyncSnapshot<Decimal> snapshot) {
|
||||
if (snapshot.connectionState ==
|
||||
ConnectionState.done &&
|
||||
snapshot.hasData) {
|
||||
return Text(
|
||||
"${Format.localizedStringAsFixed(
|
||||
value: snapshot.data!,
|
||||
locale: locale,
|
||||
decimalPlaces: coin == Coin.monero
|
||||
? Constants.decimalPlacesMonero
|
||||
: coin == Coin.wownero
|
||||
? Constants.decimalPlacesWownero
|
||||
: Constants.decimalPlaces,
|
||||
)} ${coin.ticker}",
|
||||
style: STextStyles.itemSubtitle(context),
|
||||
);
|
||||
} else {
|
||||
return AnimatedText(
|
||||
stringsToLoopThrough: const [
|
||||
"Loading balance",
|
||||
"Loading balance.",
|
||||
"Loading balance..",
|
||||
"Loading balance..."
|
||||
],
|
||||
style: STextStyles.itemSubtitle(context),
|
||||
);
|
||||
}
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(6),
|
||||
child: SvgPicture.asset(
|
||||
Assets.svg.iconFor(coin: coin),
|
||||
width: 24,
|
||||
height: 24,
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
width: 12,
|
||||
),
|
||||
Expanded(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
manager.walletName,
|
||||
style: STextStyles.titleBold12(context),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 2,
|
||||
),
|
||||
FutureBuilder(
|
||||
future: manager.totalBalance,
|
||||
builder: (builderContext, AsyncSnapshot<Decimal> snapshot) {
|
||||
if (snapshot.connectionState == ConnectionState.done &&
|
||||
snapshot.hasData) {
|
||||
return Text(
|
||||
"${Format.localizedStringAsFixed(
|
||||
value: snapshot.data!,
|
||||
locale: locale,
|
||||
decimalPlaces: coin == Coin.monero
|
||||
? Constants.decimalPlacesMonero
|
||||
: coin == Coin.wownero
|
||||
? Constants.decimalPlacesWownero
|
||||
: Constants.decimalPlaces,
|
||||
)} ${coin.ticker}",
|
||||
style: STextStyles.itemSubtitle(context),
|
||||
);
|
||||
} else {
|
||||
return AnimatedText(
|
||||
stringsToLoopThrough: const [
|
||||
"Loading balance",
|
||||
"Loading balance.",
|
||||
"Loading balance..",
|
||||
"Loading balance..."
|
||||
],
|
||||
style: STextStyles.itemSubtitle(context),
|
||||
);
|
||||
}
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
|
Loading…
Reference in a new issue