diff --git a/assets/images/dark/stack.png b/assets/images/dark/stack.png deleted file mode 100644 index b59af1608..000000000 Binary files a/assets/images/dark/stack.png and /dev/null differ diff --git a/assets/images/dark/stack.svg b/assets/images/dark/stack.svg index 43f29e515..22dce4736 100644 --- a/assets/images/dark/stack.svg +++ b/assets/images/dark/stack.svg @@ -1,440 +1,115 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/assets/images/light/stack.png b/assets/images/light/stack.png deleted file mode 100644 index b59af1608..000000000 Binary files a/assets/images/light/stack.png and /dev/null differ diff --git a/assets/images/light/stack.svg b/assets/images/light/stack.svg index 43f29e515..22dce4736 100644 --- a/assets/images/light/stack.svg +++ b/assets/images/light/stack.svg @@ -1,440 +1,115 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/assets/images/oledBlack/stack.png b/assets/images/oledBlack/stack.png deleted file mode 100644 index b59af1608..000000000 Binary files a/assets/images/oledBlack/stack.png and /dev/null differ diff --git a/assets/images/oledBlack/stack.svg b/assets/images/oledBlack/stack.svg index 43f29e515..22dce4736 100644 --- a/assets/images/oledBlack/stack.svg +++ b/assets/images/oledBlack/stack.svg @@ -1,440 +1,115 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist index 4ef19051a..dd711a0b1 100644 --- a/ios/Runner/Info.plist +++ b/ios/Runner/Info.plist @@ -2,6 +2,8 @@ + ITSAppUsesNonExemptEncryption + CADisableMinimumFrameDurationOnPhone CFBundleDevelopmentRegion @@ -29,7 +31,7 @@ LSSupportsOpeningDocumentsInPlace NSCameraUsageDescription - App requires access to the Camera to scan QR codes from other people's installed app in order to coordinate sending Firo. + App requires access to the Camera to scan QR codes from other people's installed app in order to coordinate sending. NSFaceIDUsageDescription This app requires Face ID permissions so that the user can securely lock their wallet if their device uses Face ID. It will be useful feature for all users, and especially those prone to forget their login pin on iPhones where Touch ID is not available. NSPhotoLibraryUsageDescription diff --git a/lib/pages/add_wallet_views/add_wallet_view/sub_widgets/next_button.dart b/lib/pages/add_wallet_views/add_wallet_view/sub_widgets/next_button.dart index 939f16a31..57216b182 100644 --- a/lib/pages/add_wallet_views/add_wallet_view/sub_widgets/next_button.dart +++ b/lib/pages/add_wallet_views/add_wallet_view/sub_widgets/next_button.dart @@ -28,8 +28,6 @@ class AddWalletNextButton extends ConsumerWidget { final selectedCoin = ref.read(addWalletSelectedCoinStateProvider.state).state; - //todo: check if print needed - // debugPrint("Next pressed with ${selectedCoin!.name} selected!"); Navigator.of(context).pushNamed( CreateOrRestoreWalletView.routeName, arguments: selectedCoin, diff --git a/lib/pages/add_wallet_views/create_or_restore_wallet_view/create_or_restore_wallet_view.dart b/lib/pages/add_wallet_views/create_or_restore_wallet_view/create_or_restore_wallet_view.dart index 206e5e787..7108b35be 100644 --- a/lib/pages/add_wallet_views/create_or_restore_wallet_view/create_or_restore_wallet_view.dart +++ b/lib/pages/add_wallet_views/create_or_restore_wallet_view/create_or_restore_wallet_view.dart @@ -89,41 +89,40 @@ class CreateOrRestoreWalletView extends StatelessWidget { }, ), ), - body: Container( - color: Theme.of(context).extension()!.background, - child: Padding( - padding: const EdgeInsets.all(16), - child: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - Padding( - padding: const EdgeInsets.all(31), - child: CoinImage( + body: SafeArea( + child: Container( + color: Theme.of(context).extension()!.background, + child: Padding( + padding: const EdgeInsets.all(16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + CoinImage( coin: coin, isDesktop: isDesktop, ), - ), - const Spacer( - flex: 2, - ), - CreateRestoreWalletTitle( - coin: coin, - isDesktop: isDesktop, - ), - const SizedBox( - height: 8, - ), - CreateRestoreWalletSubTitle( - isDesktop: isDesktop, - ), - const Spacer( - flex: 5, - ), - CreateWalletButtonGroup( - coin: coin, - isDesktop: isDesktop, - ), - ], + const Spacer( + flex: 2, + ), + CreateRestoreWalletTitle( + coin: coin, + isDesktop: isDesktop, + ), + const SizedBox( + height: 8, + ), + CreateRestoreWalletSubTitle( + isDesktop: isDesktop, + ), + const Spacer( + flex: 5, + ), + CreateWalletButtonGroup( + coin: coin, + isDesktop: isDesktop, + ), + ], + ), ), ), ), diff --git a/lib/pages/add_wallet_views/create_or_restore_wallet_view/sub_widgets/coin_image.dart b/lib/pages/add_wallet_views/create_or_restore_wallet_view/sub_widgets/coin_image.dart index eda21d79d..874580faa 100644 --- a/lib/pages/add_wallet_views/create_or_restore_wallet_view/sub_widgets/coin_image.dart +++ b/lib/pages/add_wallet_views/create_or_restore_wallet_view/sub_widgets/coin_image.dart @@ -18,7 +18,7 @@ class CoinImage extends ConsumerWidget { Widget build(BuildContext context, WidgetRef ref) { return SvgPicture.asset( Assets.svg.imageFor(coin: coin, context: context), - width: isDesktop ? 324 : MediaQuery.of(context).size.width, + width: isDesktop ? 324 : MediaQuery.of(context).size.width / 1.6, ); } } diff --git a/lib/pages/buy_view/sub_widgets/fiat_selection_view.dart b/lib/pages/buy_view/sub_widgets/fiat_selection_view.dart index dfaec0dec..09ee82a79 100644 --- a/lib/pages/buy_view/sub_widgets/fiat_selection_view.dart +++ b/lib/pages/buy_view/sub_widgets/fiat_selection_view.dart @@ -76,7 +76,7 @@ class _FiatSelectionViewState extends State { @override Widget build(BuildContext context) { Locale locale = Localizations.localeOf(context); - var format = NumberFormat.simpleCurrency(locale: locale.toString()); + final format = NumberFormat.simpleCurrency(locale: locale.toString()); // See https://stackoverflow.com/a/67055685 final isDesktop = Util.isDesktop; @@ -186,80 +186,178 @@ class _FiatSelectionViewState extends State { height: 12, ), Flexible( - child: RoundedWhiteContainer( - padding: const EdgeInsets.all(0), - child: ListView.builder( - shrinkWrap: true, - primary: isDesktop ? false : null, - itemCount: _fiats.length, - itemBuilder: (builderContext, index) { - return Padding( - padding: const EdgeInsets.symmetric(vertical: 4), - child: GestureDetector( - onTap: () { - Navigator.of(context).pop(_fiats[index]); - }, - child: RoundedWhiteContainer( - child: Row( + child: SingleChildScrollView( + child: RoundedWhiteContainer( + padding: const EdgeInsets.all(0), + child: Table( + columnWidths: const { + 0: IntrinsicColumnWidth(), + 1: FlexColumnWidth(), + }, + defaultVerticalAlignment: TableCellVerticalAlignment.middle, + children: [ + ..._fiats.map( + (e) { + return TableRow( children: [ - Container( - padding: const EdgeInsets.all(7.5), - decoration: BoxDecoration( - color: Theme.of(context) - .extension()! - .currencyListItemBG, - borderRadius: BorderRadius.circular(4), - ), - child: Text( - format.simpleCurrencySymbol( - _fiats[index].ticker.toUpperCase()), - style: STextStyles.subtitle(context).apply( - fontSizeFactor: (1 / - format - .simpleCurrencySymbol(_fiats[index] - .ticker - .toUpperCase()) - .length * // Couldn't get pow() working here - format - .simpleCurrencySymbol(_fiats[index] - .ticker - .toUpperCase()) - .length)), - textAlign: TextAlign.center, + TableCell( + verticalAlignment: + TableCellVerticalAlignment.fill, + child: GestureDetector( + onTap: () => Navigator.of(context).pop(e), + child: Container( + color: Colors.transparent, + padding: const EdgeInsets.only(left: 12), + child: Column( + mainAxisSize: MainAxisSize.min, + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: + CrossAxisAlignment.stretch, + children: [ + Container( + padding: const EdgeInsets.all(7.5), + decoration: BoxDecoration( + color: Theme.of(context) + .extension()! + .currencyListItemBG, + borderRadius: + BorderRadius.circular(4), + ), + child: Text( + format.simpleCurrencySymbol( + e.ticker.toUpperCase()), + style: STextStyles.subtitle(context) + .apply( + fontSizeFactor: (1 / + format + .simpleCurrencySymbol( + e.ticker.toUpperCase()) + .length * // Couldn't get pow() working here + format + .simpleCurrencySymbol( + e.ticker.toUpperCase()) + .length), + ), + textAlign: TextAlign.center, + ), + ), + ], + ), + ), ), ), - const SizedBox( - width: 10, - ), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - _fiats[index].name, - style: STextStyles.largeMedium14(context), + GestureDetector( + onTap: () => Navigator.of(context).pop(e), + child: Container( + color: Colors.transparent, + child: Padding( + padding: const EdgeInsets.all(12), + child: Column( + crossAxisAlignment: + CrossAxisAlignment.start, + children: [ + Text( + e.name, + style: + STextStyles.largeMedium14(context), + ), + const SizedBox( + height: 2, + ), + Text( + e.ticker.toUpperCase(), + style: STextStyles.smallMed12(context) + .copyWith( + color: Theme.of(context) + .extension()! + .textSubtitle1, + ), + ), + ], ), - const SizedBox( - height: 2, - ), - Text( - _fiats[index].ticker.toUpperCase(), - style: STextStyles.smallMed12(context) - .copyWith( - color: Theme.of(context) - .extension()! - .textSubtitle1, - ), - ), - ], + ), ), ), ], - ), - ), + ); + }, ), - ); - }, + ], + ), + + // child: ListView.builder( + // shrinkWrap: true, + // primary: isDesktop ? false : null, + // itemCount: _fiats.length, + // itemBuilder: (builderContext, index) { + // return Padding( + // padding: const EdgeInsets.symmetric(vertical: 4), + // child: GestureDetector( + // onTap: () { + // Navigator.of(context).pop(_fiats[index]); + // }, + // child: RoundedWhiteContainer( + // child: Row( + // children: [ + // Container( + // padding: const EdgeInsets.all(7.5), + // decoration: BoxDecoration( + // color: Theme.of(context) + // .extension()! + // .currencyListItemBG, + // borderRadius: BorderRadius.circular(4), + // ), + // child: Text( + // format.simpleCurrencySymbol( + // _fiats[index].ticker.toUpperCase()), + // style: STextStyles.subtitle(context).apply( + // fontSizeFactor: (1 / + // format + // .simpleCurrencySymbol(_fiats[index] + // .ticker + // .toUpperCase()) + // .length * // Couldn't get pow() working here + // format + // .simpleCurrencySymbol(_fiats[index] + // .ticker + // .toUpperCase()) + // .length)), + // textAlign: TextAlign.center, + // ), + // ), + // const SizedBox( + // width: 10, + // ), + // Expanded( + // child: Column( + // crossAxisAlignment: CrossAxisAlignment.start, + // children: [ + // Text( + // _fiats[index].name, + // style: STextStyles.largeMedium14(context), + // ), + // const SizedBox( + // height: 2, + // ), + // Text( + // _fiats[index].ticker.toUpperCase(), + // style: STextStyles.smallMed12(context) + // .copyWith( + // color: Theme.of(context) + // .extension()! + // .textSubtitle1, + // ), + // ), + // ], + // ), + // ), + // ], + // ), + // ), + // ), + // ); + // }, + // ), ), ), ), diff --git a/lib/pages/coin_control/utxo_card.dart b/lib/pages/coin_control/utxo_card.dart index c5145f55a..e2900a48b 100644 --- a/lib/pages/coin_control/utxo_card.dart +++ b/lib/pages/coin_control/utxo_card.dart @@ -1,6 +1,5 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:isar/isar.dart'; import 'package:stackwallet/db/main_db.dart'; import 'package:stackwallet/models/isar/models/isar_models.dart'; import 'package:stackwallet/providers/global/wallets_provider.dart'; @@ -36,7 +35,8 @@ class UtxoCard extends ConsumerStatefulWidget { } class _UtxoCardState extends ConsumerState { - late final UTXO utxo; + late Stream stream; + late UTXO utxo; late bool _selected; @@ -44,6 +44,8 @@ class _UtxoCardState extends ConsumerState { void initState() { _selected = widget.initialSelectedState; utxo = widget.utxo; + + stream = MainDB.instance.watchUTXO(id: utxo.id); super.initState(); } @@ -57,19 +59,6 @@ class _UtxoCardState extends ConsumerState { final currentChainHeight = ref.watch(walletsChangeNotifierProvider .select((value) => value.getManager(widget.walletId).currentHeight)); - String? label; - if (utxo.address != null) { - label = MainDB.instance.isar.addressLabels - .where() - .addressStringWalletIdEqualTo(utxo.address!, widget.walletId) - .findFirstSync() - ?.value; - - if (label != null && label.isEmpty) { - label = null; - } - } - return ConditionalParent( condition: widget.onPressed != null, builder: (child) => MaterialButton( @@ -92,69 +81,79 @@ class _UtxoCardState extends ConsumerState { color: widget.onPressed == null ? Theme.of(context).extension()!.popupBG : Colors.transparent, - child: Row( - children: [ - ConditionalParent( - condition: widget.canSelect, - builder: (child) => GestureDetector( - onTap: () { - _selected = !_selected; - widget.onSelectedChanged(_selected); - setState(() {}); - }, - child: child, - ), - child: UTXOStatusIcon( - blocked: utxo.isBlocked, - status: utxo.isConfirmed( - currentChainHeight, - coin.requiredConfirmations, - ) - ? UTXOStatusIconStatus.confirmed - : UTXOStatusIconStatus.unconfirmed, - background: Theme.of(context).extension()!.popupBG, - selected: _selected, - width: 32, - height: 32, - ), - ), - const SizedBox( - width: 10, - ), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisSize: MainAxisSize.min, + child: StreamBuilder( + stream: stream, + builder: (context, snapshot) { + if (snapshot.hasData) { + utxo = snapshot.data!; + } + return Row( children: [ - Text( - "${Format.satoshisToAmount( - utxo.value, - coin: coin, - ).toStringAsFixed(coin.decimals)} ${coin.ticker}", - style: STextStyles.w600_14(context), + ConditionalParent( + condition: widget.canSelect, + builder: (child) => GestureDetector( + onTap: () { + _selected = !_selected; + widget.onSelectedChanged(_selected); + setState(() {}); + }, + child: child, + ), + child: UTXOStatusIcon( + blocked: utxo.isBlocked, + status: utxo.isConfirmed( + currentChainHeight, + coin.requiredConfirmations, + ) + ? UTXOStatusIconStatus.confirmed + : UTXOStatusIconStatus.unconfirmed, + background: + Theme.of(context).extension()!.popupBG, + selected: _selected, + width: 32, + height: 32, + ), ), const SizedBox( - height: 2, + width: 10, ), - Row( - children: [ - Flexible( - child: Text( - label ?? utxo.address ?? utxo.txid, - style: STextStyles.w500_12(context).copyWith( - color: Theme.of(context) - .extension()! - .textSubtitle1, - ), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + Text( + "${Format.satoshisToAmount( + utxo.value, + coin: coin, + ).toStringAsFixed(coin.decimals)} ${coin.ticker}", + style: STextStyles.w600_14(context), ), - ), - ], + const SizedBox( + height: 2, + ), + Row( + children: [ + Flexible( + child: Text( + utxo.name.isNotEmpty + ? utxo.name + : utxo.address ?? utxo.txid, + style: STextStyles.w500_12(context).copyWith( + color: Theme.of(context) + .extension()! + .textSubtitle1, + ), + ), + ), + ], + ), + ], + ), ), ], - ), - ), - ], - ), + ); + }), ), ); } diff --git a/lib/pages/coin_control/utxo_details_view.dart b/lib/pages/coin_control/utxo_details_view.dart index 9838ad6e7..180cae39d 100644 --- a/lib/pages/coin_control/utxo_details_view.dart +++ b/lib/pages/coin_control/utxo_details_view.dart @@ -176,6 +176,82 @@ class _UtxoDetailsViewState extends ConsumerState { ], ), ), + const SizedBox( + height: _spacing, + ), + RoundedWhiteContainer( + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + "Label", + style: STextStyles.w500_14(context).copyWith( + color: Theme.of(context) + .extension()! + .textSubtitle1, + ), + ), + SimpleEditButton( + editValue: utxo!.name, + editLabel: "label", + onValueChanged: (newName) { + MainDB.instance.putUTXO( + utxo!.copyWith( + name: newName, + ), + ); + }, + ), + ], + ), + const SizedBox( + height: 4, + ), + Text( + utxo!.name, + style: STextStyles.w500_14(context), + ), + ], + ), + ), + const SizedBox( + height: _spacing, + ), + RoundedWhiteContainer( + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + "Address", + style: STextStyles.w500_14(context).copyWith( + color: Theme.of(context) + .extension()! + .textSubtitle1, + ), + ), + SimpleCopyButton( + data: utxo!.address!, + ), + ], + ), + const SizedBox( + height: 4, + ), + Text( + utxo!.address!, + style: STextStyles.w500_14(context), + ), + ], + ), + ), if (label != null && label!.value.isNotEmpty) const SizedBox( height: _spacing, @@ -215,40 +291,6 @@ class _UtxoDetailsViewState extends ConsumerState { const SizedBox( height: _spacing, ), - RoundedWhiteContainer( - child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - "Address", - style: STextStyles.w500_14(context).copyWith( - color: Theme.of(context) - .extension()! - .textSubtitle1, - ), - ), - SimpleCopyButton( - data: utxo!.address!, - ), - ], - ), - const SizedBox( - height: 4, - ), - Text( - utxo!.address!, - style: STextStyles.w500_14(context), - ), - ], - ), - ), - const SizedBox( - height: _spacing, - ), RoundedWhiteContainer( child: Column( mainAxisSize: MainAxisSize.min, @@ -309,48 +351,6 @@ class _UtxoDetailsViewState extends ConsumerState { const SizedBox( height: _spacing, ), - RoundedWhiteContainer( - child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - "Note", - style: STextStyles.w500_14(context).copyWith( - color: Theme.of(context) - .extension()! - .textSubtitle1, - ), - ), - SimpleEditButton( - editValue: utxo!.name, - editLabel: "note", - onValueChanged: (newName) { - MainDB.instance.putUTXO( - utxo!.copyWith( - name: newName, - ), - ); - }, - ), - ], - ), - const SizedBox( - height: 4, - ), - Text( - utxo!.name, - style: STextStyles.w500_14(context), - ), - ], - ), - ), - const SizedBox( - height: _spacing, - ), if (utxo!.isBlocked) Column( mainAxisSize: MainAxisSize.min, diff --git a/lib/pages/exchange_view/exchange_form.dart b/lib/pages/exchange_view/exchange_form.dart index c04360bf6..ab7cab56e 100644 --- a/lib/pages/exchange_view/exchange_form.dart +++ b/lib/pages/exchange_view/exchange_form.dart @@ -618,6 +618,16 @@ class _ExchangeFormState extends ConsumerState { if (walletInitiated) { WidgetsBinding.instance.addPostFrameCallback((timeStamp) { ref.read(exchangeFormStateProvider).reset(shouldNotifyListeners: true); + ExchangeDataLoadingService.instance + .getAggregateCurrency( + coin!.ticker, + ExchangeRateType.estimated, + ) + .then((value) { + if (value != null) { + ref.read(exchangeFormStateProvider).updateSendCurrency(value, true); + } + }); }); } else { _sendController.text = @@ -848,7 +858,7 @@ class _ExchangeFormState extends ConsumerState { enabled: ref.watch( exchangeFormStateProvider.select((value) => value.canExchange)), onPressed: onExchangePressed, - label: "Exchange", + label: "Swap", ) ], ); diff --git a/lib/pages/exchange_view/exchange_step_views/step_1_view.dart b/lib/pages/exchange_view/exchange_step_views/step_1_view.dart index c57e0acad..b866de448 100644 --- a/lib/pages/exchange_view/exchange_step_views/step_1_view.dart +++ b/lib/pages/exchange_view/exchange_step_views/step_1_view.dart @@ -56,7 +56,7 @@ class _Step1ViewState extends State { }, ), title: Text( - "Exchange", + "Swap", style: STextStyles.navBarTitle(context), ), ), diff --git a/lib/pages/exchange_view/exchange_step_views/step_2_view.dart b/lib/pages/exchange_view/exchange_step_views/step_2_view.dart index 61f3517ce..a32df6e74 100644 --- a/lib/pages/exchange_view/exchange_step_views/step_2_view.dart +++ b/lib/pages/exchange_view/exchange_step_views/step_2_view.dart @@ -144,7 +144,7 @@ class _Step2ViewState extends ConsumerState { }, ), title: Text( - "Exchange", + "Swap", style: STextStyles.navBarTitle(context), ), ), diff --git a/lib/pages/exchange_view/exchange_step_views/step_3_view.dart b/lib/pages/exchange_view/exchange_step_views/step_3_view.dart index 0c5eaa8c9..22c356b5d 100644 --- a/lib/pages/exchange_view/exchange_step_views/step_3_view.dart +++ b/lib/pages/exchange_view/exchange_step_views/step_3_view.dart @@ -72,7 +72,7 @@ class _Step3ViewState extends ConsumerState { }, ), title: Text( - "Exchange", + "Swap", style: STextStyles.navBarTitle(context), ), ), diff --git a/lib/pages/exchange_view/exchange_step_views/step_4_view.dart b/lib/pages/exchange_view/exchange_step_views/step_4_view.dart index 2507ac2d4..1d32b4811 100644 --- a/lib/pages/exchange_view/exchange_step_views/step_4_view.dart +++ b/lib/pages/exchange_view/exchange_step_views/step_4_view.dart @@ -152,7 +152,7 @@ class _Step4ViewState extends ConsumerState { ), ), title: Text( - "Exchange", + "Swap", style: STextStyles.navBarTitle(context), ), ), diff --git a/lib/pages/exchange_view/trade_details_view.dart b/lib/pages/exchange_view/trade_details_view.dart index bb9316c27..76653bd18 100644 --- a/lib/pages/exchange_view/trade_details_view.dart +++ b/lib/pages/exchange_view/trade_details_view.dart @@ -322,7 +322,7 @@ class _TradeDetailsViewState extends ConsumerState { width: 16, ), SelectableText( - "Exchange", + "Swap service", style: STextStyles.desktopTextMedium(context), ), ], @@ -1052,7 +1052,7 @@ class _TradeDetailsViewState extends ConsumerState { crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( - "Exchange", + "Swap service", style: STextStyles.itemSubtitle(context), ), if (isDesktop) diff --git a/lib/pages/exchange_view/wallet_initiated_exchange_view.dart b/lib/pages/exchange_view/wallet_initiated_exchange_view.dart index bfdb5e9cd..99ba04979 100644 --- a/lib/pages/exchange_view/wallet_initiated_exchange_view.dart +++ b/lib/pages/exchange_view/wallet_initiated_exchange_view.dart @@ -127,7 +127,7 @@ class _WalletInitiatedExchangeViewState }, ), title: Text( - "Exchange", + "Swap", style: STextStyles.navBarTitle(context), ), ), diff --git a/lib/pages/home_view/home_view.dart b/lib/pages/home_view/home_view.dart index c5c253a01..ea9b29558 100644 --- a/lib/pages/home_view/home_view.dart +++ b/lib/pages/home_view/home_view.dart @@ -107,23 +107,8 @@ class _HomeViewState extends ConsumerState { _rotateIconController = RotateIconController(); _children = [ const WalletsView(), - if (Constants.enableExchange) - Stack( - children: [ - const ExchangeView(), - // ExchangeLoadingOverlayView( - // unawaitedLoad: _loadCNData, - // ), - ], - ), - if (Constants.enableBuy) - // Stack( - // children: [ - const BuyView(), - // BuyLoadingOverlayView( - // unawaitedLoad: _loadSimplexData, - // ), - // ], + if (Constants.enableExchange) const ExchangeView(), + if (Constants.enableExchange) const BuyView(), ]; ref.read(notificationsProvider).startCheckingWatchedNotifications(); diff --git a/lib/pages/home_view/sub_widgets/home_view_button_bar.dart b/lib/pages/home_view/sub_widgets/home_view_button_bar.dart index bf1caab77..f532cf3a2 100644 --- a/lib/pages/home_view/sub_widgets/home_view_button_bar.dart +++ b/lib/pages/home_view/sub_widgets/home_view_button_bar.dart @@ -111,7 +111,7 @@ class _HomeViewButtonBarState extends ConsumerState { // } }, child: Text( - "Exchange", + "Swap", style: STextStyles.button(context).copyWith( fontSize: 14, color: selectedIndex == 1 diff --git a/lib/pages/wallet_view/sub_widgets/wallet_navigation_bar.dart b/lib/pages/wallet_view/sub_widgets/wallet_navigation_bar.dart deleted file mode 100644 index 18a1dfb34..000000000 --- a/lib/pages/wallet_view/sub_widgets/wallet_navigation_bar.dart +++ /dev/null @@ -1,592 +0,0 @@ -import 'dart:async'; - -import 'package:flutter/material.dart'; -import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:flutter_svg/flutter_svg.dart'; -import 'package:stackwallet/pages/coin_control/coin_control_view.dart'; -import 'package:stackwallet/pages/paynym/paynym_claim_view.dart'; -import 'package:stackwallet/pages/paynym/paynym_home_view.dart'; -import 'package:stackwallet/providers/global/paynym_api_provider.dart'; -import 'package:stackwallet/providers/global/prefs_provider.dart'; -import 'package:stackwallet/providers/global/wallets_provider.dart'; -import 'package:stackwallet/providers/wallet/my_paynym_account_state_provider.dart'; -import 'package:stackwallet/services/mixins/paynym_wallet_interface.dart'; -import 'package:stackwallet/utilities/assets.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; -import 'package:stackwallet/utilities/enums/derive_path_type_enum.dart'; -import 'package:stackwallet/utilities/logger.dart'; -import 'package:stackwallet/utilities/text_styles.dart'; -import 'package:stackwallet/utilities/theme/stack_colors.dart'; -import 'package:stackwallet/widgets/loading_indicator.dart'; -import 'package:tuple/tuple.dart'; - -class WalletNavigationBar extends ConsumerStatefulWidget { - const WalletNavigationBar({ - Key? key, - required this.onReceivePressed, - required this.onSendPressed, - required this.onExchangePressed, - required this.onBuyPressed, - required this.height, - required this.enableExchange, - required this.coin, - required this.walletId, - }) : super(key: key); - - final VoidCallback onReceivePressed; - final VoidCallback onSendPressed; - final VoidCallback onExchangePressed; - final VoidCallback onBuyPressed; - final double height; - final bool enableExchange; - final Coin coin; - final String walletId; - - @override - ConsumerState createState() => - _WalletNavigationBarState(); -} - -class _WalletNavigationBarState extends ConsumerState { - double scale = 0; - final duration = const Duration(milliseconds: 200); - - @override - Widget build(BuildContext context) { - final showMore = ref.watch( - walletsChangeNotifierProvider.select( - (value) => value.getManager(widget.walletId).hasPaynymSupport, - ), - ) || - (ref.watch( - walletsChangeNotifierProvider.select( - (value) => - value.getManager(widget.walletId).hasCoinControlSupport, - ), - ) && - ref.watch( - prefsChangeNotifierProvider.select( - (value) => value.enableCoinControl, - ), - )); - - return Column( - mainAxisAlignment: MainAxisAlignment.end, - crossAxisAlignment: CrossAxisAlignment.end, - children: [ - // const Spacer(), - - AnimatedScale( - scale: scale, - duration: duration, - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - // AnimatedOpacity( - // opacity: scale, - // duration: duration, - // child: GestureDetector( - // onTap: () {}, - // child: Container( - // padding: const EdgeInsets.all(16), - // width: 146, - // decoration: BoxDecoration( - // color: - // Theme.of(context).extension()!.popupBG, - // boxShadow: [ - // Theme.of(context) - // .extension()! - // .standardBoxShadow - // ], - // borderRadius: BorderRadius.circular( - // widget.height / 2.0, - // ), - // ), - // child: Row( - // mainAxisAlignment: MainAxisAlignment.center, - // children: [ - // Text( - // "Whirlpool", - // style: STextStyles.w600_12(context), - // ), - // ], - // ), - // ), - // ), - // ), - // const SizedBox( - // height: 8, - // ), - if (ref.watch( - walletsChangeNotifierProvider.select( - (value) => value - .getManager(widget.walletId) - .hasCoinControlSupport, - ), - ) && - ref.watch( - prefsChangeNotifierProvider.select( - (value) => value.enableCoinControl, - ), - )) - AnimatedOpacity( - opacity: scale, - duration: duration, - child: GestureDetector( - onTap: () { - if (mounted) { - // hide more context menu - setState(() { - scale = 0; - }); - - Navigator.of(context).pushNamed( - CoinControlView.routeName, - arguments: Tuple2( - widget.walletId, - CoinControlViewType.manage, - ), - ); - } - }, - child: Container( - padding: const EdgeInsets.all(16), - width: 146, - decoration: BoxDecoration( - color: - Theme.of(context).extension()!.popupBG, - boxShadow: [ - Theme.of(context) - .extension()! - .standardBoxShadow - ], - borderRadius: BorderRadius.circular( - widget.height / 2.0, - ), - ), - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text( - "Coin control", - style: STextStyles.buttonSmall(context), - ), - const SizedBox( - width: 16, - ), - SvgPicture.asset( - Assets.svg.coinControl.gamePad, - height: 20, - width: 20, - color: Theme.of(context) - .extension()! - .bottomNavIconIcon, - ), - ], - ), - ), - ), - ), - if (ref.watch( - walletsChangeNotifierProvider.select( - (value) => value - .getManager(widget.walletId) - .hasCoinControlSupport, - ), - ) && - ref.watch( - prefsChangeNotifierProvider.select( - (value) => value.enableCoinControl, - ), - ) && - ref.watch( - walletsChangeNotifierProvider.select( - (value) => - value.getManager(widget.walletId).hasPaynymSupport, - ), - )) - const SizedBox( - height: 8, - ), - if (ref.watch(walletsChangeNotifierProvider.select((value) => - value.getManager(widget.walletId).hasPaynymSupport))) - AnimatedOpacity( - opacity: scale, - duration: duration, - child: Consumer(builder: (context, ref, __) { - return GestureDetector( - onTap: () async { - setState(() { - scale = 0; - }); - unawaited( - showDialog( - context: context, - builder: (context) => const LoadingIndicator( - width: 100, - ), - ), - ); - - final manager = ref - .read(walletsChangeNotifierProvider) - .getManager(widget.walletId); - - final paynymInterface = - manager.wallet as PaynymWalletInterface; - - final code = await paynymInterface.getPaymentCode( - DerivePathTypeExt.primaryFor(manager.coin)); - - final account = await ref - .read(paynymAPIProvider) - .nym(code.toString()); - - Logging.instance.log( - "my nym account: $account", - level: LogLevel.Info, - ); - - if (mounted) { - Navigator.of(context).pop(); - - // check if account exists and for matching code to see if claimed - if (account.value != null && - account.value!.codes.first.claimed) { - ref.read(myPaynymAccountStateProvider.state).state = - account.value!; - - await Navigator.of(context).pushNamed( - PaynymHomeView.routeName, - arguments: widget.walletId, - ); - } else { - await Navigator.of(context).pushNamed( - PaynymClaimView.routeName, - arguments: widget.walletId, - ); - } - } - }, - child: Container( - padding: const EdgeInsets.all(16), - width: 146, - decoration: BoxDecoration( - color: Theme.of(context) - .extension()! - .popupBG, - boxShadow: [ - Theme.of(context) - .extension()! - .standardBoxShadow - ], - borderRadius: BorderRadius.circular( - widget.height / 2.0, - ), - ), - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text( - "Paynym", - style: STextStyles.buttonSmall(context), - ), - const SizedBox( - width: 16, - ), - SvgPicture.asset( - Assets.svg.robotHead, - height: 20, - width: 20, - color: Theme.of(context) - .extension()! - .bottomNavIconIcon, - ), - ], - ), - ), - ); - }), - ), - const SizedBox( - height: 8, - ), - ], - ), - ), - Container( - height: widget.height, - decoration: BoxDecoration( - color: Theme.of(context).extension()!.bottomNavBack, - boxShadow: [ - Theme.of(context).extension()!.standardBoxShadow - ], - borderRadius: BorderRadius.circular( - widget.height / 2.0, - ), - ), - child: Padding( - padding: const EdgeInsets.symmetric( - horizontal: 6, - vertical: 4, - ), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - const SizedBox( - width: 12, - ), - RawMaterialButton( - constraints: const BoxConstraints( - minWidth: 66, - ), - onPressed: widget.onReceivePressed, - splashColor: - Theme.of(context).extension()!.highlight, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular( - widget.height / 2.0, - ), - ), - child: Container( - color: Colors.transparent, - child: Padding( - padding: const EdgeInsets.symmetric(vertical: 2.0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - const Spacer(), - Container( - decoration: BoxDecoration( - color: Theme.of(context) - .extension()! - .accentColorDark - .withOpacity(0.4), - borderRadius: BorderRadius.circular( - 24, - ), - ), - child: Padding( - padding: const EdgeInsets.all(6.0), - child: SvgPicture.asset( - Assets.svg.arrowDownLeft, - width: 12, - height: 12, - color: Theme.of(context) - .extension()! - .accentColorDark, - ), - ), - ), - const SizedBox( - height: 4, - ), - Text( - "Receive", - style: STextStyles.buttonSmall(context), - ), - const Spacer(), - ], - ), - ), - ), - ), - RawMaterialButton( - constraints: const BoxConstraints( - minWidth: 66, - ), - onPressed: widget.onSendPressed, - splashColor: - Theme.of(context).extension()!.highlight, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular( - widget.height / 2.0, - ), - ), - child: Container( - color: Colors.transparent, - child: Padding( - padding: const EdgeInsets.symmetric(vertical: 2.0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - const Spacer(), - Container( - decoration: BoxDecoration( - color: Theme.of(context) - .extension()! - .accentColorDark - .withOpacity(0.4), - borderRadius: BorderRadius.circular( - 24, - ), - ), - child: Padding( - padding: const EdgeInsets.all(6.0), - child: SvgPicture.asset( - Assets.svg.arrowUpRight, - width: 12, - height: 12, - color: Theme.of(context) - .extension()! - .accentColorDark, - ), - ), - ), - const SizedBox( - height: 4, - ), - Text( - "Send", - style: STextStyles.buttonSmall(context), - ), - const Spacer(), - ], - ), - ), - ), - ), - if (widget.enableExchange) - RawMaterialButton( - constraints: const BoxConstraints( - minWidth: 66, - ), - onPressed: widget.onExchangePressed, - splashColor: - Theme.of(context).extension()!.highlight, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular( - widget.height / 2.0, - ), - ), - child: Container( - color: Colors.transparent, - child: Padding( - padding: const EdgeInsets.symmetric(vertical: 2.0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - const Spacer(), - SvgPicture.asset( - Assets.svg.exchange(context), - width: 24, - height: 24, - ), - const SizedBox( - height: 4, - ), - Text( - "Exchange", - style: STextStyles.buttonSmall(context), - ), - const Spacer(), - ], - ), - ), - ), - ), - if (widget.coin.hasBuySupport) - RawMaterialButton( - constraints: const BoxConstraints( - minWidth: 66, - ), - onPressed: widget.onBuyPressed, - splashColor: - Theme.of(context).extension()!.highlight, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular( - widget.height / 2.0, - ), - ), - child: Container( - color: Colors.transparent, - child: Padding( - padding: const EdgeInsets.symmetric(vertical: 2.0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - const Spacer(), - SvgPicture.asset( - Assets.svg.buy(context), - width: 24, - height: 24, - ), - const SizedBox( - height: 4, - ), - Text( - "Buy", - style: STextStyles.buttonSmall(context), - ), - const Spacer(), - ], - ), - ), - ), - ), - if (showMore) - RawMaterialButton( - constraints: const BoxConstraints( - minWidth: 66, - ), - onPressed: () { - if (scale == 0) { - setState(() { - scale = 1; - }); - } else if (scale == 1) { - setState(() { - scale = 0; - }); - } - }, - splashColor: - Theme.of(context).extension()!.highlight, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular( - widget.height / 2.0, - ), - ), - child: Container( - color: Colors.transparent, - child: Padding( - padding: const EdgeInsets.symmetric(vertical: 2.0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - const Spacer(), - const SizedBox( - height: 2, - ), - SvgPicture.asset( - Assets.svg.bars, - width: 20, - height: 20, - color: Theme.of(context) - .extension()! - .bottomNavIconIcon, - ), - const SizedBox( - height: 6, - ), - Text( - "More", - style: STextStyles.buttonSmall(context), - ), - const Spacer(), - ], - ), - ), - ), - ), - const SizedBox( - width: 12, - ), - ], - ), - ), - ), - ], - ); - } -} diff --git a/lib/pages/wallet_view/wallet_view.dart b/lib/pages/wallet_view/wallet_view.dart index 28c77f30f..eaea818e9 100644 --- a/lib/pages/wallet_view/wallet_view.dart +++ b/lib/pages/wallet_view/wallet_view.dart @@ -5,23 +5,29 @@ 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:isar/isar.dart'; +import 'package:stackwallet/models/isar/exchange_cache/currency.dart'; import 'package:stackwallet/notifications/show_flush_bar.dart'; import 'package:stackwallet/pages/buy_view/buy_in_wallet_view.dart'; +import 'package:stackwallet/pages/coin_control/coin_control_view.dart'; import 'package:stackwallet/pages/exchange_view/wallet_initiated_exchange_view.dart'; import 'package:stackwallet/pages/home_view/home_view.dart'; import 'package:stackwallet/pages/notification_views/notifications_view.dart'; +import 'package:stackwallet/pages/paynym/paynym_claim_view.dart'; +import 'package:stackwallet/pages/paynym/paynym_home_view.dart'; import 'package:stackwallet/pages/receive_view/receive_view.dart'; import 'package:stackwallet/pages/send_view/send_view.dart'; import 'package:stackwallet/pages/settings_views/wallet_settings_view/wallet_network_settings_view/wallet_network_settings_view.dart'; import 'package:stackwallet/pages/settings_views/wallet_settings_view/wallet_settings_view.dart'; import 'package:stackwallet/pages/wallet_view/sub_widgets/transactions_list.dart'; -import 'package:stackwallet/pages/wallet_view/sub_widgets/wallet_navigation_bar.dart'; import 'package:stackwallet/pages/wallet_view/sub_widgets/wallet_summary.dart'; import 'package:stackwallet/pages/wallet_view/transaction_views/all_transactions_view.dart'; import 'package:stackwallet/providers/global/auto_swb_service_provider.dart'; +import 'package:stackwallet/providers/global/paynym_api_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/providers/wallet/my_paynym_account_state_provider.dart'; import 'package:stackwallet/providers/wallet/public_private_balance_state_provider.dart'; import 'package:stackwallet/providers/wallet/wallet_balance_toggle_state_provider.dart'; import 'package:stackwallet/services/coins/firo/firo_wallet.dart'; @@ -29,11 +35,15 @@ 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'; import 'package:stackwallet/services/event_bus/global_event_bus.dart'; +import 'package:stackwallet/services/exchange/exchange_data_loading_service.dart'; +import 'package:stackwallet/services/mixins/paynym_wallet_interface.dart'; import 'package:stackwallet/utilities/assets.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/derive_path_type_enum.dart'; import 'package:stackwallet/utilities/enums/wallet_balance_toggle_state.dart'; +import 'package:stackwallet/utilities/logger.dart'; import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/utilities/theme/stack_colors.dart'; import 'package:stackwallet/widgets/background.dart'; @@ -41,7 +51,16 @@ import 'package:stackwallet/widgets/conditional_parent.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/loading_indicator.dart'; import 'package:stackwallet/widgets/stack_dialog.dart'; +import 'package:stackwallet/widgets/wallet_navigation_bar/components/icons/buy_nav_icon.dart'; +import 'package:stackwallet/widgets/wallet_navigation_bar/components/icons/coin_control_nav_icon.dart'; +import 'package:stackwallet/widgets/wallet_navigation_bar/components/icons/exchange_nav_icon.dart'; +import 'package:stackwallet/widgets/wallet_navigation_bar/components/icons/paynym_nav_icon.dart'; +import 'package:stackwallet/widgets/wallet_navigation_bar/components/icons/receive_nav_icon.dart'; +import 'package:stackwallet/widgets/wallet_navigation_bar/components/icons/send_nav_icon.dart'; +import 'package:stackwallet/widgets/wallet_navigation_bar/components/wallet_navigation_bar_item.dart'; +import 'package:stackwallet/widgets/wallet_navigation_bar/wallet_navigation_bar.dart'; import 'package:tuple/tuple.dart'; /// [eventBus] should only be set during testing @@ -239,19 +258,14 @@ class _WalletViewState extends ConsumerState { } void _onExchangePressed(BuildContext context) async { - // too expensive - // unawaited(ExchangeDataLoadingService.instance.loadAll(ref)); - final coin = ref.read(managerProvider).coin; - if (coin == Coin.epicCash) { - await showDialog( - context: context, - builder: (_) => const StackOkDialog( - title: "Exchange not available for Epic Cash", - ), - ); - } else if (coin.name.endsWith("TestNet")) { + final currency = ExchangeDataLoadingService.instance.isar.currencies + .where() + .tickerEqualToAnyExchangeNameName(coin.ticker) + .findFirstSync(); + + if (coin.isTestNet) { await showDialog( context: context, builder: (_) => const StackOkDialog( @@ -259,41 +273,13 @@ class _WalletViewState extends ConsumerState { ), ); } else { - // ref.read(currentExchangeNameStateProvider.state).state = - // ChangeNowExchange.exchangeName; - // final walletId = ref.read(managerProvider).walletId; - // ref.read(prefsChangeNotifierProvider).exchangeRateType = - // ExchangeRateType.estimated; - // - // final currencies = ref - // .read(availableChangeNowCurrenciesProvider) - // .currencies - // .where((element) => - // element.ticker.toLowerCase() == coin.ticker.toLowerCase()); - // - // if (currencies.isNotEmpty) { - // ref - // .read(exchangeFormStateProvider(ExchangeRateType.estimated)) - // .setCurrencies( - // currencies.first, - // ref - // .read(availableChangeNowCurrenciesProvider) - // .currencies - // .firstWhere( - // (element) => - // element.ticker.toLowerCase() != - // coin.ticker.toLowerCase(), - // ), - // ); - // } - if (mounted) { unawaited( Navigator.of(context).pushNamed( WalletInitiatedExchangeView.routeName, arguments: Tuple2( walletId, - coin, + currency == null ? Coin.bitcoin : coin, ), ), ); @@ -301,6 +287,28 @@ class _WalletViewState extends ConsumerState { } } + void _onBuyPressed(BuildContext context) async { + final coin = ref.read(managerProvider).coin; + + if (coin.isTestNet) { + await showDialog( + context: context, + builder: (_) => const StackOkDialog( + title: "Buy not available for test net coins", + ), + ); + } else { + if (mounted) { + unawaited( + Navigator.of(context).pushNamed( + BuyInWalletView.routeName, + arguments: coin.hasBuySupport ? coin : Coin.bitcoin, + ), + ); + } + } + } + Future attemptAnonymize() async { bool shouldPop = false; unawaited( @@ -398,297 +406,303 @@ class _WalletViewState extends ConsumerState { child: WillPopScope( onWillPop: _onWillPop, child: Background( - child: Scaffold( - backgroundColor: - Theme.of(context).extension()!.background, - appBar: AppBar( - leading: AppBarBackButton( - onPressed: () { - _logout(); - Navigator.of(context).pop(); - }, - ), - titleSpacing: 0, - title: Row( - children: [ - SvgPicture.asset( - Assets.svg.iconFor(coin: coin), - // color: Theme.of(context).extension()!.accentColorDark - width: 24, - height: 24, + child: Stack( + children: [ + Scaffold( + backgroundColor: + Theme.of(context).extension()!.background, + appBar: AppBar( + leading: AppBarBackButton( + onPressed: () { + _logout(); + Navigator.of(context).pop(); + }, ), - const SizedBox( - width: 16, - ), - Expanded( - child: Text( - ref.watch( - managerProvider.select((value) => value.walletName)), - style: STextStyles.navBarTitle(context), - overflow: TextOverflow.ellipsis, - ), - ) - ], - ), - actions: [ - Padding( - padding: const EdgeInsets.only( - top: 10, - bottom: 10, - right: 10, - ), - child: AspectRatio( - aspectRatio: 1, - child: AppBarIconButton( - key: const Key("walletViewRadioButton"), - size: 36, - shadows: const [], - color: Theme.of(context) - .extension()! - .background, - icon: _buildNetworkIcon(_currentSyncStatus), - onPressed: () { - Navigator.of(context).pushNamed( - WalletNetworkSettingsView.routeName, - arguments: Tuple3( - walletId, - _currentSyncStatus, - _currentNodeStatus, - ), - ); - }, - ), - ), - ), - Padding( - padding: const EdgeInsets.only( - top: 10, - bottom: 10, - right: 10, - ), - child: AspectRatio( - aspectRatio: 1, - child: AppBarIconButton( - key: const Key("walletViewAlertsButton"), - size: 36, - shadows: const [], - color: Theme.of(context) - .extension()! - .background, - icon: SvgPicture.asset( - ref.watch(notificationsProvider.select((value) => - value.hasUnreadNotificationsFor(walletId))) - ? Assets.svg.bellNew(context) - : Assets.svg.bell, - width: 20, - height: 20, - color: ref.watch(notificationsProvider.select((value) => - value.hasUnreadNotificationsFor(walletId))) - ? null - : Theme.of(context) - .extension()! - .topNavIconPrimary, + titleSpacing: 0, + title: Row( + children: [ + SvgPicture.asset( + Assets.svg.iconFor(coin: coin), + // color: Theme.of(context).extension()!.accentColorDark + width: 24, + height: 24, ), - onPressed: () { - // reset unread state - ref.refresh(unreadNotificationsStateProvider); - - Navigator.of(context) - .pushNamed( - NotificationsView.routeName, - arguments: walletId, - ) - .then((_) { - final Set unreadNotificationIds = ref - .read(unreadNotificationsStateProvider.state) - .state; - if (unreadNotificationIds.isEmpty) return; - - List> futures = []; - for (int i = 0; - i < unreadNotificationIds.length - 1; - i++) { - futures.add(ref - .read(notificationsProvider) - .markAsRead( - unreadNotificationIds.elementAt(i), false)); - } - - // wait for multiple to update if any - Future.wait(futures).then((_) { - // only notify listeners once - ref - .read(notificationsProvider) - .markAsRead(unreadNotificationIds.last, true); - }); - }); - }, - ), - ), - ), - Padding( - padding: const EdgeInsets.only( - top: 10, - bottom: 10, - right: 10, - ), - child: AspectRatio( - aspectRatio: 1, - child: AppBarIconButton( - key: const Key("walletViewSettingsButton"), - size: 36, - shadows: const [], - color: Theme.of(context) - .extension()! - .background, - icon: SvgPicture.asset( - Assets.svg.bars, - color: Theme.of(context) - .extension()! - .accentColorDark, - width: 20, - height: 20, - ), - onPressed: () { - //todo: check if print needed - // debugPrint("wallet view settings tapped"); - Navigator.of(context).pushNamed( - WalletSettingsView.routeName, - arguments: Tuple4( - walletId, - ref.read(managerProvider).coin, - _currentSyncStatus, - _currentNodeStatus, - ), - ); - }, - ), - ), - ), - ], - ), - body: SafeArea( - child: Container( - color: Theme.of(context).extension()!.background, - child: Column( - children: [ - const SizedBox( - height: 10, - ), - Center( - child: Padding( - padding: const EdgeInsets.symmetric(horizontal: 16), - child: WalletSummary( - walletId: walletId, - managerProvider: managerProvider, - initialSyncStatus: ref.watch(managerProvider - .select((value) => value.isRefreshing)) - ? WalletSyncStatus.syncing - : WalletSyncStatus.synced, - ), - ), - ), - if (coin == Coin.firo) const SizedBox( - height: 10, + width: 16, ), - if (coin == Coin.firo) - Padding( - padding: const EdgeInsets.symmetric(horizontal: 16), - child: Row( - children: [ - Expanded( - child: TextButton( - style: Theme.of(context) - .extension()! - .getSecondaryEnabledButtonStyle(context), - onPressed: () async { - await showDialog( - 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(context) - .copyWith( - color: Theme.of(context) - .extension()! - .accentColorDark, - ), - ), - ), - rightButton: TextButton( - onPressed: () async { - Navigator.of(context).pop(); - - unawaited(attemptAnonymize()); - }, - style: Theme.of(context) - .extension()! - .getPrimaryEnabledButtonStyle( - context), - child: Text( - "Continue", - style: STextStyles.button(context), - ), - ), - ), - ); - }, - child: Text( - "Anonymize funds", - style: STextStyles.button(context).copyWith( - color: Theme.of(context) - .extension()! - .buttonTextSecondary, - ), - ), + Expanded( + child: Text( + ref.watch(managerProvider + .select((value) => value.walletName)), + style: STextStyles.navBarTitle(context), + overflow: TextOverflow.ellipsis, + ), + ) + ], + ), + actions: [ + Padding( + padding: const EdgeInsets.only( + top: 10, + bottom: 10, + right: 10, + ), + child: AspectRatio( + aspectRatio: 1, + child: AppBarIconButton( + key: const Key("walletViewRadioButton"), + size: 36, + shadows: const [], + color: Theme.of(context) + .extension()! + .background, + icon: _buildNetworkIcon(_currentSyncStatus), + onPressed: () { + Navigator.of(context).pushNamed( + WalletNetworkSettingsView.routeName, + arguments: Tuple3( + walletId, + _currentSyncStatus, + _currentNodeStatus, ), - ), - ], + ); + }, ), ), - const SizedBox( - height: 20, ), Padding( - padding: const EdgeInsets.symmetric(horizontal: 16), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - "Transactions", - style: STextStyles.itemSubtitle(context).copyWith( - color: Theme.of(context) - .extension()! - .textDark3, - ), + padding: const EdgeInsets.only( + top: 10, + bottom: 10, + right: 10, + ), + child: AspectRatio( + aspectRatio: 1, + child: AppBarIconButton( + key: const Key("walletViewAlertsButton"), + size: 36, + shadows: const [], + color: Theme.of(context) + .extension()! + .background, + icon: SvgPicture.asset( + ref.watch(notificationsProvider.select((value) => + value.hasUnreadNotificationsFor(walletId))) + ? Assets.svg.bellNew(context) + : Assets.svg.bell, + width: 20, + height: 20, + color: ref.watch(notificationsProvider.select( + (value) => value + .hasUnreadNotificationsFor(walletId))) + ? null + : Theme.of(context) + .extension()! + .topNavIconPrimary, ), - CustomTextButton( - text: "See all", - onTap: () { - Navigator.of(context).pushNamed( - AllTransactionsView.routeName, - arguments: walletId, - ); - }, - ), - ], + onPressed: () { + // reset unread state + ref.refresh(unreadNotificationsStateProvider); + + Navigator.of(context) + .pushNamed( + NotificationsView.routeName, + arguments: walletId, + ) + .then((_) { + final Set unreadNotificationIds = ref + .read(unreadNotificationsStateProvider.state) + .state; + if (unreadNotificationIds.isEmpty) return; + + List> futures = []; + for (int i = 0; + i < unreadNotificationIds.length - 1; + i++) { + futures.add(ref + .read(notificationsProvider) + .markAsRead( + unreadNotificationIds.elementAt(i), + false)); + } + + // wait for multiple to update if any + Future.wait(futures).then((_) { + // only notify listeners once + ref.read(notificationsProvider).markAsRead( + unreadNotificationIds.last, true); + }); + }); + }, + ), ), ), - const SizedBox( - height: 12, + Padding( + padding: const EdgeInsets.only( + top: 10, + bottom: 10, + right: 10, + ), + child: AspectRatio( + aspectRatio: 1, + child: AppBarIconButton( + key: const Key("walletViewSettingsButton"), + size: 36, + shadows: const [], + color: Theme.of(context) + .extension()! + .background, + icon: SvgPicture.asset( + Assets.svg.bars, + color: Theme.of(context) + .extension()! + .accentColorDark, + width: 20, + height: 20, + ), + onPressed: () { + //todo: check if print needed + // debugPrint("wallet view settings tapped"); + Navigator.of(context).pushNamed( + WalletSettingsView.routeName, + arguments: Tuple4( + walletId, + ref.read(managerProvider).coin, + _currentSyncStatus, + _currentNodeStatus, + ), + ); + }, + ), + ), ), - Expanded( - child: Stack( - children: [ + ], + ), + body: SafeArea( + child: Container( + color: + Theme.of(context).extension()!.background, + child: Column( + children: [ + const SizedBox( + height: 10, + ), + Center( + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 16), + child: WalletSummary( + walletId: walletId, + managerProvider: managerProvider, + initialSyncStatus: ref.watch(managerProvider + .select((value) => value.isRefreshing)) + ? WalletSyncStatus.syncing + : WalletSyncStatus.synced, + ), + ), + ), + 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( + style: Theme.of(context) + .extension()! + .getSecondaryEnabledButtonStyle( + context), + onPressed: () async { + await showDialog( + 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(context) + .copyWith( + color: Theme.of(context) + .extension()! + .accentColorDark, + ), + ), + ), + rightButton: TextButton( + onPressed: () async { + Navigator.of(context).pop(); + + unawaited(attemptAnonymize()); + }, + style: Theme.of(context) + .extension()! + .getPrimaryEnabledButtonStyle( + context), + child: Text( + "Continue", + style: + STextStyles.button(context), + ), + ), + ), + ); + }, + child: Text( + "Anonymize funds", + style: + STextStyles.button(context).copyWith( + color: Theme.of(context) + .extension()! + .buttonTextSecondary, + ), + ), + ), + ), + ], + ), + ), + const SizedBox( + height: 20, + ), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 16), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + "Transactions", + style: + STextStyles.itemSubtitle(context).copyWith( + color: Theme.of(context) + .extension()! + .textDark3, + ), + ), + CustomTextButton( + text: "See all", + onTap: () { + Navigator.of(context).pushNamed( + AllTransactionsView.routeName, + arguments: walletId, + ); + }, + ), + ], + ), + ), + const SizedBox( + height: 12, + ), + Expanded( + child: Padding( padding: const EdgeInsets.symmetric(horizontal: 16), child: ClipRRect( borderRadius: BorderRadius.vertical( @@ -741,98 +755,159 @@ class _WalletViewState extends ConsumerState { ), ), ), - Column( - mainAxisAlignment: MainAxisAlignment.end, - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Padding( - padding: const EdgeInsets.only( - bottom: 14, - left: 16, - right: 16, - ), - child: WalletNavigationBar( - walletId: widget.walletId, - coin: ref.watch(managerProvider - .select((value) => value.coin)), - enableExchange: - Constants.enableExchange && - ref.watch(managerProvider.select( - (value) => value.coin)) != - Coin.epicCash, - height: WalletView.navBarHeight, - onExchangePressed: () => - _onExchangePressed(context), - onReceivePressed: () async { - final coin = - ref.read(managerProvider).coin; - if (mounted) { - unawaited( - Navigator.of(context).pushNamed( - ReceiveView.routeName, - arguments: Tuple2( - walletId, - coin, - ), - )); - } - }, - onSendPressed: () { - final walletId = - 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( - walletId, - coin, - ), - ); - }, - onBuyPressed: () { - unawaited( - Navigator.of(context).pushNamed( - BuyInWalletView.routeName, - arguments: coin, - )); - }, - ), - ), - ], - ), - ], - ) - ], - ), + ), + ], ), - ], + ), ), ), - ), + WalletNavigationBar( + items: [ + WalletNavigationBarItemData( + label: "Receive", + icon: const ReceiveNavIcon(), + onTap: () { + final coin = ref.read(managerProvider).coin; + if (mounted) { + unawaited( + Navigator.of(context).pushNamed( + ReceiveView.routeName, + arguments: Tuple2( + walletId, + coin, + ), + ), + ); + } + }, + ), + WalletNavigationBarItemData( + label: "Send", + icon: const SendNavIcon(), + onTap: () { + final walletId = 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( + walletId, + coin, + ), + ); + }, + ), + if (Constants.enableExchange) + WalletNavigationBarItemData( + label: "Swap", + icon: const ExchangeNavIcon(), + onTap: () => _onExchangePressed(context), + ), + if (Constants.enableExchange) + WalletNavigationBarItemData( + label: "Buy", + icon: const BuyNavIcon(), + onTap: () => _onBuyPressed(context), + ), + ], + moreItems: [ + if (ref.watch( + walletsChangeNotifierProvider.select( + (value) => value + .getManager(widget.walletId) + .hasCoinControlSupport, + ), + ) && + ref.watch( + prefsChangeNotifierProvider.select( + (value) => value.enableCoinControl, + ), + )) + WalletNavigationBarItemData( + label: "Coin control", + icon: const CoinControlNavIcon(), + onTap: () { + Navigator.of(context).pushNamed( + CoinControlView.routeName, + arguments: Tuple2( + widget.walletId, + CoinControlViewType.manage, + ), + ); + }, + ), + if (ref.watch(walletsChangeNotifierProvider.select((value) => + value.getManager(widget.walletId).hasPaynymSupport))) + WalletNavigationBarItemData( + label: "PayNym", + icon: const PaynymNavIcon(), + onTap: () async { + unawaited( + showDialog( + context: context, + builder: (context) => const LoadingIndicator( + width: 100, + ), + ), + ); + + final manager = ref + .read(walletsChangeNotifierProvider) + .getManager(widget.walletId); + + final paynymInterface = + manager.wallet as PaynymWalletInterface; + + final code = await paynymInterface.getPaymentCode( + DerivePathTypeExt.primaryFor(manager.coin)); + + final account = await ref + .read(paynymAPIProvider) + .nym(code.toString()); + + Logging.instance.log( + "my nym account: $account", + level: LogLevel.Info, + ); + + if (mounted) { + Navigator.of(context).pop(); + + // check if account exists and for matching code to see if claimed + if (account.value != null && + account.value!.codes.first.claimed) { + ref.read(myPaynymAccountStateProvider.state).state = + account.value!; + + await Navigator.of(context).pushNamed( + PaynymHomeView.routeName, + arguments: widget.walletId, + ); + } else { + await Navigator.of(context).pushNamed( + PaynymClaimView.routeName, + arguments: widget.walletId, + ); + } + } + }, + ), + ], + ), + ], ), ), ), diff --git a/lib/pages/wallets_view/sub_widgets/empty_wallets.dart b/lib/pages/wallets_view/sub_widgets/empty_wallets.dart index 76770ccf7..4db5ce741 100644 --- a/lib/pages/wallets_view/sub_widgets/empty_wallets.dart +++ b/lib/pages/wallets_view/sub_widgets/empty_wallets.dart @@ -38,21 +38,10 @@ class EmptyWallets extends ConsumerWidget { const Spacer( flex: 2, ), - (isSorbet || isForest || isOcean) - ? SvgPicture.asset( - Assets.svg.stack(context), - width: isDesktop - ? 324 - : MediaQuery.of(context).size.width / 3, - ) - : Image( - image: AssetImage( - Assets.png.stack(context), - ), - width: isDesktop - ? 324 - : MediaQuery.of(context).size.width / 3, - ), + SvgPicture.asset( + Assets.svg.stack(context), + width: isDesktop ? 324 : MediaQuery.of(context).size.width / 3, + ), SizedBox( height: isDesktop ? 30 : 16, ), diff --git a/lib/pages_desktop_specific/desktop_exchange/desktop_exchange_view.dart b/lib/pages_desktop_specific/desktop_exchange/desktop_exchange_view.dart index 39680fab0..e45f2d234 100644 --- a/lib/pages_desktop_specific/desktop_exchange/desktop_exchange_view.dart +++ b/lib/pages_desktop_specific/desktop_exchange/desktop_exchange_view.dart @@ -95,7 +95,7 @@ class _DesktopExchangeViewState extends ConsumerState { left: 24, ), child: Text( - "Exchange", + "Swap", style: STextStyles.desktopH3(context), ), ), diff --git a/lib/pages_desktop_specific/desktop_exchange/exchange_steps/subwidgets/desktop_step_1.dart b/lib/pages_desktop_specific/desktop_exchange/exchange_steps/subwidgets/desktop_step_1.dart index b57fb1899..16c3b8116 100644 --- a/lib/pages_desktop_specific/desktop_exchange/exchange_steps/subwidgets/desktop_step_1.dart +++ b/lib/pages_desktop_specific/desktop_exchange/exchange_steps/subwidgets/desktop_step_1.dart @@ -37,7 +37,7 @@ class DesktopStep1 extends ConsumerWidget { child: Column( children: [ DesktopStepItem( - label: "Exchange", + label: "Swap", value: ref.watch(exchangeFormStateProvider .select((value) => value.exchange.name)), ), diff --git a/lib/pages_desktop_specific/desktop_exchange/exchange_steps/subwidgets/desktop_step_3.dart b/lib/pages_desktop_specific/desktop_exchange/exchange_steps/subwidgets/desktop_step_3.dart index aeb8ece54..ef72553fa 100644 --- a/lib/pages_desktop_specific/desktop_exchange/exchange_steps/subwidgets/desktop_step_3.dart +++ b/lib/pages_desktop_specific/desktop_exchange/exchange_steps/subwidgets/desktop_step_3.dart @@ -35,7 +35,7 @@ class _DesktopStep3State extends ConsumerState { child: Column( children: [ DesktopStepItem( - label: "Exchange", + label: "Swap", value: ref.watch(exchangeFormStateProvider .select((value) => value.exchange.name)), ), diff --git a/lib/pages_desktop_specific/desktop_menu.dart b/lib/pages_desktop_specific/desktop_menu.dart index b705a33be..8db3f3425 100644 --- a/lib/pages_desktop_specific/desktop_menu.dart +++ b/lib/pages_desktop_specific/desktop_menu.dart @@ -153,7 +153,7 @@ class _DesktopMenuState extends ConsumerState { DesktopMenuItem( duration: duration, icon: const DesktopExchangeIcon(), - label: "Exchange", + label: "Swap", value: DesktopMenuItemId.exchange, onChanged: updateSelectedMenuItem, controller: controllers[1], diff --git a/lib/pages_desktop_specific/my_stack_view/wallet_view/desktop_wallet_view.dart b/lib/pages_desktop_specific/my_stack_view/wallet_view/desktop_wallet_view.dart index 2e5087c4a..ec3b1b3ec 100644 --- a/lib/pages_desktop_specific/my_stack_view/wallet_view/desktop_wallet_view.dart +++ b/lib/pages_desktop_specific/my_stack_view/wallet_view/desktop_wallet_view.dart @@ -504,7 +504,7 @@ class _DesktopWalletViewState extends ConsumerState { // onPressed: () { // _onExchangePressed(context); // }, - // label: "Exchange", + // label: "Swap", // icon: Container( // width: 24, // height: 24, diff --git a/lib/utilities/constants.dart b/lib/utilities/constants.dart index 2d600b69f..19516c5b9 100644 --- a/lib/utilities/constants.dart +++ b/lib/utilities/constants.dart @@ -21,8 +21,9 @@ abstract class Constants { } static bool enableExchange = Util.isDesktop || !Platform.isIOS; - static bool enableBuy = - true; // true for development, TODO change to "Util.isDesktop || !Platform.isIOS;" as above or even just = enableExchange + // just use enable exchange flag + // static bool enableBuy = enableExchange; + // // true; // true for development, //TODO: correct for monero? static const int _satsPerCoinMonero = 1000000000000; diff --git a/lib/utilities/enums/coin_enum.dart b/lib/utilities/enums/coin_enum.dart index b8b1fed13..0e8a010ab 100644 --- a/lib/utilities/enums/coin_enum.dart +++ b/lib/utilities/enums/coin_enum.dart @@ -195,6 +195,29 @@ extension CoinExt on Coin { } } + bool get isTestNet { + switch (this) { + case Coin.bitcoin: + case Coin.litecoin: + case Coin.bitcoincash: + case Coin.dogecoin: + case Coin.firo: + case Coin.namecoin: + case Coin.particl: + case Coin.epicCash: + case Coin.monero: + case Coin.wownero: + return false; + + case Coin.dogecoinTestNet: + case Coin.bitcoinTestNet: + case Coin.litecoinTestNet: + case Coin.bitcoincashTestnet: + case Coin.firoTestNet: + return true; + } + } + int get requiredConfirmations { switch (this) { case Coin.bitcoin: diff --git a/lib/widgets/wallet_navigation_bar/components/icons/buy_nav_icon.dart b/lib/widgets/wallet_navigation_bar/components/icons/buy_nav_icon.dart new file mode 100644 index 000000000..fa2975f1a --- /dev/null +++ b/lib/widgets/wallet_navigation_bar/components/icons/buy_nav_icon.dart @@ -0,0 +1,16 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_svg/flutter_svg.dart'; +import 'package:stackwallet/utilities/assets.dart'; + +class BuyNavIcon extends StatelessWidget { + const BuyNavIcon({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return SvgPicture.asset( + Assets.svg.buy(context), + width: 24, + height: 24, + ); + } +} diff --git a/lib/widgets/wallet_navigation_bar/components/icons/coin_control_nav_icon.dart b/lib/widgets/wallet_navigation_bar/components/icons/coin_control_nav_icon.dart new file mode 100644 index 000000000..d55cd463f --- /dev/null +++ b/lib/widgets/wallet_navigation_bar/components/icons/coin_control_nav_icon.dart @@ -0,0 +1,18 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_svg/flutter_svg.dart'; +import 'package:stackwallet/utilities/assets.dart'; +import 'package:stackwallet/utilities/theme/stack_colors.dart'; + +class CoinControlNavIcon extends StatelessWidget { + const CoinControlNavIcon({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return SvgPicture.asset( + Assets.svg.coinControl.gamePad, + height: 20, + width: 20, + color: Theme.of(context).extension()!.bottomNavIconIcon, + ); + } +} diff --git a/lib/widgets/wallet_navigation_bar/components/icons/exchange_nav_icon.dart b/lib/widgets/wallet_navigation_bar/components/icons/exchange_nav_icon.dart new file mode 100644 index 000000000..9735fa989 --- /dev/null +++ b/lib/widgets/wallet_navigation_bar/components/icons/exchange_nav_icon.dart @@ -0,0 +1,16 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_svg/flutter_svg.dart'; +import 'package:stackwallet/utilities/assets.dart'; + +class ExchangeNavIcon extends StatelessWidget { + const ExchangeNavIcon({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return SvgPicture.asset( + Assets.svg.exchange(context), + width: 24, + height: 24, + ); + } +} diff --git a/lib/widgets/wallet_navigation_bar/components/icons/paynym_nav_icon.dart b/lib/widgets/wallet_navigation_bar/components/icons/paynym_nav_icon.dart new file mode 100644 index 000000000..26a2fd96d --- /dev/null +++ b/lib/widgets/wallet_navigation_bar/components/icons/paynym_nav_icon.dart @@ -0,0 +1,18 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_svg/flutter_svg.dart'; +import 'package:stackwallet/utilities/assets.dart'; +import 'package:stackwallet/utilities/theme/stack_colors.dart'; + +class PaynymNavIcon extends StatelessWidget { + const PaynymNavIcon({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return SvgPicture.asset( + Assets.svg.robotHead, + height: 20, + width: 20, + color: Theme.of(context).extension()!.bottomNavIconIcon, + ); + } +} diff --git a/lib/widgets/wallet_navigation_bar/components/icons/receive_nav_icon.dart b/lib/widgets/wallet_navigation_bar/components/icons/receive_nav_icon.dart new file mode 100644 index 000000000..54420543f --- /dev/null +++ b/lib/widgets/wallet_navigation_bar/components/icons/receive_nav_icon.dart @@ -0,0 +1,32 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_svg/flutter_svg.dart'; +import 'package:stackwallet/utilities/assets.dart'; +import 'package:stackwallet/utilities/theme/stack_colors.dart'; + +class ReceiveNavIcon extends StatelessWidget { + const ReceiveNavIcon({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return Container( + decoration: BoxDecoration( + color: Theme.of(context) + .extension()! + .accentColorDark + .withOpacity(0.4), + borderRadius: BorderRadius.circular( + 24, + ), + ), + child: Padding( + padding: const EdgeInsets.all(6.0), + child: SvgPicture.asset( + Assets.svg.arrowDownLeft, + width: 12, + height: 12, + color: Theme.of(context).extension()!.accentColorDark, + ), + ), + ); + } +} diff --git a/lib/widgets/wallet_navigation_bar/components/icons/send_nav_icon.dart b/lib/widgets/wallet_navigation_bar/components/icons/send_nav_icon.dart new file mode 100644 index 000000000..7b7da5799 --- /dev/null +++ b/lib/widgets/wallet_navigation_bar/components/icons/send_nav_icon.dart @@ -0,0 +1,32 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_svg/flutter_svg.dart'; +import 'package:stackwallet/utilities/assets.dart'; +import 'package:stackwallet/utilities/theme/stack_colors.dart'; + +class SendNavIcon extends StatelessWidget { + const SendNavIcon({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return Container( + decoration: BoxDecoration( + color: Theme.of(context) + .extension()! + .accentColorDark + .withOpacity(0.4), + borderRadius: BorderRadius.circular( + 24, + ), + ), + child: Padding( + padding: const EdgeInsets.all(6.0), + child: SvgPicture.asset( + Assets.svg.arrowUpRight, + width: 12, + height: 12, + color: Theme.of(context).extension()!.accentColorDark, + ), + ), + ); + } +} diff --git a/lib/widgets/wallet_navigation_bar/components/icons/whirlpool_nav_icon.dart b/lib/widgets/wallet_navigation_bar/components/icons/whirlpool_nav_icon.dart new file mode 100644 index 000000000..bc7b0f399 --- /dev/null +++ b/lib/widgets/wallet_navigation_bar/components/icons/whirlpool_nav_icon.dart @@ -0,0 +1,18 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_svg/flutter_svg.dart'; +import 'package:stackwallet/utilities/assets.dart'; +import 'package:stackwallet/utilities/theme/stack_colors.dart'; + +class WhirlpoolNavIcon extends StatelessWidget { + const WhirlpoolNavIcon({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return SvgPicture.asset( + Assets.svg.whirlPool, + height: 20, + width: 20, + color: Theme.of(context).extension()!.bottomNavIconIcon, + ); + } +} diff --git a/lib/widgets/wallet_navigation_bar/components/wallet_navigation_bar_item.dart b/lib/widgets/wallet_navigation_bar/components/wallet_navigation_bar_item.dart new file mode 100644 index 000000000..8f1cade50 --- /dev/null +++ b/lib/widgets/wallet_navigation_bar/components/wallet_navigation_bar_item.dart @@ -0,0 +1,125 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:stackwallet/utilities/text_styles.dart'; +import 'package:stackwallet/utilities/theme/stack_colors.dart'; +import 'package:stackwallet/widgets/rounded_container.dart'; +import 'package:stackwallet/widgets/wallet_navigation_bar/wallet_navigation_bar.dart'; + +class WalletNavigationBarItemData { + WalletNavigationBarItemData({ + required this.icon, + required this.label, + required this.onTap, + this.isMore = false, + this.overrideText, + }); + + final Widget icon; + final String? label; + final VoidCallback? onTap; + final bool isMore; + final Widget? overrideText; +} + +class WalletNavigationBarItem extends ConsumerWidget { + const WalletNavigationBarItem({ + Key? key, + required this.data, + required this.disableDuration, + }) : super(key: key); + + final WalletNavigationBarItemData data; + final Duration disableDuration; + + @override + Widget build(BuildContext context, WidgetRef ref) { + return GestureDetector( + onTap: data.isMore || !ref.watch(walletNavBarMore.state).state + ? data.onTap + : null, + child: RoundedContainer( + color: Colors.transparent, + padding: const EdgeInsets.all(0), + radiusMultiplier: 2, + child: AnimatedOpacity( + opacity: + data.isMore || !ref.watch(walletNavBarMore.state).state ? 1 : 0.2, + duration: disableDuration, + child: Padding( + padding: const EdgeInsets.symmetric(vertical: 8.0), + child: ConstrainedBox( + constraints: const BoxConstraints( + maxHeight: 45, + ), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + SizedBox( + width: 24, + height: 24, + child: Center( + child: data.icon, + ), + ), + const Spacer(), + data.overrideText ?? + Text( + data.label ?? "", + style: STextStyles.buttonSmall(context), + ), + ], + ), + ), + ), + ), + ), + ); + } +} + +class WalletNavigationBarMoreItem extends ConsumerWidget { + const WalletNavigationBarMoreItem({ + Key? key, + required this.data, + }) : super(key: key); + + final WalletNavigationBarItemData data; + + @override + Widget build(BuildContext context, WidgetRef ref) { + return GestureDetector( + onTap: () { + data.onTap?.call(); + ref.read(walletNavBarMore.state).state = false; + }, + child: Material( + color: Colors.transparent, + child: RoundedContainer( + color: Theme.of(context).extension()!.bottomNavBack, + radiusMultiplier: 100, + padding: const EdgeInsets.symmetric( + vertical: 16, + horizontal: 30, + ), + child: Row( + children: [ + Expanded( + child: Text( + data.label ?? "", + textAlign: TextAlign.center, + style: STextStyles.buttonSmall(context), + ), + ), + const SizedBox( + width: 10, + ), + data.icon, + ], + ), + ), + ), + ); + } +} diff --git a/lib/widgets/wallet_navigation_bar/wallet_navigation_bar.dart b/lib/widgets/wallet_navigation_bar/wallet_navigation_bar.dart new file mode 100644 index 000000000..31e796eb9 --- /dev/null +++ b/lib/widgets/wallet_navigation_bar/wallet_navigation_bar.dart @@ -0,0 +1,231 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:flutter_svg/svg.dart'; +import 'package:stackwallet/utilities/assets.dart'; +import 'package:stackwallet/utilities/text_styles.dart'; +import 'package:stackwallet/utilities/theme/stack_colors.dart'; +import 'package:stackwallet/widgets/conditional_parent.dart'; +import 'package:stackwallet/widgets/wallet_navigation_bar/components/wallet_navigation_bar_item.dart'; + +final walletNavBarMore = StateProvider.autoDispose((ref) => false); + +class WalletNavigationBar extends ConsumerStatefulWidget { + const WalletNavigationBar({ + Key? key, + required this.items, + required this.moreItems, + }) : super(key: key); + + final List items; + final List moreItems; + + @override + ConsumerState createState() => + _WalletNavigationBarState(); +} + +class _WalletNavigationBarState extends ConsumerState { + static const double horizontalPadding = 16; + + final _moreDuration = const Duration(milliseconds: 200); + + void _onMorePressed() { + ref.read(walletNavBarMore.state).state = + !ref.read(walletNavBarMore.state).state; + } + + @override + Widget build(BuildContext context) { + final width = MediaQuery.of(context).size.width - 40; + + final hasMore = widget.moreItems.isNotEmpty; + final buttonCount = widget.items.length + (hasMore ? 1 : 0); + + return Stack( + alignment: Alignment.bottomCenter, + children: [ + IgnorePointer( + ignoring: !ref.read(walletNavBarMore.state).state, + child: GestureDetector( + onTap: () { + if (ref.read(walletNavBarMore.state).state) { + ref.read(walletNavBarMore.state).state = false; + } + }, + child: AnimatedOpacity( + opacity: ref.watch(walletNavBarMore.state).state ? 1 : 0, + duration: _moreDuration, + child: Container( + color: Colors.black.withOpacity(0.7), + ), + ), + ), + ), + Padding( + padding: const EdgeInsets.only( + left: horizontalPadding, + right: horizontalPadding, + bottom: horizontalPadding, + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Column( + crossAxisAlignment: CrossAxisAlignment.end, + mainAxisSize: MainAxisSize.min, + children: [ + AnimatedScale( + scale: ref.watch(walletNavBarMore.state).state ? 1 : 0, + duration: _moreDuration, + alignment: const Alignment( + 0.5, + 1.0, + ), + child: AnimatedOpacity( + opacity: ref.watch(walletNavBarMore.state).state ? 1 : 0, + duration: _moreDuration, + child: IntrinsicWidth( + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + mainAxisSize: MainAxisSize.min, + children: [ + ...widget.moreItems.map( + (e) { + return Column( + children: [ + WalletNavigationBarMoreItem(data: e), + const SizedBox( + height: 8, + ), + ], + ); + }, + ), + ], + ), + ), + ), + ), + Material( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular( + 1000, + ), + ), + child: Container( + decoration: BoxDecoration( + color: Theme.of(context) + .extension()! + .bottomNavBack, + boxShadow: [ + Theme.of(context) + .extension()! + .standardBoxShadow + ], + borderRadius: BorderRadius.circular( + 1000, + ), + ), + child: Padding( + padding: const EdgeInsets.symmetric( + vertical: 6, + horizontal: 20, + ), + // child: IntrinsicWidth( + child: ConditionalParent( + condition: buttonCount > 4, + builder: (child) => SizedBox( + width: width * 0.9, + child: child, + ), + child: ConditionalParent( + condition: buttonCount <= 4, + builder: (child) => SizedBox( + width: width * 0.2 * buttonCount, + child: child, + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + ...widget.items.map( + (e) => Expanded( + child: WalletNavigationBarItem( + data: e, + disableDuration: _moreDuration, + ), + ), + ), + if (hasMore) + Expanded( + child: WalletNavigationBarItem( + data: WalletNavigationBarItemData( + icon: AnimatedCrossFade( + firstChild: SvgPicture.asset( + Assets.svg.bars, + width: 20, + height: 20, + color: Theme.of(context) + .extension()! + .bottomNavIconIcon, + ), + secondChild: SvgPicture.asset( + Assets.svg.bars, + width: 20, + height: 20, + color: Theme.of(context) + .extension()! + .infoItemIcons, + ), + crossFadeState: ref + .watch(walletNavBarMore.state) + .state + ? CrossFadeState.showSecond + : CrossFadeState.showFirst, + duration: _moreDuration, + ), + overrideText: AnimatedCrossFade( + firstChild: Text( + "More", + style: STextStyles.buttonSmall( + context), + ), + secondChild: Text( + "More", + style: + STextStyles.buttonSmall(context) + .copyWith( + color: Theme.of(context) + .extension()! + .infoItemIcons, + ), + ), + crossFadeState: ref + .watch(walletNavBarMore.state) + .state + ? CrossFadeState.showSecond + : CrossFadeState.showFirst, + duration: _moreDuration, + ), + label: null, + isMore: true, + onTap: _onMorePressed, + ), + disableDuration: _moreDuration, + ), + ), + ], + ), + ), + ), + ), + ), + ), + ], + ), + ], + ), + ), + ], + ); + } +}