diff --git a/lib/pages/address_book_views/subviews/add_address_book_entry_view.dart b/lib/pages/address_book_views/subviews/add_address_book_entry_view.dart index a28997e0f..4fa89908c 100644 --- a/lib/pages/address_book_views/subviews/add_address_book_entry_view.dart +++ b/lib/pages/address_book_views/subviews/add_address_book_entry_view.dart @@ -16,6 +16,7 @@ import 'package:stackwallet/utilities/constants.dart'; import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/utilities/theme/stack_colors.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/emoji_select_sheet.dart'; import 'package:stackwallet/widgets/icon_widgets/x_icon.dart'; import 'package:stackwallet/widgets/stack_text_field.dart'; @@ -73,10 +74,23 @@ class _AddAddressBookEntryViewState } List<NewContactAddressEntryForm> forms = []; - int _formCount = 0; + final Set<int> _formIds = {}; + + void _removeForm(int id) { + forms.retainWhere((e) => e.id != id); + _formIds.remove(id); + ref.refresh(addressEntryDataProvider(id)); + setState(() {}); + } void _addForm() { - int id = ++_formCount; + int id = 0; + // ensure unique form id while allowing reuse of removed form ids + while (_formIds.contains(id)) { + id++; + } + _formIds.add(id); + forms.add( NewContactAddressEntryForm( key: Key("contactAddressEntryForm_$id"), @@ -303,22 +317,34 @@ class _AddAddressBookEntryViewState }, ), ), - if (_formCount <= 1) + if (forms.length <= 1) const SizedBox( height: 8, ), - if (_formCount <= 1) forms[0], - if (_formCount > 1) - for (int i = 0; i < _formCount; i++) + if (forms.length <= 1) forms[0], + if (forms.length > 1) + for (int i = 0; i < forms.length; i++) Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const SizedBox( height: 12, ), - Text( - "Address ${i + 1}", - style: STextStyles.smallMed12(context), + Row( + mainAxisAlignment: + MainAxisAlignment.spaceBetween, + children: [ + Text( + "Address ${i + 1}", + style: STextStyles.smallMed12(context), + ), + BlueTextButton( + onTap: () { + _removeForm(forms[i].id); + }, + text: "Remove", + ), + ], ), const SizedBox( height: 8, @@ -329,7 +355,7 @@ class _AddAddressBookEntryViewState const SizedBox( height: 16, ), - GestureDetector( + BlueTextButton( onTap: () { _addForm(); scrollController.animateTo( @@ -338,11 +364,15 @@ class _AddAddressBookEntryViewState curve: Curves.easeInOut, ); }, - child: Text( - "+ Add another address", - style: STextStyles.largeMedium14(context), - ), + text: "+ Add another address", ), + // GestureDetector( + // + // child: Text( + // "+ Add another address", + // style: STextStyles.largeMedium14(context), + // ), + // ), const SizedBox( height: 16, ), @@ -411,10 +441,12 @@ class _AddAddressBookEntryViewState } List<ContactAddressEntry> entries = []; - for (int i = 0; i < _formCount; i++) { + for (int i = 0; + i < forms.length; + i++) { entries.add(ref .read(addressEntryDataProvider( - i + 1)) + forms[i].id)) .buildAddressEntry()); } Contact contact = Contact( @@ -438,7 +470,15 @@ class _AddAddressBookEntryViewState : null, child: Text( "Save", - style: STextStyles.button(context), + style: STextStyles.button(context).copyWith( + color: shouldEnableSave + ? Theme.of(context) + .extension<StackColors>()! + .buttonTextPrimary + : Theme.of(context) + .extension<StackColors>()! + .buttonTextPrimaryDisabled, + ), ), ); }, diff --git a/lib/pages/send_view/confirm_transaction_view.dart b/lib/pages/send_view/confirm_transaction_view.dart index fff346ee7..65537f20e 100644 --- a/lib/pages/send_view/confirm_transaction_view.dart +++ b/lib/pages/send_view/confirm_transaction_view.dart @@ -144,6 +144,7 @@ class _ConfirmTransactionViewState final managerProvider = ref.watch(walletsChangeNotifierProvider .select((value) => value.getManagerProvider(walletId))); return Scaffold( + backgroundColor: Theme.of(context).extension<StackColors>()!.background, appBar: AppBar( backgroundColor: Theme.of(context).extension<StackColors>()!.background, leading: AppBarBackButton( @@ -294,7 +295,12 @@ class _ConfirmTransactionViewState children: [ Text( "Total amount", - style: STextStyles.titleBold12(context), + style: + STextStyles.titleBold12(context).copyWith( + color: Theme.of(context) + .extension<StackColors>()! + .textConfirmTotalAmount, + ), ), Text( "${Format.satoshiAmountToPrettyString( @@ -308,7 +314,12 @@ class _ConfirmTransactionViewState managerProvider .select((value) => value.coin), ).ticker}", - style: STextStyles.itemSubtitle12(context), + style: STextStyles.itemSubtitle12(context) + .copyWith( + color: Theme.of(context) + .extension<StackColors>()! + .textConfirmTotalAmount, + ), textAlign: TextAlign.right, ), ], diff --git a/lib/pages/send_view/send_view.dart b/lib/pages/send_view/send_view.dart index ee9644c2a..f87252291 100644 --- a/lib/pages/send_view/send_view.dart +++ b/lib/pages/send_view/send_view.dart @@ -1060,6 +1060,11 @@ class _SendViewState extends ConsumerState<SendView> { height: 8, ), TextField( + style: STextStyles.smallMed14(context).copyWith( + color: Theme.of(context) + .extension<StackColors>()! + .textDark, + ), key: const Key("amountInputFieldCryptoTextFieldKey"), controller: cryptoAmountController, focusNode: _cryptoFocus, @@ -1106,6 +1111,11 @@ class _SendViewState extends ConsumerState<SendView> { height: 8, ), TextField( + style: STextStyles.smallMed14(context).copyWith( + color: Theme.of(context) + .extension<StackColors>()! + .textDark, + ), key: const Key("amountInputFieldFiatTextFieldKey"), controller: baseAmountController, focusNode: _baseFocus, diff --git a/lib/pages/wallet_view/sub_widgets/wallet_navigation_bar.dart b/lib/pages/wallet_view/sub_widgets/wallet_navigation_bar.dart index b82992673..04147c883 100644 --- a/lib/pages/wallet_view/sub_widgets/wallet_navigation_bar.dart +++ b/lib/pages/wallet_view/sub_widgets/wallet_navigation_bar.dart @@ -27,7 +27,7 @@ class WalletNavigationBar extends StatelessWidget { return Container( height: height, decoration: BoxDecoration( - color: Theme.of(context).extension<StackColors>()!.popupBG, + color: Theme.of(context).extension<StackColors>()!.bottomNavBack, boxShadow: [ Theme.of(context).extension<StackColors>()!.standardBoxShadow ], diff --git a/lib/services/coins/firo/firo_wallet.dart b/lib/services/coins/firo/firo_wallet.dart index a88f37996..aafa5e6f2 100644 --- a/lib/services/coins/firo/firo_wallet.dart +++ b/lib/services/coins/firo/firo_wallet.dart @@ -623,6 +623,7 @@ Future<dynamic> isolateCreateJoinSplitTransaction( "value": amount, "fees": Format.satoshisToAmount(fee).toDouble(), "fee": fee, + "vSize": extTx.virtualSize(), "jmintValue": changeToMint, "publicCoin": "jmintData.publicCoin", "spendCoinIndexes": spendCoinIndexes, @@ -1142,6 +1143,17 @@ class FiroWallet extends CoinServiceAPI { throw Exception("Error Creating Transaction!"); } } else { + final fee = txHexOrError["fee"] as int; + final vSize = txHexOrError["vSize"] as int; + + Logging.instance.log("prepared fee: $fee", level: LogLevel.Info); + Logging.instance.log("prepared vSize: $vSize", level: LogLevel.Info); + + // fee should never be less than vSize sanity check + if (fee < vSize) { + throw Exception( + "Error in fee calculation: Transaction fee cannot be less than vSize"); + } return txHexOrError as Map<String, dynamic>; } } catch (e, s) { diff --git a/lib/services/wallets_service.dart b/lib/services/wallets_service.dart index b978f1edc..0700950a4 100644 --- a/lib/services/wallets_service.dart +++ b/lib/services/wallets_service.dart @@ -294,6 +294,10 @@ class WalletsService extends ChangeNotifier { key: "${walletId}_mnemonicHasBeenVerified") as bool?; if (isVerified == null) { + Logging.instance.log( + "isMnemonicVerified(walletId: $walletId) returned null which should never happen!", + level: LogLevel.Error, + ); throw Exception( "isMnemonicVerified(walletId: $walletId) returned null which should never happen!"); } else { @@ -307,9 +311,17 @@ class WalletsService extends ChangeNotifier { key: "${walletId}_mnemonicHasBeenVerified") as bool?; if (isVerified == null) { + Logging.instance.log( + "setMnemonicVerified(walletId: $walletId) tried running on non existent wallet!", + level: LogLevel.Error, + ); throw Exception( "setMnemonicVerified(walletId: $walletId) tried running on non existent wallet!"); } else if (isVerified) { + Logging.instance.log( + "setMnemonicVerified(walletId: $walletId) tried running on already verified wallet!", + level: LogLevel.Error, + ); throw Exception( "setMnemonicVerified(walletId: $walletId) tried running on already verified wallet!"); } else { @@ -317,6 +329,10 @@ class WalletsService extends ChangeNotifier { boxName: DB.boxNameAllWalletsData, key: "${walletId}_mnemonicHasBeenVerified", value: true); + Logging.instance.log( + "setMnemonicVerified(walletId: $walletId) successful", + level: LogLevel.Error, + ); } } @@ -331,6 +347,11 @@ class WalletsService extends ChangeNotifier { return 3; } + Logging.instance.log( + "deleteWallet called with name=$name and id=$walletId", + level: LogLevel.Warning, + ); + final shell = names.remove(walletId); if (shell == null) { diff --git a/lib/utilities/theme/color_theme.dart b/lib/utilities/theme/color_theme.dart index 73da6ba66..d30499f81 100644 --- a/lib/utilities/theme/color_theme.dart +++ b/lib/utilities/theme/color_theme.dart @@ -173,6 +173,7 @@ abstract class StackColorTheme { Color get loadingOverlayTextColor; Color get myStackContactIconBG; + Color get textConfirmTotalAmount; } class CoinThemeColor { diff --git a/lib/utilities/theme/dark_colors.dart b/lib/utilities/theme/dark_colors.dart index ee7551a27..b28880da8 100644 --- a/lib/utilities/theme/dark_colors.dart +++ b/lib/utilities/theme/dark_colors.dart @@ -70,7 +70,7 @@ class DarkColors extends StackColorTheme { @override Color get numpadBackDefault => const Color(0xFF4C86E9); @override - Color get bottomNavBack => const Color(0xFFA2A2A2); + Color get bottomNavBack => const Color(0xFF3E4148); // button text/element @override @@ -299,4 +299,6 @@ class DarkColors extends StackColorTheme { Color get loadingOverlayTextColor => const Color(0xFFF7F7F7); @override Color get myStackContactIconBG => const Color(0x88747778); + @override + Color get textConfirmTotalAmount => const Color(0xFF003921); } diff --git a/lib/utilities/theme/light_colors.dart b/lib/utilities/theme/light_colors.dart index 994a876d8..4c7ac7ab4 100644 --- a/lib/utilities/theme/light_colors.dart +++ b/lib/utilities/theme/light_colors.dart @@ -70,7 +70,7 @@ class LightColors extends StackColorTheme { @override Color get numpadBackDefault => const Color(0xFF232323); @override - Color get bottomNavBack => const Color(0xFFA2A2A2); + Color get bottomNavBack => const Color(0xFFFFFFFF); // button text/element @override @@ -299,4 +299,6 @@ class LightColors extends StackColorTheme { Color get loadingOverlayTextColor => const Color(0xFFF7F7F7); @override Color get myStackContactIconBG => textFieldDefaultBG; + @override + Color get textConfirmTotalAmount => const Color(0xFF232323); } diff --git a/lib/utilities/theme/stack_colors.dart b/lib/utilities/theme/stack_colors.dart index b14f710c8..16cc70c93 100644 --- a/lib/utilities/theme/stack_colors.dart +++ b/lib/utilities/theme/stack_colors.dart @@ -168,6 +168,7 @@ class StackColors extends ThemeExtension<StackColors> { final Color warningBackground; final Color loadingOverlayTextColor; final Color myStackContactIconBG; + final Color textConfirmTotalAmount; StackColors({ required this.themeType, @@ -298,6 +299,7 @@ class StackColors extends ThemeExtension<StackColors> { required this.warningBackground, required this.loadingOverlayTextColor, required this.myStackContactIconBG, + required this.textConfirmTotalAmount, }); factory StackColors.fromStackColorTheme(StackColorTheme colorTheme) { @@ -432,6 +434,7 @@ class StackColors extends ThemeExtension<StackColors> { warningBackground: colorTheme.warningBackground, loadingOverlayTextColor: colorTheme.loadingOverlayTextColor, myStackContactIconBG: colorTheme.myStackContactIconBG, + textConfirmTotalAmount: colorTheme.textConfirmTotalAmount, ); } @@ -565,6 +568,7 @@ class StackColors extends ThemeExtension<StackColors> { Color? warningBackground, Color? loadingOverlayTextColor, Color? myStackContactIconBG, + Color? textConfirmTotalAmount, }) { return StackColors( themeType: themeType ?? this.themeType, @@ -730,6 +734,8 @@ class StackColors extends ThemeExtension<StackColors> { loadingOverlayTextColor: loadingOverlayTextColor ?? this.loadingOverlayTextColor, myStackContactIconBG: myStackContactIconBG ?? this.myStackContactIconBG, + textConfirmTotalAmount: + textConfirmTotalAmount ?? this.textConfirmTotalAmount, ); } @@ -1377,6 +1383,11 @@ class StackColors extends ThemeExtension<StackColors> { other.myStackContactIconBG, t, )!, + textConfirmTotalAmount: Color.lerp( + textConfirmTotalAmount, + other.textConfirmTotalAmount, + t, + )!, ); }