mirror of
https://github.com/cypherstack/stack_wallet.git
synced 2025-01-30 14:15:52 +00:00
WIP firo redesign
This commit is contained in:
parent
94941dfb94
commit
fbc398bc14
9 changed files with 938 additions and 159 deletions
|
@ -13,7 +13,9 @@ import 'package:stackwallet/pages/send_view/sub_widgets/transaction_fee_selectio
|
|||
import 'package:stackwallet/providers/providers.dart';
|
||||
import 'package:stackwallet/providers/ui/fee_rate_type_state_provider.dart';
|
||||
import 'package:stackwallet/providers/ui/preview_tx_button_state_provider.dart';
|
||||
import 'package:stackwallet/providers/wallet/public_private_balance_state_provider.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/address_utils.dart';
|
||||
import 'package:stackwallet/utilities/assets.dart';
|
||||
|
@ -37,6 +39,8 @@ import 'package:stackwallet/widgets/stack_dialog.dart';
|
|||
import 'package:stackwallet/widgets/stack_text_field.dart';
|
||||
import 'package:stackwallet/widgets/textfield_icon_button.dart';
|
||||
|
||||
import 'sub_widgets/firo_balance_selection_sheet.dart';
|
||||
|
||||
class SendView extends ConsumerStatefulWidget {
|
||||
const SendView({
|
||||
Key? key,
|
||||
|
@ -82,6 +86,9 @@ class _SendViewState extends ConsumerState<SendView> {
|
|||
Decimal? _cachedAmountToSend;
|
||||
String? _address;
|
||||
|
||||
String? _privateBalanceString;
|
||||
String? _publicBalanceString;
|
||||
|
||||
bool _addressToggleFlag = false;
|
||||
|
||||
bool _cryptoAmountChangeLock = false;
|
||||
|
@ -196,6 +203,26 @@ class _SendViewState extends ConsumerState<SendView> {
|
|||
return cachedFees[amount]!;
|
||||
}
|
||||
|
||||
Future<String?> _firoBalanceFuture(
|
||||
ChangeNotifierProvider<Manager> provider, String locale) async {
|
||||
final wallet = ref.read(provider).wallet as FiroWallet?;
|
||||
|
||||
if (wallet != null) {
|
||||
Decimal? balance;
|
||||
if (ref.read(publicPrivateBalanceStateProvider.state).state ==
|
||||
"Private") {
|
||||
balance = await wallet.availablePrivateBalance();
|
||||
} else {
|
||||
balance = await wallet.availablePublicBalance();
|
||||
}
|
||||
|
||||
return Format.localizedStringAsFixed(
|
||||
value: balance, locale: locale, decimalPlaces: 8);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
ref.refresh(feeSheetSessionCacheProvider);
|
||||
|
@ -334,21 +361,59 @@ class _SendViewState extends ConsumerState<SendView> {
|
|||
children: [
|
||||
SvgPicture.asset(
|
||||
Assets.svg.iconFor(coin: coin),
|
||||
width: 18,
|
||||
height: 18,
|
||||
width: 22,
|
||||
height: 22,
|
||||
),
|
||||
const SizedBox(
|
||||
width: 6,
|
||||
),
|
||||
if (coin != Coin.firo &&
|
||||
coin != Coin.firoTestNet)
|
||||
Text(
|
||||
ref.watch(provider
|
||||
.select((value) => value.walletName)),
|
||||
style: STextStyles.titleBold12,
|
||||
),
|
||||
if (coin == Coin.firo ||
|
||||
coin == Coin.firoTestNet)
|
||||
Column(
|
||||
crossAxisAlignment:
|
||||
CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
ref.watch(provider.select(
|
||||
(value) => value.walletName)),
|
||||
style: STextStyles.titleBold12
|
||||
.copyWith(fontSize: 14),
|
||||
),
|
||||
// const SizedBox(
|
||||
// height: 2,
|
||||
// ),
|
||||
Text(
|
||||
"${ref.watch(publicPrivateBalanceStateProvider.state).state} balance",
|
||||
style: STextStyles.label
|
||||
.copyWith(fontSize: 10),
|
||||
),
|
||||
],
|
||||
),
|
||||
const Spacer(),
|
||||
FutureBuilder(
|
||||
future: ref.watch(provider.select(
|
||||
(value) => value.availableBalance)),
|
||||
future: (coin != Coin.firo &&
|
||||
coin != Coin.firoTestNet)
|
||||
? ref.watch(provider.select(
|
||||
(value) => value.availableBalance))
|
||||
: ref
|
||||
.watch(
|
||||
publicPrivateBalanceStateProvider
|
||||
.state)
|
||||
.state ==
|
||||
"Private"
|
||||
? (ref.watch(provider).wallet
|
||||
as FiroWallet)
|
||||
.availablePrivateBalance()
|
||||
: (ref.watch(provider).wallet
|
||||
as FiroWallet)
|
||||
.availablePublicBalance(),
|
||||
builder:
|
||||
(_, AsyncSnapshot<Decimal> snapshot) {
|
||||
if (snapshot.connectionState ==
|
||||
|
@ -423,6 +488,9 @@ class _SendViewState extends ConsumerState<SendView> {
|
|||
fontSize: 10,
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 2,
|
||||
),
|
||||
AnimatedText(
|
||||
stringsToLoopThrough: const [
|
||||
"Loading balance ",
|
||||
|
@ -730,6 +798,141 @@ class _SendViewState extends ConsumerState<SendView> {
|
|||
}
|
||||
},
|
||||
),
|
||||
if (coin == Coin.firo)
|
||||
const SizedBox(
|
||||
height: 12,
|
||||
),
|
||||
if (coin == Coin.firo)
|
||||
Text(
|
||||
"Send from",
|
||||
style: STextStyles.smallMed12,
|
||||
textAlign: TextAlign.left,
|
||||
),
|
||||
if (coin == Coin.firo)
|
||||
const SizedBox(
|
||||
height: 8,
|
||||
),
|
||||
if (coin == Coin.firo)
|
||||
Stack(
|
||||
children: [
|
||||
const TextField(
|
||||
readOnly: true,
|
||||
textInputAction: TextInputAction.none,
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 12,
|
||||
),
|
||||
child: RawMaterialButton(
|
||||
splashColor: CFColors.splashLight,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(
|
||||
Constants.size.circularBorderRadius,
|
||||
),
|
||||
),
|
||||
onPressed: () {
|
||||
showModalBottomSheet<dynamic>(
|
||||
backgroundColor: Colors.transparent,
|
||||
context: context,
|
||||
shape: const RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.vertical(
|
||||
top: Radius.circular(20),
|
||||
),
|
||||
),
|
||||
builder: (_) => FiroBalanceSelectionSheet(
|
||||
walletId: walletId,
|
||||
),
|
||||
);
|
||||
},
|
||||
child: Row(
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
Text(
|
||||
"${ref.watch(publicPrivateBalanceStateProvider.state).state} balance",
|
||||
style: STextStyles.itemSubtitle12,
|
||||
),
|
||||
const SizedBox(
|
||||
width: 10,
|
||||
),
|
||||
FutureBuilder(
|
||||
future: _firoBalanceFuture(
|
||||
provider, locale),
|
||||
builder: (context,
|
||||
AsyncSnapshot<String?>
|
||||
snapshot) {
|
||||
if (snapshot.connectionState ==
|
||||
ConnectionState.done &&
|
||||
snapshot.hasData) {
|
||||
if (ref
|
||||
.read(
|
||||
publicPrivateBalanceStateProvider
|
||||
.state)
|
||||
.state ==
|
||||
"Private") {
|
||||
_privateBalanceString =
|
||||
snapshot.data!;
|
||||
} else {
|
||||
_publicBalanceString =
|
||||
snapshot.data!;
|
||||
}
|
||||
}
|
||||
if (ref
|
||||
.read(
|
||||
publicPrivateBalanceStateProvider
|
||||
.state)
|
||||
.state ==
|
||||
"Private" &&
|
||||
_privateBalanceString !=
|
||||
null) {
|
||||
return Text(
|
||||
"$_privateBalanceString ${coin.ticker}",
|
||||
style:
|
||||
STextStyles.itemSubtitle,
|
||||
);
|
||||
} else if (ref
|
||||
.read(
|
||||
publicPrivateBalanceStateProvider
|
||||
.state)
|
||||
.state ==
|
||||
"Public" &&
|
||||
_publicBalanceString !=
|
||||
null) {
|
||||
return Text(
|
||||
"$_publicBalanceString ${coin.ticker}",
|
||||
style:
|
||||
STextStyles.itemSubtitle,
|
||||
);
|
||||
} else {
|
||||
return AnimatedText(
|
||||
stringsToLoopThrough: const [
|
||||
"Loading balance",
|
||||
"Loading balance.",
|
||||
"Loading balance..",
|
||||
"Loading balance...",
|
||||
],
|
||||
style:
|
||||
STextStyles.itemSubtitle,
|
||||
);
|
||||
}
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
SvgPicture.asset(
|
||||
Assets.svg.chevronDown,
|
||||
width: 8,
|
||||
height: 4,
|
||||
color: CFColors.gray3,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
const SizedBox(
|
||||
height: 12,
|
||||
),
|
||||
|
@ -744,10 +947,34 @@ class _SendViewState extends ConsumerState<SendView> {
|
|||
BlueTextButton(
|
||||
text: "Send all ${coin.ticker}",
|
||||
onTap: () async {
|
||||
if (coin == Coin.firo ||
|
||||
coin == Coin.firoTestNet) {
|
||||
final firoWallet =
|
||||
ref.read(provider).wallet as FiroWallet;
|
||||
if (ref
|
||||
.read(
|
||||
publicPrivateBalanceStateProvider
|
||||
.state)
|
||||
.state ==
|
||||
"Private") {
|
||||
cryptoAmountController.text =
|
||||
(await firoWallet
|
||||
.availablePrivateBalance())
|
||||
.toStringAsFixed(
|
||||
Constants.decimalPlaces);
|
||||
} else {
|
||||
cryptoAmountController.text =
|
||||
(await firoWallet
|
||||
.availablePublicBalance())
|
||||
.toStringAsFixed(
|
||||
Constants.decimalPlaces);
|
||||
}
|
||||
} else {
|
||||
cryptoAmountController.text = (await ref
|
||||
.read(provider)
|
||||
.availableBalance)
|
||||
.toStringAsFixed(Constants.decimalPlaces);
|
||||
}
|
||||
},
|
||||
),
|
||||
],
|
||||
|
|
|
@ -0,0 +1,287 @@
|
|||
import 'package:decimal/decimal.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:stackwallet/providers/providers.dart';
|
||||
import 'package:stackwallet/providers/wallet/public_private_balance_state_provider.dart';
|
||||
import 'package:stackwallet/services/coins/firo/firo_wallet.dart';
|
||||
import 'package:stackwallet/utilities/cfcolors.dart';
|
||||
import 'package:stackwallet/utilities/constants.dart';
|
||||
import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
||||
import 'package:stackwallet/utilities/text_styles.dart';
|
||||
import 'package:stackwallet/widgets/animated_text.dart';
|
||||
|
||||
class FiroBalanceSelectionSheet extends ConsumerStatefulWidget {
|
||||
const FiroBalanceSelectionSheet({
|
||||
Key? key,
|
||||
required this.walletId,
|
||||
}) : super(key: key);
|
||||
|
||||
final String walletId;
|
||||
|
||||
@override
|
||||
ConsumerState<FiroBalanceSelectionSheet> createState() =>
|
||||
_FiroBalanceSelectionSheetState();
|
||||
}
|
||||
|
||||
class _FiroBalanceSelectionSheetState
|
||||
extends ConsumerState<FiroBalanceSelectionSheet> {
|
||||
late final String walletId;
|
||||
|
||||
final stringsToLoopThrough = [
|
||||
"Loading balance",
|
||||
"Loading balance.",
|
||||
"Loading balance..",
|
||||
"Loading balance...",
|
||||
];
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
walletId = widget.walletId;
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
debugPrint("BUILD: $runtimeType");
|
||||
|
||||
final manager = ref.watch(walletsChangeNotifierProvider
|
||||
.select((value) => value.getManager(walletId)));
|
||||
final firoWallet = manager.wallet as FiroWallet;
|
||||
|
||||
return Container(
|
||||
decoration: const BoxDecoration(
|
||||
color: CFColors.white,
|
||||
borderRadius: BorderRadius.vertical(
|
||||
top: Radius.circular(20),
|
||||
),
|
||||
),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(
|
||||
left: 24,
|
||||
right: 24,
|
||||
top: 10,
|
||||
bottom: 0,
|
||||
),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Center(
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
color: CFColors.fieldGray,
|
||||
borderRadius: BorderRadius.circular(
|
||||
Constants.size.circularBorderRadius,
|
||||
),
|
||||
),
|
||||
width: 60,
|
||||
height: 4,
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 36,
|
||||
),
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
"Select balance",
|
||||
style: STextStyles.pageTitleH2,
|
||||
textAlign: TextAlign.left,
|
||||
),
|
||||
const SizedBox(
|
||||
height: 16,
|
||||
),
|
||||
GestureDetector(
|
||||
onTap: () {
|
||||
final state =
|
||||
ref.read(publicPrivateBalanceStateProvider.state).state;
|
||||
if (state != "Private") {
|
||||
ref.read(publicPrivateBalanceStateProvider.state).state =
|
||||
"Private";
|
||||
}
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
child: Container(
|
||||
color: Colors.transparent,
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
SizedBox(
|
||||
width: 20,
|
||||
height: 20,
|
||||
child: Radio(
|
||||
activeColor: CFColors.link2,
|
||||
value: "Private",
|
||||
groupValue: ref
|
||||
.watch(
|
||||
publicPrivateBalanceStateProvider.state)
|
||||
.state,
|
||||
onChanged: (x) {
|
||||
ref
|
||||
.read(publicPrivateBalanceStateProvider
|
||||
.state)
|
||||
.state = "Private";
|
||||
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(
|
||||
width: 12,
|
||||
),
|
||||
Flexible(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
// Row(
|
||||
// children: [
|
||||
Text(
|
||||
"Private balance",
|
||||
style: STextStyles.titleBold12.copyWith(
|
||||
color: const Color(0xFF44464E),
|
||||
),
|
||||
textAlign: TextAlign.left,
|
||||
),
|
||||
const SizedBox(
|
||||
width: 2,
|
||||
),
|
||||
FutureBuilder(
|
||||
future: firoWallet.availablePrivateBalance(),
|
||||
builder:
|
||||
(context, AsyncSnapshot<Decimal> snapshot) {
|
||||
if (snapshot.connectionState ==
|
||||
ConnectionState.done &&
|
||||
snapshot.hasData) {
|
||||
return Text(
|
||||
"${snapshot.data!} ${manager.coin.ticker}",
|
||||
style: STextStyles.itemSubtitle,
|
||||
textAlign: TextAlign.left,
|
||||
);
|
||||
} else {
|
||||
return AnimatedText(
|
||||
stringsToLoopThrough:
|
||||
stringsToLoopThrough,
|
||||
style: STextStyles.itemSubtitle,
|
||||
);
|
||||
}
|
||||
},
|
||||
)
|
||||
],
|
||||
),
|
||||
// ],
|
||||
// ),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 16,
|
||||
),
|
||||
GestureDetector(
|
||||
onTap: () {
|
||||
final state =
|
||||
ref.read(publicPrivateBalanceStateProvider.state).state;
|
||||
if (state != "Public") {
|
||||
ref.read(publicPrivateBalanceStateProvider.state).state =
|
||||
"Public";
|
||||
}
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
child: Container(
|
||||
color: Colors.transparent,
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Column(
|
||||
children: [
|
||||
SizedBox(
|
||||
width: 20,
|
||||
height: 20,
|
||||
child: Radio(
|
||||
activeColor: CFColors.link2,
|
||||
value: "Public",
|
||||
groupValue: ref
|
||||
.watch(
|
||||
publicPrivateBalanceStateProvider.state)
|
||||
.state,
|
||||
onChanged: (x) {
|
||||
ref
|
||||
.read(publicPrivateBalanceStateProvider
|
||||
.state)
|
||||
.state = "Public";
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(
|
||||
width: 12,
|
||||
),
|
||||
Flexible(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
// Row(
|
||||
// children: [
|
||||
Text(
|
||||
"Public balance",
|
||||
style: STextStyles.titleBold12.copyWith(
|
||||
color: const Color(0xFF44464E),
|
||||
),
|
||||
textAlign: TextAlign.left,
|
||||
),
|
||||
const SizedBox(
|
||||
width: 2,
|
||||
),
|
||||
FutureBuilder(
|
||||
future: firoWallet.availablePublicBalance(),
|
||||
builder:
|
||||
(context, AsyncSnapshot<Decimal> snapshot) {
|
||||
if (snapshot.connectionState ==
|
||||
ConnectionState.done &&
|
||||
snapshot.hasData) {
|
||||
return Text(
|
||||
"${snapshot.data!} ${manager.coin.ticker}",
|
||||
style: STextStyles.itemSubtitle,
|
||||
textAlign: TextAlign.left,
|
||||
);
|
||||
} else {
|
||||
return AnimatedText(
|
||||
stringsToLoopThrough:
|
||||
stringsToLoopThrough,
|
||||
style: STextStyles.itemSubtitle,
|
||||
);
|
||||
}
|
||||
},
|
||||
)
|
||||
// ],
|
||||
// ),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 16,
|
||||
),
|
||||
const SizedBox(
|
||||
height: 24,
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -1,8 +1,10 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:stackwallet/providers/providers.dart';
|
||||
import 'package:stackwallet/providers/wallet/wallet_balance_toggle_state_provider.dart';
|
||||
import 'package:stackwallet/utilities/cfcolors.dart';
|
||||
import 'package:stackwallet/utilities/constants.dart';
|
||||
import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
||||
import 'package:stackwallet/utilities/enums/wallet_balance_toggle_state.dart';
|
||||
import 'package:stackwallet/utilities/text_styles.dart';
|
||||
|
||||
|
@ -18,6 +20,9 @@ class WalletBalanceToggleSheet extends ConsumerWidget {
|
|||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final maxHeight = MediaQuery.of(context).size.height * 0.60;
|
||||
|
||||
final coin = ref.watch(walletsChangeNotifierProvider
|
||||
.select((value) => value.getManager(walletId).coin));
|
||||
|
||||
return Container(
|
||||
decoration: const BoxDecoration(
|
||||
color: CFColors.white,
|
||||
|
@ -105,6 +110,7 @@ class WalletBalanceToggleSheet extends ConsumerWidget {
|
|||
const SizedBox(
|
||||
width: 12,
|
||||
),
|
||||
if (coin != Coin.firo && coin != Coin.firoTestNet)
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
|
@ -115,7 +121,6 @@ class WalletBalanceToggleSheet extends ConsumerWidget {
|
|||
const SizedBox(
|
||||
height: 2,
|
||||
),
|
||||
// TODO need text from design
|
||||
Text(
|
||||
"Current spendable (unlocked) balance",
|
||||
style: STextStyles.itemSubtitle12.copyWith(
|
||||
|
@ -124,6 +129,25 @@ class WalletBalanceToggleSheet extends ConsumerWidget {
|
|||
),
|
||||
],
|
||||
),
|
||||
if (coin == Coin.firo || coin == Coin.firoTestNet)
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
"Private balance",
|
||||
style: STextStyles.titleBold12,
|
||||
),
|
||||
const SizedBox(
|
||||
height: 2,
|
||||
),
|
||||
Text(
|
||||
"Current private spendable (unlocked) balance",
|
||||
style: STextStyles.itemSubtitle12.copyWith(
|
||||
color: CFColors.neutral60,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
@ -172,6 +196,7 @@ class WalletBalanceToggleSheet extends ConsumerWidget {
|
|||
const SizedBox(
|
||||
width: 12,
|
||||
),
|
||||
if (coin != Coin.firo && coin != Coin.firoTestNet)
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
|
@ -182,7 +207,6 @@ class WalletBalanceToggleSheet extends ConsumerWidget {
|
|||
const SizedBox(
|
||||
height: 2,
|
||||
),
|
||||
// TODO need text from design
|
||||
Text(
|
||||
"Total wallet balance",
|
||||
style: STextStyles.itemSubtitle12.copyWith(
|
||||
|
@ -191,6 +215,25 @@ class WalletBalanceToggleSheet extends ConsumerWidget {
|
|||
),
|
||||
],
|
||||
),
|
||||
if (coin == Coin.firo || coin == Coin.firoTestNet)
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
"Public balance",
|
||||
style: STextStyles.titleBold12,
|
||||
),
|
||||
const SizedBox(
|
||||
height: 2,
|
||||
),
|
||||
Text(
|
||||
"Current public spendable (unlocked) balance",
|
||||
style: STextStyles.itemSubtitle12.copyWith(
|
||||
color: CFColors.neutral60,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
|
|
@ -6,6 +6,7 @@ import 'package:stackwallet/pages/wallet_view/sub_widgets/wallet_balance_toggle_
|
|||
import 'package:stackwallet/pages/wallet_view/sub_widgets/wallet_refresh_button.dart';
|
||||
import 'package:stackwallet/providers/providers.dart';
|
||||
import 'package:stackwallet/providers/wallet/wallet_balance_toggle_state_provider.dart';
|
||||
import 'package:stackwallet/services/coins/firo/firo_wallet.dart';
|
||||
import 'package:stackwallet/services/coins/manager.dart';
|
||||
import 'package:stackwallet/services/event_bus/events/global/wallet_sync_status_changed_event.dart';
|
||||
import 'package:stackwallet/utilities/assets.dart';
|
||||
|
@ -67,15 +68,25 @@ class _WalletSummaryInfoState extends State<WalletSummaryInfo> {
|
|||
Expanded(
|
||||
child: Consumer(
|
||||
builder: (_, ref, __) {
|
||||
final totalBalanceFuture = ref
|
||||
.watch(managerProvider.select((value) => value.totalBalance));
|
||||
|
||||
final availableBalanceFuture = ref.watch(
|
||||
managerProvider.select((value) => value.availableBalance));
|
||||
|
||||
final Coin coin =
|
||||
ref.watch(managerProvider.select((value) => value.coin));
|
||||
|
||||
Future<Decimal>? totalBalanceFuture;
|
||||
Future<Decimal>? availableBalanceFuture;
|
||||
if (coin == Coin.firo || coin == Coin.firoTestNet) {
|
||||
final firoWallet =
|
||||
ref.watch(managerProvider.select((value) => value.wallet))
|
||||
as FiroWallet;
|
||||
totalBalanceFuture = firoWallet.availablePublicBalance();
|
||||
availableBalanceFuture = firoWallet.availablePrivateBalance();
|
||||
} else {
|
||||
totalBalanceFuture = ref.watch(
|
||||
managerProvider.select((value) => value.totalBalance));
|
||||
|
||||
availableBalanceFuture = ref.watch(
|
||||
managerProvider.select((value) => value.availableBalance));
|
||||
}
|
||||
|
||||
final locale = ref.watch(localeServiceChangeNotifierProvider
|
||||
.select((value) => value.locale));
|
||||
|
||||
|
@ -114,6 +125,14 @@ class _WalletSummaryInfoState extends State<WalletSummaryInfo> {
|
|||
onTap: showSheet,
|
||||
child: Row(
|
||||
children: [
|
||||
if (coin == Coin.firo || coin == Coin.firoTestNet)
|
||||
Text(
|
||||
"${_showAvailable ? "Private" : "Public"} Balance",
|
||||
style: STextStyles.subtitle.copyWith(
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
if (coin != Coin.firo && coin != Coin.firoTestNet)
|
||||
Text(
|
||||
"${_showAvailable ? "Available" : "Full"} Balance",
|
||||
style: STextStyles.subtitle.copyWith(
|
||||
|
@ -166,6 +185,14 @@ class _WalletSummaryInfoState extends State<WalletSummaryInfo> {
|
|||
onTap: showSheet,
|
||||
child: Row(
|
||||
children: [
|
||||
if (coin == Coin.firo || coin == Coin.firoTestNet)
|
||||
Text(
|
||||
"${_showAvailable ? "Private" : "Public"} Balance",
|
||||
style: STextStyles.subtitle.copyWith(
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
if (coin != Coin.firo && coin != Coin.firoTestNet)
|
||||
Text(
|
||||
"${_showAvailable ? "Available" : "Full"} Balance",
|
||||
style: STextStyles.subtitle.copyWith(
|
||||
|
|
|
@ -71,11 +71,11 @@ class _TransactionDetailsViewState
|
|||
fee = Format.satoshisToAmount(_transaction.fees);
|
||||
amountPrefix = _transaction.txType.toLowerCase() == "sent" ? "- " : "+ ";
|
||||
|
||||
if (coin == Coin.firo || coin == Coin.firoTestNet) {
|
||||
showFeePending = true;
|
||||
} else {
|
||||
showFeePending = false;
|
||||
}
|
||||
// if (coin == Coin.firo || coin == Coin.firoTestNet) {
|
||||
// showFeePending = true;
|
||||
// } else {
|
||||
// showFeePending = false;
|
||||
// }
|
||||
super.initState();
|
||||
}
|
||||
|
||||
|
@ -86,9 +86,10 @@ class _TransactionDetailsViewState
|
|||
|
||||
String whatIsIt(String type) {
|
||||
if (type == "Received") {
|
||||
if (_transaction.isMinting) {
|
||||
return "Minting";
|
||||
} else if (_transaction.confirmedStatus) {
|
||||
// if (_transaction.isMinting) {
|
||||
// return "Minting";
|
||||
// } else
|
||||
if (_transaction.confirmedStatus) {
|
||||
return "Received";
|
||||
} else {
|
||||
return "Receiving";
|
||||
|
@ -507,83 +508,83 @@ class _TransactionDetailsViewState
|
|||
],
|
||||
),
|
||||
),
|
||||
if ((coin == Coin.firoTestNet || coin == Coin.firo) &&
|
||||
_transaction.subType == "mint")
|
||||
const SizedBox(
|
||||
height: 12,
|
||||
),
|
||||
if ((coin == Coin.firoTestNet || coin == Coin.firo) &&
|
||||
_transaction.subType == "mint")
|
||||
RoundedWhiteContainer(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
"Mint Transaction ID",
|
||||
style: STextStyles.itemSubtitle,
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(
|
||||
height: 8,
|
||||
),
|
||||
// Flexible(
|
||||
// child: FittedBox(
|
||||
// fit: BoxFit.scaleDown,
|
||||
// child:
|
||||
SelectableText(
|
||||
_transaction.otherData ?? "Unknown",
|
||||
style: STextStyles.itemSubtitle12,
|
||||
),
|
||||
// if ((coin == Coin.firoTestNet || coin == Coin.firo) &&
|
||||
// _transaction.subType == "mint")
|
||||
// const SizedBox(
|
||||
// height: 12,
|
||||
// ),
|
||||
// if ((coin == Coin.firoTestNet || coin == Coin.firo) &&
|
||||
// _transaction.subType == "mint")
|
||||
// RoundedWhiteContainer(
|
||||
// child: Column(
|
||||
// crossAxisAlignment: CrossAxisAlignment.start,
|
||||
// children: [
|
||||
// Row(
|
||||
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
// children: [
|
||||
// Text(
|
||||
// "Mint Transaction ID",
|
||||
// style: STextStyles.itemSubtitle,
|
||||
// ),
|
||||
const SizedBox(
|
||||
height: 8,
|
||||
),
|
||||
BlueTextButton(
|
||||
text: "Open in block explorer",
|
||||
onTap: () async {
|
||||
final uri = getBlockExplorerTransactionUrlFor(
|
||||
coin: coin,
|
||||
txid: _transaction.otherData ?? "Unknown",
|
||||
);
|
||||
// ref
|
||||
// .read(
|
||||
// shouldShowLockscreenOnResumeStateProvider
|
||||
// .state)
|
||||
// .state = false;
|
||||
try {
|
||||
await launchUrl(
|
||||
uri,
|
||||
mode: LaunchMode.externalApplication,
|
||||
);
|
||||
} catch (_) {
|
||||
showDialog<void>(
|
||||
context: context,
|
||||
builder: (_) => StackOkDialog(
|
||||
title: "Could not open in block explorer",
|
||||
message:
|
||||
"Failed to open \"${uri.toString()}\"",
|
||||
),
|
||||
);
|
||||
} finally {
|
||||
// Future<void>.delayed(
|
||||
// const Duration(seconds: 1),
|
||||
// () => ref
|
||||
// .read(
|
||||
// shouldShowLockscreenOnResumeStateProvider
|
||||
// .state)
|
||||
// .state = true,
|
||||
// ],
|
||||
// ),
|
||||
// const SizedBox(
|
||||
// height: 8,
|
||||
// ),
|
||||
// // Flexible(
|
||||
// // child: FittedBox(
|
||||
// // fit: BoxFit.scaleDown,
|
||||
// // child:
|
||||
// SelectableText(
|
||||
// _transaction.otherData ?? "Unknown",
|
||||
// style: STextStyles.itemSubtitle12,
|
||||
// ),
|
||||
// // ),
|
||||
// // ),
|
||||
// const SizedBox(
|
||||
// height: 8,
|
||||
// ),
|
||||
// BlueTextButton(
|
||||
// text: "Open in block explorer",
|
||||
// onTap: () async {
|
||||
// final uri = getBlockExplorerTransactionUrlFor(
|
||||
// coin: coin,
|
||||
// txid: _transaction.otherData ?? "Unknown",
|
||||
// );
|
||||
}
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
// // ref
|
||||
// // .read(
|
||||
// // shouldShowLockscreenOnResumeStateProvider
|
||||
// // .state)
|
||||
// // .state = false;
|
||||
// try {
|
||||
// await launchUrl(
|
||||
// uri,
|
||||
// mode: LaunchMode.externalApplication,
|
||||
// );
|
||||
// } catch (_) {
|
||||
// unawaited(showDialog<void>(
|
||||
// context: context,
|
||||
// builder: (_) => StackOkDialog(
|
||||
// title: "Could not open in block explorer",
|
||||
// message:
|
||||
// "Failed to open \"${uri.toString()}\"",
|
||||
// ),
|
||||
// ));
|
||||
// } finally {
|
||||
// // Future<void>.delayed(
|
||||
// // const Duration(seconds: 1),
|
||||
// // () => ref
|
||||
// // .read(
|
||||
// // shouldShowLockscreenOnResumeStateProvider
|
||||
// // .state)
|
||||
// // .state = true,
|
||||
// // );
|
||||
// }
|
||||
// },
|
||||
// ),
|
||||
// ],
|
||||
// ),
|
||||
// ),
|
||||
if (coin == Coin.epicCash)
|
||||
const SizedBox(
|
||||
height: 12,
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
import 'dart:async';
|
||||
|
||||
import 'package:decimal/decimal.dart';
|
||||
import 'package:event_bus/event_bus.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:flutter_svg/svg.dart';
|
||||
import 'package:stackwallet/notifications/show_flush_bar.dart';
|
||||
import 'package:stackwallet/pages/exchange_view/sub_widgets/exchange_rate_sheet.dart';
|
||||
import 'package:stackwallet/pages/exchange_view/wallet_initiated_exchange_view.dart';
|
||||
import 'package:stackwallet/pages/home_view/home_view.dart';
|
||||
|
@ -22,6 +24,7 @@ import 'package:stackwallet/providers/global/auto_swb_service_provider.dart';
|
|||
import 'package:stackwallet/providers/providers.dart';
|
||||
import 'package:stackwallet/providers/ui/transaction_filter_provider.dart';
|
||||
import 'package:stackwallet/providers/ui/unread_notifications_provider.dart';
|
||||
import 'package:stackwallet/services/coins/firo/firo_wallet.dart';
|
||||
import 'package:stackwallet/services/coins/manager.dart';
|
||||
import 'package:stackwallet/services/event_bus/events/global/node_connection_status_changed_event.dart';
|
||||
import 'package:stackwallet/services/event_bus/events/global/wallet_sync_status_changed_event.dart';
|
||||
|
@ -31,12 +34,18 @@ import 'package:stackwallet/utilities/cfcolors.dart';
|
|||
import 'package:stackwallet/utilities/constants.dart';
|
||||
import 'package:stackwallet/utilities/enums/backup_frequency_type.dart';
|
||||
import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
||||
import 'package:stackwallet/utilities/enums/flush_bar_type.dart';
|
||||
import 'package:stackwallet/utilities/text_styles.dart';
|
||||
import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart';
|
||||
import 'package:stackwallet/widgets/custom_buttons/blue_text_button.dart';
|
||||
import 'package:stackwallet/widgets/custom_loading_overlay.dart';
|
||||
import 'package:stackwallet/widgets/stack_dialog.dart';
|
||||
import 'package:tuple/tuple.dart';
|
||||
|
||||
import '../../providers/wallet/public_private_balance_state_provider.dart';
|
||||
import '../../providers/wallet/wallet_balance_toggle_state_provider.dart';
|
||||
import '../../utilities/enums/wallet_balance_toggle_state.dart';
|
||||
|
||||
/// [eventBus] should only be set during testing
|
||||
class WalletView extends ConsumerStatefulWidget {
|
||||
const WalletView({
|
||||
|
@ -271,10 +280,78 @@ class _WalletViewState extends ConsumerState<WalletView> {
|
|||
}
|
||||
}
|
||||
|
||||
Future<void> attemptAnonymize() async {
|
||||
bool shouldPop = false;
|
||||
unawaited(
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) => WillPopScope(
|
||||
child: const CustomLoadingOverlay(
|
||||
message: "Anonymizing balance",
|
||||
eventBus: null,
|
||||
),
|
||||
onWillPop: () async => shouldPop,
|
||||
),
|
||||
),
|
||||
);
|
||||
final firoWallet = ref.read(managerProvider).wallet as FiroWallet;
|
||||
|
||||
final publicBalance = await firoWallet.availablePublicBalance();
|
||||
if (publicBalance <= Decimal.zero) {
|
||||
shouldPop = true;
|
||||
if (mounted) {
|
||||
Navigator.of(context).popUntil(
|
||||
ModalRoute.withName(WalletView.routeName),
|
||||
);
|
||||
unawaited(
|
||||
showFloatingFlushBar(
|
||||
type: FlushBarType.info,
|
||||
message: "No funds available to anonymize!",
|
||||
context: context,
|
||||
),
|
||||
);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
await firoWallet.anonymizeAllPublicFunds();
|
||||
shouldPop = true;
|
||||
if (mounted) {
|
||||
Navigator.of(context).popUntil(
|
||||
ModalRoute.withName(WalletView.routeName),
|
||||
);
|
||||
unawaited(
|
||||
showFloatingFlushBar(
|
||||
type: FlushBarType.success,
|
||||
message: "Anonymize transaction submitted",
|
||||
context: context,
|
||||
),
|
||||
);
|
||||
}
|
||||
} catch (e) {
|
||||
shouldPop = true;
|
||||
if (mounted) {
|
||||
Navigator.of(context).popUntil(
|
||||
ModalRoute.withName(WalletView.routeName),
|
||||
);
|
||||
await showDialog<dynamic>(
|
||||
context: context,
|
||||
builder: (_) => StackOkDialog(
|
||||
title: "Anonymize all failed",
|
||||
message: "Reason: $e",
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
debugPrint("BUILD: $runtimeType");
|
||||
|
||||
final coin = ref.watch(managerProvider.select((value) => value.coin));
|
||||
|
||||
return WillPopScope(
|
||||
onWillPop: _onWillPop,
|
||||
child: Scaffold(
|
||||
|
@ -283,9 +360,7 @@ class _WalletViewState extends ConsumerState<WalletView> {
|
|||
title: Row(
|
||||
children: [
|
||||
SvgPicture.asset(
|
||||
Assets.svg.iconFor(
|
||||
coin: ref
|
||||
.watch(managerProvider.select((value) => value.coin))),
|
||||
Assets.svg.iconFor(coin: coin),
|
||||
// color: CFColors.stackAccent,
|
||||
width: 24,
|
||||
height: 24,
|
||||
|
@ -440,6 +515,69 @@ class _WalletViewState extends ConsumerState<WalletView> {
|
|||
),
|
||||
),
|
||||
),
|
||||
if (coin == Coin.firo)
|
||||
const SizedBox(
|
||||
height: 10,
|
||||
),
|
||||
if (coin == Coin.firo)
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: TextButton(
|
||||
onPressed: () async {
|
||||
await showDialog<void>(
|
||||
context: context,
|
||||
builder: (context) => StackDialog(
|
||||
title: "Attention!",
|
||||
message:
|
||||
"You're about to anonymize all of your public funds.",
|
||||
leftButton: TextButton(
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
child: Text(
|
||||
"Cancel",
|
||||
style: STextStyles.button.copyWith(
|
||||
color: CFColors.stackAccent,
|
||||
),
|
||||
),
|
||||
),
|
||||
rightButton: TextButton(
|
||||
onPressed: () async {
|
||||
Navigator.of(context).pop();
|
||||
|
||||
unawaited(attemptAnonymize());
|
||||
},
|
||||
style: Theme.of(context)
|
||||
.textButtonTheme
|
||||
.style
|
||||
?.copyWith(
|
||||
backgroundColor:
|
||||
MaterialStateProperty.all<Color>(
|
||||
CFColors.stackAccent,
|
||||
),
|
||||
),
|
||||
child: Text(
|
||||
"Continue",
|
||||
style: STextStyles.button,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
child: Text(
|
||||
"Anonymize funds",
|
||||
style: STextStyles.button.copyWith(
|
||||
color: CFColors.stackAccent,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 20,
|
||||
),
|
||||
|
@ -550,6 +688,25 @@ class _WalletViewState extends ConsumerState<WalletView> {
|
|||
ref.read(managerProvider).walletId;
|
||||
final coin =
|
||||
ref.read(managerProvider).coin;
|
||||
switch (ref
|
||||
.read(walletBalanceToggleStateProvider
|
||||
.state)
|
||||
.state) {
|
||||
case WalletBalanceToggleState.full:
|
||||
ref
|
||||
.read(
|
||||
publicPrivateBalanceStateProvider
|
||||
.state)
|
||||
.state = "Public";
|
||||
break;
|
||||
case WalletBalanceToggleState.available:
|
||||
ref
|
||||
.read(
|
||||
publicPrivateBalanceStateProvider
|
||||
.state)
|
||||
.state = "Private";
|
||||
break;
|
||||
}
|
||||
Navigator.of(context).pushNamed(
|
||||
SendView.routeName,
|
||||
arguments: Tuple2(
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
|
||||
final publicPrivateBalanceStateProvider =
|
||||
StateProvider<String>((_) => "Private");
|
|
@ -1761,7 +1761,12 @@ class FiroWallet extends CoinServiceAPI {
|
|||
balances.add(
|
||||
(lelantusBalance + utxosValue + _unconfirmedLelantusBalance) * price);
|
||||
|
||||
balances.add(utxosValue);
|
||||
int availableSats =
|
||||
utxos.satoshiBalance - utxos.satoshiBalanceUnconfirmed;
|
||||
if (availableSats < 0) {
|
||||
availableSats = 0;
|
||||
}
|
||||
balances.add(Format.satoshisToAmount(availableSats));
|
||||
|
||||
Logging.instance.log("balances $balances", level: LogLevel.Info);
|
||||
await DB.instance.put<dynamic>(
|
||||
|
@ -2782,6 +2787,7 @@ class FiroWallet extends CoinServiceAPI {
|
|||
Decimal currentPrice = await firoPrice;
|
||||
final List<Map<String, dynamic>> outputArray = [];
|
||||
int satoshiBalance = 0;
|
||||
int satoshiBalancePending = 0;
|
||||
|
||||
for (int i = 0; i < utxoData.length; i++) {
|
||||
for (int j = 0; j < utxoData[i].length; j++) {
|
||||
|
@ -2795,16 +2801,22 @@ class FiroWallet extends CoinServiceAPI {
|
|||
);
|
||||
|
||||
final Map<String, dynamic> tx = {};
|
||||
final int confirmations = txn["confirmations"] as int? ?? 0;
|
||||
final bool confirmed = confirmations >= MINIMUM_CONFIRMATIONS;
|
||||
if (!confirmed) {
|
||||
satoshiBalancePending += value;
|
||||
}
|
||||
|
||||
tx["txid"] = txn["txid"];
|
||||
tx["vout"] = utxoData[i][j]["tx_pos"];
|
||||
tx["value"] = value;
|
||||
|
||||
tx["status"] = <String, dynamic>{};
|
||||
tx["status"]["confirmed"] = confirmed;
|
||||
tx["status"]["confirmations"] = confirmations;
|
||||
tx["status"]["confirmed"] =
|
||||
txn["confirmations"] == null ? false : txn["confirmations"] > 0;
|
||||
tx["status"]["confirmations"] =
|
||||
txn["confirmations"] == null ? 0 : txn["confirmations"]!;
|
||||
|
||||
tx["status"]["block_height"] = txn["height"];
|
||||
tx["status"]["block_hash"] = txn["blockhash"];
|
||||
tx["status"]["block_time"] = txn["blocktime"];
|
||||
|
@ -2832,6 +2844,7 @@ class FiroWallet extends CoinServiceAPI {
|
|||
.toDecimal(scaleOnInfinitePrecision: Constants.decimalPlaces)
|
||||
.toString(),
|
||||
"outputArray": outputArray,
|
||||
"unconfirmed": satoshiBalancePending,
|
||||
};
|
||||
|
||||
final dataModel = UtxoData.fromJson(result);
|
||||
|
|
|
@ -37,10 +37,30 @@ class _TransactionCardState extends ConsumerState<TransactionCard> {
|
|||
if (coin == Coin.epicCash && _transaction.slateId == null) {
|
||||
return "Restored Funds";
|
||||
}
|
||||
|
||||
if (_transaction.subType == "mint") {
|
||||
// if (type == "Received") {
|
||||
if (_transaction.confirmedStatus) {
|
||||
return "Anonymized";
|
||||
} else {
|
||||
return "Anonymizing";
|
||||
}
|
||||
// } else if (type == "Sent") {
|
||||
// if (_transaction.confirmedStatus) {
|
||||
// return "Sent MINT";
|
||||
// } else {
|
||||
// return "Sending MINT";
|
||||
// }
|
||||
// } else {
|
||||
// return type;
|
||||
// }
|
||||
}
|
||||
|
||||
if (type == "Received") {
|
||||
if (_transaction.isMinting) {
|
||||
return "Minting";
|
||||
} else if (_transaction.confirmedStatus) {
|
||||
// if (_transaction.isMinting) {
|
||||
// return "Minting";
|
||||
// } else
|
||||
if (_transaction.confirmedStatus) {
|
||||
return "Received";
|
||||
} else {
|
||||
return "Receiving";
|
||||
|
|
Loading…
Reference in a new issue