mirror of
https://github.com/cypherstack/stack_wallet.git
synced 2024-12-23 11:59:30 +00:00
Merge branch 'staging' into ui-fixes
This commit is contained in:
commit
54dba90825
18 changed files with 733 additions and 533 deletions
|
@ -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) {
|
||||
|
|
|
@ -163,7 +163,7 @@ class ExchangeFormState extends ChangeNotifier {
|
|||
}
|
||||
}
|
||||
|
||||
void setCurrencies(AggregateCurrency from, AggregateCurrency to) {
|
||||
void setCurrencies(AggregateCurrency? from, AggregateCurrency? to) {
|
||||
_sendCurrency = from;
|
||||
_receiveCurrency = to;
|
||||
}
|
||||
|
|
|
@ -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,67 +505,90 @@ class _RestoreOptionsViewState extends ConsumerState<RestoreOptionsView> {
|
|||
),
|
||||
body: Container(
|
||||
color: Colors.transparent,
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.circular(
|
||||
Constants.size.circularBorderRadius,
|
||||
),
|
||||
child: TextField(
|
||||
key: const Key("mnemonicPassphraseFieldKey1"),
|
||||
focusNode: passwordFocusNode,
|
||||
controller: passwordController,
|
||||
style: isDesktop
|
||||
? STextStyles.desktopTextMedium(context).copyWith(
|
||||
height: 2,
|
||||
)
|
||||
: STextStyles.field(context),
|
||||
obscureText: hidePassword,
|
||||
enableSuggestions: false,
|
||||
autocorrect: false,
|
||||
decoration: standardInputDecoration(
|
||||
"Recovery phrase password",
|
||||
passwordFocusNode,
|
||||
context,
|
||||
).copyWith(
|
||||
suffixIcon: UnconstrainedBox(
|
||||
child: ConditionalParent(
|
||||
condition: isDesktop,
|
||||
builder: (child) => SizedBox(
|
||||
height: 70,
|
||||
child: child,
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
SizedBox(
|
||||
width: isDesktop ? 24 : 16,
|
||||
child: Column(
|
||||
children: [
|
||||
ClipRRect(
|
||||
borderRadius: BorderRadius.circular(
|
||||
Constants.size.circularBorderRadius,
|
||||
),
|
||||
child: TextField(
|
||||
key: const Key("mnemonicPassphraseFieldKey1"),
|
||||
focusNode: passwordFocusNode,
|
||||
controller: passwordController,
|
||||
style: isDesktop
|
||||
? STextStyles.desktopTextMedium(context)
|
||||
.copyWith(
|
||||
height: 2,
|
||||
)
|
||||
: STextStyles.field(context),
|
||||
obscureText: hidePassword,
|
||||
enableSuggestions: false,
|
||||
autocorrect: false,
|
||||
decoration: standardInputDecoration(
|
||||
"Recovery phrase password",
|
||||
passwordFocusNode,
|
||||
context,
|
||||
).copyWith(
|
||||
suffixIcon: UnconstrainedBox(
|
||||
child: ConditionalParent(
|
||||
condition: isDesktop,
|
||||
builder: (child) => SizedBox(
|
||||
height: 70,
|
||||
child: child,
|
||||
),
|
||||
GestureDetector(
|
||||
key: const Key(
|
||||
"mnemonicPassphraseFieldShowPasswordButtonKey"),
|
||||
onTap: () async {
|
||||
setState(() {
|
||||
hidePassword = !hidePassword;
|
||||
});
|
||||
},
|
||||
child: SvgPicture.asset(
|
||||
hidePassword
|
||||
? Assets.svg.eye
|
||||
: Assets.svg.eyeSlash,
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.textDark3,
|
||||
width: isDesktop ? 24 : 16,
|
||||
height: isDesktop ? 24 : 16,
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
SizedBox(
|
||||
width: isDesktop ? 24 : 16,
|
||||
),
|
||||
GestureDetector(
|
||||
key: const Key(
|
||||
"mnemonicPassphraseFieldShowPasswordButtonKey"),
|
||||
onTap: () async {
|
||||
setState(() {
|
||||
hidePassword = !hidePassword;
|
||||
});
|
||||
},
|
||||
child: SvgPicture.asset(
|
||||
hidePassword
|
||||
? Assets.svg.eye
|
||||
: Assets.svg.eyeSlash,
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.textDark3,
|
||||
width: isDesktop ? 24 : 16,
|
||||
height: isDesktop ? 24 : 16,
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
width: 12,
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(
|
||||
width: 12,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
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),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
});
|
||||
|
|
|
@ -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;
|
||||
});
|
||||
|
|
|
@ -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})",
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,22 +799,23 @@ class _ConfirmTransactionViewState
|
|||
style: STextStyles.desktopTextExtraExtraSmall(context),
|
||||
),
|
||||
),
|
||||
if (isDesktop)
|
||||
if (isDesktop && !widget.isPaynymTransaction)
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(
|
||||
top: 10,
|
||||
left: 32,
|
||||
right: 32,
|
||||
padding: const EdgeInsets.only(
|
||||
top: 10,
|
||||
left: 32,
|
||||
right: 32,
|
||||
),
|
||||
child: RoundedContainer(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 16,
|
||||
vertical: 18,
|
||||
),
|
||||
child: RoundedContainer(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 16,
|
||||
vertical: 18,
|
||||
),
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.textFieldDefaultBG,
|
||||
child: Builder(builder: (context) {
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.textFieldDefaultBG,
|
||||
child: Builder(
|
||||
builder: (context) {
|
||||
final coin = ref
|
||||
.watch(walletsChangeNotifierProvider
|
||||
.select((value) => value.getManager(walletId)))
|
||||
|
@ -770,64 +835,10 @@ 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(
|
||||
height: isDesktop ? 23 : 12,
|
||||
|
|
|
@ -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)) {
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -106,12 +106,12 @@ class _FavoriteWalletsState extends ConsumerState<FavoriteWallets> {
|
|||
ManageFavoritesView.routeName,
|
||||
);
|
||||
},
|
||||
)
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 12,
|
||||
height: 20,
|
||||
),
|
||||
!hasFavorites
|
||||
? Padding(
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
});
|
||||
|
|
|
@ -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,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -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 ?? "";
|
||||
txData["address"] = _address;
|
||||
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,87 +433,19 @@ class _DesktopSendState extends ConsumerState<DesktopSend> {
|
|||
}
|
||||
|
||||
void _updatePreviewButtonState(String? address, Decimal? amount) {
|
||||
final isValidAddress = ref
|
||||
.read(walletsChangeNotifierProvider)
|
||||
.getManager(walletId)
|
||||
.validateAddress(address ?? "");
|
||||
ref.read(previewTxButtonStateProvider.state).state =
|
||||
(isValidAddress && amount != null && amount > Decimal.zero);
|
||||
if (isPaynymSend) {
|
||||
ref.read(previewTxButtonStateProvider.state).state =
|
||||
(amount != null && amount > Decimal.zero);
|
||||
} else {
|
||||
final isValidAddress = ref
|
||||
.read(walletsChangeNotifierProvider)
|
||||
.getManager(walletId)
|
||||
.validateAddress(address ?? "");
|
||||
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,
|
||||
String locale,
|
||||
|
@ -773,7 +663,10 @@ class _DesktopSendState extends ConsumerState<DesktopSend> {
|
|||
|
||||
@override
|
||||
void initState() {
|
||||
ref.refresh(feeSheetSessionCacheProvider);
|
||||
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,199 +1021,204 @@ class _DesktopSendState extends ConsumerState<DesktopSend> {
|
|||
const SizedBox(
|
||||
height: 20,
|
||||
),
|
||||
Text(
|
||||
"Send to",
|
||||
style: STextStyles.desktopTextExtraSmall(context).copyWith(
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.textFieldActiveSearchIconRight,
|
||||
),
|
||||
textAlign: TextAlign.left,
|
||||
),
|
||||
const SizedBox(
|
||||
height: 10,
|
||||
),
|
||||
ClipRRect(
|
||||
borderRadius: BorderRadius.circular(
|
||||
Constants.size.circularBorderRadius,
|
||||
),
|
||||
child: TextField(
|
||||
minLines: 1,
|
||||
maxLines: 5,
|
||||
key: const Key("sendViewAddressFieldKey"),
|
||||
controller: sendToController,
|
||||
readOnly: false,
|
||||
autocorrect: false,
|
||||
enableSuggestions: false,
|
||||
// inputFormatters: <TextInputFormatter>[
|
||||
// FilteringTextInputFormatter.allow(
|
||||
// RegExp("[a-zA-Z0-9]{34}")),
|
||||
// ],
|
||||
toolbarOptions: const ToolbarOptions(
|
||||
copy: false,
|
||||
cut: false,
|
||||
paste: true,
|
||||
selectAll: false,
|
||||
),
|
||||
onChanged: (newValue) {
|
||||
_address = newValue;
|
||||
_updatePreviewButtonState(_address, _amountToSend);
|
||||
|
||||
setState(() {
|
||||
_addressToggleFlag = newValue.isNotEmpty;
|
||||
});
|
||||
},
|
||||
focusNode: _addressFocusNode,
|
||||
if (!isPaynymSend)
|
||||
Text(
|
||||
"Send to",
|
||||
style: STextStyles.desktopTextExtraSmall(context).copyWith(
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.textFieldActiveText,
|
||||
height: 1.8,
|
||||
.textFieldActiveSearchIconRight,
|
||||
),
|
||||
decoration: standardInputDecoration(
|
||||
"Enter ${coin.ticker} address",
|
||||
_addressFocusNode,
|
||||
context,
|
||||
desktopMed: true,
|
||||
).copyWith(
|
||||
contentPadding: const EdgeInsets.only(
|
||||
left: 16,
|
||||
top: 11,
|
||||
bottom: 12,
|
||||
right: 5,
|
||||
textAlign: TextAlign.left,
|
||||
),
|
||||
if (!isPaynymSend)
|
||||
const SizedBox(
|
||||
height: 10,
|
||||
),
|
||||
if (!isPaynymSend)
|
||||
ClipRRect(
|
||||
borderRadius: BorderRadius.circular(
|
||||
Constants.size.circularBorderRadius,
|
||||
),
|
||||
child: TextField(
|
||||
minLines: 1,
|
||||
maxLines: 5,
|
||||
key: const Key("sendViewAddressFieldKey"),
|
||||
controller: sendToController,
|
||||
readOnly: false,
|
||||
autocorrect: false,
|
||||
enableSuggestions: false,
|
||||
// inputFormatters: <TextInputFormatter>[
|
||||
// FilteringTextInputFormatter.allow(
|
||||
// RegExp("[a-zA-Z0-9]{34}")),
|
||||
// ],
|
||||
toolbarOptions: const ToolbarOptions(
|
||||
copy: false,
|
||||
cut: false,
|
||||
paste: true,
|
||||
selectAll: false,
|
||||
),
|
||||
suffixIcon: Padding(
|
||||
padding: sendToController.text.isEmpty
|
||||
? const EdgeInsets.only(right: 8)
|
||||
: const EdgeInsets.only(right: 0),
|
||||
child: UnconstrainedBox(
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||
children: [
|
||||
_addressToggleFlag
|
||||
? TextFieldIconButton(
|
||||
key: const Key(
|
||||
"sendViewClearAddressFieldButtonKey"),
|
||||
onTap: () {
|
||||
sendToController.text = "";
|
||||
_address = "";
|
||||
_updatePreviewButtonState(
|
||||
_address, _amountToSend);
|
||||
setState(() {
|
||||
_addressToggleFlag = false;
|
||||
});
|
||||
},
|
||||
child: const XIcon(),
|
||||
)
|
||||
: TextFieldIconButton(
|
||||
key: const Key(
|
||||
"sendViewPasteAddressFieldButtonKey"),
|
||||
onTap: pasteAddress,
|
||||
child: sendToController.text.isEmpty
|
||||
? const ClipboardIcon()
|
||||
: const XIcon(),
|
||||
),
|
||||
if (sendToController.text.isEmpty)
|
||||
TextFieldIconButton(
|
||||
key: const Key("sendViewAddressBookButtonKey"),
|
||||
onTap: () async {
|
||||
final entry =
|
||||
await showDialog<ContactAddressEntry?>(
|
||||
context: context,
|
||||
builder: (context) => DesktopDialog(
|
||||
maxWidth: 696,
|
||||
maxHeight: 600,
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(
|
||||
left: 32,
|
||||
),
|
||||
child: Text(
|
||||
"Address book",
|
||||
style:
|
||||
STextStyles.desktopH3(context),
|
||||
),
|
||||
),
|
||||
const DesktopDialogCloseButton(),
|
||||
],
|
||||
),
|
||||
Expanded(
|
||||
child: AddressBookAddressChooser(
|
||||
coin: coin,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
onChanged: (newValue) {
|
||||
_address = newValue;
|
||||
_updatePreviewButtonState(_address, _amountToSend);
|
||||
|
||||
setState(() {
|
||||
_addressToggleFlag = newValue.isNotEmpty;
|
||||
});
|
||||
},
|
||||
focusNode: _addressFocusNode,
|
||||
style: STextStyles.desktopTextExtraSmall(context).copyWith(
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.textFieldActiveText,
|
||||
height: 1.8,
|
||||
),
|
||||
decoration: standardInputDecoration(
|
||||
"Enter ${coin.ticker} address",
|
||||
_addressFocusNode,
|
||||
context,
|
||||
desktopMed: true,
|
||||
).copyWith(
|
||||
contentPadding: const EdgeInsets.only(
|
||||
left: 16,
|
||||
top: 11,
|
||||
bottom: 12,
|
||||
right: 5,
|
||||
),
|
||||
suffixIcon: Padding(
|
||||
padding: sendToController.text.isEmpty
|
||||
? const EdgeInsets.only(right: 8)
|
||||
: const EdgeInsets.only(right: 0),
|
||||
child: UnconstrainedBox(
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||
children: [
|
||||
_addressToggleFlag
|
||||
? TextFieldIconButton(
|
||||
key: const Key(
|
||||
"sendViewClearAddressFieldButtonKey"),
|
||||
onTap: () {
|
||||
sendToController.text = "";
|
||||
_address = "";
|
||||
_updatePreviewButtonState(
|
||||
_address, _amountToSend);
|
||||
setState(() {
|
||||
_addressToggleFlag = false;
|
||||
});
|
||||
},
|
||||
child: const XIcon(),
|
||||
)
|
||||
: TextFieldIconButton(
|
||||
key: const Key(
|
||||
"sendViewPasteAddressFieldButtonKey"),
|
||||
onTap: pasteAddress,
|
||||
child: sendToController.text.isEmpty
|
||||
? const ClipboardIcon()
|
||||
: const XIcon(),
|
||||
),
|
||||
);
|
||||
|
||||
if (entry != null) {
|
||||
sendToController.text =
|
||||
entry.other ?? entry.label;
|
||||
|
||||
_address = entry.address;
|
||||
|
||||
_updatePreviewButtonState(
|
||||
_address,
|
||||
_amountToSend,
|
||||
if (sendToController.text.isEmpty)
|
||||
TextFieldIconButton(
|
||||
key: const Key("sendViewAddressBookButtonKey"),
|
||||
onTap: () async {
|
||||
final entry =
|
||||
await showDialog<ContactAddressEntry?>(
|
||||
context: context,
|
||||
builder: (context) => DesktopDialog(
|
||||
maxWidth: 696,
|
||||
maxHeight: 600,
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(
|
||||
left: 32,
|
||||
),
|
||||
child: Text(
|
||||
"Address book",
|
||||
style: STextStyles.desktopH3(
|
||||
context),
|
||||
),
|
||||
),
|
||||
const DesktopDialogCloseButton(),
|
||||
],
|
||||
),
|
||||
Expanded(
|
||||
child: AddressBookAddressChooser(
|
||||
coin: coin,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
setState(() {
|
||||
_addressToggleFlag = true;
|
||||
});
|
||||
}
|
||||
},
|
||||
child: const AddressBookIcon(),
|
||||
),
|
||||
// if (sendToController.text.isEmpty)
|
||||
// TextFieldIconButton(
|
||||
// key: const Key("sendViewScanQrButtonKey"),
|
||||
// onTap: scanQr,
|
||||
// child: const QrCodeIcon(),
|
||||
// )
|
||||
],
|
||||
if (entry != null) {
|
||||
sendToController.text =
|
||||
entry.other ?? entry.label;
|
||||
|
||||
_address = entry.address;
|
||||
|
||||
_updatePreviewButtonState(
|
||||
_address,
|
||||
_amountToSend,
|
||||
);
|
||||
|
||||
setState(() {
|
||||
_addressToggleFlag = true;
|
||||
});
|
||||
}
|
||||
},
|
||||
child: const AddressBookIcon(),
|
||||
),
|
||||
// if (sendToController.text.isEmpty)
|
||||
// TextFieldIconButton(
|
||||
// key: const Key("sendViewScanQrButtonKey"),
|
||||
// onTap: scanQr,
|
||||
// child: const QrCodeIcon(),
|
||||
// )
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
Builder(
|
||||
builder: (_) {
|
||||
final error = _updateInvalidAddressText(
|
||||
_address ?? "",
|
||||
ref.read(walletsChangeNotifierProvider).getManager(walletId),
|
||||
);
|
||||
if (!isPaynymSend)
|
||||
Builder(
|
||||
builder: (_) {
|
||||
final error = _updateInvalidAddressText(
|
||||
_address ?? "",
|
||||
ref.read(walletsChangeNotifierProvider).getManager(walletId),
|
||||
);
|
||||
|
||||
if (error == null || error.isEmpty) {
|
||||
return Container();
|
||||
} else {
|
||||
return Align(
|
||||
alignment: Alignment.topLeft,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(
|
||||
left: 12.0,
|
||||
top: 4.0,
|
||||
),
|
||||
child: Text(
|
||||
error,
|
||||
textAlign: TextAlign.left,
|
||||
style: STextStyles.label(context).copyWith(
|
||||
color:
|
||||
Theme.of(context).extension<StackColors>()!.textError,
|
||||
if (error == null || error.isEmpty) {
|
||||
return Container();
|
||||
} else {
|
||||
return Align(
|
||||
alignment: Alignment.topLeft,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(
|
||||
left: 12.0,
|
||||
top: 4.0,
|
||||
),
|
||||
child: Text(
|
||||
error,
|
||||
textAlign: TextAlign.left,
|
||||
style: STextStyles.label(context).copyWith(
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.textError,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
},
|
||||
),
|
||||
// const SizedBox(
|
||||
// height: 20,
|
||||
// ),
|
||||
|
@ -1368,9 +1286,10 @@ class _DesktopSendState extends ConsumerState<DesktopSend> {
|
|||
// ),
|
||||
// ),
|
||||
// ),
|
||||
const SizedBox(
|
||||
height: 20,
|
||||
),
|
||||
if (!isPaynymSend)
|
||||
const SizedBox(
|
||||
height: 20,
|
||||
),
|
||||
if (coin != Coin.epicCash)
|
||||
Text(
|
||||
"Transaction fee (estimated)",
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 {
|
||||
|
|
Loading…
Reference in a new issue