diff --git a/.gitignore b/.gitignore index cf2d96802..3ffacac45 100644 --- a/.gitignore +++ b/.gitignore @@ -37,6 +37,8 @@ lib/generated_plugin_registrant.dart test/services/coins/bitcoin/bitcoin_wallet_test_parameters.dart test/services/coins/firo/firo_wallet_test_parameters.dart test/services/coins/dogecoin/dogecoin_wallet_test_parameters.dart +test/services/coins/namecoin/namecoin_wallet_test_parameters.dart +test/services/coins/bitcoincash/bitcoincash_wallet_test_parameters.dart /integration_test/private.dart # Exceptions to above rules. @@ -46,3 +48,4 @@ test/services/coins/dogecoin/dogecoin_wallet_test_parameters.dart coverage scripts/**/build /lib/external_api_keys.dart +/test/services/coins/bitcoincash/bitcoincash_wallet_test_parameters.dart diff --git a/assets/images/bitcoincash.png b/assets/images/bitcoincash.png new file mode 100644 index 000000000..18552e02e Binary files /dev/null and b/assets/images/bitcoincash.png differ diff --git a/assets/images/namecoin.png b/assets/images/namecoin.png new file mode 100644 index 000000000..45cf8abb7 Binary files /dev/null and b/assets/images/namecoin.png differ diff --git a/assets/images/wownero.png b/assets/images/wownero.png new file mode 100644 index 000000000..857ab2b4c Binary files /dev/null and b/assets/images/wownero.png differ diff --git a/assets/svg/address-book2.svg b/assets/svg/address-book2.svg new file mode 100644 index 000000000..18de31c55 --- /dev/null +++ b/assets/svg/address-book2.svg @@ -0,0 +1,4 @@ + + + + diff --git a/assets/svg/chevron-right.svg b/assets/svg/chevron-right.svg new file mode 100644 index 000000000..c8efcde44 --- /dev/null +++ b/assets/svg/chevron-right.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/svg/coin_icons/Bitcoincash.svg b/assets/svg/coin_icons/Bitcoincash.svg new file mode 100644 index 000000000..4e700f9e0 --- /dev/null +++ b/assets/svg/coin_icons/Bitcoincash.svg @@ -0,0 +1 @@ +bitcoin-cash-bch \ No newline at end of file diff --git a/assets/svg/coin_icons/Namecoin.svg b/assets/svg/coin_icons/Namecoin.svg new file mode 100644 index 000000000..2cda6aaf0 --- /dev/null +++ b/assets/svg/coin_icons/Namecoin.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/svg/dark/bell-new.svg b/assets/svg/dark/bell-new.svg new file mode 100644 index 000000000..f976e0986 --- /dev/null +++ b/assets/svg/dark/bell-new.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/assets/svg/dark/buy-coins-icon.svg b/assets/svg/dark/buy-coins-icon.svg new file mode 100644 index 000000000..9170c4190 --- /dev/null +++ b/assets/svg/dark/buy-coins-icon.svg @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/assets/svg/dark/exchange-2.svg b/assets/svg/dark/exchange-2.svg new file mode 100644 index 000000000..ee04dcebe --- /dev/null +++ b/assets/svg/dark/exchange-2.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/assets/svg/dark/stack-icon1.svg b/assets/svg/dark/stack-icon1.svg new file mode 100644 index 000000000..4fb16176a --- /dev/null +++ b/assets/svg/dark/stack-icon1.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/assets/svg/dark/tx-exchange-icon-failed.svg b/assets/svg/dark/tx-exchange-icon-failed.svg new file mode 100644 index 000000000..64acda4e9 --- /dev/null +++ b/assets/svg/dark/tx-exchange-icon-failed.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/assets/svg/dark/tx-exchange-icon-pending.svg b/assets/svg/dark/tx-exchange-icon-pending.svg new file mode 100644 index 000000000..f9cdeb7c2 --- /dev/null +++ b/assets/svg/dark/tx-exchange-icon-pending.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/assets/svg/dark/tx-exchange-icon.svg b/assets/svg/dark/tx-exchange-icon.svg new file mode 100644 index 000000000..36b2cf7cc --- /dev/null +++ b/assets/svg/dark/tx-exchange-icon.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/assets/svg/dark/tx-icon-receive-failed.svg b/assets/svg/dark/tx-icon-receive-failed.svg new file mode 100644 index 000000000..cb1d500b1 --- /dev/null +++ b/assets/svg/dark/tx-icon-receive-failed.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/assets/svg/dark/tx-icon-receive-pending.svg b/assets/svg/dark/tx-icon-receive-pending.svg new file mode 100644 index 000000000..efb8350b3 --- /dev/null +++ b/assets/svg/dark/tx-icon-receive-pending.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/assets/svg/dark/tx-icon-receive.svg b/assets/svg/dark/tx-icon-receive.svg new file mode 100644 index 000000000..15be19d52 --- /dev/null +++ b/assets/svg/dark/tx-icon-receive.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/assets/svg/dark/tx-icon-send-failed.svg b/assets/svg/dark/tx-icon-send-failed.svg new file mode 100644 index 000000000..2be637ef3 --- /dev/null +++ b/assets/svg/dark/tx-icon-send-failed.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/assets/svg/dark/tx-icon-send-pending.svg b/assets/svg/dark/tx-icon-send-pending.svg new file mode 100644 index 000000000..50cca5a9e --- /dev/null +++ b/assets/svg/dark/tx-icon-send-pending.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/assets/svg/dark/tx-icon-send.svg b/assets/svg/dark/tx-icon-send.svg new file mode 100644 index 000000000..0e64ee37e --- /dev/null +++ b/assets/svg/dark/tx-icon-send.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/assets/svg/exchange-3.svg b/assets/svg/exchange-3.svg new file mode 100644 index 000000000..4a3c92524 --- /dev/null +++ b/assets/svg/exchange-3.svg @@ -0,0 +1,4 @@ + + + + diff --git a/assets/svg/bell-new.svg b/assets/svg/light/bell-new.svg similarity index 100% rename from assets/svg/bell-new.svg rename to assets/svg/light/bell-new.svg diff --git a/assets/svg/buy-coins-icon.svg b/assets/svg/light/buy-coins-icon.svg similarity index 100% rename from assets/svg/buy-coins-icon.svg rename to assets/svg/light/buy-coins-icon.svg diff --git a/assets/svg/exchange-2.svg b/assets/svg/light/exchange-2.svg similarity index 100% rename from assets/svg/exchange-2.svg rename to assets/svg/light/exchange-2.svg diff --git a/assets/svg/light/stack-icon1.svg b/assets/svg/light/stack-icon1.svg new file mode 100644 index 000000000..f316012d7 --- /dev/null +++ b/assets/svg/light/stack-icon1.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/assets/svg/tx-exchange-icon-failed.svg b/assets/svg/light/tx-exchange-icon-failed.svg similarity index 100% rename from assets/svg/tx-exchange-icon-failed.svg rename to assets/svg/light/tx-exchange-icon-failed.svg diff --git a/assets/svg/tx-exchange-icon-pending.svg b/assets/svg/light/tx-exchange-icon-pending.svg similarity index 100% rename from assets/svg/tx-exchange-icon-pending.svg rename to assets/svg/light/tx-exchange-icon-pending.svg diff --git a/assets/svg/tx-exchange-icon.svg b/assets/svg/light/tx-exchange-icon.svg similarity index 100% rename from assets/svg/tx-exchange-icon.svg rename to assets/svg/light/tx-exchange-icon.svg diff --git a/assets/svg/tx-icon-receive-failed.svg b/assets/svg/light/tx-icon-receive-failed.svg similarity index 100% rename from assets/svg/tx-icon-receive-failed.svg rename to assets/svg/light/tx-icon-receive-failed.svg diff --git a/assets/svg/tx-icon-receive-pending.svg b/assets/svg/light/tx-icon-receive-pending.svg similarity index 100% rename from assets/svg/tx-icon-receive-pending.svg rename to assets/svg/light/tx-icon-receive-pending.svg diff --git a/assets/svg/tx-icon-receive.svg b/assets/svg/light/tx-icon-receive.svg similarity index 100% rename from assets/svg/tx-icon-receive.svg rename to assets/svg/light/tx-icon-receive.svg diff --git a/assets/svg/tx-icon-send-failed.svg b/assets/svg/light/tx-icon-send-failed.svg similarity index 100% rename from assets/svg/tx-icon-send-failed.svg rename to assets/svg/light/tx-icon-send-failed.svg diff --git a/assets/svg/tx-icon-send-pending.svg b/assets/svg/light/tx-icon-send-pending.svg similarity index 100% rename from assets/svg/tx-icon-send-pending.svg rename to assets/svg/light/tx-icon-send-pending.svg diff --git a/assets/svg/tx-icon-send.svg b/assets/svg/light/tx-icon-send.svg similarity index 100% rename from assets/svg/tx-icon-send.svg rename to assets/svg/light/tx-icon-send.svg diff --git a/assets/svg/message-question-1.svg b/assets/svg/message-question-1.svg new file mode 100644 index 000000000..17e066651 --- /dev/null +++ b/assets/svg/message-question-1.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/assets/svg/minimize.svg b/assets/svg/minimize.svg new file mode 100644 index 000000000..94292fed4 --- /dev/null +++ b/assets/svg/minimize.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/assets/svg/stack-icon1.svg b/assets/svg/stack-icon1.svg deleted file mode 100644 index bf5f8fae7..000000000 --- a/assets/svg/stack-icon1.svg +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - - - - - diff --git a/assets/svg/wallet-fa.svg b/assets/svg/wallet-fa.svg new file mode 100644 index 000000000..a91170596 --- /dev/null +++ b/assets/svg/wallet-fa.svg @@ -0,0 +1,4 @@ + + + + diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index ee489cbef..f4931c674 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -449,7 +449,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; - CURRENT_PROJECT_VERSION = 51; + CURRENT_PROJECT_VERSION = 61; DEVELOPMENT_TEAM = 4DQKUWSG6C; ENABLE_BITCODE = NO; FRAMEWORK_SEARCH_PATHS = ( @@ -503,7 +503,7 @@ "$(PROJECT_DIR)/../crypto_plugins/flutter_libmonero/cw_shared_external/ios/External/ios/**", "$(PROJECT_DIR)/../crypto_plugins/flutter_libepiccash/ios/libs", ); - MARKETING_VERSION = 1.4.39; + MARKETING_VERSION = 1.4.46; ONLY_ACTIVE_ARCH = NO; PRODUCT_BUNDLE_IDENTIFIER = com.cypherstack.stackwallet; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -633,7 +633,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; - CURRENT_PROJECT_VERSION = 51; + CURRENT_PROJECT_VERSION = 61; DEVELOPMENT_TEAM = 4DQKUWSG6C; ENABLE_BITCODE = NO; FRAMEWORK_SEARCH_PATHS = ( @@ -687,7 +687,7 @@ "$(PROJECT_DIR)/../crypto_plugins/flutter_libmonero/cw_shared_external/ios/External/ios/**", "$(PROJECT_DIR)/../crypto_plugins/flutter_libepiccash/ios/libs", ); - MARKETING_VERSION = 1.4.39; + MARKETING_VERSION = 1.4.46; ONLY_ACTIVE_ARCH = NO; PRODUCT_BUNDLE_IDENTIFIER = com.cypherstack.stackwallet; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -709,7 +709,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; - CURRENT_PROJECT_VERSION = 51; + CURRENT_PROJECT_VERSION = 61; DEVELOPMENT_TEAM = 4DQKUWSG6C; ENABLE_BITCODE = NO; FRAMEWORK_SEARCH_PATHS = ( @@ -763,7 +763,7 @@ "$(PROJECT_DIR)/../crypto_plugins/flutter_libmonero/cw_shared_external/ios/External/ios/**", "$(PROJECT_DIR)/../crypto_plugins/flutter_libepiccash/ios/libs", ); - MARKETING_VERSION = 1.4.39; + MARKETING_VERSION = 1.4.46; ONLY_ACTIVE_ARCH = NO; PRODUCT_BUNDLE_IDENTIFIER = com.cypherstack.stackwallet; PRODUCT_NAME = "$(TARGET_NAME)"; diff --git a/lib/hive/db.dart b/lib/hive/db.dart index 3aae3096a..c8e148923 100644 --- a/lib/hive/db.dart +++ b/lib/hive/db.dart @@ -9,7 +9,6 @@ import 'package:stackwallet/models/notification_model.dart'; import 'package:stackwallet/models/trade_wallet_lookup.dart'; import 'package:stackwallet/services/wallets_service.dart'; import 'package:stackwallet/utilities/enums/coin_enum.dart'; - import 'package:stackwallet/utilities/logger.dart'; class DB { @@ -30,6 +29,7 @@ class DB { static const String boxNameWalletsToDeleteOnStart = "walletsToDeleteOnStart"; static const String boxNamePriceCache = "priceAPIPrice24hCache"; static const String boxNameDBInfo = "dbInfo"; + static const String boxNameTheme = "theme"; String boxNameTxCache({required Coin coin}) => "${coin.name}_txCache"; String boxNameSetCache({required Coin coin}) => diff --git a/lib/main.dart b/lib/main.dart index 5aeb89508..914fe59c2 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -29,6 +29,7 @@ import 'package:stackwallet/pages/loading_view.dart'; import 'package:stackwallet/pages/pinpad_views/create_pin_view.dart'; import 'package:stackwallet/pages/pinpad_views/lock_screen_view.dart'; import 'package:stackwallet/pages/settings_views/global_settings_view/stack_backup_views/restore_from_encrypted_string_view.dart'; +import 'package:stackwallet/pages_desktop_specific/home/desktop_home_view.dart'; import 'package:stackwallet/providers/exchange/available_currencies_state_provider.dart'; import 'package:stackwallet/providers/exchange/available_floating_rate_pairs_state_provider.dart'; import 'package:stackwallet/providers/exchange/change_now_provider.dart'; @@ -41,6 +42,7 @@ import 'package:stackwallet/providers/global/base_currencies_provider.dart'; // import 'package:stackwallet/providers/global/has_authenticated_start_state_provider.dart'; import 'package:stackwallet/providers/global/trades_service_provider.dart'; import 'package:stackwallet/providers/providers.dart'; +import 'package:stackwallet/providers/ui/color_theme_provider.dart'; import 'package:stackwallet/route_generator.dart'; import 'package:stackwallet/services/debug_service.dart'; import 'package:stackwallet/services/locale_service.dart'; @@ -49,13 +51,17 @@ import 'package:stackwallet/services/notifications_api.dart'; import 'package:stackwallet/services/notifications_service.dart'; import 'package:stackwallet/services/trade_service.dart'; import 'package:stackwallet/services/wallets.dart'; -import 'package:stackwallet/utilities/cfcolors.dart'; import 'package:stackwallet/utilities/constants.dart'; import 'package:stackwallet/utilities/db_version_migration.dart'; import 'package:stackwallet/utilities/enums/backup_frequency_type.dart'; import 'package:stackwallet/utilities/logger.dart'; import 'package:stackwallet/utilities/prefs.dart'; -import 'package:stackwallet/utilities/text_styles.dart'; +import 'package:stackwallet/utilities/theme/color_theme.dart'; +import 'package:stackwallet/utilities/theme/dark_colors.dart'; +import 'package:stackwallet/utilities/theme/light_colors.dart'; +import 'package:stackwallet/utilities/theme/stack_colors.dart'; +import 'package:stackwallet/utilities/util.dart'; +import 'package:window_size/window_size.dart'; final openedFromSWBFileStringStateProvider = StateProvider((ref) => null); @@ -65,6 +71,13 @@ final openedFromSWBFileStringStateProvider = // miscellaneous box for later use void main() async { WidgetsBinding widgetsBinding = WidgetsFlutterBinding.ensureInitialized(); + + if (Util.isDesktop) { + setWindowTitle('Stack Wallet'); + setWindowMinSize(const Size(1200, 900)); + setWindowMaxSize(Size.infinite); + } + Directory appDirectory = (await getApplicationDocumentsDirectory()); if (Platform.isIOS) { appDirectory = (await getLibraryDirectory()); @@ -130,6 +143,8 @@ void main() async { monero.onStartup(); + await Hive.openBox(DB.boxNameTheme); + // SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, // overlays: [SystemUiOverlay.bottom]); await NotificationApi.init(); @@ -333,6 +348,18 @@ class _MaterialAppWithThemeState extends ConsumerState @override void initState() { + final colorScheme = DB.instance + .get(boxName: DB.boxNameTheme, key: "colorScheme") as String?; + + ThemeType themeType; + switch (colorScheme) { + case "dark": + themeType = ThemeType.dark; + break; + case "light": + default: + themeType = ThemeType.light; + } loadingCompleter = Completer(); WidgetsBinding.instance.addObserver(this); // load locale and prefs @@ -343,8 +370,12 @@ class _MaterialAppWithThemeState extends ConsumerState _prefs = ref.read(prefsChangeNotifierProvider); _wallets = ref.read(walletsChangeNotifierProvider); - if (Platform.isAndroid) { - WidgetsBinding.instance.addPostFrameCallback((_) async { + WidgetsBinding.instance.addPostFrameCallback((_) async { + ref.read(colorThemeProvider.state).state = + StackColors.fromStackColorTheme( + themeType == ThemeType.dark ? DarkColors() : LightColors()); + + if (Platform.isAndroid) { // fetch open file if it exists await getOpenFile(); @@ -358,8 +389,8 @@ class _MaterialAppWithThemeState extends ConsumerState ref.read(openedFromSWBFileStringStateProvider.state).state = null; } // ref.read(shouldShowLockscreenOnResumeStateProvider.state).state = false; - }); - } + } + }); super.initState(); } @@ -491,36 +522,45 @@ class _MaterialAppWithThemeState extends ConsumerState // addToDebugMessagesDB: false); // }); + final colorScheme = ref.watch(colorThemeProvider.state).state; + return MaterialApp( key: GlobalKey(), navigatorKey: navigatorKey, title: 'Stack Wallet', onGenerateRoute: RouteGenerator.generateRoute, theme: ThemeData( - highlightColor: CFColors.splashLight, + extensions: [colorScheme], + highlightColor: colorScheme.highlight, brightness: Brightness.light, fontFamily: GoogleFonts.inter().fontFamily, - textTheme: GoogleFonts.interTextTheme().copyWith( - button: STextStyles.button, - ), + unselectedWidgetColor: colorScheme.radioButtonBorderDisabled, + // textTheme: GoogleFonts.interTextTheme().copyWith( + // button: STextStyles.button(context), + // subtitle1: STextStyles.field(context).copyWith( + // color: colorScheme.textDark, + // ), + // ), radioTheme: const RadioThemeData( splashRadius: 0, materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, ), // splashFactory: NoSplash.splashFactory, splashColor: Colors.transparent, - buttonTheme: const ButtonThemeData( - splashColor: CFColors.splashMed, + buttonTheme: ButtonThemeData( + splashColor: colorScheme.splash, ), textButtonTheme: TextButtonThemeData( style: ButtonStyle( // splashFactory: NoSplash.splashFactory, - overlayColor: MaterialStateProperty.all(CFColors.splashMed), + overlayColor: MaterialStateProperty.all(colorScheme.splash), minimumSize: MaterialStateProperty.all(const Size(46, 46)), - textStyle: MaterialStateProperty.all(STextStyles.button), - foregroundColor: MaterialStateProperty.all(CFColors.white), - backgroundColor: - MaterialStateProperty.all(CFColors.buttonGray), + // textStyle: MaterialStateProperty.all( + // STextStyles.button(context)), + foregroundColor: + MaterialStateProperty.all(colorScheme.buttonTextSecondary), + backgroundColor: MaterialStateProperty.all( + colorScheme.buttonBackSecondary), shape: MaterialStateProperty.all( RoundedRectangleBorder( // 1000 to be relatively sure it keeps its pill shape @@ -529,8 +569,8 @@ class _MaterialAppWithThemeState extends ConsumerState ), ), ), - primaryColor: CFColors.stackAccent, - primarySwatch: CFColors.createMaterialColor(CFColors.stackAccent), + primaryColor: colorScheme.accentColorDark, + primarySwatch: Util.createMaterialColor(colorScheme.accentColorDark), checkboxTheme: CheckboxThemeData( splashRadius: 0, shape: RoundedRectangleBorder( @@ -540,40 +580,44 @@ class _MaterialAppWithThemeState extends ConsumerState checkColor: MaterialStateColor.resolveWith( (state) { if (state.contains(MaterialState.selected)) { - return CFColors.white; + return colorScheme.checkboxIconChecked; } - return CFColors.link2; + return colorScheme.checkboxBGChecked; }, ), fillColor: MaterialStateColor.resolveWith( (states) { if (states.contains(MaterialState.selected)) { - return CFColors.link2; + return colorScheme.checkboxBGChecked; } - return CFColors.disabledButton; + return colorScheme.checkboxBorderEmpty; }, ), ), - appBarTheme: const AppBarTheme( + appBarTheme: AppBarTheme( centerTitle: false, - color: CFColors.almostWhite, + color: colorScheme.background, elevation: 0, ), inputDecorationTheme: InputDecorationTheme( - focusColor: CFColors.fieldGray, - fillColor: CFColors.fieldGray, + focusColor: colorScheme.textFieldDefaultBG, + fillColor: colorScheme.textFieldDefaultBG, filled: true, contentPadding: const EdgeInsets.symmetric( vertical: 6, horizontal: 12, ), - labelStyle: STextStyles.fieldLabel, - hintStyle: STextStyles.fieldLabel, - enabledBorder: _buildOutlineInputBorder(CFColors.fieldGray), - focusedBorder: _buildOutlineInputBorder(CFColors.fieldGray), - errorBorder: _buildOutlineInputBorder(CFColors.fieldGray), - disabledBorder: _buildOutlineInputBorder(CFColors.fieldGray), - focusedErrorBorder: _buildOutlineInputBorder(CFColors.fieldGray), + // labelStyle: STextStyles.fieldLabel(context), + // hintStyle: STextStyles.fieldLabel(context), + enabledBorder: + _buildOutlineInputBorder(colorScheme.textFieldDefaultBG), + focusedBorder: + _buildOutlineInputBorder(colorScheme.textFieldDefaultBG), + errorBorder: _buildOutlineInputBorder(colorScheme.textFieldDefaultBG), + disabledBorder: + _buildOutlineInputBorder(colorScheme.textFieldDefaultBG), + focusedErrorBorder: + _buildOutlineInputBorder(colorScheme.textFieldDefaultBG), ), ), home: FutureBuilder( @@ -595,6 +639,14 @@ class _MaterialAppWithThemeState extends ConsumerState ref.read(prefsChangeNotifierProvider).startupWalletId; } + // TODO proper desktop auth view + if (Util.isDesktop) { + Future.delayed(Duration.zero).then((value) => + Navigator.of(context).pushNamedAndRemoveUntil( + DesktopHomeView.routeName, (route) => false)); + return Container(); + } + return LockscreenView( isInitialAppLogin: true, routeOnSuccess: HomeView.routeName, diff --git a/lib/notifications/notification_card.dart b/lib/notifications/notification_card.dart index 2047169db..67be236f0 100644 --- a/lib/notifications/notification_card.dart +++ b/lib/notifications/notification_card.dart @@ -1,9 +1,9 @@ import 'package:flutter/material.dart'; import 'package:flutter_svg/svg.dart'; import 'package:stackwallet/models/notification_model.dart'; -import 'package:stackwallet/utilities/cfcolors.dart'; import 'package:stackwallet/utilities/format.dart'; import 'package:stackwallet/utilities/text_styles.dart'; +import 'package:stackwallet/utilities/theme/stack_colors.dart'; import 'package:stackwallet/widgets/rounded_container.dart'; import 'package:stackwallet/widgets/rounded_white_container.dart'; @@ -42,7 +42,9 @@ class NotificationCard extends StatelessWidget { ), child: SvgPicture.asset( notification.iconAssetName, - color: CFColors.stackAccent, + color: Theme.of(context) + .extension()! + .accentColorDark, width: 24, height: 24, ), @@ -56,7 +58,7 @@ class NotificationCard extends StatelessWidget { children: [ Text( notification.title, - style: STextStyles.titleBold12, + style: STextStyles.titleBold12(context), ), const SizedBox( height: 2, @@ -66,11 +68,11 @@ class NotificationCard extends StatelessWidget { children: [ Text( notification.description, - style: STextStyles.label, + style: STextStyles.label(context), ), Text( extractPrettyDateString(notification.date), - style: STextStyles.label, + style: STextStyles.label(context), ), ], ), @@ -83,7 +85,10 @@ class NotificationCard extends StatelessWidget { if (notification.read) Positioned.fill( child: RoundedContainer( - color: CFColors.almostWhite.withOpacity(0.5), + color: Theme.of(context) + .extension()! + .background + .withOpacity(0.5), ), ), ], diff --git a/lib/notifications/show_flush_bar.dart b/lib/notifications/show_flush_bar.dart index b250302bd..5320c8a9d 100644 --- a/lib/notifications/show_flush_bar.dart +++ b/lib/notifications/show_flush_bar.dart @@ -2,9 +2,9 @@ import 'package:another_flushbar/flushbar.dart'; import 'package:another_flushbar/flushbar_route.dart' as flushRoute; import 'package:flutter/material.dart'; import 'package:flutter_svg/svg.dart'; -import 'package:stackwallet/utilities/cfcolors.dart'; import 'package:stackwallet/utilities/constants.dart'; import 'package:stackwallet/utilities/enums/flush_bar_type.dart'; +import 'package:stackwallet/utilities/theme/stack_colors.dart'; Future showFloatingFlushBar({ required FlushBarType type, @@ -19,16 +19,16 @@ Future showFloatingFlushBar({ Color fg; switch (type) { case FlushBarType.success: - fg = CFColors.notificationGreenForeground; - bg = CFColors.notificationGreenBackground; + fg = Theme.of(context).extension()!.snackBarTextSuccess; + bg = Theme.of(context).extension()!.snackBarBackSuccess; break; case FlushBarType.info: - fg = CFColors.notificationBlueForeground; - bg = CFColors.notificationBlueBackground; + fg = Theme.of(context).extension()!.snackBarTextInfo; + bg = Theme.of(context).extension()!.snackBarBackInfo; break; case FlushBarType.warning: - fg = CFColors.notificationRedForeground; - bg = CFColors.notificationRedBackground; + fg = Theme.of(context).extension()!.snackBarTextError; + bg = Theme.of(context).extension()!.snackBarBackError; break; } final bar = Flushbar( @@ -53,6 +53,7 @@ Future showFloatingFlushBar({ Constants.size.circularBorderRadius, ), margin: const EdgeInsets.all(20), + maxWidth: 550, ); final _route = flushRoute.showFlushbar( diff --git a/lib/pages/add_wallet_views/add_wallet_view/add_wallet_view.dart b/lib/pages/add_wallet_views/add_wallet_view/add_wallet_view.dart index 45180c842..ae72e1846 100644 --- a/lib/pages/add_wallet_views/add_wallet_view/add_wallet_view.dart +++ b/lib/pages/add_wallet_views/add_wallet_view/add_wallet_view.dart @@ -1,85 +1,223 @@ import 'package:flutter/material.dart'; -import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:stackwallet/pages/add_wallet_views/add_wallet_view/sub_widgets/coin_select_item.dart'; +import 'package:flutter_svg/svg.dart'; +import 'package:stackwallet/pages/add_wallet_views/add_wallet_view/sub_widgets/add_wallet_text.dart'; +import 'package:stackwallet/pages/add_wallet_views/add_wallet_view/sub_widgets/mobile_coin_list.dart'; import 'package:stackwallet/pages/add_wallet_views/add_wallet_view/sub_widgets/next_button.dart'; -import 'package:stackwallet/providers/global/prefs_provider.dart'; -import 'package:stackwallet/utilities/cfcolors.dart'; +import 'package:stackwallet/pages/add_wallet_views/add_wallet_view/sub_widgets/searchable_coin_list.dart'; +import 'package:stackwallet/pages_desktop_specific/home/my_stack_view/exit_to_my_stack_button.dart'; +import 'package:stackwallet/utilities/assets.dart'; +import 'package:stackwallet/utilities/constants.dart'; import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/text_styles.dart'; +import 'package:stackwallet/utilities/theme/stack_colors.dart'; +import 'package:stackwallet/utilities/util.dart'; import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart'; +import 'package:stackwallet/widgets/desktop/desktop_app_bar.dart'; +import 'package:stackwallet/widgets/desktop/desktop_scaffold.dart'; +import 'package:stackwallet/widgets/icon_widgets/x_icon.dart'; +import 'package:stackwallet/widgets/rounded_white_container.dart'; +import 'package:stackwallet/widgets/stack_text_field.dart'; +import 'package:stackwallet/widgets/textfield_icon_button.dart'; -class AddWalletView extends StatelessWidget { +class AddWalletView extends StatefulWidget { const AddWalletView({Key? key}) : super(key: key); static const routeName = "/addWallet"; @override - Widget build(BuildContext context) { - List coins = [...Coin.values]; - coins.remove(Coin.firoTestNet); - return Scaffold( - appBar: AppBar( - leading: AppBarBackButton( - onPressed: () { - Navigator.of(context).pop(); - }, - ), - ), - body: Container( - color: CFColors.almostWhite, - child: Padding( - padding: const EdgeInsets.all(16), - child: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - Text( - "Add wallet", - textAlign: TextAlign.center, - style: STextStyles.pageTitleH1, - ), - const SizedBox( - height: 16, - ), - Text( - "Select wallet currency", - textAlign: TextAlign.center, - style: STextStyles.subtitle, - ), - const SizedBox( - height: 16, - ), - Expanded( - child: Consumer( - builder: (_, ref, __) { - bool showTestNet = ref.watch( - prefsChangeNotifierProvider - .select((value) => value.showTestNetCoins), - ); + State createState() => _AddWalletViewState(); +} - return ListView.builder( - itemCount: showTestNet - ? coins.length - : coins.length - (kTestNetCoinCount), - itemBuilder: (ctx, index) { - return Padding( - padding: const EdgeInsets.all(4), - child: CoinSelectItem( - coin: coins[index], +class _AddWalletViewState extends State { + late final TextEditingController _searchFieldController; + late final FocusNode _searchFocusNode; + + String _searchTerm = ""; + + final List coins = [...Coin.values]; + + @override + void initState() { + _searchFieldController = TextEditingController(); + _searchFocusNode = FocusNode(); + coins.remove(Coin.firoTestNet); + super.initState(); + } + + @override + void dispose() { + _searchFieldController.dispose(); + _searchFocusNode.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + debugPrint("BUILD: $runtimeType"); + + if (Util.isDesktop) { + return DesktopScaffold( + appBar: const DesktopAppBar( + isCompactHeight: false, + leading: AppBarBackButton(), + trailing: ExitToMyStackButton(), + ), + body: Column( + children: [ + const AddWalletText( + isDesktop: true, + ), + const SizedBox( + height: 16, + ), + Expanded( + child: SizedBox( + width: 480, + child: RoundedWhiteContainer( + radiusMultiplier: 2, + padding: const EdgeInsets.only( + left: 16, + top: 16, + right: 16, + bottom: 0, + ), + child: Column( + children: [ + Padding( + padding: const EdgeInsets.all(4.0), + child: ClipRRect( + borderRadius: BorderRadius.circular( + Constants.size.circularBorderRadius, ), - ); - }, - ); - }, + child: TextField( + controller: _searchFieldController, + focusNode: _searchFocusNode, + onChanged: (value) { + setState(() { + _searchTerm = value; + }); + }, + style: + STextStyles.desktopTextMedium(context).copyWith( + height: 2, + ), + decoration: standardInputDecoration( + "Search", + _searchFocusNode, + context, + ).copyWith( + contentPadding: const EdgeInsets.symmetric( + vertical: 10, + ), + prefixIcon: Padding( + padding: const EdgeInsets.symmetric( + horizontal: 16, + // vertical: 20, + ), + child: SvgPicture.asset( + Assets.svg.search, + width: 24, + height: 24, + color: Theme.of(context) + .extension()! + .textFieldDefaultSearchIconLeft, + ), + ), + suffixIcon: _searchFieldController.text.isNotEmpty + ? Padding( + padding: const EdgeInsets.only(right: 10), + child: UnconstrainedBox( + child: Row( + children: [ + TextFieldIconButton( + child: const XIcon( + width: 24, + height: 24, + ), + onTap: () async { + setState(() { + _searchFieldController.text = + ""; + _searchTerm = ""; + }); + }, + ), + ], + ), + ), + ) + : null, + ), + ), + ), + ), + Expanded( + child: SearchableCoinList( + coins: coins, + isDesktop: true, + searchTerm: _searchTerm, + ), + ), + ], + ), ), ), - const SizedBox( - height: 16, + ), + const SizedBox( + height: 16, + ), + const SizedBox( + height: 70, + width: 480, + child: AddWalletNextButton( + isDesktop: true, ), - const AddWalletNextButton(), - ], + ), + const SizedBox( + height: 32, + ), + ], + ), + ); + } else { + return Scaffold( + appBar: AppBar( + leading: AppBarBackButton( + onPressed: () { + Navigator.of(context).pop(); + }, ), ), - ), - ); + body: Container( + color: Theme.of(context).extension()!.background, + child: Padding( + padding: const EdgeInsets.all(16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + const AddWalletText( + isDesktop: false, + ), + const SizedBox( + height: 16, + ), + Expanded( + child: MobileCoinList( + coins: coins, + isDesktop: false, + ), + ), + const SizedBox( + height: 16, + ), + const AddWalletNextButton( + isDesktop: false, + ), + ], + ), + ), + ), + ); + } } } diff --git a/lib/pages/add_wallet_views/add_wallet_view/sub_widgets/add_wallet_text.dart b/lib/pages/add_wallet_views/add_wallet_view/sub_widgets/add_wallet_text.dart new file mode 100644 index 000000000..40e20c3f0 --- /dev/null +++ b/lib/pages/add_wallet_views/add_wallet_view/sub_widgets/add_wallet_text.dart @@ -0,0 +1,34 @@ +import 'package:flutter/material.dart'; +import 'package:stackwallet/utilities/text_styles.dart'; + +class AddWalletText extends StatelessWidget { + const AddWalletText({Key? key, required this.isDesktop}) : super(key: key); + + final bool isDesktop; + + @override + Widget build(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Text( + "Add wallet", + textAlign: TextAlign.center, + style: isDesktop + ? STextStyles.desktopH2(context) + : STextStyles.pageTitleH1(context), + ), + const SizedBox( + height: 16, + ), + Text( + "Select wallet currency", + textAlign: TextAlign.center, + style: isDesktop + ? STextStyles.desktopSubtitleH2(context) + : STextStyles.subtitle(context), + ), + ], + ); + } +} diff --git a/lib/pages/add_wallet_views/add_wallet_view/sub_widgets/coin_select_item.dart b/lib/pages/add_wallet_views/add_wallet_view/sub_widgets/coin_select_item.dart index 8ab1a4ffe..0821b8aae 100644 --- a/lib/pages/add_wallet_views/add_wallet_view/sub_widgets/coin_select_item.dart +++ b/lib/pages/add_wallet_views/add_wallet_view/sub_widgets/coin_select_item.dart @@ -3,10 +3,11 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_svg/svg.dart'; import 'package:stackwallet/providers/providers.dart'; import 'package:stackwallet/utilities/assets.dart'; -import 'package:stackwallet/utilities/cfcolors.dart'; import 'package:stackwallet/utilities/constants.dart'; import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/text_styles.dart'; +import 'package:stackwallet/utilities/theme/stack_colors.dart'; +import 'package:stackwallet/utilities/util.dart'; class CoinSelectItem extends ConsumerWidget { const CoinSelectItem({ @@ -20,40 +21,71 @@ class CoinSelectItem extends ConsumerWidget { Widget build(BuildContext context, WidgetRef ref) { debugPrint("BUILD: CoinSelectItem for ${coin.name}"); final selectedCoin = ref.watch(addWalletSelectedCoinStateProvider); + + final isDesktop = Util.isDesktop; + return Container( decoration: BoxDecoration( // color: selectedCoin == coin ? CFColors.selection : CFColors.white, - color: selectedCoin == coin ? CFColors.selected2 : CFColors.white, + color: selectedCoin == coin + ? Theme.of(context).extension()!.textFieldActiveBG + : Theme.of(context).extension()!.popupBG, borderRadius: BorderRadius.circular(Constants.size.circularBorderRadius), ), child: MaterialButton( - // splashColor: CFColors.splashLight, + // splashColor: Theme.of(context).extension()!.highlight, key: Key("coinSelectItemButtonKey_${coin.name}"), - padding: const EdgeInsets.all(12), + padding: isDesktop + ? const EdgeInsets.only(left: 24) + : const EdgeInsets.all(12), materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(Constants.size.circularBorderRadius), ), - child: Row( - children: [ - SvgPicture.asset( - Assets.svg.iconFor(coin: coin), - width: 26, - height: 26, - ), - const SizedBox( - width: 10, - ), - Text( - coin.prettyName, - style: STextStyles.subtitle.copyWith( - fontWeight: FontWeight.w600, - fontSize: 14, + child: ConstrainedBox( + constraints: BoxConstraints( + minHeight: isDesktop ? 70 : 0, + ), + child: Row( + children: [ + SvgPicture.asset( + Assets.svg.iconFor(coin: coin), + width: 26, + height: 26, ), - ), - ], + SizedBox( + width: isDesktop ? 12 : 10, + ), + Text( + coin.prettyName, + style: isDesktop + ? STextStyles.desktopTextMedium(context) + : STextStyles.subtitle(context).copyWith( + fontWeight: FontWeight.w600, + fontSize: 14, + ), + ), + if (isDesktop && selectedCoin == coin) const Spacer(), + if (isDesktop && selectedCoin == coin) + Padding( + padding: const EdgeInsets.only( + right: 18, + ), + child: SizedBox( + width: 24, + height: 24, + child: SvgPicture.asset( + Assets.svg.check, + color: Theme.of(context) + .extension()! + .accentColorDark, + ), + ), + ), + ], + ), ), onPressed: () => ref.read(addWalletSelectedCoinStateProvider.state).state = coin, diff --git a/lib/pages/add_wallet_views/add_wallet_view/sub_widgets/mobile_coin_list.dart b/lib/pages/add_wallet_views/add_wallet_view/sub_widgets/mobile_coin_list.dart new file mode 100644 index 000000000..1f36f3b65 --- /dev/null +++ b/lib/pages/add_wallet_views/add_wallet_view/sub_widgets/mobile_coin_list.dart @@ -0,0 +1,40 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:stackwallet/pages/add_wallet_views/add_wallet_view/sub_widgets/coin_select_item.dart'; +import 'package:stackwallet/providers/global/prefs_provider.dart'; +import 'package:stackwallet/utilities/enums/coin_enum.dart'; + +class MobileCoinList extends StatelessWidget { + const MobileCoinList({ + Key? key, + required this.coins, + required this.isDesktop, + }) : super(key: key); + + final List coins; + final bool isDesktop; + + @override + Widget build(BuildContext context) { + return Consumer( + builder: (_, ref, __) { + bool showTestNet = ref.watch( + prefsChangeNotifierProvider.select((value) => value.showTestNetCoins), + ); + + return ListView.builder( + itemCount: + showTestNet ? coins.length : coins.length - (kTestNetCoinCount), + itemBuilder: (ctx, index) { + return Padding( + padding: const EdgeInsets.all(4), + child: CoinSelectItem( + coin: coins[index], + ), + ); + }, + ); + }, + ); + } +} 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 61a0ef7b1..9314a8770 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 @@ -2,19 +2,27 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:stackwallet/pages/add_wallet_views/create_or_restore_wallet_view/create_or_restore_wallet_view.dart'; import 'package:stackwallet/providers/providers.dart'; -import 'package:stackwallet/utilities/cfcolors.dart'; import 'package:stackwallet/utilities/text_styles.dart'; +import 'package:stackwallet/utilities/theme/stack_colors.dart'; class AddWalletNextButton extends ConsumerWidget { - const AddWalletNextButton({Key? key}) : super(key: key); + const AddWalletNextButton({ + Key? key, + required this.isDesktop, + }) : super(key: key); + + final bool isDesktop; @override Widget build(BuildContext context, WidgetRef ref) { debugPrint("BUILD: NextButton"); final selectedCoin = ref.watch(addWalletSelectedCoinStateProvider.state).state; + + final enabled = selectedCoin != null; + return TextButton( - onPressed: selectedCoin == null + onPressed: !enabled ? null : () { final selectedCoin = @@ -25,22 +33,20 @@ class AddWalletNextButton extends ConsumerWidget { arguments: selectedCoin, ); }, - style: selectedCoin == null - ? Theme.of(context).textButtonTheme.style?.copyWith( - backgroundColor: MaterialStateProperty.all( - CFColors.stackAccent.withOpacity( - 0.25, - ), - ), - ) - : Theme.of(context).textButtonTheme.style?.copyWith( - backgroundColor: MaterialStateProperty.all( - CFColors.stackAccent, - ), - ), + style: enabled + ? Theme.of(context) + .extension()! + .getPrimaryEnabledButtonColor(context) + : Theme.of(context) + .extension()! + .getPrimaryDisabledButtonColor(context), child: Text( "Next", - style: STextStyles.button, + style: isDesktop + ? enabled + ? STextStyles.desktopButtonEnabled(context) + : STextStyles.desktopButtonDisabled(context) + : STextStyles.button(context), ), ); } diff --git a/lib/pages/add_wallet_views/add_wallet_view/sub_widgets/searchable_coin_list.dart b/lib/pages/add_wallet_views/add_wallet_view/sub_widgets/searchable_coin_list.dart new file mode 100644 index 000000000..fb443b915 --- /dev/null +++ b/lib/pages/add_wallet_views/add_wallet_view/sub_widgets/searchable_coin_list.dart @@ -0,0 +1,57 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:stackwallet/pages/add_wallet_views/add_wallet_view/sub_widgets/coin_select_item.dart'; +import 'package:stackwallet/providers/global/prefs_provider.dart'; +import 'package:stackwallet/utilities/enums/coin_enum.dart'; + +class SearchableCoinList extends ConsumerWidget { + const SearchableCoinList({ + Key? key, + required this.coins, + required this.isDesktop, + required this.searchTerm, + }) : super(key: key); + + final List coins; + final bool isDesktop; + final String searchTerm; + + List filterCoins(String text, bool showTestNetCoins) { + final _coins = [...coins]; + if (text.isNotEmpty) { + final lowercaseTerm = text.toLowerCase(); + _coins.retainWhere((e) => + e.ticker.toLowerCase().contains(lowercaseTerm) || + e.prettyName.toLowerCase().contains(lowercaseTerm) || + e.name.toLowerCase().contains(lowercaseTerm)); + } + if (!showTestNetCoins) { + _coins.removeWhere((e) => e.name.endsWith("TestNet")); + } + // remove firo testnet regardless + _coins.remove(Coin.firoTestNet); + + return _coins; + } + + @override + Widget build(BuildContext context, WidgetRef ref) { + bool showTestNet = ref.watch( + prefsChangeNotifierProvider.select((value) => value.showTestNetCoins), + ); + + final _coins = filterCoins(searchTerm, showTestNet); + + return ListView.builder( + itemCount: _coins.length, + itemBuilder: (ctx, index) { + return Padding( + padding: const EdgeInsets.all(4), + child: CoinSelectItem( + coin: _coins[index], + ), + ); + }, + ); + } +} 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 50c91a514..ffd32479d 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 @@ -1,12 +1,15 @@ import 'package:flutter/material.dart'; -import 'package:stackwallet/pages/add_wallet_views/name_your_wallet_view/name_your_wallet_view.dart'; -import 'package:stackwallet/utilities/assets.dart'; -import 'package:stackwallet/utilities/cfcolors.dart'; -import 'package:stackwallet/utilities/enums/add_wallet_type_enum.dart'; +import 'package:stackwallet/pages/add_wallet_views/create_or_restore_wallet_view/sub_widgets/coin_image.dart'; +import 'package:stackwallet/pages/add_wallet_views/create_or_restore_wallet_view/sub_widgets/create_or_restore_wallet_subtitle.dart'; +import 'package:stackwallet/pages/add_wallet_views/create_or_restore_wallet_view/sub_widgets/create_or_restore_wallet_title.dart'; +import 'package:stackwallet/pages/add_wallet_views/create_or_restore_wallet_view/sub_widgets/create_wallet_button_group.dart'; +import 'package:stackwallet/pages_desktop_specific/home/my_stack_view/exit_to_my_stack_button.dart'; import 'package:stackwallet/utilities/enums/coin_enum.dart'; -import 'package:stackwallet/utilities/text_styles.dart'; +import 'package:stackwallet/utilities/theme/stack_colors.dart'; +import 'package:stackwallet/utilities/util.dart'; import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart'; -import 'package:tuple/tuple.dart'; +import 'package:stackwallet/widgets/desktop/desktop_app_bar.dart'; +import 'package:stackwallet/widgets/desktop/desktop_scaffold.dart'; class CreateOrRestoreWalletView extends StatelessWidget { const CreateOrRestoreWalletView({ @@ -22,97 +25,100 @@ class CreateOrRestoreWalletView extends StatelessWidget { Widget build(BuildContext context) { debugPrint("BUILD: $runtimeType"); - return Scaffold( - appBar: AppBar( - leading: AppBarBackButton( - onPressed: () { - Navigator.of(context).pop(); - }, + final isDesktop = Util.isDesktop; + + if (isDesktop) { + return DesktopScaffold( + appBar: const DesktopAppBar( + isCompactHeight: false, + leading: AppBarBackButton(), + trailing: ExitToMyStackButton(), ), - ), - body: Container( - color: CFColors.almostWhite, - child: Padding( - padding: const EdgeInsets.all(16), + body: SizedBox( + width: 480, child: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, children: [ - Padding( - padding: const EdgeInsets.all(31), - child: Image( - image: AssetImage( - Assets.png.imageFor(coin: coin), - ), - width: MediaQuery.of(context).size.width / 3, - ), - ), - const Spacer( - flex: 2, - ), - Text( - "Add ${coin.prettyName} wallet", - textAlign: TextAlign.center, - style: STextStyles.pageTitleH1, + CreateRestoreWalletTitle( + coin: coin, + isDesktop: isDesktop, ), const SizedBox( - height: 8, + height: 16, ), - Text( - "Create a new wallet or restore an existing wallet from seed.", - textAlign: TextAlign.center, - style: STextStyles.subtitle), - const Spacer( - flex: 5, - ), - TextButton( - style: Theme.of(context).textButtonTheme.style?.copyWith( - backgroundColor: MaterialStateProperty.all( - CFColors.stackAccent, - ), - ), - onPressed: () { - Navigator.of(context).pushNamed( - NameYourWalletView.routeName, - arguments: Tuple2( - AddWalletType.New, - coin, - ), - ); - }, - child: Text( - "Create new wallet", - style: STextStyles.button, + SizedBox( + width: 324, + child: CreateRestoreWalletSubTitle( + isDesktop: isDesktop, ), ), const SizedBox( - height: 12, + height: 32, ), - TextButton( - style: Theme.of(context).textButtonTheme.style?.copyWith( - backgroundColor: MaterialStateProperty.all( - CFColors.stackAccent.withOpacity(0.25), - ), - ), - onPressed: () { - Navigator.of(context).pushNamed( - NameYourWalletView.routeName, - arguments: Tuple2( - AddWalletType.Restore, - coin, - ), - ); - }, - child: Text( - "Restore wallet", - style: STextStyles.button.copyWith( - color: CFColors.stackAccent, - ), - ), + CoinImage( + coin: coin, + isDesktop: isDesktop, + ), + const SizedBox( + height: 32, + ), + CreateWalletButtonGroup( + coin: coin, + isDesktop: isDesktop, ), ], ), ), - ), - ); + ); + } else { + return Scaffold( + appBar: AppBar( + leading: AppBarBackButton( + onPressed: () { + Navigator.of(context).pop(); + }, + ), + ), + 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( + 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 new file mode 100644 index 000000000..c96cc14ad --- /dev/null +++ b/lib/pages/add_wallet_views/create_or_restore_wallet_view/sub_widgets/coin_image.dart @@ -0,0 +1,24 @@ +import 'package:flutter/material.dart'; +import 'package:stackwallet/utilities/assets.dart'; +import 'package:stackwallet/utilities/enums/coin_enum.dart'; + +class CoinImage extends StatelessWidget { + const CoinImage({ + Key? key, + required this.coin, + required this.isDesktop, + }) : super(key: key); + + final Coin coin; + final bool isDesktop; + + @override + Widget build(BuildContext context) { + return Image( + image: AssetImage( + Assets.png.imageFor(coin: coin), + ), + width: isDesktop ? 324 : MediaQuery.of(context).size.width / 3, + ); + } +} diff --git a/lib/pages/add_wallet_views/create_or_restore_wallet_view/sub_widgets/create_or_restore_wallet_subtitle.dart b/lib/pages/add_wallet_views/create_or_restore_wallet_view/sub_widgets/create_or_restore_wallet_subtitle.dart new file mode 100644 index 000000000..2b6168509 --- /dev/null +++ b/lib/pages/add_wallet_views/create_or_restore_wallet_view/sub_widgets/create_or_restore_wallet_subtitle.dart @@ -0,0 +1,22 @@ +import 'package:flutter/material.dart'; +import 'package:stackwallet/utilities/text_styles.dart'; + +class CreateRestoreWalletSubTitle extends StatelessWidget { + const CreateRestoreWalletSubTitle({ + Key? key, + required this.isDesktop, + }) : super(key: key); + + final bool isDesktop; + + @override + Widget build(BuildContext context) { + return Text( + "Create a new wallet or restore an existing wallet from seed.", + textAlign: TextAlign.center, + style: isDesktop + ? STextStyles.desktopSubtitleH2(context) + : STextStyles.subtitle(context), + ); + } +} diff --git a/lib/pages/add_wallet_views/create_or_restore_wallet_view/sub_widgets/create_or_restore_wallet_title.dart b/lib/pages/add_wallet_views/create_or_restore_wallet_view/sub_widgets/create_or_restore_wallet_title.dart new file mode 100644 index 000000000..8ac5af718 --- /dev/null +++ b/lib/pages/add_wallet_views/create_or_restore_wallet_view/sub_widgets/create_or_restore_wallet_title.dart @@ -0,0 +1,25 @@ +import 'package:flutter/material.dart'; +import 'package:stackwallet/utilities/enums/coin_enum.dart'; +import 'package:stackwallet/utilities/text_styles.dart'; + +class CreateRestoreWalletTitle extends StatelessWidget { + const CreateRestoreWalletTitle({ + Key? key, + required this.coin, + required this.isDesktop, + }) : super(key: key); + + final Coin coin; + final bool isDesktop; + + @override + Widget build(BuildContext context) { + return Text( + "Add ${coin.prettyName} wallet", + textAlign: TextAlign.center, + style: isDesktop + ? STextStyles.desktopH2(context) + : STextStyles.pageTitleH1(context), + ); + } +} diff --git a/lib/pages/add_wallet_views/create_or_restore_wallet_view/sub_widgets/create_wallet_button_group.dart b/lib/pages/add_wallet_views/create_or_restore_wallet_view/sub_widgets/create_wallet_button_group.dart new file mode 100644 index 000000000..4a7661892 --- /dev/null +++ b/lib/pages/add_wallet_views/create_or_restore_wallet_view/sub_widgets/create_wallet_button_group.dart @@ -0,0 +1,86 @@ +import 'package:flutter/material.dart'; +import 'package:stackwallet/pages/add_wallet_views/name_your_wallet_view/name_your_wallet_view.dart'; +import 'package:stackwallet/utilities/enums/add_wallet_type_enum.dart'; +import 'package:stackwallet/utilities/enums/coin_enum.dart'; +import 'package:stackwallet/utilities/text_styles.dart'; +import 'package:stackwallet/utilities/theme/stack_colors.dart'; +import 'package:tuple/tuple.dart'; + +class CreateWalletButtonGroup extends StatelessWidget { + const CreateWalletButtonGroup({ + Key? key, + required this.coin, + required this.isDesktop, + }) : super(key: key); + + final Coin coin; + final bool isDesktop; + + @override + Widget build(BuildContext context) { + return Column( + crossAxisAlignment: + isDesktop ? CrossAxisAlignment.center : CrossAxisAlignment.stretch, + children: [ + ConstrainedBox( + constraints: BoxConstraints( + minHeight: isDesktop ? 70 : 0, + minWidth: isDesktop ? 480 : 0, + ), + child: TextButton( + style: Theme.of(context) + .extension()! + .getPrimaryEnabledButtonColor(context), + onPressed: () { + Navigator.of(context).pushNamed( + NameYourWalletView.routeName, + arguments: Tuple2( + AddWalletType.New, + coin, + ), + ); + }, + child: Text( + "Create new wallet", + style: isDesktop + ? STextStyles.desktopButtonEnabled(context) + : STextStyles.button(context), + ), + ), + ), + SizedBox( + height: isDesktop ? 16 : 12, + ), + ConstrainedBox( + constraints: BoxConstraints( + minHeight: isDesktop ? 70 : 0, + minWidth: isDesktop ? 480 : 0, + ), + child: TextButton( + style: Theme.of(context) + .extension()! + .getSecondaryEnabledButtonColor(context), + onPressed: () { + Navigator.of(context).pushNamed( + NameYourWalletView.routeName, + arguments: Tuple2( + AddWalletType.Restore, + coin, + ), + ); + }, + child: Text( + "Restore wallet", + style: isDesktop + ? STextStyles.desktopButtonSecondaryEnabled(context) + : STextStyles.button(context).copyWith( + color: Theme.of(context) + .extension()! + .accentColorDark), + ), + ), + ), + ], + ); + } +} diff --git a/lib/pages/add_wallet_views/name_your_wallet_view/name_your_wallet_view.dart b/lib/pages/add_wallet_views/name_your_wallet_view/name_your_wallet_view.dart index 5338c8461..cff9fd2cf 100644 --- a/lib/pages/add_wallet_views/name_your_wallet_view/name_your_wallet_view.dart +++ b/lib/pages/add_wallet_views/name_your_wallet_view/name_your_wallet_view.dart @@ -1,19 +1,25 @@ +import 'dart:async'; + import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:stackwallet/notifications/show_flush_bar.dart'; import 'package:stackwallet/pages/add_wallet_views/new_wallet_recovery_phrase_warning_view/new_wallet_recovery_phrase_warning_view.dart'; -import 'package:stackwallet/pages/add_wallet_views/restore_wallet_view/restore_options_view.dart'; +import 'package:stackwallet/pages/add_wallet_views/restore_wallet_view/restore_options_view/restore_options_view.dart'; +import 'package:stackwallet/pages_desktop_specific/home/my_stack_view/exit_to_my_stack_button.dart'; import 'package:stackwallet/providers/global/wallets_service_provider.dart'; import 'package:stackwallet/providers/ui/verify_recovery_phrase/mnemonic_word_count_state_provider.dart'; import 'package:stackwallet/utilities/assets.dart'; -import 'package:stackwallet/utilities/cfcolors.dart'; import 'package:stackwallet/utilities/constants.dart'; import 'package:stackwallet/utilities/enums/add_wallet_type_enum.dart'; import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/enums/flush_bar_type.dart'; import 'package:stackwallet/utilities/name_generator.dart'; import 'package:stackwallet/utilities/text_styles.dart'; +import 'package:stackwallet/utilities/theme/stack_colors.dart'; +import 'package:stackwallet/utilities/util.dart'; import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart'; +import 'package:stackwallet/widgets/desktop/desktop_app_bar.dart'; +import 'package:stackwallet/widgets/desktop/desktop_scaffold.dart'; import 'package:stackwallet/widgets/icon_widgets/dice_icon.dart'; import 'package:stackwallet/widgets/icon_widgets/x_icon.dart'; import 'package:stackwallet/widgets/rounded_white_container.dart'; @@ -21,14 +27,6 @@ import 'package:stackwallet/widgets/stack_text_field.dart'; import 'package:stackwallet/widgets/textfield_icon_button.dart'; import 'package:tuple/tuple.dart'; -// TODO replace with real list and move out of this file -const kWalletNameWordList = [ - "Bubby", - "Baby", - "Bobby", - "Booby", -]; - class NameYourWalletView extends ConsumerStatefulWidget { const NameYourWalletView({ Key? key, @@ -59,6 +57,8 @@ class _NameYourWalletViewState extends ConsumerState { Set namesToExclude = {}; late final NameGenerator generator; + late final bool isDesktop; + Future _generateRandomWalletName() async { final name = generator.generate(namesToExclude: namesToExclude); namesToExclude.add(name); @@ -67,6 +67,8 @@ class _NameYourWalletViewState extends ConsumerState { @override void initState() { + isDesktop = Util.isDesktop; + ref.read(walletsServiceChangeNotifierProvider).walletNames.then( (value) => namesToExclude.addAll( value.values.map((e) => e.name), @@ -92,231 +94,270 @@ class _NameYourWalletViewState extends ConsumerState { Widget build(BuildContext context) { debugPrint( "BUILD: NameYourWalletView with ${coin.name} ${addWalletType.name}"); - return Scaffold( - appBar: AppBar( - leading: AppBarBackButton( - onPressed: () { - if (textFieldFocusNode.hasFocus) { - textFieldFocusNode.unfocus(); - Future.delayed(const Duration(milliseconds: 100)) - .then((value) => Navigator.of(context).pop()); - } else { - if (mounted) { - Navigator.of(context).pop(); - } - } - }, + + if (isDesktop) { + return DesktopScaffold( + appBar: const DesktopAppBar( + leading: AppBarBackButton(), + trailing: ExitToMyStackButton(), + isCompactHeight: false, ), - ), - body: Container( - color: CFColors.almostWhite, - child: Padding( - padding: const EdgeInsets.all(16), - child: LayoutBuilder( - builder: (ctx, constraints) { - return SingleChildScrollView( - child: ConstrainedBox( - constraints: BoxConstraints(minHeight: constraints.maxHeight), - child: IntrinsicHeight( - child: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, + body: SizedBox( + width: 480, + child: _content(), + ), + ); + } else { + return Scaffold( + appBar: AppBar( + leading: AppBarBackButton( + onPressed: () { + if (textFieldFocusNode.hasFocus) { + textFieldFocusNode.unfocus(); + Future.delayed(const Duration(milliseconds: 100)) + .then((value) => Navigator.of(context).pop()); + } else { + if (mounted) { + Navigator.of(context).pop(); + } + } + }, + ), + ), + body: Container( + color: Theme.of(context).extension()!.background, + child: Padding( + padding: const EdgeInsets.all(16), + child: LayoutBuilder( + builder: (ctx, constraints) { + return SingleChildScrollView( + child: ConstrainedBox( + constraints: + BoxConstraints(minHeight: constraints.maxHeight), + child: IntrinsicHeight( + child: _content(), + ), + ), + ); + }, + ), + ), + ), + ); + } + } + + Widget _content() => Column( + crossAxisAlignment: + isDesktop ? CrossAxisAlignment.center : CrossAxisAlignment.stretch, + children: [ + if (!isDesktop) + const Spacer( + flex: 1, + ), + if (!isDesktop) + Image( + image: AssetImage( + Assets.png.imageFor(coin: coin), + ), + height: 100, + ), + SizedBox( + height: isDesktop ? 24 : 16, + ), + Text( + "Name your ${coin.prettyName} wallet", + textAlign: TextAlign.center, + style: isDesktop + ? STextStyles.desktopH2(context) + : STextStyles.pageTitleH1(context), + ), + SizedBox( + height: isDesktop ? 16 : 8, + ), + Text( + "Enter a label for your wallet (e.g. Savings)", + textAlign: TextAlign.center, + style: isDesktop + ? STextStyles.desktopSubtitleH2(context) + : STextStyles.subtitle(context), + ), + SizedBox( + height: isDesktop ? 40 : 16, + ), + ClipRRect( + borderRadius: BorderRadius.circular( + Constants.size.circularBorderRadius, + ), + child: TextField( + onChanged: (string) { + if (string.isEmpty) { + if (_nextEnabled) { + setState(() { + _nextEnabled = false; + _showDiceIcon = true; + }); + } + } else { + if (!_nextEnabled) { + setState(() { + _nextEnabled = true; + _showDiceIcon = false; + }); + } + } + }, + focusNode: textFieldFocusNode, + controller: textEditingController, + style: isDesktop + ? STextStyles.desktopTextMedium(context).copyWith( + height: 2, + ) + : STextStyles.field(context), + decoration: standardInputDecoration( + "Enter wallet name", + textFieldFocusNode, + context, + ).copyWith( + suffixIcon: Padding( + padding: EdgeInsets.only(right: isDesktop ? 6 : 0), + child: UnconstrainedBox( + child: Row( children: [ - const Spacer( - flex: 1, - ), - Image( - image: AssetImage( - Assets.png.imageFor(coin: coin), - ), - height: 100, - ), - const SizedBox( - height: 16, - ), - Text( - "Name your ${coin.prettyName} wallet", - textAlign: TextAlign.center, - style: STextStyles.pageTitleH1, - ), - const SizedBox( - height: 8, - ), - Text( - "Enter a label for your wallet (e.g. Savings)", - textAlign: TextAlign.center, - style: STextStyles.subtitle, - ), - const SizedBox( - height: 16, - ), - ClipRRect( - borderRadius: BorderRadius.circular( - Constants.size.circularBorderRadius, - ), - child: TextField( - onChanged: (string) { - if (string.isEmpty) { - if (_nextEnabled) { - setState(() { - _nextEnabled = false; - _showDiceIcon = true; - }); - } - } else { - if (!_nextEnabled) { - setState(() { - _nextEnabled = true; - _showDiceIcon = false; - }); - } - } - }, - focusNode: textFieldFocusNode, - controller: textEditingController, - style: STextStyles.field, - decoration: standardInputDecoration( - "Enter wallet name", - textFieldFocusNode, - ).copyWith( - suffixIcon: Padding( - padding: const EdgeInsets.only(right: 0), - child: UnconstrainedBox( - child: Row( - children: [ - TextFieldIconButton( - key: const Key( - "genRandomWalletNameButtonKey"), - child: _showDiceIcon - ? const DiceIcon() - : const XIcon(), - onTap: () async { - if (_showDiceIcon) { - textEditingController.text = - await _generateRandomWalletName(); - setState(() { - _nextEnabled = true; - _showDiceIcon = false; - }); - } else { - textEditingController.text = ""; - setState(() { - _nextEnabled = false; - _showDiceIcon = true; - }); - } - }, - ) - ], - ), + TextFieldIconButton( + key: const Key("genRandomWalletNameButtonKey"), + child: _showDiceIcon + ? DiceIcon( + width: isDesktop ? 20 : 17, + height: isDesktop ? 20 : 17, + ) + : XIcon( + width: isDesktop ? 21 : 18, + height: isDesktop ? 21 : 18, ), - ), - ), - ), - ), - const SizedBox( - height: 8, - ), - RoundedWhiteContainer( - child: Center( - child: Text( - "Roll the dice to pick a random name.", - style: STextStyles.itemSubtitle, - ), - ), - ), - const Spacer( - flex: 4, - ), - TextButton( - onPressed: _nextEnabled - ? () async { - final walletsService = ref.read( - walletsServiceChangeNotifierProvider); - final name = textEditingController.text; - - if (await walletsService - .checkForDuplicate(name)) { - showFloatingFlushBar( - type: FlushBarType.warning, - message: "Wallet name already in use.", - iconAsset: Assets.svg.circleAlert, - context: context, - ); - } else { - // hide keyboard if has focus - if (FocusScope.of(context).hasFocus) { - FocusScope.of(context).unfocus(); - await Future.delayed( - const Duration(milliseconds: 50)); - } - - if (mounted) { - switch (widget.addWalletType) { - case AddWalletType.New: - Navigator.of(context).pushNamed( - NewWalletRecoveryPhraseWarningView - .routeName, - arguments: Tuple2( - name, - coin, - ), - ); - break; - case AddWalletType.Restore: - ref - .read( - mnemonicWordCountStateProvider - .state) - .state = Constants - .possibleLengthsForCoin(coin) - .first; - Navigator.of(context).pushNamed( - RestoreOptionsView.routeName, - arguments: Tuple2( - name, - coin, - ), - ); - break; - } - } - } - } - : null, - style: _nextEnabled - ? Theme.of(context) - .textButtonTheme - .style - ?.copyWith( - backgroundColor: - MaterialStateProperty.all( - CFColors.stackAccent, - )) - : Theme.of(context) - .textButtonTheme - .style - ?.copyWith( - backgroundColor: - MaterialStateProperty.all( - CFColors.stackAccent.withOpacity( - 0.25, - ), - ), - ), - child: Text( - "Next", - style: STextStyles.button, - ), - ), + onTap: () async { + if (_showDiceIcon) { + textEditingController.text = + await _generateRandomWalletName(); + setState(() { + _nextEnabled = true; + _showDiceIcon = false; + }); + } else { + textEditingController.text = ""; + setState(() { + _nextEnabled = false; + _showDiceIcon = true; + }); + } + }, + ) ], ), ), ), - ); - }, + ), + ), ), - ), - ), - ); - } + SizedBox( + height: isDesktop ? 16 : 8, + ), + RoundedWhiteContainer( + child: Center( + child: Text( + "Roll the dice to pick a random name.", + style: isDesktop + ? STextStyles.desktopTextExtraSmall(context).copyWith( + color: Theme.of(context) + .extension()! + .textSubtitle1, + ) + : STextStyles.itemSubtitle(context), + ), + ), + ), + if (!isDesktop) + const Spacer( + flex: 4, + ), + if (isDesktop) + const SizedBox( + height: 32, + ), + ConstrainedBox( + constraints: BoxConstraints( + minWidth: isDesktop ? 480 : 0, + minHeight: isDesktop ? 70 : 0, + ), + child: TextButton( + onPressed: _nextEnabled + ? () async { + final walletsService = + ref.read(walletsServiceChangeNotifierProvider); + final name = textEditingController.text; + + if (await walletsService.checkForDuplicate(name)) { + unawaited(showFloatingFlushBar( + type: FlushBarType.warning, + message: "Wallet name already in use.", + iconAsset: Assets.svg.circleAlert, + context: context, + )); + } else { + // hide keyboard if has focus + if (FocusScope.of(context).hasFocus) { + FocusScope.of(context).unfocus(); + await Future.delayed( + const Duration(milliseconds: 50)); + } + + if (mounted) { + switch (widget.addWalletType) { + case AddWalletType.New: + unawaited(Navigator.of(context).pushNamed( + NewWalletRecoveryPhraseWarningView.routeName, + arguments: Tuple2( + name, + coin, + ), + )); + break; + case AddWalletType.Restore: + ref + .read(mnemonicWordCountStateProvider.state) + .state = Constants.possibleLengthsForCoin( + coin) + .first; + unawaited(Navigator.of(context).pushNamed( + RestoreOptionsView.routeName, + arguments: Tuple2( + name, + coin, + ), + )); + break; + } + } + } + } + : null, + style: _nextEnabled + ? Theme.of(context) + .extension()! + .getPrimaryEnabledButtonColor(context) + : Theme.of(context) + .extension()! + .getPrimaryDisabledButtonColor(context), + child: Text( + "Next", + style: isDesktop + ? _nextEnabled + ? STextStyles.desktopButtonEnabled(context) + : STextStyles.desktopButtonDisabled(context) + : STextStyles.button(context), + ), + ), + ), + ], + ); } diff --git a/lib/pages/add_wallet_views/new_wallet_recovery_phrase_view/new_wallet_recovery_phrase_view.dart b/lib/pages/add_wallet_views/new_wallet_recovery_phrase_view/new_wallet_recovery_phrase_view.dart index 7f12e8b6d..207451569 100644 --- a/lib/pages/add_wallet_views/new_wallet_recovery_phrase_view/new_wallet_recovery_phrase_view.dart +++ b/lib/pages/add_wallet_views/new_wallet_recovery_phrase_view/new_wallet_recovery_phrase_view.dart @@ -1,3 +1,4 @@ +import 'dart:async'; import 'dart:math'; import 'package:flutter/material.dart'; @@ -8,15 +9,20 @@ import 'package:stackwallet/notifications/show_flush_bar.dart'; import 'package:stackwallet/pages/add_wallet_views/new_wallet_recovery_phrase_view/sub_widgets/mnemonic_table.dart'; import 'package:stackwallet/pages/add_wallet_views/new_wallet_recovery_phrase_warning_view/new_wallet_recovery_phrase_warning_view.dart'; import 'package:stackwallet/pages/add_wallet_views/verify_recovery_phrase_view/verify_recovery_phrase_view.dart'; +import 'package:stackwallet/pages_desktop_specific/home/desktop_home_view.dart'; +import 'package:stackwallet/pages_desktop_specific/home/my_stack_view/exit_to_my_stack_button.dart'; import 'package:stackwallet/providers/providers.dart'; import 'package:stackwallet/services/coins/manager.dart'; import 'package:stackwallet/utilities/assets.dart'; -import 'package:stackwallet/utilities/cfcolors.dart'; import 'package:stackwallet/utilities/clipboard_interface.dart'; import 'package:stackwallet/utilities/constants.dart'; import 'package:stackwallet/utilities/enums/flush_bar_type.dart'; import 'package:stackwallet/utilities/text_styles.dart'; +import 'package:stackwallet/utilities/theme/stack_colors.dart'; +import 'package:stackwallet/utilities/util.dart'; import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart'; +import 'package:stackwallet/widgets/desktop/desktop_app_bar.dart'; +import 'package:stackwallet/widgets/desktop/desktop_scaffold.dart'; import 'package:tuple/tuple.dart'; class NewWalletRecoveryPhraseView extends ConsumerStatefulWidget { @@ -46,12 +52,14 @@ class _NewWalletRecoveryPhraseViewState late Manager _manager; late List _mnemonic; late ClipboardInterface _clipboardInterface; + late final bool isDesktop; @override void initState() { _manager = widget.manager; _mnemonic = widget.mnemonic; _clipboardInterface = widget.clipboardInterface; + isDesktop = Util.isDesktop; super.initState(); } @@ -67,144 +75,239 @@ class _NewWalletRecoveryPhraseViewState await _manager.exitCurrentWallet(); } + Future _copy() async { + final words = await _manager.mnemonic; + await _clipboardInterface.setData(ClipboardData(text: words.join(" "))); + unawaited(showFloatingFlushBar( + type: FlushBarType.info, + message: "Copied to clipboard", + iconAsset: Assets.svg.copy, + context: context, + )); + } + @override Widget build(BuildContext context) { debugPrint("BUILD: $runtimeType"); return WillPopScope( - onWillPop: onWillPop, - child: Scaffold( - appBar: AppBar( - leading: AppBarBackButton( - onPressed: () async { - await delete(); + onWillPop: onWillPop, + child: MasterScaffold( + isDesktop: isDesktop, + appBar: isDesktop + ? DesktopAppBar( + isCompactHeight: false, + leading: AppBarBackButton( + onPressed: () async { + await delete(); - if (mounted) { - Navigator.of(context).popUntil( - ModalRoute.withName( - NewWalletRecoveryPhraseWarningView.routeName, + if (mounted) { + Navigator.of(context).popUntil( + ModalRoute.withName( + NewWalletRecoveryPhraseWarningView.routeName, + ), + ); + } + // Navigator.of(context).pop(); + }, ), - ); - } - // Navigator.of(context).pop(); - }, - ), - actions: [ - Padding( - padding: const EdgeInsets.all(10), - child: AspectRatio( - aspectRatio: 1, - child: AppBarIconButton( - color: CFColors.almostWhite, - shadows: const [], - icon: SvgPicture.asset( - Assets.svg.copy, - width: 24, - height: 24, + trailing: ExitToMyStackButton( + onPressed: () async { + await delete(); + if (mounted) { + Navigator.of(context).popUntil( + ModalRoute.withName(DesktopHomeView.routeName), + ); + } + }, ), - onPressed: () async { - final words = await _manager.mnemonic; - await _clipboardInterface - .setData(ClipboardData(text: words.join(" "))); - showFloatingFlushBar( - type: FlushBarType.info, - message: "Copied to clipboard", - iconAsset: Assets.svg.copy, - context: context, - ); - }, - ), - ), - ), - ], - ), - body: Container( - color: CFColors.almostWhite, - child: Padding( - padding: const EdgeInsets.all(16), - child: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - const SizedBox( - height: 4, - ), - Text( - _manager.walletName, - textAlign: TextAlign.center, - style: STextStyles.label.copyWith( - fontSize: 12, - ), - ), - const SizedBox( - height: 4, - ), - Text( - "Recovery Phrase", - textAlign: TextAlign.center, - style: STextStyles.pageTitleH1, - ), - const SizedBox( - height: 16, - ), - Container( - decoration: BoxDecoration( - color: CFColors.white, - borderRadius: BorderRadius.circular( - Constants.size.circularBorderRadius), - ), - child: Padding( - padding: const EdgeInsets.all(12), - child: Text( - "Please write down your recovery phrase in the correct order and save it to keep your funds secure. You will also be asked to verify the words on the next screen.", - style: STextStyles.label.copyWith( - color: CFColors.stackAccent, - ), - ), - ), - ), - const SizedBox( - height: 8, - ), - Expanded( - child: SingleChildScrollView( - child: MnemonicTable( - words: _mnemonic, - ), - ), - ), - const SizedBox( - height: 16, - ), - TextButton( - onPressed: () async { - final int next = Random().nextInt(_mnemonic.length); - ref - .read(verifyMnemonicWordIndexStateProvider.state) - .update((state) => next); + ) + : AppBar( + leading: AppBarBackButton( + onPressed: () async { + await delete(); - ref - .read(verifyMnemonicCorrectWordStateProvider.state) - .update((state) => _mnemonic[next]); - - Navigator.of(context).pushNamed( - VerifyRecoveryPhraseView.routeName, - arguments: Tuple2(_manager, _mnemonic), - ); - }, - style: Theme.of(context).textButtonTheme.style?.copyWith( - backgroundColor: MaterialStateProperty.all( - CFColors.stackAccent, + if (mounted) { + Navigator.of(context).popUntil( + ModalRoute.withName( + NewWalletRecoveryPhraseWarningView.routeName, + ), + ); + } + }, + ), + actions: [ + Padding( + padding: const EdgeInsets.all(10), + child: AspectRatio( + aspectRatio: 1, + child: AppBarIconButton( + color: Theme.of(context) + .extension()! + .background, + shadows: const [], + icon: SvgPicture.asset( + Assets.svg.copy, + width: 24, + height: 24, + color: Theme.of(context) + .extension()! + .topNavIconPrimary, + ), + onPressed: () async { + await _copy(); + }, ), ), - child: Text( - "I saved my recovery phrase", - style: STextStyles.button, - ), + ), + ], ), - ], + body: Container( + color: Theme.of(context).extension()!.background, + width: isDesktop ? 600 : null, + child: Padding( + padding: isDesktop + ? const EdgeInsets.all(0) + : const EdgeInsets.all(16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + if (!isDesktop) + const SizedBox( + height: 4, + ), + if (!isDesktop) + Text( + _manager.walletName, + textAlign: TextAlign.center, + style: STextStyles.label(context).copyWith( + fontSize: 12, + ), + ), + SizedBox( + height: isDesktop ? 24 : 4, + ), + Text( + "Recovery Phrase", + textAlign: TextAlign.center, + style: isDesktop + ? STextStyles.desktopH2(context) + : STextStyles.pageTitleH1(context), + ), + const SizedBox( + height: 16, + ), + Container( + decoration: BoxDecoration( + color: isDesktop + ? Theme.of(context) + .extension()! + .background + : Theme.of(context).extension()!.popupBG, + borderRadius: BorderRadius.circular( + Constants.size.circularBorderRadius), + ), + child: Padding( + padding: isDesktop + ? const EdgeInsets.all(0) + : const EdgeInsets.all(12), + child: Text( + "Please write down your recovery phrase in the correct order and save it to keep your funds secure. You will also be asked to verify the words on the next screen.", + textAlign: TextAlign.center, + style: isDesktop + ? STextStyles.desktopSubtitleH2(context) + : STextStyles.label(context).copyWith( + color: Theme.of(context) + .extension()! + .accentColorDark), + ), + ), + ), + SizedBox( + height: isDesktop ? 21 : 8, + ), + if (!isDesktop) + Expanded( + child: SingleChildScrollView( + child: MnemonicTable( + words: _mnemonic, + isDesktop: isDesktop, + ), + ), + ), + if (isDesktop) + MnemonicTable( + words: _mnemonic, + isDesktop: isDesktop, + ), + SizedBox( + height: isDesktop ? 24 : 16, + ), + if (isDesktop) + SizedBox( + height: 70, + child: TextButton( + onPressed: () async { + await _copy(); + }, + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + SvgPicture.asset( + Assets.svg.copy, + width: 20, + height: 20, + ), + const SizedBox( + width: 10, + ), + Text( + "Copy to clipboard", + style: STextStyles.desktopButtonSecondaryEnabled( + context), + ) + ], + ), + ), + ), + if (isDesktop) + const SizedBox( + height: 16, + ), + ConstrainedBox( + constraints: BoxConstraints( + minHeight: isDesktop ? 70 : 0, + ), + child: TextButton( + onPressed: () async { + final int next = Random().nextInt(_mnemonic.length); + ref + .read(verifyMnemonicWordIndexStateProvider.state) + .update((state) => next); + + ref + .read(verifyMnemonicCorrectWordStateProvider.state) + .update((state) => _mnemonic[next]); + + unawaited(Navigator.of(context).pushNamed( + VerifyRecoveryPhraseView.routeName, + arguments: Tuple2(_manager, _mnemonic), + )); + }, + style: Theme.of(context) + .extension()! + .getPrimaryEnabledButtonColor(context), + child: Text( + "I saved my recovery phrase", + style: isDesktop + ? STextStyles.desktopButtonEnabled(context) + : STextStyles.button(context), + ), + ), + ), + ], + ), ), ), - ), - ), - ); + )); } } diff --git a/lib/pages/add_wallet_views/new_wallet_recovery_phrase_view/sub_widgets/mnemonic_table.dart b/lib/pages/add_wallet_views/new_wallet_recovery_phrase_view/sub_widgets/mnemonic_table.dart index 9b33f5248..946f54d4a 100644 --- a/lib/pages/add_wallet_views/new_wallet_recovery_phrase_view/sub_widgets/mnemonic_table.dart +++ b/lib/pages/add_wallet_views/new_wallet_recovery_phrase_view/sub_widgets/mnemonic_table.dart @@ -1,19 +1,20 @@ -import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; import 'package:stackwallet/pages/add_wallet_views/new_wallet_recovery_phrase_view/sub_widgets/mnemonic_table_item.dart'; class MnemonicTable extends StatelessWidget { const MnemonicTable({ Key? key, required this.words, + required this.isDesktop, }) : super(key: key); final List words; - - static const wordsPerRow = 3; + final bool isDesktop; @override Widget build(BuildContext context) { debugPrint("BUILD: $runtimeType"); + final wordsPerRow = isDesktop ? 4 : 3; final int rows = words.length ~/ wordsPerRow; @@ -26,51 +27,54 @@ class MnemonicTable extends StatelessWidget { children: [ for (int i = 1; i <= rows; i++) Padding( - padding: const EdgeInsets.symmetric(vertical: 5), + padding: EdgeInsets.symmetric(vertical: isDesktop ? 8 : 5), child: Row( children: [ for (int j = 1; j <= wordsPerRow; j++) ...[ if (j > 1) - const SizedBox( - width: 6, + SizedBox( + width: isDesktop ? 10 : 6, ), Expanded( child: MnemonicTableItem( number: ++index, word: words[index - 1], + isDesktop: isDesktop, ), ), ], ], ), ), - Padding( - padding: const EdgeInsets.symmetric(vertical: 5), - child: Row( - children: [ - for (int i = index; i < words.length; i++) ...[ - if (i > index) + if (index != words.length) + Padding( + padding: EdgeInsets.symmetric(vertical: isDesktop ? 8 : 5), + child: Row( + children: [ + for (int i = index; i < words.length; i++) ...[ + if (i > index) + SizedBox( + width: isDesktop ? 10 : 6, + ), + Expanded( + child: MnemonicTableItem( + number: i + 1, + word: words[i], + isDesktop: isDesktop, + ), + ), + ], + for (int i = remainder; i < wordsPerRow; i++) ...[ const SizedBox( width: 6, ), - Expanded( - child: MnemonicTableItem( - number: i + 1, - word: words[i], + Expanded( + child: Container(), ), - ), + ], ], - for (int i = remainder; i < wordsPerRow; i++) ...[ - const SizedBox( - width: 6, - ), - Expanded( - child: Container(), - ), - ], - ], + ), ), - ), ], ); } diff --git a/lib/pages/add_wallet_views/new_wallet_recovery_phrase_view/sub_widgets/mnemonic_table_item.dart b/lib/pages/add_wallet_views/new_wallet_recovery_phrase_view/sub_widgets/mnemonic_table_item.dart index dfc8897f8..8928ff3a6 100644 --- a/lib/pages/add_wallet_views/new_wallet_recovery_phrase_view/sub_widgets/mnemonic_table_item.dart +++ b/lib/pages/add_wallet_views/new_wallet_recovery_phrase_view/sub_widgets/mnemonic_table_item.dart @@ -1,49 +1,57 @@ import 'package:flutter/material.dart'; -import 'package:stackwallet/utilities/cfcolors.dart'; -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/rounded_white_container.dart'; class MnemonicTableItem extends StatelessWidget { const MnemonicTableItem({ Key? key, required this.number, required this.word, + required this.isDesktop, }) : super(key: key); final int number; final String word; + final bool isDesktop; @override Widget build(BuildContext context) { debugPrint("BUILD: $runtimeType"); - return Container( - decoration: BoxDecoration( - color: CFColors.white, - borderRadius: BorderRadius.circular( - Constants.size.circularBorderRadius, - ), - ), - child: Padding( - padding: const EdgeInsets.all(8), - child: Row( - mainAxisAlignment: MainAxisAlignment.start, - children: [ - Text( - number.toString(), - style: STextStyles.baseXS.copyWith( - color: CFColors.gray3, - fontSize: 10, - ), - ), - const SizedBox( - width: 8, - ), - Text( - word, - style: STextStyles.baseXS, - ), - ], - ), + return RoundedWhiteContainer( + padding: isDesktop + ? const EdgeInsets.symmetric(horizontal: 12, vertical: 9) + : const EdgeInsets.all(8), + child: Row( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Text( + number.toString(), + style: isDesktop + ? STextStyles.desktopTextExtraSmall(context).copyWith( + color: Theme.of(context) + .extension()! + .textSubtitle2, + ) + : STextStyles.baseXS(context).copyWith( + color: Theme.of(context) + .extension()! + .textSubtitle2, + fontSize: 10, + ), + ), + const SizedBox( + width: 8, + ), + Text( + word, + style: isDesktop + ? STextStyles.desktopTextExtraSmall(context).copyWith( + color: Theme.of(context).extension()!.textDark, + ) + : STextStyles.baseXS(context), + ), + ], ), ); } diff --git a/lib/pages/add_wallet_views/new_wallet_recovery_phrase_warning_view/new_wallet_recovery_phrase_warning_view.dart b/lib/pages/add_wallet_views/new_wallet_recovery_phrase_warning_view/new_wallet_recovery_phrase_warning_view.dart index 4711ff2fd..603e5cca1 100644 --- a/lib/pages/add_wallet_views/new_wallet_recovery_phrase_warning_view/new_wallet_recovery_phrase_warning_view.dart +++ b/lib/pages/add_wallet_views/new_wallet_recovery_phrase_warning_view/new_wallet_recovery_phrase_warning_view.dart @@ -1,18 +1,25 @@ +import 'dart:async'; + import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:stackwallet/pages/add_wallet_views/new_wallet_recovery_phrase_view/new_wallet_recovery_phrase_view.dart'; +import 'package:stackwallet/pages_desktop_specific/home/my_stack_view/exit_to_my_stack_button.dart'; import 'package:stackwallet/providers/providers.dart'; import 'package:stackwallet/services/coins/coin_service.dart'; import 'package:stackwallet/services/coins/manager.dart'; import 'package:stackwallet/services/transaction_notification_tracker.dart'; -import 'package:stackwallet/utilities/cfcolors.dart'; import 'package:stackwallet/utilities/constants.dart'; import 'package:stackwallet/utilities/default_nodes.dart'; import 'package:stackwallet/utilities/enums/coin_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/utilities/util.dart'; import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart'; +import 'package:stackwallet/widgets/desktop/desktop_app_bar.dart'; +import 'package:stackwallet/widgets/desktop/desktop_scaffold.dart'; import 'package:stackwallet/widgets/loading_indicator.dart'; +import 'package:stackwallet/widgets/rounded_white_container.dart'; import 'package:tuple/tuple.dart'; class NewWalletRecoveryPhraseWarningView extends StatefulWidget { @@ -36,11 +43,13 @@ class _NewWalletRecoveryPhraseWarningViewState extends State { late final Coin coin; late final String walletName; + late final bool isDesktop; @override void initState() { coin = widget.coin; walletName = widget.walletName; + isDesktop = Util.isDesktop; super.initState(); } @@ -52,60 +61,72 @@ class _NewWalletRecoveryPhraseWarningViewState ? Constants.seedPhraseWordCountMonero : Constants.seedPhraseWordCountBip39; - return Scaffold( - appBar: AppBar( - leading: AppBarBackButton( - onPressed: () { - Navigator.of(context).pop(); - }, - ), - ), - body: Container( - color: CFColors.almostWhite, - child: Padding( - padding: const EdgeInsets.all(16), - child: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - const SizedBox( - height: 4, - ), + return MasterScaffold( + isDesktop: isDesktop, + appBar: isDesktop + ? const DesktopAppBar( + isCompactHeight: false, + leading: AppBarBackButton(), + trailing: ExitToMyStackButton(), + ) + : AppBar( + leading: const AppBarBackButton(), + ), + body: Padding( + padding: EdgeInsets.all(isDesktop ? 0 : 16), + child: Column( + crossAxisAlignment: isDesktop + ? CrossAxisAlignment.center + : CrossAxisAlignment.stretch, + children: [ + const SizedBox( + height: 4, + ), + if (!isDesktop) Text( walletName, textAlign: TextAlign.center, - style: STextStyles.label.copyWith( + style: STextStyles.label(context).copyWith( fontSize: 12, ), ), + const SizedBox( + height: 4, + ), + Text( + "Recovery Phrase", + textAlign: TextAlign.center, + style: isDesktop + ? STextStyles.desktopH2(context) + : STextStyles.pageTitleH1(context), + ), + SizedBox( + height: isDesktop ? 32 : 16, + ), + RoundedWhiteContainer( + padding: isDesktop + ? const EdgeInsets.all(32) + : const EdgeInsets.all(12), + width: isDesktop ? 480 : null, + child: Text( + "On the next screen you will see $_numberOfPhraseWords words that make up your recovery phrase.\n\nPlease write it down. Keep it safe and never share it with anyone. Your recovery phrase is the only way you can access your funds if you forget your PIN, lose your phone, etc.\n\nStack Wallet does not keep nor is able to restore your recover phrase. Only you have access to your wallet.", + style: isDesktop + ? STextStyles.desktopTextMediumRegular(context) + : STextStyles.subtitle(context).copyWith( + fontSize: 12, + ), + ), + ), + if (!isDesktop) const Spacer(), + if (isDesktop) const SizedBox( - height: 4, + height: 32, ), - Text( - "Recovery Phrase", - textAlign: TextAlign.center, - style: STextStyles.pageTitleH1, + ConstrainedBox( + constraints: BoxConstraints( + maxWidth: isDesktop ? 480 : 0, ), - const SizedBox( - height: 16, - ), - Container( - decoration: BoxDecoration( - color: CFColors.white, - borderRadius: BorderRadius.circular( - Constants.size.circularBorderRadius), - ), - child: Padding( - padding: const EdgeInsets.all(12), - child: Text( - "On the next screen you will see $_numberOfPhraseWords words that make up your recovery phrase.\n\nPlease write it down. Keep it safe and never share it with anyone. Your recovery phrase is the only way you can access your funds if you forget your PIN, lose your phone, etc.\n\nStack Wallet does not keep nor is able to restore your recover phrase. Only you have access to your wallet.", - style: STextStyles.subtitle.copyWith( - fontSize: 12, - ), - ), - ), - ), - const Spacer(), - Consumer( + child: Consumer( builder: (_, ref, __) { return Column( crossAxisAlignment: CrossAxisAlignment.stretch, @@ -119,6 +140,9 @@ class _NewWalletRecoveryPhraseWarningViewState child: Container( color: Colors.transparent, child: Row( + crossAxisAlignment: isDesktop + ? CrossAxisAlignment.start + : CrossAxisAlignment.center, children: [ Checkbox( materialTapTargetSize: @@ -131,138 +155,143 @@ class _NewWalletRecoveryPhraseWarningViewState newValue!; }, ), - const SizedBox( - width: 4, + SizedBox( + width: isDesktop ? 14 : 4, ), Flexible( child: Text( "I understand that if I lose my recovery phrase, I will not be able to access my funds.", - style: STextStyles.baseXS, + style: isDesktop + ? STextStyles.desktopTextMedium(context) + : STextStyles.baseXS(context), ), ), ], ), ), ), - const SizedBox( - height: 16, + SizedBox( + height: isDesktop ? 32 : 16, ), - TextButton( - onPressed: ref.read(checkBoxStateProvider.state).state - ? () async { - try { - showDialog( - context: context, - barrierDismissible: false, - useSafeArea: true, - builder: (ctx) { - return const Center( - child: LoadingIndicator( - width: 50, - height: 50, - ), - ); - }, - ); - - final walletsService = ref.read( - walletsServiceChangeNotifierProvider); - - final walletId = - await walletsService.addNewWallet( - name: walletName, - coin: coin, - shouldNotifyListeners: false, - ); - - var node = ref - .read(nodeServiceChangeNotifierProvider) - .getPrimaryNodeFor(coin: coin); - - if (node == null) { - node = DefaultNodes.getNodeFor(coin); - ref - .read(nodeServiceChangeNotifierProvider) - .setPrimaryNodeFor( - coin: coin, - node: node, + ConstrainedBox( + constraints: BoxConstraints( + minHeight: isDesktop ? 70 : 0, + ), + child: TextButton( + onPressed: ref.read(checkBoxStateProvider.state).state + ? () async { + try { + unawaited(showDialog( + context: context, + barrierDismissible: false, + useSafeArea: true, + builder: (ctx) { + return const Center( + child: LoadingIndicator( + width: 50, + height: 50, + ), ); - } + }, + )); - final txTracker = - TransactionNotificationTracker( - walletId: walletId!); + final walletsService = ref.read( + walletsServiceChangeNotifierProvider); - final failovers = ref - .read(nodeServiceChangeNotifierProvider) - .failoverNodesFor(coin: widget.coin); - - final wallet = CoinServiceAPI.from( - coin, - walletId, - walletName, - node, - txTracker, - ref.read(prefsChangeNotifierProvider), - failovers, - ); - - final manager = Manager(wallet); - - await manager.initializeNew(); - - // pop progress dialog - if (mounted) { - Navigator.pop(context); - } - // set checkbox back to unchecked to annoy users to agree again :P - ref.read(checkBoxStateProvider.state).state = - false; - - if (mounted) { - Navigator.of(context).pushNamed( - NewWalletRecoveryPhraseView.routeName, - arguments: Tuple2( - manager, - await manager.mnemonic, - ), + final walletId = + await walletsService.addNewWallet( + name: walletName, + coin: coin, + shouldNotifyListeners: false, ); + + var node = ref + .read(nodeServiceChangeNotifierProvider) + .getPrimaryNodeFor(coin: coin); + + if (node == null) { + node = DefaultNodes.getNodeFor(coin); + await ref + .read( + nodeServiceChangeNotifierProvider) + .setPrimaryNodeFor( + coin: coin, + node: node, + ); + } + + final txTracker = + TransactionNotificationTracker( + walletId: walletId!); + + final failovers = ref + .read(nodeServiceChangeNotifierProvider) + .failoverNodesFor(coin: widget.coin); + + final wallet = CoinServiceAPI.from( + coin, + walletId, + walletName, + node, + txTracker, + ref.read(prefsChangeNotifierProvider), + failovers, + ); + + final manager = Manager(wallet); + + await manager.initializeNew(); + + // pop progress dialog + if (mounted) { + Navigator.pop(context); + } + // set checkbox back to unchecked to annoy users to agree again :P + ref + .read(checkBoxStateProvider.state) + .state = false; + + if (mounted) { + unawaited(Navigator.of(context).pushNamed( + NewWalletRecoveryPhraseView.routeName, + arguments: Tuple2( + manager, + await manager.mnemonic, + ), + )); + } + } catch (e, s) { + Logging.instance + .log("$e\n$s", level: LogLevel.Fatal); + // TODO: handle gracefully + // any network/socket exception here will break new wallet creation + rethrow; } - } catch (e, s) { - Logging.instance - .log("$e\n$s", level: LogLevel.Fatal); - // TODO: handle gracefully - // any network/socket exception here will break new wallet creation - rethrow; } - } - : null, - style: ref.read(checkBoxStateProvider.state).state - ? Theme.of(context).textButtonTheme.style?.copyWith( - backgroundColor: - MaterialStateProperty.all( - CFColors.stackAccent, - ), - ) - : Theme.of(context).textButtonTheme.style?.copyWith( - backgroundColor: - MaterialStateProperty.all( - CFColors.stackAccent.withOpacity( - 0.25, - ), - ), - ), - child: Text( - "View recovery phrase", - style: STextStyles.button, + : null, + style: ref.read(checkBoxStateProvider.state).state + ? Theme.of(context) + .extension()! + .getPrimaryEnabledButtonColor(context) + : Theme.of(context) + .extension()! + .getPrimaryDisabledButtonColor(context), + child: Text( + "View recovery phrase", + style: isDesktop + ? ref.read(checkBoxStateProvider.state).state + ? STextStyles.desktopButtonEnabled(context) + : STextStyles.desktopButtonDisabled(context) + : STextStyles.button(context), + ), ), ), ], ); }, ), - ], - ), + ), + ], ), ), ); diff --git a/lib/pages/add_wallet_views/restore_wallet_view/confirm_recovery_dialog.dart b/lib/pages/add_wallet_views/restore_wallet_view/confirm_recovery_dialog.dart index 6cf709ac1..6ccc44d03 100644 --- a/lib/pages/add_wallet_views/restore_wallet_view/confirm_recovery_dialog.dart +++ b/lib/pages/add_wallet_views/restore_wallet_view/confirm_recovery_dialog.dart @@ -1,6 +1,6 @@ import 'package:flutter/material.dart'; -import 'package:stackwallet/utilities/cfcolors.dart'; import 'package:stackwallet/utilities/text_styles.dart'; +import 'package:stackwallet/utilities/theme/stack_colors.dart'; import 'package:stackwallet/widgets/stack_dialog.dart'; class ConfirmRecoveryDialog extends StatelessWidget { @@ -20,28 +20,24 @@ class ConfirmRecoveryDialog extends StatelessWidget { message: "Restoring your wallet may take a while. Please do not exit this screen once the process is started.", leftButton: TextButton( - style: Theme.of(context).textButtonTheme.style?.copyWith( - backgroundColor: MaterialStateProperty.all( - CFColors.buttonGray, - ), - ), + style: Theme.of(context) + .extension()! + .getSecondaryEnabledButtonColor(context), child: Text( "Cancel", - style: STextStyles.itemSubtitle12, + style: STextStyles.itemSubtitle12(context), ), onPressed: () { Navigator.of(context).pop(); }, ), rightButton: TextButton( - style: Theme.of(context).textButtonTheme.style?.copyWith( - backgroundColor: MaterialStateProperty.all( - CFColors.stackAccent, - ), - ), + style: Theme.of(context) + .extension()! + .getPrimaryEnabledButtonColor(context), child: Text( "Restore", - style: STextStyles.button, + style: STextStyles.button(context), ), onPressed: () { Navigator.of(context).pop(); diff --git a/lib/pages/add_wallet_views/restore_wallet_view/restore_options_view.dart b/lib/pages/add_wallet_views/restore_wallet_view/restore_options_view.dart deleted file mode 100644 index d7f78041d..000000000 --- a/lib/pages/add_wallet_views/restore_wallet_view/restore_options_view.dart +++ /dev/null @@ -1,409 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:flutter_rounded_date_picker/flutter_rounded_date_picker.dart'; -import 'package:flutter_svg/svg.dart'; -import 'package:google_fonts/google_fonts.dart'; -import 'package:stackwallet/pages/add_wallet_views/restore_wallet_view/restore_wallet_view.dart'; -import 'package:stackwallet/pages/add_wallet_views/restore_wallet_view/sub_widgets/mnemonic_word_count_select_sheet.dart'; -import 'package:stackwallet/providers/ui/verify_recovery_phrase/mnemonic_word_count_state_provider.dart'; -import 'package:stackwallet/utilities/assets.dart'; -import 'package:stackwallet/utilities/cfcolors.dart'; -import 'package:stackwallet/utilities/constants.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; -import 'package:stackwallet/utilities/format.dart'; -import 'package:stackwallet/utilities/text_styles.dart'; -import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart'; -import 'package:stackwallet/widgets/rounded_white_container.dart'; -import 'package:tuple/tuple.dart'; - -class RestoreOptionsView extends ConsumerStatefulWidget { - const RestoreOptionsView({ - Key? key, - required this.walletName, - required this.coin, - }) : super(key: key); - - static const routeName = "/restoreOptions"; - - final String walletName; - final Coin coin; - - @override - ConsumerState createState() => _RestoreOptionsViewState(); -} - -class _RestoreOptionsViewState extends ConsumerState { - late final String walletName; - late final Coin coin; - - late TextEditingController _dateController; - late TextEditingController _lengthController; - late FocusNode textFieldFocusNode; - - final bool _nextEnabled = true; - DateTime _restoreFromDate = DateTime.fromMillisecondsSinceEpoch(0); - - @override - void initState() { - walletName = widget.walletName; - coin = widget.coin; - - _dateController = TextEditingController(); - _lengthController = TextEditingController(); - textFieldFocusNode = FocusNode(); - - super.initState(); - } - - @override - void dispose() { - _dateController.dispose(); - _lengthController.dispose(); - textFieldFocusNode.dispose(); - super.dispose(); - } - - final _datePickerTextStyleBase = GoogleFonts.inter( - color: CFColors.gray3, - fontSize: 12, - fontWeight: FontWeight.w400, - letterSpacing: 0.5, - ); - MaterialRoundedDatePickerStyle _buildDatePickerStyle() { - return MaterialRoundedDatePickerStyle( - paddingMonthHeader: const EdgeInsets.only(top: 11), - colorArrowNext: CFColors.neutral60, - colorArrowPrevious: CFColors.neutral60, - textStyleButtonNegative: _datePickerTextStyleBase.copyWith( - fontSize: 16, fontWeight: FontWeight.w600), - textStyleButtonPositive: _datePickerTextStyleBase.copyWith( - fontSize: 16, fontWeight: FontWeight.w600), - textStyleCurrentDayOnCalendar: _datePickerTextStyleBase.copyWith( - color: CFColors.stackAccent, - ), - textStyleDayHeader: _datePickerTextStyleBase.copyWith( - color: CFColors.stackAccent, - fontSize: 16, - fontWeight: FontWeight.w600, - ), - textStyleDayOnCalendar: _datePickerTextStyleBase, - textStyleDayOnCalendarDisabled: _datePickerTextStyleBase.copyWith( - color: CFColors.neutral80, - ), - textStyleDayOnCalendarSelected: _datePickerTextStyleBase.copyWith( - color: CFColors.white, - ), - textStyleMonthYearHeader: _datePickerTextStyleBase.copyWith( - color: CFColors.neutral60, - fontSize: 16, - fontWeight: FontWeight.w600, - ), - textStyleYearButton: _datePickerTextStyleBase.copyWith( - color: CFColors.white, - fontSize: 16, - fontWeight: FontWeight.w600, - ), - textStyleButtonAction: GoogleFonts.inter(), - ); - } - - MaterialRoundedYearPickerStyle _buildYearPickerStyle() { - return MaterialRoundedYearPickerStyle( - textStyleYear: _datePickerTextStyleBase.copyWith( - color: CFColors.gray3, - fontWeight: FontWeight.w600, - fontSize: 16, - ), - textStyleYearSelected: _datePickerTextStyleBase.copyWith( - color: CFColors.stackAccent, - fontWeight: FontWeight.w600, - fontSize: 18, - ), - ); - } - - @override - Widget build(BuildContext context) { - debugPrint("BUILD: $runtimeType with ${coin.name} $walletName"); - - return Scaffold( - appBar: AppBar( - leading: AppBarBackButton( - onPressed: () { - if (textFieldFocusNode.hasFocus) { - textFieldFocusNode.unfocus(); - Future.delayed(const Duration(milliseconds: 100)) - .then((value) => Navigator.of(context).pop()); - } else { - Navigator.of(context).pop(); - } - }, - ), - ), - body: Container( - color: CFColors.almostWhite, - child: Padding( - padding: const EdgeInsets.all(16), - child: LayoutBuilder( - builder: (ctx, constraints) { - return SingleChildScrollView( - child: ConstrainedBox( - constraints: BoxConstraints(minHeight: constraints.maxHeight), - child: IntrinsicHeight( - child: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - const Spacer( - flex: 1, - ), - Image( - image: AssetImage( - Assets.png.imageFor(coin: coin), - ), - height: 100, - ), - const SizedBox( - height: 16, - ), - Text( - "Restore options", - textAlign: TextAlign.center, - style: STextStyles.pageTitleH1, - ), - const SizedBox( - height: 24, - ), - if (coin == Coin.monero || coin == Coin.epicCash) - Text( - "Choose start date", - style: STextStyles.smallMed12, - textAlign: TextAlign.left, - ), - if (coin == Coin.monero || coin == Coin.epicCash) - const SizedBox( - height: 8, - ), - if (coin == Coin.monero || coin == Coin.epicCash) - Container( - color: Colors.transparent, - child: TextField( - onTap: () async { - final height = - MediaQuery.of(context).size.height; - // check and hide keyboard - if (FocusScope.of(context).hasFocus) { - FocusScope.of(context).unfocus(); - await Future.delayed( - const Duration(milliseconds: 125)); - } - - final date = await showRoundedDatePicker( - context: context, - initialDate: DateTime.now(), - height: height * 0.5, - theme: ThemeData( - primarySwatch: CFColors.createMaterialColor( - CFColors.stackAccent), - ), - //TODO pick a better initial date - // 2007 chosen as that is just before bitcoin launched - firstDate: DateTime(2007), - lastDate: DateTime.now(), - borderRadius: - Constants.size.circularBorderRadius * 2, - - textPositiveButton: "SELECT", - - styleDatePicker: _buildDatePickerStyle(), - styleYearPicker: _buildYearPickerStyle(), - ); - if (date != null) { - _restoreFromDate = date; - _dateController.text = - Format.formatDate(date); - } - }, - controller: _dateController, - style: STextStyles.field, - decoration: InputDecoration( - hintText: "Restore from...", - suffixIcon: UnconstrainedBox( - child: Row( - children: [ - const SizedBox( - width: 16, - ), - SvgPicture.asset( - Assets.svg.calendar, - color: CFColors.neutral50, - width: 16, - height: 16, - ), - const SizedBox( - width: 12, - ), - ], - ), - ), - ), - key: const Key("restoreOptionsViewDatePickerKey"), - readOnly: true, - toolbarOptions: const ToolbarOptions( - copy: true, - cut: false, - paste: false, - selectAll: false, - ), - onChanged: (newValue) {}, - ), - ), - if (coin == Coin.monero || coin == Coin.epicCash) - const SizedBox( - height: 8, - ), - if (coin == Coin.monero || coin == Coin.epicCash) - RoundedWhiteContainer( - child: Center( - child: Text( - "Choose the date you made the wallet (approximate is fine)", - style: STextStyles.smallMed12.copyWith( - fontSize: 10, - ), - ), - ), - ), - if (coin == Coin.monero || coin == Coin.epicCash) - const SizedBox( - height: 16, - ), - Text( - "Choose recovery phrase length", - style: STextStyles.smallMed12, - textAlign: TextAlign.left, - ), - const SizedBox( - height: 8, - ), - Stack( - children: [ - TextField( - controller: _lengthController, - readOnly: true, - textInputAction: TextInputAction.none, - ), - Padding( - padding: const EdgeInsets.symmetric( - horizontal: 12, - ), - child: RawMaterialButton( - splashColor: CFColors.splashLight, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular( - Constants.size.circularBorderRadius, - ), - ), - onPressed: () { - showModalBottomSheet( - backgroundColor: Colors.transparent, - context: context, - shape: const RoundedRectangleBorder( - borderRadius: BorderRadius.vertical( - top: Radius.circular(20), - ), - ), - builder: (_) { - return MnemonicWordCountSelectSheet( - lengthOptions: - Constants.possibleLengthsForCoin( - coin), - ); - }, - ); - }, - child: Row( - mainAxisAlignment: - MainAxisAlignment.spaceBetween, - children: [ - Text( - "${ref.watch(mnemonicWordCountStateProvider.state).state} words", - style: STextStyles.itemSubtitle12, - ), - SvgPicture.asset( - Assets.svg.chevronDown, - width: 8, - height: 4, - color: CFColors.gray3, - ), - ], - ), - ), - ) - ], - ), - const Spacer( - flex: 3, - ), - TextButton( - onPressed: _nextEnabled - ? () async { - // hide keyboard if has focus - if (FocusScope.of(context).hasFocus) { - FocusScope.of(context).unfocus(); - await Future.delayed( - const Duration(milliseconds: 75)); - } - - if (mounted) { - Navigator.of(context).pushNamed( - RestoreWalletView.routeName, - arguments: Tuple4( - walletName, - coin, - ref - .read(mnemonicWordCountStateProvider - .state) - .state, - _restoreFromDate, - ), - ); - } - } - : null, - style: _nextEnabled - ? Theme.of(context) - .textButtonTheme - .style - ?.copyWith( - backgroundColor: - MaterialStateProperty.all( - CFColors.stackAccent, - ), - ) - : Theme.of(context) - .textButtonTheme - .style - ?.copyWith( - backgroundColor: - MaterialStateProperty.all( - CFColors.stackAccent.withOpacity( - 0.25, - ), - ), - ), - child: Text( - "Next", - style: STextStyles.button, - ), - ), - ], - ), - ), - ), - ); - }, - ), - ), - ), - ); - } -} diff --git a/lib/pages/add_wallet_views/restore_wallet_view/restore_options_view/restore_options_view.dart b/lib/pages/add_wallet_views/restore_wallet_view/restore_options_view/restore_options_view.dart new file mode 100644 index 000000000..5df7fd81d --- /dev/null +++ b/lib/pages/add_wallet_views/restore_wallet_view/restore_options_view/restore_options_view.dart @@ -0,0 +1,405 @@ +import 'package:dropdown_button2/dropdown_button2.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:flutter_rounded_date_picker/flutter_rounded_date_picker.dart'; +import 'package:flutter_svg/svg.dart'; +import 'package:google_fonts/google_fonts.dart'; +import 'package:stackwallet/pages/add_wallet_views/restore_wallet_view/restore_options_view/sub_widgets/mobile_mnemonic_length_selector.dart'; +import 'package:stackwallet/pages/add_wallet_views/restore_wallet_view/restore_options_view/sub_widgets/restore_from_date_picker.dart'; +import 'package:stackwallet/pages/add_wallet_views/restore_wallet_view/restore_options_view/sub_widgets/restore_options_next_button.dart'; +import 'package:stackwallet/pages/add_wallet_views/restore_wallet_view/restore_options_view/sub_widgets/restore_options_platform_layout.dart'; +import 'package:stackwallet/pages/add_wallet_views/restore_wallet_view/restore_wallet_view.dart'; +import 'package:stackwallet/pages/add_wallet_views/restore_wallet_view/sub_widgets/mnemonic_word_count_select_sheet.dart'; +import 'package:stackwallet/providers/ui/color_theme_provider.dart'; +import 'package:stackwallet/providers/ui/verify_recovery_phrase/mnemonic_word_count_state_provider.dart'; +import 'package:stackwallet/utilities/assets.dart'; +import 'package:stackwallet/utilities/constants.dart'; +import 'package:stackwallet/utilities/enums/coin_enum.dart'; +import 'package:stackwallet/utilities/format.dart'; +import 'package:stackwallet/utilities/text_styles.dart'; +import 'package:stackwallet/utilities/theme/stack_colors.dart'; +import 'package:stackwallet/utilities/util.dart'; +import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart'; +import 'package:stackwallet/widgets/desktop/desktop_app_bar.dart'; +import 'package:stackwallet/widgets/desktop/desktop_scaffold.dart'; +import 'package:stackwallet/widgets/rounded_white_container.dart'; +import 'package:tuple/tuple.dart'; + +class RestoreOptionsView extends ConsumerStatefulWidget { + const RestoreOptionsView({ + Key? key, + required this.walletName, + required this.coin, + }) : super(key: key); + + static const routeName = "/restoreOptions"; + + final String walletName; + final Coin coin; + + @override + ConsumerState createState() => _RestoreOptionsViewState(); +} + +class _RestoreOptionsViewState extends ConsumerState { + late final String walletName; + late final Coin coin; + late final bool isDesktop; + + late TextEditingController _dateController; + late FocusNode textFieldFocusNode; + + final bool _nextEnabled = true; + DateTime _restoreFromDate = DateTime.fromMillisecondsSinceEpoch(0); + late final Color baseColor; + + @override + void initState() { + baseColor = ref.read(colorThemeProvider.state).state.textSubtitle2; + walletName = widget.walletName; + coin = widget.coin; + isDesktop = Util.isDesktop; + + _dateController = TextEditingController(); + textFieldFocusNode = FocusNode(); + + super.initState(); + } + + @override + void dispose() { + _dateController.dispose(); + textFieldFocusNode.dispose(); + super.dispose(); + } + + TextStyle get _datePickerTextStyleBase => GoogleFonts.inter( + color: baseColor, + fontSize: 12, + fontWeight: FontWeight.w400, + letterSpacing: 0.5, + ); + MaterialRoundedDatePickerStyle _buildDatePickerStyle() { + return MaterialRoundedDatePickerStyle( + paddingMonthHeader: const EdgeInsets.only(top: 11), + colorArrowNext: Theme.of(context).extension()!.textSubtitle1, + colorArrowPrevious: + Theme.of(context).extension()!.textSubtitle1, + textStyleButtonNegative: _datePickerTextStyleBase.copyWith( + fontSize: 16, fontWeight: FontWeight.w600), + textStyleButtonPositive: _datePickerTextStyleBase.copyWith( + fontSize: 16, fontWeight: FontWeight.w600), + textStyleCurrentDayOnCalendar: _datePickerTextStyleBase.copyWith( + color: Theme.of(context).extension()!.accentColorDark, + ), + textStyleDayHeader: _datePickerTextStyleBase.copyWith( + color: Theme.of(context).extension()!.accentColorDark, + fontSize: 16, + fontWeight: FontWeight.w600, + ), + textStyleDayOnCalendar: _datePickerTextStyleBase, + textStyleDayOnCalendarDisabled: _datePickerTextStyleBase.copyWith( + color: Theme.of(context).extension()!.textSubtitle3, + ), + textStyleDayOnCalendarSelected: _datePickerTextStyleBase.copyWith( + color: Theme.of(context).extension()!.popupBG, + ), + textStyleMonthYearHeader: _datePickerTextStyleBase.copyWith( + color: Theme.of(context).extension()!.textSubtitle1, + fontSize: 16, + fontWeight: FontWeight.w600, + ), + textStyleYearButton: _datePickerTextStyleBase.copyWith( + color: Theme.of(context).extension()!.textWhite, + fontSize: 16, + fontWeight: FontWeight.w600, + ), + textStyleButtonAction: GoogleFonts.inter(), + ); + } + + MaterialRoundedYearPickerStyle _buildYearPickerStyle() { + return MaterialRoundedYearPickerStyle( + textStyleYear: _datePickerTextStyleBase.copyWith( + color: Theme.of(context).extension()!.textSubtitle2, + fontWeight: FontWeight.w600, + fontSize: 16, + ), + textStyleYearSelected: _datePickerTextStyleBase.copyWith( + color: Theme.of(context).extension()!.accentColorDark, + fontWeight: FontWeight.w600, + fontSize: 18, + ), + ); + } + + Future nextPressed() async { + if (!isDesktop) { + // hide keyboard if has focus + if (FocusScope.of(context).hasFocus) { + FocusScope.of(context).unfocus(); + await Future.delayed(const Duration(milliseconds: 75)); + } + } + + if (mounted) { + await Navigator.of(context).pushNamed( + RestoreWalletView.routeName, + arguments: Tuple4( + walletName, + coin, + ref.read(mnemonicWordCountStateProvider.state).state, + _restoreFromDate, + ), + ); + } + } + + Future chooseDate() async { + final height = MediaQuery.of(context).size.height; + // check and hide keyboard + if (FocusScope.of(context).hasFocus) { + FocusScope.of(context).unfocus(); + await Future.delayed(const Duration(milliseconds: 125)); + } + + final date = await showRoundedDatePicker( + context: context, + initialDate: DateTime.now(), + height: height * 0.5, + theme: ThemeData( + primarySwatch: Util.createMaterialColor( + Theme.of(context).extension()!.accentColorDark), + ), + //TODO pick a better initial date + // 2007 chosen as that is just before bitcoin launched + firstDate: DateTime(2007), + lastDate: DateTime.now(), + borderRadius: Constants.size.circularBorderRadius * 2, + + textPositiveButton: "SELECT", + + styleDatePicker: _buildDatePickerStyle(), + styleYearPicker: _buildYearPickerStyle(), + ); + if (date != null) { + _restoreFromDate = date; + _dateController.text = Format.formatDate(date); + } + } + + Future chooseMnemonicLength() async { + await showModalBottomSheet( + backgroundColor: Colors.transparent, + context: context, + shape: const RoundedRectangleBorder( + borderRadius: BorderRadius.vertical( + top: Radius.circular(20), + ), + ), + builder: (_) { + return MnemonicWordCountSelectSheet( + lengthOptions: Constants.possibleLengthsForCoin(coin), + ); + }, + ); + } + + @override + Widget build(BuildContext context) { + debugPrint("BUILD: $runtimeType with ${coin.name} $walletName"); + + final lengths = Constants.possibleLengthsForCoin(coin).toList(); + + return DesktopScaffold( + appBar: isDesktop + ? const DesktopAppBar( + isCompactHeight: false, + leading: AppBarBackButton(), + ) + : AppBar( + leading: AppBarBackButton( + onPressed: () { + if (textFieldFocusNode.hasFocus) { + textFieldFocusNode.unfocus(); + Future.delayed(const Duration(milliseconds: 100)) + .then((value) => Navigator.of(context).pop()); + } else { + Navigator.of(context).pop(); + } + }, + ), + ), + body: RestoreOptionsPlatformLayout( + isDesktop: isDesktop, + child: ConstrainedBox( + constraints: BoxConstraints( + maxWidth: isDesktop ? 480 : double.infinity, + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + if (!isDesktop) + const Spacer( + flex: 1, + ), + if (!isDesktop) + Image( + image: AssetImage( + Assets.png.imageFor(coin: coin), + ), + height: 100, + ), + SizedBox( + height: isDesktop ? 24 : 16, + ), + Text( + "Restore options", + textAlign: TextAlign.center, + style: isDesktop + ? STextStyles.desktopH2(context) + : STextStyles.pageTitleH1(context), + ), + SizedBox( + height: isDesktop ? 40 : 24, + ), + if (coin == Coin.monero || coin == Coin.epicCash) + Text( + "Choose start date", + style: isDesktop + ? STextStyles.desktopTextExtraSmall(context).copyWith( + color: Theme.of(context) + .extension()! + .textDark3, + ) + : STextStyles.smallMed12(context), + textAlign: TextAlign.left, + ), + if (coin == Coin.monero || coin == Coin.epicCash) + SizedBox( + height: isDesktop ? 16 : 8, + ), + if (coin == Coin.monero || coin == Coin.epicCash) + + // if (!isDesktop) + RestoreFromDatePicker( + onTap: chooseDate, + ), + + // if (isDesktop) + // // TODO desktop date picker + if (coin == Coin.monero || coin == Coin.epicCash) + const SizedBox( + height: 8, + ), + if (coin == Coin.monero || coin == Coin.epicCash) + RoundedWhiteContainer( + child: Center( + child: Text( + "Choose the date you made the wallet (approximate is fine)", + style: isDesktop + ? STextStyles.desktopTextExtraSmall(context).copyWith( + color: Theme.of(context) + .extension()! + .textSubtitle1, + ) + : STextStyles.smallMed12(context).copyWith( + fontSize: 10, + ), + ), + ), + ), + if (coin == Coin.monero || coin == Coin.epicCash) + SizedBox( + height: isDesktop ? 24 : 16, + ), + Text( + "Choose recovery phrase length", + style: isDesktop + ? STextStyles.desktopTextExtraSmall(context).copyWith( + color: Theme.of(context) + .extension()! + .textDark3, + ) + : STextStyles.smallMed12(context), + textAlign: TextAlign.left, + ), + SizedBox( + height: isDesktop ? 16 : 8, + ), + if (isDesktop) + DropdownButtonHideUnderline( + child: DropdownButton2( + value: + ref.watch(mnemonicWordCountStateProvider.state).state, + items: [ + ...lengths.map( + (e) => DropdownMenuItem( + value: e, + child: Text( + "$e words", + style: STextStyles.desktopTextMedium(context), + ), + ), + ), + ], + onChanged: (value) { + if (value is int) { + ref.read(mnemonicWordCountStateProvider.state).state = + value; + } + }, + isExpanded: true, + icon: SvgPicture.asset( + Assets.svg.chevronDown, + width: 12, + height: 6, + color: Theme.of(context) + .extension()! + .textFieldActiveSearchIconRight, + ), + buttonPadding: const EdgeInsets.symmetric( + horizontal: 16, + vertical: 8, + ), + buttonDecoration: BoxDecoration( + color: Theme.of(context) + .extension()! + .textFieldDefaultBG, + borderRadius: BorderRadius.circular( + Constants.size.circularBorderRadius, + ), + ), + dropdownDecoration: BoxDecoration( + color: Theme.of(context) + .extension()! + .textFieldDefaultBG, + borderRadius: BorderRadius.circular( + Constants.size.circularBorderRadius, + ), + ), + ), + ), + if (!isDesktop) + MobileMnemonicLengthSelector( + chooseMnemonicLength: chooseMnemonicLength, + ), + if (!isDesktop) + const Spacer( + flex: 3, + ), + if (isDesktop) + const SizedBox( + height: 32, + ), + RestoreOptionsNextButton( + isDesktop: isDesktop, + onPressed: _nextEnabled ? nextPressed : null, + ), + ], + ), + ), + ), + ); + } +} diff --git a/lib/pages/add_wallet_views/restore_wallet_view/restore_options_view/sub_widgets/mobile_mnemonic_length_selector.dart b/lib/pages/add_wallet_views/restore_wallet_view/restore_options_view/sub_widgets/mobile_mnemonic_length_selector.dart new file mode 100644 index 000000000..49896e107 --- /dev/null +++ b/lib/pages/add_wallet_views/restore_wallet_view/restore_options_view/sub_widgets/mobile_mnemonic_length_selector.dart @@ -0,0 +1,60 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:flutter_svg/svg.dart'; +import 'package:stackwallet/providers/ui/verify_recovery_phrase/mnemonic_word_count_state_provider.dart'; +import 'package:stackwallet/utilities/assets.dart'; +import 'package:stackwallet/utilities/constants.dart'; +import 'package:stackwallet/utilities/text_styles.dart'; +import 'package:stackwallet/utilities/theme/stack_colors.dart'; + +class MobileMnemonicLengthSelector extends ConsumerWidget { + const MobileMnemonicLengthSelector({ + Key? key, + required this.chooseMnemonicLength, + }) : super(key: key); + + final VoidCallback chooseMnemonicLength; + + @override + Widget build(BuildContext context, WidgetRef ref) { + return Stack( + children: [ + const TextField( + // controller: _lengthController, + readOnly: true, + textInputAction: TextInputAction.none, + ), + Padding( + padding: const EdgeInsets.symmetric( + horizontal: 12, + ), + child: RawMaterialButton( + splashColor: Theme.of(context).extension()!.highlight, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular( + Constants.size.circularBorderRadius, + ), + ), + onPressed: chooseMnemonicLength, + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + "${ref.watch(mnemonicWordCountStateProvider.state).state} words", + style: STextStyles.itemSubtitle12(context), + ), + SvgPicture.asset( + Assets.svg.chevronDown, + width: 8, + height: 4, + color: + Theme.of(context).extension()!.textSubtitle2, + ), + ], + ), + ), + ) + ], + ); + } +} diff --git a/lib/pages/add_wallet_views/restore_wallet_view/restore_options_view/sub_widgets/restore_from_date_picker.dart b/lib/pages/add_wallet_views/restore_wallet_view/restore_options_view/sub_widgets/restore_from_date_picker.dart new file mode 100644 index 000000000..0207a4c61 --- /dev/null +++ b/lib/pages/add_wallet_views/restore_wallet_view/restore_options_view/sub_widgets/restore_from_date_picker.dart @@ -0,0 +1,76 @@ +import 'package:flutter/material.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'; + +class RestoreFromDatePicker extends StatefulWidget { + const RestoreFromDatePicker({Key? key, required this.onTap}) + : super(key: key); + + final VoidCallback onTap; + + @override + State createState() => _RestoreFromDatePickerState(); +} + +class _RestoreFromDatePickerState extends State { + late final TextEditingController _dateController; + late final VoidCallback onTap; + + @override + void initState() { + onTap = widget.onTap; + _dateController = TextEditingController(); + + super.initState(); + } + + @override + void dispose() { + _dateController.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Container( + color: Colors.transparent, + child: TextField( + onTap: onTap, + controller: _dateController, + style: STextStyles.field(context), + decoration: InputDecoration( + hintText: "Restore from...", + suffixIcon: UnconstrainedBox( + child: Row( + children: [ + const SizedBox( + width: 16, + ), + SvgPicture.asset( + Assets.svg.calendar, + color: Theme.of(context).extension()!.textDark3, + width: 16, + height: 16, + ), + const SizedBox( + width: 12, + ), + ], + ), + ), + ), + key: const Key("restoreOptionsViewDatePickerKey"), + readOnly: true, + toolbarOptions: const ToolbarOptions( + copy: true, + cut: false, + paste: false, + selectAll: false, + ), + onChanged: (newValue) {}, + ), + ); + } +} diff --git a/lib/pages/add_wallet_views/restore_wallet_view/restore_options_view/sub_widgets/restore_options_next_button.dart b/lib/pages/add_wallet_views/restore_wallet_view/restore_options_view/sub_widgets/restore_options_next_button.dart new file mode 100644 index 000000000..502502f94 --- /dev/null +++ b/lib/pages/add_wallet_views/restore_wallet_view/restore_options_view/sub_widgets/restore_options_next_button.dart @@ -0,0 +1,37 @@ +import 'package:flutter/material.dart'; +import 'package:stackwallet/utilities/text_styles.dart'; +import 'package:stackwallet/utilities/theme/stack_colors.dart'; + +class RestoreOptionsNextButton extends StatelessWidget { + const RestoreOptionsNextButton({ + Key? key, + required this.isDesktop, + this.onPressed, + }) : super(key: key); + + final bool isDesktop; + final VoidCallback? onPressed; + + @override + Widget build(BuildContext context) { + return ConstrainedBox( + constraints: BoxConstraints( + minHeight: isDesktop ? 70 : 0, + ), + child: TextButton( + onPressed: onPressed, + style: onPressed != null + ? Theme.of(context) + .extension()! + .getPrimaryEnabledButtonColor(context) + : Theme.of(context) + .extension()! + .getPrimaryDisabledButtonColor(context), + child: Text( + "Next", + style: STextStyles.button(context), + ), + ), + ); + } +} diff --git a/lib/pages/add_wallet_views/restore_wallet_view/restore_options_view/sub_widgets/restore_options_platform_layout.dart b/lib/pages/add_wallet_views/restore_wallet_view/restore_options_view/sub_widgets/restore_options_platform_layout.dart new file mode 100644 index 000000000..12121cd7d --- /dev/null +++ b/lib/pages/add_wallet_views/restore_wallet_view/restore_options_view/sub_widgets/restore_options_platform_layout.dart @@ -0,0 +1,39 @@ +import 'package:flutter/material.dart'; +import 'package:stackwallet/utilities/theme/stack_colors.dart'; + +class RestoreOptionsPlatformLayout extends StatelessWidget { + const RestoreOptionsPlatformLayout({ + Key? key, + required this.isDesktop, + required this.child, + }) : super(key: key); + + final bool isDesktop; + final Widget child; + + @override + Widget build(BuildContext context) { + if (isDesktop) { + return child; + } else { + return Container( + color: Theme.of(context).extension()!.background, + child: Padding( + padding: const EdgeInsets.all(16), + child: LayoutBuilder( + builder: (ctx, constraints) { + return SingleChildScrollView( + child: ConstrainedBox( + constraints: BoxConstraints(minHeight: constraints.maxHeight), + child: IntrinsicHeight( + child: child, + ), + ), + ); + }, + ), + ), + ); + } + } +} diff --git a/lib/pages/add_wallet_views/restore_wallet_view/restore_wallet_view.dart b/lib/pages/add_wallet_views/restore_wallet_view/restore_wallet_view.dart index 4e4871bda..a0ac25383 100644 --- a/lib/pages/add_wallet_views/restore_wallet_view/restore_wallet_view.dart +++ b/lib/pages/add_wallet_views/restore_wallet_view/restore_wallet_view.dart @@ -16,6 +16,7 @@ import 'package:stackwallet/pages/add_wallet_views/restore_wallet_view/sub_widge import 'package:stackwallet/pages/add_wallet_views/restore_wallet_view/sub_widgets/restore_succeeded_dialog.dart'; import 'package:stackwallet/pages/add_wallet_views/restore_wallet_view/sub_widgets/restoring_dialog.dart'; import 'package:stackwallet/pages/home_view/home_view.dart'; +import 'package:stackwallet/pages_desktop_specific/home/desktop_home_view.dart'; import 'package:stackwallet/providers/providers.dart'; import 'package:stackwallet/services/coins/coin_service.dart'; import 'package:stackwallet/services/coins/manager.dart'; @@ -23,7 +24,6 @@ import 'package:stackwallet/services/transaction_notification_tracker.dart'; import 'package:stackwallet/utilities/address_utils.dart'; import 'package:stackwallet/utilities/assets.dart'; import 'package:stackwallet/utilities/barcode_scanner_interface.dart'; -import 'package:stackwallet/utilities/cfcolors.dart'; import 'package:stackwallet/utilities/clipboard_interface.dart'; import 'package:stackwallet/utilities/constants.dart'; import 'package:stackwallet/utilities/custom_text_selection_controls.dart'; @@ -33,6 +33,8 @@ import 'package:stackwallet/utilities/enums/flush_bar_type.dart'; import 'package:stackwallet/utilities/enums/form_input_status_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/utilities/util.dart'; import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart'; import 'package:stackwallet/widgets/icon_widgets/clipboard_icon.dart'; import 'package:stackwallet/widgets/icon_widgets/qrcode_icon.dart'; @@ -66,6 +68,7 @@ class RestoreWalletView extends ConsumerStatefulWidget { class _RestoreWalletViewState extends ConsumerState { final _formKey = GlobalKey(); late final int _seedWordCount; + late final bool isDesktop; final HashSet _wordListHashSet = HashSet.from(bip39wordlist.WORDLIST); final ScrollController controller = ScrollController(); @@ -85,13 +88,13 @@ class _RestoreWalletViewState extends ConsumerState { final text = data!.text!.trim(); if (text.isEmpty || _controllers.isEmpty) { - delegate.pasteText(SelectionChangedCause.toolbar); + unawaited(delegate.pasteText(SelectionChangedCause.toolbar)); return; } final words = text.split(" "); if (words.isEmpty) { - delegate.pasteText(SelectionChangedCause.toolbar); + unawaited(delegate.pasteText(SelectionChangedCause.toolbar)); return; } @@ -115,6 +118,7 @@ class _RestoreWalletViewState extends ConsumerState { @override void initState() { _seedWordCount = widget.seedWordsLength; + isDesktop = Util.isDesktop; textSelectionControls = Platform.isIOS ? CustomCupertinoTextSelectionControls(onPaste: onControlsPaste) @@ -190,13 +194,13 @@ class _RestoreWalletViewState extends ConsumerState { // TODO: do actual check to make sure it is a valid mnemonic for monero if (bip39.validateMnemonic(mnemonic) == false && !(widget.coin == Coin.monero)) { - showFloatingFlushBar( + unawaited(showFloatingFlushBar( type: FlushBarType.warning, message: "Invalid seed phrase!", context: context, - ); + )); } else { - if (!Platform.isLinux) Wakelock.enable(); + if (!Platform.isLinux) await Wakelock.enable(); final walletsService = ref.read(walletsServiceChangeNotifierProvider); final walletId = await walletsService.addNewWallet( @@ -206,7 +210,7 @@ class _RestoreWalletViewState extends ConsumerState { ); bool isRestoring = true; // show restoring in progress - showDialog( + unawaited(showDialog( context: context, useSafeArea: false, barrierDismissible: false, @@ -225,7 +229,7 @@ class _RestoreWalletViewState extends ConsumerState { }, ); }, - ); + )); var node = ref .read(nodeServiceChangeNotifierProvider) @@ -233,7 +237,7 @@ class _RestoreWalletViewState extends ConsumerState { if (node == null) { node = DefaultNodes.getNodeFor(widget.coin); - ref.read(nodeServiceChangeNotifierProvider).setPrimaryNodeFor( + await ref.read(nodeServiceChangeNotifierProvider).setPrimaryNodeFor( coin: widget.coin, node: node, ); @@ -282,26 +286,31 @@ class _RestoreWalletViewState extends ConsumerState { .addWallet(walletId: manager.walletId, manager: manager); if (mounted) { - Navigator.of(context).pushNamedAndRemoveUntil( - HomeView.routeName, (route) => false); + if (isDesktop) { + Navigator.of(context) + .popUntil(ModalRoute.withName(DesktopHomeView.routeName)); + } else { + unawaited(Navigator.of(context).pushNamedAndRemoveUntil( + HomeView.routeName, (route) => false)); + } } - showDialog( + await showDialog( context: context, useSafeArea: false, barrierDismissible: true, builder: (context) { return const RestoreSucceededDialog(); }, - ).then( - (_) { - if (!Platform.isLinux) Wakelock.disable(); - // timer.cancel(); - }, ); + if (!Platform.isLinux && !isDesktop) { + await Wakelock.disable(); + } } } catch (e) { - if (!Platform.isLinux) Wakelock.disable(); + if (!Platform.isLinux && !isDesktop) { + await Wakelock.disable(); + } // if (e is HiveError && // e.message == "Box has already been closed.") { @@ -316,7 +325,7 @@ class _RestoreWalletViewState extends ConsumerState { Navigator.pop(context); // show restoring wallet failed dialog - showDialog( + await showDialog( context: context, useSafeArea: false, barrierDismissible: true, @@ -331,7 +340,9 @@ class _RestoreWalletViewState extends ConsumerState { } } - if (!Platform.isLinux) Wakelock.disable(); + if (!Platform.isLinux && !isDesktop) { + await Wakelock.disable(); + } } } } @@ -343,27 +354,35 @@ class _RestoreWalletViewState extends ConsumerState { Widget? suffixIcon; switch (status) { case FormInputStatus.empty: - color = CFColors.fieldGray; - prefixColor = CFColors.gray3; + color = Theme.of(context).extension()!.textFieldDefaultBG; + prefixColor = Theme.of(context).extension()!.textSubtitle2; break; case FormInputStatus.invalid: - color = CFColors.notificationRedBackground; - prefixColor = CFColors.notificationRedForeground; + color = Theme.of(context).extension()!.textFieldErrorBG; + prefixColor = Theme.of(context) + .extension()! + .textFieldErrorSearchIconLeft; suffixIcon = SvgPicture.asset( Assets.svg.alertCircle, width: 16, height: 16, - color: CFColors.notificationRedForeground, + color: Theme.of(context) + .extension()! + .textFieldErrorSearchIconRight, ); break; case FormInputStatus.valid: - color = CFColors.notificationGreenBackground; - prefixColor = CFColors.notificationGreenForeground; + color = Theme.of(context).extension()!.textFieldSuccessBG; + prefixColor = Theme.of(context) + .extension()! + .textFieldSuccessSearchIconLeft; suffixIcon = SvgPicture.asset( Assets.svg.checkCircle, width: 16, height: 16, - color: CFColors.notificationGreenForeground, + color: Theme.of(context) + .extension()! + .textFieldSuccessSearchIconRight, ); break; } @@ -383,7 +402,7 @@ class _RestoreWalletViewState extends ConsumerState { ), child: Text( prefix, - style: STextStyles.fieldLabel.copyWith( + style: STextStyles.fieldLabel(context).copyWith( color: prefixColor, ), ), @@ -441,8 +460,71 @@ class _RestoreWalletViewState extends ConsumerState { }); } - controller.animateTo(controller.position.maxScrollExtent, - duration: const Duration(milliseconds: 300), curve: Curves.decelerate); + if (!isDesktop) { + controller.animateTo( + controller.position.maxScrollExtent, + duration: const Duration(milliseconds: 300), + curve: Curves.decelerate, + ); + } + } + + Future scanMnemonicQr() async { + try { + final qrResult = await scanner.scan(); + + final results = AddressUtils.decodeQRSeedData(qrResult.rawContent); + + Logging.instance.log("scan parsed: $results", level: LogLevel.Info); + + if (results["mnemonic"] != null) { + final list = (results["mnemonic"] as List) + .map((value) => value as String) + .toList(growable: false); + if (list.isNotEmpty) { + _clearAndPopulateMnemonic(list); + Logging.instance.log("mnemonic populated", level: LogLevel.Info); + } else { + Logging.instance + .log("mnemonic failed to populate", level: LogLevel.Info); + } + } + } on PlatformException catch (e) { + // likely failed to get camera permissions + Logging.instance + .log("Restore wallet qr scan failed: $e", level: LogLevel.Warning); + } + } + + Future pasteMnemonic() async { + debugPrint("restoreWalletPasteButton tapped"); + final ClipboardData? data = + await widget.clipboard.getData(Clipboard.kTextPlain); + + if (data?.text != null && data!.text!.isNotEmpty) { + final content = data.text!.trim(); + final list = content.split(" "); + _clearAndPopulateMnemonic(list); + } + } + + Future requestRestore() async { + // wait for keyboard to disappear + FocusScope.of(context).unfocus(); + await Future.delayed( + const Duration(milliseconds: 100), + ); + + await showDialog( + context: context, + useSafeArea: false, + barrierDismissible: true, + builder: (context) { + return ConfirmRecoveryDialog( + onConfirm: attemptRestore, + ); + }, + ); } @override @@ -473,41 +555,15 @@ class _RestoreWalletViewState extends ConsumerState { key: const Key("restoreWalletViewQrCodeButton"), size: 36, shadows: const [], - color: CFColors.almostWhite, - icon: const QrCodeIcon( + color: Theme.of(context).extension()!.background, + icon: QrCodeIcon( width: 20, height: 20, - color: CFColors.stackAccent, + color: Theme.of(context) + .extension()! + .accentColorDark, ), - onPressed: () async { - try { - final qrResult = await scanner.scan(); - - final results = - AddressUtils.decodeQRSeedData(qrResult.rawContent); - - Logging.instance - .log("scan parsed: $results", level: LogLevel.Info); - - if (results["mnemonic"] != null) { - final list = (results["mnemonic"] as List) - .map((value) => value as String) - .toList(growable: false); - if (list.isNotEmpty) { - _clearAndPopulateMnemonic(list); - Logging.instance - .log("mnemonic populated", level: LogLevel.Info); - } else { - Logging.instance.log("mnemonic failed to populate", - level: LogLevel.Info); - } - } - } on PlatformException catch (e) { - // likely failed to get camera permissions - Logging.instance.log("Restore wallet qr scan failed: $e", - level: LogLevel.Warning); - } - }, + onPressed: scanMnemonicQr, ), ), ), @@ -523,51 +579,43 @@ class _RestoreWalletViewState extends ConsumerState { key: const Key("restoreWalletPasteButton"), size: 36, shadows: const [], - color: CFColors.almostWhite, - icon: const ClipboardIcon( + color: Theme.of(context).extension()!.background, + icon: ClipboardIcon( width: 20, height: 20, - color: CFColors.stackAccent, + color: Theme.of(context) + .extension()! + .accentColorDark, ), - onPressed: () async { - debugPrint("restoreWalletPasteButton tapped"); - final ClipboardData? data = - await widget.clipboard.getData(Clipboard.kTextPlain); - - if (data?.text != null && data!.text!.isNotEmpty) { - final content = data.text!.trim(); - final list = content.split(" "); - _clearAndPopulateMnemonic(list); - } - }, + onPressed: pasteMnemonic, ), ), ), ], ), body: Container( - color: CFColors.almostWhite, + color: Theme.of(context).extension()!.background, child: Padding( padding: const EdgeInsets.all(12.0), child: Column( children: [ Text( widget.walletName, - style: STextStyles.itemSubtitle, + style: STextStyles.itemSubtitle(context), ), const SizedBox( height: 4, ), Text( "Recovery phrase", - style: STextStyles.pageTitleH1, + style: STextStyles.pageTitleH1(context), ), const SizedBox( height: 8, ), Text( "Enter your $_seedWordCount-word recovery phrase.", - style: STextStyles.subtitle, + style: STextStyles.subtitle(context), ), const SizedBox( height: 10, @@ -617,7 +665,11 @@ class _RestoreWalletViewState extends ConsumerState { } }, controller: _controllers[i - 1], - style: STextStyles.field, + style: STextStyles.field(context).copyWith( + color: Theme.of(context) + .extension()! + .overlay, + ), ), ), if (_inputStatuses[i - 1] == @@ -632,78 +684,29 @@ class _RestoreWalletViewState extends ConsumerState { child: Text( "Please check spelling", textAlign: TextAlign.left, - style: STextStyles.label.copyWith( - color: CFColors - .notificationRedForeground, + style: + STextStyles.label(context).copyWith( + color: Theme.of(context) + .extension()! + .textError, ), ), ), ) ], ), - // if (widget.coin == Coin.monero || - // widget.coin == Coin.epicCash) - // Padding( - // padding: const EdgeInsets.only( - // top: 8.0, - // ), - // child: ClipRRect( - // borderRadius: BorderRadius.circular( - // Constants.size.circularBorderRadius, - // ), - // child: TextField( - // key: Key("restoreMnemonicFormField_height"), - // inputFormatters: [ - // FilteringTextInputFormatter.allow( - // RegExp("[0-9]*")), - // ], - // keyboardType: - // TextInputType.numberWithOptions(), - // controller: _heightController, - // focusNode: _heightFocusNode, - // style: STextStyles.field, - // decoration: standardInputDecoration( - // "Height", - // _heightFocusNode, - // ), - // ), - // ), - // ), Padding( padding: const EdgeInsets.only( top: 8.0, ), child: TextButton( style: Theme.of(context) - .textButtonTheme - .style - ?.copyWith( - backgroundColor: - MaterialStateProperty.all( - CFColors.stackAccent, - ), - ), - onPressed: () async { - // wait for keyboard to disappear - FocusScope.of(context).unfocus(); - await Future.delayed( - const Duration(milliseconds: 100), - ); - - showDialog( - context: context, - useSafeArea: false, - barrierDismissible: true, - builder: (context) { - return ConfirmRecoveryDialog( - onConfirm: attemptRestore, - ); - }, - ); - }, + .extension()! + .getPrimaryEnabledButtonColor(context), + onPressed: requestRestore, child: Text( "Restore", - style: STextStyles.button, + style: STextStyles.button(context), ), ), ), diff --git a/lib/pages/add_wallet_views/restore_wallet_view/sub_widgets/mnemonic_word_count_select_sheet.dart b/lib/pages/add_wallet_views/restore_wallet_view/sub_widgets/mnemonic_word_count_select_sheet.dart index 50ab388ff..44bdf5f99 100644 --- a/lib/pages/add_wallet_views/restore_wallet_view/sub_widgets/mnemonic_word_count_select_sheet.dart +++ b/lib/pages/add_wallet_views/restore_wallet_view/sub_widgets/mnemonic_word_count_select_sheet.dart @@ -1,9 +1,9 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:stackwallet/providers/ui/verify_recovery_phrase/mnemonic_word_count_state_provider.dart'; -import 'package:stackwallet/utilities/cfcolors.dart'; import 'package:stackwallet/utilities/constants.dart'; import 'package:stackwallet/utilities/text_styles.dart'; +import 'package:stackwallet/utilities/theme/stack_colors.dart'; class MnemonicWordCountSelectSheet extends ConsumerWidget { const MnemonicWordCountSelectSheet({ @@ -22,9 +22,9 @@ class MnemonicWordCountSelectSheet extends ConsumerWidget { return false; }, child: Container( - decoration: const BoxDecoration( - color: CFColors.white, - borderRadius: BorderRadius.vertical( + decoration: BoxDecoration( + color: Theme.of(context).extension()!.popupBG, + borderRadius: const BorderRadius.vertical( top: Radius.circular(20), ), ), @@ -42,7 +42,9 @@ class MnemonicWordCountSelectSheet extends ConsumerWidget { Center( child: Container( decoration: BoxDecoration( - color: CFColors.fieldGray, + color: Theme.of(context) + .extension()! + .textFieldDefaultBG, borderRadius: BorderRadius.circular( Constants.size.circularBorderRadius, ), @@ -62,7 +64,7 @@ class MnemonicWordCountSelectSheet extends ConsumerWidget { children: [ Text( "Phrase length", - style: STextStyles.pageTitleH2, + style: STextStyles.pageTitleH2(context), textAlign: TextAlign.left, ), const SizedBox( @@ -96,7 +98,9 @@ class MnemonicWordCountSelectSheet extends ConsumerWidget { width: 20, height: 20, child: Radio( - activeColor: CFColors.link2, + activeColor: Theme.of(context) + .extension()! + .radioButtonIconEnabled, value: lengthOptions[i], groupValue: ref .watch(mnemonicWordCountStateProvider @@ -118,9 +122,7 @@ class MnemonicWordCountSelectSheet extends ConsumerWidget { ), Text( "${lengthOptions[i]} words", - style: STextStyles.titleBold12.copyWith( - color: const Color(0xFF44464E), - ), + style: STextStyles.titleBold12(context), textAlign: TextAlign.left, ), ], diff --git a/lib/pages/add_wallet_views/restore_wallet_view/sub_widgets/restore_failed_dialog.dart b/lib/pages/add_wallet_views/restore_wallet_view/sub_widgets/restore_failed_dialog.dart index 866223cfe..daf5cf1fc 100644 --- a/lib/pages/add_wallet_views/restore_wallet_view/sub_widgets/restore_failed_dialog.dart +++ b/lib/pages/add_wallet_views/restore_wallet_view/sub_widgets/restore_failed_dialog.dart @@ -1,8 +1,8 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:stackwallet/providers/providers.dart'; -import 'package:stackwallet/utilities/cfcolors.dart'; import 'package:stackwallet/utilities/text_styles.dart'; +import 'package:stackwallet/utilities/theme/stack_colors.dart'; import 'package:stackwallet/widgets/stack_dialog.dart'; class RestoreFailedDialog extends ConsumerStatefulWidget { @@ -45,14 +45,12 @@ class _RestoreFailedDialogState extends ConsumerState { title: "Restore failed", message: errorMessage, rightButton: TextButton( - style: Theme.of(context).textButtonTheme.style?.copyWith( - backgroundColor: MaterialStateProperty.all( - CFColors.buttonGray, - ), - ), + style: Theme.of(context) + .extension()! + .getSecondaryEnabledButtonColor(context), child: Text( "Ok", - style: STextStyles.itemSubtitle12, + style: STextStyles.itemSubtitle12(context), ), onPressed: () async { ref diff --git a/lib/pages/add_wallet_views/restore_wallet_view/sub_widgets/restore_succeeded_dialog.dart b/lib/pages/add_wallet_views/restore_wallet_view/sub_widgets/restore_succeeded_dialog.dart index 2cfdaba2a..2cd539c0c 100644 --- a/lib/pages/add_wallet_views/restore_wallet_view/sub_widgets/restore_succeeded_dialog.dart +++ b/lib/pages/add_wallet_views/restore_wallet_view/sub_widgets/restore_succeeded_dialog.dart @@ -1,8 +1,8 @@ import 'package:flutter/material.dart'; import 'package:flutter_svg/svg.dart'; import 'package:stackwallet/utilities/assets.dart'; -import 'package:stackwallet/utilities/cfcolors.dart'; import 'package:stackwallet/utilities/text_styles.dart'; +import 'package:stackwallet/utilities/theme/stack_colors.dart'; import 'package:stackwallet/widgets/stack_dialog.dart'; class RestoreSucceededDialog extends StatelessWidget { @@ -17,17 +17,15 @@ class RestoreSucceededDialog extends StatelessWidget { Assets.svg.checkCircle, width: 24, height: 24, - color: CFColors.stackGreen, + color: Theme.of(context).extension()!.accentColorGreen, ), rightButton: TextButton( - style: Theme.of(context).textButtonTheme.style?.copyWith( - backgroundColor: MaterialStateProperty.all( - CFColors.buttonGray, - ), - ), + style: Theme.of(context) + .extension()! + .getSecondaryEnabledButtonColor(context), child: Text( "Ok", - style: STextStyles.itemSubtitle12, + style: STextStyles.itemSubtitle12(context), ), onPressed: () { Navigator.of(context).pop(); diff --git a/lib/pages/add_wallet_views/restore_wallet_view/sub_widgets/restoring_dialog.dart b/lib/pages/add_wallet_views/restore_wallet_view/sub_widgets/restoring_dialog.dart index 59ad53c20..80a688d03 100644 --- a/lib/pages/add_wallet_views/restore_wallet_view/sub_widgets/restoring_dialog.dart +++ b/lib/pages/add_wallet_views/restore_wallet_view/sub_widgets/restoring_dialog.dart @@ -1,8 +1,8 @@ import 'package:flutter/material.dart'; import 'package:flutter_svg/svg.dart'; import 'package:stackwallet/utilities/assets.dart'; -import 'package:stackwallet/utilities/cfcolors.dart'; import 'package:stackwallet/utilities/text_styles.dart'; +import 'package:stackwallet/utilities/theme/stack_colors.dart'; import 'package:stackwallet/widgets/stack_dialog.dart'; class RestoringDialog extends StatefulWidget { @@ -59,22 +59,19 @@ class _RestoringDialogState extends State message: "This may take a while. Please do not exit this screen.", icon: RotationTransition( turns: _spinAnimation, - child: SvgPicture.asset( - Assets.svg.arrowRotate3, - width: 24, - height: 24, - color: CFColors.stackAccent, - ), + child: SvgPicture.asset(Assets.svg.arrowRotate3, + width: 24, + height: 24, + color: + Theme.of(context).extension()!.accentColorDark), ), rightButton: TextButton( - style: Theme.of(context).textButtonTheme.style?.copyWith( - backgroundColor: MaterialStateProperty.all( - CFColors.buttonGray, - ), - ), + style: Theme.of(context) + .extension()! + .getSecondaryEnabledButtonColor(context), child: Text( "Cancel", - style: STextStyles.itemSubtitle12, + style: STextStyles.itemSubtitle12(context), ), onPressed: () async { await onCancel.call(); diff --git a/lib/pages/add_wallet_views/verify_recovery_phrase_view/sub_widgets/word_table.dart b/lib/pages/add_wallet_views/verify_recovery_phrase_view/sub_widgets/word_table.dart index 0046607c4..768ed05af 100644 --- a/lib/pages/add_wallet_views/verify_recovery_phrase_view/sub_widgets/word_table.dart +++ b/lib/pages/add_wallet_views/verify_recovery_phrase_view/sub_widgets/word_table.dart @@ -6,9 +6,11 @@ class WordTable extends ConsumerWidget { const WordTable({ Key? key, required this.words, + required this.isDesktop, }) : super(key: key); final List words; + final bool isDesktop; static const wordsPerRow = 3; static const wordsToShow = 9; @@ -24,18 +26,19 @@ class WordTable extends ConsumerWidget { children: [ for (int i = 1; i <= rows; i++) Padding( - padding: const EdgeInsets.symmetric(vertical: 5), + padding: EdgeInsets.symmetric(vertical: isDesktop ? 8 : 5), child: Row( children: [ for (int j = 1; j <= wordsPerRow; j++) ...[ if (j > 1) - const SizedBox( - width: 6, + SizedBox( + width: isDesktop ? 10 : 6, ), Expanded( child: WordTableItem( number: ++index, word: words[index - 1], + isDesktop: isDesktop, ), ), ], diff --git a/lib/pages/add_wallet_views/verify_recovery_phrase_view/sub_widgets/word_table_item.dart b/lib/pages/add_wallet_views/verify_recovery_phrase_view/sub_widgets/word_table_item.dart index 3d7d87d22..1cdc1a4f8 100644 --- a/lib/pages/add_wallet_views/verify_recovery_phrase_view/sub_widgets/word_table_item.dart +++ b/lib/pages/add_wallet_views/verify_recovery_phrase_view/sub_widgets/word_table_item.dart @@ -1,19 +1,21 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:stackwallet/providers/providers.dart'; -import 'package:stackwallet/utilities/cfcolors.dart'; import 'package:stackwallet/utilities/constants.dart'; import 'package:stackwallet/utilities/text_styles.dart'; +import 'package:stackwallet/utilities/theme/stack_colors.dart'; class WordTableItem extends ConsumerWidget { const WordTableItem({ Key? key, required this.number, required this.word, + required this.isDesktop, }) : super(key: key); final int number; final String word; + final bool isDesktop; @override Widget build(BuildContext context, WidgetRef ref) { @@ -22,15 +24,22 @@ class WordTableItem extends ConsumerWidget { ref.watch(verifyMnemonicSelectedWordStateProvider.state).state; return Container( decoration: BoxDecoration( - color: selectedWord == word ? CFColors.selection : CFColors.white, + color: selectedWord == word + ? Theme.of(context).extension()!.snackBarBackInfo + : Theme.of(context).extension()!.popupBG, borderRadius: BorderRadius.circular( Constants.size.circularBorderRadius, ), ), child: MaterialButton( - splashColor: CFColors.splashLight, + splashColor: Theme.of(context).extension()!.highlight, key: Key("coinSelectItemButtonKey_$word"), - padding: const EdgeInsets.all(12), + padding: isDesktop + ? const EdgeInsets.symmetric( + vertical: 18, + horizontal: 12, + ) + : const EdgeInsets.all(12), materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, shape: RoundedRectangleBorder( borderRadius: @@ -45,7 +54,12 @@ class WordTableItem extends ConsumerWidget { Text( word, textAlign: TextAlign.center, - style: STextStyles.baseXS, + style: isDesktop + ? STextStyles.desktopTextExtraSmall(context).copyWith( + color: + Theme.of(context).extension()!.textDark, + ) + : STextStyles.baseXS(context), ), ], ), diff --git a/lib/pages/add_wallet_views/verify_recovery_phrase_view/verify_recovery_phrase_view.dart b/lib/pages/add_wallet_views/verify_recovery_phrase_view/verify_recovery_phrase_view.dart index 6e0c1dd2b..cdfff73ca 100644 --- a/lib/pages/add_wallet_views/verify_recovery_phrase_view/verify_recovery_phrase_view.dart +++ b/lib/pages/add_wallet_views/verify_recovery_phrase_view/verify_recovery_phrase_view.dart @@ -1,3 +1,4 @@ +import 'dart:async'; import 'dart:math'; import 'package:flutter/material.dart'; @@ -6,14 +7,19 @@ import 'package:stackwallet/notifications/show_flush_bar.dart'; import 'package:stackwallet/pages/add_wallet_views/new_wallet_recovery_phrase_view/new_wallet_recovery_phrase_view.dart'; import 'package:stackwallet/pages/add_wallet_views/verify_recovery_phrase_view/sub_widgets/word_table.dart'; import 'package:stackwallet/pages/home_view/home_view.dart'; +import 'package:stackwallet/pages_desktop_specific/home/desktop_home_view.dart'; +import 'package:stackwallet/pages_desktop_specific/home/my_stack_view/exit_to_my_stack_button.dart'; import 'package:stackwallet/providers/providers.dart'; import 'package:stackwallet/services/coins/manager.dart'; import 'package:stackwallet/utilities/assets.dart'; -import 'package:stackwallet/utilities/cfcolors.dart'; import 'package:stackwallet/utilities/constants.dart'; import 'package:stackwallet/utilities/enums/flush_bar_type.dart'; import 'package:stackwallet/utilities/text_styles.dart'; +import 'package:stackwallet/utilities/theme/stack_colors.dart'; +import 'package:stackwallet/utilities/util.dart'; import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart'; +import 'package:stackwallet/widgets/desktop/desktop_app_bar.dart'; +import 'package:stackwallet/widgets/desktop/desktop_scaffold.dart'; import 'package:tuple/tuple.dart'; class VerifyRecoveryPhraseView extends ConsumerStatefulWidget { @@ -39,11 +45,13 @@ class _VerifyRecoveryPhraseViewState { late Manager _manager; late List _mnemonic; + late final bool isDesktop; @override void initState() { _manager = widget.manager; _mnemonic = widget.mnemonic; + isDesktop = Util.isDesktop; // WidgetsBinding.instance?.addObserver(this); super.initState(); } @@ -75,6 +83,62 @@ class _VerifyRecoveryPhraseViewState // } // } + Future _continue(bool isMatch) async { + if (isMatch) { + await ref.read(walletsServiceChangeNotifierProvider).setMnemonicVerified( + walletId: _manager.walletId, + ); + + ref + .read(walletsChangeNotifierProvider.notifier) + .addWallet(walletId: _manager.walletId, manager: _manager); + + if (mounted) { + if (isDesktop) { + Navigator.of(context).popUntil( + ModalRoute.withName( + DesktopHomeView.routeName, + ), + ); + } else { + unawaited( + Navigator.of(context).pushNamedAndRemoveUntil( + HomeView.routeName, + (route) => false, + ), + ); + } + } + + unawaited(showFloatingFlushBar( + type: FlushBarType.success, + message: "Correct! Your wallet is set up.", + iconAsset: Assets.svg.check, + context: context, + )); + } else { + unawaited(showFloatingFlushBar( + type: FlushBarType.warning, + message: "Incorrect. Please try again.", + iconAsset: Assets.svg.circleX, + context: context, + )); + + final int next = Random().nextInt(_mnemonic.length); + ref + .read(verifyMnemonicWordIndexStateProvider.state) + .update((state) => next); + + ref + .read(verifyMnemonicCorrectWordStateProvider.state) + .update((state) => _mnemonic[next]); + + ref + .read(verifyMnemonicSelectedWordStateProvider.state) + .update((state) => ""); + } + } + Tuple2, String> randomize( List mnemonic, int chosenIndex, int wordsToShow) { final List remaining = []; @@ -113,12 +177,12 @@ class _VerifyRecoveryPhraseViewState return false; } - // Future delete() async { - // await ref - // .read(walletsServiceChangeNotifierProvider) - // .deleteWallet(_manager.walletName, false); - // await _manager.exitCurrentWallet(); - // } + Future delete() async { + await ref + .read(walletsServiceChangeNotifierProvider) + .deleteWallet(_manager.walletName, false); + await _manager.exitCurrentWallet(); + } @override Widget build(BuildContext context) { @@ -128,51 +192,80 @@ class _VerifyRecoveryPhraseViewState return WillPopScope( onWillPop: onWillPop, - child: Scaffold( - appBar: AppBar( - leading: AppBarBackButton( - onPressed: () async { - // await delete(); - Navigator.of(context).popUntil( - ModalRoute.withName( - // NewWalletRecoveryPhraseWarningView.routeName, - NewWalletRecoveryPhraseView.routeName, + child: MasterScaffold( + isDesktop: isDesktop, + appBar: isDesktop + ? DesktopAppBar( + isCompactHeight: false, + leading: AppBarBackButton( + onPressed: () async { + Navigator.of(context).popUntil( + ModalRoute.withName( + NewWalletRecoveryPhraseView.routeName, + ), + ); + }, ), - ); - }, - ), - ), - body: Container( - color: CFColors.almostWhite, + trailing: ExitToMyStackButton( + onPressed: () async { + await delete(); + if (mounted) { + Navigator.of(context).popUntil( + ModalRoute.withName(DesktopHomeView.routeName), + ); + } + }, + ), + ) + : AppBar( + leading: AppBarBackButton( + onPressed: () async { + Navigator.of(context).popUntil( + ModalRoute.withName( + NewWalletRecoveryPhraseView.routeName, + ), + ); + }, + ), + ), + body: SizedBox( + width: isDesktop ? 410 : null, child: Padding( - padding: const EdgeInsets.all(16), + padding: + isDesktop ? const EdgeInsets.all(0) : const EdgeInsets.all(16), child: Column( crossAxisAlignment: CrossAxisAlignment.center, children: [ - const SizedBox( - height: 4, + SizedBox( + height: isDesktop ? 24 : 4, ), Text( "Verify recovery phrase", textAlign: TextAlign.center, - style: STextStyles.label.copyWith( - fontSize: 12, - ), + style: isDesktop + ? STextStyles.desktopH2(context) + : STextStyles.label(context).copyWith( + fontSize: 12, + ), ), - const SizedBox( - height: 4, + SizedBox( + height: isDesktop ? 16 : 4, ), Text( - "Tap word number ", + isDesktop ? "Select word number" : "Tap word number ", textAlign: TextAlign.center, - style: STextStyles.pageTitleH1, + style: isDesktop + ? STextStyles.desktopSubtitleH1(context) + : STextStyles.pageTitleH1(context), ), - const SizedBox( - height: 12, + SizedBox( + height: isDesktop ? 16 : 12, ), Container( decoration: BoxDecoration( - color: CFColors.fieldGray, + color: Theme.of(context) + .extension()! + .textFieldDefaultBG, borderRadius: BorderRadius.circular( Constants.size.circularBorderRadius), ), @@ -184,7 +277,7 @@ class _VerifyRecoveryPhraseViewState child: Text( "${correctIndex + 1}", textAlign: TextAlign.center, - style: STextStyles.subtitle.copyWith( + style: STextStyles.subtitle(context).copyWith( fontWeight: FontWeight.w600, fontSize: 32, letterSpacing: 0.25, @@ -192,10 +285,19 @@ class _VerifyRecoveryPhraseViewState ), ), ), + if (isDesktop) + const SizedBox( + height: 40, + ), WordTable( words: randomize(_mnemonic, correctIndex, 9).item1, + isDesktop: isDesktop, ), - const Spacer(), + if (!isDesktop) const Spacer(), + if (isDesktop) + const SizedBox( + height: 40, + ), Row( children: [ Expanded( @@ -210,92 +312,37 @@ class _VerifyRecoveryPhraseViewState verifyMnemonicCorrectWordStateProvider.state) .state; - return TextButton( - onPressed: selectedWord.isNotEmpty - ? () async { - if (correctWord == selectedWord) { - await ref - .read( - walletsServiceChangeNotifierProvider) - .setMnemonicVerified( - walletId: _manager.walletId, - ); - - ref - .read(walletsChangeNotifierProvider - .notifier) - .addWallet( - walletId: _manager.walletId, - manager: _manager); - - if (mounted) { - Navigator.of(context) - .pushNamedAndRemoveUntil( - HomeView.routeName, - (route) => false); - } - - showFloatingFlushBar( - type: FlushBarType.success, - message: - "Correct! Your wallet is set up.", - iconAsset: Assets.svg.check, - context: context, - ); - } else { - showFloatingFlushBar( - type: FlushBarType.warning, - message: "Incorrect. Please try again.", - iconAsset: Assets.svg.circleX, - context: context, - ); - - final int next = - Random().nextInt(_mnemonic.length); - ref - .read( - verifyMnemonicWordIndexStateProvider - .state) - .update((state) => next); - - ref - .read( - verifyMnemonicCorrectWordStateProvider - .state) - .update((state) => _mnemonic[next]); - - ref - .read( - verifyMnemonicSelectedWordStateProvider - .state) - .update((state) => ""); + return ConstrainedBox( + constraints: BoxConstraints( + minHeight: isDesktop ? 70 : 0, + ), + child: TextButton( + onPressed: selectedWord.isNotEmpty + ? () async { + await _continue( + correctWord == selectedWord); } - } - : null, - style: selectedWord.isNotEmpty - ? Theme.of(context) - .textButtonTheme - .style - ?.copyWith( - backgroundColor: - MaterialStateProperty.all( - CFColors.stackAccent, - ), + : null, + style: selectedWord.isNotEmpty + ? Theme.of(context) + .extension()! + .getPrimaryEnabledButtonColor(context) + : Theme.of(context) + .extension()! + .getPrimaryDisabledButtonColor(context), + child: isDesktop + ? Text( + "Verify", + style: selectedWord.isNotEmpty + ? STextStyles.desktopButtonEnabled( + context) + : STextStyles.desktopButtonDisabled( + context), ) - : Theme.of(context) - .textButtonTheme - .style - ?.copyWith( - backgroundColor: - MaterialStateProperty.all( - CFColors.stackAccent.withOpacity( - 0.25, - ), - ), + : Text( + "Continue", + style: STextStyles.button(context), ), - child: Text( - "Continue", - style: STextStyles.button, ), ); }, diff --git a/lib/pages/address_book_views/address_book_view.dart b/lib/pages/address_book_views/address_book_view.dart index 3266d5986..b70ef19ed 100644 --- a/lib/pages/address_book_views/address_book_view.dart +++ b/lib/pages/address_book_views/address_book_view.dart @@ -9,10 +9,10 @@ import 'package:stackwallet/providers/global/address_book_service_provider.dart' import 'package:stackwallet/providers/providers.dart'; import 'package:stackwallet/providers/ui/address_book_providers/address_book_filter_provider.dart'; import 'package:stackwallet/utilities/assets.dart'; -import 'package:stackwallet/utilities/cfcolors.dart'; import 'package:stackwallet/utilities/constants.dart'; import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/text_styles.dart'; +import 'package:stackwallet/utilities/theme/stack_colors.dart'; import 'package:stackwallet/widgets/address_book_card.dart'; import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart'; import 'package:stackwallet/widgets/icon_widgets/x_icon.dart'; @@ -102,7 +102,7 @@ class _AddressBookViewState extends ConsumerState { addressBookServiceProvider.select((value) => value.addressBookEntries)); return Scaffold( - backgroundColor: CFColors.almostWhite, + backgroundColor: Theme.of(context).extension()!.background, appBar: AppBar( leading: AppBarBackButton( onPressed: () { @@ -111,7 +111,7 @@ class _AddressBookViewState extends ConsumerState { ), title: Text( "Address book", - style: STextStyles.navBarTitle, + style: STextStyles.navBarTitle(context), ), actions: [ Padding( @@ -126,10 +126,12 @@ class _AddressBookViewState extends ConsumerState { key: const Key("addressBookFilterViewButton"), size: 36, shadows: const [], - color: CFColors.almostWhite, + color: Theme.of(context).extension()!.background, icon: SvgPicture.asset( Assets.svg.filter, - color: CFColors.stackAccent, + color: Theme.of(context) + .extension()! + .accentColorDark, width: 20, height: 20, ), @@ -153,10 +155,12 @@ class _AddressBookViewState extends ConsumerState { key: const Key("addressBookAddNewContactViewButton"), size: 36, shadows: const [], - color: CFColors.almostWhite, + color: Theme.of(context).extension()!.background, icon: SvgPicture.asset( Assets.svg.plus, - color: CFColors.stackAccent, + color: Theme.of(context) + .extension()! + .accentColorDark, width: 20, height: 20, ), @@ -201,10 +205,11 @@ class _AddressBookViewState extends ConsumerState { _searchTerm = value; }); }, - style: STextStyles.field, + style: STextStyles.field(context), decoration: standardInputDecoration( "Search", _searchFocusNode, + context, ).copyWith( prefixIcon: Padding( padding: const EdgeInsets.symmetric( @@ -244,7 +249,7 @@ class _AddressBookViewState extends ConsumerState { ), Text( "Favorites", - style: STextStyles.smallMed12, + style: STextStyles.smallMed12(context), ), const SizedBox( height: 12, @@ -297,7 +302,7 @@ class _AddressBookViewState extends ConsumerState { child: Center( child: Text( "Your favorite contacts will appear here", - style: STextStyles.itemSubtitle, + style: STextStyles.itemSubtitle(context), ), ), ); @@ -310,7 +315,7 @@ class _AddressBookViewState extends ConsumerState { ), Text( "All contacts", - style: STextStyles.smallMed12, + style: STextStyles.smallMed12(context), ), const SizedBox( height: 12, @@ -360,7 +365,7 @@ class _AddressBookViewState extends ConsumerState { child: Center( child: Text( "Your contacts will appear here", - style: STextStyles.itemSubtitle, + style: STextStyles.itemSubtitle(context), ), ), ); 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 9d0eede18..a28997e0f 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 @@ -11,10 +11,10 @@ import 'package:stackwallet/providers/ui/address_book_providers/contact_name_is_ import 'package:stackwallet/providers/ui/address_book_providers/valid_contact_state_provider.dart'; import 'package:stackwallet/utilities/assets.dart'; import 'package:stackwallet/utilities/barcode_scanner_interface.dart'; -import 'package:stackwallet/utilities/cfcolors.dart'; import 'package:stackwallet/utilities/clipboard_interface.dart'; 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/emoji_select_sheet.dart'; import 'package:stackwallet/widgets/icon_widgets/x_icon.dart'; @@ -93,7 +93,7 @@ class _AddAddressBookEntryViewState debugPrint("BUILD: $runtimeType"); return Scaffold( - backgroundColor: CFColors.almostWhite, + backgroundColor: Theme.of(context).extension()!.background, appBar: AppBar( leading: AppBarBackButton( onPressed: () async { @@ -108,7 +108,7 @@ class _AddAddressBookEntryViewState ), title: Text( "New contact", - style: STextStyles.navBarTitle, + style: STextStyles.navBarTitle(context), ), actions: [ Padding( @@ -123,10 +123,16 @@ class _AddAddressBookEntryViewState key: const Key("addAddressBookEntryFavoriteButtonKey"), size: 36, shadows: const [], - color: CFColors.almostWhite, + color: Theme.of(context).extension()!.background, icon: SvgPicture.asset( Assets.svg.star, - color: _isFavorite ? CFColors.link2 : CFColors.buttonGray, + color: _isFavorite + ? Theme.of(context) + .extension()! + .favoriteStarActive + : Theme.of(context) + .extension()! + .favoriteStarInactive, width: 20, height: 20, ), @@ -198,7 +204,9 @@ class _AddAddressBookEntryViewState width: 48, decoration: BoxDecoration( borderRadius: BorderRadius.circular(24), - color: CFColors.textFieldActive, + color: Theme.of(context) + .extension()! + .textFieldActiveBG, ), child: Center( child: _selectedEmoji == null @@ -209,7 +217,8 @@ class _AddAddressBookEntryViewState ) : Text( _selectedEmoji!.char, - style: STextStyles.pageTitleH1, + style: + STextStyles.pageTitleH1(context), ), ), ), @@ -219,20 +228,25 @@ class _AddAddressBookEntryViewState height: 14, width: 14, decoration: BoxDecoration( - borderRadius: BorderRadius.circular(14), - color: CFColors.stackAccent, - ), + borderRadius: BorderRadius.circular(14), + color: Theme.of(context) + .extension()! + .accentColorDark), child: Center( child: _selectedEmoji == null ? SvgPicture.asset( Assets.svg.plus, - color: CFColors.white, + color: Theme.of(context) + .extension()! + .textWhite, width: 12, height: 12, ) : SvgPicture.asset( Assets.svg.thickX, - color: CFColors.white, + color: Theme.of(context) + .extension()! + .textWhite, width: 8, height: 8, ), @@ -253,10 +267,11 @@ class _AddAddressBookEntryViewState child: TextField( controller: nameController, focusNode: nameFocusNode, - style: STextStyles.field, + style: STextStyles.field(context), decoration: standardInputDecoration( "Enter contact name", nameFocusNode, + context, ).copyWith( suffixIcon: ref .read(contactNameIsNotEmptyStateProvider @@ -303,7 +318,7 @@ class _AddAddressBookEntryViewState ), Text( "Address ${i + 1}", - style: STextStyles.smallMed12, + style: STextStyles.smallMed12(context), ), const SizedBox( height: 8, @@ -325,7 +340,7 @@ class _AddAddressBookEntryViewState }, child: Text( "+ Add another address", - style: STextStyles.largeMedium14, + style: STextStyles.largeMedium14(context), ), ), const SizedBox( @@ -336,17 +351,15 @@ class _AddAddressBookEntryViewState children: [ Expanded( child: TextButton( - style: ButtonStyle( - backgroundColor: - MaterialStateProperty.all( - CFColors.buttonGray, - ), - ), + style: Theme.of(context) + .extension()! + .getSecondaryEnabledButtonColor(context), child: Text( "Cancel", - style: STextStyles.button.copyWith( - color: CFColors.stackAccent, - ), + style: STextStyles.button(context).copyWith( + color: Theme.of(context) + .extension()! + .accentColorDark), ), onPressed: () async { if (FocusScope.of(context).hasFocus) { @@ -380,13 +393,14 @@ class _AddAddressBookEntryViewState validForms && nameExists; return TextButton( - style: ButtonStyle( - backgroundColor: - MaterialStateProperty.all( - shouldEnableSave - ? CFColors.stackAccent - : CFColors.disabledButton, - )), + style: shouldEnableSave + ? Theme.of(context) + .extension()! + .getPrimaryEnabledButtonColor(context) + : Theme.of(context) + .extension()! + .getPrimaryDisabledButtonColor( + context), onPressed: shouldEnableSave ? () async { if (FocusScope.of(context).hasFocus) { @@ -424,7 +438,7 @@ class _AddAddressBookEntryViewState : null, child: Text( "Save", - style: STextStyles.button, + style: STextStyles.button(context), ), ); }, diff --git a/lib/pages/address_book_views/subviews/add_new_contact_address_view.dart b/lib/pages/address_book_views/subviews/add_new_contact_address_view.dart index 50d03aef7..e5dbaa7b9 100644 --- a/lib/pages/address_book_views/subviews/add_new_contact_address_view.dart +++ b/lib/pages/address_book_views/subviews/add_new_contact_address_view.dart @@ -9,9 +9,9 @@ import 'package:stackwallet/providers/ui/address_book_providers/address_entry_da import 'package:stackwallet/providers/ui/address_book_providers/valid_contact_state_provider.dart'; import 'package:stackwallet/utilities/assets.dart'; import 'package:stackwallet/utilities/barcode_scanner_interface.dart'; -import 'package:stackwallet/utilities/cfcolors.dart'; import 'package:stackwallet/utilities/clipboard_interface.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'; class AddNewContactAddressView extends ConsumerStatefulWidget { @@ -56,7 +56,7 @@ class _AddNewContactAddressViewState .select((value) => value.getContactById(contactId))); return Scaffold( - backgroundColor: CFColors.almostWhite, + backgroundColor: Theme.of(context).extension()!.background, appBar: AppBar( leading: AppBarBackButton( onPressed: () async { @@ -71,7 +71,7 @@ class _AddNewContactAddressViewState ), title: Text( "Add new address", - style: STextStyles.navBarTitle, + style: STextStyles.navBarTitle(context), ), ), body: LayoutBuilder( @@ -99,7 +99,9 @@ class _AddNewContactAddressViewState width: 48, decoration: BoxDecoration( borderRadius: BorderRadius.circular(24), - color: CFColors.textFieldActive, + color: Theme.of(context) + .extension()! + .textFieldActiveBG, ), child: Center( child: contact.emojiChar == null @@ -110,7 +112,7 @@ class _AddNewContactAddressViewState ) : Text( contact.emojiChar!, - style: STextStyles.pageTitleH1, + style: STextStyles.pageTitleH1(context), ), ), ), @@ -122,7 +124,7 @@ class _AddNewContactAddressViewState fit: BoxFit.scaleDown, child: Text( contact.name, - style: STextStyles.pageTitleH2, + style: STextStyles.pageTitleH2(context), ), ), ), @@ -144,17 +146,15 @@ class _AddNewContactAddressViewState children: [ Expanded( child: TextButton( - style: ButtonStyle( - backgroundColor: - MaterialStateProperty.all( - CFColors.buttonGray, - ), - ), + style: Theme.of(context) + .extension()! + .getSecondaryEnabledButtonColor(context), child: Text( "Cancel", - style: STextStyles.button.copyWith( - color: CFColors.stackAccent, - ), + style: STextStyles.button(context).copyWith( + color: Theme.of(context) + .extension()! + .accentColorDark), ), onPressed: () async { if (FocusScope.of(context).hasFocus) { @@ -178,14 +178,15 @@ class _AddNewContactAddressViewState ref.watch(validContactStateProvider([0])); return TextButton( - style: ButtonStyle( - backgroundColor: - MaterialStateProperty.all( - shouldEnableSave - ? CFColors.stackAccent - : CFColors.disabledButton, - ), - ), + style: shouldEnableSave + ? Theme.of(context) + .extension()! + .getPrimaryEnabledButtonColor( + context) + : Theme.of(context) + .extension()! + .getPrimaryDisabledButtonColor( + context), onPressed: shouldEnableSave ? () async { if (FocusScope.of(context) @@ -222,7 +223,7 @@ class _AddNewContactAddressViewState : null, child: Text( "Save", - style: STextStyles.button, + style: STextStyles.button(context), ), ); }, diff --git a/lib/pages/address_book_views/subviews/address_book_filter_view.dart b/lib/pages/address_book_views/subviews/address_book_filter_view.dart index e990919de..35968621a 100644 --- a/lib/pages/address_book_views/subviews/address_book_filter_view.dart +++ b/lib/pages/address_book_views/subviews/address_book_filter_view.dart @@ -2,9 +2,9 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:stackwallet/providers/global/prefs_provider.dart'; import 'package:stackwallet/providers/ui/address_book_providers/address_book_filter_provider.dart'; -import 'package:stackwallet/utilities/cfcolors.dart'; import 'package:stackwallet/utilities/enums/coin_enum.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/rounded_white_container.dart'; @@ -42,9 +42,9 @@ class _AddressBookFilterViewState extends ConsumerState { @override Widget build(BuildContext context) { return Scaffold( - backgroundColor: CFColors.almostWhite, + backgroundColor: Theme.of(context).extension()!.background, appBar: AppBar( - backgroundColor: CFColors.almostWhite, + backgroundColor: Theme.of(context).extension()!.background, leading: AppBarBackButton( onPressed: () async { Navigator.of(context).pop(); @@ -52,7 +52,7 @@ class _AddressBookFilterViewState extends ConsumerState { ), title: Text( "Filter addresses", - style: STextStyles.navBarTitle, + style: STextStyles.navBarTitle(context), ), ), body: Padding( @@ -72,7 +72,7 @@ class _AddressBookFilterViewState extends ConsumerState { RoundedWhiteContainer( child: Text( "Only selected cryptocurrency addresses will be displayed.", - style: STextStyles.itemSubtitle, + style: STextStyles.itemSubtitle(context), ), ), const SizedBox( @@ -80,7 +80,7 @@ class _AddressBookFilterViewState extends ConsumerState { ), Text( "Select cryptocurrency", - style: STextStyles.smallMed12, + style: STextStyles.smallMed12(context), ), const SizedBox( height: 12, @@ -154,7 +154,8 @@ class _AddressBookFilterViewState extends ConsumerState { Text( coin.prettyName, style: - STextStyles.largeMedium14, + STextStyles.largeMedium14( + context), ), const SizedBox( height: 2, @@ -162,7 +163,8 @@ class _AddressBookFilterViewState extends ConsumerState { Text( coin.ticker, style: - STextStyles.itemSubtitle, + STextStyles.itemSubtitle( + context), ), ], ) diff --git a/lib/pages/address_book_views/subviews/coin_select_sheet.dart b/lib/pages/address_book_views/subviews/coin_select_sheet.dart index 5008a688f..7be2f8739 100644 --- a/lib/pages/address_book_views/subviews/coin_select_sheet.dart +++ b/lib/pages/address_book_views/subviews/coin_select_sheet.dart @@ -3,10 +3,10 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_svg/svg.dart'; import 'package:stackwallet/providers/global/prefs_provider.dart'; import 'package:stackwallet/utilities/assets.dart'; -import 'package:stackwallet/utilities/cfcolors.dart'; import 'package:stackwallet/utilities/constants.dart'; import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/text_styles.dart'; +import 'package:stackwallet/utilities/theme/stack_colors.dart'; class CoinSelectSheet extends StatelessWidget { const CoinSelectSheet({Key? key}) : super(key: key); @@ -17,9 +17,9 @@ class CoinSelectSheet extends StatelessWidget { var coins_ = [...Coin.values]; coins_.remove(Coin.firoTestNet); return Container( - decoration: const BoxDecoration( - color: CFColors.white, - borderRadius: BorderRadius.vertical( + decoration: BoxDecoration( + color: Theme.of(context).extension()!.popupBG, + borderRadius: const BorderRadius.vertical( top: Radius.circular(20), ), ), @@ -39,7 +39,9 @@ class CoinSelectSheet extends StatelessWidget { Center( child: Container( decoration: BoxDecoration( - color: CFColors.fieldGray, + color: Theme.of(context) + .extension()! + .textFieldDefaultBG, borderRadius: BorderRadius.circular( Constants.size.circularBorderRadius, ), @@ -53,7 +55,7 @@ class CoinSelectSheet extends StatelessWidget { ), Text( "Select address cryptocurrency", - style: STextStyles.pageTitleH2, + style: STextStyles.pageTitleH2(context), textAlign: TextAlign.left, ), const SizedBox( @@ -77,7 +79,7 @@ class CoinSelectSheet extends StatelessWidget { return Padding( padding: const EdgeInsets.symmetric(vertical: 4), child: RawMaterialButton( - // splashColor: CFColors.splashLight, + // splashColor: Theme.of(context).extension()!.highlight, onPressed: () { Navigator.of(context).pop(coin); }, @@ -95,7 +97,7 @@ class CoinSelectSheet extends StatelessWidget { ), Text( coin.prettyName, - style: STextStyles.itemSubtitle12, + style: STextStyles.itemSubtitle12(context), ), ], ), diff --git a/lib/pages/address_book_views/subviews/contact_details_view.dart b/lib/pages/address_book_views/subviews/contact_details_view.dart index c22b1faa8..6538af0dc 100644 --- a/lib/pages/address_book_views/subviews/contact_details_view.dart +++ b/lib/pages/address_book_views/subviews/contact_details_view.dart @@ -13,11 +13,11 @@ import 'package:stackwallet/providers/providers.dart'; import 'package:stackwallet/providers/ui/address_book_providers/address_entry_data_provider.dart'; import 'package:stackwallet/services/coins/manager.dart'; import 'package:stackwallet/utilities/assets.dart'; -import 'package:stackwallet/utilities/cfcolors.dart'; import 'package:stackwallet/utilities/clipboard_interface.dart'; import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/enums/flush_bar_type.dart'; import 'package:stackwallet/utilities/text_styles.dart'; +import 'package:stackwallet/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/loading_indicator.dart'; @@ -105,7 +105,7 @@ class _ContactDetailsViewState extends ConsumerState { .select((value) => value.getContactById(_contactId))); return Scaffold( - backgroundColor: CFColors.almostWhite, + backgroundColor: Theme.of(context).extension()!.background, appBar: AppBar( leading: AppBarBackButton( onPressed: () { @@ -114,7 +114,7 @@ class _ContactDetailsViewState extends ConsumerState { ), title: Text( "Contact details", - style: STextStyles.navBarTitle, + style: STextStyles.navBarTitle(context), ), actions: [ Padding( @@ -129,12 +129,16 @@ class _ContactDetailsViewState extends ConsumerState { key: const Key("contactDetails"), size: 36, shadows: const [], - color: CFColors.almostWhite, + color: Theme.of(context).extension()!.background, icon: SvgPicture.asset( Assets.svg.star, color: _contact.isFavorite - ? CFColors.link2 - : CFColors.buttonGray, + ? Theme.of(context) + .extension()! + .favoriteStarActive + : Theme.of(context) + .extension()! + .favoriteStarInactive, width: 20, height: 20, ), @@ -160,10 +164,12 @@ class _ContactDetailsViewState extends ConsumerState { key: const Key("contactDetailsViewDeleteContactButtonKey"), size: 36, shadows: const [], - color: CFColors.almostWhite, + color: Theme.of(context).extension()!.background, icon: SvgPicture.asset( Assets.svg.trash, - color: CFColors.stackAccent, + color: Theme.of(context) + .extension()! + .accentColorDark, width: 20, height: 20, ), @@ -177,16 +183,11 @@ class _ContactDetailsViewState extends ConsumerState { message: "Contact will be deleted permanently!", leftButton: TextButton( style: Theme.of(context) - .textButtonTheme - .style - ?.copyWith( - backgroundColor: MaterialStateProperty.all( - CFColors.buttonGray, - ), - ), + .extension()! + .getSecondaryEnabledButtonColor(context), child: Text( "Cancel", - style: STextStyles.itemSubtitle12, + style: STextStyles.itemSubtitle12(context), ), onPressed: () { Navigator.of(context).pop(); @@ -194,16 +195,11 @@ class _ContactDetailsViewState extends ConsumerState { ), rightButton: TextButton( style: Theme.of(context) - .textButtonTheme - .style - ?.copyWith( - backgroundColor: MaterialStateProperty.all( - CFColors.stackAccent, - ), - ), + .extension()! + .getPrimaryEnabledButtonColor(context), child: Text( "Delete", - style: STextStyles.button, + style: STextStyles.button(context), ), onPressed: () { ref @@ -246,7 +242,9 @@ class _ContactDetailsViewState extends ConsumerState { width: 48, decoration: BoxDecoration( borderRadius: BorderRadius.circular(24), - color: CFColors.textFieldActive, + color: Theme.of(context) + .extension()! + .textFieldActiveBG, ), child: Center( child: _contact.emojiChar == null @@ -257,7 +255,7 @@ class _ContactDetailsViewState extends ConsumerState { ) : Text( _contact.emojiChar!, - style: STextStyles.pageTitleH1, + style: STextStyles.pageTitleH1(context), ), ), ), @@ -269,7 +267,7 @@ class _ContactDetailsViewState extends ConsumerState { child: Text( _contact.name, textAlign: TextAlign.left, - style: STextStyles.pageTitleH2, + style: STextStyles.pageTitleH2(context), ), ), const Spacer(), @@ -280,29 +278,29 @@ class _ContactDetailsViewState extends ConsumerState { arguments: _contact.id, ); }, - style: ButtonStyle( - minimumSize: - MaterialStateProperty.all(const Size(46, 32)), - backgroundColor: MaterialStateProperty.all( - CFColors.buttonGray, - ), - ), + style: Theme.of(context) + .extension()! + .getSecondaryEnabledButtonColor(context)! + .copyWith( + minimumSize: MaterialStateProperty.all( + const Size(46, 32)), + ), child: Padding( padding: const EdgeInsets.symmetric(horizontal: 12), child: Row( children: [ - SvgPicture.asset( - Assets.svg.pencil, - width: 10, - height: 10, - color: CFColors.stackAccent, - ), + SvgPicture.asset(Assets.svg.pencil, + width: 10, + height: 10, + color: Theme.of(context) + .extension()! + .accentColorDark), const SizedBox( width: 4, ), Text( "Edit", - style: STextStyles.buttonSmall, + style: STextStyles.buttonSmall(context), ), ], ), @@ -318,7 +316,7 @@ class _ContactDetailsViewState extends ConsumerState { children: [ Text( "Addresses", - style: STextStyles.itemSubtitle, + style: STextStyles.itemSubtitle(context), ), BlueTextButton( text: "Add new", @@ -356,7 +354,8 @@ class _ContactDetailsViewState extends ConsumerState { children: [ Text( "${e.label} (${e.coin.ticker})", - style: STextStyles.itemSubtitle12, + style: + STextStyles.itemSubtitle12(context), ), const SizedBox( height: 2, @@ -365,8 +364,8 @@ class _ContactDetailsViewState extends ConsumerState { fit: BoxFit.scaleDown, child: Text( e.address, - style: - STextStyles.itemSubtitle.copyWith( + style: STextStyles.itemSubtitle(context) + .copyWith( fontSize: 8, ), ), @@ -391,14 +390,16 @@ class _ContactDetailsViewState extends ConsumerState { ); }, child: RoundedContainer( - color: CFColors.fieldGray, + color: Theme.of(context) + .extension()! + .textFieldDefaultBG, padding: const EdgeInsets.all(4), - child: SvgPicture.asset( - Assets.svg.pencil, - width: 12, - height: 12, - color: CFColors.stackAccent, - ), + child: SvgPicture.asset(Assets.svg.pencil, + width: 12, + height: 12, + color: Theme.of(context) + .extension()! + .accentColorDark), ), ), const SizedBox( @@ -417,14 +418,16 @@ class _ContactDetailsViewState extends ConsumerState { ); }, child: RoundedContainer( - color: CFColors.fieldGray, + color: Theme.of(context) + .extension()! + .textFieldDefaultBG, padding: const EdgeInsets.all(4), - child: SvgPicture.asset( - Assets.svg.copy, - width: 12, - height: 12, - color: CFColors.stackAccent, - ), + child: SvgPicture.asset(Assets.svg.copy, + width: 12, + height: 12, + color: Theme.of(context) + .extension()! + .accentColorDark), ), ), ], @@ -439,7 +442,7 @@ class _ContactDetailsViewState extends ConsumerState { ), Text( "Transaction history", - style: STextStyles.itemSubtitle, + style: STextStyles.itemSubtitle(context), ), const SizedBox( height: 12, @@ -475,7 +478,7 @@ class _ContactDetailsViewState extends ConsumerState { child: Center( child: Text( "No transactions found", - style: STextStyles.itemSubtitle, + style: STextStyles.itemSubtitle(context), ), ), ); diff --git a/lib/pages/address_book_views/subviews/contact_popup.dart b/lib/pages/address_book_views/subviews/contact_popup.dart index b1a926e33..a14581c0a 100644 --- a/lib/pages/address_book_views/subviews/contact_popup.dart +++ b/lib/pages/address_book_views/subviews/contact_popup.dart @@ -10,11 +10,11 @@ import 'package:stackwallet/providers/exchange/exchange_flow_is_active_state_pro import 'package:stackwallet/providers/global/address_book_service_provider.dart'; import 'package:stackwallet/providers/providers.dart'; import 'package:stackwallet/utilities/assets.dart'; -import 'package:stackwallet/utilities/cfcolors.dart'; import 'package:stackwallet/utilities/clipboard_interface.dart'; import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/enums/flush_bar_type.dart'; import 'package:stackwallet/utilities/text_styles.dart'; +import 'package:stackwallet/utilities/theme/stack_colors.dart'; import 'package:stackwallet/widgets/rounded_container.dart'; import 'package:stackwallet/widgets/rounded_white_container.dart'; import 'package:tuple/tuple.dart'; @@ -71,7 +71,8 @@ class ContactPopUp extends ConsumerWidget { ), child: Container( decoration: BoxDecoration( - color: CFColors.white, + color: + Theme.of(context).extension()!.popupBG, borderRadius: BorderRadius.circular( 20, ), @@ -98,13 +99,15 @@ class ContactPopUp extends ConsumerWidget { width: 32, height: 32, decoration: BoxDecoration( - color: CFColors.contactIconBackground, + color: Theme.of(context) + .extension()! + .textFieldDefaultBG, borderRadius: BorderRadius.circular(32), ), child: contact.id == "default" ? Center( child: SvgPicture.asset( - Assets.svg.stackIcon, + Assets.svg.stackIcon(context), width: 20, ), ) @@ -126,7 +129,8 @@ class ContactPopUp extends ConsumerWidget { Expanded( child: Text( contact.name, - style: STextStyles.itemSubtitle12, + style: + STextStyles.itemSubtitle12(context), ), ), if (contact.id != "default") @@ -138,20 +142,21 @@ class ContactPopUp extends ConsumerWidget { arguments: contact.id, ); }, - style: ButtonStyle( - minimumSize: - MaterialStateProperty.all( - const Size(46, 32)), - backgroundColor: - MaterialStateProperty.all( - CFColors.buttonGray, - ), - ), + style: Theme.of(context) + .extension()! + .getSecondaryEnabledButtonColor( + context)! + .copyWith( + minimumSize: + MaterialStateProperty.all< + Size>(const Size(46, 32)), + ), child: Padding( padding: const EdgeInsets.symmetric( horizontal: 18), child: Text("Details", - style: STextStyles.buttonSmall), + style: STextStyles.buttonSmall( + context)), ), ), ], @@ -162,7 +167,9 @@ class ContactPopUp extends ConsumerWidget { ), Container( height: 1, - color: CFColors.almostWhite, + color: Theme.of(context) + .extension()! + .background, ), if (addresses.isEmpty) Padding( @@ -172,7 +179,8 @@ class ContactPopUp extends ConsumerWidget { child: Center( child: Text( "No ${active[0].coin.prettyName} addresses found", - style: STextStyles.itemSubtitle, + style: + STextStyles.itemSubtitle(context), ), ), ), @@ -212,20 +220,23 @@ class ContactPopUp extends ConsumerWidget { Text( e.other!, style: - STextStyles.itemSubtitle12, + STextStyles.itemSubtitle12( + context), ), if (contact.id != "default") Text( "${e.label} (${e.coin.ticker})", style: - STextStyles.itemSubtitle12, + STextStyles.itemSubtitle12( + context), ), const SizedBox( height: 2, ), Text( e.address, - style: STextStyles.itemSubtitle + style: STextStyles.itemSubtitle( + context) .copyWith( fontSize: 8, ), @@ -254,14 +265,17 @@ class ContactPopUp extends ConsumerWidget { ); }, child: RoundedContainer( - color: CFColors.fieldGray, + color: Theme.of(context) + .extension()! + .textFieldDefaultBG, padding: const EdgeInsets.all(4), child: SvgPicture.asset( - Assets.svg.copy, - width: 12, - height: 12, - color: CFColors.stackAccent, - ), + Assets.svg.copy, + width: 12, + height: 12, + color: Theme.of(context) + .extension()! + .accentColorDark), ), ), ], @@ -304,15 +318,20 @@ class ContactPopUp extends ConsumerWidget { } }, child: RoundedContainer( - color: CFColors.fieldGray, + color: Theme.of(context) + .extension()! + .textFieldDefaultBG, padding: const EdgeInsets.all(4), child: SvgPicture.asset( - Assets.svg.circleArrowUpRight, - width: 12, - height: 12, - color: CFColors.stackAccent, - ), + Assets + .svg.circleArrowUpRight, + width: 12, + height: 12, + color: Theme.of(context) + .extension< + StackColors>()! + .accentColorDark), ), ), ], diff --git a/lib/pages/address_book_views/subviews/edit_contact_address_view.dart b/lib/pages/address_book_views/subviews/edit_contact_address_view.dart index fc67f064c..618a41982 100644 --- a/lib/pages/address_book_views/subviews/edit_contact_address_view.dart +++ b/lib/pages/address_book_views/subviews/edit_contact_address_view.dart @@ -9,9 +9,9 @@ import 'package:stackwallet/providers/ui/address_book_providers/address_entry_da import 'package:stackwallet/providers/ui/address_book_providers/valid_contact_state_provider.dart'; import 'package:stackwallet/utilities/assets.dart'; import 'package:stackwallet/utilities/barcode_scanner_interface.dart'; -import 'package:stackwallet/utilities/cfcolors.dart'; import 'package:stackwallet/utilities/clipboard_interface.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'; class EditContactAddressView extends ConsumerStatefulWidget { @@ -60,7 +60,7 @@ class _EditContactAddressViewState .select((value) => value.getContactById(contactId))); return Scaffold( - backgroundColor: CFColors.almostWhite, + backgroundColor: Theme.of(context).extension()!.background, appBar: AppBar( leading: AppBarBackButton( onPressed: () async { @@ -75,7 +75,7 @@ class _EditContactAddressViewState ), title: Text( "Edit address", - style: STextStyles.navBarTitle, + style: STextStyles.navBarTitle(context), ), ), body: LayoutBuilder( @@ -103,7 +103,9 @@ class _EditContactAddressViewState width: 48, decoration: BoxDecoration( borderRadius: BorderRadius.circular(24), - color: CFColors.textFieldActive, + color: Theme.of(context) + .extension()! + .textFieldActiveBG, ), child: Center( child: contact.emojiChar == null @@ -114,7 +116,7 @@ class _EditContactAddressViewState ) : Text( contact.emojiChar!, - style: STextStyles.pageTitleH1, + style: STextStyles.pageTitleH1(context), ), ), ), @@ -126,7 +128,7 @@ class _EditContactAddressViewState fit: BoxFit.scaleDown, child: Text( contact.name, - style: STextStyles.pageTitleH2, + style: STextStyles.pageTitleH2(context), ), ), ), @@ -168,7 +170,7 @@ class _EditContactAddressViewState }, child: Text( "Delete address", - style: STextStyles.link, + style: STextStyles.link(context), ), ), const Spacer(), @@ -179,17 +181,15 @@ class _EditContactAddressViewState children: [ Expanded( child: TextButton( - style: ButtonStyle( - backgroundColor: - MaterialStateProperty.all( - CFColors.buttonGray, - ), - ), + style: Theme.of(context) + .extension()! + .getSecondaryEnabledButtonColor(context), child: Text( "Cancel", - style: STextStyles.button.copyWith( - color: CFColors.stackAccent, - ), + style: STextStyles.button(context).copyWith( + color: Theme.of(context) + .extension()! + .accentColorDark), ), onPressed: () async { if (FocusScope.of(context).hasFocus) { @@ -213,14 +213,15 @@ class _EditContactAddressViewState ref.watch(validContactStateProvider([0])); return TextButton( - style: ButtonStyle( - backgroundColor: - MaterialStateProperty.all( - shouldEnableSave - ? CFColors.stackAccent - : CFColors.disabledButton, - ), - ), + style: shouldEnableSave + ? Theme.of(context) + .extension()! + .getPrimaryEnabledButtonColor( + context) + : Theme.of(context) + .extension()! + .getPrimaryDisabledButtonColor( + context), onPressed: shouldEnableSave ? () async { if (FocusScope.of(context) @@ -272,7 +273,7 @@ class _EditContactAddressViewState : null, child: Text( "Save", - style: STextStyles.button, + style: STextStyles.button(context), ), ); }, diff --git a/lib/pages/address_book_views/subviews/edit_contact_name_emoji_view.dart b/lib/pages/address_book_views/subviews/edit_contact_name_emoji_view.dart index d8c4f7708..45c23b13c 100644 --- a/lib/pages/address_book_views/subviews/edit_contact_name_emoji_view.dart +++ b/lib/pages/address_book_views/subviews/edit_contact_name_emoji_view.dart @@ -4,9 +4,9 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_svg/svg.dart'; import 'package:stackwallet/providers/global/address_book_service_provider.dart'; import 'package:stackwallet/utilities/assets.dart'; -import 'package:stackwallet/utilities/cfcolors.dart'; 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/emoji_select_sheet.dart'; import 'package:stackwallet/widgets/icon_widgets/x_icon.dart'; @@ -68,7 +68,7 @@ class _EditContactNameEmojiViewState .select((value) => value.getContactById(contactId))); return Scaffold( - backgroundColor: CFColors.almostWhite, + backgroundColor: Theme.of(context).extension()!.background, appBar: AppBar( leading: AppBarBackButton( onPressed: () async { @@ -83,7 +83,7 @@ class _EditContactNameEmojiViewState ), title: Text( "Edit contact", - style: STextStyles.navBarTitle, + style: STextStyles.navBarTitle(context), ), ), body: LayoutBuilder( @@ -139,7 +139,9 @@ class _EditContactNameEmojiViewState width: 48, decoration: BoxDecoration( borderRadius: BorderRadius.circular(24), - color: CFColors.textFieldActive, + color: Theme.of(context) + .extension()! + .textFieldActiveBG, ), child: Center( child: _selectedEmoji == null @@ -150,7 +152,8 @@ class _EditContactNameEmojiViewState ) : Text( _selectedEmoji!.char, - style: STextStyles.pageTitleH1, + style: STextStyles.pageTitleH1( + context), ), ), ), @@ -160,20 +163,25 @@ class _EditContactNameEmojiViewState height: 14, width: 14, decoration: BoxDecoration( - borderRadius: BorderRadius.circular(14), - color: CFColors.stackAccent, - ), + borderRadius: BorderRadius.circular(14), + color: Theme.of(context) + .extension()! + .accentColorDark), child: Center( child: _selectedEmoji == null ? SvgPicture.asset( Assets.svg.plus, - color: CFColors.white, + color: Theme.of(context) + .extension()! + .textWhite, width: 12, height: 12, ) : SvgPicture.asset( Assets.svg.thickX, - color: CFColors.white, + color: Theme.of(context) + .extension()! + .textWhite, width: 8, height: 8, ), @@ -194,11 +202,12 @@ class _EditContactNameEmojiViewState child: TextField( controller: nameController, focusNode: nameFocusNode, - style: STextStyles.field, + style: STextStyles.field(context), onChanged: (_) => setState(() {}), decoration: standardInputDecoration( "Enter contact name", nameFocusNode, + context, ).copyWith( suffixIcon: nameController.text.isNotEmpty ? Padding( @@ -230,17 +239,15 @@ class _EditContactNameEmojiViewState children: [ Expanded( child: TextButton( - style: ButtonStyle( - backgroundColor: - MaterialStateProperty.all( - CFColors.buttonGray, - ), - ), + style: Theme.of(context) + .extension()! + .getSecondaryEnabledButtonColor(context), child: Text( "Cancel", - style: STextStyles.button.copyWith( - color: CFColors.stackAccent, - ), + style: STextStyles.button(context).copyWith( + color: Theme.of(context) + .extension()! + .accentColorDark), ), onPressed: () async { if (FocusScope.of(context).hasFocus) { @@ -264,14 +271,15 @@ class _EditContactNameEmojiViewState nameController.text.isNotEmpty; return TextButton( - style: ButtonStyle( - backgroundColor: - MaterialStateProperty.all( - shouldEnableSave - ? CFColors.stackAccent - : CFColors.disabledButton, - ), - ), + style: shouldEnableSave + ? Theme.of(context) + .extension()! + .getPrimaryEnabledButtonColor( + context) + : Theme.of(context) + .extension()! + .getPrimaryDisabledButtonColor( + context), onPressed: shouldEnableSave ? () async { if (FocusScope.of(context) @@ -303,7 +311,7 @@ class _EditContactNameEmojiViewState : null, child: Text( "Save", - style: STextStyles.button, + style: STextStyles.button(context), ), ); }, diff --git a/lib/pages/address_book_views/subviews/new_contact_address_entry_form.dart b/lib/pages/address_book_views/subviews/new_contact_address_entry_form.dart index 568222870..73de8b0aa 100644 --- a/lib/pages/address_book_views/subviews/new_contact_address_entry_form.dart +++ b/lib/pages/address_book_views/subviews/new_contact_address_entry_form.dart @@ -8,12 +8,12 @@ import 'package:stackwallet/providers/ui/address_book_providers/address_entry_da import 'package:stackwallet/utilities/address_utils.dart'; import 'package:stackwallet/utilities/assets.dart'; import 'package:stackwallet/utilities/barcode_scanner_interface.dart'; -import 'package:stackwallet/utilities/cfcolors.dart'; import 'package:stackwallet/utilities/clipboard_interface.dart'; import 'package:stackwallet/utilities/constants.dart'; import 'package:stackwallet/utilities/enums/coin_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/icon_widgets/clipboard_icon.dart'; import 'package:stackwallet/widgets/icon_widgets/qrcode_icon.dart'; import 'package:stackwallet/widgets/icon_widgets/x_icon.dart'; @@ -72,15 +72,16 @@ class _NewContactAddressEntryFormState children: [ TextField( readOnly: true, - style: STextStyles.field, + style: STextStyles.field(context), decoration: InputDecoration( hintText: "Select cryptocurrency", - hintStyle: STextStyles.fieldLabel, + hintStyle: STextStyles.fieldLabel(context), prefixIcon: Center( child: Padding( padding: const EdgeInsets.symmetric(horizontal: 12), child: RawMaterialButton( - splashColor: CFColors.splashLight, + splashColor: + Theme.of(context).extension()!.highlight, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular( Constants.size.circularBorderRadius, @@ -106,7 +107,7 @@ class _NewContactAddressEntryFormState null ? Text( "Select cryptocurrency", - style: STextStyles.fieldLabel, + style: STextStyles.fieldLabel(context), ) : Row( children: [ @@ -126,7 +127,7 @@ class _NewContactAddressEntryFormState .watch(addressEntryDataProvider(widget.id) .select((value) => value.coin))! .prettyName, - style: STextStyles.itemSubtitle12, + style: STextStyles.itemSubtitle12(context), ), ], ), @@ -134,7 +135,9 @@ class _NewContactAddressEntryFormState Assets.svg.chevronDown, width: 8, height: 4, - color: CFColors.gray3, + color: Theme.of(context) + .extension()! + .textSubtitle2, ), ], ), @@ -153,10 +156,11 @@ class _NewContactAddressEntryFormState child: TextField( focusNode: addressLabelFocusNode, controller: addressLabelController, - style: STextStyles.field, + style: STextStyles.field(context), decoration: standardInputDecoration( "Enter address label", addressLabelFocusNode, + context, ).copyWith( suffixIcon: addressLabelController.text.isNotEmpty ? Padding( @@ -195,10 +199,11 @@ class _NewContactAddressEntryFormState child: TextField( focusNode: addressFocusNode, controller: addressController, - style: STextStyles.field, + style: STextStyles.field(context), decoration: standardInputDecoration( "Paste address", addressFocusNode, + context, ).copyWith( suffixIcon: UnconstrainedBox( child: Row( @@ -351,8 +356,9 @@ class _NewContactAddressEntryFormState Text( "Invalid address", textAlign: TextAlign.left, - style: STextStyles.label.copyWith( - color: CFColors.notificationRedForeground, + style: STextStyles.label(context).copyWith( + color: + Theme.of(context).extension()!.textError, ), ), ], diff --git a/lib/pages/buy_view/buy_view.dart b/lib/pages/buy_view/buy_view.dart index 249fb2442..8f759b79c 100644 --- a/lib/pages/buy_view/buy_view.dart +++ b/lib/pages/buy_view/buy_view.dart @@ -20,7 +20,7 @@ class _BuyViewState extends State { Center( child: Text( "Coming soon", - style: STextStyles.pageTitleH1, + style: STextStyles.pageTitleH1(context), ), ), ], diff --git a/lib/pages/exchange_view/confirm_change_now_send.dart b/lib/pages/exchange_view/confirm_change_now_send.dart index dc15457e2..6fd6c8a08 100644 --- a/lib/pages/exchange_view/confirm_change_now_send.dart +++ b/lib/pages/exchange_view/confirm_change_now_send.dart @@ -1,3 +1,5 @@ +import 'dart:async'; + import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:stackwallet/models/exchange/change_now/exchange_transaction.dart'; @@ -8,10 +10,10 @@ import 'package:stackwallet/pages/wallet_view/wallet_view.dart'; import 'package:stackwallet/providers/exchange/trade_sent_from_stack_lookup_provider.dart'; import 'package:stackwallet/providers/providers.dart'; import 'package:stackwallet/route_generator.dart'; -import 'package:stackwallet/utilities/cfcolors.dart'; import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/format.dart'; import 'package:stackwallet/utilities/text_styles.dart'; +import 'package:stackwallet/utilities/theme/stack_colors.dart'; import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart'; import 'package:stackwallet/widgets/rounded_container.dart'; import 'package:stackwallet/widgets/rounded_white_container.dart'; @@ -47,14 +49,14 @@ class _ConfirmChangeNowSendViewState late final ExchangeTransaction trade; Future _attemptSend(BuildContext context) async { - showDialog( + unawaited(showDialog( context: context, useSafeArea: false, barrierDismissible: false, builder: (context) { return const SendingTransactionDialog(); }, - ); + )); final String note = transactionInfo["note"] as String? ?? ""; final manager = @@ -62,10 +64,10 @@ class _ConfirmChangeNowSendViewState try { final txid = await manager.confirmSend(txData: transactionInfo); - manager.refresh(); + unawaited(manager.refresh()); // save note - ref + await ref .read(notesServiceChangeNotifierProvider(walletId)) .editOrAddNote(txid: txid, note: note); @@ -86,7 +88,7 @@ class _ConfirmChangeNowSendViewState // pop sending dialog Navigator.of(context).pop(); - showDialog( + await showDialog( context: context, useSafeArea: false, barrierDismissible: true, @@ -95,15 +97,15 @@ class _ConfirmChangeNowSendViewState title: "Broadcast transaction failed", message: e.toString(), rightButton: TextButton( - style: Theme.of(context).textButtonTheme.style?.copyWith( - backgroundColor: MaterialStateProperty.all( - CFColors.buttonGray, - ), - ), + style: Theme.of(context) + .extension()! + .getSecondaryEnabledButtonColor(context), child: Text( "Ok", - style: STextStyles.button.copyWith( - color: CFColors.stackAccent, + style: STextStyles.button(context).copyWith( + color: Theme.of(context) + .extension()! + .buttonTextSecondary, ), ), onPressed: () { @@ -131,7 +133,7 @@ class _ConfirmChangeNowSendViewState .select((value) => value.getManagerProvider(walletId))); return Scaffold( appBar: AppBar( - backgroundColor: CFColors.almostWhite, + backgroundColor: Theme.of(context).extension()!.background, leading: AppBarBackButton( onPressed: () async { // if (FocusScope.of(context).hasFocus) { @@ -143,7 +145,7 @@ class _ConfirmChangeNowSendViewState ), title: Text( "Confirm transaction", - style: STextStyles.navBarTitle, + style: STextStyles.navBarTitle(context), ), ), body: LayoutBuilder( @@ -167,7 +169,7 @@ class _ConfirmChangeNowSendViewState children: [ Text( "Send ${ref.watch(managerProvider.select((value) => value.coin)).ticker}", - style: STextStyles.pageTitleH1, + style: STextStyles.pageTitleH1(context), ), const SizedBox( height: 12, @@ -178,7 +180,7 @@ class _ConfirmChangeNowSendViewState children: [ Text( "Send from", - style: STextStyles.smallMed12, + style: STextStyles.smallMed12(context), ), const SizedBox( height: 4, @@ -188,7 +190,7 @@ class _ConfirmChangeNowSendViewState .watch(walletsChangeNotifierProvider) .getManager(walletId) .walletName, - style: STextStyles.itemSubtitle12, + style: STextStyles.itemSubtitle12(context), ), ], ), @@ -205,14 +207,14 @@ class _ConfirmChangeNowSendViewState children: [ Text( "ChangeNOW address", - style: STextStyles.smallMed12, + style: STextStyles.smallMed12(context), ), const SizedBox( height: 4, ), Text( "${transactionInfo["address"] ?? "ERROR"}", - style: STextStyles.itemSubtitle12, + style: STextStyles.itemSubtitle12(context), ), ], ), @@ -226,7 +228,7 @@ class _ConfirmChangeNowSendViewState children: [ Text( "Amount", - style: STextStyles.smallMed12, + style: STextStyles.smallMed12(context), ), Text( "${Format.satoshiAmountToPrettyString( @@ -239,7 +241,7 @@ class _ConfirmChangeNowSendViewState managerProvider .select((value) => value.coin), ).ticker}", - style: STextStyles.itemSubtitle12, + style: STextStyles.itemSubtitle12(context), textAlign: TextAlign.right, ), ], @@ -254,7 +256,7 @@ class _ConfirmChangeNowSendViewState children: [ Text( "Transaction fee", - style: STextStyles.smallMed12, + style: STextStyles.smallMed12(context), ), Text( "${Format.satoshiAmountToPrettyString( @@ -267,7 +269,7 @@ class _ConfirmChangeNowSendViewState managerProvider .select((value) => value.coin), ).ticker}", - style: STextStyles.itemSubtitle12, + style: STextStyles.itemSubtitle12(context), textAlign: TextAlign.right, ), ], @@ -282,14 +284,14 @@ class _ConfirmChangeNowSendViewState children: [ Text( "Note", - style: STextStyles.smallMed12, + style: STextStyles.smallMed12(context), ), const SizedBox( height: 4, ), Text( transactionInfo["note"] as String? ?? "", - style: STextStyles.itemSubtitle12, + style: STextStyles.itemSubtitle12(context), ), ], ), @@ -303,11 +305,11 @@ class _ConfirmChangeNowSendViewState children: [ Text( "Trade ID", - style: STextStyles.smallMed12, + style: STextStyles.smallMed12(context), ), Text( trade.id, - style: STextStyles.itemSubtitle12, + style: STextStyles.itemSubtitle12(context), textAlign: TextAlign.right, ), ], @@ -317,13 +319,15 @@ class _ConfirmChangeNowSendViewState height: 12, ), RoundedContainer( - color: CFColors.stackGreen15, + color: Theme.of(context) + .extension()! + .snackBarBackSuccess, child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( "Total amount", - style: STextStyles.titleBold12, + style: STextStyles.titleBold12(context), ), Text( "${Format.satoshiAmountToPrettyString( @@ -337,7 +341,7 @@ class _ConfirmChangeNowSendViewState managerProvider .select((value) => value.coin), ).ticker}", - style: STextStyles.itemSubtitle12, + style: STextStyles.itemSubtitle12(context), textAlign: TextAlign.right, ), ], @@ -348,13 +352,9 @@ class _ConfirmChangeNowSendViewState ), const Spacer(), TextButton( - style: - Theme.of(context).textButtonTheme.style?.copyWith( - backgroundColor: - MaterialStateProperty.all( - CFColors.stackAccent, - ), - ), + style: Theme.of(context) + .extension()! + .getPrimaryEnabledButtonColor(context), onPressed: () async { final unlocked = await Navigator.push( context, @@ -378,12 +378,12 @@ class _ConfirmChangeNowSendViewState ); if (unlocked is bool && unlocked && mounted) { - _attemptSend(context); + await _attemptSend(context); } }, child: Text( "Send", - style: STextStyles.button, + style: STextStyles.button(context), ), ), ], diff --git a/lib/pages/exchange_view/edit_trade_note_view.dart b/lib/pages/exchange_view/edit_trade_note_view.dart index 457b0e6bc..5e1571b73 100644 --- a/lib/pages/exchange_view/edit_trade_note_view.dart +++ b/lib/pages/exchange_view/edit_trade_note_view.dart @@ -1,9 +1,9 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:stackwallet/providers/exchange/trade_note_service_provider.dart'; -import 'package:stackwallet/utilities/cfcolors.dart'; 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/icon_widgets/x_icon.dart'; import 'package:stackwallet/widgets/stack_text_field.dart'; @@ -46,9 +46,9 @@ class _EditNoteViewState extends ConsumerState { @override Widget build(BuildContext context) { return Scaffold( - backgroundColor: CFColors.almostWhite, + backgroundColor: Theme.of(context).extension()!.background, appBar: AppBar( - backgroundColor: CFColors.almostWhite, + backgroundColor: Theme.of(context).extension()!.background, leading: AppBarBackButton( onPressed: () async { if (FocusScope.of(context).hasFocus) { @@ -62,7 +62,7 @@ class _EditNoteViewState extends ConsumerState { ), title: Text( "Edit trade note", - style: STextStyles.navBarTitle, + style: STextStyles.navBarTitle(context), ), ), body: Padding( @@ -86,12 +86,13 @@ class _EditNoteViewState extends ConsumerState { ), child: TextField( controller: _noteController, - style: STextStyles.field, + style: STextStyles.field(context), focusNode: noteFieldFocusNode, onChanged: (_) => setState(() {}), decoration: standardInputDecoration( "Note", noteFieldFocusNode, + context, ).copyWith( suffixIcon: _noteController.text.isNotEmpty ? Padding( @@ -126,16 +127,12 @@ class _EditNoteViewState extends ConsumerState { Navigator.of(context).pop(); } }, - style: - Theme.of(context).textButtonTheme.style?.copyWith( - backgroundColor: - MaterialStateProperty.all( - CFColors.stackAccent, - ), - ), + style: Theme.of(context) + .extension()! + .getPrimaryEnabledButtonColor(context), child: Text( "Save", - style: STextStyles.button, + style: STextStyles.button(context), ), ) ], diff --git a/lib/pages/exchange_view/exchange_coin_selection/fixed_rate_pair_coin_selection_view.dart b/lib/pages/exchange_view/exchange_coin_selection/fixed_rate_pair_coin_selection_view.dart index 7741d1d54..82a8ba0ea 100644 --- a/lib/pages/exchange_view/exchange_coin_selection/fixed_rate_pair_coin_selection_view.dart +++ b/lib/pages/exchange_view/exchange_coin_selection/fixed_rate_pair_coin_selection_view.dart @@ -4,10 +4,10 @@ import 'package:flutter_svg/svg.dart'; import 'package:stackwallet/models/exchange/change_now/currency.dart'; import 'package:stackwallet/models/exchange/change_now/fixed_rate_market.dart'; import 'package:stackwallet/utilities/assets.dart'; -import 'package:stackwallet/utilities/cfcolors.dart'; import 'package:stackwallet/utilities/constants.dart'; import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/text_styles.dart'; +import 'package:stackwallet/utilities/theme/stack_colors.dart'; import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart'; import 'package:stackwallet/widgets/icon_widgets/x_icon.dart'; import 'package:stackwallet/widgets/loading_indicator.dart'; @@ -119,7 +119,7 @@ class _FixedRateMarketPairCoinSelectionViewState @override Widget build(BuildContext context) { return Scaffold( - backgroundColor: CFColors.almostWhite, + backgroundColor: Theme.of(context).extension()!.background, appBar: AppBar( leading: AppBarBackButton( onPressed: () async { @@ -134,7 +134,7 @@ class _FixedRateMarketPairCoinSelectionViewState ), title: Text( "Choose a coin to exchange", - style: STextStyles.pageTitleH2, + style: STextStyles.pageTitleH2(context), ), ), body: Padding( @@ -155,10 +155,11 @@ class _FixedRateMarketPairCoinSelectionViewState controller: _searchController, focusNode: _searchFocusNode, onChanged: filter, - style: STextStyles.field, + style: STextStyles.field(context), decoration: standardInputDecoration( "Search", _searchFocusNode, + context, ).copyWith( prefixIcon: Padding( padding: const EdgeInsets.symmetric( @@ -198,7 +199,7 @@ class _FixedRateMarketPairCoinSelectionViewState ), Text( "Popular coins", - style: STextStyles.smallMed12, + style: STextStyles.smallMed12(context), ), const SizedBox( height: 12, @@ -232,12 +233,12 @@ class _FixedRateMarketPairCoinSelectionViewState child: Row( children: [ SizedBox( - width: 20, - height: 20, + width: 24, + height: 24, child: SvgPicture.network( tuple.item1, - width: 20, - height: 20, + width: 24, + height: 24, placeholderBuilder: (_) => const LoadingIndicator(), ), @@ -245,9 +246,28 @@ class _FixedRateMarketPairCoinSelectionViewState const SizedBox( width: 10, ), - Text( - "${tuple.item2} / ${ticker.toUpperCase()}", - style: STextStyles.titleBold12, + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + tuple.item2, + style: STextStyles.largeMedium14(context), + ), + const SizedBox( + height: 2, + ), + Text( + ticker.toUpperCase(), + style: STextStyles.smallMed12(context) + .copyWith( + color: Theme.of(context) + .extension()! + .textSubtitle1, + ), + ), + ], + ), ), ], ), @@ -263,7 +283,7 @@ class _FixedRateMarketPairCoinSelectionViewState ), Text( "All coins", - style: STextStyles.smallMed12, + style: STextStyles.smallMed12(context), ), const SizedBox( height: 12, @@ -289,12 +309,12 @@ class _FixedRateMarketPairCoinSelectionViewState child: Row( children: [ SizedBox( - width: 20, - height: 20, + width: 24, + height: 24, child: SvgPicture.network( tuple.item1, - width: 20, - height: 20, + width: 24, + height: 24, placeholderBuilder: (_) => const LoadingIndicator(), ), @@ -302,9 +322,28 @@ class _FixedRateMarketPairCoinSelectionViewState const SizedBox( width: 10, ), - Text( - "${tuple.item2} / ${ticker.toUpperCase()}", - style: STextStyles.titleBold12, + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + tuple.item2, + style: STextStyles.largeMedium14(context), + ), + const SizedBox( + height: 2, + ), + Text( + ticker.toUpperCase(), + style: STextStyles.smallMed12(context) + .copyWith( + color: Theme.of(context) + .extension()! + .textSubtitle1, + ), + ), + ], + ), ), ], ), diff --git a/lib/pages/exchange_view/exchange_coin_selection/floating_rate_currency_selection_view.dart b/lib/pages/exchange_view/exchange_coin_selection/floating_rate_currency_selection_view.dart index 94f7c039b..28ed9accb 100644 --- a/lib/pages/exchange_view/exchange_coin_selection/floating_rate_currency_selection_view.dart +++ b/lib/pages/exchange_view/exchange_coin_selection/floating_rate_currency_selection_view.dart @@ -2,10 +2,10 @@ import 'package:flutter/material.dart'; import 'package:flutter_svg/svg.dart'; import 'package:stackwallet/models/exchange/change_now/currency.dart'; import 'package:stackwallet/utilities/assets.dart'; -import 'package:stackwallet/utilities/cfcolors.dart'; import 'package:stackwallet/utilities/constants.dart'; import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/text_styles.dart'; +import 'package:stackwallet/utilities/theme/stack_colors.dart'; import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart'; import 'package:stackwallet/widgets/icon_widgets/x_icon.dart'; import 'package:stackwallet/widgets/loading_indicator.dart'; @@ -75,7 +75,7 @@ class _FloatingRateCurrencySelectionViewState @override Widget build(BuildContext context) { return Scaffold( - backgroundColor: CFColors.almostWhite, + backgroundColor: Theme.of(context).extension()!.background, appBar: AppBar( leading: AppBarBackButton( onPressed: () async { @@ -90,7 +90,7 @@ class _FloatingRateCurrencySelectionViewState ), title: Text( "Choose a coin to exchange", - style: STextStyles.pageTitleH2, + style: STextStyles.pageTitleH2(context), ), ), body: Padding( @@ -111,10 +111,11 @@ class _FloatingRateCurrencySelectionViewState controller: _searchController, focusNode: _searchFocusNode, onChanged: filter, - style: STextStyles.field, + style: STextStyles.field(context), decoration: standardInputDecoration( "Search", _searchFocusNode, + context, ).copyWith( prefixIcon: Padding( padding: const EdgeInsets.symmetric( @@ -139,6 +140,7 @@ class _FloatingRateCurrencySelectionViewState setState(() { _searchController.text = ""; }); + filter(""); }, ), ], @@ -154,7 +156,7 @@ class _FloatingRateCurrencySelectionViewState ), Text( "Popular coins", - style: STextStyles.smallMed12, + style: STextStyles.smallMed12(context), ), const SizedBox( height: 12, @@ -183,12 +185,12 @@ class _FloatingRateCurrencySelectionViewState child: Row( children: [ SizedBox( - width: 20, - height: 20, + width: 24, + height: 24, child: SvgPicture.network( items[index].image, - width: 20, - height: 20, + width: 24, + height: 24, placeholderBuilder: (_) => const LoadingIndicator(), ), @@ -196,9 +198,28 @@ class _FloatingRateCurrencySelectionViewState const SizedBox( width: 10, ), - Text( - "${items[index].name} / ${items[index].ticker.toUpperCase()}", - style: STextStyles.titleBold12, + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + items[index].name, + style: STextStyles.largeMedium14(context), + ), + const SizedBox( + height: 2, + ), + Text( + items[index].ticker.toUpperCase(), + style: STextStyles.smallMed12(context) + .copyWith( + color: Theme.of(context) + .extension()! + .textSubtitle1, + ), + ), + ], + ), ), ], ), @@ -214,7 +235,7 @@ class _FloatingRateCurrencySelectionViewState ), Text( "All coins", - style: STextStyles.smallMed12, + style: STextStyles.smallMed12(context), ), const SizedBox( height: 12, @@ -236,12 +257,12 @@ class _FloatingRateCurrencySelectionViewState child: Row( children: [ SizedBox( - width: 20, - height: 20, + width: 24, + height: 24, child: SvgPicture.network( _currencies[index].image, - width: 20, - height: 20, + width: 24, + height: 24, placeholderBuilder: (_) => const LoadingIndicator(), ), @@ -249,9 +270,28 @@ class _FloatingRateCurrencySelectionViewState const SizedBox( width: 10, ), - Text( - "${_currencies[index].name} / ${_currencies[index].ticker.toUpperCase()}", - style: STextStyles.titleBold12, + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + _currencies[index].name, + style: STextStyles.largeMedium14(context), + ), + const SizedBox( + height: 2, + ), + Text( + _currencies[index].ticker.toUpperCase(), + style: STextStyles.smallMed12(context) + .copyWith( + color: Theme.of(context) + .extension()! + .textSubtitle1, + ), + ), + ], + ), ), ], ), diff --git a/lib/pages/exchange_view/exchange_loading_overlay.dart b/lib/pages/exchange_view/exchange_loading_overlay.dart index 28484022a..e4e6c1f27 100644 --- a/lib/pages/exchange_view/exchange_loading_overlay.dart +++ b/lib/pages/exchange_view/exchange_loading_overlay.dart @@ -1,8 +1,8 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:stackwallet/providers/exchange/changenow_initial_load_status.dart'; -import 'package:stackwallet/utilities/cfcolors.dart'; import 'package:stackwallet/utilities/text_styles.dart'; +import 'package:stackwallet/utilities/theme/stack_colors.dart'; import 'package:stackwallet/widgets/custom_loading_overlay.dart'; import 'package:stackwallet/widgets/stack_dialog.dart'; @@ -65,7 +65,10 @@ class _ExchangeLoadingOverlayViewState if (_statusEst == ChangeNowLoadStatus.loading || (_statusFixed == ChangeNowLoadStatus.loading && userReloaded)) Container( - color: CFColors.stackAccent.withOpacity(0.7), + color: Theme.of(context) + .extension()! + .overlay + .withOpacity(0.7), child: const CustomLoadingOverlay( message: "Loading ChangeNOW data", eventBus: null), ), @@ -74,7 +77,10 @@ class _ExchangeLoadingOverlayViewState _statusEst != ChangeNowLoadStatus.loading && _statusFixed != ChangeNowLoadStatus.loading) Container( - color: CFColors.stackAccent.withOpacity(0.7), + color: Theme.of(context) + .extension()! + .overlay + .withOpacity(0.7), child: Column( mainAxisAlignment: MainAxisAlignment.end, children: [ @@ -83,10 +89,16 @@ class _ExchangeLoadingOverlayViewState message: "ChangeNOW requires a working internet connection. Tap OK to try fetching again.", rightButton: TextButton( + style: Theme.of(context) + .extension()! + .getSecondaryEnabledButtonColor(context), child: Text( "OK", - style: STextStyles.button - .copyWith(color: CFColors.stackAccent), + style: STextStyles.button(context).copyWith( + color: Theme.of(context) + .extension()! + .buttonTextSecondary, + ), ), onPressed: () { userReloaded = true; 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 32a5a4205..95f086003 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 @@ -3,9 +3,9 @@ import 'package:stackwallet/models/exchange/incomplete_exchange.dart'; import 'package:stackwallet/pages/exchange_view/exchange_step_views/step_2_view.dart'; import 'package:stackwallet/pages/exchange_view/sub_widgets/exchange_rate_sheet.dart'; import 'package:stackwallet/pages/exchange_view/sub_widgets/step_row.dart'; -import 'package:stackwallet/utilities/cfcolors.dart'; import 'package:stackwallet/utilities/clipboard_interface.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/rounded_white_container.dart'; @@ -40,7 +40,7 @@ class _Step1ViewState extends State { @override Widget build(BuildContext context) { return Scaffold( - backgroundColor: CFColors.almostWhite, + backgroundColor: Theme.of(context).extension()!.background, appBar: AppBar( leading: AppBarBackButton( onPressed: () async { @@ -55,7 +55,7 @@ class _Step1ViewState extends State { ), title: Text( "Exchange", - style: STextStyles.navBarTitle, + style: STextStyles.navBarTitle(context), ), ), body: LayoutBuilder( @@ -84,14 +84,14 @@ class _Step1ViewState extends State { ), Text( "Confirm amount", - style: STextStyles.pageTitleH1, + style: STextStyles.pageTitleH1(context), ), const SizedBox( height: 8, ), Text( "Network fees and other exchange charges are included in the rate.", - style: STextStyles.itemSubtitle, + style: STextStyles.itemSubtitle(context), ), const SizedBox( height: 24, @@ -102,11 +102,19 @@ class _Step1ViewState extends State { children: [ Text( "You send", - style: STextStyles.itemSubtitle, + style: STextStyles.itemSubtitle(context) + .copyWith( + color: Theme.of(context) + .extension()! + .infoItemText), ), Text( - "${model.sendAmount.toStringAsFixed(8)} ${model.sendTicker}", - style: STextStyles.itemSubtitle12, + "${model.sendAmount.toStringAsFixed(8)} ${model.sendTicker.toUpperCase()}", + style: STextStyles.itemSubtitle12(context) + .copyWith( + color: Theme.of(context) + .extension()! + .infoItemText), ), ], ), @@ -120,11 +128,19 @@ class _Step1ViewState extends State { children: [ Text( "You receive", - style: STextStyles.itemSubtitle, + style: STextStyles.itemSubtitle(context) + .copyWith( + color: Theme.of(context) + .extension()! + .infoItemText), ), Text( - "~${model.receiveAmount.toStringAsFixed(8)} ${model.receiveTicker}", - style: STextStyles.itemSubtitle12, + "~${model.receiveAmount.toStringAsFixed(8)} ${model.receiveTicker.toUpperCase()}", + style: STextStyles.itemSubtitle12(context) + .copyWith( + color: Theme.of(context) + .extension()! + .infoItemText), ), ], ), @@ -140,11 +156,20 @@ class _Step1ViewState extends State { model.rateType == ExchangeRateType.estimated ? "Estimated rate" : "Fixed rate", - style: STextStyles.itemSubtitle, + style: + STextStyles.itemSubtitle(context).copyWith( + color: Theme.of(context) + .extension()! + .infoItemLabel, + ), ), Text( model.rateInfo, - style: STextStyles.itemSubtitle12, + style: STextStyles.itemSubtitle12(context) + .copyWith( + color: Theme.of(context) + .extension()! + .infoItemText), ), ], ), @@ -158,16 +183,12 @@ class _Step1ViewState extends State { Navigator.of(context).pushNamed(Step2View.routeName, arguments: model); }, - style: - Theme.of(context).textButtonTheme.style?.copyWith( - backgroundColor: - MaterialStateProperty.all( - CFColors.stackAccent, - ), - ), + style: Theme.of(context) + .extension()! + .getPrimaryEnabledButtonColor(context), child: Text( "Next", - style: STextStyles.button, + style: STextStyles.button(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 57e10f0eb..3ac7fd8ec 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 @@ -10,12 +10,12 @@ import 'package:stackwallet/providers/exchange/exchange_send_from_wallet_id_prov import 'package:stackwallet/providers/providers.dart'; import 'package:stackwallet/utilities/address_utils.dart'; import 'package:stackwallet/utilities/barcode_scanner_interface.dart'; -import 'package:stackwallet/utilities/cfcolors.dart'; import 'package:stackwallet/utilities/clipboard_interface.dart'; import 'package:stackwallet/utilities/constants.dart'; import 'package:stackwallet/utilities/enums/coin_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/custom_buttons/app_bar_icon_button.dart'; import 'package:stackwallet/widgets/icon_widgets/addressbook_icon.dart'; import 'package:stackwallet/widgets/icon_widgets/clipboard_icon.dart'; @@ -95,7 +95,7 @@ class _Step2ViewState extends ConsumerState { @override Widget build(BuildContext context) { return Scaffold( - backgroundColor: CFColors.almostWhite, + backgroundColor: Theme.of(context).extension()!.background, appBar: AppBar( leading: AppBarBackButton( onPressed: () async { @@ -110,7 +110,7 @@ class _Step2ViewState extends ConsumerState { ), title: Text( "Exchange", - style: STextStyles.navBarTitle, + style: STextStyles.navBarTitle(context), ), ), body: LayoutBuilder( @@ -139,14 +139,14 @@ class _Step2ViewState extends ConsumerState { ), Text( "Exchange details", - style: STextStyles.pageTitleH1, + style: STextStyles.pageTitleH1(context), ), const SizedBox( height: 8, ), Text( "Enter your recipient and refund addresses", - style: STextStyles.itemSubtitle, + style: STextStyles.itemSubtitle(context), ), const SizedBox( height: 24, @@ -156,9 +156,7 @@ class _Step2ViewState extends ConsumerState { children: [ Text( "Recipient Wallet", - style: STextStyles.itemSubtitle.copyWith( - color: CFColors.neutral50, - ), + style: STextStyles.smallMed12(context), ), // GestureDetector( // onTap: () { @@ -166,7 +164,7 @@ class _Step2ViewState extends ConsumerState { // }, // child: Text( // "Choose from Stack", - // style: STextStyles.link2, + // style: STextStyles.link2(context), // ), // ), ], @@ -196,10 +194,11 @@ class _Step2ViewState extends ConsumerState { selectAll: false, ), focusNode: _toFocusNode, - style: STextStyles.field, + style: STextStyles.field(context), decoration: standardInputDecoration( - "Enter the ${model.receiveTicker} payout address", + "Enter the ${model.receiveTicker.toUpperCase()} payout address", _toFocusNode, + context, ).copyWith( contentPadding: const EdgeInsets.only( left: 16, @@ -335,8 +334,8 @@ class _Step2ViewState extends ConsumerState { ), RoundedWhiteContainer( child: Text( - "This is the wallet where your ${model.receiveTicker} will be sent to.", - style: STextStyles.label, + "This is the wallet where your ${model.receiveTicker.toUpperCase()} will be sent to.", + style: STextStyles.label(context), ), ), const SizedBox( @@ -347,7 +346,7 @@ class _Step2ViewState extends ConsumerState { children: [ Text( "Refund Wallet (required)", - style: STextStyles.smallMed12, + style: STextStyles.smallMed12(context), ), // GestureDetector( // onTap: () { @@ -355,7 +354,7 @@ class _Step2ViewState extends ConsumerState { // }, // child: Text( // "Choose from Stack", - // style: STextStyles.link2, + // style: STextStyles.link2(context), // ), // ), ], @@ -384,10 +383,11 @@ class _Step2ViewState extends ConsumerState { selectAll: false, ), focusNode: _refundFocusNode, - style: STextStyles.field, + style: STextStyles.field(context), decoration: standardInputDecoration( - "Enter ${model.sendTicker} refund address", + "Enter ${model.sendTicker.toUpperCase()} refund address", _refundFocusNode, + context, ).copyWith( contentPadding: const EdgeInsets.only( left: 16, @@ -526,7 +526,7 @@ class _Step2ViewState extends ConsumerState { RoundedWhiteContainer( child: Text( "In case something goes wrong during the exchange, we might need a refund address so we can return your coins back to you.", - style: STextStyles.label, + style: STextStyles.label(context), ), ), const Spacer(), @@ -537,10 +537,15 @@ class _Step2ViewState extends ConsumerState { onPressed: () { Navigator.of(context).pop(); }, + style: Theme.of(context) + .extension()! + .getSecondaryEnabledButtonColor(context), child: Text( "Back", - style: STextStyles.button.copyWith( - color: CFColors.stackAccent, + style: STextStyles.button(context).copyWith( + color: Theme.of(context) + .extension()! + .buttonTextSecondary, ), ), ), @@ -559,17 +564,11 @@ class _Step2ViewState extends ConsumerState { arguments: model); }, style: Theme.of(context) - .textButtonTheme - .style - ?.copyWith( - backgroundColor: - MaterialStateProperty.all( - CFColors.stackAccent, - ), - ), + .extension()! + .getPrimaryEnabledButtonColor(context), child: Text( "Next", - style: STextStyles.button, + style: STextStyles.button(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 a0c79343f..604e3707f 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 @@ -12,9 +12,9 @@ import 'package:stackwallet/providers/exchange/change_now_provider.dart'; import 'package:stackwallet/providers/global/trades_service_provider.dart'; import 'package:stackwallet/services/notifications_api.dart'; import 'package:stackwallet/utilities/assets.dart'; -import 'package:stackwallet/utilities/cfcolors.dart'; import 'package:stackwallet/utilities/clipboard_interface.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/rounded_white_container.dart'; import 'package:stackwallet/widgets/stack_dialog.dart'; @@ -50,7 +50,7 @@ class _Step3ViewState extends ConsumerState { @override Widget build(BuildContext context) { return Scaffold( - backgroundColor: CFColors.almostWhite, + backgroundColor: Theme.of(context).extension()!.background, appBar: AppBar( leading: AppBarBackButton( onPressed: () async { @@ -65,7 +65,7 @@ class _Step3ViewState extends ConsumerState { ), title: Text( "Exchange", - style: STextStyles.navBarTitle, + style: STextStyles.navBarTitle(context), ), ), body: LayoutBuilder( @@ -94,7 +94,7 @@ class _Step3ViewState extends ConsumerState { ), Text( "Confirm exchange details", - style: STextStyles.pageTitleH1, + style: STextStyles.pageTitleH1(context), ), const SizedBox( height: 24, @@ -104,12 +104,12 @@ class _Step3ViewState extends ConsumerState { children: [ Text( "You send", - style: STextStyles.itemSubtitle, + style: STextStyles.itemSubtitle(context), ), const Spacer(), Text( - "${model.sendAmount.toString()} ${model.sendTicker}", - style: STextStyles.itemSubtitle12, + "${model.sendAmount.toString()} ${model.sendTicker.toUpperCase()}", + style: STextStyles.itemSubtitle12(context), ) ], ), @@ -122,12 +122,12 @@ class _Step3ViewState extends ConsumerState { children: [ Text( "You receive", - style: STextStyles.itemSubtitle, + style: STextStyles.itemSubtitle(context), ), const Spacer(), Text( - "${model.receiveAmount.toString()} ${model.receiveTicker}", - style: STextStyles.itemSubtitle12, + "${model.receiveAmount.toString()} ${model.receiveTicker.toUpperCase()}", + style: STextStyles.itemSubtitle12(context), ) ], ), @@ -140,12 +140,12 @@ class _Step3ViewState extends ConsumerState { children: [ Text( "Estimated rate", - style: STextStyles.itemSubtitle, + style: STextStyles.itemSubtitle(context), ), const Spacer(), Text( model.rateInfo, - style: STextStyles.itemSubtitle12, + style: STextStyles.itemSubtitle12(context), ) ], ), @@ -158,15 +158,15 @@ class _Step3ViewState extends ConsumerState { crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( - "Recipient ${model.receiveTicker} address", - style: STextStyles.itemSubtitle, + "Recipient ${model.receiveTicker.toUpperCase()} address", + style: STextStyles.itemSubtitle(context), ), const SizedBox( height: 4, ), Text( model.recipientAddress!, - style: STextStyles.itemSubtitle12, + style: STextStyles.itemSubtitle12(context), ) ], ), @@ -179,15 +179,15 @@ class _Step3ViewState extends ConsumerState { crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( - "Refund ${model.sendTicker} address", - style: STextStyles.itemSubtitle, + "Refund ${model.sendTicker.toUpperCase()} address", + style: STextStyles.itemSubtitle(context), ), const SizedBox( height: 4, ), Text( model.refundAddress!, - style: STextStyles.itemSubtitle12, + style: STextStyles.itemSubtitle12(context), ) ], ), @@ -203,10 +203,15 @@ class _Step3ViewState extends ConsumerState { onPressed: () { Navigator.of(context).pop(); }, + style: Theme.of(context) + .extension()! + .getSecondaryEnabledButtonColor(context), child: Text( "Back", - style: STextStyles.button.copyWith( - color: CFColors.stackAccent, + style: STextStyles.button(context).copyWith( + color: Theme.of(context) + .extension()! + .buttonTextSecondary, ), ), ), @@ -304,17 +309,11 @@ class _Step3ViewState extends ConsumerState { } }, style: Theme.of(context) - .textButtonTheme - .style - ?.copyWith( - backgroundColor: - MaterialStateProperty.all( - CFColors.stackAccent, - ), - ), + .extension()! + .getPrimaryEnabledButtonColor(context), child: Text( "Next", - style: STextStyles.button, + style: STextStyles.button(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 91c3f1a6d..4a228baab 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 @@ -18,13 +18,13 @@ import 'package:stackwallet/providers/exchange/exchange_send_from_wallet_id_prov import 'package:stackwallet/providers/providers.dart'; import 'package:stackwallet/route_generator.dart'; import 'package:stackwallet/utilities/assets.dart'; -import 'package:stackwallet/utilities/cfcolors.dart'; import 'package:stackwallet/utilities/clipboard_interface.dart'; import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/enums/fee_rate_type_enum.dart'; import 'package:stackwallet/utilities/enums/flush_bar_type.dart'; import 'package:stackwallet/utilities/format.dart'; import 'package:stackwallet/utilities/text_styles.dart'; +import 'package:stackwallet/utilities/theme/stack_colors.dart'; import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart'; import 'package:stackwallet/widgets/rounded_container.dart'; import 'package:stackwallet/widgets/rounded_white_container.dart'; @@ -114,7 +114,7 @@ class _Step4ViewState extends ConsumerState { final bool isWalletCoin = _isWalletCoinAndHasWallet(model.trade!.fromCurrency, ref); return Scaffold( - backgroundColor: CFColors.almostWhite, + backgroundColor: Theme.of(context).extension()!.background, appBar: AppBar( leading: AppBarBackButton( onPressed: () async { @@ -129,7 +129,7 @@ class _Step4ViewState extends ConsumerState { ), title: Text( "Exchange", - style: STextStyles.navBarTitle, + style: STextStyles.navBarTitle(context), ), ), body: LayoutBuilder( @@ -157,35 +157,41 @@ class _Step4ViewState extends ConsumerState { height: 14, ), Text( - "Send ${model.sendTicker} to the address below", - style: STextStyles.pageTitleH1, + "Send ${model.sendTicker.toUpperCase()} to the address below", + style: STextStyles.pageTitleH1(context), ), const SizedBox( height: 8, ), Text( - "Send ${model.sendTicker} to the address below. Once it is received, ChangeNOW will send the ${model.receiveTicker} to the recipient address you provided. You can find this trade details and check its status in the list of trades.", - style: STextStyles.itemSubtitle, + "Send ${model.sendTicker.toUpperCase()} to the address below. Once it is received, ChangeNOW will send the ${model.receiveTicker.toUpperCase()} to the recipient address you provided. You can find this trade details and check its status in the list of trades.", + style: STextStyles.itemSubtitle(context), ), const SizedBox( height: 12, ), RoundedContainer( - color: CFColors.warningBackground, + color: Theme.of(context) + .extension()! + .warningBackground, child: RichText( text: TextSpan( text: "You must send at least ${model.sendAmount.toString()} ${model.sendTicker}. ", - style: STextStyles.label.copyWith( - color: CFColors.stackAccent, + style: STextStyles.label(context).copyWith( + color: Theme.of(context) + .extension()! + .warningForeground, fontWeight: FontWeight.w700, ), children: [ TextSpan( text: "If you send less than ${model.sendAmount.toString()} ${model.sendTicker}, your transaction may not be converted and it may not be refunded.", - style: STextStyles.label.copyWith( - color: CFColors.stackAccent, + style: STextStyles.label(context).copyWith( + color: Theme.of(context) + .extension()! + .warningForeground, fontWeight: FontWeight.w500, ), ), @@ -206,9 +212,7 @@ class _Step4ViewState extends ConsumerState { children: [ Text( "Amount", - style: STextStyles.itemSubtitle.copyWith( - color: CFColors.neutral50, - ), + style: STextStyles.itemSubtitle(context), ), GestureDetector( onTap: () async { @@ -225,7 +229,9 @@ class _Step4ViewState extends ConsumerState { children: [ SvgPicture.asset( Assets.svg.copy, - color: CFColors.link2, + color: Theme.of(context) + .extension()! + .infoItemIcons, width: 10, ), const SizedBox( @@ -233,7 +239,7 @@ class _Step4ViewState extends ConsumerState { ), Text( "Copy", - style: STextStyles.link2, + style: STextStyles.link2(context), ), ], ), @@ -244,8 +250,8 @@ class _Step4ViewState extends ConsumerState { height: 4, ), Text( - "${model.sendAmount.toString()} ${model.sendTicker}", - style: STextStyles.itemSubtitle12, + "${model.sendAmount.toString()} ${model.sendTicker.toUpperCase()}", + style: STextStyles.itemSubtitle12(context), ), ], ), @@ -262,10 +268,8 @@ class _Step4ViewState extends ConsumerState { MainAxisAlignment.spaceBetween, children: [ Text( - "Send ${model.sendTicker} to this address", - style: STextStyles.itemSubtitle.copyWith( - color: CFColors.neutral50, - ), + "Send ${model.sendTicker.toUpperCase()} to this address", + style: STextStyles.itemSubtitle(context), ), GestureDetector( onTap: () async { @@ -282,7 +286,9 @@ class _Step4ViewState extends ConsumerState { children: [ SvgPicture.asset( Assets.svg.copy, - color: CFColors.link2, + color: Theme.of(context) + .extension()! + .infoItemIcons, width: 10, ), const SizedBox( @@ -290,7 +296,7 @@ class _Step4ViewState extends ConsumerState { ), Text( "Copy", - style: STextStyles.link2, + style: STextStyles.link2(context), ), ], ), @@ -302,7 +308,7 @@ class _Step4ViewState extends ConsumerState { ), Text( model.trade!.payinAddress, - style: STextStyles.itemSubtitle12, + style: STextStyles.itemSubtitle12(context), ), ], ), @@ -315,14 +321,14 @@ class _Step4ViewState extends ConsumerState { children: [ Text( "Trade ID", - style: STextStyles.itemSubtitle, + style: STextStyles.itemSubtitle(context), ), const Spacer(), Row( children: [ Text( model.trade!.id, - style: STextStyles.itemSubtitle12, + style: STextStyles.itemSubtitle12(context), ), const SizedBox( width: 10, @@ -340,7 +346,9 @@ class _Step4ViewState extends ConsumerState { }, child: SvgPicture.asset( Assets.svg.copy, - color: CFColors.link2, + color: Theme.of(context) + .extension()! + .infoItemIcons, width: 12, ), ) @@ -358,14 +366,15 @@ class _Step4ViewState extends ConsumerState { children: [ Text( "Status", - style: STextStyles.itemSubtitle.copyWith( - color: CFColors.neutral50, - ), + style: STextStyles.itemSubtitle(context), ), Text( _statusString, - style: STextStyles.itemSubtitle.copyWith( - color: CFColors.status.forStatus(_status), + style: + STextStyles.itemSubtitle(context).copyWith( + color: Theme.of(context) + .extension()! + .colorForStatus(_status), ), ), ], @@ -390,7 +399,8 @@ class _Step4ViewState extends ConsumerState { Center( child: Text( "Send ${model.sendTicker} to this address", - style: STextStyles.pageTitleH2, + style: + STextStyles.pageTitleH2(context), ), ), const SizedBox( @@ -405,7 +415,9 @@ class _Step4ViewState extends ConsumerState { .size .width / 2, - foregroundColor: CFColors.stackAccent, + foregroundColor: Theme.of(context) + .extension()! + .accentColorDark, ), ), const SizedBox( @@ -418,11 +430,18 @@ class _Step4ViewState extends ConsumerState { child: TextButton( onPressed: () => Navigator.of(context).pop(), + style: Theme.of(context) + .extension()! + .getSecondaryEnabledButtonColor( + context), child: Text( "Cancel", style: - STextStyles.button.copyWith( - color: CFColors.stackAccent, + STextStyles.button(context) + .copyWith( + color: Theme.of(context) + .extension()! + .buttonTextSecondary, ), ), ), @@ -435,16 +454,12 @@ class _Step4ViewState extends ConsumerState { }, ); }, - style: - Theme.of(context).textButtonTheme.style?.copyWith( - backgroundColor: - MaterialStateProperty.all( - CFColors.stackAccent, - ), - ), + style: Theme.of(context) + .extension()! + .getPrimaryEnabledButtonColor(context), child: Text( "Show QR Code", - style: STextStyles.button, + style: STextStyles.button(context), ), ), if (isWalletCoin) @@ -563,21 +578,18 @@ class _Step4ViewState extends ConsumerState { message: e.toString(), rightButton: TextButton( style: Theme.of(context) - .textButtonTheme - .style - ?.copyWith( - backgroundColor: - MaterialStateProperty - .all( - CFColors.buttonGray, - ), - ), + .extension()! + .getSecondaryEnabledButtonColor( + context), child: Text( "Ok", - style: STextStyles.button + style: STextStyles.button( + context) .copyWith( - color: - CFColors.stackAccent, + color: Theme.of(context) + .extension< + StackColors>()! + .buttonTextSecondary, ), ), onPressed: () { @@ -614,10 +626,15 @@ class _Step4ViewState extends ConsumerState { ), ); }, + style: Theme.of(context) + .extension()! + .getSecondaryEnabledButtonColor(context), child: Text( buttonTitle, - style: STextStyles.button.copyWith( - color: CFColors.stackAccent, + style: STextStyles.button(context).copyWith( + color: Theme.of(context) + .extension()! + .buttonTextSecondary, ), ), ); diff --git a/lib/pages/exchange_view/exchange_view.dart b/lib/pages/exchange_view/exchange_view.dart index b95315359..2f0bfe194 100644 --- a/lib/pages/exchange_view/exchange_view.dart +++ b/lib/pages/exchange_view/exchange_view.dart @@ -29,10 +29,10 @@ import 'package:stackwallet/providers/exchange/trade_sent_from_stack_lookup_prov import 'package:stackwallet/providers/global/trades_service_provider.dart'; import 'package:stackwallet/providers/providers.dart'; import 'package:stackwallet/utilities/assets.dart'; -import 'package:stackwallet/utilities/cfcolors.dart'; import 'package:stackwallet/utilities/constants.dart'; import 'package:stackwallet/utilities/enums/flush_bar_type.dart'; import 'package:stackwallet/utilities/text_styles.dart'; +import 'package:stackwallet/utilities/theme/stack_colors.dart'; import 'package:stackwallet/widgets/custom_loading_overlay.dart'; import 'package:stackwallet/widgets/loading_indicator.dart'; import 'package:stackwallet/widgets/stack_dialog.dart'; @@ -66,7 +66,10 @@ class _ExchangeViewState extends ConsumerState { builder: (_) => WillPopScope( onWillPop: () async => false, child: Container( - color: CFColors.stackAccent.withOpacity(0.8), + color: Theme.of(context) + .extension()! + .overlay + .withOpacity(0.6), child: const CustomLoadingOverlay( message: "Updating exchange rate", eventBus: null, @@ -366,8 +369,10 @@ class _ExchangeViewState extends ConsumerState { ), Text( "You will send", - style: STextStyles.itemSubtitle.copyWith( - color: CFColors.neutral50, + style: STextStyles.itemSubtitle(context).copyWith( + color: Theme.of(context) + .extension()! + .textDark3, ), ), const SizedBox( @@ -436,7 +441,7 @@ class _ExchangeViewState extends ConsumerState { right: 12, ), hintText: "0", - hintStyle: STextStyles.fieldLabel.copyWith( + hintStyle: STextStyles.fieldLabel(context).copyWith( fontSize: 14, ), prefixIcon: FittedBox( @@ -561,7 +566,10 @@ class _ExchangeViewState extends ConsumerState { width: 18, height: 18, decoration: BoxDecoration( - color: CFColors.gray3, + color: Theme.of(context) + .extension< + StackColors>()! + .textFieldDefaultBG, borderRadius: BorderRadius.circular( 18, @@ -583,7 +591,7 @@ class _ExchangeViewState extends ConsumerState { width: 18, height: 18, decoration: BoxDecoration( - // color: CFColors.stackAccent, + // color: Theme.of(context).extension()!.accentColorDark borderRadius: BorderRadius.circular(18), ), @@ -591,7 +599,9 @@ class _ExchangeViewState extends ConsumerState { Assets.svg.circleQuestion, width: 18, height: 18, - color: CFColors.gray3, + color: Theme.of(context) + .extension()! + .textFieldDefaultBG, ), ); } @@ -615,8 +625,11 @@ class _ExchangeViewState extends ConsumerState { .market?.from .toUpperCase())) ?? "-", - style: STextStyles.smallMed14.copyWith( - color: CFColors.stackAccent, + style: STextStyles.smallMed14(context) + .copyWith( + color: Theme.of(context) + .extension()! + .textDark, ), ), const SizedBox( @@ -626,7 +639,9 @@ class _ExchangeViewState extends ConsumerState { Assets.svg.chevronDown, width: 5, height: 2.5, - color: CFColors.stackAccent, + color: Theme.of(context) + .extension()! + .textDark, ), ], ), @@ -646,25 +661,41 @@ class _ExchangeViewState extends ConsumerState { alignment: Alignment.bottomLeft, child: Text( "You will receive", - style: STextStyles.itemSubtitle.copyWith( - color: CFColors.neutral50, + style: + STextStyles.itemSubtitle(context).copyWith( + color: Theme.of(context) + .extension()! + .textDark3, ), ), ), ), Center( - child: GestureDetector( - onTap: () async { - await _swap(); - }, - child: Padding( - padding: const EdgeInsets.all(4), - child: SvgPicture.asset( - Assets.svg.swap, - width: 20, - height: 20, + child: Column( + children: [ + const SizedBox( + height: 6, ), - ), + GestureDetector( + onTap: () async { + await _swap(); + }, + child: Padding( + padding: const EdgeInsets.all(4), + child: SvgPicture.asset( + Assets.svg.swap, + width: 20, + height: 20, + color: Theme.of(context) + .extension()! + .accentColorDark, + ), + ), + ), + const SizedBox( + height: 6, + ), + ], ), ), Positioned.fill( @@ -679,7 +710,7 @@ class _ExchangeViewState extends ConsumerState { : ref.watch(fixedRateExchangeFormProvider .select((value) => value.sendAmountWarning)), - style: STextStyles.errorSmall, + style: STextStyles.errorSmall(context), ), ), ), @@ -755,7 +786,7 @@ class _ExchangeViewState extends ConsumerState { right: 12, ), hintText: "0", - hintStyle: STextStyles.fieldLabel.copyWith( + hintStyle: STextStyles.fieldLabel(context).copyWith( fontSize: 14, ), prefixIcon: FittedBox( @@ -874,7 +905,10 @@ class _ExchangeViewState extends ConsumerState { width: 18, height: 18, decoration: BoxDecoration( - color: CFColors.gray3, + color: Theme.of(context) + .extension< + StackColors>()! + .textFieldDefaultBG, borderRadius: BorderRadius.circular( 18), @@ -895,7 +929,7 @@ class _ExchangeViewState extends ConsumerState { width: 18, height: 18, decoration: BoxDecoration( - // color: CFColors.stackAccent, + // color: Theme.of(context).extension()!.accentColorDark borderRadius: BorderRadius.circular(18), ), @@ -903,7 +937,9 @@ class _ExchangeViewState extends ConsumerState { Assets.svg.circleQuestion, width: 18, height: 18, - color: CFColors.gray3, + color: Theme.of(context) + .extension()! + .textFieldDefaultBG, ), ); } @@ -927,8 +963,11 @@ class _ExchangeViewState extends ConsumerState { .market?.to .toUpperCase())) ?? "-", - style: STextStyles.smallMed14.copyWith( - color: CFColors.stackAccent, + style: STextStyles.smallMed14(context) + .copyWith( + color: Theme.of(context) + .extension()! + .textDark, ), ), const SizedBox( @@ -938,7 +977,9 @@ class _ExchangeViewState extends ConsumerState { Assets.svg.chevronDown, width: 5, height: 2.5, - color: CFColors.stackAccent, + color: Theme.of(context) + .extension()! + .textDark, ), ], ), @@ -966,7 +1007,7 @@ class _ExchangeViewState extends ConsumerState { // Text( // ref.watch(exchangeFormSateProvider.select( // (value) => value.minimumReceiveWarning)), - // style: STextStyles.errorSmall, + // style: STextStyles.errorSmall(context), // ), // ], // ), @@ -1117,28 +1158,20 @@ class _ExchangeViewState extends ConsumerState { height: 12, ), TextButton( - style: Theme.of(context) - .textButtonTheme - .style - ?.copyWith( - backgroundColor: MaterialStateProperty.all( - ((ref - .read( - prefsChangeNotifierProvider) - .exchangeRateType == - ExchangeRateType.estimated) - ? ref.watch( - estimatedRateExchangeFormProvider - .select((value) => - value.canExchange)) - : ref.watch( - fixedRateExchangeFormProvider - .select((value) => - value.canExchange))) - ? CFColors.stackAccent - : CFColors.buttonGray, - ), - ), + style: ((ref + .read(prefsChangeNotifierProvider) + .exchangeRateType == + ExchangeRateType.estimated) + ? ref.watch(estimatedRateExchangeFormProvider + .select((value) => value.canExchange)) + : ref.watch(fixedRateExchangeFormProvider + .select((value) => value.canExchange))) + ? Theme.of(context) + .extension()! + .getPrimaryEnabledButtonColor(context) + : Theme.of(context) + .extension()! + .getPrimaryDisabledButtonColor(context), onPressed: ((ref .read(prefsChangeNotifierProvider) .exchangeRateType == @@ -1304,18 +1337,13 @@ class _ExchangeViewState extends ConsumerState { "${response.value!.warningMessage!}\n\nDo you want to attempt trade anyways?", leftButton: TextButton( style: Theme.of(context) - .textButtonTheme - .style - ?.copyWith( - backgroundColor: - MaterialStateProperty.all< - Color>( - CFColors.buttonGray, - ), - ), + .extension()! + .getSecondaryEnabledButtonColor( + context), child: Text( "Cancel", - style: STextStyles.itemSubtitle12, + style: STextStyles.itemSubtitle12( + context), ), onPressed: () { // notify return to cancel @@ -1324,18 +1352,12 @@ class _ExchangeViewState extends ConsumerState { ), rightButton: TextButton( style: Theme.of(context) - .textButtonTheme - .style - ?.copyWith( - backgroundColor: - MaterialStateProperty.all< - Color>( - CFColors.stackAccent, - ), - ), + .extension()! + .getPrimaryEnabledButtonColor( + context), child: Text( "Attempt", - style: STextStyles.button, + style: STextStyles.button(context), ), onPressed: () { // continue and try to attempt trade @@ -1351,7 +1373,7 @@ class _ExchangeViewState extends ConsumerState { } String rate = - "1 $fromTicker ~${ref.read(fixedRateExchangeFormProvider).rate!.toStringAsFixed(8)} $toTicker"; + "1 ${fromTicker.toUpperCase()} ~${ref.read(fixedRateExchangeFormProvider).rate!.toStringAsFixed(8)} ${toTicker.toUpperCase()}"; final model = IncompleteExchangeModel( sendTicker: fromTicker, @@ -1379,7 +1401,7 @@ class _ExchangeViewState extends ConsumerState { : null, child: Text( "Exchange", - style: STextStyles.button, + style: STextStyles.button(context), ), ), const SizedBox( @@ -1387,8 +1409,8 @@ class _ExchangeViewState extends ConsumerState { ), // Text( // "Trades", - // style: STextStyles.itemSubtitle.copyWith( - // color: CFColors.neutral50, + // style: STextStyles.itemSubtitle(context).copyWith( + // color: Theme.of(context).extension()!.textDark3, // ), // ), // SizedBox( @@ -1427,8 +1449,10 @@ class _ExchangeViewState extends ConsumerState { ), Text( "Trades", - style: STextStyles.itemSubtitle.copyWith( - color: CFColors.neutral50, + style: STextStyles.itemSubtitle(context).copyWith( + color: Theme.of(context) + .extension()! + .textDark3, ), ), const SizedBox( @@ -1471,6 +1495,7 @@ class _ExchangeViewState extends ConsumerState { debugPrint("name: ${manager.walletName}"); + // TODO store tx data completely locally in isar so we don't lock up ui here when querying txData final txData = await manager.transactionData; final tx = txData.getAllTransactions()[txid]; @@ -1500,7 +1525,9 @@ class _ExchangeViewState extends ConsumerState { padding: const EdgeInsets.symmetric(horizontal: 4), child: Container( decoration: BoxDecoration( - color: CFColors.white, + color: Theme.of(context) + .extension()! + .popupBG, borderRadius: BorderRadius.circular( Constants.size.circularBorderRadius, ), @@ -1510,7 +1537,7 @@ class _ExchangeViewState extends ConsumerState { child: Text( "Trades will appear here", textAlign: TextAlign.center, - style: STextStyles.itemSubtitle, + style: STextStyles.itemSubtitle(context), ), ), ), @@ -1542,7 +1569,7 @@ class RateInfo extends ConsumerWidget { return Container( decoration: BoxDecoration( - color: CFColors.white, + color: Theme.of(context).extension()!.popupBG, borderRadius: BorderRadius.circular( Constants.size.circularBorderRadius, ), @@ -1620,7 +1647,7 @@ class RateInfo extends ConsumerWidget { children: [ Text( isEstimated ? "Estimated rate" : "Fixed rate", - style: STextStyles.itemSubtitle, + style: STextStyles.itemSubtitle(context), ), const SizedBox( width: 6, @@ -1630,7 +1657,9 @@ class RateInfo extends ConsumerWidget { Assets.svg.chevronDown, width: 5, height: 2.5, - color: CFColors.neutral60, + color: Theme.of(context) + .extension()! + .infoItemLabel, ), ], ), @@ -1647,7 +1676,7 @@ class RateInfo extends ConsumerWidget { .select((value) => value.rateDisplayString)) : ref.watch(fixedRateExchangeFormProvider .select((value) => value.rateDisplayString)), - style: STextStyles.itemSubtitle12, + style: STextStyles.itemSubtitle12(context), ), ), ), diff --git a/lib/pages/exchange_view/send_from_view.dart b/lib/pages/exchange_view/send_from_view.dart index e50796e75..e677ab5c0 100644 --- a/lib/pages/exchange_view/send_from_view.dart +++ b/lib/pages/exchange_view/send_from_view.dart @@ -1,3 +1,5 @@ +import 'dart:async'; + import 'package:decimal/decimal.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; @@ -9,12 +11,12 @@ import 'package:stackwallet/pages/send_view/sub_widgets/building_transaction_dia import 'package:stackwallet/providers/providers.dart'; import 'package:stackwallet/route_generator.dart'; import 'package:stackwallet/utilities/assets.dart'; -import 'package:stackwallet/utilities/cfcolors.dart'; import 'package:stackwallet/utilities/constants.dart'; import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/enums/fee_rate_type_enum.dart'; import 'package:stackwallet/utilities/format.dart'; import 'package:stackwallet/utilities/text_styles.dart'; +import 'package:stackwallet/utilities/theme/stack_colors.dart'; import 'package:stackwallet/widgets/animated_text.dart'; import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart'; import 'package:stackwallet/widgets/rounded_white_container.dart'; @@ -58,7 +60,7 @@ class _SendFromViewState extends ConsumerState { @override Widget build(BuildContext context) { return Scaffold( - backgroundColor: CFColors.almostWhite, + backgroundColor: Theme.of(context).extension()!.background, appBar: AppBar( leading: AppBarBackButton( onPressed: () { @@ -67,7 +69,7 @@ class _SendFromViewState extends ConsumerState { ), title: Text( "Send ", - style: STextStyles.navBarTitle, + style: STextStyles.navBarTitle(context), ), ), body: Padding( @@ -77,14 +79,14 @@ class _SendFromViewState extends ConsumerState { children: [ Text( "Choose your ${coin.ticker} wallet", - style: STextStyles.pageTitleH1, + style: STextStyles.pageTitleH1(context), ), const SizedBox( height: 8, ), Text( "You need to send ${amount.toStringAsFixed(coin == Coin.monero ? 12 : 8)} ${coin.ticker}", - style: STextStyles.itemSubtitle, + style: STextStyles.itemSubtitle(context), ), const SizedBox( height: 16, @@ -159,7 +161,7 @@ class _SendFromCardState extends ConsumerState { return RoundedWhiteContainer( padding: const EdgeInsets.all(0), child: MaterialButton( - splashColor: CFColors.splashLight, + splashColor: Theme.of(context).extension()!.highlight, key: Key("walletsSheetItemButtonKey_$walletId"), padding: const EdgeInsets.all(5), materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, @@ -174,7 +176,7 @@ class _SendFromCardState extends ConsumerState { try { bool wasCancelled = false; - showDialog( + unawaited(showDialog( context: context, useSafeArea: false, barrierDismissible: false, @@ -187,7 +189,7 @@ class _SendFromCardState extends ConsumerState { }, ); }, - ); + )); final txData = await manager.prepareSend( address: address, @@ -210,7 +212,7 @@ class _SendFromCardState extends ConsumerState { txData["address"] = address; if (mounted) { - Navigator.of(context).push( + await Navigator.of(context).push( RouteGenerator.getRoute( shouldUseMaterialRoute: RouteGenerator.useMaterialPageRoute, builder: (_) => ConfirmChangeNowSendView( @@ -231,7 +233,7 @@ class _SendFromCardState extends ConsumerState { // pop building dialog Navigator.of(context).pop(); - showDialog( + await showDialog( context: context, useSafeArea: false, barrierDismissible: true, @@ -240,15 +242,15 @@ class _SendFromCardState extends ConsumerState { title: "Transaction failed", message: e.toString(), rightButton: TextButton( - style: Theme.of(context).textButtonTheme.style?.copyWith( - backgroundColor: MaterialStateProperty.all( - CFColors.buttonGray, - ), - ), + style: Theme.of(context) + .extension()! + .getSecondaryEnabledButtonColor(context), child: Text( "Ok", - style: STextStyles.button.copyWith( - color: CFColors.stackAccent, + style: STextStyles.button(context).copyWith( + color: Theme.of(context) + .extension()! + .buttonTextSecondary, ), ), onPressed: () { @@ -265,7 +267,10 @@ class _SendFromCardState extends ConsumerState { children: [ Container( decoration: BoxDecoration( - color: CFColors.coin.forCoin(manager.coin).withOpacity(0.5), + color: Theme.of(context) + .extension()! + .colorForCoin(manager.coin) + .withOpacity(0.5), borderRadius: BorderRadius.circular( Constants.size.circularBorderRadius, ), @@ -288,7 +293,7 @@ class _SendFromCardState extends ConsumerState { children: [ Text( manager.walletName, - style: STextStyles.titleBold12, + style: STextStyles.titleBold12(context), ), const SizedBox( height: 2, @@ -304,7 +309,7 @@ class _SendFromCardState extends ConsumerState { locale: locale, decimalPlaces: coin == Coin.monero ? 12 : 8, )} ${coin.ticker}", - style: STextStyles.itemSubtitle, + style: STextStyles.itemSubtitle(context), ); } else { return AnimatedText( @@ -314,7 +319,7 @@ class _SendFromCardState extends ConsumerState { "Loading balance..", "Loading balance..." ], - style: STextStyles.itemSubtitle, + style: STextStyles.itemSubtitle(context), ); } }, diff --git a/lib/pages/exchange_view/sub_widgets/exchange_rate_sheet.dart b/lib/pages/exchange_view/sub_widgets/exchange_rate_sheet.dart index 4a96a6074..efef2f964 100644 --- a/lib/pages/exchange_view/sub_widgets/exchange_rate_sheet.dart +++ b/lib/pages/exchange_view/sub_widgets/exchange_rate_sheet.dart @@ -1,9 +1,9 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:stackwallet/providers/providers.dart'; -import 'package:stackwallet/utilities/cfcolors.dart'; import 'package:stackwallet/utilities/constants.dart'; import 'package:stackwallet/utilities/text_styles.dart'; +import 'package:stackwallet/utilities/theme/stack_colors.dart'; enum ExchangeRateType { estimated, fixed } @@ -15,9 +15,9 @@ class ExchangeRateSheet extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { return Container( - decoration: const BoxDecoration( - color: CFColors.white, - borderRadius: BorderRadius.vertical( + decoration: BoxDecoration( + color: Theme.of(context).extension()!.popupBG, + borderRadius: const BorderRadius.vertical( top: Radius.circular(20), ), ), @@ -35,7 +35,8 @@ class ExchangeRateSheet extends ConsumerWidget { Center( child: Container( decoration: BoxDecoration( - color: CFColors.fieldGray, + color: + Theme.of(context).extension()!.textSubtitle4, borderRadius: BorderRadius.circular( Constants.size.circularBorderRadius, ), @@ -49,7 +50,7 @@ class ExchangeRateSheet extends ConsumerWidget { ), Text( "Exchange rate", - style: STextStyles.pageTitleH2, + style: STextStyles.pageTitleH2(context), textAlign: TextAlign.left, ), const SizedBox( @@ -76,7 +77,9 @@ class ExchangeRateSheet extends ConsumerWidget { width: 20, height: 20, child: Radio( - activeColor: CFColors.link2, + activeColor: Theme.of(context) + .extension()! + .radioButtonIconEnabled, value: ExchangeRateType.estimated, groupValue: ref.watch(prefsChangeNotifierProvider .select((value) => value.exchangeRateType)), @@ -102,9 +105,7 @@ class ExchangeRateSheet extends ConsumerWidget { children: [ Text( "Estimated rate", - style: STextStyles.titleBold12.copyWith( - color: const Color(0xFF44464E), - ), + style: STextStyles.titleBold12(context), textAlign: TextAlign.left, ), const SizedBox( @@ -112,7 +113,11 @@ class ExchangeRateSheet extends ConsumerWidget { ), Text( "ChangeNOW will pick the best rate for you during the moment of the exchange.", - style: STextStyles.itemSubtitle, + style: STextStyles.itemSubtitle(context).copyWith( + color: Theme.of(context) + .extension()! + .textSubtitle1, + ), textAlign: TextAlign.left, ), ], @@ -146,7 +151,9 @@ class ExchangeRateSheet extends ConsumerWidget { width: 20, height: 20, child: Radio( - activeColor: CFColors.link2, + activeColor: Theme.of(context) + .extension()! + .radioButtonIconEnabled, value: ExchangeRateType.fixed, groupValue: ref.watch(prefsChangeNotifierProvider .select((value) => value.exchangeRateType)), @@ -169,9 +176,7 @@ class ExchangeRateSheet extends ConsumerWidget { children: [ Text( "Fixed rate", - style: STextStyles.titleBold12.copyWith( - color: const Color(0xFF44464E), - ), + style: STextStyles.titleBold12(context), textAlign: TextAlign.left, ), const SizedBox( @@ -179,7 +184,11 @@ class ExchangeRateSheet extends ConsumerWidget { ), Text( "You will get the exact exchange amount displayed - ChangeNOW takes all the rate risks.", - style: STextStyles.itemSubtitle, + style: STextStyles.itemSubtitle(context).copyWith( + color: Theme.of(context) + .extension()! + .textSubtitle1, + ), textAlign: TextAlign.left, ) ], diff --git a/lib/pages/exchange_view/sub_widgets/step_indicator.dart b/lib/pages/exchange_view/sub_widgets/step_indicator.dart index c4923a379..fd0d3a859 100644 --- a/lib/pages/exchange_view/sub_widgets/step_indicator.dart +++ b/lib/pages/exchange_view/sub_widgets/step_indicator.dart @@ -1,8 +1,8 @@ -import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; import 'package:flutter_svg/svg.dart'; import 'package:google_fonts/google_fonts.dart'; import 'package:stackwallet/utilities/assets.dart'; -import 'package:stackwallet/utilities/cfcolors.dart'; +import 'package:stackwallet/utilities/theme/stack_colors.dart'; enum StepIndicatorStatus { current, completed, incomplete } @@ -19,18 +19,22 @@ class StepIndicator extends StatelessWidget { final double size; - Color get background { + Color background(BuildContext context) { switch (status) { case StepIndicatorStatus.current: - return CFColors.selection; + return Theme.of(context) + .extension()! + .stepIndicatorBGNumber; case StepIndicatorStatus.completed: - return CFColors.selection; + return Theme.of(context).extension()!.stepIndicatorBGCheck; case StepIndicatorStatus.incomplete: - return CFColors.stackAccent.withOpacity(0.2); + return Theme.of(context) + .extension()! + .stepIndicatorBGInactive; } } - Widget get centered { + Widget centered(BuildContext context) { switch (status) { case StepIndicatorStatus.current: return Text( @@ -38,13 +42,16 @@ class StepIndicator extends StatelessWidget { style: GoogleFonts.roboto( fontWeight: FontWeight.w600, fontSize: 8, - color: CFColors.link2, + color: Theme.of(context) + .extension()! + .stepIndicatorIconNumber, ), ); case StepIndicatorStatus.completed: return SvgPicture.asset( Assets.svg.check, - color: CFColors.link2, + color: + Theme.of(context).extension()!.stepIndicatorIconText, width: 10, ); case StepIndicatorStatus.incomplete: @@ -53,7 +60,9 @@ class StepIndicator extends StatelessWidget { style: GoogleFonts.roboto( fontWeight: FontWeight.w600, fontSize: 8, - color: CFColors.white, + color: Theme.of(context) + .extension()! + .stepIndicatorIconInactive, ), ); } @@ -66,10 +75,10 @@ class StepIndicator extends StatelessWidget { height: size, decoration: BoxDecoration( borderRadius: BorderRadius.circular(size / 2), - color: background, + color: background(context), ), child: Center( - child: centered, + child: centered(context), ), ); } diff --git a/lib/pages/exchange_view/sub_widgets/step_row.dart b/lib/pages/exchange_view/sub_widgets/step_row.dart index 5404eb98b..398ac1c16 100644 --- a/lib/pages/exchange_view/sub_widgets/step_row.dart +++ b/lib/pages/exchange_view/sub_widgets/step_row.dart @@ -1,6 +1,6 @@ -import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; import 'package:stackwallet/pages/exchange_view/sub_widgets/step_indicator.dart'; -import 'package:stackwallet/utilities/cfcolors.dart'; +import 'package:stackwallet/utilities/theme/stack_colors.dart'; class StepRow extends StatelessWidget { const StepRow({ @@ -18,15 +18,17 @@ class StepRow extends StatelessWidget { final double indicatorSize; final double minSpacing; - Color getColor(int index) { + Color getColor(int index, BuildContext context) { if (current >= count - 1) { - return CFColors.stackAccent; + return Theme.of(context).extension()!.accentColorDark; } if (current <= index) { - return CFColors.stackAccent.withOpacity(0.2); + return Theme.of(context) + .extension()! + .stepIndicatorBGLinesInactive; } else { - return CFColors.link2; + return Theme.of(context).extension()!.stepIndicatorBGLines; } } @@ -40,7 +42,7 @@ class StepRow extends StatelessWidget { } } - List _buildList(double spacerWidth) { + List _buildList(double spacerWidth, BuildContext context) { List list = []; for (int i = 0; i < count - 1; i++) { list.add(StepIndicator( @@ -51,7 +53,7 @@ class StepRow extends StatelessWidget { width: spacerWidth, dotSize: 1.5, spacing: 4, - color: getColor(i), + color: getColor(i, context), )); } list.add(StepIndicator( @@ -68,7 +70,7 @@ class StepRow extends StatelessWidget { return Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - ..._buildList(spacerWidth), + ..._buildList(spacerWidth, context), ], ); } diff --git a/lib/pages/exchange_view/trade_details_view.dart b/lib/pages/exchange_view/trade_details_view.dart index 68b1f49a6..439b0f659 100644 --- a/lib/pages/exchange_view/trade_details_view.dart +++ b/lib/pages/exchange_view/trade_details_view.dart @@ -17,12 +17,12 @@ import 'package:stackwallet/providers/exchange/trade_note_service_provider.dart' import 'package:stackwallet/providers/global/trades_service_provider.dart'; import 'package:stackwallet/providers/providers.dart'; import 'package:stackwallet/utilities/assets.dart'; -import 'package:stackwallet/utilities/cfcolors.dart'; import 'package:stackwallet/utilities/clipboard_interface.dart'; import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/enums/flush_bar_type.dart'; import 'package:stackwallet/utilities/format.dart'; import 'package:stackwallet/utilities/text_styles.dart'; +import 'package:stackwallet/utilities/theme/stack_colors.dart'; import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart'; import 'package:stackwallet/widgets/rounded_container.dart'; import 'package:stackwallet/widgets/rounded_white_container.dart'; @@ -108,11 +108,11 @@ class _TradeDetailsViewState extends ConsumerState { case ChangeNowTransactionStatus.Sending: case ChangeNowTransactionStatus.Refunded: case ChangeNowTransactionStatus.Verifying: - return Assets.svg.txExchangePending; + return Assets.svg.txExchangePending(context); case ChangeNowTransactionStatus.Finished: - return Assets.svg.txExchange; + return Assets.svg.txExchange(context); case ChangeNowTransactionStatus.Failed: - return Assets.svg.txExchangeFailed; + return Assets.svg.txExchangeFailed(context); } } @@ -140,9 +140,9 @@ class _TradeDetailsViewState extends ConsumerState { Decimal.parse("-1"); return Scaffold( - backgroundColor: CFColors.almostWhite, + backgroundColor: Theme.of(context).extension()!.background, appBar: AppBar( - backgroundColor: CFColors.almostWhite, + backgroundColor: Theme.of(context).extension()!.background, leading: AppBarBackButton( onPressed: () async { Navigator.of(context).pop(); @@ -150,7 +150,7 @@ class _TradeDetailsViewState extends ConsumerState { ), title: Text( "Trade details", - style: STextStyles.navBarTitle, + style: STextStyles.navBarTitle(context), ), ), body: Padding( @@ -170,7 +170,7 @@ class _TradeDetailsViewState extends ConsumerState { children: [ SelectableText( "${trade.fromCurrency.toUpperCase()} → ${trade.toCurrency.toUpperCase()}", - style: STextStyles.titleBold12, + style: STextStyles.titleBold12(context), ), const SizedBox( height: 4, @@ -180,7 +180,7 @@ class _TradeDetailsViewState extends ConsumerState { localeServiceChangeNotifierProvider .select((value) => value.locale), ), decimalPlaces: trade.fromCurrency.toLowerCase() == "xmr" ? 12 : 8)} ${trade.fromCurrency.toUpperCase()}", - style: STextStyles.itemSubtitle, + style: STextStyles.itemSubtitle(context), ), ], ), @@ -212,18 +212,21 @@ class _TradeDetailsViewState extends ConsumerState { children: [ Text( "Status", - style: STextStyles.itemSubtitle, + style: STextStyles.itemSubtitle(context), ), const SizedBox( height: 4, ), SelectableText( trade.statusObject?.status.name ?? trade.statusString, - style: STextStyles.itemSubtitle.copyWith( + style: STextStyles.itemSubtitle(context).copyWith( color: trade.statusObject != null - ? CFColors.status - .forStatus(trade.statusObject!.status) - : CFColors.stackAccent, + ? Theme.of(context) + .extension()! + .colorForStatus(trade.statusObject!.status) + : Theme.of(context) + .extension()! + .accentColorDark, ), ), // ), @@ -237,15 +240,19 @@ class _TradeDetailsViewState extends ConsumerState { ), if (!sentFromStack && !hasTx) RoundedContainer( - color: CFColors.warningBackground, + color: Theme.of(context) + .extension()! + .warningBackground, child: RichText( text: TextSpan( text: "You must send at least ${sendAmount.toStringAsFixed( trade.fromCurrency.toLowerCase() == "xmr" ? 12 : 8, )} ${trade.fromCurrency.toUpperCase()}. ", - style: STextStyles.label.copyWith( - color: CFColors.stackAccent, + style: STextStyles.label(context).copyWith( + color: Theme.of(context) + .extension()! + .warningForeground, fontWeight: FontWeight.w700, ), children: [ @@ -256,8 +263,10 @@ class _TradeDetailsViewState extends ConsumerState { ? 12 : 8, )} ${trade.fromCurrency.toUpperCase()}, your transaction may not be converted and it may not be refunded.", - style: STextStyles.label.copyWith( - color: CFColors.stackAccent, + style: STextStyles.label(context).copyWith( + color: Theme.of(context) + .extension()! + .warningForeground, fontWeight: FontWeight.w500, ), ), @@ -275,14 +284,14 @@ class _TradeDetailsViewState extends ConsumerState { children: [ Text( "Sent from", - style: STextStyles.itemSubtitle, + style: STextStyles.itemSubtitle(context), ), const SizedBox( height: 4, ), SelectableText( widget.walletName!, - style: STextStyles.itemSubtitle12, + style: STextStyles.itemSubtitle12(context), ), const SizedBox( height: 10, @@ -300,7 +309,7 @@ class _TradeDetailsViewState extends ConsumerState { }, child: Text( "View transaction", - style: STextStyles.link2, + style: STextStyles.link2(context), ), ), ], @@ -317,14 +326,14 @@ class _TradeDetailsViewState extends ConsumerState { children: [ Text( "ChangeNOW address", - style: STextStyles.itemSubtitle, + style: STextStyles.itemSubtitle(context), ), const SizedBox( height: 4, ), SelectableText( trade.payinAddress, - style: STextStyles.itemSubtitle12, + style: STextStyles.itemSubtitle12(context), ), ], ), @@ -340,14 +349,14 @@ class _TradeDetailsViewState extends ConsumerState { children: [ Text( "Send ${trade.fromCurrency.toUpperCase()} to this address", - style: STextStyles.itemSubtitle, + style: STextStyles.itemSubtitle(context), ), const SizedBox( height: 4, ), SelectableText( trade.payinAddress, - style: STextStyles.itemSubtitle12, + style: STextStyles.itemSubtitle12(context), ), const SizedBox( height: 10, @@ -368,8 +377,9 @@ class _TradeDetailsViewState extends ConsumerState { children: [ Center( child: Text( - "Recovery phrase QR code", - style: STextStyles.pageTitleH2, + "Send ${trade.fromCurrency.toUpperCase()} to this address", + style: + STextStyles.pageTitleH2(context), ), ), const SizedBox( @@ -382,12 +392,16 @@ class _TradeDetailsViewState extends ConsumerState { width: width + 20, height: width + 20, child: QrImage( - data: trade.payinAddress, - size: width, - backgroundColor: CFColors.white, - foregroundColor: - CFColors.stackAccent, - ), + data: trade.payinAddress, + size: width, + backgroundColor: Theme.of( + context) + .extension()! + .popupBG, + foregroundColor: Theme.of( + context) + .extension()! + .accentColorDark), ), ), ), @@ -402,19 +416,18 @@ class _TradeDetailsViewState extends ConsumerState { // await _capturePng(true); Navigator.of(context).pop(); }, - style: ButtonStyle( - backgroundColor: - MaterialStateProperty.all< - Color>( - CFColors.buttonGray, - ), - ), + style: Theme.of(context) + .extension()! + .getSecondaryEnabledButtonColor( + context), child: Text( "Cancel", - style: - STextStyles.button.copyWith( - color: CFColors.stackAccent, - ), + style: STextStyles.button(context) + .copyWith( + color: Theme.of(context) + .extension< + StackColors>()! + .accentColorDark), ), ), ), @@ -428,17 +441,19 @@ class _TradeDetailsViewState extends ConsumerState { child: Row( children: [ SvgPicture.asset( - Assets.svg.pencil, - width: 10, - height: 10, - color: CFColors.link2, + Assets.svg.qrcode, + width: 12, + height: 12, + color: Theme.of(context) + .extension()! + .infoItemIcons, ), const SizedBox( width: 4, ), Text( - "Edit", - style: STextStyles.link2, + "Show QR code", + style: STextStyles.link2(context), ), ], ), @@ -458,7 +473,7 @@ class _TradeDetailsViewState extends ConsumerState { children: [ Text( "Trade note", - style: STextStyles.itemSubtitle, + style: STextStyles.itemSubtitle(context), ), GestureDetector( onTap: () { @@ -478,14 +493,16 @@ class _TradeDetailsViewState extends ConsumerState { Assets.svg.pencil, width: 10, height: 10, - color: CFColors.link2, + color: Theme.of(context) + .extension()! + .infoItemIcons, ), const SizedBox( width: 4, ), Text( "Edit", - style: STextStyles.link2, + style: STextStyles.link2(context), ), ], ), @@ -498,7 +515,7 @@ class _TradeDetailsViewState extends ConsumerState { SelectableText( ref.watch(tradeNoteServiceProvider.select( (value) => value.getNote(tradeId: tradeId))), - style: STextStyles.itemSubtitle12, + style: STextStyles.itemSubtitle12(context), ), ], ), @@ -517,7 +534,7 @@ class _TradeDetailsViewState extends ConsumerState { children: [ Text( "Transaction note", - style: STextStyles.itemSubtitle, + style: STextStyles.itemSubtitle(context), ), GestureDetector( onTap: () { @@ -536,14 +553,16 @@ class _TradeDetailsViewState extends ConsumerState { Assets.svg.pencil, width: 10, height: 10, - color: CFColors.link2, + color: Theme.of(context) + .extension()! + .infoItemIcons, ), const SizedBox( width: 4, ), Text( "Edit", - style: STextStyles.link2, + style: STextStyles.link2(context), ), ], ), @@ -567,7 +586,7 @@ class _TradeDetailsViewState extends ConsumerState { } return SelectableText( _note, - style: STextStyles.itemSubtitle12, + style: STextStyles.itemSubtitle12(context), ); }, ), @@ -583,7 +602,7 @@ class _TradeDetailsViewState extends ConsumerState { children: [ Text( "Date", - style: STextStyles.itemSubtitle, + style: STextStyles.itemSubtitle(context), ), // Flexible( // child: FittedBox( @@ -592,7 +611,7 @@ class _TradeDetailsViewState extends ConsumerState { SelectableText( Format.extractDateFrom( trade.date.millisecondsSinceEpoch ~/ 1000), - style: STextStyles.itemSubtitle12, + style: STextStyles.itemSubtitle12(context), ), // ), // ), @@ -608,7 +627,7 @@ class _TradeDetailsViewState extends ConsumerState { children: [ Text( "Exchange", - style: STextStyles.itemSubtitle, + style: STextStyles.itemSubtitle(context), ), // Flexible( // child: FittedBox( @@ -616,7 +635,7 @@ class _TradeDetailsViewState extends ConsumerState { // child: SelectableText( "ChangeNOW", - style: STextStyles.itemSubtitle12, + style: STextStyles.itemSubtitle12(context), ), // ), // ), @@ -631,14 +650,14 @@ class _TradeDetailsViewState extends ConsumerState { children: [ Text( "Trade ID", - style: STextStyles.itemSubtitle, + style: STextStyles.itemSubtitle(context), ), const Spacer(), Row( children: [ Text( trade.id, - style: STextStyles.itemSubtitle12, + style: STextStyles.itemSubtitle12(context), ), const SizedBox( width: 10, @@ -655,7 +674,9 @@ class _TradeDetailsViewState extends ConsumerState { }, child: SvgPicture.asset( Assets.svg.copy, - color: CFColors.link2, + color: Theme.of(context) + .extension()! + .infoItemIcons, width: 12, ), ) @@ -673,7 +694,7 @@ class _TradeDetailsViewState extends ConsumerState { children: [ Text( "Tracking", - style: STextStyles.itemSubtitle, + style: STextStyles.itemSubtitle(context), ), const SizedBox( height: 4, @@ -689,7 +710,7 @@ class _TradeDetailsViewState extends ConsumerState { }, child: Text( "https://changenow.io/exchange/txs/${trade.id}", - style: STextStyles.link2, + style: STextStyles.link2(context), ), ), ], diff --git a/lib/pages/exchange_view/wallet_initiated_exchange_view.dart b/lib/pages/exchange_view/wallet_initiated_exchange_view.dart index 551f8b5d9..2be98f002 100644 --- a/lib/pages/exchange_view/wallet_initiated_exchange_view.dart +++ b/lib/pages/exchange_view/wallet_initiated_exchange_view.dart @@ -26,10 +26,10 @@ import 'package:stackwallet/providers/exchange/fixed_rate_exchange_form_provider import 'package:stackwallet/providers/exchange/fixed_rate_market_pairs_provider.dart'; import 'package:stackwallet/providers/providers.dart'; import 'package:stackwallet/utilities/assets.dart'; -import 'package:stackwallet/utilities/cfcolors.dart'; import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/enums/flush_bar_type.dart'; import 'package:stackwallet/utilities/text_styles.dart'; +import 'package:stackwallet/utilities/theme/stack_colors.dart'; import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart'; import 'package:stackwallet/widgets/custom_loading_overlay.dart'; import 'package:stackwallet/widgets/loading_indicator.dart'; @@ -81,7 +81,10 @@ class _WalletInitiatedExchangeViewState builder: (_) => WillPopScope( onWillPop: () async => false, child: Container( - color: CFColors.stackAccent.withOpacity(0.8), + color: Theme.of(context) + .extension()! + .accentColorDark + .withOpacity(0.8), child: const CustomLoadingOverlay( message: "Updating exchange rate", eventBus: null, @@ -353,7 +356,7 @@ class _WalletInitiatedExchangeViewState }); return Scaffold( - backgroundColor: CFColors.almostWhite, + backgroundColor: Theme.of(context).extension()!.background, appBar: AppBar( leading: AppBarBackButton( onPressed: () async { @@ -368,7 +371,7 @@ class _WalletInitiatedExchangeViewState ), title: Text( "Exchange", - style: STextStyles.navBarTitle, + style: STextStyles.navBarTitle(context), ), ), body: LayoutBuilder( @@ -397,22 +400,24 @@ class _WalletInitiatedExchangeViewState ), Text( "Exchange amount", - style: STextStyles.pageTitleH1, + style: STextStyles.pageTitleH1(context), ), const SizedBox( height: 8, ), Text( "Network fees and other exchange charges are included in the rate.", - style: STextStyles.itemSubtitle, + style: STextStyles.itemSubtitle(context), ), const SizedBox( height: 24, ), Text( "You will send", - style: STextStyles.itemSubtitle.copyWith( - color: CFColors.neutral50, + style: STextStyles.itemSubtitle(context).copyWith( + color: Theme.of(context) + .extension()! + .textDark3, ), ), const SizedBox( @@ -481,7 +486,7 @@ class _WalletInitiatedExchangeViewState right: 12, ), hintText: "0", - hintStyle: STextStyles.fieldLabel.copyWith( + hintStyle: STextStyles.fieldLabel(context).copyWith( fontSize: 14, ), prefixIcon: FittedBox( @@ -621,7 +626,10 @@ class _WalletInitiatedExchangeViewState width: 18, height: 18, decoration: BoxDecoration( - color: CFColors.gray3, + color: Theme.of(context) + .extension< + StackColors>()! + .textSubtitle2, borderRadius: BorderRadius .circular( @@ -645,7 +653,7 @@ class _WalletInitiatedExchangeViewState width: 18, height: 18, decoration: BoxDecoration( - // color: CFColors.stackAccent, + // color: Theme.of(context).extension()!.accentColorDark borderRadius: BorderRadius.circular( 18), @@ -654,7 +662,10 @@ class _WalletInitiatedExchangeViewState Assets.svg.circleQuestion, width: 18, height: 18, - color: CFColors.gray3, + color: Theme.of(context) + .extension< + StackColors>()! + .textSubtitle2, ), ); } @@ -678,10 +689,11 @@ class _WalletInitiatedExchangeViewState .market?.from .toUpperCase())) ?? "-", - style: - STextStyles.smallMed14.copyWith( - color: CFColors.stackAccent, - ), + style: STextStyles.smallMed14(context) + .copyWith( + color: Theme.of(context) + .extension()! + .accentColorDark), ), const SizedBox( width: 6, @@ -705,11 +717,12 @@ class _WalletInitiatedExchangeViewState return Container(); } return SvgPicture.asset( - Assets.svg.chevronDown, - width: 5, - height: 2.5, - color: CFColors.stackAccent, - ); + Assets.svg.chevronDown, + width: 5, + height: 2.5, + color: Theme.of(context) + .extension()! + .accentColorDark); }), ], ), @@ -729,8 +742,11 @@ class _WalletInitiatedExchangeViewState alignment: Alignment.bottomLeft, child: Text( "You will receive", - style: STextStyles.itemSubtitle.copyWith( - color: CFColors.neutral50, + style: STextStyles.itemSubtitle(context) + .copyWith( + color: Theme.of(context) + .extension()! + .textDark3, ), ), ), @@ -762,7 +778,7 @@ class _WalletInitiatedExchangeViewState : ref.watch(fixedRateExchangeFormProvider .select((value) => value.sendAmountWarning)), - style: STextStyles.errorSmall, + style: STextStyles.errorSmall(context), ), ), ), @@ -838,7 +854,7 @@ class _WalletInitiatedExchangeViewState right: 12, ), hintText: "0", - hintStyle: STextStyles.fieldLabel.copyWith( + hintStyle: STextStyles.fieldLabel(context).copyWith( fontSize: 14, ), prefixIcon: FittedBox( @@ -980,7 +996,10 @@ class _WalletInitiatedExchangeViewState width: 18, height: 18, decoration: BoxDecoration( - color: CFColors.gray3, + color: Theme.of(context) + .extension< + StackColors>()! + .textSubtitle2, borderRadius: BorderRadius .circular(18), @@ -1002,7 +1021,7 @@ class _WalletInitiatedExchangeViewState width: 18, height: 18, decoration: BoxDecoration( - // color: CFColors.stackAccent, + // color: Theme.of(context).extension()!.accentColorDark borderRadius: BorderRadius.circular( 18), @@ -1011,7 +1030,10 @@ class _WalletInitiatedExchangeViewState Assets.svg.circleQuestion, width: 18, height: 18, - color: CFColors.gray3, + color: Theme.of(context) + .extension< + StackColors>()! + .textSubtitle2, ), ); } @@ -1035,10 +1057,11 @@ class _WalletInitiatedExchangeViewState .market?.to .toUpperCase())) ?? "-", - style: - STextStyles.smallMed14.copyWith( - color: CFColors.stackAccent, - ), + style: STextStyles.smallMed14(context) + .copyWith( + color: Theme.of(context) + .extension()! + .accentColorDark), ), const SizedBox( width: 6, @@ -1062,11 +1085,12 @@ class _WalletInitiatedExchangeViewState return Container(); } return SvgPicture.asset( - Assets.svg.chevronDown, - width: 5, - height: 2.5, - color: CFColors.stackAccent, - ); + Assets.svg.chevronDown, + width: 5, + height: 2.5, + color: Theme.of(context) + .extension()! + .accentColorDark); }), ], ), @@ -1094,7 +1118,7 @@ class _WalletInitiatedExchangeViewState // Text( // ref.watch(exchangeFormSateProvider.select( // (value) => value.minimumReceiveWarning)), - // style: STextStyles.errorSmall, + // style: STextStyles.errorSmall(context), // ), // ], // ), @@ -1215,27 +1239,20 @@ class _WalletInitiatedExchangeViewState ), const Spacer(), TextButton( - style: - Theme.of(context).textButtonTheme.style?.copyWith( - backgroundColor: - MaterialStateProperty.all( - ((ref - .read( - prefsChangeNotifierProvider) - .exchangeRateType == - ExchangeRateType.estimated) - ? ref.watch( - estimatedRateExchangeFormProvider - .select((value) => - value.canExchange)) - : ref.watch( - fixedRateExchangeFormProvider - .select((value) => - value.canExchange))) - ? CFColors.stackAccent - : CFColors.buttonGray, - ), - ), + style: ((ref + .read(prefsChangeNotifierProvider) + .exchangeRateType == + ExchangeRateType.estimated) + ? ref.watch(estimatedRateExchangeFormProvider + .select((value) => value.canExchange)) + : ref.watch(fixedRateExchangeFormProvider + .select((value) => value.canExchange))) + ? Theme.of(context) + .extension()! + .getPrimaryEnabledButtonColor(context) + : Theme.of(context) + .extension()! + .getSecondaryEnabledButtonColor(context), onPressed: ((ref .read(prefsChangeNotifierProvider) .exchangeRateType == @@ -1472,18 +1489,13 @@ class _WalletInitiatedExchangeViewState "${response.value!.warningMessage!}\n\nDo you want to attempt trade anyways?", leftButton: TextButton( style: Theme.of(context) - .textButtonTheme - .style - ?.copyWith( - backgroundColor: - MaterialStateProperty.all< - Color>( - CFColors.buttonGray, - ), - ), + .extension()! + .getSecondaryEnabledButtonColor( + context), child: Text( "Cancel", - style: STextStyles.itemSubtitle12, + style: STextStyles.itemSubtitle12( + context), ), onPressed: () { // notify return to cancel @@ -1492,18 +1504,13 @@ class _WalletInitiatedExchangeViewState ), rightButton: TextButton( style: Theme.of(context) - .textButtonTheme - .style - ?.copyWith( - backgroundColor: - MaterialStateProperty.all< - Color>( - CFColors.stackAccent, - ), - ), + .extension()! + .getPrimaryEnabledButtonColor( + context), child: Text( "Attempt", - style: STextStyles.button, + style: + STextStyles.button(context), ), onPressed: () { // continue and try to attempt trade @@ -1547,7 +1554,7 @@ class _WalletInitiatedExchangeViewState : null, child: Text( "Next", - style: STextStyles.button, + style: STextStyles.button(context), ), ), ], diff --git a/lib/pages/home_view/home_view.dart b/lib/pages/home_view/home_view.dart index 669561adf..b561207ab 100644 --- a/lib/pages/home_view/home_view.dart +++ b/lib/pages/home_view/home_view.dart @@ -15,9 +15,9 @@ import 'package:stackwallet/providers/ui/home_view_index_provider.dart'; import 'package:stackwallet/providers/ui/unread_notifications_provider.dart'; import 'package:stackwallet/services/change_now/change_now_loading_service.dart'; import 'package:stackwallet/utilities/assets.dart'; -import 'package:stackwallet/utilities/cfcolors.dart'; 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/stack_dialog.dart'; @@ -44,7 +44,6 @@ class _HomeViewState extends ConsumerState { final _cnLoadingService = ChangeNowLoadingService(); Future _onWillPop() async { - // go to home view when tapping back on the main exchange view if (ref.read(homeViewPageIndexStateProvider.state).state == 1) { ref.read(homeViewPageIndexStateProvider.state).state = 0; @@ -144,8 +143,7 @@ class _HomeViewState extends ConsumerState { GestureDetector( onTap: _hiddenOptions, child: SvgPicture.asset( - Assets.svg.stackIcon, - // color: CFColors.stackAccent, + Assets.svg.stackIcon(context), width: 24, height: 24, ), @@ -155,7 +153,7 @@ class _HomeViewState extends ConsumerState { ), Text( "My Stack", - style: STextStyles.navBarTitle, + style: STextStyles.navBarTitle(context), ) ], ), @@ -172,14 +170,20 @@ class _HomeViewState extends ConsumerState { key: const Key("walletsViewAlertsButton"), size: 36, shadows: const [], - color: CFColors.almostWhite, + color: Theme.of(context).extension()!.background, icon: SvgPicture.asset( ref.watch(notificationsProvider .select((value) => value.hasUnreadNotifications)) - ? Assets.svg.bellNew + ? Assets.svg.bellNew(context) : Assets.svg.bell, width: 20, height: 20, + color: ref.watch(notificationsProvider + .select((value) => value.hasUnreadNotifications)) + ? null + : Theme.of(context) + .extension()! + .topNavIconPrimary, ), onPressed: () { // reset unread state @@ -225,10 +229,12 @@ class _HomeViewState extends ConsumerState { key: const Key("walletsViewSettingsButton"), size: 36, shadows: const [], - color: CFColors.almostWhite, + color: Theme.of(context).extension()!.background, icon: SvgPicture.asset( Assets.svg.gear, - color: CFColors.stackAccent, + color: Theme.of(context) + .extension()! + .topNavIconPrimary, width: 20, height: 20, ), @@ -243,15 +249,18 @@ class _HomeViewState extends ConsumerState { ], ), body: Container( - color: CFColors.almostWhite, + color: Theme.of(context).extension()!.background, child: Column( children: [ if (Constants.enableExchange) Container( - decoration: const BoxDecoration( - color: CFColors.almostWhite, + decoration: BoxDecoration( + color: + Theme.of(context).extension()!.background, boxShadow: [ - CFColors.standardBoxShadow, + Theme.of(context) + .extension()! + .standardBoxShadow, ], ), child: const Padding( 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 ca7133a0f..7541b166f 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 @@ -10,9 +10,9 @@ import 'package:stackwallet/providers/exchange/estimate_rate_exchange_form_provi import 'package:stackwallet/providers/exchange/fixed_rate_exchange_form_provider.dart'; import 'package:stackwallet/providers/exchange/fixed_rate_market_pairs_provider.dart'; import 'package:stackwallet/providers/providers.dart'; -import 'package:stackwallet/utilities/cfcolors.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/stack_dialog.dart'; class HomeViewButtonBar extends ConsumerStatefulWidget { @@ -147,14 +147,21 @@ class _HomeViewButtonBarState extends ConsumerState { children: [ Expanded( child: TextButton( - style: ButtonStyle( - minimumSize: MaterialStateProperty.all(const Size(46, 36)), - backgroundColor: MaterialStateProperty.all( - selectedIndex == 0 - ? CFColors.stackAccent - : CFColors.disabledButton, - ), - ), + style: selectedIndex == 0 + ? Theme.of(context) + .extension()! + .getPrimaryEnabledButtonColor(context)! + .copyWith( + minimumSize: + MaterialStateProperty.all(const Size(46, 36)), + ) + : Theme.of(context) + .extension()! + .getSecondaryEnabledButtonColor(context)! + .copyWith( + minimumSize: + MaterialStateProperty.all(const Size(46, 36)), + ), onPressed: () { FocusScope.of(context).unfocus(); if (selectedIndex != 0) { @@ -163,10 +170,13 @@ class _HomeViewButtonBarState extends ConsumerState { }, child: Text( "Wallets", - style: STextStyles.button.copyWith( + style: STextStyles.button(context).copyWith( fontSize: 14, - color: - selectedIndex == 0 ? CFColors.light1 : CFColors.stackAccent, + color: selectedIndex == 0 + ? Theme.of(context) + .extension()! + .buttonTextPrimary + : Theme.of(context).extension()!.textDark, ), ), ), @@ -176,14 +186,21 @@ class _HomeViewButtonBarState extends ConsumerState { ), Expanded( child: TextButton( - style: ButtonStyle( - minimumSize: MaterialStateProperty.all(const Size(46, 36)), - backgroundColor: MaterialStateProperty.all( - selectedIndex == 1 - ? CFColors.stackAccent - : CFColors.disabledButton, - ), - ), + style: selectedIndex == 1 + ? Theme.of(context) + .extension()! + .getPrimaryEnabledButtonColor(context)! + .copyWith( + minimumSize: + MaterialStateProperty.all(const Size(46, 36)), + ) + : Theme.of(context) + .extension()! + .getSecondaryEnabledButtonColor(context)! + .copyWith( + minimumSize: + MaterialStateProperty.all(const Size(46, 36)), + ), onPressed: () async { FocusScope.of(context).unfocus(); if (selectedIndex != 1) { @@ -215,10 +232,13 @@ class _HomeViewButtonBarState extends ConsumerState { }, child: Text( "Exchange", - style: STextStyles.button.copyWith( + style: STextStyles.button(context).copyWith( fontSize: 14, - color: - selectedIndex == 1 ? CFColors.light1 : CFColors.stackAccent, + color: selectedIndex == 1 + ? Theme.of(context) + .extension()! + .buttonTextPrimary + : Theme.of(context).extension()!.textDark, ), ), ), @@ -246,10 +266,10 @@ class _HomeViewButtonBarState extends ConsumerState { // }, // child: Text( // "Buy", - // style: STextStyles.button.copyWith( + // style: STextStyles.button(context).copyWith( // fontSize: 14, // color: - // selectedIndex == 2 ? CFColors.light1 : CFColors.stackAccent, + // selectedIndex == 2 ? CFColors.light1 : Theme.of(context).extension()!.accentColorDark // ), // ), // ), diff --git a/lib/pages/intro_view.dart b/lib/pages/intro_view.dart index 0b2101a1a..ca8725886 100644 --- a/lib/pages/intro_view.dart +++ b/lib/pages/intro_view.dart @@ -1,9 +1,12 @@ import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_svg/svg.dart'; import 'package:stackwallet/pages/pinpad_views/create_pin_view.dart'; +import 'package:stackwallet/pages_desktop_specific/create_password/create_password_view.dart'; import 'package:stackwallet/utilities/assets.dart'; -import 'package:stackwallet/utilities/cfcolors.dart'; import 'package:stackwallet/utilities/text_styles.dart'; +import 'package:stackwallet/utilities/theme/stack_colors.dart'; +import 'package:stackwallet/utilities/util.dart'; import 'package:url_launcher/url_launcher.dart'; class IntroView extends StatefulWidget { @@ -14,8 +17,11 @@ class IntroView extends StatefulWidget { } class _IntroViewState extends State { + late final bool isDesktop; + @override void initState() { + isDesktop = Util.isDesktop; super.initState(); } @@ -23,28 +29,22 @@ class _IntroViewState extends State { Widget build(BuildContext context) { debugPrint("BUILD: $runtimeType "); return Scaffold( - body: Container( - color: CFColors.almostWhite, - child: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - Expanded( - child: Padding( - padding: const EdgeInsets.only( - left: 47, - right: 47, - top: 67, - bottom: 4, - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - const Spacer( - flex: 2, + backgroundColor: Theme.of(context).extension()!.background, + body: Center( + child: !isDesktop + ? Column( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + const Spacer( + flex: 2, + ), + Padding( + padding: const EdgeInsets.symmetric( + horizontal: 16, ), - ConstrainedBox( + child: ConstrainedBox( constraints: const BoxConstraints( - maxWidth: 400, + maxWidth: 300, ), child: Image( image: AssetImage( @@ -52,91 +52,216 @@ class _IntroViewState extends State { ), ), ), - const Spacer( - flex: 1, + ), + const Spacer( + flex: 1, + ), + AppNameText( + isDesktop: isDesktop, + ), + const SizedBox( + height: 8, + ), + Padding( + padding: const EdgeInsets.symmetric( + horizontal: 48, ), - Text( - "Stack Wallet", - textAlign: TextAlign.center, - style: STextStyles.pageTitleH1, + child: IntroAboutText( + isDesktop: isDesktop, ), - const SizedBox( - height: 8, + ), + const Spacer( + flex: 4, + ), + Padding( + padding: const EdgeInsets.symmetric( + horizontal: 32, ), - Text( - "An open-source, multicoin wallet for everyone", - textAlign: TextAlign.center, - style: STextStyles.subtitle, + child: PrivacyAndTOSText( + isDesktop: isDesktop, ), - // Center(child: Text("for everyone")), - const Spacer( - flex: 4, + ), + Padding( + padding: const EdgeInsets.symmetric( + horizontal: 16, + vertical: 16, ), - RichText( - textAlign: TextAlign.center, - text: TextSpan( - style: STextStyles.label, - children: [ - const TextSpan( - text: "By using Stack Wallet, you agree to the "), - TextSpan( - text: "Terms of service", - style: STextStyles.richLink, - recognizer: TapGestureRecognizer() - ..onTap = () { - launchUrl( - Uri.parse( - "https://stackwallet.com/terms-of-service.html"), - mode: LaunchMode.externalApplication, - ); - }, + child: Row( + children: [ + Expanded( + child: GetStartedButton( + isDesktop: isDesktop, ), - const TextSpan(text: " and "), - TextSpan( - text: "Privacy policy", - style: STextStyles.richLink, - recognizer: TapGestureRecognizer() - ..onTap = () { - launchUrl( - Uri.parse( - "https://stackwallet.com/privacy-policy.html"), - mode: LaunchMode.externalApplication, - ); - }, - ), - ], + ), + ], + ), + ), + ], + ) + : SizedBox( + width: 350, + height: 540, + child: Column( + children: [ + const Spacer( + flex: 2, + ), + SizedBox( + width: 130, + height: 130, + child: SvgPicture.asset( + Assets.svg.stackIcon(context), ), ), + const Spacer( + flex: 42, + ), + AppNameText( + isDesktop: isDesktop, + ), + const Spacer( + flex: 24, + ), + IntroAboutText( + isDesktop: isDesktop, + ), + const Spacer( + flex: 42, + ), + GetStartedButton( + isDesktop: isDesktop, + ), + const Spacer( + flex: 65, + ), + PrivacyAndTOSText( + isDesktop: isDesktop, + ), ], ), ), - ), - Padding( - padding: const EdgeInsets.symmetric( - horizontal: 16, - vertical: 16, - ), - child: TextButton( - style: Theme.of(context).textButtonTheme.style?.copyWith( - backgroundColor: MaterialStateProperty.all( - CFColors.stackAccent, - ), - ), - onPressed: () { - // // TODO do global password/pin creation - // Navigator.of(context).pushNamed(HomeView.routeName); - - Navigator.of(context).pushNamed(CreatePinView.routeName); - }, - child: Text( - "Get started", - style: STextStyles.button, - ), - ), - ), - ], - ), ), ); } } + +class AppNameText extends StatelessWidget { + const AppNameText({Key? key, required this.isDesktop}) : super(key: key); + + final bool isDesktop; + + @override + Widget build(BuildContext context) { + return Text( + "Stack Wallet", + textAlign: TextAlign.center, + style: !isDesktop + ? STextStyles.pageTitleH1(context) + : STextStyles.pageTitleH1(context).copyWith( + fontSize: 40, + ), + ); + } +} + +class IntroAboutText extends StatelessWidget { + const IntroAboutText({Key? key, required this.isDesktop}) : super(key: key); + + final bool isDesktop; + + @override + Widget build(BuildContext context) { + return Text( + "An open-source, multicoin wallet for everyone", + textAlign: TextAlign.center, + style: !isDesktop + ? STextStyles.subtitle(context) + : STextStyles.subtitle(context).copyWith( + fontSize: 24, + ), + ); + } +} + +class PrivacyAndTOSText extends StatelessWidget { + const PrivacyAndTOSText({Key? key, required this.isDesktop}) + : super(key: key); + + final bool isDesktop; + + @override + Widget build(BuildContext context) { + final fontSize = isDesktop ? 18.0 : 12.0; + return RichText( + textAlign: TextAlign.center, + text: TextSpan( + style: STextStyles.label(context).copyWith(fontSize: fontSize), + children: [ + const TextSpan(text: "By using Stack Wallet, you agree to the "), + TextSpan( + text: "Terms of service", + style: STextStyles.richLink(context).copyWith(fontSize: fontSize), + recognizer: TapGestureRecognizer() + ..onTap = () { + launchUrl( + Uri.parse("https://stackwallet.com/terms-of-service.html"), + mode: LaunchMode.externalApplication, + ); + }, + ), + const TextSpan(text: " and "), + TextSpan( + text: "Privacy policy", + style: STextStyles.richLink(context).copyWith(fontSize: fontSize), + recognizer: TapGestureRecognizer() + ..onTap = () { + launchUrl( + Uri.parse("https://stackwallet.com/privacy-policy.html"), + mode: LaunchMode.externalApplication, + ); + }, + ), + ], + ), + ); + } +} + +class GetStartedButton extends StatelessWidget { + const GetStartedButton({Key? key, required this.isDesktop}) : super(key: key); + + final bool isDesktop; + + @override + Widget build(BuildContext context) { + return !isDesktop + ? TextButton( + style: Theme.of(context) + .extension()! + .getPrimaryEnabledButtonColor(context), + onPressed: () { + Navigator.of(context).pushNamed(CreatePinView.routeName); + }, + child: Text( + "Get started", + style: STextStyles.button(context), + ), + ) + : SizedBox( + width: 328, + height: 70, + child: TextButton( + style: Theme.of(context) + .extension()! + .getPrimaryEnabledButtonColor(context), + onPressed: () { + Navigator.of(context).pushNamed(CreatePasswordView.routeName); + }, + child: Text( + "Get started", + style: STextStyles.button(context).copyWith(fontSize: 20), + ), + ), + ); + } +} diff --git a/lib/pages/loading_view.dart b/lib/pages/loading_view.dart index 30ef87fa4..c252913df 100644 --- a/lib/pages/loading_view.dart +++ b/lib/pages/loading_view.dart @@ -3,7 +3,7 @@ import 'dart:math'; import 'package:flutter/material.dart'; import 'package:lottie/lottie.dart'; import 'package:stackwallet/utilities/assets.dart'; -import 'package:stackwallet/utilities/cfcolors.dart'; +import 'package:stackwallet/utilities/theme/stack_colors.dart'; class LoadingView extends StatelessWidget { const LoadingView({Key? key}) : super(key: key); @@ -12,9 +12,9 @@ class LoadingView extends StatelessWidget { Widget build(BuildContext context) { final size = MediaQuery.of(context).size; return Scaffold( - backgroundColor: CFColors.almostWhite, + backgroundColor: Theme.of(context).extension()!.background, body: Container( - color: CFColors.almostWhite, + color: Theme.of(context).extension()!.background, child: Center( child: SizedBox( width: min(size.width, size.height) * 0.5, diff --git a/lib/pages/manage_favorites_view/manage_favorites_view.dart b/lib/pages/manage_favorites_view/manage_favorites_view.dart index e1810626f..7d2b58781 100644 --- a/lib/pages/manage_favorites_view/manage_favorites_view.dart +++ b/lib/pages/manage_favorites_view/manage_favorites_view.dart @@ -1,10 +1,9 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:stackwallet/providers/providers.dart'; -import 'package:stackwallet/services/coins/manager.dart'; -import 'package:stackwallet/utilities/cfcolors.dart'; 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/managed_favorite.dart'; @@ -20,7 +19,7 @@ class ManageFavoritesView extends StatelessWidget { appBar: AppBar( title: Text( "Favorite wallets", - style: STextStyles.navBarTitle, + style: STextStyles.navBarTitle(context), ), leading: AppBarBackButton( onPressed: () { @@ -29,7 +28,7 @@ class ManageFavoritesView extends StatelessWidget { ), ), body: Container( - color: CFColors.almostWhite, + color: Theme.of(context).extension()!.background, child: Padding( padding: const EdgeInsets.only( left: 12, @@ -43,7 +42,7 @@ class ManageFavoritesView extends StatelessWidget { padding: const EdgeInsets.symmetric(horizontal: 4), child: Container( decoration: BoxDecoration( - color: CFColors.white, + color: Theme.of(context).extension()!.popupBG, borderRadius: BorderRadius.circular( Constants.size.circularBorderRadius, ), @@ -52,7 +51,7 @@ class ManageFavoritesView extends StatelessWidget { padding: const EdgeInsets.all(12.0), child: Text( "Drag to change wallet order.", - style: STextStyles.label, + style: STextStyles.label(context), ), ), ), @@ -68,10 +67,7 @@ class ManageFavoritesView extends StatelessWidget { key: key, itemCount: favorites.length, itemBuilder: (builderContext, index) { - final walletId = ref - .read(favorites[index] - as ChangeNotifierProvider) - .walletId; + final walletId = ref.read(favorites[index]).walletId; return Padding( key: Key( "manageFavoriteWalletsItem_$walletId", @@ -120,8 +116,9 @@ class ManageFavoritesView extends StatelessWidget { ), child: Text( "Add to favorites", - style: STextStyles.itemSubtitle12.copyWith( - color: CFColors.neutral50, + style: STextStyles.itemSubtitle12(context).copyWith( + color: + Theme.of(context).extension()!.textDark3, ), ), ), @@ -135,10 +132,7 @@ class ManageFavoritesView extends StatelessWidget { itemBuilder: (buildContext, index) { // final walletId = ref.watch( // nonFavorites[index].select((value) => value.walletId)); - final walletId = ref - .read(nonFavorites[index] - as ChangeNotifierProvider) - .walletId; + final walletId = ref.read(nonFavorites[index]).walletId; return Padding( key: Key( "manageNonFavoriteWalletsItem_$walletId", diff --git a/lib/pages/notification_views/notifications_view.dart b/lib/pages/notification_views/notifications_view.dart index c562c72b6..a034a34e4 100644 --- a/lib/pages/notification_views/notifications_view.dart +++ b/lib/pages/notification_views/notifications_view.dart @@ -3,8 +3,8 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:stackwallet/notifications/notification_card.dart'; import 'package:stackwallet/providers/providers.dart'; import 'package:stackwallet/providers/ui/unread_notifications_provider.dart'; -import 'package:stackwallet/utilities/cfcolors.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/rounded_white_container.dart'; @@ -44,11 +44,11 @@ class _NotificationsViewState extends ConsumerState { .toList(growable: false); return Scaffold( - backgroundColor: CFColors.almostWhite, + backgroundColor: Theme.of(context).extension()!.background, appBar: AppBar( title: Text( "Notifications", - style: STextStyles.navBarTitle, + style: STextStyles.navBarTitle(context), ), leading: AppBarBackButton( onPressed: () async { @@ -95,7 +95,7 @@ class _NotificationsViewState extends ConsumerState { fit: BoxFit.scaleDown, child: Text( "Notifications will appear here", - style: STextStyles.itemSubtitle, + style: STextStyles.itemSubtitle(context), ), ), ), diff --git a/lib/pages/pinpad_views/create_pin_view.dart b/lib/pages/pinpad_views/create_pin_view.dart index df9c0c8eb..c4e4ee592 100644 --- a/lib/pages/pinpad_views/create_pin_view.dart +++ b/lib/pages/pinpad_views/create_pin_view.dart @@ -1,6 +1,5 @@ import 'dart:io'; -import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_secure_storage/flutter_secure_storage.dart'; @@ -10,11 +9,11 @@ import 'package:stackwallet/pages/home_view/home_view.dart'; import 'package:stackwallet/providers/global/prefs_provider.dart'; import 'package:stackwallet/utilities/assets.dart'; import 'package:stackwallet/utilities/biometrics.dart'; -import 'package:stackwallet/utilities/cfcolors.dart'; import 'package:stackwallet/utilities/constants.dart'; import 'package:stackwallet/utilities/enums/flush_bar_type.dart'; import 'package:stackwallet/utilities/flutter_secure_storage_interface.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_pin_put/custom_pin_put.dart'; @@ -41,8 +40,10 @@ class CreatePinView extends ConsumerStatefulWidget { class _CreatePinViewState extends ConsumerState { BoxDecoration get _pinPutDecoration { return BoxDecoration( - color: CFColors.gray3, - border: Border.all(width: 1, color: CFColors.gray3), + color: Theme.of(context).extension()!.textSubtitle3, + border: Border.all( + width: 1, + color: Theme.of(context).extension()!.textSubtitle3), borderRadius: BorderRadius.circular(6), ); } @@ -81,7 +82,7 @@ class _CreatePinViewState extends ConsumerState { @override Widget build(BuildContext context) { return Scaffold( - backgroundColor: CFColors.almostWhite, + backgroundColor: Theme.of(context).extension()!.background, appBar: AppBar( leading: AppBarBackButton( onPressed: () async { @@ -106,14 +107,14 @@ class _CreatePinViewState extends ConsumerState { children: [ Text( "Create a PIN", - style: STextStyles.pageTitleH1, + style: STextStyles.pageTitleH1(context), ), const SizedBox( height: 8, ), Text( "This PIN protects access to your wallet.", - style: STextStyles.subtitle, + style: STextStyles.subtitle(context), ), const SizedBox( height: 36, @@ -122,28 +123,33 @@ class _CreatePinViewState extends ConsumerState { fieldsCount: Constants.pinLength, eachFieldHeight: 12, eachFieldWidth: 12, - textStyle: STextStyles.label.copyWith( + textStyle: STextStyles.label(context).copyWith( fontSize: 1, ), focusNode: _pinPutFocusNode1, controller: _pinPutController1, useNativeKeyboard: false, obscureText: "", - inputDecoration: const InputDecoration( + inputDecoration: InputDecoration( border: InputBorder.none, enabledBorder: InputBorder.none, focusedBorder: InputBorder.none, disabledBorder: InputBorder.none, errorBorder: InputBorder.none, focusedErrorBorder: InputBorder.none, - fillColor: CFColors.almostWhite, + fillColor: + Theme.of(context).extension()!.background, counterText: "", ), submittedFieldDecoration: _pinPutDecoration.copyWith( - color: CFColors.link2, + color: Theme.of(context) + .extension()! + .infoItemIcons, border: Border.all( width: 1, - color: CFColors.link2, + color: Theme.of(context) + .extension()! + .infoItemIcons, ), ), selectedFieldDecoration: _pinPutDecoration, @@ -166,14 +172,14 @@ class _CreatePinViewState extends ConsumerState { children: [ Text( "Confirm PIN", - style: STextStyles.pageTitleH1, + style: STextStyles.pageTitleH1(context), ), const SizedBox( height: 8, ), Text( "This PIN protects access to your wallet.", - style: STextStyles.subtitle, + style: STextStyles.subtitle(context), ), const SizedBox( height: 36, @@ -189,21 +195,26 @@ class _CreatePinViewState extends ConsumerState { controller: _pinPutController2, useNativeKeyboard: false, obscureText: "", - inputDecoration: const InputDecoration( + inputDecoration: InputDecoration( border: InputBorder.none, enabledBorder: InputBorder.none, focusedBorder: InputBorder.none, disabledBorder: InputBorder.none, errorBorder: InputBorder.none, focusedErrorBorder: InputBorder.none, - fillColor: CFColors.almostWhite, + fillColor: + Theme.of(context).extension()!.background, counterText: "", ), submittedFieldDecoration: _pinPutDecoration.copyWith( - color: CFColors.link2, + color: Theme.of(context) + .extension()! + .infoItemIcons, border: Border.all( width: 1, - color: CFColors.link2, + color: Theme.of(context) + .extension()! + .infoItemIcons, ), ), selectedFieldDecoration: _pinPutDecoration, diff --git a/lib/pages/pinpad_views/lock_screen_view.dart b/lib/pages/pinpad_views/lock_screen_view.dart index 03dd5bb26..00d8b1914 100644 --- a/lib/pages/pinpad_views/lock_screen_view.dart +++ b/lib/pages/pinpad_views/lock_screen_view.dart @@ -12,11 +12,11 @@ import 'package:stackwallet/providers/global/wallets_provider.dart'; // import 'package:stackwallet/providers/global/should_show_lockscreen_on_resume_state_provider.dart'; import 'package:stackwallet/utilities/assets.dart'; import 'package:stackwallet/utilities/biometrics.dart'; -import 'package:stackwallet/utilities/cfcolors.dart'; import 'package:stackwallet/utilities/constants.dart'; import 'package:stackwallet/utilities/enums/flush_bar_type.dart'; import 'package:stackwallet/utilities/flutter_secure_storage_interface.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_pin_put/custom_pin_put.dart'; import 'package:stackwallet/widgets/shake/shake.dart'; @@ -151,8 +151,10 @@ class _LockscreenViewState extends ConsumerState { BoxDecoration get _pinPutDecoration { return BoxDecoration( - color: CFColors.gray3, - border: Border.all(width: 1, color: CFColors.gray3), + color: Theme.of(context).extension()!.textSubtitle2, + border: Border.all( + width: 1, + color: Theme.of(context).extension()!.textSubtitle2), borderRadius: BorderRadius.circular(6), ); } @@ -164,7 +166,7 @@ class _LockscreenViewState extends ConsumerState { late Biometrics biometrics; Scaffold get _body => Scaffold( - backgroundColor: CFColors.almostWhite, + backgroundColor: Theme.of(context).extension()!.background, appBar: AppBar( leading: widget.showBackButton ? AppBarBackButton( @@ -196,7 +198,7 @@ class _LockscreenViewState extends ConsumerState { Center( child: Text( "Enter PIN", - style: STextStyles.pageTitleH1, + style: STextStyles.pageTitleH1(context), ), ), const SizedBox( @@ -206,28 +208,34 @@ class _LockscreenViewState extends ConsumerState { fieldsCount: Constants.pinLength, eachFieldHeight: 12, eachFieldWidth: 12, - textStyle: STextStyles.label.copyWith( + textStyle: STextStyles.label(context).copyWith( fontSize: 1, ), focusNode: _pinFocusNode, controller: _pinTextController, useNativeKeyboard: false, obscureText: "", - inputDecoration: const InputDecoration( + inputDecoration: InputDecoration( border: InputBorder.none, enabledBorder: InputBorder.none, focusedBorder: InputBorder.none, disabledBorder: InputBorder.none, errorBorder: InputBorder.none, focusedErrorBorder: InputBorder.none, - fillColor: CFColors.almostWhite, + fillColor: Theme.of(context) + .extension()! + .background, counterText: "", ), submittedFieldDecoration: _pinPutDecoration.copyWith( - color: CFColors.link2, + color: Theme.of(context) + .extension()! + .infoItemIcons, border: Border.all( width: 1, - color: CFColors.link2, + color: Theme.of(context) + .extension()! + .infoItemIcons, ), ), selectedFieldDecoration: _pinPutDecoration, diff --git a/lib/pages/receive_view/generate_receiving_uri_qr_code_view.dart b/lib/pages/receive_view/generate_receiving_uri_qr_code_view.dart index 037677a40..744d8b53c 100644 --- a/lib/pages/receive_view/generate_receiving_uri_qr_code_view.dart +++ b/lib/pages/receive_view/generate_receiving_uri_qr_code_view.dart @@ -12,13 +12,13 @@ import 'package:qr_flutter/qr_flutter.dart'; import 'package:share_plus/share_plus.dart'; import 'package:stackwallet/notifications/show_flush_bar.dart'; import 'package:stackwallet/utilities/assets.dart'; -import 'package:stackwallet/utilities/cfcolors.dart'; import 'package:stackwallet/utilities/clipboard_interface.dart'; import 'package:stackwallet/utilities/constants.dart'; import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/enums/flush_bar_type.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/custom_buttons/app_bar_icon_button.dart'; import 'package:stackwallet/widgets/icon_widgets/x_icon.dart'; import 'package:stackwallet/widgets/rounded_white_container.dart'; @@ -101,7 +101,7 @@ class _GenerateUriQrCodeViewState extends State { Widget build(BuildContext context) { debugPrint("BUILD: $runtimeType"); return Scaffold( - backgroundColor: CFColors.almostWhite, + backgroundColor: Theme.of(context).extension()!.background, appBar: AppBar( leading: AppBarBackButton( onPressed: () async { @@ -116,7 +116,7 @@ class _GenerateUriQrCodeViewState extends State { ), title: Text( "Generate QR code", - style: STextStyles.navBarTitle, + style: STextStyles.navBarTitle(context), ), ), body: LayoutBuilder( @@ -141,7 +141,7 @@ class _GenerateUriQrCodeViewState extends State { RoundedWhiteContainer( child: Text( "The new QR code with your address, amount and note will appear in the pop up window.", - style: STextStyles.itemSubtitle, + style: STextStyles.itemSubtitle(context), ), ), const SizedBox( @@ -149,7 +149,7 @@ class _GenerateUriQrCodeViewState extends State { ), Text( "Amount (Optional)", - style: STextStyles.smallMed12, + style: STextStyles.smallMed12(context), textAlign: TextAlign.left, ), const SizedBox( @@ -162,13 +162,14 @@ class _GenerateUriQrCodeViewState extends State { child: TextField( controller: amountController, focusNode: _amountFocusNode, - style: STextStyles.field, + style: STextStyles.field(context), keyboardType: const TextInputType.numberWithOptions( decimal: true), onChanged: (_) => setState(() {}), decoration: standardInputDecoration( "Amount", _amountFocusNode, + context, ).copyWith( suffixIcon: amountController.text.isNotEmpty ? Padding( @@ -197,7 +198,7 @@ class _GenerateUriQrCodeViewState extends State { ), Text( "Note (Optional)", - style: STextStyles.smallMed12, + style: STextStyles.smallMed12(context), textAlign: TextAlign.left, ), const SizedBox( @@ -210,11 +211,12 @@ class _GenerateUriQrCodeViewState extends State { child: TextField( controller: noteController, focusNode: _noteFocusNode, - style: STextStyles.field, + style: STextStyles.field(context), onChanged: (_) => setState(() {}), decoration: standardInputDecoration( "Note", _noteFocusNode, + context, ).copyWith( suffixIcon: noteController.text.isNotEmpty ? Padding( @@ -244,13 +246,9 @@ class _GenerateUriQrCodeViewState extends State { height: 8, ), TextButton( - style: - Theme.of(context).textButtonTheme.style?.copyWith( - backgroundColor: - MaterialStateProperty.all( - CFColors.stackAccent, - ), - ), + style: Theme.of(context) + .extension()! + .getPrimaryEnabledButtonColor(context), onPressed: () { final amountString = amountController.text; final noteString = noteController.text; @@ -305,7 +303,8 @@ class _GenerateUriQrCodeViewState extends State { Center( child: Text( "New QR code", - style: STextStyles.pageTitleH2, + style: + STextStyles.pageTitleH2(context), ), ), const SizedBox( @@ -318,12 +317,16 @@ class _GenerateUriQrCodeViewState extends State { width: width + 20, height: width + 20, child: QrImage( - data: uriString, - size: width, - backgroundColor: CFColors.white, - foregroundColor: - CFColors.stackAccent, - ), + data: uriString, + size: width, + backgroundColor: Theme.of( + context) + .extension()! + .popupBG, + foregroundColor: Theme.of( + context) + .extension()! + .accentColorDark), ), ), ), @@ -338,13 +341,10 @@ class _GenerateUriQrCodeViewState extends State { // TODO: add save button as well await _capturePng(true); }, - style: ButtonStyle( - backgroundColor: - MaterialStateProperty.all< - Color>( - CFColors.buttonGray, - ), - ), + style: Theme.of(context) + .extension()! + .getSecondaryEnabledButtonColor( + context), child: Row( mainAxisAlignment: MainAxisAlignment.center, @@ -367,10 +367,13 @@ class _GenerateUriQrCodeViewState extends State { "Share", textAlign: TextAlign.center, - style: STextStyles.button + style: STextStyles.button( + context) .copyWith( - color: CFColors - .stackAccent, + color: Theme.of(context) + .extension< + StackColors>()! + .buttonTextSecondary, ), ), const SizedBox( @@ -391,7 +394,7 @@ class _GenerateUriQrCodeViewState extends State { }, child: Text( "Generate QR Code", - style: STextStyles.button, + style: STextStyles.button(context), ), ), ], diff --git a/lib/pages/receive_view/receive_view.dart b/lib/pages/receive_view/receive_view.dart index b0f49682b..50e0ffd5e 100644 --- a/lib/pages/receive_view/receive_view.dart +++ b/lib/pages/receive_view/receive_view.dart @@ -10,11 +10,11 @@ import 'package:stackwallet/pages/receive_view/generate_receiving_uri_qr_code_vi import 'package:stackwallet/providers/providers.dart'; import 'package:stackwallet/route_generator.dart'; import 'package:stackwallet/utilities/assets.dart'; -import 'package:stackwallet/utilities/cfcolors.dart'; import 'package:stackwallet/utilities/clipboard_interface.dart'; import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/enums/flush_bar_type.dart'; import 'package:stackwallet/utilities/text_styles.dart'; +import 'package:stackwallet/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/custom_loading_overlay.dart'; @@ -51,9 +51,15 @@ class _ReceiveViewState extends ConsumerState { builder: (_) { return WillPopScope( onWillPop: () async => shouldPop, - child: const CustomLoadingOverlay( - message: "Generating address", - eventBus: null, + child: Container( + color: Theme.of(context) + .extension()! + .overlay + .withOpacity(0.5), + child: const CustomLoadingOverlay( + message: "Generating address", + eventBus: null, + ), ), ); }, @@ -110,7 +116,7 @@ class _ReceiveViewState extends ConsumerState { }); return Scaffold( - backgroundColor: CFColors.almostWhite, + backgroundColor: Theme.of(context).extension()!.background, appBar: AppBar( leading: AppBarBackButton( onPressed: () { @@ -119,7 +125,7 @@ class _ReceiveViewState extends ConsumerState { ), title: Text( "Receive ${coin.ticker}", - style: STextStyles.navBarTitle, + style: STextStyles.navBarTitle(context), ), ), body: Padding( @@ -149,7 +155,7 @@ class _ReceiveViewState extends ConsumerState { children: [ Text( "Your ${coin.ticker} address", - style: STextStyles.itemSubtitle, + style: STextStyles.itemSubtitle(context), ), const Spacer(), Row( @@ -158,14 +164,16 @@ class _ReceiveViewState extends ConsumerState { Assets.svg.copy, width: 10, height: 10, - color: CFColors.link2, + color: Theme.of(context) + .extension()! + .infoItemIcons, ), const SizedBox( width: 4, ), Text( "Copy", - style: STextStyles.link2, + style: STextStyles.link2(context), ), ], ), @@ -179,7 +187,7 @@ class _ReceiveViewState extends ConsumerState { Expanded( child: Text( receivingAddress, - style: STextStyles.itemSubtitle12, + style: STextStyles.itemSubtitle12(context), ), ), ], @@ -195,16 +203,15 @@ class _ReceiveViewState extends ConsumerState { if (coin != Coin.epicCash) TextButton( onPressed: generateNewAddress, - style: ButtonStyle( - backgroundColor: MaterialStateProperty.all( - CFColors.buttonGray, - ), - ), + style: Theme.of(context) + .extension()! + .getSecondaryEnabledButtonColor(context), child: Text( "Generate new address", - style: STextStyles.button.copyWith( - color: CFColors.stackAccent, - ), + style: STextStyles.button(context).copyWith( + color: Theme.of(context) + .extension()! + .accentColorDark), ), ), const SizedBox( @@ -217,10 +224,11 @@ class _ReceiveViewState extends ConsumerState { child: Column( children: [ QrImage( - data: "${coin.uriScheme}:$receivingAddress", - size: MediaQuery.of(context).size.width / 2, - foregroundColor: CFColors.stackAccent, - ), + data: "${coin.uriScheme}:$receivingAddress", + size: MediaQuery.of(context).size.width / 2, + foregroundColor: Theme.of(context) + .extension()! + .accentColorDark), const SizedBox( height: 20, ), diff --git a/lib/pages/send_view/confirm_transaction_view.dart b/lib/pages/send_view/confirm_transaction_view.dart index 5d28619aa..fff346ee7 100644 --- a/lib/pages/send_view/confirm_transaction_view.dart +++ b/lib/pages/send_view/confirm_transaction_view.dart @@ -7,21 +7,20 @@ import 'package:stackwallet/pages/pinpad_views/lock_screen_view.dart'; import 'package:stackwallet/pages/send_view/sub_widgets/sending_transaction_dialog.dart'; import 'package:stackwallet/pages/wallet_view/wallet_view.dart'; import 'package:stackwallet/providers/providers.dart'; +import 'package:stackwallet/providers/wallet/public_private_balance_state_provider.dart'; import 'package:stackwallet/route_generator.dart'; import 'package:stackwallet/services/coins/epiccash/epiccash_wallet.dart'; import 'package:stackwallet/services/coins/firo/firo_wallet.dart'; -import 'package:stackwallet/utilities/cfcolors.dart'; import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/enums/flush_bar_type.dart'; import 'package:stackwallet/utilities/format.dart'; import 'package:stackwallet/utilities/text_styles.dart'; +import 'package:stackwallet/utilities/theme/stack_colors.dart'; import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart'; import 'package:stackwallet/widgets/rounded_container.dart'; import 'package:stackwallet/widgets/rounded_white_container.dart'; import 'package:stackwallet/widgets/stack_dialog.dart'; -import '../../providers/wallet/public_private_balance_state_provider.dart'; - class ConfirmTransactionView extends ConsumerStatefulWidget { const ConfirmTransactionView({ Key? key, @@ -112,16 +111,15 @@ class _ConfirmTransactionViewState title: "Broadcast transaction failed", message: e.toString(), rightButton: TextButton( - style: Theme.of(context).textButtonTheme.style?.copyWith( - backgroundColor: MaterialStateProperty.all( - CFColors.buttonGray, - ), - ), + style: Theme.of(context) + .extension()! + .getSecondaryEnabledButtonColor(context), child: Text( "Ok", - style: STextStyles.button.copyWith( - color: CFColors.stackAccent, - ), + style: STextStyles.button(context).copyWith( + color: Theme.of(context) + .extension()! + .accentColorDark), ), onPressed: () { Navigator.of(context).pop(); @@ -147,7 +145,7 @@ class _ConfirmTransactionViewState .select((value) => value.getManagerProvider(walletId))); return Scaffold( appBar: AppBar( - backgroundColor: CFColors.almostWhite, + backgroundColor: Theme.of(context).extension()!.background, leading: AppBarBackButton( onPressed: () async { // if (FocusScope.of(context).hasFocus) { @@ -159,7 +157,7 @@ class _ConfirmTransactionViewState ), title: Text( "Confirm transaction", - style: STextStyles.navBarTitle, + style: STextStyles.navBarTitle(context), ), ), body: LayoutBuilder( @@ -183,7 +181,7 @@ class _ConfirmTransactionViewState children: [ Text( "Send ${ref.watch(managerProvider.select((value) => value.coin)).ticker}", - style: STextStyles.pageTitleH1, + style: STextStyles.pageTitleH1(context), ), const SizedBox( height: 12, @@ -194,14 +192,14 @@ class _ConfirmTransactionViewState children: [ Text( "Recipient", - style: STextStyles.smallMed12, + style: STextStyles.smallMed12(context), ), const SizedBox( height: 4, ), Text( "${transactionInfo["address"] ?? "ERROR"}", - style: STextStyles.itemSubtitle12, + style: STextStyles.itemSubtitle12(context), ), ], ), @@ -215,7 +213,7 @@ class _ConfirmTransactionViewState children: [ Text( "Amount", - style: STextStyles.smallMed12, + style: STextStyles.smallMed12(context), ), Text( "${Format.satoshiAmountToPrettyString( @@ -228,7 +226,7 @@ class _ConfirmTransactionViewState managerProvider .select((value) => value.coin), ).ticker}", - style: STextStyles.itemSubtitle12, + style: STextStyles.itemSubtitle12(context), textAlign: TextAlign.right, ), ], @@ -243,7 +241,7 @@ class _ConfirmTransactionViewState children: [ Text( "Transaction fee", - style: STextStyles.smallMed12, + style: STextStyles.smallMed12(context), ), Text( "${Format.satoshiAmountToPrettyString( @@ -256,7 +254,7 @@ class _ConfirmTransactionViewState managerProvider .select((value) => value.coin), ).ticker}", - style: STextStyles.itemSubtitle12, + style: STextStyles.itemSubtitle12(context), textAlign: TextAlign.right, ), ], @@ -271,14 +269,14 @@ class _ConfirmTransactionViewState children: [ Text( "Note", - style: STextStyles.smallMed12, + style: STextStyles.smallMed12(context), ), const SizedBox( height: 4, ), Text( transactionInfo["note"] as String, - style: STextStyles.itemSubtitle12, + style: STextStyles.itemSubtitle12(context), ), ], ), @@ -288,13 +286,15 @@ class _ConfirmTransactionViewState height: 12, ), RoundedContainer( - color: CFColors.stackGreen15, + color: Theme.of(context) + .extension()! + .snackBarBackSuccess, child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( "Total amount", - style: STextStyles.titleBold12, + style: STextStyles.titleBold12(context), ), Text( "${Format.satoshiAmountToPrettyString( @@ -308,7 +308,7 @@ class _ConfirmTransactionViewState managerProvider .select((value) => value.coin), ).ticker}", - style: STextStyles.itemSubtitle12, + style: STextStyles.itemSubtitle12(context), textAlign: TextAlign.right, ), ], @@ -318,13 +318,9 @@ class _ConfirmTransactionViewState height: 16, ), TextButton( - style: - Theme.of(context).textButtonTheme.style?.copyWith( - backgroundColor: - MaterialStateProperty.all( - CFColors.stackAccent, - ), - ), + style: Theme.of(context) + .extension()! + .getPrimaryEnabledButtonColor(context), onPressed: () async { final unlocked = await Navigator.push( context, @@ -353,7 +349,7 @@ class _ConfirmTransactionViewState }, child: Text( "Send", - style: STextStyles.button, + style: STextStyles.button(context), ), ), ], diff --git a/lib/pages/send_view/send_view.dart b/lib/pages/send_view/send_view.dart index 6dc274464..ee9644c2a 100644 --- a/lib/pages/send_view/send_view.dart +++ b/lib/pages/send_view/send_view.dart @@ -9,6 +9,7 @@ import 'package:stackwallet/models/send_view_auto_fill_data.dart'; import 'package:stackwallet/pages/address_book_views/address_book_view.dart'; import 'package:stackwallet/pages/send_view/confirm_transaction_view.dart'; import 'package:stackwallet/pages/send_view/sub_widgets/building_transaction_dialog.dart'; +import 'package:stackwallet/pages/send_view/sub_widgets/firo_balance_selection_sheet.dart'; import 'package:stackwallet/pages/send_view/sub_widgets/transaction_fee_selection_sheet.dart'; import 'package:stackwallet/providers/providers.dart'; import 'package:stackwallet/providers/ui/fee_rate_type_state_provider.dart'; @@ -20,7 +21,6 @@ import 'package:stackwallet/services/coins/manager.dart'; import 'package:stackwallet/utilities/address_utils.dart'; import 'package:stackwallet/utilities/assets.dart'; import 'package:stackwallet/utilities/barcode_scanner_interface.dart'; -import 'package:stackwallet/utilities/cfcolors.dart'; import 'package:stackwallet/utilities/clipboard_interface.dart'; import 'package:stackwallet/utilities/constants.dart'; import 'package:stackwallet/utilities/enums/coin_enum.dart'; @@ -28,6 +28,7 @@ import 'package:stackwallet/utilities/enums/fee_rate_type_enum.dart'; import 'package:stackwallet/utilities/format.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/animated_text.dart'; import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart'; import 'package:stackwallet/widgets/custom_buttons/blue_text_button.dart'; @@ -39,8 +40,6 @@ import 'package:stackwallet/widgets/stack_dialog.dart'; import 'package:stackwallet/widgets/stack_text_field.dart'; import 'package:stackwallet/widgets/textfield_icon_button.dart'; -import 'sub_widgets/firo_balance_selection_sheet.dart'; - class SendView extends ConsumerStatefulWidget { const SendView({ Key? key, @@ -360,7 +359,7 @@ class _SendViewState extends ConsumerState { } return Scaffold( - backgroundColor: CFColors.almostWhite, + backgroundColor: Theme.of(context).extension()!.background, appBar: AppBar( leading: AppBarBackButton( onPressed: () async { @@ -375,7 +374,7 @@ class _SendViewState extends ConsumerState { ), title: Text( "Send ${coin.ticker}", - style: STextStyles.navBarTitle, + style: STextStyles.navBarTitle(context), ), ), body: LayoutBuilder( @@ -400,7 +399,9 @@ class _SendViewState extends ConsumerState { children: [ Container( decoration: BoxDecoration( - color: CFColors.white, + color: Theme.of(context) + .extension()! + .popupBG, borderRadius: BorderRadius.circular( Constants.size.circularBorderRadius, ), @@ -419,10 +420,14 @@ class _SendViewState extends ConsumerState { ), if (coin != Coin.firo && coin != Coin.firoTestNet) - Text( - ref.watch(provider - .select((value) => value.walletName)), - style: STextStyles.titleBold12, + Expanded( + child: Text( + ref.watch(provider + .select((value) => value.walletName)), + style: STextStyles.titleBold12(context), + overflow: TextOverflow.ellipsis, + maxLines: 1, + ), ), if (coin == Coin.firo || coin == Coin.firoTestNet) @@ -433,7 +438,7 @@ class _SendViewState extends ConsumerState { Text( ref.watch(provider.select( (value) => value.walletName)), - style: STextStyles.titleBold12 + style: STextStyles.titleBold12(context) .copyWith(fontSize: 14), ), // const SizedBox( @@ -441,12 +446,19 @@ class _SendViewState extends ConsumerState { // ), Text( "${ref.watch(publicPrivateBalanceStateProvider.state).state} balance", - style: STextStyles.label + style: STextStyles.label(context) .copyWith(fontSize: 10), ), ], ), - const Spacer(), + if (coin != Coin.firo && + coin != Coin.firoTestNet) + const SizedBox( + width: 10, + ), + if (coin == Coin.firo || + coin == Coin.firoTestNet) + const Spacer(), FutureBuilder( future: (coin != Coin.firo && coin != Coin.firoTestNet) @@ -491,7 +503,8 @@ class _SendViewState extends ConsumerState { locale: locale, decimalPlaces: 8, )} ${coin.ticker}", - style: STextStyles.titleBold12 + style: STextStyles.titleBold12( + context) .copyWith( fontSize: 10, ), @@ -510,7 +523,8 @@ class _SendViewState extends ConsumerState { locale: locale, decimalPlaces: 2, )} ${ref.watch(prefsChangeNotifierProvider.select((value) => value.currency))}", - style: STextStyles.titleBold12 + style: STextStyles.titleBold12( + context) .copyWith( fontSize: 8, fontWeight: FontWeight.w400, @@ -533,7 +547,8 @@ class _SendViewState extends ConsumerState { "Loading balance.. ", "Loading balance...", ], - style: STextStyles.itemSubtitle + style: STextStyles.itemSubtitle( + context) .copyWith( fontSize: 10, ), @@ -548,7 +563,8 @@ class _SendViewState extends ConsumerState { "Loading balance.. ", "Loading balance...", ], - style: STextStyles.itemSubtitle + style: STextStyles.itemSubtitle( + context) .copyWith( fontSize: 8, ), @@ -567,7 +583,7 @@ class _SendViewState extends ConsumerState { ), Text( "Send to", - style: STextStyles.smallMed12, + style: STextStyles.smallMed12(context), textAlign: TextAlign.left, ), const SizedBox( @@ -603,10 +619,11 @@ class _SendViewState extends ConsumerState { }); }, focusNode: _addressFocusNode, - style: STextStyles.field, + style: STextStyles.field(context), decoration: standardInputDecoration( "Enter ${coin.ticker} address", _addressFocusNode, + context, ).copyWith( contentPadding: const EdgeInsets.only( left: 16, @@ -839,8 +856,10 @@ class _SendViewState extends ConsumerState { child: Text( error, textAlign: TextAlign.left, - style: STextStyles.label.copyWith( - color: CFColors.notificationRedForeground, + style: STextStyles.label(context).copyWith( + color: Theme.of(context) + .extension()! + .textError, ), ), ), @@ -855,7 +874,7 @@ class _SendViewState extends ConsumerState { if (coin == Coin.firo) Text( "Send from", - style: STextStyles.smallMed12, + style: STextStyles.smallMed12(context), textAlign: TextAlign.left, ), if (coin == Coin.firo) @@ -874,7 +893,9 @@ class _SendViewState extends ConsumerState { horizontal: 12, ), child: RawMaterialButton( - splashColor: CFColors.splashLight, + splashColor: Theme.of(context) + .extension()! + .highlight, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular( Constants.size.circularBorderRadius, @@ -902,7 +923,8 @@ class _SendViewState extends ConsumerState { children: [ Text( "${ref.watch(publicPrivateBalanceStateProvider.state).state} balance", - style: STextStyles.itemSubtitle12, + style: STextStyles.itemSubtitle12( + context), ), const SizedBox( width: 10, @@ -940,7 +962,8 @@ class _SendViewState extends ConsumerState { return Text( "$_privateBalanceString ${coin.ticker}", style: - STextStyles.itemSubtitle, + STextStyles.itemSubtitle( + context), ); } else if (ref .read( @@ -953,7 +976,8 @@ class _SendViewState extends ConsumerState { return Text( "$_publicBalanceString ${coin.ticker}", style: - STextStyles.itemSubtitle, + STextStyles.itemSubtitle( + context), ); } else { return AnimatedText( @@ -964,7 +988,8 @@ class _SendViewState extends ConsumerState { "Loading balance...", ], style: - STextStyles.itemSubtitle, + STextStyles.itemSubtitle( + context), ); } }, @@ -975,7 +1000,9 @@ class _SendViewState extends ConsumerState { Assets.svg.chevronDown, width: 8, height: 4, - color: CFColors.gray3, + color: Theme.of(context) + .extension()! + .textSubtitle2, ), ], ), @@ -991,7 +1018,7 @@ class _SendViewState extends ConsumerState { children: [ Text( "Amount", - style: STextStyles.smallMed12, + style: STextStyles.smallMed12(context), textAlign: TextAlign.left, ), BlueTextButton( @@ -1056,7 +1083,7 @@ class _SendViewState extends ConsumerState { right: 12, ), hintText: "0", - hintStyle: STextStyles.fieldLabel.copyWith( + hintStyle: STextStyles.fieldLabel(context).copyWith( fontSize: 14, ), prefixIcon: FittedBox( @@ -1065,9 +1092,11 @@ class _SendViewState extends ConsumerState { padding: const EdgeInsets.all(12), child: Text( coin.ticker, - style: STextStyles.smallMed14.copyWith( - color: CFColors.stackAccent, - ), + style: STextStyles.smallMed14(context) + .copyWith( + color: Theme.of(context) + .extension()! + .accentColorDark), ), ), ), @@ -1157,7 +1186,7 @@ class _SendViewState extends ConsumerState { right: 12, ), hintText: "0", - hintStyle: STextStyles.fieldLabel.copyWith( + hintStyle: STextStyles.fieldLabel(context).copyWith( fontSize: 14, ), prefixIcon: FittedBox( @@ -1167,9 +1196,11 @@ class _SendViewState extends ConsumerState { child: Text( ref.watch(prefsChangeNotifierProvider .select((value) => value.currency)), - style: STextStyles.smallMed14.copyWith( - color: CFColors.stackAccent, - ), + style: STextStyles.smallMed14(context) + .copyWith( + color: Theme.of(context) + .extension()! + .accentColorDark), ), ), ), @@ -1180,7 +1211,7 @@ class _SendViewState extends ConsumerState { ), Text( "Note (optional)", - style: STextStyles.smallMed12, + style: STextStyles.smallMed12(context), textAlign: TextAlign.left, ), const SizedBox( @@ -1193,11 +1224,12 @@ class _SendViewState extends ConsumerState { child: TextField( controller: noteController, focusNode: _noteFocusNode, - style: STextStyles.field, + style: STextStyles.field(context), onChanged: (_) => setState(() {}), decoration: standardInputDecoration( "Type something...", _noteFocusNode, + context, ).copyWith( suffixIcon: noteController.text.isNotEmpty ? Padding( @@ -1226,7 +1258,7 @@ class _SendViewState extends ConsumerState { ), Text( "Transaction fee (estimated)", - style: STextStyles.smallMed12, + style: STextStyles.smallMed12(context), textAlign: TextAlign.left, ), const SizedBox( @@ -1244,7 +1276,9 @@ class _SendViewState extends ConsumerState { horizontal: 12, ), child: RawMaterialButton( - splashColor: CFColors.splashLight, + splashColor: Theme.of(context) + .extension()! + .highlight, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular( Constants.size.circularBorderRadius, @@ -1297,7 +1331,8 @@ class _SendViewState extends ConsumerState { return Text( "~${snapshot.data! as String} ${coin.ticker}", style: - STextStyles.itemSubtitle, + STextStyles.itemSubtitle( + context), ); } else { return AnimatedText( @@ -1308,7 +1343,8 @@ class _SendViewState extends ConsumerState { "Calculating...", ], style: - STextStyles.itemSubtitle, + STextStyles.itemSubtitle( + context), ); } }, @@ -1329,7 +1365,8 @@ class _SendViewState extends ConsumerState { .state .prettyName, style: - STextStyles.itemSubtitle12, + STextStyles.itemSubtitle12( + context), ), const SizedBox( width: 10, @@ -1344,7 +1381,8 @@ class _SendViewState extends ConsumerState { return Text( "~${snapshot.data! as String} ${coin.ticker}", style: STextStyles - .itemSubtitle, + .itemSubtitle( + context), ); } else { return AnimatedText( @@ -1355,7 +1393,8 @@ class _SendViewState extends ConsumerState { "Calculating...", ], style: STextStyles - .itemSubtitle, + .itemSubtitle( + context), ); } }, @@ -1366,7 +1405,9 @@ class _SendViewState extends ConsumerState { Assets.svg.chevronDown, width: 8, height: 4, - color: CFColors.gray3, + color: Theme.of(context) + .extension()! + .textSubtitle2, ), ], ), @@ -1407,21 +1448,17 @@ class _SendViewState extends ConsumerState { "Sending to self is currently disabled", rightButton: TextButton( style: Theme.of(context) - .textButtonTheme - .style - ?.copyWith( - backgroundColor: - MaterialStateProperty.all< - Color>( - CFColors.buttonGray, - ), - ), + .extension()! + .getSecondaryEnabledButtonColor( + context), child: Text( "Ok", - style: - STextStyles.button.copyWith( - color: CFColors.stackAccent, - ), + style: STextStyles.button(context) + .copyWith( + color: Theme.of(context) + .extension< + StackColors>()! + .accentColorDark), ), onPressed: () { Navigator.of(context).pop(); @@ -1476,21 +1513,17 @@ class _SendViewState extends ConsumerState { "You are about to send your entire balance. Would you like to continue?", leftButton: TextButton( style: Theme.of(context) - .textButtonTheme - .style - ?.copyWith( - backgroundColor: - MaterialStateProperty.all< - Color>( - CFColors.buttonGray, - ), - ), + .extension()! + .getSecondaryEnabledButtonColor( + context), child: Text( "Cancel", - style: - STextStyles.button.copyWith( - color: CFColors.stackAccent, - ), + style: STextStyles.button(context) + .copyWith( + color: Theme.of(context) + .extension< + StackColors>()! + .accentColorDark), ), onPressed: () { Navigator.of(context).pop(false); @@ -1498,18 +1531,13 @@ class _SendViewState extends ConsumerState { ), rightButton: TextButton( style: Theme.of(context) - .textButtonTheme - .style - ?.copyWith( - backgroundColor: - MaterialStateProperty.all< - Color>( - CFColors.stackAccent, - ), - ), + .extension()! + .getPrimaryEnabledButtonColor( + context), child: Text( "Yes", - style: STextStyles.button, + style: + STextStyles.button(context), ), onPressed: () { Navigator.of(context).pop(true); @@ -1612,21 +1640,18 @@ class _SendViewState extends ConsumerState { message: e.toString(), rightButton: TextButton( style: Theme.of(context) - .textButtonTheme - .style - ?.copyWith( - backgroundColor: - MaterialStateProperty - .all( - CFColors.buttonGray, - ), - ), + .extension()! + .getSecondaryEnabledButtonColor( + context), child: Text( "Ok", - style: - STextStyles.button.copyWith( - color: CFColors.stackAccent, - ), + style: STextStyles.button( + context) + .copyWith( + color: Theme.of(context) + .extension< + StackColors>()! + .accentColorDark), ), onPressed: () { Navigator.of(context).pop(); @@ -1643,28 +1668,14 @@ class _SendViewState extends ConsumerState { .watch(previewTxButtonStateProvider.state) .state ? Theme.of(context) - .textButtonTheme - .style - ?.copyWith( - backgroundColor: - MaterialStateProperty.all( - CFColors.stackAccent, - ), - ) + .extension()! + .getPrimaryEnabledButtonColor(context) : Theme.of(context) - .textButtonTheme - .style - ?.copyWith( - backgroundColor: - MaterialStateProperty.all( - CFColors.stackAccent.withOpacity( - 0.25, - ), - ), - ), + .extension()! + .getPrimaryDisabledButtonColor(context), child: Text( "Preview", - style: STextStyles.button, + style: STextStyles.button(context), ), ), const SizedBox( diff --git a/lib/pages/send_view/sub_widgets/building_transaction_dialog.dart b/lib/pages/send_view/sub_widgets/building_transaction_dialog.dart index 226a28323..0b6786915 100644 --- a/lib/pages/send_view/sub_widgets/building_transaction_dialog.dart +++ b/lib/pages/send_view/sub_widgets/building_transaction_dialog.dart @@ -1,8 +1,8 @@ import 'package:flutter/material.dart'; import 'package:flutter_svg/svg.dart'; import 'package:stackwallet/utilities/assets.dart'; -import 'package:stackwallet/utilities/cfcolors.dart'; import 'package:stackwallet/utilities/text_styles.dart'; +import 'package:stackwallet/utilities/theme/stack_colors.dart'; import 'package:stackwallet/widgets/stack_dialog.dart'; class BuildingTransactionDialog extends StatefulWidget { @@ -62,20 +62,18 @@ class _RestoringDialogState extends State turns: _spinAnimation, child: SvgPicture.asset( Assets.svg.arrowRotate, - color: CFColors.stackAccent, + color: Theme.of(context).extension()!.accentColorDark, width: 24, height: 24, ), ), rightButton: TextButton( - style: Theme.of(context).textButtonTheme.style?.copyWith( - backgroundColor: MaterialStateProperty.all( - CFColors.buttonGray, - ), - ), + style: Theme.of(context) + .extension()! + .getSecondaryEnabledButtonColor(context), child: Text( "Cancel", - style: STextStyles.itemSubtitle12, + style: STextStyles.itemSubtitle12(context), ), onPressed: () { Navigator.of(context).pop(); diff --git a/lib/pages/send_view/sub_widgets/firo_balance_selection_sheet.dart b/lib/pages/send_view/sub_widgets/firo_balance_selection_sheet.dart index 8cb1e64dd..e639a8cf8 100644 --- a/lib/pages/send_view/sub_widgets/firo_balance_selection_sheet.dart +++ b/lib/pages/send_view/sub_widgets/firo_balance_selection_sheet.dart @@ -4,10 +4,10 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:stackwallet/providers/providers.dart'; import 'package:stackwallet/providers/wallet/public_private_balance_state_provider.dart'; import 'package:stackwallet/services/coins/firo/firo_wallet.dart'; -import 'package:stackwallet/utilities/cfcolors.dart'; import 'package:stackwallet/utilities/constants.dart'; import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/text_styles.dart'; +import 'package:stackwallet/utilities/theme/stack_colors.dart'; import 'package:stackwallet/widgets/animated_text.dart'; class FiroBalanceSelectionSheet extends ConsumerStatefulWidget { @@ -49,9 +49,9 @@ class _FiroBalanceSelectionSheetState final firoWallet = manager.wallet as FiroWallet; return Container( - decoration: const BoxDecoration( - color: CFColors.white, - borderRadius: BorderRadius.vertical( + decoration: BoxDecoration( + color: Theme.of(context).extension()!.popupBG, + borderRadius: const BorderRadius.vertical( top: Radius.circular(20), ), ), @@ -69,7 +69,9 @@ class _FiroBalanceSelectionSheetState Center( child: Container( decoration: BoxDecoration( - color: CFColors.fieldGray, + color: Theme.of(context) + .extension()! + .textFieldDefaultBG, borderRadius: BorderRadius.circular( Constants.size.circularBorderRadius, ), @@ -86,7 +88,7 @@ class _FiroBalanceSelectionSheetState children: [ Text( "Select balance", - style: STextStyles.pageTitleH2, + style: STextStyles.pageTitleH2(context), textAlign: TextAlign.left, ), const SizedBox( @@ -114,7 +116,9 @@ class _FiroBalanceSelectionSheetState width: 20, height: 20, child: Radio( - activeColor: CFColors.link2, + activeColor: Theme.of(context) + .extension()! + .radioButtonIconEnabled, value: "Private", groupValue: ref .watch( @@ -143,9 +147,7 @@ class _FiroBalanceSelectionSheetState // children: [ Text( "Private balance", - style: STextStyles.titleBold12.copyWith( - color: const Color(0xFF44464E), - ), + style: STextStyles.titleBold12(context), textAlign: TextAlign.left, ), const SizedBox( @@ -160,14 +162,14 @@ class _FiroBalanceSelectionSheetState snapshot.hasData) { return Text( "${snapshot.data!} ${manager.coin.ticker}", - style: STextStyles.itemSubtitle, + style: STextStyles.itemSubtitle(context), textAlign: TextAlign.left, ); } else { return AnimatedText( stringsToLoopThrough: stringsToLoopThrough, - style: STextStyles.itemSubtitle, + style: STextStyles.itemSubtitle(context), ); } }, @@ -205,7 +207,9 @@ class _FiroBalanceSelectionSheetState width: 20, height: 20, child: Radio( - activeColor: CFColors.link2, + activeColor: Theme.of(context) + .extension()! + .radioButtonIconEnabled, value: "Public", groupValue: ref .watch( @@ -233,9 +237,7 @@ class _FiroBalanceSelectionSheetState // children: [ Text( "Public balance", - style: STextStyles.titleBold12.copyWith( - color: const Color(0xFF44464E), - ), + style: STextStyles.titleBold12(context), textAlign: TextAlign.left, ), const SizedBox( @@ -250,14 +252,14 @@ class _FiroBalanceSelectionSheetState snapshot.hasData) { return Text( "${snapshot.data!} ${manager.coin.ticker}", - style: STextStyles.itemSubtitle, + style: STextStyles.itemSubtitle(context), textAlign: TextAlign.left, ); } else { return AnimatedText( stringsToLoopThrough: stringsToLoopThrough, - style: STextStyles.itemSubtitle, + style: STextStyles.itemSubtitle(context), ); } }, diff --git a/lib/pages/send_view/sub_widgets/sending_transaction_dialog.dart b/lib/pages/send_view/sub_widgets/sending_transaction_dialog.dart index df04fb32a..1eb106b53 100644 --- a/lib/pages/send_view/sub_widgets/sending_transaction_dialog.dart +++ b/lib/pages/send_view/sub_widgets/sending_transaction_dialog.dart @@ -1,7 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_svg/svg.dart'; import 'package:stackwallet/utilities/assets.dart'; -import 'package:stackwallet/utilities/cfcolors.dart'; +import 'package:stackwallet/utilities/theme/stack_colors.dart'; import 'package:stackwallet/widgets/stack_dialog.dart'; class SendingTransactionDialog extends StatefulWidget { @@ -55,7 +55,7 @@ class _RestoringDialogState extends State turns: _spinAnimation, child: SvgPicture.asset( Assets.svg.arrowRotate, - color: CFColors.stackAccent, + color: Theme.of(context).extension()!.accentColorDark, width: 24, height: 24, ), diff --git a/lib/pages/send_view/sub_widgets/transaction_fee_selection_sheet.dart b/lib/pages/send_view/sub_widgets/transaction_fee_selection_sheet.dart index 4eca34f3d..ff26fe782 100644 --- a/lib/pages/send_view/sub_widgets/transaction_fee_selection_sheet.dart +++ b/lib/pages/send_view/sub_widgets/transaction_fee_selection_sheet.dart @@ -6,12 +6,12 @@ import 'package:stackwallet/providers/providers.dart'; import 'package:stackwallet/providers/ui/fee_rate_type_state_provider.dart'; import 'package:stackwallet/providers/wallet/public_private_balance_state_provider.dart'; import 'package:stackwallet/services/coins/firo/firo_wallet.dart'; -import 'package:stackwallet/utilities/cfcolors.dart'; import 'package:stackwallet/utilities/constants.dart'; import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/enums/fee_rate_type_enum.dart'; import 'package:stackwallet/utilities/format.dart'; import 'package:stackwallet/utilities/text_styles.dart'; +import 'package:stackwallet/utilities/theme/stack_colors.dart'; import 'package:stackwallet/widgets/animated_text.dart'; final feeSheetSessionCacheProvider = @@ -162,9 +162,9 @@ class _TransactionFeeSelectionSheetState .select((value) => value.getManager(walletId))); return Container( - decoration: const BoxDecoration( - color: CFColors.white, - borderRadius: BorderRadius.vertical( + decoration: BoxDecoration( + color: Theme.of(context).extension()!.popupBG, + borderRadius: const BorderRadius.vertical( top: Radius.circular(20), ), ), @@ -182,7 +182,9 @@ class _TransactionFeeSelectionSheetState Center( child: Container( decoration: BoxDecoration( - color: CFColors.fieldGray, + color: Theme.of(context) + .extension()! + .textFieldDefaultBG, borderRadius: BorderRadius.circular( Constants.size.circularBorderRadius, ), @@ -207,7 +209,7 @@ class _TransactionFeeSelectionSheetState children: [ Text( "Fee rate", - style: STextStyles.pageTitleH2, + style: STextStyles.pageTitleH2(context), textAlign: TextAlign.left, ), const SizedBox( @@ -235,7 +237,9 @@ class _TransactionFeeSelectionSheetState width: 20, height: 20, child: Radio( - activeColor: CFColors.link2, + activeColor: Theme.of(context) + .extension()! + .radioButtonIconEnabled, value: FeeRateType.fast, groupValue: ref .watch(feeRateTypeStateProvider.state) @@ -262,9 +266,7 @@ class _TransactionFeeSelectionSheetState children: [ Text( FeeRateType.fast.prettyName, - style: STextStyles.titleBold12.copyWith( - color: const Color(0xFF44464E), - ), + style: STextStyles.titleBold12(context), textAlign: TextAlign.left, ), const SizedBox( @@ -274,7 +276,8 @@ class _TransactionFeeSelectionSheetState AnimatedText( stringsToLoopThrough: stringsToLoopThrough, - style: STextStyles.itemSubtitle, + style: + STextStyles.itemSubtitle(context), ), if (feeObject != null) FutureBuilder( @@ -296,14 +299,16 @@ class _TransactionFeeSelectionSheetState snapshot.hasData) { return Text( "(~${snapshot.data!} ${manager.coin.ticker})", - style: STextStyles.itemSubtitle, + style: STextStyles.itemSubtitle( + context), textAlign: TextAlign.left, ); } else { return AnimatedText( stringsToLoopThrough: stringsToLoopThrough, - style: STextStyles.itemSubtitle, + style: STextStyles.itemSubtitle( + context), ); } }, @@ -317,7 +322,7 @@ class _TransactionFeeSelectionSheetState AnimatedText( stringsToLoopThrough: stringsToLoopThrough, - style: STextStyles.itemSubtitle, + style: STextStyles.itemSubtitle(context), ), if (feeObject != null) Text( @@ -326,7 +331,7 @@ class _TransactionFeeSelectionSheetState manager.coin), feeObject!.numberOfBlocksFast, ), - style: STextStyles.itemSubtitle, + style: STextStyles.itemSubtitle(context), textAlign: TextAlign.left, ), ], @@ -360,7 +365,9 @@ class _TransactionFeeSelectionSheetState width: 20, height: 20, child: Radio( - activeColor: CFColors.link2, + activeColor: Theme.of(context) + .extension()! + .radioButtonIconEnabled, value: FeeRateType.average, groupValue: ref .watch(feeRateTypeStateProvider.state) @@ -386,9 +393,7 @@ class _TransactionFeeSelectionSheetState children: [ Text( FeeRateType.average.prettyName, - style: STextStyles.titleBold12.copyWith( - color: const Color(0xFF44464E), - ), + style: STextStyles.titleBold12(context), textAlign: TextAlign.left, ), const SizedBox( @@ -398,7 +403,8 @@ class _TransactionFeeSelectionSheetState AnimatedText( stringsToLoopThrough: stringsToLoopThrough, - style: STextStyles.itemSubtitle, + style: + STextStyles.itemSubtitle(context), ), if (feeObject != null) FutureBuilder( @@ -420,14 +426,16 @@ class _TransactionFeeSelectionSheetState snapshot.hasData) { return Text( "(~${snapshot.data!} ${manager.coin.ticker})", - style: STextStyles.itemSubtitle, + style: STextStyles.itemSubtitle( + context), textAlign: TextAlign.left, ); } else { return AnimatedText( stringsToLoopThrough: stringsToLoopThrough, - style: STextStyles.itemSubtitle, + style: STextStyles.itemSubtitle( + context), ); } }, @@ -441,7 +449,7 @@ class _TransactionFeeSelectionSheetState AnimatedText( stringsToLoopThrough: stringsToLoopThrough, - style: STextStyles.itemSubtitle, + style: STextStyles.itemSubtitle(context), ), if (feeObject != null) Text( @@ -450,7 +458,7 @@ class _TransactionFeeSelectionSheetState manager.coin), feeObject!.numberOfBlocksAverage, ), - style: STextStyles.itemSubtitle, + style: STextStyles.itemSubtitle(context), textAlign: TextAlign.left, ), ], @@ -484,7 +492,9 @@ class _TransactionFeeSelectionSheetState width: 20, height: 20, child: Radio( - activeColor: CFColors.link2, + activeColor: Theme.of(context) + .extension()! + .radioButtonIconEnabled, value: FeeRateType.slow, groupValue: ref .watch(feeRateTypeStateProvider.state) @@ -511,9 +521,7 @@ class _TransactionFeeSelectionSheetState children: [ Text( FeeRateType.slow.prettyName, - style: STextStyles.titleBold12.copyWith( - color: const Color(0xFF44464E), - ), + style: STextStyles.titleBold12(context), textAlign: TextAlign.left, ), const SizedBox( @@ -523,7 +531,8 @@ class _TransactionFeeSelectionSheetState AnimatedText( stringsToLoopThrough: stringsToLoopThrough, - style: STextStyles.itemSubtitle, + style: + STextStyles.itemSubtitle(context), ), if (feeObject != null) FutureBuilder( @@ -545,14 +554,16 @@ class _TransactionFeeSelectionSheetState snapshot.hasData) { return Text( "(~${snapshot.data!} ${manager.coin.ticker})", - style: STextStyles.itemSubtitle, + style: STextStyles.itemSubtitle( + context), textAlign: TextAlign.left, ); } else { return AnimatedText( stringsToLoopThrough: stringsToLoopThrough, - style: STextStyles.itemSubtitle, + style: STextStyles.itemSubtitle( + context), ); } }, @@ -566,7 +577,7 @@ class _TransactionFeeSelectionSheetState AnimatedText( stringsToLoopThrough: stringsToLoopThrough, - style: STextStyles.itemSubtitle, + style: STextStyles.itemSubtitle(context), ), if (feeObject != null) Text( @@ -575,7 +586,7 @@ class _TransactionFeeSelectionSheetState manager.coin), feeObject!.numberOfBlocksSlow, ), - style: STextStyles.itemSubtitle, + style: STextStyles.itemSubtitle(context), textAlign: TextAlign.left, ), ], diff --git a/lib/pages/settings_views/global_settings_view/about_view.dart b/lib/pages/settings_views/global_settings_view/about_view.dart index f1043866d..dc2da2488 100644 --- a/lib/pages/settings_views/global_settings_view/about_view.dart +++ b/lib/pages/settings_views/global_settings_view/about_view.dart @@ -1,21 +1,20 @@ import 'dart:convert'; -import 'package:http/http.dart'; import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_libepiccash/git_versions.dart' as EPIC_VERSIONS; +import 'package:flutter_libmonero/git_versions.dart' as MONERO_VERSIONS; import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:http/http.dart'; +import 'package:lelantus/git_versions.dart' as FIRO_VERSIONS; import 'package:package_info_plus/package_info_plus.dart'; -import 'package:stackwallet/utilities/cfcolors.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/custom_buttons/app_bar_icon_button.dart'; import 'package:stackwallet/widgets/custom_buttons/blue_text_button.dart'; import 'package:stackwallet/widgets/rounded_white_container.dart'; import 'package:url_launcher/url_launcher.dart'; -import 'package:flutter_libepiccash/git_versions.dart' as EPIC_VERSIONS; -import 'package:flutter_libmonero/git_versions.dart' as MONERO_VERSIONS; -import 'package:lelantus/git_versions.dart' as FIRO_VERSIONS; - -import 'package:stackwallet/utilities/logger.dart'; const kGithubAPI = "https://api.github.com"; const kGithubSearch = "/search/commits"; @@ -119,7 +118,7 @@ class AboutView extends ConsumerWidget { Future commitMoneroFuture = Future.wait(futureMoneroList); return Scaffold( - backgroundColor: CFColors.almostWhite, + backgroundColor: Theme.of(context).extension()!.background, appBar: AppBar( leading: AppBarBackButton( onPressed: () async { @@ -128,7 +127,7 @@ class AboutView extends ConsumerWidget { ), title: Text( "About", - style: STextStyles.navBarTitle, + style: STextStyles.navBarTitle(context), ), ), body: Padding( @@ -168,7 +167,7 @@ class AboutView extends ConsumerWidget { Center( child: Text( appName, - style: STextStyles.pageTitleH2, + style: STextStyles.pageTitleH2(context), ), ), const SizedBox( @@ -181,14 +180,14 @@ class AboutView extends ConsumerWidget { children: [ Text( "Version", - style: STextStyles.titleBold12, + style: STextStyles.titleBold12(context), ), const SizedBox( height: 4, ), SelectableText( version, - style: STextStyles.itemSubtitle, + style: STextStyles.itemSubtitle(context), ), ], ), @@ -203,14 +202,14 @@ class AboutView extends ConsumerWidget { children: [ Text( "Build number", - style: STextStyles.titleBold12, + style: STextStyles.titleBold12(context), ), const SizedBox( height: 4, ), SelectableText( build, - style: STextStyles.itemSubtitle, + style: STextStyles.itemSubtitle(context), ), ], ), @@ -225,14 +224,14 @@ class AboutView extends ConsumerWidget { children: [ Text( "Build signature", - style: STextStyles.titleBold12, + style: STextStyles.titleBold12(context), ), const SizedBox( height: 4, ), SelectableText( signature, - style: STextStyles.itemSubtitle, + style: STextStyles.itemSubtitle(context), ), ], ), @@ -265,19 +264,28 @@ class AboutView extends ConsumerWidget { } } TextStyle indicationStyle = - STextStyles.itemSubtitle; + STextStyles.itemSubtitle(context); switch (stateOfCommit) { case CommitStatus.isHead: - indicationStyle = STextStyles.itemSubtitle - .copyWith(color: CFColors.stackGreen); + indicationStyle = + STextStyles.itemSubtitle(context).copyWith( + color: Theme.of(context) + .extension()! + .accentColorGreen); break; case CommitStatus.isOldCommit: - indicationStyle = STextStyles.itemSubtitle - .copyWith(color: CFColors.stackYellow); + indicationStyle = + STextStyles.itemSubtitle(context).copyWith( + color: Theme.of(context) + .extension()! + .accentColorYellow); break; case CommitStatus.notACommit: - indicationStyle = STextStyles.itemSubtitle - .copyWith(color: CFColors.stackRed); + indicationStyle = + STextStyles.itemSubtitle(context).copyWith( + color: Theme.of(context) + .extension()! + .accentColorRed); break; default: break; @@ -288,7 +296,7 @@ class AboutView extends ConsumerWidget { children: [ Text( "Firo Build Commit", - style: STextStyles.titleBold12, + style: STextStyles.titleBold12(context), ), const SizedBox( height: 4, @@ -325,19 +333,28 @@ class AboutView extends ConsumerWidget { } } TextStyle indicationStyle = - STextStyles.itemSubtitle; + STextStyles.itemSubtitle(context); switch (stateOfCommit) { case CommitStatus.isHead: - indicationStyle = STextStyles.itemSubtitle - .copyWith(color: CFColors.stackGreen); + indicationStyle = + STextStyles.itemSubtitle(context).copyWith( + color: Theme.of(context) + .extension()! + .accentColorGreen); break; case CommitStatus.isOldCommit: - indicationStyle = STextStyles.itemSubtitle - .copyWith(color: CFColors.stackYellow); + indicationStyle = + STextStyles.itemSubtitle(context).copyWith( + color: Theme.of(context) + .extension()! + .accentColorYellow); break; case CommitStatus.notACommit: - indicationStyle = STextStyles.itemSubtitle - .copyWith(color: CFColors.stackRed); + indicationStyle = + STextStyles.itemSubtitle(context).copyWith( + color: Theme.of(context) + .extension()! + .accentColorRed); break; default: break; @@ -348,7 +365,7 @@ class AboutView extends ConsumerWidget { children: [ Text( "Epic Cash Build Commit", - style: STextStyles.titleBold12, + style: STextStyles.titleBold12(context), ), const SizedBox( height: 4, @@ -385,19 +402,28 @@ class AboutView extends ConsumerWidget { } } TextStyle indicationStyle = - STextStyles.itemSubtitle; + STextStyles.itemSubtitle(context); switch (stateOfCommit) { case CommitStatus.isHead: - indicationStyle = STextStyles.itemSubtitle - .copyWith(color: CFColors.stackGreen); + indicationStyle = + STextStyles.itemSubtitle(context).copyWith( + color: Theme.of(context) + .extension()! + .accentColorGreen); break; case CommitStatus.isOldCommit: - indicationStyle = STextStyles.itemSubtitle - .copyWith(color: CFColors.stackYellow); + indicationStyle = + STextStyles.itemSubtitle(context).copyWith( + color: Theme.of(context) + .extension()! + .accentColorYellow); break; case CommitStatus.notACommit: - indicationStyle = STextStyles.itemSubtitle - .copyWith(color: CFColors.stackRed); + indicationStyle = + STextStyles.itemSubtitle(context).copyWith( + color: Theme.of(context) + .extension()! + .accentColorRed); break; default: break; @@ -408,7 +434,7 @@ class AboutView extends ConsumerWidget { children: [ Text( "Monero Build Commit", - style: STextStyles.titleBold12, + style: STextStyles.titleBold12(context), ), const SizedBox( height: 4, @@ -430,7 +456,7 @@ class AboutView extends ConsumerWidget { children: [ Text( "Website", - style: STextStyles.titleBold12, + style: STextStyles.titleBold12(context), ), const SizedBox( height: 4, @@ -454,14 +480,14 @@ class AboutView extends ConsumerWidget { RichText( textAlign: TextAlign.center, text: TextSpan( - style: STextStyles.label, + style: STextStyles.label(context), children: [ const TextSpan( text: "By using Stack Wallet, you agree to the "), TextSpan( text: "Terms of service", - style: STextStyles.richLink, + style: STextStyles.richLink(context), recognizer: TapGestureRecognizer() ..onTap = () { launchUrl( @@ -474,7 +500,7 @@ class AboutView extends ConsumerWidget { const TextSpan(text: " and "), TextSpan( text: "Privacy policy", - style: STextStyles.richLink, + style: STextStyles.richLink(context), recognizer: TapGestureRecognizer() ..onTap = () { launchUrl( diff --git a/lib/pages/settings_views/global_settings_view/advanced_views/advanced_settings_view.dart b/lib/pages/settings_views/global_settings_view/advanced_views/advanced_settings_view.dart index 833e6c9ef..035efb2db 100644 --- a/lib/pages/settings_views/global_settings_view/advanced_views/advanced_settings_view.dart +++ b/lib/pages/settings_views/global_settings_view/advanced_views/advanced_settings_view.dart @@ -2,9 +2,9 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:stackwallet/pages/settings_views/global_settings_view/advanced_views/debug_view.dart'; import 'package:stackwallet/providers/global/prefs_provider.dart'; -import 'package:stackwallet/utilities/cfcolors.dart'; 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/draggable_switch_button.dart'; import 'package:stackwallet/widgets/rounded_white_container.dart'; @@ -21,7 +21,7 @@ class AdvancedSettingsView extends StatelessWidget { debugPrint("BUILD: $runtimeType"); return Scaffold( - backgroundColor: CFColors.almostWhite, + backgroundColor: Theme.of(context).extension()!.background, appBar: AppBar( leading: AppBarBackButton( onPressed: () { @@ -30,7 +30,7 @@ class AdvancedSettingsView extends StatelessWidget { ), title: Text( "Advanced", - style: STextStyles.navBarTitle, + style: STextStyles.navBarTitle(context), ), ), body: Padding( @@ -41,7 +41,7 @@ class AdvancedSettingsView extends StatelessWidget { RoundedWhiteContainer( padding: const EdgeInsets.all(0), child: RawMaterialButton( - // splashColor: CFColors.splashLight, + // splashColor: Theme.of(context).extension()!.highlight, materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular( @@ -60,7 +60,7 @@ class AdvancedSettingsView extends StatelessWidget { children: [ Text( "Debug info", - style: STextStyles.titleBold12, + style: STextStyles.titleBold12(context), textAlign: TextAlign.left, ), ], @@ -75,7 +75,7 @@ class AdvancedSettingsView extends StatelessWidget { child: Consumer( builder: (_, ref, __) { return RawMaterialButton( - // splashColor: CFColors.splashLight, + // splashColor: Theme.of(context).extension()!.highlight, materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular( @@ -90,7 +90,7 @@ class AdvancedSettingsView extends StatelessWidget { children: [ Text( "Toggle testnet coins", - style: STextStyles.titleBold12, + style: STextStyles.titleBold12(context), textAlign: TextAlign.left, ), SizedBox( diff --git a/lib/pages/settings_views/global_settings_view/advanced_views/debug_view.dart b/lib/pages/settings_views/global_settings_view/advanced_views/debug_view.dart index 73129bfda..6b073ea69 100644 --- a/lib/pages/settings_views/global_settings_view/advanced_views/debug_view.dart +++ b/lib/pages/settings_views/global_settings_view/advanced_views/debug_view.dart @@ -1,3 +1,4 @@ +import 'dart:async'; import 'dart:io'; import 'package:event_bus/event_bus.dart'; @@ -10,11 +11,11 @@ import 'package:stackwallet/models/isar/models/log.dart'; import 'package:stackwallet/notifications/show_flush_bar.dart'; import 'package:stackwallet/providers/global/debug_service_provider.dart'; import 'package:stackwallet/utilities/assets.dart'; -import 'package:stackwallet/utilities/cfcolors.dart'; import 'package:stackwallet/utilities/constants.dart'; import 'package:stackwallet/utilities/enums/flush_bar_type.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/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'; @@ -89,7 +90,7 @@ class _DebugViewState extends ConsumerState { @override Widget build(BuildContext context) { return Scaffold( - backgroundColor: CFColors.almostWhite, + backgroundColor: Theme.of(context).extension()!.background, appBar: AppBar( leading: AppBarBackButton( onPressed: () async { @@ -98,7 +99,7 @@ class _DebugViewState extends ConsumerState { ), title: Text( "Debug", - style: STextStyles.navBarTitle, + style: STextStyles.navBarTitle(context), ), actions: [ Padding( @@ -113,15 +114,17 @@ class _DebugViewState extends ConsumerState { key: const Key("deleteLogsAppBarButtonKey"), size: 36, shadows: const [], - color: CFColors.almostWhite, + color: Theme.of(context).extension()!.background, icon: SvgPicture.asset( Assets.svg.trash, - color: CFColors.stackAccent, + color: Theme.of(context) + .extension()! + .accentColorDark, width: 20, height: 20, ), onPressed: () async { - showDialog( + await showDialog( context: context, builder: (_) => StackDialog( title: "Delete logs?", @@ -129,16 +132,11 @@ class _DebugViewState extends ConsumerState { "You are about to delete all logs permanently. Are you sure?", leftButton: TextButton( style: Theme.of(context) - .textButtonTheme - .style - ?.copyWith( - backgroundColor: MaterialStateProperty.all( - CFColors.buttonGray, - ), - ), + .extension()! + .getSecondaryEnabledButtonColor(context), child: Text( "Cancel", - style: STextStyles.itemSubtitle12, + style: STextStyles.itemSubtitle12(context), ), onPressed: () { Navigator.of(context).pop(); @@ -146,22 +144,17 @@ class _DebugViewState extends ConsumerState { ), rightButton: TextButton( style: Theme.of(context) - .textButtonTheme - .style - ?.copyWith( - backgroundColor: MaterialStateProperty.all( - CFColors.stackAccent, - ), - ), + .extension()! + .getPrimaryEnabledButtonColor(context), child: Text( "Delete logs", - style: STextStyles.button, + style: STextStyles.button(context), ), onPressed: () async { Navigator.of(context).pop(); bool shouldPop = false; - showDialog( + unawaited(showDialog( barrierDismissible: false, context: context, builder: (_) => WillPopScope( @@ -169,24 +162,27 @@ class _DebugViewState extends ConsumerState { return shouldPop; }, child: const CustomLoadingOverlay( - message: "Generating Stack logs file", + message: "Deleting logs...", eventBus: null, ), ), - ); + )); await ref .read(debugServiceProvider) .deleteAllMessages(); + await ref + .read(debugServiceProvider) + .updateRecentLogs(); shouldPop = true; if (mounted) { Navigator.pop(context); - showFloatingFlushBar( + unawaited(showFloatingFlushBar( type: FlushBarType.info, context: context, - message: 'Logs cleared!'); + message: 'Logs cleared!')); } }, ), @@ -226,10 +222,11 @@ class _DebugViewState extends ConsumerState { onChanged: (newString) { setState(() => _searchTerm = newString); }, - style: STextStyles.field, + style: STextStyles.field(context), decoration: standardInputDecoration( "Search", _searchFocusNode, + context, ).copyWith( prefixIcon: Padding( padding: const EdgeInsets.symmetric( @@ -317,7 +314,7 @@ class _DebugViewState extends ConsumerState { if (path != null) { final eventBus = EventBus(); bool shouldPop = false; - showDialog( + unawaited(showDialog( barrierDismissible: false, context: context, builder: (_) => WillPopScope( @@ -329,7 +326,7 @@ class _DebugViewState extends ConsumerState { eventBus: eventBus, ), ), - ); + )); await ref .read(debugServiceProvider) @@ -339,10 +336,10 @@ class _DebugViewState extends ConsumerState { if (mounted) { Navigator.pop(context); - showFloatingFlushBar( + unawaited(showFloatingFlushBar( type: FlushBarType.info, context: context, - message: 'Logs file saved'); + message: 'Logs file saved')); } } }, @@ -383,14 +380,18 @@ class _DebugViewState extends ConsumerState { return Container( key: Key("log_${log.id}_${log.timestampInMillisUTC}"), decoration: BoxDecoration( - color: CFColors.white, + color: Theme.of(context) + .extension()! + .popupBG, borderRadius: _borderRadius(index, logs.length), ), child: Padding( padding: const EdgeInsets.all(4), child: RoundedContainer( padding: const EdgeInsets.all(0), - color: CFColors.white, + color: Theme.of(context) + .extension()! + .popupBG, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ @@ -398,24 +399,35 @@ class _DebugViewState extends ConsumerState { children: [ Text( " [${log.logLevel.name}]", - style: STextStyles.baseXS.copyWith( + style: STextStyles.baseXS(context) + .copyWith( fontSize: 8, color: (log.logLevel == LogLevel.Info - ? CFColors.stackGreen + ? Theme.of(context) + .extension()! + .topNavIconGreen : (log.logLevel == LogLevel.Warning - ? CFColors.stackYellow + ? Theme.of(context) + .extension()! + .topNavIconYellow : (log.logLevel == LogLevel.Error ? Colors.orange - : CFColors.stackRed))), + : Theme.of(context) + .extension< + StackColors>()! + .topNavIconRed))), ), ), Text( "[${DateTime.fromMillisecondsSinceEpoch(log.timestampInMillisUTC, isUtc: true)}]: ", - style: STextStyles.baseXS.copyWith( + style: STextStyles.baseXS(context) + .copyWith( fontSize: 8, - color: CFColors.neutral50, + color: Theme.of(context) + .extension()! + .textDark3, ), ), ], @@ -434,7 +446,7 @@ class _DebugViewState extends ConsumerState { children: [ SelectableText( log.message, - style: STextStyles.baseXS + style: STextStyles.baseXS(context) .copyWith(fontSize: 8), ), ], diff --git a/lib/pages/settings_views/global_settings_view/appearance_settings_view.dart b/lib/pages/settings_views/global_settings_view/appearance_settings_view.dart index 4bb213972..b0cf35a84 100644 --- a/lib/pages/settings_views/global_settings_view/appearance_settings_view.dart +++ b/lib/pages/settings_views/global_settings_view/appearance_settings_view.dart @@ -1,9 +1,14 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:stackwallet/hive/db.dart'; import 'package:stackwallet/providers/providers.dart'; -import 'package:stackwallet/utilities/cfcolors.dart'; +import 'package:stackwallet/providers/ui/color_theme_provider.dart'; import 'package:stackwallet/utilities/constants.dart'; import 'package:stackwallet/utilities/text_styles.dart'; +import 'package:stackwallet/utilities/theme/color_theme.dart'; +import 'package:stackwallet/utilities/theme/dark_colors.dart'; +import 'package:stackwallet/utilities/theme/light_colors.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/draggable_switch_button.dart'; import 'package:stackwallet/widgets/rounded_white_container.dart'; @@ -16,7 +21,7 @@ class AppearanceSettingsView extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { return Scaffold( - backgroundColor: CFColors.almostWhite, + backgroundColor: Theme.of(context).extension()!.background, appBar: AppBar( leading: AppBarBackButton( onPressed: () async { @@ -25,7 +30,7 @@ class AppearanceSettingsView extends ConsumerWidget { ), title: Text( "Appearance", - style: STextStyles.navBarTitle, + style: STextStyles.navBarTitle(context), ), ), body: Padding( @@ -45,7 +50,9 @@ class AppearanceSettingsView extends ConsumerWidget { child: Consumer( builder: (_, ref, __) { return RawMaterialButton( - splashColor: CFColors.splashLight, + splashColor: Theme.of(context) + .extension()! + .highlight, materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, shape: RoundedRectangleBorder( @@ -63,7 +70,7 @@ class AppearanceSettingsView extends ConsumerWidget { children: [ Text( "Display favorite wallets", - style: STextStyles.titleBold12, + style: STextStyles.titleBold12(context), textAlign: TextAlign.left, ), SizedBox( @@ -89,6 +96,71 @@ class AppearanceSettingsView extends ConsumerWidget { }, ), ), + const SizedBox( + height: 10, + ), + RoundedWhiteContainer( + child: Consumer( + builder: (_, ref, __) { + return RawMaterialButton( + splashColor: Theme.of(context) + .extension()! + .highlight, + materialTapTargetSize: + MaterialTapTargetSize.shrinkWrap, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular( + Constants.size.circularBorderRadius, + ), + ), + onPressed: null, + child: Padding( + padding: + const EdgeInsets.symmetric(vertical: 8), + child: Row( + mainAxisAlignment: + MainAxisAlignment.spaceBetween, + children: [ + Text( + "Enable dark mode", + style: STextStyles.titleBold12(context), + textAlign: TextAlign.left, + ), + SizedBox( + height: 20, + width: 40, + child: DraggableSwitchButton( + isOn: (DB.instance.get( + boxName: DB.boxNameTheme, + key: "colorScheme") + as String?) == + "dark", + onValueChanged: (newValue) { + DB.instance.put( + boxName: DB.boxNameTheme, + key: "colorScheme", + value: (newValue + ? ThemeType.dark + : ThemeType.light) + .name, + ); + ref + .read(colorThemeProvider.state) + .state = + StackColors.fromStackColorTheme( + newValue + ? DarkColors() + : LightColors()); + }, + ), + ) + ], + ), + ), + ); + }, + ), + ), ], ), ), diff --git a/lib/pages/settings_views/global_settings_view/currency_view.dart b/lib/pages/settings_views/global_settings_view/currency_view.dart index 7cb3c51e2..cae947caa 100644 --- a/lib/pages/settings_views/global_settings_view/currency_view.dart +++ b/lib/pages/settings_views/global_settings_view/currency_view.dart @@ -4,9 +4,9 @@ import 'package:flutter_svg/svg.dart'; import 'package:stackwallet/providers/global/base_currencies_provider.dart'; import 'package:stackwallet/providers/providers.dart'; import 'package:stackwallet/utilities/assets.dart'; -import 'package:stackwallet/utilities/cfcolors.dart'; 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/icon_widgets/x_icon.dart'; import 'package:stackwallet/widgets/rounded_container.dart'; @@ -101,7 +101,7 @@ class _CurrencyViewState extends ConsumerState { } currenciesWithoutSelected = _filtered(); return Scaffold( - backgroundColor: CFColors.almostWhite, + backgroundColor: Theme.of(context).extension()!.background, appBar: AppBar( leading: AppBarBackButton( onPressed: () async { @@ -116,7 +116,7 @@ class _CurrencyViewState extends ConsumerState { ), title: Text( "Currency", - style: STextStyles.navBarTitle, + style: STextStyles.navBarTitle(context), ), ), body: Padding( @@ -145,10 +145,11 @@ class _CurrencyViewState extends ConsumerState { onChanged: (newString) { setState(() => filter = newString); }, - style: STextStyles.field, + style: STextStyles.field(context), decoration: standardInputDecoration( "Search", _searchFocusNode, + context, ).copyWith( prefixIcon: Padding( padding: const EdgeInsets.symmetric( @@ -203,7 +204,9 @@ class _CurrencyViewState extends ConsumerState { (context, index) { return Container( decoration: BoxDecoration( - color: CFColors.white, + color: Theme.of(context) + .extension()! + .popupBG, borderRadius: _borderRadius(index), ), child: Padding( @@ -213,8 +216,12 @@ class _CurrencyViewState extends ConsumerState { child: RoundedContainer( padding: const EdgeInsets.all(0), color: currenciesWithoutSelected[index] == current - ? CFColors.selected - : CFColors.white, + ? Theme.of(context) + .extension()! + .currencyListItemBG + : Theme.of(context) + .extension()! + .popupBG, child: RawMaterialButton( onPressed: () async { onTap(index); @@ -234,7 +241,9 @@ class _CurrencyViewState extends ConsumerState { width: 20, height: 20, child: Radio( - activeColor: CFColors.link2, + activeColor: Theme.of(context) + .extension()! + .radioButtonIconEnabled, materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, value: true, @@ -261,7 +270,8 @@ class _CurrencyViewState extends ConsumerState { ? const Key( "selectedCurrencySettingsCurrencyText") : null, - style: STextStyles.largeMedium14, + style: STextStyles.largeMedium14( + context), ), const SizedBox( height: 2, @@ -279,7 +289,8 @@ class _CurrencyViewState extends ConsumerState { ? const Key( "selectedCurrencySettingsCurrencyTextDescription") : null, - style: STextStyles.itemSubtitle, + style: STextStyles.itemSubtitle( + context), ), ], ), diff --git a/lib/pages/settings_views/global_settings_view/global_settings_view.dart b/lib/pages/settings_views/global_settings_view/global_settings_view.dart index 2f52b9c37..1b334cf18 100644 --- a/lib/pages/settings_views/global_settings_view/global_settings_view.dart +++ b/lib/pages/settings_views/global_settings_view/global_settings_view.dart @@ -15,8 +15,8 @@ import 'package:stackwallet/pages/settings_views/global_settings_view/syncing_pr import 'package:stackwallet/pages/settings_views/sub_widgets/settings_list_button.dart'; import 'package:stackwallet/route_generator.dart'; import 'package:stackwallet/utilities/assets.dart'; -import 'package:stackwallet/utilities/cfcolors.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/rounded_white_container.dart'; @@ -31,7 +31,7 @@ class GlobalSettingsView extends StatelessWidget { Widget build(BuildContext context) { debugPrint("BUILD: $runtimeType"); return Scaffold( - backgroundColor: CFColors.almostWhite, + backgroundColor: Theme.of(context).extension()!.background, appBar: AppBar( leading: AppBarBackButton( onPressed: () { @@ -40,7 +40,7 @@ class GlobalSettingsView extends StatelessWidget { ), title: Text( "Settings", - style: STextStyles.navBarTitle, + style: STextStyles.navBarTitle(context), ), ), body: LayoutBuilder( @@ -231,12 +231,12 @@ class GlobalSettingsView extends StatelessWidget { // ?.copyWith( // backgroundColor: // MaterialStateProperty.all( - // CFColors.stackAccent, + // Theme.of(context).extension()!.accentColorDark // ), // ), // child: Text( // "fire test notification", - // style: STextStyles.button, + // style: STextStyles.button(context), // ), // onPressed: () async { // NotificationApi.showNotification2( diff --git a/lib/pages/settings_views/global_settings_view/hidden_settings.dart b/lib/pages/settings_views/global_settings_view/hidden_settings.dart index 43929b94f..6b6377ab6 100644 --- a/lib/pages/settings_views/global_settings_view/hidden_settings.dart +++ b/lib/pages/settings_views/global_settings_view/hidden_settings.dart @@ -5,9 +5,9 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:stackwallet/notifications/show_flush_bar.dart'; import 'package:stackwallet/providers/global/debug_service_provider.dart'; import 'package:stackwallet/providers/providers.dart'; -import 'package:stackwallet/utilities/cfcolors.dart'; import 'package:stackwallet/utilities/enums/flush_bar_type.dart'; import 'package:stackwallet/utilities/text_styles.dart'; +import 'package:stackwallet/utilities/theme/stack_colors.dart'; import 'package:stackwallet/widgets/rounded_white_container.dart'; class HiddenSettings extends StatelessWidget { @@ -18,12 +18,12 @@ class HiddenSettings extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( - backgroundColor: CFColors.almostWhite, + backgroundColor: Theme.of(context).extension()!.background, appBar: AppBar( leading: Container(), title: Text( "Not so secret anymore", - style: STextStyles.navBarTitle, + style: STextStyles.navBarTitle(context), ), ), body: Padding( @@ -63,9 +63,10 @@ class HiddenSettings extends StatelessWidget { child: RoundedWhiteContainer( child: Text( "Delete notifications", - style: STextStyles.button.copyWith( - color: CFColors.stackAccent, - ), + style: STextStyles.button(context).copyWith( + color: Theme.of(context) + .extension()! + .accentColorDark), ), ), ); @@ -91,8 +92,8 @@ class HiddenSettings extends StatelessWidget { // child: RoundedWhiteContainer( // child: Text( // "Delete trade history", - // style: STextStyles.button.copyWith( - // color: CFColors.stackAccent, + // style: STextStyles.button(context).copyWith( + // color: Theme.of(context).extension()!.accentColorDark // ), // ), // ), @@ -117,9 +118,10 @@ class HiddenSettings extends StatelessWidget { child: RoundedWhiteContainer( child: Text( "Delete Debug Logs", - style: STextStyles.button.copyWith( - color: CFColors.stackAccent, - ), + style: STextStyles.button(context).copyWith( + color: Theme.of(context) + .extension()! + .accentColorDark), ), ), ); @@ -146,8 +148,8 @@ class HiddenSettings extends StatelessWidget { // child: RoundedWhiteContainer( // child: Text( // "Lottie test", - // style: STextStyles.button.copyWith( - // color: CFColors.stackAccent, + // style: STextStyles.button(context).copyWith( + // color: Theme.of(context).extension()!.accentColorDark // ), // ), // ), diff --git a/lib/pages/settings_views/global_settings_view/language_view.dart b/lib/pages/settings_views/global_settings_view/language_view.dart index e9941b82a..75a2751a2 100644 --- a/lib/pages/settings_views/global_settings_view/language_view.dart +++ b/lib/pages/settings_views/global_settings_view/language_view.dart @@ -3,10 +3,10 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_svg/svg.dart'; import 'package:stackwallet/providers/providers.dart'; import 'package:stackwallet/utilities/assets.dart'; -import 'package:stackwallet/utilities/cfcolors.dart'; import 'package:stackwallet/utilities/constants.dart'; import 'package:stackwallet/utilities/enums/languages_enum.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/icon_widgets/x_icon.dart'; import 'package:stackwallet/widgets/rounded_container.dart'; @@ -99,7 +99,7 @@ class _LanguageViewState extends ConsumerState { } listWithoutSelected = _filtered(); return Scaffold( - backgroundColor: CFColors.almostWhite, + backgroundColor: Theme.of(context).extension()!.background, appBar: AppBar( leading: AppBarBackButton( onPressed: () async { @@ -114,7 +114,7 @@ class _LanguageViewState extends ConsumerState { ), title: Text( "Language", - style: STextStyles.navBarTitle, + style: STextStyles.navBarTitle(context), ), ), body: Padding( @@ -143,10 +143,11 @@ class _LanguageViewState extends ConsumerState { onChanged: (newString) { setState(() => filter = newString); }, - style: STextStyles.field, + style: STextStyles.field(context), decoration: standardInputDecoration( "Search", _searchFocusNode, + context, ).copyWith( prefixIcon: Padding( padding: const EdgeInsets.symmetric( @@ -201,7 +202,9 @@ class _LanguageViewState extends ConsumerState { (context, index) { return Container( decoration: BoxDecoration( - color: CFColors.white, + color: Theme.of(context) + .extension()! + .popupBG, borderRadius: _borderRadius(index), ), child: Padding( @@ -211,8 +214,12 @@ class _LanguageViewState extends ConsumerState { child: RoundedContainer( padding: const EdgeInsets.all(0), color: index == 0 - ? CFColors.selected - : CFColors.white, + ? Theme.of(context) + .extension()! + .currencyListItemBG + : Theme.of(context) + .extension()! + .popupBG, child: RawMaterialButton( onPressed: () async { onTap(index); @@ -232,7 +239,9 @@ class _LanguageViewState extends ConsumerState { width: 20, height: 20, child: Radio( - activeColor: CFColors.link2, + activeColor: Theme.of(context) + .extension()! + .radioButtonIconEnabled, value: true, groupValue: index == 0, onChanged: (_) { @@ -253,7 +262,8 @@ class _LanguageViewState extends ConsumerState { ? const Key( "selectedLanguageSettingsLanguageText") : null, - style: STextStyles.largeMedium14, + style: STextStyles.largeMedium14( + context), ), const SizedBox( height: 2, @@ -264,7 +274,8 @@ class _LanguageViewState extends ConsumerState { ? const Key( "selectedLanguageSettingsLanguageTextDescription") : null, - style: STextStyles.itemSubtitle, + style: STextStyles.itemSubtitle( + context), ), ], ), diff --git a/lib/pages/settings_views/global_settings_view/manage_nodes_views/add_edit_node_view.dart b/lib/pages/settings_views/global_settings_view/manage_nodes_views/add_edit_node_view.dart index 0d1ce7ad8..0cf3ebc4f 100644 --- a/lib/pages/settings_views/global_settings_view/manage_nodes_views/add_edit_node_view.dart +++ b/lib/pages/settings_views/global_settings_view/manage_nodes_views/add_edit_node_view.dart @@ -11,7 +11,6 @@ import 'package:stackwallet/notifications/show_flush_bar.dart'; import 'package:stackwallet/providers/global/node_service_provider.dart'; import 'package:stackwallet/providers/providers.dart'; import 'package:stackwallet/utilities/assets.dart'; -import 'package:stackwallet/utilities/cfcolors.dart'; import 'package:stackwallet/utilities/constants.dart'; import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/enums/flush_bar_type.dart'; @@ -20,6 +19,7 @@ import 'package:stackwallet/utilities/logger.dart'; import 'package:stackwallet/utilities/test_epic_box_connection.dart'; import 'package:stackwallet/utilities/test_monero_node_connection.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/icon_widgets/x_icon.dart'; import 'package:stackwallet/widgets/stack_dialog.dart'; @@ -113,9 +113,12 @@ class _AddEditNodeViewState extends ConsumerState { break; case Coin.bitcoin: + // case Coin.bitcoincash: case Coin.dogecoin: case Coin.firo: + case Coin.namecoin: case Coin.bitcoinTestNet: + // case Coin.bitcoincashTestnet: case Coin.firoTestNet: case Coin.dogecoinTestNet: final client = ElectrumX( @@ -137,17 +140,17 @@ class _AddEditNodeViewState extends ConsumerState { if (showFlushBar) { if (testPassed) { - showFloatingFlushBar( + unawaited(showFloatingFlushBar( type: FlushBarType.success, message: "Server ping success", context: context, - ); + )); } else { - showFloatingFlushBar( + unawaited(showFloatingFlushBar( type: FlushBarType.warning, message: "Server unreachable", context: context, - ); + )); } } @@ -189,7 +192,7 @@ class _AddEditNodeViewState extends ConsumerState { : null; return Scaffold( - backgroundColor: CFColors.almostWhite, + backgroundColor: Theme.of(context).extension()!.background, appBar: AppBar( leading: AppBarBackButton( onPressed: () async { @@ -204,7 +207,7 @@ class _AddEditNodeViewState extends ConsumerState { ), title: Text( viewType == AddEditNodeViewType.edit ? "Edit node" : "Add node", - style: STextStyles.navBarTitle, + style: STextStyles.navBarTitle(context), ), actions: [ if (viewType == AddEditNodeViewType.edit) @@ -220,10 +223,12 @@ class _AddEditNodeViewState extends ConsumerState { key: const Key("deleteNodeAppBarButtonKey"), size: 36, shadows: const [], - color: CFColors.almostWhite, + color: Theme.of(context).extension()!.background, icon: SvgPicture.asset( Assets.svg.trash, - color: CFColors.stackAccent, + color: Theme.of(context) + .extension()! + .accentColorDark, width: 20, height: 20, ), @@ -290,31 +295,31 @@ class _AddEditNodeViewState extends ConsumerState { await _testConnection(); } : null, - style: ButtonStyle( - backgroundColor: MaterialStateProperty.all( - CFColors.buttonGray, - ), - ), + style: Theme.of(context) + .extension()! + .getSecondaryEnabledButtonColor(context), child: Text( "Test connection", - style: STextStyles.button.copyWith( + style: STextStyles.button(context).copyWith( color: testConnectionEnabled - ? CFColors.stackAccent - : CFColors.white, + ? Theme.of(context) + .extension()! + .textDark + : Theme.of(context) + .extension()! + .textWhite, ), ), ), const SizedBox(height: 16), TextButton( - style: - Theme.of(context).textButtonTheme.style?.copyWith( - backgroundColor: - MaterialStateProperty.all( - saveEnabled - ? CFColors.stackAccent - : CFColors.disabledButton, - ), - ), + style: saveEnabled + ? Theme.of(context) + .extension()! + .getPrimaryEnabledButtonColor(context) + : Theme.of(context) + .extension()! + .getPrimaryDisabledButtonColor(context), onPressed: saveEnabled ? () async { final canConnect = await _testConnection( @@ -337,9 +342,12 @@ class _AddEditNodeViewState extends ConsumerState { }, child: Text( "Cancel", - style: STextStyles.button.copyWith( - color: CFColors.stackAccent, - ), + style: STextStyles.button(context) + .copyWith( + color: Theme.of(context) + .extension< + StackColors>()! + .accentColorDark), ), ), rightButton: TextButton( @@ -347,18 +355,12 @@ class _AddEditNodeViewState extends ConsumerState { Navigator.of(context).pop(true); }, style: Theme.of(context) - .textButtonTheme - .style - ?.copyWith( - backgroundColor: - MaterialStateProperty.all< - Color>( - CFColors.stackAccent, - ), - ), + .extension()! + .getPrimaryEnabledButtonColor( + context), child: Text( "Save", - style: STextStyles.button, + style: STextStyles.button(context), ), ), ), @@ -451,7 +453,7 @@ class _AddEditNodeViewState extends ConsumerState { : null, child: Text( "Save", - style: STextStyles.button, + style: STextStyles.button(context), ), ), ], @@ -527,7 +529,10 @@ class _NodeFormState extends ConsumerState { case Coin.bitcoin: case Coin.dogecoin: case Coin.firo: + case Coin.namecoin: + // case Coin.bitcoincash: case Coin.bitcoinTestNet: + // case Coin.bitcoincashTestnet: case Coin.firoTestNet: case Coin.dogecoinTestNet: return false; @@ -645,10 +650,11 @@ class _NodeFormState extends ConsumerState { enabled: enableField(_nameController), controller: _nameController, focusNode: _nameFocusNode, - style: STextStyles.field, + style: STextStyles.field(context), decoration: standardInputDecoration( "Node name", _nameFocusNode, + context, ).copyWith( suffixIcon: !widget.readOnly && _nameController.text.isNotEmpty ? Padding( @@ -691,12 +697,13 @@ class _NodeFormState extends ConsumerState { enabled: enableField(_hostController), controller: _hostController, focusNode: _hostFocusNode, - style: STextStyles.field, + style: STextStyles.field(context), decoration: standardInputDecoration( (widget.coin != Coin.monero && widget.coin != Coin.epicCash) ? "IP address" : "Url", _hostFocusNode, + context, ).copyWith( suffixIcon: !widget.readOnly && _hostController.text.isNotEmpty @@ -741,10 +748,11 @@ class _NodeFormState extends ConsumerState { focusNode: _portFocusNode, inputFormatters: [FilteringTextInputFormatter.digitsOnly], keyboardType: TextInputType.number, - style: STextStyles.field, + style: STextStyles.field(context), decoration: standardInputDecoration( "Port", _portFocusNode, + context, ).copyWith( suffixIcon: !widget.readOnly && _portController.text.isNotEmpty @@ -789,10 +797,11 @@ class _NodeFormState extends ConsumerState { enabled: enableField(_usernameController), keyboardType: TextInputType.number, focusNode: _usernameFocusNode, - style: STextStyles.field, + style: STextStyles.field(context), decoration: standardInputDecoration( "Login (optional)", _usernameFocusNode, + context, ).copyWith( suffixIcon: !widget.readOnly && _usernameController.text.isNotEmpty @@ -835,10 +844,11 @@ class _NodeFormState extends ConsumerState { enabled: enableField(_passwordController), keyboardType: TextInputType.number, focusNode: _passwordFocusNode, - style: STextStyles.field, + style: STextStyles.field(context), decoration: standardInputDecoration( "Password (optional)", _passwordFocusNode, + context, ).copyWith( suffixIcon: !widget.readOnly && _passwordController.text.isNotEmpty @@ -891,8 +901,9 @@ class _NodeFormState extends ConsumerState { height: 20, child: Checkbox( fillColor: widget.readOnly - ? MaterialStateProperty.all( - CFColors.disabledButton) + ? MaterialStateProperty.all(Theme.of(context) + .extension()! + .checkboxBGDisabled) : null, materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, @@ -912,7 +923,7 @@ class _NodeFormState extends ConsumerState { ), Text( "Use SSL", - style: STextStyles.itemSubtitle12, + style: STextStyles.itemSubtitle12(context), ) ], ), @@ -975,7 +986,7 @@ class _NodeFormState extends ConsumerState { ), Text( "Use as failover", - style: STextStyles.itemSubtitle12, + style: STextStyles.itemSubtitle12(context), ) ], ), diff --git a/lib/pages/settings_views/global_settings_view/manage_nodes_views/coin_nodes_view.dart b/lib/pages/settings_views/global_settings_view/manage_nodes_views/coin_nodes_view.dart index e4b28db78..12573042e 100644 --- a/lib/pages/settings_views/global_settings_view/manage_nodes_views/coin_nodes_view.dart +++ b/lib/pages/settings_views/global_settings_view/manage_nodes_views/coin_nodes_view.dart @@ -4,9 +4,9 @@ import 'package:flutter_svg/svg.dart'; import 'package:stackwallet/pages/settings_views/global_settings_view/manage_nodes_views/add_edit_node_view.dart'; import 'package:stackwallet/pages/settings_views/sub_widgets/nodes_list.dart'; import 'package:stackwallet/utilities/assets.dart'; -import 'package:stackwallet/utilities/cfcolors.dart'; import 'package:stackwallet/utilities/enums/coin_enum.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:tuple/tuple.dart'; @@ -38,7 +38,7 @@ class _CoinNodesViewState extends ConsumerState { @override Widget build(BuildContext context) { return Scaffold( - backgroundColor: CFColors.almostWhite, + backgroundColor: Theme.of(context).extension()!.background, appBar: AppBar( leading: AppBarBackButton( onPressed: () { @@ -47,7 +47,7 @@ class _CoinNodesViewState extends ConsumerState { ), title: Text( "${widget.coin.prettyName} nodes", - style: STextStyles.navBarTitle, + style: STextStyles.navBarTitle(context), ), actions: [ Padding( @@ -62,10 +62,12 @@ class _CoinNodesViewState extends ConsumerState { key: const Key("manageNodesAddNewNodeButtonKey"), size: 36, shadows: const [], - color: CFColors.almostWhite, + color: Theme.of(context).extension()!.background, icon: SvgPicture.asset( Assets.svg.plus, - color: CFColors.stackAccent, + color: Theme.of(context) + .extension()! + .accentColorDark, width: 20, height: 20, ), diff --git a/lib/pages/settings_views/global_settings_view/manage_nodes_views/manage_nodes_view.dart b/lib/pages/settings_views/global_settings_view/manage_nodes_views/manage_nodes_view.dart index 09b3ac752..22f239232 100644 --- a/lib/pages/settings_views/global_settings_view/manage_nodes_views/manage_nodes_view.dart +++ b/lib/pages/settings_views/global_settings_view/manage_nodes_views/manage_nodes_view.dart @@ -4,10 +4,10 @@ import 'package:flutter_svg/svg.dart'; import 'package:stackwallet/pages/settings_views/global_settings_view/manage_nodes_views/coin_nodes_view.dart'; import 'package:stackwallet/providers/providers.dart'; import 'package:stackwallet/utilities/assets.dart'; -import 'package:stackwallet/utilities/cfcolors.dart'; import 'package:stackwallet/utilities/constants.dart'; import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/text_styles.dart'; +import 'package:stackwallet/utilities/theme/stack_colors.dart'; import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart'; import 'package:stackwallet/widgets/rounded_white_container.dart'; @@ -45,10 +45,10 @@ class _ManageNodesViewState extends ConsumerState { List coins = showTestNet ? _coins - : _coins.sublist(0, Coin.values.length - kTestNetCoinCount); + : _coins.sublist(0, _coins.length - kTestNetCoinCount); return Scaffold( - backgroundColor: CFColors.almostWhite, + backgroundColor: Theme.of(context).extension()!.background, appBar: AppBar( leading: AppBarBackButton( onPressed: () { @@ -57,7 +57,7 @@ class _ManageNodesViewState extends ConsumerState { ), title: Text( "Manage nodes", - style: STextStyles.navBarTitle, + style: STextStyles.navBarTitle(context), ), ), body: Padding( @@ -82,7 +82,7 @@ class _ManageNodesViewState extends ConsumerState { child: RoundedWhiteContainer( padding: const EdgeInsets.all(0), child: RawMaterialButton( - // splashColor: CFColors.splashLight, + // splashColor: Theme.of(context).extension()!.highlight, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular( Constants.size.circularBorderRadius, @@ -112,11 +112,11 @@ class _ManageNodesViewState extends ConsumerState { children: [ Text( "${coin.prettyName} nodes", - style: STextStyles.titleBold12, + style: STextStyles.titleBold12(context), ), Text( count > 1 ? "$count nodes" : "Default", - style: STextStyles.label, + style: STextStyles.label(context), ), ], ) diff --git a/lib/pages/settings_views/global_settings_view/manage_nodes_views/node_details_view.dart b/lib/pages/settings_views/global_settings_view/manage_nodes_views/node_details_view.dart index a188acc01..377905630 100644 --- a/lib/pages/settings_views/global_settings_view/manage_nodes_views/node_details_view.dart +++ b/lib/pages/settings_views/global_settings_view/manage_nodes_views/node_details_view.dart @@ -7,10 +7,8 @@ import 'package:flutter_svg/svg.dart'; import 'package:stackwallet/electrumx_rpc/electrumx.dart'; import 'package:stackwallet/notifications/show_flush_bar.dart'; import 'package:stackwallet/pages/settings_views/global_settings_view/manage_nodes_views/add_edit_node_view.dart'; -import 'package:stackwallet/providers/global/node_service_provider.dart'; import 'package:stackwallet/providers/providers.dart'; import 'package:stackwallet/utilities/assets.dart'; -import 'package:stackwallet/utilities/cfcolors.dart'; import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/enums/flush_bar_type.dart'; import 'package:stackwallet/utilities/flutter_secure_storage_interface.dart'; @@ -18,6 +16,7 @@ import 'package:stackwallet/utilities/logger.dart'; import 'package:stackwallet/utilities/test_epic_box_connection.dart'; import 'package:stackwallet/utilities/test_monero_node_connection.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:tuple/tuple.dart'; @@ -103,6 +102,9 @@ class _NodeDetailsViewState extends ConsumerState { case Coin.bitcoinTestNet: case Coin.firoTestNet: case Coin.dogecoinTestNet: + // case Coin.bitcoincash: + case Coin.namecoin: + // case Coin.bitcoincashTestnet: final client = ElectrumX( host: node!.host, port: node.port, @@ -138,7 +140,7 @@ class _NodeDetailsViewState extends ConsumerState { @override Widget build(BuildContext context) { return Scaffold( - backgroundColor: CFColors.almostWhite, + backgroundColor: Theme.of(context).extension()!.background, appBar: AppBar( leading: AppBarBackButton( onPressed: () async { @@ -153,7 +155,7 @@ class _NodeDetailsViewState extends ConsumerState { ), title: Text( "Node details", - style: STextStyles.navBarTitle, + style: STextStyles.navBarTitle(context), ), actions: [ if (!nodeId.startsWith("default")) @@ -169,10 +171,12 @@ class _NodeDetailsViewState extends ConsumerState { key: const Key("nodeDetailsEditNodeAppBarButtonKey"), size: 36, shadows: const [], - color: CFColors.almostWhite, + color: Theme.of(context).extension()!.background, icon: SvgPicture.asset( Assets.svg.pencil, - color: CFColors.stackAccent, + color: Theme.of(context) + .extension()! + .accentColorDark, width: 20, height: 20, ), @@ -221,19 +225,18 @@ class _NodeDetailsViewState extends ConsumerState { ), const Spacer(), TextButton( - style: ButtonStyle( - backgroundColor: MaterialStateProperty.all( - CFColors.buttonGray, - ), - ), + style: Theme.of(context) + .extension()! + .getSecondaryEnabledButtonColor(context), onPressed: () async { await _testConnection(ref, context); }, child: Text( "Test connection", - style: STextStyles.button.copyWith( - color: CFColors.stackAccent, - ), + style: STextStyles.button(context).copyWith( + color: Theme.of(context) + .extension()! + .accentColorDark), ), ), const SizedBox(height: 16), diff --git a/lib/pages/settings_views/global_settings_view/security_views/change_pin_view/change_pin_view.dart b/lib/pages/settings_views/global_settings_view/security_views/change_pin_view/change_pin_view.dart index abb372f8c..f083eb63a 100644 --- a/lib/pages/settings_views/global_settings_view/security_views/change_pin_view/change_pin_view.dart +++ b/lib/pages/settings_views/global_settings_view/security_views/change_pin_view/change_pin_view.dart @@ -4,11 +4,11 @@ import 'package:google_fonts/google_fonts.dart'; import 'package:stackwallet/notifications/show_flush_bar.dart'; import 'package:stackwallet/pages/settings_views/global_settings_view/security_views/security_view.dart'; import 'package:stackwallet/utilities/assets.dart'; -import 'package:stackwallet/utilities/cfcolors.dart'; import 'package:stackwallet/utilities/constants.dart'; import 'package:stackwallet/utilities/enums/flush_bar_type.dart'; import 'package:stackwallet/utilities/flutter_secure_storage_interface.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_pin_put/custom_pin_put.dart'; @@ -31,8 +31,10 @@ class ChangePinView extends StatefulWidget { class _ChangePinViewState extends State { BoxDecoration get _pinPutDecoration { return BoxDecoration( - color: CFColors.gray3, - border: Border.all(width: 1, color: CFColors.gray3), + color: Theme.of(context).extension()!.textSubtitle2, + border: Border.all( + width: 1, + color: Theme.of(context).extension()!.textSubtitle2), borderRadius: BorderRadius.circular(6), ); } @@ -69,7 +71,7 @@ class _ChangePinViewState extends State { @override Widget build(BuildContext context) { return Scaffold( - backgroundColor: CFColors.almostWhite, + backgroundColor: Theme.of(context).extension()!.background, appBar: AppBar( leading: AppBarBackButton( onPressed: () async { @@ -95,7 +97,7 @@ class _ChangePinViewState extends State { Center( child: Text( "Create new PIN", - style: STextStyles.pageTitleH1, + style: STextStyles.pageTitleH1(context), ), ), const SizedBox( @@ -105,28 +107,33 @@ class _ChangePinViewState extends State { fieldsCount: Constants.pinLength, eachFieldHeight: 12, eachFieldWidth: 12, - textStyle: STextStyles.label.copyWith( + textStyle: STextStyles.label(context).copyWith( fontSize: 1, ), focusNode: _pinPutFocusNode1, controller: _pinPutController1, useNativeKeyboard: false, obscureText: "", - inputDecoration: const InputDecoration( + inputDecoration: InputDecoration( border: InputBorder.none, enabledBorder: InputBorder.none, focusedBorder: InputBorder.none, disabledBorder: InputBorder.none, errorBorder: InputBorder.none, focusedErrorBorder: InputBorder.none, - fillColor: CFColors.almostWhite, + fillColor: + Theme.of(context).extension()!.background, counterText: "", ), submittedFieldDecoration: _pinPutDecoration.copyWith( - color: CFColors.link2, + color: Theme.of(context) + .extension()! + .infoItemIcons, border: Border.all( width: 1, - color: CFColors.link2, + color: Theme.of(context) + .extension()! + .infoItemIcons, ), ), selectedFieldDecoration: _pinPutDecoration, @@ -151,7 +158,7 @@ class _ChangePinViewState extends State { Center( child: Text( "Confirm new PIN", - style: STextStyles.pageTitleH1, + style: STextStyles.pageTitleH1(context), ), ), const SizedBox( @@ -168,21 +175,26 @@ class _ChangePinViewState extends State { controller: _pinPutController2, useNativeKeyboard: false, obscureText: "", - inputDecoration: const InputDecoration( + inputDecoration: InputDecoration( border: InputBorder.none, enabledBorder: InputBorder.none, focusedBorder: InputBorder.none, disabledBorder: InputBorder.none, errorBorder: InputBorder.none, focusedErrorBorder: InputBorder.none, - fillColor: CFColors.almostWhite, + fillColor: + Theme.of(context).extension()!.background, counterText: "", ), submittedFieldDecoration: _pinPutDecoration.copyWith( - color: CFColors.link2, + color: Theme.of(context) + .extension()! + .infoItemIcons, border: Border.all( width: 1, - color: CFColors.link2, + color: Theme.of(context) + .extension()! + .infoItemIcons, ), ), selectedFieldDecoration: _pinPutDecoration, diff --git a/lib/pages/settings_views/global_settings_view/security_views/security_view.dart b/lib/pages/settings_views/global_settings_view/security_views/security_view.dart index 1cb1a6a92..24fce5cd8 100644 --- a/lib/pages/settings_views/global_settings_view/security_views/security_view.dart +++ b/lib/pages/settings_views/global_settings_view/security_views/security_view.dart @@ -4,9 +4,9 @@ import 'package:stackwallet/pages/pinpad_views/lock_screen_view.dart'; import 'package:stackwallet/pages/settings_views/global_settings_view/security_views/change_pin_view/change_pin_view.dart'; import 'package:stackwallet/providers/global/prefs_provider.dart'; import 'package:stackwallet/route_generator.dart'; -import 'package:stackwallet/utilities/cfcolors.dart'; 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/draggable_switch_button.dart'; import 'package:stackwallet/widgets/rounded_white_container.dart'; @@ -23,7 +23,7 @@ class SecurityView extends StatelessWidget { debugPrint("BUILD: $runtimeType"); return Scaffold( - backgroundColor: CFColors.almostWhite, + backgroundColor: Theme.of(context).extension()!.background, appBar: AppBar( leading: AppBarBackButton( onPressed: () { @@ -32,7 +32,7 @@ class SecurityView extends StatelessWidget { ), title: Text( "Security", - style: STextStyles.navBarTitle, + style: STextStyles.navBarTitle(context), ), ), body: Padding( @@ -43,7 +43,7 @@ class SecurityView extends StatelessWidget { RoundedWhiteContainer( padding: const EdgeInsets.all(0), child: RawMaterialButton( - // splashColor: CFColors.splashLight, + // splashColor: Theme.of(context).extension()!.highlight, materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular( @@ -77,7 +77,7 @@ class SecurityView extends StatelessWidget { children: [ Text( "Change PIN", - style: STextStyles.titleBold12, + style: STextStyles.titleBold12(context), textAlign: TextAlign.left, ), ], @@ -92,7 +92,7 @@ class SecurityView extends StatelessWidget { child: Consumer( builder: (_, ref, __) { return RawMaterialButton( - // splashColor: CFColors.splashLight, + // splashColor: Theme.of(context).extension()!.highlight, materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular( @@ -118,7 +118,7 @@ class SecurityView extends StatelessWidget { children: [ Text( "Enable biometric authentication", - style: STextStyles.titleBold12, + style: STextStyles.titleBold12(context), textAlign: TextAlign.left, ), SizedBox( diff --git a/lib/pages/settings_views/global_settings_view/stack_backup_views/auto_backup_view.dart b/lib/pages/settings_views/global_settings_view/stack_backup_views/auto_backup_view.dart index 0b97c5582..3f832a4af 100644 --- a/lib/pages/settings_views/global_settings_view/stack_backup_views/auto_backup_view.dart +++ b/lib/pages/settings_views/global_settings_view/stack_backup_views/auto_backup_view.dart @@ -6,11 +6,11 @@ import 'package:stackwallet/pages/settings_views/global_settings_view/stack_back import 'package:stackwallet/pages/settings_views/global_settings_view/stack_backup_views/edit_auto_backup_view.dart'; import 'package:stackwallet/providers/global/auto_swb_service_provider.dart'; import 'package:stackwallet/providers/providers.dart'; -import 'package:stackwallet/utilities/cfcolors.dart'; import 'package:stackwallet/utilities/constants.dart'; import 'package:stackwallet/utilities/enums/backup_frequency_type.dart'; import 'package:stackwallet/utilities/format.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/custom_buttons/draggable_switch_button.dart'; @@ -81,15 +81,14 @@ class _AutoBackupViewState extends ConsumerState { title: "Enable Auto Backup", message: "To enable Auto Backup, you need to create a backup file.", leftButton: TextButton( - style: Theme.of(context).textButtonTheme.style?.copyWith( - backgroundColor: MaterialStateProperty.all( - CFColors.buttonGray, - ), - ), + style: Theme.of(context) + .extension()! + .getSecondaryEnabledButtonColor(context), child: Text( "Back", - style: STextStyles.button.copyWith( - color: CFColors.stackAccent, + style: STextStyles.button(context).copyWith( + color: + Theme.of(context).extension()!.accentColorDark, ), ), onPressed: () { @@ -97,14 +96,12 @@ class _AutoBackupViewState extends ConsumerState { }, ), rightButton: TextButton( - style: Theme.of(context).textButtonTheme.style?.copyWith( - backgroundColor: MaterialStateProperty.all( - CFColors.stackAccent, - ), - ), + style: Theme.of(context) + .extension()! + .getPrimaryEnabledButtonColor(context), child: Text( "Continue", - style: STextStyles.button, + style: STextStyles.button(context), ), onPressed: () { Navigator.of(context).pop(true); @@ -141,15 +138,14 @@ class _AutoBackupViewState extends ConsumerState { message: "You are turning off Auto Backup. You can turn it back on at any time. Your previous Auto Backup file will not be deleted. Remember to backup your wallets manually so you don't lose important information.", leftButton: TextButton( - style: Theme.of(context).textButtonTheme.style?.copyWith( - backgroundColor: MaterialStateProperty.all( - CFColors.buttonGray, - ), - ), + style: Theme.of(context) + .extension()! + .getSecondaryEnabledButtonColor(context), child: Text( "Back", - style: STextStyles.button.copyWith( - color: CFColors.stackAccent, + style: STextStyles.button(context).copyWith( + color: + Theme.of(context).extension()!.accentColorDark, ), ), onPressed: () { @@ -157,14 +153,12 @@ class _AutoBackupViewState extends ConsumerState { }, ), rightButton: TextButton( - style: Theme.of(context).textButtonTheme.style?.copyWith( - backgroundColor: MaterialStateProperty.all( - CFColors.stackAccent, - ), - ), + style: Theme.of(context) + .extension()! + .getPrimaryEnabledButtonColor(context), child: Text( "Disable", - style: STextStyles.button, + style: STextStyles.button(context), ), onPressed: () { Navigator.of(context).pop(true); @@ -230,7 +224,7 @@ class _AutoBackupViewState extends ConsumerState { }); return Scaffold( - backgroundColor: CFColors.almostWhite, + backgroundColor: Theme.of(context).extension()!.background, appBar: AppBar( leading: AppBarBackButton( onPressed: () { @@ -239,7 +233,7 @@ class _AutoBackupViewState extends ConsumerState { ), title: Text( "Auto Backup", - style: STextStyles.navBarTitle, + style: STextStyles.navBarTitle(context), ), ), body: Padding( @@ -250,7 +244,7 @@ class _AutoBackupViewState extends ConsumerState { RoundedWhiteContainer( padding: const EdgeInsets.all(0), child: RawMaterialButton( - // splashColor: CFColors.splashLight, + // splashColor: Theme.of(context).extension()!.highlight, materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular( @@ -268,7 +262,7 @@ class _AutoBackupViewState extends ConsumerState { children: [ Text( "Auto Backup", - style: STextStyles.titleBold12, + style: STextStyles.titleBold12(context), textAlign: TextAlign.left, ), SizedBox( @@ -302,14 +296,14 @@ class _AutoBackupViewState extends ConsumerState { child: RichText( textAlign: TextAlign.left, text: TextSpan( - style: STextStyles.label, + style: STextStyles.label(context), children: [ const TextSpan( text: "Auto Backup is a custom Stack Wallet feature that offers a convenient backup of your data.\n\nTo ensure maximum security, we recommend using a unique password that you haven't used anywhere else on the internet before. Your password is not stored.\n\nFor more information, please see our website "), TextSpan( text: "stackwallet.com.", - style: STextStyles.richLink, + style: STextStyles.richLink(context), recognizer: TapGestureRecognizer() ..onTap = () { launchUrl( @@ -338,7 +332,7 @@ class _AutoBackupViewState extends ConsumerState { ), Text( "Backed up ${prettySinceLastBackupString(ref.watch(prefsChangeNotifierProvider.select((value) => value.lastAutoBackup)))}", - style: STextStyles.itemSubtitle, + style: STextStyles.itemSubtitle(context), ) ], ), @@ -348,7 +342,7 @@ class _AutoBackupViewState extends ConsumerState { ), Text( "Auto Backup file", - style: STextStyles.smallMed12, + style: STextStyles.smallMed12(context), ), const SizedBox( height: 10, @@ -362,8 +356,11 @@ class _AutoBackupViewState extends ConsumerState { focusNode: fileLocationFocusNode, controller: fileLocationController, enabled: false, - style: STextStyles.field.copyWith( - color: CFColors.stackAccent.withOpacity(0.5), + style: STextStyles.field(context).copyWith( + color: Theme.of(context) + .extension()! + .textDark + .withOpacity(0.5), ), readOnly: true, enableSuggestions: false, @@ -377,6 +374,7 @@ class _AutoBackupViewState extends ConsumerState { decoration: standardInputDecoration( "Saved to", fileLocationFocusNode, + context, ), ), ), @@ -392,8 +390,11 @@ class _AutoBackupViewState extends ConsumerState { focusNode: passwordFocusNode, controller: passwordController, enabled: false, - style: STextStyles.field.copyWith( - color: CFColors.stackAccent.withOpacity(0.5), + style: STextStyles.field(context).copyWith( + color: Theme.of(context) + .extension()! + .textDark + .withOpacity(0.5), ), obscureText: true, enableSuggestions: false, @@ -407,6 +408,7 @@ class _AutoBackupViewState extends ConsumerState { decoration: standardInputDecoration( "Passphrase", passwordFocusNode, + context, ), ), ), @@ -415,7 +417,7 @@ class _AutoBackupViewState extends ConsumerState { ), Text( "Auto Backup frequency", - style: STextStyles.smallMed12, + style: STextStyles.smallMed12(context), ), const SizedBox( height: 10, @@ -424,8 +426,11 @@ class _AutoBackupViewState extends ConsumerState { key: const Key("backupFrequencyFieldKey"), controller: frequencyController, enabled: false, - style: STextStyles.field.copyWith( - color: CFColors.stackAccent.withOpacity(0.5), + style: STextStyles.field(context).copyWith( + color: Theme.of(context) + .extension()! + .textDark + .withOpacity(0.5), ), toolbarOptions: const ToolbarOptions( copy: true, diff --git a/lib/pages/settings_views/global_settings_view/stack_backup_views/create_auto_backup_view.dart b/lib/pages/settings_views/global_settings_view/stack_backup_views/create_auto_backup_view.dart index c711137a1..22ace0a8e 100644 --- a/lib/pages/settings_views/global_settings_view/stack_backup_views/create_auto_backup_view.dart +++ b/lib/pages/settings_views/global_settings_view/stack_backup_views/create_auto_backup_view.dart @@ -14,13 +14,13 @@ import 'package:stackwallet/pages/settings_views/global_settings_view/stack_back import 'package:stackwallet/pages/settings_views/global_settings_view/stack_backup_views/sub_views/backup_frequency_type_select_sheet.dart'; import 'package:stackwallet/providers/global/prefs_provider.dart'; import 'package:stackwallet/utilities/assets.dart'; -import 'package:stackwallet/utilities/cfcolors.dart'; import 'package:stackwallet/utilities/constants.dart'; import 'package:stackwallet/utilities/enums/flush_bar_type.dart'; import 'package:stackwallet/utilities/flutter_secure_storage_interface.dart'; import 'package:stackwallet/utilities/format.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/custom_buttons/app_bar_icon_button.dart'; import 'package:stackwallet/widgets/progress_bar.dart'; import 'package:stackwallet/widgets/stack_dialog.dart'; @@ -102,7 +102,7 @@ class _EnableAutoBackupViewState extends ConsumerState { debugPrint("BUILD: $runtimeType"); return Scaffold( - backgroundColor: CFColors.almostWhite, + backgroundColor: Theme.of(context).extension()!.background, appBar: AppBar( leading: AppBarBackButton( onPressed: () { @@ -111,7 +111,7 @@ class _EnableAutoBackupViewState extends ConsumerState { ), title: Text( "Create Auto Backup", - style: STextStyles.navBarTitle, + style: STextStyles.navBarTitle(context), ), ), body: Padding( @@ -128,7 +128,7 @@ class _EnableAutoBackupViewState extends ConsumerState { children: [ Text( "Create your backup file", - style: STextStyles.smallMed12, + style: STextStyles.smallMed12(context), ), const SizedBox( height: 10, @@ -153,7 +153,7 @@ class _EnableAutoBackupViewState extends ConsumerState { } }, controller: fileLocationController, - style: STextStyles.field, + style: STextStyles.field(context), decoration: InputDecoration( hintText: "Save to...", suffixIcon: UnconstrainedBox( @@ -164,7 +164,9 @@ class _EnableAutoBackupViewState extends ConsumerState { ), SvgPicture.asset( Assets.svg.folder, - color: CFColors.neutral50, + color: Theme.of(context) + .extension()! + .textDark3, width: 16, height: 16, ), @@ -197,13 +199,14 @@ class _EnableAutoBackupViewState extends ConsumerState { key: const Key("createBackupPasswordFieldKey1"), focusNode: passwordFocusNode, controller: passwordController, - style: STextStyles.field, + style: STextStyles.field(context), obscureText: hidePassword, enableSuggestions: false, autocorrect: false, decoration: standardInputDecoration( "Create passphrase", passwordFocusNode, + context, ).copyWith( suffixIcon: UnconstrainedBox( child: Row( @@ -223,7 +226,9 @@ class _EnableAutoBackupViewState extends ConsumerState { hidePassword ? Assets.svg.eye : Assets.svg.eyeSlash, - color: CFColors.neutral50, + color: Theme.of(context) + .extension()! + .textDark3, width: 16, height: 16, ), @@ -284,7 +289,7 @@ class _EnableAutoBackupViewState extends ConsumerState { child: passwordFeedback.isNotEmpty ? Text( passwordFeedback, - style: STextStyles.infoSmall, + style: STextStyles.infoSmall(context), ) : null, ), @@ -302,11 +307,19 @@ class _EnableAutoBackupViewState extends ConsumerState { width: MediaQuery.of(context).size.width - 32 - 24, height: 5, fillColor: passwordStrength < 0.51 - ? CFColors.stackRed + ? Theme.of(context) + .extension()! + .accentColorRed : passwordStrength < 1 - ? CFColors.stackYellow - : CFColors.stackGreen, - backgroundColor: CFColors.buttonGray, + ? Theme.of(context) + .extension()! + .accentColorYellow + : Theme.of(context) + .extension()! + .accentColorGreen, + backgroundColor: Theme.of(context) + .extension()! + .buttonBackSecondary, percent: passwordStrength < 0.25 ? 0.03 : passwordStrength, ), @@ -322,13 +335,14 @@ class _EnableAutoBackupViewState extends ConsumerState { key: const Key("createBackupPasswordFieldKey2"), focusNode: passwordRepeatFocusNode, controller: passwordRepeatController, - style: STextStyles.field, + style: STextStyles.field(context), obscureText: hidePassword, enableSuggestions: false, autocorrect: false, decoration: standardInputDecoration( "Confirm passphrase", passwordRepeatFocusNode, + context, ).copyWith( suffixIcon: UnconstrainedBox( child: Row( @@ -348,7 +362,9 @@ class _EnableAutoBackupViewState extends ConsumerState { hidePassword ? Assets.svg.eye : Assets.svg.eyeSlash, - color: CFColors.neutral50, + color: Theme.of(context) + .extension()! + .textDark3, width: 16, height: 16, ), @@ -371,7 +387,7 @@ class _EnableAutoBackupViewState extends ConsumerState { ), Text( "Auto Backup frequency", - style: STextStyles.smallMed12, + style: STextStyles.smallMed12(context), ), const SizedBox( height: 10, @@ -384,7 +400,9 @@ class _EnableAutoBackupViewState extends ConsumerState { ), Positioned.fill( child: RawMaterialButton( - splashColor: CFColors.splashLight, + splashColor: Theme.of(context) + .extension()! + .highlight, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular( Constants.size.circularBorderRadius, @@ -415,13 +433,15 @@ class _EnableAutoBackupViewState extends ConsumerState { prefsChangeNotifierProvider.select( (value) => value.backupFrequencyType))), - style: STextStyles.itemSubtitle12, + style: STextStyles.itemSubtitle12(context), ), Padding( padding: const EdgeInsets.only(right: 4.0), child: SvgPicture.asset( Assets.svg.chevronDown, - color: CFColors.gray3, + color: Theme.of(context) + .extension()! + .textSubtitle2, width: 12, height: 6, ), @@ -438,13 +458,13 @@ class _EnableAutoBackupViewState extends ConsumerState { height: 10, ), TextButton( - style: Theme.of(context).textButtonTheme.style?.copyWith( - backgroundColor: MaterialStateProperty.all( - shouldEnableCreate - ? CFColors.stackAccent - : CFColors.disabledButton, - ), - ), + style: shouldEnableCreate + ? Theme.of(context) + .extension()! + .getPrimaryEnabledButtonColor(context) + : Theme.of(context) + .extension()! + .getPrimaryDisabledButtonColor(context), onPressed: !shouldEnableCreate ? null : () async { @@ -596,7 +616,7 @@ class _EnableAutoBackupViewState extends ConsumerState { }, child: Text( "Enable Auto Backup", - style: STextStyles.button, + style: STextStyles.button(context), ), ), ], diff --git a/lib/pages/settings_views/global_settings_view/stack_backup_views/create_backup_information_view.dart b/lib/pages/settings_views/global_settings_view/stack_backup_views/create_backup_information_view.dart index 4b0a1aaac..772c446f2 100644 --- a/lib/pages/settings_views/global_settings_view/stack_backup_views/create_backup_information_view.dart +++ b/lib/pages/settings_views/global_settings_view/stack_backup_views/create_backup_information_view.dart @@ -1,7 +1,7 @@ import 'package:flutter/material.dart'; import 'package:stackwallet/pages/settings_views/global_settings_view/stack_backup_views/create_backup_view.dart'; -import 'package:stackwallet/utilities/cfcolors.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/rounded_white_container.dart'; @@ -13,7 +13,7 @@ class CreateBackupInfoView extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( - backgroundColor: CFColors.almostWhite, + backgroundColor: Theme.of(context).extension()!.background, appBar: AppBar( leading: AppBarBackButton( onPressed: () async { @@ -26,7 +26,7 @@ class CreateBackupInfoView extends StatelessWidget { ), title: Text( "Create backup", - style: STextStyles.navBarTitle, + style: STextStyles.navBarTitle(context), ), ), body: Padding( @@ -45,7 +45,7 @@ class CreateBackupInfoView extends StatelessWidget { Center( child: Text( "Info", - style: STextStyles.pageTitleH2, + style: STextStyles.pageTitleH2(context), ), ), const SizedBox( @@ -55,7 +55,7 @@ class CreateBackupInfoView extends StatelessWidget { child: Text( // TODO: need info "{lorem ipsum}", - style: STextStyles.baseXS, + style: STextStyles.baseXS(context), ), ), const SizedBox( @@ -64,20 +64,15 @@ class CreateBackupInfoView extends StatelessWidget { const Spacer(), TextButton( style: Theme.of(context) - .textButtonTheme - .style - ?.copyWith( - backgroundColor: MaterialStateProperty.all( - CFColors.stackAccent, - ), - ), + .extension()! + .getPrimaryEnabledButtonColor(context), onPressed: () { Navigator.of(context) .pushNamed(CreateBackupView.routeName); }, child: Text( "Next", - style: STextStyles.button, + style: STextStyles.button(context), ), ), ], diff --git a/lib/pages/settings_views/global_settings_view/stack_backup_views/create_backup_view.dart b/lib/pages/settings_views/global_settings_view/stack_backup_views/create_backup_view.dart index c22e71651..964111cd3 100644 --- a/lib/pages/settings_views/global_settings_view/stack_backup_views/create_backup_view.dart +++ b/lib/pages/settings_views/global_settings_view/stack_backup_views/create_backup_view.dart @@ -1,3 +1,4 @@ +import 'dart:async'; import 'dart:convert'; import 'dart:io'; @@ -8,11 +9,11 @@ import 'package:stackwallet/notifications/show_flush_bar.dart'; import 'package:stackwallet/pages/settings_views/global_settings_view/stack_backup_views/helpers/restore_create_backup.dart'; import 'package:stackwallet/pages/settings_views/global_settings_view/stack_backup_views/helpers/stack_file_system.dart'; import 'package:stackwallet/utilities/assets.dart'; -import 'package:stackwallet/utilities/cfcolors.dart'; import 'package:stackwallet/utilities/constants.dart'; import 'package:stackwallet/utilities/enums/flush_bar_type.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/custom_buttons/app_bar_icon_button.dart'; import 'package:stackwallet/widgets/progress_bar.dart'; import 'package:stackwallet/widgets/stack_dialog.dart'; @@ -81,7 +82,7 @@ class _RestoreFromFileViewState extends State { @override Widget build(BuildContext context) { return Scaffold( - backgroundColor: CFColors.almostWhite, + backgroundColor: Theme.of(context).extension()!.background, appBar: AppBar( leading: AppBarBackButton( onPressed: () async { @@ -96,7 +97,7 @@ class _RestoreFromFileViewState extends State { ), title: Text( "Create backup", - style: STextStyles.navBarTitle, + style: STextStyles.navBarTitle(context), ), ), body: Padding( @@ -152,7 +153,7 @@ class _RestoreFromFileViewState extends State { } }, controller: fileLocationController, - style: STextStyles.field, + style: STextStyles.field(context), decoration: InputDecoration( hintText: "Save to...", suffixIcon: UnconstrainedBox( @@ -163,7 +164,9 @@ class _RestoreFromFileViewState extends State { ), SvgPicture.asset( Assets.svg.folder, - color: CFColors.neutral50, + color: Theme.of(context) + .extension()! + .textDark3, width: 16, height: 16, ), @@ -200,13 +203,14 @@ class _RestoreFromFileViewState extends State { key: const Key("createBackupPasswordFieldKey1"), focusNode: passwordFocusNode, controller: passwordController, - style: STextStyles.field, + style: STextStyles.field(context), obscureText: hidePassword, enableSuggestions: false, autocorrect: false, decoration: standardInputDecoration( "Create passphrase", passwordFocusNode, + context, ).copyWith( suffixIcon: UnconstrainedBox( child: Row( @@ -226,7 +230,9 @@ class _RestoreFromFileViewState extends State { hidePassword ? Assets.svg.eye : Assets.svg.eyeSlash, - color: CFColors.neutral50, + color: Theme.of(context) + .extension()! + .textDark3, width: 16, height: 16, ), @@ -287,7 +293,7 @@ class _RestoreFromFileViewState extends State { child: passwordFeedback.isNotEmpty ? Text( passwordFeedback, - style: STextStyles.infoSmall, + style: STextStyles.infoSmall(context), ) : null, ), @@ -305,11 +311,15 @@ class _RestoreFromFileViewState extends State { width: MediaQuery.of(context).size.width - 32 - 24, height: 5, fillColor: passwordStrength < 0.51 - ? CFColors.stackRed + ? Theme.of(context) + .extension()! + .accentColorRed : passwordStrength < 1 - ? CFColors.stackYellow - : CFColors.stackGreen, - backgroundColor: CFColors.buttonGray, + ? Theme.of(context).extension()!.accentColorYellow + : Theme.of(context).extension()!.accentColorGreen, + backgroundColor: Theme.of(context) + .extension()! + .buttonBackSecondary, percent: passwordStrength < 0.25 ? 0.03 : passwordStrength, @@ -326,13 +336,14 @@ class _RestoreFromFileViewState extends State { key: const Key("createBackupPasswordFieldKey2"), focusNode: passwordRepeatFocusNode, controller: passwordRepeatController, - style: STextStyles.field, + style: STextStyles.field(context), obscureText: hidePassword, enableSuggestions: false, autocorrect: false, decoration: standardInputDecoration( "Confirm passphrase", passwordRepeatFocusNode, + context, ).copyWith( suffixIcon: UnconstrainedBox( child: Row( @@ -352,7 +363,9 @@ class _RestoreFromFileViewState extends State { hidePassword ? Assets.svg.eye : Assets.svg.eyeSlash, - color: CFColors.neutral50, + color: Theme.of(context) + .extension()! + .textDark3, width: 16, height: 16, ), @@ -375,16 +388,9 @@ class _RestoreFromFileViewState extends State { ), const Spacer(), TextButton( - style: Theme.of(context) - .textButtonTheme - .style - ?.copyWith( - backgroundColor: MaterialStateProperty.all( - shouldEnableCreate - ? CFColors.stackAccent - : CFColors.disabledButton, - ), - ), + style: shouldEnableCreate + ? Theme.of(context) .extension()!.getPrimaryEnabledButtonColor(context) + : Theme.of(context) .extension()!.getPrimaryDisabledButtonColor(context), onPressed: !shouldEnableCreate ? null : () async { @@ -396,46 +402,46 @@ class _RestoreFromFileViewState extends State { passwordRepeatController.text; if (pathToSave.isEmpty) { - showFloatingFlushBar( + unawaited(showFloatingFlushBar( type: FlushBarType.warning, message: "Directory not chosen", context: context, - ); + )); return; } if (!(await Directory(pathToSave).exists())) { - showFloatingFlushBar( + unawaited(showFloatingFlushBar( type: FlushBarType.warning, message: "Directory does not exist", context: context, - ); + )); return; } if (passphrase.isEmpty) { - showFloatingFlushBar( + unawaited(showFloatingFlushBar( type: FlushBarType.warning, message: "A passphrase is required", context: context, - ); + )); return; } if (passphrase != repeatPassphrase) { - showFloatingFlushBar( + unawaited(showFloatingFlushBar( type: FlushBarType.warning, message: "Passphrase does not match", context: context, - ); + )); return; } - showDialog( + unawaited(showDialog( context: context, barrierDismissible: false, builder: (_) => const StackDialog( title: "Encrypting backup", message: "This shouldn't take long", ), - ); + )); // make sure the dialog is able to be displayed for at least 1 second await Future.delayed( const Duration(seconds: 1)); @@ -480,7 +486,7 @@ class _RestoreFromFileViewState extends State { }, child: Text( "Create backup", - style: STextStyles.button, + style: STextStyles.button(context), ), ), ], diff --git a/lib/pages/settings_views/global_settings_view/stack_backup_views/dialogs/cancel_stack_restore_dialog.dart b/lib/pages/settings_views/global_settings_view/stack_backup_views/dialogs/cancel_stack_restore_dialog.dart index 9dc0b23d3..16e51a35d 100644 --- a/lib/pages/settings_views/global_settings_view/stack_backup_views/dialogs/cancel_stack_restore_dialog.dart +++ b/lib/pages/settings_views/global_settings_view/stack_backup_views/dialogs/cancel_stack_restore_dialog.dart @@ -1,6 +1,6 @@ import 'package:flutter/material.dart'; -import 'package:stackwallet/utilities/cfcolors.dart'; import 'package:stackwallet/utilities/text_styles.dart'; +import 'package:stackwallet/utilities/theme/stack_colors.dart'; import 'package:stackwallet/widgets/stack_dialog.dart'; class CancelStackRestoreDialog extends StatelessWidget { @@ -19,29 +19,26 @@ class CancelStackRestoreDialog extends StatelessWidget { message: "Cancelling will revert any changes that may have been applied", leftButton: TextButton( - style: Theme.of(context).textButtonTheme.style?.copyWith( - backgroundColor: MaterialStateProperty.all( - CFColors.buttonGray, - ), - ), + style: Theme.of(context) + .extension()! + .getSecondaryEnabledButtonColor(context), child: Text( "Back", - style: STextStyles.itemSubtitle12, + style: STextStyles.itemSubtitle12(context), ), onPressed: () { Navigator.of(context).pop(false); }, ), rightButton: TextButton( - style: Theme.of(context).textButtonTheme.style?.copyWith( - backgroundColor: MaterialStateProperty.all( - CFColors.stackAccent, - ), - ), + style: Theme.of(context) + .extension()! + .getPrimaryEnabledButtonColor(context), child: Text( "Yes, cancel", - style: STextStyles.itemSubtitle12.copyWith( - color: CFColors.white, + style: STextStyles.itemSubtitle12(context).copyWith( + color: + Theme.of(context).extension()!.buttonTextPrimary, ), ), onPressed: () { diff --git a/lib/pages/settings_views/global_settings_view/stack_backup_views/edit_auto_backup_view.dart b/lib/pages/settings_views/global_settings_view/stack_backup_views/edit_auto_backup_view.dart index 6a3bed03e..fa14358ea 100644 --- a/lib/pages/settings_views/global_settings_view/stack_backup_views/edit_auto_backup_view.dart +++ b/lib/pages/settings_views/global_settings_view/stack_backup_views/edit_auto_backup_view.dart @@ -14,13 +14,13 @@ import 'package:stackwallet/pages/settings_views/global_settings_view/stack_back import 'package:stackwallet/pages/settings_views/global_settings_view/stack_backup_views/sub_views/backup_frequency_type_select_sheet.dart'; import 'package:stackwallet/providers/global/prefs_provider.dart'; import 'package:stackwallet/utilities/assets.dart'; -import 'package:stackwallet/utilities/cfcolors.dart'; import 'package:stackwallet/utilities/constants.dart'; import 'package:stackwallet/utilities/enums/flush_bar_type.dart'; import 'package:stackwallet/utilities/flutter_secure_storage_interface.dart'; import 'package:stackwallet/utilities/format.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/custom_buttons/app_bar_icon_button.dart'; import 'package:stackwallet/widgets/progress_bar.dart'; import 'package:stackwallet/widgets/stack_dialog.dart'; @@ -104,7 +104,7 @@ class _EditAutoBackupViewState extends ConsumerState { debugPrint("BUILD: $runtimeType"); return Scaffold( - backgroundColor: CFColors.almostWhite, + backgroundColor: Theme.of(context).extension()!.background, appBar: AppBar( leading: AppBarBackButton( onPressed: () { @@ -113,7 +113,7 @@ class _EditAutoBackupViewState extends ConsumerState { ), title: Text( "Edit Auto Backup", - style: STextStyles.navBarTitle, + style: STextStyles.navBarTitle(context), ), ), body: Padding( @@ -130,7 +130,7 @@ class _EditAutoBackupViewState extends ConsumerState { children: [ Text( "Create your backup", - style: STextStyles.smallMed12, + style: STextStyles.smallMed12(context), ), const SizedBox( height: 10, @@ -155,7 +155,7 @@ class _EditAutoBackupViewState extends ConsumerState { } }, controller: fileLocationController, - style: STextStyles.field, + style: STextStyles.field(context), decoration: InputDecoration( hintText: "Save to...", suffixIcon: UnconstrainedBox( @@ -166,7 +166,9 @@ class _EditAutoBackupViewState extends ConsumerState { ), SvgPicture.asset( Assets.svg.folder, - color: CFColors.neutral50, + color: Theme.of(context) + .extension()! + .textDark3, width: 16, height: 16, ), @@ -199,13 +201,14 @@ class _EditAutoBackupViewState extends ConsumerState { key: const Key("createBackupPasswordFieldKey1"), focusNode: passwordFocusNode, controller: passwordController, - style: STextStyles.field, + style: STextStyles.field(context), obscureText: hidePassword, enableSuggestions: false, autocorrect: false, decoration: standardInputDecoration( "Create passphrase", passwordFocusNode, + context, ).copyWith( suffixIcon: UnconstrainedBox( child: Row( @@ -225,7 +228,9 @@ class _EditAutoBackupViewState extends ConsumerState { hidePassword ? Assets.svg.eye : Assets.svg.eyeSlash, - color: CFColors.neutral50, + color: Theme.of(context) + .extension()! + .textDark3, width: 16, height: 16, ), @@ -286,7 +291,7 @@ class _EditAutoBackupViewState extends ConsumerState { child: passwordFeedback.isNotEmpty ? Text( passwordFeedback, - style: STextStyles.infoSmall, + style: STextStyles.infoSmall(context), ) : null, ), @@ -304,11 +309,19 @@ class _EditAutoBackupViewState extends ConsumerState { width: MediaQuery.of(context).size.width - 32 - 24, height: 5, fillColor: passwordStrength < 0.51 - ? CFColors.stackRed + ? Theme.of(context) + .extension()! + .accentColorRed : passwordStrength < 1 - ? CFColors.stackYellow - : CFColors.stackGreen, - backgroundColor: CFColors.buttonGray, + ? Theme.of(context) + .extension()! + .accentColorYellow + : Theme.of(context) + .extension()! + .accentColorGreen, + backgroundColor: Theme.of(context) + .extension()! + .buttonBackSecondary, percent: passwordStrength < 0.25 ? 0.03 : passwordStrength, ), @@ -324,13 +337,14 @@ class _EditAutoBackupViewState extends ConsumerState { key: const Key("createBackupPasswordFieldKey2"), focusNode: passwordRepeatFocusNode, controller: passwordRepeatController, - style: STextStyles.field, + style: STextStyles.field(context), obscureText: hidePassword, enableSuggestions: false, autocorrect: false, decoration: standardInputDecoration( "Confirm passphrase", passwordRepeatFocusNode, + context, ).copyWith( suffixIcon: UnconstrainedBox( child: Row( @@ -350,7 +364,9 @@ class _EditAutoBackupViewState extends ConsumerState { hidePassword ? Assets.svg.eye : Assets.svg.eyeSlash, - color: CFColors.neutral50, + color: Theme.of(context) + .extension()! + .textDark3, width: 16, height: 16, ), @@ -373,7 +389,7 @@ class _EditAutoBackupViewState extends ConsumerState { ), Text( "Auto Backup frequency", - style: STextStyles.smallMed12, + style: STextStyles.smallMed12(context), ), const SizedBox( height: 10, @@ -386,7 +402,9 @@ class _EditAutoBackupViewState extends ConsumerState { ), Positioned.fill( child: RawMaterialButton( - splashColor: CFColors.splashLight, + splashColor: Theme.of(context) + .extension()! + .highlight, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular( Constants.size.circularBorderRadius, @@ -417,13 +435,15 @@ class _EditAutoBackupViewState extends ConsumerState { prefsChangeNotifierProvider.select( (value) => value.backupFrequencyType))), - style: STextStyles.itemSubtitle12, + style: STextStyles.itemSubtitle12(context), ), Padding( padding: const EdgeInsets.only(right: 4.0), child: SvgPicture.asset( Assets.svg.chevronDown, - color: CFColors.gray3, + color: Theme.of(context) + .extension()! + .textSubtitle2, width: 12, height: 6, ), @@ -440,13 +460,13 @@ class _EditAutoBackupViewState extends ConsumerState { height: 10, ), TextButton( - style: Theme.of(context).textButtonTheme.style?.copyWith( - backgroundColor: MaterialStateProperty.all( - shouldEnableCreate - ? CFColors.stackAccent - : CFColors.disabledButton, - ), - ), + style: shouldEnableCreate + ? Theme.of(context) + .extension()! + .getPrimaryEnabledButtonColor(context) + : Theme.of(context) + .extension()! + .getPrimaryDisabledButtonColor(context), onPressed: !shouldEnableCreate ? null : () async { @@ -597,7 +617,7 @@ class _EditAutoBackupViewState extends ConsumerState { }, child: Text( "Save", - style: STextStyles.button, + style: STextStyles.button(context), ), ) ], diff --git a/lib/pages/settings_views/global_settings_view/stack_backup_views/restore_from_encrypted_string_view.dart b/lib/pages/settings_views/global_settings_view/stack_backup_views/restore_from_encrypted_string_view.dart index 639f1e34a..3173bc402 100644 --- a/lib/pages/settings_views/global_settings_view/stack_backup_views/restore_from_encrypted_string_view.dart +++ b/lib/pages/settings_views/global_settings_view/stack_backup_views/restore_from_encrypted_string_view.dart @@ -8,10 +8,10 @@ import 'package:stackwallet/pages/settings_views/global_settings_view/stack_back import 'package:stackwallet/pages/settings_views/global_settings_view/stack_backup_views/sub_views/stack_restore_progress_view.dart'; import 'package:stackwallet/route_generator.dart'; import 'package:stackwallet/utilities/assets.dart'; -import 'package:stackwallet/utilities/cfcolors.dart'; import 'package:stackwallet/utilities/constants.dart'; import 'package:stackwallet/utilities/enums/flush_bar_type.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/loading_indicator.dart'; import 'package:stackwallet/widgets/stack_text_field.dart'; @@ -63,7 +63,7 @@ class _RestoreFromEncryptedStringViewState return WillPopScope( onWillPop: _onWillPop, child: Scaffold( - backgroundColor: CFColors.almostWhite, + backgroundColor: Theme.of(context).extension()!.background, appBar: AppBar( leading: AppBarBackButton( onPressed: () async { @@ -78,7 +78,7 @@ class _RestoreFromEncryptedStringViewState ), title: Text( "Restore from file", - style: STextStyles.navBarTitle, + style: STextStyles.navBarTitle(context), ), ), body: Padding( @@ -102,13 +102,14 @@ class _RestoreFromEncryptedStringViewState key: const Key("restoreFromFilePasswordFieldKey"), focusNode: passwordFocusNode, controller: passwordController, - style: STextStyles.field, + style: STextStyles.field(context), obscureText: hidePassword, enableSuggestions: false, autocorrect: false, decoration: standardInputDecoration( "Enter password", passwordFocusNode, + context, ).copyWith( suffixIcon: UnconstrainedBox( child: Row( @@ -128,7 +129,9 @@ class _RestoreFromEncryptedStringViewState hidePassword ? Assets.svg.eye : Assets.svg.eyeSlash, - color: CFColors.neutral50, + color: Theme.of(context) + .extension()! + .textDark3, width: 16, height: 16, ), @@ -150,15 +153,13 @@ class _RestoreFromEncryptedStringViewState ), const Spacer(), TextButton( - style: - Theme.of(context).textButtonTheme.style?.copyWith( - backgroundColor: - MaterialStateProperty.all( - passwordController.text.isEmpty - ? CFColors.disabledButton - : CFColors.stackAccent, - ), - ), + style: passwordController.text.isEmpty + ? Theme.of(context) + .extension()! + .getPrimaryEnabledButtonColor(context) + : Theme.of(context) + .extension()! + .getPrimaryDisabledButtonColor(context), onPressed: passwordController.text.isEmpty ? null : () async { @@ -190,9 +191,12 @@ class _RestoreFromEncryptedStringViewState child: Center( child: Text( "Decrypting Stack backup file", - style: STextStyles.pageTitleH2 + style: STextStyles.pageTitleH2( + context) .copyWith( - color: CFColors.white, + color: Theme.of(context) + .extension()! + .textWhite, ), ), ), @@ -247,7 +251,7 @@ class _RestoreFromEncryptedStringViewState }, child: Text( "Restore", - style: STextStyles.button, + style: STextStyles.button(context), ), ), ], diff --git a/lib/pages/settings_views/global_settings_view/stack_backup_views/restore_from_file_view.dart b/lib/pages/settings_views/global_settings_view/stack_backup_views/restore_from_file_view.dart index 261a16361..feda62d0a 100644 --- a/lib/pages/settings_views/global_settings_view/stack_backup_views/restore_from_file_view.dart +++ b/lib/pages/settings_views/global_settings_view/stack_backup_views/restore_from_file_view.dart @@ -10,11 +10,11 @@ import 'package:stackwallet/pages/settings_views/global_settings_view/stack_back import 'package:stackwallet/pages/settings_views/global_settings_view/stack_backup_views/sub_views/stack_restore_progress_view.dart'; import 'package:stackwallet/route_generator.dart'; import 'package:stackwallet/utilities/assets.dart'; -import 'package:stackwallet/utilities/cfcolors.dart'; import 'package:stackwallet/utilities/constants.dart'; import 'package:stackwallet/utilities/enums/flush_bar_type.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/custom_buttons/app_bar_icon_button.dart'; import 'package:stackwallet/widgets/loading_indicator.dart'; import 'package:stackwallet/widgets/stack_text_field.dart'; @@ -64,7 +64,7 @@ class _RestoreFromFileViewState extends ConsumerState { @override Widget build(BuildContext context) { return Scaffold( - backgroundColor: CFColors.almostWhite, + backgroundColor: Theme.of(context).extension()!.background, appBar: AppBar( leading: AppBarBackButton( onPressed: () async { @@ -79,7 +79,7 @@ class _RestoreFromFileViewState extends ConsumerState { ), title: Text( "Restore from file", - style: STextStyles.navBarTitle, + style: STextStyles.navBarTitle(context), ), ), body: Padding( @@ -127,7 +127,7 @@ class _RestoreFromFileViewState extends ConsumerState { } }, controller: fileLocationController, - style: STextStyles.field, + style: STextStyles.field(context), decoration: InputDecoration( hintText: "Choose file...", suffixIcon: UnconstrainedBox( @@ -138,7 +138,9 @@ class _RestoreFromFileViewState extends ConsumerState { ), SvgPicture.asset( Assets.svg.folder, - color: CFColors.neutral50, + color: Theme.of(context) + .extension()! + .textDark3, width: 16, height: 16, ), @@ -170,13 +172,14 @@ class _RestoreFromFileViewState extends ConsumerState { key: const Key("restoreFromFilePasswordFieldKey"), focusNode: passwordFocusNode, controller: passwordController, - style: STextStyles.field, + style: STextStyles.field(context), obscureText: hidePassword, enableSuggestions: false, autocorrect: false, decoration: standardInputDecoration( "Enter password", passwordFocusNode, + context, ).copyWith( suffixIcon: UnconstrainedBox( child: Row( @@ -196,7 +199,9 @@ class _RestoreFromFileViewState extends ConsumerState { hidePassword ? Assets.svg.eye : Assets.svg.eyeSlash, - color: CFColors.neutral50, + color: Theme.of(context) + .extension()! + .textDark3, width: 16, height: 16, ), @@ -218,17 +223,14 @@ class _RestoreFromFileViewState extends ConsumerState { ), const Spacer(), TextButton( - style: Theme.of(context) - .textButtonTheme - .style - ?.copyWith( - backgroundColor: MaterialStateProperty.all( - passwordController.text.isEmpty || - fileLocationController.text.isEmpty - ? CFColors.disabledButton - : CFColors.stackAccent, - ), - ), + style: passwordController.text.isEmpty || + fileLocationController.text.isEmpty + ? Theme.of(context) + .extension()! + .getPrimaryDisabledButtonColor(context) + : Theme.of(context) + .extension()! + .getPrimaryEnabledButtonColor(context), onPressed: passwordController.text.isEmpty || fileLocationController.text.isEmpty ? null @@ -272,9 +274,12 @@ class _RestoreFromFileViewState extends ConsumerState { child: Center( child: Text( "Decrypting Stack backup file", - style: STextStyles.pageTitleH2 + style: STextStyles.pageTitleH2( + context) .copyWith( - color: CFColors.white, + color: Theme.of(context) + .extension()! + .textWhite, ), ), ), @@ -325,7 +330,7 @@ class _RestoreFromFileViewState extends ConsumerState { }, child: Text( "Restore", - style: STextStyles.button, + style: STextStyles.button(context), ), ), ], diff --git a/lib/pages/settings_views/global_settings_view/stack_backup_views/stack_backup_view.dart b/lib/pages/settings_views/global_settings_view/stack_backup_views/stack_backup_view.dart index b7e299816..679043fe7 100644 --- a/lib/pages/settings_views/global_settings_view/stack_backup_views/stack_backup_view.dart +++ b/lib/pages/settings_views/global_settings_view/stack_backup_views/stack_backup_view.dart @@ -4,9 +4,9 @@ import 'package:stackwallet/pages/settings_views/global_settings_view/stack_back import 'package:stackwallet/pages/settings_views/global_settings_view/stack_backup_views/create_backup_view.dart'; import 'package:stackwallet/pages/settings_views/global_settings_view/stack_backup_views/restore_from_file_view.dart'; import 'package:stackwallet/utilities/assets.dart'; -import 'package:stackwallet/utilities/cfcolors.dart'; 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/rounded_white_container.dart'; @@ -22,7 +22,7 @@ class StackBackupView extends StatelessWidget { debugPrint("BUILD: $runtimeType"); return Scaffold( - backgroundColor: CFColors.almostWhite, + backgroundColor: Theme.of(context).extension()!.background, appBar: AppBar( leading: AppBarBackButton( onPressed: () { @@ -31,7 +31,7 @@ class StackBackupView extends StatelessWidget { ), title: Text( "Stack backup", - style: STextStyles.navBarTitle, + style: STextStyles.navBarTitle(context), ), ), body: Padding( @@ -42,7 +42,7 @@ class StackBackupView extends StatelessWidget { RoundedWhiteContainer( padding: const EdgeInsets.all(0), child: RawMaterialButton( - // splashColor: CFColors.splashLight, + // splashColor: Theme.of(context).extension()!.highlight, materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular( @@ -69,7 +69,7 @@ class StackBackupView extends StatelessWidget { ), Text( "Auto Backup", - style: STextStyles.titleBold12, + style: STextStyles.titleBold12(context), textAlign: TextAlign.left, ), ], @@ -83,7 +83,7 @@ class StackBackupView extends StatelessWidget { RoundedWhiteContainer( padding: const EdgeInsets.all(0), child: RawMaterialButton( - // splashColor: CFColors.splashLight, + // splashColor: Theme.of(context).extension()!.highlight, materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular( @@ -111,7 +111,7 @@ class StackBackupView extends StatelessWidget { ), Text( "Create manual backup", - style: STextStyles.titleBold12, + style: STextStyles.titleBold12(context), textAlign: TextAlign.left, ), ], @@ -125,7 +125,7 @@ class StackBackupView extends StatelessWidget { RoundedWhiteContainer( padding: const EdgeInsets.all(0), child: RawMaterialButton( - // splashColor: CFColors.splashLight, + // splashColor: Theme.of(context).extension()!.highlight, materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular( @@ -153,7 +153,7 @@ class StackBackupView extends StatelessWidget { ), Text( "Restore backup", - style: STextStyles.titleBold12, + style: STextStyles.titleBold12(context), textAlign: TextAlign.left, ), ], diff --git a/lib/pages/settings_views/global_settings_view/stack_backup_views/sub_views/backup_frequency_type_select_sheet.dart b/lib/pages/settings_views/global_settings_view/stack_backup_views/sub_views/backup_frequency_type_select_sheet.dart index 6bc049ce1..b64defcf7 100644 --- a/lib/pages/settings_views/global_settings_view/stack_backup_views/sub_views/backup_frequency_type_select_sheet.dart +++ b/lib/pages/settings_views/global_settings_view/stack_backup_views/sub_views/backup_frequency_type_select_sheet.dart @@ -1,10 +1,10 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:stackwallet/providers/global/prefs_provider.dart'; -import 'package:stackwallet/utilities/cfcolors.dart'; import 'package:stackwallet/utilities/constants.dart'; import 'package:stackwallet/utilities/enums/backup_frequency_type.dart'; import 'package:stackwallet/utilities/text_styles.dart'; +import 'package:stackwallet/utilities/theme/stack_colors.dart'; class BackupFrequencyTypeSelectSheet extends ConsumerWidget { const BackupFrequencyTypeSelectSheet({ @@ -31,9 +31,9 @@ class BackupFrequencyTypeSelectSheet extends ConsumerWidget { return false; }, child: Container( - decoration: const BoxDecoration( - color: CFColors.white, - borderRadius: BorderRadius.vertical( + decoration: BoxDecoration( + color: Theme.of(context).extension()!.popupBG, + borderRadius: const BorderRadius.vertical( top: Radius.circular(20), ), ), @@ -51,7 +51,9 @@ class BackupFrequencyTypeSelectSheet extends ConsumerWidget { Center( child: Container( decoration: BoxDecoration( - color: CFColors.fieldGray, + color: Theme.of(context) + .extension()! + .textFieldDefaultBG, borderRadius: BorderRadius.circular( Constants.size.circularBorderRadius, ), @@ -68,7 +70,7 @@ class BackupFrequencyTypeSelectSheet extends ConsumerWidget { children: [ Text( "Auto Backup frequency", - style: STextStyles.pageTitleH2, + style: STextStyles.pageTitleH2(context), textAlign: TextAlign.left, ), const SizedBox( @@ -94,13 +96,15 @@ class BackupFrequencyTypeSelectSheet extends ConsumerWidget { child: Container( color: Colors.transparent, child: Row( - crossAxisAlignment: CrossAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.start, children: [ SizedBox( width: 20, height: 20, child: Radio( - activeColor: CFColors.link2, + activeColor: Theme.of(context) + .extension()! + .radioButtonIconEnabled, value: BackupFrequencyType.values[i], groupValue: ref.watch( prefsChangeNotifierProvider.select( @@ -118,17 +122,17 @@ class BackupFrequencyTypeSelectSheet extends ConsumerWidget { const SizedBox( width: 12, ), - Column( - children: [ - Text( - prettyFrequencyType( - BackupFrequencyType.values[i]), - style: STextStyles.titleBold12.copyWith( - color: const Color(0xFF44464E), + Flexible( + child: Column( + children: [ + Text( + prettyFrequencyType( + BackupFrequencyType.values[i]), + style: STextStyles.titleBold12(context), + textAlign: TextAlign.left, ), - textAlign: TextAlign.left, - ), - ], + ], + ), ), ], ), diff --git a/lib/pages/settings_views/global_settings_view/stack_backup_views/sub_views/recovery_phrase_view.dart b/lib/pages/settings_views/global_settings_view/stack_backup_views/sub_views/recovery_phrase_view.dart index 90b5a2c32..7b30a21b0 100644 --- a/lib/pages/settings_views/global_settings_view/stack_backup_views/sub_views/recovery_phrase_view.dart +++ b/lib/pages/settings_views/global_settings_view/stack_backup_views/sub_views/recovery_phrase_view.dart @@ -4,10 +4,10 @@ import 'package:flutter_svg/svg.dart'; import 'package:stackwallet/notifications/show_flush_bar.dart'; import 'package:stackwallet/pages/add_wallet_views/new_wallet_recovery_phrase_view/sub_widgets/mnemonic_table.dart'; import 'package:stackwallet/utilities/assets.dart'; -import 'package:stackwallet/utilities/cfcolors.dart'; import 'package:stackwallet/utilities/clipboard_interface.dart'; import 'package:stackwallet/utilities/enums/flush_bar_type.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'; class RecoverPhraseView extends StatelessWidget { @@ -28,7 +28,7 @@ class RecoverPhraseView extends StatelessWidget { Widget build(BuildContext context) { debugPrint("BUILD: $runtimeType"); return Scaffold( - backgroundColor: CFColors.almostWhite, + backgroundColor: Theme.of(context).extension()!.background, appBar: AppBar( leading: AppBarBackButton( onPressed: () { @@ -41,7 +41,7 @@ class RecoverPhraseView extends StatelessWidget { child: AspectRatio( aspectRatio: 1, child: AppBarIconButton( - color: CFColors.almostWhite, + color: Theme.of(context).extension()!.background, shadows: const [], icon: SvgPicture.asset( Assets.svg.copy, @@ -74,7 +74,7 @@ class RecoverPhraseView extends StatelessWidget { Text( walletName, textAlign: TextAlign.center, - style: STextStyles.label.copyWith( + style: STextStyles.label(context).copyWith( fontSize: 12, ), ), @@ -84,7 +84,7 @@ class RecoverPhraseView extends StatelessWidget { Text( "Recovery Phrase", textAlign: TextAlign.center, - style: STextStyles.pageTitleH1, + style: STextStyles.pageTitleH1(context), ), const SizedBox( height: 12, @@ -93,6 +93,7 @@ class RecoverPhraseView extends StatelessWidget { child: SingleChildScrollView( child: MnemonicTable( words: mnemonic, + isDesktop: false, ), ), ), diff --git a/lib/pages/settings_views/global_settings_view/stack_backup_views/sub_views/stack_restore_progress_view.dart b/lib/pages/settings_views/global_settings_view/stack_backup_views/sub_views/stack_restore_progress_view.dart index 81760a73e..367d211ed 100644 --- a/lib/pages/settings_views/global_settings_view/stack_backup_views/sub_views/stack_restore_progress_view.dart +++ b/lib/pages/settings_views/global_settings_view/stack_backup_views/sub_views/stack_restore_progress_view.dart @@ -1,3 +1,5 @@ +import 'dart:async'; + import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_svg/svg.dart'; @@ -11,10 +13,10 @@ import 'package:stackwallet/pages/settings_views/global_settings_view/stack_back import 'package:stackwallet/providers/providers.dart'; import 'package:stackwallet/providers/stack_restore/stack_restoring_ui_state_provider.dart'; import 'package:stackwallet/utilities/assets.dart'; -import 'package:stackwallet/utilities/cfcolors.dart'; import 'package:stackwallet/utilities/enums/stack_restoring_status.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/custom_buttons/app_bar_icon_button.dart'; import 'package:stackwallet/widgets/icon_widgets/addressbook_icon.dart'; import 'package:stackwallet/widgets/loading_indicator.dart'; @@ -39,7 +41,7 @@ class _StackRestoreProgressViewState extends ConsumerState { Future _cancel() async { bool shouldPop = false; - showDialog( + unawaited(showDialog( barrierDismissible: false, context: context, builder: (_) => WillPopScope( @@ -55,8 +57,9 @@ class _StackRestoreProgressViewState child: Center( child: Text( "Cancelling restore. Please wait.", - style: STextStyles.pageTitleH2.copyWith( - color: CFColors.white, + style: STextStyles.pageTitleH2(context).copyWith( + color: + Theme.of(context).extension()!.textWhite, ), ), ), @@ -72,7 +75,7 @@ class _StackRestoreProgressViewState ], ), ), - ); + )); await SWB.cancelRestore(); shouldPop = true; @@ -138,22 +141,23 @@ class _StackRestoreProgressViewState case StackRestoringStatus.waiting: return SvgPicture.asset( Assets.svg.loader, - color: CFColors.buttonGray, + color: + Theme.of(context).extension()!.buttonBackSecondary, ); case StackRestoringStatus.restoring: return SvgPicture.asset( Assets.svg.loader, - color: CFColors.stackGreen, + color: Theme.of(context).extension()!.accentColorGreen, ); case StackRestoringStatus.success: return SvgPicture.asset( Assets.svg.checkCircle, - color: CFColors.stackGreen, + color: Theme.of(context).extension()!.accentColorGreen, ); case StackRestoringStatus.failed: return SvgPicture.asset( Assets.svg.circleAlert, - color: CFColors.error, + color: Theme.of(context).extension()!.textError, ); } } @@ -178,7 +182,7 @@ class _StackRestoreProgressViewState return WillPopScope( onWillPop: _onWillPop, child: Scaffold( - backgroundColor: CFColors.almostWhite, + backgroundColor: Theme.of(context).extension()!.background, appBar: AppBar( leading: AppBarBackButton( onPressed: () async { @@ -200,7 +204,7 @@ class _StackRestoreProgressViewState ), title: Text( "Restoring Stack wallet", - style: STextStyles.navBarTitle, + style: STextStyles.navBarTitle(context), ), ), body: Padding( @@ -222,7 +226,7 @@ class _StackRestoreProgressViewState children: [ Text( "Settings", - style: STextStyles.itemSubtitle, + style: STextStyles.itemSubtitle(context), ), const SizedBox( height: 12, @@ -237,13 +241,17 @@ class _StackRestoreProgressViewState height: 32, child: RoundedContainer( padding: const EdgeInsets.all(0), - color: CFColors.buttonGray, + color: Theme.of(context) + .extension()! + .buttonBackSecondary, child: Center( child: SvgPicture.asset( Assets.svg.gear, width: 16, height: 16, - color: CFColors.stackAccent, + color: Theme.of(context) + .extension()! + .accentColorDark, ), ), ), @@ -257,7 +265,7 @@ class _StackRestoreProgressViewState subTitle: state == StackRestoringStatus.failed ? Text( "Something went wrong", - style: STextStyles.errorSmall, + style: STextStyles.errorSmall(context), ) : null, ); @@ -271,17 +279,21 @@ class _StackRestoreProgressViewState final state = ref.watch(stackRestoringUIStateProvider .select((value) => value.addressBook)); return RestoringItemCard( - left: const SizedBox( + left: SizedBox( width: 32, height: 32, child: RoundedContainer( - padding: EdgeInsets.all(0), - color: CFColors.buttonGray, + padding: const EdgeInsets.all(0), + color: Theme.of(context) + .extension()! + .buttonBackSecondary, child: Center( child: AddressBookIcon( width: 16, height: 16, - color: CFColors.stackAccent, + color: Theme.of(context) + .extension()! + .accentColorDark, ), ), ), @@ -295,7 +307,7 @@ class _StackRestoreProgressViewState subTitle: state == StackRestoringStatus.failed ? Text( "Something went wrong", - style: STextStyles.errorSmall, + style: STextStyles.errorSmall(context), ) : null, ); @@ -314,13 +326,17 @@ class _StackRestoreProgressViewState height: 32, child: RoundedContainer( padding: const EdgeInsets.all(0), - color: CFColors.buttonGray, + color: Theme.of(context) + .extension()! + .buttonBackSecondary, child: Center( child: SvgPicture.asset( Assets.svg.node, width: 16, height: 16, - color: CFColors.stackAccent, + color: Theme.of(context) + .extension()! + .accentColorDark, ), ), ), @@ -334,7 +350,7 @@ class _StackRestoreProgressViewState subTitle: state == StackRestoringStatus.failed ? Text( "Something went wrong", - style: STextStyles.errorSmall, + style: STextStyles.errorSmall(context), ) : null, ); @@ -353,13 +369,17 @@ class _StackRestoreProgressViewState height: 32, child: RoundedContainer( padding: const EdgeInsets.all(0), - color: CFColors.buttonGray, + color: Theme.of(context) + .extension()! + .buttonBackSecondary, child: Center( child: SvgPicture.asset( Assets.svg.arrowRotate2, width: 16, height: 16, - color: CFColors.stackAccent, + color: Theme.of(context) + .extension()! + .accentColorDark, ), ), ), @@ -373,7 +393,7 @@ class _StackRestoreProgressViewState subTitle: state == StackRestoringStatus.failed ? Text( "Something went wrong", - style: STextStyles.errorSmall, + style: STextStyles.errorSmall(context), ) : null, ); @@ -384,7 +404,7 @@ class _StackRestoreProgressViewState ), Text( "Wallets", - style: STextStyles.itemSubtitle, + style: STextStyles.itemSubtitle(context), ), const SizedBox( height: 8, @@ -423,10 +443,15 @@ class _StackRestoreProgressViewState } } }, + style: Theme.of(context) + .extension()! + .getSecondaryEnabledButtonColor(context), child: Text( _success ? "OK" : "Cancel restore process", - style: STextStyles.button.copyWith( - color: CFColors.stackAccent, + style: STextStyles.button(context).copyWith( + color: Theme.of(context) + .extension()! + .buttonTextPrimary, ), ), ), diff --git a/lib/pages/settings_views/global_settings_view/stack_backup_views/sub_widgets/restoring_item_card.dart b/lib/pages/settings_views/global_settings_view/stack_backup_views/sub_widgets/restoring_item_card.dart index c671408b3..47b879b2f 100644 --- a/lib/pages/settings_views/global_settings_view/stack_backup_views/sub_widgets/restoring_item_card.dart +++ b/lib/pages/settings_views/global_settings_view/stack_backup_views/sub_widgets/restoring_item_card.dart @@ -48,7 +48,7 @@ class RestoringItemCard extends StatelessWidget { children: [ Text( title, - style: STextStyles.titleBold12, + style: STextStyles.titleBold12(context), ), if (subTitle != null) const SizedBox( diff --git a/lib/pages/settings_views/global_settings_view/stack_backup_views/sub_widgets/restoring_wallet_card.dart b/lib/pages/settings_views/global_settings_view/stack_backup_views/sub_widgets/restoring_wallet_card.dart index 67e96947b..8f9890a6a 100644 --- a/lib/pages/settings_views/global_settings_view/stack_backup_views/sub_widgets/restoring_wallet_card.dart +++ b/lib/pages/settings_views/global_settings_view/stack_backup_views/sub_widgets/restoring_wallet_card.dart @@ -7,10 +7,10 @@ import 'package:stackwallet/pages/settings_views/global_settings_view/stack_back import 'package:stackwallet/providers/stack_restore/stack_restoring_ui_state_provider.dart'; import 'package:stackwallet/route_generator.dart'; import 'package:stackwallet/utilities/assets.dart'; -import 'package:stackwallet/utilities/cfcolors.dart'; import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/enums/stack_restoring_status.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:stackwallet/widgets/rounded_container.dart'; @@ -35,23 +35,23 @@ class _RestoringWalletCardState extends ConsumerState { case StackRestoringStatus.waiting: return SvgPicture.asset( Assets.svg.loader, - color: CFColors.buttonGray, + color: Theme.of(context).extension()!.buttonBackSecondary, ); case StackRestoringStatus.restoring: return const LoadingIndicator(); // return SvgPicture.asset( // Assets.svg.loader, - // color: CFColors.stackGreen, + // color: Theme.of(context).extension()!.accentColorGreen, // ); case StackRestoringStatus.success: return SvgPicture.asset( Assets.svg.checkCircle, - color: CFColors.stackGreen, + color: Theme.of(context).extension()!.accentColorGreen, ); case StackRestoringStatus.failed: return SvgPicture.asset( Assets.svg.circleAlert, - color: CFColors.error, + color: Theme.of(context).extension()!.textError, ); } } @@ -73,7 +73,7 @@ class _RestoringWalletCardState extends ConsumerState { height: 32, child: RoundedContainer( padding: const EdgeInsets.all(0), - color: CFColors.coin.forCoin(coin), + color: Theme.of(context).extension()!.colorForCoin(coin), child: Center( child: SvgPicture.asset( Assets.svg.iconFor( @@ -143,26 +143,26 @@ class _RestoringWalletCardState extends ConsumerState { subTitle: restoringStatus == StackRestoringStatus.failed ? Text( "Unable to restore. Tap icon to retry.", - style: STextStyles.errorSmall, + style: STextStyles.errorSmall(context), ) : ref.watch(provider.select((value) => value.address)) != null ? Text( ref.watch(provider.select((value) => value.address))!, - style: STextStyles.infoSmall, + style: STextStyles.infoSmall(context), ) : null, button: restoringStatus == StackRestoringStatus.failed ? Container( height: 20, decoration: BoxDecoration( - color: CFColors.buttonGray, + color: Theme.of(context).extension()!.buttonBackSecondary, borderRadius: BorderRadius.circular( 1000, ), ), child: RawMaterialButton( materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, - splashColor: CFColors.splashLight, + splashColor: Theme.of(context).extension()!.highlight, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular( 1000, @@ -186,9 +186,8 @@ class _RestoringWalletCardState extends ConsumerState { padding: const EdgeInsets.symmetric(horizontal: 8.0), child: Text( "Show recovery phrase", - style: STextStyles.infoSmall.copyWith( - color: CFColors.stackAccent, - ), + style: STextStyles.infoSmall(context).copyWith( + color: Theme.of(context).extension()!.accentColorDark), ), ), ), diff --git a/lib/pages/settings_views/global_settings_view/startup_preferences/startup_preferences_view.dart b/lib/pages/settings_views/global_settings_view/startup_preferences/startup_preferences_view.dart index 861886625..baf649ba2 100644 --- a/lib/pages/settings_views/global_settings_view/startup_preferences/startup_preferences_view.dart +++ b/lib/pages/settings_views/global_settings_view/startup_preferences/startup_preferences_view.dart @@ -2,9 +2,9 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:stackwallet/pages/settings_views/global_settings_view/startup_preferences/startup_wallet_selection_view.dart'; import 'package:stackwallet/providers/global/prefs_provider.dart'; -import 'package:stackwallet/utilities/cfcolors.dart'; 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/rounded_white_container.dart'; @@ -23,7 +23,7 @@ class _StartupPreferencesViewState @override Widget build(BuildContext context) { return Scaffold( - backgroundColor: CFColors.almostWhite, + backgroundColor: Theme.of(context).extension()!.background, appBar: AppBar( leading: AppBarBackButton( onPressed: () async { @@ -32,7 +32,7 @@ class _StartupPreferencesViewState ), title: Text( "Startup preferences", - style: STextStyles.navBarTitle, + style: STextStyles.navBarTitle(context), ), ), body: Padding( @@ -56,7 +56,7 @@ class _StartupPreferencesViewState Padding( padding: const EdgeInsets.all(4.0), child: RawMaterialButton( - // splashColor: CFColors.splashLight, + // splashColor: Theme.of(context).extension()!.highlight, materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, shape: RoundedRectangleBorder( @@ -81,7 +81,9 @@ class _StartupPreferencesViewState width: 20, height: 20, child: Radio( - activeColor: CFColors.link2, + activeColor: Theme.of(context) + .extension()! + .radioButtonIconEnabled, value: false, groupValue: ref.watch( prefsChangeNotifierProvider @@ -108,12 +110,14 @@ class _StartupPreferencesViewState children: [ Text( "Home screen", - style: STextStyles.titleBold12, + style: STextStyles.titleBold12( + context), textAlign: TextAlign.left, ), Text( "Stack Wallet home screen", - style: STextStyles.itemSubtitle, + style: STextStyles.itemSubtitle( + context), textAlign: TextAlign.left, ), ], @@ -128,7 +132,7 @@ class _StartupPreferencesViewState Padding( padding: const EdgeInsets.all(4), child: RawMaterialButton( - // splashColor: CFColors.splashLight, + // splashColor: Theme.of(context).extension()!.highlight, materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, shape: RoundedRectangleBorder( @@ -153,7 +157,9 @@ class _StartupPreferencesViewState width: 20, height: 20, child: Radio( - activeColor: CFColors.link2, + activeColor: Theme.of(context) + .extension()! + .radioButtonIconEnabled, value: true, groupValue: ref.watch( prefsChangeNotifierProvider @@ -180,12 +186,14 @@ class _StartupPreferencesViewState children: [ Text( "Specific wallet", - style: STextStyles.titleBold12, + style: STextStyles.titleBold12( + context), textAlign: TextAlign.left, ), Text( "Select a specific wallet to load into on startup", - style: STextStyles.itemSubtitle, + style: STextStyles.itemSubtitle( + context), textAlign: TextAlign.left, ), ], @@ -222,7 +230,7 @@ class _StartupPreferencesViewState ), Flexible( child: RawMaterialButton( - // splashColor: CFColors.splashLight, + // splashColor: Theme.of(context).extension()!.highlight, materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, shape: RoundedRectangleBorder( @@ -242,7 +250,8 @@ class _StartupPreferencesViewState children: [ Text( "Select wallet...", - style: STextStyles.link2, + style: + STextStyles.link2(context), textAlign: TextAlign.left, ), ], diff --git a/lib/pages/settings_views/global_settings_view/startup_preferences/startup_wallet_selection_view.dart b/lib/pages/settings_views/global_settings_view/startup_preferences/startup_wallet_selection_view.dart index 9569419e5..5d9f2edb1 100644 --- a/lib/pages/settings_views/global_settings_view/startup_preferences/startup_wallet_selection_view.dart +++ b/lib/pages/settings_views/global_settings_view/startup_preferences/startup_wallet_selection_view.dart @@ -3,9 +3,9 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_svg/svg.dart'; import 'package:stackwallet/providers/providers.dart'; import 'package:stackwallet/utilities/assets.dart'; -import 'package:stackwallet/utilities/cfcolors.dart'; 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/draggable_switch_button.dart'; import 'package:stackwallet/widgets/rounded_white_container.dart'; @@ -34,7 +34,7 @@ class _StartupWalletSelectionViewState } return Scaffold( - backgroundColor: CFColors.almostWhite, + backgroundColor: Theme.of(context).extension()!.background, appBar: AppBar( leading: AppBarBackButton( onPressed: () async { @@ -45,7 +45,7 @@ class _StartupWalletSelectionViewState fit: BoxFit.scaleDown, child: Text( "Select startup wallet", - style: STextStyles.navBarTitle, + style: STextStyles.navBarTitle(context), ), ), ), @@ -72,7 +72,7 @@ class _StartupWalletSelectionViewState ), Text( "Select a wallet to load into immediately on startup", - style: STextStyles.smallMed12, + style: STextStyles.smallMed12(context), ), const SizedBox( height: 12, @@ -90,8 +90,9 @@ class _StartupWalletSelectionViewState children: [ Container( decoration: BoxDecoration( - color: CFColors.coin - .forCoin(manager.coin) + color: Theme.of(context) + .extension()! + .colorForCoin(manager.coin) .withOpacity(0.5), borderRadius: BorderRadius.circular( Constants.size.circularBorderRadius, @@ -110,58 +111,62 @@ class _StartupWalletSelectionViewState const SizedBox( width: 12, ), - Column( - mainAxisAlignment: - MainAxisAlignment.spaceBetween, - crossAxisAlignment: - CrossAxisAlignment.start, - children: [ - Text( - manager.walletName, - style: STextStyles.titleBold12, - ), - // const SizedBox( - // height: 2, - // ), - // FutureBuilder( - // future: manager.totalBalance, - // builder: (builderContext, - // AsyncSnapshot snapshot) { - // if (snapshot.connectionState == - // ConnectionState.done && - // snapshot.hasData) { - // return Text( - // "${Format.localizedStringAsFixed( - // value: snapshot.data!, - // locale: ref.watch( - // localeServiceChangeNotifierProvider - // .select((value) => - // value.locale)), - // decimalPlaces: 8, - // )} ${manager.coin.ticker}", - // style: STextStyles.itemSubtitle, - // ); - // } else { - // return AnimatedText( - // stringsToLoopThrough: const [ - // "Loading balance", - // "Loading balance.", - // "Loading balance..", - // "Loading balance..." - // ], - // style: STextStyles.itemSubtitle, - // ); - // } - // }, - // ), - ], + Expanded( + child: Column( + mainAxisAlignment: + MainAxisAlignment.spaceBetween, + crossAxisAlignment: + CrossAxisAlignment.start, + children: [ + Text( + manager.walletName, + style: STextStyles.titleBold12( + context), + ), + // const SizedBox( + // height: 2, + // ), + // FutureBuilder( + // future: manager.totalBalance, + // builder: (builderContext, + // AsyncSnapshot snapshot) { + // if (snapshot.connectionState == + // ConnectionState.done && + // snapshot.hasData) { + // return Text( + // "${Format.localizedStringAsFixed( + // value: snapshot.data!, + // locale: ref.watch( + // localeServiceChangeNotifierProvider + // .select((value) => + // value.locale)), + // decimalPlaces: 8, + // )} ${manager.coin.ticker}", + // style: STextStyles.itemSubtitle(context), + // ); + // } else { + // return AnimatedText( + // stringsToLoopThrough: const [ + // "Loading balance", + // "Loading balance.", + // "Loading balance..", + // "Loading balance..." + // ], + // style: STextStyles.itemSubtitle(context), + // ); + // } + // }, + // ), + ], + ), ), - const Spacer(), SizedBox( height: 20, width: 20, child: Radio( - activeColor: CFColors.link2, + activeColor: Theme.of(context) + .extension()! + .radioButtonIconEnabled, value: manager.walletId, groupValue: ref.watch( prefsChangeNotifierProvider.select( diff --git a/lib/pages/settings_views/global_settings_view/support_view.dart b/lib/pages/settings_views/global_settings_view/support_view.dart index 3b62e0fb8..fdfa6f404 100644 --- a/lib/pages/settings_views/global_settings_view/support_view.dart +++ b/lib/pages/settings_views/global_settings_view/support_view.dart @@ -1,9 +1,9 @@ import 'package:flutter/material.dart'; import 'package:flutter_svg/svg.dart'; import 'package:stackwallet/utilities/assets.dart'; -import 'package:stackwallet/utilities/cfcolors.dart'; 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/rounded_white_container.dart'; import 'package:url_launcher/url_launcher.dart'; @@ -21,7 +21,7 @@ class SupportView extends StatelessWidget { debugPrint("BUILD: $runtimeType"); return Scaffold( - backgroundColor: CFColors.almostWhite, + backgroundColor: Theme.of(context).extension()!.background, appBar: AppBar( leading: AppBarBackButton( onPressed: () { @@ -30,7 +30,7 @@ class SupportView extends StatelessWidget { ), title: Text( "Support", - style: STextStyles.navBarTitle, + style: STextStyles.navBarTitle(context), ), ), body: Padding( @@ -41,7 +41,7 @@ class SupportView extends StatelessWidget { RoundedWhiteContainer( child: Text( "If you need support or want to report a bug, reach out to us on any of our socials!", - style: STextStyles.smallMed12, + style: STextStyles.smallMed12(context), ), ), const SizedBox( @@ -50,7 +50,7 @@ class SupportView extends StatelessWidget { RoundedWhiteContainer( padding: const EdgeInsets.all(0), child: RawMaterialButton( - // splashColor: CFColors.splashLight, + // splashColor: Theme.of(context).extension()!.highlight, materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular( @@ -74,13 +74,16 @@ class SupportView extends StatelessWidget { Assets.socials.telegram, width: iconSize, height: iconSize, + color: Theme.of(context) + .extension()! + .accentColorDark, ), const SizedBox( width: 12, ), Text( "Telegram", - style: STextStyles.titleBold12, + style: STextStyles.titleBold12(context), textAlign: TextAlign.left, ), ], @@ -94,7 +97,7 @@ class SupportView extends StatelessWidget { RoundedWhiteContainer( padding: const EdgeInsets.all(0), child: RawMaterialButton( - // splashColor: CFColors.splashLight, + // splashColor: Theme.of(context).extension()!.highlight, materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular( @@ -118,13 +121,16 @@ class SupportView extends StatelessWidget { Assets.socials.discord, width: iconSize, height: iconSize, + color: Theme.of(context) + .extension()! + .accentColorDark, ), const SizedBox( width: 12, ), Text( "Discord", - style: STextStyles.titleBold12, + style: STextStyles.titleBold12(context), textAlign: TextAlign.left, ), ], @@ -138,7 +144,7 @@ class SupportView extends StatelessWidget { RoundedWhiteContainer( padding: const EdgeInsets.all(0), child: RawMaterialButton( - // splashColor: CFColors.splashLight, + // splashColor: Theme.of(context).extension()!.highlight, materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular( @@ -162,13 +168,16 @@ class SupportView extends StatelessWidget { Assets.socials.reddit, width: iconSize, height: iconSize, + color: Theme.of(context) + .extension()! + .accentColorDark, ), const SizedBox( width: 12, ), Text( "Reddit", - style: STextStyles.titleBold12, + style: STextStyles.titleBold12(context), textAlign: TextAlign.left, ), ], @@ -182,7 +191,7 @@ class SupportView extends StatelessWidget { RoundedWhiteContainer( padding: const EdgeInsets.all(0), child: RawMaterialButton( - // splashColor: CFColors.splashLight, + // splashColor: Theme.of(context).extension()!.highlight, materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular( @@ -206,13 +215,16 @@ class SupportView extends StatelessWidget { Assets.socials.twitter, width: iconSize, height: iconSize, + color: Theme.of(context) + .extension()! + .accentColorDark, ), const SizedBox( width: 12, ), Text( "Twitter", - style: STextStyles.titleBold12, + style: STextStyles.titleBold12(context), textAlign: TextAlign.left, ), ], @@ -226,7 +238,7 @@ class SupportView extends StatelessWidget { RoundedWhiteContainer( padding: const EdgeInsets.all(0), child: RawMaterialButton( - // splashColor: CFColors.splashLight, + // splashColor: Theme.of(context).extension()!.highlight, materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular( @@ -250,13 +262,16 @@ class SupportView extends StatelessWidget { Assets.svg.envelope, width: iconSize, height: iconSize, + color: Theme.of(context) + .extension()! + .accentColorDark, ), const SizedBox( width: 12, ), Text( "Email", - style: STextStyles.titleBold12, + style: STextStyles.titleBold12(context), textAlign: TextAlign.left, ), ], diff --git a/lib/pages/settings_views/global_settings_view/syncing_preferences_views/syncing_options_view.dart b/lib/pages/settings_views/global_settings_view/syncing_preferences_views/syncing_options_view.dart index 5bf9f5275..bada67353 100644 --- a/lib/pages/settings_views/global_settings_view/syncing_preferences_views/syncing_options_view.dart +++ b/lib/pages/settings_views/global_settings_view/syncing_preferences_views/syncing_options_view.dart @@ -2,10 +2,10 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:stackwallet/pages/settings_views/global_settings_view/syncing_preferences_views/wallet_syncing_options_view.dart'; import 'package:stackwallet/providers/providers.dart'; -import 'package:stackwallet/utilities/cfcolors.dart'; import 'package:stackwallet/utilities/constants.dart'; import 'package:stackwallet/utilities/enums/sync_type_enum.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/rounded_white_container.dart'; @@ -17,7 +17,7 @@ class SyncingOptionsView extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { return Scaffold( - backgroundColor: CFColors.almostWhite, + backgroundColor: Theme.of(context).extension()!.background, appBar: AppBar( leading: AppBarBackButton( onPressed: () async { @@ -26,7 +26,7 @@ class SyncingOptionsView extends ConsumerWidget { ), title: Text( "Syncing", - style: STextStyles.navBarTitle, + style: STextStyles.navBarTitle(context), ), ), body: Padding( @@ -49,7 +49,7 @@ class SyncingOptionsView extends ConsumerWidget { Padding( padding: const EdgeInsets.all(4), child: RawMaterialButton( - // splashColor: CFColors.splashLight, + // splashColor: Theme.of(context).extension()!.highlight, materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, shape: RoundedRectangleBorder( @@ -90,7 +90,9 @@ class SyncingOptionsView extends ConsumerWidget { width: 20, height: 20, child: Radio( - activeColor: CFColors.link2, + activeColor: Theme.of(context) + .extension()! + .radioButtonIconEnabled, value: SyncingType.currentWalletOnly, groupValue: ref.watch( @@ -118,12 +120,14 @@ class SyncingOptionsView extends ConsumerWidget { children: [ Text( "Sync only currently open wallet", - style: STextStyles.titleBold12, + style: STextStyles.titleBold12( + context), textAlign: TextAlign.left, ), Text( "Sync only the wallet that you are using", - style: STextStyles.itemSubtitle, + style: STextStyles.itemSubtitle( + context), textAlign: TextAlign.left, ), ], @@ -138,7 +142,7 @@ class SyncingOptionsView extends ConsumerWidget { Padding( padding: const EdgeInsets.all(4.0), child: RawMaterialButton( - // splashColor: CFColors.splashLight, + // splashColor: Theme.of(context).extension()!.highlight, materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, shape: RoundedRectangleBorder( @@ -177,7 +181,9 @@ class SyncingOptionsView extends ConsumerWidget { width: 20, height: 20, child: Radio( - activeColor: CFColors.link2, + activeColor: Theme.of(context) + .extension()! + .radioButtonIconEnabled, value: SyncingType.allWalletsOnStartup, groupValue: ref.watch( @@ -205,12 +211,14 @@ class SyncingOptionsView extends ConsumerWidget { children: [ Text( "Sync all wallets at startup", - style: STextStyles.titleBold12, + style: STextStyles.titleBold12( + context), textAlign: TextAlign.left, ), Text( "All of your wallets will start syncing when you open the app", - style: STextStyles.itemSubtitle, + style: STextStyles.itemSubtitle( + context), textAlign: TextAlign.left, ), ], @@ -225,7 +233,7 @@ class SyncingOptionsView extends ConsumerWidget { Padding( padding: const EdgeInsets.all(4), child: RawMaterialButton( - // splashColor: CFColors.splashLight, + // splashColor: Theme.of(context).extension()!.highlight, materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, shape: RoundedRectangleBorder( @@ -268,7 +276,9 @@ class SyncingOptionsView extends ConsumerWidget { width: 20, height: 20, child: Radio( - activeColor: CFColors.link2, + activeColor: Theme.of(context) + .extension()! + .radioButtonIconEnabled, value: SyncingType .selectedWalletsAtStartup, groupValue: ref.watch( @@ -296,12 +306,14 @@ class SyncingOptionsView extends ConsumerWidget { children: [ Text( "Sync only selected wallets at startup", - style: STextStyles.titleBold12, + style: STextStyles.titleBold12( + context), textAlign: TextAlign.left, ), Text( "Only the wallets you select will start syncing when you open the app", - style: STextStyles.itemSubtitle, + style: STextStyles.itemSubtitle( + context), textAlign: TextAlign.left, ), ], @@ -340,7 +352,7 @@ class SyncingOptionsView extends ConsumerWidget { ), Flexible( child: RawMaterialButton( - // splashColor: CFColors.splashLight, + // splashColor: Theme.of(context).extension()!.highlight, materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, shape: RoundedRectangleBorder( @@ -360,7 +372,8 @@ class SyncingOptionsView extends ConsumerWidget { children: [ Text( "Select wallets...", - style: STextStyles.link2, + style: + STextStyles.link2(context), textAlign: TextAlign.left, ), ], diff --git a/lib/pages/settings_views/global_settings_view/syncing_preferences_views/syncing_preferences_view.dart b/lib/pages/settings_views/global_settings_view/syncing_preferences_views/syncing_preferences_view.dart index 82f723623..e48ebb342 100644 --- a/lib/pages/settings_views/global_settings_view/syncing_preferences_views/syncing_preferences_view.dart +++ b/lib/pages/settings_views/global_settings_view/syncing_preferences_views/syncing_preferences_view.dart @@ -2,10 +2,10 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:stackwallet/pages/settings_views/global_settings_view/syncing_preferences_views/syncing_options_view.dart'; import 'package:stackwallet/providers/providers.dart'; -import 'package:stackwallet/utilities/cfcolors.dart'; import 'package:stackwallet/utilities/constants.dart'; import 'package:stackwallet/utilities/enums/sync_type_enum.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/draggable_switch_button.dart'; import 'package:stackwallet/widgets/rounded_white_container.dart'; @@ -29,7 +29,7 @@ class SyncingPreferencesView extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { return Scaffold( - backgroundColor: CFColors.almostWhite, + backgroundColor: Theme.of(context).extension()!.background, appBar: AppBar( leading: AppBarBackButton( onPressed: () async { @@ -38,7 +38,7 @@ class SyncingPreferencesView extends ConsumerWidget { ), title: Text( "Syncing preferences", - style: STextStyles.navBarTitle, + style: STextStyles.navBarTitle(context), ), ), body: Padding( @@ -57,7 +57,7 @@ class SyncingPreferencesView extends ConsumerWidget { RoundedWhiteContainer( padding: const EdgeInsets.all(0), child: RawMaterialButton( - // splashColor: CFColors.splashLight, + // splashColor: Theme.of(context).extension()!.highlight, padding: const EdgeInsets.all(0), materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, @@ -79,14 +79,14 @@ class SyncingPreferencesView extends ConsumerWidget { children: [ Text( "Syncing", - style: STextStyles.titleBold12, + style: STextStyles.titleBold12(context), textAlign: TextAlign.left, ), Text( _currentTypeDescription(ref.watch( prefsChangeNotifierProvider.select( (value) => value.syncType))), - style: STextStyles.itemSubtitle, + style: STextStyles.itemSubtitle(context), textAlign: TextAlign.left, ) ], @@ -104,7 +104,7 @@ class SyncingPreferencesView extends ConsumerWidget { child: Consumer( builder: (_, ref, __) { return RawMaterialButton( - // splashColor: CFColors.splashLight, + // splashColor: Theme.of(context).extension()!.highlight, materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, shape: RoundedRectangleBorder( @@ -122,7 +122,7 @@ class SyncingPreferencesView extends ConsumerWidget { children: [ Text( "AutoSync only on Wi-Fi", - style: STextStyles.titleBold12, + style: STextStyles.titleBold12(context), textAlign: TextAlign.left, ), SizedBox( diff --git a/lib/pages/settings_views/global_settings_view/syncing_preferences_views/wallet_syncing_options_view.dart b/lib/pages/settings_views/global_settings_view/syncing_preferences_views/wallet_syncing_options_view.dart index 29fc3a4c8..1e302cf12 100644 --- a/lib/pages/settings_views/global_settings_view/syncing_preferences_views/wallet_syncing_options_view.dart +++ b/lib/pages/settings_views/global_settings_view/syncing_preferences_views/wallet_syncing_options_view.dart @@ -4,12 +4,12 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_svg/svg.dart'; import 'package:stackwallet/providers/providers.dart'; import 'package:stackwallet/utilities/assets.dart'; -import 'package:stackwallet/utilities/cfcolors.dart'; import 'package:stackwallet/utilities/constants.dart'; import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/enums/sync_type_enum.dart'; import 'package:stackwallet/utilities/format.dart'; import 'package:stackwallet/utilities/text_styles.dart'; +import 'package:stackwallet/utilities/theme/stack_colors.dart'; import 'package:stackwallet/widgets/animated_text.dart'; import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart'; import 'package:stackwallet/widgets/custom_buttons/draggable_switch_button.dart'; @@ -26,7 +26,7 @@ class WalletSyncingOptionsView extends ConsumerWidget { .watch(walletsChangeNotifierProvider.select((value) => value.managers)); return Scaffold( - backgroundColor: CFColors.almostWhite, + backgroundColor: Theme.of(context).extension()!.background, appBar: AppBar( leading: AppBarBackButton( onPressed: () async { @@ -37,7 +37,7 @@ class WalletSyncingOptionsView extends ConsumerWidget { fit: BoxFit.scaleDown, child: Text( "Sync only selected wallets at startup", - style: STextStyles.navBarTitle, + style: STextStyles.navBarTitle(context), ), ), ), @@ -64,7 +64,7 @@ class WalletSyncingOptionsView extends ConsumerWidget { ), Text( "Choose the wallets to sync automatically at startup", - style: STextStyles.smallMed12, + style: STextStyles.smallMed12(context), ), const SizedBox( height: 12, @@ -82,8 +82,9 @@ class WalletSyncingOptionsView extends ConsumerWidget { children: [ Container( decoration: BoxDecoration( - color: CFColors.coin - .forCoin(manager.coin) + color: Theme.of(context) + .extension()! + .colorForCoin(manager.coin) .withOpacity(0.5), borderRadius: BorderRadius.circular( Constants.size.circularBorderRadius, @@ -110,7 +111,8 @@ class WalletSyncingOptionsView extends ConsumerWidget { children: [ Text( manager.walletName, - style: STextStyles.titleBold12, + style: + STextStyles.titleBold12(context), ), const SizedBox( height: 2, @@ -131,7 +133,8 @@ class WalletSyncingOptionsView extends ConsumerWidget { value.locale)), decimalPlaces: 8, )} ${manager.coin.ticker}", - style: STextStyles.itemSubtitle, + style: STextStyles.itemSubtitle( + context), ); } else { return AnimatedText( @@ -141,7 +144,8 @@ class WalletSyncingOptionsView extends ConsumerWidget { "Loading balance..", "Loading balance..." ], - style: STextStyles.itemSubtitle, + style: STextStyles.itemSubtitle( + context), ); } }, diff --git a/lib/pages/settings_views/sub_widgets/settings_list_button.dart b/lib/pages/settings_views/sub_widgets/settings_list_button.dart index eb25a8e1b..5081e0f76 100644 --- a/lib/pages/settings_views/sub_widgets/settings_list_button.dart +++ b/lib/pages/settings_views/sub_widgets/settings_list_button.dart @@ -1,8 +1,8 @@ import 'package:flutter/material.dart'; import 'package:flutter_svg/svg.dart'; -import 'package:stackwallet/utilities/cfcolors.dart'; import 'package:stackwallet/utilities/constants.dart'; import 'package:stackwallet/utilities/text_styles.dart'; +import 'package:stackwallet/utilities/theme/stack_colors.dart'; class SettingsListButton extends StatelessWidget { const SettingsListButton({ @@ -21,7 +21,7 @@ class SettingsListButton extends StatelessWidget { @override Widget build(BuildContext context) { return RawMaterialButton( - // splashColor: CFColors.splashLight, + // splashColor: Theme.of(context).extension()!.highlight, constraints: const BoxConstraints( minHeight: 32, minWidth: 32, @@ -41,7 +41,9 @@ class SettingsListButton extends StatelessWidget { width: 32, height: 32, decoration: BoxDecoration( - color: CFColors.buttonGray, + color: Theme.of(context) + .extension()! + .buttonBackSecondary, borderRadius: BorderRadius.circular(100), ), child: Center( @@ -51,7 +53,9 @@ class SettingsListButton extends StatelessWidget { child: Center( child: SvgPicture.asset( iconAssetName, - color: CFColors.stackAccent, + color: Theme.of(context) + .extension()! + .accentColorDark, width: iconSize, height: iconSize, ), @@ -65,8 +69,10 @@ class SettingsListButton extends StatelessWidget { Expanded( child: Text( title, - style: STextStyles.smallMed14.copyWith( - color: CFColors.stackAccent, + style: STextStyles.smallMed14(context).copyWith( + color: Theme.of(context) + .extension()! + .accentColorDark, ), ), ), diff --git a/lib/pages/settings_views/wallet_settings_view/wallet_backup_views/wallet_backup_view.dart b/lib/pages/settings_views/wallet_settings_view/wallet_backup_views/wallet_backup_view.dart index ad46137ba..3d557d245 100644 --- a/lib/pages/settings_views/wallet_settings_view/wallet_backup_views/wallet_backup_view.dart +++ b/lib/pages/settings_views/wallet_settings_view/wallet_backup_views/wallet_backup_view.dart @@ -1,3 +1,5 @@ +import 'dart:async'; + import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; @@ -8,11 +10,11 @@ import 'package:stackwallet/pages/add_wallet_views/new_wallet_recovery_phrase_vi import 'package:stackwallet/providers/global/wallets_provider.dart'; import 'package:stackwallet/utilities/address_utils.dart'; import 'package:stackwallet/utilities/assets.dart'; -import 'package:stackwallet/utilities/cfcolors.dart'; import 'package:stackwallet/utilities/clipboard_interface.dart'; import 'package:stackwallet/utilities/constants.dart'; import 'package:stackwallet/utilities/enums/flush_bar_type.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/stack_dialog.dart'; @@ -34,7 +36,7 @@ class WalletBackupView extends ConsumerWidget { Widget build(BuildContext context, WidgetRef ref) { debugPrint("BUILD: $runtimeType"); return Scaffold( - backgroundColor: CFColors.almostWhite, + backgroundColor: Theme.of(context).extension()!.background, appBar: AppBar( leading: AppBarBackButton( onPressed: () { @@ -43,7 +45,7 @@ class WalletBackupView extends ConsumerWidget { ), title: Text( "Wallet backup", - style: STextStyles.navBarTitle, + style: STextStyles.navBarTitle(context), ), actions: [ Padding( @@ -51,22 +53,25 @@ class WalletBackupView extends ConsumerWidget { child: AspectRatio( aspectRatio: 1, child: AppBarIconButton( - color: CFColors.almostWhite, + color: Theme.of(context).extension()!.background, shadows: const [], icon: SvgPicture.asset( Assets.svg.copy, width: 20, height: 20, + color: Theme.of(context) + .extension()! + .topNavIconPrimary, ), onPressed: () async { await clipboardInterface .setData(ClipboardData(text: mnemonic.join(" "))); - showFloatingFlushBar( + unawaited(showFloatingFlushBar( type: FlushBarType.info, message: "Copied to clipboard", iconAsset: Assets.svg.copy, context: context, - ); + )); }, ), ), @@ -87,7 +92,7 @@ class WalletBackupView extends ConsumerWidget { .select((value) => value.getManager(walletId))) .walletName, textAlign: TextAlign.center, - style: STextStyles.label.copyWith( + style: STextStyles.label(context).copyWith( fontSize: 12, ), ), @@ -97,14 +102,14 @@ class WalletBackupView extends ConsumerWidget { Text( "Recovery Phrase", textAlign: TextAlign.center, - style: STextStyles.pageTitleH1, + style: STextStyles.pageTitleH1(context), ), const SizedBox( height: 16, ), Container( decoration: BoxDecoration( - color: CFColors.white, + color: Theme.of(context).extension()!.popupBG, borderRadius: BorderRadius.circular(Constants.size.circularBorderRadius), ), @@ -112,7 +117,7 @@ class WalletBackupView extends ConsumerWidget { padding: const EdgeInsets.all(12), child: Text( "Please write down your backup key. Keep it safe and never share it with anyone. Your backup key is the only way you can access your funds if you forget your PIN, lose your phone, etc.\n\nStack Wallet does not keep nor is able to restore your backup key. Only you have access to your wallet.", - style: STextStyles.label, + style: STextStyles.label(context), ), ), ), @@ -123,6 +128,7 @@ class WalletBackupView extends ConsumerWidget { child: SingleChildScrollView( child: MnemonicTable( words: mnemonic, + isDesktop: false, ), ), ), @@ -130,11 +136,9 @@ class WalletBackupView extends ConsumerWidget { height: 12, ), TextButton( - style: Theme.of(context).textButtonTheme.style?.copyWith( - backgroundColor: MaterialStateProperty.all( - CFColors.stackAccent, - ), - ), + style: Theme.of(context) + .extension()! + .getPrimaryEnabledButtonColor(context), onPressed: () { String data = AddressUtils.encodeQRSeedData(mnemonic); @@ -151,7 +155,7 @@ class WalletBackupView extends ConsumerWidget { Center( child: Text( "Recovery phrase QR code", - style: STextStyles.pageTitleH2, + style: STextStyles.pageTitleH2(context), ), ), const SizedBox( @@ -164,11 +168,14 @@ class WalletBackupView extends ConsumerWidget { width: width + 20, height: width + 20, child: QrImage( - data: data, - size: width, - backgroundColor: CFColors.white, - foregroundColor: CFColors.stackAccent, - ), + data: data, + size: width, + backgroundColor: Theme.of(context) + .extension()! + .popupBG, + foregroundColor: Theme.of(context) + .extension()! + .accentColorDark), ), ), ), @@ -183,17 +190,15 @@ class WalletBackupView extends ConsumerWidget { // await _capturePng(true); Navigator.of(context).pop(); }, - style: ButtonStyle( - backgroundColor: - MaterialStateProperty.all( - CFColors.buttonGray, - ), - ), + style: Theme.of(context) + .extension()! + .getSecondaryEnabledButtonColor(context), child: Text( "Cancel", - style: STextStyles.button.copyWith( - color: CFColors.stackAccent, - ), + style: STextStyles.button(context).copyWith( + color: Theme.of(context) + .extension()! + .accentColorDark), ), ), ), @@ -206,7 +211,7 @@ class WalletBackupView extends ConsumerWidget { }, child: Text( "Show QR Code", - style: STextStyles.button, + style: STextStyles.button(context), ), ), ], diff --git a/lib/pages/settings_views/wallet_settings_view/wallet_network_settings_view/sub_widgets/confirm_full_rescan.dart b/lib/pages/settings_views/wallet_settings_view/wallet_network_settings_view/sub_widgets/confirm_full_rescan.dart index 90d1ed8a2..141eb4c99 100644 --- a/lib/pages/settings_views/wallet_settings_view/wallet_network_settings_view/sub_widgets/confirm_full_rescan.dart +++ b/lib/pages/settings_views/wallet_settings_view/wallet_network_settings_view/sub_widgets/confirm_full_rescan.dart @@ -1,6 +1,6 @@ import 'package:flutter/material.dart'; -import 'package:stackwallet/utilities/cfcolors.dart'; import 'package:stackwallet/utilities/text_styles.dart'; +import 'package:stackwallet/utilities/theme/stack_colors.dart'; import 'package:stackwallet/widgets/stack_dialog.dart'; class ConfirmFullRescanDialog extends StatelessWidget { @@ -20,28 +20,24 @@ class ConfirmFullRescanDialog extends StatelessWidget { message: "Warning! It may take a while. If you exit before completion, you will have to redo the process.", leftButton: TextButton( - style: Theme.of(context).textButtonTheme.style?.copyWith( - backgroundColor: MaterialStateProperty.all( - CFColors.buttonGray, - ), - ), + style: Theme.of(context) + .extension()! + .getSecondaryEnabledButtonColor(context), child: Text( "Cancel", - style: STextStyles.itemSubtitle12, + style: STextStyles.itemSubtitle12(context), ), onPressed: () { Navigator.of(context).pop(); }, ), rightButton: TextButton( - style: Theme.of(context).textButtonTheme.style?.copyWith( - backgroundColor: MaterialStateProperty.all( - CFColors.stackAccent, - ), - ), + style: Theme.of(context) + .extension()! + .getPrimaryEnabledButtonColor(context), child: Text( "Rescan", - style: STextStyles.button, + style: STextStyles.button(context), ), onPressed: () { Navigator.of(context).pop(); diff --git a/lib/pages/settings_views/wallet_settings_view/wallet_network_settings_view/sub_widgets/rescanning_dialog.dart b/lib/pages/settings_views/wallet_settings_view/wallet_network_settings_view/sub_widgets/rescanning_dialog.dart index 85f5bbf92..da39b1017 100644 --- a/lib/pages/settings_views/wallet_settings_view/wallet_network_settings_view/sub_widgets/rescanning_dialog.dart +++ b/lib/pages/settings_views/wallet_settings_view/wallet_network_settings_view/sub_widgets/rescanning_dialog.dart @@ -1,7 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_svg/svg.dart'; import 'package:stackwallet/utilities/assets.dart'; -import 'package:stackwallet/utilities/cfcolors.dart'; +import 'package:stackwallet/utilities/theme/stack_colors.dart'; import 'package:stackwallet/widgets/stack_dialog.dart'; class RescanningDialog extends StatefulWidget { @@ -62,7 +62,7 @@ class _RescanningDialogState extends State Assets.svg.arrowRotate3, width: 24, height: 24, - color: CFColors.stackAccent, + color: Theme.of(context).extension()!.accentColorDark, ), ), // rightButton: TextButton( @@ -73,7 +73,7 @@ class _RescanningDialogState extends State // ), // child: Text( // "Cancel", - // style: STextStyles.itemSubtitle12, + // style: STextStyles.itemSubtitle12(context), // ), // onPressed: () { // Navigator.of(context).pop(); diff --git a/lib/pages/settings_views/wallet_settings_view/wallet_network_settings_view/wallet_network_settings_view.dart b/lib/pages/settings_views/wallet_settings_view/wallet_network_settings_view/wallet_network_settings_view.dart index 479ef9716..892cd13d8 100644 --- a/lib/pages/settings_views/wallet_settings_view/wallet_network_settings_view/wallet_network_settings_view.dart +++ b/lib/pages/settings_views/wallet_settings_view/wallet_network_settings_view/wallet_network_settings_view.dart @@ -18,10 +18,10 @@ import 'package:stackwallet/services/event_bus/events/global/refresh_percent_cha 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/utilities/assets.dart'; -import 'package:stackwallet/utilities/cfcolors.dart'; import 'package:stackwallet/utilities/constants.dart'; import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/text_styles.dart'; +import 'package:stackwallet/utilities/theme/stack_colors.dart'; import 'package:stackwallet/widgets/animated_text.dart'; import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart'; import 'package:stackwallet/widgets/custom_buttons/blue_text_button.dart'; @@ -107,14 +107,12 @@ class _WalletNetworkSettingsViewState builder: (context) => StackDialog( title: "Rescan completed", rightButton: TextButton( - style: Theme.of(context).textButtonTheme.style?.copyWith( - backgroundColor: MaterialStateProperty.all( - CFColors.buttonGray, - ), - ), + style: Theme.of(context) + .extension()! + .getSecondaryEnabledButtonColor(context), child: Text( "Ok", - style: STextStyles.itemSubtitle12, + style: STextStyles.itemSubtitle12(context), ), onPressed: () { Navigator.of(context).pop(); @@ -139,14 +137,12 @@ class _WalletNetworkSettingsViewState title: "Rescan failed", message: e.toString(), rightButton: TextButton( - style: Theme.of(context).textButtonTheme.style?.copyWith( - backgroundColor: MaterialStateProperty.all( - CFColors.buttonGray, - ), - ), + style: Theme.of(context) + .extension()! + .getSecondaryEnabledButtonColor(context), child: Text( "Ok", - style: STextStyles.itemSubtitle12, + style: STextStyles.itemSubtitle12(context), ), onPressed: () { Navigator.of(context).pop(); @@ -287,7 +283,7 @@ class _WalletNetworkSettingsViewState } return Scaffold( - backgroundColor: CFColors.almostWhite, + backgroundColor: Theme.of(context).extension()!.background, appBar: AppBar( leading: AppBarBackButton( onPressed: () { @@ -296,7 +292,7 @@ class _WalletNetworkSettingsViewState ), title: Text( "Network", - style: STextStyles.navBarTitle, + style: STextStyles.navBarTitle(context), ), actions: [ Padding( @@ -311,10 +307,12 @@ class _WalletNetworkSettingsViewState key: const Key("walletNetworkSettingsAddNewNodeViewButton"), size: 36, shadows: const [], - color: CFColors.almostWhite, + color: Theme.of(context).extension()!.background, icon: SvgPicture.asset( Assets.svg.verticalEllipsis, - color: CFColors.stackAccent, + color: Theme.of(context) + .extension()! + .accentColorDark, width: 20, height: 20, ), @@ -331,7 +329,9 @@ class _WalletNetworkSettingsViewState right: 10, child: Container( decoration: BoxDecoration( - color: CFColors.white, + color: Theme.of(context) + .extension()! + .popupBG, borderRadius: BorderRadius.circular( Constants.size.circularBorderRadius), // boxShadow: [CFColors.standardBoxShadow], @@ -359,7 +359,7 @@ class _WalletNetworkSettingsViewState color: Colors.transparent, child: Text( "Rescan blockchain", - style: STextStyles.baseXS, + style: STextStyles.baseXS(context), ), ), ), @@ -397,7 +397,7 @@ class _WalletNetworkSettingsViewState Text( "Blockchain status", textAlign: TextAlign.left, - style: STextStyles.smallMed12, + style: STextStyles.smallMed12(context), ), GestureDetector( onTap: () { @@ -408,7 +408,7 @@ class _WalletNetworkSettingsViewState }, child: Text( "Resync", - style: STextStyles.link2, + style: STextStyles.link2(context), ), ), ], @@ -424,7 +424,10 @@ class _WalletNetworkSettingsViewState width: _iconSize, height: _iconSize, decoration: BoxDecoration( - color: CFColors.stackGreen.withOpacity(0.2), + color: Theme.of(context) + .extension()! + .accentColorGreen + .withOpacity(0.2), borderRadius: BorderRadius.circular(_iconSize), ), child: Center( @@ -432,7 +435,9 @@ class _WalletNetworkSettingsViewState Assets.svg.radio, height: 14, width: 14, - color: CFColors.stackGreen, + color: Theme.of(context) + .extension()! + .accentColorGreen, ), ), ), @@ -449,12 +454,15 @@ class _WalletNetworkSettingsViewState children: [ Text( "Synchronized", - style: STextStyles.w600_10, + style: STextStyles.w600_10(context), ), Text( "100%", - style: STextStyles.syncPercent.copyWith( - color: CFColors.stackGreen, + style: STextStyles.syncPercent(context) + .copyWith( + color: Theme.of(context) + .extension()! + .accentColorGreen, ), ), ], @@ -466,8 +474,12 @@ class _WalletNetworkSettingsViewState ProgressBar( width: progressLength, height: 5, - fillColor: CFColors.stackGreen, - backgroundColor: CFColors.fieldGray, + fillColor: Theme.of(context) + .extension()! + .accentColorGreen, + backgroundColor: Theme.of(context) + .extension()! + .textFieldDefaultBG, percent: 1, ), ], @@ -483,7 +495,10 @@ class _WalletNetworkSettingsViewState width: _iconSize, height: _iconSize, decoration: BoxDecoration( - color: CFColors.stackYellow.withOpacity(0.2), + color: Theme.of(context) + .extension()! + .accentColorYellow + .withOpacity(0.2), borderRadius: BorderRadius.circular(_iconSize), ), child: Center( @@ -491,7 +506,9 @@ class _WalletNetworkSettingsViewState Assets.svg.radioSyncing, height: 14, width: 14, - color: CFColors.stackYellow, + color: Theme.of(context) + .extension()! + .accentColorYellow, ), ), ), @@ -507,7 +524,7 @@ class _WalletNetworkSettingsViewState MainAxisAlignment.spaceBetween, children: [ AnimatedText( - style: STextStyles.w600_10, + style: STextStyles.w600_10(context), stringsToLoopThrough: const [ "Synchronizing", "Synchronizing.", @@ -520,17 +537,23 @@ class _WalletNetworkSettingsViewState Text( _percentString(_percent), style: - STextStyles.syncPercent.copyWith( - color: CFColors.stackYellow, + STextStyles.syncPercent(context) + .copyWith( + color: Theme.of(context) + .extension()! + .accentColorYellow, ), ), if (coin == Coin.monero || coin == Coin.epicCash) Text( " (Blocks to go: ${_blocksRemaining == -1 ? "?" : _blocksRemaining})", - style: STextStyles.syncPercent - .copyWith( - color: CFColors.stackYellow, + style: + STextStyles.syncPercent(context) + .copyWith( + color: Theme.of(context) + .extension()! + .accentColorYellow, ), ), ], @@ -544,8 +567,12 @@ class _WalletNetworkSettingsViewState ProgressBar( width: progressLength, height: 5, - fillColor: CFColors.stackYellow, - backgroundColor: CFColors.fieldGray, + fillColor: Theme.of(context) + .extension()! + .accentColorYellow, + backgroundColor: Theme.of(context) + .extension()! + .textFieldDefaultBG, percent: _percent, ), ], @@ -561,7 +588,10 @@ class _WalletNetworkSettingsViewState width: _iconSize, height: _iconSize, decoration: BoxDecoration( - color: CFColors.link.withOpacity(0.2), + color: Theme.of(context) + .extension()! + .accentColorRed + .withOpacity(0.2), borderRadius: BorderRadius.circular(_iconSize), ), child: Center( @@ -569,7 +599,9 @@ class _WalletNetworkSettingsViewState Assets.svg.radioProblem, height: 14, width: 14, - color: CFColors.link, + color: Theme.of(context) + .extension()! + .accentColorRed, ), ), ), @@ -586,14 +618,20 @@ class _WalletNetworkSettingsViewState children: [ Text( "Unable to synchronize", - style: STextStyles.w600_10.copyWith( - color: CFColors.link, + style: + STextStyles.w600_10(context).copyWith( + color: Theme.of(context) + .extension()! + .accentColorRed, ), ), Text( "0%", - style: STextStyles.syncPercent.copyWith( - color: CFColors.link, + style: STextStyles.syncPercent(context) + .copyWith( + color: Theme.of(context) + .extension()! + .accentColorRed, ), ), ], @@ -605,8 +643,12 @@ class _WalletNetworkSettingsViewState ProgressBar( width: progressLength, height: 5, - fillColor: CFColors.link, - backgroundColor: CFColors.fieldGray, + fillColor: Theme.of(context) + .extension()! + .accentColorRed, + backgroundColor: Theme.of(context) + .extension()! + .textFieldDefaultBG, percent: 0, ), ], @@ -620,10 +662,16 @@ class _WalletNetworkSettingsViewState top: 12, ), child: RoundedContainer( - color: CFColors.warningBackground, + color: Theme.of(context) + .extension()! + .warningBackground, child: Text( "Please check your internet connection and make sure your current node is not having issues.", - style: STextStyles.baseXS, + style: STextStyles.baseXS(context).copyWith( + color: Theme.of(context) + .extension()! + .warningForeground, + ), ), ), ), @@ -636,7 +684,7 @@ class _WalletNetworkSettingsViewState Text( "${ref.watch(walletsChangeNotifierProvider.select((value) => value.getManager(widget.walletId).coin)).prettyName} nodes", textAlign: TextAlign.left, - style: STextStyles.smallMed12, + style: STextStyles.smallMed12(context), ), BlueTextButton( text: "Add new node", diff --git a/lib/pages/settings_views/wallet_settings_view/wallet_settings_view.dart b/lib/pages/settings_views/wallet_settings_view/wallet_settings_view.dart index 99f8c0214..6e5cdd5ed 100644 --- a/lib/pages/settings_views/wallet_settings_view/wallet_settings_view.dart +++ b/lib/pages/settings_views/wallet_settings_view/wallet_settings_view.dart @@ -22,10 +22,10 @@ import 'package:stackwallet/services/event_bus/events/global/node_connection_sta 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/utilities/assets.dart'; -import 'package:stackwallet/utilities/cfcolors.dart'; import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/enums/flush_bar_type.dart'; import 'package:stackwallet/utilities/text_styles.dart'; +import 'package:stackwallet/utilities/theme/stack_colors.dart'; import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart'; import 'package:stackwallet/widgets/rounded_white_container.dart'; import 'package:tuple/tuple.dart'; @@ -133,7 +133,7 @@ class _WalletSettingsViewState extends State { Widget build(BuildContext context) { debugPrint("BUILD: $runtimeType"); return Scaffold( - backgroundColor: CFColors.almostWhite, + backgroundColor: Theme.of(context).extension()!.background, appBar: AppBar( leading: AppBarBackButton( onPressed: () { @@ -142,7 +142,7 @@ class _WalletSettingsViewState extends State { ), title: Text( "Settings", - style: STextStyles.navBarTitle, + style: STextStyles.navBarTitle(context), ), ), body: LayoutBuilder( @@ -170,6 +170,7 @@ class _WalletSettingsViewState extends State { children: [ SettingsListButton( iconAssetName: Assets.svg.addressBook, + iconSize: 16, title: "Address book", onPressed: () { Navigator.of(context).pushNamed( @@ -183,6 +184,7 @@ class _WalletSettingsViewState extends State { ), SettingsListButton( iconAssetName: Assets.svg.node, + iconSize: 16, title: "Network", onPressed: () { Navigator.of(context).pushNamed( @@ -202,6 +204,7 @@ class _WalletSettingsViewState extends State { builder: (_, ref, __) { return SettingsListButton( iconAssetName: Assets.svg.lock, + iconSize: 16, title: "Wallet backup", onPressed: () async { final mnemonic = await ref @@ -245,6 +248,7 @@ class _WalletSettingsViewState extends State { SettingsListButton( iconAssetName: Assets.svg.downloadFolder, title: "Wallet settings", + iconSize: 16, onPressed: () { Navigator.of(context).pushNamed( WalletSettingsWalletSettingsView.routeName, @@ -297,17 +301,15 @@ class _WalletSettingsViewState extends State { ModalRoute.withName(HomeView.routeName), ); }, - style: ButtonStyle( - backgroundColor: - MaterialStateProperty.all( - CFColors.buttonGray, - ), - ), + style: Theme.of(context) + .extension()! + .getSecondaryEnabledButtonColor(context), child: Text( "Log out", - style: STextStyles.button.copyWith( - color: CFColors.stackAccent, - ), + style: STextStyles.button(context).copyWith( + color: Theme.of(context) + .extension()! + .accentColorDark), ), ); }, @@ -409,9 +411,10 @@ class _EpiBoxInfoFormState extends ConsumerState { }, child: Text( "Save", - style: STextStyles.button.copyWith( - color: CFColors.stackAccent, - ), + style: STextStyles.button(context).copyWith( + color: Theme.of(context) + .extension()! + .accentColorDark), ), ), ], diff --git a/lib/pages/settings_views/wallet_settings_view/wallet_settings_wallet_settings/delete_wallet_recovery_phrase_view.dart b/lib/pages/settings_views/wallet_settings_view/wallet_settings_wallet_settings/delete_wallet_recovery_phrase_view.dart index 2ad55ae68..66d666c20 100644 --- a/lib/pages/settings_views/wallet_settings_view/wallet_settings_wallet_settings/delete_wallet_recovery_phrase_view.dart +++ b/lib/pages/settings_views/wallet_settings_view/wallet_settings_wallet_settings/delete_wallet_recovery_phrase_view.dart @@ -8,11 +8,11 @@ import 'package:stackwallet/pages/home_view/home_view.dart'; import 'package:stackwallet/providers/providers.dart'; import 'package:stackwallet/services/coins/manager.dart'; import 'package:stackwallet/utilities/assets.dart'; -import 'package:stackwallet/utilities/cfcolors.dart'; import 'package:stackwallet/utilities/clipboard_interface.dart'; import 'package:stackwallet/utilities/constants.dart'; import 'package:stackwallet/utilities/enums/flush_bar_type.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/stack_dialog.dart'; @@ -55,7 +55,7 @@ class _DeleteWalletRecoveryPhraseViewState debugPrint("BUILD: $runtimeType"); return Scaffold( - backgroundColor: CFColors.almostWhite, + backgroundColor: Theme.of(context).extension()!.background, appBar: AppBar( leading: AppBarBackButton( onPressed: () { @@ -68,12 +68,15 @@ class _DeleteWalletRecoveryPhraseViewState child: AspectRatio( aspectRatio: 1, child: AppBarIconButton( - color: CFColors.almostWhite, + color: Theme.of(context).extension()!.background, shadows: const [], icon: SvgPicture.asset( Assets.svg.copy, width: 20, height: 20, + color: Theme.of(context) + .extension()! + .topNavIconPrimary, ), onPressed: () async { final words = await _manager.mnemonic; @@ -102,7 +105,7 @@ class _DeleteWalletRecoveryPhraseViewState Text( _manager.walletName, textAlign: TextAlign.center, - style: STextStyles.label.copyWith( + style: STextStyles.label(context).copyWith( fontSize: 12, ), ), @@ -112,14 +115,14 @@ class _DeleteWalletRecoveryPhraseViewState Text( "Recovery Phrase", textAlign: TextAlign.center, - style: STextStyles.pageTitleH1, + style: STextStyles.pageTitleH1(context), ), const SizedBox( height: 16, ), Container( decoration: BoxDecoration( - color: CFColors.white, + color: Theme.of(context).extension()!.popupBG, borderRadius: BorderRadius.circular(Constants.size.circularBorderRadius), ), @@ -127,9 +130,10 @@ class _DeleteWalletRecoveryPhraseViewState padding: const EdgeInsets.all(12), child: Text( "Please write down your recovery phrase in the correct order and save it to keep your funds secure. You will also be asked to verify the words on the next screen.", - style: STextStyles.label.copyWith( - color: CFColors.stackAccent, - ), + style: STextStyles.label(context).copyWith( + color: Theme.of(context) + .extension()! + .accentColorDark), ), ), ), @@ -140,6 +144,7 @@ class _DeleteWalletRecoveryPhraseViewState child: SingleChildScrollView( child: MnemonicTable( words: _mnemonic, + isDesktop: false, ), ), ), @@ -147,11 +152,9 @@ class _DeleteWalletRecoveryPhraseViewState height: 16, ), TextButton( - style: Theme.of(context).textButtonTheme.style?.copyWith( - backgroundColor: MaterialStateProperty.all( - CFColors.stackAccent, - ), - ), + style: Theme.of(context) + .extension()! + .getPrimaryEnabledButtonColor(context), onPressed: () { showDialog( barrierDismissible: true, @@ -159,27 +162,24 @@ class _DeleteWalletRecoveryPhraseViewState builder: (_) => StackDialog( title: "Thanks! Your wallet will be deleted.", leftButton: TextButton( - style: ButtonStyle( - backgroundColor: MaterialStateProperty.all( - CFColors.buttonGray, - ), - ), + style: Theme.of(context) + .extension()! + .getSecondaryEnabledButtonColor(context), onPressed: () { Navigator.pop(context); }, child: Text( "Cancel", - style: STextStyles.button.copyWith( - color: CFColors.stackAccent, - ), + style: STextStyles.button(context).copyWith( + color: Theme.of(context) + .extension()! + .accentColorDark), ), ), rightButton: TextButton( - style: Theme.of(context).textButtonTheme.style?.copyWith( - backgroundColor: MaterialStateProperty.all( - CFColors.stackAccent, - ), - ), + style: Theme.of(context) + .extension()! + .getPrimaryEnabledButtonColor(context), onPressed: () async { final walletId = _manager.walletId; final walletsInstance = @@ -199,7 +199,7 @@ class _DeleteWalletRecoveryPhraseViewState }, child: Text( "Ok", - style: STextStyles.button, + style: STextStyles.button(context), ), ), ), @@ -207,7 +207,7 @@ class _DeleteWalletRecoveryPhraseViewState }, child: Text( "Continue", - style: STextStyles.button, + style: STextStyles.button(context), ), ), ], diff --git a/lib/pages/settings_views/wallet_settings_view/wallet_settings_wallet_settings/delete_wallet_warning_view.dart b/lib/pages/settings_views/wallet_settings_view/wallet_settings_wallet_settings/delete_wallet_warning_view.dart index ea4013917..ec8c5a128 100644 --- a/lib/pages/settings_views/wallet_settings_view/wallet_settings_wallet_settings/delete_wallet_warning_view.dart +++ b/lib/pages/settings_views/wallet_settings_view/wallet_settings_wallet_settings/delete_wallet_warning_view.dart @@ -2,8 +2,8 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:stackwallet/pages/settings_views/wallet_settings_view/wallet_settings_wallet_settings/delete_wallet_recovery_phrase_view.dart'; import 'package:stackwallet/providers/providers.dart'; -import 'package:stackwallet/utilities/cfcolors.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/rounded_container.dart'; import 'package:tuple/tuple.dart'; @@ -21,7 +21,7 @@ class DeleteWalletWarningView extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { return Scaffold( - backgroundColor: CFColors.almostWhite, + backgroundColor: Theme.of(context).extension()!.background, appBar: AppBar( leading: AppBarBackButton( onPressed: () { @@ -44,45 +44,47 @@ class DeleteWalletWarningView extends ConsumerWidget { Center( child: Text( "Attention!", - style: STextStyles.pageTitleH1, + style: STextStyles.pageTitleH1(context), ), ), const SizedBox( height: 16, ), RoundedContainer( - color: CFColors.warningBackground, + color: + Theme.of(context).extension()!.warningBackground, child: Text( "You are going to permanently delete you wallet.\n\nIf you delete your wallet, the only way you can have access to your funds is by using your backup key.\n\nStack Wallet does not keep nor is able to restore your backup key or your wallet.\n\nPLEASE SAVE YOUR BACKUP KEY.", - style: STextStyles.baseXS, + style: STextStyles.baseXS(context).copyWith( + color: Theme.of(context) + .extension()! + .warningForeground, + ), ), ), const Spacer(), TextButton( - style: ButtonStyle( - backgroundColor: MaterialStateProperty.all( - CFColors.buttonGray, - ), - ), + style: Theme.of(context) + .extension()! + .getSecondaryEnabledButtonColor(context), onPressed: () { Navigator.pop(context); }, child: Text( "Cancel", - style: STextStyles.button.copyWith( - color: CFColors.stackAccent, - ), + style: STextStyles.button(context).copyWith( + color: Theme.of(context) + .extension()! + .accentColorDark), ), ), const SizedBox( height: 12, ), TextButton( - style: Theme.of(context).textButtonTheme.style?.copyWith( - backgroundColor: MaterialStateProperty.all( - CFColors.stackAccent, - ), - ), + style: Theme.of(context) + .extension()! + .getPrimaryEnabledButtonColor(context), onPressed: () async { final manager = ref .read(walletsChangeNotifierProvider) @@ -98,7 +100,7 @@ class DeleteWalletWarningView extends ConsumerWidget { }, child: Text( "View Backup Key", - style: STextStyles.button, + style: STextStyles.button(context), ), ), const SizedBox( diff --git a/lib/pages/settings_views/wallet_settings_view/wallet_settings_wallet_settings/rename_wallet_view.dart b/lib/pages/settings_views/wallet_settings_view/wallet_settings_wallet_settings/rename_wallet_view.dart index 1a474e75e..b876216e0 100644 --- a/lib/pages/settings_views/wallet_settings_view/wallet_settings_wallet_settings/rename_wallet_view.dart +++ b/lib/pages/settings_views/wallet_settings_view/wallet_settings_wallet_settings/rename_wallet_view.dart @@ -2,10 +2,10 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:stackwallet/notifications/show_flush_bar.dart'; import 'package:stackwallet/providers/providers.dart'; -import 'package:stackwallet/utilities/cfcolors.dart'; import 'package:stackwallet/utilities/constants.dart'; import 'package:stackwallet/utilities/enums/flush_bar_type.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/icon_widgets/x_icon.dart'; import 'package:stackwallet/widgets/stack_text_field.dart'; @@ -52,7 +52,7 @@ class _RenameWalletViewState extends ConsumerState { @override Widget build(BuildContext context) { return Scaffold( - backgroundColor: CFColors.almostWhite, + backgroundColor: Theme.of(context).extension()!.background, appBar: AppBar( leading: AppBarBackButton( onPressed: () { @@ -61,7 +61,7 @@ class _RenameWalletViewState extends ConsumerState { ), title: Text( "Rename wallet", - style: STextStyles.navBarTitle, + style: STextStyles.navBarTitle(context), ), ), body: Padding( @@ -76,11 +76,12 @@ class _RenameWalletViewState extends ConsumerState { child: TextField( controller: _controller, focusNode: _focusNode, - style: STextStyles.field, - onChanged: (_) => setState((){}), + style: STextStyles.field(context), + onChanged: (_) => setState(() {}), decoration: standardInputDecoration( "Wallet name", _focusNode, + context, ).copyWith( suffixIcon: _controller.text.isNotEmpty ? Padding( @@ -106,11 +107,9 @@ class _RenameWalletViewState extends ConsumerState { ), const Spacer(), TextButton( - style: Theme.of(context).textButtonTheme.style?.copyWith( - backgroundColor: MaterialStateProperty.all( - CFColors.stackAccent, - ), - ), + style: Theme.of(context) + .extension()! + .getPrimaryEnabledButtonColor(context), onPressed: () async { final newName = _controller.text; final success = await ref @@ -142,7 +141,7 @@ class _RenameWalletViewState extends ConsumerState { }, child: Text( "Save", - style: STextStyles.button, + style: STextStyles.button(context), ), ), ], diff --git a/lib/pages/settings_views/wallet_settings_view/wallet_settings_wallet_settings/wallet_settings_wallet_settings_view.dart b/lib/pages/settings_views/wallet_settings_view/wallet_settings_wallet_settings/wallet_settings_wallet_settings_view.dart index cca82f688..52aa6027a 100644 --- a/lib/pages/settings_views/wallet_settings_view/wallet_settings_wallet_settings/wallet_settings_wallet_settings_view.dart +++ b/lib/pages/settings_views/wallet_settings_view/wallet_settings_wallet_settings/wallet_settings_wallet_settings_view.dart @@ -5,9 +5,9 @@ import 'package:stackwallet/pages/settings_views/wallet_settings_view/wallet_set import 'package:stackwallet/pages/settings_views/wallet_settings_view/wallet_settings_wallet_settings/rename_wallet_view.dart'; import 'package:stackwallet/providers/providers.dart'; import 'package:stackwallet/route_generator.dart'; -import 'package:stackwallet/utilities/cfcolors.dart'; 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/rounded_white_container.dart'; import 'package:stackwallet/widgets/stack_dialog.dart'; @@ -25,7 +25,7 @@ class WalletSettingsWalletSettingsView extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { return Scaffold( - backgroundColor: CFColors.almostWhite, + backgroundColor: Theme.of(context).extension()!.background, appBar: AppBar( leading: AppBarBackButton( onPressed: () { @@ -34,7 +34,7 @@ class WalletSettingsWalletSettingsView extends ConsumerWidget { ), title: Text( "Wallet settings", - style: STextStyles.navBarTitle, + style: STextStyles.navBarTitle(context), ), ), body: Padding( @@ -50,7 +50,7 @@ class WalletSettingsWalletSettingsView extends ConsumerWidget { RoundedWhiteContainer( padding: const EdgeInsets.all(0), child: RawMaterialButton( - // splashColor: CFColors.splashLight, + // splashColor: Theme.of(context).extension()!.highlight, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular( Constants.size.circularBorderRadius, @@ -72,7 +72,7 @@ class WalletSettingsWalletSettingsView extends ConsumerWidget { children: [ Text( "Rename wallet", - style: STextStyles.titleBold12, + style: STextStyles.titleBold12(context), ), ], ), @@ -85,7 +85,7 @@ class WalletSettingsWalletSettingsView extends ConsumerWidget { RoundedWhiteContainer( padding: const EdgeInsets.all(0), child: RawMaterialButton( - // splashColor: CFColors.splashLight, + // splashColor: Theme.of(context).extension()!.highlight, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular( Constants.size.circularBorderRadius, @@ -101,29 +101,24 @@ class WalletSettingsWalletSettingsView extends ConsumerWidget { title: "Do you want to delete ${ref.read(walletsChangeNotifierProvider).getManager(walletId).walletName}?", leftButton: TextButton( - style: ButtonStyle( - backgroundColor: MaterialStateProperty.all( - CFColors.buttonGray, - ), - ), + style: Theme.of(context) + .extension()! + .getSecondaryEnabledButtonColor(context), onPressed: () { Navigator.pop(context); }, child: Text( "Cancel", - style: STextStyles.button.copyWith( - color: CFColors.stackAccent, - ), + style: STextStyles.button(context).copyWith( + color: Theme.of(context) + .extension()! + .accentColorDark), ), ), rightButton: TextButton( - style: - Theme.of(context).textButtonTheme.style?.copyWith( - backgroundColor: - MaterialStateProperty.all( - CFColors.stackAccent, - ), - ), + style: Theme.of(context) + .extension()! + .getPrimaryEnabledButtonColor(context), onPressed: () { Navigator.pop(context); Navigator.push( @@ -149,7 +144,7 @@ class WalletSettingsWalletSettingsView extends ConsumerWidget { }, child: Text( "Delete", - style: STextStyles.button, + style: STextStyles.button(context), ), ), ), @@ -164,7 +159,7 @@ class WalletSettingsWalletSettingsView extends ConsumerWidget { children: [ Text( "Delete wallet", - style: STextStyles.titleBold12, + style: STextStyles.titleBold12(context), ), ], ), diff --git a/lib/pages/wallet_view/sub_widgets/no_transactions_found.dart b/lib/pages/wallet_view/sub_widgets/no_transactions_found.dart index aa7019fe9..35aa1eaf2 100644 --- a/lib/pages/wallet_view/sub_widgets/no_transactions_found.dart +++ b/lib/pages/wallet_view/sub_widgets/no_transactions_found.dart @@ -15,7 +15,7 @@ class NoTransActionsFound extends StatelessWidget { fit: BoxFit.scaleDown, child: Text( "Transactions will appear here", - style: STextStyles.itemSubtitle, + style: STextStyles.itemSubtitle(context), ), ), ), diff --git a/lib/pages/wallet_view/sub_widgets/transactions_list.dart b/lib/pages/wallet_view/sub_widgets/transactions_list.dart index efc3e74e5..bda060071 100644 --- a/lib/pages/wallet_view/sub_widgets/transactions_list.dart +++ b/lib/pages/wallet_view/sub_widgets/transactions_list.dart @@ -6,8 +6,8 @@ import 'package:stackwallet/models/paymint/transactions_model.dart'; import 'package:stackwallet/pages/wallet_view/sub_widgets/no_transactions_found.dart'; import 'package:stackwallet/providers/global/wallets_provider.dart'; import 'package:stackwallet/services/coins/manager.dart'; -import 'package:stackwallet/utilities/cfcolors.dart'; import 'package:stackwallet/utilities/constants.dart'; +import 'package:stackwallet/utilities/theme/stack_colors.dart'; import 'package:stackwallet/widgets/loading_indicator.dart'; import 'package:stackwallet/widgets/transaction_card.dart'; @@ -127,7 +127,7 @@ class _TransactionsListState extends ConsumerState { final tx = list[index]; return Container( decoration: BoxDecoration( - color: CFColors.white, + color: Theme.of(context).extension()!.popupBG, borderRadius: radius, ), child: TransactionCard( diff --git a/lib/pages/wallet_view/sub_widgets/tx_icon.dart b/lib/pages/wallet_view/sub_widgets/tx_icon.dart index 45b4e610d..6222301a6 100644 --- a/lib/pages/wallet_view/sub_widgets/tx_icon.dart +++ b/lib/pages/wallet_view/sub_widgets/tx_icon.dart @@ -9,7 +9,8 @@ class TxIcon extends StatelessWidget { static const Size size = Size(32, 32); - String _getAssetName(bool isCancelled, bool isReceived, bool isPending) { + String _getAssetName( + bool isCancelled, bool isReceived, bool isPending, BuildContext context) { if (!isReceived && transaction.subType == "mint") { if (isCancelled) { return Assets.svg.anonymizeFailed; @@ -22,20 +23,20 @@ class TxIcon extends StatelessWidget { if (isReceived) { if (isCancelled) { - return Assets.svg.receiveCancelled; + return Assets.svg.receiveCancelled(context); } if (isPending) { - return Assets.svg.receivePending; + return Assets.svg.receivePending(context); } - return Assets.svg.receive; + return Assets.svg.receive(context); } else { if (isCancelled) { - return Assets.svg.sendCancelled; + return Assets.svg.sendCancelled(context); } if (isPending) { - return Assets.svg.sendPending; + return Assets.svg.sendPending(context); } - return Assets.svg.send; + return Assets.svg.send(context); } } @@ -52,6 +53,7 @@ class TxIcon extends StatelessWidget { transaction.isCancelled, txIsReceived, !transaction.confirmedStatus, + context, ), width: size.width, height: size.height, diff --git a/lib/pages/wallet_view/sub_widgets/wallet_balance_toggle_sheet.dart b/lib/pages/wallet_view/sub_widgets/wallet_balance_toggle_sheet.dart index 1d51aa74d..afdac6d8e 100644 --- a/lib/pages/wallet_view/sub_widgets/wallet_balance_toggle_sheet.dart +++ b/lib/pages/wallet_view/sub_widgets/wallet_balance_toggle_sheet.dart @@ -2,11 +2,11 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:stackwallet/providers/providers.dart'; import 'package:stackwallet/providers/wallet/wallet_balance_toggle_state_provider.dart'; -import 'package:stackwallet/utilities/cfcolors.dart'; import 'package:stackwallet/utilities/constants.dart'; import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/enums/wallet_balance_toggle_state.dart'; import 'package:stackwallet/utilities/text_styles.dart'; +import 'package:stackwallet/utilities/theme/stack_colors.dart'; class WalletBalanceToggleSheet extends ConsumerWidget { const WalletBalanceToggleSheet({ @@ -24,9 +24,9 @@ class WalletBalanceToggleSheet extends ConsumerWidget { .select((value) => value.getManager(walletId).coin)); return Container( - decoration: const BoxDecoration( - color: CFColors.white, - borderRadius: BorderRadius.vertical( + decoration: BoxDecoration( + color: Theme.of(context).extension()!.popupBG, + borderRadius: const BorderRadius.vertical( top: Radius.circular(20), ), ), @@ -46,7 +46,9 @@ class WalletBalanceToggleSheet extends ConsumerWidget { Center( child: Container( decoration: BoxDecoration( - color: CFColors.fieldGray, + color: Theme.of(context) + .extension()! + .textFieldDefaultBG, borderRadius: BorderRadius.circular( Constants.size.circularBorderRadius, ), @@ -62,7 +64,7 @@ class WalletBalanceToggleSheet extends ConsumerWidget { padding: const EdgeInsets.only(left: 8.0), child: Text( "Wallet balance", - style: STextStyles.pageTitleH2, + style: STextStyles.pageTitleH2(context), textAlign: TextAlign.left, ), ), @@ -94,7 +96,9 @@ class WalletBalanceToggleSheet extends ConsumerWidget { width: 20, height: 20, child: Radio( - activeColor: CFColors.link2, + activeColor: Theme.of(context) + .extension()! + .radioButtonIconEnabled, value: WalletBalanceToggleState.available, groupValue: ref .watch(walletBalanceToggleStateProvider.state) @@ -116,15 +120,18 @@ class WalletBalanceToggleSheet extends ConsumerWidget { children: [ Text( "Available balance", - style: STextStyles.titleBold12, + style: STextStyles.titleBold12(context), ), const SizedBox( height: 2, ), Text( "Current spendable (unlocked) balance", - style: STextStyles.itemSubtitle12.copyWith( - color: CFColors.neutral60, + style: + STextStyles.itemSubtitle12(context).copyWith( + color: Theme.of(context) + .extension()! + .textSubtitle1, ), ), ], @@ -135,15 +142,18 @@ class WalletBalanceToggleSheet extends ConsumerWidget { children: [ Text( "Private balance", - style: STextStyles.titleBold12, + style: STextStyles.titleBold12(context), ), const SizedBox( height: 2, ), Text( "Current private spendable (unlocked) balance", - style: STextStyles.itemSubtitle12.copyWith( - color: CFColors.neutral60, + style: + STextStyles.itemSubtitle12(context).copyWith( + color: Theme.of(context) + .extension()! + .textSubtitle1, ), ), ], @@ -180,7 +190,9 @@ class WalletBalanceToggleSheet extends ConsumerWidget { width: 20, height: 20, child: Radio( - activeColor: CFColors.link2, + activeColor: Theme.of(context) + .extension()! + .radioButtonIconEnabled, value: WalletBalanceToggleState.full, groupValue: ref .watch(walletBalanceToggleStateProvider.state) @@ -202,15 +214,18 @@ class WalletBalanceToggleSheet extends ConsumerWidget { children: [ Text( "Full balance", - style: STextStyles.titleBold12, + style: STextStyles.titleBold12(context), ), const SizedBox( height: 2, ), Text( "Total wallet balance", - style: STextStyles.itemSubtitle12.copyWith( - color: CFColors.neutral60, + style: + STextStyles.itemSubtitle12(context).copyWith( + color: Theme.of(context) + .extension()! + .textSubtitle1, ), ), ], @@ -221,15 +236,18 @@ class WalletBalanceToggleSheet extends ConsumerWidget { children: [ Text( "Public balance", - style: STextStyles.titleBold12, + style: STextStyles.titleBold12(context), ), const SizedBox( height: 2, ), Text( "Current public spendable (unlocked) balance", - style: STextStyles.itemSubtitle12.copyWith( - color: CFColors.neutral60, + style: + STextStyles.itemSubtitle12(context).copyWith( + color: Theme.of(context) + .extension()! + .textSubtitle1, ), ), ], 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 da817069f..b82992673 100644 --- a/lib/pages/wallet_view/sub_widgets/wallet_navigation_bar.dart +++ b/lib/pages/wallet_view/sub_widgets/wallet_navigation_bar.dart @@ -1,8 +1,8 @@ import 'package:flutter/material.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:stackwallet/utilities/assets.dart'; -import 'package:stackwallet/utilities/cfcolors.dart'; import 'package:stackwallet/utilities/text_styles.dart'; +import 'package:stackwallet/utilities/theme/stack_colors.dart'; class WalletNavigationBar extends StatelessWidget { const WalletNavigationBar({ @@ -27,8 +27,10 @@ class WalletNavigationBar extends StatelessWidget { return Container( height: height, decoration: BoxDecoration( - color: CFColors.white, - boxShadow: const [CFColors.standardBoxShadow], + color: Theme.of(context).extension()!.popupBG, + boxShadow: [ + Theme.of(context).extension()!.standardBoxShadow + ], borderRadius: BorderRadius.circular( height / 2.0, ), @@ -49,7 +51,8 @@ class WalletNavigationBar extends StatelessWidget { minWidth: 66, ), onPressed: onReceivePressed, - splashColor: CFColors.splashLight, + splashColor: + Theme.of(context).extension()!.highlight, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular( height / 2.0, @@ -65,7 +68,10 @@ class WalletNavigationBar extends StatelessWidget { const Spacer(), Container( decoration: BoxDecoration( - color: CFColors.stackAccent.withOpacity(0.4), + color: Theme.of(context) + .extension()! + .accentColorDark + .withOpacity(0.4), borderRadius: BorderRadius.circular( 24, ), @@ -76,7 +82,9 @@ class WalletNavigationBar extends StatelessWidget { Assets.svg.arrowDownLeft, width: 12, height: 12, - color: CFColors.stackAccent, + color: Theme.of(context) + .extension()! + .accentColorDark, ), ), ), @@ -85,7 +93,7 @@ class WalletNavigationBar extends StatelessWidget { ), Text( "Receive", - style: STextStyles.buttonSmall, + style: STextStyles.buttonSmall(context), ), const Spacer(), ], @@ -98,7 +106,8 @@ class WalletNavigationBar extends StatelessWidget { minWidth: 66, ), onPressed: onSendPressed, - splashColor: CFColors.splashLight, + splashColor: + Theme.of(context).extension()!.highlight, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular( height / 2.0, @@ -114,7 +123,10 @@ class WalletNavigationBar extends StatelessWidget { const Spacer(), Container( decoration: BoxDecoration( - color: CFColors.stackAccent.withOpacity(0.4), + color: Theme.of(context) + .extension()! + .accentColorDark + .withOpacity(0.4), borderRadius: BorderRadius.circular( 24, ), @@ -125,7 +137,9 @@ class WalletNavigationBar extends StatelessWidget { Assets.svg.arrowUpRight, width: 12, height: 12, - color: CFColors.stackAccent, + color: Theme.of(context) + .extension()! + .accentColorDark, ), ), ), @@ -134,7 +148,7 @@ class WalletNavigationBar extends StatelessWidget { ), Text( "Send", - style: STextStyles.buttonSmall, + style: STextStyles.buttonSmall(context), ), const Spacer(), ], @@ -148,7 +162,8 @@ class WalletNavigationBar extends StatelessWidget { minWidth: 66, ), onPressed: onExchangePressed, - splashColor: CFColors.splashLight, + splashColor: + Theme.of(context).extension()!.highlight, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular( height / 2.0, @@ -163,7 +178,7 @@ class WalletNavigationBar extends StatelessWidget { children: [ const Spacer(), SvgPicture.asset( - Assets.svg.exchange, + Assets.svg.exchange(context), width: 24, height: 24, ), @@ -172,7 +187,7 @@ class WalletNavigationBar extends StatelessWidget { ), Text( "Exchange", - style: STextStyles.buttonSmall, + style: STextStyles.buttonSmall(context), ), const Spacer(), ], @@ -208,7 +223,7 @@ class WalletNavigationBar extends StatelessWidget { // ), // Text( // "Buy", - // style: STextStyles.buttonSmall, + // style: STextStyles.buttonSmall(context), // ), // Spacer(), // ], @@ -236,7 +251,7 @@ class WalletNavigationBar extends StatelessWidget { // Widget build(BuildContext context) { // return Container( // child: MaterialButton( -// splashColor: CFColors.splashLight, +// splashColor: Theme.of(context).extension()!.highlight, // padding: const EdgeInsets.all(0), // minWidth: 45, // shape: RoundedRectangleBorder( @@ -257,7 +272,7 @@ class WalletNavigationBar extends StatelessWidget { // ), // Text( // text, -// style: STextStyles.itemSubtitle12.copyWith( +// style: STextStyles.itemSubtitle12(context).copyWith( // fontSize: 10, // ), // ), diff --git a/lib/pages/wallet_view/sub_widgets/wallet_refresh_button.dart b/lib/pages/wallet_view/sub_widgets/wallet_refresh_button.dart index d03e83803..7faae106f 100644 --- a/lib/pages/wallet_view/sub_widgets/wallet_refresh_button.dart +++ b/lib/pages/wallet_view/sub_widgets/wallet_refresh_button.dart @@ -8,8 +8,8 @@ import 'package:stackwallet/providers/global/wallets_provider.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/utilities/assets.dart'; -import 'package:stackwallet/utilities/cfcolors.dart'; import 'package:stackwallet/utilities/constants.dart'; +import 'package:stackwallet/utilities/theme/stack_colors.dart'; /// [eventBus] should only be set during testing class WalletRefreshButton extends ConsumerStatefulWidget { @@ -96,7 +96,7 @@ class _RefreshButtonState extends ConsumerState height: 36, width: 36, child: MaterialButton( - splashColor: CFColors.splashLight, + splashColor: Theme.of(context).extension()!.highlight, onPressed: () { final managerProvider = ref .read(walletsChangeNotifierProvider) @@ -123,7 +123,7 @@ class _RefreshButtonState extends ConsumerState Assets.svg.arrowRotate, width: 24, height: 24, - color: CFColors.stackAccent, + color: Theme.of(context).extension()!.textFavoriteCard, ), ), ), diff --git a/lib/pages/wallet_view/sub_widgets/wallet_summary.dart b/lib/pages/wallet_view/sub_widgets/wallet_summary.dart index 786748356..2a5beb705 100644 --- a/lib/pages/wallet_view/sub_widgets/wallet_summary.dart +++ b/lib/pages/wallet_view/sub_widgets/wallet_summary.dart @@ -5,8 +5,8 @@ import 'package:stackwallet/pages/wallet_view/sub_widgets/wallet_summary_info.da import 'package:stackwallet/services/coins/manager.dart'; import 'package:stackwallet/services/event_bus/events/global/wallet_sync_status_changed_event.dart'; import 'package:stackwallet/utilities/assets.dart'; -import 'package:stackwallet/utilities/cfcolors.dart'; import 'package:stackwallet/utilities/constants.dart'; +import 'package:stackwallet/utilities/theme/stack_colors.dart'; class WalletSummary extends StatelessWidget { const WalletSummary({ @@ -48,7 +48,7 @@ class WalletSummary extends StatelessWidget { builder: (_, ref, __) { return Container( decoration: BoxDecoration( - color: CFColors.coin.forCoin(ref + color: Theme.of(context).extension()!.colorForCoin(ref .watch(managerProvider.select((value) => value.coin))), borderRadius: BorderRadius.circular( Constants.size.circularBorderRadius, diff --git a/lib/pages/wallet_view/sub_widgets/wallet_summary_info.dart b/lib/pages/wallet_view/sub_widgets/wallet_summary_info.dart index 8687e8a59..9b4c384b5 100644 --- a/lib/pages/wallet_view/sub_widgets/wallet_summary_info.dart +++ b/lib/pages/wallet_view/sub_widgets/wallet_summary_info.dart @@ -10,11 +10,11 @@ import 'package:stackwallet/services/coins/firo/firo_wallet.dart'; import 'package:stackwallet/services/coins/manager.dart'; import 'package:stackwallet/services/event_bus/events/global/wallet_sync_status_changed_event.dart'; import 'package:stackwallet/utilities/assets.dart'; -import 'package:stackwallet/utilities/cfcolors.dart'; import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/enums/wallet_balance_toggle_state.dart'; import 'package:stackwallet/utilities/format.dart'; import 'package:stackwallet/utilities/text_styles.dart'; +import 'package:stackwallet/utilities/theme/stack_colors.dart'; import 'package:stackwallet/widgets/animated_text.dart'; class WalletSummaryInfo extends StatefulWidget { @@ -128,15 +128,21 @@ class _WalletSummaryInfoState extends State { if (coin == Coin.firo || coin == Coin.firoTestNet) Text( "${_showAvailable ? "Private" : "Public"} Balance", - style: STextStyles.subtitle.copyWith( + style: STextStyles.subtitle(context).copyWith( fontWeight: FontWeight.w500, + color: Theme.of(context) + .extension()! + .textFavoriteCard, ), ), if (coin != Coin.firo && coin != Coin.firoTestNet) Text( "${_showAvailable ? "Available" : "Full"} Balance", - style: STextStyles.subtitle.copyWith( + style: STextStyles.subtitle(context).copyWith( fontWeight: FontWeight.w500, + color: Theme.of(context) + .extension()! + .textFavoriteCard, ), ), const SizedBox( @@ -144,7 +150,9 @@ class _WalletSummaryInfoState extends State { ), SvgPicture.asset( Assets.svg.chevronDown, - color: CFColors.stackAccent, + color: Theme.of(context) + .extension()! + .textFavoriteCard, width: 8, height: 4, ), @@ -160,8 +168,11 @@ class _WalletSummaryInfoState extends State { locale: locale, decimalPlaces: 8, )} ${coin.ticker}", - style: STextStyles.pageTitleH1.copyWith( + style: STextStyles.pageTitleH1(context).copyWith( fontSize: 24, + color: Theme.of(context) + .extension()! + .textFavoriteCard, ), ), ), @@ -171,8 +182,11 @@ class _WalletSummaryInfoState extends State { locale: locale, decimalPlaces: 2, )} $baseCurrency", - style: STextStyles.subtitle.copyWith( + style: STextStyles.subtitle(context).copyWith( fontWeight: FontWeight.w500, + color: Theme.of(context) + .extension()! + .textFavoriteCard, ), ), ], @@ -188,15 +202,21 @@ class _WalletSummaryInfoState extends State { if (coin == Coin.firo || coin == Coin.firoTestNet) Text( "${_showAvailable ? "Private" : "Public"} Balance", - style: STextStyles.subtitle.copyWith( + style: STextStyles.subtitle(context).copyWith( fontWeight: FontWeight.w500, + color: Theme.of(context) + .extension()! + .textFavoriteCard, ), ), if (coin != Coin.firo && coin != Coin.firoTestNet) Text( "${_showAvailable ? "Available" : "Full"} Balance", - style: STextStyles.subtitle.copyWith( + style: STextStyles.subtitle(context).copyWith( fontWeight: FontWeight.w500, + color: Theme.of(context) + .extension()! + .textFavoriteCard, ), ), const SizedBox( @@ -204,9 +224,11 @@ class _WalletSummaryInfoState extends State { ), SvgPicture.asset( Assets.svg.chevronDown, - color: CFColors.stackAccent, width: 8, height: 4, + color: Theme.of(context) + .extension()! + .textFavoriteCard, ), ], ), @@ -219,8 +241,11 @@ class _WalletSummaryInfoState extends State { "Loading balance..", "Loading balance..." ], - style: STextStyles.pageTitleH1.copyWith( + style: STextStyles.pageTitleH1(context).copyWith( fontSize: 24, + color: Theme.of(context) + .extension()! + .textFavoriteCard, ), ), AnimatedText( @@ -230,8 +255,11 @@ class _WalletSummaryInfoState extends State { "Loading balance..", "Loading balance..." ], - style: STextStyles.subtitle.copyWith( + style: STextStyles.subtitle(context).copyWith( fontWeight: FontWeight.w500, + color: Theme.of(context) + .extension()! + .textFavoriteCard, ), ), ], diff --git a/lib/pages/wallet_view/transaction_views/all_transactions_view.dart b/lib/pages/wallet_view/transaction_views/all_transactions_view.dart index b2c3c4383..78f24ba6a 100644 --- a/lib/pages/wallet_view/transaction_views/all_transactions_view.dart +++ b/lib/pages/wallet_view/transaction_views/all_transactions_view.dart @@ -9,9 +9,9 @@ import 'package:stackwallet/providers/global/address_book_service_provider.dart' import 'package:stackwallet/providers/providers.dart'; import 'package:stackwallet/providers/ui/transaction_filter_provider.dart'; import 'package:stackwallet/utilities/assets.dart'; -import 'package:stackwallet/utilities/cfcolors.dart'; 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/icon_widgets/x_icon.dart'; import 'package:stackwallet/widgets/loading_indicator.dart'; @@ -165,9 +165,9 @@ class _TransactionDetailsViewState extends ConsumerState { @override Widget build(BuildContext context) { return Scaffold( - backgroundColor: CFColors.almostWhite, + backgroundColor: Theme.of(context).extension()!.background, appBar: AppBar( - backgroundColor: CFColors.almostWhite, + backgroundColor: Theme.of(context).extension()!.background, leading: AppBarBackButton( onPressed: () async { if (FocusScope.of(context).hasFocus) { @@ -181,7 +181,7 @@ class _TransactionDetailsViewState extends ConsumerState { ), title: Text( "Transactions", - style: STextStyles.navBarTitle, + style: STextStyles.navBarTitle(context), ), actions: [ Padding( @@ -196,10 +196,12 @@ class _TransactionDetailsViewState extends ConsumerState { key: const Key("transactionSearchFilterViewButton"), size: 36, shadows: const [], - color: CFColors.almostWhite, + color: Theme.of(context).extension()!.background, icon: SvgPicture.asset( Assets.svg.filter, - color: CFColors.stackAccent, + color: Theme.of(context) + .extension()! + .accentColorDark, width: 20, height: 20, ), @@ -239,10 +241,11 @@ class _TransactionDetailsViewState extends ConsumerState { _searchString = value; }); }, - style: STextStyles.field, + style: STextStyles.field(context), decoration: standardInputDecoration( "Search", searchFieldFocusNode, + context, ).copyWith( prefixIcon: Padding( padding: const EdgeInsets.symmetric( @@ -324,7 +327,7 @@ class _TransactionDetailsViewState extends ConsumerState { ), Text( month.item1, - style: STextStyles.smallMed12, + style: STextStyles.smallMed12(context), ), const SizedBox( height: 12, diff --git a/lib/pages/wallet_view/transaction_views/dialogs/cancelling_transaction_progress_dialog.dart b/lib/pages/wallet_view/transaction_views/dialogs/cancelling_transaction_progress_dialog.dart index 27c294495..7d737ab41 100644 --- a/lib/pages/wallet_view/transaction_views/dialogs/cancelling_transaction_progress_dialog.dart +++ b/lib/pages/wallet_view/transaction_views/dialogs/cancelling_transaction_progress_dialog.dart @@ -1,8 +1,7 @@ -import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_svg/svg.dart'; import 'package:stackwallet/utilities/assets.dart'; -import 'package:stackwallet/utilities/cfcolors.dart'; +import 'package:stackwallet/utilities/theme/stack_colors.dart'; import 'package:stackwallet/widgets/stack_dialog.dart'; class CancellingTransactionProgressDialog extends StatefulWidget { @@ -57,7 +56,7 @@ class _CancellingTransactionProgressDialogState Assets.svg.arrowRotate3, width: 24, height: 24, - color: CFColors.stackAccent, + color: Theme.of(context).extension()!.accentColorDark, ), ), // rightButton: TextButton( @@ -68,7 +67,7 @@ class _CancellingTransactionProgressDialogState // ), // child: Text( // "Cancel", - // style: STextStyles.itemSubtitle12, + // style: STextStyles.itemSubtitle12(context), // ), // onPressed: () { // Navigator.of(context).pop(); diff --git a/lib/pages/wallet_view/transaction_views/edit_note_view.dart b/lib/pages/wallet_view/transaction_views/edit_note_view.dart index 532b814f7..aa085429b 100644 --- a/lib/pages/wallet_view/transaction_views/edit_note_view.dart +++ b/lib/pages/wallet_view/transaction_views/edit_note_view.dart @@ -1,9 +1,9 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:stackwallet/providers/providers.dart'; -import 'package:stackwallet/utilities/cfcolors.dart'; 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/icon_widgets/x_icon.dart'; import 'package:stackwallet/widgets/stack_text_field.dart'; @@ -48,9 +48,10 @@ class _EditNoteViewState extends ConsumerState { @override Widget build(BuildContext context) { return Scaffold( - backgroundColor: CFColors.almostWhite, + backgroundColor: Theme.of(context).extension()!.background, appBar: AppBar( - backgroundColor: CFColors.almostWhite, + backgroundColor: + Theme.of(context).extension()!.background, leading: AppBarBackButton( onPressed: () async { if (FocusScope.of(context).hasFocus) { @@ -64,7 +65,7 @@ class _EditNoteViewState extends ConsumerState { ), title: Text( "Edit note", - style: STextStyles.navBarTitle, + style: STextStyles.navBarTitle(context), ), ), body: Padding( @@ -87,11 +88,12 @@ class _EditNoteViewState extends ConsumerState { ), child: TextField( controller: _noteController, - style: STextStyles.field, + style: STextStyles.field(context), focusNode: noteFieldFocusNode, decoration: standardInputDecoration( "Note", noteFieldFocusNode, + context, ).copyWith( suffixIcon: _noteController.text.isNotEmpty ? Padding( @@ -129,16 +131,12 @@ class _EditNoteViewState extends ConsumerState { Navigator.of(context).pop(); } }, - style: - Theme.of(context).textButtonTheme.style?.copyWith( - backgroundColor: - MaterialStateProperty.all( - CFColors.stackAccent, - ), - ), + style: Theme.of(context) + .extension()! + .getPrimaryEnabledButtonColor(context), child: Text( "Save", - style: STextStyles.button, + style: STextStyles.button(context), ), ) ], diff --git a/lib/pages/wallet_view/transaction_views/transaction_details_view.dart b/lib/pages/wallet_view/transaction_views/transaction_details_view.dart index 3bed97db6..391b5caec 100644 --- a/lib/pages/wallet_view/transaction_views/transaction_details_view.dart +++ b/lib/pages/wallet_view/transaction_views/transaction_details_view.dart @@ -16,13 +16,13 @@ import 'package:stackwallet/services/coins/epiccash/epiccash_wallet.dart'; import 'package:stackwallet/services/coins/manager.dart'; import 'package:stackwallet/utilities/assets.dart'; import 'package:stackwallet/utilities/block_explorers.dart'; -import 'package:stackwallet/utilities/cfcolors.dart'; import 'package:stackwallet/utilities/constants.dart'; import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/enums/flush_bar_type.dart'; import 'package:stackwallet/utilities/format.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/custom_buttons/app_bar_icon_button.dart'; import 'package:stackwallet/widgets/custom_buttons/blue_text_button.dart'; import 'package:stackwallet/widgets/rounded_white_container.dart'; @@ -169,7 +169,7 @@ class _TransactionDetailsViewState }), Text( "Never show again", - style: STextStyles.smallMed14, + style: STextStyles.smallMed14(context), ) ], ), @@ -179,23 +179,22 @@ class _TransactionDetailsViewState }, child: Text( "Cancel", - style: STextStyles.button.copyWith( - color: CFColors.stackAccent, - ), + style: STextStyles.button(context).copyWith( + color: Theme.of(context) + .extension()! + .accentColorDark), ), ), rightButton: TextButton( - style: Theme.of(context).textButtonTheme.style?.copyWith( - backgroundColor: MaterialStateProperty.all( - CFColors.stackAccent, - ), - ), + style: Theme.of(context) + .extension()! + .getPrimaryEnabledButtonColor(context), onPressed: () { Navigator.of(context).pop(true); }, child: Text( "Continue", - style: STextStyles.button, + style: STextStyles.button(context), ), ), ), @@ -206,9 +205,9 @@ class _TransactionDetailsViewState @override Widget build(BuildContext context) { return Scaffold( - backgroundColor: CFColors.almostWhite, + backgroundColor: Theme.of(context).extension()!.background, appBar: AppBar( - backgroundColor: CFColors.almostWhite, + backgroundColor: Theme.of(context).extension()!.background, leading: AppBarBackButton( onPressed: () async { // if (FocusScope.of(context).hasFocus) { @@ -220,7 +219,7 @@ class _TransactionDetailsViewState ), title: Text( "Transaction details", - style: STextStyles.navBarTitle, + style: STextStyles.navBarTitle(context), ), ), body: Padding( @@ -249,7 +248,7 @@ class _TransactionDetailsViewState ), decimalPlaces: Constants.decimalPlaces, )} ${coin.ticker}", - style: STextStyles.titleBold12, + style: STextStyles.titleBold12(context), ), const SizedBox( height: 2, @@ -263,7 +262,7 @@ class _TransactionDetailsViewState (value) => value.currency, ), )}", - style: STextStyles.itemSubtitle, + style: STextStyles.itemSubtitle(context), ), ], ), @@ -282,7 +281,7 @@ class _TransactionDetailsViewState children: [ Text( "Status", - style: STextStyles.itemSubtitle, + style: STextStyles.itemSubtitle(context), ), // Flexible( // child: FittedBox( @@ -292,7 +291,7 @@ class _TransactionDetailsViewState _transaction.isCancelled ? "Cancelled" : whatIsIt(_transaction.txType), - style: STextStyles.itemSubtitle12, + style: STextStyles.itemSubtitle12(context), ), // ), // ), @@ -318,7 +317,7 @@ class _TransactionDetailsViewState _transaction.txType.toLowerCase() == "sent" ? "Sent to" : "Received on", - style: STextStyles.itemSubtitle, + style: STextStyles.itemSubtitle(context), ), const SizedBox( height: 8, @@ -338,13 +337,13 @@ class _TransactionDetailsViewState } return SelectableText( addressOrContactName, - style: STextStyles.itemSubtitle12, + style: STextStyles.itemSubtitle12(context), ); }, ) : SelectableText( _transaction.address, - style: STextStyles.itemSubtitle12, + style: STextStyles.itemSubtitle12(context), ), ], ), @@ -361,7 +360,7 @@ class _TransactionDetailsViewState children: [ Text( "Note", - style: STextStyles.itemSubtitle, + style: STextStyles.itemSubtitle(context), ), GestureDetector( onTap: () { @@ -380,14 +379,16 @@ class _TransactionDetailsViewState Assets.svg.pencil, width: 10, height: 10, - color: CFColors.link2, + color: Theme.of(context) + .extension()! + .infoItemIcons, ), const SizedBox( width: 4, ), Text( "Edit", - style: STextStyles.link2, + style: STextStyles.link2(context), ), ], ), @@ -411,7 +412,7 @@ class _TransactionDetailsViewState } return SelectableText( _note, - style: STextStyles.itemSubtitle12, + style: STextStyles.itemSubtitle12(context), ); }, ), @@ -427,7 +428,7 @@ class _TransactionDetailsViewState children: [ Text( "Date", - style: STextStyles.itemSubtitle, + style: STextStyles.itemSubtitle(context), ), // Flexible( // child: FittedBox( @@ -435,7 +436,7 @@ class _TransactionDetailsViewState // child: SelectableText( Format.extractDateFrom(_transaction.timestamp), - style: STextStyles.itemSubtitle12, + style: STextStyles.itemSubtitle12(context), ), // ), // ), @@ -451,7 +452,7 @@ class _TransactionDetailsViewState children: [ Text( "Transaction fee", - style: STextStyles.itemSubtitle, + style: STextStyles.itemSubtitle(context), ), // Flexible( // child: FittedBox( @@ -477,7 +478,7 @@ class _TransactionDetailsViewState localeServiceChangeNotifierProvider .select((value) => value.locale)), decimalPlaces: Constants.decimalPlaces), - style: STextStyles.itemSubtitle12, + style: STextStyles.itemSubtitle12(context), ), // ), // ), @@ -493,7 +494,7 @@ class _TransactionDetailsViewState children: [ Text( "Block height", - style: STextStyles.itemSubtitle, + style: STextStyles.itemSubtitle(context), ), // Flexible( // child: FittedBox( @@ -506,7 +507,7 @@ class _TransactionDetailsViewState : _transaction.confirmations > 0 ? "${_transaction.height}" : "Pending", - style: STextStyles.itemSubtitle12, + style: STextStyles.itemSubtitle12(context), ), // ), // ), @@ -525,7 +526,7 @@ class _TransactionDetailsViewState children: [ Text( "Transaction ID", - style: STextStyles.itemSubtitle, + style: STextStyles.itemSubtitle(context), ), ], ), @@ -538,7 +539,7 @@ class _TransactionDetailsViewState // child: SelectableText( _transaction.txid, - style: STextStyles.itemSubtitle12, + style: STextStyles.itemSubtitle12(context), ), if (coin != Coin.epicCash) const SizedBox( @@ -557,8 +558,8 @@ class _TransactionDetailsViewState .read(prefsChangeNotifierProvider) .hideBlockExplorerWarning == false) { - final shouldContinue = - await showExplorerWarning(uri.host); + final shouldContinue = await showExplorerWarning( + "${uri.scheme}://${uri.host}"); if (!shouldContinue) { return; @@ -617,7 +618,7 @@ class _TransactionDetailsViewState // children: [ // Text( // "Mint Transaction ID", - // style: STextStyles.itemSubtitle, + // style: STextStyles.itemSubtitle(context), // ), // ], // ), @@ -630,7 +631,7 @@ class _TransactionDetailsViewState // // child: // SelectableText( // _transaction.otherData ?? "Unknown", - // style: STextStyles.itemSubtitle12, + // style: STextStyles.itemSubtitle12(context), // ), // // ), // // ), @@ -689,7 +690,7 @@ class _TransactionDetailsViewState children: [ Text( "Slate ID", - style: STextStyles.itemSubtitle, + style: STextStyles.itemSubtitle(context), ), // Flexible( // child: FittedBox( @@ -697,7 +698,7 @@ class _TransactionDetailsViewState // child: SelectableText( _transaction.slateId ?? "Unknown", - style: STextStyles.itemSubtitle12, + style: STextStyles.itemSubtitle12(context), ), // ), // ), @@ -722,7 +723,7 @@ class _TransactionDetailsViewState child: TextButton( style: ButtonStyle( backgroundColor: MaterialStateProperty.all( - CFColors.error, + Theme.of(context).extension()!.textError, ), ), onPressed: () async { @@ -787,7 +788,7 @@ class _TransactionDetailsViewState }, child: Text( "Cancel Transaction", - style: STextStyles.button, + style: STextStyles.button(context), ), ), ) diff --git a/lib/pages/wallet_view/transaction_views/transaction_search_filter_view.dart b/lib/pages/wallet_view/transaction_views/transaction_search_filter_view.dart index 6b9fbd7e3..5966e3f5c 100644 --- a/lib/pages/wallet_view/transaction_views/transaction_search_filter_view.dart +++ b/lib/pages/wallet_view/transaction_views/transaction_search_filter_view.dart @@ -7,13 +7,15 @@ import 'package:flutter_svg/svg.dart'; import 'package:google_fonts/google_fonts.dart'; import 'package:stackwallet/models/transaction_filter.dart'; import 'package:stackwallet/providers/providers.dart'; +import 'package:stackwallet/providers/ui/color_theme_provider.dart'; import 'package:stackwallet/providers/ui/transaction_filter_provider.dart'; import 'package:stackwallet/utilities/assets.dart'; -import 'package:stackwallet/utilities/cfcolors.dart'; import 'package:stackwallet/utilities/constants.dart'; import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/format.dart'; import 'package:stackwallet/utilities/text_styles.dart'; +import 'package:stackwallet/utilities/theme/stack_colors.dart'; +import 'package:stackwallet/utilities/util.dart'; import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart'; import 'package:stackwallet/widgets/icon_widgets/x_icon.dart'; import 'package:stackwallet/widgets/rounded_white_container.dart'; @@ -49,8 +51,11 @@ class _TransactionSearchViewState final keywordTextFieldFocusNode = FocusNode(); final amountTextFieldFocusNode = FocusNode(); + late Color baseColor; + @override initState() { + baseColor = ref.read(colorThemeProvider.state).state.textSubtitle2; final filterState = ref.read(transactionFilterProvider.state).state; if (filterState != null) { _isActiveReceivedCheckbox = filterState.received; @@ -88,9 +93,10 @@ class _TransactionSearchViewState final isDateSelected = _fromDateString.isEmpty; return Text( isDateSelected ? "From..." : _fromDateString, - style: STextStyles.fieldLabel.copyWith( - color: isDateSelected ? CFColors.gray3 : CFColors.stackAccent, - ), + style: STextStyles.fieldLabel(context).copyWith( + color: isDateSelected + ? Theme.of(context).extension()!.textSubtitle2 + : Theme.of(context).extension()!.accentColorDark), ); } @@ -98,53 +104,56 @@ class _TransactionSearchViewState final isDateSelected = _toDateString.isEmpty; return Text( isDateSelected ? "To..." : _toDateString, - style: STextStyles.fieldLabel.copyWith( - color: isDateSelected ? CFColors.gray3 : CFColors.stackAccent, - ), + style: STextStyles.fieldLabel(context).copyWith( + color: isDateSelected + ? Theme.of(context).extension()!.textSubtitle2 + : Theme.of(context).extension()!.accentColorDark), ); } var _selectedFromDate = DateTime(2007); var _selectedToDate = DateTime.now(); - final _datePickerTextStyleBase = GoogleFonts.inter( - color: CFColors.gray3, - fontSize: 12, - fontWeight: FontWeight.w400, - letterSpacing: 0.5, - ); + TextStyle get _datePickerTextStyleBase => GoogleFonts.inter( + color: baseColor, + fontSize: 12, + fontWeight: FontWeight.w400, + letterSpacing: 0.5, + ); MaterialRoundedDatePickerStyle _buildDatePickerStyle() { return MaterialRoundedDatePickerStyle( + backgroundPicker: Theme.of(context).extension()!.popupBG, + // backgroundHeader: Theme.of(context).extension()!.textSubtitle2, paddingMonthHeader: const EdgeInsets.only(top: 11), - colorArrowNext: CFColors.neutral60, - colorArrowPrevious: CFColors.neutral60, + colorArrowNext: Theme.of(context).extension()!.textSubtitle1, + colorArrowPrevious: + Theme.of(context).extension()!.textSubtitle1, textStyleButtonNegative: _datePickerTextStyleBase.copyWith( fontSize: 16, fontWeight: FontWeight.w600), textStyleButtonPositive: _datePickerTextStyleBase.copyWith( fontSize: 16, fontWeight: FontWeight.w600), textStyleCurrentDayOnCalendar: _datePickerTextStyleBase.copyWith( - color: CFColors.stackAccent, - ), + color: Theme.of(context).extension()!.accentColorDark), textStyleDayHeader: _datePickerTextStyleBase.copyWith( - color: CFColors.stackAccent, + color: Theme.of(context).extension()!.accentColorDark, fontSize: 16, fontWeight: FontWeight.w600, ), textStyleDayOnCalendar: _datePickerTextStyleBase, textStyleDayOnCalendarDisabled: _datePickerTextStyleBase.copyWith( - color: CFColors.neutral80, + color: Theme.of(context).extension()!.textSubtitle3, ), textStyleDayOnCalendarSelected: _datePickerTextStyleBase.copyWith( - color: CFColors.white, + color: Theme.of(context).extension()!.textWhite, ), textStyleMonthYearHeader: _datePickerTextStyleBase.copyWith( - color: CFColors.neutral60, + color: Theme.of(context).extension()!.textSubtitle1, fontSize: 16, fontWeight: FontWeight.w600, ), textStyleYearButton: _datePickerTextStyleBase.copyWith( - color: CFColors.white, + color: Theme.of(context).extension()!.textWhite, fontSize: 16, fontWeight: FontWeight.w600, ), @@ -154,13 +163,14 @@ class _TransactionSearchViewState MaterialRoundedYearPickerStyle _buildYearPickerStyle() { return MaterialRoundedYearPickerStyle( + backgroundPicker: Theme.of(context).extension()!.popupBG, textStyleYear: _datePickerTextStyleBase.copyWith( - color: CFColors.gray3, + color: Theme.of(context).extension()!.textSubtitle2, fontWeight: FontWeight.w600, fontSize: 16, ), textStyleYearSelected: _datePickerTextStyleBase.copyWith( - color: CFColors.stackAccent, + color: Theme.of(context).extension()!.accentColorDark, fontWeight: FontWeight.w600, fontSize: 18, ), @@ -182,6 +192,8 @@ class _TransactionSearchViewState GestureDetector( key: const Key("transactionSearchViewFromDatePickerKey"), onTap: () async { + final color = + Theme.of(context).extension()!.accentColorDark; final height = MediaQuery.of(context).size.height; // check and hide keyboard if (FocusScope.of(context).hasFocus) { @@ -196,8 +208,9 @@ class _TransactionSearchViewState initialDate: DateTime.now(), height: height * 0.5, theme: ThemeData( - primarySwatch: - CFColors.createMaterialColor(CFColors.stackAccent), + primarySwatch: Util.createMaterialColor( + color, + ), ), //TODO pick a better initial date // 2007 chosen as that is just before bitcoin launched @@ -231,11 +244,15 @@ class _TransactionSearchViewState child: Container( width: width, decoration: BoxDecoration( - color: CFColors.fieldGray, + color: Theme.of(context) + .extension()! + .textFieldDefaultBG, borderRadius: BorderRadius.circular(Constants.size.circularBorderRadius), border: Border.all( - color: CFColors.fieldGray, + color: Theme.of(context) + .extension()! + .textFieldDefaultBG, width: 1, ), ), @@ -247,7 +264,9 @@ class _TransactionSearchViewState Assets.svg.calendar, height: 20, width: 20, - color: CFColors.gray3, + color: Theme.of(context) + .extension()! + .textSubtitle2, ), const SizedBox( width: 10, @@ -275,6 +294,8 @@ class _TransactionSearchViewState GestureDetector( key: const Key("transactionSearchViewToDatePickerKey"), onTap: () async { + final color = + Theme.of(context).extension()!.accentColorDark; final height = MediaQuery.of(context).size.height; // check and hide keyboard if (FocusScope.of(context).hasFocus) { @@ -288,8 +309,9 @@ class _TransactionSearchViewState context: context, height: height * 0.5, theme: ThemeData( - primarySwatch: - CFColors.createMaterialColor(CFColors.stackAccent), + primarySwatch: Util.createMaterialColor( + color, + ), ), //TODO pick a better initial date // 2007 chosen as that is just before bitcoin launched @@ -324,11 +346,15 @@ class _TransactionSearchViewState child: Container( width: width, decoration: BoxDecoration( - color: CFColors.fieldGray, + color: Theme.of(context) + .extension()! + .textFieldDefaultBG, borderRadius: BorderRadius.circular(Constants.size.circularBorderRadius), border: Border.all( - color: CFColors.fieldGray, + color: Theme.of(context) + .extension()! + .textFieldDefaultBG, width: 1, ), ), @@ -340,7 +366,9 @@ class _TransactionSearchViewState Assets.svg.calendar, height: 20, width: 20, - color: CFColors.gray3, + color: Theme.of(context) + .extension()! + .textSubtitle2, ), const SizedBox( width: 10, @@ -363,9 +391,9 @@ class _TransactionSearchViewState @override Widget build(BuildContext context) { return Scaffold( - backgroundColor: CFColors.almostWhite, + backgroundColor: Theme.of(context).extension()!.background, appBar: AppBar( - backgroundColor: CFColors.almostWhite, + backgroundColor: Theme.of(context).extension()!.background, leading: AppBarBackButton( onPressed: () async { if (FocusScope.of(context).hasFocus) { @@ -379,7 +407,7 @@ class _TransactionSearchViewState ), title: Text( "Transactions filter", - style: STextStyles.navBarTitle, + style: STextStyles.navBarTitle(context), ), ), body: Padding( @@ -402,7 +430,7 @@ class _TransactionSearchViewState child: FittedBox( child: Text( "Transactions", - style: STextStyles.smallMed12, + style: STextStyles.smallMed12(context), ), ), ), @@ -452,7 +480,8 @@ class _TransactionSearchViewState child: FittedBox( child: Text( "Sent", - style: STextStyles.itemSubtitle12, + style: STextStyles.itemSubtitle12( + context), ), ), ) @@ -504,7 +533,8 @@ class _TransactionSearchViewState child: FittedBox( child: Text( "Received", - style: STextStyles.itemSubtitle12, + style: STextStyles.itemSubtitle12( + context), ), ), ) @@ -525,7 +555,7 @@ class _TransactionSearchViewState child: FittedBox( child: Text( "Date", - style: STextStyles.smallMed12, + style: STextStyles.smallMed12(context), ), ), ), @@ -541,7 +571,7 @@ class _TransactionSearchViewState child: FittedBox( child: Text( "Amount", - style: STextStyles.smallMed12, + style: STextStyles.smallMed12(context), ), ), ), @@ -570,10 +600,11 @@ class _TransactionSearchViewState ? newValue : oldValue), ], - style: STextStyles.field, + style: STextStyles.field(context), decoration: standardInputDecoration( "Enter ${widget.coin.ticker} amount...", keywordTextFieldFocusNode, + context, ).copyWith( suffixIcon: _amountTextEditingController .text.isNotEmpty @@ -607,7 +638,7 @@ class _TransactionSearchViewState child: FittedBox( child: Text( "Keyword", - style: STextStyles.smallMed12, + style: STextStyles.smallMed12(context), ), ), ), @@ -623,11 +654,12 @@ class _TransactionSearchViewState const Key("transactionSearchViewKeywordFieldKey"), controller: _keywordTextEditingController, focusNode: keywordTextFieldFocusNode, - style: STextStyles.field, + style: STextStyles.field(context), onChanged: (_) => setState(() {}), decoration: standardInputDecoration( "Type keyword...", keywordTextFieldFocusNode, + context, ).copyWith( suffixIcon: _keywordTextEditingController .text.isNotEmpty @@ -673,17 +705,15 @@ class _TransactionSearchViewState Navigator.of(context).pop(); } }, - style: ButtonStyle( - backgroundColor: - MaterialStateProperty.all( - CFColors.buttonGray, - ), - ), + style: Theme.of(context) + .extension()! + .getSecondaryEnabledButtonColor(context), child: Text( "Cancel", - style: STextStyles.button.copyWith( - color: CFColors.stackAccent, - ), + style: STextStyles.button(context).copyWith( + color: Theme.of(context) + .extension()! + .accentColorDark), ), ), ), @@ -696,20 +726,14 @@ class _TransactionSearchViewState height: 48, child: TextButton( style: Theme.of(context) - .textButtonTheme - .style - ?.copyWith( - backgroundColor: - MaterialStateProperty.all( - CFColors.stackAccent, - ), - ), + .extension()! + .getPrimaryEnabledButtonColor(context), onPressed: () async { _onApplyPressed(); }, child: Text( "Save", - style: STextStyles.button, + style: STextStyles.button(context), ), ), ), diff --git a/lib/pages/wallet_view/wallet_view.dart b/lib/pages/wallet_view/wallet_view.dart index b06b8627c..95dfc4a98 100644 --- a/lib/pages/wallet_view/wallet_view.dart +++ b/lib/pages/wallet_view/wallet_view.dart @@ -33,13 +33,13 @@ import 'package:stackwallet/services/event_bus/events/global/node_connection_sta 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/utilities/assets.dart'; -import 'package:stackwallet/utilities/cfcolors.dart'; import 'package:stackwallet/utilities/constants.dart'; import 'package:stackwallet/utilities/enums/backup_frequency_type.dart'; import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/enums/flush_bar_type.dart'; import 'package:stackwallet/utilities/enums/wallet_balance_toggle_state.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/custom_loading_overlay.dart'; @@ -208,21 +208,21 @@ class _WalletViewState extends ConsumerState { case WalletSyncStatus.unableToSync: return SvgPicture.asset( Assets.svg.radioProblem, - color: CFColors.link, + color: Theme.of(context).extension()!.accentColorRed, width: 20, height: 20, ); case WalletSyncStatus.synced: return SvgPicture.asset( Assets.svg.radio, - color: CFColors.stackGreen, + color: Theme.of(context).extension()!.accentColorGreen, width: 20, height: 20, ); case WalletSyncStatus.syncing: return SvgPicture.asset( Assets.svg.radioSyncing, - color: CFColors.stackYellow, + color: Theme.of(context).extension()!.accentColorYellow, width: 20, height: 20, ); @@ -375,7 +375,7 @@ class _WalletViewState extends ConsumerState { children: [ SvgPicture.asset( Assets.svg.iconFor(coin: coin), - // color: CFColors.stackAccent, + // color: Theme.of(context).extension()!.accentColorDark width: 24, height: 24, ), @@ -386,7 +386,7 @@ class _WalletViewState extends ConsumerState { child: Text( ref.watch( managerProvider.select((value) => value.walletName)), - style: STextStyles.navBarTitle, + style: STextStyles.navBarTitle(context), overflow: TextOverflow.ellipsis, ), ) @@ -405,7 +405,7 @@ class _WalletViewState extends ConsumerState { key: const Key("walletViewRadioButton"), size: 36, shadows: const [], - color: CFColors.almostWhite, + color: Theme.of(context).extension()!.background, icon: _buildNetworkIcon(_currentSyncStatus), onPressed: () { Navigator.of(context).pushNamed( @@ -432,14 +432,20 @@ class _WalletViewState extends ConsumerState { key: const Key("walletViewAlertsButton"), size: 36, shadows: const [], - color: CFColors.almostWhite, + color: Theme.of(context).extension()!.background, icon: SvgPicture.asset( ref.watch(notificationsProvider.select((value) => value.hasUnreadNotificationsFor(walletId))) - ? Assets.svg.bellNew + ? 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, ), onPressed: () { // reset unread state @@ -488,10 +494,12 @@ class _WalletViewState extends ConsumerState { key: const Key("walletViewSettingsButton"), size: 36, shadows: const [], - color: CFColors.almostWhite, + color: Theme.of(context).extension()!.background, icon: SvgPicture.asset( Assets.svg.bars, - color: CFColors.stackAccent, + color: Theme.of(context) + .extension()! + .accentColorDark, width: 20, height: 20, ), @@ -514,7 +522,7 @@ class _WalletViewState extends ConsumerState { ), body: SafeArea( child: Container( - color: CFColors.almostWhite, + color: Theme.of(context).extension()!.background, child: Column( children: [ const SizedBox( @@ -544,6 +552,9 @@ class _WalletViewState extends ConsumerState { children: [ Expanded( child: TextButton( + style: Theme.of(context) + .extension()! + .getSecondaryEnabledButtonColor(context), onPressed: () async { await showDialog( context: context, @@ -557,8 +568,11 @@ class _WalletViewState extends ConsumerState { }, child: Text( "Cancel", - style: STextStyles.button.copyWith( - color: CFColors.stackAccent, + style: + STextStyles.button(context).copyWith( + color: Theme.of(context) + .extension()! + .accentColorDark, ), ), ), @@ -569,17 +583,11 @@ class _WalletViewState extends ConsumerState { unawaited(attemptAnonymize()); }, style: Theme.of(context) - .textButtonTheme - .style - ?.copyWith( - backgroundColor: - MaterialStateProperty.all( - CFColors.stackAccent, - ), - ), + .extension()! + .getPrimaryEnabledButtonColor(context), child: Text( "Continue", - style: STextStyles.button, + style: STextStyles.button(context), ), ), ), @@ -587,8 +595,10 @@ class _WalletViewState extends ConsumerState { }, child: Text( "Anonymize funds", - style: STextStyles.button.copyWith( - color: CFColors.stackAccent, + style: STextStyles.button(context).copyWith( + color: Theme.of(context) + .extension()! + .buttonTextSecondary, ), ), ), @@ -606,8 +616,10 @@ class _WalletViewState extends ConsumerState { children: [ Text( "Transactions", - style: STextStyles.itemSubtitle.copyWith( - color: CFColors.neutral50, + style: STextStyles.itemSubtitle(context).copyWith( + color: Theme.of(context) + .extension()! + .textDark3, ), ), BlueTextButton( diff --git a/lib/pages/wallets_sheet/wallets_sheet.dart b/lib/pages/wallets_sheet/wallets_sheet.dart index 553cc093e..b69971ab5 100644 --- a/lib/pages/wallets_sheet/wallets_sheet.dart +++ b/lib/pages/wallets_sheet/wallets_sheet.dart @@ -1,10 +1,10 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:stackwallet/providers/providers.dart'; -import 'package:stackwallet/utilities/cfcolors.dart'; import 'package:stackwallet/utilities/constants.dart'; import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/text_styles.dart'; +import 'package:stackwallet/utilities/theme/stack_colors.dart'; import 'package:stackwallet/widgets/wallet_card.dart'; class WalletsSheet extends ConsumerWidget { @@ -23,9 +23,9 @@ class WalletsSheet extends ConsumerWidget { final maxHeight = MediaQuery.of(context).size.height * 0.60; return Container( - decoration: const BoxDecoration( - color: CFColors.white, - borderRadius: BorderRadius.vertical( + decoration: BoxDecoration( + color: Theme.of(context).extension()!.popupBG, + borderRadius: const BorderRadius.vertical( top: Radius.circular(20), ), ), @@ -45,7 +45,9 @@ class WalletsSheet extends ConsumerWidget { Center( child: Container( decoration: BoxDecoration( - color: CFColors.fieldGray, + color: Theme.of(context) + .extension()! + .textFieldDefaultBG, borderRadius: BorderRadius.circular( Constants.size.circularBorderRadius, ), @@ -59,7 +61,7 @@ class WalletsSheet extends ConsumerWidget { ), Text( "${coin.prettyName} (${coin.ticker}) wallets", - style: STextStyles.pageTitleH2, + style: STextStyles.pageTitleH2(context), textAlign: TextAlign.left, ), const SizedBox( diff --git a/lib/pages/wallets_view/sub_widgets/all_wallets.dart b/lib/pages/wallets_view/sub_widgets/all_wallets.dart index 3707ce69c..eae7374bf 100644 --- a/lib/pages/wallets_view/sub_widgets/all_wallets.dart +++ b/lib/pages/wallets_view/sub_widgets/all_wallets.dart @@ -4,6 +4,7 @@ import 'package:stackwallet/pages/add_wallet_views/add_wallet_view/add_wallet_vi import 'package:stackwallet/pages/wallets_view/sub_widgets/wallet_list_item.dart'; import 'package:stackwallet/providers/providers.dart'; import 'package:stackwallet/utilities/text_styles.dart'; +import 'package:stackwallet/utilities/theme/stack_colors.dart'; import 'package:stackwallet/widgets/custom_buttons/blue_text_button.dart'; class AllWallets extends StatelessWidget { @@ -19,7 +20,9 @@ class AllWallets extends StatelessWidget { children: [ Text( "All wallets", - style: STextStyles.itemSubtitle, + style: STextStyles.itemSubtitle(context).copyWith( + color: Theme.of(context).extension()!.textDark, + ), ), BlueTextButton( text: "Add new", diff --git a/lib/pages/wallets_view/sub_widgets/empty_wallets.dart b/lib/pages/wallets_view/sub_widgets/empty_wallets.dart index c4bbab967..4309186ac 100644 --- a/lib/pages/wallets_view/sub_widgets/empty_wallets.dart +++ b/lib/pages/wallets_view/sub_widgets/empty_wallets.dart @@ -2,8 +2,9 @@ import 'package:flutter/material.dart'; import 'package:flutter_svg/svg.dart'; import 'package:stackwallet/pages/add_wallet_views/add_wallet_view/add_wallet_view.dart'; import 'package:stackwallet/utilities/assets.dart'; -import 'package:stackwallet/utilities/cfcolors.dart'; import 'package:stackwallet/utilities/text_styles.dart'; +import 'package:stackwallet/utilities/theme/stack_colors.dart'; +import 'package:stackwallet/utilities/util.dart'; class EmptyWallets extends StatelessWidget { const EmptyWallets({Key? key}) : super(key: key); @@ -11,73 +12,116 @@ class EmptyWallets extends StatelessWidget { @override Widget build(BuildContext context) { debugPrint("BUILD: $runtimeType"); + + final isDesktop = Util.isDesktop; + return SafeArea( child: Padding( padding: const EdgeInsets.symmetric( horizontal: 43, ), - child: Column( - children: [ - const Spacer( - flex: 2, - ), - Image( - image: AssetImage( - Assets.png.stack, + child: ConstrainedBox( + constraints: BoxConstraints( + maxWidth: isDesktop ? 330 : double.infinity, + ), + child: Column( + children: [ + const Spacer( + flex: 2, ), - width: MediaQuery.of(context).size.width / 3, - ), - const SizedBox( - height: 16, - ), - Text( - "You do not have any wallets yet. Start building your crypto Stack!", - textAlign: TextAlign.center, - style: STextStyles.subtitle.copyWith( - color: CFColors.neutral60, + Image( + image: AssetImage( + Assets.png.stack, + ), + width: isDesktop ? 324 : MediaQuery.of(context).size.width / 3, ), - ), - const SizedBox( - height: 16, - ), - Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - TextButton( - style: Theme.of(context).textButtonTheme.style?.copyWith( - backgroundColor: MaterialStateProperty.all( - CFColors.stackAccent, - ), + SizedBox( + height: isDesktop ? 30 : 16, + ), + Text( + "You do not have any wallets yet. Start building your crypto Stack!", + textAlign: TextAlign.center, + style: isDesktop + ? STextStyles.desktopSubtitleH2(context).copyWith( + color: Theme.of(context) + .extension()! + .textSubtitle1, + ) + : STextStyles.subtitle(context).copyWith( + color: Theme.of(context) + .extension()! + .textSubtitle1, ), - onPressed: () { - Navigator.of(context).pushNamed(AddWalletView.routeName); - }, - child: Container( - padding: const EdgeInsets.symmetric( - horizontal: 16, - ), - child: Row( - children: [ - SvgPicture.asset( - Assets.svg.plus, - ), - const SizedBox( - width: 5, - ), - Text( - "Add Wallet", - style: STextStyles.button, - ), - ], - ), + ), + SizedBox( + height: isDesktop ? 30 : 16, + ), + if (isDesktop) + const SizedBox( + width: 328, + height: 70, + child: AddWalletButton( + isDesktop: true, ), ), - ], - ), - const Spacer( - flex: 5, - ), - ], + if (!isDesktop) + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: const [ + AddWalletButton( + isDesktop: false, + ), + ], + ), + const Spacer( + flex: 5, + ), + ], + ), + ), + ), + ); + } +} + +class AddWalletButton extends StatelessWidget { + const AddWalletButton({Key? key, required this.isDesktop}) : super(key: key); + + final bool isDesktop; + + @override + Widget build(BuildContext context) { + return TextButton( + style: Theme.of(context) + .extension()! + .getPrimaryEnabledButtonColor(context), + onPressed: () { + Navigator.of(context).pushNamed(AddWalletView.routeName); + }, + child: Center( + child: Container( + padding: const EdgeInsets.symmetric( + horizontal: 16, + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + SvgPicture.asset( + Assets.svg.plus, + width: isDesktop ? 18 : null, + height: isDesktop ? 18 : null, + ), + SizedBox( + width: isDesktop ? 8 : 5, + ), + Text( + "Add Wallet", + style: isDesktop + ? STextStyles.desktopButtonEnabled(context) + : STextStyles.button(context), + ), + ], + ), ), ), ); diff --git a/lib/pages/wallets_view/sub_widgets/favorite_card.dart b/lib/pages/wallets_view/sub_widgets/favorite_card.dart index 30112885c..bc95d51b5 100644 --- a/lib/pages/wallets_view/sub_widgets/favorite_card.dart +++ b/lib/pages/wallets_view/sub_widgets/favorite_card.dart @@ -6,11 +6,11 @@ import 'package:stackwallet/pages/wallet_view/wallet_view.dart'; import 'package:stackwallet/providers/providers.dart'; import 'package:stackwallet/services/coins/manager.dart'; import 'package:stackwallet/utilities/assets.dart'; -import 'package:stackwallet/utilities/cfcolors.dart'; import 'package:stackwallet/utilities/constants.dart'; import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/format.dart'; import 'package:stackwallet/utilities/text_styles.dart'; +import 'package:stackwallet/utilities/theme/stack_colors.dart'; import 'package:tuple/tuple.dart'; class FavoriteCard extends ConsumerStatefulWidget { @@ -70,7 +70,7 @@ class _FavoriteCardState extends ConsumerState { width: widget.width, height: widget.height, decoration: BoxDecoration( - color: CFColors.coin.forCoin(coin), + color: Theme.of(context).extension()!.colorForCoin(coin), borderRadius: BorderRadius.circular( Constants.size.circularBorderRadius, ), @@ -128,23 +128,29 @@ class _FavoriteCardState extends ConsumerState { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text( - ref.watch( - managerProvider.select((value) => value.walletName)), - style: STextStyles.itemSubtitle12, - ), - const Spacer(), - SvgPicture.asset( - Assets.svg.iconFor(coin: coin), - width: 24, - height: 24, - ), - ], + Expanded( + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Expanded( + child: Text( + ref.watch(managerProvider + .select((value) => value.walletName)), + style: STextStyles.itemSubtitle12(context).copyWith( + color: Theme.of(context).extension()!.textFavoriteCard, + ), + overflow: TextOverflow.fade, + ), + ), + SvgPicture.asset( + Assets.svg.iconFor(coin: coin), + width: 24, + height: 24, + ), + ], + ), ), - const Spacer(), FutureBuilder( future: ref.watch( managerProvider.select((value) => value.totalBalance)), @@ -177,8 +183,9 @@ class _FavoriteCardState extends ConsumerState { .select((value) => value.locale), ), )} ${coin.ticker}", - style: STextStyles.titleBold12.copyWith( + style: STextStyles.titleBold12(context).copyWith( fontSize: 16, + color: Theme.of(context).extension()!.textFavoriteCard, ), ), ), @@ -197,8 +204,9 @@ class _FavoriteCardState extends ConsumerState { prefsChangeNotifierProvider .select((value) => value.currency), )}", - style: STextStyles.itemSubtitle12.copyWith( + style: STextStyles.itemSubtitle12(context).copyWith( fontSize: 10, + color: Theme.of(context).extension()!.textFavoriteCard, ), ), ], diff --git a/lib/pages/wallets_view/sub_widgets/favorite_wallets.dart b/lib/pages/wallets_view/sub_widgets/favorite_wallets.dart index 2f7efe58b..073747386 100644 --- a/lib/pages/wallets_view/sub_widgets/favorite_wallets.dart +++ b/lib/pages/wallets_view/sub_widgets/favorite_wallets.dart @@ -8,9 +8,9 @@ import 'package:stackwallet/pages/wallets_view/sub_widgets/favorite_card.dart'; import 'package:stackwallet/providers/providers.dart'; import 'package:stackwallet/services/coins/manager.dart'; import 'package:stackwallet/utilities/assets.dart'; -import 'package:stackwallet/utilities/cfcolors.dart'; 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_page_view/custom_page_view.dart' as cpv; @@ -82,19 +82,24 @@ class _FavoriteWalletsState extends ConsumerState { children: [ Text( "Favorite Wallets", - style: STextStyles.itemSubtitle, + style: STextStyles.itemSubtitle(context).copyWith( + color: Theme.of(context).extension()!.textDark3, + ), ), const Spacer(), if (hasFavorites) TextButton( style: ButtonStyle( - backgroundColor: - MaterialStateProperty.all(CFColors.almostWhite), + backgroundColor: MaterialStateProperty.all( + Theme.of(context).extension()!.background), ), child: SvgPicture.asset( Assets.svg.ellipsis, width: 16, height: 16, + color: Theme.of(context) + .extension()! + .accentColorDark, ), onPressed: () { Navigator.of(context).pushNamed( @@ -117,12 +122,15 @@ class _FavoriteWalletsState extends ConsumerState { height: cardHeight, width: cardWidth, decoration: BoxDecoration( - color: CFColors.fieldGray, + color: Theme.of(context) + .extension()! + .textFieldDefaultBG, borderRadius: BorderRadius.circular( Constants.size.circularBorderRadius), ), child: MaterialButton( - splashColor: CFColors.splashLight, + splashColor: + Theme.of(context).extension()!.highlight, key: const Key("favoriteWalletsAddFavoriteButtonKey"), padding: const EdgeInsets.all(12), materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, @@ -141,14 +149,16 @@ class _FavoriteWalletsState extends ConsumerState { Assets.svg.plus, width: 8, height: 8, - color: CFColors.neutral60, + color: Theme.of(context) + .extension()! + .textSubtitle1, ), const SizedBox( width: 4, ), Text( "Add a favorite", - style: STextStyles.itemSubtitle.copyWith( + style: STextStyles.itemSubtitle(context).copyWith( fontSize: 10, ), ), diff --git a/lib/pages/wallets_view/sub_widgets/wallet_list_item.dart b/lib/pages/wallets_view/sub_widgets/wallet_list_item.dart index 95f1b469e..842b1f4c4 100644 --- a/lib/pages/wallets_view/sub_widgets/wallet_list_item.dart +++ b/lib/pages/wallets_view/sub_widgets/wallet_list_item.dart @@ -4,11 +4,11 @@ import 'package:flutter_svg/svg.dart'; import 'package:stackwallet/pages/wallets_sheet/wallets_sheet.dart'; import 'package:stackwallet/providers/providers.dart'; import 'package:stackwallet/utilities/assets.dart'; -import 'package:stackwallet/utilities/cfcolors.dart'; import 'package:stackwallet/utilities/constants.dart'; import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/format.dart'; import 'package:stackwallet/utilities/text_styles.dart'; +import 'package:stackwallet/utilities/theme/stack_colors.dart'; import 'package:stackwallet/widgets/rounded_white_container.dart'; class WalletListItem extends ConsumerWidget { @@ -32,7 +32,7 @@ class WalletListItem extends ConsumerWidget { return RoundedWhiteContainer( padding: const EdgeInsets.all(0), child: MaterialButton( - // splashColor: CFColors.splashLight, + // splashColor: Theme.of(context).extension()!.highlight, key: Key("walletListItemButtonKey_${coin.name}"), padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 13), materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, @@ -78,11 +78,16 @@ class WalletListItem extends ConsumerWidget { final double percentChange = tuple.item2; - var percentChangedColor = CFColors.stackAccent; + var percentChangedColor = + Theme.of(context).extension()!.textDark; if (percentChange > 0) { - percentChangedColor = CFColors.stackGreen; + percentChangedColor = Theme.of(context) + .extension()! + .accentColorGreen; } else if (percentChange < 0) { - percentChangedColor = CFColors.stackRed; + percentChangedColor = Theme.of(context) + .extension()! + .accentColorRed; } return Column( @@ -90,11 +95,14 @@ class WalletListItem extends ConsumerWidget { children: [ Row( children: [ - Text(coin.prettyName), + Text( + coin.prettyName, + style: STextStyles.titleBold12(context), + ), const Spacer(), Text( "$priceString $currency/${coin.ticker}", - style: STextStyles.itemSubtitle, + style: STextStyles.itemSubtitle(context), ), ], ), @@ -105,12 +113,12 @@ class WalletListItem extends ConsumerWidget { children: [ Text( walletCountString, - style: STextStyles.itemSubtitle, + style: STextStyles.itemSubtitle(context), ), const Spacer(), Text( "${percentChange.toStringAsFixed(2)}%", - style: STextStyles.itemSubtitle.copyWith( + style: STextStyles.itemSubtitle(context).copyWith( color: percentChangedColor, ), ), diff --git a/lib/pages_desktop_specific/create_password/create_password_view.dart b/lib/pages_desktop_specific/create_password/create_password_view.dart new file mode 100644 index 000000000..2391a22f6 --- /dev/null +++ b/lib/pages_desktop_specific/create_password/create_password_view.dart @@ -0,0 +1,414 @@ +import 'dart:async'; + +import 'package:flutter/material.dart'; +import 'package:flutter_secure_storage/flutter_secure_storage.dart'; +import 'package:flutter_svg/svg.dart'; +import 'package:stackwallet/notifications/show_flush_bar.dart'; +import 'package:stackwallet/pages_desktop_specific/home/desktop_home_view.dart'; +import 'package:stackwallet/utilities/assets.dart'; +import 'package:stackwallet/utilities/constants.dart'; +import 'package:stackwallet/utilities/enums/flush_bar_type.dart'; +import 'package:stackwallet/utilities/flutter_secure_storage_interface.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/desktop/desktop_app_bar.dart'; +import 'package:stackwallet/widgets/desktop/desktop_scaffold.dart'; +import 'package:stackwallet/widgets/progress_bar.dart'; +import 'package:stackwallet/widgets/stack_text_field.dart'; +import 'package:zxcvbn/zxcvbn.dart'; + +class CreatePasswordView extends StatefulWidget { + const CreatePasswordView({ + Key? key, + this.secureStore = const SecureStorageWrapper( + FlutterSecureStorage(), + ), + }) : super(key: key); + + static const String routeName = "/createPasswordDesktop"; + + final FlutterSecureStorageInterface secureStore; + + @override + State createState() => _CreatePasswordViewState(); +} + +class _CreatePasswordViewState extends State { + late final TextEditingController passwordController; + late final TextEditingController passwordRepeatController; + + late final FocusNode passwordFocusNode; + late final FocusNode passwordRepeatFocusNode; + final zxcvbn = Zxcvbn(); + + String passwordFeedback = + "Add another word or two. Uncommon words are better. Use a few words, avoid common phrases. No need for symbols, digits, or uppercase letters."; + bool shouldShowPasswordHint = true; + bool hidePassword = true; + double passwordStrength = 0.0; + + bool get nextEnabled => + passwordController.text.isNotEmpty && + passwordRepeatController.text.isNotEmpty; + + bool get fieldsMatch => + passwordController.text == passwordRepeatController.text; + + void onNextPressed() async { + final String passphrase = passwordController.text; + final String repeatPassphrase = passwordRepeatController.text; + + if (passphrase.isEmpty) { + unawaited(showFloatingFlushBar( + type: FlushBarType.warning, + message: "A password is required", + context: context, + )); + return; + } + if (passphrase != repeatPassphrase) { + unawaited(showFloatingFlushBar( + type: FlushBarType.warning, + message: "Password does not match", + context: context, + )); + return; + } + + await widget.secureStore + .write(key: "stackDesktopPassword", value: passphrase); + + if (mounted) { + unawaited(Navigator.of(context) + .pushReplacementNamed(DesktopHomeView.routeName)); + } + + unawaited(showFloatingFlushBar( + type: FlushBarType.success, + message: "Your password is set up", + context: context, + )); + } + + @override + void initState() { + passwordController = TextEditingController(); + passwordRepeatController = TextEditingController(); + + passwordFocusNode = FocusNode(); + passwordRepeatFocusNode = FocusNode(); + + super.initState(); + } + + @override + void dispose() { + passwordController.dispose(); + passwordRepeatController.dispose(); + + passwordFocusNode.dispose(); + passwordRepeatFocusNode.dispose(); + + super.dispose(); + } + + @override + Widget build(BuildContext context) { + debugPrint("BUILD: $runtimeType "); + + return DesktopScaffold( + appBar: DesktopAppBar( + leading: AppBarBackButton( + onPressed: () async { + if (mounted) { + Navigator.of(context).pop(); + } + }, + ), + isCompactHeight: false, + ), + body: Column( + children: [ + Expanded( + child: Center( + child: SizedBox( + width: 480, + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + "Create a password", + style: STextStyles.desktopH2(context), + ), + const SizedBox( + height: 16, + ), + Text( + "Protect your funds with a strong password", + style: STextStyles.desktopSubtitleH2(context), + ), + const SizedBox( + height: 40, + ), + ClipRRect( + borderRadius: BorderRadius.circular( + Constants.size.circularBorderRadius, + ), + child: TextField( + key: const Key("createBackupPasswordFieldKey1"), + focusNode: passwordFocusNode, + controller: passwordController, + style: STextStyles.desktopTextMedium(context).copyWith( + height: 2, + ), + obscureText: hidePassword, + enableSuggestions: false, + autocorrect: false, + decoration: standardInputDecoration( + "Create password", + passwordFocusNode, + context, + ).copyWith( + suffixIcon: UnconstrainedBox( + child: SizedBox( + height: 70, + child: Row( + children: [ + GestureDetector( + key: const Key( + "createDesktopPasswordFieldShowPasswordButtonKey"), + onTap: () async { + setState(() { + hidePassword = !hidePassword; + }); + }, + child: Container( + decoration: BoxDecoration( + color: Colors.transparent, + borderRadius: + BorderRadius.circular(1000), + ), + height: 32, + width: 32, + child: Center( + child: SvgPicture.asset( + hidePassword + ? Assets.svg.eye + : Assets.svg.eyeSlash, + color: Theme.of(context) + .extension()! + .textDark3, + width: 24, + height: 19, + ), + ), + ), + ), + const SizedBox( + width: 10, + ), + ], + ), + ), + ), + ), + onChanged: (newValue) { + if (newValue.isEmpty) { + setState(() { + passwordFeedback = ""; + }); + return; + } + final result = zxcvbn.evaluate(newValue); + String suggestionsAndTips = ""; + for (var sug + in result.feedback.suggestions!.toSet()) { + suggestionsAndTips += "$sug\n"; + } + suggestionsAndTips += result.feedback.warning!; + String feedback = + // "Password Strength: ${((result.score! / 4.0) * 100).toInt()}%\n" + suggestionsAndTips; + + passwordStrength = result.score! / 4; + + // hack fix to format back string returned from zxcvbn + if (feedback.contains("phrasesNo need")) { + feedback = feedback.replaceFirst( + "phrasesNo need", "phrases\nNo need"); + } + + if (feedback.endsWith("\n")) { + feedback = + feedback.substring(0, feedback.length - 2); + } + + setState(() { + passwordFeedback = feedback; + }); + }, + ), + ), + if (passwordFocusNode.hasFocus || + passwordRepeatFocusNode.hasFocus || + passwordController.text.isNotEmpty) + Padding( + padding: EdgeInsets.only( + top: passwordFeedback.isNotEmpty ? 4 : 8, + ), + child: passwordFeedback.isNotEmpty + ? Text( + passwordFeedback, + style: + STextStyles.desktopTextExtraSmall(context) + .copyWith( + color: Theme.of(context) + .extension()! + .textSubtitle1, + ), + ) + : null, + ), + if (passwordFocusNode.hasFocus || + passwordRepeatFocusNode.hasFocus || + passwordController.text.isNotEmpty) + Padding( + padding: const EdgeInsets.only( + top: 10, + ), + child: ProgressBar( + key: const Key("createDesktopPasswordProgressBar"), + width: 458, + height: 8, + fillColor: passwordStrength < 0.51 + ? Theme.of(context) + .extension()! + .accentColorRed + : passwordStrength < 1 + ? Theme.of(context) + .extension()! + .accentColorYellow + : Theme.of(context) + .extension()! + .accentColorGreen, + backgroundColor: Theme.of(context) + .extension()! + .buttonBackSecondary, + percent: + passwordStrength < 0.25 ? 0.03 : passwordStrength, + ), + ), + const SizedBox( + height: 16, + ), + ClipRRect( + borderRadius: BorderRadius.circular( + Constants.size.circularBorderRadius, + ), + child: TextField( + key: const Key("createDesktopPasswordFieldKey2"), + focusNode: passwordRepeatFocusNode, + controller: passwordRepeatController, + style: STextStyles.desktopTextMedium(context).copyWith( + height: 2, + ), + obscureText: hidePassword, + enableSuggestions: false, + autocorrect: false, + decoration: standardInputDecoration( + "Confirm password", + passwordRepeatFocusNode, + context, + ).copyWith( + suffixIcon: UnconstrainedBox( + child: SizedBox( + height: 70, + child: Row( + children: [ + GestureDetector( + key: const Key( + "createDesktopPasswordFieldShowPasswordButtonKey2"), + onTap: () async { + setState(() { + hidePassword = !hidePassword; + }); + }, + child: Container( + decoration: BoxDecoration( + color: Colors.transparent, + borderRadius: + BorderRadius.circular(1000), + ), + height: 32, + width: 32, + child: Center( + child: SvgPicture.asset( + fieldsMatch && passwordStrength == 1 + ? Assets.svg.checkCircle + : hidePassword + ? Assets.svg.eye + : Assets.svg.eyeSlash, + color: fieldsMatch && + passwordStrength == 1 + ? Theme.of(context) + .extension()! + .accentColorGreen + : Theme.of(context) + .extension()! + .textDark3, + width: 24, + height: 19, + ), + ), + ), + ), + const SizedBox( + width: 10, + ), + ], + ), + ), + ), + ), + onChanged: (newValue) { + setState(() {}); + }, + ), + ), + const SizedBox( + height: 32, + ), + SizedBox( + width: 480, + height: 70, + child: TextButton( + style: nextEnabled + ? Theme.of(context) + .extension()! + .getPrimaryEnabledButtonColor(context) + : Theme.of(context) + .extension()! + .getPrimaryDisabledButtonColor(context), + onPressed: nextEnabled ? onNextPressed : null, + child: Text( + "Next", + style: nextEnabled + ? STextStyles.desktopButtonEnabled(context) + : STextStyles.desktopButtonDisabled(context), + ), + ), + ), + ], + ), + ), + ), + ), + const SizedBox( + height: kDesktopAppBarHeight, + ), + ], + ), + ); + } +} diff --git a/lib/pages_desktop_specific/home/desktop_home_view.dart b/lib/pages_desktop_specific/home/desktop_home_view.dart new file mode 100644 index 000000000..bd4996ec1 --- /dev/null +++ b/lib/pages_desktop_specific/home/desktop_home_view.dart @@ -0,0 +1,71 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:stackwallet/pages_desktop_specific/home/desktop_menu.dart'; +import 'package:stackwallet/pages_desktop_specific/home/my_stack_view/my_stack_view.dart'; +import 'package:stackwallet/utilities/theme/stack_colors.dart'; + +class DesktopHomeView extends ConsumerStatefulWidget { + const DesktopHomeView({Key? key}) : super(key: key); + + static const String routeName = "/desktopHome"; + + @override + ConsumerState createState() => _DesktopHomeViewState(); +} + +class _DesktopHomeViewState extends ConsumerState { + int currentViewIndex = 0; + final List contentViews = [ + // const Navigator( + // onGenerateRoute: RouteGenerator.generateRoute, + // initialRoute: MyStackView.routeName, + // ), + const MyStackView( + key: Key("myStackViewKey"), + ), + Container( + color: Colors.green, + ), + Container( + color: Colors.red, + ), + Container( + color: Colors.orange, + ), + Container( + color: Colors.yellow, + ), + Container( + color: Colors.blue, + ), + Container( + color: Colors.pink, + ), + Container( + color: Colors.purple, + ), + ]; + + void onMenuSelectionChanged(int newIndex) { + setState(() { + currentViewIndex = newIndex; + }); + } + + @override + Widget build(BuildContext context) { + return Material( + color: Theme.of(context).extension()!.background, + child: Row( + children: [ + DesktopMenu( + onSelectionChanged: onMenuSelectionChanged, + ), + Expanded( + child: contentViews[currentViewIndex], + ), + ], + ), + ); + } +} diff --git a/lib/pages_desktop_specific/home/desktop_menu.dart b/lib/pages_desktop_specific/home/desktop_menu.dart new file mode 100644 index 000000000..b71c20f6e --- /dev/null +++ b/lib/pages_desktop_specific/home/desktop_menu.dart @@ -0,0 +1,221 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:flutter_svg/flutter_svg.dart'; +import 'package:stackwallet/pages_desktop_specific/home/desktop_menu_item.dart'; +import 'package:stackwallet/utilities/assets.dart'; +import 'package:stackwallet/utilities/text_styles.dart'; +import 'package:stackwallet/utilities/theme/stack_colors.dart'; + +class DesktopMenu extends ConsumerStatefulWidget { + const DesktopMenu({ + Key? key, + required this.onSelectionChanged, + }) : super(key: key); + + final void Function(int)? onSelectionChanged; + + @override + ConsumerState createState() => _DesktopMenuState(); +} + +class _DesktopMenuState extends ConsumerState { + static const expandedWidth = 225.0; + static const minimizedWidth = 72.0; + + double _width = expandedWidth; + int selectedMenuItem = 0; + + void updateSelectedMenuItem(int index) { + setState(() { + selectedMenuItem = index; + }); + widget.onSelectionChanged?.call(index); + } + + void toggleMinimize() { + setState(() { + _width = _width == expandedWidth ? minimizedWidth : expandedWidth; + }); + } + + @override + Widget build(BuildContext context) { + return Material( + color: Theme.of(context).extension()!.popupBG, + child: SizedBox( + width: _width, + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + SizedBox( + height: _width == expandedWidth ? 22 : 25, + ), + SizedBox( + width: _width == expandedWidth ? 70 : 32, + height: _width == expandedWidth ? 70 : 32, + child: SvgPicture.asset( + Assets.svg.stackIcon(context), + ), + ), + const SizedBox( + height: 10, + ), + Text( + _width == expandedWidth ? "Stack Wallet" : "", + style: STextStyles.desktopH2(context).copyWith( + fontSize: 18, + height: 23.4 / 18, + ), + ), + const SizedBox( + height: 60, + ), + SizedBox( + width: _width == expandedWidth + ? _width - 32 // 16 padding on either side + : _width - 16, // 8 padding on either side + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + DesktopMenuItem( + icon: SvgPicture.asset( + Assets.svg.walletFa, + width: 20, + height: 20, + ), + label: "My Stack", + value: 0, + group: selectedMenuItem, + onChanged: updateSelectedMenuItem, + iconOnly: _width == minimizedWidth, + ), + const SizedBox( + height: 2, + ), + DesktopMenuItem( + icon: SvgPicture.asset( + Assets.svg.exchange3, + width: 20, + height: 20, + ), + label: "Exchange", + value: 1, + group: selectedMenuItem, + onChanged: updateSelectedMenuItem, + iconOnly: _width == minimizedWidth, + ), + const SizedBox( + height: 2, + ), + DesktopMenuItem( + icon: SvgPicture.asset( + Assets.svg.bell, + width: 20, + height: 20, + ), + label: "Notifications", + value: 2, + group: selectedMenuItem, + onChanged: updateSelectedMenuItem, + iconOnly: _width == minimizedWidth, + ), + const SizedBox( + height: 2, + ), + DesktopMenuItem( + icon: SvgPicture.asset( + Assets.svg.addressBook2, + width: 20, + height: 20, + ), + label: "Address Book", + value: 3, + group: selectedMenuItem, + onChanged: updateSelectedMenuItem, + iconOnly: _width == minimizedWidth, + ), + const SizedBox( + height: 2, + ), + DesktopMenuItem( + icon: SvgPicture.asset( + Assets.svg.gear, + width: 20, + height: 20, + ), + label: "Settings", + value: 4, + group: selectedMenuItem, + onChanged: updateSelectedMenuItem, + iconOnly: _width == minimizedWidth, + ), + const SizedBox( + height: 2, + ), + DesktopMenuItem( + icon: SvgPicture.asset( + Assets.svg.messageQuestion, + width: 20, + height: 20, + ), + label: "Support", + value: 5, + group: selectedMenuItem, + onChanged: updateSelectedMenuItem, + iconOnly: _width == minimizedWidth, + ), + const SizedBox( + height: 2, + ), + DesktopMenuItem( + icon: SvgPicture.asset( + Assets.svg.messageQuestion, + width: 20, + height: 20, + ), + label: "About", + value: 6, + group: selectedMenuItem, + onChanged: updateSelectedMenuItem, + iconOnly: _width == minimizedWidth, + ), + const SizedBox( + height: 2, + ), + DesktopMenuItem( + icon: SvgPicture.asset( + Assets.svg.messageQuestion, + width: 20, + height: 20, + ), + label: "Exit", + value: 7, + group: selectedMenuItem, + onChanged: updateSelectedMenuItem, + iconOnly: _width == minimizedWidth, + ), + ], + ), + ), + const Spacer(), + Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + const Spacer(), + IconButton( + splashRadius: 18, + onPressed: toggleMinimize, + icon: SvgPicture.asset( + Assets.svg.minimize, + height: 12, + width: 12, + ), + ), + ], + ) + ], + ), + ), + ); + } +} diff --git a/lib/pages_desktop_specific/home/desktop_menu_item.dart b/lib/pages_desktop_specific/home/desktop_menu_item.dart new file mode 100644 index 000000000..76d945e2d --- /dev/null +++ b/lib/pages_desktop_specific/home/desktop_menu_item.dart @@ -0,0 +1,62 @@ +import 'package:flutter/material.dart'; +import 'package:stackwallet/utilities/text_styles.dart'; +import 'package:stackwallet/utilities/theme/stack_colors.dart'; + +class DesktopMenuItem extends StatelessWidget { + const DesktopMenuItem({ + Key? key, + required this.icon, + required this.label, + required this.value, + required this.group, + required this.onChanged, + required this.iconOnly, + }) : super(key: key); + + final Widget icon; + final String label; + final T value; + final T group; + final void Function(T) onChanged; + final bool iconOnly; + + @override + Widget build(BuildContext context) { + return TextButton( + style: value == group + ? Theme.of(context) + .extension()! + .getDesktopMenuButtonColorSelected(context) + : Theme.of(context) + .extension()! + .getDesktopMenuButtonColor(context), + onPressed: () { + onChanged(value); + }, + child: Padding( + padding: EdgeInsets.symmetric( + vertical: 16, + horizontal: iconOnly ? 0 : 16, + ), + child: Row( + mainAxisAlignment: + iconOnly ? MainAxisAlignment.center : MainAxisAlignment.start, + children: [ + icon, + if (!iconOnly) + const SizedBox( + width: 12, + ), + if (!iconOnly) + Text( + label, + style: value == group + ? STextStyles.desktopMenuItemSelected(context) + : STextStyles.desktopMenuItem(context), + ), + ], + ), + ), + ); + } +} diff --git a/lib/pages_desktop_specific/home/my_stack_view/coin_wallets_table.dart b/lib/pages_desktop_specific/home/my_stack_view/coin_wallets_table.dart new file mode 100644 index 000000000..64e4a23d3 --- /dev/null +++ b/lib/pages_desktop_specific/home/my_stack_view/coin_wallets_table.dart @@ -0,0 +1,48 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:stackwallet/utilities/constants.dart'; +import 'package:stackwallet/utilities/theme/stack_colors.dart'; +import 'package:stackwallet/widgets/wallet_info_row/wallet_info_row.dart'; + +class CoinWalletsTable extends ConsumerWidget { + const CoinWalletsTable({ + Key? key, + required this.walletIds, + }) : super(key: key); + + final List walletIds; + + @override + Widget build(BuildContext context, WidgetRef ref) { + return Container( + decoration: BoxDecoration( + color: Theme.of(context).extension()!.popupBG, + borderRadius: BorderRadius.circular( + Constants.size.circularBorderRadius, + ), + ), + child: Padding( + padding: const EdgeInsets.symmetric( + horizontal: 20, + vertical: 16, + ), + child: Column( + children: [ + for (int i = 0; i < walletIds.length; i++) + Column( + children: [ + if (i != 0) + const SizedBox( + height: 32, + ), + WalletInfoRow( + walletId: walletIds[i], + ), + ], + ), + ], + ), + ), + ); + } +} diff --git a/lib/pages_desktop_specific/home/my_stack_view/exit_to_my_stack_button.dart b/lib/pages_desktop_specific/home/my_stack_view/exit_to_my_stack_button.dart new file mode 100644 index 000000000..d34e1f7b3 --- /dev/null +++ b/lib/pages_desktop_specific/home/my_stack_view/exit_to_my_stack_button.dart @@ -0,0 +1,45 @@ +import 'package:flutter/material.dart'; +import 'package:stackwallet/pages_desktop_specific/home/desktop_home_view.dart'; +import 'package:stackwallet/utilities/text_styles.dart'; +import 'package:stackwallet/utilities/theme/stack_colors.dart'; + +class ExitToMyStackButton extends StatelessWidget { + const ExitToMyStackButton({ + Key? key, + this.onPressed, + }) : super(key: key); + + final VoidCallback? onPressed; + + @override + Widget build(BuildContext context) { + return Padding( + padding: const EdgeInsets.only( + right: 24, + ), + child: SizedBox( + height: 56, + child: TextButton( + style: Theme.of(context) + .extension()! + .getSmallSecondaryEnabledButtonColor(context), + onPressed: onPressed ?? + () { + Navigator.of(context).popUntil( + ModalRoute.withName(DesktopHomeView.routeName), + ); + }, + child: Padding( + padding: const EdgeInsets.symmetric( + horizontal: 30, + ), + child: Text( + "Exit to My Stack", + style: STextStyles.desktopButtonSmallSecondaryEnabled(context), + ), + ), + ), + ), + ); + } +} diff --git a/lib/pages_desktop_specific/home/my_stack_view/my_stack_view.dart b/lib/pages_desktop_specific/home/my_stack_view/my_stack_view.dart new file mode 100644 index 000000000..b7860542a --- /dev/null +++ b/lib/pages_desktop_specific/home/my_stack_view/my_stack_view.dart @@ -0,0 +1,62 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:flutter_svg/flutter_svg.dart'; +import 'package:stackwallet/pages/wallets_view/sub_widgets/empty_wallets.dart'; +import 'package:stackwallet/pages_desktop_specific/home/my_stack_view/my_wallets.dart'; +import 'package:stackwallet/providers/global/prefs_provider.dart'; +import 'package:stackwallet/providers/global/wallets_provider.dart'; +import 'package:stackwallet/utilities/assets.dart'; +import 'package:stackwallet/utilities/text_styles.dart'; +import 'package:stackwallet/widgets/desktop/desktop_app_bar.dart'; + +class MyStackView extends ConsumerStatefulWidget { + const MyStackView({Key? key}) : super(key: key); + + static const String routeName = "/myStackDesktop"; + + @override + ConsumerState createState() => _MyStackViewState(); +} + +class _MyStackViewState extends ConsumerState { + @override + Widget build(BuildContext context) { + debugPrint("BUILD: $runtimeType"); + final hasWallets = ref.watch(walletsChangeNotifierProvider).hasWallets; + + final showFavorites = ref.watch(prefsChangeNotifierProvider + .select((value) => value.showFavoriteWallets)); + + return Column( + children: [ + DesktopAppBar( + isCompactHeight: true, + leading: Row( + children: [ + const SizedBox( + width: 24, + ), + SizedBox( + width: 32, + height: 32, + child: SvgPicture.asset( + Assets.svg.stackIcon(context), + ), + ), + const SizedBox( + width: 12, + ), + Text( + "My Stack", + style: STextStyles.desktopH3(context), + ) + ], + ), + ), + Expanded( + child: hasWallets ? const MyWallets() : const EmptyWallets(), + ), + ], + ); + } +} diff --git a/lib/pages_desktop_specific/home/my_stack_view/my_wallets.dart b/lib/pages_desktop_specific/home/my_stack_view/my_wallets.dart new file mode 100644 index 000000000..e41c7643d --- /dev/null +++ b/lib/pages_desktop_specific/home/my_stack_view/my_wallets.dart @@ -0,0 +1,74 @@ +import 'package:flutter/material.dart'; +import 'package:stackwallet/pages/add_wallet_views/add_wallet_view/add_wallet_view.dart'; +import 'package:stackwallet/pages_desktop_specific/home/my_stack_view/wallet_summary_table.dart'; +import 'package:stackwallet/utilities/text_styles.dart'; +import 'package:stackwallet/utilities/theme/stack_colors.dart'; +import 'package:stackwallet/widgets/custom_buttons/blue_text_button.dart'; + +class MyWallets extends StatefulWidget { + const MyWallets({Key? key}) : super(key: key); + + @override + State createState() => _MyWalletsState(); +} + +class _MyWalletsState extends State { + @override + Widget build(BuildContext context) { + return Padding( + padding: const EdgeInsets.all(24), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + "Favorite wallets", + style: STextStyles.desktopTextExtraSmall(context).copyWith( + color: Theme.of(context) + .extension()! + .textFieldActiveSearchIconRight, + ), + ), + const SizedBox( + height: 20, + ), + // TODO favorites grid + Container( + color: Colors.deepPurpleAccent, + height: 210, + ), + + const SizedBox( + height: 40, + ), + + Row( + children: [ + Text( + "All wallets", + style: STextStyles.desktopTextExtraSmall(context).copyWith( + color: Theme.of(context) + .extension()! + .textFieldActiveSearchIconRight, + ), + ), + const Spacer(), + BlueTextButton( + text: "Add new wallet", + onTap: () { + Navigator.of(context).pushNamed(AddWalletView.routeName); + }, + ), + ], + ), + + const SizedBox( + height: 20, + ), + const Expanded( + child: WalletSummaryTable(), + ), + ], + ), + ); + } +} diff --git a/lib/pages_desktop_specific/home/my_stack_view/wallet_summary_table.dart b/lib/pages_desktop_specific/home/my_stack_view/wallet_summary_table.dart new file mode 100644 index 000000000..243d9d036 --- /dev/null +++ b/lib/pages_desktop_specific/home/my_stack_view/wallet_summary_table.dart @@ -0,0 +1,168 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:flutter_svg/svg.dart'; +import 'package:stackwallet/pages_desktop_specific/home/my_stack_view/coin_wallets_table.dart'; +import 'package:stackwallet/providers/providers.dart'; +import 'package:stackwallet/utilities/assets.dart'; +import 'package:stackwallet/utilities/constants.dart'; +import 'package:stackwallet/utilities/enums/coin_enum.dart'; +import 'package:stackwallet/utilities/format.dart'; +import 'package:stackwallet/utilities/text_styles.dart'; +import 'package:stackwallet/utilities/theme/stack_colors.dart'; +import 'package:stackwallet/widgets/table_view/table_view.dart'; +import 'package:stackwallet/widgets/table_view/table_view_cell.dart'; +import 'package:stackwallet/widgets/table_view/table_view_row.dart'; + +class WalletSummaryTable extends ConsumerStatefulWidget { + const WalletSummaryTable({Key? key}) : super(key: key); + + @override + ConsumerState createState() => _WalletTableState(); +} + +class _WalletTableState extends ConsumerState { + @override + Widget build(BuildContext context) { + final providersByCoin = ref + .watch( + walletsChangeNotifierProvider.select( + (value) => value.getManagerProvidersByCoin(), + ), + ) + .entries + .toList(growable: false); + + return TableView( + rows: [ + for (int i = 0; i < providersByCoin.length; i++) + TableViewRow( + padding: const EdgeInsets.symmetric( + horizontal: 20, + vertical: 16, + ), + decoration: BoxDecoration( + color: Theme.of(context).extension()!.popupBG, + borderRadius: BorderRadius.circular( + Constants.size.circularBorderRadius, + ), + ), + cells: [ + TableViewCell( + flex: 4, + child: Row( + children: [ + SvgPicture.asset( + Assets.svg.iconFor(coin: providersByCoin[i].key), + width: 28, + height: 28, + ), + const SizedBox( + width: 10, + ), + Text( + providersByCoin[i].key.prettyName, + style: + STextStyles.desktopTextExtraSmall(context).copyWith( + color: Theme.of(context) + .extension()! + .textDark, + ), + ) + ], + ), + ), + TableViewCell( + flex: 4, + child: Text( + providersByCoin[i].value.length == 1 + ? "${providersByCoin[i].value.length} wallet" + : "${providersByCoin[i].value.length} wallets", + style: STextStyles.desktopTextExtraSmall(context).copyWith( + color: Theme.of(context) + .extension()! + .textSubtitle1, + ), + ), + ), + TableViewCell( + flex: 6, + child: TablePriceInfo( + coin: providersByCoin[i].key, + ), + ), + ], + expandingChild: CoinWalletsTable( + walletIds: ref.watch( + walletsChangeNotifierProvider.select( + (value) => value.getWalletIdsFor( + coin: providersByCoin[i].key, + ), + ), + ), + ), + ) + ], + ); + } +} + +class TablePriceInfo extends ConsumerWidget { + const TablePriceInfo({Key? key, required this.coin}) : super(key: key); + + final Coin coin; + + @override + Widget build(BuildContext context, WidgetRef ref) { + final tuple = ref.watch( + priceAnd24hChangeNotifierProvider.select( + (value) => value.getPrice(coin), + ), + ); + + final currency = ref.watch( + prefsChangeNotifierProvider.select( + (value) => value.currency, + ), + ); + + final priceString = Format.localizedStringAsFixed( + value: tuple.item1, + locale: ref + .watch( + localeServiceChangeNotifierProvider.notifier, + ) + .locale, + decimalPlaces: 2, + ); + + final double percentChange = tuple.item2; + + var percentChangedColor = + Theme.of(context).extension()!.textDark; + if (percentChange > 0) { + percentChangedColor = + Theme.of(context).extension()!.accentColorGreen; + } else if (percentChange < 0) { + percentChangedColor = + Theme.of(context).extension()!.accentColorRed; + } + + return Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + "$priceString $currency/${coin.ticker}", + style: STextStyles.desktopTextExtraSmall(context).copyWith( + color: Theme.of(context).extension()!.textSubtitle1, + ), + ), + Text( + "${percentChange.toStringAsFixed(2)}%", + style: STextStyles.desktopTextExtraSmall(context).copyWith( + color: percentChangedColor, + ), + ), + ], + ); + } +} diff --git a/lib/providers/ui/color_theme_provider.dart b/lib/providers/ui/color_theme_provider.dart new file mode 100644 index 000000000..9843f0f9c --- /dev/null +++ b/lib/providers/ui/color_theme_provider.dart @@ -0,0 +1,6 @@ +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:stackwallet/utilities/theme/light_colors.dart'; +import 'package:stackwallet/utilities/theme/stack_colors.dart'; + +final colorThemeProvider = StateProvider( + (ref) => StackColors.fromStackColorTheme(LightColors())); diff --git a/lib/route_generator.dart b/lib/route_generator.dart index df15f65fe..797b62969 100644 --- a/lib/route_generator.dart +++ b/lib/route_generator.dart @@ -10,7 +10,7 @@ import 'package:stackwallet/pages/add_wallet_views/create_or_restore_wallet_view import 'package:stackwallet/pages/add_wallet_views/name_your_wallet_view/name_your_wallet_view.dart'; import 'package:stackwallet/pages/add_wallet_views/new_wallet_recovery_phrase_view/new_wallet_recovery_phrase_view.dart'; import 'package:stackwallet/pages/add_wallet_views/new_wallet_recovery_phrase_warning_view/new_wallet_recovery_phrase_warning_view.dart'; -import 'package:stackwallet/pages/add_wallet_views/restore_wallet_view/restore_options_view.dart'; +import 'package:stackwallet/pages/add_wallet_views/restore_wallet_view/restore_options_view/restore_options_view.dart'; import 'package:stackwallet/pages/add_wallet_views/restore_wallet_view/restore_wallet_view.dart'; import 'package:stackwallet/pages/add_wallet_views/verify_recovery_phrase_view/verify_recovery_phrase_view.dart'; import 'package:stackwallet/pages/address_book_views/address_book_view.dart'; @@ -75,6 +75,9 @@ import 'package:stackwallet/pages/wallet_view/transaction_views/transaction_deta import 'package:stackwallet/pages/wallet_view/transaction_views/transaction_search_filter_view.dart'; import 'package:stackwallet/pages/wallet_view/wallet_view.dart'; import 'package:stackwallet/pages/wallets_view/wallets_view.dart'; +import 'package:stackwallet/pages_desktop_specific/create_password/create_password_view.dart'; +import 'package:stackwallet/pages_desktop_specific/home/desktop_home_view.dart'; +import 'package:stackwallet/pages_desktop_specific/home/my_stack_view/my_stack_view.dart'; import 'package:stackwallet/services/coins/manager.dart'; import 'package:stackwallet/services/event_bus/events/global/node_connection_status_changed_event.dart'; import 'package:stackwallet/services/event_bus/events/global/wallet_sync_status_changed_event.dart'; @@ -876,6 +879,27 @@ class RouteGenerator { } return _routeError("${settings.name} invalid args: ${args.toString()}"); + // == Desktop specific routes ============================================ + case CreatePasswordView.routeName: + return getRoute( + shouldUseMaterialRoute: useMaterialPageRoute, + builder: (_) => const CreatePasswordView(), + settings: RouteSettings(name: settings.name)); + + case DesktopHomeView.routeName: + return getRoute( + shouldUseMaterialRoute: useMaterialPageRoute, + builder: (_) => const DesktopHomeView(), + settings: RouteSettings(name: settings.name)); + + case MyStackView.routeName: + return getRoute( + shouldUseMaterialRoute: useMaterialPageRoute, + builder: (_) => const MyStackView(), + settings: RouteSettings(name: settings.name)); + + // == End of desktop specific routes ===================================== + default: return _routeError(""); } diff --git a/lib/services/coins/bitcoin/bitcoin_wallet.dart b/lib/services/coins/bitcoin/bitcoin_wallet.dart index e1ea02abe..da3bdfed0 100644 --- a/lib/services/coins/bitcoin/bitcoin_wallet.dart +++ b/lib/services/coins/bitcoin/bitcoin_wallet.dart @@ -2250,7 +2250,7 @@ class BitcoinWallet extends CoinServiceAPI { batches[batchNumber] = {}; } final scripthash = _convertToScriptHash(allAddresses[i], _network); - final id = const Uuid().v1(); + final id = Logger.isTestEnv ? "$i" : const Uuid().v1(); requestIdToAddressMap[id] = allAddresses[i]; batches[batchNumber]!.addAll({ id: [scripthash] diff --git a/lib/services/coins/bitcoincash/bitcoincash_wallet.dart b/lib/services/coins/bitcoincash/bitcoincash_wallet.dart new file mode 100644 index 000000000..81b8198e5 --- /dev/null +++ b/lib/services/coins/bitcoincash/bitcoincash_wallet.dart @@ -0,0 +1,3111 @@ +// import 'dart:async'; +// import 'dart:convert'; +// import 'dart:io'; +// import 'dart:typed_data'; +// +// import 'package:bech32/bech32.dart'; +// import 'package:bip32/bip32.dart' as bip32; +// import 'package:bip39/bip39.dart' as bip39; +// import 'package:bitcoindart/bitcoindart.dart'; +// import 'package:bs58check/bs58check.dart' as bs58check; +// import 'package:crypto/crypto.dart'; +// import 'package:decimal/decimal.dart'; +// import 'package:flutter/foundation.dart'; +// import 'package:flutter_secure_storage/flutter_secure_storage.dart'; +// import 'package:http/http.dart'; +// import 'package:stackwallet/electrumx_rpc/cached_electrumx.dart'; +// import 'package:stackwallet/electrumx_rpc/electrumx.dart'; +// import 'package:stackwallet/hive/db.dart'; +// import 'package:stackwallet/models/models.dart' as models; +// import 'package:stackwallet/models/paymint/fee_object_model.dart'; +// import 'package:stackwallet/models/paymint/transactions_model.dart'; +// import 'package:stackwallet/models/paymint/utxo_model.dart'; +// import 'package:stackwallet/services/coins/coin_service.dart'; +// import 'package:stackwallet/services/event_bus/events/global/node_connection_status_changed_event.dart'; +// import 'package:stackwallet/services/event_bus/events/global/refresh_percent_changed_event.dart'; +// import 'package:stackwallet/services/event_bus/events/global/updated_in_background_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/node_service.dart'; +// import 'package:stackwallet/services/notifications_api.dart'; +// import 'package:stackwallet/services/price.dart'; +// import 'package:stackwallet/services/transaction_notification_tracker.dart'; +// import 'package:stackwallet/utilities/assets.dart'; +// import 'package:stackwallet/utilities/constants.dart'; +// import 'package:stackwallet/utilities/default_nodes.dart'; +// import 'package:stackwallet/utilities/enums/coin_enum.dart'; +// import 'package:stackwallet/utilities/enums/fee_rate_type_enum.dart'; +// import 'package:stackwallet/utilities/flutter_secure_storage_interface.dart'; +// import 'package:stackwallet/utilities/format.dart'; +// import 'package:stackwallet/utilities/logger.dart'; +// import 'package:stackwallet/utilities/prefs.dart'; +// import 'package:tuple/tuple.dart'; +// import 'package:uuid/uuid.dart'; +// import 'package:bitbox/bitbox.dart' as Bitbox; +// +// const int MINIMUM_CONFIRMATIONS = 3; +// const int DUST_LIMIT = 546; +// +// const String GENESIS_HASH_MAINNET = +// "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f"; +// const String GENESIS_HASH_TESTNET = +// "000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943"; +// +// enum DerivePathType { bip44 } +// +// bip32.BIP32 getBip32Node(int chain, int index, String mnemonic, +// NetworkType network, DerivePathType derivePathType) { +// final root = getBip32Root(mnemonic, network); +// +// final node = getBip32NodeFromRoot(chain, index, root, derivePathType); +// return node; +// } +// +// /// wrapper for compute() +// bip32.BIP32 getBip32NodeWrapper( +// Tuple5 args, +// ) { +// return getBip32Node( +// args.item1, +// args.item2, +// args.item3, +// args.item4, +// args.item5, +// ); +// } +// +// bip32.BIP32 getBip32NodeFromRoot( +// int chain, int index, bip32.BIP32 root, DerivePathType derivePathType) { +// String coinType; +// switch (root.network.wif) { +// case 0x80: // bch mainnet wif +// coinType = "145"; // bch mainnet +// break; +// case 0xef: // bch testnet wif +// coinType = "1"; // bch testnet +// break; +// default: +// throw Exception("Invalid Bitcoincash network type used!"); +// } +// switch (derivePathType) { +// case DerivePathType.bip44: +// return root.derivePath("m/44'/$coinType'/0'/$chain/$index"); +// default: +// throw Exception("DerivePathType must not be null."); +// } +// } +// +// /// wrapper for compute() +// bip32.BIP32 getBip32NodeFromRootWrapper( +// Tuple4 args, +// ) { +// return getBip32NodeFromRoot( +// args.item1, +// args.item2, +// args.item3, +// args.item4, +// ); +// } +// +// bip32.BIP32 getBip32Root(String mnemonic, NetworkType network) { +// final seed = bip39.mnemonicToSeed(mnemonic); +// final networkType = bip32.NetworkType( +// wif: network.wif, +// bip32: bip32.Bip32Type( +// public: network.bip32.public, +// private: network.bip32.private, +// ), +// ); +// +// final root = bip32.BIP32.fromSeed(seed, networkType); +// return root; +// } +// +// /// wrapper for compute() +// bip32.BIP32 getBip32RootWrapper(Tuple2 args) { +// return getBip32Root(args.item1, args.item2); +// } +// +// class BitcoinCashWallet extends CoinServiceAPI { +// static const integrationTestFlag = +// bool.fromEnvironment("IS_INTEGRATION_TEST"); +// final _prefs = Prefs.instance; +// +// Timer? timer; +// late Coin _coin; +// +// late final TransactionNotificationTracker txTracker; +// +// NetworkType get _network { +// switch (coin) { +// case Coin.bitcoincash: +// return bitcoincash; +// case Coin.bitcoincashTestnet: +// return bitcoincashtestnet; +// default: +// throw Exception("Bitcoincash network type not set!"); +// } +// } +// +// List outputsList = []; +// +// @override +// Coin get coin => _coin; +// +// @override +// Future> get allOwnAddresses => +// _allOwnAddresses ??= _fetchAllOwnAddresses(); +// Future>? _allOwnAddresses; +// +// Future? _utxoData; +// Future get utxoData => _utxoData ??= _fetchUtxoData(); +// +// @override +// Future> get unspentOutputs async => +// (await utxoData).unspentOutputArray; +// +// @override +// Future get availableBalance async { +// final data = await utxoData; +// return Format.satoshisToAmount( +// data.satoshiBalance - data.satoshiBalanceUnconfirmed); +// } +// +// @override +// Future get pendingBalance async { +// final data = await utxoData; +// return Format.satoshisToAmount(data.satoshiBalanceUnconfirmed); +// } +// +// @override +// Future get balanceMinusMaxFee async => +// (await availableBalance) - +// (Decimal.fromInt((await maxFee)) / Decimal.fromInt(Constants.satsPerCoin)) +// .toDecimal(); +// +// @override +// Future get totalBalance async { +// if (!isActive) { +// final totalBalance = DB.instance +// .get(boxName: walletId, key: 'totalBalance') as int?; +// if (totalBalance == null) { +// final data = await utxoData; +// return Format.satoshisToAmount(data.satoshiBalance); +// } else { +// return Format.satoshisToAmount(totalBalance); +// } +// } +// final data = await utxoData; +// return Format.satoshisToAmount(data.satoshiBalance); +// } +// +// @override +// Future get currentReceivingAddress => +// _currentReceivingAddressP2PKH ??= +// _getCurrentAddressForChain(0, DerivePathType.bip44); +// +// Future? _currentReceivingAddressP2PKH; +// +// @override +// Future exit() async { +// _hasCalledExit = true; +// timer?.cancel(); +// timer = null; +// stopNetworkAlivePinging(); +// } +// +// bool _hasCalledExit = false; +// +// @override +// bool get hasCalledExit => _hasCalledExit; +// +// @override +// Future get fees => _feeObject ??= _getFees(); +// Future? _feeObject; +// +// @override +// Future get maxFee async { +// final fee = (await fees).fast; +// final satsFee = +// Format.satoshisToAmount(fee) * Decimal.fromInt(Constants.satsPerCoin); +// return satsFee.floor().toBigInt().toInt(); +// } +// +// @override +// Future> get mnemonic => _getMnemonicList(); +// +// Future get chainHeight async { +// try { +// final result = await _electrumXClient.getBlockHeadTip(); +// return result["height"] as int; +// } catch (e, s) { +// Logging.instance.log("Exception caught in chainHeight: $e\n$s", +// level: LogLevel.Error); +// return -1; +// } +// } +// +// Future get storedChainHeight async { +// final storedHeight = DB.instance +// .get(boxName: walletId, key: "storedChainHeight") as int?; +// return storedHeight ?? 0; +// } +// +// Future updateStoredChainHeight({required int newHeight}) async { +// DB.instance.put( +// boxName: walletId, key: "storedChainHeight", value: newHeight); +// } +// +// DerivePathType addressType({required String address}) { +// Uint8List? decodeBase58; +// Segwit? decodeBech32; +// try { +// decodeBase58 = bs58check.decode(address); +// } catch (err) { +// // Base58check decode fail +// } +// if (decodeBase58 != null) { +// if (decodeBase58[0] == _network.pubKeyHash) { +// // P2PKH +// return DerivePathType.bip44; +// } +// throw ArgumentError('Invalid version or Network mismatch'); +// } else { +// try { +// decodeBech32 = segwit.decode(address); +// } catch (err) { +// // Bech32 decode fail +// } +// if (_network.bech32 != decodeBech32!.hrp) { +// throw ArgumentError('Invalid prefix or Network mismatch'); +// } +// if (decodeBech32.version != 0) { +// throw ArgumentError('Invalid address version'); +// } +// } +// throw ArgumentError('$address has no matching Script'); +// } +// +// bool longMutex = false; +// +// @override +// Future recoverFromMnemonic({ +// required String mnemonic, +// required int maxUnusedAddressGap, +// required int maxNumberOfIndexesToCheck, +// required int height, +// }) async { +// longMutex = true; +// final start = DateTime.now(); +// try { +// Logging.instance.log("IS_INTEGRATION_TEST: $integrationTestFlag", +// level: LogLevel.Info); +// if (!integrationTestFlag) { +// final features = await electrumXClient.getServerFeatures(); +// Logging.instance.log("features: $features", level: LogLevel.Info); +// switch (coin) { +// case Coin.bitcoincash: +// if (features['genesis_hash'] != GENESIS_HASH_MAINNET) { +// throw Exception("genesis hash does not match main net!"); +// } +// break; +// case Coin.bitcoincashTestnet: +// if (features['genesis_hash'] != GENESIS_HASH_TESTNET) { +// throw Exception("genesis hash does not match test net!"); +// } +// break; +// default: +// throw Exception( +// "Attempted to generate a BitcoinCashWallet using a non bch coin type: ${coin.name}"); +// } +// } +// // check to make sure we aren't overwriting a mnemonic +// // this should never fail +// if ((await _secureStore.read(key: '${_walletId}_mnemonic')) != null) { +// longMutex = false; +// throw Exception("Attempted to overwrite mnemonic on restore!"); +// } +// await _secureStore.write( +// key: '${_walletId}_mnemonic', value: mnemonic.trim()); +// await _recoverWalletFromBIP32SeedPhrase( +// mnemonic: mnemonic.trim(), +// maxUnusedAddressGap: maxUnusedAddressGap, +// maxNumberOfIndexesToCheck: maxNumberOfIndexesToCheck, +// ); +// } catch (e, s) { +// Logging.instance.log( +// "Exception rethrown from recoverFromMnemonic(): $e\n$s", +// level: LogLevel.Error); +// longMutex = false; +// rethrow; +// } +// longMutex = false; +// +// final end = DateTime.now(); +// Logging.instance.log( +// "$walletName recovery time: ${end.difference(start).inMilliseconds} millis", +// level: LogLevel.Info); +// } +// +// Future _recoverWalletFromBIP32SeedPhrase({ +// required String mnemonic, +// int maxUnusedAddressGap = 20, +// int maxNumberOfIndexesToCheck = 1000, +// }) async { +// longMutex = true; +// +// Map> p2pkhReceiveDerivations = {}; +// Map> p2pkhChangeDerivations = {}; +// +// final root = await compute(getBip32RootWrapper, Tuple2(mnemonic, _network)); +// +// List p2pkhReceiveAddressArray = []; +// int p2pkhReceiveIndex = -1; +// +// List p2pkhChangeAddressArray = []; +// int p2pkhChangeIndex = -1; +// +// // The gap limit will be capped at [maxUnusedAddressGap] +// int receivingGapCounter = 0; +// int changeGapCounter = 0; +// +// // actual size is 12 due to p2pkh so 12x1 +// const txCountBatchSize = 12; +// +// try { +// // receiving addresses +// Logging.instance +// .log("checking receiving addresses...", level: LogLevel.Info); +// for (int index = 0; +// index < maxNumberOfIndexesToCheck && +// receivingGapCounter < maxUnusedAddressGap; +// index += txCountBatchSize) { +// Logging.instance.log( +// "index: $index, \t receivingGapCounter: $receivingGapCounter", +// level: LogLevel.Info); +// +// final receivingP2pkhID = "k_$index"; +// Map txCountCallArgs = {}; +// final Map receivingNodes = {}; +// +// for (int j = 0; j < txCountBatchSize; j++) { +// // bip44 / P2PKH +// final node44 = await compute( +// getBip32NodeFromRootWrapper, +// Tuple4( +// 0, +// index + j, +// root, +// DerivePathType.bip44, +// ), +// ); +// final p2pkhReceiveAddress = P2PKH( +// data: PaymentData(pubkey: node44.publicKey), +// network: _network) +// .data +// .address!; +// receivingNodes.addAll({ +// "${receivingP2pkhID}_$j": { +// "node": node44, +// "address": p2pkhReceiveAddress, +// } +// }); +// txCountCallArgs.addAll({ +// "${receivingP2pkhID}_$j": p2pkhReceiveAddress, +// }); +// } +// +// // get address tx counts +// final counts = await _getBatchTxCount(addresses: txCountCallArgs); +// +// // check and add appropriate addresses +// for (int k = 0; k < txCountBatchSize; k++) { +// int p2pkhTxCount = counts["${receivingP2pkhID}_$k"]!; +// if (p2pkhTxCount > 0) { +// final node = receivingNodes["${receivingP2pkhID}_$k"]; +// // add address to array +// p2pkhReceiveAddressArray.add(node["address"] as String); +// // set current index +// p2pkhReceiveIndex = index + k; +// // reset counter +// receivingGapCounter = 0; +// // add info to derivations +// p2pkhReceiveDerivations[node["address"] as String] = { +// "pubKey": Format.uint8listToString( +// (node["node"] as bip32.BIP32).publicKey), +// "wif": (node["node"] as bip32.BIP32).toWIF(), +// }; +// } +// +// // increase counter when no tx history found +// if (p2pkhTxCount == 0) { +// receivingGapCounter++; +// } +// } +// } +// +// Logging.instance +// .log("checking change addresses...", level: LogLevel.Info); +// // change addresses +// for (int index = 0; +// index < maxNumberOfIndexesToCheck && +// changeGapCounter < maxUnusedAddressGap; +// index += txCountBatchSize) { +// Logging.instance.log( +// "index: $index, \t changeGapCounter: $changeGapCounter", +// level: LogLevel.Info); +// final changeP2pkhID = "k_$index"; +// Map args = {}; +// final Map changeNodes = {}; +// +// for (int j = 0; j < txCountBatchSize; j++) { +// // bip44 / P2PKH +// final node44 = await compute( +// getBip32NodeFromRootWrapper, +// Tuple4( +// 1, +// index + j, +// root, +// DerivePathType.bip44, +// ), +// ); +// final p2pkhChangeAddress = P2PKH( +// data: PaymentData(pubkey: node44.publicKey), +// network: _network) +// .data +// .address!; +// changeNodes.addAll({ +// "${changeP2pkhID}_$j": { +// "node": node44, +// "address": p2pkhChangeAddress, +// } +// }); +// args.addAll({ +// "${changeP2pkhID}_$j": p2pkhChangeAddress, +// }); +// } +// +// // get address tx counts +// final counts = await _getBatchTxCount(addresses: args); +// +// // check and add appropriate addresses +// for (int k = 0; k < txCountBatchSize; k++) { +// int p2pkhTxCount = counts["${changeP2pkhID}_$k"]!; +// if (p2pkhTxCount > 0) { +// final node = changeNodes["${changeP2pkhID}_$k"]; +// // add address to array +// p2pkhChangeAddressArray.add(node["address"] as String); +// // set current index +// p2pkhChangeIndex = index + k; +// // reset counter +// changeGapCounter = 0; +// // add info to derivations +// p2pkhChangeDerivations[node["address"] as String] = { +// "pubKey": Format.uint8listToString( +// (node["node"] as bip32.BIP32).publicKey), +// "wif": (node["node"] as bip32.BIP32).toWIF(), +// }; +// } +// +// // increase counter when no tx history found +// if (p2pkhTxCount == 0) { +// changeGapCounter++; +// } +// } +// } +// +// // save the derivations (if any) +// if (p2pkhReceiveDerivations.isNotEmpty) { +// await addDerivations( +// chain: 0, +// derivePathType: DerivePathType.bip44, +// derivationsToAdd: p2pkhReceiveDerivations); +// } +// if (p2pkhChangeDerivations.isNotEmpty) { +// await addDerivations( +// chain: 1, +// derivePathType: DerivePathType.bip44, +// derivationsToAdd: p2pkhChangeDerivations); +// } +// +// // If restoring a wallet that never received any funds, then set receivingArray manually +// // If we didn't do this, it'd store an empty array +// if (p2pkhReceiveIndex == -1) { +// final address = +// await _generateAddressForChain(0, 0, DerivePathType.bip44); +// p2pkhReceiveAddressArray.add(address); +// p2pkhReceiveIndex = 0; +// } +// +// // If restoring a wallet that never sent any funds with change, then set changeArray +// // manually. If we didn't do this, it'd store an empty array. +// if (p2pkhChangeIndex == -1) { +// final address = +// await _generateAddressForChain(1, 0, DerivePathType.bip44); +// p2pkhChangeAddressArray.add(address); +// p2pkhChangeIndex = 0; +// } +// +// await DB.instance.put( +// boxName: walletId, +// key: 'receivingAddressesP2PKH', +// value: p2pkhReceiveAddressArray); +// await DB.instance.put( +// boxName: walletId, +// key: 'changeAddressesP2PKH', +// value: p2pkhChangeAddressArray); +// await DB.instance.put( +// boxName: walletId, +// key: 'receivingIndexP2PKH', +// value: p2pkhReceiveIndex); +// await DB.instance.put( +// boxName: walletId, key: 'changeIndexP2PKH', value: p2pkhChangeIndex); +// await DB.instance +// .put(boxName: walletId, key: "id", value: _walletId); +// await DB.instance +// .put(boxName: walletId, key: "isFavorite", value: false); +// +// longMutex = false; +// } catch (e, s) { +// Logging.instance.log( +// "Exception rethrown from _recoverWalletFromBIP32SeedPhrase(): $e\n$s", +// level: LogLevel.Info); +// +// longMutex = false; +// rethrow; +// } +// } +// +// Future refreshIfThereIsNewData() async { +// if (longMutex) return false; +// if (_hasCalledExit) return false; +// Logging.instance.log("refreshIfThereIsNewData", level: LogLevel.Info); +// +// try { +// bool needsRefresh = false; +// Logging.instance.log( +// "notified unconfirmed transactions: ${txTracker.pendings}", +// level: LogLevel.Info); +// Set txnsToCheck = {}; +// +// for (final String txid in txTracker.pendings) { +// if (!txTracker.wasNotifiedConfirmed(txid)) { +// txnsToCheck.add(txid); +// } +// } +// +// for (String txid in txnsToCheck) { +// final txn = await electrumXClient.getTransaction(txHash: txid); +// var confirmations = txn["confirmations"]; +// if (confirmations is! int) continue; +// bool isUnconfirmed = confirmations < MINIMUM_CONFIRMATIONS; +// if (!isUnconfirmed) { +// // unconfirmedTxs = {}; +// needsRefresh = true; +// break; +// } +// } +// if (!needsRefresh) { +// var allOwnAddresses = await _fetchAllOwnAddresses(); +// List> allTxs = +// await _fetchHistory(allOwnAddresses); +// final txData = await transactionData; +// for (Map transaction in allTxs) { +// if (txData.findTransaction(transaction['tx_hash'] as String) == +// null) { +// Logging.instance.log( +// " txid not found in address history already ${transaction['tx_hash']}", +// level: LogLevel.Info); +// needsRefresh = true; +// break; +// } +// } +// } +// return needsRefresh; +// } catch (e, s) { +// Logging.instance.log( +// "Exception caught in refreshIfThereIsNewData: $e\n$s", +// level: LogLevel.Info); +// rethrow; +// } +// } +// +// Future getAllTxsToWatch( +// TransactionData txData, +// ) async { +// if (_hasCalledExit) return; +// List unconfirmedTxnsToNotifyPending = []; +// List unconfirmedTxnsToNotifyConfirmed = []; +// +// // Get all unconfirmed incoming transactions +// for (final chunk in txData.txChunks) { +// for (final tx in chunk.transactions) { +// if (tx.confirmedStatus) { +// if (txTracker.wasNotifiedPending(tx.txid) && +// !txTracker.wasNotifiedConfirmed(tx.txid)) { +// unconfirmedTxnsToNotifyConfirmed.add(tx); +// } +// } else { +// if (!txTracker.wasNotifiedPending(tx.txid)) { +// unconfirmedTxnsToNotifyPending.add(tx); +// } +// } +// } +// } +// +// // notify on new incoming transaction +// for (final tx in unconfirmedTxnsToNotifyPending) { +// if (tx.txType == "Received") { +// NotificationApi.showNotification( +// title: "Incoming transaction", +// body: walletName, +// walletId: walletId, +// iconAssetName: Assets.svg.iconFor(coin: coin), +// date: DateTime.now(), +// shouldWatchForUpdates: tx.confirmations < MINIMUM_CONFIRMATIONS, +// coinName: coin.name, +// txid: tx.txid, +// confirmations: tx.confirmations, +// requiredConfirmations: MINIMUM_CONFIRMATIONS, +// ); +// await txTracker.addNotifiedPending(tx.txid); +// } else if (tx.txType == "Sent") { +// NotificationApi.showNotification( +// title: "Sending transaction", +// body: walletName, +// walletId: walletId, +// iconAssetName: Assets.svg.iconFor(coin: coin), +// date: DateTime.fromMillisecondsSinceEpoch(tx.timestamp * 1000), +// shouldWatchForUpdates: tx.confirmations < MINIMUM_CONFIRMATIONS, +// coinName: coin.name, +// txid: tx.txid, +// confirmations: tx.confirmations, +// requiredConfirmations: MINIMUM_CONFIRMATIONS, +// ); +// await txTracker.addNotifiedPending(tx.txid); +// } +// } +// +// // notify on confirmed +// for (final tx in unconfirmedTxnsToNotifyConfirmed) { +// if (tx.txType == "Received") { +// NotificationApi.showNotification( +// title: "Incoming transaction confirmed", +// body: walletName, +// walletId: walletId, +// iconAssetName: Assets.svg.iconFor(coin: coin), +// date: DateTime.now(), +// shouldWatchForUpdates: false, +// coinName: coin.name, +// ); +// +// await txTracker.addNotifiedConfirmed(tx.txid); +// } else if (tx.txType == "Sent") { +// NotificationApi.showNotification( +// title: "Outgoing transaction confirmed", +// body: walletName, +// walletId: walletId, +// iconAssetName: Assets.svg.iconFor(coin: coin), +// date: DateTime.now(), +// shouldWatchForUpdates: false, +// coinName: coin.name, +// ); +// await txTracker.addNotifiedConfirmed(tx.txid); +// } +// } +// } +// +// bool refreshMutex = false; +// +// bool _shouldAutoSync = false; +// +// @override +// bool get shouldAutoSync => _shouldAutoSync; +// +// @override +// set shouldAutoSync(bool shouldAutoSync) { +// if (_shouldAutoSync != shouldAutoSync) { +// _shouldAutoSync = shouldAutoSync; +// if (!shouldAutoSync) { +// timer?.cancel(); +// timer = null; +// stopNetworkAlivePinging(); +// } else { +// startNetworkAlivePinging(); +// refresh(); +// } +// } +// } +// +// //TODO Show percentages properly/more consistently +// /// Refreshes display data for the wallet +// @override +// Future refresh() async { +// final bchaddr = Bitbox.Address.toCashAddress(await currentReceivingAddress); +// print("bchaddr: $bchaddr ${await currentReceivingAddress}"); +// +// if (refreshMutex) { +// Logging.instance.log("$walletId $walletName refreshMutex denied", +// level: LogLevel.Info); +// return; +// } else { +// refreshMutex = true; +// } +// +// try { +// GlobalEventBus.instance.fire( +// WalletSyncStatusChangedEvent( +// WalletSyncStatus.syncing, +// walletId, +// coin, +// ), +// ); +// +// GlobalEventBus.instance.fire(RefreshPercentChangedEvent(0.0, walletId)); +// +// GlobalEventBus.instance.fire(RefreshPercentChangedEvent(0.1, walletId)); +// +// final currentHeight = await chainHeight; +// const storedHeight = 1; //await storedChainHeight; +// +// Logging.instance +// .log("chain height: $currentHeight", level: LogLevel.Info); +// Logging.instance +// .log("cached height: $storedHeight", level: LogLevel.Info); +// +// if (currentHeight != storedHeight) { +// if (currentHeight != -1) { +// // -1 failed to fetch current height +// updateStoredChainHeight(newHeight: currentHeight); +// } +// +// GlobalEventBus.instance.fire(RefreshPercentChangedEvent(0.2, walletId)); +// await _checkChangeAddressForTransactions(DerivePathType.bip44); +// +// GlobalEventBus.instance.fire(RefreshPercentChangedEvent(0.3, walletId)); +// await _checkCurrentReceivingAddressesForTransactions(); +// +// final newTxData = _fetchTransactionData(); +// GlobalEventBus.instance +// .fire(RefreshPercentChangedEvent(0.50, walletId)); +// +// final newUtxoData = _fetchUtxoData(); +// final feeObj = _getFees(); +// GlobalEventBus.instance +// .fire(RefreshPercentChangedEvent(0.60, walletId)); +// +// _transactionData = Future(() => newTxData); +// +// GlobalEventBus.instance +// .fire(RefreshPercentChangedEvent(0.70, walletId)); +// _feeObject = Future(() => feeObj); +// _utxoData = Future(() => newUtxoData); +// GlobalEventBus.instance +// .fire(RefreshPercentChangedEvent(0.80, walletId)); +// +// await getAllTxsToWatch(await newTxData); +// GlobalEventBus.instance +// .fire(RefreshPercentChangedEvent(0.90, walletId)); +// } +// +// GlobalEventBus.instance.fire(RefreshPercentChangedEvent(1.0, walletId)); +// GlobalEventBus.instance.fire( +// WalletSyncStatusChangedEvent( +// WalletSyncStatus.synced, +// walletId, +// coin, +// ), +// ); +// refreshMutex = false; +// +// if (shouldAutoSync) { +// timer ??= Timer.periodic(const Duration(seconds: 150), (timer) async { +// // chain height check currently broken +// // if ((await chainHeight) != (await storedChainHeight)) { +// if (await refreshIfThereIsNewData()) { +// await refresh(); +// GlobalEventBus.instance.fire(UpdatedInBackgroundEvent( +// "New data found in $walletId $walletName in background!", +// walletId)); +// } +// // } +// }); +// } +// } catch (error, strace) { +// refreshMutex = false; +// GlobalEventBus.instance.fire( +// NodeConnectionStatusChangedEvent( +// NodeConnectionStatus.disconnected, +// walletId, +// coin, +// ), +// ); +// GlobalEventBus.instance.fire( +// WalletSyncStatusChangedEvent( +// WalletSyncStatus.unableToSync, +// walletId, +// coin, +// ), +// ); +// Logging.instance.log( +// "Caught exception in refreshWalletData(): $error\n$strace", +// level: LogLevel.Error); +// } +// } +// +// @override +// Future> prepareSend({ +// required String address, +// required int satoshiAmount, +// Map? args, +// }) async { +// try { +// final feeRateType = args?["feeRate"]; +// final feeRateAmount = args?["feeRateAmount"]; +// if (feeRateType is FeeRateType || feeRateAmount is int) { +// late final int rate; +// if (feeRateType is FeeRateType) { +// int fee = 0; +// final feeObject = await fees; +// switch (feeRateType) { +// case FeeRateType.fast: +// fee = feeObject.fast; +// break; +// case FeeRateType.average: +// fee = feeObject.medium; +// break; +// case FeeRateType.slow: +// fee = feeObject.slow; +// break; +// } +// rate = fee; +// } else { +// rate = feeRateAmount as int; +// } +// // check for send all +// bool isSendAll = false; +// final balance = Format.decimalAmountToSatoshis(await availableBalance); +// if (satoshiAmount == balance) { +// isSendAll = true; +// } +// +// final result = +// await coinSelection(satoshiAmount, rate, address, isSendAll); +// Logging.instance.log("SEND RESULT: $result", level: LogLevel.Info); +// if (result is int) { +// switch (result) { +// case 1: +// throw Exception("Insufficient balance!"); +// case 2: +// throw Exception("Insufficient funds to pay for transaction fee!"); +// default: +// throw Exception("Transaction failed with error code $result"); +// } +// } else { +// final hex = result["hex"]; +// if (hex is String) { +// final fee = result["fee"] as int; +// final vSize = result["vSize"] as int; +// +// Logging.instance.log("txHex: $hex", level: LogLevel.Info); +// Logging.instance.log("fee: $fee", level: LogLevel.Info); +// Logging.instance.log("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 result as Map; +// } else { +// throw Exception("sent hex is not a String!!!"); +// } +// } +// } else { +// throw ArgumentError("Invalid fee rate argument provided!"); +// } +// } catch (e, s) { +// Logging.instance.log("Exception rethrown from prepareSend(): $e\n$s", +// level: LogLevel.Error); +// rethrow; +// } +// } +// +// @override +// Future confirmSend({dynamic txData}) async { +// try { +// Logging.instance.log("confirmSend txData: $txData", level: LogLevel.Info); +// final txHash = await _electrumXClient.broadcastTransaction( +// rawTx: txData["hex"] as String); +// Logging.instance.log("Sent txHash: $txHash", level: LogLevel.Info); +// return txHash; +// } catch (e, s) { +// Logging.instance.log("Exception rethrown from confirmSend(): $e\n$s", +// level: LogLevel.Error); +// rethrow; +// } +// } +// +// @override +// Future send({ +// required String toAddress, +// required int amount, +// Map args = const {}, +// }) async { +// try { +// final txData = await prepareSend( +// address: toAddress, satoshiAmount: amount, args: args); +// final txHash = await confirmSend(txData: txData); +// return txHash; +// } catch (e, s) { +// Logging.instance +// .log("Exception rethrown from send(): $e\n$s", level: LogLevel.Error); +// rethrow; +// } +// } +// +// @override +// Future testNetworkConnection() async { +// try { +// final result = await _electrumXClient.ping(); +// return result; +// } catch (_) { +// return false; +// } +// } +// +// Timer? _networkAliveTimer; +// +// void startNetworkAlivePinging() { +// // call once on start right away +// _periodicPingCheck(); +// +// // then periodically check +// _networkAliveTimer = Timer.periodic( +// Constants.networkAliveTimerDuration, +// (_) async { +// _periodicPingCheck(); +// }, +// ); +// } +// +// void _periodicPingCheck() async { +// bool hasNetwork = await testNetworkConnection(); +// _isConnected = hasNetwork; +// if (_isConnected != hasNetwork) { +// NodeConnectionStatus status = hasNetwork +// ? NodeConnectionStatus.connected +// : NodeConnectionStatus.disconnected; +// GlobalEventBus.instance +// .fire(NodeConnectionStatusChangedEvent(status, walletId, coin)); +// } +// } +// +// void stopNetworkAlivePinging() { +// _networkAliveTimer?.cancel(); +// _networkAliveTimer = null; +// } +// +// bool _isConnected = false; +// +// @override +// bool get isConnected => _isConnected; +// +// @override +// Future initializeNew() async { +// Logging.instance +// .log("Generating new ${coin.prettyName} wallet.", level: LogLevel.Info); +// +// if ((DB.instance.get(boxName: walletId, key: "id")) != null) { +// throw Exception( +// "Attempted to initialize a new wallet using an existing wallet ID!"); +// } +// await _prefs.init(); +// try { +// await _generateNewWallet(); +// } catch (e, s) { +// Logging.instance.log("Exception rethrown from initializeNew(): $e\n$s", +// level: LogLevel.Fatal); +// rethrow; +// } +// await Future.wait([ +// DB.instance.put(boxName: walletId, key: "id", value: _walletId), +// DB.instance +// .put(boxName: walletId, key: "isFavorite", value: false), +// ]); +// } +// +// @override +// Future initializeExisting() async { +// Logging.instance.log("Opening existing ${coin.prettyName} wallet.", +// level: LogLevel.Info); +// +// if ((DB.instance.get(boxName: walletId, key: "id")) == null) { +// throw Exception( +// "Attempted to initialize an existing wallet using an unknown wallet ID!"); +// } +// await _prefs.init(); +// final data = +// DB.instance.get(boxName: walletId, key: "latest_tx_model") +// as TransactionData?; +// if (data != null) { +// _transactionData = Future(() => data); +// } +// } +// +// @override +// Future get transactionData => +// _transactionData ??= _fetchTransactionData(); +// Future? _transactionData; +// +// @override +// bool validateAddress(String address) { +// try { +// // 0 for bitcoincash: address scheme, 1 for legacy address +// final format = Bitbox.Address.detectFormat(address); +// print("format $format"); +// return true; +// } catch (e, s) { +// return false; +// } +// } +// +// @override +// String get walletId => _walletId; +// late String _walletId; +// +// @override +// String get walletName => _walletName; +// late String _walletName; +// +// // setter for updating on rename +// @override +// set walletName(String newName) => _walletName = newName; +// +// late ElectrumX _electrumXClient; +// +// ElectrumX get electrumXClient => _electrumXClient; +// +// late CachedElectrumX _cachedElectrumXClient; +// +// CachedElectrumX get cachedElectrumXClient => _cachedElectrumXClient; +// +// late FlutterSecureStorageInterface _secureStore; +// +// late PriceAPI _priceAPI; +// +// BitcoinCashWallet({ +// required String walletId, +// required String walletName, +// required Coin coin, +// required ElectrumX client, +// required CachedElectrumX cachedClient, +// required TransactionNotificationTracker tracker, +// PriceAPI? priceAPI, +// FlutterSecureStorageInterface? secureStore, +// }) { +// txTracker = tracker; +// _walletId = walletId; +// _walletName = walletName; +// _coin = coin; +// _electrumXClient = client; +// _cachedElectrumXClient = cachedClient; +// +// _priceAPI = priceAPI ?? PriceAPI(Client()); +// _secureStore = +// secureStore ?? const SecureStorageWrapper(FlutterSecureStorage()); +// } +// +// @override +// Future updateNode(bool shouldRefresh) async { +// final failovers = NodeService() +// .failoverNodesFor(coin: coin) +// .map((e) => ElectrumXNode( +// address: e.host, +// port: e.port, +// name: e.name, +// id: e.id, +// useSSL: e.useSSL, +// )) +// .toList(); +// final newNode = await getCurrentNode(); +// _cachedElectrumXClient = CachedElectrumX.from( +// node: newNode, +// prefs: _prefs, +// failovers: failovers, +// ); +// _electrumXClient = ElectrumX.from( +// node: newNode, +// prefs: _prefs, +// failovers: failovers, +// ); +// +// if (shouldRefresh) { +// refresh(); +// } +// } +// +// Future> _getMnemonicList() async { +// final mnemonicString = +// await _secureStore.read(key: '${_walletId}_mnemonic'); +// if (mnemonicString == null) { +// return []; +// } +// final List data = mnemonicString.split(' '); +// return data; +// } +// +// Future getCurrentNode() async { +// final node = NodeService().getPrimaryNodeFor(coin: coin) ?? +// DefaultNodes.getNodeFor(coin); +// +// return ElectrumXNode( +// address: node.host, +// port: node.port, +// name: node.name, +// useSSL: node.useSSL, +// id: node.id, +// ); +// } +// +// Future> _fetchAllOwnAddresses() async { +// final List allAddresses = []; +// +// final receivingAddressesP2PKH = DB.instance.get( +// boxName: walletId, key: 'receivingAddressesP2PKH') as List; +// final changeAddressesP2PKH = +// DB.instance.get(boxName: walletId, key: 'changeAddressesP2PKH') +// as List; +// +// // for (var i = 0; i < receivingAddresses.length; i++) { +// // if (!allAddresses.contains(receivingAddresses[i])) { +// // allAddresses.add(receivingAddresses[i]); +// // } +// // } +// // for (var i = 0; i < changeAddresses.length; i++) { +// // if (!allAddresses.contains(changeAddresses[i])) { +// // allAddresses.add(changeAddresses[i]); +// // } +// // } +// for (var i = 0; i < receivingAddressesP2PKH.length; i++) { +// if (!allAddresses.contains(receivingAddressesP2PKH[i])) { +// allAddresses.add(receivingAddressesP2PKH[i] as String); +// } +// } +// for (var i = 0; i < changeAddressesP2PKH.length; i++) { +// if (!allAddresses.contains(changeAddressesP2PKH[i])) { +// allAddresses.add(changeAddressesP2PKH[i] as String); +// } +// } +// return allAddresses; +// } +// +// Future _getFees() async { +// try { +// //TODO adjust numbers for different speeds? +// const int f = 1, m = 5, s = 20; +// +// final fast = await electrumXClient.estimateFee(blocks: f); +// final medium = await electrumXClient.estimateFee(blocks: m); +// final slow = await electrumXClient.estimateFee(blocks: s); +// +// final feeObject = FeeObject( +// numberOfBlocksFast: f, +// numberOfBlocksAverage: m, +// numberOfBlocksSlow: s, +// fast: Format.decimalAmountToSatoshis(fast), +// medium: Format.decimalAmountToSatoshis(medium), +// slow: Format.decimalAmountToSatoshis(slow), +// ); +// +// Logging.instance.log("fetched fees: $feeObject", level: LogLevel.Info); +// return feeObject; +// } catch (e) { +// Logging.instance +// .log("Exception rethrown from _getFees(): $e", level: LogLevel.Error); +// rethrow; +// } +// } +// +// Future _generateNewWallet() async { +// Logging.instance +// .log("IS_INTEGRATION_TEST: $integrationTestFlag", level: LogLevel.Info); +// if (!integrationTestFlag) { +// final features = await electrumXClient.getServerFeatures(); +// Logging.instance.log("features: $features", level: LogLevel.Info); +// switch (coin) { +// case Coin.bitcoincash: +// if (features['genesis_hash'] != GENESIS_HASH_MAINNET) { +// throw Exception("genesis hash does not match main net!"); +// } +// break; +// case Coin.bitcoincashTestnet: +// if (features['genesis_hash'] != GENESIS_HASH_TESTNET) { +// throw Exception("genesis hash does not match test net!"); +// } +// break; +// default: +// throw Exception( +// "Attempted to generate a BitcoinWallet using a non bitcoin coin type: ${coin.name}"); +// } +// } +// +// // this should never fail +// if ((await _secureStore.read(key: '${_walletId}_mnemonic')) != null) { +// throw Exception( +// "Attempted to overwrite mnemonic on generate new wallet!"); +// } +// await _secureStore.write( +// key: '${_walletId}_mnemonic', +// value: bip39.generateMnemonic(strength: 256)); +// +// // Set relevant indexes +// await DB.instance +// .put(boxName: walletId, key: "receivingIndexP2PKH", value: 0); +// await DB.instance +// .put(boxName: walletId, key: "changeIndexP2PKH", value: 0); +// await DB.instance.put( +// boxName: walletId, +// key: 'blocked_tx_hashes', +// value: ["0xdefault"], +// ); // A list of transaction hashes to represent frozen utxos in wallet +// // initialize address book entries +// await DB.instance.put( +// boxName: walletId, +// key: 'addressBookEntries', +// value: {}); +// +// // Generate and add addresses to relevant arrays +// // final initialReceivingAddress = +// // await _generateAddressForChain(0, 0, DerivePathType.bip44); +// // final initialChangeAddress = +// // await _generateAddressForChain(1, 0, DerivePathType.bip44); +// final initialReceivingAddressP2PKH = +// await _generateAddressForChain(0, 0, DerivePathType.bip44); +// final initialChangeAddressP2PKH = +// await _generateAddressForChain(1, 0, DerivePathType.bip44); +// +// // await _addToAddressesArrayForChain( +// // initialReceivingAddress, 0, DerivePathType.bip44); +// // await _addToAddressesArrayForChain( +// // initialChangeAddress, 1, DerivePathType.bip44); +// await _addToAddressesArrayForChain( +// initialReceivingAddressP2PKH, 0, DerivePathType.bip44); +// await _addToAddressesArrayForChain( +// initialChangeAddressP2PKH, 1, DerivePathType.bip44); +// +// // this._currentReceivingAddress = Future(() => initialReceivingAddress); +// _currentReceivingAddressP2PKH = Future(() => initialReceivingAddressP2PKH); +// +// Logging.instance.log("_generateNewWalletFinished", level: LogLevel.Info); +// } +// +// /// Generates a new internal or external chain address for the wallet using a BIP44 derivation path. +// /// [chain] - Use 0 for receiving (external), 1 for change (internal). Should not be any other value! +// /// [index] - This can be any integer >= 0 +// Future _generateAddressForChain( +// int chain, +// int index, +// DerivePathType derivePathType, +// ) async { +// final mnemonic = await _secureStore.read(key: '${_walletId}_mnemonic'); +// final node = await compute( +// getBip32NodeWrapper, +// Tuple5( +// chain, +// index, +// mnemonic!, +// _network, +// derivePathType, +// ), +// ); +// final data = PaymentData(pubkey: node.publicKey); +// String address; +// +// switch (derivePathType) { +// case DerivePathType.bip44: +// address = P2PKH(data: data, network: _network).data.address!; +// break; +// // default: +// // // should never hit this due to all enum cases handled +// // return null; +// } +// +// // add generated address & info to derivations +// await addDerivation( +// chain: chain, +// address: address, +// pubKey: Format.uint8listToString(node.publicKey), +// wif: node.toWIF(), +// derivePathType: derivePathType, +// ); +// +// return address; +// } +// +// /// Increases the index for either the internal or external chain, depending on [chain]. +// /// [chain] - Use 0 for receiving (external), 1 for change (internal). Should not be any other value! +// Future _incrementAddressIndexForChain( +// int chain, DerivePathType derivePathType) async { +// // Here we assume chain == 1 if it isn't 0 +// String indexKey = chain == 0 ? "receivingIndex" : "changeIndex"; +// switch (derivePathType) { +// case DerivePathType.bip44: +// indexKey += "P2PKH"; +// break; +// } +// +// final newIndex = +// (DB.instance.get(boxName: walletId, key: indexKey)) + 1; +// await DB.instance +// .put(boxName: walletId, key: indexKey, value: newIndex); +// } +// +// /// Adds [address] to the relevant chain's address array, which is determined by [chain]. +// /// [address] - Expects a standard native segwit address +// /// [chain] - Use 0 for receiving (external), 1 for change (internal). Should not be any other value! +// Future _addToAddressesArrayForChain( +// String address, int chain, DerivePathType derivePathType) async { +// String chainArray = ''; +// if (chain == 0) { +// chainArray = 'receivingAddresses'; +// } else { +// chainArray = 'changeAddresses'; +// } +// switch (derivePathType) { +// case DerivePathType.bip44: +// chainArray += "P2PKH"; +// break; +// } +// +// final addressArray = +// DB.instance.get(boxName: walletId, key: chainArray); +// if (addressArray == null) { +// Logging.instance.log( +// 'Attempting to add the following to $chainArray array for chain $chain:${[ +// address +// ]}', +// level: LogLevel.Info); +// await DB.instance +// .put(boxName: walletId, key: chainArray, value: [address]); +// } else { +// // Make a deep copy of the existing list +// final List newArray = []; +// addressArray +// .forEach((dynamic _address) => newArray.add(_address as String)); +// newArray.add(address); // Add the address passed into the method +// await DB.instance +// .put(boxName: walletId, key: chainArray, value: newArray); +// } +// } +// +// /// Returns the latest receiving/change (external/internal) address for the wallet depending on [chain] +// /// and +// /// [chain] - Use 0 for receiving (external), 1 for change (internal). Should not be any other value! +// Future _getCurrentAddressForChain( +// int chain, DerivePathType derivePathType) async { +// // Here, we assume that chain == 1 if it isn't 0 +// String arrayKey = chain == 0 ? "receivingAddresses" : "changeAddresses"; +// switch (derivePathType) { +// case DerivePathType.bip44: +// arrayKey += "P2PKH"; +// break; +// } +// final internalChainArray = +// DB.instance.get(boxName: walletId, key: arrayKey); +// return internalChainArray.last as String; +// } +// +// String _buildDerivationStorageKey( +// {required int chain, required DerivePathType derivePathType}) { +// String key; +// String chainId = chain == 0 ? "receive" : "change"; +// switch (derivePathType) { +// case DerivePathType.bip44: +// key = "${walletId}_${chainId}DerivationsP2PKH"; +// break; +// } +// return key; +// } +// +// Future> _fetchDerivations( +// {required int chain, required DerivePathType derivePathType}) async { +// // build lookup key +// final key = _buildDerivationStorageKey( +// chain: chain, derivePathType: derivePathType); +// +// // fetch current derivations +// final derivationsString = await _secureStore.read(key: key); +// return Map.from( +// jsonDecode(derivationsString ?? "{}") as Map); +// } +// +// /// Add a single derivation to the local secure storage for [chain] and +// /// [derivePathType] where [chain] must either be 1 for change or 0 for receive. +// /// This will overwrite a previous entry where the address of the new derivation +// /// matches a derivation currently stored. +// Future addDerivation({ +// required int chain, +// required String address, +// required String pubKey, +// required String wif, +// required DerivePathType derivePathType, +// }) async { +// // build lookup key +// final key = _buildDerivationStorageKey( +// chain: chain, derivePathType: derivePathType); +// +// // fetch current derivations +// final derivationsString = await _secureStore.read(key: key); +// final derivations = +// Map.from(jsonDecode(derivationsString ?? "{}") as Map); +// +// // add derivation +// derivations[address] = { +// "pubKey": pubKey, +// "wif": wif, +// }; +// +// // save derivations +// final newReceiveDerivationsString = jsonEncode(derivations); +// await _secureStore.write(key: key, value: newReceiveDerivationsString); +// } +// +// /// Add multiple derivations to the local secure storage for [chain] and +// /// [derivePathType] where [chain] must either be 1 for change or 0 for receive. +// /// This will overwrite any previous entries where the address of the new derivation +// /// matches a derivation currently stored. +// /// The [derivationsToAdd] must be in the format of: +// /// { +// /// addressA : { +// /// "pubKey": , +// /// "wif": , +// /// }, +// /// addressB : { +// /// "pubKey": , +// /// "wif": , +// /// }, +// /// } +// Future addDerivations({ +// required int chain, +// required DerivePathType derivePathType, +// required Map derivationsToAdd, +// }) async { +// // build lookup key +// final key = _buildDerivationStorageKey( +// chain: chain, derivePathType: derivePathType); +// +// // fetch current derivations +// final derivationsString = await _secureStore.read(key: key); +// final derivations = +// Map.from(jsonDecode(derivationsString ?? "{}") as Map); +// +// // add derivation +// derivations.addAll(derivationsToAdd); +// +// // save derivations +// final newReceiveDerivationsString = jsonEncode(derivations); +// await _secureStore.write(key: key, value: newReceiveDerivationsString); +// } +// +// Future _fetchUtxoData() async { +// final List allAddresses = await _fetchAllOwnAddresses(); +// +// try { +// final fetchedUtxoList = >>[]; +// +// final Map>> batches = {}; +// const batchSizeMax = 10; +// int batchNumber = 0; +// for (int i = 0; i < allAddresses.length; i++) { +// if (batches[batchNumber] == null) { +// batches[batchNumber] = {}; +// } +// final scripthash = _convertToScriptHash(allAddresses[i], _network); +// print("SCRIPT_HASH_FOR_ADDRESS ${allAddresses[i]} IS $scripthash"); +// batches[batchNumber]!.addAll({ +// scripthash: [scripthash] +// }); +// if (i % batchSizeMax == batchSizeMax - 1) { +// batchNumber++; +// } +// } +// +// for (int i = 0; i < batches.length; i++) { +// final response = +// await _electrumXClient.getBatchUTXOs(args: batches[i]!); +// for (final entry in response.entries) { +// if (entry.value.isNotEmpty) { +// fetchedUtxoList.add(entry.value); +// } +// } +// } +// +// final priceData = +// await _priceAPI.getPricesAnd24hChange(baseCurrency: _prefs.currency); +// Decimal currentPrice = priceData[coin]?.item1 ?? Decimal.zero; +// final List> outputArray = []; +// int satoshiBalance = 0; +// int satoshiBalancePending = 0; +// +// for (int i = 0; i < fetchedUtxoList.length; i++) { +// for (int j = 0; j < fetchedUtxoList[i].length; j++) { +// int value = fetchedUtxoList[i][j]["value"] as int; +// satoshiBalance += value; +// +// final txn = await cachedElectrumXClient.getTransaction( +// txHash: fetchedUtxoList[i][j]["tx_hash"] as String, +// verbose: true, +// coin: coin, +// ); +// +// final Map utxo = {}; +// final int confirmations = txn["confirmations"] as int? ?? 0; +// final bool confirmed = txn["confirmations"] == null +// ? false +// : txn["confirmations"] as int >= MINIMUM_CONFIRMATIONS; +// if (!confirmed) { +// satoshiBalancePending += value; +// } +// +// utxo["txid"] = txn["txid"]; +// utxo["vout"] = fetchedUtxoList[i][j]["tx_pos"]; +// utxo["value"] = value; +// +// utxo["status"] = {}; +// utxo["status"]["confirmed"] = confirmed; +// utxo["status"]["confirmations"] = confirmations; +// utxo["status"]["block_height"] = fetchedUtxoList[i][j]["height"]; +// utxo["status"]["block_hash"] = txn["blockhash"]; +// utxo["status"]["block_time"] = txn["blocktime"]; +// +// final fiatValue = ((Decimal.fromInt(value) * currentPrice) / +// Decimal.fromInt(Constants.satsPerCoin)) +// .toDecimal(scaleOnInfinitePrecision: 2); +// utxo["rawWorth"] = fiatValue; +// utxo["fiatWorth"] = fiatValue.toString(); +// outputArray.add(utxo); +// } +// } +// +// Decimal currencyBalanceRaw = +// ((Decimal.fromInt(satoshiBalance) * currentPrice) / +// Decimal.fromInt(Constants.satsPerCoin)) +// .toDecimal(scaleOnInfinitePrecision: 2); +// +// final Map result = { +// "total_user_currency": currencyBalanceRaw.toString(), +// "total_sats": satoshiBalance, +// "total_btc": (Decimal.fromInt(satoshiBalance) / +// Decimal.fromInt(Constants.satsPerCoin)) +// .toDecimal(scaleOnInfinitePrecision: Constants.decimalPlaces) +// .toString(), +// "outputArray": outputArray, +// "unconfirmed": satoshiBalancePending, +// }; +// +// final dataModel = UtxoData.fromJson(result); +// +// final List allOutputs = dataModel.unspentOutputArray; +// Logging.instance +// .log('Outputs fetched: $allOutputs', level: LogLevel.Info); +// await _sortOutputs(allOutputs); +// await DB.instance.put( +// boxName: walletId, key: 'latest_utxo_model', value: dataModel); +// await DB.instance.put( +// boxName: walletId, +// key: 'totalBalance', +// value: dataModel.satoshiBalance); +// return dataModel; +// } catch (e, s) { +// Logging.instance +// .log("Output fetch unsuccessful: $e\n$s", level: LogLevel.Error); +// final latestTxModel = +// DB.instance.get(boxName: walletId, key: 'latest_utxo_model'); +// +// if (latestTxModel == null) { +// final emptyModel = { +// "total_user_currency": "0.00", +// "total_sats": 0, +// "total_btc": "0", +// "outputArray": [] +// }; +// return UtxoData.fromJson(emptyModel); +// } else { +// Logging.instance +// .log("Old output model located", level: LogLevel.Warning); +// return latestTxModel as models.UtxoData; +// } +// } +// } +// +// /// Takes in a list of UtxoObjects and adds a name (dependent on object index within list) +// /// and checks for the txid associated with the utxo being blocked and marks it accordingly. +// /// Now also checks for output labeling. +// Future _sortOutputs(List utxos) async { +// final blockedHashArray = +// DB.instance.get(boxName: walletId, key: 'blocked_tx_hashes') +// as List?; +// final List lst = []; +// if (blockedHashArray != null) { +// for (var hash in blockedHashArray) { +// lst.add(hash as String); +// } +// } +// final labels = +// DB.instance.get(boxName: walletId, key: 'labels') as Map? ?? +// {}; +// +// outputsList = []; +// +// for (var i = 0; i < utxos.length; i++) { +// if (labels[utxos[i].txid] != null) { +// utxos[i].txName = labels[utxos[i].txid] as String? ?? ""; +// } else { +// utxos[i].txName = 'Output #$i'; +// } +// +// if (utxos[i].status.confirmed == false) { +// outputsList.add(utxos[i]); +// } else { +// if (lst.contains(utxos[i].txid)) { +// utxos[i].blocked = true; +// outputsList.add(utxos[i]); +// } else if (!lst.contains(utxos[i].txid)) { +// outputsList.add(utxos[i]); +// } +// } +// } +// } +// +// Future getTxCount({required String address}) async { +// String? scripthash; +// try { +// scripthash = _convertToScriptHash(address, _network); +// final transactions = +// await electrumXClient.getHistory(scripthash: scripthash); +// return transactions.length; +// } catch (e) { +// Logging.instance.log( +// "Exception rethrown in _getTxCount(address: $address, scripthash: $scripthash): $e", +// level: LogLevel.Error); +// rethrow; +// } +// } +// +// Future> _getBatchTxCount({ +// required Map addresses, +// }) async { +// try { +// final Map> args = {}; +// print("Address $addresses"); +// for (final entry in addresses.entries) { +// args[entry.key] = [_convertToScriptHash(entry.value, _network)]; +// } +// +// print("Args ${jsonEncode(args)}"); +// +// final response = await electrumXClient.getBatchHistory(args: args); +// print("Response ${jsonEncode(response)}"); +// final Map result = {}; +// for (final entry in response.entries) { +// result[entry.key] = entry.value.length; +// } +// print("result ${jsonEncode(result)}"); +// return result; +// } catch (e, s) { +// Logging.instance.log( +// "Exception rethrown in _getBatchTxCount(address: $addresses: $e\n$s", +// level: LogLevel.Error); +// rethrow; +// } +// } +// +// Future _checkReceivingAddressForTransactions( +// DerivePathType derivePathType) async { +// try { +// final String currentExternalAddr = +// await _getCurrentAddressForChain(0, derivePathType); +// final int txCount = await getTxCount(address: currentExternalAddr); +// Logging.instance.log( +// 'Number of txs for current receiving address $currentExternalAddr: $txCount', +// level: LogLevel.Info); +// +// if (txCount >= 1) { +// // First increment the receiving index +// await _incrementAddressIndexForChain(0, derivePathType); +// +// // Check the new receiving index +// String indexKey = "receivingIndex"; +// switch (derivePathType) { +// case DerivePathType.bip44: +// indexKey += "P2PKH"; +// break; +// } +// final newReceivingIndex = +// DB.instance.get(boxName: walletId, key: indexKey) as int; +// +// // Use new index to derive a new receiving address +// final newReceivingAddress = await _generateAddressForChain( +// 0, newReceivingIndex, derivePathType); +// +// // Add that new receiving address to the array of receiving addresses +// await _addToAddressesArrayForChain( +// newReceivingAddress, 0, derivePathType); +// +// // Set the new receiving address that the service +// +// switch (derivePathType) { +// case DerivePathType.bip44: +// _currentReceivingAddressP2PKH = Future(() => newReceivingAddress); +// break; +// } +// } +// } on SocketException catch (se, s) { +// Logging.instance.log( +// "SocketException caught in _checkReceivingAddressForTransactions($derivePathType): $se\n$s", +// level: LogLevel.Error); +// return; +// } catch (e, s) { +// Logging.instance.log( +// "Exception rethrown from _checkReceivingAddressForTransactions($derivePathType): $e\n$s", +// level: LogLevel.Error); +// rethrow; +// } +// } +// +// Future _checkChangeAddressForTransactions( +// DerivePathType derivePathType) async { +// try { +// final String currentExternalAddr = +// await _getCurrentAddressForChain(1, derivePathType); +// final int txCount = await getTxCount(address: currentExternalAddr); +// Logging.instance.log( +// 'Number of txs for current change address $currentExternalAddr: $txCount', +// level: LogLevel.Info); +// +// if (txCount >= 1) { +// // First increment the change index +// await _incrementAddressIndexForChain(1, derivePathType); +// +// // Check the new change index +// String indexKey = "changeIndex"; +// switch (derivePathType) { +// case DerivePathType.bip44: +// indexKey += "P2PKH"; +// break; +// } +// final newChangeIndex = +// DB.instance.get(boxName: walletId, key: indexKey) as int; +// +// // Use new index to derive a new change address +// final newChangeAddress = +// await _generateAddressForChain(1, newChangeIndex, derivePathType); +// +// // Add that new receiving address to the array of change addresses +// await _addToAddressesArrayForChain(newChangeAddress, 1, derivePathType); +// } +// } catch (e, s) { +// Logging.instance.log( +// "Exception rethrown from _checkChangeAddressForTransactions($derivePathType): $e\n$s", +// level: LogLevel.Error); +// rethrow; +// } +// } +// +// Future _checkCurrentReceivingAddressesForTransactions() async { +// try { +// for (final type in DerivePathType.values) { +// await _checkReceivingAddressForTransactions(type); +// } +// } catch (e, s) { +// Logging.instance.log( +// "Exception rethrown from _checkCurrentReceivingAddressesForTransactions(): $e\n$s", +// level: LogLevel.Info); +// rethrow; +// } +// } +// +// /// public wrapper because dart can't test private... +// Future checkCurrentReceivingAddressesForTransactions() async { +// if (Platform.environment["FLUTTER_TEST"] == "true") { +// try { +// return _checkCurrentReceivingAddressesForTransactions(); +// } catch (_) { +// rethrow; +// } +// } +// } +// +// Future _checkCurrentChangeAddressesForTransactions() async { +// try { +// for (final type in DerivePathType.values) { +// await _checkChangeAddressForTransactions(type); +// } +// } catch (e, s) { +// Logging.instance.log( +// "Exception rethrown from _checkCurrentChangeAddressesForTransactions(): $e\n$s", +// level: LogLevel.Error); +// rethrow; +// } +// } +// +// /// public wrapper because dart can't test private... +// Future checkCurrentChangeAddressesForTransactions() async { +// if (Platform.environment["FLUTTER_TEST"] == "true") { +// try { +// return _checkCurrentChangeAddressesForTransactions(); +// } catch (_) { +// rethrow; +// } +// } +// } +// +// /// attempts to convert a string to a valid scripthash +// /// +// /// Returns the scripthash or throws an exception on invalid bch address +// String _convertToScriptHash(String bchAddress, NetworkType network) { +// try { +// final output = Address.addressToOutputScript(bchAddress, network); +// final hash = sha256.convert(output.toList(growable: false)).toString(); +// +// final chars = hash.split(""); +// final reversedPairs = []; +// var i = chars.length - 1; +// while (i > 0) { +// reversedPairs.add(chars[i - 1]); +// reversedPairs.add(chars[i]); +// i -= 2; +// } +// return reversedPairs.join(""); +// } catch (e) { +// rethrow; +// } +// } +// +// Future>> _fetchHistory( +// List allAddresses) async { +// try { +// List> allTxHashes = []; +// +// final Map>> batches = {}; +// final Map requestIdToAddressMap = {}; +// const batchSizeMax = 10; +// int batchNumber = 0; +// for (int i = 0; i < allAddresses.length; i++) { +// if (batches[batchNumber] == null) { +// batches[batchNumber] = {}; +// } +// final scripthash = _convertToScriptHash(allAddresses[i], _network); +// final id = Logger.isTestEnv ? "$i" : const Uuid().v1(); +// requestIdToAddressMap[id] = allAddresses[i]; +// batches[batchNumber]!.addAll({ +// id: [scripthash] +// }); +// if (i % batchSizeMax == batchSizeMax - 1) { +// batchNumber++; +// } +// } +// +// for (int i = 0; i < batches.length; i++) { +// final response = +// await _electrumXClient.getBatchHistory(args: batches[i]!); +// for (final entry in response.entries) { +// for (int j = 0; j < entry.value.length; j++) { +// entry.value[j]["address"] = requestIdToAddressMap[entry.key]; +// if (!allTxHashes.contains(entry.value[j])) { +// allTxHashes.add(entry.value[j]); +// } +// } +// } +// } +// +// return allTxHashes; +// } catch (e, s) { +// Logging.instance.log("_fetchHistory: $e\n$s", level: LogLevel.Error); +// rethrow; +// } +// } +// +// bool _duplicateTxCheck( +// List> allTransactions, String txid) { +// for (int i = 0; i < allTransactions.length; i++) { +// if (allTransactions[i]["txid"] == txid) { +// return true; +// } +// } +// return false; +// } +// +// Future _fetchTransactionData() async { +// final List allAddresses = await _fetchAllOwnAddresses(); +// +// final changeAddressesP2PKH = +// DB.instance.get(boxName: walletId, key: 'changeAddressesP2PKH') +// as List; +// +// final List> allTxHashes = +// await _fetchHistory(allAddresses); +// +// final cachedTransactions = +// DB.instance.get(boxName: walletId, key: 'latest_tx_model') +// as TransactionData?; +// int latestTxnBlockHeight = +// DB.instance.get(boxName: walletId, key: "storedTxnDataHeight") +// as int? ?? +// 0; +// +// final unconfirmedCachedTransactions = +// cachedTransactions?.getAllTransactions() ?? {}; +// unconfirmedCachedTransactions +// .removeWhere((key, value) => value.confirmedStatus); +// +// print("CACHED_TRANSACTIONS_IS $cachedTransactions"); +// if (cachedTransactions != null) { +// for (final tx in allTxHashes.toList(growable: false)) { +// final txHeight = tx["height"] as int; +// if (txHeight > 0 && +// txHeight < latestTxnBlockHeight - MINIMUM_CONFIRMATIONS) { +// if (unconfirmedCachedTransactions[tx["tx_hash"] as String] == null) { +// allTxHashes.remove(tx); +// } +// } +// } +// } +// +// List> allTransactions = []; +// +// for (final txHash in allTxHashes) { +// Logging.instance.log("bch: $txHash", level: LogLevel.Info); +// final tx = await cachedElectrumXClient.getTransaction( +// txHash: txHash["tx_hash"] as String, +// verbose: true, +// coin: coin, +// ); +// +// // Logging.instance.log("TRANSACTION: ${jsonEncode(tx)}"); +// // TODO fix this for sent to self transactions? +// if (!_duplicateTxCheck(allTransactions, tx["txid"] as String)) { +// tx["address"] = txHash["address"]; +// tx["height"] = txHash["height"]; +// allTransactions.add(tx); +// } +// } +// +// Logging.instance.log("addAddresses: $allAddresses", level: LogLevel.Info); +// Logging.instance.log("allTxHashes: $allTxHashes", level: LogLevel.Info); +// +// Logging.instance.log("allTransactions length: ${allTransactions.length}", +// level: LogLevel.Info); +// +// final priceData = +// await _priceAPI.getPricesAnd24hChange(baseCurrency: _prefs.currency); +// Decimal currentPrice = priceData[coin]?.item1 ?? Decimal.zero; +// final List> midSortedArray = []; +// +// for (final txObject in allTransactions) { +// List sendersArray = []; +// List recipientsArray = []; +// +// // Usually only has value when txType = 'Send' +// int inputAmtSentFromWallet = 0; +// // Usually has value regardless of txType due to change addresses +// int outputAmtAddressedToWallet = 0; +// int fee = 0; +// +// Map midSortedTx = {}; +// +// for (int i = 0; i < (txObject["vin"] as List).length; i++) { +// final input = txObject["vin"][i] as Map; +// final prevTxid = input["txid"] as String; +// final prevOut = input["vout"] as int; +// +// final tx = await _cachedElectrumXClient.getTransaction( +// txHash: prevTxid, coin: coin); +// +// for (final out in tx["vout"] as List) { +// if (prevOut == out["n"]) { +// final address = out["scriptPubKey"]["addresses"][0] as String?; +// if (address != null) { +// sendersArray.add(address); +// } +// } +// } +// } +// +// Logging.instance.log("sendersArray: $sendersArray", level: LogLevel.Info); +// +// for (final output in txObject["vout"] as List) { +// final address = output["scriptPubKey"]["addresses"][0] as String?; +// if (address != null) { +// recipientsArray.add(address); +// } +// } +// +// Logging.instance +// .log("recipientsArray: $recipientsArray", level: LogLevel.Info); +// +// final foundInSenders = +// allAddresses.any((element) => sendersArray.contains(element)); +// Logging.instance +// .log("foundInSenders: $foundInSenders", level: LogLevel.Info); +// +// // If txType = Sent, then calculate inputAmtSentFromWallet +// if (foundInSenders) { +// int totalInput = 0; +// for (int i = 0; i < (txObject["vin"] as List).length; i++) { +// final input = txObject["vin"][i] as Map; +// final prevTxid = input["txid"] as String; +// final prevOut = input["vout"] as int; +// final tx = await _cachedElectrumXClient.getTransaction( +// txHash: prevTxid, +// coin: coin, +// ); +// +// for (final out in tx["vout"] as List) { +// if (prevOut == out["n"]) { +// inputAmtSentFromWallet += +// (Decimal.parse(out["value"].toString()) * +// Decimal.fromInt(Constants.satsPerCoin)) +// .toBigInt() +// .toInt(); +// } +// } +// } +// totalInput = inputAmtSentFromWallet; +// int totalOutput = 0; +// +// for (final output in txObject["vout"] as List) { +// final address = output["scriptPubKey"]["addresses"][0]; +// final value = output["value"]; +// final _value = (Decimal.parse(value.toString()) * +// Decimal.fromInt(Constants.satsPerCoin)) +// .toBigInt() +// .toInt(); +// totalOutput += _value; +// if (changeAddressesP2PKH.contains(address)) { +// inputAmtSentFromWallet -= _value; +// } else { +// // change address from 'sent from' to the 'sent to' address +// txObject["address"] = address; +// } +// } +// // calculate transaction fee +// fee = totalInput - totalOutput; +// // subtract fee from sent to calculate correct value of sent tx +// inputAmtSentFromWallet -= fee; +// } else { +// // counters for fee calculation +// int totalOut = 0; +// int totalIn = 0; +// +// // add up received tx value +// for (final output in txObject["vout"] as List) { +// final address = output["scriptPubKey"]["addresses"][0]; +// if (address != null) { +// final value = (Decimal.parse(output["value"].toString()) * +// Decimal.fromInt(Constants.satsPerCoin)) +// .toBigInt() +// .toInt(); +// totalOut += value; +// if (allAddresses.contains(address)) { +// outputAmtAddressedToWallet += value; +// } +// } +// } +// +// // calculate fee for received tx +// for (int i = 0; i < (txObject["vin"] as List).length; i++) { +// final input = txObject["vin"][i] as Map; +// final prevTxid = input["txid"] as String; +// final prevOut = input["vout"] as int; +// final tx = await _cachedElectrumXClient.getTransaction( +// txHash: prevTxid, +// coin: coin, +// ); +// +// for (final out in tx["vout"] as List) { +// if (prevOut == out["n"]) { +// totalIn += (Decimal.parse(out["value"].toString()) * +// Decimal.fromInt(Constants.satsPerCoin)) +// .toBigInt() +// .toInt(); +// } +// } +// } +// fee = totalIn - totalOut; +// } +// +// // create final tx map +// midSortedTx["txid"] = txObject["txid"]; +// midSortedTx["confirmed_status"] = (txObject["confirmations"] != null) && +// (txObject["confirmations"] as int >= MINIMUM_CONFIRMATIONS); +// midSortedTx["confirmations"] = txObject["confirmations"] ?? 0; +// midSortedTx["timestamp"] = txObject["blocktime"] ?? +// (DateTime.now().millisecondsSinceEpoch ~/ 1000); +// +// if (foundInSenders) { +// midSortedTx["txType"] = "Sent"; +// midSortedTx["amount"] = inputAmtSentFromWallet; +// final String worthNow = +// ((currentPrice * Decimal.fromInt(inputAmtSentFromWallet)) / +// Decimal.fromInt(Constants.satsPerCoin)) +// .toDecimal(scaleOnInfinitePrecision: 2) +// .toStringAsFixed(2); +// midSortedTx["worthNow"] = worthNow; +// midSortedTx["worthAtBlockTimestamp"] = worthNow; +// } else { +// midSortedTx["txType"] = "Received"; +// midSortedTx["amount"] = outputAmtAddressedToWallet; +// final worthNow = +// ((currentPrice * Decimal.fromInt(outputAmtAddressedToWallet)) / +// Decimal.fromInt(Constants.satsPerCoin)) +// .toDecimal(scaleOnInfinitePrecision: 2) +// .toStringAsFixed(2); +// midSortedTx["worthNow"] = worthNow; +// } +// midSortedTx["aliens"] = []; +// midSortedTx["fees"] = fee; +// midSortedTx["address"] = txObject["address"]; +// midSortedTx["inputSize"] = txObject["vin"].length; +// midSortedTx["outputSize"] = txObject["vout"].length; +// midSortedTx["inputs"] = txObject["vin"]; +// midSortedTx["outputs"] = txObject["vout"]; +// +// final int height = txObject["height"] as int; +// midSortedTx["height"] = height; +// +// if (height >= latestTxnBlockHeight) { +// latestTxnBlockHeight = height; +// } +// +// midSortedArray.add(midSortedTx); +// } +// +// // sort by date ---- //TODO not sure if needed +// // shouldn't be any issues with a null timestamp but I got one at some point? +// midSortedArray +// .sort((a, b) => (b["timestamp"] as int) - (a["timestamp"] as int)); +// // { +// // final aT = a["timestamp"]; +// // final bT = b["timestamp"]; +// // +// // if (aT == null && bT == null) { +// // return 0; +// // } else if (aT == null) { +// // return -1; +// // } else if (bT == null) { +// // return 1; +// // } else { +// // return bT - aT; +// // } +// // }); +// +// // buildDateTimeChunks +// final Map result = {"dateTimeChunks": []}; +// final dateArray = []; +// +// for (int i = 0; i < midSortedArray.length; i++) { +// final txObject = midSortedArray[i]; +// final date = extractDateFromTimestamp(txObject["timestamp"] as int); +// final txTimeArray = [txObject["timestamp"], date]; +// +// if (dateArray.contains(txTimeArray[1])) { +// result["dateTimeChunks"].forEach((dynamic chunk) { +// if (extractDateFromTimestamp(chunk["timestamp"] as int) == +// txTimeArray[1]) { +// if (chunk["transactions"] == null) { +// chunk["transactions"] = >[]; +// } +// chunk["transactions"].add(txObject); +// } +// }); +// } else { +// dateArray.add(txTimeArray[1]); +// final chunk = { +// "timestamp": txTimeArray[0], +// "transactions": [txObject], +// }; +// result["dateTimeChunks"].add(chunk); +// } +// } +// +// final transactionsMap = cachedTransactions?.getAllTransactions() ?? {}; +// transactionsMap +// .addAll(TransactionData.fromJson(result).getAllTransactions()); +// +// final txModel = TransactionData.fromMap(transactionsMap); +// +// await DB.instance.put( +// boxName: walletId, +// key: 'storedTxnDataHeight', +// value: latestTxnBlockHeight); +// await DB.instance.put( +// boxName: walletId, key: 'latest_tx_model', value: txModel); +// +// return txModel; +// } +// +// int estimateTxFee({required int vSize, required int feeRatePerKB}) { +// return vSize * (feeRatePerKB / 1000).ceil(); +// } +// +// /// The coinselection algorithm decides whether or not the user is eligible to make the transaction +// /// with [satoshiAmountToSend] and [selectedTxFeeRate]. If so, it will call buildTrasaction() and return +// /// a map containing the tx hex along with other important information. If not, then it will return +// /// an integer (1 or 2) +// dynamic coinSelection(int satoshiAmountToSend, int selectedTxFeeRate, +// String _recipientAddress, bool isSendAll, +// {int additionalOutputs = 0, List? utxos}) async { +// Logging.instance +// .log("Starting coinSelection ----------", level: LogLevel.Info); +// final List availableOutputs = utxos ?? outputsList; +// final List spendableOutputs = []; +// int spendableSatoshiValue = 0; +// +// // Build list of spendable outputs and totaling their satoshi amount +// for (var i = 0; i < availableOutputs.length; i++) { +// if (availableOutputs[i].blocked == false && +// availableOutputs[i].status.confirmed == true) { +// spendableOutputs.add(availableOutputs[i]); +// spendableSatoshiValue += availableOutputs[i].value; +// } +// } +// +// // sort spendable by age (oldest first) +// spendableOutputs.sort( +// (a, b) => b.status.confirmations.compareTo(a.status.confirmations)); +// +// Logging.instance.log("spendableOutputs.length: ${spendableOutputs.length}", +// level: LogLevel.Info); +// Logging.instance +// .log("spendableOutputs: $spendableOutputs", level: LogLevel.Info); +// Logging.instance.log("spendableSatoshiValue: $spendableSatoshiValue", +// level: LogLevel.Info); +// Logging.instance +// .log("satoshiAmountToSend: $satoshiAmountToSend", level: LogLevel.Info); +// // If the amount the user is trying to send is smaller than the amount that they have spendable, +// // then return 1, which indicates that they have an insufficient balance. +// if (spendableSatoshiValue < satoshiAmountToSend) { +// return 1; +// // If the amount the user wants to send is exactly equal to the amount they can spend, then return +// // 2, which indicates that they are not leaving enough over to pay the transaction fee +// } else if (spendableSatoshiValue == satoshiAmountToSend && !isSendAll) { +// return 2; +// } +// // If neither of these statements pass, we assume that the user has a spendable balance greater +// // than the amount they're attempting to send. Note that this value still does not account for +// // the added transaction fee, which may require an extra input and will need to be checked for +// // later on. +// +// // Possible situation right here +// int satoshisBeingUsed = 0; +// int inputsBeingConsumed = 0; +// List utxoObjectsToUse = []; +// +// for (var i = 0; +// satoshisBeingUsed < satoshiAmountToSend && i < spendableOutputs.length; +// i++) { +// utxoObjectsToUse.add(spendableOutputs[i]); +// satoshisBeingUsed += spendableOutputs[i].value; +// inputsBeingConsumed += 1; +// } +// for (int i = 0; +// i < additionalOutputs && inputsBeingConsumed < spendableOutputs.length; +// i++) { +// utxoObjectsToUse.add(spendableOutputs[inputsBeingConsumed]); +// satoshisBeingUsed += spendableOutputs[inputsBeingConsumed].value; +// inputsBeingConsumed += 1; +// } +// +// Logging.instance +// .log("satoshisBeingUsed: $satoshisBeingUsed", level: LogLevel.Info); +// Logging.instance +// .log("inputsBeingConsumed: $inputsBeingConsumed", level: LogLevel.Info); +// Logging.instance +// .log('utxoObjectsToUse: $utxoObjectsToUse', level: LogLevel.Info); +// Logging.instance +// .log('satoshiAmountToSend $satoshiAmountToSend', level: LogLevel.Info); +// +// // numberOfOutputs' length must always be equal to that of recipientsArray and recipientsAmtArray +// List recipientsArray = [_recipientAddress]; +// List recipientsAmtArray = [satoshiAmountToSend]; +// +// // gather required signing data +// final utxoSigningData = await fetchBuildTxData(utxoObjectsToUse); +// +// if (isSendAll) { +// Logging.instance +// .log("Attempting to send all $coin", level: LogLevel.Info); +// +// final int vSizeForOneOutput = (await buildTransaction( +// utxosToUse: utxoObjectsToUse, +// utxoSigningData: utxoSigningData, +// recipients: [_recipientAddress], +// satoshiAmounts: [satoshisBeingUsed - 1], +// ))["vSize"] as int; +// int feeForOneOutput = estimateTxFee( +// vSize: vSizeForOneOutput, +// feeRatePerKB: selectedTxFeeRate, +// ); +// if (feeForOneOutput < (vSizeForOneOutput + 1)) { +// feeForOneOutput = (vSizeForOneOutput + 1); +// } +// +// final int amount = satoshiAmountToSend - feeForOneOutput; +// dynamic txn = await buildTransaction( +// utxosToUse: utxoObjectsToUse, +// utxoSigningData: utxoSigningData, +// recipients: recipientsArray, +// satoshiAmounts: [amount], +// ); +// Map transactionObject = { +// "hex": txn["hex"], +// "recipient": recipientsArray[0], +// "recipientAmt": amount, +// "fee": feeForOneOutput, +// "vSize": txn["vSize"], +// }; +// return transactionObject; +// } +// +// final int vSizeForOneOutput = (await buildTransaction( +// utxosToUse: utxoObjectsToUse, +// utxoSigningData: utxoSigningData, +// recipients: [_recipientAddress], +// satoshiAmounts: [satoshisBeingUsed - 1], +// ))["vSize"] as int; +// final int vSizeForTwoOutPuts = (await buildTransaction( +// utxosToUse: utxoObjectsToUse, +// utxoSigningData: utxoSigningData, +// recipients: [ +// _recipientAddress, +// await _getCurrentAddressForChain(1, DerivePathType.bip44), +// ], +// satoshiAmounts: [ +// satoshiAmountToSend, +// satoshisBeingUsed - satoshiAmountToSend - 1, +// ], // dust limit is the minimum amount a change output should be +// ))["vSize"] as int; +// debugPrint("vSizeForOneOutput $vSizeForOneOutput"); +// debugPrint("vSizeForTwoOutPuts $vSizeForTwoOutPuts"); +// +// // Assume 1 output, only for recipient and no change +// var feeForOneOutput = estimateTxFee( +// vSize: vSizeForOneOutput, +// feeRatePerKB: selectedTxFeeRate, +// ); +// // Assume 2 outputs, one for recipient and one for change +// var feeForTwoOutputs = estimateTxFee( +// vSize: vSizeForTwoOutPuts, +// feeRatePerKB: selectedTxFeeRate, +// ); +// +// Logging.instance +// .log("feeForTwoOutputs: $feeForTwoOutputs", level: LogLevel.Info); +// Logging.instance +// .log("feeForOneOutput: $feeForOneOutput", level: LogLevel.Info); +// if (feeForOneOutput < (vSizeForOneOutput + 1)) { +// feeForOneOutput = (vSizeForOneOutput + 1); +// } +// if (feeForTwoOutputs < ((vSizeForTwoOutPuts + 1))) { +// feeForTwoOutputs = ((vSizeForTwoOutPuts + 1)); +// } +// +// Logging.instance +// .log("feeForTwoOutputs: $feeForTwoOutputs", level: LogLevel.Info); +// Logging.instance +// .log("feeForOneOutput: $feeForOneOutput", level: LogLevel.Info); +// +// if (satoshisBeingUsed - satoshiAmountToSend > feeForOneOutput) { +// if (satoshisBeingUsed - satoshiAmountToSend > +// feeForOneOutput + DUST_LIMIT) { +// // Here, we know that theoretically, we may be able to include another output(change) but we first need to +// // factor in the value of this output in satoshis. +// int changeOutputSize = +// satoshisBeingUsed - satoshiAmountToSend - feeForTwoOutputs; +// // We check to see if the user can pay for the new transaction with 2 outputs instead of one. If they can and +// // the second output's size > 546 satoshis, we perform the mechanics required to properly generate and use a new +// // change address. +// if (changeOutputSize > DUST_LIMIT && +// satoshisBeingUsed - satoshiAmountToSend - changeOutputSize == +// feeForTwoOutputs) { +// // generate new change address if current change address has been used +// await _checkChangeAddressForTransactions(DerivePathType.bip44); +// final String newChangeAddress = +// await _getCurrentAddressForChain(1, DerivePathType.bip44); +// +// int feeBeingPaid = +// satoshisBeingUsed - satoshiAmountToSend - changeOutputSize; +// +// recipientsArray.add(newChangeAddress); +// recipientsAmtArray.add(changeOutputSize); +// // At this point, we have the outputs we're going to use, the amounts to send along with which addresses +// // we intend to send these amounts to. We have enough to send instructions to build the transaction. +// Logging.instance.log('2 outputs in tx', level: LogLevel.Info); +// Logging.instance +// .log('Input size: $satoshisBeingUsed', level: LogLevel.Info); +// Logging.instance.log('Recipient output size: $satoshiAmountToSend', +// level: LogLevel.Info); +// Logging.instance.log('Change Output Size: $changeOutputSize', +// level: LogLevel.Info); +// Logging.instance.log( +// 'Difference (fee being paid): $feeBeingPaid sats', +// level: LogLevel.Info); +// Logging.instance +// .log('Estimated fee: $feeForTwoOutputs', level: LogLevel.Info); +// dynamic txn = await buildTransaction( +// utxosToUse: utxoObjectsToUse, +// utxoSigningData: utxoSigningData, +// recipients: recipientsArray, +// satoshiAmounts: recipientsAmtArray, +// ); +// +// // make sure minimum fee is accurate if that is being used +// if (txn["vSize"] - feeBeingPaid == 1) { +// int changeOutputSize = +// satoshisBeingUsed - satoshiAmountToSend - (txn["vSize"] as int); +// feeBeingPaid = +// satoshisBeingUsed - satoshiAmountToSend - changeOutputSize; +// recipientsAmtArray.removeLast(); +// recipientsAmtArray.add(changeOutputSize); +// Logging.instance.log('Adjusted Input size: $satoshisBeingUsed', +// level: LogLevel.Info); +// Logging.instance.log( +// 'Adjusted Recipient output size: $satoshiAmountToSend', +// level: LogLevel.Info); +// Logging.instance.log( +// 'Adjusted Change Output Size: $changeOutputSize', +// level: LogLevel.Info); +// Logging.instance.log( +// 'Adjusted Difference (fee being paid): $feeBeingPaid sats', +// level: LogLevel.Info); +// Logging.instance.log('Adjusted Estimated fee: $feeForTwoOutputs', +// level: LogLevel.Info); +// txn = await buildTransaction( +// utxosToUse: utxoObjectsToUse, +// utxoSigningData: utxoSigningData, +// recipients: recipientsArray, +// satoshiAmounts: recipientsAmtArray, +// ); +// } +// +// Map transactionObject = { +// "hex": txn["hex"], +// "recipient": recipientsArray[0], +// "recipientAmt": recipientsAmtArray[0], +// "fee": feeBeingPaid, +// "vSize": txn["vSize"], +// }; +// return transactionObject; +// } else { +// // Something went wrong here. It either overshot or undershot the estimated fee amount or the changeOutputSize +// // is smaller than or equal to [DUST_LIMIT]. Revert to single output transaction. +// Logging.instance.log('1 output in tx', level: LogLevel.Info); +// Logging.instance +// .log('Input size: $satoshisBeingUsed', level: LogLevel.Info); +// Logging.instance.log('Recipient output size: $satoshiAmountToSend', +// level: LogLevel.Info); +// Logging.instance.log( +// 'Difference (fee being paid): ${satoshisBeingUsed - satoshiAmountToSend} sats', +// level: LogLevel.Info); +// Logging.instance +// .log('Estimated fee: $feeForOneOutput', level: LogLevel.Info); +// dynamic txn = await buildTransaction( +// utxosToUse: utxoObjectsToUse, +// utxoSigningData: utxoSigningData, +// recipients: recipientsArray, +// satoshiAmounts: recipientsAmtArray, +// ); +// Map transactionObject = { +// "hex": txn["hex"], +// "recipient": recipientsArray[0], +// "recipientAmt": recipientsAmtArray[0], +// "fee": satoshisBeingUsed - satoshiAmountToSend, +// "vSize": txn["vSize"], +// }; +// return transactionObject; +// } +// } else { +// // No additional outputs needed since adding one would mean that it'd be smaller than 546 sats +// // which makes it uneconomical to add to the transaction. Here, we pass data directly to instruct +// // the wallet to begin crafting the transaction that the user requested. +// Logging.instance.log('1 output in tx', level: LogLevel.Info); +// Logging.instance +// .log('Input size: $satoshisBeingUsed', level: LogLevel.Info); +// Logging.instance.log('Recipient output size: $satoshiAmountToSend', +// level: LogLevel.Info); +// Logging.instance.log( +// 'Difference (fee being paid): ${satoshisBeingUsed - satoshiAmountToSend} sats', +// level: LogLevel.Info); +// Logging.instance +// .log('Estimated fee: $feeForOneOutput', level: LogLevel.Info); +// dynamic txn = await buildTransaction( +// utxosToUse: utxoObjectsToUse, +// utxoSigningData: utxoSigningData, +// recipients: recipientsArray, +// satoshiAmounts: recipientsAmtArray, +// ); +// Map transactionObject = { +// "hex": txn["hex"], +// "recipient": recipientsArray[0], +// "recipientAmt": recipientsAmtArray[0], +// "fee": satoshisBeingUsed - satoshiAmountToSend, +// "vSize": txn["vSize"], +// }; +// return transactionObject; +// } +// } else if (satoshisBeingUsed - satoshiAmountToSend == feeForOneOutput) { +// // In this scenario, no additional change output is needed since inputs - outputs equal exactly +// // what we need to pay for fees. Here, we pass data directly to instruct the wallet to begin +// // crafting the transaction that the user requested. +// Logging.instance.log('1 output in tx', level: LogLevel.Info); +// Logging.instance +// .log('Input size: $satoshisBeingUsed', level: LogLevel.Info); +// Logging.instance.log('Recipient output size: $satoshiAmountToSend', +// level: LogLevel.Info); +// Logging.instance.log( +// 'Fee being paid: ${satoshisBeingUsed - satoshiAmountToSend} sats', +// level: LogLevel.Info); +// Logging.instance +// .log('Estimated fee: $feeForOneOutput', level: LogLevel.Info); +// dynamic txn = await buildTransaction( +// utxosToUse: utxoObjectsToUse, +// utxoSigningData: utxoSigningData, +// recipients: recipientsArray, +// satoshiAmounts: recipientsAmtArray, +// ); +// Map transactionObject = { +// "hex": txn["hex"], +// "recipient": recipientsArray[0], +// "recipientAmt": recipientsAmtArray[0], +// "fee": feeForOneOutput, +// "vSize": txn["vSize"], +// }; +// return transactionObject; +// } else { +// // Remember that returning 2 indicates that the user does not have a sufficient balance to +// // pay for the transaction fee. Ideally, at this stage, we should check if the user has any +// // additional outputs they're able to spend and then recalculate fees. +// Logging.instance.log( +// 'Cannot pay tx fee - checking for more outputs and trying again', +// level: LogLevel.Warning); +// // try adding more outputs +// if (spendableOutputs.length > inputsBeingConsumed) { +// return coinSelection(satoshiAmountToSend, selectedTxFeeRate, +// _recipientAddress, isSendAll, +// additionalOutputs: additionalOutputs + 1, utxos: utxos); +// } +// return 2; +// } +// } +// +// Future> fetchBuildTxData( +// List utxosToUse, +// ) async { +// // return data +// Map results = {}; +// Map> addressTxid = {}; +// +// // addresses to check +// List addressesP2PKH = []; +// +// try { +// // Populating the addresses to check +// for (var i = 0; i < utxosToUse.length; i++) { +// final txid = utxosToUse[i].txid; +// final tx = await _cachedElectrumXClient.getTransaction( +// txHash: txid, +// coin: coin, +// ); +// +// for (final output in tx["vout"] as List) { +// final n = output["n"]; +// if (n != null && n == utxosToUse[i].vout) { +// final address = output["scriptPubKey"]["addresses"][0] as String; +// if (!addressTxid.containsKey(address)) { +// addressTxid[address] = []; +// } +// (addressTxid[address] as List).add(txid); +// switch (addressType(address: address)) { +// case DerivePathType.bip44: +// addressesP2PKH.add(address); +// break; +// } +// } +// } +// } +// +// // p2pkh / bip44 +// final p2pkhLength = addressesP2PKH.length; +// if (p2pkhLength > 0) { +// final receiveDerivations = await _fetchDerivations( +// chain: 0, +// derivePathType: DerivePathType.bip44, +// ); +// final changeDerivations = await _fetchDerivations( +// chain: 1, +// derivePathType: DerivePathType.bip44, +// ); +// for (int i = 0; i < p2pkhLength; i++) { +// // receives +// final receiveDerivation = receiveDerivations[addressesP2PKH[i]]; +// // if a match exists it will not be null +// if (receiveDerivation != null) { +// final data = P2PKH( +// data: PaymentData( +// pubkey: Format.stringToUint8List( +// receiveDerivation["pubKey"] as String)), +// network: _network, +// ).data; +// +// for (String tx in addressTxid[addressesP2PKH[i]]!) { +// results[tx] = { +// "output": data.output, +// "keyPair": ECPair.fromWIF( +// receiveDerivation["wif"] as String, +// network: _network, +// ), +// }; +// } +// } else { +// // if its not a receive, check change +// final changeDerivation = changeDerivations[addressesP2PKH[i]]; +// // if a match exists it will not be null +// if (changeDerivation != null) { +// final data = P2PKH( +// data: PaymentData( +// pubkey: Format.stringToUint8List( +// changeDerivation["pubKey"] as String)), +// network: _network, +// ).data; +// +// for (String tx in addressTxid[addressesP2PKH[i]]!) { +// results[tx] = { +// "output": data.output, +// "keyPair": ECPair.fromWIF( +// changeDerivation["wif"] as String, +// network: _network, +// ), +// }; +// } +// } +// } +// } +// } +// +// return results; +// } catch (e, s) { +// Logging.instance +// .log("fetchBuildTxData() threw: $e,\n$s", level: LogLevel.Error); +// rethrow; +// } +// } +// +// /// Builds and signs a transaction +// Future> buildTransaction({ +// required List utxosToUse, +// required Map utxoSigningData, +// required List recipients, +// required List satoshiAmounts, +// }) async { +// final builder = Bitbox.Bitbox.transactionBuilder(); +// +// // retrieve address' utxos from the rest api +// List _utxos = +// []; // await Bitbox.Address.utxo(address) as List; +// utxosToUse.forEach((element) { +// _utxos.add(Bitbox.Utxo( +// element.txid, +// element.vout, +// Bitbox.BitcoinCash.fromSatoshi(element.value), +// element.value, +// 0, +// MINIMUM_CONFIRMATIONS + 1)); +// }); +// Logger.print("bch utxos: ${_utxos}"); +// +// // placeholder for input signatures +// final signatures = []; +// +// // placeholder for total input balance +// int totalBalance = 0; +// +// // iterate through the list of address _utxos and use them as inputs for the +// // withdrawal transaction +// _utxos.forEach((Bitbox.Utxo utxo) { +// // add the utxo as an input for the transaction +// builder.addInput(utxo.txid, utxo.vout); +// final ec = utxoSigningData[utxo.txid]["keyPair"] as ECPair; +// +// final bitboxEC = Bitbox.ECPair.fromWIF(ec.toWIF()); +// +// // add a signature to the list to be used later +// signatures.add({ +// "vin": signatures.length, +// "key_pair": bitboxEC, +// "original_amount": utxo.satoshis +// }); +// +// totalBalance += utxo.satoshis; +// }); +// +// // calculate the fee based on number of inputs and one expected output +// final fee = +// Bitbox.BitcoinCash.getByteCount(signatures.length, recipients.length); +// +// // calculate how much balance will be left over to spend after the fee +// final sendAmount = totalBalance - fee; +// +// // add the output based on the address provided in the testing data +// for (int i = 0; i < recipients.length; i++) { +// String recipient = recipients[i]; +// int satoshiAmount = satoshiAmounts[i]; +// builder.addOutput(recipient, satoshiAmount); +// } +// +// // sign all inputs +// signatures.forEach((signature) { +// builder.sign( +// signature["vin"] as int, +// signature["key_pair"] as Bitbox.ECPair, +// signature["original_amount"] as int); +// }); +// +// // build the transaction +// final tx = builder.build(); +// final txHex = tx.toHex(); +// final vSize = tx.virtualSize(); +// Logger.print("bch raw hex: $txHex"); +// +// return {"hex": txHex, "vSize": vSize}; +// } +// +// @override +// Future fullRescan( +// int maxUnusedAddressGap, +// int maxNumberOfIndexesToCheck, +// ) async { +// Logging.instance.log("Starting full rescan!", level: LogLevel.Info); +// longMutex = true; +// GlobalEventBus.instance.fire( +// WalletSyncStatusChangedEvent( +// WalletSyncStatus.syncing, +// walletId, +// coin, +// ), +// ); +// +// // clear cache +// _cachedElectrumXClient.clearSharedTransactionCache(coin: coin); +// +// // back up data +// await _rescanBackup(); +// +// try { +// final mnemonic = await _secureStore.read(key: '${_walletId}_mnemonic'); +// await _recoverWalletFromBIP32SeedPhrase( +// mnemonic: mnemonic!, +// maxUnusedAddressGap: maxUnusedAddressGap, +// maxNumberOfIndexesToCheck: maxNumberOfIndexesToCheck, +// ); +// +// longMutex = false; +// Logging.instance.log("Full rescan complete!", level: LogLevel.Info); +// GlobalEventBus.instance.fire( +// WalletSyncStatusChangedEvent( +// WalletSyncStatus.synced, +// walletId, +// coin, +// ), +// ); +// } catch (e, s) { +// GlobalEventBus.instance.fire( +// WalletSyncStatusChangedEvent( +// WalletSyncStatus.unableToSync, +// walletId, +// coin, +// ), +// ); +// +// // restore from backup +// await _rescanRestore(); +// +// longMutex = false; +// Logging.instance.log("Exception rethrown from fullRescan(): $e\n$s", +// level: LogLevel.Error); +// rethrow; +// } +// } +// +// Future _rescanRestore() async { +// Logging.instance.log("starting rescan restore", level: LogLevel.Info); +// +// // restore from backup +// // p2pkh +// final tempReceivingAddressesP2PKH = DB.instance +// .get(boxName: walletId, key: 'receivingAddressesP2PKH_BACKUP'); +// final tempChangeAddressesP2PKH = DB.instance +// .get(boxName: walletId, key: 'changeAddressesP2PKH_BACKUP'); +// final tempReceivingIndexP2PKH = DB.instance +// .get(boxName: walletId, key: 'receivingIndexP2PKH_BACKUP'); +// final tempChangeIndexP2PKH = DB.instance +// .get(boxName: walletId, key: 'changeIndexP2PKH_BACKUP'); +// await DB.instance.put( +// boxName: walletId, +// key: 'receivingAddressesP2PKH', +// value: tempReceivingAddressesP2PKH); +// await DB.instance.put( +// boxName: walletId, +// key: 'changeAddressesP2PKH', +// value: tempChangeAddressesP2PKH); +// await DB.instance.put( +// boxName: walletId, +// key: 'receivingIndexP2PKH', +// value: tempReceivingIndexP2PKH); +// await DB.instance.put( +// boxName: walletId, +// key: 'changeIndexP2PKH', +// value: tempChangeIndexP2PKH); +// await DB.instance.delete( +// key: 'receivingAddressesP2PKH_BACKUP', boxName: walletId); +// await DB.instance +// .delete(key: 'changeAddressesP2PKH_BACKUP', boxName: walletId); +// await DB.instance +// .delete(key: 'receivingIndexP2PKH_BACKUP', boxName: walletId); +// await DB.instance +// .delete(key: 'changeIndexP2PKH_BACKUP', boxName: walletId); +// +// // P2PKH derivations +// final p2pkhReceiveDerivationsString = await _secureStore.read( +// key: "${walletId}_receiveDerivationsP2PKH_BACKUP"); +// final p2pkhChangeDerivationsString = await _secureStore.read( +// key: "${walletId}_changeDerivationsP2PKH_BACKUP"); +// +// await _secureStore.write( +// key: "${walletId}_receiveDerivationsP2PKH", +// value: p2pkhReceiveDerivationsString); +// await _secureStore.write( +// key: "${walletId}_changeDerivationsP2PKH", +// value: p2pkhChangeDerivationsString); +// +// await _secureStore.delete( +// key: "${walletId}_receiveDerivationsP2PKH_BACKUP"); +// await _secureStore.delete(key: "${walletId}_changeDerivationsP2PKH_BACKUP"); +// +// // UTXOs +// final utxoData = DB.instance +// .get(boxName: walletId, key: 'latest_utxo_model_BACKUP'); +// await DB.instance.put( +// boxName: walletId, key: 'latest_utxo_model', value: utxoData); +// await DB.instance +// .delete(key: 'latest_utxo_model_BACKUP', boxName: walletId); +// +// Logging.instance.log("rescan restore complete", level: LogLevel.Info); +// } +// +// Future _rescanBackup() async { +// Logging.instance.log("starting rescan backup", level: LogLevel.Info); +// +// // backup current and clear data +// // p2pkh +// final tempReceivingAddressesP2PKH = DB.instance +// .get(boxName: walletId, key: 'receivingAddressesP2PKH'); +// await DB.instance.put( +// boxName: walletId, +// key: 'receivingAddressesP2PKH_BACKUP', +// value: tempReceivingAddressesP2PKH); +// await DB.instance +// .delete(key: 'receivingAddressesP2PKH', boxName: walletId); +// +// final tempChangeAddressesP2PKH = DB.instance +// .get(boxName: walletId, key: 'changeAddressesP2PKH'); +// await DB.instance.put( +// boxName: walletId, +// key: 'changeAddressesP2PKH_BACKUP', +// value: tempChangeAddressesP2PKH); +// await DB.instance +// .delete(key: 'changeAddressesP2PKH', boxName: walletId); +// +// final tempReceivingIndexP2PKH = +// DB.instance.get(boxName: walletId, key: 'receivingIndexP2PKH'); +// await DB.instance.put( +// boxName: walletId, +// key: 'receivingIndexP2PKH_BACKUP', +// value: tempReceivingIndexP2PKH); +// await DB.instance +// .delete(key: 'receivingIndexP2PKH', boxName: walletId); +// +// final tempChangeIndexP2PKH = +// DB.instance.get(boxName: walletId, key: 'changeIndexP2PKH'); +// await DB.instance.put( +// boxName: walletId, +// key: 'changeIndexP2PKH_BACKUP', +// value: tempChangeIndexP2PKH); +// await DB.instance +// .delete(key: 'changeIndexP2PKH', boxName: walletId); +// +// // P2PKH derivations +// final p2pkhReceiveDerivationsString = +// await _secureStore.read(key: "${walletId}_receiveDerivationsP2PKH"); +// final p2pkhChangeDerivationsString = +// await _secureStore.read(key: "${walletId}_changeDerivationsP2PKH"); +// +// await _secureStore.write( +// key: "${walletId}_receiveDerivationsP2PKH_BACKUP", +// value: p2pkhReceiveDerivationsString); +// await _secureStore.write( +// key: "${walletId}_changeDerivationsP2PKH_BACKUP", +// value: p2pkhChangeDerivationsString); +// +// await _secureStore.delete(key: "${walletId}_receiveDerivationsP2PKH"); +// await _secureStore.delete(key: "${walletId}_changeDerivationsP2PKH"); +// +// // UTXOs +// final utxoData = +// DB.instance.get(boxName: walletId, key: 'latest_utxo_model'); +// await DB.instance.put( +// boxName: walletId, key: 'latest_utxo_model_BACKUP', value: utxoData); +// await DB.instance +// .delete(key: 'latest_utxo_model', boxName: walletId); +// +// Logging.instance.log("rescan backup complete", level: LogLevel.Info); +// } +// +// @override +// set isFavorite(bool markFavorite) { +// DB.instance.put( +// boxName: walletId, key: "isFavorite", value: markFavorite); +// } +// +// @override +// bool get isFavorite { +// try { +// return DB.instance.get(boxName: walletId, key: "isFavorite") +// as bool; +// } catch (e, s) { +// Logging.instance +// .log("isFavorite fetch failed: $e\n$s", level: LogLevel.Error); +// rethrow; +// } +// } +// +// @override +// bool get isRefreshing => refreshMutex; +// +// bool isActive = false; +// +// @override +// void Function(bool)? get onIsActiveWalletChanged => +// (isActive) => this.isActive = isActive; +// +// @override +// Future estimateFeeFor(int satoshiAmount, int feeRate) async { +// final available = Format.decimalAmountToSatoshis(await availableBalance); +// +// if (available == satoshiAmount) { +// return satoshiAmount - sweepAllEstimate(feeRate); +// } else if (satoshiAmount <= 0 || satoshiAmount > available) { +// return roughFeeEstimate(1, 2, feeRate); +// } +// +// int runningBalance = 0; +// int inputCount = 0; +// for (final output in outputsList) { +// runningBalance += output.value; +// inputCount++; +// if (runningBalance > satoshiAmount) { +// break; +// } +// } +// +// final oneOutPutFee = roughFeeEstimate(inputCount, 1, feeRate); +// final twoOutPutFee = roughFeeEstimate(inputCount, 2, feeRate); +// +// if (runningBalance - satoshiAmount > oneOutPutFee) { +// if (runningBalance - satoshiAmount > oneOutPutFee + DUST_LIMIT) { +// final change = runningBalance - satoshiAmount - twoOutPutFee; +// if (change > DUST_LIMIT && +// runningBalance - satoshiAmount - change == twoOutPutFee) { +// return runningBalance - satoshiAmount - change; +// } else { +// return runningBalance - satoshiAmount; +// } +// } else { +// return runningBalance - satoshiAmount; +// } +// } else if (runningBalance - satoshiAmount == oneOutPutFee) { +// return oneOutPutFee; +// } else { +// return twoOutPutFee; +// } +// } +// +// // TODO: correct formula for bch? +// int roughFeeEstimate(int inputCount, int outputCount, int feeRatePerKB) { +// return ((181 * inputCount) + (34 * outputCount) + 10) * +// (feeRatePerKB / 1000).ceil(); +// } +// +// int sweepAllEstimate(int feeRate) { +// int available = 0; +// int inputCount = 0; +// for (final output in outputsList) { +// if (output.status.confirmed) { +// available += output.value; +// inputCount++; +// } +// } +// +// // transaction will only have 1 output minus the fee +// final estimatedFee = roughFeeEstimate(inputCount, 1, feeRate); +// +// return available - estimatedFee; +// } +// +// @override +// Future generateNewAddress() async { +// try { +// await _incrementAddressIndexForChain( +// 0, DerivePathType.bip44); // First increment the receiving index +// final newReceivingIndex = DB.instance.get( +// boxName: walletId, +// key: 'receivingIndexP2PKH') as int; // Check the new receiving index +// final newReceivingAddress = await _generateAddressForChain( +// 0, +// newReceivingIndex, +// DerivePathType +// .bip44); // Use new index to derive a new receiving address +// await _addToAddressesArrayForChain( +// newReceivingAddress, +// 0, +// DerivePathType +// .bip44); // Add that new receiving address to the array of receiving addresses +// _currentReceivingAddressP2PKH = Future(() => +// newReceivingAddress); // Set the new receiving address that the service +// +// return true; +// } catch (e, s) { +// Logging.instance.log( +// "Exception rethrown from generateNewAddress(): $e\n$s", +// level: LogLevel.Error); +// return false; +// } +// } +// } +// +// // Bitcoincash Network +// final bitcoincash = NetworkType( +// messagePrefix: '\x18Bitcoin Signed Message:\n', +// bech32: 'bc', +// bip32: Bip32Type(public: 0x0488b21e, private: 0x0488ade4), +// pubKeyHash: 0x00, +// scriptHash: 0x05, +// wif: 0x80); +// +// final bitcoincashtestnet = NetworkType( +// messagePrefix: '\x18Bitcoin Signed Message:\n', +// bech32: 'tb', +// bip32: Bip32Type(public: 0x043587cf, private: 0x04358394), +// pubKeyHash: 0x6f, +// scriptHash: 0xc4, +// wif: 0xef); diff --git a/lib/services/coins/coin_service.dart b/lib/services/coins/coin_service.dart index bc0e4be28..69acd843f 100644 --- a/lib/services/coins/coin_service.dart +++ b/lib/services/coins/coin_service.dart @@ -8,6 +8,7 @@ import 'package:stackwallet/services/coins/dogecoin/dogecoin_wallet.dart'; import 'package:stackwallet/services/coins/epiccash/epiccash_wallet.dart'; import 'package:stackwallet/services/coins/firo/firo_wallet.dart'; import 'package:stackwallet/services/coins/monero/monero_wallet.dart'; +import 'package:stackwallet/services/coins/namecoin/namecoin_wallet.dart'; import 'package:stackwallet/services/transaction_notification_tracker.dart'; import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/prefs.dart'; @@ -97,6 +98,26 @@ abstract class CoinServiceAPI { tracker: tracker, ); + // case Coin.bitcoincash: + // return BitcoinCashWallet( + // walletId: walletId, + // walletName: walletName, + // coin: coin, + // client: client, + // cachedClient: cachedClient, + // tracker: tracker, + // ); + // + // case Coin.bitcoincashTestnet: + // return BitcoinCashWallet( + // walletId: walletId, + // walletName: walletName, + // coin: coin, + // client: client, + // cachedClient: cachedClient, + // tracker: tracker, + // ); + case Coin.dogecoin: return DogecoinWallet( walletId: walletId, @@ -123,6 +144,16 @@ abstract class CoinServiceAPI { // tracker: tracker, ); + case Coin.namecoin: + return NamecoinWallet( + walletId: walletId, + walletName: walletName, + coin: coin, + tracker: tracker, + cachedClient: cachedClient, + client: client, + ); + case Coin.dogecoinTestNet: return DogecoinWallet( walletId: walletId, diff --git a/lib/services/coins/namecoin/namecoin_wallet.dart b/lib/services/coins/namecoin/namecoin_wallet.dart new file mode 100644 index 000000000..9734a9b51 --- /dev/null +++ b/lib/services/coins/namecoin/namecoin_wallet.dart @@ -0,0 +1,3814 @@ +import 'dart:async'; +import 'dart:convert'; +import 'dart:io'; +import 'dart:typed_data'; + +import 'package:bech32/bech32.dart'; +import 'package:bip32/bip32.dart' as bip32; +import 'package:bip39/bip39.dart' as bip39; +import 'package:bitcoindart/bitcoindart.dart'; +import 'package:bs58check/bs58check.dart' as bs58check; +import 'package:crypto/crypto.dart'; +import 'package:decimal/decimal.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter_secure_storage/flutter_secure_storage.dart'; +import 'package:http/http.dart'; +import 'package:stackwallet/electrumx_rpc/cached_electrumx.dart'; +import 'package:stackwallet/electrumx_rpc/electrumx.dart'; +import 'package:stackwallet/hive/db.dart'; +import 'package:stackwallet/models/models.dart' as models; +import 'package:stackwallet/models/paymint/fee_object_model.dart'; +import 'package:stackwallet/models/paymint/transactions_model.dart'; +import 'package:stackwallet/models/paymint/utxo_model.dart'; +import 'package:stackwallet/services/coins/coin_service.dart'; +import 'package:stackwallet/services/event_bus/events/global/node_connection_status_changed_event.dart'; +import 'package:stackwallet/services/event_bus/events/global/refresh_percent_changed_event.dart'; +import 'package:stackwallet/services/event_bus/events/global/updated_in_background_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/node_service.dart'; +import 'package:stackwallet/services/notifications_api.dart'; +import 'package:stackwallet/services/price.dart'; +import 'package:stackwallet/services/transaction_notification_tracker.dart'; +import 'package:stackwallet/utilities/assets.dart'; +import 'package:stackwallet/utilities/constants.dart'; +import 'package:stackwallet/utilities/default_nodes.dart'; +import 'package:stackwallet/utilities/enums/coin_enum.dart'; +import 'package:stackwallet/utilities/enums/fee_rate_type_enum.dart'; +import 'package:stackwallet/utilities/flutter_secure_storage_interface.dart'; +import 'package:stackwallet/utilities/format.dart'; +import 'package:stackwallet/utilities/logger.dart'; +import 'package:stackwallet/utilities/prefs.dart'; +import 'package:tuple/tuple.dart'; +import 'package:uuid/uuid.dart'; + +const int MINIMUM_CONFIRMATIONS = 2; +// Find real dust limit +const int DUST_LIMIT = 546; + +const String GENESIS_HASH_MAINNET = + "000000000062b72c5e2ceb45fbc8587e807c155b0da735e6483dfba2f0a9c770"; +const String GENESIS_HASH_TESTNET = + "00000007199508e34a9ff81e6ec0c477a4cccff2a4767a8eee39c11db367b008"; + +enum DerivePathType { bip44, bip49, bip84 } + +bip32.BIP32 getBip32Node( + int chain, + int index, + String mnemonic, + NetworkType network, + DerivePathType derivePathType, +) { + final root = getBip32Root(mnemonic, network); + + final node = getBip32NodeFromRoot(chain, index, root, derivePathType); + return node; +} + +/// wrapper for compute() +bip32.BIP32 getBip32NodeWrapper( + Tuple5 args, +) { + return getBip32Node( + args.item1, + args.item2, + args.item3, + args.item4, + args.item5, + ); +} + +bip32.BIP32 getBip32NodeFromRoot( + int chain, + int index, + bip32.BIP32 root, + DerivePathType derivePathType, +) { + String coinType; + switch (root.network.wif) { + case 0xb4: // nmc mainnet wif + coinType = "7"; // nmc mainnet + break; + default: + throw Exception("Invalid Namecoin network type used!"); + } + switch (derivePathType) { + case DerivePathType.bip44: + return root.derivePath("m/44'/$coinType'/0'/$chain/$index"); + case DerivePathType.bip49: + return root.derivePath("m/49'/$coinType'/0'/$chain/$index"); + case DerivePathType.bip84: + return root.derivePath("m/84'/$coinType'/0'/$chain/$index"); + default: + throw Exception("DerivePathType must not be null."); + } +} + +/// wrapper for compute() +bip32.BIP32 getBip32NodeFromRootWrapper( + Tuple4 args, +) { + return getBip32NodeFromRoot( + args.item1, + args.item2, + args.item3, + args.item4, + ); +} + +bip32.BIP32 getBip32Root(String mnemonic, NetworkType network) { + final seed = bip39.mnemonicToSeed(mnemonic); + final networkType = bip32.NetworkType( + wif: network.wif, + bip32: bip32.Bip32Type( + public: network.bip32.public, + private: network.bip32.private, + ), + ); + + final root = bip32.BIP32.fromSeed(seed, networkType); + return root; +} + +/// wrapper for compute() +bip32.BIP32 getBip32RootWrapper(Tuple2 args) { + return getBip32Root(args.item1, args.item2); +} + +class NamecoinWallet extends CoinServiceAPI { + static const integrationTestFlag = + bool.fromEnvironment("IS_INTEGRATION_TEST"); + + final _prefs = Prefs.instance; + + Timer? timer; + late Coin _coin; + + late final TransactionNotificationTracker txTracker; + + NetworkType get _network { + switch (coin) { + case Coin.namecoin: + return namecoin; + default: + throw Exception("Invalid network type!"); + } + } + + List outputsList = []; + + @override + set isFavorite(bool markFavorite) { + DB.instance.put( + boxName: walletId, key: "isFavorite", value: markFavorite); + } + + @override + bool get isFavorite { + try { + return DB.instance.get(boxName: walletId, key: "isFavorite") + as bool; + } catch (e, s) { + Logging.instance + .log("isFavorite fetch failed: $e\n$s", level: LogLevel.Error); + rethrow; + } + } + + @override + Coin get coin => _coin; + + @override + Future> get allOwnAddresses => + _allOwnAddresses ??= _fetchAllOwnAddresses(); + Future>? _allOwnAddresses; + + Future? _utxoData; + Future get utxoData => _utxoData ??= _fetchUtxoData(); + + @override + Future> get unspentOutputs async => + (await utxoData).unspentOutputArray; + + @override + Future get availableBalance async { + final data = await utxoData; + return Format.satoshisToAmount( + data.satoshiBalance - data.satoshiBalanceUnconfirmed); + } + + @override + Future get pendingBalance async { + final data = await utxoData; + return Format.satoshisToAmount(data.satoshiBalanceUnconfirmed); + } + + @override + Future get balanceMinusMaxFee async => + (await availableBalance) - + (Decimal.fromInt((await maxFee)) / Decimal.fromInt(Constants.satsPerCoin)) + .toDecimal(); + + @override + Future get totalBalance async { + if (!isActive) { + final totalBalance = DB.instance + .get(boxName: walletId, key: 'totalBalance') as int?; + if (totalBalance == null) { + final data = await utxoData; + return Format.satoshisToAmount(data.satoshiBalance); + } else { + return Format.satoshisToAmount(totalBalance); + } + } + final data = await utxoData; + return Format.satoshisToAmount(data.satoshiBalance); + } + + @override + Future get currentReceivingAddress => _currentReceivingAddress ??= + _getCurrentAddressForChain(0, DerivePathType.bip84); + Future? _currentReceivingAddress; + + Future get currentLegacyReceivingAddress => + _currentReceivingAddressP2PKH ??= + _getCurrentAddressForChain(0, DerivePathType.bip44); + Future? _currentReceivingAddressP2PKH; + + Future get currentReceivingAddressP2SH => + _currentReceivingAddressP2SH ??= + _getCurrentAddressForChain(0, DerivePathType.bip49); + Future? _currentReceivingAddressP2SH; + + @override + Future exit() async { + _hasCalledExit = true; + timer?.cancel(); + timer = null; + stopNetworkAlivePinging(); + } + + bool _hasCalledExit = false; + + @override + bool get hasCalledExit => _hasCalledExit; + + @override + Future get fees => _feeObject ??= _getFees(); + Future? _feeObject; + + @override + Future get maxFee async { + final fee = (await fees).fast as String; + final satsFee = Decimal.parse(fee) * Decimal.fromInt(Constants.satsPerCoin); + return satsFee.floor().toBigInt().toInt(); + } + + @override + Future> get mnemonic => _getMnemonicList(); + + Future get chainHeight async { + try { + final result = await _electrumXClient.getBlockHeadTip(); + return result["height"] as int; + } catch (e, s) { + Logging.instance.log("Exception caught in chainHeight: $e\n$s", + level: LogLevel.Error); + return -1; + } + } + + int get storedChainHeight { + final storedHeight = DB.instance + .get(boxName: walletId, key: "storedChainHeight") as int?; + return storedHeight ?? 0; + } + + Future updateStoredChainHeight({required int newHeight}) async { + await DB.instance.put( + boxName: walletId, key: "storedChainHeight", value: newHeight); + } + + DerivePathType addressType({required String address}) { + Uint8List? decodeBase58; + Segwit? decodeBech32; + try { + decodeBase58 = bs58check.decode(address); + } catch (err) { + // Base58check decode fail + } + if (decodeBase58 != null) { + if (decodeBase58[0] == _network.pubKeyHash) { + // P2PKH + return DerivePathType.bip44; + } + if (decodeBase58[0] == _network.scriptHash) { + // P2SH + return DerivePathType.bip49; + } + throw ArgumentError('Invalid version or Network mismatch'); + } else { + try { + decodeBech32 = segwit.decode(address, namecoin.bech32!); + } catch (err) { + // Bech32 decode fail + } + if (_network.bech32 != decodeBech32!.hrp) { + throw ArgumentError('Invalid prefix or Network mismatch'); + } + if (decodeBech32.version != 0) { + throw ArgumentError('Invalid address version'); + } + // P2WPKH + return DerivePathType.bip84; + } + } + + bool longMutex = false; + + @override + Future recoverFromMnemonic({ + required String mnemonic, + required int maxUnusedAddressGap, + required int maxNumberOfIndexesToCheck, + required int height, + }) async { + longMutex = true; + final start = DateTime.now(); + try { + Logging.instance.log("IS_INTEGRATION_TEST: $integrationTestFlag", + level: LogLevel.Info); + if (!integrationTestFlag) { + final features = await electrumXClient.getServerFeatures(); + Logging.instance.log("features: $features", level: LogLevel.Info); + switch (coin) { + case Coin.namecoin: + if (features['genesis_hash'] != GENESIS_HASH_MAINNET) { + throw Exception("genesis hash does not match main net!"); + } + break; + default: + throw Exception( + "Attempted to generate a NamecoinWallet using a non namecoin coin type: ${coin.name}"); + } + // if (_networkType == BasicNetworkType.main) { + // if (features['genesis_hash'] != GENESIS_HASH_MAINNET) { + // throw Exception("genesis hash does not match main net!"); + // } + // } else if (_networkType == BasicNetworkType.test) { + // if (features['genesis_hash'] != GENESIS_HASH_TESTNET) { + // throw Exception("genesis hash does not match test net!"); + // } + // } + } + // check to make sure we aren't overwriting a mnemonic + // this should never fail + if ((await _secureStore.read(key: '${_walletId}_mnemonic')) != null) { + longMutex = false; + throw Exception("Attempted to overwrite mnemonic on restore!"); + } + await _secureStore.write( + key: '${_walletId}_mnemonic', value: mnemonic.trim()); + await _recoverWalletFromBIP32SeedPhrase( + mnemonic: mnemonic.trim(), + maxUnusedAddressGap: maxUnusedAddressGap, + maxNumberOfIndexesToCheck: maxNumberOfIndexesToCheck, + ); + } catch (e, s) { + Logging.instance.log( + "Exception rethrown from recoverFromMnemonic(): $e\n$s", + level: LogLevel.Error); + longMutex = false; + rethrow; + } + longMutex = false; + + final end = DateTime.now(); + Logging.instance.log( + "$walletName recovery time: ${end.difference(start).inMilliseconds} millis", + level: LogLevel.Info); + } + + Future> _checkGaps( + int maxNumberOfIndexesToCheck, + int maxUnusedAddressGap, + int txCountBatchSize, + bip32.BIP32 root, + DerivePathType type, + int account) async { + List addressArray = []; + int returningIndex = -1; + Map> derivations = {}; + int gapCounter = 0; + for (int index = 0; + index < maxNumberOfIndexesToCheck && gapCounter < maxUnusedAddressGap; + index += txCountBatchSize) { + List iterationsAddressArray = []; + Logging.instance.log( + "index: $index, \t GapCounter $account ${type.name}: $gapCounter", + level: LogLevel.Info); + + final _id = "k_$index"; + Map txCountCallArgs = {}; + final Map receivingNodes = {}; + + for (int j = 0; j < txCountBatchSize; j++) { + final node = await compute( + getBip32NodeFromRootWrapper, + Tuple4( + account, + index + j, + root, + type, + ), + ); + String? address; + switch (type) { + case DerivePathType.bip44: + address = P2PKH( + data: PaymentData(pubkey: node.publicKey), + network: _network) + .data + .address!; + break; + case DerivePathType.bip49: + address = P2SH( + data: PaymentData( + redeem: P2WPKH( + data: PaymentData(pubkey: node.publicKey), + network: _network, + overridePrefix: namecoin.bech32!) + .data), + network: _network) + .data + .address!; + break; + case DerivePathType.bip84: + address = P2WPKH( + network: _network, + data: PaymentData(pubkey: node.publicKey), + overridePrefix: namecoin.bech32!) + .data + .address!; + break; + default: + throw Exception("No Path type $type exists"); + } + receivingNodes.addAll({ + "${_id}_$j": { + "node": node, + "address": address, + } + }); + txCountCallArgs.addAll({ + "${_id}_$j": address, + }); + } + + // get address tx counts + final counts = await _getBatchTxCount(addresses: txCountCallArgs); + + // check and add appropriate addresses + for (int k = 0; k < txCountBatchSize; k++) { + int count = counts["${_id}_$k"]!; + if (count > 0) { + final node = receivingNodes["${_id}_$k"]; + // add address to array + addressArray.add(node["address"] as String); + iterationsAddressArray.add(node["address"] as String); + // set current index + returningIndex = index + k; + // reset counter + gapCounter = 0; + // add info to derivations + derivations[node["address"] as String] = { + "pubKey": Format.uint8listToString( + (node["node"] as bip32.BIP32).publicKey), + "wif": (node["node"] as bip32.BIP32).toWIF(), + }; + } + + // increase counter when no tx history found + if (count == 0) { + gapCounter++; + } + } + // cache all the transactions while waiting for the current function to finish. + unawaited(getTransactionCacheEarly(iterationsAddressArray)); + } + return { + "addressArray": addressArray, + "index": returningIndex, + "derivations": derivations + }; + } + + Future getTransactionCacheEarly(List allAddresses) async { + try { + final List> allTxHashes = + await _fetchHistory(allAddresses); + for (final txHash in allTxHashes) { + try { + unawaited(cachedElectrumXClient.getTransaction( + txHash: txHash["tx_hash"] as String, + verbose: true, + coin: coin, + )); + } catch (e) { + continue; + } + } + } catch (e) { + // + } + } + + Future _recoverWalletFromBIP32SeedPhrase({ + required String mnemonic, + int maxUnusedAddressGap = 20, + int maxNumberOfIndexesToCheck = 1000, + }) async { + longMutex = true; + + Map> p2pkhReceiveDerivations = {}; + Map> p2shReceiveDerivations = {}; + Map> p2wpkhReceiveDerivations = {}; + Map> p2pkhChangeDerivations = {}; + Map> p2shChangeDerivations = {}; + Map> p2wpkhChangeDerivations = {}; + + final root = await compute(getBip32RootWrapper, Tuple2(mnemonic, _network)); + + List p2pkhReceiveAddressArray = []; + List p2shReceiveAddressArray = []; + List p2wpkhReceiveAddressArray = []; + int p2pkhReceiveIndex = -1; + int p2shReceiveIndex = -1; + int p2wpkhReceiveIndex = -1; + + List p2pkhChangeAddressArray = []; + List p2shChangeAddressArray = []; + List p2wpkhChangeAddressArray = []; + int p2pkhChangeIndex = -1; + int p2shChangeIndex = -1; + int p2wpkhChangeIndex = -1; + + // actual size is 36 due to p2pkh, p2sh, and p2wpkh so 12x3 + const txCountBatchSize = 12; + + try { + // receiving addresses + Logging.instance + .log("checking receiving addresses...", level: LogLevel.Info); + final resultReceive44 = _checkGaps(maxNumberOfIndexesToCheck, + maxUnusedAddressGap, txCountBatchSize, root, DerivePathType.bip44, 0); + + final resultReceive49 = _checkGaps(maxNumberOfIndexesToCheck, + maxUnusedAddressGap, txCountBatchSize, root, DerivePathType.bip49, 0); + + final resultReceive84 = _checkGaps(maxNumberOfIndexesToCheck, + maxUnusedAddressGap, txCountBatchSize, root, DerivePathType.bip84, 0); + + Logging.instance + .log("checking change addresses...", level: LogLevel.Info); + // change addresses + final resultChange44 = _checkGaps(maxNumberOfIndexesToCheck, + maxUnusedAddressGap, txCountBatchSize, root, DerivePathType.bip44, 1); + + final resultChange49 = _checkGaps(maxNumberOfIndexesToCheck, + maxUnusedAddressGap, txCountBatchSize, root, DerivePathType.bip49, 1); + + final resultChange84 = _checkGaps(maxNumberOfIndexesToCheck, + maxUnusedAddressGap, txCountBatchSize, root, DerivePathType.bip84, 1); + + await Future.wait([ + resultReceive44, + resultReceive49, + resultReceive84, + resultChange44, + resultChange49, + resultChange84 + ]); + + p2pkhReceiveAddressArray = + (await resultReceive44)['addressArray'] as List; + p2pkhReceiveIndex = (await resultReceive44)['index'] as int; + p2pkhReceiveDerivations = (await resultReceive44)['derivations'] + as Map>; + + p2shReceiveAddressArray = + (await resultReceive49)['addressArray'] as List; + p2shReceiveIndex = (await resultReceive49)['index'] as int; + p2shReceiveDerivations = (await resultReceive49)['derivations'] + as Map>; + + p2wpkhReceiveAddressArray = + (await resultReceive84)['addressArray'] as List; + p2wpkhReceiveIndex = (await resultReceive84)['index'] as int; + p2wpkhReceiveDerivations = (await resultReceive84)['derivations'] + as Map>; + + p2pkhChangeAddressArray = + (await resultChange44)['addressArray'] as List; + p2pkhChangeIndex = (await resultChange44)['index'] as int; + p2pkhChangeDerivations = (await resultChange44)['derivations'] + as Map>; + + p2shChangeAddressArray = + (await resultChange49)['addressArray'] as List; + p2shChangeIndex = (await resultChange49)['index'] as int; + p2shChangeDerivations = (await resultChange49)['derivations'] + as Map>; + + p2wpkhChangeAddressArray = + (await resultChange84)['addressArray'] as List; + p2wpkhChangeIndex = (await resultChange84)['index'] as int; + p2wpkhChangeDerivations = (await resultChange84)['derivations'] + as Map>; + + // save the derivations (if any) + if (p2pkhReceiveDerivations.isNotEmpty) { + await addDerivations( + chain: 0, + derivePathType: DerivePathType.bip44, + derivationsToAdd: p2pkhReceiveDerivations); + } + if (p2shReceiveDerivations.isNotEmpty) { + await addDerivations( + chain: 0, + derivePathType: DerivePathType.bip49, + derivationsToAdd: p2shReceiveDerivations); + } + if (p2wpkhReceiveDerivations.isNotEmpty) { + await addDerivations( + chain: 0, + derivePathType: DerivePathType.bip84, + derivationsToAdd: p2wpkhReceiveDerivations); + } + if (p2pkhChangeDerivations.isNotEmpty) { + await addDerivations( + chain: 1, + derivePathType: DerivePathType.bip44, + derivationsToAdd: p2pkhChangeDerivations); + } + if (p2shChangeDerivations.isNotEmpty) { + await addDerivations( + chain: 1, + derivePathType: DerivePathType.bip49, + derivationsToAdd: p2shChangeDerivations); + } + if (p2wpkhChangeDerivations.isNotEmpty) { + await addDerivations( + chain: 1, + derivePathType: DerivePathType.bip84, + derivationsToAdd: p2wpkhChangeDerivations); + } + + // If restoring a wallet that never received any funds, then set receivingArray manually + // If we didn't do this, it'd store an empty array + if (p2pkhReceiveIndex == -1) { + final address = + await _generateAddressForChain(0, 0, DerivePathType.bip44); + p2pkhReceiveAddressArray.add(address); + p2pkhReceiveIndex = 0; + } + if (p2shReceiveIndex == -1) { + final address = + await _generateAddressForChain(0, 0, DerivePathType.bip49); + p2shReceiveAddressArray.add(address); + p2shReceiveIndex = 0; + } + if (p2wpkhReceiveIndex == -1) { + final address = + await _generateAddressForChain(0, 0, DerivePathType.bip84); + p2wpkhReceiveAddressArray.add(address); + p2wpkhReceiveIndex = 0; + } + + // If restoring a wallet that never sent any funds with change, then set changeArray + // manually. If we didn't do this, it'd store an empty array. + if (p2pkhChangeIndex == -1) { + final address = + await _generateAddressForChain(1, 0, DerivePathType.bip44); + p2pkhChangeAddressArray.add(address); + p2pkhChangeIndex = 0; + } + if (p2shChangeIndex == -1) { + final address = + await _generateAddressForChain(1, 0, DerivePathType.bip49); + p2shChangeAddressArray.add(address); + p2shChangeIndex = 0; + } + if (p2wpkhChangeIndex == -1) { + final address = + await _generateAddressForChain(1, 0, DerivePathType.bip84); + p2wpkhChangeAddressArray.add(address); + p2wpkhChangeIndex = 0; + } + + await DB.instance.put( + boxName: walletId, + key: 'receivingAddressesP2WPKH', + value: p2wpkhReceiveAddressArray); + await DB.instance.put( + boxName: walletId, + key: 'changeAddressesP2WPKH', + value: p2wpkhChangeAddressArray); + await DB.instance.put( + boxName: walletId, + key: 'receivingAddressesP2PKH', + value: p2pkhReceiveAddressArray); + await DB.instance.put( + boxName: walletId, + key: 'changeAddressesP2PKH', + value: p2pkhChangeAddressArray); + await DB.instance.put( + boxName: walletId, + key: 'receivingAddressesP2SH', + value: p2shReceiveAddressArray); + await DB.instance.put( + boxName: walletId, + key: 'changeAddressesP2SH', + value: p2shChangeAddressArray); + await DB.instance.put( + boxName: walletId, + key: 'receivingIndexP2WPKH', + value: p2wpkhReceiveIndex); + await DB.instance.put( + boxName: walletId, + key: 'changeIndexP2WPKH', + value: p2wpkhChangeIndex); + await DB.instance.put( + boxName: walletId, key: 'changeIndexP2PKH', value: p2pkhChangeIndex); + await DB.instance.put( + boxName: walletId, + key: 'receivingIndexP2PKH', + value: p2pkhReceiveIndex); + await DB.instance.put( + boxName: walletId, + key: 'receivingIndexP2SH', + value: p2shReceiveIndex); + await DB.instance.put( + boxName: walletId, key: 'changeIndexP2SH', value: p2shChangeIndex); + await DB.instance + .put(boxName: walletId, key: "id", value: _walletId); + await DB.instance + .put(boxName: walletId, key: "isFavorite", value: false); + + longMutex = false; + } catch (e, s) { + Logging.instance.log( + "Exception rethrown from _recoverWalletFromBIP32SeedPhrase(): $e\n$s", + level: LogLevel.Error); + + longMutex = false; + rethrow; + } + } + + Future refreshIfThereIsNewData() async { + if (longMutex) return false; + if (_hasCalledExit) return false; + Logging.instance.log("refreshIfThereIsNewData", level: LogLevel.Info); + + try { + bool needsRefresh = false; + Set txnsToCheck = {}; + + for (final String txid in txTracker.pendings) { + if (!txTracker.wasNotifiedConfirmed(txid)) { + txnsToCheck.add(txid); + } + } + + for (String txid in txnsToCheck) { + final txn = await electrumXClient.getTransaction(txHash: txid); + int confirmations = txn["confirmations"] as int? ?? 0; + bool isUnconfirmed = confirmations < MINIMUM_CONFIRMATIONS; + if (!isUnconfirmed) { + // unconfirmedTxs = {}; + needsRefresh = true; + break; + } + } + if (!needsRefresh) { + var allOwnAddresses = await _fetchAllOwnAddresses(); + List> allTxs = + await _fetchHistory(allOwnAddresses); + final txData = await transactionData; + for (Map transaction in allTxs) { + if (txData.findTransaction(transaction['tx_hash'] as String) == + null) { + Logging.instance.log( + " txid not found in address history already ${transaction['tx_hash']}", + level: LogLevel.Info); + needsRefresh = true; + break; + } + } + } + return needsRefresh; + } catch (e, s) { + Logging.instance.log( + "Exception caught in refreshIfThereIsNewData: $e\n$s", + level: LogLevel.Error); + rethrow; + } + } + + Future getAllTxsToWatch( + TransactionData txData, + ) async { + if (_hasCalledExit) return; + List unconfirmedTxnsToNotifyPending = []; + List unconfirmedTxnsToNotifyConfirmed = []; + + for (final chunk in txData.txChunks) { + for (final tx in chunk.transactions) { + if (tx.confirmedStatus) { + // get all transactions that were notified as pending but not as confirmed + if (txTracker.wasNotifiedPending(tx.txid) && + !txTracker.wasNotifiedConfirmed(tx.txid)) { + unconfirmedTxnsToNotifyConfirmed.add(tx); + } + } else { + // get all transactions that were not notified as pending yet + if (!txTracker.wasNotifiedPending(tx.txid)) { + unconfirmedTxnsToNotifyPending.add(tx); + } + } + } + } + + // notify on unconfirmed transactions + for (final tx in unconfirmedTxnsToNotifyPending) { + if (tx.txType == "Received") { + unawaited(NotificationApi.showNotification( + title: "Incoming transaction", + body: walletName, + walletId: walletId, + iconAssetName: Assets.svg.iconFor(coin: coin), + date: DateTime.fromMillisecondsSinceEpoch(tx.timestamp * 1000), + shouldWatchForUpdates: tx.confirmations < MINIMUM_CONFIRMATIONS, + coinName: coin.name, + txid: tx.txid, + confirmations: tx.confirmations, + requiredConfirmations: MINIMUM_CONFIRMATIONS, + )); + await txTracker.addNotifiedPending(tx.txid); + } else if (tx.txType == "Sent") { + unawaited(NotificationApi.showNotification( + title: "Sending transaction", + body: walletName, + walletId: walletId, + iconAssetName: Assets.svg.iconFor(coin: coin), + date: DateTime.fromMillisecondsSinceEpoch(tx.timestamp * 1000), + shouldWatchForUpdates: tx.confirmations < MINIMUM_CONFIRMATIONS, + coinName: coin.name, + txid: tx.txid, + confirmations: tx.confirmations, + requiredConfirmations: MINIMUM_CONFIRMATIONS, + )); + await txTracker.addNotifiedPending(tx.txid); + } + } + + // notify on confirmed + for (final tx in unconfirmedTxnsToNotifyConfirmed) { + if (tx.txType == "Received") { + unawaited(NotificationApi.showNotification( + title: "Incoming transaction confirmed", + body: walletName, + walletId: walletId, + iconAssetName: Assets.svg.iconFor(coin: coin), + date: DateTime.fromMillisecondsSinceEpoch(tx.timestamp * 1000), + shouldWatchForUpdates: false, + coinName: coin.name, + )); + await txTracker.addNotifiedConfirmed(tx.txid); + } else if (tx.txType == "Sent") { + unawaited(NotificationApi.showNotification( + title: "Outgoing transaction confirmed", + body: walletName, + walletId: walletId, + iconAssetName: Assets.svg.iconFor(coin: coin), + date: DateTime.fromMillisecondsSinceEpoch(tx.timestamp * 1000), + shouldWatchForUpdates: false, + coinName: coin.name, + )); + await txTracker.addNotifiedConfirmed(tx.txid); + } + } + } + + bool _shouldAutoSync = false; + + @override + bool get shouldAutoSync => _shouldAutoSync; + + @override + set shouldAutoSync(bool shouldAutoSync) { + if (_shouldAutoSync != shouldAutoSync) { + _shouldAutoSync = shouldAutoSync; + if (!shouldAutoSync) { + timer?.cancel(); + timer = null; + stopNetworkAlivePinging(); + } else { + startNetworkAlivePinging(); + refresh(); + } + } + } + + @override + bool get isRefreshing => refreshMutex; + + bool refreshMutex = false; + + //TODO Show percentages properly/more consistently + /// Refreshes display data for the wallet + @override + Future refresh() async { + if (refreshMutex) { + Logging.instance.log("$walletId $walletName refreshMutex denied", + level: LogLevel.Info); + return; + } else { + refreshMutex = true; + } + + try { + GlobalEventBus.instance.fire( + WalletSyncStatusChangedEvent( + WalletSyncStatus.syncing, + walletId, + coin, + ), + ); + + GlobalEventBus.instance.fire(RefreshPercentChangedEvent(0.0, walletId)); + + GlobalEventBus.instance.fire(RefreshPercentChangedEvent(0.1, walletId)); + + final currentHeight = await chainHeight; + const storedHeight = 1; //await storedChainHeight; + + Logging.instance + .log("chain height: $currentHeight", level: LogLevel.Info); + Logging.instance + .log("cached height: $storedHeight", level: LogLevel.Info); + + if (currentHeight != storedHeight) { + if (currentHeight != -1) { + // -1 failed to fetch current height + unawaited(updateStoredChainHeight(newHeight: currentHeight)); + } + + GlobalEventBus.instance.fire(RefreshPercentChangedEvent(0.2, walletId)); + final changeAddressForTransactions = + _checkChangeAddressForTransactions(DerivePathType.bip84); + + GlobalEventBus.instance.fire(RefreshPercentChangedEvent(0.3, walletId)); + final currentReceivingAddressesForTransactions = + _checkCurrentReceivingAddressesForTransactions(); + + final newTxData = _fetchTransactionData(); + GlobalEventBus.instance + .fire(RefreshPercentChangedEvent(0.50, walletId)); + + final newUtxoData = _fetchUtxoData(); + final feeObj = _getFees(); + GlobalEventBus.instance + .fire(RefreshPercentChangedEvent(0.60, walletId)); + + _transactionData = Future(() => newTxData); + + GlobalEventBus.instance + .fire(RefreshPercentChangedEvent(0.70, walletId)); + _feeObject = Future(() => feeObj); + _utxoData = Future(() => newUtxoData); + GlobalEventBus.instance + .fire(RefreshPercentChangedEvent(0.80, walletId)); + + final allTxsToWatch = getAllTxsToWatch(await newTxData); + await Future.wait([ + newTxData, + changeAddressForTransactions, + currentReceivingAddressesForTransactions, + newUtxoData, + feeObj, + allTxsToWatch, + ]); + GlobalEventBus.instance + .fire(RefreshPercentChangedEvent(0.90, walletId)); + } + + refreshMutex = false; + GlobalEventBus.instance.fire(RefreshPercentChangedEvent(1.0, walletId)); + GlobalEventBus.instance.fire( + WalletSyncStatusChangedEvent( + WalletSyncStatus.synced, + walletId, + coin, + ), + ); + + if (shouldAutoSync) { + timer ??= Timer.periodic(const Duration(seconds: 30), (timer) async { + Logging.instance.log( + "Periodic refresh check for $walletId $walletName in object instance: $hashCode", + level: LogLevel.Info); + // chain height check currently broken + // if ((await chainHeight) != (await storedChainHeight)) { + if (await refreshIfThereIsNewData()) { + await refresh(); + GlobalEventBus.instance.fire(UpdatedInBackgroundEvent( + "New data found in $walletId $walletName in background!", + walletId)); + } + // } + }); + } + } catch (error, strace) { + refreshMutex = false; + GlobalEventBus.instance.fire( + NodeConnectionStatusChangedEvent( + NodeConnectionStatus.disconnected, + walletId, + coin, + ), + ); + GlobalEventBus.instance.fire( + WalletSyncStatusChangedEvent( + WalletSyncStatus.unableToSync, + walletId, + coin, + ), + ); + Logging.instance.log( + "Caught exception in refreshWalletData(): $error\n$strace", + level: LogLevel.Error); + } + } + + @override + Future> prepareSend({ + required String address, + required int satoshiAmount, + Map? args, + }) async { + try { + final feeRateType = args?["feeRate"]; + final feeRateAmount = args?["feeRateAmount"]; + if (feeRateType is FeeRateType || feeRateAmount is int) { + late final int rate; + if (feeRateType is FeeRateType) { + int fee = 0; + final feeObject = await fees; + switch (feeRateType) { + case FeeRateType.fast: + fee = feeObject.fast; + break; + case FeeRateType.average: + fee = feeObject.medium; + break; + case FeeRateType.slow: + fee = feeObject.slow; + break; + } + rate = fee; + } else { + rate = feeRateAmount as int; + } + + // check for send all + bool isSendAll = false; + final balance = Format.decimalAmountToSatoshis(await availableBalance); + if (satoshiAmount == balance) { + isSendAll = true; + } + + final txData = + await coinSelection(satoshiAmount, rate, address, isSendAll); + + Logging.instance.log("prepare send: $txData", level: LogLevel.Info); + try { + if (txData is int) { + switch (txData) { + case 1: + throw Exception("Insufficient balance!"); + case 2: + throw Exception( + "Insufficient funds to pay for transaction fee!"); + default: + throw Exception("Transaction failed with error code $txData"); + } + } else { + final hex = txData["hex"]; + + if (hex is String) { + final fee = txData["fee"] as int; + final vSize = txData["vSize"] as int; + + Logging.instance + .log("prepared txHex: $hex", level: LogLevel.Info); + 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 txData as Map; + } else { + throw Exception("prepared hex is not a String!!!"); + } + } + } catch (e, s) { + Logging.instance.log("Exception rethrown from prepareSend(): $e\n$s", + level: LogLevel.Error); + rethrow; + } + } else { + throw ArgumentError("Invalid fee rate argument provided!"); + } + } catch (e, s) { + Logging.instance.log("Exception rethrown from prepareSend(): $e\n$s", + level: LogLevel.Error); + rethrow; + } + } + + @override + Future confirmSend({required Map txData}) async { + try { + Logging.instance.log("confirmSend txData: $txData", level: LogLevel.Info); + + final hex = txData["hex"] as String; + + final txHash = await _electrumXClient.broadcastTransaction(rawTx: hex); + Logging.instance.log("Sent txHash: $txHash", level: LogLevel.Info); + + return txHash; + } catch (e, s) { + Logging.instance.log("Exception rethrown from confirmSend(): $e\n$s", + level: LogLevel.Error); + rethrow; + } + } + + @override + Future send({ + required String toAddress, + required int amount, + Map args = const {}, + }) async { + try { + final txData = await prepareSend( + address: toAddress, satoshiAmount: amount, args: args); + final txHash = await confirmSend(txData: txData); + return txHash; + } catch (e, s) { + Logging.instance + .log("Exception rethrown from send(): $e\n$s", level: LogLevel.Error); + rethrow; + } + } + + @override + Future testNetworkConnection() async { + try { + final result = await _electrumXClient.ping(); + return result; + } catch (_) { + return false; + } + } + + Timer? _networkAliveTimer; + + void startNetworkAlivePinging() { + // call once on start right away + _periodicPingCheck(); + + // then periodically check + _networkAliveTimer = Timer.periodic( + Constants.networkAliveTimerDuration, + (_) async { + _periodicPingCheck(); + }, + ); + } + + void _periodicPingCheck() async { + bool hasNetwork = await testNetworkConnection(); + _isConnected = hasNetwork; + if (_isConnected != hasNetwork) { + NodeConnectionStatus status = hasNetwork + ? NodeConnectionStatus.connected + : NodeConnectionStatus.disconnected; + GlobalEventBus.instance + .fire(NodeConnectionStatusChangedEvent(status, walletId, coin)); + } + } + + void stopNetworkAlivePinging() { + _networkAliveTimer?.cancel(); + _networkAliveTimer = null; + } + + bool _isConnected = false; + + @override + bool get isConnected => _isConnected; + + @override + Future initializeNew() async { + Logging.instance + .log("Generating new ${coin.prettyName} wallet.", level: LogLevel.Info); + + if ((DB.instance.get(boxName: walletId, key: "id")) != null) { + throw Exception( + "Attempted to initialize a new wallet using an existing wallet ID!"); + } + + await _prefs.init(); + try { + await _generateNewWallet(); + } catch (e, s) { + Logging.instance.log("Exception rethrown from initializeNew(): $e\n$s", + level: LogLevel.Fatal); + rethrow; + } + await Future.wait([ + DB.instance.put(boxName: walletId, key: "id", value: walletId), + DB.instance + .put(boxName: walletId, key: "isFavorite", value: false), + ]); + } + + @override + Future initializeExisting() async { + Logging.instance.log("Opening existing ${coin.prettyName} wallet.", + level: LogLevel.Info); + + if ((DB.instance.get(boxName: walletId, key: "id")) == null) { + throw Exception( + "Attempted to initialize an existing wallet using an unknown wallet ID!"); + } + await _prefs.init(); + final data = + DB.instance.get(boxName: walletId, key: "latest_tx_model") + as TransactionData?; + if (data != null) { + _transactionData = Future(() => data); + } + } + + @override + Future get transactionData => + _transactionData ??= _fetchTransactionData(); + Future? _transactionData; + + @override + bool validateAddress(String address) { + return Address.validateAddress(address, _network, namecoin.bech32!); + } + + @override + String get walletId => _walletId; + late String _walletId; + + @override + String get walletName => _walletName; + late String _walletName; + + // setter for updating on rename + @override + set walletName(String newName) => _walletName = newName; + + late ElectrumX _electrumXClient; + + ElectrumX get electrumXClient => _electrumXClient; + + late CachedElectrumX _cachedElectrumXClient; + + CachedElectrumX get cachedElectrumXClient => _cachedElectrumXClient; + + late FlutterSecureStorageInterface _secureStore; + + late PriceAPI _priceAPI; + + NamecoinWallet({ + required String walletId, + required String walletName, + required Coin coin, + required ElectrumX client, + required CachedElectrumX cachedClient, + required TransactionNotificationTracker tracker, + PriceAPI? priceAPI, + FlutterSecureStorageInterface? secureStore, + }) { + txTracker = tracker; + _walletId = walletId; + _walletName = walletName; + _coin = coin; + _electrumXClient = client; + _cachedElectrumXClient = cachedClient; + + _priceAPI = priceAPI ?? PriceAPI(Client()); + _secureStore = + secureStore ?? const SecureStorageWrapper(FlutterSecureStorage()); + } + + @override + Future updateNode(bool shouldRefresh) async { + final failovers = NodeService() + .failoverNodesFor(coin: coin) + .map((e) => ElectrumXNode( + address: e.host, + port: e.port, + name: e.name, + id: e.id, + useSSL: e.useSSL, + )) + .toList(); + final newNode = await getCurrentNode(); + _cachedElectrumXClient = CachedElectrumX.from( + node: newNode, + prefs: _prefs, + failovers: failovers, + ); + _electrumXClient = ElectrumX.from( + node: newNode, + prefs: _prefs, + failovers: failovers, + ); + + if (shouldRefresh) { + unawaited(refresh()); + } + } + + Future> _getMnemonicList() async { + final mnemonicString = + await _secureStore.read(key: '${_walletId}_mnemonic'); + if (mnemonicString == null) { + return []; + } + final List data = mnemonicString.split(' '); + return data; + } + + Future getCurrentNode() async { + final node = NodeService().getPrimaryNodeFor(coin: coin) ?? + DefaultNodes.getNodeFor(coin); + + return ElectrumXNode( + address: node.host, + port: node.port, + name: node.name, + useSSL: node.useSSL, + id: node.id, + ); + } + + Future> _fetchAllOwnAddresses() async { + final List allAddresses = []; + final receivingAddresses = DB.instance.get( + boxName: walletId, key: 'receivingAddressesP2WPKH') as List; + final changeAddresses = DB.instance.get( + boxName: walletId, key: 'changeAddressesP2WPKH') as List; + final receivingAddressesP2PKH = DB.instance.get( + boxName: walletId, key: 'receivingAddressesP2PKH') as List; + final changeAddressesP2PKH = + DB.instance.get(boxName: walletId, key: 'changeAddressesP2PKH') + as List; + final receivingAddressesP2SH = DB.instance.get( + boxName: walletId, key: 'receivingAddressesP2SH') as List; + final changeAddressesP2SH = + DB.instance.get(boxName: walletId, key: 'changeAddressesP2SH') + as List; + + for (var i = 0; i < receivingAddresses.length; i++) { + if (!allAddresses.contains(receivingAddresses[i])) { + allAddresses.add(receivingAddresses[i] as String); + } + } + for (var i = 0; i < changeAddresses.length; i++) { + if (!allAddresses.contains(changeAddresses[i])) { + allAddresses.add(changeAddresses[i] as String); + } + } + for (var i = 0; i < receivingAddressesP2PKH.length; i++) { + if (!allAddresses.contains(receivingAddressesP2PKH[i])) { + allAddresses.add(receivingAddressesP2PKH[i] as String); + } + } + for (var i = 0; i < changeAddressesP2PKH.length; i++) { + if (!allAddresses.contains(changeAddressesP2PKH[i])) { + allAddresses.add(changeAddressesP2PKH[i] as String); + } + } + for (var i = 0; i < receivingAddressesP2SH.length; i++) { + if (!allAddresses.contains(receivingAddressesP2SH[i])) { + allAddresses.add(receivingAddressesP2SH[i] as String); + } + } + for (var i = 0; i < changeAddressesP2SH.length; i++) { + if (!allAddresses.contains(changeAddressesP2SH[i])) { + allAddresses.add(changeAddressesP2SH[i] as String); + } + } + return allAddresses; + } + + Future _getFees() async { + try { + //TODO adjust numbers for different speeds? + const int f = 1, m = 5, s = 20; + + final fast = await electrumXClient.estimateFee(blocks: f); + final medium = await electrumXClient.estimateFee(blocks: m); + final slow = await electrumXClient.estimateFee(blocks: s); + + final feeObject = FeeObject( + numberOfBlocksFast: f, + numberOfBlocksAverage: m, + numberOfBlocksSlow: s, + fast: Format.decimalAmountToSatoshis(fast), + medium: Format.decimalAmountToSatoshis(medium), + slow: Format.decimalAmountToSatoshis(slow), + ); + + Logging.instance.log("fetched fees: $feeObject", level: LogLevel.Info); + return feeObject; + } catch (e) { + Logging.instance + .log("Exception rethrown from _getFees(): $e", level: LogLevel.Error); + rethrow; + } + } + + Future _generateNewWallet() async { + Logging.instance + .log("IS_INTEGRATION_TEST: $integrationTestFlag", level: LogLevel.Info); + if (!integrationTestFlag) { + final features = await electrumXClient.getServerFeatures(); + Logging.instance.log("features: $features", level: LogLevel.Info); + switch (coin) { + case Coin.namecoin: + if (features['genesis_hash'] != GENESIS_HASH_MAINNET) { + throw Exception("genesis hash does not match main net!"); + } + break; + default: + throw Exception( + "Attempted to generate a NamecoinWallet using a non namecoin coin type: ${coin.name}"); + } + } + + // this should never fail + if ((await _secureStore.read(key: '${_walletId}_mnemonic')) != null) { + throw Exception( + "Attempted to overwrite mnemonic on generate new wallet!"); + } + await _secureStore.write( + key: '${_walletId}_mnemonic', + value: bip39.generateMnemonic(strength: 256)); + + // Set relevant indexes + await DB.instance + .put(boxName: walletId, key: "receivingIndexP2WPKH", value: 0); + await DB.instance + .put(boxName: walletId, key: "changeIndexP2WPKH", value: 0); + await DB.instance + .put(boxName: walletId, key: "receivingIndexP2PKH", value: 0); + await DB.instance + .put(boxName: walletId, key: "changeIndexP2PKH", value: 0); + await DB.instance + .put(boxName: walletId, key: "receivingIndexP2SH", value: 0); + await DB.instance + .put(boxName: walletId, key: "changeIndexP2SH", value: 0); + await DB.instance.put( + boxName: walletId, + key: 'blocked_tx_hashes', + value: ["0xdefault"], + ); // A list of transaction hashes to represent frozen utxos in wallet + // initialize address book entries + await DB.instance.put( + boxName: walletId, + key: 'addressBookEntries', + value: {}); + + // Generate and add addresses to relevant arrays + await Future.wait([ + // P2WPKH + _generateAddressForChain(0, 0, DerivePathType.bip84).then( + (initialReceivingAddressP2WPKH) { + _addToAddressesArrayForChain( + initialReceivingAddressP2WPKH, 0, DerivePathType.bip84); + _currentReceivingAddress = + Future(() => initialReceivingAddressP2WPKH); + }, + ), + _generateAddressForChain(1, 0, DerivePathType.bip84).then( + (initialChangeAddressP2WPKH) => _addToAddressesArrayForChain( + initialChangeAddressP2WPKH, + 1, + DerivePathType.bip84, + ), + ), + + // P2PKH + _generateAddressForChain(0, 0, DerivePathType.bip44).then( + (initialReceivingAddressP2PKH) { + _addToAddressesArrayForChain( + initialReceivingAddressP2PKH, 0, DerivePathType.bip44); + _currentReceivingAddressP2PKH = + Future(() => initialReceivingAddressP2PKH); + }, + ), + _generateAddressForChain(1, 0, DerivePathType.bip44).then( + (initialChangeAddressP2PKH) => _addToAddressesArrayForChain( + initialChangeAddressP2PKH, + 1, + DerivePathType.bip44, + ), + ), + + // P2SH + _generateAddressForChain(0, 0, DerivePathType.bip49).then( + (initialReceivingAddressP2SH) { + _addToAddressesArrayForChain( + initialReceivingAddressP2SH, 0, DerivePathType.bip49); + _currentReceivingAddressP2SH = + Future(() => initialReceivingAddressP2SH); + }, + ), + _generateAddressForChain(1, 0, DerivePathType.bip49).then( + (initialChangeAddressP2SH) => _addToAddressesArrayForChain( + initialChangeAddressP2SH, + 1, + DerivePathType.bip49, + ), + ), + ]); + + // // P2PKH + // _generateAddressForChain(0, 0, DerivePathType.bip44).then( + // (initialReceivingAddressP2PKH) { + // _addToAddressesArrayForChain( + // initialReceivingAddressP2PKH, 0, DerivePathType.bip44); + // this._currentReceivingAddressP2PKH = + // Future(() => initialReceivingAddressP2PKH); + // }, + // ); + // _generateAddressForChain(1, 0, DerivePathType.bip44) + // .then((initialChangeAddressP2PKH) => _addToAddressesArrayForChain( + // initialChangeAddressP2PKH, + // 1, + // DerivePathType.bip44, + // )); + // + // // P2SH + // _generateAddressForChain(0, 0, DerivePathType.bip49).then( + // (initialReceivingAddressP2SH) { + // _addToAddressesArrayForChain( + // initialReceivingAddressP2SH, 0, DerivePathType.bip49); + // this._currentReceivingAddressP2SH = + // Future(() => initialReceivingAddressP2SH); + // }, + // ); + // _generateAddressForChain(1, 0, DerivePathType.bip49) + // .then((initialChangeAddressP2SH) => _addToAddressesArrayForChain( + // initialChangeAddressP2SH, + // 1, + // DerivePathType.bip49, + // )); + + Logging.instance.log("_generateNewWalletFinished", level: LogLevel.Info); + } + + /// Generates a new internal or external chain address for the wallet using a BIP84, BIP44, or BIP49 derivation path. + /// [chain] - Use 0 for receiving (external), 1 for change (internal). Should not be any other value! + /// [index] - This can be any integer >= 0 + Future _generateAddressForChain( + int chain, + int index, + DerivePathType derivePathType, + ) async { + final mnemonic = await _secureStore.read(key: '${_walletId}_mnemonic'); + final node = await compute( + getBip32NodeWrapper, + Tuple5( + chain, + index, + mnemonic!, + _network, + derivePathType, + ), + ); + final data = PaymentData(pubkey: node.publicKey); + String address; + + switch (derivePathType) { + case DerivePathType.bip44: + address = P2PKH(data: data, network: _network).data.address!; + break; + case DerivePathType.bip49: + address = P2SH( + data: PaymentData( + redeem: P2WPKH( + data: data, + network: _network, + overridePrefix: namecoin.bech32!) + .data), + network: _network) + .data + .address!; + break; + case DerivePathType.bip84: + address = P2WPKH( + network: _network, data: data, overridePrefix: namecoin.bech32!) + .data + .address!; + break; + } + + // add generated address & info to derivations + await addDerivation( + chain: chain, + address: address, + pubKey: Format.uint8listToString(node.publicKey), + wif: node.toWIF(), + derivePathType: derivePathType, + ); + + return address; + } + + /// Increases the index for either the internal or external chain, depending on [chain]. + /// [chain] - Use 0 for receiving (external), 1 for change (internal). Should not be any other value! + Future _incrementAddressIndexForChain( + int chain, DerivePathType derivePathType) async { + // Here we assume chain == 1 if it isn't 0 + String indexKey = chain == 0 ? "receivingIndex" : "changeIndex"; + switch (derivePathType) { + case DerivePathType.bip44: + indexKey += "P2PKH"; + break; + case DerivePathType.bip49: + indexKey += "P2SH"; + break; + case DerivePathType.bip84: + indexKey += "P2WPKH"; + break; + } + + final newIndex = + (DB.instance.get(boxName: walletId, key: indexKey)) + 1; + await DB.instance + .put(boxName: walletId, key: indexKey, value: newIndex); + } + + /// Adds [address] to the relevant chain's address array, which is determined by [chain]. + /// [address] - Expects a standard native segwit address + /// [chain] - Use 0 for receiving (external), 1 for change (internal). Should not be any other value! + Future _addToAddressesArrayForChain( + String address, int chain, DerivePathType derivePathType) async { + String chainArray = ''; + if (chain == 0) { + chainArray = 'receivingAddresses'; + } else { + chainArray = 'changeAddresses'; + } + switch (derivePathType) { + case DerivePathType.bip44: + chainArray += "P2PKH"; + break; + case DerivePathType.bip49: + chainArray += "P2SH"; + break; + case DerivePathType.bip84: + chainArray += "P2WPKH"; + break; + } + + final addressArray = + DB.instance.get(boxName: walletId, key: chainArray); + if (addressArray == null) { + Logging.instance.log( + 'Attempting to add the following to $chainArray array for chain $chain:${[ + address + ]}', + level: LogLevel.Info); + await DB.instance + .put(boxName: walletId, key: chainArray, value: [address]); + } else { + // Make a deep copy of the existing list + final List newArray = []; + addressArray + .forEach((dynamic _address) => newArray.add(_address as String)); + newArray.add(address); // Add the address passed into the method + await DB.instance + .put(boxName: walletId, key: chainArray, value: newArray); + } + } + + /// Returns the latest receiving/change (external/internal) address for the wallet depending on [chain] + /// and + /// [chain] - Use 0 for receiving (external), 1 for change (internal). Should not be any other value! + Future _getCurrentAddressForChain( + int chain, DerivePathType derivePathType) async { + // Here, we assume that chain == 1 if it isn't 0 + String arrayKey = chain == 0 ? "receivingAddresses" : "changeAddresses"; + switch (derivePathType) { + case DerivePathType.bip44: + arrayKey += "P2PKH"; + break; + case DerivePathType.bip49: + arrayKey += "P2SH"; + break; + case DerivePathType.bip84: + arrayKey += "P2WPKH"; + break; + } + final internalChainArray = + DB.instance.get(boxName: walletId, key: arrayKey); + return internalChainArray.last as String; + } + + String _buildDerivationStorageKey({ + required int chain, + required DerivePathType derivePathType, + }) { + String key; + String chainId = chain == 0 ? "receive" : "change"; + switch (derivePathType) { + case DerivePathType.bip44: + key = "${walletId}_${chainId}DerivationsP2PKH"; + break; + case DerivePathType.bip49: + key = "${walletId}_${chainId}DerivationsP2SH"; + break; + case DerivePathType.bip84: + key = "${walletId}_${chainId}DerivationsP2WPKH"; + break; + } + return key; + } + + Future> _fetchDerivations({ + required int chain, + required DerivePathType derivePathType, + }) async { + // build lookup key + final key = _buildDerivationStorageKey( + chain: chain, derivePathType: derivePathType); + + // fetch current derivations + final derivationsString = await _secureStore.read(key: key); + return Map.from( + jsonDecode(derivationsString ?? "{}") as Map); + } + + /// Add a single derivation to the local secure storage for [chain] and + /// [derivePathType] where [chain] must either be 1 for change or 0 for receive. + /// This will overwrite a previous entry where the address of the new derivation + /// matches a derivation currently stored. + Future addDerivation({ + required int chain, + required String address, + required String pubKey, + required String wif, + required DerivePathType derivePathType, + }) async { + // build lookup key + final key = _buildDerivationStorageKey( + chain: chain, derivePathType: derivePathType); + + // fetch current derivations + final derivationsString = await _secureStore.read(key: key); + final derivations = + Map.from(jsonDecode(derivationsString ?? "{}") as Map); + + // add derivation + derivations[address] = { + "pubKey": pubKey, + "wif": wif, + }; + + // save derivations + final newReceiveDerivationsString = jsonEncode(derivations); + await _secureStore.write(key: key, value: newReceiveDerivationsString); + } + + /// Add multiple derivations to the local secure storage for [chain] and + /// [derivePathType] where [chain] must either be 1 for change or 0 for receive. + /// This will overwrite any previous entries where the address of the new derivation + /// matches a derivation currently stored. + /// The [derivationsToAdd] must be in the format of: + /// { + /// addressA : { + /// "pubKey": , + /// "wif": , + /// }, + /// addressB : { + /// "pubKey": , + /// "wif": , + /// }, + /// } + Future addDerivations({ + required int chain, + required DerivePathType derivePathType, + required Map derivationsToAdd, + }) async { + // build lookup key + final key = _buildDerivationStorageKey( + chain: chain, derivePathType: derivePathType); + + // fetch current derivations + final derivationsString = await _secureStore.read(key: key); + final derivations = + Map.from(jsonDecode(derivationsString ?? "{}") as Map); + + // add derivation + derivations.addAll(derivationsToAdd); + + // save derivations + final newReceiveDerivationsString = jsonEncode(derivations); + await _secureStore.write(key: key, value: newReceiveDerivationsString); + } + + Future _fetchUtxoData() async { + final List allAddresses = await _fetchAllOwnAddresses(); + + try { + final fetchedUtxoList = >>[]; + + final Map>> batches = {}; + const batchSizeMax = 100; + int batchNumber = 0; + for (int i = 0; i < allAddresses.length; i++) { + if (batches[batchNumber] == null) { + batches[batchNumber] = {}; + } + final scripthash = _convertToScriptHash(allAddresses[i], _network); + + print("SCRIPT_HASH_FOR_ADDRESS ${allAddresses[i]} IS $scripthash"); + batches[batchNumber]!.addAll({ + scripthash: [scripthash] + }); + if (i % batchSizeMax == batchSizeMax - 1) { + batchNumber++; + } + } + + for (int i = 0; i < batches.length; i++) { + final response = + await _electrumXClient.getBatchUTXOs(args: batches[i]!); + for (final entry in response.entries) { + if (entry.value.isNotEmpty) { + fetchedUtxoList.add(entry.value); + } + } + } + final priceData = + await _priceAPI.getPricesAnd24hChange(baseCurrency: _prefs.currency); + Decimal currentPrice = priceData[coin]?.item1 ?? Decimal.zero; + final List> outputArray = []; + int satoshiBalance = 0; + int satoshiBalancePending = 0; + + for (int i = 0; i < fetchedUtxoList.length; i++) { + for (int j = 0; j < fetchedUtxoList[i].length; j++) { + int value = fetchedUtxoList[i][j]["value"] as int; + satoshiBalance += value; + + final txn = await cachedElectrumXClient.getTransaction( + txHash: fetchedUtxoList[i][j]["tx_hash"] as String, + verbose: true, + coin: coin, + ); + + final Map utxo = {}; + final int confirmations = txn["confirmations"] as int? ?? 0; + final bool confirmed = confirmations >= MINIMUM_CONFIRMATIONS; + if (!confirmed) { + satoshiBalancePending += value; + } + + utxo["txid"] = txn["txid"]; + utxo["vout"] = fetchedUtxoList[i][j]["tx_pos"]; + utxo["value"] = value; + + utxo["status"] = {}; + utxo["status"]["confirmed"] = confirmed; + utxo["status"]["confirmations"] = confirmations; + utxo["status"]["block_height"] = fetchedUtxoList[i][j]["height"]; + utxo["status"]["block_hash"] = txn["blockhash"]; + utxo["status"]["block_time"] = txn["blocktime"]; + + final fiatValue = ((Decimal.fromInt(value) * currentPrice) / + Decimal.fromInt(Constants.satsPerCoin)) + .toDecimal(scaleOnInfinitePrecision: 2); + utxo["rawWorth"] = fiatValue; + utxo["fiatWorth"] = fiatValue.toString(); + outputArray.add(utxo); + } + } + + Decimal currencyBalanceRaw = + ((Decimal.fromInt(satoshiBalance) * currentPrice) / + Decimal.fromInt(Constants.satsPerCoin)) + .toDecimal(scaleOnInfinitePrecision: 2); + + final Map result = { + "total_user_currency": currencyBalanceRaw.toString(), + "total_sats": satoshiBalance, + "total_btc": (Decimal.fromInt(satoshiBalance) / + Decimal.fromInt(Constants.satsPerCoin)) + .toDecimal(scaleOnInfinitePrecision: Constants.decimalPlaces) + .toString(), + "outputArray": outputArray, + "unconfirmed": satoshiBalancePending, + }; + + final dataModel = UtxoData.fromJson(result); + + final List allOutputs = dataModel.unspentOutputArray; + Logging.instance + .log('Outputs fetched: $allOutputs', level: LogLevel.Info); + await _sortOutputs(allOutputs); + await DB.instance.put( + boxName: walletId, key: 'latest_utxo_model', value: dataModel); + await DB.instance.put( + boxName: walletId, + key: 'totalBalance', + value: dataModel.satoshiBalance); + return dataModel; + } catch (e, s) { + Logging.instance + .log("Output fetch unsuccessful: $e\n$s", level: LogLevel.Error); + final latestTxModel = + DB.instance.get(boxName: walletId, key: 'latest_utxo_model') + as models.UtxoData?; + + if (latestTxModel == null) { + final emptyModel = { + "total_user_currency": "0.00", + "total_sats": 0, + "total_btc": "0", + "outputArray": [] + }; + return UtxoData.fromJson(emptyModel); + } else { + Logging.instance + .log("Old output model located", level: LogLevel.Warning); + return latestTxModel; + } + } + } + + /// Takes in a list of UtxoObjects and adds a name (dependent on object index within list) + /// and checks for the txid associated with the utxo being blocked and marks it accordingly. + /// Now also checks for output labeling. + Future _sortOutputs(List utxos) async { + final blockedHashArray = + DB.instance.get(boxName: walletId, key: 'blocked_tx_hashes') + as List?; + final List lst = []; + if (blockedHashArray != null) { + for (var hash in blockedHashArray) { + lst.add(hash as String); + } + } + final labels = + DB.instance.get(boxName: walletId, key: 'labels') as Map? ?? + {}; + + outputsList = []; + + for (var i = 0; i < utxos.length; i++) { + if (labels[utxos[i].txid] != null) { + utxos[i].txName = labels[utxos[i].txid] as String? ?? ""; + } else { + utxos[i].txName = 'Output #$i'; + } + + if (utxos[i].status.confirmed == false) { + outputsList.add(utxos[i]); + } else { + if (lst.contains(utxos[i].txid)) { + utxos[i].blocked = true; + outputsList.add(utxos[i]); + } else if (!lst.contains(utxos[i].txid)) { + outputsList.add(utxos[i]); + } + } + } + } + + Future getTxCount({required String address}) async { + String? scripthash; + try { + scripthash = _convertToScriptHash(address, _network); + final transactions = + await electrumXClient.getHistory(scripthash: scripthash); + return transactions.length; + } catch (e) { + Logging.instance.log( + "Exception rethrown in _getTxCount(address: $address, scripthash: $scripthash): $e", + level: LogLevel.Error); + rethrow; + } + } + + Future> _getBatchTxCount({ + required Map addresses, + }) async { + try { + final Map> args = {}; + print("Address $addresses"); + for (final entry in addresses.entries) { + args[entry.key] = [_convertToScriptHash(entry.value, _network)]; + } + print("Args ${jsonEncode(args)}"); + final response = await electrumXClient.getBatchHistory(args: args); + print("Response ${jsonEncode(response)}"); + final Map result = {}; + for (final entry in response.entries) { + result[entry.key] = entry.value.length; + } + + return result; + } catch (e, s) { + Logging.instance.log( + "Exception rethrown in _getBatchTxCount(address: $addresses: $e\n$s", + level: LogLevel.Error); + rethrow; + } + } + + Future _checkReceivingAddressForTransactions( + DerivePathType derivePathType) async { + try { + final String currentExternalAddr = + await _getCurrentAddressForChain(0, derivePathType); + final int txCount = await getTxCount(address: currentExternalAddr); + Logging.instance.log( + 'Number of txs for current receiving address $currentExternalAddr: $txCount', + level: LogLevel.Info); + + if (txCount >= 1) { + // First increment the receiving index + await _incrementAddressIndexForChain(0, derivePathType); + + // Check the new receiving index + String indexKey = "receivingIndex"; + switch (derivePathType) { + case DerivePathType.bip44: + indexKey += "P2PKH"; + break; + case DerivePathType.bip49: + indexKey += "P2SH"; + break; + case DerivePathType.bip84: + indexKey += "P2WPKH"; + break; + } + final newReceivingIndex = + DB.instance.get(boxName: walletId, key: indexKey) as int; + + // Use new index to derive a new receiving address + final newReceivingAddress = await _generateAddressForChain( + 0, newReceivingIndex, derivePathType); + + // Add that new receiving address to the array of receiving addresses + await _addToAddressesArrayForChain( + newReceivingAddress, 0, derivePathType); + + // Set the new receiving address that the service + + switch (derivePathType) { + case DerivePathType.bip44: + _currentReceivingAddressP2PKH = Future(() => newReceivingAddress); + break; + case DerivePathType.bip49: + _currentReceivingAddressP2SH = Future(() => newReceivingAddress); + break; + case DerivePathType.bip84: + _currentReceivingAddress = Future(() => newReceivingAddress); + break; + } + } + } catch (e, s) { + Logging.instance.log( + "Exception rethrown from _checkReceivingAddressForTransactions($derivePathType): $e\n$s", + level: LogLevel.Error); + rethrow; + } + } + + Future _checkChangeAddressForTransactions( + DerivePathType derivePathType) async { + try { + final String currentExternalAddr = + await _getCurrentAddressForChain(1, derivePathType); + final int txCount = await getTxCount(address: currentExternalAddr); + Logging.instance.log( + 'Number of txs for current change address $currentExternalAddr: $txCount', + level: LogLevel.Info); + + if (txCount >= 1) { + // First increment the change index + await _incrementAddressIndexForChain(1, derivePathType); + + // Check the new change index + String indexKey = "changeIndex"; + switch (derivePathType) { + case DerivePathType.bip44: + indexKey += "P2PKH"; + break; + case DerivePathType.bip49: + indexKey += "P2SH"; + break; + case DerivePathType.bip84: + indexKey += "P2WPKH"; + break; + } + final newChangeIndex = + DB.instance.get(boxName: walletId, key: indexKey) as int; + + // Use new index to derive a new change address + final newChangeAddress = + await _generateAddressForChain(1, newChangeIndex, derivePathType); + + // Add that new receiving address to the array of change addresses + await _addToAddressesArrayForChain(newChangeAddress, 1, derivePathType); + } + } on SocketException catch (se, s) { + Logging.instance.log( + "SocketException caught in _checkReceivingAddressForTransactions($derivePathType): $se\n$s", + level: LogLevel.Error); + return; + } catch (e, s) { + Logging.instance.log( + "Exception rethrown from _checkReceivingAddressForTransactions($derivePathType): $e\n$s", + level: LogLevel.Error); + rethrow; + } + } + + Future _checkCurrentReceivingAddressesForTransactions() async { + try { + for (final type in DerivePathType.values) { + await _checkReceivingAddressForTransactions(type); + } + } catch (e, s) { + Logging.instance.log( + "Exception rethrown from _checkCurrentReceivingAddressesForTransactions(): $e\n$s", + level: LogLevel.Error); + rethrow; + } + } + + /// public wrapper because dart can't test private... + Future checkCurrentReceivingAddressesForTransactions() async { + if (Platform.environment["FLUTTER_TEST"] == "true") { + try { + return _checkCurrentReceivingAddressesForTransactions(); + } catch (_) { + rethrow; + } + } + } + + Future _checkCurrentChangeAddressesForTransactions() async { + try { + for (final type in DerivePathType.values) { + await _checkChangeAddressForTransactions(type); + } + } catch (e, s) { + Logging.instance.log( + "Exception rethrown from _checkCurrentChangeAddressesForTransactions(): $e\n$s", + level: LogLevel.Error); + rethrow; + } + } + + /// public wrapper because dart can't test private... + Future checkCurrentChangeAddressesForTransactions() async { + if (Platform.environment["FLUTTER_TEST"] == "true") { + try { + return _checkCurrentChangeAddressesForTransactions(); + } catch (_) { + rethrow; + } + } + } + + /// attempts to convert a string to a valid scripthash + /// + /// Returns the scripthash or throws an exception on invalid namecoin address + String _convertToScriptHash(String namecoinAddress, NetworkType network) { + try { + final output = Address.addressToOutputScript( + namecoinAddress, network, namecoin.bech32!); + final hash = sha256.convert(output.toList(growable: false)).toString(); + + final chars = hash.split(""); + final reversedPairs = []; + var i = chars.length - 1; + while (i > 0) { + reversedPairs.add(chars[i - 1]); + reversedPairs.add(chars[i]); + i -= 2; + } + return reversedPairs.join(""); + } catch (e) { + rethrow; + } + } + + Future>> _fetchHistory( + List allAddresses) async { + try { + List> allTxHashes = []; + + final Map>> batches = {}; + final Map requestIdToAddressMap = {}; + const batchSizeMax = 100; + int batchNumber = 0; + for (int i = 0; i < allAddresses.length; i++) { + if (batches[batchNumber] == null) { + batches[batchNumber] = {}; + } + final scripthash = _convertToScriptHash(allAddresses[i], _network); + final id = Logger.isTestEnv ? "$i" : const Uuid().v1(); + requestIdToAddressMap[id] = allAddresses[i]; + batches[batchNumber]!.addAll({ + id: [scripthash] + }); + if (i % batchSizeMax == batchSizeMax - 1) { + batchNumber++; + } + } + + for (int i = 0; i < batches.length; i++) { + final response = + await _electrumXClient.getBatchHistory(args: batches[i]!); + for (final entry in response.entries) { + for (int j = 0; j < entry.value.length; j++) { + entry.value[j]["address"] = requestIdToAddressMap[entry.key]; + if (!allTxHashes.contains(entry.value[j])) { + allTxHashes.add(entry.value[j]); + } + } + } + } + + return allTxHashes; + } catch (e, s) { + Logging.instance.log("_fetchHistory: $e\n$s", level: LogLevel.Error); + rethrow; + } + } + + bool _duplicateTxCheck( + List> allTransactions, String txid) { + for (int i = 0; i < allTransactions.length; i++) { + if (allTransactions[i]["txid"] == txid) { + return true; + } + } + return false; + } + + Future>> fastFetch(List allTxHashes) async { + List> allTransactions = []; + + const futureLimit = 30; + List>> transactionFutures = []; + int currentFutureCount = 0; + for (final txHash in allTxHashes) { + Future> transactionFuture = + cachedElectrumXClient.getTransaction( + txHash: txHash, + verbose: true, + coin: coin, + ); + transactionFutures.add(transactionFuture); + currentFutureCount++; + if (currentFutureCount > futureLimit) { + currentFutureCount = 0; + await Future.wait(transactionFutures); + for (final fTx in transactionFutures) { + final tx = await fTx; + + allTransactions.add(tx); + } + } + } + if (currentFutureCount != 0) { + currentFutureCount = 0; + await Future.wait(transactionFutures); + for (final fTx in transactionFutures) { + final tx = await fTx; + + allTransactions.add(tx); + } + } + return allTransactions; + } + + Future _fetchTransactionData() async { + final List allAddresses = await _fetchAllOwnAddresses(); + + final changeAddresses = DB.instance.get( + boxName: walletId, key: 'changeAddressesP2WPKH') as List; + final changeAddressesP2PKH = + DB.instance.get(boxName: walletId, key: 'changeAddressesP2PKH') + as List; + final changeAddressesP2SH = + DB.instance.get(boxName: walletId, key: 'changeAddressesP2SH') + as List; + + for (var i = 0; i < changeAddressesP2PKH.length; i++) { + changeAddresses.add(changeAddressesP2PKH[i] as String); + } + for (var i = 0; i < changeAddressesP2SH.length; i++) { + changeAddresses.add(changeAddressesP2SH[i] as String); + } + + final List> allTxHashes = + await _fetchHistory(allAddresses); + + final cachedTransactions = + DB.instance.get(boxName: walletId, key: 'latest_tx_model') + as TransactionData?; + int latestTxnBlockHeight = + DB.instance.get(boxName: walletId, key: "storedTxnDataHeight") + as int? ?? + 0; + + final unconfirmedCachedTransactions = + cachedTransactions?.getAllTransactions() ?? {}; + unconfirmedCachedTransactions + .removeWhere((key, value) => value.confirmedStatus); + + if (cachedTransactions != null) { + for (final tx in allTxHashes.toList(growable: false)) { + final txHeight = tx["height"] as int; + if (txHeight > 0 && + txHeight < latestTxnBlockHeight - MINIMUM_CONFIRMATIONS) { + if (unconfirmedCachedTransactions[tx["tx_hash"] as String] == null) { + allTxHashes.remove(tx); + } + } + } + } + + Set hashes = {}; + for (var element in allTxHashes) { + hashes.add(element['tx_hash'] as String); + } + await fastFetch(hashes.toList()); + List> allTransactions = []; + + for (final txHash in allTxHashes) { + final tx = await cachedElectrumXClient.getTransaction( + txHash: txHash["tx_hash"] as String, + verbose: true, + coin: coin, + ); + + // Logging.instance.log("TRANSACTION: ${jsonEncode(tx)}"); + // TODO fix this for sent to self transactions? + if (!_duplicateTxCheck(allTransactions, tx["txid"] as String)) { + tx["address"] = txHash["address"]; + tx["height"] = txHash["height"]; + allTransactions.add(tx); + } + } + + Logging.instance.log("addAddresses: $allAddresses", level: LogLevel.Info); + Logging.instance.log("allTxHashes: $allTxHashes", level: LogLevel.Info); + + Logging.instance.log("allTransactions length: ${allTransactions.length}", + level: LogLevel.Info); + + final priceData = + await _priceAPI.getPricesAnd24hChange(baseCurrency: _prefs.currency); + Decimal currentPrice = priceData[coin]?.item1 ?? Decimal.zero; + final List> midSortedArray = []; + + Set vHashes = {}; + for (final txObject in allTransactions) { + for (int i = 0; i < (txObject["vin"] as List).length; i++) { + final input = txObject["vin"]![i] as Map; + final prevTxid = input["txid"] as String; + vHashes.add(prevTxid); + } + } + await fastFetch(vHashes.toList()); + + for (final txObject in allTransactions) { + List sendersArray = []; + List recipientsArray = []; + + // Usually only has value when txType = 'Send' + int inputAmtSentFromWallet = 0; + // Usually has value regardless of txType due to change addresses + int outputAmtAddressedToWallet = 0; + int fee = 0; + + Map midSortedTx = {}; + + for (int i = 0; i < (txObject["vin"] as List).length; i++) { + final input = txObject["vin"]![i] as Map; + final prevTxid = input["txid"] as String; + final prevOut = input["vout"] as int; + + final tx = await _cachedElectrumXClient.getTransaction( + txHash: prevTxid, + coin: coin, + ); + + for (final out in tx["vout"] as List) { + if (prevOut == out["n"]) { + final address = out["scriptPubKey"]["addresses"][0] as String?; + if (address != null) { + sendersArray.add(address); + } + } + } + } + + Logging.instance.log("sendersArray: $sendersArray", level: LogLevel.Info); + + for (final output in txObject["vout"] as List) { + final address = output["scriptPubKey"]["addresses"][0] as String?; + if (address != null) { + recipientsArray.add(address); + } + } + + Logging.instance + .log("recipientsArray: $recipientsArray", level: LogLevel.Info); + + final foundInSenders = + allAddresses.any((element) => sendersArray.contains(element)); + Logging.instance + .log("foundInSenders: $foundInSenders", level: LogLevel.Info); + + // If txType = Sent, then calculate inputAmtSentFromWallet + if (foundInSenders) { + int totalInput = 0; + for (int i = 0; i < (txObject["vin"] as List).length; i++) { + final input = txObject["vin"]![i] as Map; + final prevTxid = input["txid"] as String; + final prevOut = input["vout"] as int; + final tx = await _cachedElectrumXClient.getTransaction( + txHash: prevTxid, + coin: coin, + ); + + for (final out in tx["vout"] as List) { + if (prevOut == out["n"]) { + inputAmtSentFromWallet += + (Decimal.parse(out["value"]!.toString()) * + Decimal.fromInt(Constants.satsPerCoin)) + .toBigInt() + .toInt(); + } + } + } + totalInput = inputAmtSentFromWallet; + int totalOutput = 0; + + for (final output in txObject["vout"] as List) { + final address = output["scriptPubKey"]["addresses"][0]; + final value = output["value"]; + final _value = (Decimal.parse(value.toString()) * + Decimal.fromInt(Constants.satsPerCoin)) + .toBigInt() + .toInt(); + totalOutput += _value; + if (changeAddresses.contains(address)) { + inputAmtSentFromWallet -= _value; + } else { + // change address from 'sent from' to the 'sent to' address + txObject["address"] = address; + } + } + // calculate transaction fee + fee = totalInput - totalOutput; + // subtract fee from sent to calculate correct value of sent tx + inputAmtSentFromWallet -= fee; + } else { + // counters for fee calculation + int totalOut = 0; + int totalIn = 0; + + // add up received tx value + for (final output in txObject["vout"] as List) { + final address = output["scriptPubKey"]["addresses"][0]; + if (address != null) { + final value = (Decimal.parse(output["value"].toString()) * + Decimal.fromInt(Constants.satsPerCoin)) + .toBigInt() + .toInt(); + totalOut += value; + if (allAddresses.contains(address)) { + outputAmtAddressedToWallet += value; + } + } + } + + // calculate fee for received tx + for (int i = 0; i < (txObject["vin"] as List).length; i++) { + final input = txObject["vin"][i] as Map; + final prevTxid = input["txid"] as String; + final prevOut = input["vout"] as int; + final tx = await _cachedElectrumXClient.getTransaction( + txHash: prevTxid, + coin: coin, + ); + + for (final out in tx["vout"] as List) { + if (prevOut == out["n"]) { + totalIn += (Decimal.parse(out["value"].toString()) * + Decimal.fromInt(Constants.satsPerCoin)) + .toBigInt() + .toInt(); + } + } + } + fee = totalIn - totalOut; + } + + // create final tx map + midSortedTx["txid"] = txObject["txid"]; + midSortedTx["confirmed_status"] = (txObject["confirmations"] != null) && + (txObject["confirmations"] as int >= MINIMUM_CONFIRMATIONS); + midSortedTx["confirmations"] = txObject["confirmations"] ?? 0; + midSortedTx["timestamp"] = txObject["blocktime"] ?? + (DateTime.now().millisecondsSinceEpoch ~/ 1000); + + if (foundInSenders) { + midSortedTx["txType"] = "Sent"; + midSortedTx["amount"] = inputAmtSentFromWallet; + final String worthNow = + ((currentPrice * Decimal.fromInt(inputAmtSentFromWallet)) / + Decimal.fromInt(Constants.satsPerCoin)) + .toDecimal(scaleOnInfinitePrecision: 2) + .toStringAsFixed(2); + midSortedTx["worthNow"] = worthNow; + midSortedTx["worthAtBlockTimestamp"] = worthNow; + } else { + midSortedTx["txType"] = "Received"; + midSortedTx["amount"] = outputAmtAddressedToWallet; + final worthNow = + ((currentPrice * Decimal.fromInt(outputAmtAddressedToWallet)) / + Decimal.fromInt(Constants.satsPerCoin)) + .toDecimal(scaleOnInfinitePrecision: 2) + .toStringAsFixed(2); + midSortedTx["worthNow"] = worthNow; + } + midSortedTx["aliens"] = []; + midSortedTx["fees"] = fee; + midSortedTx["address"] = txObject["address"]; + midSortedTx["inputSize"] = txObject["vin"].length; + midSortedTx["outputSize"] = txObject["vout"].length; + midSortedTx["inputs"] = txObject["vin"]; + midSortedTx["outputs"] = txObject["vout"]; + + final int height = txObject["height"] as int; + midSortedTx["height"] = height; + + if (height >= latestTxnBlockHeight) { + latestTxnBlockHeight = height; + } + + midSortedArray.add(midSortedTx); + } + + // sort by date ---- //TODO not sure if needed + // shouldn't be any issues with a null timestamp but I got one at some point? + midSortedArray + .sort((a, b) => (b["timestamp"] as int) - (a["timestamp"] as int)); + // { + // final aT = a["timestamp"]; + // final bT = b["timestamp"]; + // + // if (aT == null && bT == null) { + // return 0; + // } else if (aT == null) { + // return -1; + // } else if (bT == null) { + // return 1; + // } else { + // return bT - aT; + // } + // }); + + // buildDateTimeChunks + final Map result = {"dateTimeChunks": []}; + final dateArray = []; + + for (int i = 0; i < midSortedArray.length; i++) { + final txObject = midSortedArray[i]; + final date = extractDateFromTimestamp(txObject["timestamp"] as int); + final txTimeArray = [txObject["timestamp"], date]; + + if (dateArray.contains(txTimeArray[1])) { + result["dateTimeChunks"].forEach((dynamic chunk) { + if (extractDateFromTimestamp(chunk["timestamp"] as int) == + txTimeArray[1]) { + if (chunk["transactions"] == null) { + chunk["transactions"] = >[]; + } + chunk["transactions"].add(txObject); + } + }); + } else { + dateArray.add(txTimeArray[1]); + final chunk = { + "timestamp": txTimeArray[0], + "transactions": [txObject], + }; + result["dateTimeChunks"].add(chunk); + } + } + + final transactionsMap = cachedTransactions?.getAllTransactions() ?? {}; + transactionsMap + .addAll(TransactionData.fromJson(result).getAllTransactions()); + + final txModel = TransactionData.fromMap(transactionsMap); + + await DB.instance.put( + boxName: walletId, + key: 'storedTxnDataHeight', + value: latestTxnBlockHeight); + await DB.instance.put( + boxName: walletId, key: 'latest_tx_model', value: txModel); + + return txModel; + } + + int estimateTxFee({required int vSize, required int feeRatePerKB}) { + return vSize * (feeRatePerKB / 1000).ceil(); + } + + /// The coinselection algorithm decides whether or not the user is eligible to make the transaction + /// with [satoshiAmountToSend] and [selectedTxFeeRate]. If so, it will call buildTrasaction() and return + /// a map containing the tx hex along with other important information. If not, then it will return + /// an integer (1 or 2) + dynamic coinSelection( + int satoshiAmountToSend, + int selectedTxFeeRate, + String _recipientAddress, + bool isSendAll, { + int additionalOutputs = 0, + List? utxos, + }) async { + Logging.instance + .log("Starting coinSelection ----------", level: LogLevel.Info); + final List availableOutputs = utxos ?? outputsList; + final List spendableOutputs = []; + int spendableSatoshiValue = 0; + + // Build list of spendable outputs and totaling their satoshi amount + for (var i = 0; i < availableOutputs.length; i++) { + if (availableOutputs[i].blocked == false && + availableOutputs[i].status.confirmed == true) { + spendableOutputs.add(availableOutputs[i]); + spendableSatoshiValue += availableOutputs[i].value; + } + } + + // sort spendable by age (oldest first) + spendableOutputs.sort( + (a, b) => b.status.confirmations.compareTo(a.status.confirmations)); + + Logging.instance.log("spendableOutputs.length: ${spendableOutputs.length}", + level: LogLevel.Info); + Logging.instance + .log("spendableOutputs: $spendableOutputs", level: LogLevel.Info); + Logging.instance.log("spendableSatoshiValue: $spendableSatoshiValue", + level: LogLevel.Info); + Logging.instance + .log("satoshiAmountToSend: $satoshiAmountToSend", level: LogLevel.Info); + // If the amount the user is trying to send is smaller than the amount that they have spendable, + // then return 1, which indicates that they have an insufficient balance. + if (spendableSatoshiValue < satoshiAmountToSend) { + return 1; + // If the amount the user wants to send is exactly equal to the amount they can spend, then return + // 2, which indicates that they are not leaving enough over to pay the transaction fee + } else if (spendableSatoshiValue == satoshiAmountToSend && !isSendAll) { + return 2; + } + // If neither of these statements pass, we assume that the user has a spendable balance greater + // than the amount they're attempting to send. Note that this value still does not account for + // the added transaction fee, which may require an extra input and will need to be checked for + // later on. + + // Possible situation right here + int satoshisBeingUsed = 0; + int inputsBeingConsumed = 0; + List utxoObjectsToUse = []; + + for (var i = 0; + satoshisBeingUsed < satoshiAmountToSend && i < spendableOutputs.length; + i++) { + utxoObjectsToUse.add(spendableOutputs[i]); + satoshisBeingUsed += spendableOutputs[i].value; + inputsBeingConsumed += 1; + } + for (int i = 0; + i < additionalOutputs && inputsBeingConsumed < spendableOutputs.length; + i++) { + utxoObjectsToUse.add(spendableOutputs[inputsBeingConsumed]); + satoshisBeingUsed += spendableOutputs[inputsBeingConsumed].value; + inputsBeingConsumed += 1; + } + + Logging.instance + .log("satoshisBeingUsed: $satoshisBeingUsed", level: LogLevel.Info); + Logging.instance + .log("inputsBeingConsumed: $inputsBeingConsumed", level: LogLevel.Info); + Logging.instance + .log('utxoObjectsToUse: $utxoObjectsToUse', level: LogLevel.Info); + + // numberOfOutputs' length must always be equal to that of recipientsArray and recipientsAmtArray + List recipientsArray = [_recipientAddress]; + List recipientsAmtArray = [satoshiAmountToSend]; + + // gather required signing data + final utxoSigningData = await fetchBuildTxData(utxoObjectsToUse); + + if (isSendAll) { + Logging.instance + .log("Attempting to send all $coin", level: LogLevel.Info); + + final int vSizeForOneOutput = (await buildTransaction( + utxosToUse: utxoObjectsToUse, + utxoSigningData: utxoSigningData, + recipients: [_recipientAddress], + satoshiAmounts: [satoshisBeingUsed - 1], + ))["vSize"] as int; + int feeForOneOutput = estimateTxFee( + vSize: vSizeForOneOutput, + feeRatePerKB: selectedTxFeeRate, + ); + + final int roughEstimate = + roughFeeEstimate(spendableOutputs.length, 1, selectedTxFeeRate); + if (feeForOneOutput < roughEstimate) { + feeForOneOutput = roughEstimate; + } + + final int amount = satoshiAmountToSend - feeForOneOutput; + dynamic txn = await buildTransaction( + utxosToUse: utxoObjectsToUse, + utxoSigningData: utxoSigningData, + recipients: recipientsArray, + satoshiAmounts: [amount], + ); + Map transactionObject = { + "hex": txn["hex"], + "recipient": recipientsArray[0], + "recipientAmt": amount, + "fee": feeForOneOutput, + "vSize": txn["vSize"], + }; + return transactionObject; + } + + final int vSizeForOneOutput = (await buildTransaction( + utxosToUse: utxoObjectsToUse, + utxoSigningData: utxoSigningData, + recipients: [_recipientAddress], + satoshiAmounts: [satoshisBeingUsed - 1], + ))["vSize"] as int; + final int vSizeForTwoOutPuts = (await buildTransaction( + utxosToUse: utxoObjectsToUse, + utxoSigningData: utxoSigningData, + recipients: [ + _recipientAddress, + await _getCurrentAddressForChain(1, DerivePathType.bip84), + ], + satoshiAmounts: [ + satoshiAmountToSend, + satoshisBeingUsed - satoshiAmountToSend - 1 + ], // dust limit is the minimum amount a change output should be + ))["vSize"] as int; + + // Assume 1 output, only for recipient and no change + final feeForOneOutput = estimateTxFee( + vSize: vSizeForOneOutput, + feeRatePerKB: selectedTxFeeRate, + ); + // Assume 2 outputs, one for recipient and one for change + final feeForTwoOutputs = estimateTxFee( + vSize: vSizeForTwoOutPuts, + feeRatePerKB: selectedTxFeeRate, + ); + + Logging.instance + .log("feeForTwoOutputs: $feeForTwoOutputs", level: LogLevel.Info); + Logging.instance + .log("feeForOneOutput: $feeForOneOutput", level: LogLevel.Info); + + if (satoshisBeingUsed - satoshiAmountToSend > feeForOneOutput) { + if (satoshisBeingUsed - satoshiAmountToSend > + feeForOneOutput + DUST_LIMIT) { + // Here, we know that theoretically, we may be able to include another output(change) but we first need to + // factor in the value of this output in satoshis. + int changeOutputSize = + satoshisBeingUsed - satoshiAmountToSend - feeForTwoOutputs; + // We check to see if the user can pay for the new transaction with 2 outputs instead of one. If they can and + // the second output's size > DUST_LIMIT satoshis, we perform the mechanics required to properly generate and use a new + // change address. + if (changeOutputSize > DUST_LIMIT && + satoshisBeingUsed - satoshiAmountToSend - changeOutputSize == + feeForTwoOutputs) { + // generate new change address if current change address has been used + await _checkChangeAddressForTransactions(DerivePathType.bip84); + final String newChangeAddress = + await _getCurrentAddressForChain(1, DerivePathType.bip84); + + int feeBeingPaid = + satoshisBeingUsed - satoshiAmountToSend - changeOutputSize; + + recipientsArray.add(newChangeAddress); + recipientsAmtArray.add(changeOutputSize); + // At this point, we have the outputs we're going to use, the amounts to send along with which addresses + // we intend to send these amounts to. We have enough to send instructions to build the transaction. + Logging.instance.log('2 outputs in tx', level: LogLevel.Info); + Logging.instance + .log('Input size: $satoshisBeingUsed', level: LogLevel.Info); + Logging.instance.log('Recipient output size: $satoshiAmountToSend', + level: LogLevel.Info); + Logging.instance.log('Change Output Size: $changeOutputSize', + level: LogLevel.Info); + Logging.instance.log( + 'Difference (fee being paid): $feeBeingPaid sats', + level: LogLevel.Info); + Logging.instance + .log('Estimated fee: $feeForTwoOutputs', level: LogLevel.Info); + dynamic txn = await buildTransaction( + utxosToUse: utxoObjectsToUse, + utxoSigningData: utxoSigningData, + recipients: recipientsArray, + satoshiAmounts: recipientsAmtArray, + ); + + // make sure minimum fee is accurate if that is being used + if (txn["vSize"] - feeBeingPaid == 1) { + int changeOutputSize = + satoshisBeingUsed - satoshiAmountToSend - (txn["vSize"] as int); + feeBeingPaid = + satoshisBeingUsed - satoshiAmountToSend - changeOutputSize; + recipientsAmtArray.removeLast(); + recipientsAmtArray.add(changeOutputSize); + Logging.instance.log('Adjusted Input size: $satoshisBeingUsed', + level: LogLevel.Info); + Logging.instance.log( + 'Adjusted Recipient output size: $satoshiAmountToSend', + level: LogLevel.Info); + Logging.instance.log( + 'Adjusted Change Output Size: $changeOutputSize', + level: LogLevel.Info); + Logging.instance.log( + 'Adjusted Difference (fee being paid): $feeBeingPaid sats', + level: LogLevel.Info); + Logging.instance.log('Adjusted Estimated fee: $feeForTwoOutputs', + level: LogLevel.Info); + txn = await buildTransaction( + utxosToUse: utxoObjectsToUse, + utxoSigningData: utxoSigningData, + recipients: recipientsArray, + satoshiAmounts: recipientsAmtArray, + ); + } + + Map transactionObject = { + "hex": txn["hex"], + "recipient": recipientsArray[0], + "recipientAmt": recipientsAmtArray[0], + "fee": feeBeingPaid, + "vSize": txn["vSize"], + }; + return transactionObject; + } else { + // Something went wrong here. It either overshot or undershot the estimated fee amount or the changeOutputSize + // is smaller than or equal to DUST_LIMIT. Revert to single output transaction. + Logging.instance.log('1 output in tx', level: LogLevel.Info); + Logging.instance + .log('Input size: $satoshisBeingUsed', level: LogLevel.Info); + Logging.instance.log('Recipient output size: $satoshiAmountToSend', + level: LogLevel.Info); + Logging.instance.log( + 'Difference (fee being paid): ${satoshisBeingUsed - satoshiAmountToSend} sats', + level: LogLevel.Info); + Logging.instance + .log('Estimated fee: $feeForOneOutput', level: LogLevel.Info); + dynamic txn = await buildTransaction( + utxosToUse: utxoObjectsToUse, + utxoSigningData: utxoSigningData, + recipients: recipientsArray, + satoshiAmounts: recipientsAmtArray, + ); + Map transactionObject = { + "hex": txn["hex"], + "recipient": recipientsArray[0], + "recipientAmt": recipientsAmtArray[0], + "fee": satoshisBeingUsed - satoshiAmountToSend, + "vSize": txn["vSize"], + }; + return transactionObject; + } + } else { + // No additional outputs needed since adding one would mean that it'd be smaller than DUST_LIMIT sats + // which makes it uneconomical to add to the transaction. Here, we pass data directly to instruct + // the wallet to begin crafting the transaction that the user requested. + Logging.instance.log('1 output in tx', level: LogLevel.Info); + Logging.instance + .log('Input size: $satoshisBeingUsed', level: LogLevel.Info); + Logging.instance.log('Recipient output size: $satoshiAmountToSend', + level: LogLevel.Info); + Logging.instance.log( + 'Difference (fee being paid): ${satoshisBeingUsed - satoshiAmountToSend} sats', + level: LogLevel.Info); + Logging.instance + .log('Estimated fee: $feeForOneOutput', level: LogLevel.Info); + dynamic txn = await buildTransaction( + utxosToUse: utxoObjectsToUse, + utxoSigningData: utxoSigningData, + recipients: recipientsArray, + satoshiAmounts: recipientsAmtArray, + ); + Map transactionObject = { + "hex": txn["hex"], + "recipient": recipientsArray[0], + "recipientAmt": recipientsAmtArray[0], + "fee": satoshisBeingUsed - satoshiAmountToSend, + "vSize": txn["vSize"], + }; + return transactionObject; + } + } else if (satoshisBeingUsed - satoshiAmountToSend == feeForOneOutput) { + // In this scenario, no additional change output is needed since inputs - outputs equal exactly + // what we need to pay for fees. Here, we pass data directly to instruct the wallet to begin + // crafting the transaction that the user requested. + Logging.instance.log('1 output in tx', level: LogLevel.Info); + Logging.instance + .log('Input size: $satoshisBeingUsed', level: LogLevel.Info); + Logging.instance.log('Recipient output size: $satoshiAmountToSend', + level: LogLevel.Info); + Logging.instance.log( + 'Fee being paid: ${satoshisBeingUsed - satoshiAmountToSend} sats', + level: LogLevel.Info); + Logging.instance + .log('Estimated fee: $feeForOneOutput', level: LogLevel.Info); + dynamic txn = await buildTransaction( + utxosToUse: utxoObjectsToUse, + utxoSigningData: utxoSigningData, + recipients: recipientsArray, + satoshiAmounts: recipientsAmtArray, + ); + Map transactionObject = { + "hex": txn["hex"], + "recipient": recipientsArray[0], + "recipientAmt": recipientsAmtArray[0], + "fee": feeForOneOutput, + "vSize": txn["vSize"], + }; + return transactionObject; + } else { + // Remember that returning 2 indicates that the user does not have a sufficient balance to + // pay for the transaction fee. Ideally, at this stage, we should check if the user has any + // additional outputs they're able to spend and then recalculate fees. + Logging.instance.log( + 'Cannot pay tx fee - checking for more outputs and trying again', + level: LogLevel.Warning); + // try adding more outputs + if (spendableOutputs.length > inputsBeingConsumed) { + return coinSelection(satoshiAmountToSend, selectedTxFeeRate, + _recipientAddress, isSendAll, + additionalOutputs: additionalOutputs + 1, utxos: utxos); + } + return 2; + } + } + + Future> fetchBuildTxData( + List utxosToUse, + ) async { + // return data + Map results = {}; + Map> addressTxid = {}; + + // addresses to check + List addressesP2PKH = []; + List addressesP2SH = []; + List addressesP2WPKH = []; + Logging.instance.log("utxos: $utxosToUse", level: LogLevel.Info); + + try { + // Populating the addresses to check + for (var i = 0; i < utxosToUse.length; i++) { + final txid = utxosToUse[i].txid; + final tx = await _cachedElectrumXClient.getTransaction( + txHash: txid, + coin: coin, + ); + Logging.instance.log("tx: ${json.encode(tx)}", + level: LogLevel.Info, printFullLength: true); + + for (final output in tx["vout"] as List) { + final n = output["n"]; + if (n != null && n == utxosToUse[i].vout) { + final address = output["scriptPubKey"]["addresses"][0] as String; + if (!addressTxid.containsKey(address)) { + addressTxid[address] = []; + } + (addressTxid[address] as List).add(txid); + switch (addressType(address: address)) { + case DerivePathType.bip44: + addressesP2PKH.add(address); + break; + case DerivePathType.bip49: + addressesP2SH.add(address); + break; + case DerivePathType.bip84: + addressesP2WPKH.add(address); + break; + } + } + } + } + + // p2pkh / bip44 + final p2pkhLength = addressesP2PKH.length; + if (p2pkhLength > 0) { + final receiveDerivations = await _fetchDerivations( + chain: 0, + derivePathType: DerivePathType.bip44, + ); + final changeDerivations = await _fetchDerivations( + chain: 1, + derivePathType: DerivePathType.bip44, + ); + for (int i = 0; i < p2pkhLength; i++) { + // receives + final receiveDerivation = receiveDerivations[addressesP2PKH[i]]; + // if a match exists it will not be null + if (receiveDerivation != null) { + final data = P2PKH( + data: PaymentData( + pubkey: Format.stringToUint8List( + receiveDerivation["pubKey"] as String)), + network: _network, + ).data; + + for (String tx in addressTxid[addressesP2PKH[i]]!) { + results[tx] = { + "output": data.output, + "keyPair": ECPair.fromWIF( + receiveDerivation["wif"] as String, + network: _network, + ), + }; + } + } else { + // if its not a receive, check change + final changeDerivation = changeDerivations[addressesP2PKH[i]]; + // if a match exists it will not be null + if (changeDerivation != null) { + final data = P2PKH( + data: PaymentData( + pubkey: Format.stringToUint8List( + changeDerivation["pubKey"] as String)), + network: _network, + ).data; + + for (String tx in addressTxid[addressesP2PKH[i]]!) { + results[tx] = { + "output": data.output, + "keyPair": ECPair.fromWIF( + changeDerivation["wif"] as String, + network: _network, + ), + }; + } + } + } + } + } + + // p2sh / bip49 + final p2shLength = addressesP2SH.length; + if (p2shLength > 0) { + final receiveDerivations = await _fetchDerivations( + chain: 0, + derivePathType: DerivePathType.bip49, + ); + final changeDerivations = await _fetchDerivations( + chain: 1, + derivePathType: DerivePathType.bip49, + ); + for (int i = 0; i < p2shLength; i++) { + // receives + final receiveDerivation = receiveDerivations[addressesP2SH[i]]; + // if a match exists it will not be null + if (receiveDerivation != null) { + final p2wpkh = P2WPKH( + data: PaymentData( + pubkey: Format.stringToUint8List( + receiveDerivation["pubKey"] as String)), + network: _network, + overridePrefix: namecoin.bech32!) + .data; + + final redeemScript = p2wpkh.output; + + final data = + P2SH(data: PaymentData(redeem: p2wpkh), network: _network).data; + + for (String tx in addressTxid[addressesP2SH[i]]!) { + results[tx] = { + "output": data.output, + "keyPair": ECPair.fromWIF( + receiveDerivation["wif"] as String, + network: _network, + ), + "redeemScript": redeemScript, + }; + } + } else { + // if its not a receive, check change + final changeDerivation = changeDerivations[addressesP2SH[i]]; + // if a match exists it will not be null + if (changeDerivation != null) { + final p2wpkh = P2WPKH( + data: PaymentData( + pubkey: Format.stringToUint8List( + changeDerivation["pubKey"] as String)), + network: _network, + overridePrefix: namecoin.bech32!) + .data; + + final redeemScript = p2wpkh.output; + + final data = + P2SH(data: PaymentData(redeem: p2wpkh), network: _network) + .data; + + for (String tx in addressTxid[addressesP2SH[i]]!) { + results[tx] = { + "output": data.output, + "keyPair": ECPair.fromWIF( + changeDerivation["wif"] as String, + network: _network, + ), + "redeemScript": redeemScript, + }; + } + } + } + } + } + + // p2wpkh / bip84 + final p2wpkhLength = addressesP2WPKH.length; + if (p2wpkhLength > 0) { + final receiveDerivations = await _fetchDerivations( + chain: 0, + derivePathType: DerivePathType.bip84, + ); + final changeDerivations = await _fetchDerivations( + chain: 1, + derivePathType: DerivePathType.bip84, + ); + + for (int i = 0; i < p2wpkhLength; i++) { + // receives + final receiveDerivation = receiveDerivations[addressesP2WPKH[i]]; + // if a match exists it will not be null + if (receiveDerivation != null) { + final data = P2WPKH( + data: PaymentData( + pubkey: Format.stringToUint8List( + receiveDerivation["pubKey"] as String)), + network: _network, + overridePrefix: namecoin.bech32!) + .data; + + for (String tx in addressTxid[addressesP2WPKH[i]]!) { + results[tx] = { + "output": data.output, + "keyPair": ECPair.fromWIF( + receiveDerivation["wif"] as String, + network: _network, + ), + }; + } + } else { + // if its not a receive, check change + final changeDerivation = changeDerivations[addressesP2WPKH[i]]; + // if a match exists it will not be null + if (changeDerivation != null) { + final data = P2WPKH( + data: PaymentData( + pubkey: Format.stringToUint8List( + changeDerivation["pubKey"] as String)), + network: _network, + overridePrefix: namecoin.bech32!) + .data; + + for (String tx in addressTxid[addressesP2WPKH[i]]!) { + results[tx] = { + "output": data.output, + "keyPair": ECPair.fromWIF( + changeDerivation["wif"] as String, + network: _network, + ), + }; + } + } + } + } + } + + return results; + } catch (e, s) { + Logging.instance + .log("fetchBuildTxData() threw: $e,\n$s", level: LogLevel.Error); + rethrow; + } + } + + /// Builds and signs a transaction + Future> buildTransaction({ + required List utxosToUse, + required Map utxoSigningData, + required List recipients, + required List satoshiAmounts, + }) async { + Logging.instance + .log("Starting buildTransaction ----------", level: LogLevel.Info); + + final txb = TransactionBuilder(network: _network); + txb.setVersion(2); + + // Add transaction inputs + for (var i = 0; i < utxosToUse.length; i++) { + final txid = utxosToUse[i].txid; + txb.addInput(txid, utxosToUse[i].vout, null, + utxoSigningData[txid]["output"] as Uint8List, namecoin.bech32!); + } + + // Add transaction output + for (var i = 0; i < recipients.length; i++) { + txb.addOutput(recipients[i], satoshiAmounts[i], namecoin.bech32!); + } + + try { + // Sign the transaction accordingly + for (var i = 0; i < utxosToUse.length; i++) { + final txid = utxosToUse[i].txid; + txb.sign( + vin: i, + keyPair: utxoSigningData[txid]["keyPair"] as ECPair, + witnessValue: utxosToUse[i].value, + redeemScript: utxoSigningData[txid]["redeemScript"] as Uint8List?, + overridePrefix: namecoin.bech32!); + } + } catch (e, s) { + Logging.instance.log("Caught exception while signing transaction: $e\n$s", + level: LogLevel.Error); + rethrow; + } + + final builtTx = txb.build(namecoin.bech32!); + final vSize = builtTx.virtualSize(); + + return {"hex": builtTx.toHex(), "vSize": vSize}; + } + + @override + Future fullRescan( + int maxUnusedAddressGap, + int maxNumberOfIndexesToCheck, + ) async { + Logging.instance.log("Starting full rescan!", level: LogLevel.Info); + longMutex = true; + GlobalEventBus.instance.fire( + WalletSyncStatusChangedEvent( + WalletSyncStatus.syncing, + walletId, + coin, + ), + ); + + // clear cache + await _cachedElectrumXClient.clearSharedTransactionCache(coin: coin); + + // back up data + await _rescanBackup(); + + try { + final mnemonic = await _secureStore.read(key: '${_walletId}_mnemonic'); + await _recoverWalletFromBIP32SeedPhrase( + mnemonic: mnemonic!, + maxUnusedAddressGap: maxUnusedAddressGap, + maxNumberOfIndexesToCheck: maxNumberOfIndexesToCheck, + ); + + longMutex = false; + Logging.instance.log("Full rescan complete!", level: LogLevel.Info); + GlobalEventBus.instance.fire( + WalletSyncStatusChangedEvent( + WalletSyncStatus.synced, + walletId, + coin, + ), + ); + } catch (e, s) { + GlobalEventBus.instance.fire( + WalletSyncStatusChangedEvent( + WalletSyncStatus.unableToSync, + walletId, + coin, + ), + ); + + // restore from backup + await _rescanRestore(); + + longMutex = false; + Logging.instance.log("Exception rethrown from fullRescan(): $e\n$s", + level: LogLevel.Error); + rethrow; + } + } + + Future _rescanRestore() async { + Logging.instance.log("starting rescan restore", level: LogLevel.Info); + + // restore from backup + // p2pkh + final tempReceivingAddressesP2PKH = DB.instance + .get(boxName: walletId, key: 'receivingAddressesP2PKH_BACKUP'); + final tempChangeAddressesP2PKH = DB.instance + .get(boxName: walletId, key: 'changeAddressesP2PKH_BACKUP'); + final tempReceivingIndexP2PKH = DB.instance + .get(boxName: walletId, key: 'receivingIndexP2PKH_BACKUP'); + final tempChangeIndexP2PKH = DB.instance + .get(boxName: walletId, key: 'changeIndexP2PKH_BACKUP'); + await DB.instance.put( + boxName: walletId, + key: 'receivingAddressesP2PKH', + value: tempReceivingAddressesP2PKH); + await DB.instance.put( + boxName: walletId, + key: 'changeAddressesP2PKH', + value: tempChangeAddressesP2PKH); + await DB.instance.put( + boxName: walletId, + key: 'receivingIndexP2PKH', + value: tempReceivingIndexP2PKH); + await DB.instance.put( + boxName: walletId, + key: 'changeIndexP2PKH', + value: tempChangeIndexP2PKH); + await DB.instance.delete( + key: 'receivingAddressesP2PKH_BACKUP', boxName: walletId); + await DB.instance + .delete(key: 'changeAddressesP2PKH_BACKUP', boxName: walletId); + await DB.instance + .delete(key: 'receivingIndexP2PKH_BACKUP', boxName: walletId); + await DB.instance + .delete(key: 'changeIndexP2PKH_BACKUP', boxName: walletId); + + // p2Sh + final tempReceivingAddressesP2SH = DB.instance + .get(boxName: walletId, key: 'receivingAddressesP2SH_BACKUP'); + final tempChangeAddressesP2SH = DB.instance + .get(boxName: walletId, key: 'changeAddressesP2SH_BACKUP'); + final tempReceivingIndexP2SH = DB.instance + .get(boxName: walletId, key: 'receivingIndexP2SH_BACKUP'); + final tempChangeIndexP2SH = DB.instance + .get(boxName: walletId, key: 'changeIndexP2SH_BACKUP'); + await DB.instance.put( + boxName: walletId, + key: 'receivingAddressesP2SH', + value: tempReceivingAddressesP2SH); + await DB.instance.put( + boxName: walletId, + key: 'changeAddressesP2SH', + value: tempChangeAddressesP2SH); + await DB.instance.put( + boxName: walletId, + key: 'receivingIndexP2SH', + value: tempReceivingIndexP2SH); + await DB.instance.put( + boxName: walletId, key: 'changeIndexP2SH', value: tempChangeIndexP2SH); + await DB.instance.delete( + key: 'receivingAddressesP2SH_BACKUP', boxName: walletId); + await DB.instance + .delete(key: 'changeAddressesP2SH_BACKUP', boxName: walletId); + await DB.instance + .delete(key: 'receivingIndexP2SH_BACKUP', boxName: walletId); + await DB.instance + .delete(key: 'changeIndexP2SH_BACKUP', boxName: walletId); + + // p2wpkh + final tempReceivingAddressesP2WPKH = DB.instance.get( + boxName: walletId, key: 'receivingAddressesP2WPKH_BACKUP'); + final tempChangeAddressesP2WPKH = DB.instance + .get(boxName: walletId, key: 'changeAddressesP2WPKH_BACKUP'); + final tempReceivingIndexP2WPKH = DB.instance + .get(boxName: walletId, key: 'receivingIndexP2WPKH_BACKUP'); + final tempChangeIndexP2WPKH = DB.instance + .get(boxName: walletId, key: 'changeIndexP2WPKH_BACKUP'); + await DB.instance.put( + boxName: walletId, + key: 'receivingAddressesP2WPKH', + value: tempReceivingAddressesP2WPKH); + await DB.instance.put( + boxName: walletId, + key: 'changeAddressesP2WPKH', + value: tempChangeAddressesP2WPKH); + await DB.instance.put( + boxName: walletId, + key: 'receivingIndexP2WPKH', + value: tempReceivingIndexP2WPKH); + await DB.instance.put( + boxName: walletId, + key: 'changeIndexP2WPKH', + value: tempChangeIndexP2WPKH); + await DB.instance.delete( + key: 'receivingAddressesP2WPKH_BACKUP', boxName: walletId); + await DB.instance.delete( + key: 'changeAddressesP2WPKH_BACKUP', boxName: walletId); + await DB.instance + .delete(key: 'receivingIndexP2WPKH_BACKUP', boxName: walletId); + await DB.instance + .delete(key: 'changeIndexP2WPKH_BACKUP', boxName: walletId); + + // P2PKH derivations + final p2pkhReceiveDerivationsString = await _secureStore.read( + key: "${walletId}_receiveDerivationsP2PKH_BACKUP"); + final p2pkhChangeDerivationsString = await _secureStore.read( + key: "${walletId}_changeDerivationsP2PKH_BACKUP"); + + await _secureStore.write( + key: "${walletId}_receiveDerivationsP2PKH", + value: p2pkhReceiveDerivationsString); + await _secureStore.write( + key: "${walletId}_changeDerivationsP2PKH", + value: p2pkhChangeDerivationsString); + + await _secureStore.delete( + key: "${walletId}_receiveDerivationsP2PKH_BACKUP"); + await _secureStore.delete(key: "${walletId}_changeDerivationsP2PKH_BACKUP"); + + // P2SH derivations + final p2shReceiveDerivationsString = await _secureStore.read( + key: "${walletId}_receiveDerivationsP2SH_BACKUP"); + final p2shChangeDerivationsString = await _secureStore.read( + key: "${walletId}_changeDerivationsP2SH_BACKUP"); + + await _secureStore.write( + key: "${walletId}_receiveDerivationsP2SH", + value: p2shReceiveDerivationsString); + await _secureStore.write( + key: "${walletId}_changeDerivationsP2SH", + value: p2shChangeDerivationsString); + + await _secureStore.delete(key: "${walletId}_receiveDerivationsP2SH_BACKUP"); + await _secureStore.delete(key: "${walletId}_changeDerivationsP2SH_BACKUP"); + + // P2WPKH derivations + final p2wpkhReceiveDerivationsString = await _secureStore.read( + key: "${walletId}_receiveDerivationsP2WPKH_BACKUP"); + final p2wpkhChangeDerivationsString = await _secureStore.read( + key: "${walletId}_changeDerivationsP2WPKH_BACKUP"); + + await _secureStore.write( + key: "${walletId}_receiveDerivationsP2WPKH", + value: p2wpkhReceiveDerivationsString); + await _secureStore.write( + key: "${walletId}_changeDerivationsP2WPKH", + value: p2wpkhChangeDerivationsString); + + await _secureStore.delete( + key: "${walletId}_receiveDerivationsP2WPKH_BACKUP"); + await _secureStore.delete( + key: "${walletId}_changeDerivationsP2WPKH_BACKUP"); + + // UTXOs + final utxoData = DB.instance + .get(boxName: walletId, key: 'latest_utxo_model_BACKUP'); + await DB.instance.put( + boxName: walletId, key: 'latest_utxo_model', value: utxoData); + await DB.instance + .delete(key: 'latest_utxo_model_BACKUP', boxName: walletId); + + Logging.instance.log("rescan restore complete", level: LogLevel.Info); + } + + Future _rescanBackup() async { + Logging.instance.log("starting rescan backup", level: LogLevel.Info); + + // backup current and clear data + // p2pkh + final tempReceivingAddressesP2PKH = DB.instance + .get(boxName: walletId, key: 'receivingAddressesP2PKH'); + await DB.instance.put( + boxName: walletId, + key: 'receivingAddressesP2PKH_BACKUP', + value: tempReceivingAddressesP2PKH); + await DB.instance + .delete(key: 'receivingAddressesP2PKH', boxName: walletId); + + final tempChangeAddressesP2PKH = DB.instance + .get(boxName: walletId, key: 'changeAddressesP2PKH'); + await DB.instance.put( + boxName: walletId, + key: 'changeAddressesP2PKH_BACKUP', + value: tempChangeAddressesP2PKH); + await DB.instance + .delete(key: 'changeAddressesP2PKH', boxName: walletId); + + final tempReceivingIndexP2PKH = + DB.instance.get(boxName: walletId, key: 'receivingIndexP2PKH'); + await DB.instance.put( + boxName: walletId, + key: 'receivingIndexP2PKH_BACKUP', + value: tempReceivingIndexP2PKH); + await DB.instance + .delete(key: 'receivingIndexP2PKH', boxName: walletId); + + final tempChangeIndexP2PKH = + DB.instance.get(boxName: walletId, key: 'changeIndexP2PKH'); + await DB.instance.put( + boxName: walletId, + key: 'changeIndexP2PKH_BACKUP', + value: tempChangeIndexP2PKH); + await DB.instance + .delete(key: 'changeIndexP2PKH', boxName: walletId); + + // p2sh + final tempReceivingAddressesP2SH = DB.instance + .get(boxName: walletId, key: 'receivingAddressesP2SH'); + await DB.instance.put( + boxName: walletId, + key: 'receivingAddressesP2SH_BACKUP', + value: tempReceivingAddressesP2SH); + await DB.instance + .delete(key: 'receivingAddressesP2SH', boxName: walletId); + + final tempChangeAddressesP2SH = + DB.instance.get(boxName: walletId, key: 'changeAddressesP2SH'); + await DB.instance.put( + boxName: walletId, + key: 'changeAddressesP2SH_BACKUP', + value: tempChangeAddressesP2SH); + await DB.instance + .delete(key: 'changeAddressesP2SH', boxName: walletId); + + final tempReceivingIndexP2SH = + DB.instance.get(boxName: walletId, key: 'receivingIndexP2SH'); + await DB.instance.put( + boxName: walletId, + key: 'receivingIndexP2SH_BACKUP', + value: tempReceivingIndexP2SH); + await DB.instance + .delete(key: 'receivingIndexP2SH', boxName: walletId); + + final tempChangeIndexP2SH = + DB.instance.get(boxName: walletId, key: 'changeIndexP2SH'); + await DB.instance.put( + boxName: walletId, + key: 'changeIndexP2SH_BACKUP', + value: tempChangeIndexP2SH); + await DB.instance + .delete(key: 'changeIndexP2SH', boxName: walletId); + + // p2wpkh + final tempReceivingAddressesP2WPKH = DB.instance + .get(boxName: walletId, key: 'receivingAddressesP2WPKH'); + await DB.instance.put( + boxName: walletId, + key: 'receivingAddressesP2WPKH_BACKUP', + value: tempReceivingAddressesP2WPKH); + await DB.instance + .delete(key: 'receivingAddressesP2WPKH', boxName: walletId); + + final tempChangeAddressesP2WPKH = DB.instance + .get(boxName: walletId, key: 'changeAddressesP2WPKH'); + await DB.instance.put( + boxName: walletId, + key: 'changeAddressesP2WPKH_BACKUP', + value: tempChangeAddressesP2WPKH); + await DB.instance + .delete(key: 'changeAddressesP2WPKH', boxName: walletId); + + final tempReceivingIndexP2WPKH = DB.instance + .get(boxName: walletId, key: 'receivingIndexP2WPKH'); + await DB.instance.put( + boxName: walletId, + key: 'receivingIndexP2WPKH_BACKUP', + value: tempReceivingIndexP2WPKH); + await DB.instance + .delete(key: 'receivingIndexP2WPKH', boxName: walletId); + + final tempChangeIndexP2WPKH = + DB.instance.get(boxName: walletId, key: 'changeIndexP2WPKH'); + await DB.instance.put( + boxName: walletId, + key: 'changeIndexP2WPKH_BACKUP', + value: tempChangeIndexP2WPKH); + await DB.instance + .delete(key: 'changeIndexP2WPKH', boxName: walletId); + + // P2PKH derivations + final p2pkhReceiveDerivationsString = + await _secureStore.read(key: "${walletId}_receiveDerivationsP2PKH"); + final p2pkhChangeDerivationsString = + await _secureStore.read(key: "${walletId}_changeDerivationsP2PKH"); + + await _secureStore.write( + key: "${walletId}_receiveDerivationsP2PKH_BACKUP", + value: p2pkhReceiveDerivationsString); + await _secureStore.write( + key: "${walletId}_changeDerivationsP2PKH_BACKUP", + value: p2pkhChangeDerivationsString); + + await _secureStore.delete(key: "${walletId}_receiveDerivationsP2PKH"); + await _secureStore.delete(key: "${walletId}_changeDerivationsP2PKH"); + + // P2SH derivations + final p2shReceiveDerivationsString = + await _secureStore.read(key: "${walletId}_receiveDerivationsP2SH"); + final p2shChangeDerivationsString = + await _secureStore.read(key: "${walletId}_changeDerivationsP2SH"); + + await _secureStore.write( + key: "${walletId}_receiveDerivationsP2SH_BACKUP", + value: p2shReceiveDerivationsString); + await _secureStore.write( + key: "${walletId}_changeDerivationsP2SH_BACKUP", + value: p2shChangeDerivationsString); + + await _secureStore.delete(key: "${walletId}_receiveDerivationsP2SH"); + await _secureStore.delete(key: "${walletId}_changeDerivationsP2SH"); + + // P2WPKH derivations + final p2wpkhReceiveDerivationsString = + await _secureStore.read(key: "${walletId}_receiveDerivationsP2WPKH"); + final p2wpkhChangeDerivationsString = + await _secureStore.read(key: "${walletId}_changeDerivationsP2WPKH"); + + await _secureStore.write( + key: "${walletId}_receiveDerivationsP2WPKH_BACKUP", + value: p2wpkhReceiveDerivationsString); + await _secureStore.write( + key: "${walletId}_changeDerivationsP2WPKH_BACKUP", + value: p2wpkhChangeDerivationsString); + + await _secureStore.delete(key: "${walletId}_receiveDerivationsP2WPKH"); + await _secureStore.delete(key: "${walletId}_changeDerivationsP2WPKH"); + + // UTXOs + final utxoData = + DB.instance.get(boxName: walletId, key: 'latest_utxo_model'); + await DB.instance.put( + boxName: walletId, key: 'latest_utxo_model_BACKUP', value: utxoData); + await DB.instance + .delete(key: 'latest_utxo_model', boxName: walletId); + + Logging.instance.log("rescan backup complete", level: LogLevel.Info); + } + + bool isActive = false; + + @override + void Function(bool)? get onIsActiveWalletChanged => + (isActive) => this.isActive = isActive; + + @override + Future estimateFeeFor(int satoshiAmount, int feeRate) async { + final available = Format.decimalAmountToSatoshis(await availableBalance); + + if (available == satoshiAmount) { + return satoshiAmount - sweepAllEstimate(feeRate); + } else if (satoshiAmount <= 0 || satoshiAmount > available) { + return roughFeeEstimate(1, 2, feeRate); + } + + int runningBalance = 0; + int inputCount = 0; + for (final output in outputsList) { + runningBalance += output.value; + inputCount++; + if (runningBalance > satoshiAmount) { + break; + } + } + + final oneOutPutFee = roughFeeEstimate(inputCount, 1, feeRate); + final twoOutPutFee = roughFeeEstimate(inputCount, 2, feeRate); + + if (runningBalance - satoshiAmount > oneOutPutFee) { + if (runningBalance - satoshiAmount > oneOutPutFee + DUST_LIMIT) { + final change = runningBalance - satoshiAmount - twoOutPutFee; + if (change > DUST_LIMIT && + runningBalance - satoshiAmount - change == twoOutPutFee) { + return runningBalance - satoshiAmount - change; + } else { + return runningBalance - satoshiAmount; + } + } else { + return runningBalance - satoshiAmount; + } + } else if (runningBalance - satoshiAmount == oneOutPutFee) { + return oneOutPutFee; + } else { + return twoOutPutFee; + } + } + + // TODO: Check if this is the correct formula for namecoin + int roughFeeEstimate(int inputCount, int outputCount, int feeRatePerKB) { + return ((42 + (272 * inputCount) + (128 * outputCount)) / 4).ceil() * + (feeRatePerKB / 1000).ceil(); + } + + int sweepAllEstimate(int feeRate) { + int available = 0; + int inputCount = 0; + for (final output in outputsList) { + if (output.status.confirmed) { + available += output.value; + inputCount++; + } + } + + // transaction will only have 1 output minus the fee + final estimatedFee = roughFeeEstimate(inputCount, 1, feeRate); + + return available - estimatedFee; + } + + @override + Future generateNewAddress() async { + try { + await _incrementAddressIndexForChain( + 0, DerivePathType.bip84); // First increment the receiving index + final newReceivingIndex = DB.instance.get( + boxName: walletId, + key: 'receivingIndexP2WPKH') as int; // Check the new receiving index + final newReceivingAddress = await _generateAddressForChain( + 0, + newReceivingIndex, + DerivePathType + .bip84); // Use new index to derive a new receiving address + await _addToAddressesArrayForChain( + newReceivingAddress, + 0, + DerivePathType + .bip84); // Add that new receiving address to the array of receiving addresses + _currentReceivingAddress = Future(() => + newReceivingAddress); // Set the new receiving address that the service + + return true; + } catch (e, s) { + Logging.instance.log( + "Exception rethrown from generateNewAddress(): $e\n$s", + level: LogLevel.Error); + return false; + } + } +} + +// Namecoin Network +final namecoin = NetworkType( + messagePrefix: '\x18Namecoin Signed Message:\n', + bech32: 'nc', + bip32: Bip32Type(public: 0x0488b21e, private: 0x0488ade4), + pubKeyHash: 0x34, //From 52 + scriptHash: 0x0d, //13 + wif: 0xb4); //from 180 diff --git a/lib/services/price.dart b/lib/services/price.dart index 6a7160576..c1211d0ca 100644 --- a/lib/services/price.dart +++ b/lib/services/price.dart @@ -79,7 +79,8 @@ class PriceAPI { Map> result = {}; try { final uri = Uri.parse( - "https://api.coingecko.com/api/v3/coins/markets?vs_currency=${baseCurrency.toLowerCase()}&ids=monero,bitcoin,epic-cash,zcoin,dogecoin&order=market_cap_desc&per_page=10&page=1&sparkline=false"); + "https://api.coingecko.com/api/v3/coins/markets?vs_currency=${baseCurrency.toLowerCase()}&ids=monero,bitcoin,epic-cash,zcoin,dogecoin,namecoin&order=market_cap_desc&per_page=10&page=1&sparkline=false"); + // "https://api.coingecko.com/api/v3/coins/markets?vs_currency=${baseCurrency.toLowerCase()}&ids=monero,bitcoin,epic-cash,zcoin,dogecoin,bitcoin-cash,namecoin&order=market_cap_desc&per_page=10&page=1&sparkline=false"); // final uri = Uri.parse( // "https://api.coingecko.com/api/v3/coins/markets?vs_currency=${baseCurrency.toLowerCase()}&ids=monero%2Cbitcoin%2Cepic-cash%2Czcoin%2Cdogecoin&order=market_cap_desc&per_page=10&page=1&sparkline=false"); diff --git a/lib/services/wallets.dart b/lib/services/wallets.dart index 66bd968d4..034db9308 100644 --- a/lib/services/wallets.dart +++ b/lib/services/wallets.dart @@ -51,6 +51,16 @@ class Wallets extends ChangeNotifier { _managerProviderMap.values.toList(growable: false); List get managers => _managerMap.values.toList(growable: false); + List getWalletIdsFor({required Coin coin}) { + final List result = []; + for (final manager in _managerMap.values) { + if (manager.coin == coin) { + result.add(manager.walletId); + } + } + return result; + } + Map>> getManagerProvidersByCoin() { Map>> result = {}; for (final manager in _managerMap.values) { diff --git a/lib/utilities/address_utils.dart b/lib/utilities/address_utils.dart index 805dc64db..6acee305d 100644 --- a/lib/utilities/address_utils.dart +++ b/lib/utilities/address_utils.dart @@ -3,8 +3,10 @@ import 'dart:convert'; import 'package:bitcoindart/bitcoindart.dart'; import 'package:crypto/crypto.dart'; import 'package:flutter_libepiccash/epic_cash.dart'; +// import 'package:stackwallet/services/coins/bitcoincash/bitcoincash_wallet.dart'; import 'package:stackwallet/services/coins/dogecoin/dogecoin_wallet.dart'; import 'package:stackwallet/services/coins/firo/firo_wallet.dart'; +import 'package:stackwallet/services/coins/namecoin/namecoin_wallet.dart'; import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/logger.dart'; @@ -40,6 +42,8 @@ class AddressUtils { switch (coin) { case Coin.bitcoin: return Address.validateAddress(address, bitcoin); + // case Coin.bitcoincash: + // return Address.validateAddress(address, bitcoincash); case Coin.dogecoin: return Address.validateAddress(address, dogecoin); case Coin.epicCash: @@ -49,8 +53,12 @@ class AddressUtils { case Coin.monero: return RegExp("[a-zA-Z0-9]{95}").hasMatch(address) || RegExp("[a-zA-Z0-9]{106}").hasMatch(address); + case Coin.namecoin: + return Address.validateAddress(address, namecoin, namecoin.bech32!); case Coin.bitcoinTestNet: return Address.validateAddress(address, testnet); + // case Coin.bitcoincashTestnet: + // return Address.validateAddress(address, bitcoincashtestnet); case Coin.firoTestNet: return Address.validateAddress(address, firoTestNetwork); case Coin.dogecoinTestNet: diff --git a/lib/utilities/assets.dart b/lib/utilities/assets.dart index 72ceac3ca..b61f91312 100644 --- a/lib/utilities/assets.dart +++ b/lib/utilities/assets.dart @@ -1,4 +1,6 @@ +import 'package:flutter/material.dart'; import 'package:stackwallet/utilities/enums/coin_enum.dart'; +import 'package:stackwallet/utilities/theme/stack_colors.dart'; abstract class Assets { static const svg = _SVG(); @@ -19,11 +21,39 @@ class _SOCIALS { class _SVG { const _SVG(); + String bellNew(BuildContext context) => + "assets/svg/${Theme.of(context).extension()!.themeType.name}/bell-new.svg"; + String stackIcon(BuildContext context) => + "assets/svg/${Theme.of(context).extension()!.themeType.name}/stack-icon1.svg"; + String exchange(BuildContext context) => + "assets/svg/${Theme.of(context).extension()!.themeType.name}/exchange-2.svg"; + String buy(BuildContext context) => + "assets/svg/${Theme.of(context).extension()!.themeType.name}/buy-coins-icon.svg"; + + String receive(BuildContext context) => + "assets/svg/${Theme.of(context).extension()!.themeType.name}/tx-icon-receive.svg"; + String receivePending(BuildContext context) => + "assets/svg/${Theme.of(context).extension()!.themeType.name}/tx-icon-receive-pending.svg"; + String receiveCancelled(BuildContext context) => + "assets/svg/${Theme.of(context).extension()!.themeType.name}/tx-icon-receive-failed.svg"; + + String send(BuildContext context) => + "assets/svg/${Theme.of(context).extension()!.themeType.name}/tx-icon-send.svg"; + String sendPending(BuildContext context) => + "assets/svg/${Theme.of(context).extension()!.themeType.name}/tx-icon-send-pending.svg"; + String sendCancelled(BuildContext context) => + "assets/svg/${Theme.of(context).extension()!.themeType.name}/tx-icon-send-failed.svg"; + + String txExchange(BuildContext context) => + "assets/svg/${Theme.of(context).extension()!.themeType.name}/tx-exchange-icon.svg"; + String txExchangePending(BuildContext context) => + "assets/svg/${Theme.of(context).extension()!.themeType.name}/tx-exchange-icon-pending.svg"; + String txExchangeFailed(BuildContext context) => + "assets/svg/${Theme.of(context).extension()!.themeType.name}/tx-exchange-icon-failed.svg"; + String get plus => "assets/svg/plus.svg"; String get gear => "assets/svg/gear.svg"; String get bell => "assets/svg/bell.svg"; - String get bellNew => "assets/svg/bell-new.svg"; - String get stackIcon => "assets/svg/stack-icon1.svg"; String get arrowLeft => "assets/svg/arrow-left-fa.svg"; String get star => "assets/svg/star.svg"; String get copy => "assets/svg/copy-fa.svg"; @@ -35,8 +65,6 @@ class _SVG { String get bars => "assets/svg/bars.svg"; String get filter => "assets/svg/filter.svg"; String get pending => "assets/svg/pending.svg"; - String get exchange => "assets/svg/exchange-2.svg"; - String get buy => "assets/svg/buy-coins-icon.svg"; String get radio => "assets/svg/signal-stream.svg"; String get arrowRotate => "assets/svg/arrow-rotate.svg"; String get arrowRotate2 => "assets/svg/arrow-rotate2.svg"; @@ -51,6 +79,7 @@ class _SVG { String get lock => "assets/svg/lock-keyhole.svg"; String get network => "assets/svg/network-wired.svg"; String get addressBook => "assets/svg/address-book.svg"; + String get addressBook2 => "assets/svg/address-book2.svg"; String get arrowRotate3 => "assets/svg/rotate-exclamation.svg"; String get delete => "assets/svg/delete.svg"; String get arrowRight => "assets/svg/arrow-right.svg"; @@ -89,29 +118,26 @@ class _SVG { String get anonymizePending => "assets/svg/tx-icon-anonymize-pending.svg"; String get anonymizeFailed => "assets/svg/tx-icon-anonymize-failed.svg"; - String get receive => "assets/svg/tx-icon-receive.svg"; - String get receivePending => "assets/svg/tx-icon-receive-pending.svg"; - String get receiveCancelled => "assets/svg/tx-icon-receive-failed.svg"; - - String get send => "assets/svg/tx-icon-send.svg"; - String get sendPending => "assets/svg/tx-icon-send-pending.svg"; - String get sendCancelled => "assets/svg/tx-icon-send-failed.svg"; - String get ellipse1 => "assets/svg/Ellipse-43.svg"; String get ellipse2 => "assets/svg/Ellipse-42.svg"; - String get txExchange => "assets/svg/tx-exchange-icon.svg"; - String get txExchangePending => "assets/svg/tx-exchange-icon-pending.svg"; - String get txExchangeFailed => "assets/svg/tx-exchange-icon-failed.svg"; - String get bitcoin => "assets/svg/coin_icons/Bitcoin.svg"; + String get bitcoincash => "assets/svg/coin_icons/Bitcoincash.svg"; String get dogecoin => "assets/svg/coin_icons/Dogecoin.svg"; String get epicCash => "assets/svg/coin_icons/EpicCash.svg"; String get firo => "assets/svg/coin_icons/Firo.svg"; String get monero => "assets/svg/coin_icons/Monero.svg"; + String get namecoin => "assets/svg/coin_icons/Namecoin.svg"; + + String get chevronRight => "assets/svg/chevron-right.svg"; + String get minimize => "assets/svg/minimize.svg"; + String get walletFa => "assets/svg/wallet-fa.svg"; + String get exchange3 => "assets/svg/exchange-3.svg"; + String get messageQuestion => "assets/svg/message-question-1.svg"; // TODO provide proper assets String get bitcoinTestnet => "assets/svg/coin_icons/Bitcoin.svg"; + String get bitcoincashTestnet => "assets/svg/coin_icons/Bitcoincash.svg"; String get firoTestnet => "assets/svg/coin_icons/Firo.svg"; String get dogecoinTestnet => "assets/svg/coin_icons/Dogecoin.svg"; @@ -119,6 +145,8 @@ class _SVG { switch (coin) { case Coin.bitcoin: return bitcoin; + // case Coin.bitcoincash: + // return bitcoincash; case Coin.dogecoin: return dogecoin; case Coin.epicCash: @@ -127,8 +155,12 @@ class _SVG { return firo; case Coin.monero: return monero; + case Coin.namecoin: + return namecoin; case Coin.bitcoinTestNet: return bitcoinTestnet; + // case Coin.bitcoincashTestnet: + // return bitcoincashTestnet; case Coin.firoTestNet: return firoTestnet; case Coin.dogecoinTestNet: @@ -148,22 +180,30 @@ class _PNG { String get dogecoin => "assets/images/doge.png"; String get bitcoin => "assets/images/bitcoin.png"; String get epicCash => "assets/images/epic-cash.png"; + String get bitcoincash => "assets/images/bitcoincash.png"; + String get namecoin => "assets/images/namecoin.png"; String imageFor({required Coin coin}) { switch (coin) { case Coin.bitcoin: case Coin.bitcoinTestNet: return bitcoin; + // case Coin.bitcoincash: + // case Coin.bitcoincashTestnet: + // return bitcoincash; case Coin.dogecoin: case Coin.dogecoinTestNet: return dogecoin; case Coin.epicCash: return epicCash; case Coin.firo: + return firo; case Coin.firoTestNet: return firo; case Coin.monero: return monero; + case Coin.namecoin: + return namecoin; } } } diff --git a/lib/utilities/block_explorers.dart b/lib/utilities/block_explorers.dart index a9b3d5db5..e12fe84f8 100644 --- a/lib/utilities/block_explorers.dart +++ b/lib/utilities/block_explorers.dart @@ -22,5 +22,12 @@ Uri getBlockExplorerTransactionUrlFor({ return Uri.parse("https://explorer.firo.org/tx/$txid"); case Coin.firoTestNet: return Uri.parse("https://testexplorer.firo.org/tx/$txid"); + // case Coin.bitcoincash: + // return Uri.parse("https://blockchair.com/bitcoin-cash/transaction/$txid"); + // case Coin.bitcoincashTestnet: + // return Uri.parse( + // "https://blockexplorer.one/bitcoin-cash/testnet/tx/$txid"); + case Coin.namecoin: + return Uri.parse("https://chainz.cryptoid.info/nmc/tx.dws?$txid.htm"); } } diff --git a/lib/utilities/cfcolors.dart b/lib/utilities/cfcolors.dart deleted file mode 100644 index 741ca1230..000000000 --- a/lib/utilities/cfcolors.dart +++ /dev/null @@ -1,148 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:stackwallet/models/exchange/change_now/exchange_transaction_status.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; - -class _CoinThemeColor { - const _CoinThemeColor(); - - Color get bitcoin => const Color(0xFFFCC17B); - Color get firo => const Color(0xFFFF897A); - Color get dogecoin => const Color(0xFFFFE079); - Color get epicCash => const Color(0xFFC5C7CB); - Color get monero => const Color(0xFFFF9E6B); - - Color forCoin(Coin coin) { - switch (coin) { - case Coin.bitcoin: - case Coin.bitcoinTestNet: - return bitcoin; - case Coin.dogecoin: - case Coin.dogecoinTestNet: - return dogecoin; - case Coin.epicCash: - return epicCash; - case Coin.firo: - case Coin.firoTestNet: - return firo; - case Coin.monero: - return monero; - } - } -} - -class _ChangeNowTradeStatusColors { - const _ChangeNowTradeStatusColors(); - - Color get yellow => const Color(0xFFD3A90F); - Color get green => CFColors.stackGreen; - Color get red => CFColors.link; - Color get gray => CFColors.gray3; - - Color forStatus(ChangeNowTransactionStatus status) { - switch (status) { - case ChangeNowTransactionStatus.New: - case ChangeNowTransactionStatus.Waiting: - case ChangeNowTransactionStatus.Confirming: - case ChangeNowTransactionStatus.Exchanging: - case ChangeNowTransactionStatus.Sending: - case ChangeNowTransactionStatus.Verifying: - return yellow; - case ChangeNowTransactionStatus.Finished: - return green; - case ChangeNowTransactionStatus.Failed: - return red; - case ChangeNowTransactionStatus.Refunded: - return gray; - } - } -} - -abstract class CFColors { - static const coin = _CoinThemeColor(); - static const status = _ChangeNowTradeStatusColors(); - - static const Color splashLight = Color(0x44A9ACAC); - static const Color splashMed = Color(0x358E9192); - static const Color splashDark = Color(0x33232323); - - static const Color selected = Color(0xFFF9F9FC); - static const Color selected2 = Color(0xFFE0E3E3); - - static const Color primary = Color(0xFF0052DF); - static const Color primaryLight = Color(0xFFDAE2FF); - - static const Color link = Color(0xFFC00205); - static const Color link2 = Color(0xFF0056D2); - - static const Color warningBackground = Color(0xFFFFDAD3); - - static const Color marked = Color(0xFFF61515); - static const Color stackGreen = Color(0xFF00A578); - static const Color stackYellow = Color(0xFFF4C517); - static const Color stackGreen15 = Color(0xFFD2EBE4); - static const Color stackRed = Color(0xFFDC5673); - static const Color sentTx = Color(0x66FE805C); - static const Color receivedTx = Color(0x6600A578); - // static const Color stackAccent = Color(0xFF232323); - // static const Color stackAccent = Color(0xFF232323); - static const Color stackAccent = Color(0xFF232323); - static const Color black = Color(0xFF191B23); - - static const Color primaryBlue = Color(0xFF074EE8); - static const Color notificationBlueBackground = Color(0xFFDAE2FF); - static const Color notificationBlueForeground = Color(0xFF002A78); - static const Color notificationGreenBackground = Color(0xFFB9E9D4); - static const Color notificationGreenForeground = Color(0xFF006C4D); - static const Color notificationRedBackground = Color(0xFFFFDAD4); - static const Color notificationRedForeground = Color(0xFF930006); - static const Color error = Color(0xFF930006); - - static const Color almostWhite = Color(0xFFF7F7F7); - static const Color light1 = Color(0xFFF5F5F5); - - static const Color disabledButton = Color(0xFFE0E3E3); - - static const Color neutral80 = Color(0xFFC5C6C9); - static const Color neutral60 = Color(0xFF8E9192); - static const Color neutral50 = Color(0xFF747778); - static const Color selection = Color(0xFFD9E2FF); - static const Color buttonGray = Color(0xFFE0E3E3); - - static const Color textFieldInactive = Color(0xFFEEEFF1); - static const Color fieldGray = Color(0xFFEEEFF1); - static const Color textFieldActive = Color(0xFFE9EAEC); - - static const Color contactIconBackground = Color(0xFFF4F5F8); - - static const Color gray3 = Color(0xFFA9ACAC); - // shadow - static const Color shadowColor = Color(0x0F2D3132); - static const BoxShadow standardBoxShadow = BoxShadow( - color: CFColors.shadowColor, - spreadRadius: 3, - blurRadius: 4, - ); - - // generic - static const Color white = Color(0xFFFFFFFF); - - static MaterialColor createMaterialColor(Color color) { - List strengths = [.05]; - final swatch = {}; - final int r = color.red, g = color.green, b = color.blue; - - for (int i = 1; i < 10; i++) { - strengths.add(0.1 * i); - } - for (var strength in strengths) { - final double ds = 0.5 - strength; - swatch[(strength * 1000).round()] = Color.fromRGBO( - r + ((ds < 0 ? r : (255 - r)) * ds).round(), - g + ((ds < 0 ? g : (255 - g)) * ds).round(), - b + ((ds < 0 ? b : (255 - b)) * ds).round(), - 1, - ); - } - return MaterialColor(color.value, swatch); - } -} diff --git a/lib/utilities/constants.dart b/lib/utilities/constants.dart index 3b82cde40..62f31a770 100644 --- a/lib/utilities/constants.dart +++ b/lib/utilities/constants.dart @@ -39,12 +39,15 @@ abstract class Constants { final List values = []; switch (coin) { case Coin.bitcoin: + // case Coin.bitcoincash: + // case Coin.bitcoincashTestnet: case Coin.dogecoin: case Coin.firo: case Coin.bitcoinTestNet: case Coin.dogecoinTestNet: case Coin.firoTestNet: case Coin.epicCash: + case Coin.namecoin: values.addAll([24, 21, 18, 15, 12]); break; @@ -62,6 +65,10 @@ abstract class Constants { case Coin.bitcoinTestNet: return 600; + // case Coin.bitcoincash: + // case Coin.bitcoincashTestnet: + // return 600; + case Coin.dogecoin: case Coin.dogecoinTestNet: return 60; @@ -75,6 +82,9 @@ abstract class Constants { case Coin.monero: return 120; + + case Coin.namecoin: + return 600; } } diff --git a/lib/utilities/default_nodes.dart b/lib/utilities/default_nodes.dart index d2e042439..5fa82f9ac 100644 --- a/lib/utilities/default_nodes.dart +++ b/lib/utilities/default_nodes.dart @@ -13,7 +13,10 @@ abstract class DefaultNodes { firo, monero, epicCash, + // bitcoincash, + namecoin, bitcoinTestnet, + // bitcoincashTestnet, dogecoinTestnet, firoTestnet, ]; @@ -30,6 +33,18 @@ abstract class DefaultNodes { isDown: false, ); + // static NodeModel get bitcoincash => NodeModel( + // host: "bitcoincash.stackwallet.com", + // port: 50002, + // name: defaultName, + // id: _nodeId(Coin.bitcoincash), + // useSSL: true, + // enabled: true, + // coinName: Coin.bitcoincash.name, + // isFailover: true, + // isDown: false, + // ); + static NodeModel get dogecoin => NodeModel( host: "dogecoin.stackwallet.com", port: 50022, @@ -80,6 +95,18 @@ abstract class DefaultNodes { isDown: false, ); + static NodeModel get namecoin => NodeModel( + host: "namecoin.stackwallet.com", + port: 57002, + name: defaultName, + id: _nodeId(Coin.namecoin), + useSSL: true, + enabled: true, + coinName: Coin.namecoin.name, + isFailover: true, + isDown: false, + ); + static NodeModel get bitcoinTestnet => NodeModel( host: "electrumx-testnet.cypherstack.com", port: 51002, @@ -116,10 +143,25 @@ abstract class DefaultNodes { isDown: false, ); + // static NodeModel get bitcoincashTestnet => NodeModel( + // host: "testnet.hsmiths.com", + // port: 53012, + // name: defaultName, + // id: _nodeId(Coin.bitcoincash), + // useSSL: true, + // enabled: true, + // coinName: Coin.bitcoincash.name, + // isFailover: true, + // isDown: false, + // ); + static NodeModel getNodeFor(Coin coin) { switch (coin) { case Coin.bitcoin: return bitcoin; + // + // case Coin.bitcoincash: + // return bitcoincash; case Coin.dogecoin: return dogecoin; @@ -133,9 +175,15 @@ abstract class DefaultNodes { case Coin.monero: return monero; + case Coin.namecoin: + return namecoin; + case Coin.bitcoinTestNet: return bitcoinTestnet; + // case Coin.bitcoincashTestnet: + // return bitcoincashTestnet; + case Coin.firoTestNet: return firoTestnet; diff --git a/lib/utilities/enums/coin_enum.dart b/lib/utilities/enums/coin_enum.dart index 9e489dde4..1c30d86ec 100644 --- a/lib/utilities/enums/coin_enum.dart +++ b/lib/utilities/enums/coin_enum.dart @@ -5,19 +5,24 @@ import 'package:stackwallet/services/coins/epiccash/epiccash_wallet.dart' as epic; import 'package:stackwallet/services/coins/firo/firo_wallet.dart' as firo; import 'package:stackwallet/services/coins/monero/monero_wallet.dart' as xmr; +import 'package:stackwallet/services/coins/namecoin/namecoin_wallet.dart' + as nmc; enum Coin { bitcoin, + // bitcoincash, dogecoin, epicCash, firo, monero, + namecoin, /// /// /// bitcoinTestNet, + // bitcoincashTestnet, dogecoinTestNet, firoTestNet, } @@ -30,6 +35,8 @@ extension CoinExt on Coin { switch (this) { case Coin.bitcoin: return "Bitcoin"; + // case Coin.bitcoincash: + // return "Bitcoin Cash"; case Coin.dogecoin: return "Dogecoin"; case Coin.epicCash: @@ -38,8 +45,12 @@ extension CoinExt on Coin { return "Firo"; case Coin.monero: return "Monero"; + case Coin.namecoin: + return "Namecoin"; case Coin.bitcoinTestNet: return "tBitcoin"; + // case Coin.bitcoincashTestnet: + // return "tBitcoin Cash"; case Coin.firoTestNet: return "tFiro"; case Coin.dogecoinTestNet: @@ -51,6 +62,8 @@ extension CoinExt on Coin { switch (this) { case Coin.bitcoin: return "BTC"; + // case Coin.bitcoincash: + // return "BCH"; case Coin.dogecoin: return "DOGE"; case Coin.epicCash: @@ -59,8 +72,12 @@ extension CoinExt on Coin { return "FIRO"; case Coin.monero: return "XMR"; + case Coin.namecoin: + return "NMC"; case Coin.bitcoinTestNet: return "tBTC"; + // case Coin.bitcoincashTestnet: + // return "tBCH"; case Coin.firoTestNet: return "tFIRO"; case Coin.dogecoinTestNet: @@ -72,6 +89,8 @@ extension CoinExt on Coin { switch (this) { case Coin.bitcoin: return "bitcoin"; + // case Coin.bitcoincash: + // return "bitcoincash"; case Coin.dogecoin: return "dogecoin"; case Coin.epicCash: @@ -81,8 +100,12 @@ extension CoinExt on Coin { return "firo"; case Coin.monero: return "monero"; + case Coin.namecoin: + return "namecoin"; case Coin.bitcoinTestNet: return "bitcoin"; + // case Coin.bitcoincashTestnet: + // return "bitcoincash"; case Coin.firoTestNet: return "firo"; case Coin.dogecoinTestNet: @@ -93,9 +116,12 @@ extension CoinExt on Coin { bool get isElectrumXCoin { switch (this) { case Coin.bitcoin: + // case Coin.bitcoincash: case Coin.dogecoin: case Coin.firo: + case Coin.namecoin: case Coin.bitcoinTestNet: + // case Coin.bitcoincashTestnet: case Coin.firoTestNet: case Coin.dogecoinTestNet: return true; @@ -112,6 +138,10 @@ extension CoinExt on Coin { case Coin.bitcoinTestNet: return btc.MINIMUM_CONFIRMATIONS; + // case Coin.bitcoincash: + // case Coin.bitcoincashTestnet: + // return bch.MINIMUM_CONFIRMATIONS; + case Coin.firo: case Coin.firoTestNet: return firo.MINIMUM_CONFIRMATIONS; @@ -125,6 +155,8 @@ extension CoinExt on Coin { case Coin.monero: return xmr.MINIMUM_CONFIRMATIONS; + case Coin.namecoin: + return nmc.MINIMUM_CONFIRMATIONS; } } } @@ -134,6 +166,10 @@ Coin coinFromPrettyName(String name) { case "Bitcoin": case "bitcoin": return Coin.bitcoin; + // case "Bitcoincash": + // case "bitcoincash": + // case "Bitcoin Cash": + // return Coin.bitcoincash; case "Dogecoin": case "dogecoin": return Coin.dogecoin; @@ -146,10 +182,18 @@ Coin coinFromPrettyName(String name) { case "Monero": case "monero": return Coin.monero; + case "Namecoin": + case "namecoin": + return Coin.namecoin; case "Bitcoin Testnet": case "tBitcoin": case "bitcoinTestNet": return Coin.bitcoinTestNet; + + // case "Bitcoincash Testnet": + // case "tBitcoin Cash": + // case "Bitcoin Cash Testnet": + // return Coin.bitcoincashTestnet; case "Firo Testnet": case "tFiro": case "firoTestNet": @@ -168,6 +212,8 @@ Coin coinFromTickerCaseInsensitive(String ticker) { switch (ticker.toLowerCase()) { case "btc": return Coin.bitcoin; + // case "bch": + // return Coin.bitcoincash; case "doge": return Coin.dogecoin; case "epic": @@ -176,8 +222,12 @@ Coin coinFromTickerCaseInsensitive(String ticker) { return Coin.firo; case "xmr": return Coin.monero; + case "nmc": + return Coin.namecoin; case "tbtc": return Coin.bitcoinTestNet; + // case "tbch": + // return Coin.bitcoincashTestnet; case "tfiro": return Coin.firoTestNet; case "tdoge": diff --git a/lib/utilities/text_styles.dart b/lib/utilities/text_styles.dart index 71612a660..191f863f1 100644 --- a/lib/utilities/text_styles.dart +++ b/lib/utilities/text_styles.dart @@ -1,175 +1,259 @@ import 'package:flutter/material.dart'; import 'package:google_fonts/google_fonts.dart'; -import 'package:stackwallet/utilities/cfcolors.dart'; +import 'package:stackwallet/utilities/theme/stack_colors.dart'; class STextStyles { - static final TextStyle pageTitleH1 = GoogleFonts.inter( - color: CFColors.black, - fontWeight: FontWeight.w600, - fontSize: 20, - ); + static TextStyle pageTitleH1(BuildContext context) => GoogleFonts.inter( + color: Theme.of(context).extension()!.textDark, + fontWeight: FontWeight.w600, + fontSize: 20, + ); - static final TextStyle pageTitleH2 = GoogleFonts.inter( - color: CFColors.stackAccent, - fontWeight: FontWeight.w600, - fontSize: 18, - ); + static TextStyle pageTitleH2(BuildContext context) => GoogleFonts.inter( + color: Theme.of(context).extension()!.textDark, + fontWeight: FontWeight.w600, + fontSize: 18, + ); - static final TextStyle navBarTitle = GoogleFonts.inter( - color: CFColors.stackAccent, - fontWeight: FontWeight.w600, - fontSize: 16, - ); + static TextStyle navBarTitle(BuildContext context) => GoogleFonts.inter( + color: Theme.of(context).extension()!.textDark, + fontWeight: FontWeight.w600, + fontSize: 16, + ); - static final TextStyle titleBold12 = GoogleFonts.inter( - color: CFColors.stackAccent, - fontWeight: FontWeight.w600, - fontSize: 16, - ); + static TextStyle titleBold12(BuildContext context) => GoogleFonts.inter( + color: Theme.of(context).extension()!.textDark, + fontWeight: FontWeight.w600, + fontSize: 16, + ); - static final TextStyle subtitle = GoogleFonts.inter( - color: CFColors.stackAccent, - fontWeight: FontWeight.w400, - fontSize: 16, - ); + static TextStyle subtitle(BuildContext context) => GoogleFonts.inter( + color: Theme.of(context).extension()!.textDark, + fontWeight: FontWeight.w400, + fontSize: 16, + ); - static final TextStyle button = GoogleFonts.inter( - color: CFColors.white, - fontWeight: FontWeight.w500, - fontSize: 16, - ); + static TextStyle button(BuildContext context) => GoogleFonts.inter( + color: Theme.of(context).extension()!.buttonTextPrimary, + fontWeight: FontWeight.w500, + fontSize: 16, + ); - static final TextStyle largeMedium14 = GoogleFonts.inter( - color: CFColors.stackAccent, - fontWeight: FontWeight.w500, - fontSize: 16, - ); + static TextStyle largeMedium14(BuildContext context) => GoogleFonts.inter( + color: Theme.of(context).extension()!.textDark, + fontWeight: FontWeight.w500, + fontSize: 16, + ); - static final TextStyle smallMed14 = GoogleFonts.inter( - color: CFColors.neutral50, - fontWeight: FontWeight.w500, - fontSize: 16, - ); + static TextStyle smallMed14(BuildContext context) => GoogleFonts.inter( + color: Theme.of(context).extension()!.textDark3, + fontWeight: FontWeight.w500, + fontSize: 16, + ); - static final TextStyle smallMed12 = GoogleFonts.inter( - color: CFColors.neutral50, - fontWeight: FontWeight.w500, - fontSize: 14, - ); + static TextStyle smallMed12(BuildContext context) => GoogleFonts.inter( + color: Theme.of(context).extension()!.textDark3, + fontWeight: FontWeight.w500, + fontSize: 14, + ); - static final TextStyle label = GoogleFonts.inter( - color: CFColors.neutral60, - fontWeight: FontWeight.w500, - fontSize: 12, - ); + static TextStyle label(BuildContext context) => GoogleFonts.inter( + color: Theme.of(context).extension()!.textSubtitle1, + fontWeight: FontWeight.w500, + fontSize: 12, + ); - static final TextStyle itemSubtitle = GoogleFonts.inter( - color: CFColors.neutral60, - fontWeight: FontWeight.w500, - fontSize: 14, - ); + static TextStyle itemSubtitle(BuildContext context) => GoogleFonts.inter( + color: Theme.of(context).extension()!.infoItemLabel, + fontWeight: FontWeight.w500, + fontSize: 14, + ); - static final TextStyle itemSubtitle12 = GoogleFonts.inter( - color: CFColors.stackAccent, - fontWeight: FontWeight.w500, - fontSize: 14, - ); + static TextStyle itemSubtitle12(BuildContext context) => GoogleFonts.inter( + color: Theme.of(context).extension()!.textDark, + fontWeight: FontWeight.w500, + fontSize: 14, + ); - static final TextStyle fieldLabel = GoogleFonts.inter( - color: CFColors.gray3, - fontWeight: FontWeight.w500, - fontSize: 14, - height: 1.5, - ); + static TextStyle fieldLabel(BuildContext context) => GoogleFonts.inter( + color: Theme.of(context).extension()!.textSubtitle2, + fontWeight: FontWeight.w500, + fontSize: 14, + height: 1.5, + ); - static final TextStyle field = GoogleFonts.inter( - color: CFColors.stackAccent, - fontWeight: FontWeight.w500, - fontSize: 14, - height: 1.5, - ); + static TextStyle field(BuildContext context) => GoogleFonts.inter( + color: Theme.of(context).extension()!.textDark, + fontWeight: FontWeight.w500, + fontSize: 14, + height: 1.5, + ); - static final TextStyle baseXS = GoogleFonts.inter( - color: CFColors.stackAccent, - fontWeight: FontWeight.w400, - fontSize: 14, - ); + static TextStyle baseXS(BuildContext context) => GoogleFonts.inter( + color: Theme.of(context).extension()!.textDark, + fontWeight: FontWeight.w400, + fontSize: 14, + ); - static final TextStyle link = GoogleFonts.inter( - color: CFColors.link, - fontWeight: FontWeight.w500, - fontSize: 14, - ); + static TextStyle link(BuildContext context) => GoogleFonts.inter( + color: Theme.of(context).extension()!.accentColorRed, + fontWeight: FontWeight.w500, + fontSize: 14, + ); - static final TextStyle link2 = GoogleFonts.inter( - color: CFColors.link2, - fontWeight: FontWeight.w500, - fontSize: 14, - ); + static TextStyle link2(BuildContext context) => GoogleFonts.inter( + color: Theme.of(context).extension()!.infoItemIcons, + fontWeight: FontWeight.w500, + fontSize: 14, + ); - static final TextStyle richLink = GoogleFonts.inter( - color: CFColors.primaryBlue, - fontWeight: FontWeight.w500, - fontSize: 12, - ); + static TextStyle richLink(BuildContext context) => GoogleFonts.inter( + color: Theme.of(context).extension()!.accentColorBlue, + fontWeight: FontWeight.w500, + fontSize: 12, + ); - static final TextStyle w600_10 = GoogleFonts.inter( - color: CFColors.stackAccent, - fontWeight: FontWeight.w600, - fontSize: 12, - ); + static TextStyle w600_10(BuildContext context) => GoogleFonts.inter( + color: Theme.of(context).extension()!.textDark, + fontWeight: FontWeight.w600, + fontSize: 12, + ); - static final TextStyle syncPercent = GoogleFonts.inter( - color: CFColors.stackAccent, - fontWeight: FontWeight.w500, - fontSize: 12, - ); + static TextStyle syncPercent(BuildContext context) => GoogleFonts.inter( + color: Theme.of(context).extension()!.textDark, + fontWeight: FontWeight.w500, + fontSize: 12, + ); - static final TextStyle buttonSmall = GoogleFonts.inter( - color: CFColors.stackAccent, - fontWeight: FontWeight.w500, - fontSize: 12, - ); + static TextStyle buttonSmall(BuildContext context) => GoogleFonts.inter( + color: Theme.of(context).extension()!.textDark, + fontWeight: FontWeight.w500, + fontSize: 12, + ); - static final TextStyle errorSmall = GoogleFonts.inter( - color: CFColors.error, - fontWeight: FontWeight.w500, - fontSize: 10, - ); + static TextStyle errorSmall(BuildContext context) => GoogleFonts.inter( + color: Theme.of(context).extension()!.textError, + fontWeight: FontWeight.w500, + fontSize: 10, + ); - static final TextStyle infoSmall = GoogleFonts.inter( - color: CFColors.neutral60, - fontWeight: FontWeight.w500, - fontSize: 10, - ); + static TextStyle infoSmall(BuildContext context) => GoogleFonts.inter( + color: Theme.of(context).extension()!.textSubtitle1, + fontWeight: FontWeight.w500, + fontSize: 10, + ); - // static final TextStyle pinkHeader = GoogleFonts.workSans( - // color: CFColors.spark, - // fontWeight: FontWeight.w600, - // fontSize: 20, - // ); - // - // static final TextStyle textField = GoogleFonts.workSans( - // color: CFColors.dusk, - // fontWeight: FontWeight.w400, - // fontSize: 16, - // ); - // - // static final TextStyle textFieldHint = GoogleFonts.workSans( - // color: CFColors.twilight, - // fontWeight: FontWeight.w400, - // fontSize: 16, - // ); - // - // static final TextStyle textFieldSuffix = GoogleFonts.workSans( - // color: CFColors.twilight, - // fontWeight: FontWeight.w600, - // fontSize: 16, - // ); - // - // static final TextStyle label = GoogleFonts.workSans( - // color: CFColors.twilight, - // fontWeight: FontWeight.w500, - // fontSize: 12, - // ); +// Desktop + + static TextStyle desktopH2(BuildContext context) => GoogleFonts.inter( + color: Theme.of(context).extension()!.textDark, + fontWeight: FontWeight.w600, + fontSize: 32, + height: 32 / 32, + ); + + static TextStyle desktopH3(BuildContext context) => GoogleFonts.inter( + color: Theme.of(context).extension()!.textDark, + fontWeight: FontWeight.w600, + fontSize: 24, + height: 24 / 24, + ); + + static TextStyle desktopTextMedium(BuildContext context) => GoogleFonts.inter( + color: Theme.of(context).extension()!.textDark, + fontWeight: FontWeight.w500, + fontSize: 20, + height: 30 / 20, + ); + + static TextStyle desktopTextMediumRegular(BuildContext context) => + GoogleFonts.inter( + color: Theme.of(context).extension()!.textDark, + fontWeight: FontWeight.w400, + fontSize: 20, + height: 30 / 20, + ); + + static TextStyle desktopSubtitleH2(BuildContext context) => GoogleFonts.inter( + color: Theme.of(context).extension()!.textDark, + fontWeight: FontWeight.w400, + fontSize: 20, + height: 28 / 20, + ); + + static TextStyle desktopSubtitleH1(BuildContext context) => GoogleFonts.inter( + color: Theme.of(context).extension()!.textDark, + fontWeight: FontWeight.w400, + fontSize: 24, + height: 33 / 24, + ); + + static TextStyle desktopButtonEnabled(BuildContext context) => + GoogleFonts.inter( + color: Theme.of(context).extension()!.buttonTextPrimary, + fontWeight: FontWeight.w500, + fontSize: 20, + height: 26 / 20, + ); + + static TextStyle desktopButtonDisabled(BuildContext context) => + GoogleFonts.inter( + color: Theme.of(context) + .extension()! + .buttonTextPrimaryDisabled, + fontWeight: FontWeight.w500, + fontSize: 20, + height: 26 / 20, + ); + + static TextStyle desktopButtonSecondaryEnabled(BuildContext context) => + GoogleFonts.inter( + color: Theme.of(context).extension()!.buttonTextSecondary, + fontWeight: FontWeight.w500, + fontSize: 20, + height: 26 / 20, + ); + + static TextStyle desktopTextExtraSmall(BuildContext context) => + GoogleFonts.inter( + color: Theme.of(context) + .extension()! + .buttonTextPrimaryDisabled, + fontWeight: FontWeight.w500, + fontSize: 16, + height: 24 / 16, + ); + + static TextStyle desktopButtonSmallSecondaryEnabled(BuildContext context) => + GoogleFonts.inter( + color: Theme.of(context).extension()!.buttonTextSecondary, + fontWeight: FontWeight.w500, + fontSize: 16, + height: 24 / 16, + ); + + static TextStyle desktopTextFieldLabel(BuildContext context) => + GoogleFonts.inter( + color: Theme.of(context).extension()!.textSubtitle2, + fontWeight: FontWeight.w500, + fontSize: 20, + height: 30 / 20, + ); + + static TextStyle desktopMenuItem(BuildContext context) => GoogleFonts.inter( + color: Theme.of(context) + .extension()! + .textDark + .withOpacity(0.8), + fontWeight: FontWeight.w500, + fontSize: 16, + height: 20.8 / 16, + ); + static TextStyle desktopMenuItemSelected(BuildContext context) => + GoogleFonts.inter( + color: Theme.of(context).extension()!.textDark, + fontWeight: FontWeight.w500, + fontSize: 16, + height: 20.8 / 16, + ); } diff --git a/lib/utilities/theme/color_theme.dart b/lib/utilities/theme/color_theme.dart new file mode 100644 index 000000000..73da6ba66 --- /dev/null +++ b/lib/utilities/theme/color_theme.dart @@ -0,0 +1,214 @@ +import 'dart:ui'; + +import 'package:stackwallet/utilities/enums/coin_enum.dart'; + +enum ThemeType { + light, + dark, +} + +abstract class StackColorTheme { + ThemeType get themeType; + + Color get background; + Color get overlay; + + Color get accentColorBlue; + Color get accentColorGreen; + Color get accentColorYellow; + Color get accentColorRed; + Color get accentColorOrange; + Color get accentColorDark; + + Color get shadow; + + Color get textDark; + Color get textDark2; + Color get textDark3; + Color get textSubtitle1; + Color get textSubtitle2; + Color get textSubtitle3; + Color get textSubtitle4; + Color get textSubtitle5; + Color get textSubtitle6; + Color get textWhite; + Color get textFavoriteCard; + Color get textError; + +// button background + Color get buttonBackPrimary; + Color get buttonBackSecondary; + Color get buttonBackPrimaryDisabled; + Color get buttonBackSecondaryDisabled; + Color get buttonBackBorder; + Color get buttonBackBorderDisabled; + Color get numberBackDefault; + Color get numpadBackDefault; + Color get bottomNavBack; + +// button text/element + Color get buttonTextPrimary; + Color get buttonTextSecondary; + Color get buttonTextPrimaryDisabled; + Color get buttonTextSecondaryDisabled; + Color get buttonTextBorder; + Color get buttonTextDisabled; + Color get buttonTextBorderless; + Color get buttonTextBorderlessDisabled; + Color get numberTextDefault; + Color get numpadTextDefault; + Color get bottomNavText; + +// switch background + Color get switchBGOn; + Color get switchBGOff; + Color get switchBGDisabled; + +// switch circle + Color get switchCircleOn; + Color get switchCircleOff; + Color get switchCircleDisabled; + +// step indicator background + Color get stepIndicatorBGCheck; + Color get stepIndicatorBGNumber; + Color get stepIndicatorBGInactive; + Color get stepIndicatorBGLines; + Color get stepIndicatorBGLinesInactive; + Color get stepIndicatorIconText; + Color get stepIndicatorIconNumber; + Color get stepIndicatorIconInactive; + +// checkbox + Color get checkboxBGChecked; + Color get checkboxBorderEmpty; + Color get checkboxBGDisabled; + Color get checkboxIconChecked; + Color get checkboxIconDisabled; + Color get checkboxTextLabel; + +// snack bar + Color get snackBarBackSuccess; + Color get snackBarBackError; + Color get snackBarBackInfo; + Color get snackBarTextSuccess; + Color get snackBarTextError; + Color get snackBarTextInfo; + +// icons + Color get bottomNavIconBack; + Color get bottomNavIconIcon; + Color get topNavIconPrimary; + Color get topNavIconGreen; + Color get topNavIconYellow; + Color get topNavIconRed; + Color get settingsIconBack; + Color get settingsIconIcon; + Color get settingsIconBack2; + Color get settingsIconElement; + +// text field + Color get textFieldActiveBG; + Color get textFieldDefaultBG; + Color get textFieldErrorBG; + Color get textFieldSuccessBG; + Color get textFieldActiveSearchIconLeft; + Color get textFieldDefaultSearchIconLeft; + Color get textFieldErrorSearchIconLeft; + Color get textFieldSuccessSearchIconLeft; + Color get textFieldActiveText; + Color get textFieldDefaultText; + Color get textFieldErrorText; + Color get textFieldSuccessText; + Color get textFieldActiveLabel; + Color get textFieldErrorLabel; + Color get textFieldSuccessLabel; + Color get textFieldActiveSearchIconRight; + Color get textFieldDefaultSearchIconRight; + Color get textFieldErrorSearchIconRight; + Color get textFieldSuccessSearchIconRight; + +// settings item level2 + Color get settingsItem2ActiveBG; + Color get settingsItem2ActiveText; + Color get settingsItem2ActiveSub; + +// radio buttons + Color get radioButtonIconBorder; + Color get radioButtonIconBorderDisabled; + Color get radioButtonBorderEnabled; + Color get radioButtonBorderDisabled; + Color get radioButtonIconCircle; + Color get radioButtonIconEnabled; + Color get radioButtonTextEnabled; + Color get radioButtonTextDisabled; + Color get radioButtonLabelEnabled; + Color get radioButtonLabelDisabled; + +// info text + Color get infoItemBG; + Color get infoItemLabel; + Color get infoItemText; + Color get infoItemIcons; + +// popup + Color get popupBG; + +// currency list + Color get currencyListItemBG; + +// bottom nav + Color get stackWalletBG; + Color get stackWalletMid; + Color get stackWalletBottom; + Color get bottomNavShadow; + + Color get favoriteStarActive; + Color get favoriteStarInactive; + + Color get splash; + Color get highlight; + Color get warningForeground; + Color get warningBackground; + + Color get loadingOverlayTextColor; + Color get myStackContactIconBG; +} + +class CoinThemeColor { + const CoinThemeColor(); + + Color get bitcoin => const Color(0xFFFCC17B); + Color get bitcoincash => const Color(0xFF7BCFB8); + Color get firo => const Color(0xFFFF897A); + Color get dogecoin => const Color(0xFFFFE079); + Color get epicCash => const Color(0xFFC5C7CB); + Color get monero => const Color(0xFFFF9E6B); + Color get namecoin => const Color(0xFF91B1E1); + Color get wownero => const Color(0xFFED80C1); + + Color forCoin(Coin coin) { + switch (coin) { + case Coin.bitcoin: + case Coin.bitcoinTestNet: + return bitcoin; + // case Coin.bitcoincash: + // case Coin.bitcoincashTestnet: + // return bitcoincash; + case Coin.dogecoin: + case Coin.dogecoinTestNet: + return dogecoin; + case Coin.epicCash: + return epicCash; + case Coin.firo: + case Coin.firoTestNet: + return firo; + case Coin.monero: + return monero; + case Coin.namecoin: + return namecoin; + // case Coin.wownero: + // return wownero; + } + } +} diff --git a/lib/utilities/theme/dark_colors.dart b/lib/utilities/theme/dark_colors.dart new file mode 100644 index 000000000..ee7551a27 --- /dev/null +++ b/lib/utilities/theme/dark_colors.dart @@ -0,0 +1,302 @@ +import 'package:flutter/material.dart'; +import 'package:stackwallet/utilities/theme/color_theme.dart'; + +class DarkColors extends StackColorTheme { + @override + ThemeType get themeType => ThemeType.dark; + + @override + Color get background => const Color(0xFF2A2D34); + @override + Color get overlay => const Color(0xFF111215); + + @override + Color get accentColorBlue => const Color(0xFF4C86E9); + @override + Color get accentColorGreen => const Color(0xFF4CC0A0); + @override + Color get accentColorYellow => const Color(0xFFF7D65D); + @override + Color get accentColorRed => const Color(0xFFD34E50); + @override + Color get accentColorOrange => const Color(0xFFFEA68D); + @override + Color get accentColorDark => const Color(0xFFF3F3F3); + + @override + Color get shadow => const Color(0x0F2D3132); + + @override + Color get textDark => const Color(0xFFF3F3F3); + @override + Color get textDark2 => const Color(0xFFDBDBDB); + @override + Color get textDark3 => const Color(0xFFEEEFF1); + @override + Color get textSubtitle1 => const Color(0xFF9E9E9E); + @override + Color get textSubtitle2 => const Color(0xFF969696); + @override + Color get textSubtitle3 => const Color(0xFFA9ACAC); + @override + Color get textSubtitle4 => const Color(0xFF8E9192); + @override + Color get textSubtitle5 => const Color(0xFF747778); + @override + Color get textSubtitle6 => const Color(0xFF414141); + @override + Color get textWhite => const Color(0xFF232323); + @override + Color get textFavoriteCard => const Color(0xFF232323); + @override + Color get textError => const Color(0xFFF37475); + + // button background + @override + Color get buttonBackPrimary => const Color(0xFF4C86E9); + @override + Color get buttonBackSecondary => const Color(0xFF444E5C); + @override + Color get buttonBackPrimaryDisabled => const Color(0xFF38517C); + @override + Color get buttonBackSecondaryDisabled => const Color(0xFF3B3F46); + @override + Color get buttonBackBorder => const Color(0xFF4C86E9); + @override + Color get buttonBackBorderDisabled => const Color(0xFF314265); + + @override + Color get numberBackDefault => const Color(0xFF484B51); + @override + Color get numpadBackDefault => const Color(0xFF4C86E9); + @override + Color get bottomNavBack => const Color(0xFFA2A2A2); + + // button text/element + @override + Color get buttonTextPrimary => const Color(0xFFFFFFFF); + @override + Color get buttonTextSecondary => const Color(0xFFFFFFFF); + @override + Color get buttonTextPrimaryDisabled => const Color(0xFFFFFFFF); + @override + Color get buttonTextSecondaryDisabled => const Color(0xFF6A6C71); + @override + Color get buttonTextBorder => const Color(0xFF4C86E9); + @override + Color get buttonTextDisabled => const Color(0xFF314265); + @override + Color get buttonTextBorderless => const Color(0xFF4C86E9); + @override + Color get buttonTextBorderlessDisabled => const Color(0xFFB6B6B6); + @override + Color get numberTextDefault => const Color(0xFFFFFFFF); + @override + Color get numpadTextDefault => const Color(0xFFFFFFFF); + @override + Color get bottomNavText => const Color(0xFFFFFFFF); + + // switch + @override + Color get switchBGOn => const Color(0xFF4C86E9); + @override + Color get switchBGOff => const Color(0xFFC1D9FF); + @override + Color get switchBGDisabled => const Color(0xFFB5B7BA); + @override + Color get switchCircleOn => const Color(0xFFC9DDFF); + @override + Color get switchCircleOff => const Color(0xFFFFFFFF); + @override + Color get switchCircleDisabled => const Color(0xFFFFFFFF); + + // step indicator background + @override + Color get stepIndicatorBGCheck => const Color(0xFF4C86E9); + @override + Color get stepIndicatorBGNumber => const Color(0xFF4C86E9); + @override + Color get stepIndicatorBGInactive => const Color(0xFF3B3F46); + @override + Color get stepIndicatorBGLines => const Color(0xFF4C86E9); + @override + Color get stepIndicatorBGLinesInactive => const Color(0xFF3B3F46); + @override + Color get stepIndicatorIconText => const Color(0xFFFFFFFF); + @override + Color get stepIndicatorIconNumber => const Color(0xFFFFFFFF); + @override + Color get stepIndicatorIconInactive => const Color(0xFF747474); + + // checkbox + @override + Color get checkboxBGChecked => const Color(0xFF4C86E9); + @override + Color get checkboxBorderEmpty => const Color(0xFF8E9192); + @override + Color get checkboxBGDisabled => const Color(0xFFADC7EC); + @override + Color get checkboxIconChecked => const Color(0xFFFFFFFF); + @override + Color get checkboxIconDisabled => const Color(0xFFFFFFFF); + @override + Color get checkboxTextLabel => const Color(0xFFFFFFFF); + + // snack bar + @override + Color get snackBarBackSuccess => const Color(0xFF8EF5C3); + @override + Color get snackBarBackError => const Color(0xFFFFB4A9); + @override + Color get snackBarBackInfo => const Color(0xFFB4C4FF); + @override + Color get snackBarTextSuccess => const Color(0xFF003921); + @override + Color get snackBarTextError => const Color(0xFF690001); + @override + Color get snackBarTextInfo => const Color(0xFF00297A); + + // icons + @override + Color get bottomNavIconBack => const Color(0xFF7F8185); + @override + Color get bottomNavIconIcon => const Color(0xFFFFFFFF); + + @override + Color get topNavIconPrimary => const Color(0xFFFFFFFF); + @override + Color get topNavIconGreen => const Color(0xFF4CC0A0); + @override + Color get topNavIconYellow => const Color(0xFFF7D65D); + @override + Color get topNavIconRed => const Color(0xFFD34E50); + + @override + Color get settingsIconBack => const Color(0xFFE0E3E3); + @override + Color get settingsIconIcon => const Color(0xFF232323); + @override + Color get settingsIconBack2 => const Color(0xFF94D6C4); + @override + Color get settingsIconElement => const Color(0xFF00A578); + + // text field + @override + Color get textFieldActiveBG => const Color(0xFF4C5360); + @override + Color get textFieldDefaultBG => const Color(0xFF444953); + @override + Color get textFieldErrorBG => const Color(0xFFFFB4A9); + @override + Color get textFieldSuccessBG => const Color(0xFF8EF5C3); + + @override + Color get textFieldActiveSearchIconLeft => const Color(0xFFA9ACAC); + @override + Color get textFieldDefaultSearchIconLeft => const Color(0xFFA9ACAC); + @override + Color get textFieldErrorSearchIconLeft => const Color(0xFF690001); + @override + Color get textFieldSuccessSearchIconLeft => const Color(0xFF003921); + + @override + Color get textFieldActiveText => const Color(0xFFFFFFFF); + @override + Color get textFieldDefaultText => const Color(0xFFA9ACAC); + @override + Color get textFieldErrorText => const Color(0xFF000000); + @override + Color get textFieldSuccessText => const Color(0xFF000000); + + @override + Color get textFieldActiveLabel => const Color(0xFFA9ACAC); + @override + Color get textFieldErrorLabel => const Color(0xFF690001); + @override + Color get textFieldSuccessLabel => const Color(0xFF003921); + + @override + Color get textFieldActiveSearchIconRight => const Color(0xFFC4C7C7); + @override + Color get textFieldDefaultSearchIconRight => const Color(0xFF747778); + @override + Color get textFieldErrorSearchIconRight => const Color(0xFF690001); + @override + Color get textFieldSuccessSearchIconRight => const Color(0xFF003921); + + // settings item level2 + @override + Color get settingsItem2ActiveBG => const Color(0xFF484B51); + @override + Color get settingsItem2ActiveText => const Color(0xFFFFFFFF); + @override + Color get settingsItem2ActiveSub => const Color(0xFF9E9E9E); + + // radio buttons + @override + Color get radioButtonIconBorder => const Color(0xFF4C86E9); + @override + Color get radioButtonIconBorderDisabled => const Color(0xFF9E9E9E); + @override + Color get radioButtonBorderEnabled => const Color(0xFF4C86E9); + @override + Color get radioButtonBorderDisabled => const Color(0xFFCDCDCD); + @override + Color get radioButtonIconCircle => const Color(0xFF9E9E9E); + @override + Color get radioButtonIconEnabled => const Color(0xFF4C86E9); + @override + Color get radioButtonTextEnabled => const Color(0xFF44464E); + @override + Color get radioButtonTextDisabled => const Color(0xFF44464E); + @override + Color get radioButtonLabelEnabled => const Color(0xFF8E9192); + @override + Color get radioButtonLabelDisabled => const Color(0xFF8E9192); + + // info text + @override + Color get infoItemBG => const Color(0xFF333942); + @override + Color get infoItemLabel => const Color(0xFF9E9E9E); + @override + Color get infoItemText => const Color(0xFFFFFFFF); + @override + Color get infoItemIcons => const Color(0xFF4C86E9); + + // popup + @override + Color get popupBG => const Color(0xFF333942); + + // currency list + @override + Color get currencyListItemBG => const Color(0xFF484B51); + + // bottom nav + @override + Color get stackWalletBG => const Color(0xFF35383D); + @override + Color get stackWalletMid => const Color(0xFF292D34); + @override + Color get stackWalletBottom => const Color(0xFFFFFFFF); + @override + Color get bottomNavShadow => const Color(0xFF282E33); + + @override + Color get favoriteStarActive => accentColorYellow; + @override + Color get favoriteStarInactive => textSubtitle2; + + @override + Color get splash => const Color(0x358E9192); + @override + Color get highlight => const Color(0x44A9ACAC); + @override + Color get warningForeground => snackBarTextError; + @override + Color get warningBackground => const Color(0xFFFFB4A9); + @override + Color get loadingOverlayTextColor => const Color(0xFFF7F7F7); + @override + Color get myStackContactIconBG => const Color(0x88747778); +} diff --git a/lib/utilities/theme/light_colors.dart b/lib/utilities/theme/light_colors.dart new file mode 100644 index 000000000..994a876d8 --- /dev/null +++ b/lib/utilities/theme/light_colors.dart @@ -0,0 +1,302 @@ +import 'package:flutter/material.dart'; +import 'package:stackwallet/utilities/theme/color_theme.dart'; + +class LightColors extends StackColorTheme { + @override + ThemeType get themeType => ThemeType.light; + + @override + Color get background => const Color(0xFFF7F7F7); + @override + Color get overlay => const Color(0xFF111215); + + @override + Color get accentColorBlue => const Color(0xFF4C86E9); + @override + Color get accentColorGreen => const Color(0xFF4CC0A0); + @override + Color get accentColorYellow => const Color(0xFFF7D65D); + @override + Color get accentColorRed => const Color(0xFFD34E50); + @override + Color get accentColorOrange => const Color(0xFFFEA68D); + @override + Color get accentColorDark => const Color(0xFF232323); + + @override + Color get shadow => const Color(0x0F2D3132); + + @override + Color get textDark => const Color(0xFF232323); + @override + Color get textDark2 => const Color(0xFF414141); + @override + Color get textDark3 => const Color(0xFF747778); + @override + Color get textSubtitle1 => const Color(0xFF8E9192); + @override + Color get textSubtitle2 => const Color(0xFFA9ACAC); + @override + Color get textSubtitle3 => const Color(0xFFC4C7C7); + @override + Color get textSubtitle4 => const Color(0xFFE0E3E3); + @override + Color get textSubtitle5 => const Color(0xFFEEEFF1); + @override + Color get textSubtitle6 => const Color(0xFFF5F5F5); + @override + Color get textWhite => const Color(0xFFFFFFFF); + @override + Color get textFavoriteCard => const Color(0xFF232323); + @override + Color get textError => const Color(0xFF930006); + + // button background + @override + Color get buttonBackPrimary => const Color(0xFF232323); + @override + Color get buttonBackSecondary => const Color(0xFFE0E3E3); + @override + Color get buttonBackPrimaryDisabled => const Color(0xFFD7D7D7); + @override + Color get buttonBackSecondaryDisabled => const Color(0xFFF0F1F1); + @override + Color get buttonBackBorder => const Color(0xFF232323); + @override + Color get buttonBackBorderDisabled => const Color(0xFFB6B6B6); + + @override + Color get numberBackDefault => const Color(0xFFFFFFFF); + @override + Color get numpadBackDefault => const Color(0xFF232323); + @override + Color get bottomNavBack => const Color(0xFFA2A2A2); + + // button text/element + @override + Color get buttonTextPrimary => const Color(0xFFFFFFFF); + @override + Color get buttonTextSecondary => const Color(0xFF232323); + @override + Color get buttonTextPrimaryDisabled => const Color(0xFFF8F8F8); + @override + Color get buttonTextSecondaryDisabled => const Color(0xFFB7B7B7); + @override + Color get buttonTextBorder => const Color(0xFF232323); + @override + Color get buttonTextDisabled => const Color(0xFFB6B6B6); + @override + Color get buttonTextBorderless => const Color(0xFF0052DF); + @override + Color get buttonTextBorderlessDisabled => const Color(0xFFB6B6B6); + @override + Color get numberTextDefault => const Color(0xFF232323); + @override + Color get numpadTextDefault => const Color(0xFFFFFFFF); + @override + Color get bottomNavText => const Color(0xFF232323); + + // switch + @override + Color get switchBGOn => const Color(0xFF0052DF); + @override + Color get switchBGOff => const Color(0xFFD8E4FB); + @override + Color get switchBGDisabled => const Color(0xFFC5C6C9); + @override + Color get switchCircleOn => const Color(0xFFDAE2FF); + @override + Color get switchCircleOff => const Color(0xFFFBFCFF); + @override + Color get switchCircleDisabled => const Color(0xFFFBFCFF); + + // step indicator background + @override + Color get stepIndicatorBGCheck => const Color(0xFFD9E2FF); + @override + Color get stepIndicatorBGNumber => const Color(0xFFD9E2FF); + @override + Color get stepIndicatorBGInactive => const Color(0xFFCDCDCD); + @override + Color get stepIndicatorBGLines => const Color(0xFF0056D2); + @override + Color get stepIndicatorBGLinesInactive => const Color(0xFFCDCDCD); + @override + Color get stepIndicatorIconText => const Color(0xFF0056D2); + @override + Color get stepIndicatorIconNumber => const Color(0xFF0056D2); + @override + Color get stepIndicatorIconInactive => const Color(0xFFF7F7F7); + + // checkbox + @override + Color get checkboxBGChecked => const Color(0xFF0056D2); + @override + Color get checkboxBorderEmpty => const Color(0xFF8E9192); + @override + Color get checkboxBGDisabled => const Color(0xFFADC7EC); + @override + Color get checkboxIconChecked => const Color(0xFFFFFFFF); + @override + Color get checkboxIconDisabled => const Color(0xFFFFFFFF); + @override + Color get checkboxTextLabel => const Color(0xFF232323); + + // snack bar + @override + Color get snackBarBackSuccess => const Color(0xFFB9E9D4); + @override + Color get snackBarBackError => const Color(0xFFFFDAD4); + @override + Color get snackBarBackInfo => const Color(0xFFDAE2FF); + @override + Color get snackBarTextSuccess => const Color(0xFF006C4D); + @override + Color get snackBarTextError => const Color(0xFF930006); + @override + Color get snackBarTextInfo => const Color(0xFF002A78); + + // icons + @override + Color get bottomNavIconBack => const Color(0xFFA2A2A2); + @override + Color get bottomNavIconIcon => const Color(0xFF232323); + + @override + Color get topNavIconPrimary => const Color(0xFF232323); + @override + Color get topNavIconGreen => const Color(0xFF00A578); + @override + Color get topNavIconYellow => const Color(0xFFF4C517); + @override + Color get topNavIconRed => const Color(0xFFC00205); + + @override + Color get settingsIconBack => const Color(0xFFE0E3E3); + @override + Color get settingsIconIcon => const Color(0xFF232323); + @override + Color get settingsIconBack2 => const Color(0xFF94D6C4); + @override + Color get settingsIconElement => const Color(0xFF00A578); + + // text field + @override + Color get textFieldActiveBG => const Color(0xFFEEEFF1); + @override + Color get textFieldDefaultBG => const Color(0xFFEEEFF1); + @override + Color get textFieldErrorBG => const Color(0xFFFFDAD4); + @override + Color get textFieldSuccessBG => const Color(0xFFB9E9D4); + + @override + Color get textFieldActiveSearchIconLeft => const Color(0xFFA9ACAC); + @override + Color get textFieldDefaultSearchIconLeft => const Color(0xFFA9ACAC); + @override + Color get textFieldErrorSearchIconLeft => const Color(0xFF930006); + @override + Color get textFieldSuccessSearchIconLeft => const Color(0xFF006C4D); + + @override + Color get textFieldActiveText => const Color(0xFF232323); + @override + Color get textFieldDefaultText => const Color(0xFFA9ACAC); + @override + Color get textFieldErrorText => const Color(0xFF000000); + @override + Color get textFieldSuccessText => const Color(0xFF000000); + + @override + Color get textFieldActiveLabel => const Color(0xFFA9ACAC); + @override + Color get textFieldErrorLabel => const Color(0xFF930006); + @override + Color get textFieldSuccessLabel => const Color(0xFF006C4D); + + @override + Color get textFieldActiveSearchIconRight => const Color(0xFF747778); + @override + Color get textFieldDefaultSearchIconRight => const Color(0xFF747778); + @override + Color get textFieldErrorSearchIconRight => const Color(0xFF930006); + @override + Color get textFieldSuccessSearchIconRight => const Color(0xFF006C4D); + + // settings item level2 + @override + Color get settingsItem2ActiveBG => const Color(0xFFFFFFFF); + @override + Color get settingsItem2ActiveText => const Color(0xFF232323); + @override + Color get settingsItem2ActiveSub => const Color(0xFF8E9192); + + // radio buttons + @override + Color get radioButtonIconBorder => const Color(0xFF0056D2); + @override + Color get radioButtonIconBorderDisabled => const Color(0xFF8F909A); + @override + Color get radioButtonBorderEnabled => const Color(0xFF0056D2); + @override + Color get radioButtonBorderDisabled => const Color(0xFF8F909A); + @override + Color get radioButtonIconCircle => const Color(0xFF0056D2); + @override + Color get radioButtonIconEnabled => const Color(0xFF0056D2); + @override + Color get radioButtonTextEnabled => const Color(0xFF44464E); + @override + Color get radioButtonTextDisabled => const Color(0xFF44464E); + @override + Color get radioButtonLabelEnabled => const Color(0xFF8E9192); + @override + Color get radioButtonLabelDisabled => const Color(0xFF8E9192); + + // info text + @override + Color get infoItemBG => const Color(0xFFFFFFFF); + @override + Color get infoItemLabel => const Color(0xFF8E9192); + @override + Color get infoItemText => const Color(0xFF232323); + @override + Color get infoItemIcons => const Color(0xFF0056D2); + + // popup + @override + Color get popupBG => const Color(0xFFFFFFFF); + + // currency list + @override + Color get currencyListItemBG => const Color(0xFFF9F9FC); + + // bottom nav + @override + Color get stackWalletBG => const Color(0xFFFFFFFF); + @override + Color get stackWalletMid => const Color(0xFFFFFFFF); + @override + Color get stackWalletBottom => const Color(0xFF232323); + @override + Color get bottomNavShadow => const Color(0xFF282E33); + + @override + Color get favoriteStarActive => infoItemIcons; + @override + Color get favoriteStarInactive => textSubtitle3; + + @override + Color get splash => const Color(0x358E9192); + @override + Color get highlight => const Color(0x44A9ACAC); + @override + Color get warningForeground => textDark; + @override + Color get warningBackground => const Color(0xFFFFDAD3); + @override + Color get loadingOverlayTextColor => const Color(0xFFF7F7F7); + @override + Color get myStackContactIconBG => textFieldDefaultBG; +} diff --git a/lib/utilities/theme/stack_colors.dart b/lib/utilities/theme/stack_colors.dart new file mode 100644 index 000000000..b14f710c8 --- /dev/null +++ b/lib/utilities/theme/stack_colors.dart @@ -0,0 +1,1475 @@ +import 'package:flutter/material.dart'; +import 'package:stackwallet/models/exchange/change_now/exchange_transaction_status.dart'; +import 'package:stackwallet/utilities/enums/coin_enum.dart'; +import 'package:stackwallet/utilities/theme/color_theme.dart'; + +class StackColors extends ThemeExtension { + final ThemeType themeType; + + final Color background; + final Color overlay; + + final Color accentColorBlue; + final Color accentColorGreen; + final Color accentColorYellow; + final Color accentColorRed; + final Color accentColorOrange; + final Color accentColorDark; + + final Color shadow; + + final Color textDark; + final Color textDark2; + final Color textDark3; + final Color textSubtitle1; + final Color textSubtitle2; + final Color textSubtitle3; + final Color textSubtitle4; + final Color textSubtitle5; + final Color textSubtitle6; + final Color textWhite; + final Color textFavoriteCard; + final Color textError; + +// button background + final Color buttonBackPrimary; + final Color buttonBackSecondary; + final Color buttonBackPrimaryDisabled; + final Color buttonBackSecondaryDisabled; + final Color buttonBackBorder; + final Color buttonBackBorderDisabled; + final Color numberBackDefault; + final Color numpadBackDefault; + final Color bottomNavBack; + +// button text/element + final Color buttonTextPrimary; + final Color buttonTextSecondary; + final Color buttonTextPrimaryDisabled; + final Color buttonTextSecondaryDisabled; + final Color buttonTextBorder; + final Color buttonTextDisabled; + final Color buttonTextBorderless; + final Color buttonTextBorderlessDisabled; + final Color numberTextDefault; + final Color numpadTextDefault; + final Color bottomNavText; + +// switch background + final Color switchBGOn; + final Color switchBGOff; + final Color switchBGDisabled; + +// switch circle + final Color switchCircleOn; + final Color switchCircleOff; + final Color switchCircleDisabled; + +// step indicator background + final Color stepIndicatorBGCheck; + final Color stepIndicatorBGNumber; + final Color stepIndicatorBGInactive; + final Color stepIndicatorBGLines; + final Color stepIndicatorBGLinesInactive; + final Color stepIndicatorIconText; + final Color stepIndicatorIconNumber; + final Color stepIndicatorIconInactive; + +// checkbox + final Color checkboxBGChecked; + final Color checkboxBorderEmpty; + final Color checkboxBGDisabled; + final Color checkboxIconChecked; + final Color checkboxIconDisabled; + final Color checkboxTextLabel; + +// snack bar + final Color snackBarBackSuccess; + final Color snackBarBackError; + final Color snackBarBackInfo; + final Color snackBarTextSuccess; + final Color snackBarTextError; + final Color snackBarTextInfo; + +// icons + final Color bottomNavIconBack; + final Color bottomNavIconIcon; + final Color topNavIconPrimary; + final Color topNavIconGreen; + final Color topNavIconYellow; + final Color topNavIconRed; + final Color settingsIconBack; + final Color settingsIconIcon; + final Color settingsIconBack2; + final Color settingsIconElement; + +// text field + final Color textFieldActiveBG; + final Color textFieldDefaultBG; + final Color textFieldErrorBG; + final Color textFieldSuccessBG; + final Color textFieldActiveSearchIconLeft; + final Color textFieldDefaultSearchIconLeft; + final Color textFieldErrorSearchIconLeft; + final Color textFieldSuccessSearchIconLeft; + final Color textFieldActiveText; + final Color textFieldDefaultText; + final Color textFieldErrorText; + final Color textFieldSuccessText; + final Color textFieldActiveLabel; + final Color textFieldErrorLabel; + final Color textFieldSuccessLabel; + final Color textFieldActiveSearchIconRight; + final Color textFieldDefaultSearchIconRight; + final Color textFieldErrorSearchIconRight; + final Color textFieldSuccessSearchIconRight; + +// settings item level2 + final Color settingsItem2ActiveBG; + final Color settingsItem2ActiveText; + final Color settingsItem2ActiveSub; + +// radio buttons + final Color radioButtonIconBorder; + final Color radioButtonIconBorderDisabled; + final Color radioButtonBorderEnabled; + final Color radioButtonBorderDisabled; + final Color radioButtonIconCircle; + final Color radioButtonIconEnabled; + final Color radioButtonTextEnabled; + final Color radioButtonTextDisabled; + final Color radioButtonLabelEnabled; + final Color radioButtonLabelDisabled; + +// info text + final Color infoItemBG; + final Color infoItemLabel; + final Color infoItemText; + final Color infoItemIcons; + +// popup + final Color popupBG; + +// currency list + final Color currencyListItemBG; + +// bottom nav + final Color stackWalletBG; + final Color stackWalletMid; + final Color stackWalletBottom; + final Color bottomNavShadow; + + final Color favoriteStarActive; + final Color favoriteStarInactive; + + final Color splash; + final Color highlight; + final Color warningForeground; + final Color warningBackground; + final Color loadingOverlayTextColor; + final Color myStackContactIconBG; + + StackColors({ + required this.themeType, + required this.background, + required this.overlay, + required this.accentColorBlue, + required this.accentColorGreen, + required this.accentColorYellow, + required this.accentColorRed, + required this.accentColorOrange, + required this.accentColorDark, + required this.shadow, + required this.textDark, + required this.textDark2, + required this.textDark3, + required this.textSubtitle1, + required this.textSubtitle2, + required this.textSubtitle3, + required this.textSubtitle4, + required this.textSubtitle5, + required this.textSubtitle6, + required this.textWhite, + required this.textFavoriteCard, + required this.textError, + required this.buttonBackPrimary, + required this.buttonBackSecondary, + required this.buttonBackPrimaryDisabled, + required this.buttonBackSecondaryDisabled, + required this.buttonBackBorder, + required this.buttonBackBorderDisabled, + required this.numberBackDefault, + required this.numpadBackDefault, + required this.bottomNavBack, + required this.buttonTextPrimary, + required this.buttonTextSecondary, + required this.buttonTextPrimaryDisabled, + required this.buttonTextSecondaryDisabled, + required this.buttonTextBorder, + required this.buttonTextDisabled, + required this.buttonTextBorderless, + required this.buttonTextBorderlessDisabled, + required this.numberTextDefault, + required this.numpadTextDefault, + required this.bottomNavText, + required this.switchBGOn, + required this.switchBGOff, + required this.switchBGDisabled, + required this.switchCircleOn, + required this.switchCircleOff, + required this.switchCircleDisabled, + required this.stepIndicatorBGCheck, + required this.stepIndicatorBGNumber, + required this.stepIndicatorBGInactive, + required this.stepIndicatorBGLines, + required this.stepIndicatorBGLinesInactive, + required this.stepIndicatorIconText, + required this.stepIndicatorIconNumber, + required this.stepIndicatorIconInactive, + required this.checkboxBGChecked, + required this.checkboxBorderEmpty, + required this.checkboxBGDisabled, + required this.checkboxIconChecked, + required this.checkboxIconDisabled, + required this.checkboxTextLabel, + required this.snackBarBackSuccess, + required this.snackBarBackError, + required this.snackBarBackInfo, + required this.snackBarTextSuccess, + required this.snackBarTextError, + required this.snackBarTextInfo, + required this.bottomNavIconBack, + required this.bottomNavIconIcon, + required this.topNavIconPrimary, + required this.topNavIconGreen, + required this.topNavIconYellow, + required this.topNavIconRed, + required this.settingsIconBack, + required this.settingsIconIcon, + required this.settingsIconBack2, + required this.settingsIconElement, + required this.textFieldActiveBG, + required this.textFieldDefaultBG, + required this.textFieldErrorBG, + required this.textFieldSuccessBG, + required this.textFieldActiveSearchIconLeft, + required this.textFieldDefaultSearchIconLeft, + required this.textFieldErrorSearchIconLeft, + required this.textFieldSuccessSearchIconLeft, + required this.textFieldActiveText, + required this.textFieldDefaultText, + required this.textFieldErrorText, + required this.textFieldSuccessText, + required this.textFieldActiveLabel, + required this.textFieldErrorLabel, + required this.textFieldSuccessLabel, + required this.textFieldActiveSearchIconRight, + required this.textFieldDefaultSearchIconRight, + required this.textFieldErrorSearchIconRight, + required this.textFieldSuccessSearchIconRight, + required this.settingsItem2ActiveBG, + required this.settingsItem2ActiveText, + required this.settingsItem2ActiveSub, + required this.radioButtonIconBorder, + required this.radioButtonIconBorderDisabled, + required this.radioButtonBorderEnabled, + required this.radioButtonBorderDisabled, + required this.radioButtonIconCircle, + required this.radioButtonIconEnabled, + required this.radioButtonTextEnabled, + required this.radioButtonTextDisabled, + required this.radioButtonLabelEnabled, + required this.radioButtonLabelDisabled, + required this.infoItemBG, + required this.infoItemLabel, + required this.infoItemText, + required this.infoItemIcons, + required this.popupBG, + required this.currencyListItemBG, + required this.stackWalletBG, + required this.stackWalletMid, + required this.stackWalletBottom, + required this.bottomNavShadow, + required this.favoriteStarActive, + required this.favoriteStarInactive, + required this.splash, + required this.highlight, + required this.warningForeground, + required this.warningBackground, + required this.loadingOverlayTextColor, + required this.myStackContactIconBG, + }); + + factory StackColors.fromStackColorTheme(StackColorTheme colorTheme) { + return StackColors( + themeType: colorTheme.themeType, + background: colorTheme.background, + overlay: colorTheme.overlay, + accentColorBlue: colorTheme.accentColorBlue, + accentColorGreen: colorTheme.accentColorGreen, + accentColorYellow: colorTheme.accentColorYellow, + accentColorRed: colorTheme.accentColorRed, + accentColorOrange: colorTheme.accentColorOrange, + accentColorDark: colorTheme.accentColorDark, + shadow: colorTheme.shadow, + textDark: colorTheme.textDark, + textDark2: colorTheme.textDark2, + textDark3: colorTheme.textDark3, + textSubtitle1: colorTheme.textSubtitle1, + textSubtitle2: colorTheme.textSubtitle2, + textSubtitle3: colorTheme.textSubtitle3, + textSubtitle4: colorTheme.textSubtitle4, + textSubtitle5: colorTheme.textSubtitle5, + textSubtitle6: colorTheme.textSubtitle6, + textWhite: colorTheme.textWhite, + textFavoriteCard: colorTheme.textFavoriteCard, + textError: colorTheme.textError, + buttonBackPrimary: colorTheme.buttonBackPrimary, + buttonBackSecondary: colorTheme.buttonBackSecondary, + buttonBackPrimaryDisabled: colorTheme.buttonBackPrimaryDisabled, + buttonBackSecondaryDisabled: colorTheme.buttonBackSecondaryDisabled, + buttonBackBorder: colorTheme.buttonBackBorder, + buttonBackBorderDisabled: colorTheme.buttonBackBorderDisabled, + numberBackDefault: colorTheme.numberBackDefault, + numpadBackDefault: colorTheme.numpadBackDefault, + bottomNavBack: colorTheme.bottomNavBack, + buttonTextPrimary: colorTheme.buttonTextPrimary, + buttonTextSecondary: colorTheme.buttonTextSecondary, + buttonTextPrimaryDisabled: colorTheme.buttonTextPrimaryDisabled, + buttonTextSecondaryDisabled: colorTheme.buttonTextSecondaryDisabled, + buttonTextBorder: colorTheme.buttonTextBorder, + buttonTextDisabled: colorTheme.buttonTextDisabled, + buttonTextBorderless: colorTheme.buttonTextBorderless, + buttonTextBorderlessDisabled: colorTheme.buttonTextBorderlessDisabled, + numberTextDefault: colorTheme.numberTextDefault, + numpadTextDefault: colorTheme.numpadTextDefault, + bottomNavText: colorTheme.bottomNavText, + switchBGOn: colorTheme.switchBGOn, + switchBGOff: colorTheme.switchBGOff, + switchBGDisabled: colorTheme.switchBGDisabled, + switchCircleOn: colorTheme.switchCircleOn, + switchCircleOff: colorTheme.switchCircleOff, + switchCircleDisabled: colorTheme.switchCircleDisabled, + stepIndicatorBGCheck: colorTheme.stepIndicatorBGCheck, + stepIndicatorBGNumber: colorTheme.stepIndicatorBGNumber, + stepIndicatorBGInactive: colorTheme.stepIndicatorBGInactive, + stepIndicatorBGLines: colorTheme.stepIndicatorBGLines, + stepIndicatorBGLinesInactive: colorTheme.stepIndicatorBGLinesInactive, + stepIndicatorIconText: colorTheme.stepIndicatorIconText, + stepIndicatorIconNumber: colorTheme.stepIndicatorIconNumber, + stepIndicatorIconInactive: colorTheme.stepIndicatorIconInactive, + checkboxBGChecked: colorTheme.checkboxBGChecked, + checkboxBorderEmpty: colorTheme.checkboxBorderEmpty, + checkboxBGDisabled: colorTheme.checkboxBGDisabled, + checkboxIconChecked: colorTheme.checkboxIconChecked, + checkboxIconDisabled: colorTheme.checkboxIconDisabled, + checkboxTextLabel: colorTheme.checkboxTextLabel, + snackBarBackSuccess: colorTheme.snackBarBackSuccess, + snackBarBackError: colorTheme.snackBarBackError, + snackBarBackInfo: colorTheme.snackBarBackInfo, + snackBarTextSuccess: colorTheme.snackBarTextSuccess, + snackBarTextError: colorTheme.snackBarTextError, + snackBarTextInfo: colorTheme.snackBarTextInfo, + bottomNavIconBack: colorTheme.bottomNavIconBack, + bottomNavIconIcon: colorTheme.bottomNavIconIcon, + topNavIconPrimary: colorTheme.topNavIconPrimary, + topNavIconGreen: colorTheme.topNavIconGreen, + topNavIconYellow: colorTheme.topNavIconYellow, + topNavIconRed: colorTheme.topNavIconRed, + settingsIconBack: colorTheme.settingsIconBack, + settingsIconIcon: colorTheme.settingsIconIcon, + settingsIconBack2: colorTheme.settingsIconBack2, + settingsIconElement: colorTheme.settingsIconElement, + textFieldActiveBG: colorTheme.textFieldActiveBG, + textFieldDefaultBG: colorTheme.textFieldDefaultBG, + textFieldErrorBG: colorTheme.textFieldErrorBG, + textFieldSuccessBG: colorTheme.textFieldSuccessBG, + textFieldActiveSearchIconLeft: colorTheme.textFieldActiveSearchIconLeft, + textFieldDefaultSearchIconLeft: colorTheme.textFieldDefaultSearchIconLeft, + textFieldErrorSearchIconLeft: colorTheme.textFieldErrorSearchIconLeft, + textFieldSuccessSearchIconLeft: colorTheme.textFieldSuccessSearchIconLeft, + textFieldActiveText: colorTheme.textFieldActiveText, + textFieldDefaultText: colorTheme.textFieldDefaultText, + textFieldErrorText: colorTheme.textFieldErrorText, + textFieldSuccessText: colorTheme.textFieldSuccessText, + textFieldActiveLabel: colorTheme.textFieldActiveLabel, + textFieldErrorLabel: colorTheme.textFieldErrorLabel, + textFieldSuccessLabel: colorTheme.textFieldSuccessLabel, + textFieldActiveSearchIconRight: colorTheme.textFieldActiveSearchIconRight, + textFieldDefaultSearchIconRight: + colorTheme.textFieldDefaultSearchIconRight, + textFieldErrorSearchIconRight: colorTheme.textFieldErrorSearchIconRight, + textFieldSuccessSearchIconRight: + colorTheme.textFieldSuccessSearchIconRight, + settingsItem2ActiveBG: colorTheme.settingsItem2ActiveBG, + settingsItem2ActiveText: colorTheme.settingsItem2ActiveText, + settingsItem2ActiveSub: colorTheme.settingsItem2ActiveSub, + radioButtonIconBorder: colorTheme.radioButtonIconBorder, + radioButtonIconBorderDisabled: colorTheme.radioButtonIconBorderDisabled, + radioButtonBorderEnabled: colorTheme.radioButtonBorderEnabled, + radioButtonBorderDisabled: colorTheme.radioButtonBorderDisabled, + radioButtonIconCircle: colorTheme.radioButtonIconCircle, + radioButtonIconEnabled: colorTheme.radioButtonIconEnabled, + radioButtonTextEnabled: colorTheme.radioButtonTextEnabled, + radioButtonTextDisabled: colorTheme.radioButtonTextDisabled, + radioButtonLabelEnabled: colorTheme.radioButtonLabelEnabled, + radioButtonLabelDisabled: colorTheme.radioButtonLabelDisabled, + infoItemBG: colorTheme.infoItemBG, + infoItemLabel: colorTheme.infoItemLabel, + infoItemText: colorTheme.infoItemText, + infoItemIcons: colorTheme.infoItemIcons, + popupBG: colorTheme.popupBG, + currencyListItemBG: colorTheme.currencyListItemBG, + stackWalletBG: colorTheme.stackWalletBG, + stackWalletMid: colorTheme.stackWalletMid, + stackWalletBottom: colorTheme.stackWalletBottom, + bottomNavShadow: colorTheme.bottomNavShadow, + favoriteStarActive: colorTheme.favoriteStarActive, + favoriteStarInactive: colorTheme.favoriteStarInactive, + splash: colorTheme.splash, + highlight: colorTheme.highlight, + warningForeground: colorTheme.warningForeground, + warningBackground: colorTheme.warningBackground, + loadingOverlayTextColor: colorTheme.loadingOverlayTextColor, + myStackContactIconBG: colorTheme.myStackContactIconBG, + ); + } + + @override + ThemeExtension copyWith({ + ThemeType? themeType, + Color? background, + Color? overlay, + Color? accentColorBlue, + Color? accentColorGreen, + Color? accentColorYellow, + Color? accentColorRed, + Color? accentColorOrange, + Color? accentColorDark, + Color? shadow, + Color? textDark, + Color? textDark2, + Color? textDark3, + Color? textSubtitle1, + Color? textSubtitle2, + Color? textSubtitle3, + Color? textSubtitle4, + Color? textSubtitle5, + Color? textSubtitle6, + Color? textWhite, + Color? textFavoriteCard, + Color? textError, + Color? buttonBackPrimary, + Color? buttonBackSecondary, + Color? buttonBackPrimaryDisabled, + Color? buttonBackSecondaryDisabled, + Color? buttonBackBorder, + Color? buttonBackBorderDisabled, + Color? numberBackDefault, + Color? numpadBackDefault, + Color? bottomNavBack, + Color? buttonTextPrimary, + Color? buttonTextSecondary, + Color? buttonTextPrimaryDisabled, + Color? buttonTextSecondaryDisabled, + Color? buttonTextBorder, + Color? buttonTextDisabled, + Color? buttonTextBorderless, + Color? buttonTextBorderlessDisabled, + Color? numberTextDefault, + Color? numpadTextDefault, + Color? bottomNavText, + Color? switchBGOn, + Color? switchBGOff, + Color? switchBGDisabled, + Color? switchCircleOn, + Color? switchCircleOff, + Color? switchCircleDisabled, + Color? stepIndicatorBGCheck, + Color? stepIndicatorBGNumber, + Color? stepIndicatorBGInactive, + Color? stepIndicatorBGLines, + Color? stepIndicatorBGLinesInactive, + Color? stepIndicatorIconText, + Color? stepIndicatorIconNumber, + Color? stepIndicatorIconInactive, + Color? checkboxBGChecked, + Color? checkboxBorderEmpty, + Color? checkboxBGDisabled, + Color? checkboxIconChecked, + Color? checkboxIconDisabled, + Color? checkboxTextLabel, + Color? snackBarBackSuccess, + Color? snackBarBackError, + Color? snackBarBackInfo, + Color? snackBarTextSuccess, + Color? snackBarTextError, + Color? snackBarTextInfo, + Color? bottomNavIconBack, + Color? bottomNavIconIcon, + Color? topNavIconPrimary, + Color? topNavIconGreen, + Color? topNavIconYellow, + Color? topNavIconRed, + Color? settingsIconBack, + Color? settingsIconIcon, + Color? settingsIconBack2, + Color? settingsIconElement, + Color? textFieldActiveBG, + Color? textFieldDefaultBG, + Color? textFieldErrorBG, + Color? textFieldSuccessBG, + Color? textFieldActiveSearchIconLeft, + Color? textFieldDefaultSearchIconLeft, + Color? textFieldErrorSearchIconLeft, + Color? textFieldSuccessSearchIconLeft, + Color? textFieldActiveText, + Color? textFieldDefaultText, + Color? textFieldErrorText, + Color? textFieldSuccessText, + Color? textFieldActiveLabel, + Color? textFieldErrorLabel, + Color? textFieldSuccessLabel, + Color? textFieldActiveSearchIconRight, + Color? textFieldDefaultSearchIconRight, + Color? textFieldErrorSearchIconRight, + Color? textFieldSuccessSearchIconRight, + Color? settingsItem2ActiveBG, + Color? settingsItem2ActiveText, + Color? settingsItem2ActiveSub, + Color? radioButtonIconBorder, + Color? radioButtonIconBorderDisabled, + Color? radioButtonBorderEnabled, + Color? radioButtonBorderDisabled, + Color? radioButtonIconCircle, + Color? radioButtonIconEnabled, + Color? radioButtonTextEnabled, + Color? radioButtonTextDisabled, + Color? radioButtonLabelEnabled, + Color? radioButtonLabelDisabled, + Color? infoItemBG, + Color? infoItemLabel, + Color? infoItemText, + Color? infoItemIcons, + Color? popupBG, + Color? currencyListItemBG, + Color? stackWalletBG, + Color? stackWalletMid, + Color? stackWalletBottom, + Color? bottomNavShadow, + Color? favoriteStarActive, + Color? favoriteStarInactive, + Color? splash, + Color? highlight, + Color? warningForeground, + Color? warningBackground, + Color? loadingOverlayTextColor, + Color? myStackContactIconBG, + }) { + return StackColors( + themeType: themeType ?? this.themeType, + background: background ?? this.background, + overlay: overlay ?? this.overlay, + accentColorBlue: accentColorBlue ?? this.accentColorBlue, + accentColorGreen: accentColorGreen ?? this.accentColorGreen, + accentColorYellow: accentColorYellow ?? this.accentColorYellow, + accentColorRed: accentColorRed ?? this.accentColorRed, + accentColorOrange: accentColorOrange ?? this.accentColorOrange, + accentColorDark: accentColorDark ?? this.accentColorDark, + shadow: shadow ?? this.shadow, + textDark: textDark ?? this.textDark, + textDark2: textDark2 ?? this.textDark2, + textDark3: textDark3 ?? this.textDark3, + textSubtitle1: textSubtitle1 ?? this.textSubtitle1, + textSubtitle2: textSubtitle2 ?? this.textSubtitle2, + textSubtitle3: textSubtitle3 ?? this.textSubtitle3, + textSubtitle4: textSubtitle4 ?? this.textSubtitle4, + textSubtitle5: textSubtitle5 ?? this.textSubtitle5, + textSubtitle6: textSubtitle6 ?? this.textSubtitle6, + textWhite: textWhite ?? this.textWhite, + textFavoriteCard: textFavoriteCard ?? this.textFavoriteCard, + textError: textError ?? this.textError, + buttonBackPrimary: buttonBackPrimary ?? this.buttonBackPrimary, + buttonBackSecondary: buttonBackSecondary ?? this.buttonBackSecondary, + buttonBackPrimaryDisabled: + buttonBackPrimaryDisabled ?? this.buttonBackPrimaryDisabled, + buttonBackSecondaryDisabled: + buttonBackSecondaryDisabled ?? this.buttonBackSecondaryDisabled, + buttonBackBorder: buttonBackBorder ?? this.buttonBackBorder, + buttonBackBorderDisabled: + buttonBackBorderDisabled ?? this.buttonBackBorderDisabled, + numberBackDefault: numberBackDefault ?? this.numberBackDefault, + numpadBackDefault: numpadBackDefault ?? this.numpadBackDefault, + bottomNavBack: bottomNavBack ?? this.bottomNavBack, + buttonTextPrimary: buttonTextPrimary ?? this.buttonTextPrimary, + buttonTextSecondary: buttonTextSecondary ?? this.buttonTextSecondary, + buttonTextPrimaryDisabled: + buttonTextPrimaryDisabled ?? this.buttonTextPrimaryDisabled, + buttonTextSecondaryDisabled: + buttonTextSecondaryDisabled ?? this.buttonTextSecondaryDisabled, + buttonTextBorder: buttonTextBorder ?? this.buttonTextBorder, + buttonTextDisabled: buttonTextDisabled ?? this.buttonTextDisabled, + buttonTextBorderless: buttonTextBorderless ?? this.buttonTextBorderless, + buttonTextBorderlessDisabled: + buttonTextBorderlessDisabled ?? this.buttonTextBorderlessDisabled, + numberTextDefault: numberTextDefault ?? this.numberTextDefault, + numpadTextDefault: numpadTextDefault ?? this.numpadTextDefault, + bottomNavText: bottomNavText ?? this.bottomNavText, + switchBGOn: switchBGOn ?? this.switchBGOn, + switchBGOff: switchBGOff ?? this.switchBGOff, + switchBGDisabled: switchBGDisabled ?? this.switchBGDisabled, + switchCircleOn: switchCircleOn ?? this.switchCircleOn, + switchCircleOff: switchCircleOff ?? this.switchCircleOff, + switchCircleDisabled: switchCircleDisabled ?? this.switchCircleDisabled, + stepIndicatorBGCheck: stepIndicatorBGCheck ?? this.stepIndicatorBGCheck, + stepIndicatorBGNumber: + stepIndicatorBGNumber ?? this.stepIndicatorBGNumber, + stepIndicatorBGInactive: + stepIndicatorBGInactive ?? this.stepIndicatorBGInactive, + stepIndicatorBGLines: stepIndicatorBGLines ?? this.stepIndicatorBGLines, + stepIndicatorBGLinesInactive: + stepIndicatorBGLinesInactive ?? this.stepIndicatorBGLinesInactive, + stepIndicatorIconText: + stepIndicatorIconText ?? this.stepIndicatorIconText, + stepIndicatorIconNumber: + stepIndicatorIconNumber ?? this.stepIndicatorIconNumber, + stepIndicatorIconInactive: + stepIndicatorIconInactive ?? this.stepIndicatorIconInactive, + checkboxBGChecked: checkboxBGChecked ?? this.checkboxBGChecked, + checkboxBorderEmpty: checkboxBorderEmpty ?? this.checkboxBorderEmpty, + checkboxBGDisabled: checkboxBGDisabled ?? this.checkboxBGDisabled, + checkboxIconChecked: checkboxIconChecked ?? this.checkboxIconChecked, + checkboxIconDisabled: checkboxIconDisabled ?? this.checkboxIconDisabled, + checkboxTextLabel: checkboxTextLabel ?? this.checkboxTextLabel, + snackBarBackSuccess: snackBarBackSuccess ?? this.snackBarBackSuccess, + snackBarBackError: snackBarBackError ?? this.snackBarBackError, + snackBarBackInfo: snackBarBackInfo ?? this.snackBarBackInfo, + snackBarTextSuccess: snackBarTextSuccess ?? this.snackBarTextSuccess, + snackBarTextError: snackBarTextError ?? this.snackBarTextError, + snackBarTextInfo: snackBarTextInfo ?? this.snackBarTextInfo, + bottomNavIconBack: bottomNavIconBack ?? this.bottomNavIconBack, + bottomNavIconIcon: bottomNavIconIcon ?? this.bottomNavIconIcon, + topNavIconPrimary: topNavIconPrimary ?? this.topNavIconPrimary, + topNavIconGreen: topNavIconGreen ?? this.topNavIconGreen, + topNavIconYellow: topNavIconYellow ?? this.topNavIconYellow, + topNavIconRed: topNavIconRed ?? this.topNavIconRed, + settingsIconBack: settingsIconBack ?? this.settingsIconBack, + settingsIconIcon: settingsIconIcon ?? this.settingsIconIcon, + settingsIconBack2: settingsIconBack2 ?? this.settingsIconBack2, + settingsIconElement: settingsIconElement ?? this.settingsIconElement, + textFieldActiveBG: textFieldActiveBG ?? this.textFieldActiveBG, + textFieldDefaultBG: textFieldDefaultBG ?? this.textFieldDefaultBG, + textFieldErrorBG: textFieldErrorBG ?? this.textFieldErrorBG, + textFieldSuccessBG: textFieldSuccessBG ?? this.textFieldSuccessBG, + textFieldActiveSearchIconLeft: + textFieldActiveSearchIconLeft ?? this.textFieldActiveSearchIconLeft, + textFieldDefaultSearchIconLeft: + textFieldDefaultSearchIconLeft ?? this.textFieldDefaultSearchIconLeft, + textFieldErrorSearchIconLeft: + textFieldErrorSearchIconLeft ?? this.textFieldErrorSearchIconLeft, + textFieldSuccessSearchIconLeft: + textFieldSuccessSearchIconLeft ?? this.textFieldSuccessSearchIconLeft, + textFieldActiveText: textFieldActiveText ?? this.textFieldActiveText, + textFieldDefaultText: textFieldDefaultText ?? this.textFieldDefaultText, + textFieldErrorText: textFieldErrorText ?? this.textFieldErrorText, + textFieldSuccessText: textFieldSuccessText ?? this.textFieldSuccessText, + textFieldActiveLabel: textFieldActiveLabel ?? this.textFieldActiveLabel, + textFieldErrorLabel: textFieldErrorLabel ?? this.textFieldErrorLabel, + textFieldSuccessLabel: + textFieldSuccessLabel ?? this.textFieldSuccessLabel, + textFieldActiveSearchIconRight: + textFieldActiveSearchIconRight ?? this.textFieldActiveSearchIconRight, + textFieldDefaultSearchIconRight: textFieldDefaultSearchIconRight ?? + this.textFieldDefaultSearchIconRight, + textFieldErrorSearchIconRight: + textFieldErrorSearchIconRight ?? this.textFieldErrorSearchIconRight, + textFieldSuccessSearchIconRight: textFieldSuccessSearchIconRight ?? + this.textFieldSuccessSearchIconRight, + settingsItem2ActiveBG: + settingsItem2ActiveBG ?? this.settingsItem2ActiveBG, + settingsItem2ActiveText: + settingsItem2ActiveText ?? this.settingsItem2ActiveText, + settingsItem2ActiveSub: + settingsItem2ActiveSub ?? this.settingsItem2ActiveSub, + radioButtonIconBorder: + radioButtonIconBorder ?? this.radioButtonIconBorder, + radioButtonIconBorderDisabled: + radioButtonIconBorderDisabled ?? this.radioButtonIconBorderDisabled, + radioButtonBorderEnabled: + radioButtonBorderEnabled ?? this.radioButtonBorderEnabled, + radioButtonBorderDisabled: + radioButtonBorderDisabled ?? this.radioButtonBorderDisabled, + radioButtonIconCircle: + radioButtonIconCircle ?? this.radioButtonIconCircle, + radioButtonIconEnabled: + radioButtonIconEnabled ?? this.radioButtonIconEnabled, + radioButtonTextEnabled: + radioButtonTextEnabled ?? this.radioButtonTextEnabled, + radioButtonTextDisabled: + radioButtonTextDisabled ?? this.radioButtonTextDisabled, + radioButtonLabelEnabled: + radioButtonLabelEnabled ?? this.radioButtonLabelEnabled, + radioButtonLabelDisabled: + radioButtonLabelDisabled ?? this.radioButtonLabelDisabled, + infoItemBG: infoItemBG ?? this.infoItemBG, + infoItemLabel: infoItemLabel ?? this.infoItemLabel, + infoItemText: infoItemText ?? this.infoItemText, + infoItemIcons: infoItemIcons ?? this.infoItemIcons, + popupBG: popupBG ?? this.popupBG, + currencyListItemBG: currencyListItemBG ?? this.currencyListItemBG, + stackWalletBG: stackWalletBG ?? this.stackWalletBG, + stackWalletMid: stackWalletMid ?? this.stackWalletMid, + stackWalletBottom: stackWalletBottom ?? this.stackWalletBottom, + bottomNavShadow: bottomNavShadow ?? this.bottomNavShadow, + favoriteStarActive: favoriteStarActive ?? this.favoriteStarActive, + favoriteStarInactive: favoriteStarInactive ?? this.favoriteStarInactive, + splash: splash ?? this.splash, + highlight: highlight ?? this.highlight, + warningForeground: warningForeground ?? this.warningForeground, + warningBackground: warningBackground ?? this.warningBackground, + loadingOverlayTextColor: + loadingOverlayTextColor ?? this.loadingOverlayTextColor, + myStackContactIconBG: myStackContactIconBG ?? this.myStackContactIconBG, + ); + } + + @override + ThemeExtension lerp( + ThemeExtension? other, + double t, + ) { + if (other is! StackColors) { + return this; + } + + return StackColors( + themeType: other.themeType, + background: Color.lerp( + background, + other.background, + t, + )!, + overlay: Color.lerp( + overlay, + other.overlay, + t, + )!, + accentColorBlue: Color.lerp( + accentColorBlue, + other.accentColorBlue, + t, + )!, + accentColorGreen: Color.lerp( + accentColorGreen, + other.accentColorGreen, + t, + )!, + accentColorYellow: Color.lerp( + accentColorYellow, + other.accentColorYellow, + t, + )!, + accentColorRed: Color.lerp( + accentColorRed, + other.accentColorRed, + t, + )!, + accentColorOrange: Color.lerp( + accentColorOrange, + other.accentColorOrange, + t, + )!, + accentColorDark: Color.lerp( + accentColorDark, + other.accentColorDark, + t, + )!, + shadow: Color.lerp( + shadow, + other.shadow, + t, + )!, + textDark: Color.lerp( + textDark, + other.textDark, + t, + )!, + textDark2: Color.lerp( + textDark2, + other.textDark2, + t, + )!, + textDark3: Color.lerp( + textDark3, + other.textDark3, + t, + )!, + textSubtitle1: Color.lerp( + textSubtitle1, + other.textSubtitle1, + t, + )!, + textSubtitle2: Color.lerp( + textSubtitle2, + other.textSubtitle2, + t, + )!, + textSubtitle3: Color.lerp( + textSubtitle3, + other.textSubtitle3, + t, + )!, + textSubtitle4: Color.lerp( + textSubtitle4, + other.textSubtitle4, + t, + )!, + textSubtitle5: Color.lerp( + textSubtitle5, + other.textSubtitle5, + t, + )!, + textSubtitle6: Color.lerp( + textSubtitle6, + other.textSubtitle6, + t, + )!, + textWhite: Color.lerp( + textWhite, + other.textWhite, + t, + )!, + textFavoriteCard: Color.lerp( + textFavoriteCard, + other.textFavoriteCard, + t, + )!, + textError: Color.lerp( + textError, + other.textError, + t, + )!, + buttonBackPrimary: Color.lerp( + buttonBackPrimary, + other.buttonBackPrimary, + t, + )!, + buttonBackSecondary: Color.lerp( + buttonBackSecondary, + other.buttonBackSecondary, + t, + )!, + buttonBackPrimaryDisabled: Color.lerp( + buttonBackPrimaryDisabled, + other.buttonBackPrimaryDisabled, + t, + )!, + buttonBackSecondaryDisabled: Color.lerp( + buttonBackSecondaryDisabled, + other.buttonBackSecondaryDisabled, + t, + )!, + buttonBackBorder: Color.lerp( + buttonBackBorder, + other.buttonBackBorder, + t, + )!, + buttonBackBorderDisabled: Color.lerp( + buttonBackBorderDisabled, + other.buttonBackBorderDisabled, + t, + )!, + numberBackDefault: Color.lerp( + numberBackDefault, + other.numberBackDefault, + t, + )!, + numpadBackDefault: Color.lerp( + numpadBackDefault, + other.numpadBackDefault, + t, + )!, + bottomNavBack: Color.lerp( + bottomNavBack, + other.bottomNavBack, + t, + )!, + buttonTextPrimary: Color.lerp( + buttonTextPrimary, + other.buttonTextPrimary, + t, + )!, + buttonTextSecondary: Color.lerp( + buttonTextSecondary, + other.buttonTextSecondary, + t, + )!, + buttonTextPrimaryDisabled: Color.lerp( + buttonTextPrimaryDisabled, + other.buttonTextPrimaryDisabled, + t, + )!, + buttonTextSecondaryDisabled: Color.lerp( + buttonTextSecondaryDisabled, + other.buttonTextSecondaryDisabled, + t, + )!, + buttonTextBorder: Color.lerp( + buttonTextBorder, + other.buttonTextBorder, + t, + )!, + buttonTextDisabled: Color.lerp( + buttonTextDisabled, + other.buttonTextDisabled, + t, + )!, + buttonTextBorderless: Color.lerp( + buttonTextBorderless, + other.buttonTextBorderless, + t, + )!, + buttonTextBorderlessDisabled: Color.lerp( + buttonTextBorderlessDisabled, + other.buttonTextBorderlessDisabled, + t, + )!, + numberTextDefault: Color.lerp( + numberTextDefault, + other.numberTextDefault, + t, + )!, + numpadTextDefault: Color.lerp( + numpadTextDefault, + other.numpadTextDefault, + t, + )!, + bottomNavText: Color.lerp( + bottomNavText, + other.bottomNavText, + t, + )!, + switchBGOn: Color.lerp( + switchBGOn, + other.switchBGOn, + t, + )!, + switchBGOff: Color.lerp( + switchBGOff, + other.switchBGOff, + t, + )!, + switchBGDisabled: Color.lerp( + switchBGDisabled, + other.switchBGDisabled, + t, + )!, + switchCircleOn: Color.lerp( + switchCircleOn, + other.switchCircleOn, + t, + )!, + switchCircleOff: Color.lerp( + switchCircleOff, + other.switchCircleOff, + t, + )!, + switchCircleDisabled: Color.lerp( + switchCircleDisabled, + other.switchCircleDisabled, + t, + )!, + stepIndicatorBGCheck: Color.lerp( + stepIndicatorBGCheck, + other.stepIndicatorBGCheck, + t, + )!, + stepIndicatorBGNumber: Color.lerp( + stepIndicatorBGNumber, + other.stepIndicatorBGNumber, + t, + )!, + stepIndicatorBGInactive: Color.lerp( + stepIndicatorBGInactive, + other.stepIndicatorBGInactive, + t, + )!, + stepIndicatorBGLines: Color.lerp( + stepIndicatorBGLines, + other.stepIndicatorBGLines, + t, + )!, + stepIndicatorBGLinesInactive: Color.lerp( + stepIndicatorBGLinesInactive, + other.stepIndicatorBGLinesInactive, + t, + )!, + stepIndicatorIconText: Color.lerp( + stepIndicatorIconText, + other.stepIndicatorIconText, + t, + )!, + stepIndicatorIconNumber: Color.lerp( + stepIndicatorIconNumber, + other.stepIndicatorIconNumber, + t, + )!, + stepIndicatorIconInactive: Color.lerp( + stepIndicatorIconInactive, + other.stepIndicatorIconInactive, + t, + )!, + checkboxBGChecked: Color.lerp( + checkboxBGChecked, + other.checkboxBGChecked, + t, + )!, + checkboxBorderEmpty: Color.lerp( + checkboxBorderEmpty, + other.checkboxBorderEmpty, + t, + )!, + checkboxBGDisabled: Color.lerp( + checkboxBGDisabled, + other.checkboxBGDisabled, + t, + )!, + checkboxIconChecked: Color.lerp( + checkboxIconChecked, + other.checkboxIconChecked, + t, + )!, + checkboxIconDisabled: Color.lerp( + checkboxIconDisabled, + other.checkboxIconDisabled, + t, + )!, + checkboxTextLabel: Color.lerp( + checkboxTextLabel, + other.checkboxTextLabel, + t, + )!, + snackBarBackSuccess: Color.lerp( + snackBarBackSuccess, + other.snackBarBackSuccess, + t, + )!, + snackBarBackError: Color.lerp( + snackBarBackError, + other.snackBarBackError, + t, + )!, + snackBarBackInfo: Color.lerp( + snackBarBackInfo, + other.snackBarBackInfo, + t, + )!, + snackBarTextSuccess: Color.lerp( + snackBarTextSuccess, + other.snackBarTextSuccess, + t, + )!, + snackBarTextError: Color.lerp( + snackBarTextError, + other.snackBarTextError, + t, + )!, + snackBarTextInfo: Color.lerp( + snackBarTextInfo, + other.snackBarTextInfo, + t, + )!, + bottomNavIconBack: Color.lerp( + bottomNavIconBack, + other.bottomNavIconBack, + t, + )!, + bottomNavIconIcon: Color.lerp( + bottomNavIconIcon, + other.bottomNavIconIcon, + t, + )!, + topNavIconPrimary: Color.lerp( + topNavIconPrimary, + other.topNavIconPrimary, + t, + )!, + topNavIconGreen: Color.lerp( + topNavIconGreen, + other.topNavIconGreen, + t, + )!, + topNavIconYellow: Color.lerp( + topNavIconYellow, + other.topNavIconYellow, + t, + )!, + topNavIconRed: Color.lerp( + topNavIconRed, + other.topNavIconRed, + t, + )!, + settingsIconBack: Color.lerp( + settingsIconBack, + other.settingsIconBack, + t, + )!, + settingsIconIcon: Color.lerp( + settingsIconIcon, + other.settingsIconIcon, + t, + )!, + settingsIconBack2: Color.lerp( + settingsIconBack2, + other.settingsIconBack2, + t, + )!, + settingsIconElement: Color.lerp( + settingsIconElement, + other.settingsIconElement, + t, + )!, + textFieldActiveBG: Color.lerp( + textFieldActiveBG, + other.textFieldActiveBG, + t, + )!, + textFieldDefaultBG: Color.lerp( + textFieldDefaultBG, + other.textFieldDefaultBG, + t, + )!, + textFieldErrorBG: Color.lerp( + textFieldErrorBG, + other.textFieldErrorBG, + t, + )!, + textFieldSuccessBG: Color.lerp( + textFieldSuccessBG, + other.textFieldSuccessBG, + t, + )!, + textFieldActiveSearchIconLeft: Color.lerp( + textFieldActiveSearchIconLeft, + other.textFieldActiveSearchIconLeft, + t, + )!, + textFieldDefaultSearchIconLeft: Color.lerp( + textFieldDefaultSearchIconLeft, + other.textFieldDefaultSearchIconLeft, + t, + )!, + textFieldErrorSearchIconLeft: Color.lerp( + textFieldErrorSearchIconLeft, + other.textFieldErrorSearchIconLeft, + t, + )!, + textFieldSuccessSearchIconLeft: Color.lerp( + textFieldSuccessSearchIconLeft, + other.textFieldSuccessSearchIconLeft, + t, + )!, + textFieldActiveText: Color.lerp( + textFieldActiveText, + other.textFieldActiveText, + t, + )!, + textFieldDefaultText: Color.lerp( + textFieldDefaultText, + other.textFieldDefaultText, + t, + )!, + textFieldErrorText: Color.lerp( + textFieldErrorText, + other.textFieldErrorText, + t, + )!, + textFieldSuccessText: Color.lerp( + textFieldSuccessText, + other.textFieldSuccessText, + t, + )!, + textFieldActiveLabel: Color.lerp( + textFieldActiveLabel, + other.textFieldActiveLabel, + t, + )!, + textFieldErrorLabel: Color.lerp( + textFieldErrorLabel, + other.textFieldErrorLabel, + t, + )!, + textFieldSuccessLabel: Color.lerp( + textFieldSuccessLabel, + other.textFieldSuccessLabel, + t, + )!, + textFieldActiveSearchIconRight: Color.lerp( + textFieldActiveSearchIconRight, + other.textFieldActiveSearchIconRight, + t, + )!, + textFieldDefaultSearchIconRight: Color.lerp( + textFieldDefaultSearchIconRight, + other.textFieldDefaultSearchIconRight, + t)!, + textFieldErrorSearchIconRight: Color.lerp( + textFieldErrorSearchIconRight, + other.textFieldErrorSearchIconRight, + t, + )!, + textFieldSuccessSearchIconRight: Color.lerp( + textFieldSuccessSearchIconRight, + other.textFieldSuccessSearchIconRight, + t)!, + settingsItem2ActiveBG: Color.lerp( + settingsItem2ActiveBG, + other.settingsItem2ActiveBG, + t, + )!, + settingsItem2ActiveText: Color.lerp( + settingsItem2ActiveText, + other.settingsItem2ActiveText, + t, + )!, + settingsItem2ActiveSub: Color.lerp( + settingsItem2ActiveSub, + other.settingsItem2ActiveSub, + t, + )!, + radioButtonIconBorder: Color.lerp( + radioButtonIconBorder, + other.radioButtonIconBorder, + t, + )!, + radioButtonIconBorderDisabled: Color.lerp( + radioButtonIconBorderDisabled, + other.radioButtonIconBorderDisabled, + t, + )!, + radioButtonBorderEnabled: Color.lerp( + radioButtonBorderEnabled, + other.radioButtonBorderEnabled, + t, + )!, + radioButtonBorderDisabled: Color.lerp( + radioButtonBorderDisabled, + other.radioButtonBorderDisabled, + t, + )!, + radioButtonIconCircle: Color.lerp( + radioButtonIconCircle, + other.radioButtonIconCircle, + t, + )!, + radioButtonIconEnabled: Color.lerp( + radioButtonIconEnabled, + other.radioButtonIconEnabled, + t, + )!, + radioButtonTextEnabled: Color.lerp( + radioButtonTextEnabled, + other.radioButtonTextEnabled, + t, + )!, + radioButtonTextDisabled: Color.lerp( + radioButtonTextDisabled, + other.radioButtonTextDisabled, + t, + )!, + radioButtonLabelEnabled: Color.lerp( + radioButtonLabelEnabled, + other.radioButtonLabelEnabled, + t, + )!, + radioButtonLabelDisabled: Color.lerp( + radioButtonLabelDisabled, + other.radioButtonLabelDisabled, + t, + )!, + infoItemBG: Color.lerp( + infoItemBG, + other.infoItemBG, + t, + )!, + infoItemLabel: Color.lerp( + infoItemLabel, + other.infoItemLabel, + t, + )!, + infoItemText: Color.lerp( + infoItemText, + other.infoItemText, + t, + )!, + infoItemIcons: Color.lerp( + infoItemIcons, + other.infoItemIcons, + t, + )!, + popupBG: Color.lerp( + popupBG, + other.popupBG, + t, + )!, + currencyListItemBG: Color.lerp( + currencyListItemBG, + other.currencyListItemBG, + t, + )!, + stackWalletBG: Color.lerp( + stackWalletBG, + other.stackWalletBG, + t, + )!, + stackWalletMid: Color.lerp( + stackWalletMid, + other.stackWalletMid, + t, + )!, + stackWalletBottom: Color.lerp( + stackWalletBottom, + other.stackWalletBottom, + t, + )!, + bottomNavShadow: Color.lerp( + bottomNavShadow, + other.bottomNavShadow, + t, + )!, + favoriteStarActive: Color.lerp( + favoriteStarActive, + other.favoriteStarActive, + t, + )!, + favoriteStarInactive: Color.lerp( + favoriteStarInactive, + other.favoriteStarInactive, + t, + )!, + splash: Color.lerp( + splash, + other.splash, + t, + )!, + highlight: Color.lerp( + highlight, + other.highlight, + t, + )!, + warningForeground: Color.lerp( + warningForeground, + other.warningForeground, + t, + )!, + warningBackground: Color.lerp( + warningBackground, + other.warningBackground, + t, + )!, + loadingOverlayTextColor: Color.lerp( + loadingOverlayTextColor, + other.loadingOverlayTextColor, + t, + )!, + myStackContactIconBG: Color.lerp( + myStackContactIconBG, + other.myStackContactIconBG, + t, + )!, + ); + } + + Color colorForCoin(Coin coin) { + switch (coin) { + case Coin.bitcoin: + case Coin.bitcoinTestNet: + return _coin.bitcoin; + // case Coin.bitcoincash: + // case Coin.bitcoincashTestnet: + // return _coin.bitcoincash; + case Coin.dogecoin: + case Coin.dogecoinTestNet: + return _coin.dogecoin; + case Coin.epicCash: + return _coin.epicCash; + case Coin.firo: + case Coin.firoTestNet: + return _coin.firo; + case Coin.monero: + return _coin.monero; + case Coin.namecoin: + return _coin.namecoin; + // case Coin.wownero: + // return wownero; + } + } + + static const _coin = CoinThemeColor(); + + BoxShadow get standardBoxShadow => BoxShadow( + color: shadow, + spreadRadius: 3, + blurRadius: 4, + ); + + Color colorForStatus(ChangeNowTransactionStatus status) { + switch (status) { + case ChangeNowTransactionStatus.New: + case ChangeNowTransactionStatus.Waiting: + case ChangeNowTransactionStatus.Confirming: + case ChangeNowTransactionStatus.Exchanging: + case ChangeNowTransactionStatus.Sending: + case ChangeNowTransactionStatus.Verifying: + return const Color(0xFFD3A90F); + case ChangeNowTransactionStatus.Finished: + return accentColorGreen; + case ChangeNowTransactionStatus.Failed: + return accentColorRed; + case ChangeNowTransactionStatus.Refunded: + return textSubtitle2; + } + } + + ButtonStyle? getPrimaryEnabledButtonColor(BuildContext context) => + Theme.of(context).textButtonTheme.style?.copyWith( + backgroundColor: MaterialStateProperty.all( + buttonBackPrimary, + ), + ); + + ButtonStyle? getPrimaryDisabledButtonColor(BuildContext context) => + Theme.of(context).textButtonTheme.style?.copyWith( + backgroundColor: MaterialStateProperty.all( + buttonBackPrimaryDisabled, + ), + ); + + ButtonStyle? getSecondaryEnabledButtonColor(BuildContext context) => + Theme.of(context).textButtonTheme.style?.copyWith( + backgroundColor: MaterialStateProperty.all( + buttonBackSecondary, + ), + ); + + ButtonStyle? getSmallSecondaryEnabledButtonColor(BuildContext context) => + Theme.of(context).textButtonTheme.style?.copyWith( + backgroundColor: MaterialStateProperty.all( + textFieldDefaultBG, + ), + ); + + ButtonStyle? getDesktopMenuButtonColor(BuildContext context) => + Theme.of(context).textButtonTheme.style?.copyWith( + backgroundColor: MaterialStateProperty.all( + popupBG, + ), + ); + + ButtonStyle? getDesktopMenuButtonColorSelected(BuildContext context) => + Theme.of(context).textButtonTheme.style?.copyWith( + backgroundColor: MaterialStateProperty.all( + textFieldDefaultBG, + ), + ); +} diff --git a/lib/utilities/util.dart b/lib/utilities/util.dart new file mode 100644 index 000000000..8a98787f2 --- /dev/null +++ b/lib/utilities/util.dart @@ -0,0 +1,29 @@ +import 'dart:io'; + +import 'package:flutter/material.dart'; + +abstract class Util { + static bool get isDesktop { + return Platform.isLinux || Platform.isMacOS || Platform.isWindows; + } + + static MaterialColor createMaterialColor(Color color) { + List strengths = [.05]; + final swatch = {}; + final int r = color.red, g = color.green, b = color.blue; + + for (int i = 1; i < 10; i++) { + strengths.add(0.1 * i); + } + for (var strength in strengths) { + final double ds = 0.5 - strength; + swatch[(strength * 1000).round()] = Color.fromRGBO( + r + ((ds < 0 ? r : (255 - r)) * ds).round(), + g + ((ds < 0 ? g : (255 - g)) * ds).round(), + b + ((ds < 0 ? b : (255 - b)) * ds).round(), + 1, + ); + } + return MaterialColor(color.value, swatch); + } +} diff --git a/lib/widgets/address_book_card.dart b/lib/widgets/address_book_card.dart index 49fa65c67..7a2fca19f 100644 --- a/lib/widgets/address_book_card.dart +++ b/lib/widgets/address_book_card.dart @@ -4,10 +4,10 @@ import 'package:flutter_svg/svg.dart'; import 'package:stackwallet/pages/address_book_views/subviews/contact_popup.dart'; import 'package:stackwallet/providers/global/address_book_service_provider.dart'; import 'package:stackwallet/utilities/assets.dart'; -import 'package:stackwallet/utilities/cfcolors.dart'; import 'package:stackwallet/utilities/constants.dart'; import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/text_styles.dart'; +import 'package:stackwallet/utilities/theme/stack_colors.dart'; import 'package:stackwallet/widgets/rounded_white_container.dart'; class AddressBookCard extends ConsumerStatefulWidget { @@ -54,7 +54,7 @@ class _AddressBookCardState extends ConsumerState { return RoundedWhiteContainer( padding: const EdgeInsets.all(4), child: RawMaterialButton( - // splashColor: CFColors.splashLight, + // splashColor: Theme.of(context).extension()!.highlight, padding: const EdgeInsets.all(0), materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, shape: RoundedRectangleBorder( @@ -80,13 +80,19 @@ class _AddressBookCardState extends ConsumerState { width: 32, height: 32, decoration: BoxDecoration( - color: CFColors.contactIconBackground, + color: contact.id == "default" + ? Theme.of(context) + .extension()! + .myStackContactIconBG + : Theme.of(context) + .extension()! + .textFieldDefaultBG, borderRadius: BorderRadius.circular(32), ), child: contact.id == "default" ? Center( child: SvgPicture.asset( - Assets.svg.stackIcon, + Assets.svg.stackIcon(context), width: 20, ), ) @@ -109,14 +115,14 @@ class _AddressBookCardState extends ConsumerState { children: [ Text( contact.name, - style: STextStyles.itemSubtitle12, + style: STextStyles.itemSubtitle12(context), ), const SizedBox( height: 4, ), Text( coinsString, - style: STextStyles.label, + style: STextStyles.label(context), ), ], ) diff --git a/lib/widgets/custom_buttons/app_bar_icon_button.dart b/lib/widgets/custom_buttons/app_bar_icon_button.dart index ef523d8e2..c3dd77629 100644 --- a/lib/widgets/custom_buttons/app_bar_icon_button.dart +++ b/lib/widgets/custom_buttons/app_bar_icon_button.dart @@ -1,7 +1,8 @@ import 'package:flutter/material.dart'; import 'package:flutter_svg/svg.dart'; import 'package:stackwallet/utilities/assets.dart'; -import 'package:stackwallet/utilities/cfcolors.dart'; +import 'package:stackwallet/utilities/theme/stack_colors.dart'; +import 'package:stackwallet/utilities/util.dart'; class AppBarIconButton extends StatelessWidget { const AppBarIconButton({ @@ -28,11 +29,11 @@ class AppBarIconButton extends StatelessWidget { width: size, decoration: BoxDecoration( borderRadius: BorderRadius.circular(1000), - color: color ?? CFColors.white, + color: color ?? Theme.of(context).extension()!.background, boxShadow: shadows, ), child: MaterialButton( - splashColor: CFColors.splashLight, + splashColor: Theme.of(context).extension()!.highlight, padding: EdgeInsets.zero, materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, shape: RoundedRectangleBorder( @@ -46,23 +47,33 @@ class AppBarIconButton extends StatelessWidget { } class AppBarBackButton extends StatelessWidget { - const AppBarBackButton({Key? key, required this.onPressed}) : super(key: key); + const AppBarBackButton({Key? key, this.onPressed}) : super(key: key); - final VoidCallback onPressed; + final VoidCallback? onPressed; @override Widget build(BuildContext context) { + final isDesktop = Util.isDesktop; return Padding( - padding: const EdgeInsets.all(10), + padding: isDesktop + ? const EdgeInsets.symmetric( + vertical: 20, + horizontal: 24, + ) + : const EdgeInsets.all(10), child: AppBarIconButton( - color: CFColors.almostWhite, + size: isDesktop ? 56 : 32, + color: isDesktop + ? Theme.of(context).extension()!.textFieldDefaultBG + : Theme.of(context).extension()!.background, shadows: const [], icon: SvgPicture.asset( Assets.svg.arrowLeft, width: 24, height: 24, + color: Theme.of(context).extension()!.topNavIconPrimary, ), - onPressed: onPressed, + onPressed: onPressed ?? Navigator.of(context).pop, ), ); } diff --git a/lib/widgets/custom_buttons/blue_text_button.dart b/lib/widgets/custom_buttons/blue_text_button.dart index 4de4bb674..18757ab93 100644 --- a/lib/widgets/custom_buttons/blue_text_button.dart +++ b/lib/widgets/custom_buttons/blue_text_button.dart @@ -1,9 +1,10 @@ -import 'package:flutter/cupertino.dart'; import 'package:flutter/gestures.dart'; -import 'package:stackwallet/utilities/cfcolors.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:stackwallet/providers/ui/color_theme_provider.dart'; import 'package:stackwallet/utilities/text_styles.dart'; -class BlueTextButton extends StatefulWidget { +class BlueTextButton extends ConsumerStatefulWidget { const BlueTextButton({Key? key, required this.text, this.onTap}) : super(key: key); @@ -11,10 +12,10 @@ class BlueTextButton extends StatefulWidget { final VoidCallback? onTap; @override - State createState() => _BlueTextButtonState(); + ConsumerState createState() => _BlueTextButtonState(); } -class _BlueTextButtonState extends State +class _BlueTextButtonState extends ConsumerState with SingleTickerProviderStateMixin { late AnimationController controller; late Animation animation; @@ -22,14 +23,18 @@ class _BlueTextButtonState extends State @override void initState() { - color = CFColors.link2; + color = ref.read(colorThemeProvider.state).state.buttonTextBorderless; controller = AnimationController( vsync: this, duration: const Duration(milliseconds: 100), ); animation = ColorTween( - begin: CFColors.link2, - end: CFColors.link2.withOpacity(0.4), + begin: ref.read(colorThemeProvider.state).state.buttonTextBorderless, + end: ref + .read(colorThemeProvider.state) + .state + .buttonTextBorderless + .withOpacity(0.4), ).animate(controller); animation.addListener(() { @@ -53,7 +58,7 @@ class _BlueTextButtonState extends State textAlign: TextAlign.center, text: TextSpan( text: widget.text, - style: STextStyles.link2.copyWith(color: color), + style: STextStyles.link2(context).copyWith(color: color), recognizer: TapGestureRecognizer() ..onTap = () { widget.onTap?.call(); diff --git a/lib/widgets/custom_buttons/draggable_switch_button.dart b/lib/widgets/custom_buttons/draggable_switch_button.dart index eeaa871ac..33dfe9860 100644 --- a/lib/widgets/custom_buttons/draggable_switch_button.dart +++ b/lib/widgets/custom_buttons/draggable_switch_button.dart @@ -1,5 +1,5 @@ import 'package:flutter/material.dart'; -import 'package:stackwallet/utilities/cfcolors.dart'; +import 'package:stackwallet/utilities/theme/stack_colors.dart'; class DraggableSwitchButton extends StatefulWidget { const DraggableSwitchButton({ @@ -37,21 +37,27 @@ class DraggableSwitchButtonState extends State { Color _colorBG(bool isOn, bool enabled, double alpha) { if (enabled) { return Color.alphaBlend( - CFColors.primary.withOpacity(alpha), - CFColors.primaryLight, + Theme.of(context) + .extension()! + .switchBGOn + .withOpacity(alpha), + Theme.of(context).extension()!.switchBGOff, ); } - return CFColors.neutral80; + return Theme.of(context).extension()!.switchBGDisabled; } Color _colorFG(bool isOn, bool enabled, double alpha) { if (enabled) { return Color.alphaBlend( - CFColors.primaryLight.withOpacity(alpha), - CFColors.white, + Theme.of(context) + .extension()! + .switchCircleOn + .withOpacity(alpha), + Theme.of(context).extension()!.switchCircleOff, ); } - return CFColors.white; + return Theme.of(context).extension()!.switchCircleDisabled; } @override diff --git a/lib/widgets/custom_buttons/favorite_toggle.dart b/lib/widgets/custom_buttons/favorite_toggle.dart index 4b7586ccc..83834a3ee 100644 --- a/lib/widgets/custom_buttons/favorite_toggle.dart +++ b/lib/widgets/custom_buttons/favorite_toggle.dart @@ -1,39 +1,48 @@ import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_svg/svg.dart'; +import 'package:stackwallet/providers/ui/color_theme_provider.dart'; import 'package:stackwallet/utilities/assets.dart'; -import 'package:stackwallet/utilities/cfcolors.dart'; +import 'package:stackwallet/utilities/theme/stack_colors.dart'; -class FavoriteToggle extends StatefulWidget { +class FavoriteToggle extends ConsumerStatefulWidget { const FavoriteToggle({ Key? key, this.backGround, this.borderRadius = BorderRadius.zero, this.initialState = false, - this.on = CFColors.link2, - this.off = CFColors.buttonGray, + this.on, + this.off, required this.onChanged, }) : super(key: key); final Color? backGround; - final Color on; - final Color off; + final Color? on; + final Color? off; final BorderRadiusGeometry borderRadius; final bool initialState; final void Function(bool)? onChanged; @override - State createState() => _FavoriteToggleState(); + ConsumerState createState() => _FavoriteToggleState(); } -class _FavoriteToggleState extends State { +class _FavoriteToggleState extends ConsumerState { late bool _isActive; late Color _color; late void Function(bool)? _onChanged; + late final Color on; + late final Color off; + @override void initState() { + on = widget.on ?? + ref.read(colorThemeProvider.state).state.favoriteStarActive; + off = widget.off ?? + ref.read(colorThemeProvider.state).state.favoriteStarInactive; _isActive = widget.initialState; - _color = _isActive ? widget.on : widget.off; + _color = _isActive ? on : off; _onChanged = widget.onChanged; super.initState(); } @@ -46,7 +55,7 @@ class _FavoriteToggleState extends State { borderRadius: widget.borderRadius, ), child: MaterialButton( - splashColor: CFColors.splashLight, + splashColor: Theme.of(context).extension()!.highlight, minWidth: 0, materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, shape: RoundedRectangleBorder( @@ -56,7 +65,7 @@ class _FavoriteToggleState extends State { ? () { _isActive = !_isActive; setState(() { - _color = _isActive ? widget.on : widget.off; + _color = _isActive ? on : off; }); _onChanged!.call(_isActive); } diff --git a/lib/widgets/custom_loading_overlay.dart b/lib/widgets/custom_loading_overlay.dart index 3c392b674..c92d7705d 100644 --- a/lib/widgets/custom_loading_overlay.dart +++ b/lib/widgets/custom_loading_overlay.dart @@ -3,8 +3,8 @@ import 'dart:async'; import 'package:event_bus/event_bus.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:stackwallet/utilities/cfcolors.dart'; import 'package:stackwallet/utilities/text_styles.dart'; +import 'package:stackwallet/utilities/theme/stack_colors.dart'; import 'package:stackwallet/widgets/loading_indicator.dart'; class CustomLoadingOverlay extends ConsumerStatefulWidget { @@ -56,8 +56,10 @@ class _CustomLoadingOverlayState extends ConsumerState { children: [ Text( widget.message, - style: STextStyles.pageTitleH2.copyWith( - color: CFColors.white, + style: STextStyles.pageTitleH2(context).copyWith( + color: Theme.of(context) + .extension()! + .loadingOverlayTextColor, ), ), if (widget.eventBus != null) @@ -67,8 +69,10 @@ class _CustomLoadingOverlayState extends ConsumerState { if (widget.eventBus != null) Text( "${(_percent * 100).toStringAsFixed(2)}%", - style: STextStyles.pageTitleH2.copyWith( - color: CFColors.white, + style: STextStyles.pageTitleH2(context).copyWith( + color: Theme.of(context) + .extension()! + .loadingOverlayTextColor, ), ), ], diff --git a/lib/widgets/custom_pin_put/pin_keyboard.dart b/lib/widgets/custom_pin_put/pin_keyboard.dart index 1942f3af4..6c1f50d78 100644 --- a/lib/widgets/custom_pin_put/pin_keyboard.dart +++ b/lib/widgets/custom_pin_put/pin_keyboard.dart @@ -2,7 +2,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:google_fonts/google_fonts.dart'; import 'package:stackwallet/utilities/assets.dart'; -import 'package:stackwallet/utilities/cfcolors.dart'; +import 'package:stackwallet/utilities/theme/stack_colors.dart'; class NumberKey extends StatefulWidget { const NumberKey({ @@ -22,7 +22,7 @@ class _NumberKeyState extends State { late final String number; late final ValueSetter onPressed; - Color _color = CFColors.white; + Color? _color; @override void initState() { @@ -34,6 +34,8 @@ class _NumberKeyState extends State { @override Widget build(BuildContext context) { + _color ??= Theme.of(context).extension()!.numberBackDefault; + return AnimatedContainer( duration: const Duration(milliseconds: 200), curve: Curves.easeInOut, @@ -45,19 +47,24 @@ class _NumberKeyState extends State { shadows: const [], ), child: MaterialButton( - // splashColor: CFColors.splashLight, + // splashColor: Theme.of(context).extension()!.highlight, materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, shape: const StadiumBorder(), onPressed: () async { onPressed.call(number); setState(() { - _color = CFColors.splashLight; + _color = Theme.of(context) + .extension()! + .numberBackDefault + .withOpacity(0.8); }); Future.delayed(const Duration(milliseconds: 200), () { if (mounted) { setState(() { - _color = CFColors.white; + _color = Theme.of(context) + .extension()! + .numberBackDefault; }); } }); @@ -66,7 +73,8 @@ class _NumberKeyState extends State { child: Text( number, style: GoogleFonts.roboto( - color: CFColors.stackAccent, + color: + Theme.of(context).extension()!.numberTextDefault, fontWeight: FontWeight.w400, fontSize: 26, ), @@ -92,7 +100,7 @@ class BackspaceKey extends StatefulWidget { class _BackspaceKeyState extends State { late final VoidCallback onPressed; - Color _color = CFColors.stackAccent; + Color? _color; @override void initState() { @@ -102,6 +110,7 @@ class _BackspaceKeyState extends State { @override Widget build(BuildContext context) { + _color ??= Theme.of(context).extension()!.numpadBackDefault; return AnimatedContainer( duration: const Duration(milliseconds: 200), curve: Curves.easeInOut, @@ -113,19 +122,24 @@ class _BackspaceKeyState extends State { shadows: const [], ), child: MaterialButton( - // splashColor: CFColors.splashLight, + // splashColor: Theme.of(context).extension()!.highlight, materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, shape: const StadiumBorder(), onPressed: () { onPressed.call(); setState(() { - _color = CFColors.stackAccent.withOpacity(0.8); + _color = Theme.of(context) + .extension()! + .numpadBackDefault + .withOpacity(0.8); }); Future.delayed(const Duration(milliseconds: 200), () { if (mounted) { setState(() { - _color = CFColors.stackAccent; + _color = Theme.of(context) + .extension()! + .numpadBackDefault; }); } }); @@ -135,6 +149,8 @@ class _BackspaceKeyState extends State { Assets.svg.delete, width: 20, height: 20, + color: + Theme.of(context).extension()!.numpadTextDefault, ), ), ), @@ -142,44 +158,44 @@ class _BackspaceKeyState extends State { } } -// class SubmitKey extends StatelessWidget { -// const SubmitKey({ -// Key? key, -// required this.onPressed, -// }) : super(key: key); -// -// final VoidCallback onPressed; -// -// @override -// Widget build(BuildContext context) { -// return Container( -// height: 72, -// width: 72, -// decoration: ShapeDecoration( -// shape: StadiumBorder(), -// color: CFColors.stackAccent, -// shadows: [], -// ), -// child: MaterialButton( -// // splashColor: CFColors.splashLight, -// materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, -// shape: StadiumBorder(), -// onPressed: () { -// onPressed.call(); -// }, -// child: Container( -// child: Center( -// child: SvgPicture.asset( -// Assets.svg.arrowRight, -// width: 20, -// height: 20, -// ), -// ), -// ), -// ), -// ); -// } -// } +class SubmitKey extends StatelessWidget { + const SubmitKey({ + Key? key, + required this.onPressed, + }) : super(key: key); + + final VoidCallback onPressed; + + @override + Widget build(BuildContext context) { + return Container( + height: 72, + width: 72, + decoration: ShapeDecoration( + shape: const StadiumBorder(), + color: Theme.of(context).extension()!.numpadBackDefault, + shadows: const [], + ), + child: MaterialButton( + // splashColor: Theme.of(context).extension()!.highlight, + materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, + shape: const StadiumBorder(), + onPressed: () { + onPressed.call(); + }, + child: Center( + child: SvgPicture.asset( + Assets.svg.arrowRight, + width: 20, + height: 20, + color: + Theme.of(context).extension()!.numpadTextDefault, + ), + ), + ), + ); + } +} class PinKeyboard extends StatelessWidget { const PinKeyboard({ @@ -203,9 +219,9 @@ class PinKeyboard extends StatelessWidget { onBackPressed.call(); } - // void _submitHandler() { - // onSubmitPressed.call(); - // } + void _submitHandler() { + onSubmitPressed.call(); + } void _numberHandler(String number) { onNumberKeyPressed.call(number); @@ -310,12 +326,12 @@ class PinKeyboard extends StatelessWidget { const SizedBox( width: 24, ), - // SubmitKey( - // onPressed: _submitHandler, - // ) BackspaceKey( onPressed: _backHandler, ), + // SubmitKey( + // onPressed: _submitHandler, + // ), ], ) ], diff --git a/lib/widgets/desktop/desktop_app_bar.dart b/lib/widgets/desktop/desktop_app_bar.dart new file mode 100644 index 000000000..1c825382c --- /dev/null +++ b/lib/widgets/desktop/desktop_app_bar.dart @@ -0,0 +1,66 @@ +import 'package:flutter/material.dart'; + +const double kDesktopAppBarHeight = 96.0; +const double kDesktopAppBarHeightCompact = 82.0; + +class DesktopAppBar extends StatefulWidget { + const DesktopAppBar({ + Key? key, + this.leading, + this.center, + this.trailing, + this.background = Colors.transparent, + required this.isCompactHeight, + }) : super(key: key); + + final Widget? leading; + final Widget? center; + final Widget? trailing; + final Color background; + final bool isCompactHeight; + + @override + State createState() => _DesktopAppBarState(); +} + +class _DesktopAppBarState extends State { + late final List items; + + @override + void initState() { + items = []; + if (widget.leading != null) { + items.add(widget.leading!); + } + + items.add(const Spacer()); + + if (widget.center != null) { + items.add(widget.center!); + items.add(const Spacer()); + } + + if (widget.trailing != null) { + items.add(widget.trailing!); + } + + super.initState(); + } + + @override + Widget build(BuildContext context) { + return Container( + decoration: BoxDecoration( + color: widget.background, + ), + height: widget.isCompactHeight + ? kDesktopAppBarHeightCompact + : kDesktopAppBarHeight, + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.center, + children: items, + ), + ); + } +} diff --git a/lib/widgets/desktop/desktop_scaffold.dart b/lib/widgets/desktop/desktop_scaffold.dart new file mode 100644 index 000000000..439289518 --- /dev/null +++ b/lib/widgets/desktop/desktop_scaffold.dart @@ -0,0 +1,67 @@ +import 'package:flutter/material.dart'; +import 'package:stackwallet/utilities/theme/stack_colors.dart'; + +class DesktopScaffold extends StatelessWidget { + const DesktopScaffold({ + Key? key, + this.background, + this.appBar, + this.body, + }) : super(key: key); + + final Color? background; + final Widget? appBar; + final Widget? body; + + @override + Widget build(BuildContext context) { + return Material( + color: + background ?? Theme.of(context).extension()!.background, + child: Column( + // crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + if (appBar != null) appBar!, + if (body != null) + Expanded( + child: body!, + ), + ], + ), + ); + } +} + +class MasterScaffold extends StatelessWidget { + const MasterScaffold({ + Key? key, + required this.isDesktop, + required this.appBar, + required this.body, + this.background, + }) : super(key: key); + + final bool isDesktop; + final Widget appBar; + final Widget body; + final Color? background; + + @override + Widget build(BuildContext context) { + if (isDesktop) { + return DesktopScaffold( + background: background ?? + Theme.of(context).extension()!.background, + appBar: appBar, + body: body, + ); + } else { + return Scaffold( + backgroundColor: background ?? + Theme.of(context).extension()!.background, + appBar: appBar as PreferredSizeWidget?, + body: body, + ); + } + } +} diff --git a/lib/widgets/emoji_select_sheet.dart b/lib/widgets/emoji_select_sheet.dart index 01fd8a6a1..85a90fec8 100644 --- a/lib/widgets/emoji_select_sheet.dart +++ b/lib/widgets/emoji_select_sheet.dart @@ -1,9 +1,9 @@ import 'package:emojis/emoji.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:stackwallet/utilities/cfcolors.dart'; import 'package:stackwallet/utilities/constants.dart'; import 'package:stackwallet/utilities/text_styles.dart'; +import 'package:stackwallet/utilities/theme/stack_colors.dart'; class EmojiSelectSheet extends ConsumerWidget { const EmojiSelectSheet({ @@ -25,9 +25,9 @@ class EmojiSelectSheet extends ConsumerWidget { final itemCount = Emoji.all().length; return Container( - decoration: const BoxDecoration( - color: CFColors.white, - borderRadius: BorderRadius.vertical( + decoration: BoxDecoration( + color: Theme.of(context).extension()!.popupBG, + borderRadius: const BorderRadius.vertical( top: Radius.circular(20), ), ), @@ -47,7 +47,9 @@ class EmojiSelectSheet extends ConsumerWidget { Center( child: Container( decoration: BoxDecoration( - color: CFColors.fieldGray, + color: Theme.of(context) + .extension()! + .textFieldDefaultBG, borderRadius: BorderRadius.circular( Constants.size.circularBorderRadius, ), @@ -61,7 +63,7 @@ class EmojiSelectSheet extends ConsumerWidget { ), Text( "Select emoji", - style: STextStyles.pageTitleH2, + style: STextStyles.pageTitleH2(context), textAlign: TextAlign.left, ), const SizedBox( diff --git a/lib/widgets/expandable.dart b/lib/widgets/expandable.dart new file mode 100644 index 000000000..ddae2201d --- /dev/null +++ b/lib/widgets/expandable.dart @@ -0,0 +1,91 @@ +import 'package:flutter/material.dart'; + +enum ExpandableState { + expanded, + collapsed, +} + +class Expandable extends StatefulWidget { + const Expandable({ + Key? key, + required this.header, + required this.body, + this.animationController, + this.animation, + this.animationDurationMultiplier = 1.0, + this.onExpandChanged, + }) : super(key: key); + + final Widget header; + final Widget body; + final AnimationController? animationController; + final Animation? animation; + final double animationDurationMultiplier; + final void Function(ExpandableState)? onExpandChanged; + + @override + State createState() => _ExpandableState(); +} + +class _ExpandableState extends State with TickerProviderStateMixin { + late final AnimationController animationController; + late final Animation animation; + late final Duration duration; + + Future toggle() async { + if (animation.isDismissed) { + await animationController.forward(); + widget.onExpandChanged?.call(ExpandableState.collapsed); + } else if (animation.isCompleted) { + await animationController.reverse(); + widget.onExpandChanged?.call(ExpandableState.expanded); + } + } + + @override + void initState() { + duration = Duration( + milliseconds: (500 * widget.animationDurationMultiplier).toInt(), + ); + animationController = widget.animationController ?? + AnimationController( + vsync: this, + duration: duration, + ); + animation = widget.animation ?? + Tween(begin: 0.0, end: 1.0).animate( + CurvedAnimation( + curve: Curves.easeInOut, + parent: animationController, + ), + ); + super.initState(); + } + + @override + void dispose() { + animationController.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Column( + mainAxisSize: MainAxisSize.min, + children: [ + GestureDetector( + onTap: toggle, + child: Container( + color: Colors.transparent, + child: widget.header, + ), + ), + SizeTransition( + sizeFactor: animation, + axisAlignment: 1.0, + child: widget.body, + ), + ], + ); + } +} diff --git a/lib/widgets/gradient_card.dart b/lib/widgets/gradient_card.dart index 154a50993..c0b276c13 100644 --- a/lib/widgets/gradient_card.dart +++ b/lib/widgets/gradient_card.dart @@ -1,7 +1,5 @@ // import 'package:flutter/material.dart'; // import 'package:stackwallet/utilities/cfcolors.dart'; -// -// class GradientCard extends StatelessWidget { // const GradientCard( // {Key key, // this.child, diff --git a/lib/widgets/icon_widgets/addressbook_icon.dart b/lib/widgets/icon_widgets/addressbook_icon.dart index a0e0db616..3e9f7b2a5 100644 --- a/lib/widgets/icon_widgets/addressbook_icon.dart +++ b/lib/widgets/icon_widgets/addressbook_icon.dart @@ -1,14 +1,14 @@ -import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; import 'package:flutter_svg/svg.dart'; import 'package:stackwallet/utilities/assets.dart'; -import 'package:stackwallet/utilities/cfcolors.dart'; +import 'package:stackwallet/utilities/theme/stack_colors.dart'; class AddressBookIcon extends StatelessWidget { const AddressBookIcon({ Key? key, this.width = 16, this.height = 16, - this.color = CFColors.neutral50, + this.color, }) : super(key: key); final double width; @@ -21,7 +21,7 @@ class AddressBookIcon extends StatelessWidget { Assets.svg.addressBook, width: width, height: height, - color: color, + color: color ?? Theme.of(context).extension()!.textDark3, ); } } diff --git a/lib/widgets/icon_widgets/clipboard_icon.dart b/lib/widgets/icon_widgets/clipboard_icon.dart index c90e77f9b..caafda0a6 100644 --- a/lib/widgets/icon_widgets/clipboard_icon.dart +++ b/lib/widgets/icon_widgets/clipboard_icon.dart @@ -1,14 +1,14 @@ -import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; import 'package:flutter_svg/svg.dart'; import 'package:stackwallet/utilities/assets.dart'; -import 'package:stackwallet/utilities/cfcolors.dart'; +import 'package:stackwallet/utilities/theme/stack_colors.dart'; class ClipboardIcon extends StatelessWidget { const ClipboardIcon({ Key? key, this.width = 18, this.height = 18, - this.color = CFColors.neutral50, + this.color, }) : super(key: key); final double width; @@ -21,7 +21,7 @@ class ClipboardIcon extends StatelessWidget { Assets.svg.clipboard, width: width, height: height, - color: color, + color: color ?? Theme.of(context).extension()!.textDark3, ); } } diff --git a/lib/widgets/icon_widgets/dice_icon.dart b/lib/widgets/icon_widgets/dice_icon.dart index e78ede912..ca502bfdf 100644 --- a/lib/widgets/icon_widgets/dice_icon.dart +++ b/lib/widgets/icon_widgets/dice_icon.dart @@ -1,14 +1,14 @@ -import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; import 'package:flutter_svg/svg.dart'; import 'package:stackwallet/utilities/assets.dart'; -import 'package:stackwallet/utilities/cfcolors.dart'; +import 'package:stackwallet/utilities/theme/stack_colors.dart'; class DiceIcon extends StatelessWidget { const DiceIcon({ Key? key, this.width = 17, this.height = 17, - this.color = CFColors.neutral50, + this.color, }) : super(key: key); final double width; @@ -21,7 +21,7 @@ class DiceIcon extends StatelessWidget { Assets.svg.dice, width: width, height: height, - color: color, + color: color ?? Theme.of(context).extension()!.textDark3, ); } } diff --git a/lib/widgets/icon_widgets/qrcode_icon.dart b/lib/widgets/icon_widgets/qrcode_icon.dart index 530afc751..598dbcf84 100644 --- a/lib/widgets/icon_widgets/qrcode_icon.dart +++ b/lib/widgets/icon_widgets/qrcode_icon.dart @@ -1,14 +1,14 @@ -import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; import 'package:flutter_svg/svg.dart'; import 'package:stackwallet/utilities/assets.dart'; -import 'package:stackwallet/utilities/cfcolors.dart'; +import 'package:stackwallet/utilities/theme/stack_colors.dart'; class QrCodeIcon extends StatelessWidget { const QrCodeIcon({ Key? key, this.width = 17, this.height = 17, - this.color = CFColors.neutral50, + this.color, }) : super(key: key); final double width; @@ -21,7 +21,7 @@ class QrCodeIcon extends StatelessWidget { Assets.svg.qrcode, width: width, height: height, - color: color, + color: color ?? Theme.of(context).extension()!.textDark3, ); } } diff --git a/lib/widgets/icon_widgets/x_icon.dart b/lib/widgets/icon_widgets/x_icon.dart index 7e1962e58..4a497a464 100644 --- a/lib/widgets/icon_widgets/x_icon.dart +++ b/lib/widgets/icon_widgets/x_icon.dart @@ -1,14 +1,14 @@ -import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; import 'package:flutter_svg/svg.dart'; import 'package:stackwallet/utilities/assets.dart'; -import 'package:stackwallet/utilities/cfcolors.dart'; +import 'package:stackwallet/utilities/theme/stack_colors.dart'; class XIcon extends StatelessWidget { const XIcon({ Key? key, this.width = 18, this.height = 18, - this.color = CFColors.neutral50, + this.color, }) : super(key: key); final double width; @@ -21,7 +21,10 @@ class XIcon extends StatelessWidget { Assets.svg.x, width: width, height: height, - color: color, + color: color ?? + Theme.of(context) + .extension()! + .textFieldActiveSearchIconRight, ); } } diff --git a/lib/widgets/managed_favorite.dart b/lib/widgets/managed_favorite.dart index e365420fe..3cd8a92d3 100644 --- a/lib/widgets/managed_favorite.dart +++ b/lib/widgets/managed_favorite.dart @@ -3,11 +3,11 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_svg/svg.dart'; import 'package:stackwallet/providers/providers.dart'; import 'package:stackwallet/utilities/assets.dart'; -import 'package:stackwallet/utilities/cfcolors.dart'; import 'package:stackwallet/utilities/constants.dart'; import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/format.dart'; import 'package:stackwallet/utilities/text_styles.dart'; +import 'package:stackwallet/utilities/theme/stack_colors.dart'; import 'package:stackwallet/widgets/custom_buttons/favorite_toggle.dart'; import 'package:stackwallet/widgets/rounded_white_container.dart'; @@ -33,7 +33,7 @@ class _ManagedFavoriteCardState extends ConsumerState { return RoundedWhiteContainer( padding: const EdgeInsets.all(4.0), child: RawMaterialButton( - onPressed: () async { + onPressed: () { final provider = ref .read(walletsChangeNotifierProvider) .getManagerProvider(manager.walletId); @@ -64,7 +64,10 @@ class _ManagedFavoriteCardState extends ConsumerState { children: [ Container( decoration: BoxDecoration( - color: CFColors.coin.forCoin(manager.coin).withOpacity(0.5), + color: Theme.of(context) + .extension()! + .colorForCoin(manager.coin) + .withOpacity(0.5), borderRadius: BorderRadius.circular( Constants.size.circularBorderRadius, ), @@ -81,29 +84,30 @@ class _ManagedFavoriteCardState extends ConsumerState { const SizedBox( width: 12, ), - Column( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - manager.walletName, - style: STextStyles.titleBold12, - ), - const SizedBox( - height: 2, - ), - Text( - "${Format.localizedStringAsFixed( - value: manager.cachedTotalBalance, - locale: ref.watch(localeServiceChangeNotifierProvider - .select((value) => value.locale)), - decimalPlaces: 8, - )} ${manager.coin.ticker}", - style: STextStyles.itemSubtitle, - ), - ], + Expanded( + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + manager.walletName, + style: STextStyles.titleBold12(context), + ), + const SizedBox( + height: 2, + ), + Text( + "${Format.localizedStringAsFixed( + value: manager.cachedTotalBalance, + locale: ref.watch(localeServiceChangeNotifierProvider + .select((value) => value.locale)), + decimalPlaces: 8, + )} ${manager.coin.ticker}", + style: STextStyles.itemSubtitle(context), + ), + ], + ), ), - const Spacer(), FavoriteToggle( borderRadius: BorderRadius.circular( Constants.size.circularBorderRadius, diff --git a/lib/widgets/node_card.dart b/lib/widgets/node_card.dart index 6f3eac6c1..1f0287013 100644 --- a/lib/widgets/node_card.dart +++ b/lib/widgets/node_card.dart @@ -3,11 +3,11 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_svg/svg.dart'; import 'package:stackwallet/providers/providers.dart'; import 'package:stackwallet/utilities/assets.dart'; -import 'package:stackwallet/utilities/cfcolors.dart'; import 'package:stackwallet/utilities/constants.dart'; import 'package:stackwallet/utilities/default_nodes.dart'; import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/text_styles.dart'; +import 'package:stackwallet/utilities/theme/stack_colors.dart'; import 'package:stackwallet/widgets/node_options_sheet.dart'; import 'package:stackwallet/widgets/rounded_white_container.dart'; @@ -78,8 +78,13 @@ class _NodeCardState extends ConsumerState { height: 24, decoration: BoxDecoration( color: _node.name == DefaultNodes.defaultName - ? CFColors.buttonGray - : CFColors.link2.withOpacity(0.2), + ? Theme.of(context) + .extension()! + .buttonBackSecondary + : Theme.of(context) + .extension()! + .infoItemIcons + .withOpacity(0.2), borderRadius: BorderRadius.circular(100), ), child: Center( @@ -88,8 +93,12 @@ class _NodeCardState extends ConsumerState { height: 11, width: 14, color: _node.name == DefaultNodes.defaultName - ? CFColors.stackAccent - : CFColors.link2, + ? Theme.of(context) + .extension()! + .accentColorDark + : Theme.of(context) + .extension()! + .infoItemIcons, ), ), ), @@ -101,14 +110,14 @@ class _NodeCardState extends ConsumerState { children: [ Text( _node.name, - style: STextStyles.titleBold12, + style: STextStyles.titleBold12(context), ), const SizedBox( height: 2, ), Text( _status, - style: STextStyles.label, + style: STextStyles.label(context), ), ], ), @@ -116,8 +125,12 @@ class _NodeCardState extends ConsumerState { SvgPicture.asset( Assets.svg.network, color: _status == "Connected" - ? CFColors.stackGreen - : CFColors.buttonGray, + ? Theme.of(context) + .extension()! + .accentColorGreen + : Theme.of(context) + .extension()! + .buttonBackSecondary, width: 20, height: 20, ), diff --git a/lib/widgets/node_options_sheet.dart b/lib/widgets/node_options_sheet.dart index f84f943d6..1ad4941c5 100644 --- a/lib/widgets/node_options_sheet.dart +++ b/lib/widgets/node_options_sheet.dart @@ -1,3 +1,5 @@ +import 'dart:async'; + import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_svg/svg.dart'; @@ -7,7 +9,6 @@ import 'package:stackwallet/notifications/show_flush_bar.dart'; import 'package:stackwallet/pages/settings_views/global_settings_view/manage_nodes_views/node_details_view.dart'; import 'package:stackwallet/providers/providers.dart'; import 'package:stackwallet/utilities/assets.dart'; -import 'package:stackwallet/utilities/cfcolors.dart'; import 'package:stackwallet/utilities/constants.dart'; import 'package:stackwallet/utilities/default_nodes.dart'; import 'package:stackwallet/utilities/enums/coin_enum.dart'; @@ -17,6 +18,7 @@ import 'package:stackwallet/utilities/logger.dart'; import 'package:stackwallet/utilities/test_epic_box_connection.dart'; import 'package:stackwallet/utilities/test_monero_node_connection.dart'; import 'package:stackwallet/utilities/text_styles.dart'; +import 'package:stackwallet/utilities/theme/stack_colors.dart'; import 'package:stackwallet/widgets/rounded_white_container.dart'; import 'package:tuple/tuple.dart'; @@ -104,6 +106,9 @@ class NodeOptionsSheet extends ConsumerWidget { case Coin.bitcoinTestNet: case Coin.firoTestNet: case Coin.dogecoinTestNet: + // case Coin.bitcoincash: + case Coin.namecoin: + // case Coin.bitcoincashTestnet: final client = ElectrumX( host: node.host, port: node.port, @@ -128,12 +133,12 @@ class NodeOptionsSheet extends ConsumerWidget { // context: context, // ); } else { - showFloatingFlushBar( + unawaited(showFloatingFlushBar( type: FlushBarType.warning, iconAsset: Assets.svg.circleAlert, message: "Could not connect to node", context: context, - ); + )); } return testPassed; @@ -154,9 +159,9 @@ class NodeOptionsSheet extends ConsumerWidget { : "Connected"; return Container( - decoration: const BoxDecoration( - color: CFColors.white, - borderRadius: BorderRadius.vertical( + decoration: BoxDecoration( + color: Theme.of(context).extension()!.popupBG, + borderRadius: const BorderRadius.vertical( top: Radius.circular(20), ), ), @@ -177,7 +182,9 @@ class NodeOptionsSheet extends ConsumerWidget { Center( child: Container( decoration: BoxDecoration( - color: CFColors.fieldGray, + color: Theme.of(context) + .extension()! + .textFieldDefaultBG, borderRadius: BorderRadius.circular( Constants.size.circularBorderRadius, ), @@ -191,7 +198,7 @@ class NodeOptionsSheet extends ConsumerWidget { ), Text( "Node options", - style: STextStyles.pageTitleH2, + style: STextStyles.pageTitleH2(context), textAlign: TextAlign.left, ), RoundedWhiteContainer( @@ -203,8 +210,13 @@ class NodeOptionsSheet extends ConsumerWidget { height: 32, decoration: BoxDecoration( color: node.name == DefaultNodes.defaultName - ? CFColors.buttonGray - : CFColors.link2.withOpacity(0.2), + ? Theme.of(context) + .extension()! + .textSubtitle4 + : Theme.of(context) + .extension()! + .infoItemIcons + .withOpacity(0.2), borderRadius: BorderRadius.circular(100), ), child: Center( @@ -213,8 +225,12 @@ class NodeOptionsSheet extends ConsumerWidget { height: 15, width: 19, color: node.name == DefaultNodes.defaultName - ? CFColors.stackAccent - : CFColors.link2, + ? Theme.of(context) + .extension()! + .accentColorDark + : Theme.of(context) + .extension()! + .infoItemIcons, ), ), ), @@ -226,14 +242,14 @@ class NodeOptionsSheet extends ConsumerWidget { children: [ Text( node.name, - style: STextStyles.titleBold12, + style: STextStyles.titleBold12(context), ), const SizedBox( height: 2, ), Text( status, - style: STextStyles.label, + style: STextStyles.label(context), ), ], ), @@ -241,8 +257,12 @@ class NodeOptionsSheet extends ConsumerWidget { SvgPicture.asset( Assets.svg.network, color: status == "Connected" - ? CFColors.stackGreen - : CFColors.buttonGray, + ? Theme.of(context) + .extension()! + .accentColorGreen + : Theme.of(context) + .extension()! + .buttonBackSecondary, width: 18, ), ], @@ -253,11 +273,9 @@ class NodeOptionsSheet extends ConsumerWidget { // if (!node.id.startsWith("default")) Expanded( child: TextButton( - style: ButtonStyle( - backgroundColor: MaterialStateProperty.all( - CFColors.buttonGray, - ), - ), + style: Theme.of(context) + .extension()! + .getSecondaryEnabledButtonColor(context), onPressed: () { Navigator.pop(context); Navigator.of(context).pushNamed( @@ -271,9 +289,10 @@ class NodeOptionsSheet extends ConsumerWidget { }, child: Text( "Details", - style: STextStyles.button.copyWith( - color: CFColors.stackAccent, - ), + style: STextStyles.button(context).copyWith( + color: Theme.of(context) + .extension()! + .accentColorDark), ), ), ), @@ -283,13 +302,13 @@ class NodeOptionsSheet extends ConsumerWidget { ), Expanded( child: TextButton( - style: ButtonStyle( - backgroundColor: MaterialStateProperty.all( - status == "Connected" - ? CFColors.disabledButton - : CFColors.stackAccent, - ), - ), + style: status == "Connected" + ? Theme.of(context) + .extension()! + .getPrimaryEnabledButtonColor(context) + : Theme.of(context) + .extension()! + .getPrimaryDisabledButtonColor(context), onPressed: status == "Connected" ? null : () async { @@ -299,7 +318,7 @@ class NodeOptionsSheet extends ConsumerWidget { return; } - ref + await ref .read(nodeServiceChangeNotifierProvider) .setPrimaryNodeFor( coin: coin, @@ -307,12 +326,12 @@ class NodeOptionsSheet extends ConsumerWidget { shouldNotifyListeners: true, ); - _notifyWalletsOfUpdatedNode(ref); + await _notifyWalletsOfUpdatedNode(ref); }, child: Text( // status == "Connected" ? "Disconnect" : "Connect", "Connect", - style: STextStyles.button, + style: STextStyles.button(context), ), ), ), diff --git a/lib/widgets/rounded_container.dart b/lib/widgets/rounded_container.dart index 91d23aa4e..7ae35afdd 100644 --- a/lib/widgets/rounded_container.dart +++ b/lib/widgets/rounded_container.dart @@ -1,5 +1,4 @@ import 'package:flutter/cupertino.dart'; - import 'package:stackwallet/utilities/constants.dart'; class RoundedContainer extends StatelessWidget { @@ -8,19 +7,27 @@ class RoundedContainer extends StatelessWidget { this.child, required this.color, this.padding = const EdgeInsets.all(12), + this.radiusMultiplier = 1.0, + this.width, + this.height, }) : super(key: key); final Widget? child; final Color color; final EdgeInsets padding; + final double radiusMultiplier; + final double? width; + final double? height; @override Widget build(BuildContext context) { return Container( + width: width, + height: height, decoration: BoxDecoration( color: color, borderRadius: BorderRadius.circular( - Constants.size.circularBorderRadius, + Constants.size.circularBorderRadius * radiusMultiplier, ), ), child: Padding( diff --git a/lib/widgets/rounded_white_container.dart b/lib/widgets/rounded_white_container.dart index 836789c4d..7525eafe5 100644 --- a/lib/widgets/rounded_white_container.dart +++ b/lib/widgets/rounded_white_container.dart @@ -1,5 +1,5 @@ -import 'package:flutter/cupertino.dart'; -import 'package:stackwallet/utilities/cfcolors.dart'; +import 'package:flutter/material.dart'; +import 'package:stackwallet/utilities/theme/stack_colors.dart'; import 'package:stackwallet/widgets/rounded_container.dart'; class RoundedWhiteContainer extends StatelessWidget { @@ -7,16 +7,25 @@ class RoundedWhiteContainer extends StatelessWidget { Key? key, this.child, this.padding = const EdgeInsets.all(12), + this.radiusMultiplier = 1.0, + this.width, + this.height, }) : super(key: key); final Widget? child; final EdgeInsets padding; + final double radiusMultiplier; + final double? width; + final double? height; @override Widget build(BuildContext context) { return RoundedContainer( - color: CFColors.white, + color: Theme.of(context).extension()!.popupBG, padding: padding, + radiusMultiplier: radiusMultiplier, + width: width, + height: height, child: child, ); } diff --git a/lib/widgets/stack_dialog.dart b/lib/widgets/stack_dialog.dart index 6bb96bbd1..be1d51596 100644 --- a/lib/widgets/stack_dialog.dart +++ b/lib/widgets/stack_dialog.dart @@ -1,6 +1,6 @@ import 'package:flutter/material.dart'; -import 'package:stackwallet/utilities/cfcolors.dart'; import 'package:stackwallet/utilities/text_styles.dart'; +import 'package:stackwallet/utilities/theme/stack_colors.dart'; class StackDialogBase extends StatelessWidget { const StackDialogBase({ @@ -25,7 +25,7 @@ class StackDialogBase extends StatelessWidget { ), child: Container( decoration: BoxDecoration( - color: CFColors.white, + color: Theme.of(context).extension()!.popupBG, borderRadius: BorderRadius.circular( 20, ), @@ -72,7 +72,7 @@ class StackDialog extends StatelessWidget { Flexible( child: Text( title, - style: STextStyles.pageTitleH2, + style: STextStyles.pageTitleH2(context), ), ), icon != null ? icon! : Container(), @@ -88,7 +88,7 @@ class StackDialog extends StatelessWidget { children: [ Text( message!, - style: STextStyles.smallMed14, + style: STextStyles.smallMed14(context), ), ], ), @@ -146,7 +146,7 @@ class StackOkDialog extends StatelessWidget { Flexible( child: Text( title, - style: STextStyles.pageTitleH2, + style: STextStyles.pageTitleH2(context), ), ), icon != null ? icon! : Container(), @@ -162,7 +162,7 @@ class StackOkDialog extends StatelessWidget { children: [ Text( message!, - style: STextStyles.smallMed14, + style: STextStyles.smallMed14(context), ), ], ), @@ -183,10 +183,12 @@ class StackOkDialog extends StatelessWidget { Navigator.of(context).pop(); onOkPressed?.call("OK"); }, + style: Theme.of(context) + .extension()! + .getPrimaryEnabledButtonColor(context), child: Text( "Ok", - style: STextStyles.button - .copyWith(color: CFColors.stackAccent), + style: STextStyles.button(context), ), ), ), diff --git a/lib/widgets/stack_text_field.dart b/lib/widgets/stack_text_field.dart index 140312999..9858c18db 100644 --- a/lib/widgets/stack_text_field.dart +++ b/lib/widgets/stack_text_field.dart @@ -1,16 +1,23 @@ import 'package:flutter/material.dart'; -import 'package:stackwallet/utilities/cfcolors.dart'; import 'package:stackwallet/utilities/text_styles.dart'; +import 'package:stackwallet/utilities/theme/stack_colors.dart'; +import 'package:stackwallet/utilities/util.dart'; InputDecoration standardInputDecoration( - String? labelText, FocusNode textFieldFocusNode) { + String? labelText, FocusNode textFieldFocusNode, BuildContext context) { + final isDesktop = Util.isDesktop; + return InputDecoration( labelText: labelText, fillColor: textFieldFocusNode.hasFocus - ? CFColors.textFieldActive - : CFColors.textFieldInactive, - labelStyle: STextStyles.fieldLabel, - hintStyle: STextStyles.fieldLabel, + ? Theme.of(context).extension()!.textFieldActiveBG + : Theme.of(context).extension()!.textFieldDefaultBG, + labelStyle: isDesktop + ? STextStyles.desktopTextFieldLabel(context) + : STextStyles.fieldLabel(context), + hintStyle: isDesktop + ? STextStyles.desktopTextFieldLabel(context) + : STextStyles.fieldLabel(context), enabledBorder: InputBorder.none, focusedBorder: InputBorder.none, errorBorder: InputBorder.none, diff --git a/lib/widgets/table_view/table_view.dart b/lib/widgets/table_view/table_view.dart new file mode 100644 index 000000000..74103fe04 --- /dev/null +++ b/lib/widgets/table_view/table_view.dart @@ -0,0 +1,36 @@ +import 'package:flutter/material.dart'; +import 'package:stackwallet/widgets/table_view/table_view_row.dart'; + +class TableView extends StatefulWidget { + const TableView({ + Key? key, + required this.rows, + this.rowSpacing = 10.0, + }) : super(key: key); + + final List rows; + final double rowSpacing; + + @override + State createState() => _TableViewState(); +} + +class _TableViewState extends State { + @override + Widget build(BuildContext context) { + return ListView( + children: [ + for (int i = 0; i < widget.rows.length; i++) + Column( + children: [ + if (i != 0) + SizedBox( + height: widget.rowSpacing, + ), + widget.rows[i], + ], + ) + ], + ); + } +} diff --git a/lib/widgets/table_view/table_view_cell.dart b/lib/widgets/table_view/table_view_cell.dart new file mode 100644 index 000000000..16a807d3c --- /dev/null +++ b/lib/widgets/table_view/table_view_cell.dart @@ -0,0 +1,17 @@ +import 'package:flutter/material.dart'; + +class TableViewCell extends StatelessWidget { + const TableViewCell({ + Key? key, + required this.flex, + required this.child, + }) : super(key: key); + + final int flex; + final Widget child; + + @override + Widget build(BuildContext context) { + return child; + } +} diff --git a/lib/widgets/table_view/table_view_row.dart b/lib/widgets/table_view/table_view_row.dart new file mode 100644 index 000000000..e20a23e94 --- /dev/null +++ b/lib/widgets/table_view/table_view_row.dart @@ -0,0 +1,70 @@ +import 'package:flutter/material.dart'; +import 'package:stackwallet/utilities/theme/stack_colors.dart'; +import 'package:stackwallet/widgets/expandable.dart'; +import 'package:stackwallet/widgets/table_view/table_view_cell.dart'; + +class TableViewRow extends StatelessWidget { + const TableViewRow({ + Key? key, + required this.cells, + required this.expandingChild, + this.decoration, + this.onExpandChanged, + this.padding = const EdgeInsets.all(0), + }) : super(key: key); + + final List cells; + final Widget? expandingChild; + final Decoration? decoration; + final void Function(ExpandableState)? onExpandChanged; + final EdgeInsetsGeometry padding; + + @override + Widget build(BuildContext context) { + return Container( + decoration: decoration, + child: expandingChild == null + ? Padding( + padding: padding, + child: Row( + children: [ + ...cells.map( + (e) => Expanded( + flex: e.flex, + child: e, + ), + ), + ], + ), + ) + : Expandable( + onExpandChanged: onExpandChanged, + header: Padding( + padding: padding, + child: Row( + children: [ + ...cells.map( + (e) => Expanded( + flex: e.flex, + child: e, + ), + ), + ], + ), + ), + body: Column( + children: [ + Container( + color: Theme.of(context) + .extension()! + .buttonBackSecondary, + width: double.infinity, + height: 1, + ), + expandingChild!, + ], + ), + ), + ); + } +} diff --git a/lib/widgets/trade_card.dart b/lib/widgets/trade_card.dart index 50756d881..ab58e2293 100644 --- a/lib/widgets/trade_card.dart +++ b/lib/widgets/trade_card.dart @@ -19,7 +19,7 @@ class TradeCard extends ConsumerWidget { final ExchangeTransaction trade; final VoidCallback onTap; - String _fetchIconAssetForStatus(String statusString) { + String _fetchIconAssetForStatus(String statusString, BuildContext context) { ChangeNowTransactionStatus? status; try { if (statusString.toLowerCase().startsWith("waiting")) { @@ -38,11 +38,11 @@ class TradeCard extends ConsumerWidget { case ChangeNowTransactionStatus.Sending: case ChangeNowTransactionStatus.Refunded: case ChangeNowTransactionStatus.Verifying: - return Assets.svg.txExchangePending; + return Assets.svg.txExchangePending(context); case ChangeNowTransactionStatus.Finished: - return Assets.svg.txExchange; + return Assets.svg.txExchange(context); case ChangeNowTransactionStatus.Failed: - return Assets.svg.txExchangeFailed; + return Assets.svg.txExchangeFailed(context); } } @@ -62,7 +62,9 @@ class TradeCard extends ConsumerWidget { child: Center( child: SvgPicture.asset( _fetchIconAssetForStatus( - trade.statusObject?.status.name ?? trade.statusString), + trade.statusObject?.status.name ?? trade.statusString, + context, + ), width: 32, height: 32, ), @@ -79,11 +81,11 @@ class TradeCard extends ConsumerWidget { children: [ Text( "${trade.fromCurrency.toUpperCase()} → ${trade.toCurrency.toUpperCase()}", - style: STextStyles.itemSubtitle12, + style: STextStyles.itemSubtitle12(context), ), Text( "${Decimal.tryParse(trade.statusObject?.amountSendDecimal ?? "") ?? "..."} ${trade.fromCurrency.toUpperCase()}", - style: STextStyles.itemSubtitle12, + style: STextStyles.itemSubtitle12(context), ), ], ), @@ -95,12 +97,12 @@ class TradeCard extends ConsumerWidget { children: [ Text( "ChangeNOW", - style: STextStyles.label, + style: STextStyles.label(context), ), Text( Format.extractDateFrom( trade.date.millisecondsSinceEpoch ~/ 1000), - style: STextStyles.label, + style: STextStyles.label(context), ), ], ), diff --git a/lib/widgets/transaction_card.dart b/lib/widgets/transaction_card.dart index 756e3d8f7..35331d398 100644 --- a/lib/widgets/transaction_card.dart +++ b/lib/widgets/transaction_card.dart @@ -7,12 +7,12 @@ import 'package:stackwallet/notifications/show_flush_bar.dart'; import 'package:stackwallet/pages/wallet_view/sub_widgets/tx_icon.dart'; import 'package:stackwallet/pages/wallet_view/transaction_views/transaction_details_view.dart'; import 'package:stackwallet/providers/providers.dart'; -import 'package:stackwallet/utilities/cfcolors.dart'; import 'package:stackwallet/utilities/constants.dart'; import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/enums/flush_bar_type.dart'; import 'package:stackwallet/utilities/format.dart'; import 'package:stackwallet/utilities/text_styles.dart'; +import 'package:stackwallet/utilities/theme/stack_colors.dart'; import 'package:tuple/tuple.dart'; class TransactionCard extends ConsumerStatefulWidget { @@ -101,7 +101,7 @@ class _TransactionCardState extends ConsumerState { .item1; return Material( - color: CFColors.white, + color: Theme.of(context).extension()!.popupBG, elevation: 0, shape: RoundedRectangleBorder( borderRadius: @@ -158,7 +158,7 @@ class _TransactionCardState extends ConsumerState { _transaction.isCancelled ? "Cancelled" : whatIsIt(_transaction.txType, coin), - style: STextStyles.itemSubtitle12, + style: STextStyles.itemSubtitle12(context), ), ), ), @@ -175,7 +175,8 @@ class _TransactionCardState extends ConsumerState { : _transaction.amount; return Text( "${Format.satoshiAmountToPrettyString(amount, locale)} ${coin.ticker}", - style: STextStyles.itemSubtitle12.copyWith( + style: STextStyles.itemSubtitle12(context) + .copyWith( fontWeight: FontWeight.w600, ), ); @@ -197,7 +198,7 @@ class _TransactionCardState extends ConsumerState { fit: BoxFit.scaleDown, child: Text( Format.extractDateFrom(_transaction.timestamp), - style: STextStyles.label, + style: STextStyles.label(context), ), ), ), @@ -222,7 +223,7 @@ class _TransactionCardState extends ConsumerState { locale: locale, decimalPlaces: 2, )} $baseCurrency", - style: STextStyles.label, + style: STextStyles.label(context), ); }, ), diff --git a/lib/widgets/wallet_card.dart b/lib/widgets/wallet_card.dart index 6601774ce..0e8a515bd 100644 --- a/lib/widgets/wallet_card.dart +++ b/lib/widgets/wallet_card.dart @@ -1,17 +1,10 @@ -import 'package:decimal/decimal.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:flutter_svg/flutter_svg.dart'; import 'package:stackwallet/pages/wallet_view/wallet_view.dart'; import 'package:stackwallet/providers/providers.dart'; -import 'package:stackwallet/utilities/assets.dart'; -import 'package:stackwallet/utilities/cfcolors.dart'; import 'package:stackwallet/utilities/constants.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; -import 'package:stackwallet/utilities/format.dart'; -import 'package:stackwallet/utilities/text_styles.dart'; -import 'package:stackwallet/widgets/animated_text.dart'; import 'package:stackwallet/widgets/rounded_white_container.dart'; +import 'package:stackwallet/widgets/wallet_info_row/wallet_info_row.dart'; import 'package:tuple/tuple.dart'; class WalletSheetCard extends ConsumerWidget { @@ -26,19 +19,10 @@ class WalletSheetCard extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { - final manager = ref.watch(ref - .watch(walletsChangeNotifierProvider.notifier) - .getManagerProvider(walletId)); - - final locale = ref.watch( - localeServiceChangeNotifierProvider.select((value) => value.locale)); - - final coin = manager.coin; - return RoundedWhiteContainer( padding: const EdgeInsets.all(0), child: MaterialButton( - // splashColor: CFColors.splashLight, + // splashColor: Theme.of(context).extension()!.highlight, key: Key("walletsSheetItemButtonKey_$walletId"), padding: const EdgeInsets.all(5), materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, @@ -58,69 +42,8 @@ class WalletSheetCard extends ConsumerWidget { .getManagerProvider(walletId)), ); }, - child: Row( - children: [ - Container( - decoration: BoxDecoration( - color: CFColors.coin.forCoin(manager.coin).withOpacity(0.5), - borderRadius: BorderRadius.circular( - Constants.size.circularBorderRadius, - ), - ), - child: Padding( - padding: const EdgeInsets.all(4), - child: SvgPicture.asset( - Assets.svg.iconFor(coin: coin), - width: 20, - height: 20, - ), - ), - ), - const SizedBox( - width: 12, - ), - Expanded( - child: Column( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - manager.walletName, - style: STextStyles.titleBold12, - ), - const SizedBox( - height: 2, - ), - FutureBuilder( - future: manager.totalBalance, - builder: (builderContext, AsyncSnapshot snapshot) { - if (snapshot.connectionState == ConnectionState.done && - snapshot.hasData) { - return Text( - "${Format.localizedStringAsFixed( - value: snapshot.data!, - locale: locale, - decimalPlaces: 8, - )} ${coin.ticker}", - style: STextStyles.itemSubtitle, - ); - } else { - return AnimatedText( - stringsToLoopThrough: const [ - "Loading balance", - "Loading balance.", - "Loading balance..", - "Loading balance..." - ], - style: STextStyles.itemSubtitle, - ); - } - }, - ), - ], - ), - ), - ], + child: WalletInfoRow( + walletId: walletId, ), ), ); diff --git a/lib/widgets/wallet_info_row/sub_widgets/wallet_info_row_balance_future.dart b/lib/widgets/wallet_info_row/sub_widgets/wallet_info_row_balance_future.dart new file mode 100644 index 000000000..a59c157ec --- /dev/null +++ b/lib/widgets/wallet_info_row/sub_widgets/wallet_info_row_balance_future.dart @@ -0,0 +1,69 @@ +import 'package:decimal/decimal.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:stackwallet/providers/providers.dart'; +import 'package:stackwallet/utilities/enums/coin_enum.dart'; +import 'package:stackwallet/utilities/format.dart'; +import 'package:stackwallet/utilities/text_styles.dart'; +import 'package:stackwallet/utilities/theme/stack_colors.dart'; +import 'package:stackwallet/utilities/util.dart'; +import 'package:stackwallet/widgets/animated_text.dart'; + +class WalletInfoRowBalanceFuture extends ConsumerWidget { + const WalletInfoRowBalanceFuture({Key? key, required this.walletId}) + : super(key: key); + + final String walletId; + + @override + Widget build(BuildContext context, WidgetRef ref) { + final manager = ref.watch(ref + .watch(walletsChangeNotifierProvider.notifier) + .getManagerProvider(walletId)); + + final locale = ref.watch( + localeServiceChangeNotifierProvider.select( + (value) => value.locale, + ), + ); + + return FutureBuilder( + future: manager.totalBalance, + builder: (builderContext, AsyncSnapshot snapshot) { + if (snapshot.connectionState == ConnectionState.done && + snapshot.hasData) { + return Text( + "${Format.localizedStringAsFixed( + value: snapshot.data!, + locale: locale, + decimalPlaces: 8, + )} ${manager.coin.ticker}", + style: Util.isDesktop + ? STextStyles.desktopTextExtraSmall(context).copyWith( + color: Theme.of(context) + .extension()! + .textSubtitle1, + ) + : STextStyles.itemSubtitle(context), + ); + } else { + return AnimatedText( + stringsToLoopThrough: const [ + "Loading balance", + "Loading balance.", + "Loading balance..", + "Loading balance..." + ], + style: Util.isDesktop + ? STextStyles.desktopTextExtraSmall(context).copyWith( + color: Theme.of(context) + .extension()! + .textSubtitle1, + ) + : STextStyles.itemSubtitle(context), + ); + } + }, + ); + } +} diff --git a/lib/widgets/wallet_info_row/sub_widgets/wallet_info_row_coin_icon.dart b/lib/widgets/wallet_info_row/sub_widgets/wallet_info_row_coin_icon.dart new file mode 100644 index 000000000..ec5924de6 --- /dev/null +++ b/lib/widgets/wallet_info_row/sub_widgets/wallet_info_row_coin_icon.dart @@ -0,0 +1,35 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_svg/svg.dart'; +import 'package:stackwallet/utilities/assets.dart'; +import 'package:stackwallet/utilities/constants.dart'; +import 'package:stackwallet/utilities/enums/coin_enum.dart'; +import 'package:stackwallet/utilities/theme/stack_colors.dart'; + +class WalletInfoCoinIcon extends StatelessWidget { + const WalletInfoCoinIcon({Key? key, required this.coin}) : super(key: key); + + final Coin coin; + + @override + Widget build(BuildContext context) { + return Container( + decoration: BoxDecoration( + color: Theme.of(context) + .extension()! + .colorForCoin(coin) + .withOpacity(0.5), + borderRadius: BorderRadius.circular( + Constants.size.circularBorderRadius, + ), + ), + child: Padding( + padding: const EdgeInsets.all(4), + child: SvgPicture.asset( + Assets.svg.iconFor(coin: coin), + width: 20, + height: 20, + ), + ), + ); + } +} diff --git a/lib/widgets/wallet_info_row/wallet_info_row.dart b/lib/widgets/wallet_info_row/wallet_info_row.dart new file mode 100644 index 000000000..4840e9b01 --- /dev/null +++ b/lib/widgets/wallet_info_row/wallet_info_row.dart @@ -0,0 +1,98 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:flutter_svg/svg.dart'; +import 'package:stackwallet/providers/providers.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/utilities/util.dart'; +import 'package:stackwallet/widgets/wallet_info_row/sub_widgets/wallet_info_row_balance_future.dart'; +import 'package:stackwallet/widgets/wallet_info_row/sub_widgets/wallet_info_row_coin_icon.dart'; + +class WalletInfoRow extends ConsumerWidget { + const WalletInfoRow({ + Key? key, + required this.walletId, + this.onPressed, + }) : super(key: key); + + final String walletId; + final VoidCallback? onPressed; + + @override + Widget build(BuildContext context, WidgetRef ref) { + final manager = ref.watch(ref + .watch(walletsChangeNotifierProvider.notifier) + .getManagerProvider(walletId)); + + return Row( + children: Util.isDesktop + ? [ + Expanded( + flex: 4, + child: Row( + children: [ + WalletInfoCoinIcon(coin: manager.coin), + const SizedBox( + width: 12, + ), + Text( + manager.walletName, + style: + STextStyles.desktopTextExtraSmall(context).copyWith( + color: Theme.of(context) + .extension()! + .textDark, + ), + ), + ], + ), + ), + Expanded( + flex: 4, + child: WalletInfoRowBalanceFuture( + walletId: walletId, + ), + ), + Expanded( + flex: 6, + child: Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + SvgPicture.asset( + Assets.svg.chevronRight, + width: 20, + height: 20, + color: Theme.of(context) + .extension()! + .textSubtitle1, + ) + ], + ), + ) + ] + : [ + WalletInfoCoinIcon(coin: manager.coin), + const SizedBox( + width: 12, + ), + Expanded( + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + manager.walletName, + style: STextStyles.titleBold12(context), + ), + const SizedBox( + height: 2, + ), + WalletInfoRowBalanceFuture(walletId: walletId), + ], + ), + ), + ], + ); + } +} diff --git a/linux/flutter/generated_plugin_registrant.cc b/linux/flutter/generated_plugin_registrant.cc index 0723b0586..fe1e41d19 100644 --- a/linux/flutter/generated_plugin_registrant.cc +++ b/linux/flutter/generated_plugin_registrant.cc @@ -13,6 +13,7 @@ #include #include #include +#include void fl_register_plugins(FlPluginRegistry* registry) { g_autoptr(FlPluginRegistrar) devicelocale_registrar = @@ -36,4 +37,7 @@ void fl_register_plugins(FlPluginRegistry* registry) { g_autoptr(FlPluginRegistrar) url_launcher_linux_registrar = fl_plugin_registry_get_registrar_for_plugin(registry, "UrlLauncherPlugin"); url_launcher_plugin_register_with_registrar(url_launcher_linux_registrar); + g_autoptr(FlPluginRegistrar) window_size_registrar = + fl_plugin_registry_get_registrar_for_plugin(registry, "WindowSizePlugin"); + window_size_plugin_register_with_registrar(window_size_registrar); } diff --git a/linux/flutter/generated_plugins.cmake b/linux/flutter/generated_plugins.cmake index 4b220680e..ba2cb50f2 100644 --- a/linux/flutter/generated_plugins.cmake +++ b/linux/flutter/generated_plugins.cmake @@ -10,6 +10,7 @@ list(APPEND FLUTTER_PLUGIN_LIST isar_flutter_libs stack_wallet_backup url_launcher_linux + window_size ) list(APPEND FLUTTER_FFI_PLUGIN_LIST diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift index e4a20406c..a4f194b8d 100644 --- a/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -17,6 +17,7 @@ import shared_preferences_macos import stack_wallet_backup import url_launcher_macos import wakelock_macos +import window_size func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { ConnectivityPlugin.register(with: registry.registrar(forPlugin: "ConnectivityPlugin")) @@ -31,4 +32,5 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { StackWalletBackupPlugin.register(with: registry.registrar(forPlugin: "StackWalletBackupPlugin")) UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin")) WakelockMacosPlugin.register(with: registry.registrar(forPlugin: "WakelockMacosPlugin")) + WindowSizePlugin.register(with: registry.registrar(forPlugin: "WindowSizePlugin")) } diff --git a/pubspec.lock b/pubspec.lock index 836298786..71145aef4 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -74,9 +74,11 @@ packages: bech32: dependency: "direct main" description: - name: bech32 - url: "https://pub.dartlang.org" - source: hosted + path: "." + ref: "22279d4bb24ed541b431acd269a1bc50af0f36a0" + resolved-ref: "22279d4bb24ed541b431acd269a1bc50af0f36a0" + url: "https://github.com/cypherstack/bech32.git" + source: git version: "0.2.1" bip32: dependency: "direct main" @@ -94,12 +96,21 @@ packages: url: "https://github.com/cypherstack/stack-bip39.git" source: git version: "1.0.6" + bitbox: + dependency: "direct main" + description: + path: "." + ref: ea65073efbaf395a5557e8cd7bd72f195cd7eb11 + resolved-ref: ea65073efbaf395a5557e8cd7bd72f195cd7eb11 + url: "https://github.com/Quppy/bitbox-flutter.git" + source: git + version: "1.0.1" bitcoindart: dependency: "direct main" description: path: "." - ref: a35968c2d2d900e77baa9f8b28c89b722c074039 - resolved-ref: a35968c2d2d900e77baa9f8b28c89b722c074039 + ref: "65eb920719c8f7895c5402a07497647e7fc4b346" + resolved-ref: "65eb920719c8f7895c5402a07497647e7fc4b346" url: "https://github.com/cypherstack/bitcoindart.git" source: git version: "3.0.1" @@ -355,6 +366,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "0.5.2" + dropdown_button2: + dependency: "direct main" + description: + name: dropdown_button2 + url: "https://pub.dartlang.org" + source: hosted + version: "1.7.2" emojis: dependency: "direct main" description: @@ -1596,6 +1614,15 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.7.0" + window_size: + dependency: "direct main" + description: + path: "plugins/window_size" + ref: HEAD + resolved-ref: "17d4710c17f4913137e7ec931f6e71eaef443363" + url: "https://github.com/google/flutter-desktop-embedding.git" + source: git + version: "0.1.0" xdg_directories: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index bd36d781f..e7d138729 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -11,7 +11,7 @@ description: Stack Wallet # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. # Read more about iOS versioning at # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html -version: 1.4.45+60 +version: 1.4.48+63 environment: sdk: ">=2.17.0 <3.0.0" @@ -46,7 +46,7 @@ dependencies: bitcoindart: git: url: https://github.com/cypherstack/bitcoindart.git - ref: a35968c2d2d900e77baa9f8b28c89b722c074039 + ref: 65eb920719c8f7895c5402a07497647e7fc4b346 stack_wallet_backup: git: @@ -64,13 +64,25 @@ dependencies: zxcvbn: ^1.0.0 dart_numerics: ^0.0.6 + window_size: + git: + url: https://github.com/google/flutter-desktop-embedding.git + path: plugins/window_size + # Bitcoin plugins bip39: git: url: https://github.com/cypherstack/stack-bip39.git ref: 3bef5acc21340f3cc78df0ad1dce5868a3ed68a5 + bitbox: + git: + url: https://github.com/Quppy/bitbox-flutter.git + ref: ea65073efbaf395a5557e8cd7bd72f195cd7eb11 bip32: ^2.0.0 - bech32: ^0.2.1 + bech32: + git: + url: https://github.com/cypherstack/bech32.git + ref: 22279d4bb24ed541b431acd269a1bc50af0f36a0 bs58check: ^1.0.2 # Storage plugins @@ -116,6 +128,7 @@ dependencies: # document_file_save_plus: ^1.0.5 isar: 3.0.0-dev.10 isar_flutter_libs: 3.0.0-dev.10 # contains the binaries + dropdown_button2: 1.7.2 dev_dependencies: flutter_test: @@ -181,10 +194,13 @@ flutter: - assets/images/doge.png - assets/images/bitcoin.png - assets/images/epic-cash.png + - assets/images/bitcoincash.png + - assets/images/namecoin.png - assets/svg/plus.svg - assets/svg/gear.svg - assets/svg/bell.svg - - assets/svg/bell-new.svg + - assets/svg/light/bell-new.svg + - assets/svg/dark/bell-new.svg - assets/svg/stack-icon1.svg - assets/svg/arrow-left-fa.svg - assets/svg/copy-fa.svg @@ -198,7 +214,8 @@ flutter: - assets/svg/bars.svg - assets/svg/filter.svg - assets/svg/pending.svg - - assets/svg/exchange-2.svg + - assets/svg/dark/exchange-2.svg + - assets/svg/light/exchange-2.svg - assets/svg/signal-stream.svg - assets/svg/buy-coins-icon.svg - assets/svg/Ellipse-43.svg @@ -214,6 +231,7 @@ flutter: - assets/svg/folder-down.svg - assets/svg/network-wired.svg - assets/svg/address-book.svg + - assets/svg/address-book2.svg - assets/svg/arrow-right.svg - assets/svg/delete.svg - assets/svg/dollar-sign.svg @@ -239,16 +257,25 @@ flutter: - assets/svg/ellipsis-vertical1.svg - assets/svg/dice-alt.svg - assets/svg/circle-arrow-up-right2.svg - - assets/svg/tx-exchange-icon.svg - - assets/svg/tx-exchange-icon-pending.svg - - assets/svg/tx-exchange-icon-failed.svg + - assets/svg/dark/tx-exchange-icon.svg + - assets/svg/light/tx-exchange-icon.svg + - assets/svg/dark/tx-exchange-icon-pending.svg + - assets/svg/light/tx-exchange-icon-pending.svg + - assets/svg/dark/tx-exchange-icon-failed.svg + - assets/svg/light/tx-exchange-icon-failed.svg - assets/svg/loader.svg - - assets/svg/tx-icon-send.svg - - assets/svg/tx-icon-send-pending.svg - - assets/svg/tx-icon-send-failed.svg - - assets/svg/tx-icon-receive.svg - - assets/svg/tx-icon-receive-pending.svg - - assets/svg/tx-icon-receive-failed.svg + - assets/svg/dark/tx-icon-send.svg + - assets/svg/light/tx-icon-send.svg + - assets/svg/dark/tx-icon-send-pending.svg + - assets/svg/light/tx-icon-send-pending.svg + - assets/svg/dark/tx-icon-send-failed.svg + - assets/svg/light/tx-icon-send-failed.svg + - assets/svg/dark/tx-icon-receive.svg + - assets/svg/light/tx-icon-receive.svg + - assets/svg/dark/tx-icon-receive-pending.svg + - assets/svg/light/tx-icon-receive-pending.svg + - assets/svg/dark/tx-icon-receive-failed.svg + - assets/svg/light/tx-icon-receive-failed.svg - assets/svg/add-backup.svg - assets/svg/auto-backup.svg - assets/svg/restore-backup.svg @@ -261,10 +288,12 @@ flutter: - assets/svg/tx-icon-anonymize-failed.svg # coin icons - assets/svg/coin_icons/Bitcoin.svg + - assets/svg/coin_icons/Bitcoincash.svg - assets/svg/coin_icons/Dogecoin.svg - assets/svg/coin_icons/EpicCash.svg - assets/svg/coin_icons/Firo.svg - assets/svg/coin_icons/Monero.svg + - assets/svg/coin_icons/Namecoin.svg # lottie animations - assets/lottie/test.json - assets/lottie/test2.json @@ -273,6 +302,11 @@ flutter: - assets/svg/socials/reddit-alien-brands.svg - assets/svg/socials/twitter-brands.svg - assets/svg/socials/telegram-brands.svg + - assets/svg/chevron-right.svg + - assets/svg/minimize.svg + - assets/svg/wallet-fa.svg + - assets/svg/exchange-3.svg + - assets/svg/message-question-1.svg # An image asset can refer to one or more resolution-specific "variants", see # https://flutter.dev/assets-and-images/#resolution-aware. diff --git a/scripts/ios/build_all.sh b/scripts/ios/build_all.sh old mode 100644 new mode 100755 diff --git a/test/price_test.dart b/test/price_test.dart index 7c22cd6fe..b700d36be 100644 --- a/test/price_test.dart +++ b/test/price_test.dart @@ -23,7 +23,8 @@ void main() { when(client.get( Uri.parse( - "https://api.coingecko.com/api/v3/coins/markets?vs_currency=btc&ids=monero,bitcoin,epic-cash,zcoin,dogecoin&order=market_cap_desc&per_page=10&page=1&sparkline=false"), + "https://api.coingecko.com/api/v3/coins/markets?vs_currency=btc&ids=monero,bitcoin,epic-cash,zcoin,dogecoin,namecoin&order=market_cap_desc&per_page=10&page=1&sparkline=false"), + // "https://api.coingecko.com/api/v3/coins/markets?vs_currency=btc&ids=monero,bitcoin,epic-cash,zcoin,dogecoin,bitcoin-cash,namecoin&order=market_cap_desc&per_page=10&page=1&sparkline=false"), headers: { 'Content-Type': 'application/json' })).thenAnswer((_) async => Response( @@ -36,10 +37,12 @@ void main() { final price = await priceAPI.getPricesAnd24hChange(baseCurrency: "btc"); expect(price.toString(), - '{Coin.bitcoin: [1, 0.0], Coin.dogecoin: [0.00000315, -2.68533], Coin.epicCash: [0.00002803, 7.27524], Coin.firo: [0.0001096, -0.89304], Coin.monero: [0.00717236, -0.77656], Coin.bitcoinTestNet: [0, 0.0], Coin.dogecoinTestNet: [0, 0.0], Coin.firoTestNet: [0, 0.0]}'); + '{Coin.bitcoin: [1, 0.0], Coin.dogecoin: [0.00000315, -2.68533], Coin.epicCash: [0.00002803, 7.27524], Coin.firo: [0.0001096, -0.89304], Coin.monero: [0.00717236, -0.77656], Coin.namecoin: [0, 0.0], Coin.bitcoinTestNet: [0, 0.0], Coin.dogecoinTestNet: [0, 0.0], Coin.firoTestNet: [0, 0.0]}'); + // '{Coin.bitcoin: [1, 0.0], Coin.bitcoincash: [0, 0.0], Coin.dogecoin: [0.00000315, -2.68533], Coin.epicCash: [0.00002803, 7.27524], Coin.firo: [0.0001096, -0.89304], Coin.monero: [0.00717236, -0.77656], Coin.namecoin: [0, 0.0], Coin.bitcoinTestNet: [0, 0.0], Coin.bitcoincashTestnet: [0, 0.0], Coin.dogecoinTestNet: [0, 0.0], Coin.firoTestNet: [0, 0.0]}'); verify(client.get( Uri.parse( - "https://api.coingecko.com/api/v3/coins/markets?vs_currency=btc&ids=monero,bitcoin,epic-cash,zcoin,dogecoin&order=market_cap_desc&per_page=10&page=1&sparkline=false"), + "https://api.coingecko.com/api/v3/coins/markets?vs_currency=btc&ids=monero,bitcoin,epic-cash,zcoin,dogecoin,namecoin&order=market_cap_desc&per_page=10&page=1&sparkline=false"), + // "https://api.coingecko.com/api/v3/coins/markets?vs_currency=btc&ids=monero,bitcoin,epic-cash,zcoin,dogecoin,bitcoin-cash,namecoin&order=market_cap_desc&per_page=10&page=1&sparkline=false"), headers: {'Content-Type': 'application/json'})).called(1); verifyNoMoreInteractions(client); @@ -50,7 +53,8 @@ void main() { when(client.get( Uri.parse( - "https://api.coingecko.com/api/v3/coins/markets?vs_currency=btc&ids=monero,bitcoin,epic-cash,zcoin,dogecoin&order=market_cap_desc&per_page=10&page=1&sparkline=false"), + "https://api.coingecko.com/api/v3/coins/markets?vs_currency=btc&ids=monero,bitcoin,epic-cash,zcoin,dogecoin,namecoin&order=market_cap_desc&per_page=10&page=1&sparkline=false"), + // "https://api.coingecko.com/api/v3/coins/markets?vs_currency=btc&ids=monero,bitcoin,epic-cash,zcoin,dogecoin,bitcoin-cash,namecoin&order=market_cap_desc&per_page=10&page=1&sparkline=false"), headers: { 'Content-Type': 'application/json' })).thenAnswer((_) async => Response( @@ -68,12 +72,14 @@ void main() { await priceAPI.getPricesAnd24hChange(baseCurrency: "btc"); expect(cachedPrice.toString(), - '{Coin.bitcoin: [1, 0.0], Coin.dogecoin: [0.00000315, -2.68533], Coin.epicCash: [0.00002803, 7.27524], Coin.firo: [0.0001096, -0.89304], Coin.monero: [0.00717236, -0.77656], Coin.bitcoinTestNet: [0, 0.0], Coin.dogecoinTestNet: [0, 0.0], Coin.firoTestNet: [0, 0.0]}'); + '{Coin.bitcoin: [1, 0.0], Coin.dogecoin: [0.00000315, -2.68533], Coin.epicCash: [0.00002803, 7.27524], Coin.firo: [0.0001096, -0.89304], Coin.monero: [0.00717236, -0.77656], Coin.namecoin: [0, 0.0], Coin.bitcoinTestNet: [0, 0.0], Coin.dogecoinTestNet: [0, 0.0], Coin.firoTestNet: [0, 0.0]}'); + // '{Coin.bitcoin: [1, 0.0], Coin.bitcoincash: [0, 0.0], Coin.dogecoin: [0.00000315, -2.68533], Coin.epicCash: [0.00002803, 7.27524], Coin.firo: [0.0001096, -0.89304], Coin.monero: [0.00717236, -0.77656], Coin.namecoin: [0, 0.0], Coin.bitcoinTestNet: [0, 0.0], Coin.bitcoincashTestnet: [0, 0.0], Coin.dogecoinTestNet: [0, 0.0], Coin.firoTestNet: [0, 0.0]}'); // verify only called once during filling of cache verify(client.get( Uri.parse( - "https://api.coingecko.com/api/v3/coins/markets?vs_currency=btc&ids=monero,bitcoin,epic-cash,zcoin,dogecoin&order=market_cap_desc&per_page=10&page=1&sparkline=false"), + "https://api.coingecko.com/api/v3/coins/markets?vs_currency=btc&ids=monero,bitcoin,epic-cash,zcoin,dogecoin,namecoin&order=market_cap_desc&per_page=10&page=1&sparkline=false"), + // "https://api.coingecko.com/api/v3/coins/markets?vs_currency=btc&ids=monero,bitcoin,epic-cash,zcoin,dogecoin,bitcoin-cash,namecoin&order=market_cap_desc&per_page=10&page=1&sparkline=false"), headers: {'Content-Type': 'application/json'})).called(1); verifyNoMoreInteractions(client); @@ -84,7 +90,7 @@ void main() { when(client.get( Uri.parse( - "https://api.coingecko.com/api/v3/coins/markets?vs_currency=btc&ids=monero,bitcoin,epic-cash,zcoin,dogecoin&order=market_cap_desc&per_page=10&page=1&sparkline=false"), + "https://api.coingecko.com/api/v3/coins/markets?vs_currency=btc&ids=monero,bitcoin,epic-cash,zcoin,dogecoin,bitcoin-cash,namecoin&order=market_cap_desc&per_page=10&page=1&sparkline=false"), headers: { 'Content-Type': 'application/json' })).thenAnswer((_) async => Response( @@ -97,7 +103,8 @@ void main() { final price = await priceAPI.getPricesAnd24hChange(baseCurrency: "btc"); expect(price.toString(), - '{Coin.bitcoin: [0, 0.0], Coin.dogecoin: [0, 0.0], Coin.epicCash: [0, 0.0], Coin.firo: [0, 0.0], Coin.monero: [0, 0.0], Coin.bitcoinTestNet: [0, 0.0], Coin.dogecoinTestNet: [0, 0.0], Coin.firoTestNet: [0, 0.0]}'); + '{Coin.bitcoin: [0, 0.0], Coin.dogecoin: [0, 0.0], Coin.epicCash: [0, 0.0], Coin.firo: [0, 0.0], Coin.monero: [0, 0.0], Coin.namecoin: [0, 0.0], Coin.bitcoinTestNet: [0, 0.0], Coin.dogecoinTestNet: [0, 0.0], Coin.firoTestNet: [0, 0.0]}'); + // '{Coin.bitcoin: [0, 0.0], Coin.bitcoincash: [0, 0.0], Coin.dogecoin: [0, 0.0], Coin.epicCash: [0, 0.0], Coin.firo: [0, 0.0], Coin.monero: [0, 0.0], Coin.namecoin: [0, 0.0], Coin.bitcoinTestNet: [0, 0.0], Coin.bitcoincashTestnet: [0, 0.0], Coin.dogecoinTestNet: [0, 0.0], Coin.firoTestNet: [0, 0.0]}'); }); test("no internet available", () async { @@ -105,7 +112,8 @@ void main() { when(client.get( Uri.parse( - "https://api.coingecko.com/api/v3/coins/markets?vs_currency=btc&ids=monero,bitcoin,epic-cash,zcoin,dogecoin&order=market_cap_desc&per_page=10&page=1&sparkline=false"), + "https://api.coingecko.com/api/v3/coins/markets?vs_currency=btc&ids=monero,bitcoin,epic-cash,zcoin,dogecoin,namecoin&order=market_cap_desc&per_page=10&page=1&sparkline=false"), + // "https://api.coingecko.com/api/v3/coins/markets?vs_currency=btc&ids=monero,bitcoin,epic-cash,zcoin,dogecoin,bitcoin-cash,namecoin&order=market_cap_desc&per_page=10&page=1&sparkline=false"), headers: { 'Content-Type': 'application/json' })).thenThrow(const SocketException( @@ -116,8 +124,10 @@ void main() { final price = await priceAPI.getPricesAnd24hChange(baseCurrency: "btc"); - expect(price.toString(), - '{Coin.bitcoin: [0, 0.0], Coin.dogecoin: [0, 0.0], Coin.epicCash: [0, 0.0], Coin.firo: [0, 0.0], Coin.monero: [0, 0.0], Coin.bitcoinTestNet: [0, 0.0], Coin.dogecoinTestNet: [0, 0.0], Coin.firoTestNet: [0, 0.0]}'); + expect( + price.toString(), + // '{Coin.bitcoin: [0, 0.0], Coin.bitcoincash: [0, 0.0], Coin.dogecoin: [0, 0.0], Coin.epicCash: [0, 0.0], Coin.firo: [0, 0.0], Coin.monero: [0, 0.0], Coin.namecoin: [0, 0.0], Coin.bitcoinTestNet: [0, 0.0], Coin.bitcoincashTestnet: [0, 0.0], Coin.dogecoinTestNet: [0, 0.0], Coin.firoTestNet: [0, 0.0]}'); + '{Coin.bitcoin: [0, 0.0], Coin.dogecoin: [0, 0.0], Coin.epicCash: [0, 0.0], Coin.firo: [0, 0.0], Coin.monero: [0, 0.0], Coin.namecoin: [0, 0.0], Coin.bitcoinTestNet: [0, 0.0], Coin.dogecoinTestNet: [0, 0.0], Coin.firoTestNet: [0, 0.0]}'); }); tearDown(() async { diff --git a/test/services/coins/bitcoin/bitcoin_wallet_test.dart b/test/services/coins/bitcoin/bitcoin_wallet_test.dart index c2fb76582..8a240a3dd 100644 --- a/test/services/coins/bitcoin/bitcoin_wallet_test.dart +++ b/test/services/coins/bitcoin/bitcoin_wallet_test.dart @@ -2423,16 +2423,36 @@ void main() { when(cachedClient?.clearSharedTransactionCache(coin: Coin.bitcoin)) .thenAnswer((realInvocation) async {}); - List dynamicArgValues = []; - - when(client?.getBatchHistory(args: anyNamed("args"))) - .thenAnswer((realInvocation) async { - if (realInvocation.namedArguments.values.first.length == 1) { - dynamicArgValues.add(realInvocation.namedArguments.values.first); - } - - return historyBatchResponse; - }); + when(client?.getBatchHistory(args: { + "0": [ + "bf5a6c56814e80eed11e1e459801515f8c2b83da812568aa9dc26e6356f6965b" + ] + })).thenAnswer((_) async => {"0": []}); + when(client?.getBatchHistory(args: { + "0": [ + "26f92666caebb9a17b14f5b573b385348cdc80065472b8961091f3226d2f650f" + ] + })).thenAnswer((_) async => {"0": []}); + when(client?.getBatchHistory(args: { + "0": [ + "06593b2d896751e8dda288bb6587b6bb6a1dee71d82a85457f5654f781e37b12" + ] + })).thenAnswer((_) async => {"0": []}); + when(client?.getBatchHistory(args: { + "0": [ + "11663d093cb17dfbed4a96d148b22d3e094b31d23c639c2814beb79f2ab0ca75" + ] + })).thenAnswer((_) async => {"0": []}); + when(client?.getBatchHistory(args: { + "0": [ + "2f18558e5d3015cb6578aee1c3e4b645725fa4e1d26ce22cb31c9949f3b4957c" + ] + })).thenAnswer((_) async => {"0": []}); + when(client?.getBatchHistory(args: { + "0": [ + "a328ae88ebce63c0010709ae900c199df2b585cdebce53a6291886dfdcc28c63" + ] + })).thenAnswer((_) async => {"0": []}); final wallet = await Hive.openBox(testWalletId); @@ -2573,13 +2593,36 @@ void main() { verify(cachedClient?.clearSharedTransactionCache(coin: Coin.bitcoin)) .called(1); - for (final arg in dynamicArgValues) { - final map = Map>.from(arg as Map); - - verify(client?.getBatchHistory(args: map)).called(1); - expect(activeScriptHashes.contains(map.values.first.first as String), - true); - } + verify(client?.getBatchHistory(args: { + "0": [ + "bf5a6c56814e80eed11e1e459801515f8c2b83da812568aa9dc26e6356f6965b" + ] + })).called(2); + verify(client?.getBatchHistory(args: { + "0": [ + "26f92666caebb9a17b14f5b573b385348cdc80065472b8961091f3226d2f650f" + ] + })).called(2); + verify(client?.getBatchHistory(args: { + "0": [ + "06593b2d896751e8dda288bb6587b6bb6a1dee71d82a85457f5654f781e37b12" + ] + })).called(2); + verify(client?.getBatchHistory(args: { + "0": [ + "11663d093cb17dfbed4a96d148b22d3e094b31d23c639c2814beb79f2ab0ca75" + ] + })).called(2); + verify(client?.getBatchHistory(args: { + "0": [ + "2f18558e5d3015cb6578aee1c3e4b645725fa4e1d26ce22cb31c9949f3b4957c" + ] + })).called(2); + verify(client?.getBatchHistory(args: { + "0": [ + "a328ae88ebce63c0010709ae900c199df2b585cdebce53a6291886dfdcc28c63" + ] + })).called(2); expect(secureStore?.writes, 25); expect(secureStore?.reads, 32); @@ -2617,16 +2660,36 @@ void main() { when(cachedClient?.clearSharedTransactionCache(coin: Coin.bitcoin)) .thenAnswer((realInvocation) async {}); - List dynamicArgValues = []; - - when(client?.getBatchHistory(args: anyNamed("args"))) - .thenAnswer((realInvocation) async { - if (realInvocation.namedArguments.values.first.length == 1) { - dynamicArgValues.add(realInvocation.namedArguments.values.first); - } - - return historyBatchResponse; - }); + when(client?.getBatchHistory(args: { + "0": [ + "bf5a6c56814e80eed11e1e459801515f8c2b83da812568aa9dc26e6356f6965b" + ] + })).thenAnswer((_) async => {"0": []}); + when(client?.getBatchHistory(args: { + "0": [ + "26f92666caebb9a17b14f5b573b385348cdc80065472b8961091f3226d2f650f" + ] + })).thenAnswer((_) async => {"0": []}); + when(client?.getBatchHistory(args: { + "0": [ + "06593b2d896751e8dda288bb6587b6bb6a1dee71d82a85457f5654f781e37b12" + ] + })).thenAnswer((_) async => {"0": []}); + when(client?.getBatchHistory(args: { + "0": [ + "11663d093cb17dfbed4a96d148b22d3e094b31d23c639c2814beb79f2ab0ca75" + ] + })).thenAnswer((_) async => {"0": []}); + when(client?.getBatchHistory(args: { + "0": [ + "2f18558e5d3015cb6578aee1c3e4b645725fa4e1d26ce22cb31c9949f3b4957c" + ] + })).thenAnswer((_) async => {"0": []}); + when(client?.getBatchHistory(args: { + "0": [ + "a328ae88ebce63c0010709ae900c199df2b585cdebce53a6291886dfdcc28c63" + ] + })).thenAnswer((_) async => {"0": []}); final wallet = await Hive.openBox(testWalletId); @@ -2738,13 +2801,36 @@ void main() { verify(cachedClient?.clearSharedTransactionCache(coin: Coin.bitcoin)) .called(1); - for (final arg in dynamicArgValues) { - final map = Map>.from(arg as Map); - - verify(client?.getBatchHistory(args: map)).called(1); - expect(activeScriptHashes.contains(map.values.first.first as String), - true); - } + verify(client?.getBatchHistory(args: { + "0": [ + "bf5a6c56814e80eed11e1e459801515f8c2b83da812568aa9dc26e6356f6965b" + ] + })).called(2); + verify(client?.getBatchHistory(args: { + "0": [ + "26f92666caebb9a17b14f5b573b385348cdc80065472b8961091f3226d2f650f" + ] + })).called(2); + verify(client?.getBatchHistory(args: { + "0": [ + "06593b2d896751e8dda288bb6587b6bb6a1dee71d82a85457f5654f781e37b12" + ] + })).called(2); + verify(client?.getBatchHistory(args: { + "0": [ + "11663d093cb17dfbed4a96d148b22d3e094b31d23c639c2814beb79f2ab0ca75" + ] + })).called(2); + verify(client?.getBatchHistory(args: { + "0": [ + "2f18558e5d3015cb6578aee1c3e4b645725fa4e1d26ce22cb31c9949f3b4957c" + ] + })).called(2); + verify(client?.getBatchHistory(args: { + "0": [ + "a328ae88ebce63c0010709ae900c199df2b585cdebce53a6291886dfdcc28c63" + ] + })).called(1); expect(secureStore?.writes, 19); expect(secureStore?.reads, 32); diff --git a/test/services/coins/bitcoincash/bitcoincash_history_sample_data.dart b/test/services/coins/bitcoincash/bitcoincash_history_sample_data.dart new file mode 100644 index 000000000..42312585e --- /dev/null +++ b/test/services/coins/bitcoincash/bitcoincash_history_sample_data.dart @@ -0,0 +1,120 @@ +final Map> historyBatchArgs0 = { + "k_0_0": ["4061323fc54ad0fd2fb6d3fd3af583068d7a733f562242a71e00ea7a82fb482b"], + "k_0_1": ["04818da846fe5e03ac993d2e0c1ccc3848ff6073c3aba6a572df4efc5432ae8b"], + "k_0_2": ["a0345933dd4146905a279f9aa35c867599fec2c52993a8f5da3a477acd0ebcfc"], + "k_0_3": ["607bc74daf946bfd9d593606f4393e44555a3dd0b529ddd08a0422be7955912e"], + "k_0_4": ["449dfb82e6f09f7e190f21fe63aaad5ccb854ba1f44f0a6622f6d71fff19fc63"], + "k_0_5": ["3643e3fe26e0b08dcbc89c47efce3b3264f361160341e3c2a6c73681dde12d39"], + "k_0_6": ["6daca5039b35adcbe62441b68eaaa48e9b0a806ab5a34314bd394b9b5c9289e5"], + "k_0_7": ["113f3d214f202795fdc3dccc6942395812270e787abb88fe4ddfa14f33d62d6f"], + "k_0_8": ["5dea575b85959647509d2ab3c92cda3776a4deba444486a7925ae3b71306e7e3"], + "k_0_9": ["5e2e6d3b43dfa29fabf66879d9ba67e4bb2f9f7ed10cfbb75e0b445eb4b84287"], + "k_0_10": [ + "1bfe42869b6b1e5efa1e1b47f382615e3d27e3e66e9cc8ae46b71ece067b4d37" + ], + "k_0_11": ["e0b38e944c5343e67c807a334fcf4b6563a6311447c99a105a0cf2cc3594ad11"] +}; + +final Map> historyBatchArgs1 = { + "k_0_0": ["50550ac9d45b7484b41e32751326127f3e121354e3bceead3e5fd020c94c4fe1"], + "k_0_1": ["f0c86f888f2aca0efaf1705247dbd1ebc02347c183e197310c9062ea2c9d2e34"], + "k_0_2": ["f729a8b3d47b265bf78ee78216174f3f5ef44aedfebf2d3224f1afadcfd6b52b"], + "k_0_3": ["82f5da8c4d26af2898dbb947c6afb83b5ad92e609345f1b89819293dd7714c75"], + "k_0_4": ["b4d6bf5639a8cd368772c26da95173940510618023e8952eb8db70aeb1d59cd2"], + "k_0_5": ["12e0f3cb2bf44b80f3c34cfd3fadc2a39de2f4776bc2be5b7100126db1238983"], + "k_0_6": ["ed5351a1e390d6635fa1ccf594998eb82fa627caf93541f3d5f1021b90e75ec7"], + "k_0_7": ["97917c094ec3afcd1b41338e7c06774b2f76c7a430e486c0080a86a141f39723"], + "k_0_8": ["58f96c6274cd3b74d362a30778497cef65f0c657ce94bb8b274b802e47876e3c"], + "k_0_9": ["99fb86f164906c621a42ee2b224972b3ea8ce10dbc1bccecbbdb1a7582e2954a"], + "k_0_10": [ + "555b8d6a03d2b93c381d2cda19fac11034bf5128ccbcbe5ff46b87f17969b4cb" + ], + "k_0_11": ["9d0163f011c1259568c188c4770606b25c823f8b76bbd262c1c7f3095ed24620"] +}; + +final Map>> historyBatchResponse = { + "k_0_0": [], + "s_0_0": [{}, {}], + "w_0_0": [], + "k_0_1": [{}], + "s_0_1": [], + "w_0_1": [{}, {}, {}], + "k_0_2": [], + "s_0_2": [], + "w_0_2": [], + "k_0_3": [], + "s_0_3": [], + "w_0_3": [], + "k_0_4": [], + "s_0_4": [], + "w_0_4": [], + "k_0_5": [], + "s_0_5": [], + "w_0_5": [], + "k_0_6": [], + "s_0_6": [], + "w_0_6": [], + "k_0_7": [], + "s_0_7": [], + "w_0_7": [], + "k_0_8": [], + "s_0_8": [], + "w_0_8": [], + "k_0_9": [], + "s_0_9": [], + "w_0_9": [], + "k_0_10": [], + "s_0_10": [], + "w_0_10": [], + "k_0_11": [], + "s_0_11": [], + "w_0_11": [] +}; + +final Map>> emptyHistoryBatchResponse = { + "k_0_0": [], + "s_0_0": [], + "w_0_0": [], + "k_0_1": [], + "s_0_1": [], + "w_0_1": [], + "k_0_2": [], + "s_0_2": [], + "w_0_2": [], + "k_0_3": [], + "s_0_3": [], + "w_0_3": [], + "k_0_4": [], + "s_0_4": [], + "w_0_4": [], + "k_0_5": [], + "s_0_5": [], + "w_0_5": [], + "k_0_6": [], + "s_0_6": [], + "w_0_6": [], + "k_0_7": [], + "s_0_7": [], + "w_0_7": [], + "k_0_8": [], + "s_0_8": [], + "w_0_8": [], + "k_0_9": [], + "s_0_9": [], + "w_0_9": [], + "k_0_10": [], + "s_0_10": [], + "w_0_10": [], + "k_0_11": [], + "s_0_11": [], + "w_0_11": [] +}; + +final List activeScriptHashes = [ + "11663d093cb17dfbed4a96d148b22d3e094b31d23c639c2814beb79f2ab0ca75", + "06593b2d896751e8dda288bb6587b6bb6a1dee71d82a85457f5654f781e37b12", + "a328ae88ebce63c0010709ae900c199df2b585cdebce53a6291886dfdcc28c63", + "26f92666caebb9a17b14f5b573b385348cdc80065472b8961091f3226d2f650f", + "2f18558e5d3015cb6578aee1c3e4b645725fa4e1d26ce22cb31c9949f3b4957c", + "bf5a6c56814e80eed11e1e459801515f8c2b83da812568aa9dc26e6356f6965b", +]; diff --git a/test/services/coins/bitcoincash/bitcoincash_transaction_data_samples.dart b/test/services/coins/bitcoincash/bitcoincash_transaction_data_samples.dart new file mode 100644 index 000000000..148818b37 --- /dev/null +++ b/test/services/coins/bitcoincash/bitcoincash_transaction_data_samples.dart @@ -0,0 +1,375 @@ +import 'package:stackwallet/models/paymint/transactions_model.dart'; + +final transactionData = TransactionData.fromMap({ + "61fedb3cb994917d2852191785ab59cb0d177d55d860bf10fd671f6a0a83247c": tx1, + "9765cc2efa42ffdfb5ec86e6ae043de4cf2158a00ed19a182c4244bc548334ba": tx2, + "070b45d901243b5856a0cccce8c5f5f548c19aaa00cb0059b37a6a9a3632288a": tx3, + "84aecde036ebe013aa3bd2fcb4741db504c7c040d34f7c33732c967646991855": tx4, +}); + +final tx1 = Transaction( + txid: "61fedb3cb994917d2852191785ab59cb0d177d55d860bf10fd671f6a0a83247c", + confirmedStatus: true, + confirmations: 187, + txType: "Received", + amount: 7000000, + fees: 742, + height: 756720, + address: "12QZH44735UHWAXFgb4hfdq756GjzXtZG7", + timestamp: 1662544771, + worthNow: "0.00", + worthAtBlockTimestamp: "0.00", + inputSize: 1, + outputSize: 2, + inputs: [ + Input( + txid: "f716d010786225004b41e35dd5eebfb11a4e5ea116e1a48235e5d3a591650732", + vout: 0, + ), + ], + outputs: [ + Output( + scriptpubkeyAddress: "12QZH44735UHWAXFgb4hfdq756GjzXtZG7", + value: 7000000, + ), + Output( + scriptpubkeyAddress: "3E1n17NnhVmWTGNbvH6ffKVNFjYT4Jke7G", + value: 71445709, + ) + ], +); + +final tx2 = Transaction( + txid: "9765cc2efa42ffdfb5ec86e6ae043de4cf2158a00ed19a182c4244bc548334ba", + confirmedStatus: true, + confirmations: 175, + txType: "Sent", + amount: 3000000, + fees: 227000, + height: 756732, + address: "1DPrEZBKKVG1Pf4HXeuCkw2Xk65EunR7CM", + timestamp: 1662553616, + worthNow: "0.00", + worthAtBlockTimestamp: "0.0", + inputSize: 1, + outputSize: 2, + inputs: [ + Input( + txid: "61fedb3cb994917d2852191785ab59cb0d177d55d860bf10fd671f6a0a83247c", + vout: 0, + ), + ], + outputs: [ + Output( + scriptpubkeyAddress: "1DPrEZBKKVG1Pf4HXeuCkw2Xk65EunR7CM", + value: 3000000, + ), + Output( + scriptpubkeyAddress: "16GbR1Xau2hKFTr1STgB39NbP8CEkGZjYG", + value: 3773000, + ), + ], +); + +final tx3 = Transaction( + txid: "070b45d901243b5856a0cccce8c5f5f548c19aaa00cb0059b37a6a9a3632288a", + confirmedStatus: true, + confirmations: 177, + txType: "Received", + amount: 2000000, + fees: 227, + height: 756738, + address: "1DPrEZBKKVG1Pf4HXeuCkw2Xk65EunR7CM", + timestamp: 1662555788, + worthNow: "0.00", + worthAtBlockTimestamp: "0.0", + inputSize: 1, + outputSize: 2, + inputs: [ + Input( + txid: "9765cc2efa42ffdfb5ec86e6ae043de4cf2158a00ed19a182c4244bc548334ba", + vout: 0, + ), + ], + outputs: [ + Output( + scriptpubkeyAddress: "1DPrEZBKKVG1Pf4HXeuCkw2Xk65EunR7CM", + value: 2000000, + ), + Output( + scriptpubkeyAddress: "16GbR1Xau2hKFTr1STgB39NbP8CEkGZjYG", + value: 1772773, + ), + ], +); + +final tx4 = Transaction( + txid: "84aecde036ebe013aa3bd2fcb4741db504c7c040d34f7c33732c967646991855", + confirmedStatus: false, + confirmations: 0, + txType: "Received", + amount: 4000000, + fees: 400, + height: 757303, + address: "1PQaBto5KmiW3R2YeexYYoDWksMpEvhYZE", + timestamp: 1662893734, + worthNow: "0.00", + worthAtBlockTimestamp: "0.00", + inputSize: 1, + outputSize: 2, + inputs: [ + Input( + txid: "070b45d901243b5856a0cccce8c5f5f548c19aaa00cb0059b37a6a9a3632288a", + vout: 0, + ), + Input( + txid: "9765cc2efa42ffdfb5ec86e6ae043de4cf2158a00ed19a182c4244bc548334ba", + vout: 0, + ), + ], + outputs: [ + Output( + scriptpubkeyAddress: "1JHcZyhgctuDCznjkxR51pQzKEJUujuc2j", + value: 999600, + ), + Output( + scriptpubkeyAddress: "1PQaBto5KmiW3R2YeexYYoDWksMpEvhYZE", + value: 4000000, + ) + ], +); + +final tx1Raw = { + "in_mempool": false, + "in_orphanpool": false, + "txid": "61fedb3cb994917d2852191785ab59cb0d177d55d860bf10fd671f6a0a83247c", + "size": 372, + "version": 1, + "locktime": 0, + "vin": [ + { + "txid": + "f716d010786225004b41e35dd5eebfb11a4e5ea116e1a48235e5d3a591650732", + "vout": 1, + "scriptSig": { + "asm": + "0 3045022100d80e1d056e8787d7fac8e59ce14d56a2dbb2aceb43da1fee47e687e318049abd02204bb06be6e8af85250b93e0f5377da535557176557563a4d0121b607ffbf3e7c1[ALL|FORKID] 304402200c528edd5f1c0aa169178f5a4c1ec5044559326f1608db6987398bdc0761aaae02205a94bb7f8dac69400823a0093e0303eaa2905b9fadbb8bbb111c3fef0a452ef0[ALL|FORKID] 522103ff1450283f08568acdb4d5f569f32e4cd4d8c1960ea049a205436f69f9916df8210230ee6aec65bc0db7e9cf507b33067f681047e180e91906e1fde1bb549f233b24210366058482ecccb47075be9d1d3edb46df331c04fa5126cd6fd9dc6cee071237b453ae", + "hex": + "00483045022100d80e1d056e8787d7fac8e59ce14d56a2dbb2aceb43da1fee47e687e318049abd02204bb06be6e8af85250b93e0f5377da535557176557563a4d0121b607ffbf3e7c14147304402200c528edd5f1c0aa169178f5a4c1ec5044559326f1608db6987398bdc0761aaae02205a94bb7f8dac69400823a0093e0303eaa2905b9fadbb8bbb111c3fef0a452ef0414c69522103ff1450283f08568acdb4d5f569f32e4cd4d8c1960ea049a205436f69f9916df8210230ee6aec65bc0db7e9cf507b33067f681047e180e91906e1fde1bb549f233b24210366058482ecccb47075be9d1d3edb46df331c04fa5126cd6fd9dc6cee071237b453ae" + }, + "sequence": 4294967295 + } + ], + "vout": [ + { + "value": 0.07, + "n": 0, + "scriptPubKey": { + "asm": + "OP_DUP OP_HASH160 0f6ca2ddb50a473f809440f77d3d931335ac2940 OP_EQUALVERIFY OP_CHECKSIG", + "hex": "76a9140f6ca2ddb50a473f809440f77d3d931335ac294088ac", + "reqSigs": 1, + "type": "pubkeyhash", + "addresses": ["12QZH44735UHWAXFgb4hfdq756GjzXtZG7"] + } + }, + { + "value": 0.71445709, + "n": 1, + "scriptPubKey": { + "asm": "OP_HASH160 872dcab340b7a8500b2585781e51e9217f11dced OP_EQUAL", + "hex": "a914872dcab340b7a8500b2585781e51e9217f11dced87", + "reqSigs": 1, + "type": "scripthash", + "addresses": ["3E1n17NnhVmWTGNbvH6ffKVNFjYT4Jke7G"] + } + } + ], + "blockhash": + "00000000000000000529d5816d2f9c97cfbe8c06bb87e9a15d9e778281ff9225", + "confirmations": 187, + "time": 1662544771, + "blocktime": 1662544771, + "hex": + "010000000132076591a5d3e53582a4e116a15e4e1ab1bfeed55de3414b0025627810d016f701000000fdfd0000483045022100d80e1d056e8787d7fac8e59ce14d56a2dbb2aceb43da1fee47e687e318049abd02204bb06be6e8af85250b93e0f5377da535557176557563a4d0121b607ffbf3e7c14147304402200c528edd5f1c0aa169178f5a4c1ec5044559326f1608db6987398bdc0761aaae02205a94bb7f8dac69400823a0093e0303eaa2905b9fadbb8bbb111c3fef0a452ef0414c69522103ff1450283f08568acdb4d5f569f32e4cd4d8c1960ea049a205436f69f9916df8210230ee6aec65bc0db7e9cf507b33067f681047e180e91906e1fde1bb549f233b24210366058482ecccb47075be9d1d3edb46df331c04fa5126cd6fd9dc6cee071237b453aeffffffff02c0cf6a00000000001976a9140f6ca2ddb50a473f809440f77d3d931335ac294088accd2c42040000000017a914872dcab340b7a8500b2585781e51e9217f11dced8700000000" +}; + +final tx2Raw = { + "in_mempool": false, + "in_orphanpool": false, + "txid": "9765cc2efa42ffdfb5ec86e6ae043de4cf2158a00ed19a182c4244bc548334ba", + "size": 225, + "version": 2, + "locktime": 0, + "vin": [ + { + "txid": + "61fedb3cb994917d2852191785ab59cb0d177d55d860bf10fd671f6a0a83247c", + "vout": 0, + "scriptSig": { + "asm": + "304402207b3301ec0ab0c7dbba32690b71e369a6872ff2d0c0cacaddc831bb04d22cef7102206e0bb6d039c408e301d49978aa34597f57d075b9a69e1a9f120e08af159b167a[ALL|FORKID] 02cb6cdf3e5758112206b4b02f21838b3d8a26c601a88030f3c5705e357d8e4ea8", + "hex": + "47304402207b3301ec0ab0c7dbba32690b71e369a6872ff2d0c0cacaddc831bb04d22cef7102206e0bb6d039c408e301d49978aa34597f57d075b9a69e1a9f120e08af159b167a412102cb6cdf3e5758112206b4b02f21838b3d8a26c601a88030f3c5705e357d8e4ea8" + }, + "sequence": 4294967295 + } + ], + "vout": [ + { + "value": 0.03, + "n": 0, + "scriptPubKey": { + "asm": + "OP_DUP OP_HASH160 87f3c240183ef0f3efe4b056029dd16d3e3d5d4f OP_EQUALVERIFY OP_CHECKSIG", + "hex": "76a91487f3c240183ef0f3efe4b056029dd16d3e3d5d4f88ac", + "reqSigs": 1, + "type": "pubkeyhash", + "addresses": ["1DPrEZBKKVG1Pf4HXeuCkw2Xk65EunR7CM"] + } + }, + { + "value": 0.03773, + "n": 1, + "scriptPubKey": { + "asm": + "OP_DUP OP_HASH160 7fa80c90c0f8aa021074702c06b3300c0b247244 OP_EQUALVERIFY OP_CHECKSIG", + "hex": "76a9147fa80c90c0f8aa021074702c06b3300c0b24724488ac", + "reqSigs": 1, + "type": "pubkeyhash", + "addresses": ["1Cdz8cpH3ZRuZViuah32YaTkNGryCS3DZj"] + } + } + ], + "blockhash": + "000000000000000005d25c8d3722e4486c486bbf864f9261631993afab557832", + "confirmations": 175, + "time": 1662553616, + "blocktime": 1662553616, + "hex": + "02000000017c24830a6a1f67fd10bf60d8557d170dcb59ab85171952287d9194b93cdbfe61000000006a47304402207b3301ec0ab0c7dbba32690b71e369a6872ff2d0c0cacaddc831bb04d22cef7102206e0bb6d039c408e301d49978aa34597f57d075b9a69e1a9f120e08af159b167a412102cb6cdf3e5758112206b4b02f21838b3d8a26c601a88030f3c5705e357d8e4ea8ffffffff02c0c62d00000000001976a91487f3c240183ef0f3efe4b056029dd16d3e3d5d4f88ac48923900000000001976a9147fa80c90c0f8aa021074702c06b3300c0b24724488ac00000000" +}; + +final tx3Raw = { + "in_mempool": false, + "in_orphanpool": false, + "txid": "070b45d901243b5856a0cccce8c5f5f548c19aaa00cb0059b37a6a9a3632288a", + "size": 226, + "version": 2, + "locktime": 0, + "vin": [ + { + "txid": + "9765cc2efa42ffdfb5ec86e6ae043de4cf2158a00ed19a182c4244bc548334ba", + "vout": 1, + "scriptSig": { + "asm": + "3045022100ed38dc64e40a5cfe137d38fbe9b7c4fe8a09ef923d7f999f35c65b029aa233ac02206f119c8d881a1b475697ec1eef815cde2e0e456ce4e234c5762fc7ddbe04ac27[ALL|FORKID] 029845663b31ebf3136039db97b3413b939b61c5bef45e4ee23544165a28ed452b", + "hex": + "483045022100ed38dc64e40a5cfe137d38fbe9b7c4fe8a09ef923d7f999f35c65b029aa233ac02206f119c8d881a1b475697ec1eef815cde2e0e456ce4e234c5762fc7ddbe04ac274121029845663b31ebf3136039db97b3413b939b61c5bef45e4ee23544165a28ed452b" + }, + "sequence": 4294967295 + } + ], + "vout": [ + { + "value": 0.02, + "n": 0, + "scriptPubKey": { + "asm": + "OP_DUP OP_HASH160 87f3c240183ef0f3efe4b056029dd16d3e3d5d4f OP_EQUALVERIFY OP_CHECKSIG", + "hex": "76a91487f3c240183ef0f3efe4b056029dd16d3e3d5d4f88ac", + "reqSigs": 1, + "type": "pubkeyhash", + "addresses": ["1DPrEZBKKVG1Pf4HXeuCkw2Xk65EunR7CM"] + } + }, + { + "value": 0.01772773, + "n": 1, + "scriptPubKey": { + "asm": + "OP_DUP OP_HASH160 39cb987d75cbe99ec577de2f1918ff2b3539491a OP_EQUALVERIFY OP_CHECKSIG", + "hex": "76a91439cb987d75cbe99ec577de2f1918ff2b3539491a88ac", + "reqSigs": 1, + "type": "pubkeyhash", + "addresses": ["16GbR1Xau2hKFTr1STgB39NbP8CEkGZjYG"] + } + } + ], + "blockhash": + "00000000000000000227adf51d47ac640c7353e873a398901ecf9becbf5988d7", + "confirmations": 179, + "time": 1662555788, + "blocktime": 1662555788, + "hex": + "0200000001ba348354bc44422c189ad10ea05821cfe43d04aee686ecb5dfff42fa2ecc6597010000006b483045022100ed38dc64e40a5cfe137d38fbe9b7c4fe8a09ef923d7f999f35c65b029aa233ac02206f119c8d881a1b475697ec1eef815cde2e0e456ce4e234c5762fc7ddbe04ac274121029845663b31ebf3136039db97b3413b939b61c5bef45e4ee23544165a28ed452bffffffff0280841e00000000001976a91487f3c240183ef0f3efe4b056029dd16d3e3d5d4f88ace50c1b00000000001976a91439cb987d75cbe99ec577de2f1918ff2b3539491a88ac00000000" +}; + +final tx4Raw = { + "in_mempool": false, + "in_orphanpool": false, + "txid": "84aecde036ebe013aa3bd2fcb4741db504c7c040d34f7c33732c967646991855", + "size": 360, + "version": 1, + "locktime": 757301, + "vin": [ + { + "txid": + "070b45d901243b5856a0cccce8c5f5f548c19aaa00cb0059b37a6a9a3632288a", + "vout": 0, + "scriptSig": { + "asm": + "95a4d53e9059dc478b2f79dc486b4dd1ea2f34f3f2f870ba26a9c16530305ddc3e25b1d1d5adc42df75b4666b9fe6ec5b41813c0e82a579ce2167f6f7ed1b305[ALL|FORKID] 02d0825e4d527c9c24e0d423187055904f91218c82652b3fe575a212fef15531fd", + "hex": + "4195a4d53e9059dc478b2f79dc486b4dd1ea2f34f3f2f870ba26a9c16530305ddc3e25b1d1d5adc42df75b4666b9fe6ec5b41813c0e82a579ce2167f6f7ed1b305412102d0825e4d527c9c24e0d423187055904f91218c82652b3fe575a212fef15531fd" + }, + "sequence": 4294967294 + }, + { + "txid": + "9765cc2efa42ffdfb5ec86e6ae043de4cf2158a00ed19a182c4244bc548334ba", + "vout": 0, + "scriptSig": { + "asm": + "f2557ee7ae3eaf6488cc24972c73578ffc6ea2db047ffc4ff0b220f5d4efe491de01e1024ee77dc88d2cfa2f44b686bf394bd2a7114aac4fac48007547e2d313[ALL|FORKID] 02d0825e4d527c9c24e0d423187055904f91218c82652b3fe575a212fef15531fd", + "hex": + "41f2557ee7ae3eaf6488cc24972c73578ffc6ea2db047ffc4ff0b220f5d4efe491de01e1024ee77dc88d2cfa2f44b686bf394bd2a7114aac4fac48007547e2d313412102d0825e4d527c9c24e0d423187055904f91218c82652b3fe575a212fef15531fd" + }, + "sequence": 4294967294 + } + ], + "vout": [ + { + "value": 0.009996, + "n": 0, + "scriptPubKey": { + "asm": + "OP_DUP OP_HASH160 bd9e7c204b6d0d90ba018250fafa398d5ec1b39d OP_EQUALVERIFY OP_CHECKSIG", + "hex": "76a914bd9e7c204b6d0d90ba018250fafa398d5ec1b39d88ac", + "reqSigs": 1, + "type": "pubkeyhash", + "addresses": ["1JHcZyhgctuDCznjkxR51pQzKEJUujuc2j"] + } + }, + { + "value": 0.04, + "n": 1, + "scriptPubKey": { + "asm": + "OP_DUP OP_HASH160 f5c809c469d24bc0bf4f6a17a9218df1a79cd247 OP_EQUALVERIFY OP_CHECKSIG", + "hex": "76a914f5c809c469d24bc0bf4f6a17a9218df1a79cd24788ac", + "reqSigs": 1, + "type": "pubkeyhash", + "addresses": ["1PQaBto5KmiW3R2YeexYYoDWksMpEvhYZE"] + } + } + ], + "blockhash": + "000000000000000005aa6b3094801ec56f36f74d4b25cad38b22dc3d24cd3e43", + "confirmations": 1, + "time": 1662893734, + "blocktime": 1662893734, + "hex": + "01000000028a2832369a6a7ab35900cb00aa9ac148f5f5c5e8cccca056583b2401d9450b0700000000644195a4d53e9059dc478b2f79dc486b4dd1ea2f34f3f2f870ba26a9c16530305ddc3e25b1d1d5adc42df75b4666b9fe6ec5b41813c0e82a579ce2167f6f7ed1b305412102d0825e4d527c9c24e0d423187055904f91218c82652b3fe575a212fef15531fdfeffffffba348354bc44422c189ad10ea05821cfe43d04aee686ecb5dfff42fa2ecc6597000000006441f2557ee7ae3eaf6488cc24972c73578ffc6ea2db047ffc4ff0b220f5d4efe491de01e1024ee77dc88d2cfa2f44b686bf394bd2a7114aac4fac48007547e2d313412102d0825e4d527c9c24e0d423187055904f91218c82652b3fe575a212fef15531fdfeffffff02b0400f00000000001976a914bd9e7c204b6d0d90ba018250fafa398d5ec1b39d88ac00093d00000000001976a914f5c809c469d24bc0bf4f6a17a9218df1a79cd24788ac358e0b00" +}; diff --git a/test/services/coins/bitcoincash/bitcoincash_utxo_sample_data.dart b/test/services/coins/bitcoincash/bitcoincash_utxo_sample_data.dart new file mode 100644 index 000000000..54ab1c37b --- /dev/null +++ b/test/services/coins/bitcoincash/bitcoincash_utxo_sample_data.dart @@ -0,0 +1,84 @@ +import 'package:stackwallet/models/paymint/utxo_model.dart'; + +final Map>> batchGetUTXOResponse0 = { + "some id 0": [ + { + "tx_pos": 0, + "value": 7000000, + "tx_hash": + "61fedb3cb994917d2852191785ab59cb0d177d55d860bf10fd671f6a0a83247c", + "height": 756720 + }, + { + "tx_pos": 0, + "value": 3000000, + "tx_hash": + "9765cc2efa42ffdfb5ec86e6ae043de4cf2158a00ed19a182c4244bc548334ba", + "height": 756732 + }, + ], + "some id 1": [ + { + "tx_pos": 1, + "value": 2000000, + "tx_hash": + "070b45d901243b5856a0cccce8c5f5f548c19aaa00cb0059b37a6a9a3632288a", + "height": 756738 + }, + ], + "some id 2": [], +}; + +final utxoList = [ + UtxoObject( + txid: "9765cc2efa42ffdfb5ec86e6ae043de4cf2158a00ed19a182c4244bc548334ba", + vout: 0, + status: Status( + confirmed: true, + confirmations: 175, + blockHeight: 756732, + blockTime: 1662553616, + blockHash: + "000000000000000005d25c8d3722e4486c486bbf864f9261631993afab557832", + ), + value: 3000000, + fiatWorth: "\$0", + txName: "1DPrEZBKKVG1Pf4HXeuCkw2Xk65EunR7CM", + blocked: false, + isCoinbase: false, + ), + UtxoObject( + txid: "f716d010786225004b41e35dd5eebfb11a4e5ea116e1a48235e5d3a591650732", + vout: 1, + status: Status( + confirmed: true, + confirmations: 11867, + blockHeight: 745443, + blockTime: 1655792385, + blockHash: + "000000000000000000065c982f4d86a402e7182d0c6a49fa6cfbdaf67a57f566", + ), + value: 78446451, + fiatWorth: "\$0", + txName: "3E1n17NnhVmWTGNbvH6ffKVNFjYT4Jke7G", + blocked: false, + isCoinbase: false, + ), + UtxoObject( + txid: "070b45d901243b5856a0cccce8c5f5f548c19aaa00cb0059b37a6a9a3632288a", + vout: 0, + status: Status( + confirmed: true, + confirmations: 572, + blockHeight: 756738, + blockTime: 1662555788, + blockHash: + "00000000000000000227adf51d47ac640c7353e873a398901ecf9becbf5988d7", + ), + value: 2000000, + fiatWorth: "\$0", + txName: "1DPrEZBKKVG1Pf4HXeuCkw2Xk65EunR7CM", + blocked: false, + isCoinbase: false, + ), +]; diff --git a/test/services/coins/bitcoincash/bitcoincash_wallet_test.dart b/test/services/coins/bitcoincash/bitcoincash_wallet_test.dart new file mode 100644 index 000000000..703876280 --- /dev/null +++ b/test/services/coins/bitcoincash/bitcoincash_wallet_test.dart @@ -0,0 +1,2851 @@ +// import 'package:bitcoindart/bitcoindart.dart'; +// import 'package:decimal/decimal.dart'; +// import 'package:flutter_test/flutter_test.dart'; +// import 'package:hive/hive.dart'; +// import 'package:hive_test/hive_test.dart'; +// import 'package:mockito/annotations.dart'; +// import 'package:mockito/mockito.dart'; +// import 'package:stackwallet/electrumx_rpc/cached_electrumx.dart'; +// import 'package:stackwallet/electrumx_rpc/electrumx.dart'; +// import 'package:stackwallet/hive/db.dart'; +// import 'package:stackwallet/models/paymint/fee_object_model.dart'; +// import 'package:stackwallet/models/paymint/transactions_model.dart'; +// import 'package:stackwallet/models/paymint/utxo_model.dart'; +// import 'package:stackwallet/services/coins/bitcoincash/bitcoincash_wallet.dart'; +// import 'package:stackwallet/services/price.dart'; +// import 'package:stackwallet/services/transaction_notification_tracker.dart'; +// import 'package:stackwallet/utilities/enums/coin_enum.dart'; +// import 'package:stackwallet/utilities/flutter_secure_storage_interface.dart'; +// +// import 'bitcoincash_history_sample_data.dart'; +// import 'bitcoincash_wallet_test.mocks.dart'; +// import 'bitcoincash_wallet_test_parameters.dart'; +// +// @GenerateMocks( +// [ElectrumX, CachedElectrumX, PriceAPI, TransactionNotificationTracker]) +void main() {} +// group("bitcoincash constants", () { +// test("bitcoincash minimum confirmations", () async { +// expect(MINIMUM_CONFIRMATIONS, 3); +// }); +// test("bitcoincash dust limit", () async { +// expect(DUST_LIMIT, 546); +// }); +// test("bitcoincash mainnet genesis block hash", () async { +// expect(GENESIS_HASH_MAINNET, +// "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f"); +// }); +// +// test("bitcoincash testnet genesis block hash", () async { +// expect(GENESIS_HASH_TESTNET, +// "000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943"); +// }); +// }); +// +// test("bitcoincash DerivePathType enum", () { +// expect(DerivePathType.values.length, 1); +// expect(DerivePathType.values.toString(), "[DerivePathType.bip44]"); +// }); +// +// group("bip32 node/root", () { +// test("getBip32Root", () { +// final root = getBip32Root(TEST_MNEMONIC, bitcoincash); +// expect(root.toWIF(), ROOT_WIF); +// }); +// +// test("basic getBip32Node", () { +// final node = +// getBip32Node(0, 0, TEST_MNEMONIC, bitcoincash, DerivePathType.bip44); +// expect(node.toWIF(), NODE_WIF_44); +// }); +// }); +// +// group("validate mainnet bitcoincash addresses", () { +// MockElectrumX? client; +// MockCachedElectrumX? cachedClient; +// MockPriceAPI? priceAPI; +// FakeSecureStorage? secureStore; +// MockTransactionNotificationTracker? tracker; +// +// BitcoinCashWallet? mainnetWallet; +// +// setUp(() { +// client = MockElectrumX(); +// cachedClient = MockCachedElectrumX(); +// priceAPI = MockPriceAPI(); +// secureStore = FakeSecureStorage(); +// tracker = MockTransactionNotificationTracker(); +// +// mainnetWallet = BitcoinCashWallet( +// walletId: "validateAddressMainNet", +// walletName: "validateAddressMainNet", +// coin: Coin.bitcoincash, +// client: client!, +// cachedClient: cachedClient!, +// tracker: tracker!, +// priceAPI: priceAPI, +// secureStore: secureStore, +// ); +// }); +// +// test("valid mainnet legacy/p2pkh address type", () { +// expect( +// mainnetWallet?.addressType( +// address: "1DP3PUePwMa5CoZwzjznVKhzdLsZftjcAT"), +// DerivePathType.bip44); +// expect(secureStore?.interactions, 0); +// verifyNoMoreInteractions(client); +// verifyNoMoreInteractions(cachedClient); +// verifyNoMoreInteractions(tracker); +// verifyNoMoreInteractions(priceAPI); +// }); +// +// test("invalid base58 address type", () { +// expect( +// () => mainnetWallet?.addressType( +// address: "mhqpGtwhcR6gFuuRjLTpHo41919QfuGy8Y"), +// throwsArgumentError); +// expect(secureStore?.interactions, 0); +// verifyNoMoreInteractions(client); +// verifyNoMoreInteractions(cachedClient); +// verifyNoMoreInteractions(tracker); +// verifyNoMoreInteractions(priceAPI); +// }); +// +// test("invalid bech32 address type", () { +// expect( +// () => mainnetWallet?.addressType( +// address: "tb1qzzlm6mnc8k54mx6akehl8p9ray8r439va5ndyq"), +// throwsArgumentError); +// expect(secureStore?.interactions, 0); +// verifyNoMoreInteractions(client); +// verifyNoMoreInteractions(cachedClient); +// verifyNoMoreInteractions(tracker); +// verifyNoMoreInteractions(priceAPI); +// }); +// +// test("address has no matching script", () { +// expect( +// () => mainnetWallet?.addressType( +// address: "mpMk94ETazqonHutyC1v6ajshgtP8oiFKU"), +// throwsArgumentError); +// expect(secureStore?.interactions, 0); +// verifyNoMoreInteractions(client); +// verifyNoMoreInteractions(cachedClient); +// verifyNoMoreInteractions(tracker); +// verifyNoMoreInteractions(priceAPI); +// }); +// +// test("invalid mainnet bitcoincash legacy/p2pkh address", () { +// expect( +// mainnetWallet?.validateAddress("mhqpGtwhcR6gFuuRjLTpHo41919QfuGy8Y"), +// true); +// expect(secureStore?.interactions, 0); +// verifyNoMoreInteractions(client); +// verifyNoMoreInteractions(cachedClient); +// verifyNoMoreInteractions(tracker); +// verifyNoMoreInteractions(priceAPI); +// }); +// }); +// +// group("testNetworkConnection", () { +// MockElectrumX? client; +// MockCachedElectrumX? cachedClient; +// MockPriceAPI? priceAPI; +// FakeSecureStorage? secureStore; +// MockTransactionNotificationTracker? tracker; +// +// BitcoinCashWallet? bch; +// +// setUp(() { +// client = MockElectrumX(); +// cachedClient = MockCachedElectrumX(); +// priceAPI = MockPriceAPI(); +// secureStore = FakeSecureStorage(); +// tracker = MockTransactionNotificationTracker(); +// +// bch = BitcoinCashWallet( +// walletId: "testNetworkConnection", +// walletName: "testNetworkConnection", +// coin: Coin.bitcoincash, +// client: client!, +// cachedClient: cachedClient!, +// tracker: tracker!, +// priceAPI: priceAPI, +// secureStore: secureStore, +// ); +// }); +// +// test("attempted connection fails due to server error", () async { +// when(client?.ping()).thenAnswer((_) async => false); +// final bool? result = await bch?.testNetworkConnection(); +// expect(result, false); +// expect(secureStore?.interactions, 0); +// verify(client?.ping()).called(1); +// verifyNoMoreInteractions(client); +// verifyNoMoreInteractions(cachedClient); +// verifyNoMoreInteractions(tracker); +// verifyNoMoreInteractions(priceAPI); +// }); +// +// test("attempted connection fails due to exception", () async { +// when(client?.ping()).thenThrow(Exception); +// final bool? result = await bch?.testNetworkConnection(); +// expect(result, false); +// expect(secureStore?.interactions, 0); +// verify(client?.ping()).called(1); +// verifyNoMoreInteractions(client); +// verifyNoMoreInteractions(cachedClient); +// verifyNoMoreInteractions(tracker); +// verifyNoMoreInteractions(priceAPI); +// }); +// +// test("attempted connection test success", () async { +// when(client?.ping()).thenAnswer((_) async => true); +// final bool? result = await bch?.testNetworkConnection(); +// expect(result, true); +// expect(secureStore?.interactions, 0); +// verify(client?.ping()).called(1); +// verifyNoMoreInteractions(client); +// verifyNoMoreInteractions(cachedClient); +// verifyNoMoreInteractions(tracker); +// verifyNoMoreInteractions(priceAPI); +// }); +// }); +// +// group("basic getters, setters, and functions", () { +// final bchcoin = Coin.bitcoincash; +// final testWalletId = "BCHtestWalletID"; +// final testWalletName = "BCHWallet"; +// +// MockElectrumX? client; +// MockCachedElectrumX? cachedClient; +// MockPriceAPI? priceAPI; +// FakeSecureStorage? secureStore; +// MockTransactionNotificationTracker? tracker; +// +// BitcoinCashWallet? bch; +// +// setUp(() async { +// client = MockElectrumX(); +// cachedClient = MockCachedElectrumX(); +// priceAPI = MockPriceAPI(); +// secureStore = FakeSecureStorage(); +// tracker = MockTransactionNotificationTracker(); +// +// bch = BitcoinCashWallet( +// walletId: testWalletId, +// walletName: testWalletName, +// coin: bchcoin, +// client: client!, +// cachedClient: cachedClient!, +// tracker: tracker!, +// priceAPI: priceAPI, +// secureStore: secureStore, +// ); +// }); +// +// test("get networkType main", () async { +// expect(bch?.coin, bchcoin); +// expect(secureStore?.interactions, 0); +// verifyNoMoreInteractions(client); +// verifyNoMoreInteractions(cachedClient); +// verifyNoMoreInteractions(tracker); +// verifyNoMoreInteractions(priceAPI); +// }); +// +// test("get networkType test", () async { +// bch = BitcoinCashWallet( +// walletId: testWalletId, +// walletName: testWalletName, +// coin: bchcoin, +// client: client!, +// cachedClient: cachedClient!, +// tracker: tracker!, +// priceAPI: priceAPI, +// secureStore: secureStore, +// ); +// expect(bch?.coin, bchcoin); +// expect(secureStore?.interactions, 0); +// verifyNoMoreInteractions(client); +// verifyNoMoreInteractions(cachedClient); +// verifyNoMoreInteractions(tracker); +// verifyNoMoreInteractions(priceAPI); +// }); +// +// test("get cryptoCurrency", () async { +// expect(Coin.bitcoincash, Coin.bitcoincash); +// expect(secureStore?.interactions, 0); +// verifyNoMoreInteractions(client); +// verifyNoMoreInteractions(cachedClient); +// verifyNoMoreInteractions(tracker); +// verifyNoMoreInteractions(priceAPI); +// }); +// +// test("get coinName", () async { +// expect(Coin.bitcoincash, Coin.bitcoincash); +// expect(secureStore?.interactions, 0); +// verifyNoMoreInteractions(client); +// verifyNoMoreInteractions(cachedClient); +// verifyNoMoreInteractions(tracker); +// verifyNoMoreInteractions(priceAPI); +// }); +// +// test("get coinTicker", () async { +// expect(Coin.bitcoincash, Coin.bitcoincash); +// expect(secureStore?.interactions, 0); +// verifyNoMoreInteractions(client); +// verifyNoMoreInteractions(cachedClient); +// verifyNoMoreInteractions(tracker); +// verifyNoMoreInteractions(priceAPI); +// }); +// +// test("get and set walletName", () async { +// expect(Coin.bitcoincash, Coin.bitcoincash); +// bch?.walletName = "new name"; +// expect(bch?.walletName, "new name"); +// expect(secureStore?.interactions, 0); +// verifyNoMoreInteractions(client); +// verifyNoMoreInteractions(cachedClient); +// verifyNoMoreInteractions(tracker); +// verifyNoMoreInteractions(priceAPI); +// }); +// +// test("estimateTxFee", () async { +// expect(bch?.estimateTxFee(vSize: 356, feeRatePerKB: 1), 356); +// expect(bch?.estimateTxFee(vSize: 356, feeRatePerKB: 900), 356); +// expect(bch?.estimateTxFee(vSize: 356, feeRatePerKB: 999), 356); +// expect(bch?.estimateTxFee(vSize: 356, feeRatePerKB: 1000), 356); +// expect(bch?.estimateTxFee(vSize: 356, feeRatePerKB: 1001), 712); +// expect(bch?.estimateTxFee(vSize: 356, feeRatePerKB: 1699), 712); +// expect(bch?.estimateTxFee(vSize: 356, feeRatePerKB: 2000), 712); +// expect(bch?.estimateTxFee(vSize: 356, feeRatePerKB: 12345), 4628); +// expect(secureStore?.interactions, 0); +// verifyNoMoreInteractions(client); +// verifyNoMoreInteractions(cachedClient); +// verifyNoMoreInteractions(tracker); +// verifyNoMoreInteractions(priceAPI); +// }); +// +// test("get fees succeeds", () async { +// when(client?.ping()).thenAnswer((_) async => true); +// when(client?.getServerFeatures()).thenAnswer((_) async => { +// "hosts": {}, +// "pruning": null, +// "server_version": "Unit tests", +// "protocol_min": "1.4", +// "protocol_max": "1.4.2", +// "genesis_hash": GENESIS_HASH_TESTNET, +// "hash_function": "sha256", +// "services": [] +// }); +// when(client?.estimateFee(blocks: 1)) +// .thenAnswer((realInvocation) async => Decimal.zero); +// when(client?.estimateFee(blocks: 5)) +// .thenAnswer((realInvocation) async => Decimal.one); +// when(client?.estimateFee(blocks: 20)) +// .thenAnswer((realInvocation) async => Decimal.ten); +// +// final fees = await bch?.fees; +// expect(fees, isA()); +// expect(fees?.slow, 1000000000); +// expect(fees?.medium, 100000000); +// expect(fees?.fast, 0); +// +// verify(client?.estimateFee(blocks: 1)).called(1); +// verify(client?.estimateFee(blocks: 5)).called(1); +// verify(client?.estimateFee(blocks: 20)).called(1); +// expect(secureStore?.interactions, 0); +// verifyNoMoreInteractions(client); +// verifyNoMoreInteractions(cachedClient); +// verifyNoMoreInteractions(tracker); +// verifyNoMoreInteractions(priceAPI); +// }); +// +// test("get fees fails", () async { +// when(client?.ping()).thenAnswer((_) async => true); +// when(client?.getServerFeatures()).thenAnswer((_) async => { +// "hosts": {}, +// "pruning": null, +// "server_version": "Unit tests", +// "protocol_min": "1.4", +// "protocol_max": "1.4.2", +// "genesis_hash": GENESIS_HASH_TESTNET, +// "hash_function": "sha256", +// "services": [] +// }); +// when(client?.estimateFee(blocks: 1)) +// .thenAnswer((realInvocation) async => Decimal.zero); +// when(client?.estimateFee(blocks: 5)) +// .thenAnswer((realInvocation) async => Decimal.one); +// when(client?.estimateFee(blocks: 20)) +// .thenThrow(Exception("some exception")); +// +// bool didThrow = false; +// try { +// await bch?.fees; +// } catch (_) { +// didThrow = true; +// } +// +// expect(didThrow, true); +// +// verify(client?.estimateFee(blocks: 1)).called(1); +// verify(client?.estimateFee(blocks: 5)).called(1); +// verify(client?.estimateFee(blocks: 20)).called(1); +// expect(secureStore?.interactions, 0); +// verifyNoMoreInteractions(client); +// verifyNoMoreInteractions(cachedClient); +// verifyNoMoreInteractions(tracker); +// verifyNoMoreInteractions(priceAPI); +// }); +// +// test("get maxFee", () async { +// when(client?.ping()).thenAnswer((_) async => true); +// when(client?.getServerFeatures()).thenAnswer((_) async => { +// "hosts": {}, +// "pruning": null, +// "server_version": "Unit tests", +// "protocol_min": "1.4", +// "protocol_max": "1.4.2", +// "genesis_hash": GENESIS_HASH_TESTNET, +// "hash_function": "sha256", +// "services": [] +// }); +// when(client?.estimateFee(blocks: 20)) +// .thenAnswer((realInvocation) async => Decimal.zero); +// when(client?.estimateFee(blocks: 5)) +// .thenAnswer((realInvocation) async => Decimal.one); +// when(client?.estimateFee(blocks: 1)) +// .thenAnswer((realInvocation) async => Decimal.ten); +// +// final maxFee = await bch?.maxFee; +// expect(maxFee, 1000000000); +// +// verify(client?.estimateFee(blocks: 1)).called(1); +// verify(client?.estimateFee(blocks: 5)).called(1); +// verify(client?.estimateFee(blocks: 20)).called(1); +// expect(secureStore?.interactions, 0); +// verifyNoMoreInteractions(client); +// verifyNoMoreInteractions(cachedClient); +// verifyNoMoreInteractions(tracker); +// verifyNoMoreInteractions(priceAPI); +// }); +// }); +// +// group("BCHWallet service class functions that depend on shared storage", () { +// final bchcoin = Coin.bitcoincash; +// final bchtestcoin = Coin.bitcoincashTestnet; +// final testWalletId = "BCHtestWalletID"; +// final testWalletName = "BCHWallet"; +// +// bool hiveAdaptersRegistered = false; +// +// MockElectrumX? client; +// MockCachedElectrumX? cachedClient; +// MockPriceAPI? priceAPI; +// FakeSecureStorage? secureStore; +// MockTransactionNotificationTracker? tracker; +// +// BitcoinCashWallet? bch; +// +// setUp(() async { +// await setUpTestHive(); +// if (!hiveAdaptersRegistered) { +// hiveAdaptersRegistered = true; +// +// // Registering Transaction Model Adapters +// Hive.registerAdapter(TransactionDataAdapter()); +// Hive.registerAdapter(TransactionChunkAdapter()); +// Hive.registerAdapter(TransactionAdapter()); +// Hive.registerAdapter(InputAdapter()); +// Hive.registerAdapter(OutputAdapter()); +// +// // Registering Utxo Model Adapters +// Hive.registerAdapter(UtxoDataAdapter()); +// Hive.registerAdapter(UtxoObjectAdapter()); +// Hive.registerAdapter(StatusAdapter()); +// +// final wallets = await Hive.openBox('wallets'); +// await wallets.put('currentWalletName', testWalletName); +// } +// +// client = MockElectrumX(); +// cachedClient = MockCachedElectrumX(); +// priceAPI = MockPriceAPI(); +// secureStore = FakeSecureStorage(); +// tracker = MockTransactionNotificationTracker(); +// +// bch = BitcoinCashWallet( +// walletId: testWalletId, +// walletName: testWalletName, +// coin: bchcoin, +// client: client!, +// cachedClient: cachedClient!, +// tracker: tracker!, +// priceAPI: priceAPI, +// secureStore: secureStore, +// ); +// }); +// +// // test("initializeWallet no network", () async { +// // when(client?.ping()).thenAnswer((_) async => false); +// // await Hive.openBox(testWalletId); +// // await Hive.openBox(DB.boxNamePrefs); +// // expect(bch?.initializeNew(), false); +// // expect(secureStore?.interactions, 0); +// // verify(client?.ping()).called(0); +// // verifyNoMoreInteractions(client); +// // verifyNoMoreInteractions(cachedClient); +// // verifyNoMoreInteractions(priceAPI); +// // }); +// +// // test("initializeExisting no network exception", () async { +// // when(client?.ping()).thenThrow(Exception("Network connection failed")); +// // // bch?.initializeNew(); +// // expect(bch?.initializeExisting(), false); +// // expect(secureStore?.interactions, 0); +// // verify(client?.ping()).called(1); +// // verifyNoMoreInteractions(client); +// // verifyNoMoreInteractions(cachedClient); +// // verifyNoMoreInteractions(priceAPI); +// // }); +// +// test("initializeNew mainnet throws bad network", () async { +// when(client?.getServerFeatures()).thenAnswer((_) async => { +// "hosts": {}, +// "pruning": null, +// "server_version": "Unit tests", +// "protocol_min": "1.4", +// "protocol_max": "1.4.2", +// "genesis_hash": GENESIS_HASH_TESTNET, +// "hash_function": "sha256", +// "services": [] +// }); +// +// await Hive.openBox(testWalletId); +// await Hive.openBox(DB.boxNamePrefs); +// +// expectLater(() => bch?.initializeNew(), throwsA(isA())) +// .then((_) { +// expect(secureStore?.interactions, 0); +// verifyNever(client?.ping()).called(0); +// verify(client?.getServerFeatures()).called(1); +// verifyNoMoreInteractions(client); +// verifyNoMoreInteractions(cachedClient); +// verifyNoMoreInteractions(priceAPI); +// }); +// }); +// +// test("initializeNew throws mnemonic overwrite exception", () async { +// when(client?.getServerFeatures()).thenAnswer((_) async => { +// "hosts": {}, +// "pruning": null, +// "server_version": "Unit tests", +// "protocol_min": "1.4", +// "protocol_max": "1.4.2", +// "genesis_hash": GENESIS_HASH_MAINNET, +// "hash_function": "sha256", +// "services": [] +// }); +// await secureStore?.write( +// key: "${testWalletId}_mnemonic", value: "some mnemonic"); +// +// await Hive.openBox(testWalletId); +// await Hive.openBox(DB.boxNamePrefs); +// +// expectLater(() => bch?.initializeNew(), throwsA(isA())) +// .then((_) { +// expect(secureStore?.interactions, 2); +// verifyNever(client?.ping()).called(0); +// verify(client?.getServerFeatures()).called(1); +// verifyNoMoreInteractions(client); +// verifyNoMoreInteractions(cachedClient); +// verifyNoMoreInteractions(priceAPI); +// }); +// }); +// +// test("initializeExisting testnet throws bad network", () async { +// when(client?.ping()).thenAnswer((_) async => true); +// when(client?.getServerFeatures()).thenAnswer((_) async => { +// "hosts": {}, +// "pruning": null, +// "server_version": "Unit tests", +// "protocol_min": "1.4", +// "protocol_max": "1.4.2", +// "genesis_hash": GENESIS_HASH_TESTNET, +// "hash_function": "sha256", +// "services": [] +// }); +// +// bch = BitcoinCashWallet( +// walletId: testWalletId, +// walletName: testWalletName, +// coin: bchcoin, +// client: client!, +// cachedClient: cachedClient!, +// tracker: tracker!, +// priceAPI: priceAPI, +// secureStore: secureStore, +// ); +// +// await Hive.openBox(testWalletId); +// await Hive.openBox(DB.boxNamePrefs); +// +// expectLater(() => bch?.initializeNew(), throwsA(isA())) +// .then((_) { +// expect(secureStore?.interactions, 0); +// verifyNever(client?.ping()).called(0); +// verify(client?.getServerFeatures()).called(1); +// verifyNoMoreInteractions(client); +// verifyNoMoreInteractions(cachedClient); +// verifyNoMoreInteractions(priceAPI); +// }); +// }); +// +// // test("getCurrentNode", () async { +// // // when(priceAPI?.getbitcoincashPrice(baseCurrency: "USD")) +// // // .thenAnswer((realInvocation) async => Decimal.fromInt(10)); +// // when(client?.ping()).thenAnswer((_) async => true); +// // when(client?.getServerFeatures()).thenAnswer((_) async => { +// // "hosts": {}, +// // "pruning": null, +// // "server_version": "Unit tests", +// // "protocol_min": "1.4", +// // "protocol_max": "1.4.2", +// // "genesis_hash": GENESIS_HASH_MAINNET, +// // "hash_function": "sha256", +// // "services": [] +// // }); +// // // await DebugService.instance.init(); +// // expect(bch?.initializeExisting(), true); +// // +// // bool didThrow = false; +// // try { +// // await bch?.getCurrentNode(); +// // } catch (_) { +// // didThrow = true; +// // } +// // // expect no nodes on a fresh wallet unless set in db externally +// // expect(didThrow, true); +// // +// // // set node +// // final wallet = await Hive.openBox(testWalletId); +// // await wallet.put("nodes", { +// // "default": { +// // "id": "some nodeID", +// // "ipAddress": "some address", +// // "port": "9000", +// // "useSSL": true, +// // } +// // }); +// // await wallet.put("activeNodeName", "default"); +// // +// // // try fetching again +// // final node = await bch?.getCurrentNode(); +// // expect(node.toString(), +// // "ElectrumXNode: {address: some address, port: 9000, name: default, useSSL: true}"); +// // +// // verify(client?.ping()).called(1); +// // verify(client?.getServerFeatures()).called(1); +// // verifyNoMoreInteractions(client); +// // verifyNoMoreInteractions(cachedClient); +// // verifyNoMoreInteractions(priceAPI); +// // }); +// +// // test("initializeWallet new main net wallet", () async { +// // when(priceAPI?.getbitcoincashPrice(baseCurrency: "USD")) +// // .thenAnswer((realInvocation) async => Decimal.fromInt(10)); +// // when(client?.ping()).thenAnswer((_) async => true); +// // when(client?.getServerFeatures()).thenAnswer((_) async => { +// // "hosts": {}, +// // "pruning": null, +// // "server_version": "Unit tests", +// // "protocol_min": "1.4", +// // "protocol_max": "1.4.2", +// // "genesis_hash": GENESIS_HASH_MAINNET, +// // "hash_function": "sha256", +// // "services": [] +// // }); +// // expect(await bch?.initializeWallet(), true); +// // +// // final wallet = await Hive.openBox(testWalletId); +// // +// // expect(await wallet.get("addressBookEntries"), {}); +// // expect(await wallet.get('notes'), null); +// // expect(await wallet.get("id"), testWalletId); +// // expect(await wallet.get("preferredFiatCurrency"), null); +// // expect(await wallet.get("blocked_tx_hashes"), ["0xdefault"]); +// // +// // final changeAddressesP2PKH = await wallet.get("changeAddressesP2PKH"); +// // expect(changeAddressesP2PKH, isA>()); +// // expect(changeAddressesP2PKH.length, 1); +// // expect(await wallet.get("changeIndexP2PKH"), 0); +// // +// // final receivingAddressesP2PKH = +// // await wallet.get("receivingAddressesP2PKH"); +// // expect(receivingAddressesP2PKH, isA>()); +// // expect(receivingAddressesP2PKH.length, 1); +// // expect(await wallet.get("receivingIndexP2PKH"), 0); +// // +// // final p2pkhReceiveDerivations = jsonDecode(await secureStore?.read( +// // key: "${testWalletId}_receiveDerivationsP2PKH")); +// // expect(p2pkhReceiveDerivations.length, 1); +// // +// // final p2pkhChangeDerivations = jsonDecode(await secureStore.read( +// // key: "${testWalletId}_changeDerivationsP2PKH")); +// // expect(p2pkhChangeDerivations.length, 1); +// // +// // expect(secureStore?.interactions, 10); +// // expect(secureStore?.reads, 7); +// // expect(secureStore?.writes, 3); +// // expect(secureStore?.deletes, 0); +// // verify(client?.ping()).called(1); +// // verify(client?.getServerFeatures()).called(1); +// // verifyNoMoreInteractions(client); +// // verifyNoMoreInteractions(cachedClient); +// // verifyNoMoreInteractions(priceAPI); +// // }); +// +// // // test("initializeWallet existing main net wallet", () async { +// // // when(priceAPI?.getbitcoincashPrice(baseCurrency: "USD")) +// // // .thenAnswer((realInvocation) async => Decimal.fromInt(10)); +// // // when(client?.ping()).thenAnswer((_) async => true); +// // // when(client?.getBatchHistory(args: anyNamed("args"))) +// // // .thenAnswer((_) async => {}); +// // // when(client?.getServerFeatures()).thenAnswer((_) async => { +// // // "hosts": {}, +// // // "pruning": null, +// // // "server_version": "Unit tests", +// // // "protocol_min": "1.4", +// // // "protocol_max": "1.4.2", +// // // "genesis_hash": GENESIS_HASH_MAINNET, +// // // "hash_function": "sha256", +// // // "services": [] +// // // }); +// // // // init new wallet +// // // expect(bch?.initializeNew(), true); +// // // +// // // // fetch data to compare later +// // // final newWallet = await Hive.openBox(testWalletId); +// // // +// // // final addressBookEntries = await newWallet.get("addressBookEntries"); +// // // final notes = await newWallet.get('notes'); +// // // final wID = await newWallet.get("id"); +// // // final currency = await newWallet.get("preferredFiatCurrency"); +// // // final blockedHashes = await newWallet.get("blocked_tx_hashes"); +// // // +// // // final changeAddressesP2PKH = await newWallet.get("changeAddressesP2PKH"); +// // // final changeIndexP2PKH = await newWallet.get("changeIndexP2PKH"); +// // // +// // // final receivingAddressesP2PKH = +// // // await newWallet.get("receivingAddressesP2PKH"); +// // // final receivingIndexP2PKH = await newWallet.get("receivingIndexP2PKH"); +// // // +// // // final p2pkhReceiveDerivations = jsonDecode(await secureStore?.read( +// // // key: "${testWalletId}_receiveDerivationsP2PKH")); +// // // +// // // final p2pkhChangeDerivations = jsonDecode(await secureStore?.read( +// // // key: "${testWalletId}_changeDerivationsP2PKH")); +// // // +// // // // exit new wallet +// // // await bch?.exit(); +// // // +// // // // open existing/created wallet +// // // bch = BitcoinCashWallet( +// // // walletId: testWalletId, +// // // walletName: testWalletName, +// // // coin: dtestcoin, +// // // client: client!, +// // // cachedClient: cachedClient!, +// // // priceAPI: priceAPI, +// // // secureStore: secureStore, +// // // ); +// // // +// // // // init existing +// // // expect(bch?.initializeExisting(), true); +// // // +// // // // compare data to ensure state matches state of previously closed wallet +// // // final wallet = await Hive.openBox(testWalletId); +// // // +// // // expect(await wallet.get("addressBookEntries"), addressBookEntries); +// // // expect(await wallet.get('notes'), notes); +// // // expect(await wallet.get("id"), wID); +// // // expect(await wallet.get("preferredFiatCurrency"), currency); +// // // expect(await wallet.get("blocked_tx_hashes"), blockedHashes); +// // // +// // // expect(await wallet.get("changeAddressesP2PKH"), changeAddressesP2PKH); +// // // expect(await wallet.get("changeIndexP2PKH"), changeIndexP2PKH); +// // // +// // // expect( +// // // await wallet.get("receivingAddressesP2PKH"), receivingAddressesP2PKH); +// // // expect(await wallet.get("receivingIndexP2PKH"), receivingIndexP2PKH); +// // // +// // // expect( +// // // jsonDecode(await secureStore?.read( +// // // key: "${testWalletId}_receiveDerivationsP2PKH")), +// // // p2pkhReceiveDerivations); +// // // +// // // expect( +// // // jsonDecode(await secureStore?.read( +// // // key: "${testWalletId}_changeDerivationsP2PKH")), +// // // p2pkhChangeDerivations); +// // // +// // // expect(secureStore?.interactions, 12); +// // // expect(secureStore?.reads, 9); +// // // expect(secureStore?.writes, 3); +// // // expect(secureStore?.deletes, 0); +// // // verify(client?.ping()).called(2); +// // // verify(client?.getServerFeatures()).called(1); +// // // verifyNoMoreInteractions(client); +// // // verifyNoMoreInteractions(cachedClient); +// // // verifyNoMoreInteractions(priceAPI); +// // // }); +// +// test("get current receiving addresses", () async { +// bch = BitcoinCashWallet( +// walletId: testWalletId, +// walletName: testWalletName, +// coin: bchtestcoin, +// client: client!, +// cachedClient: cachedClient!, +// tracker: tracker!, +// priceAPI: priceAPI, +// secureStore: secureStore, +// ); +// when(client?.ping()).thenAnswer((_) async => true); +// when(client?.getServerFeatures()).thenAnswer((_) async => { +// "hosts": {}, +// "pruning": null, +// "server_version": "Unit tests", +// "protocol_min": "1.4", +// "protocol_max": "1.4.2", +// "genesis_hash": GENESIS_HASH_TESTNET, +// "hash_function": "sha256", +// "services": [] +// }); +// +// await Hive.openBox(testWalletId); +// await Hive.openBox(DB.boxNamePrefs); +// +// await bch?.initializeNew(); +// await bch?.initializeExisting(); +// expect( +// Address.validateAddress( +// await bch!.currentReceivingAddress, bitcoincashtestnet), +// true); +// expect( +// Address.validateAddress( +// await bch!.currentReceivingAddress, bitcoincashtestnet), +// true); +// expect( +// Address.validateAddress( +// await bch!.currentReceivingAddress, bitcoincashtestnet), +// true); +// +// verifyNever(client?.ping()).called(0); +// verify(client?.getServerFeatures()).called(1); +// verifyNoMoreInteractions(client); +// verifyNoMoreInteractions(cachedClient); +// verifyNoMoreInteractions(priceAPI); +// }); +// +// test("get allOwnAddresses", () async { +// bch = BitcoinCashWallet( +// walletId: testWalletId, +// walletName: testWalletName, +// coin: bchtestcoin, +// client: client!, +// cachedClient: cachedClient!, +// tracker: tracker!, +// priceAPI: priceAPI, +// secureStore: secureStore, +// ); +// when(client?.ping()).thenAnswer((_) async => true); +// when(client?.getServerFeatures()).thenAnswer((_) async => { +// "hosts": {}, +// "pruning": null, +// "server_version": "Unit tests", +// "protocol_min": "1.4", +// "protocol_max": "1.4.2", +// "genesis_hash": GENESIS_HASH_TESTNET, +// "hash_function": "sha256", +// "services": [] +// }); +// +// await Hive.openBox(testWalletId); +// await Hive.openBox(DB.boxNamePrefs); +// +// await bch?.initializeNew(); +// await bch?.initializeExisting(); +// final addresses = await bch?.allOwnAddresses; +// expect(addresses, isA>()); +// expect(addresses?.length, 2); +// +// for (int i = 0; i < 2; i++) { +// expect( +// Address.validateAddress(addresses![i], bitcoincashtestnet), true); +// } +// +// verifyNever(client?.ping()).called(0); +// verify(client?.getServerFeatures()).called(1); +// verifyNoMoreInteractions(client); +// verifyNoMoreInteractions(cachedClient); +// verifyNoMoreInteractions(priceAPI); +// }); +// +// // test("get utxos and balances", () async { +// // bch = BitcoinCashWallet( +// // walletId: testWalletId, +// // walletName: testWalletName, +// // coin: dtestcoin, +// // client: client!, +// // cachedClient: cachedClient!, +// // tracker: tracker!, +// // priceAPI: priceAPI, +// // secureStore: secureStore, +// // ); +// // when(client?.ping()).thenAnswer((_) async => true); +// // when(client?.getServerFeatures()).thenAnswer((_) async => { +// // "hosts": {}, +// // "pruning": null, +// // "server_version": "Unit tests", +// // "protocol_min": "1.4", +// // "protocol_max": "1.4.2", +// // "genesis_hash": GENESIS_HASH_TESTNET, +// // "hash_function": "sha256", +// // "services": [] +// // }); +// // +// // await Hive.openBox(testWalletId); +// // await Hive.openBox(DB.boxNamePrefs); +// // +// // when(client?.getBatchUTXOs(args: anyNamed("args"))) +// // .thenAnswer((_) async => batchGetUTXOResponse0); +// // +// // when(client?.estimateFee(blocks: 20)) +// // .thenAnswer((realInvocation) async => Decimal.zero); +// // when(client?.estimateFee(blocks: 5)) +// // .thenAnswer((realInvocation) async => Decimal.one); +// // when(client?.estimateFee(blocks: 1)) +// // .thenAnswer((realInvocation) async => Decimal.ten); +// // +// // when(cachedClient?.getTransaction( +// // txHash: tx1.txid, +// // coin: Coin.bitcoincashTestNet, +// // )).thenAnswer((_) async => tx1Raw); +// // when(cachedClient?.getTransaction( +// // txHash: tx2.txid, +// // coin: Coin.bitcoincashTestNet, +// // )).thenAnswer((_) async => tx2Raw); +// // when(cachedClient?.getTransaction( +// // txHash: tx3.txid, +// // coin: Coin.bitcoincashTestNet, +// // )).thenAnswer((_) async => tx3Raw); +// // when(cachedClient?.getTransaction( +// // txHash: tx4.txid, +// // coin: Coin.bitcoincashTestNet, +// // )).thenAnswer((_) async => tx4Raw); +// // +// // await bch?.initializeNew(); +// // await bch?.initializeExisting(); +// // +// // final utxoData = await bch?.utxoData; +// // expect(utxoData, isA()); +// // expect(utxoData.toString(), +// // r"{totalUserCurrency: $103.2173, satoshiBalance: 1032173000, bitcoinBalance: null, unspentOutputArray: [{txid: 86198a91805b6c53839a6a97736c434a5a2f85d68595905da53df7df59b9f01a, vout: 0, value: 800000000, fiat: $80, blocked: false, status: {confirmed: true, blockHash: e52cabb4445eb9ceb3f4f8d68cc64b1ede8884ce560296c27826a48ecc477370, blockHeight: 4274457, blockTime: 1655755742, confirmations: 100}}, {txid: a4b6bd97a4b01b4305d0cf02e9bac6b7c37cda2f8e9dfe291ce4170b810ed469, vout: 0, value: 72173000, fiat: $7.2173, blocked: false, status: {confirmed: false, blockHash: bd239f922b3ecec299a90e4d1ce389334e8df4b95470fb5919966b0b650bb95b, blockHeight: 4270459, blockTime: 1655500912, confirmations: 0}}, {txid: 68c159dcc2f962cbc61f7dd3c8d0dcc14da8adb443811107115531c853fc0c60, vout: 1, value: 100000000, fiat: $10, blocked: false, status: {confirmed: false, blockHash: 9fee9b9446cfe81abb1a17bec56e6c160d9a6527e5b68b1141a827573bc2649f, blockHeight: 4255659, blockTime: 1654553247, confirmations: 0}}, {txid: 628a78606058ce4036aee3907e042742156c1894d34419578de5671b53ea5800, vout: 0, value: 60000000, fiat: $6, blocked: false, status: {confirmed: true, blockHash: bc461ab43e3a80d9a4d856ee9ff70f41d86b239d5f0581ffd6a5c572889a6b86, blockHeight: 4270352, blockTime: 1652888705, confirmations: 100}}]}"); +// // +// // final outputs = await bch?.unspentOutputs; +// // expect(outputs, isA>()); +// // expect(outputs?.length, 4); +// // +// // final availableBalance = await bch?.availableBalance; +// // expect(availableBalance, Decimal.parse("8.6")); +// // +// // final totalBalance = await bch?.totalBalance; +// // expect(totalBalance, Decimal.parse("10.32173")); +// // +// // final pendingBalance = await bch?.pendingBalance; +// // expect(pendingBalance, Decimal.parse("1.72173")); +// // +// // final balanceMinusMaxFee = await bch?.balanceMinusMaxFee; +// // expect(balanceMinusMaxFee, Decimal.parse("7.6")); +// // +// // verify(client?.ping()).called(1); +// // verify(client?.getServerFeatures()).called(1); +// // verify(client?.estimateFee(blocks: 1)).called(1); +// // verify(client?.estimateFee(blocks: 5)).called(1); +// // verify(client?.estimateFee(blocks: 20)).called(1); +// // verify(client?.getBatchUTXOs(args: anyNamed("args"))).called(1); +// // verify(cachedClient?.getTransaction( +// // txHash: tx1.txid, +// // coin: Coin.bitcoincashTestNet, +// // )).called(1); +// // verify(cachedClient?.getTransaction( +// // txHash: tx2.txid, +// // coin: Coin.bitcoincashTestNet, +// // )).called(1); +// // verify(cachedClient?.getTransaction( +// // txHash: tx3.txid, +// // coin: Coin.bitcoincashTestNet, +// // )).called(1); +// // verify(cachedClient?.getTransaction( +// // txHash: tx4.txid, +// // coin: Coin.bitcoincashTestNet, +// // )).called(1); +// // +// // verifyNoMoreInteractions(client); +// // verifyNoMoreInteractions(cachedClient); +// // verifyNoMoreInteractions(priceAPI); +// // }); +// // +// // // test("get utxos - multiple batches", () async { +// // // bch = BitcoinCashWallet( +// // // walletId: testWalletId, +// // // walletName: testWalletName, +// // // coin: dtestcoin, +// // // client: client!, +// // // cachedClient: cachedClient!, +// // // priceAPI: priceAPI, +// // // secureStore: secureStore, +// // // ); +// // // when(client?.ping()).thenAnswer((_) async => true); +// // // when(client?.getServerFeatures()).thenAnswer((_) async => { +// // // "hosts": {}, +// // // "pruning": null, +// // // "server_version": "Unit tests", +// // // "protocol_min": "1.4", +// // // "protocol_max": "1.4.2", +// // // "genesis_hash": GENESIS_HASH_TESTNET, +// // // "hash_function": "sha256", +// // // "services": [] +// // // }); +// // // +// // // when(client?.getBatchUTXOs(args: anyNamed("args"))) +// // // .thenAnswer((_) async => {}); +// // // +// // // when(priceAPI?.getbitcoincashPrice(baseCurrency: "USD")) +// // // .thenAnswer((realInvocation) async => Decimal.fromInt(10)); +// // // +// // // await bch?.initializeWallet(); +// // // +// // // // add some extra addresses to make sure we have more than the single batch size of 10 +// // // final wallet = await Hive.openBox(testWalletId); +// // // final addresses = await wallet.get("receivingAddressesP2PKH"); +// // // addresses.add("DQaAi9R58GXMpDyhePys6hHCuif4fhc1sN"); +// // // addresses.add("DBVhuF8QgeuxU2pssxzMgJqPhGCx5qyVkD"); +// // // addresses.add("DCAokB2CXXPWC2JPj6jrK6hxANwTF2m21x"); +// // // addresses.add("D6Y9brE3jUGPrqLmSEWh6yQdgY5b7ZkTib"); +// // // addresses.add("DKdtobt3M5b3kQWZf1zRUZn3Ys6JTQwbPL"); +// // // addresses.add("DBYiFr1BRc2zB19p8jxdSu6DvFGTdWvkVF"); +// // // addresses.add("DE5ffowvbHPzzY6aRVGpzxR2QqikXxUKPG"); +// // // addresses.add("DA97TLg1741J2aLK6z9bVZoWysgQbMR45K"); +// // // addresses.add("DGGmf9q4PKcJXauPRstsFetu9DjW1VSBYk"); +// // // addresses.add("D9bXqnTtufcb6oJyuZniCXbst8MMLzHxUd"); +// // // addresses.add("DA6nv8M4kYL4RxxKrcsPaPUA1KrFA7CTfN"); +// // // await wallet.put("receivingAddressesP2PKH", addresses); +// // // +// // // final utxoData = await bch?.utxoData; +// // // expect(utxoData, isA()); +// // // +// // // final outputs = await bch?.unspentOutputs; +// // // expect(outputs, isA>()); +// // // expect(outputs?.length, 0); +// // // +// // // verify(client?.ping()).called(1); +// // // verify(client?.getServerFeatures()).called(1); +// // // verify(client?.getBatchUTXOs(args: anyNamed("args"))).called(2); +// // // verify(priceAPI?.getbitcoincashPrice(baseCurrency: "USD")).called(1); +// // // +// // // verifyNoMoreInteractions(client); +// // // verifyNoMoreInteractions(cachedClient); +// // // verifyNoMoreInteractions(priceAPI); +// // // }); +// // +// test("get utxos fails", () async { +// bch = BitcoinCashWallet( +// walletId: testWalletId, +// walletName: testWalletName, +// coin: bchtestcoin, +// client: client!, +// cachedClient: cachedClient!, +// tracker: tracker!, +// priceAPI: priceAPI, +// secureStore: secureStore, +// ); +// when(client?.ping()).thenAnswer((_) async => true); +// when(client?.getServerFeatures()).thenAnswer((_) async => { +// "hosts": {}, +// "pruning": null, +// "server_version": "Unit tests", +// "protocol_min": "1.4", +// "protocol_max": "1.4.2", +// "genesis_hash": GENESIS_HASH_TESTNET, +// "hash_function": "sha256", +// "services": [] +// }); +// +// await Hive.openBox(testWalletId); +// await Hive.openBox(DB.boxNamePrefs); +// +// when(client?.getBatchUTXOs(args: anyNamed("args"))) +// .thenThrow(Exception("some exception")); +// +// await bch?.initializeNew(); +// await bch?.initializeExisting(); +// +// final utxoData = await bch?.utxoData; +// expect(utxoData, isA()); +// expect(utxoData.toString(), +// r"{totalUserCurrency: 0.00, satoshiBalance: 0, bitcoinBalance: 0, unspentOutputArray: []}"); +// +// final outputs = await bch?.unspentOutputs; +// expect(outputs, isA>()); +// expect(outputs?.length, 0); +// +// verifyNever(client?.ping()).called(0); +// verify(client?.getServerFeatures()).called(1); +// verify(client?.getBatchUTXOs(args: anyNamed("args"))).called(1); +// +// verifyNoMoreInteractions(client); +// verifyNoMoreInteractions(cachedClient); +// verifyNoMoreInteractions(priceAPI); +// }); +// +// test("chain height fetch, update, and get", () async { +// bch = BitcoinCashWallet( +// walletId: testWalletId, +// walletName: testWalletName, +// coin: bchtestcoin, +// client: client!, +// cachedClient: cachedClient!, +// tracker: tracker!, +// priceAPI: priceAPI, +// secureStore: secureStore, +// ); +// when(client?.ping()).thenAnswer((_) async => true); +// when(client?.getServerFeatures()).thenAnswer((_) async => { +// "hosts": {}, +// "pruning": null, +// "server_version": "Unit tests", +// "protocol_min": "1.4", +// "protocol_max": "1.4.2", +// "genesis_hash": GENESIS_HASH_TESTNET, +// "hash_function": "sha256", +// "services": [] +// }); +// +// await Hive.openBox(testWalletId); +// await Hive.openBox(DB.boxNamePrefs); +// +// await bch?.initializeNew(); +// await bch?.initializeExisting(); +// +// // get stored +// expect(await bch?.storedChainHeight, 0); +// +// // fetch fails +// when(client?.getBlockHeadTip()).thenThrow(Exception("Some exception")); +// expect(await bch?.chainHeight, -1); +// +// // fetch succeeds +// when(client?.getBlockHeadTip()).thenAnswer((realInvocation) async => { +// "height": 100, +// "hex": "some block hex", +// }); +// expect(await bch?.chainHeight, 100); +// +// // update +// await bch?.updateStoredChainHeight(newHeight: 1000); +// +// // fetch updated +// expect(await bch?.storedChainHeight, 1000); +// +// verifyNever(client?.ping()).called(0); +// verify(client?.getServerFeatures()).called(1); +// verify(client?.getBlockHeadTip()).called(2); +// verifyNoMoreInteractions(client); +// verifyNoMoreInteractions(cachedClient); +// verifyNoMoreInteractions(tracker); +// verifyNoMoreInteractions(priceAPI); +// }); +// +// test("getTxCount succeeds", () async { +// when(client?.getHistory( +// scripthash: +// "1df1cab6d109d506aa424b00b6a013c5e1947dc13b78d62b4d0e9f518b3035d1")) +// .thenAnswer((realInvocation) async => [ +// { +// "height": 757727, +// "tx_hash": +// "aaac451c49c2e3bcbccb8a9fded22257eeb94c1702b456171aa79250bc1b20e0" +// }, +// { +// "height": 0, +// "tx_hash": +// "9ac29f35b72ca596bc45362d1f9556b0555e1fb633ca5ac9147a7fd467700afe" +// } +// ]); +// +// final count = +// await bch?.getTxCount(address: "1MMi672ueYFXLLdtZqPe4FsrS46gNDyRq1"); +// +// expect(count, 2); +// +// verify(client?.getHistory( +// scripthash: +// "1df1cab6d109d506aa424b00b6a013c5e1947dc13b78d62b4d0e9f518b3035d1")) +// .called(1); +// +// expect(secureStore?.interactions, 0); +// verifyNoMoreInteractions(client); +// verifyNoMoreInteractions(cachedClient); +// verifyNoMoreInteractions(tracker); +// verifyNoMoreInteractions(priceAPI); +// }); +// //TODO - Needs refactoring +// test("getTxCount fails", () async { +// when(client?.getHistory( +// scripthash: +// "64953f7db441a21172de206bf70b920c8c718ed4f03df9a85073c0400be0053c")) +// .thenThrow(Exception("some exception")); +// +// bool didThrow = false; +// try { +// await bch?.getTxCount(address: "D6biRASajCy7GcJ8R6ZP4RE94fNRerJLCC"); +// } catch (_) { +// didThrow = true; +// } +// expect(didThrow, true); +// +// verifyNever(client?.getHistory( +// scripthash: +// "64953f7db441a21172de206bf70b920c8c718ed4f03df9a85073c0400be0053c")) +// .called(0); +// +// expect(secureStore?.interactions, 0); +// verifyNoMoreInteractions(client); +// verifyNoMoreInteractions(cachedClient); +// verifyNoMoreInteractions(tracker); +// verifyNoMoreInteractions(priceAPI); +// }); +// +// test("_checkCurrentReceivingAddressesForTransactions succeeds", () async { +// when(client?.ping()).thenAnswer((_) async => true); +// when(client?.getServerFeatures()).thenAnswer((_) async => { +// "hosts": {}, +// "pruning": null, +// "server_version": "Unit tests", +// "protocol_min": "1.4", +// "protocol_max": "1.4.2", +// "genesis_hash": GENESIS_HASH_MAINNET, +// "hash_function": "sha256", +// "services": [] +// }); +// when(client?.getHistory(scripthash: anyNamed("scripthash"))) +// .thenAnswer((realInvocation) async => [ +// { +// "height": 4270385, +// "tx_hash": +// "c07f740ad72c0dd759741f4c9ab4b1586a22bc16545584364ac9b3d845766271" +// }, +// { +// "height": 4270459, +// "tx_hash": +// "82da70c660daf4d42abd403795d047918c4021ff1d706b61790cda01a1c5ae5a" +// } +// ]); +// +// await Hive.openBox(testWalletId); +// await Hive.openBox(DB.boxNamePrefs); +// +// await bch?.initializeNew(); +// await bch?.initializeExisting(); +// +// bool didThrow = false; +// try { +// await bch?.checkCurrentReceivingAddressesForTransactions(); +// } catch (_) { +// didThrow = true; +// } +// expect(didThrow, false); +// +// verify(client?.getHistory(scripthash: anyNamed("scripthash"))).called(1); +// verify(client?.getServerFeatures()).called(1); +// verifyNever(client?.ping()).called(0); +// +// expect(secureStore?.interactions, 11); +// expect(secureStore?.reads, 7); +// expect(secureStore?.writes, 4); +// expect(secureStore?.deletes, 0); +// verifyNoMoreInteractions(client); +// verifyNoMoreInteractions(cachedClient); +// verifyNoMoreInteractions(priceAPI); +// }); +// +// test("_checkCurrentReceivingAddressesForTransactions fails", () async { +// when(client?.ping()).thenAnswer((_) async => true); +// when(client?.getServerFeatures()).thenAnswer((_) async => { +// "hosts": {}, +// "pruning": null, +// "server_version": "Unit tests", +// "protocol_min": "1.4", +// "protocol_max": "1.4.2", +// "genesis_hash": GENESIS_HASH_MAINNET, +// "hash_function": "sha256", +// "services": [] +// }); +// when(client?.getHistory(scripthash: anyNamed("scripthash"))) +// .thenThrow(Exception("some exception")); +// +// await Hive.openBox(testWalletId); +// await Hive.openBox(DB.boxNamePrefs); +// +// await bch?.initializeNew(); +// await bch?.initializeExisting(); +// +// bool didThrow = false; +// try { +// await bch?.checkCurrentReceivingAddressesForTransactions(); +// } catch (_) { +// didThrow = true; +// } +// expect(didThrow, true); +// +// verify(client?.getHistory(scripthash: anyNamed("scripthash"))).called(1); +// verify(client?.getServerFeatures()).called(1); +// verifyNever(client?.ping()).called(0); +// +// expect(secureStore?.interactions, 8); +// expect(secureStore?.reads, 5); +// expect(secureStore?.writes, 3); +// expect(secureStore?.deletes, 0); +// verifyNoMoreInteractions(client); +// verifyNoMoreInteractions(cachedClient); +// verifyNoMoreInteractions(priceAPI); +// }); +// +// test("_checkCurrentChangeAddressesForTransactions succeeds", () async { +// when(client?.ping()).thenAnswer((_) async => true); +// when(client?.getServerFeatures()).thenAnswer((_) async => { +// "hosts": {}, +// "pruning": null, +// "server_version": "Unit tests", +// "protocol_min": "1.4", +// "protocol_max": "1.4.2", +// "genesis_hash": GENESIS_HASH_MAINNET, +// "hash_function": "sha256", +// "services": [] +// }); +// when(client?.getHistory(scripthash: anyNamed("scripthash"))) +// .thenAnswer((realInvocation) async => [ +// { +// "height": 4286283, +// "tx_hash": +// "4c119685401e28982283e644c57d84fde6aab83324012e35c9b49e6efd99b49b" +// }, +// { +// "height": 4286295, +// "tx_hash": +// "82da70c660daf4d42abd403795d047918c4021ff1d706b61790cda01a1c5ae5a" +// } +// ]); +// +// await Hive.openBox(testWalletId); +// await Hive.openBox(DB.boxNamePrefs); +// +// await bch?.initializeNew(); +// await bch?.initializeExisting(); +// +// bool didThrow = false; +// try { +// await bch?.checkCurrentChangeAddressesForTransactions(); +// } catch (_) { +// didThrow = true; +// } +// expect(didThrow, false); +// +// verify(client?.getHistory(scripthash: anyNamed("scripthash"))).called(1); +// verify(client?.getServerFeatures()).called(1); +// verifyNever(client?.ping()).called(0); +// +// expect(secureStore?.interactions, 11); +// expect(secureStore?.reads, 7); +// expect(secureStore?.writes, 4); +// expect(secureStore?.deletes, 0); +// verifyNoMoreInteractions(client); +// verifyNoMoreInteractions(cachedClient); +// verifyNoMoreInteractions(tracker); +// verifyNoMoreInteractions(priceAPI); +// }); +// +// test("_checkCurrentChangeAddressesForTransactions fails", () async { +// when(client?.ping()).thenAnswer((_) async => true); +// when(client?.getServerFeatures()).thenAnswer((_) async => { +// "hosts": {}, +// "pruning": null, +// "server_version": "Unit tests", +// "protocol_min": "1.4", +// "protocol_max": "1.4.2", +// "genesis_hash": GENESIS_HASH_MAINNET, +// "hash_function": "sha256", +// "services": [] +// }); +// when(client?.getHistory(scripthash: anyNamed("scripthash"))) +// .thenThrow(Exception("some exception")); +// +// await Hive.openBox(testWalletId); +// await Hive.openBox(DB.boxNamePrefs); +// +// await bch?.initializeNew(); +// await bch?.initializeExisting(); +// +// bool didThrow = false; +// try { +// await bch?.checkCurrentChangeAddressesForTransactions(); +// } catch (_) { +// didThrow = true; +// } +// expect(didThrow, true); +// +// verify(client?.getHistory(scripthash: anyNamed("scripthash"))).called(1); +// verify(client?.getServerFeatures()).called(1); +// verifyNever(client?.ping()).called(0); +// +// expect(secureStore?.interactions, 8); +// expect(secureStore?.reads, 5); +// expect(secureStore?.writes, 3); +// expect(secureStore?.deletes, 0); +// verifyNoMoreInteractions(client); +// verifyNoMoreInteractions(cachedClient); +// verifyNoMoreInteractions(priceAPI); +// }); +// +// // test("getAllTxsToWatch", () async { +// // TestWidgetsFlutterBinding.ensureInitialized(); +// // var notifications = {"show": 0}; +// // const MethodChannel('dexterous.com/flutter/local_notifications') +// // .setMockMethodCallHandler((call) async { +// // notifications[call.method]++; +// // }); +// // +// // bch?.pastUnconfirmedTxs = { +// // "88b7b5077d940dde1bc63eba37a09dec8e7b9dad14c183a2e879a21b6ec0ac1c", +// // "b39bac02b65af46a49e2985278fe24ca00dd5d627395d88f53e35568a04e10fa", +// // }; +// // +// // await bch?.getAllTxsToWatch(transactionData); +// // expect(notifications.length, 1); +// // expect(notifications["show"], 3); +// // +// // expect(bch?.unconfirmedTxs, { +// // "b2f75a017a7435f1b8c2e080a865275d8f80699bba68d8dce99a94606e7b3528", +// // 'dcca229760b44834478f0b266c9b3f5801e0139fdecacdc0820e447289a006d3', +// // }); +// // +// // expect(secureStore?.interactions, 0); +// // verifyNoMoreInteractions(client); +// // verifyNoMoreInteractions(cachedClient); +// // verifyNoMoreInteractions(priceAPI); +// // }); +// // +// // test("refreshIfThereIsNewData true A", () async { +// // when(client?.getTransaction( +// // txHash: +// // "a4b6bd97a4b01b4305d0cf02e9bac6b7c37cda2f8e9dfe291ce4170b810ed469", +// // )).thenAnswer((_) async => tx2Raw); +// // when(client?.getTransaction( +// // txHash: +// // "86198a91805b6c53839a6a97736c434a5a2f85d68595905da53df7df59b9f01a", +// // )).thenAnswer((_) async => tx1Raw); +// // +// // bch = BitcoinCashWallet( +// // walletId: testWalletId, +// // walletName: testWalletName, +// // coin: dtestcoin, +// // client: client!, +// // cachedClient: cachedClient!, +// // priceAPI: priceAPI, +// // secureStore: secureStore, +// // ); +// // final wallet = await Hive.openBox(testWalletId); +// // await wallet.put('receivingAddressesP2PKH', []); +// // +// // await wallet.put('changeAddressesP2PKH', []); +// // +// // bch?.unconfirmedTxs = { +// // "a4b6bd97a4b01b4305d0cf02e9bac6b7c37cda2f8e9dfe291ce4170b810ed469", +// // "86198a91805b6c53839a6a97736c434a5a2f85d68595905da53df7df59b9f01a" +// // }; +// // +// // final result = await bch?.refreshIfThereIsNewData(); +// // +// // expect(result, true); +// // +// // verify(client?.getTransaction( +// // txHash: +// // "a4b6bd97a4b01b4305d0cf02e9bac6b7c37cda2f8e9dfe291ce4170b810ed469", +// // )).called(1); +// // verify(client?.getTransaction( +// // txHash: +// // "86198a91805b6c53839a6a97736c434a5a2f85d68595905da53df7df59b9f01a", +// // )).called(1); +// // +// // expect(secureStore?.interactions, 0); +// // verifyNoMoreInteractions(client); +// // verifyNoMoreInteractions(cachedClient); +// // verifyNoMoreInteractions(priceAPI); +// // }); +// // +// // test("refreshIfThereIsNewData true B", () async { +// // // when(priceAPI.getbitcoincashPrice(baseCurrency: "USD")) +// // // .thenAnswer((_) async => Decimal.fromInt(10)); +// // +// // when(client?.getBatchHistory(args: anyNamed("args"))) +// // .thenAnswer((realInvocation) async { +// // final uuids = Map>.from(realInvocation +// // .namedArguments.values.first as Map) +// // .keys +// // .toList(growable: false); +// // return { +// // uuids[0]: [ +// // { +// // "tx_hash": +// // "351a94874379a5444c8891162472acf66de538a1abc647d4753f3e1eb5ec66f9", +// // "height": 4286305 +// // }, +// // { +// // "tx_hash": +// // "82da70c660daf4d42abd403795d047918c4021ff1d706b61790cda01a1c5ae5a", +// // "height": 4286295 +// // } +// // ], +// // uuids[1]: [ +// // { +// // "tx_hash": +// // "4c119685401e28982283e644c57d84fde6aab83324012e35c9b49e6efd99b49b", +// // "height": 4286283 +// // } +// // ], +// // }; +// // }); +// // +// // when(client?.getTransaction( +// // txHash: +// // "82da70c660daf4d42abd403795d047918c4021ff1d706b61790cda01a1c5ae5a", +// // )).thenAnswer((_) async => tx2Raw); +// // when(client?.getTransaction( +// // txHash: +// // "4c119685401e28982283e644c57d84fde6aab83324012e35c9b49e6efd99b49b", +// // )).thenAnswer((_) async => tx1Raw); +// // +// // when(cachedClient?.getTransaction( +// // txHash: +// // "351a94874379a5444c8891162472acf66de538a1abc647d4753f3e1eb5ec66f9", +// // coin: Coin.bitcoincashTestNet, +// // callOutSideMainIsolate: false)) +// // .thenAnswer((_) async => tx3Raw); +// // when(cachedClient?.getTransaction( +// // txHash: +// // "351a94874379a5444c8891162472acf66de538a1abc647d4753f3e1eb5ec66f9", +// // coin: Coin.bitcoincashTestNet, +// // callOutSideMainIsolate: false)) +// // .thenAnswer((_) async => tx3Raw); +// // when(cachedClient?.getTransaction( +// // txHash: +// // "4c119685401e28982283e644c57d84fde6aab83324012e35c9b49e6efd99b49b", +// // coin: Coin.bitcoincashTestNet, +// // callOutSideMainIsolate: false)) +// // .thenAnswer((_) async => tx1Raw); +// // when(cachedClient?.getTransaction( +// // txHash: +// // "4493caff0e1b4f248e3c6219e7f288cfdb46c32b72a77aec469098c5f7f5154e", +// // coin: Coin.bitcoincashTestNet, +// // callOutSideMainIsolate: false)) +// // .thenAnswer((_) async => tx5Raw); +// // when(cachedClient?.getTransaction( +// // txHash: +// // "e095cbe5531d174c3fc5c9c39a0e6ba2769489cdabdc17b35b2e3a33a3c2fc61", +// // coin: Coin.bitcoincashTestNet, +// // callOutSideMainIsolate: false)) +// // .thenAnswer((_) async => tx6Raw); +// // when(cachedClient?.getTransaction( +// // txHash: +// // "d3054c63fe8cfafcbf67064ec66b9fbe1ac293860b5d6ffaddd39546658b72de", +// // coin: Coin.bitcoincashTestNet, +// // callOutSideMainIsolate: false)) +// // .thenAnswer((_) async => tx7Raw); +// // when(cachedClient?.getTransaction( +// // txHash: +// // "7b34e60cc37306f866667deb67b14096f4ea2add941fd6e2238a639000642b82", +// // coin: Coin.bitcoincashTestNet, +// // callOutSideMainIsolate: false)) +// // .thenAnswer((_) async => tx4Raw); +// // when(cachedClient?.getTransaction( +// // txHash: +// // "a70c6f0690fa84712dc6b3d20ee13862fe015a08cf2dc8949c4300d49c3bdeb5", +// // coin: Coin.bitcoincashTestNet, +// // callOutSideMainIsolate: false)) +// // .thenAnswer((_) async => tx8Raw); +// // +// // bch = BitcoinCashWallet( +// // walletId: testWalletId, +// // walletName: testWalletName, +// // coin: dtestcoin, +// // client: client!, +// // cachedClient: cachedClient!, +// // priceAPI: priceAPI, +// // secureStore: secureStore, +// // ); +// // final wallet = await Hive.openBox(testWalletId); +// // await wallet.put('receivingAddressesP2PKH', []); +// // +// // await wallet.put('changeAddressesP2PKH', []); +// // +// // bch?.unconfirmedTxs = { +// // "82da70c660daf4d42abd403795d047918c4021ff1d706b61790cda01a1c5ae5a", +// // }; +// // +// // final result = await bch?.refreshIfThereIsNewData(); +// // +// // expect(result, true); +// // +// // verify(client?.getBatchHistory(args: anyNamed("args"))).called(2); +// // verify(client?.getTransaction( +// // txHash: +// // "82da70c660daf4d42abd403795d047918c4021ff1d706b61790cda01a1c5ae5a", +// // )).called(1); +// // verify(cachedClient?.getTransaction( +// // txHash: anyNamed("tx_hash"), +// // verbose: true, +// // coin: Coin.bitcoincashTestNet, +// // callOutSideMainIsolate: false)) +// // .called(9); +// // // verify(priceAPI?.getbitcoincashPrice(baseCurrency: "USD")).called(1); +// // +// // expect(secureStore?.interactions, 0); +// // verifyNoMoreInteractions(client); +// // verifyNoMoreInteractions(cachedClient); +// // verifyNoMoreInteractions(priceAPI); +// // }); +// +// // test("refreshIfThereIsNewData false A", () async { +// // // when(priceAPI.getbitcoincashPrice(baseCurrency: "USD")) +// // // .thenAnswer((_) async => Decimal.fromInt(10)); +// // +// // when(client?.getBatchHistory(args: anyNamed("args"))) +// // .thenAnswer((realInvocation) async { +// // final uuids = Map>.from(realInvocation +// // .namedArguments.values.first as Map) +// // .keys +// // .toList(growable: false); +// // return { +// // uuids[0]: [ +// // { +// // "tx_hash": +// // "351a94874379a5444c8891162472acf66de538a1abc647d4753f3e1eb5ec66f9", +// // "height": 4286305 +// // }, +// // { +// // "tx_hash": +// // "82da70c660daf4d42abd403795d047918c4021ff1d706b61790cda01a1c5ae5a", +// // "height": 4286295 +// // } +// // ], +// // uuids[1]: [ +// // { +// // "tx_hash": +// // "4c119685401e28982283e644c57d84fde6aab83324012e35c9b49e6efd99b49b", +// // "height": 4286283 +// // } +// // ], +// // }; +// // }); +// // +// // when(client?.getTransaction( +// // txHash: +// // "82da70c660daf4d42abd403795d047918c4021ff1d706b61790cda01a1c5ae5a", +// // )).thenAnswer((_) async => tx2Raw); +// // when(client?.getTransaction( +// // txHash: +// // "4c119685401e28982283e644c57d84fde6aab83324012e35c9b49e6efd99b49b", +// // )).thenAnswer((_) async => tx1Raw); +// // +// // when(cachedClient?.getTransaction( +// // txHash: +// // "4c119685401e28982283e644c57d84fde6aab83324012e35c9b49e6efd99b49b", +// // coin: Coin.bitcoincashTestNet, +// // callOutSideMainIsolate: false)) +// // .thenAnswer((_) async => tx1Raw); +// // when(cachedClient?.getTransaction( +// // txHash: +// // "82da70c660daf4d42abd403795d047918c4021ff1d706b61790cda01a1c5ae5a", +// // coin: Coin.bitcoincashTestNet, +// // callOutSideMainIsolate: false)) +// // .thenAnswer((_) async => tx2Raw); +// // when(cachedClient?.getTransaction( +// // txHash: +// // "351a94874379a5444c8891162472acf66de538a1abc647d4753f3e1eb5ec66f9", +// // coin: Coin.bitcoincashTestNet, +// // callOutSideMainIsolate: false)) +// // .thenAnswer((_) async => tx3Raw); +// // when(cachedClient?.getTransaction( +// // txHash: +// // "4493caff0e1b4f248e3c6219e7f288cfdb46c32b72a77aec469098c5f7f5154e", +// // coin: Coin.bitcoincashTestNet, +// // callOutSideMainIsolate: false)) +// // .thenAnswer((_) async => tx5Raw); +// // when(cachedClient?.getTransaction( +// // txHash: +// // "7b34e60cc37306f866667deb67b14096f4ea2add941fd6e2238a639000642b82", +// // coin: Coin.bitcoincashTestNet, +// // callOutSideMainIsolate: false)) +// // .thenAnswer((_) async => tx4Raw); +// // when(cachedClient?.getTransaction( +// // txHash: +// // "e095cbe5531d174c3fc5c9c39a0e6ba2769489cdabdc17b35b2e3a33a3c2fc61", +// // coin: Coin.bitcoincashTestNet, +// // callOutSideMainIsolate: false)) +// // .thenAnswer((_) async => tx6Raw); +// // when(cachedClient?.getTransaction( +// // txHash: +// // "d3054c63fe8cfafcbf67064ec66b9fbe1ac293860b5d6ffaddd39546658b72de", +// // coin: Coin.bitcoincashTestNet, +// // callOutSideMainIsolate: false)) +// // .thenAnswer((_) async => tx7Raw); +// // when(cachedClient?.getTransaction( +// // txHash: +// // "a70c6f0690fa84712dc6b3d20ee13862fe015a08cf2dc8949c4300d49c3bdeb5", +// // coin: Coin.bitcoincashTestNet, +// // callOutSideMainIsolate: false)) +// // .thenAnswer((_) async => tx8Raw); +// // +// // bch = BitcoinCashWallet( +// // walletId: testWalletId, +// // walletName: testWalletName, +// // coin: dtestcoin, +// // client: client!, +// // cachedClient: cachedClient!, +// // tracker: tracker!, +// // priceAPI: priceAPI, +// // secureStore: secureStore, +// // ); +// // final wallet = await Hive.openBox(testWalletId); +// // await wallet.put('receivingAddressesP2PKH', []); +// // +// // await wallet.put('changeAddressesP2PKH', []); +// // +// // bch?.unconfirmedTxs = { +// // "82da70c660daf4d42abd403795d047918c4021ff1d706b61790cda01a1c5ae5a", +// // "351a94874379a5444c8891162472acf66de538a1abc647d4753f3e1eb5ec66f9" +// // }; +// // +// // final result = await bch?.refreshIfThereIsNewData(); +// // +// // expect(result, false); +// // +// // verify(client?.getBatchHistory(args: anyNamed("args"))).called(2); +// // verify(client?.getTransaction( +// // txHash: +// // "82da70c660daf4d42abd403795d047918c4021ff1d706b61790cda01a1c5ae5a", +// // )).called(1); +// // verify(cachedClient?.getTransaction( +// // txHash: anyNamed("tx_hash"), +// // verbose: true, +// // coin: Coin.bitcoincashTestNet, +// // callOutSideMainIsolate: false)) +// // .called(15); +// // // verify(priceAPI.getbitcoincashPrice(baseCurrency: "USD")).called(1); +// // +// // expect(secureStore?.interactions, 0); +// // verifyNoMoreInteractions(client); +// // verifyNoMoreInteractions(cachedClient); +// // verifyNoMoreInteractions(priceAPI); +// // }); +// +// // // test("refreshIfThereIsNewData false B", () async { +// // // when(client?.getBatchHistory(args: anyNamed("args"))) +// // // .thenThrow(Exception("some exception")); +// // // +// // // when(client?.getTransaction( +// // // txHash: +// // // "82da70c660daf4d42abd403795d047918c4021ff1d706b61790cda01a1c5ae5a", +// // // )).thenAnswer((_) async => tx2Raw); +// // // +// // // bch = BitcoinCashWallet( +// // // walletId: testWalletId, +// // // walletName: testWalletName, +// // // coin: dtestcoin, +// // // client: client!, +// // // cachedClient: cachedClient!, +// // // tracker: tracker!, +// // // priceAPI: priceAPI, +// // // secureStore: secureStore, +// // // ); +// // // final wallet = await Hive.openBox(testWalletId); +// // // await wallet.put('receivingAddressesP2PKH', []); +// // // +// // // await wallet.put('changeAddressesP2PKH', []); +// // // +// // // bch?.unconfirmedTxs = { +// // // "82da70c660daf4d42abd403795d047918c4021ff1d706b61790cda01a1c5ae5a", +// // // }; +// // // +// // // final result = await bch?.refreshIfThereIsNewData(); +// // // +// // // expect(result, false); +// // // +// // // verify(client?.getBatchHistory(args: anyNamed("args"))).called(1); +// // // verify(client?.getTransaction( +// // // txHash: +// // // "a4b6bd97a4b01b4305d0cf02e9bac6b7c37cda2f8e9dfe291ce4170b810ed469", +// // // )).called(1); +// // // +// // // expect(secureStore?.interactions, 0); +// // // verifyNoMoreInteractions(client); +// // // verifyNoMoreInteractions(cachedClient); +// // // verifyNoMoreInteractions(priceAPI); +// // // }); +// +// test("get mnemonic list", () async { +// when(client?.getServerFeatures()).thenAnswer((_) async => { +// "hosts": {}, +// "pruning": null, +// "server_version": "Unit tests", +// "protocol_min": "1.4", +// "protocol_max": "1.4.2", +// "genesis_hash": GENESIS_HASH_MAINNET, +// "hash_function": "sha256", +// "services": [] +// }); +// +// // when(client?.getBatchHistory(args: anyNamed("args"))) +// // .thenAnswer((thing) async { +// // print(jsonEncode(thing.namedArguments.entries.first.value)); +// // return {}; +// // }); +// +// when(client?.getBatchHistory(args: historyBatchArgs0)) +// .thenAnswer((_) async => emptyHistoryBatchResponse); +// when(client?.getBatchHistory(args: historyBatchArgs1)) +// .thenAnswer((_) async => emptyHistoryBatchResponse); +// +// final wallet = await Hive.openBox(testWalletId); +// +// // add maxNumberOfIndexesToCheck and height +// await bch?.recoverFromMnemonic( +// mnemonic: TEST_MNEMONIC, +// maxUnusedAddressGap: 2, +// maxNumberOfIndexesToCheck: 1000, +// height: 4000); +// +// expect(await bch?.mnemonic, TEST_MNEMONIC.split(" ")); +// // +// verify(client?.getServerFeatures()).called(1); +// verify(client?.getBatchHistory(args: historyBatchArgs0)).called(1); +// verify(client?.getBatchHistory(args: historyBatchArgs1)).called(1); +// +// verifyNoMoreInteractions(client); +// verifyNoMoreInteractions(cachedClient); +// verifyNoMoreInteractions(tracker); +// verifyNoMoreInteractions(priceAPI); +// }); +// +// test( +// "recoverFromMnemonic using empty seed on mainnet fails due to bad genesis hash match", +// () async { +// when(client?.getServerFeatures()).thenAnswer((_) async => { +// "hosts": {}, +// "pruning": null, +// "server_version": "Unit tests", +// "protocol_min": "1.4", +// "protocol_max": "1.4.2", +// "genesis_hash": GENESIS_HASH_TESTNET, +// "hash_function": "sha256", +// "services": [] +// }); +// +// bool hasThrown = false; +// try { +// await bch?.recoverFromMnemonic( +// mnemonic: TEST_MNEMONIC, +// maxUnusedAddressGap: 2, +// maxNumberOfIndexesToCheck: 1000, +// height: 4000); +// } catch (_) { +// hasThrown = true; +// } +// expect(hasThrown, true); +// +// verify(client?.getServerFeatures()).called(1); +// +// expect(secureStore?.interactions, 0); +// verifyNoMoreInteractions(client); +// verifyNoMoreInteractions(cachedClient); +// verifyNoMoreInteractions(priceAPI); +// }); +// +// test( +// "recoverFromMnemonic using empty seed on testnet fails due to bad genesis hash match", +// () async { +// bch = BitcoinCashWallet( +// walletId: testWalletId, +// walletName: testWalletName, +// coin: Coin.bitcoincashTestnet, +// client: client!, +// cachedClient: cachedClient!, +// tracker: tracker!, +// priceAPI: priceAPI, +// secureStore: secureStore, +// ); +// when(client?.getServerFeatures()).thenAnswer((_) async => { +// "hosts": {}, +// "pruning": null, +// "server_version": "Unit tests", +// "protocol_min": "1.4", +// "protocol_max": "1.4.2", +// "genesis_hash": GENESIS_HASH_MAINNET, +// "hash_function": "sha256", +// "services": [] +// }); +// +// bool hasThrown = false; +// try { +// await bch?.recoverFromMnemonic( +// mnemonic: TEST_MNEMONIC, +// maxUnusedAddressGap: 2, +// maxNumberOfIndexesToCheck: 1000, +// height: 4000); +// } catch (_) { +// hasThrown = true; +// } +// expect(hasThrown, true); +// +// verify(client?.getServerFeatures()).called(1); +// +// expect(secureStore?.interactions, 0); +// verifyNoMoreInteractions(client); +// verifyNoMoreInteractions(cachedClient); +// verifyNoMoreInteractions(priceAPI); +// }); +// +// test( +// "recoverFromMnemonic using empty seed on mainnet fails due to attempted overwrite of mnemonic", +// () async { +// when(client?.getServerFeatures()).thenAnswer((_) async => { +// "hosts": {}, +// "pruning": null, +// "server_version": "Unit tests", +// "protocol_min": "1.4", +// "protocol_max": "1.4.2", +// "genesis_hash": GENESIS_HASH_MAINNET, +// "hash_function": "sha256", +// "services": [] +// }); +// +// await secureStore?.write( +// key: "${testWalletId}_mnemonic", value: "some mnemonic words"); +// +// bool hasThrown = false; +// try { +// await bch?.recoverFromMnemonic( +// mnemonic: TEST_MNEMONIC, +// maxUnusedAddressGap: 2, +// maxNumberOfIndexesToCheck: 1000, +// height: 4000); +// } catch (_) { +// hasThrown = true; +// } +// expect(hasThrown, true); +// +// verify(client?.getServerFeatures()).called(1); +// +// expect(secureStore?.interactions, 2); +// verifyNoMoreInteractions(client); +// verifyNoMoreInteractions(cachedClient); +// verifyNoMoreInteractions(priceAPI); +// }); +// +// test("recoverFromMnemonic using non empty seed on mainnet succeeds", +// () async { +// when(client?.getServerFeatures()).thenAnswer((_) async => { +// "hosts": {}, +// "pruning": null, +// "server_version": "Unit tests", +// "protocol_min": "1.4", +// "protocol_max": "1.4.2", +// "genesis_hash": GENESIS_HASH_MAINNET, +// "hash_function": "sha256", +// "services": [] +// }); +// when(client?.getBatchHistory(args: historyBatchArgs0)) +// .thenAnswer((_) async => historyBatchResponse); +// when(client?.getBatchHistory(args: historyBatchArgs1)) +// .thenAnswer((_) async => historyBatchResponse); +// +// final wallet = await Hive.openBox(testWalletId); +// +// bool hasThrown = false; +// try { +// await bch?.recoverFromMnemonic( +// mnemonic: TEST_MNEMONIC, +// maxUnusedAddressGap: 2, +// maxNumberOfIndexesToCheck: 1000, +// height: 4000); +// } catch (_) { +// hasThrown = true; +// } +// expect(hasThrown, false); +// +// verify(client?.getServerFeatures()).called(1); +// verify(client?.getBatchHistory(args: historyBatchArgs0)).called(1); +// verify(client?.getBatchHistory(args: historyBatchArgs1)).called(1); +// +// expect(secureStore?.interactions, 6); +// expect(secureStore?.writes, 3); +// expect(secureStore?.reads, 3); +// expect(secureStore?.deletes, 0); +// +// verifyNoMoreInteractions(client); +// verifyNoMoreInteractions(cachedClient); +// verifyNoMoreInteractions(tracker); +// verifyNoMoreInteractions(priceAPI); +// }); +// +// test("fullRescan succeeds", () async { +// when(client?.getServerFeatures()).thenAnswer((_) async => { +// "hosts": {}, +// "pruning": null, +// "server_version": "Unit tests", +// "protocol_min": "1.4", +// "protocol_max": "1.4.2", +// "genesis_hash": GENESIS_HASH_MAINNET, +// "hash_function": "sha256", +// "services": [] +// }); +// when(client?.getBatchHistory(args: historyBatchArgs0)) +// .thenAnswer((_) async => historyBatchResponse); +// when(client?.getBatchHistory(args: historyBatchArgs1)) +// .thenAnswer((_) async => historyBatchResponse); +// +// when(cachedClient?.clearSharedTransactionCache(coin: Coin.bitcoincash)) +// .thenAnswer((realInvocation) async {}); +// +// final wallet = await Hive.openBox(testWalletId); +// +// // restore so we have something to rescan +// await bch?.recoverFromMnemonic( +// mnemonic: TEST_MNEMONIC, +// maxUnusedAddressGap: 2, +// maxNumberOfIndexesToCheck: 1000, +// height: 4000); +// +// // fetch valid wallet data +// final preReceivingAddressesP2PKH = +// await wallet.get('receivingAddressesP2PKH'); +// final preChangeAddressesP2PKH = await wallet.get('changeAddressesP2PKH'); +// final preReceivingIndexP2PKH = await wallet.get('receivingIndexP2PKH'); +// final preChangeIndexP2PKH = await wallet.get('changeIndexP2PKH'); +// final preUtxoData = await wallet.get('latest_utxo_model'); +// final preReceiveDerivationsStringP2PKH = await secureStore?.read( +// key: "${testWalletId}_receiveDerivationsP2PKH"); +// final preChangeDerivationsStringP2PKH = await secureStore?.read( +// key: "${testWalletId}_changeDerivationsP2PKH"); +// +// // destroy the data that the rescan will fix +// await wallet.put( +// 'receivingAddressesP2PKH', ["some address", "some other address"]); +// await wallet +// .put('changeAddressesP2PKH', ["some address", "some other address"]); +// +// await wallet.put('receivingIndexP2PKH', 123); +// await wallet.put('changeIndexP2PKH', 123); +// await secureStore?.write( +// key: "${testWalletId}_receiveDerivationsP2PKH", value: "{}"); +// await secureStore?.write( +// key: "${testWalletId}_changeDerivationsP2PKH", value: "{}"); +// +// bool hasThrown = false; +// try { +// await bch?.fullRescan(2, 1000); +// } catch (_) { +// hasThrown = true; +// } +// expect(hasThrown, false); +// +// // fetch wallet data again +// final receivingAddressesP2PKH = +// await wallet.get('receivingAddressesP2PKH'); +// final changeAddressesP2PKH = await wallet.get('changeAddressesP2PKH'); +// final receivingIndexP2PKH = await wallet.get('receivingIndexP2PKH'); +// final changeIndexP2PKH = await wallet.get('changeIndexP2PKH'); +// final utxoData = await wallet.get('latest_utxo_model'); +// final receiveDerivationsStringP2PKH = await secureStore?.read( +// key: "${testWalletId}_receiveDerivationsP2PKH"); +// final changeDerivationsStringP2PKH = await secureStore?.read( +// key: "${testWalletId}_changeDerivationsP2PKH"); +// +// expect(preReceivingAddressesP2PKH, receivingAddressesP2PKH); +// expect(preChangeAddressesP2PKH, changeAddressesP2PKH); +// expect(preReceivingIndexP2PKH, receivingIndexP2PKH); +// expect(preChangeIndexP2PKH, changeIndexP2PKH); +// expect(preUtxoData, utxoData); +// expect(preReceiveDerivationsStringP2PKH, receiveDerivationsStringP2PKH); +// expect(preChangeDerivationsStringP2PKH, changeDerivationsStringP2PKH); +// +// verify(client?.getServerFeatures()).called(1); +// verify(client?.getBatchHistory(args: historyBatchArgs0)).called(2); +// verify(client?.getBatchHistory(args: historyBatchArgs1)).called(2); +// verify(cachedClient?.clearSharedTransactionCache(coin: Coin.bitcoincash)) +// .called(1); +// +// expect(secureStore?.writes, 9); +// expect(secureStore?.reads, 12); +// expect(secureStore?.deletes, 2); +// +// verifyNoMoreInteractions(client); +// verifyNoMoreInteractions(cachedClient); +// verifyNoMoreInteractions(tracker); +// verifyNoMoreInteractions(priceAPI); +// }); +// +// test("fullRescan fails", () async { +// when(client?.getServerFeatures()).thenAnswer((_) async => { +// "hosts": {}, +// "pruning": null, +// "server_version": "Unit tests", +// "protocol_min": "1.4", +// "protocol_max": "1.4.2", +// "genesis_hash": GENESIS_HASH_MAINNET, +// "hash_function": "sha256", +// "services": [] +// }); +// +// when(client?.getBatchHistory(args: historyBatchArgs0)) +// .thenAnswer((_) async => historyBatchResponse); +// when(client?.getBatchHistory(args: historyBatchArgs1)) +// .thenAnswer((_) async => historyBatchResponse); +// when(client?.getBatchHistory(args: { +// "0": [ +// "04818da846fe5e03ac993d2e0c1ccc3848ff6073c3aba6a572df4efc5432ae8b" +// ] +// })).thenAnswer((realInvocation) async => {"0": []}); +// +// when(client?.getBatchHistory(args: { +// "0": [ +// "f0c86f888f2aca0efaf1705247dbd1ebc02347c183e197310c9062ea2c9d2e34" +// ] +// })).thenAnswer((realInvocation) async => {"0": []}); +// when(cachedClient?.clearSharedTransactionCache(coin: Coin.dogecoin)) +// .thenAnswer((realInvocation) async {}); +// +// final wallet = await Hive.openBox(testWalletId); +// +// // restore so we have something to rescan +// await bch?.recoverFromMnemonic( +// mnemonic: TEST_MNEMONIC, +// maxUnusedAddressGap: 2, +// maxNumberOfIndexesToCheck: 1000, +// height: 4000); +// +// // fetch wallet data +// final preReceivingAddressesP2PKH = +// await wallet.get('receivingAddressesP2PKH'); +// +// final preChangeAddressesP2PKH = await wallet.get('changeAddressesP2PKH'); +// final preReceivingIndexP2PKH = await wallet.get('receivingIndexP2PKH'); +// final preChangeIndexP2PKH = await wallet.get('changeIndexP2PKH'); +// final preUtxoData = await wallet.get('latest_utxo_model'); +// final preReceiveDerivationsStringP2PKH = await secureStore?.read( +// key: "${testWalletId}_receiveDerivationsP2PKH"); +// final preChangeDerivationsStringP2PKH = await secureStore?.read( +// key: "${testWalletId}_changeDerivationsP2PKH"); +// +// when(client?.getBatchHistory(args: historyBatchArgs0)) +// .thenThrow(Exception("fake exception")); +// +// bool hasThrown = false; +// try { +// await bch?.fullRescan(2, 1000); +// } catch (_) { +// hasThrown = true; +// } +// expect(hasThrown, true); +// +// // fetch wallet data again +// final receivingAddressesP2PKH = +// await wallet.get('receivingAddressesP2PKH'); +// +// final changeAddressesP2PKH = await wallet.get('changeAddressesP2PKH'); +// final receivingIndexP2PKH = await wallet.get('receivingIndexP2PKH'); +// final changeIndexP2PKH = await wallet.get('changeIndexP2PKH'); +// final utxoData = await wallet.get('latest_utxo_model'); +// final receiveDerivationsStringP2PKH = await secureStore?.read( +// key: "${testWalletId}_receiveDerivationsP2PKH"); +// final changeDerivationsStringP2PKH = await secureStore?.read( +// key: "${testWalletId}_changeDerivationsP2PKH"); +// +// expect(preReceivingAddressesP2PKH, receivingAddressesP2PKH); +// expect(preChangeAddressesP2PKH, changeAddressesP2PKH); +// expect(preReceivingIndexP2PKH, receivingIndexP2PKH); +// expect(preChangeIndexP2PKH, changeIndexP2PKH); +// expect(preUtxoData, utxoData); +// expect(preReceiveDerivationsStringP2PKH, receiveDerivationsStringP2PKH); +// expect(preChangeDerivationsStringP2PKH, changeDerivationsStringP2PKH); +// +// verify(client?.getServerFeatures()).called(1); +// verify(client?.getBatchHistory(args: historyBatchArgs0)).called(2); +// verify(client?.getBatchHistory(args: historyBatchArgs1)).called(1); +// verify(cachedClient?.clearSharedTransactionCache(coin: Coin.bitcoincash)) +// .called(1); +// +// expect(secureStore?.writes, 7); +// expect(secureStore?.reads, 12); +// expect(secureStore?.deletes, 4); +// }); +// +// // // test("fetchBuildTxData succeeds", () async { +// // // when(client.getServerFeatures()).thenAnswer((_) async => { +// // // "hosts": {}, +// // // "pruning": null, +// // // "server_version": "Unit tests", +// // // "protocol_min": "1.4", +// // // "protocol_max": "1.4.2", +// // // "genesis_hash": GENESIS_HASH_MAINNET, +// // // "hash_function": "sha256", +// // // "services": [] +// // // }); +// // // when(client.getBatchHistory(args: historyBatchArgs0)) +// // // .thenAnswer((_) async => historyBatchResponse); +// // // when(client.getBatchHistory(args: historyBatchArgs1)) +// // // .thenAnswer((_) async => historyBatchResponse); +// // // when(cachedClient.getTransaction( +// // // tx_hash: +// // // "339dac760e4c9c81ed30a7fde7062785cb20712b18e108accdc39800f884fda9", +// // // coinName: "bitcoincash", +// // // callOutSideMainIsolate: false)) +// // // .thenAnswer((_) async => tx9Raw); +// // // when(cachedClient.getTransaction( +// // // tx_hash: +// // // "c2edf283df75cc2724320b866857a82d80266a59d69ab5a7ca12033adbffa44e", +// // // coinName: "bitcoincash", +// // // callOutSideMainIsolate: false)) +// // // .thenAnswer((_) async => tx10Raw); +// // // when(cachedClient.getTransaction( +// // // tx_hash: +// // // "d0c451513bee7d96cb88824d9d720e6b5b90073721b4985b439687f894c3989c", +// // // coinName: "bitcoincash", +// // // callOutSideMainIsolate: false)) +// // // .thenAnswer((_) async => tx11Raw); +// // // +// // // // recover to fill data +// // // await bch.recoverFromMnemonic( +// // // mnemonic: TEST_MNEMONIC, +// // // maxUnusedAddressGap: 2, +// // // maxNumberOfIndexesToCheck: 1000, +// // // height: 4000); +// // // +// // // // modify addresses to trigger all change code branches +// // // final chg44 = +// // // await secureStore.read(key: testWalletId + "_changeDerivationsP2PKH"); +// // // await secureStore.write( +// // // key: testWalletId + "_changeDerivationsP2PKH", +// // // value: chg44.replaceFirst("1vFHF5q21GccoBwrB4zEUAs9i3Bfx797U", +// // // "D5cQWPnhM3RRJVDz8wWC5jWt3PRCfg1zA6")); +// // // +// // // final data = await bch.fetchBuildTxData(utxoList); +// // // +// // // expect(data.length, 3); +// // // expect( +// // // data["339dac760e4c9c81ed30a7fde7062785cb20712b18e108accdc39800f884fda9"] +// // // .length, +// // // 2); +// // // expect( +// // // data["c2edf283df75cc2724320b866857a82d80266a59d69ab5a7ca12033adbffa44e"] +// // // .length, +// // // 3); +// // // expect( +// // // data["d0c451513bee7d96cb88824d9d720e6b5b90073721b4985b439687f894c3989c"] +// // // .length, +// // // 2); +// // // expect( +// // // data["339dac760e4c9c81ed30a7fde7062785cb20712b18e108accdc39800f884fda9"] +// // // ["output"], +// // // isA()); +// // // expect( +// // // data["c2edf283df75cc2724320b866857a82d80266a59d69ab5a7ca12033adbffa44e"] +// // // ["output"], +// // // isA()); +// // // expect( +// // // data["d0c451513bee7d96cb88824d9d720e6b5b90073721b4985b439687f894c3989c"] +// // // ["output"], +// // // isA()); +// // // expect( +// // // data["339dac760e4c9c81ed30a7fde7062785cb20712b18e108accdc39800f884fda9"] +// // // ["keyPair"], +// // // isA()); +// // // expect( +// // // data["c2edf283df75cc2724320b866857a82d80266a59d69ab5a7ca12033adbffa44e"] +// // // ["keyPair"], +// // // isA()); +// // // expect( +// // // data["d0c451513bee7d96cb88824d9d720e6b5b90073721b4985b439687f894c3989c"] +// // // ["keyPair"], +// // // isA()); +// // // expect( +// // // data["c2edf283df75cc2724320b866857a82d80266a59d69ab5a7ca12033adbffa44e"] +// // // ["redeemScript"], +// // // isA()); +// // // +// // // // modify addresses to trigger all receiving code branches +// // // final rcv44 = await secureStore.read( +// // // key: testWalletId + "_receiveDerivationsP2PKH"); +// // // await secureStore.write( +// // // key: testWalletId + "_receiveDerivationsP2PKH", +// // // value: rcv44.replaceFirst("1RMSPixoLPuaXuhR2v4HsUMcRjLncKDaw", +// // // "D5cQWPnhM3RRJVDz8wWC5jWt3PRCfg1zA6")); +// // // +// // // final data2 = await bch.fetchBuildTxData(utxoList); +// // // +// // // expect(data2.length, 3); +// // // expect( +// // // data2["339dac760e4c9c81ed30a7fde7062785cb20712b18e108accdc39800f884fda9"] +// // // .length, +// // // 2); +// // // expect( +// // // data2["c2edf283df75cc2724320b866857a82d80266a59d69ab5a7ca12033adbffa44e"] +// // // .length, +// // // 3); +// // // expect( +// // // data2["d0c451513bee7d96cb88824d9d720e6b5b90073721b4985b439687f894c3989c"] +// // // .length, +// // // 2); +// // // expect( +// // // data2["339dac760e4c9c81ed30a7fde7062785cb20712b18e108accdc39800f884fda9"] +// // // ["output"], +// // // isA()); +// // // expect( +// // // data2["c2edf283df75cc2724320b866857a82d80266a59d69ab5a7ca12033adbffa44e"] +// // // ["output"], +// // // isA()); +// // // expect( +// // // data2["d0c451513bee7d96cb88824d9d720e6b5b90073721b4985b439687f894c3989c"] +// // // ["output"], +// // // isA()); +// // // expect( +// // // data2["339dac760e4c9c81ed30a7fde7062785cb20712b18e108accdc39800f884fda9"] +// // // ["keyPair"], +// // // isA()); +// // // expect( +// // // data2["c2edf283df75cc2724320b866857a82d80266a59d69ab5a7ca12033adbffa44e"] +// // // ["keyPair"], +// // // isA()); +// // // expect( +// // // data2["d0c451513bee7d96cb88824d9d720e6b5b90073721b4985b439687f894c3989c"] +// // // ["keyPair"], +// // // isA()); +// // // expect( +// // // data2["c2edf283df75cc2724320b866857a82d80266a59d69ab5a7ca12033adbffa44e"] +// // // ["redeemScript"], +// // // isA()); +// // // +// // // verify(client.getServerFeatures()).called(1); +// // // verify(cachedClient.getTransaction( +// // // tx_hash: +// // // "339dac760e4c9c81ed30a7fde7062785cb20712b18e108accdc39800f884fda9", +// // // coinName: "bitcoincash", +// // // callOutSideMainIsolate: false)) +// // // .called(2); +// // // verify(cachedClient.getTransaction( +// // // tx_hash: +// // // "c2edf283df75cc2724320b866857a82d80266a59d69ab5a7ca12033adbffa44e", +// // // coinName: "bitcoincash", +// // // callOutSideMainIsolate: false)) +// // // .called(2); +// // // verify(cachedClient.getTransaction( +// // // tx_hash: +// // // "d0c451513bee7d96cb88824d9d720e6b5b90073721b4985b439687f894c3989c", +// // // coinName: "bitcoincash", +// // // callOutSideMainIsolate: false)) +// // // .called(2); +// // // verify(client.getBatchHistory(args: historyBatchArgs0)).called(1); +// // // verify(client.getBatchHistory(args: historyBatchArgs1)).called(1); +// // // +// // // expect(secureStore.interactions, 38); +// // // expect(secureStore.writes, 13); +// // // expect(secureStore.reads, 25); +// // // expect(secureStore.deletes, 0); +// // // +// // // verifyNoMoreInteractions(client); +// // // verifyNoMoreInteractions(cachedClient); +// // // verifyNoMoreInteractions(priceAPI); +// // // }); +// +// // test("fetchBuildTxData throws", () async { +// // when(client?.getServerFeatures()).thenAnswer((_) async => { +// // "hosts": {}, +// // "pruning": null, +// // "server_version": "Unit tests", +// // "protocol_min": "1.4", +// // "protocol_max": "1.4.2", +// // "genesis_hash": GENESIS_HASH_MAINNET, +// // "hash_function": "sha256", +// // "services": [] +// // }); +// // when(client?.getBatchHistory(args: historyBatchArgs0)) +// // .thenAnswer((_) async => historyBatchResponse); +// // when(client?.getBatchHistory(args: historyBatchArgs1)) +// // .thenAnswer((_) async => historyBatchResponse); +// // when(cachedClient?.getTransaction( +// // txHash: +// // "2087ce09bc316877c9f10971526a2bffa3078d52ea31752639305cdcd8230703", +// // coin: Coin.bitcoincash, +// // callOutSideMainIsolate: false)) +// // .thenAnswer((_) async => tx9Raw); +// // when(cachedClient?.getTransaction( +// // txHash: +// // "ed32c967a0e86d51669ac21c2bb9bc9c50f0f55fbacdd8db21d0a986fba93bd7", +// // coin: Coin.bitcoincash, +// // callOutSideMainIsolate: false)) +// // .thenAnswer((_) async => tx10Raw); +// // when(cachedClient?.getTransaction( +// // txHash: +// // "3f0032f89ac44b281b50314cff3874c969c922839dddab77ced54e86a21c3fd4", +// // coin: Coin.bitcoincash, +// // callOutSideMainIsolate: false)) +// // .thenThrow(Exception("some exception")); +// // +// // // recover to fill data +// // await bch?.recoverFromMnemonic( +// // mnemonic: TEST_MNEMONIC, +// // maxUnusedAddressGap: 2, +// // maxNumberOfIndexesToCheck: 1000, +// // height: 4000); +// // +// // bool didThrow = false; +// // try { +// // await bch?.fetchBuildTxData(utxoList); +// // } catch (_) { +// // didThrow = true; +// // } +// // expect(didThrow, true); +// // +// // verify(client?.getServerFeatures()).called(1); +// // verify(cachedClient?.getTransaction( +// // txHash: +// // "2087ce09bc316877c9f10971526a2bffa3078d52ea31752639305cdcd8230703", +// // coin: Coin.bitcoincash, +// // callOutSideMainIsolate: false)) +// // .called(1); +// // verify(cachedClient?.getTransaction( +// // txHash: +// // "ed32c967a0e86d51669ac21c2bb9bc9c50f0f55fbacdd8db21d0a986fba93bd7", +// // coin: Coin.bitcoincash, +// // callOutSideMainIsolate: false)) +// // .called(1); +// // verify(cachedClient?.getTransaction( +// // txHash: +// // "3f0032f89ac44b281b50314cff3874c969c922839dddab77ced54e86a21c3fd4", +// // coin: Coin.bitcoincash, +// // callOutSideMainIsolate: false)) +// // .called(1); +// // verify(client?.getBatchHistory(args: historyBatchArgs0)).called(1); +// // verify(client?.getBatchHistory(args: historyBatchArgs1)).called(1); +// // +// // expect(secureStore?.interactions, 14); +// // expect(secureStore?.writes, 7); +// // expect(secureStore?.reads, 7); +// // expect(secureStore?.deletes, 0); +// // +// // verifyNoMoreInteractions(client); +// // verifyNoMoreInteractions(cachedClient); +// // verifyNoMoreInteractions(priceAPI); +// // }); +// +// // test("build transaction succeeds", () async { +// // when(client?.getServerFeatures()).thenAnswer((_) async => { +// // "hosts": {}, +// // "pruning": null, +// // "server_version": "Unit tests", +// // "protocol_min": "1.4", +// // "protocol_max": "1.4.2", +// // "genesis_hash": GENESIS_HASH_MAINNET, +// // "hash_function": "sha256", +// // "services": [] +// // }); +// // when(client?.getBatchHistory(args: historyBatchArgs0)) +// // .thenAnswer((_) async => historyBatchResponse); +// // when(client?.getBatchHistory(args: historyBatchArgs1)) +// // .thenAnswer((_) async => historyBatchResponse); +// // when(cachedClient?.getTransaction( +// // txHash: +// // "e9673acb3bfa928f92a7d5a545151a672e9613fdf972f3849e16094c1ed28268", +// // coin: Coin.bitcoincash, +// // callOutSideMainIsolate: false)) +// // .thenAnswer((_) async => tx9Raw); +// // when(cachedClient?.getTransaction( +// // txHash: +// // "fa5bfa4eb581bedb28ca96a65ee77d8e81159914b70d5b7e215994221cc02a63", +// // coin: Coin.bitcoincash, +// // callOutSideMainIsolate: false)) +// // .thenAnswer((_) async => tx10Raw); +// // when(cachedClient?.getTransaction( +// // txHash: +// // "694617f0000499be2f6af5f8d1ddbcf1a70ad4710c0cee6f33a13a64bba454ed", +// // coin: Coin.bitcoincash, +// // callOutSideMainIsolate: false)) +// // .thenAnswer((_) async => tx11Raw); +// // +// // // recover to fill data +// // await bch?.recoverFromMnemonic( +// // mnemonic: TEST_MNEMONIC, +// // maxUnusedAddressGap: 2, +// // maxNumberOfIndexesToCheck: 1000, +// // height: 4000); +// // +// // // modify addresses to properly mock data to build a tx +// // final rcv44 = await secureStore?.read( +// // key: testWalletId + "_receiveDerivationsP2PKH"); +// // await secureStore?.write( +// // key: testWalletId + "_receiveDerivationsP2PKH", +// // value: rcv44?.replaceFirst("1RMSPixoLPuaXuhR2v4HsUMcRjLncKDaw", +// // "D5cQWPnhM3RRJVDz8wWC5jWt3PRCfg1zA6")); +// // +// // final data = await bch?.fetchBuildTxData(utxoList); +// // +// // final txData = await bch?.buildTransaction( +// // utxosToUse: utxoList, +// // utxoSigningData: data!, +// // recipients: ["DS7cKFKdfbarMrYjFBQqEcHR5km6D51c74"], +// // satoshiAmounts: [13000]); +// // +// // expect(txData?.length, 2); +// // expect(txData?["hex"], isA()); +// // expect(txData?["vSize"], isA()); +// // +// // verify(client?.getServerFeatures()).called(1); +// // verify(cachedClient?.getTransaction( +// // txHash: +// // "d3054c63fe8cfafcbf67064ec66b9fbe1ac293860b5d6ffaddd39546658b72de", +// // coin: Coin.bitcoincash, +// // callOutSideMainIsolate: false)) +// // .called(1); +// // verify(cachedClient?.getTransaction( +// // txHash: +// // "fa5bfa4eb581bedb28ca96a65ee77d8e81159914b70d5b7e215994221cc02a63", +// // coin: Coin.bitcoincash, +// // callOutSideMainIsolate: false)) +// // .called(1); +// // verify(cachedClient?.getTransaction( +// // txHash: +// // "694617f0000499be2f6af5f8d1ddbcf1a70ad4710c0cee6f33a13a64bba454ed", +// // coin: Coin.bitcoincash, +// // callOutSideMainIsolate: false)) +// // .called(1); +// // verify(client?.getBatchHistory(args: historyBatchArgs0)).called(1); +// // verify(client?.getBatchHistory(args: historyBatchArgs1)).called(1); +// // +// // expect(secureStore?.interactions, 26); +// // expect(secureStore?.writes, 10); +// // expect(secureStore?.reads, 16); +// // expect(secureStore?.deletes, 0); +// // +// // verifyNoMoreInteractions(client); +// // verifyNoMoreInteractions(cachedClient); +// // verifyNoMoreInteractions(priceAPI); +// // }); +// +// test("confirmSend error 1", () async { +// bool didThrow = false; +// try { +// await bch?.confirmSend(txData: 1); +// } catch (_) { +// didThrow = true; +// } +// +// expect(didThrow, true); +// +// expect(secureStore?.interactions, 0); +// verifyNoMoreInteractions(client); +// verifyNoMoreInteractions(cachedClient); +// verifyNoMoreInteractions(tracker); +// verifyNoMoreInteractions(priceAPI); +// }); +// +// test("confirmSend error 2", () async { +// bool didThrow = false; +// try { +// await bch?.confirmSend(txData: 2); +// } catch (_) { +// didThrow = true; +// } +// +// expect(didThrow, true); +// +// expect(secureStore?.interactions, 0); +// verifyNoMoreInteractions(client); +// verifyNoMoreInteractions(cachedClient); +// verifyNoMoreInteractions(tracker); +// verifyNoMoreInteractions(priceAPI); +// }); +// +// test("confirmSend some other error code", () async { +// bool didThrow = false; +// try { +// await bch?.confirmSend(txData: 42); +// } catch (_) { +// didThrow = true; +// } +// +// expect(didThrow, true); +// +// expect(secureStore?.interactions, 0); +// verifyNoMoreInteractions(client); +// verifyNoMoreInteractions(cachedClient); +// verifyNoMoreInteractions(tracker); +// verifyNoMoreInteractions(priceAPI); +// }); +// +// test("confirmSend no hex", () async { +// bool didThrow = false; +// try { +// await bch?.confirmSend(txData: {"some": "strange map"}); +// } catch (_) { +// didThrow = true; +// } +// +// expect(didThrow, true); +// +// expect(secureStore?.interactions, 0); +// verifyNoMoreInteractions(client); +// verifyNoMoreInteractions(cachedClient); +// verifyNoMoreInteractions(tracker); +// verifyNoMoreInteractions(priceAPI); +// }); +// +// test("confirmSend fails due to vSize being greater than fee", () async { +// bool didThrow = false; +// try { +// await bch +// ?.confirmSend(txData: {"hex": "a string", "fee": 1, "vSize": 10}); +// } catch (_) { +// didThrow = true; +// } +// +// expect(didThrow, true); +// +// verify(client?.broadcastTransaction( +// rawTx: "a string", requestID: anyNamed("requestID"))) +// .called(1); +// +// expect(secureStore?.interactions, 0); +// verifyNoMoreInteractions(client); +// verifyNoMoreInteractions(cachedClient); +// verifyNoMoreInteractions(tracker); +// verifyNoMoreInteractions(priceAPI); +// }); +// +// test("confirmSend fails when broadcast transactions throws", () async { +// when(client?.broadcastTransaction( +// rawTx: "a string", requestID: anyNamed("requestID"))) +// .thenThrow(Exception("some exception")); +// +// bool didThrow = false; +// try { +// await bch +// ?.confirmSend(txData: {"hex": "a string", "fee": 10, "vSize": 10}); +// } catch (_) { +// didThrow = true; +// } +// +// expect(didThrow, true); +// +// verify(client?.broadcastTransaction( +// rawTx: "a string", requestID: anyNamed("requestID"))) +// .called(1); +// +// expect(secureStore?.interactions, 0); +// verifyNoMoreInteractions(client); +// verifyNoMoreInteractions(cachedClient); +// verifyNoMoreInteractions(tracker); +// verifyNoMoreInteractions(priceAPI); +// }); +// +// test("refresh wallet mutex locked", () async { +// when(client?.getServerFeatures()).thenAnswer((_) async => { +// "hosts": {}, +// "pruning": null, +// "server_version": "Unit tests", +// "protocol_min": "1.4", +// "protocol_max": "1.4.2", +// "genesis_hash": GENESIS_HASH_MAINNET, +// "hash_function": "sha256", +// "services": [] +// }); +// when(client?.getBatchHistory(args: historyBatchArgs0)) +// .thenAnswer((_) async => historyBatchResponse); +// when(client?.getBatchHistory(args: historyBatchArgs1)) +// .thenAnswer((_) async => historyBatchResponse); +// when(client?.getBatchHistory(args: { +// "0": [ +// "f0c86f888f2aca0efaf1705247dbd1ebc02347c183e197310c9062ea2c9d2e34" +// ] +// })).thenAnswer((realInvocation) async => {"0": []}); +// +// when(client?.getBatchHistory(args: { +// "0": [ +// "04818da846fe5e03ac993d2e0c1ccc3848ff6073c3aba6a572df4efc5432ae8b" +// ] +// })).thenAnswer((realInvocation) async => {"0": []}); +// +// final wallet = await Hive.openBox(testWalletId); +// // recover to fill data +// await bch?.recoverFromMnemonic( +// mnemonic: TEST_MNEMONIC, +// maxUnusedAddressGap: 2, +// maxNumberOfIndexesToCheck: 1000, +// height: 4000); +// +// bch?.refreshMutex = true; +// +// await bch?.refresh(); +// +// verify(client?.getServerFeatures()).called(1); +// verify(client?.getBatchHistory(args: historyBatchArgs0)).called(1); +// verify(client?.getBatchHistory(args: historyBatchArgs1)).called(1); +// +// expect(secureStore?.interactions, 6); +// expect(secureStore?.writes, 3); +// expect(secureStore?.reads, 3); +// expect(secureStore?.deletes, 0); +// +// verifyNoMoreInteractions(client); +// verifyNoMoreInteractions(cachedClient); +// verifyNoMoreInteractions(tracker); +// verifyNoMoreInteractions(priceAPI); +// }); +// +// test("refresh wallet throws", () async { +// when(client?.getBlockHeadTip()).thenThrow(Exception("some exception")); +// when(client?.getServerFeatures()).thenAnswer((_) async => { +// "hosts": {}, +// "pruning": null, +// "server_version": "Unit tests", +// "protocol_min": "1.4", +// "protocol_max": "1.4.2", +// "genesis_hash": GENESIS_HASH_MAINNET, +// "hash_function": "sha256", +// "services": [] +// }); +// when(client?.getBatchHistory(args: historyBatchArgs0)) +// .thenAnswer((_) async => historyBatchResponse); +// when(client?.getBatchHistory(args: historyBatchArgs1)) +// .thenAnswer((_) async => historyBatchResponse); +// when(client?.getBatchHistory(args: { +// "0": [ +// "f0c86f888f2aca0efaf1705247dbd1ebc02347c183e197310c9062ea2c9d2e34" +// ] +// })).thenAnswer((realInvocation) async => {"0": []}); +// +// when(client?.getBatchHistory(args: { +// "0": [ +// "04818da846fe5e03ac993d2e0c1ccc3848ff6073c3aba6a572df4efc5432ae8b" +// ] +// })).thenAnswer((realInvocation) async => {"0": []}); +// when(client?.getHistory(scripthash: anyNamed("scripthash"))) +// .thenThrow(Exception("some exception")); +// +// final wallet = await Hive.openBox(testWalletId); +// +// // recover to fill data +// await bch?.recoverFromMnemonic( +// mnemonic: TEST_MNEMONIC, +// maxUnusedAddressGap: 2, +// maxNumberOfIndexesToCheck: 1000, +// height: 4000); +// +// await bch?.refresh(); +// +// verify(client?.getServerFeatures()).called(1); +// verify(client?.getBatchHistory(args: historyBatchArgs0)).called(1); +// verify(client?.getBatchHistory(args: historyBatchArgs1)).called(1); +// verify(client?.getBlockHeadTip()).called(1); +// verify(client?.getHistory(scripthash: anyNamed("scripthash"))).called(1); +// +// expect(secureStore?.interactions, 6); +// expect(secureStore?.writes, 3); +// expect(secureStore?.reads, 3); +// expect(secureStore?.deletes, 0); +// +// verifyNoMoreInteractions(client); +// verifyNoMoreInteractions(cachedClient); +// verifyNoMoreInteractions(tracker); +// verifyNoMoreInteractions(priceAPI); +// }); +// +// // test("refresh wallet normally", () async { +// // when(client?.getBlockHeadTip()).thenAnswer((realInvocation) async => +// // {"height": 520481, "hex": "some block hex"}); +// // when(client?.getServerFeatures()).thenAnswer((_) async => { +// // "hosts": {}, +// // "pruning": null, +// // "server_version": "Unit tests", +// // "protocol_min": "1.4", +// // "protocol_max": "1.4.2", +// // "genesis_hash": GENESIS_HASH_MAINNET, +// // "hash_function": "sha256", +// // "services": [] +// // }); +// // when(client?.getBatchHistory(args: historyBatchArgs0)) +// // .thenAnswer((_) async => historyBatchResponse); +// // when(client?.getBatchHistory(args: historyBatchArgs1)) +// // .thenAnswer((_) async => historyBatchResponse); +// // when(client?.getHistory(scripthash: anyNamed("scripthash"))) +// // .thenAnswer((_) async => []); +// // when(client?.estimateFee(blocks: anyNamed("blocks"))) +// // .thenAnswer((_) async => Decimal.one); +// // // when(priceAPI?.getPricesAnd24hChange(baseCurrency: "USD")) +// // // .thenAnswer((_) async => Decimal.one); +// // +// // await Hive.openBox(testWalletId); +// // await Hive.openBox(DB.boxNamePrefs); +// // +// // // recover to fill data +// // await bch?.recoverFromMnemonic( +// // mnemonic: TEST_MNEMONIC, +// // maxUnusedAddressGap: 2, +// // maxNumberOfIndexesToCheck: 1000, +// // height: 4000); +// // +// // when(client?.getBatchHistory(args: anyNamed("args"))) +// // .thenAnswer((_) async => {}); +// // when(client?.getBatchUTXOs(args: anyNamed("args"))) +// // .thenAnswer((_) async => emptyHistoryBatchResponse); +// // +// // await bch?.refresh(); +// // +// // verify(client?.getServerFeatures()).called(1); +// // verify(client?.getBatchHistory(args: historyBatchArgs0)).called(1); +// // verify(client?.getBatchHistory(args: historyBatchArgs1)).called(1); +// // verify(client?.getBatchHistory(args: anyNamed("args"))).called(1); +// // verify(client?.getBatchUTXOs(args: anyNamed("args"))).called(1); +// // verify(client?.getHistory(scripthash: anyNamed("scripthash"))).called(2); +// // verify(client?.estimateFee(blocks: anyNamed("blocks"))).called(3); +// // verify(client?.getBlockHeadTip()).called(1); +// // // verify(priceAPI?.getPricesAnd24hChange(baseCurrency: "USD")).called(2); +// // +// // expect(secureStore?.interactions, 6); +// // expect(secureStore?.writes, 2); +// // expect(secureStore?.reads, 2); +// // expect(secureStore?.deletes, 0); +// // +// // verifyNoMoreInteractions(client); +// // verifyNoMoreInteractions(cachedClient); +// // verifyNoMoreInteractions(priceAPI); +// // }); +// }); +// +// tearDown(() async { +// await tearDownTestHive(); +// }); +// } diff --git a/test/services/coins/bitcoincash/bitcoincash_wallet_test.mocks.dart b/test/services/coins/bitcoincash/bitcoincash_wallet_test.mocks.dart new file mode 100644 index 000000000..fa38e1f9e --- /dev/null +++ b/test/services/coins/bitcoincash/bitcoincash_wallet_test.mocks.dart @@ -0,0 +1,348 @@ +// Mocks generated by Mockito 5.2.0 from annotations +// in stackwallet/test/services/coins/bitcoincash/bitcoincash_wallet_test.dart. +// Do not manually edit this file. + +import 'dart:async' as _i7; + +import 'package:decimal/decimal.dart' as _i4; +import 'package:http/http.dart' as _i3; +import 'package:mockito/mockito.dart' as _i1; +import 'package:stackwallet/electrumx_rpc/cached_electrumx.dart' as _i5; +import 'package:stackwallet/electrumx_rpc/electrumx.dart' as _i6; +import 'package:stackwallet/services/price.dart' as _i9; +import 'package:stackwallet/services/transaction_notification_tracker.dart' + as _i11; +import 'package:stackwallet/utilities/enums/coin_enum.dart' as _i8; +import 'package:stackwallet/utilities/prefs.dart' as _i2; +import 'package:tuple/tuple.dart' as _i10; + +// ignore_for_file: type=lint +// ignore_for_file: avoid_redundant_argument_values +// ignore_for_file: avoid_setters_without_getters +// ignore_for_file: comment_references +// ignore_for_file: implementation_imports +// ignore_for_file: invalid_use_of_visible_for_testing_member +// ignore_for_file: prefer_const_constructors +// ignore_for_file: unnecessary_parenthesis +// ignore_for_file: camel_case_types + +class _FakePrefs_0 extends _i1.Fake implements _i2.Prefs {} + +class _FakeClient_1 extends _i1.Fake implements _i3.Client {} + +class _FakeDecimal_2 extends _i1.Fake implements _i4.Decimal {} + +/// A class which mocks [CachedElectrumX]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockCachedElectrumX extends _i1.Mock implements _i5.CachedElectrumX { + MockCachedElectrumX() { + _i1.throwOnMissingStub(this); + } + + @override + String get server => + (super.noSuchMethod(Invocation.getter(#server), returnValue: '') + as String); + @override + int get port => + (super.noSuchMethod(Invocation.getter(#port), returnValue: 0) as int); + @override + bool get useSSL => + (super.noSuchMethod(Invocation.getter(#useSSL), returnValue: false) + as bool); + @override + _i2.Prefs get prefs => (super.noSuchMethod(Invocation.getter(#prefs), + returnValue: _FakePrefs_0()) as _i2.Prefs); + @override + List<_i6.ElectrumXNode> get failovers => + (super.noSuchMethod(Invocation.getter(#failovers), + returnValue: <_i6.ElectrumXNode>[]) as List<_i6.ElectrumXNode>); + @override + _i7.Future> getAnonymitySet( + {String? groupId, String? blockhash = r'', _i8.Coin? coin}) => + (super.noSuchMethod( + Invocation.method(#getAnonymitySet, [], + {#groupId: groupId, #blockhash: blockhash, #coin: coin}), + returnValue: + Future>.value({})) + as _i7.Future>); + @override + _i7.Future> getTransaction( + {String? txHash, _i8.Coin? coin, bool? verbose = true}) => + (super.noSuchMethod( + Invocation.method(#getTransaction, [], + {#txHash: txHash, #coin: coin, #verbose: verbose}), + returnValue: + Future>.value({})) + as _i7.Future>); + @override + _i7.Future> getUsedCoinSerials( + {_i8.Coin? coin, int? startNumber = 0}) => + (super.noSuchMethod( + Invocation.method(#getUsedCoinSerials, [], + {#coin: coin, #startNumber: startNumber}), + returnValue: Future>.value([])) + as _i7.Future>); + @override + _i7.Future clearSharedTransactionCache({_i8.Coin? coin}) => + (super.noSuchMethod( + Invocation.method(#clearSharedTransactionCache, [], {#coin: coin}), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i7.Future); +} + +/// A class which mocks [PriceAPI]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockPriceAPI extends _i1.Mock implements _i9.PriceAPI { + MockPriceAPI() { + _i1.throwOnMissingStub(this); + } + + @override + _i3.Client get client => (super.noSuchMethod(Invocation.getter(#client), + returnValue: _FakeClient_1()) as _i3.Client); + @override + void resetLastCalledToForceNextCallToUpdateCache() => super.noSuchMethod( + Invocation.method(#resetLastCalledToForceNextCallToUpdateCache, []), + returnValueForMissingStub: null); + @override + _i7.Future>> + getPricesAnd24hChange({String? baseCurrency}) => (super.noSuchMethod( + Invocation.method( + #getPricesAnd24hChange, [], {#baseCurrency: baseCurrency}), + returnValue: + Future>>.value( + <_i8.Coin, _i10.Tuple2<_i4.Decimal, double>>{})) + as _i7.Future>>); +} + +/// A class which mocks [TransactionNotificationTracker]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockTransactionNotificationTracker extends _i1.Mock + implements _i11.TransactionNotificationTracker { + MockTransactionNotificationTracker() { + _i1.throwOnMissingStub(this); + } + + @override + String get walletId => + (super.noSuchMethod(Invocation.getter(#walletId), returnValue: '') + as String); + @override + List get pendings => + (super.noSuchMethod(Invocation.getter(#pendings), returnValue: []) + as List); + @override + List get confirmeds => (super + .noSuchMethod(Invocation.getter(#confirmeds), returnValue: []) + as List); + @override + bool wasNotifiedPending(String? txid) => + (super.noSuchMethod(Invocation.method(#wasNotifiedPending, [txid]), + returnValue: false) as bool); + @override + _i7.Future addNotifiedPending(String? txid) => + (super.noSuchMethod(Invocation.method(#addNotifiedPending, [txid]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i7.Future); + @override + bool wasNotifiedConfirmed(String? txid) => + (super.noSuchMethod(Invocation.method(#wasNotifiedConfirmed, [txid]), + returnValue: false) as bool); + @override + _i7.Future addNotifiedConfirmed(String? txid) => + (super.noSuchMethod(Invocation.method(#addNotifiedConfirmed, [txid]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i7.Future); +} + +/// A class which mocks [ElectrumX]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockElectrumX extends _i1.Mock implements _i6.ElectrumX { + @override + set failovers(List<_i6.ElectrumXNode>? _failovers) => + super.noSuchMethod(Invocation.setter(#failovers, _failovers), + returnValueForMissingStub: null); + @override + int get currentFailoverIndex => + (super.noSuchMethod(Invocation.getter(#currentFailoverIndex), + returnValue: 0) as int); + @override + set currentFailoverIndex(int? _currentFailoverIndex) => super.noSuchMethod( + Invocation.setter(#currentFailoverIndex, _currentFailoverIndex), + returnValueForMissingStub: null); + @override + String get host => + (super.noSuchMethod(Invocation.getter(#host), returnValue: '') as String); + @override + int get port => + (super.noSuchMethod(Invocation.getter(#port), returnValue: 0) as int); + @override + bool get useSSL => + (super.noSuchMethod(Invocation.getter(#useSSL), returnValue: false) + as bool); + @override + _i7.Future request( + {String? command, + List? args = const [], + Duration? connectionTimeout = const Duration(seconds: 60), + String? requestID, + int? retries = 2}) => + (super.noSuchMethod( + Invocation.method(#request, [], { + #command: command, + #args: args, + #connectionTimeout: connectionTimeout, + #requestID: requestID, + #retries: retries + }), + returnValue: Future.value()) as _i7.Future); + @override + _i7.Future>> batchRequest( + {String? command, + Map>? args, + Duration? connectionTimeout = const Duration(seconds: 60), + int? retries = 2}) => + (super.noSuchMethod( + Invocation.method(#batchRequest, [], { + #command: command, + #args: args, + #connectionTimeout: connectionTimeout, + #retries: retries + }), + returnValue: Future>>.value( + >[])) + as _i7.Future>>); + @override + _i7.Future ping({String? requestID, int? retryCount = 1}) => + (super.noSuchMethod( + Invocation.method( + #ping, [], {#requestID: requestID, #retryCount: retryCount}), + returnValue: Future.value(false)) as _i7.Future); + @override + _i7.Future> getBlockHeadTip({String? requestID}) => + (super.noSuchMethod( + Invocation.method(#getBlockHeadTip, [], {#requestID: requestID}), + returnValue: + Future>.value({})) + as _i7.Future>); + @override + _i7.Future> getServerFeatures({String? requestID}) => + (super.noSuchMethod( + Invocation.method(#getServerFeatures, [], {#requestID: requestID}), + returnValue: + Future>.value({})) as _i7 + .Future>); + @override + _i7.Future broadcastTransaction({String? rawTx, String? requestID}) => + (super.noSuchMethod( + Invocation.method(#broadcastTransaction, [], + {#rawTx: rawTx, #requestID: requestID}), + returnValue: Future.value('')) as _i7.Future); + @override + _i7.Future> getBalance( + {String? scripthash, String? requestID}) => + (super.noSuchMethod( + Invocation.method(#getBalance, [], + {#scripthash: scripthash, #requestID: requestID}), + returnValue: + Future>.value({})) + as _i7.Future>); + @override + _i7.Future>> getHistory( + {String? scripthash, String? requestID}) => + (super.noSuchMethod( + Invocation.method(#getHistory, [], + {#scripthash: scripthash, #requestID: requestID}), + returnValue: Future>>.value( + >[])) + as _i7.Future>>); + @override + _i7.Future>>> getBatchHistory( + {Map>? args}) => + (super.noSuchMethod( + Invocation.method(#getBatchHistory, [], {#args: args}), + returnValue: Future>>>.value( + >>{})) as _i7 + .Future>>>); + @override + _i7.Future>> getUTXOs( + {String? scripthash, String? requestID}) => + (super.noSuchMethod( + Invocation.method( + #getUTXOs, [], {#scripthash: scripthash, #requestID: requestID}), + returnValue: Future>>.value( + >[])) as _i7 + .Future>>); + @override + _i7.Future>>> getBatchUTXOs( + {Map>? args}) => + (super.noSuchMethod(Invocation.method(#getBatchUTXOs, [], {#args: args}), + returnValue: Future>>>.value( + >>{})) as _i7 + .Future>>>); + @override + _i7.Future> getTransaction( + {String? txHash, bool? verbose = true, String? requestID}) => + (super.noSuchMethod( + Invocation.method(#getTransaction, [], + {#txHash: txHash, #verbose: verbose, #requestID: requestID}), + returnValue: + Future>.value({})) + as _i7.Future>); + @override + _i7.Future> getAnonymitySet( + {String? groupId = r'1', + String? blockhash = r'', + String? requestID}) => + (super.noSuchMethod( + Invocation.method(#getAnonymitySet, [], { + #groupId: groupId, + #blockhash: blockhash, + #requestID: requestID + }), + returnValue: + Future>.value({})) + as _i7.Future>); + @override + _i7.Future getMintData({dynamic mints, String? requestID}) => + (super.noSuchMethod( + Invocation.method( + #getMintData, [], {#mints: mints, #requestID: requestID}), + returnValue: Future.value()) as _i7.Future); + @override + _i7.Future> getUsedCoinSerials( + {String? requestID, int? startNumber}) => + (super.noSuchMethod( + Invocation.method(#getUsedCoinSerials, [], + {#requestID: requestID, #startNumber: startNumber}), + returnValue: + Future>.value({})) + as _i7.Future>); + @override + _i7.Future getLatestCoinId({String? requestID}) => (super.noSuchMethod( + Invocation.method(#getLatestCoinId, [], {#requestID: requestID}), + returnValue: Future.value(0)) as _i7.Future); + @override + _i7.Future> getFeeRate({String? requestID}) => (super + .noSuchMethod(Invocation.method(#getFeeRate, [], {#requestID: requestID}), + returnValue: + Future>.value({})) as _i7 + .Future>); + @override + _i7.Future<_i4.Decimal> estimateFee({String? requestID, int? blocks}) => + (super.noSuchMethod( + Invocation.method( + #estimateFee, [], {#requestID: requestID, #blocks: blocks}), + returnValue: Future<_i4.Decimal>.value(_FakeDecimal_2())) + as _i7.Future<_i4.Decimal>); + @override + _i7.Future<_i4.Decimal> relayFee({String? requestID}) => (super.noSuchMethod( + Invocation.method(#relayFee, [], {#requestID: requestID}), + returnValue: Future<_i4.Decimal>.value(_FakeDecimal_2())) + as _i7.Future<_i4.Decimal>); +} diff --git a/test/services/coins/namecoin/namecoin_history_sample_data.dart b/test/services/coins/namecoin/namecoin_history_sample_data.dart new file mode 100644 index 000000000..f657129f2 --- /dev/null +++ b/test/services/coins/namecoin/namecoin_history_sample_data.dart @@ -0,0 +1,186 @@ +final Map> historyBatchArgs0 = { + "k_0_0": ["d17132f41b2d55c730db5b27db721020abbd4a5087c15edcccbaa106eef8cbf3"], + "k_0_1": ["cd3dd4abe4f9efc7149ba334d2d6790020331805b0bd5c7ed89a3ac6a22f10b9"], + "k_0_2": ["82a12031d679c9dd3124047742dc22c2c7c03afa9644bddf55d4c95da41bca1c"], + "k_0_3": ["bbe10c5d3c102fd805770ed2d6c5438dce42c04d3f87e3260056d04245b17ddd"], + "k_0_4": ["d9ca5255516f963d8f348911451e2c69489a70dec7f34a4810ee8b0e32fcb04d"], + "k_0_5": ["2284461fd01b17e7443775e39b19f4378a063ff148938d2e4191cea3fd80368d"], + "k_0_6": ["cd3c32fddbf265410c34a58fefcc849b02fc16978d75e501f88f9effcbecd8fe"], + "k_0_7": ["a3bcc0c3c4a140fbcc4c4f4dff18790d8a2d5f868821f47460f68f0426291b57"], + "k_0_8": ["e400f9431798c87ea35ea19b265d9e56a73fd44c239957d9947ae79e16718fb4"], + "k_0_9": ["1fe8bb16b49725bf3703274e205a4695c398e664284cc68d92d15087a54da299"], + "k_0_10": [ + "2fabf8d61308c8b2d914489a9f02f669ed9fa68047666815cf1f3cd1bb5d8819" + ], + "k_0_11": ["42a567d344189430afe7d45d6854ef6e9d256d9ef4186afd31a1a5ff90a6a0dd"] +}; +final Map> historyBatchArgs1 = { + "k_0_0": ["bcf7aec7c10dfba33ce80149300a7c4fe66460c1dd05503b5df5780884498186"], + "k_0_1": ["587943864cefed4f1643a5ee2ce2b3c13a0c6ad7c435373f0ac328e144a15c1e"], + "k_0_2": ["fe6ad514f7427782f964b25995a90a3233589904b88f66a2d0e73e2560c9af7c"], + "k_0_3": ["6b962c5f9b4cfc004c74c5ab849304c405b02fc0e2f34ee17c185984f13c9da4"], + "k_0_4": ["720b79fab9a163ce6534828e8a673c5bf600161eba92c2b81555e79add59994c"], + "k_0_5": ["a10f4cf239abd4bcdb03dbe40b5c1d57ae3a7982adf8f177d481feb0ad3a52cd"], + "k_0_6": ["061f28e17ba1a56404b08a5899163011c7d6317e534ccd8e4d38911574f574b0"], + "k_0_7": ["ffc6297d487a13cb80689c448a3aef16cbd367a503d236d0aebd7218cc568e88"], + "k_0_8": ["f4a6c41fc432300509f97ca68db3b9d802d29f90c35a429e3886c480cdce44a2"], + "k_0_9": ["52f3bf96d02cd7e8c631b8ef36262994a3ec658427b930197ed004c8599cd7fd"], + "k_0_10": [ + "7993aef51bebe79bae2d29b775c499f390e99fdb6b9accb8034f657b6e72927a" + ], + "k_0_11": ["430214c9805d90c6a8c4489187db08157a93e60509e96b518dc8b5ba3d567206"] +}; +final Map> historyBatchArgs2 = { + "k_0_0": ["afe5085dd514032810d5b266007557ba8a0f4bee84535cb10754c6d46ab8689b"], + "k_0_1": ["dd63fc12f5e6c1ada2cf3c941d1648e6d561ce4024747bb2117d72112d83287c"], + "k_0_2": ["e65d4274e8edc5cc1e7b676652e2e13b0b00648d15cf13caa982ecd6a67731ba"], + "k_0_3": ["6c69ca274f7d7f2fae882a87bcee93d9429328995c5bc6b326b548b4cefcaa9f"], + "k_0_4": ["86f1a5e17dc42c27cdb0dff8a41c2434575ab05ed2f3689fd7b674677e5ea446"], + "k_0_5": ["a5d9b8df5b80c56e6053497a8c89a37267010926e80e0d225a019b78673a7aa7"], + "k_0_6": ["a0030024518874720b82b38d965fb5b3083d9f42fab40e6be4797c789eeb06f2"], + "k_0_7": ["f20077f7c6a6b92a1f75bbbad8dbece9ae4609cfdfc85e40ccac7d463bdfd6e0"], + "k_0_8": ["07b7bb4020c377e0741587efe9c0b3931e2e45f667bc6f1fa81a8f15fbe86ce4"], + "k_0_9": ["ca0322fc293f6e4d8c8adac178ed4aaedbd9acd2ec84acaaf1529f9ab7bda6d2"], + "k_0_10": [ + "06df1d13aa43375775d7d2838595a0c4c642f8af15b06a99d5115d9236e9a79e" + ], + "k_0_11": ["1a146c5a8dd5bf49faca3c6f65c9d955d361c6c00893c48d69cf7ff42c7b387b"] +}; + +final Map> historyBatchArgs3 = { + "k_0_0": ["5c2c77a3671417c5831c336805770344b81e6c7ef0d873c986ba65a7bacd5f68"], + "k_0_1": ["c068e7fa4aa0b8a63114f6d11c047ca4be6a8fa333eb0dac48506e8f150af73b"], + "k_0_2": ["f430c440e90c48b9e4c7e5356083e7c1495b7cad53f39ebba64cca9fb3d05c82"], + "k_0_3": ["30a7ac6789383f7f6def9a927f3b6fb661cf9406fec71a1d118c7d86052382fb"], + "k_0_4": ["a797225a9155417ab18e16b9d7ce9bf4962ae5c05df572a33c60b36a0523f257"], + "k_0_5": ["24d1e3ac9e53727d943688e67eb5c000d993e9c3cf9585d630624197fb73bed3"], + "k_0_6": ["d667a44404519649cb65632d6a3be948a1f0971025c96cb4211943d301fe0d3e"], + "k_0_7": ["be8da400f004546b528fb989c14a88324b8b0c2d5680cf080ae1e1dac4401f68"], + "k_0_8": ["addfa7682c0a2461ab0e82b3c9302b38986b442a1a76c3c839b6c2f0eaa805fe"], + "k_0_9": ["98bb3aab55f4f305fd9994334b8dd3321eda50b25fad2ef3e636714b650d0bb0"], + "k_0_10": [ + "bee1eee20d7169d03ce68d340a17f4598f589920513ec19c458db45399639a9f" + ], + "k_0_11": ["928a988dd65d100d1677a0478abfcd4d2a70aabb0812c58a2b1b4b51c395ed54"] +}; + +final Map> historyBatchArgs4 = { + "k_0_0": ["6bbfd9c1c28d6984646db4736196f67f2d1075894bb1d8990294ca7d663bece6"], + "k_0_1": ["42d6e40636f4740f9c7f95ef0bbc2a4c17f54da2bc98a32a622e2bf73eb675c3"], + "k_0_2": ["191c977174dc50a57628aea6684c428d3a5e90bbe16c4e412be51b0cfc589d38"], + "k_0_3": ["0daaf61564fd07a25ef106d958216992896f931f5bed4fbf56cc3f94443dc164"], + "k_0_4": ["ac5aca40fed2903def31c9ef1d60874247cdcc5b85238c7a1d83c67d2924d6b9"], + "k_0_5": ["c4102ff0556d863b4bab9d8232fe1f0c0fde4b6e4fe23064b4ecd0958f9726cc"], + "k_0_6": ["1c4bd1554e4992e5914dcd8f3e13927ffd46302dfdcbd2dca0cfd47c040c4256"], + "k_0_7": ["eaf5562ebef7cafa58e2c1fc4ae023e5ae8dd71ee637b08c4bc7e274e401a9a4"], + "k_0_8": ["06f7f55c221fee1b36284b5360155b8380cb9d7172b7e28eb37c61b7ebb6f227"], + "k_0_9": ["7e7ca801131ec1c5797f2c4aa46908ee50e9958cf1cbf53c2481d110800c3d6d"], + "k_0_10": [ + "3895e073aa034add7d2589bfdd1e54f6b9a8d7688d63fff0c3aac7950c6f9697" + ], + "k_0_11": ["ec17dd7c4fe8fbcfce94e9237d3c7ed7f5c91a45b1a060406e206df7e814b006"] +}; + +final Map> historyBatchArgs5 = { + "k_0_0": ["83b744ccb88827d544081c1a03ea782a7d00d6224ff9fddb7d0fbad399e1cae7"], + "k_0_1": ["86906979fc9107d06d560275d7de8305b69d7189c3206ac9070ad76e6abff874"], + "k_0_2": ["5baba32b1899d5e740838559ef39b7d8e9ba302bd24b732eeedd4c0e6ec65b51"], + "k_0_3": ["9892eb48394b0e155f63879fb89c3b068fcc071fed2e5cb11fe0729b85b53d67"], + "k_0_4": ["64192782cdaecb5e2a871a2d0fb3f541873e4750cd4e7d28e4d858ab40664a36"], + "k_0_5": ["4047ff48e96d25628acfeaec6ca75c1a668c54fd70a14414827cb59976a3b666"], + "k_0_6": ["299e8bc634ef6438c5bf99c12c2340c77c56ab974ffd767e77c17994e5cfaef8"], + "k_0_7": ["ab649fa14452563b385eb025e0b4cf2dd869c02fcdf2ec0f72725bbe2adaa3bd"], + "k_0_8": ["6be1ca4f8ee923e32137b6cdae324b841a0a60afbee4f4ae457fe31f29e001a6"], + "k_0_9": ["2a99ceea87df667135cc1801682d2c5dc7b95b7efadc48e156345ba46f4c0dc6"], + "k_0_10": [ + "9304094916a19040d3c8f10df90dae1144d1f09ac9e676e66bb76341c70388ac" + ], + "k_0_11": ["01b12fb2ea2533226471dfa863133ce390e3e13a804734e8af995a45aa7c7582"] +}; + +final Map>> historyBatchResponse = { + "k_0_0": [], + "s_0_0": [{}, {}], + "w_0_0": [], + "k_0_1": [{}], + "s_0_1": [], + "w_0_1": [{}, {}, {}], + "k_0_2": [], + "s_0_2": [], + "w_0_2": [], + "k_0_3": [], + "s_0_3": [], + "w_0_3": [], + "k_0_4": [], + "s_0_4": [], + "w_0_4": [], + "k_0_5": [], + "s_0_5": [], + "w_0_5": [], + "k_0_6": [], + "s_0_6": [], + "w_0_6": [], + "k_0_7": [], + "s_0_7": [], + "w_0_7": [], + "k_0_8": [], + "s_0_8": [], + "w_0_8": [], + "k_0_9": [], + "s_0_9": [], + "w_0_9": [], + "k_0_10": [], + "s_0_10": [], + "w_0_10": [], + "k_0_11": [], + "s_0_11": [], + "w_0_11": [] +}; + +final Map>> emptyHistoryBatchResponse = { + "k_0_0": [], + "s_0_0": [], + "w_0_0": [], + "k_0_1": [], + "s_0_1": [], + "w_0_1": [], + "k_0_2": [], + "s_0_2": [], + "w_0_2": [], + "k_0_3": [], + "s_0_3": [], + "w_0_3": [], + "k_0_4": [], + "s_0_4": [], + "w_0_4": [], + "k_0_5": [], + "s_0_5": [], + "w_0_5": [], + "k_0_6": [], + "s_0_6": [], + "w_0_6": [], + "k_0_7": [], + "s_0_7": [], + "w_0_7": [], + "k_0_8": [], + "s_0_8": [], + "w_0_8": [], + "k_0_9": [], + "s_0_9": [], + "w_0_9": [], + "k_0_10": [], + "s_0_10": [], + "w_0_10": [], + "k_0_11": [], + "s_0_11": [], + "w_0_11": [] +}; + +final List activeScriptHashes = [ + "dd63fc12f5e6c1ada2cf3c941d1648e6d561ce4024747bb2117d72112d83287c", + "587943864cefed4f1643a5ee2ce2b3c13a0c6ad7c435373f0ac328e144a15c1e", + "cd3dd4abe4f9efc7149ba334d2d6790020331805b0bd5c7ed89a3ac6a22f10b9", + "86906979fc9107d06d560275d7de8305b69d7189c3206ac9070ad76e6abff874", + "c068e7fa4aa0b8a63114f6d11c047ca4be6a8fa333eb0dac48506e8f150af73b", + "42d6e40636f4740f9c7f95ef0bbc2a4c17f54da2bc98a32a622e2bf73eb675c3" +]; diff --git a/test/services/coins/namecoin/namecoin_transaction_data_samples.dart b/test/services/coins/namecoin/namecoin_transaction_data_samples.dart new file mode 100644 index 000000000..2199cfcc3 --- /dev/null +++ b/test/services/coins/namecoin/namecoin_transaction_data_samples.dart @@ -0,0 +1,355 @@ +import 'package:stackwallet/models/paymint/transactions_model.dart'; + +final transactionData = TransactionData.fromMap({ + "3ef543d0887c3e9f9924f1b2d3b21410d0238937364663ed3414a2c2ddf4ccc6": tx1, + "dffa9543852197f9fb90f8adafaab8a0b9b4925e9ada8c6bdcaf00bf2e9f60d7": tx2, + "71b56532e9e7321bd8c30d0f8b14530743049d2f3edd5623065c46eee1dda04d": tx3, + "c7e700f7e23a85bbdd9de86d502322a933607ee7ea7e16adaf02e477cdd849b9": tx4, +}); + +final tx1 = Transaction( + txid: "3ef543d0887c3e9f9924f1b2d3b21410d0238937364663ed3414a2c2ddf4ccc6", + confirmedStatus: true, + confirmations: 212, + txType: "Received", + amount: 1000000, + fees: 23896, + height: 629633, + address: "nc1qwfda4s9qmdqpnykgpjf85n09ath983srtuxcqx", + timestamp: 1663093275, + worthNow: "0.00", + worthAtBlockTimestamp: "0.00", + inputSize: 2, + outputSize: 2, + inputs: [ + Input( + txid: "290904699ccbebd0921c4acc4f7a10f41141ee6a07bc64ebca5674c1e5ee8dfa", + vout: 1, + ), + Input( + txid: "bd84ae7e09414b0ccf5dcbf70a1f89f2fd42119a98af35dd4ecc80210fed0487", + vout: 0, + ), + ], + outputs: [ + Output( + scriptpubkeyAddress: "nc1qwfda4s9qmdqpnykgpjf85n09ath983srtuxcqx", + value: 1000000, + ), + Output( + scriptpubkeyAddress: "nc1qp7h7fxcnkqcpul202z6nh8yjy8jpt39jcpeapj", + value: 29853562, + ) + ], +); + +final tx2 = Transaction( + txid: "dffa9543852197f9fb90f8adafaab8a0b9b4925e9ada8c6bdcaf00bf2e9f60d7", + confirmedStatus: true, + confirmations: 150, + txType: "Sent", + amount: 988567, + fees: 11433, + height: 629695, + address: "nc1qraffwaq3cxngwp609e03ynwsx8ykgjnjve9f3y", + timestamp: 1663142110, + worthNow: "0.00", + worthAtBlockTimestamp: "0.00", + inputSize: 1, + outputSize: 1, + inputs: [ + Input( + txid: "3ef543d0887c3e9f9924f1b2d3b21410d0238937364663ed3414a2c2ddf4ccc6", + vout: 0, + ), + ], + outputs: [ + Output( + scriptpubkeyAddress: "nc1qraffwaq3cxngwp609e03ynwsx8ykgjnjve9f3y", + value: 988567, + ), + ], +); + +final tx3 = Transaction( + txid: "71b56532e9e7321bd8c30d0f8b14530743049d2f3edd5623065c46eee1dda04d", + confirmedStatus: true, + confirmations: 147, + txType: "Received", + amount: 988567, + fees: 11433, + height: 629699, + address: "nc1qw4srwqq2semrxje4x6zcrg53g07q0pr3yqv5kr", + timestamp: 1663145287, + worthNow: "0.00", + worthAtBlockTimestamp: "0.00", + inputSize: 2, + outputSize: 1, + inputs: [ + Input( + txid: "dffa9543852197f9fb90f8adafaab8a0b9b4925e9ada8c6bdcaf00bf2e9f60d7", + vout: 0, + ), + Input( + txid: "80f8c6de5be2243013348219bbb7043a6d8d00ddc716baf6a69eab517f9a6fc1", + vout: 1, + ), + ], + outputs: [ + Output( + scriptpubkeyAddress: "nc1qw4srwqq2semrxje4x6zcrg53g07q0pr3yqv5kr", + value: 1000000, + ), + Output( + scriptpubkeyAddress: "nc1qsgr7u4hd22rc64r9vlef69en9wzlvmjt8dzyrm", + value: 28805770, + ), + ], +); + +final tx4 = Transaction( + txid: "c7e700f7e23a85bbdd9de86d502322a933607ee7ea7e16adaf02e477cdd849b9", + confirmedStatus: true, + confirmations: 130, + txType: "Sent", + amount: 988567, + fees: 11433, + height: 629717, + address: "nc1qmdt0fxhpwx7x5ymmm9gvh229adu0kmtukfcsjk", + timestamp: 1663155739, + worthNow: "0.00", + worthAtBlockTimestamp: "0.00", + inputSize: 1, + outputSize: 1, + inputs: [ + Input( + txid: "71b56532e9e7321bd8c30d0f8b14530743049d2f3edd5623065c46eee1dda04d", + vout: 0, + ), + ], + outputs: [ + Output( + scriptpubkeyAddress: "nc1qmdt0fxhpwx7x5ymmm9gvh229adu0kmtukfcsjk", + value: 988567, + ), + ], +); + +final tx1Raw = { + "txid": "3ef543d0887c3e9f9924f1b2d3b21410d0238937364663ed3414a2c2ddf4ccc6", + "hash": "40c8dd876cf111dc00d3aa2fedc93a77c18b391931939d4f99a760226cbff675", + "version": 2, + "size": 394, + "vsize": 232, + "weight": 925, + "locktime": 0, + "vin": [ + { + "txid": + "290904699ccbebd0921c4acc4f7a10f41141ee6a07bc64ebca5674c1e5ee8dfa", + "vout": 1, + "scriptSig": { + "asm": "001466d2173325f3d379c6beb0a4949e937308edb152", + "hex": "16001466d2173325f3d379c6beb0a4949e937308edb152" + }, + "txinwitness": [ + "3044022062d0f32dc051ed1e91889a96070121c77d895f69d2ed5a307d8b320e0352186702206a0c2613e708e5ef8a935aba61b8fa14ddd6ca4e9a80a8b4ded126a879217dd101", + "0303cd92ed121ef22398826af055f3006769210e019f8fb43bd2f5556282d84997" + ], + "sequence": 4294967295 + }, + { + "txid": + "bd84ae7e09414b0ccf5dcbf70a1f89f2fd42119a98af35dd4ecc80210fed0487", + "vout": 0, + "scriptSig": {"asm": "", "hex": ""}, + "txinwitness": [ + "3045022100e8814706766a2d7588908c51209c3b7095241bbc681febdd6b317b7e9b6ea97502205c33c63e4d8a675c19122bfe0057afce2159e6bd86f2c9aced214de77099dc8b01", + "03c35212e3a4c0734735eccae9219987dc78d9cf6245ab247942d430d0a01d61be" + ], + "sequence": 4294967295 + } + ], + "vout": [ + { + "value": 0.01, + "n": 0, + "scriptPubKey": { + "asm": "0 725bdac0a0db401992c80c927a4de5eaee53c603", + "hex": "0014725bdac0a0db401992c80c927a4de5eaee53c603", + "reqSigs": 1, + "type": "witness_v0_keyhash", + "addresses": ["nc1qwfda4s9qmdqpnykgpjf85n09ath983srtuxcqx"] + } + }, + { + "value": 0.29853562, + "n": 1, + "scriptPubKey": { + "asm": "0 0fafe49b13b0301e7d4f50b53b9c9221e415c4b2", + "hex": "00140fafe49b13b0301e7d4f50b53b9c9221e415c4b2", + "reqSigs": 1, + "type": "witness_v0_keyhash", + "addresses": ["nc1qp7h7fxcnkqcpul202z6nh8yjy8jpt39jcpeapj"] + } + } + ], + "hex": + "02000000000102fa8deee5c17456caeb64bc076aee4111f4107a4fcc4a1c92d0ebcb9c69040929010000001716001466d2173325f3d379c6beb0a4949e937308edb152ffffffff8704ed0f2180cc4edd35af989a1142fdf2891f0af7cb5dcf0c4b41097eae84bd0000000000ffffffff0240420f0000000000160014725bdac0a0db401992c80c927a4de5eaee53c6037a87c701000000001600140fafe49b13b0301e7d4f50b53b9c9221e415c4b202473044022062d0f32dc051ed1e91889a96070121c77d895f69d2ed5a307d8b320e0352186702206a0c2613e708e5ef8a935aba61b8fa14ddd6ca4e9a80a8b4ded126a879217dd101210303cd92ed121ef22398826af055f3006769210e019f8fb43bd2f5556282d8499702483045022100e8814706766a2d7588908c51209c3b7095241bbc681febdd6b317b7e9b6ea97502205c33c63e4d8a675c19122bfe0057afce2159e6bd86f2c9aced214de77099dc8b012103c35212e3a4c0734735eccae9219987dc78d9cf6245ab247942d430d0a01d61be00000000", + "blockhash": + "c9f53cc7cbf654cbcc400e17b33e03a32706d6e6647ad7085c688540f980a378", + "confirmations": 212, + "time": 1663093275, + "blocktime": 1663093275 +}; + +final tx2Raw = { + "txid": "dffa9543852197f9fb90f8adafaab8a0b9b4925e9ada8c6bdcaf00bf2e9f60d7", + "hash": "32dbc0d21327e0cb94ec6069a8d235affd99689ffc5f68959bfb720bafc04bcf", + "version": 2, + "size": 192, + "vsize": 110, + "weight": 438, + "locktime": 0, + "vin": [ + { + "txid": + "3ef543d0887c3e9f9924f1b2d3b21410d0238937364663ed3414a2c2ddf4ccc6", + "vout": 0, + "scriptSig": {"asm": "", "hex": ""}, + "txinwitness": [ + "30450221009d58ebfaab8eae297910bca93a7fd48f94ce52a1731cf27fb4c043368fa10e8d02207e88f5d868113d9567999793be0a5b752ad704d04224046839763cefe46463a501", + "02f6ca5274b59dfb014f6a0d690671964290dac7f97fe825f723204e6cb8daf086" + ], + "sequence": 4294967295 + } + ], + "vout": [ + { + "value": 0.00988567, + "n": 0, + "scriptPubKey": { + "asm": "0 1f52977411c1a687074f2e5f124dd031c9644a72", + "hex": "00141f52977411c1a687074f2e5f124dd031c9644a72", + "reqSigs": 1, + "type": "witness_v0_keyhash", + "addresses": ["nc1qraffwaq3cxngwp609e03ynwsx8ykgjnjve9f3y"] + } + } + ], + "hex": + "02000000000101c6ccf4ddc2a21434ed634636378923d01014b2d3b2f124999f3e7c88d043f53e0000000000ffffffff0197150f00000000001600141f52977411c1a687074f2e5f124dd031c9644a72024830450221009d58ebfaab8eae297910bca93a7fd48f94ce52a1731cf27fb4c043368fa10e8d02207e88f5d868113d9567999793be0a5b752ad704d04224046839763cefe46463a5012102f6ca5274b59dfb014f6a0d690671964290dac7f97fe825f723204e6cb8daf08600000000", + "blockhash": + "ae1129ee834853c45b9edbb7228497c7fa423d7d1bdec8fd155f9e3c429c84d3", + "confirmations": 150, + "time": 1663142110, + "blocktime": 1663142110 +}; + +final tx3Raw = { + "txid": "71b56532e9e7321bd8c30d0f8b14530743049d2f3edd5623065c46eee1dda04d", + "hash": "bb25567e1ffb2fd6ec9aa3925a7a8dd3055a29521f7811b2b2bc01ce7d8a216e", + "version": 2, + "size": 370, + "vsize": 208, + "weight": 832, + "locktime": 0, + "vin": [ + { + "txid": + "dffa9543852197f9fb90f8adafaab8a0b9b4925e9ada8c6bdcaf00bf2e9f60d7", + "vout": 0, + "scriptSig": {"asm": "", "hex": ""}, + "txinwitness": [ + "304402203535cf570aca7c1acfa6e8d2f43e0b188b76d0b7a75ffca448e6af953ffe8b6302202ea52b312aaaf6d615d722bd92535d1e8b25fa9584a8dbe34dfa1ea9c18105ca01", + "038b68078a95f73f8710e8464dec52c61f9e21675ddf69d4f61b93cc417cf73d74" + ], + "sequence": 4294967295 + }, + { + "txid": + "80f8c6de5be2243013348219bbb7043a6d8d00ddc716baf6a69eab517f9a6fc1", + "vout": 1, + "scriptSig": {"asm": "", "hex": ""}, + "txinwitness": [ + "3044022045268613674326251c46caeaf435081ca753e4ee2018d79480c4930ad7d5e19f022050090a9add82e7272b8206b9d369675e7e9a5f1396fc93490143f0053666102901", + "028e2ede901e69887cb80603c8e207839f61a477d59beff17705162a2045dd974e" + ], + "sequence": 4294967295 + } + ], + "vout": [ + { + "value": 0.01, + "n": 0, + "scriptPubKey": { + "asm": "0 756037000a8676334b35368581a29143fc078471", + "hex": "0014756037000a8676334b35368581a29143fc078471", + "reqSigs": 1, + "type": "witness_v0_keyhash", + "addresses": ["nc1qw4srwqq2semrxje4x6zcrg53g07q0pr3yqv5kr"] + } + }, + { + "value": 0.2880577, + "n": 1, + "scriptPubKey": { + "asm": "0 8207ee56ed52878d546567f29d17332b85f66e4b", + "hex": "00148207ee56ed52878d546567f29d17332b85f66e4b", + "reqSigs": 1, + "type": "witness_v0_keyhash", + "addresses": ["nc1qsgr7u4hd22rc64r9vlef69en9wzlvmjt8dzyrm"] + } + } + ], + "hex": + "02000000000102d7609f2ebf00afdc6b8cda9a5e92b4b9a0b8aaafadf890fbf99721854395fadf0000000000ffffffffc16f9a7f51ab9ea6f6ba16c7dd008d6d3a04b7bb198234133024e25bdec6f8800100000000ffffffff0240420f0000000000160014756037000a8676334b35368581a29143fc0784718a8ab701000000001600148207ee56ed52878d546567f29d17332b85f66e4b0247304402203535cf570aca7c1acfa6e8d2f43e0b188b76d0b7a75ffca448e6af953ffe8b6302202ea52b312aaaf6d615d722bd92535d1e8b25fa9584a8dbe34dfa1ea9c18105ca0121038b68078a95f73f8710e8464dec52c61f9e21675ddf69d4f61b93cc417cf73d7402473044022045268613674326251c46caeaf435081ca753e4ee2018d79480c4930ad7d5e19f022050090a9add82e7272b8206b9d369675e7e9a5f1396fc93490143f005366610290121028e2ede901e69887cb80603c8e207839f61a477d59beff17705162a2045dd974e00000000", + "blockhash": + "98f388ba99e3b6fc421c23edf3c699ada082b01e5a5d130af7550b7fa6184f2f", + "confirmations": 147, + "time": 1663145287, + "blocktime": 1663145287 +}; + +final tx4Raw = { + "txid": "c7e700f7e23a85bbdd9de86d502322a933607ee7ea7e16adaf02e477cdd849b9", + "hash": "c6b544ddd7d901fcc7218208a6cfc8e1819c403a22cc8a1f1a7029aafa427925", + "version": 2, + "size": 192, + "vsize": 110, + "weight": 438, + "locktime": 0, + "vin": [ + { + "txid": + "71b56532e9e7321bd8c30d0f8b14530743049d2f3edd5623065c46eee1dda04d", + "vout": 0, + "scriptSig": {"asm": "", "hex": ""}, + "txinwitness": [ + "3045022100c664c6ad206999e019954c5206a26c2eca1ae2572288c0f78074c279a4a210ce022017456fdf85f744d694fa2e4638acee782d809268ea4808c04d91da3ac4fe7fd401", + "035456b63e86c0a6235cb3debfb9654966a4c2362ec678ae3b9beec53d31a25eba" + ], + "sequence": 4294967295 + } + ], + "vout": [ + { + "value": 0.00988567, + "n": 0, + "scriptPubKey": { + "asm": "0 db56f49ae171bc6a137bd950cba945eb78fb6d7c", + "hex": "0014db56f49ae171bc6a137bd950cba945eb78fb6d7c", + "reqSigs": 1, + "type": "witness_v0_keyhash", + "addresses": ["nc1qmdt0fxhpwx7x5ymmm9gvh229adu0kmtukfcsjk"] + } + } + ], + "hex": + "020000000001014da0dde1ee465c062356dd3e2f9d04430753148b0f0dc3d81b32e7e93265b5710000000000ffffffff0197150f0000000000160014db56f49ae171bc6a137bd950cba945eb78fb6d7c02483045022100c664c6ad206999e019954c5206a26c2eca1ae2572288c0f78074c279a4a210ce022017456fdf85f744d694fa2e4638acee782d809268ea4808c04d91da3ac4fe7fd40121035456b63e86c0a6235cb3debfb9654966a4c2362ec678ae3b9beec53d31a25eba00000000", + "blockhash": + "6f60029ff3a32ca2d7e7e23c02b9cb35f61e7f9481992f9c3ded2c60c7b1de9b", + "confirmations": 130, + "time": 1663155739, + "blocktime": 1663155739 +}; diff --git a/test/services/coins/namecoin/namecoin_utxo_sample_data.dart b/test/services/coins/namecoin/namecoin_utxo_sample_data.dart new file mode 100644 index 000000000..d54f00f24 --- /dev/null +++ b/test/services/coins/namecoin/namecoin_utxo_sample_data.dart @@ -0,0 +1,58 @@ +import 'package:stackwallet/models/paymint/utxo_model.dart'; + +final Map>> batchGetUTXOResponse0 = { + "some id 0": [ + { + "tx_pos": 0, + "value": 988567, + "tx_hash": + "32dbc0d21327e0cb94ec6069a8d235affd99689ffc5f68959bfb720bafc04bcf", + "height": 629695 + }, + { + "tx_pos": 0, + "value": 1000000, + "tx_hash": + "40c8dd876cf111dc00d3aa2fedc93a77c18b391931939d4f99a760226cbff675", + "height": 629633 + }, + ], + "some id 1": [], +}; + +final utxoList = [ + UtxoObject( + txid: "dffa9543852197f9fb90f8adafaab8a0b9b4925e9ada8c6bdcaf00bf2e9f60d7", + vout: 0, + status: Status( + confirmed: true, + confirmations: 150, + blockHeight: 629695, + blockTime: 1663142110, + blockHash: + "32dbc0d21327e0cb94ec6069a8d235affd99689ffc5f68959bfb720bafc04bcf", + ), + value: 988567, + fiatWorth: "\$0", + txName: "nc1qraffwaq3cxngwp609e03ynwsx8ykgjnjve9f3y", + blocked: false, + isCoinbase: false, + ), + UtxoObject( + txid: "3ef543d0887c3e9f9924f1b2d3b21410d0238937364663ed3414a2c2ddf4ccc6", + vout: 0, + status: Status( + confirmed: true, + confirmations: 212, + blockHeight: 629633, + blockTime: 1663093275, + blockHash: + "40c8dd876cf111dc00d3aa2fedc93a77c18b391931939d4f99a760226cbff675", + ), + value: 1000000, + fiatWorth: "\$0", + txName: "nc1qwfda4s9qmdqpnykgpjf85n09ath983srtuxcqx", + blocked: false, + isCoinbase: false, + ), +]; diff --git a/test/services/coins/namecoin/namecoin_wallet_test.dart b/test/services/coins/namecoin/namecoin_wallet_test.dart new file mode 100644 index 000000000..50a82bd69 --- /dev/null +++ b/test/services/coins/namecoin/namecoin_wallet_test.dart @@ -0,0 +1,1743 @@ +// import 'package:decimal/decimal.dart'; +// import 'package:flutter_test/flutter_test.dart'; +// import 'package:hive/hive.dart'; +// import 'package:hive_test/hive_test.dart'; +// import 'package:mockito/annotations.dart'; +// import 'package:mockito/mockito.dart'; +// import 'package:stackwallet/electrumx_rpc/cached_electrumx.dart'; +// import 'package:stackwallet/electrumx_rpc/electrumx.dart'; +// import 'package:stackwallet/hive/db.dart'; +// import 'package:stackwallet/models/paymint/fee_object_model.dart'; +// import 'package:stackwallet/models/paymint/transactions_model.dart'; +// import 'package:stackwallet/models/paymint/utxo_model.dart'; +// import 'package:stackwallet/services/coins/namecoin/namecoin_wallet.dart'; +// import 'package:stackwallet/services/price.dart'; +// import 'package:stackwallet/services/transaction_notification_tracker.dart'; +// import 'package:stackwallet/utilities/enums/coin_enum.dart'; +// import 'package:stackwallet/utilities/flutter_secure_storage_interface.dart'; +// import 'package:tuple/tuple.dart'; +// +// import 'namecoin_history_sample_data.dart'; +// import 'namecoin_transaction_data_samples.dart'; +// import 'namecoin_utxo_sample_data.dart'; +// import 'namecoin_wallet_test.mocks.dart'; +// import 'namecoin_wallet_test_parameters.dart'; +// +// @GenerateMocks( +// [ElectrumX, CachedElectrumX, PriceAPI, TransactionNotificationTracker]) +void main() {} +// group("namecoin constants", () { +// test("namecoin minimum confirmations", () async { +// expect(MINIMUM_CONFIRMATIONS, 2); +// }); +// test("namecoin dust limit", () async { +// expect(DUST_LIMIT, 546); +// }); +// test("namecoin mainnet genesis block hash", () async { +// expect(GENESIS_HASH_MAINNET, +// "000000000062b72c5e2ceb45fbc8587e807c155b0da735e6483dfba2f0a9c770"); +// }); +// test("namecoin testnet genesis block hash", () async { +// expect(GENESIS_HASH_TESTNET, +// "00000007199508e34a9ff81e6ec0c477a4cccff2a4767a8eee39c11db367b008"); +// }); +// }); +// +// test("namecoin DerivePathType enum", () { +// expect(DerivePathType.values.length, 3); +// expect(DerivePathType.values.toString(), +// "[DerivePathType.bip44, DerivePathType.bip49, DerivePathType.bip84]"); +// }); +// +// group("bip32 node/root", () { +// test("getBip32Root", () { +// final root = getBip32Root(TEST_MNEMONIC, namecoin); +// expect(root.toWIF(), ROOT_WIF); +// }); +// +// // test("getBip32NodeFromRoot", () { +// // final root = getBip32Root(TEST_MNEMONIC, namecoin); +// // // two mainnet +// // final node44 = getBip32NodeFromRoot(0, 0, root, DerivePathType.bip44); +// // expect(node44.toWIF(), NODE_WIF_44); +// // final node49 = getBip32NodeFromRoot(0, 0, root, DerivePathType.bip49); +// // expect(node49.toWIF(), NODE_WIF_49); +// // // and one on testnet +// // final node84 = getBip32NodeFromRoot( +// // 0, 0, getBip32Root(TEST_MNEMONIC, testnet), DerivePathType.bip84); +// // expect(node84.toWIF(), NODE_WIF_84); +// // // a bad derive path +// // bool didThrow = false; +// // try { +// // getBip32NodeFromRoot(0, 0, root, null); +// // } catch (_) { +// // didThrow = true; +// // } +// // expect(didThrow, true); +// // // finally an invalid network +// // didThrow = false; +// // final invalidNetwork = NetworkType( +// // messagePrefix: '\x18hello world\n', +// // bech32: 'gg', +// // bip32: Bip32Type(public: 0x055521e, private: 0x055555), +// // pubKeyHash: 0x55, +// // scriptHash: 0x55, +// // wif: 0x00); +// // try { +// // getBip32NodeFromRoot(0, 0, getBip32Root(TEST_MNEMONIC, invalidNetwork), +// // DerivePathType.bip44); +// // } catch (_) { +// // didThrow = true; +// // } +// // expect(didThrow, true); +// // }); +// +// // test("basic getBip32Node", () { +// // final node = +// // getBip32Node(0, 0, TEST_MNEMONIC, testnet, DerivePathType.bip84); +// // expect(node.toWIF(), NODE_WIF_84); +// // }); +// }); +// +// group("validate mainnet namecoin addresses", () { +// MockElectrumX? client; +// MockCachedElectrumX? cachedClient; +// MockPriceAPI? priceAPI; +// FakeSecureStorage? secureStore; +// MockTransactionNotificationTracker? tracker; +// +// NamecoinWallet? mainnetWallet; +// +// setUp(() { +// client = MockElectrumX(); +// cachedClient = MockCachedElectrumX(); +// priceAPI = MockPriceAPI(); +// secureStore = FakeSecureStorage(); +// tracker = MockTransactionNotificationTracker(); +// +// mainnetWallet = NamecoinWallet( +// walletId: "validateAddressMainNet", +// walletName: "validateAddressMainNet", +// coin: Coin.namecoin, +// client: client!, +// cachedClient: cachedClient!, +// tracker: tracker!, +// priceAPI: priceAPI, +// secureStore: secureStore, +// ); +// }); +// +// test("valid mainnet legacy/p2pkh address type", () { +// expect( +// mainnetWallet?.addressType( +// address: "N673DDbjPcrNgJmrhJ1xQXF9LLizQzvjEs"), +// DerivePathType.bip44); +// expect(secureStore?.interactions, 0); +// verifyNoMoreInteractions(client); +// verifyNoMoreInteractions(cachedClient); +// verifyNoMoreInteractions(tracker); +// verifyNoMoreInteractions(priceAPI); +// }); +// +// test("valid mainnet bech32 p2wpkh address type", () { +// expect( +// mainnetWallet?.addressType( +// address: "nc1q6k4x8ye6865z3rc8zkt8gyu52na7njqt6hsk4v"), +// DerivePathType.bip84); +// expect(secureStore?.interactions, 0); +// verifyNoMoreInteractions(client); +// verifyNoMoreInteractions(cachedClient); +// verifyNoMoreInteractions(tracker); +// verifyNoMoreInteractions(priceAPI); +// }); +// +// test("invalid bech32 address type", () { +// expect( +// () => mainnetWallet?.addressType( +// address: "tb1qzzlm6mnc8k54mx6akehl8p9ray8r439va5ndyq"), +// throwsArgumentError); +// expect(secureStore?.interactions, 0); +// verifyNoMoreInteractions(client); +// verifyNoMoreInteractions(cachedClient); +// verifyNoMoreInteractions(tracker); +// verifyNoMoreInteractions(priceAPI); +// }); +// +// test("address has no matching script", () { +// expect( +// () => mainnetWallet?.addressType( +// address: "mpMk94ETazqonHutyC1v6ajshgtP8oiFKU"), +// throwsArgumentError); +// expect(secureStore?.interactions, 0); +// verifyNoMoreInteractions(client); +// verifyNoMoreInteractions(cachedClient); +// verifyNoMoreInteractions(tracker); +// verifyNoMoreInteractions(priceAPI); +// }); +// }); +// +// group("testNetworkConnection", () { +// MockElectrumX? client; +// MockCachedElectrumX? cachedClient; +// MockPriceAPI? priceAPI; +// FakeSecureStorage? secureStore; +// MockTransactionNotificationTracker? tracker; +// +// NamecoinWallet? nmc; +// +// setUp(() { +// client = MockElectrumX(); +// cachedClient = MockCachedElectrumX(); +// priceAPI = MockPriceAPI(); +// secureStore = FakeSecureStorage(); +// tracker = MockTransactionNotificationTracker(); +// +// nmc = NamecoinWallet( +// walletId: "testNetworkConnection", +// walletName: "testNetworkConnection", +// coin: Coin.namecoin, +// client: client!, +// cachedClient: cachedClient!, +// tracker: tracker!, +// priceAPI: priceAPI, +// secureStore: secureStore, +// ); +// }); +// +// test("attempted connection fails due to server error", () async { +// when(client?.ping()).thenAnswer((_) async => false); +// final bool? result = await nmc?.testNetworkConnection(); +// expect(result, false); +// expect(secureStore?.interactions, 0); +// verify(client?.ping()).called(1); +// verifyNoMoreInteractions(client); +// verifyNoMoreInteractions(cachedClient); +// verifyNoMoreInteractions(priceAPI); +// }); +// +// test("attempted connection fails due to exception", () async { +// when(client?.ping()).thenThrow(Exception); +// final bool? result = await nmc?.testNetworkConnection(); +// expect(result, false); +// expect(secureStore?.interactions, 0); +// verify(client?.ping()).called(1); +// verifyNoMoreInteractions(client); +// verifyNoMoreInteractions(cachedClient); +// verifyNoMoreInteractions(priceAPI); +// }); +// +// test("attempted connection test success", () async { +// when(client?.ping()).thenAnswer((_) async => true); +// final bool? result = await nmc?.testNetworkConnection(); +// expect(result, true); +// expect(secureStore?.interactions, 0); +// verify(client?.ping()).called(1); +// verifyNoMoreInteractions(client); +// verifyNoMoreInteractions(cachedClient); +// verifyNoMoreInteractions(priceAPI); +// }); +// }); +// +// group("basic getters, setters, and functions", () { +// final testWalletId = "NMCtestWalletID"; +// final testWalletName = "NMCWallet"; +// +// MockElectrumX? client; +// MockCachedElectrumX? cachedClient; +// MockPriceAPI? priceAPI; +// FakeSecureStorage? secureStore; +// MockTransactionNotificationTracker? tracker; +// +// NamecoinWallet? nmc; +// +// setUp(() async { +// client = MockElectrumX(); +// cachedClient = MockCachedElectrumX(); +// priceAPI = MockPriceAPI(); +// secureStore = FakeSecureStorage(); +// tracker = MockTransactionNotificationTracker(); +// +// nmc = NamecoinWallet( +// walletId: testWalletId, +// walletName: testWalletName, +// coin: Coin.namecoin, +// client: client!, +// cachedClient: cachedClient!, +// tracker: tracker!, +// priceAPI: priceAPI, +// secureStore: secureStore, +// ); +// }); +// +// test("get networkType main", () async { +// expect(Coin.namecoin, Coin.namecoin); +// expect(secureStore?.interactions, 0); +// verifyNoMoreInteractions(client); +// verifyNoMoreInteractions(cachedClient); +// verifyNoMoreInteractions(priceAPI); +// }); +// +// test("get networkType test", () async { +// nmc = NamecoinWallet( +// walletId: testWalletId, +// walletName: testWalletName, +// coin: Coin.namecoin, +// client: client!, +// cachedClient: cachedClient!, +// tracker: tracker!, +// priceAPI: priceAPI, +// secureStore: secureStore, +// ); +// expect(Coin.namecoin, Coin.namecoin); +// expect(secureStore?.interactions, 0); +// verifyNoMoreInteractions(client); +// verifyNoMoreInteractions(cachedClient); +// verifyNoMoreInteractions(priceAPI); +// }); +// +// test("get cryptoCurrency", () async { +// expect(Coin.namecoin, Coin.namecoin); +// expect(secureStore?.interactions, 0); +// verifyNoMoreInteractions(client); +// verifyNoMoreInteractions(cachedClient); +// verifyNoMoreInteractions(priceAPI); +// }); +// +// test("get coinName", () async { +// expect(Coin.namecoin, Coin.namecoin); +// expect(secureStore?.interactions, 0); +// verifyNoMoreInteractions(client); +// verifyNoMoreInteractions(cachedClient); +// verifyNoMoreInteractions(priceAPI); +// }); +// +// test("get coinTicker", () async { +// expect(Coin.namecoin, Coin.namecoin); +// expect(secureStore?.interactions, 0); +// verifyNoMoreInteractions(client); +// verifyNoMoreInteractions(cachedClient); +// verifyNoMoreInteractions(priceAPI); +// }); +// +// test("get and set walletName", () async { +// expect(Coin.namecoin, Coin.namecoin); +// nmc?.walletName = "new name"; +// expect(nmc?.walletName, "new name"); +// expect(secureStore?.interactions, 0); +// verifyNoMoreInteractions(client); +// verifyNoMoreInteractions(cachedClient); +// verifyNoMoreInteractions(priceAPI); +// }); +// +// test("estimateTxFee", () async { +// expect(nmc?.estimateTxFee(vSize: 356, feeRatePerKB: 1), 356); +// expect(nmc?.estimateTxFee(vSize: 356, feeRatePerKB: 900), 356); +// expect(nmc?.estimateTxFee(vSize: 356, feeRatePerKB: 999), 356); +// expect(nmc?.estimateTxFee(vSize: 356, feeRatePerKB: 1000), 356); +// expect(nmc?.estimateTxFee(vSize: 356, feeRatePerKB: 1001), 712); +// expect(nmc?.estimateTxFee(vSize: 356, feeRatePerKB: 1699), 712); +// expect(nmc?.estimateTxFee(vSize: 356, feeRatePerKB: 2000), 712); +// expect(nmc?.estimateTxFee(vSize: 356, feeRatePerKB: 12345), 4628); +// expect(secureStore?.interactions, 0); +// verifyNoMoreInteractions(client); +// verifyNoMoreInteractions(cachedClient); +// verifyNoMoreInteractions(priceAPI); +// }); +// +// test("get fees succeeds", () async { +// when(client?.ping()).thenAnswer((_) async => true); +// when(client?.getServerFeatures()).thenAnswer((_) async => { +// "hosts": {}, +// "pruning": null, +// "server_version": "Unit tests", +// "protocol_min": "1.4", +// "protocol_max": "1.4.2", +// "genesis_hash": GENESIS_HASH_MAINNET, +// "hash_function": "sha256", +// "services": [] +// }); +// when(client?.estimateFee(blocks: 1)) +// .thenAnswer((realInvocation) async => Decimal.zero); +// when(client?.estimateFee(blocks: 5)) +// .thenAnswer((realInvocation) async => Decimal.one); +// when(client?.estimateFee(blocks: 20)) +// .thenAnswer((realInvocation) async => Decimal.ten); +// +// final fees = await nmc?.fees; +// expect(fees, isA()); +// expect(fees?.slow, 1000000000); +// expect(fees?.medium, 100000000); +// expect(fees?.fast, 0); +// +// verify(client?.estimateFee(blocks: 1)).called(1); +// verify(client?.estimateFee(blocks: 5)).called(1); +// verify(client?.estimateFee(blocks: 20)).called(1); +// expect(secureStore?.interactions, 0); +// verifyNoMoreInteractions(client); +// verifyNoMoreInteractions(cachedClient); +// verifyNoMoreInteractions(priceAPI); +// }); +// +// test("get fees fails", () async { +// when(client?.ping()).thenAnswer((_) async => true); +// when(client?.getServerFeatures()).thenAnswer((_) async => { +// "hosts": {}, +// "pruning": null, +// "server_version": "Unit tests", +// "protocol_min": "1.4", +// "protocol_max": "1.4.2", +// "genesis_hash": GENESIS_HASH_MAINNET, +// "hash_function": "sha256", +// "services": [] +// }); +// when(client?.estimateFee(blocks: 1)) +// .thenAnswer((realInvocation) async => Decimal.zero); +// when(client?.estimateFee(blocks: 5)) +// .thenAnswer((realInvocation) async => Decimal.one); +// when(client?.estimateFee(blocks: 20)) +// .thenThrow(Exception("some exception")); +// +// bool didThrow = false; +// try { +// await nmc?.fees; +// } catch (_) { +// didThrow = true; +// } +// +// expect(didThrow, true); +// +// verify(client?.estimateFee(blocks: 1)).called(1); +// verify(client?.estimateFee(blocks: 5)).called(1); +// verify(client?.estimateFee(blocks: 20)).called(1); +// expect(secureStore?.interactions, 0); +// verifyNoMoreInteractions(client); +// verifyNoMoreInteractions(cachedClient); +// verifyNoMoreInteractions(priceAPI); +// }); +// +// // test("get maxFee", () async { +// // when(client?.ping()).thenAnswer((_) async => true); +// // when(client?.getServerFeatures()).thenAnswer((_) async => { +// // "hosts": {}, +// // "pruning": null, +// // "server_version": "Unit tests", +// // "protocol_min": "1.4", +// // "protocol_max": "1.4.2", +// // "genesis_hash": GENESIS_HASH_TESTNET, +// // "hash_function": "sha256", +// // "services": [] +// // }); +// // when(client?.estimateFee(blocks: 20)) +// // .thenAnswer((realInvocation) async => Decimal.zero); +// // when(client?.estimateFee(blocks: 5)) +// // .thenAnswer((realInvocation) async => Decimal.one); +// // when(client?.estimateFee(blocks: 1)) +// // .thenAnswer((realInvocation) async => Decimal.ten); +// // +// // final maxFee = await nmc?.maxFee; +// // expect(maxFee, 1000000000); +// // +// // verify(client?.estimateFee(blocks: 1)).called(1); +// // verify(client?.estimateFee(blocks: 5)).called(1); +// // verify(client?.estimateFee(blocks: 20)).called(1); +// // expect(secureStore?.interactions, 0); +// // verifyNoMoreInteractions(client); +// // verifyNoMoreInteractions(cachedClient); +// // verifyNoMoreInteractions(tracker); +// // verifyNoMoreInteractions(priceAPI); +// // }); +// }); +// +// group("Namecoin service class functions that depend on shared storage", () { +// final testWalletId = "NMCtestWalletID"; +// final testWalletName = "NMCWallet"; +// +// bool hiveAdaptersRegistered = false; +// +// MockElectrumX? client; +// MockCachedElectrumX? cachedClient; +// MockPriceAPI? priceAPI; +// FakeSecureStorage? secureStore; +// MockTransactionNotificationTracker? tracker; +// +// NamecoinWallet? nmc; +// +// setUp(() async { +// await setUpTestHive(); +// if (!hiveAdaptersRegistered) { +// hiveAdaptersRegistered = true; +// +// // Registering Transaction Model Adapters +// Hive.registerAdapter(TransactionDataAdapter()); +// Hive.registerAdapter(TransactionChunkAdapter()); +// Hive.registerAdapter(TransactionAdapter()); +// Hive.registerAdapter(InputAdapter()); +// Hive.registerAdapter(OutputAdapter()); +// +// // Registering Utxo Model Adapters +// Hive.registerAdapter(UtxoDataAdapter()); +// Hive.registerAdapter(UtxoObjectAdapter()); +// Hive.registerAdapter(StatusAdapter()); +// +// final wallets = await Hive.openBox('wallets'); +// await wallets.put('currentWalletName', testWalletName); +// } +// +// client = MockElectrumX(); +// cachedClient = MockCachedElectrumX(); +// priceAPI = MockPriceAPI(); +// secureStore = FakeSecureStorage(); +// tracker = MockTransactionNotificationTracker(); +// +// nmc = NamecoinWallet( +// walletId: testWalletId, +// walletName: testWalletName, +// coin: Coin.namecoin, +// client: client!, +// cachedClient: cachedClient!, +// tracker: tracker!, +// priceAPI: priceAPI, +// secureStore: secureStore, +// ); +// }); +// +// // test("initializeWallet no network", () async { +// // when(client?.ping()).thenAnswer((_) async => false); +// // expect(await nmc?.initializeWallet(), false); +// // expect(secureStore?.interactions, 0); +// // verify(client?.ping()).called(1); +// // verifyNoMoreInteractions(client); +// // verifyNoMoreInteractions(cachedClient); +// // verifyNoMoreInteractions(priceAPI); +// // }); +// +// // test("initializeWallet no network exception", () async { +// // when(client?.ping()).thenThrow(Exception("Network connection failed")); +// // final wallets = await Hive.openBox(testWalletId); +// // expect(await nmc?.initializeExisting(), false); +// // expect(secureStore?.interactions, 0); +// // verify(client?.ping()).called(1); +// // verifyNoMoreInteractions(client); +// // verifyNoMoreInteractions(cachedClient); +// // verifyNoMoreInteractions(priceAPI); +// // }); +// +// test("initializeWallet mainnet throws bad network", () async { +// when(client?.ping()).thenAnswer((_) async => true); +// when(client?.getServerFeatures()).thenAnswer((_) async => { +// "hosts": {}, +// "pruning": null, +// "server_version": "Unit tests", +// "protocol_min": "1.4", +// "protocol_max": "1.4.2", +// "genesis_hash": GENESIS_HASH_MAINNET, +// "hash_function": "sha256", +// "services": [] +// }); +// // await nmc?.initializeNew(); +// final wallets = await Hive.openBox(testWalletId); +// +// expectLater(() => nmc?.initializeExisting(), throwsA(isA())) +// .then((_) { +// expect(secureStore?.interactions, 0); +// // verify(client?.ping()).called(1); +// // verify(client?.getServerFeatures()).called(1); +// verifyNoMoreInteractions(client); +// verifyNoMoreInteractions(cachedClient); +// verifyNoMoreInteractions(priceAPI); +// }); +// }); +// +// test("initializeWallet throws mnemonic overwrite exception", () async { +// when(client?.ping()).thenAnswer((_) async => true); +// when(client?.getServerFeatures()).thenAnswer((_) async => { +// "hosts": {}, +// "pruning": null, +// "server_version": "Unit tests", +// "protocol_min": "1.4", +// "protocol_max": "1.4.2", +// "genesis_hash": GENESIS_HASH_MAINNET, +// "hash_function": "sha256", +// "services": [] +// }); +// await secureStore?.write( +// key: "${testWalletId}_mnemonic", value: "some mnemonic"); +// +// final wallets = await Hive.openBox(testWalletId); +// expectLater(() => nmc?.initializeExisting(), throwsA(isA())) +// .then((_) { +// expect(secureStore?.interactions, 1); +// // verify(client?.ping()).called(1); +// // verify(client?.getServerFeatures()).called(1); +// verifyNoMoreInteractions(client); +// verifyNoMoreInteractions(cachedClient); +// verifyNoMoreInteractions(priceAPI); +// }); +// }); +// +// test( +// "recoverFromMnemonic using empty seed on mainnet fails due to bad genesis hash match", +// () async { +// when(client?.getServerFeatures()).thenAnswer((_) async => { +// "hosts": {}, +// "pruning": null, +// "server_version": "Unit tests", +// "protocol_min": "1.4", +// "protocol_max": "1.4.2", +// "genesis_hash": GENESIS_HASH_TESTNET, +// "hash_function": "sha256", +// "services": [] +// }); +// +// bool hasThrown = false; +// try { +// await nmc?.recoverFromMnemonic( +// mnemonic: TEST_MNEMONIC, +// maxUnusedAddressGap: 2, +// maxNumberOfIndexesToCheck: 1000, +// height: 4000); +// } catch (_) { +// hasThrown = true; +// } +// expect(hasThrown, true); +// +// verify(client?.getServerFeatures()).called(1); +// +// expect(secureStore?.interactions, 0); +// verifyNoMoreInteractions(client); +// verifyNoMoreInteractions(cachedClient); +// verifyNoMoreInteractions(priceAPI); +// }); +// +// test( +// "recoverFromMnemonic using empty seed on mainnet fails due to attempted overwrite of mnemonic", +// () async { +// when(client?.getServerFeatures()).thenAnswer((_) async => { +// "hosts": {}, +// "pruning": null, +// "server_version": "Unit tests", +// "protocol_min": "1.4", +// "protocol_max": "1.4.2", +// "genesis_hash": GENESIS_HASH_MAINNET, +// "hash_function": "sha256", +// "services": [] +// }); +// +// await secureStore?.write( +// key: "${testWalletId}_mnemonic", value: "some mnemonic words"); +// +// bool hasThrown = false; +// try { +// await nmc?.recoverFromMnemonic( +// mnemonic: TEST_MNEMONIC, +// maxUnusedAddressGap: 2, +// maxNumberOfIndexesToCheck: 1000, +// height: 4000); +// } catch (_) { +// hasThrown = true; +// } +// expect(hasThrown, true); +// +// verify(client?.getServerFeatures()).called(1); +// +// expect(secureStore?.interactions, 2); +// verifyNoMoreInteractions(client); +// verifyNoMoreInteractions(cachedClient); +// verifyNoMoreInteractions(priceAPI); +// }); +// +// test("recoverFromMnemonic using empty seed on mainnet succeeds", () async { +// when(client?.getServerFeatures()).thenAnswer((_) async => { +// "hosts": {}, +// "pruning": null, +// "server_version": "Unit tests", +// "protocol_min": "1.4", +// "protocol_max": "1.4.2", +// "genesis_hash": GENESIS_HASH_MAINNET, +// "hash_function": "sha256", +// "services": [] +// }); +// when(client?.getBatchHistory(args: historyBatchArgs0)) +// .thenAnswer((_) async => emptyHistoryBatchResponse); +// when(client?.getBatchHistory(args: historyBatchArgs1)) +// .thenAnswer((_) async => emptyHistoryBatchResponse); +// when(client?.getBatchHistory(args: historyBatchArgs2)) +// .thenAnswer((_) async => emptyHistoryBatchResponse); +// when(client?.getBatchHistory(args: historyBatchArgs3)) +// .thenAnswer((_) async => emptyHistoryBatchResponse); +// when(client?.getBatchHistory(args: historyBatchArgs4)) +// .thenAnswer((_) async => emptyHistoryBatchResponse); +// when(client?.getBatchHistory(args: historyBatchArgs5)) +// .thenAnswer((_) async => emptyHistoryBatchResponse); +// await DB.instance.init(); +// final wallet = await Hive.openBox(testWalletId); +// bool hasThrown = false; +// try { +// await nmc?.recoverFromMnemonic( +// mnemonic: TEST_MNEMONIC, +// maxUnusedAddressGap: 2, +// maxNumberOfIndexesToCheck: 1000, +// height: 4000); +// } catch (_) { +// hasThrown = true; +// } +// expect(hasThrown, false); +// +// verify(client?.getServerFeatures()).called(1); +// verify(client?.getBatchHistory(args: historyBatchArgs0)).called(1); +// verify(client?.getBatchHistory(args: historyBatchArgs1)).called(1); +// verify(client?.getBatchHistory(args: historyBatchArgs2)).called(1); +// verify(client?.getBatchHistory(args: historyBatchArgs3)).called(1); +// verify(client?.getBatchHistory(args: historyBatchArgs4)).called(1); +// verify(client?.getBatchHistory(args: historyBatchArgs5)).called(1); +// +// expect(secureStore?.interactions, 20); +// expect(secureStore?.writes, 7); +// expect(secureStore?.reads, 13); +// expect(secureStore?.deletes, 0); +// +// verifyNoMoreInteractions(client); +// verifyNoMoreInteractions(cachedClient); +// verifyNoMoreInteractions(priceAPI); +// }); +// +// test("get mnemonic list", () async { +// when(client?.getServerFeatures()).thenAnswer((_) async => { +// "hosts": {}, +// "pruning": null, +// "server_version": "Unit tests", +// "protocol_min": "1.4", +// "protocol_max": "1.4.2", +// "genesis_hash": GENESIS_HASH_MAINNET, +// "hash_function": "sha256", +// "services": [] +// }); +// when(client?.getBatchHistory(args: historyBatchArgs0)) +// .thenAnswer((_) async => emptyHistoryBatchResponse); +// when(client?.getBatchHistory(args: historyBatchArgs1)) +// .thenAnswer((_) async => emptyHistoryBatchResponse); +// when(client?.getBatchHistory(args: historyBatchArgs2)) +// .thenAnswer((_) async => emptyHistoryBatchResponse); +// when(client?.getBatchHistory(args: historyBatchArgs3)) +// .thenAnswer((_) async => emptyHistoryBatchResponse); +// when(client?.getBatchHistory(args: historyBatchArgs4)) +// .thenAnswer((_) async => emptyHistoryBatchResponse); +// when(client?.getBatchHistory(args: historyBatchArgs5)) +// .thenAnswer((_) async => emptyHistoryBatchResponse); +// +// final wallet = await Hive.openBox(testWalletId); +// +// await nmc?.recoverFromMnemonic( +// mnemonic: TEST_MNEMONIC, +// maxUnusedAddressGap: 2, +// maxNumberOfIndexesToCheck: 1000, +// height: 4000); +// +// expect(await nmc?.mnemonic, TEST_MNEMONIC.split(" ")); +// +// verify(client?.getServerFeatures()).called(1); +// verify(client?.getBatchHistory(args: historyBatchArgs0)).called(1); +// verify(client?.getBatchHistory(args: historyBatchArgs1)).called(1); +// verify(client?.getBatchHistory(args: historyBatchArgs2)).called(1); +// verify(client?.getBatchHistory(args: historyBatchArgs3)).called(1); +// verify(client?.getBatchHistory(args: historyBatchArgs4)).called(1); +// verify(client?.getBatchHistory(args: historyBatchArgs5)).called(1); +// +// verifyNoMoreInteractions(client); +// verifyNoMoreInteractions(cachedClient); +// verifyNoMoreInteractions(priceAPI); +// }); +// +// test("recoverFromMnemonic using non empty seed on mainnet succeeds", +// () async { +// when(client?.getServerFeatures()).thenAnswer((_) async => { +// "hosts": {}, +// "pruning": null, +// "server_version": "Unit tests", +// "protocol_min": "1.4", +// "protocol_max": "1.4.2", +// "genesis_hash": GENESIS_HASH_MAINNET, +// "hash_function": "sha256", +// "services": [] +// }); +// when(client?.getBatchHistory(args: historyBatchArgs0)) +// .thenAnswer((_) async => historyBatchResponse); +// when(client?.getBatchHistory(args: historyBatchArgs1)) +// .thenAnswer((_) async => historyBatchResponse); +// when(client?.getBatchHistory(args: historyBatchArgs2)) +// .thenAnswer((_) async => historyBatchResponse); +// when(client?.getBatchHistory(args: historyBatchArgs3)) +// .thenAnswer((_) async => historyBatchResponse); +// when(client?.getBatchHistory(args: historyBatchArgs4)) +// .thenAnswer((_) async => historyBatchResponse); +// when(client?.getBatchHistory(args: historyBatchArgs5)) +// .thenAnswer((_) async => historyBatchResponse); +// +// List dynamicArgValues = []; +// +// when(client?.getBatchHistory(args: anyNamed("args"))) +// .thenAnswer((realInvocation) async { +// if (realInvocation.namedArguments.values.first.length == 1) { +// dynamicArgValues.add(realInvocation.namedArguments.values.first); +// } +// +// return historyBatchResponse; +// }); +// +// await Hive.openBox(testWalletId); +// +// bool hasThrown = false; +// try { +// await nmc?.recoverFromMnemonic( +// mnemonic: TEST_MNEMONIC, +// maxUnusedAddressGap: 2, +// maxNumberOfIndexesToCheck: 1000, +// height: 4000); +// } catch (_) { +// hasThrown = true; +// } +// expect(hasThrown, false); +// +// verify(client?.getServerFeatures()).called(1); +// verify(client?.getBatchHistory(args: historyBatchArgs0)).called(1); +// verify(client?.getBatchHistory(args: historyBatchArgs1)).called(1); +// verify(client?.getBatchHistory(args: historyBatchArgs2)).called(1); +// verify(client?.getBatchHistory(args: historyBatchArgs3)).called(1); +// verify(client?.getBatchHistory(args: historyBatchArgs4)).called(1); +// verify(client?.getBatchHistory(args: historyBatchArgs5)).called(1); +// +// for (final arg in dynamicArgValues) { +// final map = Map>.from(arg as Map); +// +// verify(client?.getBatchHistory(args: map)).called(1); +// expect(activeScriptHashes.contains(map.values.first.first as String), +// true); +// } +// +// expect(secureStore?.interactions, 14); +// expect(secureStore?.writes, 7); +// expect(secureStore?.reads, 7); +// expect(secureStore?.deletes, 0); +// +// verifyNoMoreInteractions(client); +// verifyNoMoreInteractions(cachedClient); +// verifyNoMoreInteractions(priceAPI); +// }); +// +// test("fullRescan succeeds", () async { +// when(client?.getServerFeatures()).thenAnswer((_) async => { +// "hosts": {}, +// "pruning": null, +// "server_version": "Unit tests", +// "protocol_min": "1.4", +// "protocol_max": "1.4.2", +// "genesis_hash": GENESIS_HASH_MAINNET, +// "hash_function": "sha256", +// "services": [] +// }); +// when(client?.getBatchHistory(args: historyBatchArgs0)) +// .thenAnswer((_) async => historyBatchResponse); +// when(client?.getBatchHistory(args: historyBatchArgs1)) +// .thenAnswer((_) async => historyBatchResponse); +// when(client?.getBatchHistory(args: historyBatchArgs2)) +// .thenAnswer((_) async => historyBatchResponse); +// when(client?.getBatchHistory(args: historyBatchArgs3)) +// .thenAnswer((_) async => historyBatchResponse); +// when(client?.getBatchHistory(args: historyBatchArgs4)) +// .thenAnswer((_) async => historyBatchResponse); +// when(client?.getBatchHistory(args: historyBatchArgs5)) +// .thenAnswer((_) async => historyBatchResponse); +// when(cachedClient?.clearSharedTransactionCache(coin: Coin.namecoin)) +// .thenAnswer((realInvocation) async {}); +// +// when(client?.getBatchHistory(args: { +// "0": [ +// "dd63fc12f5e6c1ada2cf3c941d1648e6d561ce4024747bb2117d72112d83287c" +// ] +// })).thenAnswer((realInvocation) async => {"0": []}); +// +// when(client?.getBatchHistory(args: { +// "0": [ +// "86906979fc9107d06d560275d7de8305b69d7189c3206ac9070ad76e6abff874" +// ] +// })).thenAnswer((realInvocation) async => {"0": []}); +// +// when(client?.getBatchHistory(args: { +// "0": [ +// "c068e7fa4aa0b8a63114f6d11c047ca4be6a8fa333eb0dac48506e8f150af73b" +// ] +// })).thenAnswer((realInvocation) async => {"0": []}); +// +// when(client?.getBatchHistory(args: { +// "0": [ +// "cd3dd4abe4f9efc7149ba334d2d6790020331805b0bd5c7ed89a3ac6a22f10b9" +// ] +// })).thenAnswer((realInvocation) async => {"0": []}); +// when(client?.getBatchHistory(args: { +// "0": [ +// "587943864cefed4f1643a5ee2ce2b3c13a0c6ad7c435373f0ac328e144a15c1e" +// ] +// })).thenAnswer((realInvocation) async => {"0": []}); +// when(client?.getBatchHistory(args: { +// "0": [ +// "42d6e40636f4740f9c7f95ef0bbc2a4c17f54da2bc98a32a622e2bf73eb675c3" +// ] +// })).thenAnswer((realInvocation) async => {"0": []}); +// +// final wallet = await Hive.openBox(testWalletId); +// +// // restore so we have something to rescan +// await nmc?.recoverFromMnemonic( +// mnemonic: TEST_MNEMONIC, +// maxUnusedAddressGap: 2, +// maxNumberOfIndexesToCheck: 1000, +// height: 4000); +// +// // fetch valid wallet data +// final preReceivingAddressesP2PKH = +// await wallet.get('receivingAddressesP2PKH'); +// final preReceivingAddressesP2SH = +// await wallet.get('receivingAddressesP2SH'); +// final preReceivingAddressesP2WPKH = +// await wallet.get('receivingAddressesP2WPKH'); +// final preChangeAddressesP2PKH = await wallet.get('changeAddressesP2PKH'); +// final preChangeAddressesP2SH = await wallet.get('changeAddressesP2SH'); +// final preChangeAddressesP2WPKH = +// await wallet.get('changeAddressesP2WPKH'); +// final preReceivingIndexP2PKH = await wallet.get('receivingIndexP2PKH'); +// final preReceivingIndexP2SH = await wallet.get('receivingIndexP2SH'); +// final preReceivingIndexP2WPKH = await wallet.get('receivingIndexP2WPKH'); +// final preChangeIndexP2PKH = await wallet.get('changeIndexP2PKH'); +// final preChangeIndexP2SH = await wallet.get('changeIndexP2SH'); +// final preChangeIndexP2WPKH = await wallet.get('changeIndexP2WPKH'); +// final preUtxoData = await wallet.get('latest_utxo_model'); +// final preReceiveDerivationsStringP2PKH = await secureStore?.read( +// key: "${testWalletId}_receiveDerivationsP2PKH"); +// final preChangeDerivationsStringP2PKH = await secureStore?.read( +// key: "${testWalletId}_changeDerivationsP2PKH"); +// final preReceiveDerivationsStringP2SH = await secureStore?.read( +// key: "${testWalletId}_receiveDerivationsP2SH"); +// final preChangeDerivationsStringP2SH = +// await secureStore?.read(key: "${testWalletId}_changeDerivationsP2SH"); +// final preReceiveDerivationsStringP2WPKH = await secureStore?.read( +// key: "${testWalletId}_receiveDerivationsP2WPKH"); +// final preChangeDerivationsStringP2WPKH = await secureStore?.read( +// key: "${testWalletId}_changeDerivationsP2WPKH"); +// +// // destroy the data that the rescan will fix +// await wallet.put( +// 'receivingAddressesP2PKH', ["some address", "some other address"]); +// await wallet.put( +// 'receivingAddressesP2SH', ["some address", "some other address"]); +// await wallet.put( +// 'receivingAddressesP2WPKH', ["some address", "some other address"]); +// await wallet +// .put('changeAddressesP2PKH', ["some address", "some other address"]); +// await wallet +// .put('changeAddressesP2SH', ["some address", "some other address"]); +// await wallet +// .put('changeAddressesP2WPKH', ["some address", "some other address"]); +// await wallet.put('receivingIndexP2PKH', 123); +// await wallet.put('receivingIndexP2SH', 123); +// await wallet.put('receivingIndexP2WPKH', 123); +// await wallet.put('changeIndexP2PKH', 123); +// await wallet.put('changeIndexP2SH', 123); +// await wallet.put('changeIndexP2WPKH', 123); +// await secureStore?.write( +// key: "${testWalletId}_receiveDerivationsP2PKH", value: "{}"); +// await secureStore?.write( +// key: "${testWalletId}_changeDerivationsP2PKH", value: "{}"); +// await secureStore?.write( +// key: "${testWalletId}_receiveDerivationsP2SH", value: "{}"); +// await secureStore?.write( +// key: "${testWalletId}_changeDerivationsP2SH", value: "{}"); +// await secureStore?.write( +// key: "${testWalletId}_receiveDerivationsP2WPKH", value: "{}"); +// await secureStore?.write( +// key: "${testWalletId}_changeDerivationsP2WPKH", value: "{}"); +// +// bool hasThrown = false; +// try { +// await nmc?.fullRescan(2, 1000); +// } catch (_) { +// hasThrown = true; +// } +// expect(hasThrown, false); +// +// // fetch wallet data again +// final receivingAddressesP2PKH = +// await wallet.get('receivingAddressesP2PKH'); +// final receivingAddressesP2SH = await wallet.get('receivingAddressesP2SH'); +// final receivingAddressesP2WPKH = +// await wallet.get('receivingAddressesP2WPKH'); +// final changeAddressesP2PKH = await wallet.get('changeAddressesP2PKH'); +// final changeAddressesP2SH = await wallet.get('changeAddressesP2SH'); +// final changeAddressesP2WPKH = await wallet.get('changeAddressesP2WPKH'); +// final receivingIndexP2PKH = await wallet.get('receivingIndexP2PKH'); +// final receivingIndexP2SH = await wallet.get('receivingIndexP2SH'); +// final receivingIndexP2WPKH = await wallet.get('receivingIndexP2WPKH'); +// final changeIndexP2PKH = await wallet.get('changeIndexP2PKH'); +// final changeIndexP2SH = await wallet.get('changeIndexP2SH'); +// final changeIndexP2WPKH = await wallet.get('changeIndexP2WPKH'); +// final utxoData = await wallet.get('latest_utxo_model'); +// final receiveDerivationsStringP2PKH = await secureStore?.read( +// key: "${testWalletId}_receiveDerivationsP2PKH"); +// final changeDerivationsStringP2PKH = await secureStore?.read( +// key: "${testWalletId}_changeDerivationsP2PKH"); +// final receiveDerivationsStringP2SH = await secureStore?.read( +// key: "${testWalletId}_receiveDerivationsP2SH"); +// final changeDerivationsStringP2SH = +// await secureStore?.read(key: "${testWalletId}_changeDerivationsP2SH"); +// final receiveDerivationsStringP2WPKH = await secureStore?.read( +// key: "${testWalletId}_receiveDerivationsP2WPKH"); +// final changeDerivationsStringP2WPKH = await secureStore?.read( +// key: "${testWalletId}_changeDerivationsP2WPKH"); +// +// expect(preReceivingAddressesP2PKH, receivingAddressesP2PKH); +// expect(preReceivingAddressesP2SH, receivingAddressesP2SH); +// expect(preReceivingAddressesP2WPKH, receivingAddressesP2WPKH); +// expect(preChangeAddressesP2PKH, changeAddressesP2PKH); +// expect(preChangeAddressesP2SH, changeAddressesP2SH); +// expect(preChangeAddressesP2WPKH, changeAddressesP2WPKH); +// expect(preReceivingIndexP2PKH, receivingIndexP2PKH); +// expect(preReceivingIndexP2SH, receivingIndexP2SH); +// expect(preReceivingIndexP2WPKH, receivingIndexP2WPKH); +// expect(preChangeIndexP2PKH, changeIndexP2PKH); +// expect(preChangeIndexP2SH, changeIndexP2SH); +// expect(preChangeIndexP2WPKH, changeIndexP2WPKH); +// expect(preUtxoData, utxoData); +// expect(preReceiveDerivationsStringP2PKH, receiveDerivationsStringP2PKH); +// expect(preChangeDerivationsStringP2PKH, changeDerivationsStringP2PKH); +// expect(preReceiveDerivationsStringP2SH, receiveDerivationsStringP2SH); +// expect(preChangeDerivationsStringP2SH, changeDerivationsStringP2SH); +// expect(preReceiveDerivationsStringP2WPKH, receiveDerivationsStringP2WPKH); +// expect(preChangeDerivationsStringP2WPKH, changeDerivationsStringP2WPKH); +// +// verify(client?.getServerFeatures()).called(1); +// verify(client?.getBatchHistory(args: historyBatchArgs0)).called(2); +// verify(client?.getBatchHistory(args: historyBatchArgs1)).called(2); +// verify(client?.getBatchHistory(args: historyBatchArgs2)).called(2); +// verify(client?.getBatchHistory(args: historyBatchArgs3)).called(2); +// verify(client?.getBatchHistory(args: historyBatchArgs4)).called(2); +// verify(client?.getBatchHistory(args: historyBatchArgs5)).called(2); +// verify(client?.getBatchHistory(args: { +// "0": [ +// "dd63fc12f5e6c1ada2cf3c941d1648e6d561ce4024747bb2117d72112d83287c" +// ] +// })).called(2); +// verify(client?.getBatchHistory(args: { +// "0": [ +// "86906979fc9107d06d560275d7de8305b69d7189c3206ac9070ad76e6abff874" +// ] +// })).called(2); +// +// verify(client?.getBatchHistory(args: { +// "0": [ +// "c068e7fa4aa0b8a63114f6d11c047ca4be6a8fa333eb0dac48506e8f150af73b" +// ] +// })).called(2); +// +// verify(client?.getBatchHistory(args: { +// "0": [ +// "cd3dd4abe4f9efc7149ba334d2d6790020331805b0bd5c7ed89a3ac6a22f10b9" +// ] +// })).called(2); +// +// verify(client?.getBatchHistory(args: { +// "0": [ +// "587943864cefed4f1643a5ee2ce2b3c13a0c6ad7c435373f0ac328e144a15c1e" +// ] +// })).called(2); +// +// verify(client?.getBatchHistory(args: { +// "0": [ +// "42d6e40636f4740f9c7f95ef0bbc2a4c17f54da2bc98a32a622e2bf73eb675c3" +// ] +// })).called(2); +// verify(cachedClient?.clearSharedTransactionCache(coin: Coin.namecoin)) +// .called(1); +// +// // for (final arg in dynamicArgValues) { +// // final map = Map>.from(arg as Map); +// // Map argCount = {}; +// // +// // // verify(client?.getBatchHistory(args: map)).called(1); +// // // expect(activeScriptHashes.contains(map.values.first.first as String), +// // // true); +// // } +// +// // Map argCount = {}; +// // +// // for (final arg in dynamicArgValues) { +// // final map = Map>.from(arg as Map); +// // +// // final str = jsonEncode(map); +// // +// // if (argCount[str] == null) { +// // argCount[str] = 1; +// // } else { +// // argCount[str] = argCount[str]! + 1; +// // } +// // } +// // +// // argCount.forEach((key, value) => print("arg: $key\ncount: $value")); +// +// expect(secureStore?.writes, 25); +// expect(secureStore?.reads, 32); +// expect(secureStore?.deletes, 6); +// +// verifyNoMoreInteractions(client); +// verifyNoMoreInteractions(cachedClient); +// verifyNoMoreInteractions(priceAPI); +// }); +// +// test("fullRescan fails", () async { +// when(client?.getServerFeatures()).thenAnswer((_) async => { +// "hosts": {}, +// "pruning": null, +// "server_version": "Unit tests", +// "protocol_min": "1.4", +// "protocol_max": "1.4.2", +// "genesis_hash": GENESIS_HASH_MAINNET, +// "hash_function": "sha256", +// "services": [] +// }); +// +// when(client?.getBatchHistory(args: historyBatchArgs0)) +// .thenAnswer((_) async => historyBatchResponse); +// when(client?.getBatchHistory(args: historyBatchArgs1)) +// .thenAnswer((_) async => historyBatchResponse); +// when(client?.getBatchHistory(args: historyBatchArgs2)) +// .thenAnswer((_) async => historyBatchResponse); +// when(client?.getBatchHistory(args: historyBatchArgs3)) +// .thenAnswer((_) async => historyBatchResponse); +// when(client?.getBatchHistory(args: historyBatchArgs4)) +// .thenAnswer((_) async => historyBatchResponse); +// when(client?.getBatchHistory(args: historyBatchArgs5)) +// .thenAnswer((_) async => historyBatchResponse); +// +// when(client?.getBatchHistory(args: { +// "0": [ +// "dd63fc12f5e6c1ada2cf3c941d1648e6d561ce4024747bb2117d72112d83287c" +// ] +// })).thenAnswer((realInvocation) async => {"0": []}); +// +// when(client?.getBatchHistory(args: { +// "0": [ +// "cd3dd4abe4f9efc7149ba334d2d6790020331805b0bd5c7ed89a3ac6a22f10b9" +// ] +// })).thenAnswer((realInvocation) async => {"0": []}); +// +// when(client?.getBatchHistory(args: { +// "0": [ +// "42d6e40636f4740f9c7f95ef0bbc2a4c17f54da2bc98a32a622e2bf73eb675c3" +// ] +// })).thenAnswer((realInvocation) async => {"0": []}); +// +// when(client?.getBatchHistory(args: { +// "0": [ +// "587943864cefed4f1643a5ee2ce2b3c13a0c6ad7c435373f0ac328e144a15c1e" +// ] +// })).thenAnswer((realInvocation) async => {"0": []}); +// +// when(client?.getBatchHistory(args: { +// "0": [ +// "86906979fc9107d06d560275d7de8305b69d7189c3206ac9070ad76e6abff874" +// ] +// })).thenAnswer((realInvocation) async => {"0": []}); +// +// when(client?.getBatchHistory(args: { +// "0": [ +// "c068e7fa4aa0b8a63114f6d11c047ca4be6a8fa333eb0dac48506e8f150af73b" +// ] +// })).thenAnswer((realInvocation) async => {"0": []}); +// +// when(cachedClient?.clearSharedTransactionCache(coin: Coin.namecoin)) +// .thenAnswer((realInvocation) async {}); +// +// final wallet = await Hive.openBox(testWalletId); +// +// // restore so we have something to rescan +// await nmc?.recoverFromMnemonic( +// mnemonic: TEST_MNEMONIC, +// maxUnusedAddressGap: 2, +// maxNumberOfIndexesToCheck: 1000, +// height: 4000); +// +// // fetch wallet data +// final preReceivingAddressesP2PKH = +// await wallet.get('receivingAddressesP2PKH'); +// final preReceivingAddressesP2SH = +// await wallet.get('receivingAddressesP2SH'); +// final preReceivingAddressesP2WPKH = +// await wallet.get('receivingAddressesP2WPKH'); +// final preChangeAddressesP2PKH = await wallet.get('changeAddressesP2PKH'); +// final preChangeAddressesP2SH = await wallet.get('changeAddressesP2SH'); +// final preChangeAddressesP2WPKH = +// await wallet.get('changeAddressesP2WPKH'); +// final preReceivingIndexP2PKH = await wallet.get('receivingIndexP2PKH'); +// final preReceivingIndexP2SH = await wallet.get('receivingIndexP2SH'); +// final preReceivingIndexP2WPKH = await wallet.get('receivingIndexP2WPKH'); +// final preChangeIndexP2PKH = await wallet.get('changeIndexP2PKH'); +// final preChangeIndexP2SH = await wallet.get('changeIndexP2SH'); +// final preChangeIndexP2WPKH = await wallet.get('changeIndexP2WPKH'); +// final preUtxoData = await wallet.get('latest_utxo_model'); +// final preReceiveDerivationsStringP2PKH = await secureStore?.read( +// key: "${testWalletId}_receiveDerivationsP2PKH"); +// final preChangeDerivationsStringP2PKH = await secureStore?.read( +// key: "${testWalletId}_changeDerivationsP2PKH"); +// final preReceiveDerivationsStringP2SH = await secureStore?.read( +// key: "${testWalletId}_receiveDerivationsP2SH"); +// final preChangeDerivationsStringP2SH = +// await secureStore?.read(key: "${testWalletId}_changeDerivationsP2SH"); +// final preReceiveDerivationsStringP2WPKH = await secureStore?.read( +// key: "${testWalletId}_receiveDerivationsP2WPKH"); +// final preChangeDerivationsStringP2WPKH = await secureStore?.read( +// key: "${testWalletId}_changeDerivationsP2WPKH"); +// +// when(client?.getBatchHistory(args: historyBatchArgs0)) +// .thenThrow(Exception("fake exception")); +// +// bool hasThrown = false; +// try { +// await nmc?.fullRescan(2, 1000); +// } catch (_) { +// hasThrown = true; +// } +// expect(hasThrown, true); +// +// // fetch wallet data again +// final receivingAddressesP2PKH = +// await wallet.get('receivingAddressesP2PKH'); +// final receivingAddressesP2SH = await wallet.get('receivingAddressesP2SH'); +// final receivingAddressesP2WPKH = +// await wallet.get('receivingAddressesP2WPKH'); +// final changeAddressesP2PKH = await wallet.get('changeAddressesP2PKH'); +// final changeAddressesP2SH = await wallet.get('changeAddressesP2SH'); +// final changeAddressesP2WPKH = await wallet.get('changeAddressesP2WPKH'); +// final receivingIndexP2PKH = await wallet.get('receivingIndexP2PKH'); +// final receivingIndexP2SH = await wallet.get('receivingIndexP2SH'); +// final receivingIndexP2WPKH = await wallet.get('receivingIndexP2WPKH'); +// final changeIndexP2PKH = await wallet.get('changeIndexP2PKH'); +// final changeIndexP2SH = await wallet.get('changeIndexP2SH'); +// final changeIndexP2WPKH = await wallet.get('changeIndexP2WPKH'); +// final utxoData = await wallet.get('latest_utxo_model'); +// final receiveDerivationsStringP2PKH = await secureStore?.read( +// key: "${testWalletId}_receiveDerivationsP2PKH"); +// final changeDerivationsStringP2PKH = await secureStore?.read( +// key: "${testWalletId}_changeDerivationsP2PKH"); +// final receiveDerivationsStringP2SH = await secureStore?.read( +// key: "${testWalletId}_receiveDerivationsP2SH"); +// final changeDerivationsStringP2SH = +// await secureStore?.read(key: "${testWalletId}_changeDerivationsP2SH"); +// final receiveDerivationsStringP2WPKH = await secureStore?.read( +// key: "${testWalletId}_receiveDerivationsP2WPKH"); +// final changeDerivationsStringP2WPKH = await secureStore?.read( +// key: "${testWalletId}_changeDerivationsP2WPKH"); +// +// expect(preReceivingAddressesP2PKH, receivingAddressesP2PKH); +// expect(preReceivingAddressesP2SH, receivingAddressesP2SH); +// expect(preReceivingAddressesP2WPKH, receivingAddressesP2WPKH); +// expect(preChangeAddressesP2PKH, changeAddressesP2PKH); +// expect(preChangeAddressesP2SH, changeAddressesP2SH); +// expect(preChangeAddressesP2WPKH, changeAddressesP2WPKH); +// expect(preReceivingIndexP2PKH, receivingIndexP2PKH); +// expect(preReceivingIndexP2SH, receivingIndexP2SH); +// expect(preReceivingIndexP2WPKH, receivingIndexP2WPKH); +// expect(preChangeIndexP2PKH, changeIndexP2PKH); +// expect(preChangeIndexP2SH, changeIndexP2SH); +// expect(preChangeIndexP2WPKH, changeIndexP2WPKH); +// expect(preUtxoData, utxoData); +// expect(preReceiveDerivationsStringP2PKH, receiveDerivationsStringP2PKH); +// expect(preChangeDerivationsStringP2PKH, changeDerivationsStringP2PKH); +// expect(preReceiveDerivationsStringP2SH, receiveDerivationsStringP2SH); +// expect(preChangeDerivationsStringP2SH, changeDerivationsStringP2SH); +// expect(preReceiveDerivationsStringP2WPKH, receiveDerivationsStringP2WPKH); +// expect(preChangeDerivationsStringP2WPKH, changeDerivationsStringP2WPKH); +// +// verify(client?.getServerFeatures()).called(1); +// verify(client?.getBatchHistory(args: historyBatchArgs0)).called(2); +// verify(client?.getBatchHistory(args: historyBatchArgs1)).called(2); +// verify(client?.getBatchHistory(args: historyBatchArgs2)).called(2); +// verify(client?.getBatchHistory(args: historyBatchArgs3)).called(2); +// verify(client?.getBatchHistory(args: historyBatchArgs4)).called(2); +// verify(client?.getBatchHistory(args: historyBatchArgs5)).called(2); +// +// verify(client?.getBatchHistory(args: { +// "0": [ +// "dd63fc12f5e6c1ada2cf3c941d1648e6d561ce4024747bb2117d72112d83287c" +// ] +// })).called(2); +// verify(client?.getBatchHistory(args: { +// "0": [ +// "cd3dd4abe4f9efc7149ba334d2d6790020331805b0bd5c7ed89a3ac6a22f10b9" +// ] +// })).called(1); +// verify(client?.getBatchHistory(args: { +// "0": [ +// "42d6e40636f4740f9c7f95ef0bbc2a4c17f54da2bc98a32a622e2bf73eb675c3" +// ] +// })).called(2); +// verify(client?.getBatchHistory(args: { +// "0": [ +// "587943864cefed4f1643a5ee2ce2b3c13a0c6ad7c435373f0ac328e144a15c1e" +// ] +// })).called(2); +// verify(client?.getBatchHistory(args: { +// "0": [ +// "86906979fc9107d06d560275d7de8305b69d7189c3206ac9070ad76e6abff874" +// ] +// })).called(2); +// verify(client?.getBatchHistory(args: { +// "0": [ +// "c068e7fa4aa0b8a63114f6d11c047ca4be6a8fa333eb0dac48506e8f150af73b" +// ] +// })).called(2); +// verify(cachedClient?.clearSharedTransactionCache(coin: Coin.namecoin)) +// .called(1); +// +// expect(secureStore?.writes, 19); +// expect(secureStore?.reads, 32); +// expect(secureStore?.deletes, 12); +// +// verifyNoMoreInteractions(client); +// verifyNoMoreInteractions(cachedClient); +// verifyNoMoreInteractions(priceAPI); +// }); +// +// test("prepareSend fails", () async { +// when(client?.getServerFeatures()).thenAnswer((_) async => { +// "hosts": {}, +// "pruning": null, +// "server_version": "Unit tests", +// "protocol_min": "1.4", +// "protocol_max": "1.4.2", +// "genesis_hash": GENESIS_HASH_MAINNET, +// "hash_function": "sha256", +// "services": [] +// }); +// when(client?.getBatchHistory(args: historyBatchArgs0)) +// .thenAnswer((_) async => historyBatchResponse); +// when(client?.getBatchHistory(args: historyBatchArgs1)) +// .thenAnswer((_) async => historyBatchResponse); +// when(client?.getBatchHistory(args: historyBatchArgs2)) +// .thenAnswer((_) async => historyBatchResponse); +// when(client?.getBatchHistory(args: historyBatchArgs3)) +// .thenAnswer((_) async => historyBatchResponse); +// when(client?.getBatchHistory(args: historyBatchArgs4)) +// .thenAnswer((_) async => historyBatchResponse); +// when(client?.getBatchHistory(args: historyBatchArgs5)) +// .thenAnswer((_) async => historyBatchResponse); +// +// List dynamicArgValues = []; +// +// when(client?.getBatchHistory(args: anyNamed("args"))) +// .thenAnswer((realInvocation) async { +// if (realInvocation.namedArguments.values.first.length == 1) { +// dynamicArgValues.add(realInvocation.namedArguments.values.first); +// } +// +// return historyBatchResponse; +// }); +// +// await Hive.openBox(testWalletId); +// +// when(cachedClient?.getTransaction( +// txHash: +// "dffa9543852197f9fb90f8adafaab8a0b9b4925e9ada8c6bdcaf00bf2e9f60d7", +// coin: Coin.namecoin)) +// .thenAnswer((_) async => tx2Raw); +// when(cachedClient?.getTransaction( +// txHash: +// "71b56532e9e7321bd8c30d0f8b14530743049d2f3edd5623065c46eee1dda04d", +// coin: Coin.namecoin)) +// .thenAnswer((_) async => tx3Raw); +// when(cachedClient?.getTransaction( +// txHash: +// "c7e700f7e23a85bbdd9de86d502322a933607ee7ea7e16adaf02e477cdd849b9", +// coin: Coin.namecoin, +// )).thenAnswer((_) async => tx4Raw); +// +// // recover to fill data +// await nmc?.recoverFromMnemonic( +// mnemonic: TEST_MNEMONIC, +// maxUnusedAddressGap: 2, +// maxNumberOfIndexesToCheck: 1000, +// height: 4000); +// +// // modify addresses to properly mock data to build a tx +// final rcv44 = await secureStore?.read( +// key: testWalletId + "_receiveDerivationsP2PKH"); +// await secureStore?.write( +// key: testWalletId + "_receiveDerivationsP2PKH", +// value: rcv44?.replaceFirst("1RMSPixoLPuaXuhR2v4HsUMcRjLncKDaw", +// "16FuTPaeRSPVxxCnwQmdyx2PQWxX6HWzhQ")); +// final rcv49 = await secureStore?.read( +// key: testWalletId + "_receiveDerivationsP2SH"); +// await secureStore?.write( +// key: testWalletId + "_receiveDerivationsP2SH", +// value: rcv49?.replaceFirst("3AV74rKfibWmvX34F99yEvUcG4LLQ9jZZk", +// "36NvZTcMsMowbt78wPzJaHHWaNiyR73Y4g")); +// final rcv84 = await secureStore?.read( +// key: testWalletId + "_receiveDerivationsP2WPKH"); +// await secureStore?.write( +// key: testWalletId + "_receiveDerivationsP2WPKH", +// value: rcv84?.replaceFirst( +// "bc1qggtj4ka8jsaj44hhd5mpamx7mp34m2d3w7k0m0", +// "bc1q42lja79elem0anu8q8s3h2n687re9jax556pcc")); +// +// nmc?.outputsList = utxoList; +// +// bool didThrow = false; +// try { +// await nmc?.prepareSend( +// address: "nc1q6k4x8ye6865z3rc8zkt8gyu52na7njqt6hsk4v", +// satoshiAmount: 15000); +// } catch (_) { +// didThrow = true; +// } +// +// expect(didThrow, true); +// +// verify(client?.getServerFeatures()).called(1); +// +// /// verify transaction no matching calls +// +// // verify(cachedClient?.getTransaction( +// // txHash: +// // "2087ce09bc316877c9f10971526a2bffa3078d52ea31752639305cdcd8230703", +// // coin: Coin.namecoin, +// // callOutSideMainIsolate: false)) +// // .called(1); +// // verify(cachedClient?.getTransaction( +// // txHash: +// // "ed32c967a0e86d51669ac21c2bb9bc9c50f0f55fbacdd8db21d0a986fba93bd7", +// // coin: Coin.namecoin, +// // callOutSideMainIsolate: false)) +// // .called(1); +// // verify(cachedClient?.getTransaction( +// // txHash: +// // "3f0032f89ac44b281b50314cff3874c969c922839dddab77ced54e86a21c3fd4", +// // coin: Coin.namecoin, +// // callOutSideMainIsolate: false)) +// // .called(1); +// verify(client?.getBatchHistory(args: historyBatchArgs0)).called(1); +// verify(client?.getBatchHistory(args: historyBatchArgs1)).called(1); +// verify(client?.getBatchHistory(args: historyBatchArgs2)).called(1); +// verify(client?.getBatchHistory(args: historyBatchArgs3)).called(1); +// verify(client?.getBatchHistory(args: historyBatchArgs4)).called(1); +// verify(client?.getBatchHistory(args: historyBatchArgs5)).called(1); +// +// for (final arg in dynamicArgValues) { +// final map = Map>.from(arg as Map); +// +// verify(client?.getBatchHistory(args: map)).called(1); +// expect(activeScriptHashes.contains(map.values.first.first as String), +// true); +// } +// +// expect(secureStore?.interactions, 20); +// expect(secureStore?.writes, 10); +// expect(secureStore?.reads, 10); +// expect(secureStore?.deletes, 0); +// +// verifyNoMoreInteractions(client); +// verifyNoMoreInteractions(cachedClient); +// verifyNoMoreInteractions(priceAPI); +// }); +// +// test("confirmSend no hex", () async { +// bool didThrow = false; +// try { +// await nmc?.confirmSend(txData: {"some": "strange map"}); +// } catch (_) { +// didThrow = true; +// } +// +// expect(didThrow, true); +// +// expect(secureStore?.interactions, 0); +// verifyNoMoreInteractions(client); +// verifyNoMoreInteractions(cachedClient); +// verifyNoMoreInteractions(priceAPI); +// }); +// +// test("confirmSend hex is not string", () async { +// bool didThrow = false; +// try { +// await nmc?.confirmSend(txData: {"hex": true}); +// } catch (_) { +// didThrow = true; +// } +// +// expect(didThrow, true); +// +// expect(secureStore?.interactions, 0); +// verifyNoMoreInteractions(client); +// verifyNoMoreInteractions(cachedClient); +// verifyNoMoreInteractions(priceAPI); +// }); +// +// test("confirmSend hex is string but missing other data", () async { +// bool didThrow = false; +// try { +// await nmc?.confirmSend(txData: {"hex": "a string"}); +// } catch (_) { +// didThrow = true; +// } +// +// expect(didThrow, true); +// +// verify(client?.broadcastTransaction( +// rawTx: "a string", requestID: anyNamed("requestID"))) +// .called(1); +// +// expect(secureStore?.interactions, 0); +// verifyNoMoreInteractions(client); +// verifyNoMoreInteractions(cachedClient); +// verifyNoMoreInteractions(priceAPI); +// }); +// +// test("confirmSend fails due to vSize being greater than fee", () async { +// bool didThrow = false; +// try { +// await nmc +// ?.confirmSend(txData: {"hex": "a string", "fee": 1, "vSize": 10}); +// } catch (_) { +// didThrow = true; +// } +// +// expect(didThrow, true); +// +// verify(client?.broadcastTransaction( +// rawTx: "a string", requestID: anyNamed("requestID"))) +// .called(1); +// +// expect(secureStore?.interactions, 0); +// verifyNoMoreInteractions(client); +// verifyNoMoreInteractions(cachedClient); +// verifyNoMoreInteractions(priceAPI); +// }); +// +// test("confirmSend fails when broadcast transactions throws", () async { +// when(client?.broadcastTransaction( +// rawTx: "a string", requestID: anyNamed("requestID"))) +// .thenThrow(Exception("some exception")); +// +// bool didThrow = false; +// try { +// await nmc +// ?.confirmSend(txData: {"hex": "a string", "fee": 10, "vSize": 10}); +// } catch (_) { +// didThrow = true; +// } +// +// expect(didThrow, true); +// +// verify(client?.broadcastTransaction( +// rawTx: "a string", requestID: anyNamed("requestID"))) +// .called(1); +// +// expect(secureStore?.interactions, 0); +// verifyNoMoreInteractions(client); +// verifyNoMoreInteractions(cachedClient); +// verifyNoMoreInteractions(tracker); +// verifyNoMoreInteractions(priceAPI); +// }); +// // +// // // this test will create a non mocked electrumx client that will try to connect +// // // to the provided ipAddress below. This will throw a bunch of errors +// // // which what we want here as actually calling electrumx calls here is unwanted. +// // // test("listen to NodesChangedEvent", () async { +// // // nmc = NamecoinWallet( +// // // walletId: testWalletId, +// // // walletName: testWalletName, +// // // networkType: BasicNetworkType.test, +// // // client: client, +// // // cachedClient: cachedClient, +// // // priceAPI: priceAPI, +// // // secureStore: secureStore, +// // // ); +// // // +// // // // set node +// // // final wallet = await Hive.openBox(testWalletId); +// // // await wallet.put("nodes", { +// // // "default": { +// // // "id": "some nodeID", +// // // "ipAddress": "some address", +// // // "port": "9000", +// // // "useSSL": true, +// // // } +// // // }); +// // // await wallet.put("activeNodeID_Bitcoin", "default"); +// // // +// // // final a = nmc.cachedElectrumXClient; +// // // +// // // // return when refresh is called on node changed trigger +// // // nmc.longMutex = true; +// // // +// // // GlobalEventBus.instance +// // // .fire(NodesChangedEvent(NodesChangedEventType.updatedCurrentNode)); +// // // +// // // // make sure event has processed before continuing +// // // await Future.delayed(Duration(seconds: 5)); +// // // +// // // final b = nmc.cachedElectrumXClient; +// // // +// // // expect(identical(a, b), false); +// // // +// // // await nmc.exit(); +// // // +// // // expect(secureStore.interactions, 0); +// // // verifyNoMoreInteractions(client); +// // // verifyNoMoreInteractions(cachedClient); +// // // verifyNoMoreInteractions(priceAPI); +// // // }); +// +// test("refresh wallet mutex locked", () async { +// when(client?.getServerFeatures()).thenAnswer((_) async => { +// "hosts": {}, +// "pruning": null, +// "server_version": "Unit tests", +// "protocol_min": "1.4", +// "protocol_max": "1.4.2", +// "genesis_hash": GENESIS_HASH_MAINNET, +// "hash_function": "sha256", +// "services": [] +// }); +// when(client?.getBatchHistory(args: historyBatchArgs0)) +// .thenAnswer((_) async => historyBatchResponse); +// when(client?.getBatchHistory(args: historyBatchArgs1)) +// .thenAnswer((_) async => historyBatchResponse); +// when(client?.getBatchHistory(args: historyBatchArgs2)) +// .thenAnswer((_) async => historyBatchResponse); +// when(client?.getBatchHistory(args: historyBatchArgs3)) +// .thenAnswer((_) async => historyBatchResponse); +// when(client?.getBatchHistory(args: historyBatchArgs4)) +// .thenAnswer((_) async => historyBatchResponse); +// when(client?.getBatchHistory(args: historyBatchArgs5)) +// .thenAnswer((_) async => historyBatchResponse); +// +// List dynamicArgValues = []; +// +// when(client?.getBatchHistory(args: anyNamed("args"))) +// .thenAnswer((realInvocation) async { +// if (realInvocation.namedArguments.values.first.length == 1) { +// dynamicArgValues.add(realInvocation.namedArguments.values.first); +// } +// +// return historyBatchResponse; +// }); +// +// await Hive.openBox(testWalletId); +// +// // recover to fill data +// await nmc?.recoverFromMnemonic( +// mnemonic: TEST_MNEMONIC, +// maxUnusedAddressGap: 2, +// maxNumberOfIndexesToCheck: 1000, +// height: 4000); +// +// nmc?.refreshMutex = true; +// +// await nmc?.refresh(); +// +// verify(client?.getServerFeatures()).called(1); +// verify(client?.getBatchHistory(args: historyBatchArgs0)).called(1); +// verify(client?.getBatchHistory(args: historyBatchArgs1)).called(1); +// verify(client?.getBatchHistory(args: historyBatchArgs2)).called(1); +// verify(client?.getBatchHistory(args: historyBatchArgs3)).called(1); +// verify(client?.getBatchHistory(args: historyBatchArgs4)).called(1); +// verify(client?.getBatchHistory(args: historyBatchArgs5)).called(1); +// +// for (final arg in dynamicArgValues) { +// final map = Map>.from(arg as Map); +// +// verify(client?.getBatchHistory(args: map)).called(1); +// expect(activeScriptHashes.contains(map.values.first.first as String), +// true); +// } +// +// expect(secureStore?.interactions, 14); +// expect(secureStore?.writes, 7); +// expect(secureStore?.reads, 7); +// expect(secureStore?.deletes, 0); +// +// verifyNoMoreInteractions(client); +// verifyNoMoreInteractions(cachedClient); +// verifyNoMoreInteractions(tracker); +// verifyNoMoreInteractions(priceAPI); +// }); +// +// test("refresh wallet normally", () async { +// when(client?.getBlockHeadTip()).thenAnswer((realInvocation) async => +// {"height": 520481, "hex": "some block hex"}); +// when(client?.getServerFeatures()).thenAnswer((_) async => { +// "hosts": {}, +// "pruning": null, +// "server_version": "Unit tests", +// "protocol_min": "1.4", +// "protocol_max": "1.4.2", +// "genesis_hash": GENESIS_HASH_MAINNET, +// "hash_function": "sha256", +// "services": [] +// }); +// when(client?.getHistory(scripthash: anyNamed("scripthash"))) +// .thenAnswer((_) async => []); +// when(client?.estimateFee(blocks: anyNamed("blocks"))) +// .thenAnswer((_) async => Decimal.one); +// +// when(priceAPI?.getPricesAnd24hChange(baseCurrency: "USD")) +// .thenAnswer((_) async => {Coin.namecoin: Tuple2(Decimal.one, 0.3)}); +// +// final List dynamicArgValues = []; +// +// when(client?.getBatchHistory(args: anyNamed("args"))) +// .thenAnswer((realInvocation) async { +// dynamicArgValues.add(realInvocation.namedArguments.values.first); +// return historyBatchResponse; +// }); +// +// await Hive.openBox(testWalletId); +// +// // recover to fill data +// await nmc?.recoverFromMnemonic( +// mnemonic: TEST_MNEMONIC, +// maxUnusedAddressGap: 2, +// maxNumberOfIndexesToCheck: 1000, +// height: 4000); +// +// when(client?.getBatchHistory(args: anyNamed("args"))) +// .thenAnswer((_) async => {}); +// when(client?.getBatchUTXOs(args: anyNamed("args"))) +// .thenAnswer((_) async => emptyHistoryBatchResponse); +// +// await nmc?.refresh(); +// +// verify(client?.getServerFeatures()).called(1); +// verify(client?.getHistory(scripthash: anyNamed("scripthash"))).called(4); +// verify(client?.estimateFee(blocks: anyNamed("blocks"))).called(3); +// verify(client?.getBlockHeadTip()).called(1); +// verify(priceAPI?.getPricesAnd24hChange(baseCurrency: "USD")).called(2); +// +// for (final arg in dynamicArgValues) { +// final map = Map>.from(arg as Map); +// +// verify(client?.getBatchHistory(args: map)).called(1); +// } +// +// expect(secureStore?.interactions, 14); +// expect(secureStore?.writes, 7); +// expect(secureStore?.reads, 7); +// expect(secureStore?.deletes, 0); +// +// // verifyNoMoreInteractions(client); +// verifyNoMoreInteractions(cachedClient); +// verifyNoMoreInteractions(priceAPI); +// }); +// +// tearDown(() async { +// await tearDownTestHive(); +// }); +// }); +// } diff --git a/test/services/coins/namecoin/namecoin_wallet_test.mocks.dart b/test/services/coins/namecoin/namecoin_wallet_test.mocks.dart new file mode 100644 index 000000000..d86949a61 --- /dev/null +++ b/test/services/coins/namecoin/namecoin_wallet_test.mocks.dart @@ -0,0 +1,352 @@ +// Mocks generated by Mockito 5.2.0 from annotations +// in stackwallet/test/services/coins/namecoin/namecoin_wallet_test.dart. +// Do not manually edit this file. + +import 'dart:async' as _i6; + +import 'package:decimal/decimal.dart' as _i2; +import 'package:http/http.dart' as _i4; +import 'package:mockito/mockito.dart' as _i1; +import 'package:stackwallet/electrumx_rpc/cached_electrumx.dart' as _i7; +import 'package:stackwallet/electrumx_rpc/electrumx.dart' as _i5; +import 'package:stackwallet/services/price.dart' as _i9; +import 'package:stackwallet/services/transaction_notification_tracker.dart' + as _i11; +import 'package:stackwallet/utilities/enums/coin_enum.dart' as _i8; +import 'package:stackwallet/utilities/prefs.dart' as _i3; +import 'package:tuple/tuple.dart' as _i10; + +// ignore_for_file: type=lint +// ignore_for_file: avoid_redundant_argument_values +// ignore_for_file: avoid_setters_without_getters +// ignore_for_file: comment_references +// ignore_for_file: implementation_imports +// ignore_for_file: invalid_use_of_visible_for_testing_member +// ignore_for_file: prefer_const_constructors +// ignore_for_file: unnecessary_parenthesis +// ignore_for_file: camel_case_types + +class _FakeDecimal_0 extends _i1.Fake implements _i2.Decimal {} + +class _FakePrefs_1 extends _i1.Fake implements _i3.Prefs {} + +class _FakeClient_2 extends _i1.Fake implements _i4.Client {} + +/// A class which mocks [ElectrumX]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockElectrumX extends _i1.Mock implements _i5.ElectrumX { + MockElectrumX() { + _i1.throwOnMissingStub(this); + } + + @override + set failovers(List<_i5.ElectrumXNode>? _failovers) => + super.noSuchMethod(Invocation.setter(#failovers, _failovers), + returnValueForMissingStub: null); + @override + int get currentFailoverIndex => + (super.noSuchMethod(Invocation.getter(#currentFailoverIndex), + returnValue: 0) as int); + @override + set currentFailoverIndex(int? _currentFailoverIndex) => super.noSuchMethod( + Invocation.setter(#currentFailoverIndex, _currentFailoverIndex), + returnValueForMissingStub: null); + @override + String get host => + (super.noSuchMethod(Invocation.getter(#host), returnValue: '') as String); + @override + int get port => + (super.noSuchMethod(Invocation.getter(#port), returnValue: 0) as int); + @override + bool get useSSL => + (super.noSuchMethod(Invocation.getter(#useSSL), returnValue: false) + as bool); + @override + _i6.Future request( + {String? command, + List? args = const [], + Duration? connectionTimeout = const Duration(seconds: 60), + String? requestID, + int? retries = 2}) => + (super.noSuchMethod( + Invocation.method(#request, [], { + #command: command, + #args: args, + #connectionTimeout: connectionTimeout, + #requestID: requestID, + #retries: retries + }), + returnValue: Future.value()) as _i6.Future); + @override + _i6.Future>> batchRequest( + {String? command, + Map>? args, + Duration? connectionTimeout = const Duration(seconds: 60), + int? retries = 2}) => + (super.noSuchMethod( + Invocation.method(#batchRequest, [], { + #command: command, + #args: args, + #connectionTimeout: connectionTimeout, + #retries: retries + }), + returnValue: Future>>.value( + >[])) + as _i6.Future>>); + @override + _i6.Future ping({String? requestID, int? retryCount = 1}) => + (super.noSuchMethod( + Invocation.method( + #ping, [], {#requestID: requestID, #retryCount: retryCount}), + returnValue: Future.value(false)) as _i6.Future); + @override + _i6.Future> getBlockHeadTip({String? requestID}) => + (super.noSuchMethod( + Invocation.method(#getBlockHeadTip, [], {#requestID: requestID}), + returnValue: + Future>.value({})) + as _i6.Future>); + @override + _i6.Future> getServerFeatures({String? requestID}) => + (super.noSuchMethod( + Invocation.method(#getServerFeatures, [], {#requestID: requestID}), + returnValue: + Future>.value({})) as _i6 + .Future>); + @override + _i6.Future broadcastTransaction({String? rawTx, String? requestID}) => + (super.noSuchMethod( + Invocation.method(#broadcastTransaction, [], + {#rawTx: rawTx, #requestID: requestID}), + returnValue: Future.value('')) as _i6.Future); + @override + _i6.Future> getBalance( + {String? scripthash, String? requestID}) => + (super.noSuchMethod( + Invocation.method(#getBalance, [], + {#scripthash: scripthash, #requestID: requestID}), + returnValue: + Future>.value({})) + as _i6.Future>); + @override + _i6.Future>> getHistory( + {String? scripthash, String? requestID}) => + (super.noSuchMethod( + Invocation.method(#getHistory, [], + {#scripthash: scripthash, #requestID: requestID}), + returnValue: Future>>.value( + >[])) + as _i6.Future>>); + @override + _i6.Future>>> getBatchHistory( + {Map>? args}) => + (super.noSuchMethod( + Invocation.method(#getBatchHistory, [], {#args: args}), + returnValue: Future>>>.value( + >>{})) as _i6 + .Future>>>); + @override + _i6.Future>> getUTXOs( + {String? scripthash, String? requestID}) => + (super.noSuchMethod( + Invocation.method( + #getUTXOs, [], {#scripthash: scripthash, #requestID: requestID}), + returnValue: Future>>.value( + >[])) as _i6 + .Future>>); + @override + _i6.Future>>> getBatchUTXOs( + {Map>? args}) => + (super.noSuchMethod(Invocation.method(#getBatchUTXOs, [], {#args: args}), + returnValue: Future>>>.value( + >>{})) as _i6 + .Future>>>); + @override + _i6.Future> getTransaction( + {String? txHash, bool? verbose = true, String? requestID}) => + (super.noSuchMethod( + Invocation.method(#getTransaction, [], + {#txHash: txHash, #verbose: verbose, #requestID: requestID}), + returnValue: + Future>.value({})) + as _i6.Future>); + @override + _i6.Future> getAnonymitySet( + {String? groupId = r'1', + String? blockhash = r'', + String? requestID}) => + (super.noSuchMethod( + Invocation.method(#getAnonymitySet, [], { + #groupId: groupId, + #blockhash: blockhash, + #requestID: requestID + }), + returnValue: + Future>.value({})) + as _i6.Future>); + @override + _i6.Future getMintData({dynamic mints, String? requestID}) => + (super.noSuchMethod( + Invocation.method( + #getMintData, [], {#mints: mints, #requestID: requestID}), + returnValue: Future.value()) as _i6.Future); + @override + _i6.Future> getUsedCoinSerials( + {String? requestID, int? startNumber}) => + (super.noSuchMethod( + Invocation.method(#getUsedCoinSerials, [], + {#requestID: requestID, #startNumber: startNumber}), + returnValue: + Future>.value({})) + as _i6.Future>); + @override + _i6.Future getLatestCoinId({String? requestID}) => (super.noSuchMethod( + Invocation.method(#getLatestCoinId, [], {#requestID: requestID}), + returnValue: Future.value(0)) as _i6.Future); + @override + _i6.Future> getFeeRate({String? requestID}) => (super + .noSuchMethod(Invocation.method(#getFeeRate, [], {#requestID: requestID}), + returnValue: + Future>.value({})) as _i6 + .Future>); + @override + _i6.Future<_i2.Decimal> estimateFee({String? requestID, int? blocks}) => + (super.noSuchMethod( + Invocation.method( + #estimateFee, [], {#requestID: requestID, #blocks: blocks}), + returnValue: Future<_i2.Decimal>.value(_FakeDecimal_0())) + as _i6.Future<_i2.Decimal>); + @override + _i6.Future<_i2.Decimal> relayFee({String? requestID}) => (super.noSuchMethod( + Invocation.method(#relayFee, [], {#requestID: requestID}), + returnValue: Future<_i2.Decimal>.value(_FakeDecimal_0())) + as _i6.Future<_i2.Decimal>); +} + +/// A class which mocks [CachedElectrumX]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockCachedElectrumX extends _i1.Mock implements _i7.CachedElectrumX { + MockCachedElectrumX() { + _i1.throwOnMissingStub(this); + } + + @override + String get server => + (super.noSuchMethod(Invocation.getter(#server), returnValue: '') + as String); + @override + int get port => + (super.noSuchMethod(Invocation.getter(#port), returnValue: 0) as int); + @override + bool get useSSL => + (super.noSuchMethod(Invocation.getter(#useSSL), returnValue: false) + as bool); + @override + _i3.Prefs get prefs => (super.noSuchMethod(Invocation.getter(#prefs), + returnValue: _FakePrefs_1()) as _i3.Prefs); + @override + List<_i5.ElectrumXNode> get failovers => + (super.noSuchMethod(Invocation.getter(#failovers), + returnValue: <_i5.ElectrumXNode>[]) as List<_i5.ElectrumXNode>); + @override + _i6.Future> getAnonymitySet( + {String? groupId, String? blockhash = r'', _i8.Coin? coin}) => + (super.noSuchMethod( + Invocation.method(#getAnonymitySet, [], + {#groupId: groupId, #blockhash: blockhash, #coin: coin}), + returnValue: + Future>.value({})) + as _i6.Future>); + @override + _i6.Future> getTransaction( + {String? txHash, _i8.Coin? coin, bool? verbose = true}) => + (super.noSuchMethod( + Invocation.method(#getTransaction, [], + {#txHash: txHash, #coin: coin, #verbose: verbose}), + returnValue: + Future>.value({})) + as _i6.Future>); + @override + _i6.Future> getUsedCoinSerials( + {_i8.Coin? coin, int? startNumber = 0}) => + (super.noSuchMethod( + Invocation.method(#getUsedCoinSerials, [], + {#coin: coin, #startNumber: startNumber}), + returnValue: Future>.value([])) + as _i6.Future>); + @override + _i6.Future clearSharedTransactionCache({_i8.Coin? coin}) => + (super.noSuchMethod( + Invocation.method(#clearSharedTransactionCache, [], {#coin: coin}), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i6.Future); +} + +/// A class which mocks [PriceAPI]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockPriceAPI extends _i1.Mock implements _i9.PriceAPI { + MockPriceAPI() { + _i1.throwOnMissingStub(this); + } + + @override + _i4.Client get client => (super.noSuchMethod(Invocation.getter(#client), + returnValue: _FakeClient_2()) as _i4.Client); + @override + void resetLastCalledToForceNextCallToUpdateCache() => super.noSuchMethod( + Invocation.method(#resetLastCalledToForceNextCallToUpdateCache, []), + returnValueForMissingStub: null); + @override + _i6.Future>> + getPricesAnd24hChange({String? baseCurrency}) => (super.noSuchMethod( + Invocation.method( + #getPricesAnd24hChange, [], {#baseCurrency: baseCurrency}), + returnValue: + Future>>.value( + <_i8.Coin, _i10.Tuple2<_i2.Decimal, double>>{})) + as _i6.Future>>); +} + +/// A class which mocks [TransactionNotificationTracker]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockTransactionNotificationTracker extends _i1.Mock + implements _i11.TransactionNotificationTracker { + MockTransactionNotificationTracker() { + _i1.throwOnMissingStub(this); + } + + @override + String get walletId => + (super.noSuchMethod(Invocation.getter(#walletId), returnValue: '') + as String); + @override + List get pendings => + (super.noSuchMethod(Invocation.getter(#pendings), returnValue: []) + as List); + @override + List get confirmeds => (super + .noSuchMethod(Invocation.getter(#confirmeds), returnValue: []) + as List); + @override + bool wasNotifiedPending(String? txid) => + (super.noSuchMethod(Invocation.method(#wasNotifiedPending, [txid]), + returnValue: false) as bool); + @override + _i6.Future addNotifiedPending(String? txid) => + (super.noSuchMethod(Invocation.method(#addNotifiedPending, [txid]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i6.Future); + @override + bool wasNotifiedConfirmed(String? txid) => + (super.noSuchMethod(Invocation.method(#wasNotifiedConfirmed, [txid]), + returnValue: false) as bool); + @override + _i6.Future addNotifiedConfirmed(String? txid) => + (super.noSuchMethod(Invocation.method(#addNotifiedConfirmed, [txid]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i6.Future); +} diff --git a/test/widget_tests/custom_buttons/app_bar_icon_button_test.dart b/test/widget_tests/custom_buttons/app_bar_icon_button_test.dart index 12fba17fd..36179deaf 100644 --- a/test/widget_tests/custom_buttons/app_bar_icon_button_test.dart +++ b/test/widget_tests/custom_buttons/app_bar_icon_button_test.dart @@ -1,5 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:stackwallet/utilities/theme/light_colors.dart'; +import 'package:stackwallet/utilities/theme/stack_colors.dart'; import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart'; void main() { @@ -19,6 +21,11 @@ void main() { await tester.pumpWidget( MaterialApp( + theme: ThemeData( + extensions: [ + StackColors.fromStackColorTheme(LightColors()), + ], + ), home: Material( child: button, ), diff --git a/test/widget_tests/custom_buttons/draggable_switch_button_test.dart b/test/widget_tests/custom_buttons/draggable_switch_button_test.dart index d9cd53508..d8366a1f0 100644 --- a/test/widget_tests/custom_buttons/draggable_switch_button_test.dart +++ b/test/widget_tests/custom_buttons/draggable_switch_button_test.dart @@ -1,5 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:stackwallet/utilities/theme/light_colors.dart'; +import 'package:stackwallet/utilities/theme/stack_colors.dart'; import 'package:stackwallet/widgets/custom_buttons/draggable_switch_button.dart'; void main() { @@ -15,6 +17,11 @@ void main() { await tester.pumpWidget( MaterialApp( + theme: ThemeData( + extensions: [ + StackColors.fromStackColorTheme(LightColors()), + ], + ), home: button, ), ); @@ -37,6 +44,11 @@ void main() { await tester.pumpWidget( MaterialApp( + theme: ThemeData( + extensions: [ + StackColors.fromStackColorTheme(LightColors()), + ], + ), home: SizedBox( width: 200, height: 60, @@ -64,6 +76,11 @@ void main() { await tester.pumpWidget( MaterialApp( + theme: ThemeData( + extensions: [ + StackColors.fromStackColorTheme(LightColors()), + ], + ), home: SizedBox( width: 200, height: 60, diff --git a/test/widget_tests/custom_pin_put_test.dart b/test/widget_tests/custom_pin_put_test.dart index 05a7894ad..d3a449865 100644 --- a/test/widget_tests/custom_pin_put_test.dart +++ b/test/widget_tests/custom_pin_put_test.dart @@ -1,6 +1,8 @@ import 'package:flutter/material.dart'; import 'package:flutter_svg/svg.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:stackwallet/utilities/theme/light_colors.dart'; +import 'package:stackwallet/utilities/theme/stack_colors.dart'; import 'package:stackwallet/widgets/custom_pin_put/custom_pin_put.dart'; import 'package:stackwallet/widgets/custom_pin_put/pin_keyboard.dart'; @@ -10,8 +12,13 @@ void main() { const pinPut = CustomPinPut(fieldsCount: 4); await tester.pumpWidget( - const MaterialApp( - home: Material( + MaterialApp( + theme: ThemeData( + extensions: [ + StackColors.fromStackColorTheme(LightColors()), + ], + ), + home: const Material( child: pinPut, ), ), @@ -34,6 +41,11 @@ void main() { await tester.pumpWidget( MaterialApp( + theme: ThemeData( + extensions: [ + StackColors.fromStackColorTheme(LightColors()), + ], + ), home: Material( child: pinPut, ), @@ -71,6 +83,11 @@ void main() { await tester.pumpWidget( MaterialApp( + theme: ThemeData( + extensions: [ + StackColors.fromStackColorTheme(LightColors()), + ], + ), home: Material( child: pinPut, ), @@ -97,6 +114,11 @@ void main() { await tester.pumpWidget( MaterialApp( + theme: ThemeData( + extensions: [ + StackColors.fromStackColorTheme(LightColors()), + ], + ), home: Material( child: pinPut, ), @@ -123,6 +145,11 @@ void main() { await tester.pumpWidget( MaterialApp( + theme: ThemeData( + extensions: [ + StackColors.fromStackColorTheme(LightColors()), + ], + ), home: Material( child: pinPut, ), @@ -149,6 +176,11 @@ void main() { await tester.pumpWidget( MaterialApp( + theme: ThemeData( + extensions: [ + StackColors.fromStackColorTheme(LightColors()), + ], + ), home: Material( child: keyboard, ), diff --git a/windows/flutter/generated_plugin_registrant.cc b/windows/flutter/generated_plugin_registrant.cc index e2c6ccc42..98655fe05 100644 --- a/windows/flutter/generated_plugin_registrant.cc +++ b/windows/flutter/generated_plugin_registrant.cc @@ -13,6 +13,7 @@ #include #include #include +#include void RegisterPlugins(flutter::PluginRegistry* registry) { ConnectivityPlusWindowsPluginRegisterWithRegistrar( @@ -29,4 +30,6 @@ void RegisterPlugins(flutter::PluginRegistry* registry) { registry->GetRegistrarForPlugin("StackWalletBackupPluginCApi")); UrlLauncherWindowsRegisterWithRegistrar( registry->GetRegistrarForPlugin("UrlLauncherWindows")); + WindowSizePluginRegisterWithRegistrar( + registry->GetRegistrarForPlugin("WindowSizePlugin")); } diff --git a/windows/flutter/generated_plugins.cmake b/windows/flutter/generated_plugins.cmake index a0783a490..4426d9497 100644 --- a/windows/flutter/generated_plugins.cmake +++ b/windows/flutter/generated_plugins.cmake @@ -10,6 +10,7 @@ list(APPEND FLUTTER_PLUGIN_LIST permission_handler_windows stack_wallet_backup url_launcher_windows + window_size ) list(APPEND FLUTTER_FFI_PLUGIN_LIST