Merge branch 'staging' into ui-fixes

This commit is contained in:
julian-CStack 2023-02-10 14:22:00 -06:00 committed by GitHub
commit 54dba90825
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
18 changed files with 733 additions and 533 deletions

View file

@ -295,6 +295,9 @@ class _MaterialAppWithThemeState extends ConsumerState<MaterialAppWithTheme>
await ref.read(prefsChangeNotifierProvider).isExternalCallsSet()) {
if (Constants.enableExchange) {
await ExchangeDataLoadingService.instance.init();
await ExchangeDataLoadingService.instance.setCurrenciesIfEmpty(
ref.read(exchangeFormStateProvider),
);
unawaited(ExchangeDataLoadingService.instance.loadAll());
}
// if (Constants.enableBuy) {

View file

@ -163,7 +163,7 @@ class ExchangeFormState extends ChangeNotifier {
}
}
void setCurrencies(AggregateCurrency from, AggregateCurrency to) {
void setCurrencies(AggregateCurrency? from, AggregateCurrency? to) {
_sendCurrency = from;
_receiveCurrency = to;
}

View file

@ -468,9 +468,10 @@ class _RestoreOptionsViewState extends ConsumerState<RestoreOptionsView> {
header: Container(
color: Colors.transparent,
child: Padding(
padding: const EdgeInsets.symmetric(
vertical: 8.0,
horizontal: 16,
padding: const EdgeInsets.only(
top: 8.0,
bottom: 8.0,
right: 10,
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
@ -504,7 +505,9 @@ class _RestoreOptionsViewState extends ConsumerState<RestoreOptionsView> {
),
body: Container(
color: Colors.transparent,
child: ClipRRect(
child: Column(
children: [
ClipRRect(
borderRadius: BorderRadius.circular(
Constants.size.circularBorderRadius,
),
@ -513,7 +516,8 @@ class _RestoreOptionsViewState extends ConsumerState<RestoreOptionsView> {
focusNode: passwordFocusNode,
controller: passwordController,
style: isDesktop
? STextStyles.desktopTextMedium(context).copyWith(
? STextStyles.desktopTextMedium(context)
.copyWith(
height: 2,
)
: STextStyles.field(context),
@ -566,6 +570,26 @@ class _RestoreOptionsViewState extends ConsumerState<RestoreOptionsView> {
),
),
),
const SizedBox(
height: 8,
),
RoundedWhiteContainer(
child: Center(
child: Text(
"If the recovery phrase you are about to restore was created with an optional passphrase you can enter it here.",
style: isDesktop
? STextStyles.desktopTextExtraSmall(context)
.copyWith(
color: Theme.of(context)
.extension<StackColors>()!
.textSubtitle1,
)
: STextStyles.itemSubtitle(context),
),
),
),
],
),
),
),
if (!isDesktop)

View file

@ -108,6 +108,8 @@ class _ExchangeCurrencySelectionViewState
return ExchangeDataLoadingService.instance.isar.currencies
.where()
.filter()
.isFiatEqualTo(false)
.and()
.tickerEqualTo(ticker, caseSensitive: false)
.group((q) => widget.isFixedRate
? q
@ -150,6 +152,8 @@ class _ExchangeCurrencySelectionViewState
return ExchangeDataLoadingService.instance.isar.currencies
.where()
.filter()
.isFiatEqualTo(false)
.and()
.group((q) => widget.isFixedRate
? q
.rateTypeEqualTo(SupportedRateType.both)

View file

@ -36,7 +36,10 @@ class _ExchangeViewState extends ConsumerState<ExchangeView> {
ExchangeDataLoadingService.cacheVersion) {
_initialCachePopulationUnderway = true;
ExchangeDataLoadingService.instance.onLoadingComplete = () {
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
WidgetsBinding.instance.addPostFrameCallback((timeStamp) async {
await ExchangeDataLoadingService.instance.setCurrenciesIfEmpty(
ref.read(exchangeFormStateProvider),
);
setState(() {
_initialCachePopulationUnderway = false;
});
@ -51,7 +54,10 @@ class _ExchangeViewState extends ConsumerState<ExchangeView> {
ExchangeDataLoadingService.cacheVersion) {
_initialCachePopulationUnderway = true;
ExchangeDataLoadingService.instance.onLoadingComplete = () {
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
WidgetsBinding.instance.addPostFrameCallback((timeStamp) async {
await ExchangeDataLoadingService.instance.setCurrenciesIfEmpty(
ref.read(exchangeFormStateProvider),
);
setState(() {
_initialCachePopulationUnderway = false;
});

View file

@ -4,6 +4,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:stackwallet/pages/exchange_view/exchange_form.dart';
import 'package:stackwallet/pages/exchange_view/sub_widgets/step_row.dart';
import 'package:stackwallet/providers/exchange/exchange_form_state_provider.dart';
import 'package:stackwallet/providers/global/prefs_provider.dart';
import 'package:stackwallet/services/exchange/exchange_data_loading_service.dart';
import 'package:stackwallet/utilities/enums/coin_enum.dart';
@ -48,7 +49,10 @@ class _WalletInitiatedExchangeViewState
ExchangeDataLoadingService.cacheVersion) {
_initialCachePopulationUnderway = true;
ExchangeDataLoadingService.instance.onLoadingComplete = () {
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
WidgetsBinding.instance.addPostFrameCallback((timeStamp) async {
await ExchangeDataLoadingService.instance.setCurrenciesIfEmpty(
ref.read(exchangeFormStateProvider),
);
setState(() {
_initialCachePopulationUnderway = false;
});
@ -63,7 +67,10 @@ class _WalletInitiatedExchangeViewState
ExchangeDataLoadingService.cacheVersion) {
_initialCachePopulationUnderway = true;
ExchangeDataLoadingService.instance.onLoadingComplete = () {
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
WidgetsBinding.instance.addPostFrameCallback((timeStamp) async {
await ExchangeDataLoadingService.instance.setCurrenciesIfEmpty(
ref.read(exchangeFormStateProvider),
);
setState(() {
_initialCachePopulationUnderway = false;
});

View file

@ -559,6 +559,7 @@ class _PaynymHomeViewState extends ConsumerState<PaynymHomeView> {
height: isDesktop ? 56 : 48,
width: isDesktop ? 490 : null,
child: Toggle(
key: UniqueKey(),
onColor: Theme.of(context).extension<StackColors>()!.popupBG,
onText:
"Following (${ref.watch(myPaynymAccountStateProvider.state).state?.following.length ?? 0})",

View file

@ -11,6 +11,7 @@ import 'package:stackwallet/notifications/show_flush_bar.dart';
import 'package:stackwallet/pages/paynym/dialogs/confirm_paynym_connect_dialog.dart';
import 'package:stackwallet/pages/paynym/subwidgets/paynym_bot.dart';
import 'package:stackwallet/pages/send_view/confirm_transaction_view.dart';
import 'package:stackwallet/pages_desktop_specific/my_stack_view/paynym/desktop_paynym_send_dialog.dart';
import 'package:stackwallet/providers/global/wallets_provider.dart';
import 'package:stackwallet/services/mixins/paynym_wallet_interface.dart';
import 'package:stackwallet/utilities/assets.dart';
@ -102,8 +103,6 @@ class _PaynymDetailsPopupState extends ConsumerState<DesktopPaynymDetails> {
builder: (context) => ConfirmPaynymConnectDialog(
nymName: widget.accountLite.nymName,
onConfirmPressed: () {
//
print("CONFIRM NOTIF TX: $preparedTx");
Navigator.of(context, rootNavigator: true).pop();
unawaited(
showDialog(
@ -148,7 +147,13 @@ class _PaynymDetailsPopupState extends ConsumerState<DesktopPaynymDetails> {
}
Future<void> _onSend() async {
print("sned");
await showDialog<void>(
context: context,
builder: (context) => DesktopPaynymSendDialog(
walletId: widget.walletId,
accountLite: widget.accountLite,
),
);
}
@override

View file

@ -586,7 +586,9 @@ class _ConfirmTransactionViewState
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"Send to",
widget.isPaynymTransaction
? "PayNym recipient"
: "Send to",
style: STextStyles.desktopTextExtraExtraSmall(
context),
),
@ -594,7 +596,11 @@ class _ConfirmTransactionViewState
height: 2,
),
Text(
"${transactionInfo["address"] ?? "ERROR"}",
widget.isPaynymTransaction
? (transactionInfo["paynymAccountLite"]
as PaynymAccountLite)
.nymName
: "${transactionInfo["address"] ?? "ERROR"}",
style: STextStyles.desktopTextExtraExtraSmall(
context)
.copyWith(
@ -606,6 +612,64 @@ class _ConfirmTransactionViewState
],
),
),
if (widget.isPaynymTransaction)
Container(
height: 1,
color: Theme.of(context)
.extension<StackColors>()!
.background,
),
if (widget.isPaynymTransaction)
Padding(
padding: const EdgeInsets.all(12),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"Transaction fee",
style: STextStyles.desktopTextExtraExtraSmall(
context),
),
const SizedBox(
height: 2,
),
Builder(
builder: (context) {
final coin = ref
.watch(walletsChangeNotifierProvider
.select((value) =>
value.getManager(walletId)))
.coin;
final fee = Format.satoshisToAmount(
transactionInfo["fee"] as int,
coin: coin,
);
return Text(
"${Format.localizedStringAsFixed(
value: fee,
locale: ref.watch(
localeServiceChangeNotifierProvider
.select((value) => value.locale)),
decimalPlaces:
Constants.decimalPlacesForCoin(coin),
)} ${coin.ticker}",
style:
STextStyles.desktopTextExtraExtraSmall(
context)
.copyWith(
color: Theme.of(context)
.extension<StackColors>()!
.textDark,
),
);
},
),
],
),
),
// Container(
// height: 1,
// color: Theme.of(context)
@ -725,7 +789,7 @@ class _ConfirmTransactionViewState
],
),
),
if (isDesktop)
if (isDesktop && !widget.isPaynymTransaction)
Padding(
padding: const EdgeInsets.only(
left: 32,
@ -735,7 +799,7 @@ class _ConfirmTransactionViewState
style: STextStyles.desktopTextExtraExtraSmall(context),
),
),
if (isDesktop)
if (isDesktop && !widget.isPaynymTransaction)
Padding(
padding: const EdgeInsets.only(
top: 10,
@ -750,7 +814,8 @@ class _ConfirmTransactionViewState
color: Theme.of(context)
.extension<StackColors>()!
.textFieldDefaultBG,
child: Builder(builder: (context) {
child: Builder(
builder: (context) {
final coin = ref
.watch(walletsChangeNotifierProvider
.select((value) => value.getManager(walletId)))
@ -770,63 +835,9 @@ class _ConfirmTransactionViewState
)} ${coin.ticker}",
style: STextStyles.itemSubtitle(context),
);
}),
)
// DropdownButtonHideUnderline(
// child: DropdownButton2(
// offset: const Offset(0, -10),
// isExpanded: true,
//
// dropdownElevation: 0,
// value: _fee,
// items: [
// ..._dropDownItems.map(
// (e) {
// String message = _fee.toString();
//
// return DropdownMenuItem(
// value: e,
// child: Text(message),
// );
// },
// ),
// ],
// onChanged: (value) {
// if (value is int) {
// setState(() {
// _fee = value;
// });
// }
// },
// icon: SvgPicture.asset(
// Assets.svg.chevronDown,
// width: 12,
// height: 6,
// color:
// Theme.of(context).extension<StackColors>()!.textDark3,
// ),
// buttonPadding: const EdgeInsets.symmetric(
// horizontal: 16,
// vertical: 8,
// ),
// buttonDecoration: BoxDecoration(
// color: Theme.of(context)
// .extension<StackColors>()!
// .textFieldDefaultBG,
// borderRadius: BorderRadius.circular(
// Constants.size.circularBorderRadius,
// ),
// ),
// dropdownDecoration: BoxDecoration(
// color: Theme.of(context)
// .extension<StackColors>()!
// .textFieldDefaultBG,
// borderRadius: BorderRadius.circular(
// Constants.size.circularBorderRadius,
// ),
// ),
// ),
// ),
},
),
),
),
if (!isDesktop) const Spacer(),
SizedBox(

View file

@ -297,44 +297,6 @@ class _SendViewState extends ConsumerState<SendView> {
final manager =
ref.read(walletsChangeNotifierProvider).getManager(walletId);
// // TODO: remove the need for this!!
// final bool isOwnAddress =
// await manager.isOwnAddress(_address!);
// if (isOwnAddress && coin != Coin.dogecoinTestNet) {
// await showDialog<dynamic>(
// context: context,
// useSafeArea: false,
// barrierDismissible: true,
// builder: (context) {
// return StackDialog(
// title: "Transaction failed",
// message:
// "Sending to self is currently disabled",
// rightButton: TextButton(
// style: Theme.of(context)
// .extension<StackColors>()!
// .getSecondaryEnabledButtonColor(
// context),
// child: Text(
// "Ok",
// style: STextStyles.button(
// context)
// .copyWith(
// color: Theme.of(context)
// .extension<
// StackColors>()!
// .accentColorDark),
// ),
// onPressed: () {
// Navigator.of(context).pop();
// },
// ),
// );
// },
// );
// return;
// }
final amount = Format.decimalAmountToSatoshis(_amountToSend!, coin);
int availableBalance;
if ((coin == Coin.firo || coin == Coin.firoTestNet)) {

View file

@ -21,7 +21,7 @@ class AllWallets extends StatelessWidget {
Text(
"All wallets",
style: STextStyles.itemSubtitle(context).copyWith(
color: Theme.of(context).extension<StackColors>()!.textDark,
color: Theme.of(context).extension<StackColors>()!.textDark3,
),
),
CustomTextButton(

View file

@ -106,12 +106,12 @@ class _FavoriteWalletsState extends ConsumerState<FavoriteWallets> {
ManageFavoritesView.routeName,
);
},
)
),
],
),
),
const SizedBox(
height: 12,
height: 20,
),
!hasFavorites
? Padding(

View file

@ -5,6 +5,8 @@ import 'package:stackwallet/pages/wallets_view/sub_widgets/all_wallets.dart';
import 'package:stackwallet/pages/wallets_view/sub_widgets/empty_wallets.dart';
import 'package:stackwallet/pages/wallets_view/sub_widgets/favorite_wallets.dart';
import 'package:stackwallet/providers/providers.dart';
import 'package:stackwallet/providers/ui/color_theme_provider.dart';
import 'package:stackwallet/utilities/theme/color_theme.dart';
class WalletsView extends ConsumerWidget {
const WalletsView({Key? key}) : super(key: key);
@ -22,8 +24,11 @@ class WalletsView extends ConsumerWidget {
return SafeArea(
child: hasWallets
? Padding(
padding: const EdgeInsets.only(
top: 20,
padding: EdgeInsets.only(
top: ref.watch(colorThemeProvider).themeType ==
ThemeType.fruitSorbet
? 6
: 20,
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,

View file

@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:stackwallet/pages/exchange_view/exchange_form.dart';
import 'package:stackwallet/pages_desktop_specific/desktop_exchange/subwidgets/desktop_trade_history.dart';
import 'package:stackwallet/providers/exchange/exchange_form_state_provider.dart';
import 'package:stackwallet/providers/global/prefs_provider.dart';
import 'package:stackwallet/services/exchange/exchange_data_loading_service.dart';
import 'package:stackwallet/utilities/text_styles.dart';
@ -32,7 +33,10 @@ class _DesktopExchangeViewState extends ConsumerState<DesktopExchangeView> {
ExchangeDataLoadingService.cacheVersion) {
_initialCachePopulationUnderway = true;
ExchangeDataLoadingService.instance.onLoadingComplete = () {
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
WidgetsBinding.instance.addPostFrameCallback((timeStamp) async {
await ExchangeDataLoadingService.instance.setCurrenciesIfEmpty(
ref.read(exchangeFormStateProvider),
);
setState(() {
_initialCachePopulationUnderway = false;
});
@ -47,7 +51,10 @@ class _DesktopExchangeViewState extends ConsumerState<DesktopExchangeView> {
ExchangeDataLoadingService.cacheVersion) {
_initialCachePopulationUnderway = true;
ExchangeDataLoadingService.instance.onLoadingComplete = () {
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
WidgetsBinding.instance.addPostFrameCallback((timeStamp) async {
await ExchangeDataLoadingService.instance.setCurrenciesIfEmpty(
ref.read(exchangeFormStateProvider),
);
setState(() {
_initialCachePopulationUnderway = false;
});

View file

@ -0,0 +1,197 @@
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_svg/svg.dart';
import 'package:stackwallet/models/paynym/paynym_account_lite.dart';
import 'package:stackwallet/models/send_view_auto_fill_data.dart';
import 'package:stackwallet/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/desktop_send.dart';
import 'package:stackwallet/providers/global/locale_provider.dart';
import 'package:stackwallet/providers/global/prefs_provider.dart';
import 'package:stackwallet/providers/global/price_provider.dart';
import 'package:stackwallet/providers/global/wallets_provider.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/assets.dart';
import 'package:stackwallet/utilities/barcode_scanner_interface.dart';
import 'package:stackwallet/utilities/clipboard_interface.dart';
import 'package:stackwallet/utilities/enums/coin_enum.dart';
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/desktop/desktop_dialog.dart';
import 'package:stackwallet/widgets/desktop/desktop_dialog_close_button.dart';
import 'package:stackwallet/widgets/rounded_white_container.dart';
class DesktopPaynymSendDialog extends ConsumerStatefulWidget {
const DesktopPaynymSendDialog({
Key? key,
required this.walletId,
this.autoFillData,
this.clipboard = const ClipboardWrapper(),
this.barcodeScanner = const BarcodeScannerWrapper(),
this.accountLite,
}) : super(key: key);
final String walletId;
final SendViewAutoFillData? autoFillData;
final ClipboardInterface clipboard;
final BarcodeScannerInterface barcodeScanner;
final PaynymAccountLite? accountLite;
@override
ConsumerState<DesktopPaynymSendDialog> createState() =>
_DesktopPaynymSendDialogState();
}
class _DesktopPaynymSendDialogState
extends ConsumerState<DesktopPaynymSendDialog> {
@override
Widget build(BuildContext context) {
final manager = ref.watch(walletsChangeNotifierProvider
.select((value) => value.getManager(widget.walletId)));
final String locale = ref.watch(
localeServiceChangeNotifierProvider.select((value) => value.locale));
final coin = manager.coin;
final isFiro = coin == Coin.firo || coin == Coin.firoTestNet;
return DesktopDialog(
maxHeight: double.infinity,
maxWidth: 580,
child: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Padding(
padding: const EdgeInsets.only(left: 32),
child: Text(
"Send ${manager.coin.ticker.toUpperCase()}",
style: STextStyles.desktopH3(context),
),
),
const DesktopDialogCloseButton(),
],
),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 32),
child: RoundedWhiteContainer(
borderColor:
Theme.of(context).extension<StackColors>()!.background,
// Theme.of(context).extension<StackColors>()!.textSubtitle4,
child: Row(
children: [
SvgPicture.asset(
Assets.svg.iconFor(coin: coin),
width: 36,
height: 36,
),
const SizedBox(
width: 12,
),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
manager.walletName,
style: STextStyles.titleBold12(context),
overflow: TextOverflow.ellipsis,
maxLines: 1,
),
const SizedBox(
height: 2,
),
Text(
isFiro
? "${ref.watch(publicPrivateBalanceStateProvider.state).state} balance"
: "Available balance",
style: STextStyles.baseXS(context).copyWith(
color: Theme.of(context)
.extension<StackColors>()!
.textSubtitle1,
),
),
],
),
const Spacer(),
Container(
color: Colors.transparent,
child: Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Text(
"${Format.localizedStringAsFixed(
value: !isFiro
? manager.balance.getSpendable()
: ref
.watch(
publicPrivateBalanceStateProvider
.state)
.state ==
"Private"
? (manager.wallet as FiroWallet)
.availablePrivateBalance()
: (manager.wallet as FiroWallet)
.availablePublicBalance(),
locale: locale,
decimalPlaces: 8,
)} ${coin.ticker}",
style: STextStyles.titleBold12(context),
textAlign: TextAlign.right,
),
const SizedBox(
height: 2,
),
Text(
"${Format.localizedStringAsFixed(
value: (!isFiro
? manager.balance.getSpendable()
: ref
.watch(
publicPrivateBalanceStateProvider
.state)
.state ==
"Private"
? (manager.wallet as FiroWallet)
.availablePrivateBalance()
: (manager.wallet as FiroWallet)
.availablePublicBalance()) *
ref.watch(
priceAnd24hChangeNotifierProvider.select(
(value) => value.getPrice(coin).item1)),
locale: locale,
decimalPlaces: 2,
)} ${ref.watch(prefsChangeNotifierProvider.select((value) => value.currency))}",
style: STextStyles.baseXS(context).copyWith(
color: Theme.of(context)
.extension<StackColors>()!
.textSubtitle1,
),
textAlign: TextAlign.right,
)
],
),
),
],
),
),
),
const SizedBox(
height: 20,
),
Padding(
padding: const EdgeInsets.only(
left: 32,
right: 32,
bottom: 32,
),
child: DesktopSend(
walletId: manager.walletId,
accountLite: widget.accountLite,
),
),
],
),
);
}
}

View file

@ -1,5 +1,6 @@
import 'dart:async';
import 'package:bip47/bip47.dart';
import 'package:decimal/decimal.dart';
import 'package:dropdown_button2/dropdown_button2.dart';
import 'package:flutter/material.dart';
@ -7,6 +8,7 @@ import 'package:flutter/services.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:stackwallet/models/contact_address_entry.dart';
import 'package:stackwallet/models/paynym/paynym_account_lite.dart';
import 'package:stackwallet/models/send_view_auto_fill_data.dart';
import 'package:stackwallet/pages/send_view/confirm_transaction_view.dart';
import 'package:stackwallet/pages/send_view/sub_widgets/building_transaction_dialog.dart';
@ -20,6 +22,7 @@ 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/services/coins/firo/firo_wallet.dart';
import 'package:stackwallet/services/coins/manager.dart';
import 'package:stackwallet/services/mixins/paynym_wallet_interface.dart';
import 'package:stackwallet/utilities/address_utils.dart';
import 'package:stackwallet/utilities/assets.dart';
import 'package:stackwallet/utilities/barcode_scanner_interface.dart';
@ -51,12 +54,14 @@ class DesktopSend extends ConsumerStatefulWidget {
this.autoFillData,
this.clipboard = const ClipboardWrapper(),
this.barcodeScanner = const BarcodeScannerWrapper(),
this.accountLite,
}) : super(key: key);
final String walletId;
final SendViewAutoFillData? autoFillData;
final ClipboardInterface clipboard;
final BarcodeScannerInterface barcodeScanner;
final PaynymAccountLite? accountLite;
@override
ConsumerState<DesktopSend> createState() => _DesktopSendState();
@ -93,78 +98,12 @@ class _DesktopSendState extends ConsumerState<DesktopSend> {
bool _cryptoAmountChangeLock = false;
late VoidCallback onCryptoAmountChanged;
bool get isPaynymSend => widget.accountLite != null;
Future<void> previewSend() async {
final manager =
ref.read(walletsChangeNotifierProvider).getManager(walletId);
// // TODO: remove the need for this!!
// final bool isOwnAddress = await manager.isOwnAddress(_address!);
// if (isOwnAddress) {
// await showDialog<dynamic>(
// context: context,
// useSafeArea: false,
// barrierDismissible: true,
// builder: (context) {
// return DesktopDialog(
// maxWidth: 400,
// maxHeight: double.infinity,
// child: Padding(
// padding: const EdgeInsets.only(
// left: 32,
// bottom: 32,
// ),
// child: Column(
// crossAxisAlignment: CrossAxisAlignment.start,
// children: [
// Row(
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
// children: [
// Text(
// "Transaction failed",
// style: STextStyles.desktopH3(context),
// ),
// const DesktopDialogCloseButton(),
// ],
// ),
// const SizedBox(
// height: 12,
// ),
// Text(
// "Sending to self is currently disabled",
// textAlign: TextAlign.left,
// style: STextStyles.desktopTextExtraExtraSmall(context)
// .copyWith(
// fontSize: 18,
// ),
// ),
// const SizedBox(
// height: 40,
// ),
// Row(
// children: [
// Expanded(
// child: SecondaryButton(
// buttonHeight: ButtonHeight.l,
// label: "Ok",
// onPressed: () {
// Navigator.of(context).pop();
// },
// ),
// ),
// const SizedBox(
// width: 32,
// ),
// ],
// ),
// ],
// ),
// ),
// );
// },
// );
// return;
// }
final amount = Format.decimalAmountToSatoshis(_amountToSend!, coin);
int availableBalance;
if ((coin == Coin.firo || coin == Coin.firoTestNet)) {
@ -304,7 +243,19 @@ class _DesktopSendState extends ConsumerState<DesktopSend> {
Map<String, dynamic> txData;
if ((coin == Coin.firo || coin == Coin.firoTestNet) &&
if (isPaynymSend) {
final wallet = manager.wallet as PaynymWalletInterface;
final paymentCode = PaymentCode.fromPaymentCode(
widget.accountLite!.code,
wallet.networkType,
);
final feeRate = ref.read(feeRateTypeStateProvider);
txData = await wallet.preparePaymentCodeSend(
paymentCode: paymentCode,
satoshiAmount: amount,
args: {"feeRate": feeRate},
);
} else if ((coin == Coin.firo || coin == Coin.firoTestNet) &&
ref.read(publicPrivateBalanceStateProvider.state).state !=
"Private") {
txData = await (manager.wallet as FiroWallet).prepareSendPublic(
@ -321,8 +272,13 @@ class _DesktopSendState extends ConsumerState<DesktopSend> {
}
if (!wasCancelled && mounted) {
txData["note"] = _note ?? "";
if (isPaynymSend) {
txData["paynymAccountLite"] = widget.accountLite!;
txData["note"] = _note ?? "PayNym send";
} else {
txData["address"] = _address;
txData["note"] = _note ?? "";
}
// pop building dialog
Navigator.of(
context,
@ -338,6 +294,7 @@ class _DesktopSendState extends ConsumerState<DesktopSend> {
child: ConfirmTransactionView(
transactionInfo: txData,
walletId: walletId,
isPaynymTransaction: isPaynymSend,
routeOnSuccessName: DesktopHomeView.routeName,
),
),
@ -439,9 +396,9 @@ class _DesktopSendState extends ConsumerState<DesktopSend> {
_cachedAmountToSend == _amountToSend) {
return;
}
_cachedAmountToSend = _amountToSend;
Logging.instance.log("it changed $_amountToSend $_cachedAmountToSend",
level: LogLevel.Info);
_cachedAmountToSend = _amountToSend;
final price =
ref.read(priceAnd24hChangeNotifierProvider).getPrice(coin).item1;
@ -457,6 +414,7 @@ class _DesktopSendState extends ConsumerState<DesktopSend> {
}
} else {
_amountToSend = null;
_cachedAmountToSend = null;
baseAmountController.text = "";
}
@ -475,6 +433,10 @@ class _DesktopSendState extends ConsumerState<DesktopSend> {
}
void _updatePreviewButtonState(String? address, Decimal? amount) {
if (isPaynymSend) {
ref.read(previewTxButtonStateProvider.state).state =
(amount != null && amount > Decimal.zero);
} else {
final isValidAddress = ref
.read(walletsChangeNotifierProvider)
.getManager(walletId)
@ -482,79 +444,7 @@ class _DesktopSendState extends ConsumerState<DesktopSend> {
ref.read(previewTxButtonStateProvider.state).state =
(isValidAddress && amount != null && amount > Decimal.zero);
}
// late Future<String> _calculateFeesFuture;
// Map<int, String> cachedFees = {};
// Map<int, String> cachedFiroPrivateFees = {};
// Map<int, String> cachedFiroPublicFees = {};
// Future<String> calculateFees(int amount) async {
// if (amount <= 0) {
// return "0";
// }
//
// if (coin == Coin.firo || coin == Coin.firoTestNet) {
// if (ref.read(publicPrivateBalanceStateProvider.state).state ==
// "Private") {
// if (cachedFiroPrivateFees[amount] != null) {
// return cachedFiroPrivateFees[amount]!;
// }
// } else {
// if (cachedFiroPublicFees[amount] != null) {
// return cachedFiroPublicFees[amount]!;
// }
// }
// } else if (cachedFees[amount] != null) {
// return cachedFees[amount]!;
// }
//
// final manager =
// ref.read(walletsChangeNotifierProvider).getManager(walletId);
// final feeObject = await manager.fees;
//
// late final int feeRate;
//
// switch (ref.read(feeRateTypeStateProvider.state).state) {
// case FeeRateType.fast:
// feeRate = feeObject.fast;
// break;
// case FeeRateType.average:
// feeRate = feeObject.medium;
// break;
// case FeeRateType.slow:
// feeRate = feeObject.slow;
// break;
// }
//
// int fee;
//
// if (coin == Coin.firo || coin == Coin.firoTestNet) {
// if (ref.read(publicPrivateBalanceStateProvider.state).state ==
// "Private") {
// fee = await manager.estimateFeeFor(amount, feeRate);
//
// cachedFiroPrivateFees[amount] = Format.satoshisToAmount(fee)
// .toStringAsFixed(Constants.decimalPlaces);
//
// return cachedFiroPrivateFees[amount]!;
// } else {
// fee = await (manager.wallet as FiroWallet)
// .estimateFeeForPublic(amount, feeRate);
//
// cachedFiroPublicFees[amount] = Format.satoshisToAmount(fee)
// .toStringAsFixed(Constants.decimalPlaces);
//
// return cachedFiroPublicFees[amount]!;
// }
// } else {
// fee = await manager.estimateFeeFor(amount, feeRate);
// cachedFees[amount] =
// Format.satoshisToAmount(fee).toStringAsFixed(Constants.decimalPlaces);
//
// return cachedFees[amount]!;
// }
// }
}
Future<String?> _firoBalanceFuture(
ChangeNotifierProvider<Manager> provider,
@ -773,7 +663,10 @@ class _DesktopSendState extends ConsumerState<DesktopSend> {
@override
void initState() {
WidgetsBinding.instance.addPostFrameCallback((_) {
ref.refresh(feeSheetSessionCacheProvider);
ref.read(previewTxButtonStateProvider.state).state = false;
});
// _calculateFeesFuture = calculateFees(0);
_data = widget.autoFillData;
@ -799,6 +692,10 @@ class _DesktopSendState extends ConsumerState<DesktopSend> {
_addressToggleFlag = true;
}
if (isPaynymSend) {
sendToController.text = widget.accountLite!.nymName;
}
_cryptoFocus.addListener(() {
if (!_cryptoFocus.hasFocus && !_baseFocus.hasFocus) {
if (_amountToSend == null) {
@ -845,21 +742,6 @@ class _DesktopSendState extends ConsumerState<DesktopSend> {
final String locale = ref.watch(
localeServiceChangeNotifierProvider.select((value) => value.locale));
// if (coin == Coin.firo || coin == Coin.firoTestNet) {
// ref.listen(publicPrivateBalanceStateProvider, (previous, next) {
// if (_amountToSend == null) {
// setState(() {
// _calculateFeesFuture = calculateFees(0);
// });
// } else {
// setState(() {
// _calculateFeesFuture =
// calculateFees(Format.decimalAmountToSatoshis(_amountToSend!));
// });
// }
// });
// }
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
@ -975,6 +857,36 @@ class _DesktopSendState extends ConsumerState<DesktopSend> {
const SizedBox(
height: 20,
),
if (isPaynymSend)
Text(
"Send to PayNym address",
style: STextStyles.smallMed12(context),
textAlign: TextAlign.left,
),
if (isPaynymSend)
const SizedBox(
height: 10,
),
if (isPaynymSend)
TextField(
key: const Key("sendViewPaynymAddressFieldKey"),
controller: sendToController,
enabled: false,
readOnly: true,
style: STextStyles.desktopTextFieldLabel(context).copyWith(
fontSize: 16,
),
decoration: const InputDecoration(
contentPadding: EdgeInsets.symmetric(
vertical: 18,
horizontal: 16,
),
),
),
if (isPaynymSend)
const SizedBox(
height: 20,
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
@ -1020,6 +932,7 @@ class _DesktopSendState extends ConsumerState<DesktopSend> {
? newValue
: oldValue),
],
onChanged: (newValue) {},
decoration: InputDecoration(
contentPadding: const EdgeInsets.only(
top: 22,
@ -1108,6 +1021,7 @@ class _DesktopSendState extends ConsumerState<DesktopSend> {
const SizedBox(
height: 20,
),
if (!isPaynymSend)
Text(
"Send to",
style: STextStyles.desktopTextExtraSmall(context).copyWith(
@ -1117,9 +1031,11 @@ class _DesktopSendState extends ConsumerState<DesktopSend> {
),
textAlign: TextAlign.left,
),
if (!isPaynymSend)
const SizedBox(
height: 10,
),
if (!isPaynymSend)
ClipRRect(
borderRadius: BorderRadius.circular(
Constants.size.circularBorderRadius,
@ -1223,8 +1139,8 @@ class _DesktopSendState extends ConsumerState<DesktopSend> {
),
child: Text(
"Address book",
style:
STextStyles.desktopH3(context),
style: STextStyles.desktopH3(
context),
),
),
const DesktopDialogCloseButton(),
@ -1271,6 +1187,7 @@ class _DesktopSendState extends ConsumerState<DesktopSend> {
),
),
),
if (!isPaynymSend)
Builder(
builder: (_) {
final error = _updateInvalidAddressText(
@ -1292,8 +1209,9 @@ class _DesktopSendState extends ConsumerState<DesktopSend> {
error,
textAlign: TextAlign.left,
style: STextStyles.label(context).copyWith(
color:
Theme.of(context).extension<StackColors>()!.textError,
color: Theme.of(context)
.extension<StackColors>()!
.textError,
),
),
),
@ -1368,6 +1286,7 @@ class _DesktopSendState extends ConsumerState<DesktopSend> {
// ),
// ),
// ),
if (!isPaynymSend)
const SizedBox(
height: 20,
),

View file

@ -1,12 +1,16 @@
import 'package:flutter/foundation.dart';
import 'package:isar/isar.dart';
import 'package:stackwallet/hive/db.dart';
import 'package:stackwallet/models/exchange/aggregate_currency.dart';
import 'package:stackwallet/models/exchange/exchange_form_state.dart';
import 'package:stackwallet/models/isar/exchange_cache/currency.dart';
import 'package:stackwallet/models/isar/exchange_cache/pair.dart';
import 'package:stackwallet/services/exchange/change_now/change_now_exchange.dart';
import 'package:stackwallet/services/exchange/majestic_bank/majestic_bank_exchange.dart';
import 'package:stackwallet/utilities/enums/exchange_rate_type_enum.dart';
import 'package:stackwallet/utilities/logger.dart';
import 'package:stackwallet/utilities/stack_file_system.dart';
import 'package:tuple/tuple.dart';
class ExchangeDataLoadingService {
ExchangeDataLoadingService._();
@ -50,6 +54,51 @@ class ExchangeDataLoadingService {
);
}
Future<void> setCurrenciesIfEmpty(ExchangeFormState state) async {
if (state.sendCurrency == null && state.receiveCurrency == null) {
if (await isar.currencies.count() > 0) {
final sendCurrency = await getAggregateCurrency(
"BTC",
state.exchangeRateType,
);
final receiveCurrency = await getAggregateCurrency(
"XMR",
state.exchangeRateType,
);
state.setCurrencies(sendCurrency, receiveCurrency);
}
}
}
Future<AggregateCurrency?> getAggregateCurrency(
String ticker, ExchangeRateType rateType) async {
final currencies = await ExchangeDataLoadingService.instance.isar.currencies
.filter()
.group((q) => rateType == ExchangeRateType.fixed
? q
.rateTypeEqualTo(SupportedRateType.both)
.or()
.rateTypeEqualTo(SupportedRateType.fixed)
: q
.rateTypeEqualTo(SupportedRateType.both)
.or()
.rateTypeEqualTo(SupportedRateType.estimated))
.and()
.tickerEqualTo(
ticker,
caseSensitive: false,
)
.findAll();
final items = currencies
.map((e) => Tuple2(e.exchangeName, e))
.toList(growable: false);
return items.isNotEmpty
? AggregateCurrency(exchangeCurrencyPairs: items)
: null;
}
bool get isLoading => _locked;
bool _locked = false;

View file

@ -306,7 +306,7 @@ mixin PaynymWalletInterface {
{required PaymentCode paymentCode,
required int satoshiAmount,
Map<String, dynamic>? args}) async {
if (!(await hasConnected(paymentCode.notificationAddressP2PKH()))) {
if (!(await hasConnected(paymentCode.toString()))) {
throw PaynymSendException(
"No notification transaction sent to $paymentCode");
} else {