diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 17e441e5..a84b7e3e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -70,13 +70,14 @@ jobs: - uses: stelynx/dart-full-coverage@v1.1.1 with: package: ribn - ignore: "*_state.dart, do_not_import_me.dart" + ignore: "*_state.dart, do_not_import_me.dart, js_workers/* , platform_web/*" - name: Install dependencies and generated files run: make gen - name: Run tests - run: flutter test --coverage . + run: flutter test --platform chrome --coverage . + - uses: codecov/codecov-action@v1.0.2 with: diff --git a/.github/workflows/nightly_build_android.yml b/.github/workflows/nightly_build_android.yml index bed5490e..e80961bb 100644 --- a/.github/workflows/nightly_build_android.yml +++ b/.github/workflows/nightly_build_android.yml @@ -68,6 +68,9 @@ jobs: - name: Install flutter dependencies run: make gen + - name: print nversion + run: echo $nversion + - name: Build android app run: flutter build appbundle --release --build-number=${{github.run_number}} --dart-define=nightlyBuildVersion=$nversion diff --git a/.gitignore b/.gitignore index 245495f5..3d6a3c3e 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ node_modules/ dist/ mock/ pubspec.lock +.env # Ignore secrets key.properties @@ -24,6 +25,11 @@ app.*.map.json .history .svn/ +# Auto generated files +*.g.dart +*.freezed.dart +*.mocks.dart + # Android Studio will place build artifacts here /android/app/debug @@ -102,6 +108,7 @@ unlinked_spec.ds **/ios/ServiceDefinitions.json **/ios/Runner/GeneratedPluginRegistrant.* **/ios/Podfile.lock +**/ios/fastlane/report.xml # macOS **/Flutter/ephemeral/ diff --git a/Makefile b/Makefile index a95da954..143b7652 100644 --- a/Makefile +++ b/Makefile @@ -28,6 +28,7 @@ clean: ## Cleans the environment @rm -rf pubspec.lock @flutter clean @flutter pub get + fix_warnings: ## fix any warnings @echo "╠ Attempting to fix warnings..." @dart fix --dry-run @@ -44,9 +45,9 @@ gen: ## Generates the assets format: ## Formats the code @echo "╠ Formatting the code" - @dart format lib . + @dart format lib . -l 120 @flutter pub run import_sorter:main - @dart format . + @dart format . -l 120 lint: ## Lints the code @echo "╠ Verifying code..." @@ -67,6 +68,11 @@ analyze: ditto: echo "hello world" +validate_packages: + @echo "╠ Validating packages..." + @flutter pub get + @flutter pub run dependency_validator + arm_mac_hard_clean: flutter clean && \ flutter pub get && \ @@ -76,4 +82,19 @@ arm_mac_hard_clean: rm Podfile.lock && \ sudo arch -x86_64 gem install ffi && \ arch -x86_64 pod install && \ - cd .. \ No newline at end of file + cd .. + +file_test: + @reset + @flutter test test/middleware_test.dart + +nuclear_clean: + @echo "╠ Nuking pubcache completely, this might take a while...." + @flutter clean + @flutter pub cache repair + @flutter pub get + +test_coverage: + @flutter test --coverage + @genhtml coverage/lcov.info -o coverage/html + @open coverage/html/index.html diff --git a/analysis_options.yaml b/analysis_options.yaml index 51dd4f5a..f5fb2cd3 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -21,6 +21,8 @@ analyzer: dead_code: error strong-mode: implicit-casts: true + plugins: + - custom_lint linter: diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index c6466650..4981e80c 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -4,6 +4,7 @@ = 1.13.0, < 2.0.0) xcpretty (~> 0.3.0) xcpretty-travis-formatter (>= 0.0.3) + fastlane-plugin-firebase_app_distribution (0.4.2) ffi (1.15.5) fourflusher (2.3.1) fuzzy_match (2.0.4) @@ -280,11 +281,13 @@ GEM zeitwerk (2.5.4) PLATFORMS + arm64-darwin-22 universal-darwin-21 DEPENDENCIES cocoapods fastlane + fastlane-plugin-firebase_app_distribution fastlane-plugin-flutter_version! BUNDLED WITH diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index 9d94b2c6..f2871551 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -3,7 +3,7 @@ archiveVersion = 1; classes = { }; - objectVersion = 51; + objectVersion = 54; objects = { /* Begin PBXBuildFile section */ @@ -201,6 +201,7 @@ /* Begin PBXShellScriptBuildPhase section */ 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; buildActionMask = 2147483647; files = ( ); @@ -215,6 +216,7 @@ }; 9740EEB61CF901F6004384FC /* Run Script */ = { isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; buildActionMask = 2147483647; files = ( ); @@ -359,9 +361,11 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; - CODE_SIGN_STYLE = Automatic; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; + CODE_SIGN_STYLE = Manual; CURRENT_PROJECT_VERSION = 1; - DEVELOPMENT_TEAM = DZ7Z4DLW5R; + DEVELOPMENT_TEAM = ""; + "DEVELOPMENT_TEAM[sdk=iphoneos*]" = DZ7Z4DLW5R; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -372,6 +376,7 @@ PRODUCT_BUNDLE_IDENTIFIER = co.topl.ribn; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; + "PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "Firebase App Distribute Profile"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_VERSION = 5.0; VERSIONING_SYSTEM = "apple-generic"; @@ -495,9 +500,11 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; - CODE_SIGN_STYLE = Automatic; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; + CODE_SIGN_STYLE = Manual; CURRENT_PROJECT_VERSION = 1; - DEVELOPMENT_TEAM = DZ7Z4DLW5R; + DEVELOPMENT_TEAM = ""; + "DEVELOPMENT_TEAM[sdk=iphoneos*]" = DZ7Z4DLW5R; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -508,6 +515,7 @@ PRODUCT_BUNDLE_IDENTIFIER = co.topl.ribn; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; + "PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "Firebase App Distribute Profile"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 5.0; @@ -522,10 +530,12 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; - CODE_SIGN_IDENTITY = "Apple Distribution"; + CODE_SIGN_IDENTITY = "Apple Development"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; CODE_SIGN_STYLE = Manual; CURRENT_PROJECT_VERSION = 1; - DEVELOPMENT_TEAM = DZ7Z4DLW5R; + DEVELOPMENT_TEAM = ""; + "DEVELOPMENT_TEAM[sdk=iphoneos*]" = DZ7Z4DLW5R; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -535,7 +545,8 @@ MARKETING_VERSION = 0.1.0; PRODUCT_BUNDLE_IDENTIFIER = co.topl.ribn; PRODUCT_NAME = "$(TARGET_NAME)"; - PROVISIONING_PROFILE_SPECIFIER = "match AppStore co.topl.ribn"; + PROVISIONING_PROFILE_SPECIFIER = ""; + "PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "Firebase App Distribute Profile"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_VERSION = 5.0; VERSIONING_SYSTEM = "apple-generic"; diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist index bc01134e..447c41c7 100644 --- a/ios/Runner/Info.plist +++ b/ios/Runner/Info.plist @@ -51,5 +51,7 @@ CADisableMinimumFrameDurationOnPhone - - \ No newline at end of file + UIApplicationSupportsIndirectInputEvents + + + diff --git a/ios/fastlane/Fastfile b/ios/fastlane/Fastfile index 1f84c3b4..c6067095 100644 --- a/ios/fastlane/Fastfile +++ b/ios/fastlane/Fastfile @@ -111,4 +111,16 @@ platform :ios do delete_temp_keychain(keychain_name) end + + lane :distribute do + + firebase_app_distribution( + app: "TODO_CHANGE", + groups: 'topl', + release_notes: "Speedy recent transactions", + ipa_path: '../build/ios/ipa/Ribn.ipa', + service_credentials_file: '../service_account_key.json', + ) + + end end diff --git a/ios/fastlane/Pluginfile b/ios/fastlane/Pluginfile new file mode 100644 index 00000000..b18539bc --- /dev/null +++ b/ios/fastlane/Pluginfile @@ -0,0 +1,5 @@ +# Autogenerated by fastlane +# +# Ensure this file is checked in to source control! + +gem 'fastlane-plugin-firebase_app_distribution' diff --git a/ios/fastlane/README.md b/ios/fastlane/README.md index 7bece83d..1bf9ef26 100644 --- a/ios/fastlane/README.md +++ b/ios/fastlane/README.md @@ -23,6 +23,14 @@ For _fastlane_ installation instructions, see [Installing _fastlane_](https://do +### ios distribute + +```sh +[bundle exec] fastlane ios distribute +``` + + + ---- This README.md is auto-generated and will be re-generated every time [_fastlane_](https://fastlane.tools) is run. diff --git a/lib/actions/login_actions.dart b/lib/actions/login_actions.dart deleted file mode 100644 index ea2f4389..00000000 --- a/lib/actions/login_actions.dart +++ /dev/null @@ -1,14 +0,0 @@ -// Dart imports: -import 'dart:async'; -import 'dart:typed_data'; - -class AttemptLoginAction { - final String password; - final Completer completer; - const AttemptLoginAction(this.password, this.completer); -} - -class LoginSuccessAction { - final Uint8List toplExtendedPrvKeyUint8List; - const LoginSuccessAction(this.toplExtendedPrvKeyUint8List); -} diff --git a/lib/actions/misc_actions.dart b/lib/actions/misc_actions.dart index db8f37fb..491bc4fc 100644 --- a/lib/actions/misc_actions.dart +++ b/lib/actions/misc_actions.dart @@ -1,6 +1,3 @@ -// Dart imports: -import 'dart:async'; - class PersistAppState {} class FailedToPersistAppStateAction {} @@ -16,18 +13,6 @@ class NavigateToRoute { NavigateToRoute(this.route, {this.arguments}); } -class DownloadAsFileAction { - final String fileName; - final String text; - const DownloadAsFileAction(this.fileName, this.text); -} - -class DeleteWalletAction { - final String password; - final Completer completer; - const DeleteWalletAction({required this.password, required this.completer}); -} - class ResetAppStateAction { const ResetAppStateAction(); } diff --git a/lib/actions/restore_wallet_actions.dart b/lib/actions/restore_wallet_actions.dart deleted file mode 100644 index e3ea67c0..00000000 --- a/lib/actions/restore_wallet_actions.dart +++ /dev/null @@ -1,35 +0,0 @@ -// Dart imports: -import 'dart:async'; -import 'dart:typed_data'; - -class RestoreWalletWithMnemonicAction { - final String mnemonic; - final String password; - RestoreWalletWithMnemonicAction({ - required this.mnemonic, - required this.password, - }); -} - -class RestoreWalletWithToplKeyAction { - final String toplKeyStoreJson; - final String password; - final Completer completer; - - const RestoreWalletWithToplKeyAction({ - required this.toplKeyStoreJson, - required this.password, - required this.completer, - }); -} - -class SuccessfullyRestoredWalletAction { - final String keyStoreJson; - final Uint8List toplExtendedPrivateKey; - const SuccessfullyRestoredWalletAction({ - required this.keyStoreJson, - required this.toplExtendedPrivateKey, - }); -} - -class FailedToRestoreWalletAction {} diff --git a/lib/actions/user_details_actions.dart b/lib/actions/user_details_actions.dart index 3ab11710..84dfe69c 100644 --- a/lib/actions/user_details_actions.dart +++ b/lib/actions/user_details_actions.dart @@ -10,10 +10,3 @@ class UpdateAssetDetailsAction { this.icon, }); } - -class UpdateBiometricsAction { - final bool isBiometricsEnabled; - UpdateBiometricsAction({ - required this.isBiometricsEnabled, - }); -} diff --git a/lib/constants/assets.dart b/lib/constants/assets.dart index fa40246a..92d62640 100644 --- a/lib/constants/assets.dart +++ b/lib/constants/assets.dart @@ -10,15 +10,13 @@ class RibnAssets { static const seedPhraseCreatedIcon = 'assets/icons/seedphrase_created.png'; static const passwordManagerIcon = 'assets/icons/password_manager.svg'; static const encryptFileIcon = 'assets/icons/encrypt_file.svg'; - static const seedPhraseConfirmedIcon = - 'assets/icons/seed_phrase_confirmed.svg'; + static const seedPhraseConfirmedIcon = 'assets/icons/seed_phrase_confirmed.svg'; static const walletPasswordIcon = 'assets/icons/wallet_password.svg'; static const addIcon = 'assets/icons/add.svg'; static const removeIcon = 'assets/icons/remove.svg'; static const extensionIcon = 'assets/icons/extension.svg'; static const plusIcon = 'assets/icons/plus.svg'; - static const importWalletIcon = - 'packages/ribn_toolkit/assets/icons/restore_wallet.png'; + static const importWalletIcon = 'packages/ribn_toolkit/assets/icons/restore_wallet.png'; static const closeGreyIcon = 'assets/icons/close_grey.svg'; static const downloadIcon = 'assets/icons/download.svg'; static const infoIcon = 'assets/icons/info.png'; @@ -26,8 +24,7 @@ class RibnAssets { static const sentIcon = 'assets/icons/sent.svg'; static const receiveIcon = 'assets/icons/receive.png'; static const menuIcon = 'assets/icons/menu.svg'; - static const txHistoryPageActiveIcon = - 'assets/icons/tx_history_page_active.svg'; + static const txHistoryPageActiveIcon = 'assets/icons/tx_history_page_active.svg'; static const txHistoryPageIcon = 'assets/icons/tx_history_page.svg'; static const settingsIcon = 'packages/ribn_toolkit/assets/icons/settings.png'; static const supportIcon = 'packages/ribn_toolkit/assets/icons/support.png'; @@ -48,24 +45,15 @@ class RibnAssets { static const copyUnselectedIcon = 'assets/icons/copy_unselected.png'; static const copySelectedIcon = 'assets/icons/copy_selected.png'; static const unselectedAsset = 'assets/icons/asset_unselected.png'; - static const coffBlueIcon = - 'packages/ribn_toolkit/assets/asset_icons/coff_blue_icon.png'; - static const coffBrownIcon = - 'packages/ribn_toolkit/assets/asset_icons/coff_brown_icon.png'; - static const coffGreenIcon = - 'packages/ribn_toolkit/assets/asset_icons/coff_green_icon.png'; - static const coffPurpleIcon = - 'packages/ribn_toolkit/assets/asset_icons/coff_purple_icon.png'; - static const coffYellowIcon = - 'packages/ribn_toolkit/assets/asset_icons/coff_yellow_icon.png'; - static const diaBlueIcon = - 'packages/ribn_toolkit/assets/asset_icons/dia_blue_icon.png'; - static const diaGreenIcon = - 'packages/ribn_toolkit/assets/asset_icons/dia_green_icon.png'; - static const diaPurpleIcon = - 'packages/ribn_toolkit/assets/asset_icons/dia_purple_icon.png'; - static const diaYellowIcon = - 'packages/ribn_toolkit/assets/asset_icons/dia_yellow_icon.png'; + static const coffBlueIcon = 'packages/ribn_toolkit/assets/asset_icons/coff_blue_icon.png'; + static const coffBrownIcon = 'packages/ribn_toolkit/assets/asset_icons/coff_brown_icon.png'; + static const coffGreenIcon = 'packages/ribn_toolkit/assets/asset_icons/coff_green_icon.png'; + static const coffPurpleIcon = 'packages/ribn_toolkit/assets/asset_icons/coff_purple_icon.png'; + static const coffYellowIcon = 'packages/ribn_toolkit/assets/asset_icons/coff_yellow_icon.png'; + static const diaBlueIcon = 'packages/ribn_toolkit/assets/asset_icons/dia_blue_icon.png'; + static const diaGreenIcon = 'packages/ribn_toolkit/assets/asset_icons/dia_green_icon.png'; + static const diaPurpleIcon = 'packages/ribn_toolkit/assets/asset_icons/dia_purple_icon.png'; + static const diaYellowIcon = 'packages/ribn_toolkit/assets/asset_icons/dia_yellow_icon.png'; static const addressCopiedIcon = 'assets/icons/address_copied.png'; static const polysIcon = 'assets/icons/polysIcon.png'; static const undefinedIcon = 'assets/icons/undefined_icon.png'; @@ -78,32 +66,22 @@ class RibnAssets { static const smsFailed = 'assets/icons/sms_failed.png'; static const openInNewWindow = 'assets/icons/open_in_new.png'; static const roundInfoCircle = 'assets/icons/round_info_circle.png'; - static const newRibnLogo = - 'packages/ribn_toolkit/assets/icons/new_ribn_logo.png'; - static const newCircleRibnLogo = - 'packages/ribn_toolkit/assets/icons/ribn_circle_logo.png'; - static const chevronDown = - 'packages/ribn_toolkit/assets/icons/chevron_down.png'; - static const chevronDownDark = - 'packages/ribn_toolkit/assets/icons/chevron_down_dark.png'; - static const hamburgerMenu = - 'packages/ribn_toolkit/assets/icons/hamburger_menu.png'; - static const circleExclamation = - 'packages/ribn_toolkit/assets/icons/error.png'; + static const newRibnLogo = 'packages/ribn_toolkit/assets/icons/new_ribn_logo.png'; + static const newCircleRibnLogo = 'packages/ribn_toolkit/assets/icons/ribn_circle_logo.png'; + static const chevronDown = 'packages/ribn_toolkit/assets/icons/chevron_down.png'; + static const chevronDownDark = 'packages/ribn_toolkit/assets/icons/chevron_down_dark.png'; + static const hamburgerMenu = 'packages/ribn_toolkit/assets/icons/hamburger_menu.png'; + static const circleExclamation = 'packages/ribn_toolkit/assets/icons/error.png'; static const circleInfo = 'assets/icons/circle_info.png'; - static const greyHelpBubble = - 'packages/ribn_toolkit/assets/icons/gray_help_bubble.png'; + static const greyHelpBubble = 'packages/ribn_toolkit/assets/icons/gray_help_bubble.png'; static const plusBlue = 'packages/ribn_toolkit/assets/icons/plus_blue.png'; static const plusGrey = 'packages/ribn_toolkit/assets/icons/plus_grey.png'; - static const walletBlue = - 'packages/ribn_toolkit/assets/icons/wallet_blue.png'; - static const walletGrey = - 'packages/ribn_toolkit/assets/icons/wallet_grey.png'; + static const walletBlue = 'packages/ribn_toolkit/assets/icons/wallet_blue.png'; + static const walletGrey = 'packages/ribn_toolkit/assets/icons/wallet_grey.png'; static const clockBlue = 'packages/ribn_toolkit/assets/icons/clock_blue.png'; static const clockGrey = 'packages/ribn_toolkit/assets/icons/clock_grey.png'; static const copyIcon = 'packages/ribn_toolkit/assets/icons/copy_icon.png'; - static const circlePlus = - 'packages/ribn_toolkit/assets/icons/circle_plus.png'; + static const circlePlus = 'packages/ribn_toolkit/assets/icons/circle_plus.png'; static const copyIconAlternate = 'assets/icons/copy_icon_alternate.png'; static const fingerPrintAssets = 'assets/icons/finger_print_assets.png'; static const redDangerTriangle = 'assets/icons/red_danger_triangle.png'; @@ -113,16 +91,11 @@ class RibnAssets { static const passwordLockPng = 'assets/icons/password_lock.png'; static const penPaperPng = 'assets/icons/pen_paper.png'; static const programPng = 'assets/icons/program.png'; - static const onboardingBackgroundSvg = - 'assets/icons/onboarding_background.svg'; - static const onboardingBackgroundPng = - 'assets/icons/onboarding_background.png'; - static const createWalletPng = - 'packages/ribn_toolkit/assets/icons/create_wallet.png'; - static const createWalletPngWithShadow = - 'packages/ribn_toolkit/assets/icons/create_wallet_shadow.png'; - static const importWalletPng = - 'packages/ribn_toolkit/assets/icons/import_wallet.png'; + static const onboardingBackgroundSvg = 'assets/icons/onboarding_background.svg'; + static const onboardingBackgroundPng = 'assets/icons/onboarding_background.png'; + static const createWalletPng = 'packages/ribn_toolkit/assets/icons/create_wallet.png'; + static const createWalletPngWithShadow = 'packages/ribn_toolkit/assets/icons/create_wallet_shadow.png'; + static const importWalletPng = 'packages/ribn_toolkit/assets/icons/import_wallet.png'; static const walletLockPng = 'assets/icons/wallet_lock.png'; static const passwordVisiblePng = 'assets/icons/password_visible.png'; static const passwordHiddenPng = 'assets/icons/password_hidden.png'; @@ -137,15 +110,15 @@ class RibnAssets { static const touchID = 'assets/icons/touch_id.png'; static const touchIDCutout = 'assets/icons/touch_id_cutout.png'; static const iosBiometrics = 'assets/icons/iphone_biometrics.png'; - static const iosBiometricsOutline = - 'assets/icons/iphone_biometrics_outline.png'; + static const iosBiometricsOutline = 'assets/icons/iphone_biometrics_outline.png'; static const andriodBiometrics = 'assets/icons/android_biometrics.png'; - static const andriodBiometricsOutline = - 'assets/icons/android_biometrics_outline.png'; + static const andriodBiometricsOutline = 'assets/icons/android_biometrics_outline.png'; static const addPlusPng = 'assets/icons/add_plus.png'; static const documentPng = 'assets/icons/document.png'; static const polyIconCircle = 'assets/icons/poly_icon_circle.png'; static const clockWithBorder = 'assets/icons/clock_border.png'; static const walletWithBorder = 'assets/icons/wallet_with_border.png'; static const connectDApp = 'assets/icons/connect_dapp.png'; + static const improvePng = 'assets/icons/improve.png'; + static const bulletPointPng = 'assets/icons/bullet_point.png'; } diff --git a/lib/constants/environment_config.dart b/lib/constants/environment_config.dart new file mode 100644 index 00000000..1762ac9d --- /dev/null +++ b/lib/constants/environment_config.dart @@ -0,0 +1,15 @@ +class EnvironmentConfig { + static const nightlyBuildVersion = String.fromEnvironment('nightlyBuildVersion', defaultValue: ""); + + // KEYS + static const ASSIGNEE_ID = String.fromEnvironment('ASSIGNEE_ID', defaultValue: ""); + static const ISSUE_TYPE = String.fromEnvironment('ISSUE_TYPE', defaultValue: ""); + static const JIRA_ATTACH_ISSUE_URL = String.fromEnvironment('JIRA_ATTACH_ISSUE_URL', defaultValue: ""); + static const JIRA_CREATE_ISSUE_URL = String.fromEnvironment('JIRA_CREATE_ISSUE_URL', defaultValue: ""); + static const JIRA_DEFAULT_HEADERS = String.fromEnvironment('JIRA_DEFAULT_HEADERS', defaultValue: ""); + static const JIRA_DEFAULT_HEADERS_ATTACHMENTS = + String.fromEnvironment('JIRA_DEFAULT_HEADERS_ATTACHMENTS', defaultValue: ""); + + static const PROJECT_KEY = String.fromEnvironment('PROJECT_KEY', defaultValue: ""); + static const JIRA_AUTH_TOKEN = String.fromEnvironment('JIRA_AUTH_TOKEN', defaultValue: ""); +} diff --git a/lib/constants/keys.dart b/lib/constants/keys.dart index cfcbb9e7..e37e46ec 100644 --- a/lib/constants/keys.dart +++ b/lib/constants/keys.dart @@ -3,7 +3,6 @@ import 'package:flutter/material.dart'; class Keys { Keys._(); - static final GlobalKey navigatorKey = - GlobalKey(); + static final GlobalKey navigatorKey = GlobalKey(); static const isTestingEnvironment = bool.fromEnvironment('FLUTTER_TEST'); } diff --git a/lib/constants/loggers.dart b/lib/constants/loggers.dart index 5aa434a8..51a52c11 100644 --- a/lib/constants/loggers.dart +++ b/lib/constants/loggers.dart @@ -1 +1,11 @@ -const String kTransactionLogger = 'TransactionLogger'; +enum LoggerClass { + Transaction('Transaction'), + ApiError('ApiError'), + Analytics('Analytics'), + Authentication('Authentication'); + + const LoggerClass(this.string); + final String string; +} + +enum LogLevel { Info, Warning, Severe, Shout } diff --git a/lib/constants/network_utils.dart b/lib/constants/network_utils.dart index 10731458..616bdcf2 100644 --- a/lib/constants/network_utils.dart +++ b/lib/constants/network_utils.dart @@ -5,29 +5,89 @@ import 'package:brambldart/utils.dart' as constants; /// Utils and constants that relate to Topl networks. class NetworkUtils { NetworkUtils._(); + + static const String projectId = '60ff001754b7c75558146daf'; + + // Network names static const String toplNet = 'toplnet'; static const String valhalla = 'valhalla'; static const String private = 'private'; - static const String privateIP = '35.226.176.100'; + + // Network IP's + static const String privateIP = '104.197.222.150'; + static const String valhallaIP = '35.224.14.0'; + static const String toplnetIP = '34.172.5.205'; + + // ID's used by RibnNetwork static int toplNetId = constants.networkRegistry[toplNet]!; static int valhallaId = constants.networkRegistry[valhalla]!; static int privateId = constants.networkRegistry[private]!; + static Map networkFees = { - valhallaId: - PolyAmount.fromUnitAndValue(PolyUnit.nanopoly, constants.valhallaFee), - toplNetId: - PolyAmount.fromUnitAndValue(PolyUnit.nanopoly, constants.toplnetFee), + valhallaId: PolyAmount.fromUnitAndValue(PolyUnit.nanopoly, constants.valhallaFee), + toplNetId: PolyAmount.fromUnitAndValue(PolyUnit.nanopoly, constants.toplnetFee), privateId: PolyAmount.zero(), }; - static const String projectId = '60ff001754b7c75558146daf'; + static Map networkApiKeys = { valhallaId: 'Mjc0ODg3MTktYTU3ZS00MGM2LWJkMmMtYTRjMzQxMWY3MjM4', toplNetId: 'N2IyNDljZmQtZjlkNS00Nzc4LWE1MGQtMmVhMzBjMzIyYjBi', privateId: 'topl_the_world!' }; + static Map networkUrls = { valhallaId: 'https://vertx.topl.services/valhalla/$projectId', toplNetId: 'https://vertx.topl.services/mainnet/$projectId', privateId: 'http://$privateIP:9085' }; + + static Map genusIPs = { + valhallaId: valhallaIP, + // valhallaId: "http:/valhalla.genus.topl.tech", + toplNetId: toplnetIP, + // toplNetId: "http://toplnet.genus.topl.tech/", + privateId: privateIP, + }; + + // http://toplnet.genus.topl.tech/ +} + +enum Networks { + valhalla(NetworkUtils.valhalla), + toplnet(NetworkUtils.toplNet), + private(NetworkUtils.private); + + const Networks(this.name); + + final String name; +} + +class NetworkConfig { + final String networkName; + final int networkId; + final String networkUrl; + final String genusIP; + final String apiKey; + final PolyAmount fee = PolyAmount.zero(); // Leaving as zero as this isn't utilized at the moment + + factory NetworkConfig.fromNetwork(Networks network) { + final name = network.name; + final id = constants.networkRegistry[name]; + final url = NetworkUtils.networkApiKeys[id]; + final genusIP = NetworkUtils.genusIPs[id]; + final apiKey = NetworkUtils.networkApiKeys[id] ?? ""; + + if (id == null || url == null || genusIP == null) { + throw Exception("Could not instantiate network config ${network.name}"); + } + + return NetworkConfig(networkName: name, networkId: id, networkUrl: url, genusIP: genusIP, apiKey: apiKey); + } + + NetworkConfig( + {required this.networkName, + required this.networkId, + required this.networkUrl, + required this.genusIP, + this.apiKey = ""}); } diff --git a/lib/constants/routes.dart b/lib/constants/routes.dart index 41e4b5d6..efbec40c 100644 --- a/lib/constants/routes.dart +++ b/lib/constants/routes.dart @@ -9,6 +9,7 @@ class Routes { /// Routes used throughout the application. static const welcome = '/welcome'; + static const optIn = '/opt-in'; static const selectAction = '/select-action'; static const gettingStarted = '/getting-started'; static const seedPhraseInfoChecklist = '/seedphrase-checklist'; @@ -28,14 +29,10 @@ class Routes { static const restoreWalletNewPassword = '/restore-wallet/new-password'; static const enterWalletPassword = '/restore-wallet/topl-key/enter-password'; static const loginRestoreWalletWithToplKey = '/login/restore-wallet/topl-key'; - static const loginRestoreWalletEnterPassword = - '/login/restore-wallet/enter-password'; - static const onboardingRestoreWalletWithMnemonic = - '/onboarding/restore-wallet/mnemonic'; - static const onboardingRestoreWalletWithToplKey = - '/onboarding/restore-wallet/topl-key'; - static const onboardingRestoreWalletEnterPassword = - '/onboarding/restore-wallet/enter-password'; + static const loginRestoreWalletEnterPassword = '/login/restore-wallet/enter-password'; + static const onboardingRestoreWalletWithMnemonic = '/onboarding/restore-wallet/mnemonic'; + static const onboardingRestoreWalletWithToplKey = '/onboarding/restore-wallet/topl-key'; + static const onboardingRestoreWalletEnterPassword = '/onboarding/restore-wallet/enter-password'; static const onboardingEnableBiometrics = '/onboarding/enable-biometrics'; static const assetsTransferInput = '/asset-transfer'; static const polyTransferInput = '/poly-transfer-input'; diff --git a/lib/constants/rules.dart b/lib/constants/rules.dart index 7cf663a1..c08c143d 100644 --- a/lib/constants/rules.dart +++ b/lib/constants/rules.dart @@ -37,18 +37,16 @@ class Rules { NetworkUtils.valhallaId: 'https://staging.valhalla.annulus.topl.services/#/transaction/', NetworkUtils.privateId: 'https://staging.valhalla.annulus.topl.services/#/transaction/', }; - static String txHistoryUrl(String addr, int networkId) => - '${txHistoryUrls[networkId]!}/v1/address/history/$addr'; - static String txDetailsUrl(String txId, int networkId) => - '${txDetailsRedirectUrls[networkId]!}$txId'; + static String txHistoryUrl(String addr, int networkId) => '${txHistoryUrls[networkId]!}/v1/address/history/$addr'; + static String txDetailsUrl(String txId, int networkId) => '${txDetailsRedirectUrls[networkId]!}$txId'; static const transferTypes = [Strings.polyTransfer, Strings.assetTransfer, Strings.minting]; static BramblClient getBramblCient(int networkId) { final Dio httpClient = Dio( BaseOptions( baseUrl: NetworkUtils.networkUrls[networkId]!, contentType: 'application/json', - connectTimeout: 5000, - receiveTimeout: 3000, + connectTimeout: Duration(seconds: 5000), + receiveTimeout: Duration(seconds: 3000), ), ); return BramblClient( diff --git a/lib/constants/strings.dart b/lib/constants/strings.dart index 387558f8..b53e8840 100644 --- a/lib/constants/strings.dart +++ b/lib/constants/strings.dart @@ -1,6 +1,13 @@ /// All the strings that are being used throughout the app. class Strings { Strings._(); + static const String submitForm = "Submit"; + static const String uploadImage = "Upload screenshot"; + static const String description = "Description"; + static const String ribnSupportDescriptionHint = + "Write 50-500 characters about your experience, whether it was great or has room for improvement. You can also report technical bugs or request new features."; + static const String iWouldLiketTo = 'Select an option'; + static const String feedbackForm = 'How can we help?'; static const String copyToClipboard = 'Copy to clipboard'; static const String copy = 'Copy'; static const String activity = 'Activity'; @@ -41,16 +48,13 @@ class Strings { static const String sign = 'Sign'; static const String back = 'Back'; static const String welcomeToRibn = 'Welcome to Ribn'; - static const String intro = - 'Topl’s blockchain wallet used to track, tokenize, and transact impact.'; + static const String intro = 'Topl’s blockchain wallet used to track, tokenize, and transact impact.'; static const String getStarted = 'Get started'; static const String createWallet = 'Create wallet'; - static const String createWalletDescription = - 'First time? Create your new wallet\nand 15 word Seed Phrase.'; + static const String createWalletDescription = 'First time? Create your new wallet\nand 15 word Seed Phrase.'; static const String importWallet = 'Import wallet'; static const String restoreWallet = 'Restore wallet'; - static const String restoreWalletDescription = - 'Restore your existing Ribn wallet\nusing a Seed Phrase or Topl key.'; + static const String restoreWalletDescription = 'Restore your existing Ribn wallet\nusing a Seed Phrase or Topl key.'; static const String gettingStarted = 'Getting started'; static const String download = 'Download'; static const String gettingStartedDescription = @@ -67,27 +71,22 @@ This 15-word phrase will be used to restore your assets if this device is lost o static const String beforeYouStart = 'Before you start'; static const String okLetsGo = "Ok, let's go!"; static const String weRecommend = 'We Recommend:'; - static const String weRecommendSub = - 'At least one of the following to record your Seed Phrase safely:'; + static const String weRecommendSub = 'At least one of the following to record your Seed Phrase safely:'; static const String paperAndPen = 'A paper and pen.'; static const String securePasswordManager = 'A secure password manager.'; - static const String encryptTextFile = - 'A program such as PGP to encrypt your text file.'; + static const String encryptTextFile = 'A program such as PGP to encrypt your text file.'; static const String writeDownSeedPhrase = 'Write down Seed Phrase'; static const String seedPhraseFileName = 'seed_phrase'; static const String letsTryThatAgain = 'Now, Let’s Try That Again'; static const String heyIWasntKidding = '''Hey I wasn’t kidding, write these words down in the exact order they are shown. Remember don’t take any screenshots!'''; - static const String writeDownSeedPhraseDesc = - '''Now, you will write each word of your Seed Phrase down carefully. + static const String writeDownSeedPhraseDesc = '''Now, you will write each word of your Seed Phrase down carefully. Make sure they are in the exact order shown below. Don’t take screenshots!'''; static const String done = 'Done'; static const String confirmYourSeedPhrase = 'Confirm your Seed Phrase'; - static const String confirmYourSeedPhraseDesc = - 'Click each word in the correct order.'; + static const String confirmYourSeedPhraseDesc = 'Click each word in the correct order.'; static const String seedPhraseConfirmed = 'Seed Phrase Confirmed!'; - static const String seedPhraseConfirmedDesc = - '''Good job! Each word in your Seed Phrase has been input correctly. + static const String seedPhraseConfirmedDesc = '''Good job! Each word in your Seed Phrase has been input correctly. Rest assured, you have saved the correct words, in the correct order.'''; static const String cont = 'Continue'; static const String finalReview = 'Final Review'; @@ -103,8 +102,7 @@ Rest assured, you have saved the correct words, in the correct order.'''; static const String readFollowingCarefully = 'Read Following Carefully'; static const String savedMyWalletPasswordSafely = 'I have saved my Wallet Password safely. I will use this password to unlock my wallet.'; - static const String toplCannotRecoverForMe = - 'I understand that Topl cannot recover my Wallet Password for me.'; + static const String toplCannotRecoverForMe = 'I understand that Topl cannot recover my Wallet Password for me.'; static const String spAndPasswordUnrecoverable = 'I understand that my Seed phrase and Wallet Password are both unrecoverable.'; static const String walletCreated = '''Success!\nWallet Created'''; @@ -112,16 +110,13 @@ Rest assured, you have saved the correct words, in the correct order.'''; '''You’re all set. Make sure to keep your 15 word Seed phrase safe and private.\n You'll need it to recover your wallet if your device is lost or broken.'''; static const String frequentlyAskedQuestions = 'Frequently Asked Questions:'; - static const String howCanIKeepMySeedPhraseSecure = - 'How can I keep my Seed Phrase secure?'; + static const String howCanIKeepMySeedPhraseSecure = 'How can I keep my Seed Phrase secure?'; static const String howCanIKeepMySeedPhraseSecureAns = '''• Save in a password manager.\n• Keep in a safe deposit box.\n• Encrypt and store on an external drive.'''; - static const String howIsASeedPhraseDifferent = - 'How is a Seed Phrase different from a Wallet Password?'; + static const String howIsASeedPhraseDifferent = 'How is a Seed Phrase different from a Wallet Password?'; static const String howIsASeedPhraseDifferentAns = '''The Seed Phrase is different because you can restore your wallet with it. The Wallet Password is for security and only lets you unlock the wallet after it has been imported (or created) in wallet software. Your Wallet Password isn't required to lock your wallet.'''; - static const String howIsMySeedPhraseUnrecoverable = - 'How is my Seed Phrase or Wallet Password unrecoverable?'; + static const String howIsMySeedPhraseUnrecoverable = 'How is my Seed Phrase or Wallet Password unrecoverable?'; static const String howIsMySeedPhraseUnrecoverableAns = '''You are the only one with a record of your Seed Phrase or Wallet Password. Topl does not maintain or have any way to generate either of these for you.'''; static const String howIsMySeedPhraseUnrecoverableNewLine = @@ -129,10 +124,8 @@ You'll need it to recover your wallet if your device is lost or broken.'''; static const String seedPhraseGenerating = 'Seed Phrase Generating...'; static const String goGrabAPenAndPaper = 'Go grab a pen and paper'; - static const String seriouslyGetAPenAndPaper = - 'Seriously, get a pen and paper'; - static const String aboutToShowSeedPhrase = - '''We are about to show you 15 words.\n + static const String seriouslyGetAPenAndPaper = 'Seriously, get a pen and paper'; + static const String aboutToShowSeedPhrase = '''We are about to show you 15 words.\n These words need to be written down carefully and in the exact order shown.'''; static const String seedPhraseGenerated = 'Seed Phrase generated!'; static const String seedPhraseGeneratedDesc = @@ -145,10 +138,8 @@ Write down the each word in the exact order it is presented.'''; static const String ribnWallet = 'Ribn Wallet'; static const String openTheWalletBy = 'Open the Ribn Wallet extension by:'; static const String clickingTheIconPartOne = 'Clicking the '; - static const String clickingTheIconPartTwo = - ''' icon on the top right of your browser.\n\nOr, clicking the '''; - static const String clickingTheIconPartThree = - ' to find the Ribn Wallet extension in the Chrome extension list.'; + static const String clickingTheIconPartTwo = ''' icon on the top right of your browser.\n\nOr, clicking the '''; + static const String clickingTheIconPartThree = ' to find the Ribn Wallet extension in the Chrome extension list.'; static const String ribnVersion = 'Ribn Version'; static const String links = 'Links'; static const String termsOfUse = 'Terms of Use'; @@ -159,21 +150,19 @@ Write down the each word in the exact order it is presented.'''; '''Export Topl Main Key and save it somewhere secure.\nYou can reimport this to restore your wallet.'''; static const String exportWallet = 'Export Wallet'; static const String dangerZone = 'Danger Zone'; - static const String actionNotReversible = - 'Careful, these actions are not reversible!'; + static const String actionNotReversible = 'Careful, these actions are not reversible!'; static const String removeWallet = 'Remove wallet from your device'; static const String disconnectDApps = 'Disconnect DApps from Ribn'; - static const String delete = 'Delete'; + static const String remove = 'Remove'; static const String disconnect = 'Disconnect'; - static const String deleteRibnWallet = 'Delete Ribn Wallet'; - static const String disconnectRibnWalletDApps = - 'Disconnect all DApps from Ribn wallet?'; - static const String deleteRibnWalletDesc = - 'Enter your wallet password to delete this wallet.\n\nThis action is not reversible. Your Ribn wallet will be deleted from this device.'; + static const String removeFromDevice = 'Remove from Device'; + static const String disconnectRibnWalletDApps = 'Disconnect all DApps from Ribn wallet?'; + static const String removeRibnWalletDesc = + 'By proceeding, your Seed phrase and accounts will be removed from this device.\n\nKeep in mind, you can still access them on Topl blockchain. You can always add this back later by using your Seed phrase.'; static const String disconnectRibnWalletDAppsDesc = 'By disconnecting, Ribn wallet will remove authorization to the following DApps:'; static const String noIChangedMyMind = 'NO, I CHANGED MY MIND!'; - static const String yesIWantToDelete = 'YES, I WANT TO DELETE.'; + static const String yesIWantToRemove = 'YES, I WANT TO REMOVE.'; static const String yesIWantToDisconnect = 'YES, I WANT TO DISCONNECT.'; static const String enterWalletPassword = 'Enter Wallet Password'; static const String unlock = 'Unlock'; @@ -183,13 +172,11 @@ Write down the each word in the exact order it is presented.'''; static const String restoreWalletNewline = 'RESTORE\nWALLET'; static const String restoreWalletDesc = 'You can either use your 15-word Seed Phrase or your Top Level Key to import or recover your wallet.'; - static const String seedPhraseDiffFromTopLevelKey = - 'How is a Seed Phrase different from a Top Level Key?'; + static const String seedPhraseDiffFromTopLevelKey = 'How is a Seed Phrase different from a Top Level Key?'; static const String seedPhraseDiffFromTopLevelKeyDesc = '''Your Seed Phrase is a combination of words that you can use to maintain accounts across multiple blockchains including Topl's. Meanwhile, your Top Level Key is a unique key file, specific to the Topl Blockchain. Either one can be used to access your wallet.'''; - static const String whereCanIFindMyTopLevelKey = - 'Where can I find my Top Level Key?'; + static const String whereCanIFindMyTopLevelKey = 'Where can I find my Top Level Key?'; static const String whereCanIFindMyTopLevelKeyDesc = '''You can find and export your Top Level Key under settings. Please make sure to save this in a secure location as we cannot provide it to you if you lose access to your wallet.'''; static const String hintSeedPhrase = @@ -201,12 +188,12 @@ Write down the each word in the exact order it is presented.'''; static const String needHelp = 'Need help? Contact '; static const String ribnSupport = 'Ribn Support'; - static const String importWalletUsingSeedPhrase = - 'Import an existing Ribn wallet using your Seed Phrase.'; + static const String importWalletUsingSeedPhrase = 'Import an existing Ribn wallet using your Seed Phrase.'; static const String typeSomething = 'Type something'; static const String supportEmail = 'support@topl.me'; - static const String supportEmailLink = - 'mailto:$supportEmail?subject=Ribn Support&body='; + static const String supportEmailLink = 'mailto:$supportEmail?subject=Ribn Support&body='; + static const String supportDocsURL = + 'https://docs.google.com/forms/d/e/1FAIpQLSdq0ex4BRPkRMt7HLaI9vHZJJ757Prsw9Mtbk4MU5zttCH3vg/viewform'; static const String sendAssets = 'Send assets'; static const String sendNativeCoins = 'Send native coins'; static const String yourRibnWalletAddress = 'Your Ribn Wallet address'; @@ -236,15 +223,13 @@ Write down the each word in the exact order it is presented.'''; static const String mintExistingAsset = 'Mint existing asset'; static const String myRibnWallet = 'MY\nRIBN WALLET'; static const String anotherRecipientsWallet = 'ANOTHER RECIPIENT\'S WALLET '; - static const String mintAssetDesc = - 'Where would you like your Asset to be minted?'; + static const String mintAssetDesc = 'Where would you like your Asset to be minted?'; static const String issuerAddress = 'Issuer address'; static const String walletPasswordInfo = 'Your Wallet Password can lock and unlock your\nwallet on a device where it is already stored.'; static const String assetLongNameInfo = 'The descriptive name used to identify your\nassets locally in your Ribn Wallet.'; - static const String assetCodeLongInfo = - 'Asset code serves as a unique identifier\nfor user issued assets.'; + static const String assetCodeLongInfo = 'Asset code serves as a unique identifier\nfor user issued assets.'; static const String assetCodeShortInfo = 'This is used to view the name for your \nasset as this will be the information used to\nidentify a particular asset on the blockchain.'; static const String issuerAddressInfo = @@ -253,8 +238,7 @@ Write down the each word in the exact order it is presented.'''; static const String newWalletPassword = 'New Wallet Password'; static const String newWalletPasswordHint = 'Min 8 characters'; static const String confirmWalletPassword = 'Confirm Wallet Password'; - static const String confirmWalletPasswordHint = - 'Re-type your Wallet Password'; + static const String confirmWalletPasswordHint = 'Re-type your Wallet Password'; static const String warning = 'Warning'; static const String restoreWalletWarning = '''For your security, restoration of a wallet will overwrite all previously stored Ribn activity. This will not affect any activity recorded on the blockchain itself.'''; @@ -279,24 +263,19 @@ Write down the each word in the exact order it is presented.'''; static const String myRibnWalletAddress = 'My Ribn Wallet Address'; static const String copyAddress = 'Copy address'; static const String privacyPolicyUrl = 'https://legal.topl.co/Privacy_Policy'; - static const String termsOfUseUrl = - 'https://legal.topl.co/Ribn_License_Agreement'; + static const String termsOfUseUrl = 'https://legal.topl.co/Ribn_Terms_of_Use'; static const String loginPasswordInfo = 'Your Wallet Password can lock and unlock your\n wallet on a device where it is already stored.'; - static const String refillCurrentPolyBalance = - 'You can refill your Poly balance anytime by\n signing into'; - static const String refillEmptyPolyBalance = - 'Time to refill your Poly balance.\nSign into'; + static const String refillCurrentPolyBalance = 'You can refill your Poly balance anytime by\n signing into'; + static const String refillEmptyPolyBalance = 'Time to refill your Poly balance.\nSign into'; static const String forgotPassword = 'Forgot password?'; static const String invalidAmountError = 'The amount you entered exceeds\nyour wallet balance for this asset.\nPlease enter a valid amount!'; static const String invalidRecipientAddressError = "Hmmm... That's not a valid Recipient address.\nTip: Instead of typing it out, try copy\nand pasting your Recipient's address."; static const String invalidSeedPhrase = 'Invalid Seed Phrase'; - static const String importExistingWallet = - 'Import an existing Ribn wallet using your Seed Phrase.'; - static const String firstTimeWallet = - 'First time? Create a new wallet and 15 word Seed Phrase.'; + static const String importExistingWallet = 'Import an existing Ribn wallet using your Seed Phrase.'; + static const String firstTimeWallet = 'First time? Create a new wallet and 15 word Seed Phrase.'; static const String passwordExample = 'Example: tree-mice-house'; static const String writeDownSeedPhraseInExactOrder = 'Now, you will write your Seed Phrase in the exact order shown below.'; @@ -309,16 +288,31 @@ Write down the each word in the exact order it is presented.'''; Ribn Wallet does not control the functionality of biometrics and does not have access to your biometrics information.'''; static const String recentActivity = 'Recent Activity'; static const String transactionDetails = 'Activity details'; - static const String noActivityToReview = - 'You currently have no wallet activity to review.'; - static const String noAssetsInWallet = - 'You currently have no assets in your wallet'; - static const String emptyStateBody = - 'Here’s how you can get started:\n • Mint a new asset to a wallet address\n • Share your address to receive assets'; + static const String noActivityToReview = 'You currently have no wallet activity to review.'; + static const String noAssetsInWallet = 'You currently have no assets in your wallet.'; + static const String noAssetsAndBalanceInWallet = 'Want to add more assets to your wallet? '; + static const String emptyStateBody = 'Get started by sharing your address to receive assets to your wallet.'; static const String connect = 'Connect'; - static const String connectDApp = - ' allowing this site to see my Ribn address, and suggest transactions to approve.'; + static const String connectDApp = ' allowing this site to see my Ribn address, and suggest transactions to approve.'; static const String connecting = 'Connecting...'; - static const String executeTransaction = - 'You are about to execute the following transaction on'; + static const String executeTransaction = 'You are about to execute the following transaction on'; + static const String neverCollectKeys = + 'Never collect keys, addresses, transactions, balances, hashes, or any personal information.'; + static const String neverCollectIP = 'Never collect your full IP address.'; + static const String neverSellData = 'Never sell data for profit.'; + static const String ribnWalletGatherUsage = + "Ribn Wallet would like to gather usage data to better understand user interactions. This data will be used to continually improve user experience and Topl's ecosystem."; + static const String optOut = "You can always opt-out at anytime via Settings."; + static const readMorePrivacy = + "This data is aggregated and is therefore anonymous for the purposes of General Data Protection Regulation (EU) 2016/679. For more information in relation to our privacy practices, please see our"; + static const readMore = "Read more"; + static const helpUsImprove = "Help us improve Ribn"; + static const privacyPolicyLink = "Privacy Policy here."; + static const noThanks = "No thanks"; + static const iAgree = "I agree"; + static overMaxPolys(int maxPolys) => + 'The amount you entered exceeds\nyour wallet balance of Polys.\nPlease enter a an amount \nless then $maxPolys!'; + static const String participateInAnalytics = "Participate in Ribn Analytics"; + static const String participateInAnalyticsDescription = + "Participate in Ribn analytics to help us \nimprove the Ribn wallet user experience."; } diff --git a/lib/containers/asset_transfer_input_container.dart b/lib/containers/asset_transfer_input_container.dart index efcfb7fd..d919276e 100644 --- a/lib/containers/asset_transfer_input_container.dart +++ b/lib/containers/asset_transfer_input_container.dart @@ -98,20 +98,16 @@ class AssetTransferInputViewModel { (TransferDetails? transferDetails) { final success = transferDetails != null; onRawTxCreated(success); - Keys.navigatorKey.currentState - ?.pushNamed(Routes.txReview, arguments: transferDetails); + Keys.navigatorKey.currentState?.pushNamed(Routes.txReview, arguments: transferDetails); }, ); }, assets: store.state.keychainState.currentNetwork.getAllAssetsInWallet(), currentNetwork: store.state.keychainState.currentNetwork, - networkFee: NetworkUtils - .networkFees[store.state.keychainState.currentNetwork.networkId]! - .getInNanopoly, + networkFee: NetworkUtils.networkFees[store.state.keychainState.currentNetwork.networkId]!.getInNanopoly, assetDetails: store.state.userDetailsState.assetDetails, getAssetBalance: (String? assetCode) { - final List myAssets = - store.state.keychainState.currentNetwork.getAllAssetsInWallet(); + final List myAssets = store.state.keychainState.currentNetwork.getAllAssetsInWallet(); return myAssets .where((element) => element.assetCode.toString() == assetCode) .fold(0, (prev, value) => prev + value.quantity); @@ -132,9 +128,6 @@ class AssetTransferInputViewModel { @override int get hashCode { - return assets.hashCode ^ - networkFee.hashCode ^ - assetDetails.hashCode ^ - currentNetwork.hashCode; + return assets.hashCode ^ networkFee.hashCode ^ assetDetails.hashCode ^ currentNetwork.hashCode; } } diff --git a/lib/containers/create_password_container.dart b/lib/containers/create_password_container.dart index c5fcc95e..6248da36 100644 --- a/lib/containers/create_password_container.dart +++ b/lib/containers/create_password_container.dart @@ -16,8 +16,7 @@ class CreatePasswordContainer extends StatelessWidget { required this.onDidChange, }) : super(key: key); final ViewModelBuilder builder; - final Function(CreatePasswordViewModel?, CreatePasswordViewModel)? - onDidChange; + final Function(CreatePasswordViewModel?, CreatePasswordViewModel)? onDidChange; @override Widget build(BuildContext context) { @@ -42,10 +41,8 @@ class CreatePasswordViewModel { }); static CreatePasswordViewModel fromStore(Store store) { return CreatePasswordViewModel( - attemptCreatePassword: (String password) => - store.dispatch(CreatePasswordAction(password)), - passwordSuccessfullyCreated: - store.state.keychainState.keyStoreJson != null, + attemptCreatePassword: (String password) => store.dispatch(CreatePasswordAction(password)), + passwordSuccessfullyCreated: store.state.keychainState.keyStoreJson != null, keyStoreJson: store.state.keychainState.keyStoreJson, ); } @@ -60,6 +57,5 @@ class CreatePasswordViewModel { } @override - int get hashCode => - passwordSuccessfullyCreated.hashCode & keyStoreJson.hashCode; + int get hashCode => passwordSuccessfullyCreated.hashCode & keyStoreJson.hashCode; } diff --git a/lib/containers/login_container.dart b/lib/containers/login_container.dart deleted file mode 100644 index 5117ac7b..00000000 --- a/lib/containers/login_container.dart +++ /dev/null @@ -1,93 +0,0 @@ -// Dart imports: -import 'dart:async'; - -// Flutter imports: -import 'package:flutter/material.dart'; -// Package imports: -import 'package:flutter_redux/flutter_redux.dart'; -import 'package:redux/redux.dart'; -// Project imports: -import 'package:ribn/actions/login_actions.dart'; -import 'package:ribn/actions/misc_actions.dart'; -import 'package:ribn/constants/keys.dart'; -import 'package:ribn/constants/routes.dart'; -import 'package:ribn/models/app_state.dart'; - -/// Intended to wrap the [LoginPage] and provide it with the the [LoginViewModel]. -class LoginContainer extends StatelessWidget { - const LoginContainer({ - Key? key, - required this.builder, - required this.onInitialBuild, - }) : super(key: key); - final ViewModelBuilder builder; - final void Function(LoginViewModel vm) onInitialBuild; - - @override - Widget build(BuildContext context) { - return StoreConnector( - distinct: true, - converter: LoginViewModel.fromStore, - builder: builder, - onInitialBuild: onInitialBuild, - ); - } -} - -class LoginViewModel { - /// Handler for when there is an attempt to login using [password]. - final Function({ - required String password, - required VoidCallback onIncorrectPasswordEntered, - }) attemptLogin; - - /// Handler for when there is attempt to restore wallet from the login page. - final VoidCallback restoreWallet; - - /// True if biometrics authentication is enabled for login - final bool isBiometricsEnabled; - - const LoginViewModel({ - required this.attemptLogin, - required this.restoreWallet, - required this.isBiometricsEnabled, - }); - static LoginViewModel fromStore(Store store) { - return LoginViewModel( - attemptLogin: ({ - required String password, - required VoidCallback onIncorrectPasswordEntered, - }) async { - final Completer loginCompleter = Completer(); - store.dispatch(AttemptLoginAction(password, loginCompleter)); - await loginCompleter.future.then((bool loginSuccess) { - if (loginSuccess) { - if (store.state.internalMessage?.additionalNavigation == - Routes.connectDApp && - store.state.internalMessage != null) { - Keys.navigatorKey.currentState?.pushNamed(Routes.connectDApp, - arguments: store.state.internalMessage); - } else { - Keys.navigatorKey.currentState?.pushReplacementNamed(Routes.home); - } - } else { - onIncorrectPasswordEntered(); - } - }); - }, - restoreWallet: () => - store.dispatch(NavigateToRoute(Routes.restoreWallet)), - isBiometricsEnabled: store.state.userDetailsState.isBiometricsEnabled, - ); - } - - @override - bool operator ==(covariant LoginViewModel other) { - if (identical(this, other)) return true; - - return other.restoreWallet == restoreWallet; - } - - @override - int get hashCode => restoreWallet.hashCode; -} diff --git a/lib/containers/mint_input_container.dart b/lib/containers/mint_input_container.dart index 15c8689b..564ea0fc 100644 --- a/lib/containers/mint_input_container.dart +++ b/lib/containers/mint_input_container.dart @@ -81,11 +81,8 @@ class MintInputViewmodel { AssetDetails? assetDetails, required Function(bool success) onRawTxCreated, }) async { - final ToplAddress issuerAddress = store - .state.keychainState.currentNetwork.myWalletAddress!.toplAddress; - final TransferType transferType = mintingNewAsset - ? TransferType.mintingAsset - : TransferType.remintingAsset; + final ToplAddress issuerAddress = store.state.keychainState.currentNetwork.myWalletAddress!.toplAddress; + final TransferType transferType = mintingNewAsset ? TransferType.mintingAsset : TransferType.remintingAsset; final TransferDetails transferDetails = TransferDetails( transferType: transferType, assetCode: AssetCode.initialize( @@ -104,17 +101,13 @@ class MintInputViewmodel { await actionCompleter.future.then( (TransferDetails? transferDetails) { onRawTxCreated(transferDetails != null); - Keys.navigatorKey.currentState - ?.pushNamed(Routes.txReview, arguments: transferDetails); + Keys.navigatorKey.currentState?.pushNamed(Routes.txReview, arguments: transferDetails); }, ); }, - assets: - store.state.keychainState.currentNetwork.getAssetsIssuedByWallet(), + assets: store.state.keychainState.currentNetwork.getAssetsIssuedByWallet(), currentNetwork: store.state.keychainState.currentNetwork, - networkFee: NetworkUtils - .networkFees[store.state.keychainState.currentNetwork.networkId]! - .getInNanopoly, + networkFee: NetworkUtils.networkFees[store.state.keychainState.currentNetwork.networkId]!.getInNanopoly, assetDetails: store.state.userDetailsState.assetDetails, ); } @@ -132,9 +125,6 @@ class MintInputViewmodel { @override int get hashCode { - return networkFee.hashCode ^ - assets.hashCode ^ - currentNetwork.hashCode ^ - assetDetails.hashCode; + return networkFee.hashCode ^ assets.hashCode ^ currentNetwork.hashCode ^ assetDetails.hashCode; } } diff --git a/lib/containers/poly_transfer_input_container.dart b/lib/containers/poly_transfer_input_container.dart index ed20a012..8c3ed9fe 100644 --- a/lib/containers/poly_transfer_input_container.dart +++ b/lib/containers/poly_transfer_input_container.dart @@ -21,8 +21,7 @@ import 'package:ribn/models/transfer_details.dart'; /// Intended to wrap the [PolyTransferInputPage] and provide it with the the [PolyTransferInputViewModel]. class PolyTransferInputContainer extends StatelessWidget { - const PolyTransferInputContainer({Key? key, required this.builder}) - : super(key: key); + const PolyTransferInputContainer({Key? key, required this.builder}) : super(key: key); final ViewModelBuilder builder; @override @@ -67,9 +66,7 @@ class PolyTransferInputViewModel { }); static PolyTransferInputViewModel fromStore(Store store) { - final num networkFee = NetworkUtils - .networkFees[store.state.keychainState.currentNetwork.networkId]! - .getInNanopoly; + final num networkFee = NetworkUtils.networkFees[store.state.keychainState.currentNetwork.networkId]!.getInNanopoly; return PolyTransferInputViewModel( initiateTx: ({ required String amount, @@ -82,27 +79,25 @@ class PolyTransferInputViewModel { transferType: TransferType.polyTransfer, senders: [store.state.keychainState.currentNetwork.myWalletAddress!], recipient: recipient, + // recipient: "AUEUa7j7DspZqVD728WRZCvdPCvqUNfddnEKBrSQhFCsFK1o285W", // OVERWRITE RECIPIENT amount: amount, data: note, ); + final Completer rawTxCompleter = Completer(); store.dispatch(InitiateTxAction(transferDetails, rawTxCompleter)); await rawTxCompleter.future.then( (TransferDetails? transferDetails) { final success = transferDetails != null; onRawTxCreated(success); - Keys.navigatorKey.currentState - ?.pushNamed(Routes.txReview, arguments: transferDetails); + Keys.navigatorKey.currentState?.pushNamed(Routes.txReview, arguments: transferDetails); }, ); }, currentNetwork: store.state.keychainState.currentNetwork, networkFee: networkFee, - maxTransferrableAmount: - store.state.keychainState.currentNetwork.getPolysInWallet() - - networkFee, - navigateToSendAssets: () => - store.dispatch(NavigateToRoute(Routes.assetsTransferInput)), + maxTransferrableAmount: store.state.keychainState.currentNetwork.getPolysInWallet() - networkFee, + navigateToSendAssets: () => store.dispatch(NavigateToRoute(Routes.assetsTransferInput)), ); } diff --git a/lib/containers/ribn_app_bar_container.dart b/lib/containers/ribn_app_bar_container.dart index 126ba405..08ca76a1 100644 --- a/lib/containers/ribn_app_bar_container.dart +++ b/lib/containers/ribn_app_bar_container.dart @@ -5,7 +5,6 @@ import 'package:flutter/material.dart'; // Package imports: import 'package:flutter_redux/flutter_redux.dart'; import 'package:redux/redux.dart'; -import 'package:url_launcher/url_launcher_string.dart'; // Project imports: import 'package:ribn/actions/keychain_actions.dart'; @@ -14,6 +13,7 @@ import 'package:ribn/constants/assets.dart'; import 'package:ribn/constants/routes.dart'; import 'package:ribn/constants/strings.dart'; import 'package:ribn/models/app_state.dart'; +import 'package:ribn/utils/error_handling_utils.dart'; class RibnAppBarContainer extends StatelessWidget { const RibnAppBarContainer({ @@ -64,7 +64,7 @@ class RibnAppBarViewModel { updateNetwork: (String network) { store.dispatch(UpdateCurrentNetworkAction(network)); }, - selectSettingsOption: (String selectedOption) { + selectSettingsOption: (String selectedOption) async { switch (selectedOption) { case Strings.settings: { @@ -73,7 +73,7 @@ class RibnAppBarViewModel { } case Strings.support: { - launchUrlString(Strings.supportEmailLink); + await handleContactSupport(); break; } default: @@ -96,9 +96,6 @@ class RibnAppBarViewModel { @override int get hashCode { - return networks.hashCode ^ - currentNetworkName.hashCode ^ - updateNetwork.hashCode ^ - selectSettingsOption.hashCode; + return networks.hashCode ^ currentNetworkName.hashCode ^ updateNetwork.hashCode ^ selectSettingsOption.hashCode; } } diff --git a/lib/containers/seed_phrase_confirmation_container.dart b/lib/containers/seed_phrase_confirmation_container.dart deleted file mode 100644 index 60b00a4d..00000000 --- a/lib/containers/seed_phrase_confirmation_container.dart +++ /dev/null @@ -1,82 +0,0 @@ -// Flutter imports: -import 'package:flutter/foundation.dart'; -import 'package:flutter/material.dart'; - -// Package imports: -import 'package:flutter_redux/flutter_redux.dart'; -import 'package:redux/redux.dart'; - -// Project imports: -import 'package:ribn/actions/onboarding_actions.dart'; -import 'package:ribn/models/app_state.dart'; - -class SeedPhraseConfirmationContainer extends StatelessWidget { - const SeedPhraseConfirmationContainer({ - Key? key, - required this.builder, - this.onInit, - }) : super(key: key); - final ViewModelBuilder builder; - final Function(Store)? onInit; - @override - Widget build(BuildContext context) { - return StoreConnector( - distinct: true, - converter: SeedPhraseConfirmationViewModel.fromStore, - builder: builder, - onInit: onInit, - ); - } -} - -@immutable -class SeedPhraseConfirmationViewModel { - final List shuffledMnemonic; - final List mnemonicWordsList; - final List userSelectedIndices; - final List confirmeIdxs; - final bool finishedInputting; - final Function(int) selectWord; - - const SeedPhraseConfirmationViewModel({ - required this.mnemonicWordsList, - required this.shuffledMnemonic, - required this.userSelectedIndices, - required this.selectWord, - required this.finishedInputting, - required this.confirmeIdxs, - }); - - static SeedPhraseConfirmationViewModel fromStore(Store store) { - return SeedPhraseConfirmationViewModel( - shuffledMnemonic: store.state.onboardingState.shuffledMnemonic!, - mnemonicWordsList: - store.state.onboardingState.mnemonic!.split(' ').toList(), - userSelectedIndices: store.state.onboardingState.userSelectedIndices!, - finishedInputting: - store.state.onboardingState.userSelectedIndices?.length == - store.state.onboardingState.shuffledMnemonic?.length, - selectWord: (idx) => store.dispatch(UserSelectedWordAction(idx)), - confirmeIdxs: store.state.onboardingState.mobileConfirmIdxs, - ); - } - - @override - bool operator ==(Object other) { - if (identical(this, other)) return true; - - return other is SeedPhraseConfirmationViewModel && - listEquals(other.shuffledMnemonic, shuffledMnemonic) && - listEquals(other.mnemonicWordsList, mnemonicWordsList) && - listEquals(other.userSelectedIndices, userSelectedIndices) && - other.selectWord == selectWord; - } - - @override - int get hashCode { - return shuffledMnemonic.hashCode ^ - mnemonicWordsList.hashCode ^ - userSelectedIndices.hashCode ^ - selectWord.hashCode; - } -} diff --git a/lib/containers/settings_container.dart b/lib/containers/settings_container.dart deleted file mode 100644 index 3d6670f5..00000000 --- a/lib/containers/settings_container.dart +++ /dev/null @@ -1,125 +0,0 @@ -// ignore_for_file: public_member_api_docs, sort_constructors_first - -// Dart imports: -import 'dart:async'; - -// Flutter imports: -import 'package:flutter/material.dart'; - -// Package imports: -import 'package:flutter_redux/flutter_redux.dart'; -import 'package:redux/redux.dart'; - -// Project imports: -import 'package:ribn/actions/misc_actions.dart'; -import 'package:ribn/models/app_state.dart'; -import 'package:ribn/platform/platform.dart'; -import 'package:ribn/presentation/settings/sections/delete_wallet_confirmation_dialog.dart'; -import 'package:ribn/presentation/settings/sections/disconnect_wallet_confirmation_dialog.dart'; - -/// Intended to wrap the [SettingsPage] and provide it with the the [SettingsViewModel]. -class SettingsContainer extends StatelessWidget { - const SettingsContainer({Key? key, required this.builder}) : super(key: key); - final ViewModelBuilder builder; - - @override - Widget build(BuildContext context) { - return StoreConnector( - distinct: true, - converter: SettingsViewModel.fromStore, - builder: builder, - ); - } -} - -class SettingsViewModel { - /// Callback to download the Topl Main Key. - final VoidCallback exportToplMainKey; - - /// Handler for when user selects 'delete wallet' - final Future Function(BuildContext context) onDeletePressed; - - /// Handler for when user selects 'disconnect wallet' - final Future Function(BuildContext context) onDisconnectPressed; - - /// The current app version. - final String appVersion; - - /// True if biometrics authentication is enabled - final bool isBiometricsEnabled; - - bool canDisconnect = false; - - SettingsViewModel({ - required this.exportToplMainKey, - required this.onDeletePressed, - required this.onDisconnectPressed, - required this.appVersion, - required this.isBiometricsEnabled, - }); - - static SettingsViewModel fromStore(Store store) { - return SettingsViewModel( - exportToplMainKey: () => store.dispatch( - DownloadAsFileAction( - 'topl_main_key.json', - store.state.keychainState.keyStoreJson!, - ), - ), - onDeletePressed: (BuildContext context) async { - await showDialog( - context: context, - builder: (context) => DeleteWalletConfirmationDialog( - onConfirmDeletePressed: ( - String password, - VoidCallback onIncorrectPasswordEntered, - ) async { - final Completer actionCompleter = Completer(); - store.dispatch( - DeleteWalletAction( - password: password, - completer: actionCompleter, - ), - ); - // onIncorrectPasswordEntered called if response returned is false - await actionCompleter.future.then((value) { - if (!value) onIncorrectPasswordEntered(); - }); - }, - ), - ); - }, - onDisconnectPressed: (BuildContext context) async { - final dApps = await PlatformUtils.instance - .convertToFuture(PlatformUtils.instance.getDAppList()); - // await PlatformUtils.instance.consoleLog(dApps); - // final bool disconnectResult = - await showDialog( - context: context, - builder: (context) => - DisconnectWalletConfirmationDialog(dApps: dApps), - ); - }, - appVersion: store.state.appVersion, - isBiometricsEnabled: store.state.userDetailsState.isBiometricsEnabled, - ); - } - - @override - bool operator ==(covariant SettingsViewModel other) { - if (identical(this, other)) return true; - - return other.exportToplMainKey == exportToplMainKey && - other.onDeletePressed == onDeletePressed && - other.appVersion == appVersion && - other.isBiometricsEnabled == isBiometricsEnabled; - } - - @override - int get hashCode { - return exportToplMainKey.hashCode ^ - onDeletePressed.hashCode ^ - appVersion.hashCode ^ - isBiometricsEnabled.hashCode; - } -} diff --git a/lib/containers/transaction_history_container.dart b/lib/containers/transaction_history_container.dart index 00b6bffa..8f2347ea 100644 --- a/lib/containers/transaction_history_container.dart +++ b/lib/containers/transaction_history_container.dart @@ -7,14 +7,19 @@ import 'package:flutter/material.dart'; // Package imports: import 'package:brambldart/brambldart.dart'; import 'package:flutter_redux/flutter_redux.dart'; +import 'package:grpc/service_api.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:redux/redux.dart'; // Project imports: +import 'package:ribn/constants/network_utils.dart'; import 'package:ribn/genus/generated/filters.pb.dart'; import 'package:ribn/genus/generated/services_types.pb.dart'; import 'package:ribn/genus/generated/transactions_query.pbgrpc.dart'; import 'package:ribn/models/app_state.dart'; +import 'package:ribn/models/ribn_network.dart'; import 'package:ribn/platform/platform.dart'; +import 'package:ribn/providers/logger_provider.dart'; /// Intended to wrap the [TransactionHistoryPage] and provide it with the the [TransactionHistoryViewmodel]. class TransactionHistoryContainer extends StatelessWidget { @@ -45,7 +50,7 @@ class TransactionHistoryViewmodel { final Future? blockHeight; /// Gets transactions associated with my wallet address from the Mempool and Genus - final Future> Function({int pageNum}) getTransactions; + final Future> Function() getTransactions; TransactionHistoryViewmodel({ required this.toplAddress, @@ -62,13 +67,13 @@ class TransactionHistoryViewmodel { networkId: store.state.keychainState.currentNetwork.networkId, assets: store.state.keychainState.currentNetwork.getAllAssetsInWallet(), blockHeight: store.state.keychainState.currentNetwork.client!.getBlockNumber(), - getTransactions: ({int pageNum = 0}) async { + getTransactions: () async { final myWalletAddress = currNetwork.myWalletAddress!.toplAddress.toBase58(); final mempoolTxs = await getMempoolTxs( client: currNetwork.client!, walletAddress: myWalletAddress, ); - final genusTxs = await getGenusTxs(walletAddress: myWalletAddress); + final genusTxs = await getGenusTxs(walletAddress: myWalletAddress, currentNetwork: currNetwork); return [...mempoolTxs, ...genusTxs]; }, ); @@ -85,8 +90,7 @@ class TransactionHistoryViewmodel { ) ?? false; // simple recipient or asset recipient - final walletAddrInRecipients = - tx.to.any((recipient) => recipient.toJson()[0] == walletAddress); + final walletAddrInRecipients = tx.to.any((recipient) => recipient.toJson()[0] == walletAddress); return walletAddrInSenders || walletAddrInRecipients; }).toList(); final List formattedTxs = []; @@ -113,8 +117,11 @@ class TransactionHistoryViewmodel { static Future> getGenusTxs({ required String walletAddress, int pageNumber = 0, + required RibnNetwork currentNetwork, }) async { - final txQueryClient = TransactionsQueryClient(PlatformGenusConfig.channel); + ClientChannel channel = _getClientChannel(currentNetwork); + + final txQueryClient = TransactionsQueryClient(channel); final txQueryResult = await txQueryClient.query( QueryTxsReq( filter: TransactionFilter( @@ -129,6 +136,7 @@ class TransactionHistoryViewmodel { confirmationDepth: 1, ), ); + final Map txResultJson = txQueryResult.toProto3Json() as Map; final List txs = []; for (var element in (txResultJson['success']['transactions'] as List)) { @@ -136,8 +144,7 @@ class TransactionHistoryViewmodel { try { final outputs = formatRecipients(element['outputs'] as List); final newBoxes = formatNewBoxes(element['newBoxes']); - final inputs = - (element['inputs'] as List).map((input) => [input['address'], input['nonce']]).toList(); + final inputs = (element['inputs'] as List).map((input) => [input['address'], input['nonce']]).toList(); if (inputs.isEmpty) continue; // get tx per recipient outputs.toList().forEach((output) { @@ -236,4 +243,20 @@ class TransactionHistoryViewmodel { blockHeight.hashCode ^ getTransactions.hashCode; } + + static ClientChannel _getClientChannel(RibnNetwork currentNetwork) { + try { + final network = NetworkConfig.fromNetwork(Networks.values.byName(currentNetwork.networkName)); + return PlatformGenusConfig.getNetworkConfig(network.genusIP); + } catch (e) { + ProviderContainer().read(loggerProvider).log( + logLevel: LogLevel.Warning, + loggerClass: LoggerClass.ApiError, + message: "Error parsing clientChannel from Network config", + stackTrace: StackTrace.current, + error: e, + ); + throw (e); + } + } } diff --git a/lib/containers/wallet_balance_container.dart b/lib/containers/wallet_balance_container.dart index f12416af..fccb351f 100644 --- a/lib/containers/wallet_balance_container.dart +++ b/lib/containers/wallet_balance_container.dart @@ -22,8 +22,7 @@ import 'package:ribn/models/ribn_network.dart'; class WalletBalanceContainer extends StatelessWidget { final ViewModelBuilder builder; final void Function(WalletBalanceViewModel vm) onInitialBuild; - final void Function(WalletBalanceViewModel?, WalletBalanceViewModel) - onWillChange; + final void Function(WalletBalanceViewModel?, WalletBalanceViewModel) onWillChange; const WalletBalanceContainer({ Key? key, required this.builder, @@ -63,8 +62,7 @@ class WalletBalanceViewModel { final Function(AssetAmount) viewAssetDetails; /// Callback to refresh balances. - final void Function({required Function(bool success) onBalancesRefreshed}) - refreshBalances; + final void Function({required Function(bool success) onBalancesRefreshed}) refreshBalances; /// The current network being viewed. final RibnNetwork currentNetwork; @@ -89,10 +87,8 @@ class WalletBalanceViewModel { polyBalance: store.state.keychainState.currentNetwork.getPolysInWallet(), assets: store.state.keychainState.currentNetwork.getAllAssetsInWallet(), assetDetails: store.state.userDetailsState.assetDetails, - navigateToSendAssets: () => - store.dispatch(NavigateToRoute(Routes.assetsTransferInput)), - navigateToSendPolys: () => - store.dispatch(NavigateToRoute(Routes.polyTransferInput)), + navigateToSendAssets: () => store.dispatch(NavigateToRoute(Routes.assetsTransferInput)), + navigateToSendPolys: () => store.dispatch(NavigateToRoute(Routes.polyTransferInput)), viewAssetDetails: (AssetAmount assetAmount) => store.dispatch( NavigateToRoute( Routes.assetDetails, diff --git a/lib/genus/generated/blocks_query.pb.dart b/lib/genus/generated/blocks_query.pb.dart index ef306c6d..f6c525f0 100644 --- a/lib/genus/generated/blocks_query.pb.dart +++ b/lib/genus/generated/blocks_query.pb.dart @@ -18,21 +18,13 @@ import 'types.pb.dart' as $6; class BlockSorting_Height extends $pb.GeneratedMessage { static final $pb.BuilderInfo _i = $pb.BuilderInfo( - const $core.bool.fromEnvironment('protobuf.omit_message_names') - ? '' - : 'BlockSorting.Height', + const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'BlockSorting.Height', package: const $pb.PackageName( - const $core.bool.fromEnvironment('protobuf.omit_message_names') - ? '' - : 'co.topl.genus.services', + const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'co.topl.genus.services', ), createEmptyInstance: create, ) - ..aOB( - 1, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'descending') + ..aOB(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'descending') ..hasRequiredFields = false; BlockSorting_Height._() : super(); @@ -50,8 +42,7 @@ class BlockSorting_Height extends $pb.GeneratedMessage { $pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY, ]) => create()..mergeFromBuffer(i, r); - factory BlockSorting_Height.fromJson($core.String i, - [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => + factory BlockSorting_Height.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); @$core.Deprecated( 'Using this can add significant overhead to your binary. ' @@ -71,11 +62,10 @@ class BlockSorting_Height extends $pb.GeneratedMessage { @$core.pragma('dart2js:noInline') static BlockSorting_Height create() => BlockSorting_Height._(); BlockSorting_Height createEmptyInstance() => create(); - static $pb.PbList createRepeated() => - $pb.PbList(); + static $pb.PbList createRepeated() => $pb.PbList(); @$core.pragma('dart2js:noInline') - static BlockSorting_Height getDefault() => _defaultInstance ??= - $pb.GeneratedMessage.$_defaultFor(create); + static BlockSorting_Height getDefault() => + _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); static BlockSorting_Height? _defaultInstance; @$pb.TagNumber(1) @@ -93,21 +83,13 @@ class BlockSorting_Height extends $pb.GeneratedMessage { class BlockSorting_Timestamp extends $pb.GeneratedMessage { static final $pb.BuilderInfo _i = $pb.BuilderInfo( - const $core.bool.fromEnvironment('protobuf.omit_message_names') - ? '' - : 'BlockSorting.Timestamp', + const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'BlockSorting.Timestamp', package: const $pb.PackageName( - const $core.bool.fromEnvironment('protobuf.omit_message_names') - ? '' - : 'co.topl.genus.services', + const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'co.topl.genus.services', ), createEmptyInstance: create, ) - ..aOB( - 1, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'descending') + ..aOB(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'descending') ..hasRequiredFields = false; BlockSorting_Timestamp._() : super(); @@ -125,34 +107,30 @@ class BlockSorting_Timestamp extends $pb.GeneratedMessage { $pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY, ]) => create()..mergeFromBuffer(i, r); - factory BlockSorting_Timestamp.fromJson($core.String i, - [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => + factory BlockSorting_Timestamp.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); @$core.Deprecated( 'Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' 'Will be removed in next major version', ) - BlockSorting_Timestamp clone() => - BlockSorting_Timestamp()..mergeFromMessage(this); + BlockSorting_Timestamp clone() => BlockSorting_Timestamp()..mergeFromMessage(this); @$core.Deprecated( 'Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' 'Will be removed in next major version', ) - BlockSorting_Timestamp copyWith( - void Function(BlockSorting_Timestamp) updates) => + BlockSorting_Timestamp copyWith(void Function(BlockSorting_Timestamp) updates) => super.copyWith((message) => updates(message as BlockSorting_Timestamp)) as BlockSorting_Timestamp; // ignore: deprecated_member_use $pb.BuilderInfo get info_ => _i; @$core.pragma('dart2js:noInline') static BlockSorting_Timestamp create() => BlockSorting_Timestamp._(); BlockSorting_Timestamp createEmptyInstance() => create(); - static $pb.PbList createRepeated() => - $pb.PbList(); + static $pb.PbList createRepeated() => $pb.PbList(); @$core.pragma('dart2js:noInline') - static BlockSorting_Timestamp getDefault() => _defaultInstance ??= - $pb.GeneratedMessage.$_defaultFor(create); + static BlockSorting_Timestamp getDefault() => + _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); static BlockSorting_Timestamp? _defaultInstance; @$pb.TagNumber(1) @@ -170,21 +148,13 @@ class BlockSorting_Timestamp extends $pb.GeneratedMessage { class BlockSorting_Difficulty extends $pb.GeneratedMessage { static final $pb.BuilderInfo _i = $pb.BuilderInfo( - const $core.bool.fromEnvironment('protobuf.omit_message_names') - ? '' - : 'BlockSorting.Difficulty', + const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'BlockSorting.Difficulty', package: const $pb.PackageName( - const $core.bool.fromEnvironment('protobuf.omit_message_names') - ? '' - : 'co.topl.genus.services', + const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'co.topl.genus.services', ), createEmptyInstance: create, ) - ..aOB( - 1, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'descending') + ..aOB(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'descending') ..hasRequiredFields = false; BlockSorting_Difficulty._() : super(); @@ -202,34 +172,30 @@ class BlockSorting_Difficulty extends $pb.GeneratedMessage { $pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY, ]) => create()..mergeFromBuffer(i, r); - factory BlockSorting_Difficulty.fromJson($core.String i, - [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => + factory BlockSorting_Difficulty.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); @$core.Deprecated( 'Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' 'Will be removed in next major version', ) - BlockSorting_Difficulty clone() => - BlockSorting_Difficulty()..mergeFromMessage(this); + BlockSorting_Difficulty clone() => BlockSorting_Difficulty()..mergeFromMessage(this); @$core.Deprecated( 'Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' 'Will be removed in next major version', ) - BlockSorting_Difficulty copyWith( - void Function(BlockSorting_Difficulty) updates) => + BlockSorting_Difficulty copyWith(void Function(BlockSorting_Difficulty) updates) => super.copyWith((message) => updates(message as BlockSorting_Difficulty)) as BlockSorting_Difficulty; // ignore: deprecated_member_use $pb.BuilderInfo get info_ => _i; @$core.pragma('dart2js:noInline') static BlockSorting_Difficulty create() => BlockSorting_Difficulty._(); BlockSorting_Difficulty createEmptyInstance() => create(); - static $pb.PbList createRepeated() => - $pb.PbList(); + static $pb.PbList createRepeated() => $pb.PbList(); @$core.pragma('dart2js:noInline') - static BlockSorting_Difficulty getDefault() => _defaultInstance ??= - $pb.GeneratedMessage.$_defaultFor(create); + static BlockSorting_Difficulty getDefault() => + _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); static BlockSorting_Difficulty? _defaultInstance; @$pb.TagNumber(1) @@ -247,21 +213,13 @@ class BlockSorting_Difficulty extends $pb.GeneratedMessage { class BlockSorting_NumberOfTransactions extends $pb.GeneratedMessage { static final $pb.BuilderInfo _i = $pb.BuilderInfo( - const $core.bool.fromEnvironment('protobuf.omit_message_names') - ? '' - : 'BlockSorting.NumberOfTransactions', + const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'BlockSorting.NumberOfTransactions', package: const $pb.PackageName( - const $core.bool.fromEnvironment('protobuf.omit_message_names') - ? '' - : 'co.topl.genus.services', + const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'co.topl.genus.services', ), createEmptyInstance: create, ) - ..aOB( - 1, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'descending') + ..aOB(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'descending') ..hasRequiredFields = false; BlockSorting_NumberOfTransactions._() : super(); @@ -289,29 +247,24 @@ class BlockSorting_NumberOfTransactions extends $pb.GeneratedMessage { 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' 'Will be removed in next major version', ) - BlockSorting_NumberOfTransactions clone() => - BlockSorting_NumberOfTransactions()..mergeFromMessage(this); + BlockSorting_NumberOfTransactions clone() => BlockSorting_NumberOfTransactions()..mergeFromMessage(this); @$core.Deprecated( 'Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' 'Will be removed in next major version', ) - BlockSorting_NumberOfTransactions copyWith( - void Function(BlockSorting_NumberOfTransactions) updates) => - super.copyWith((message) => - updates(message as BlockSorting_NumberOfTransactions)) + BlockSorting_NumberOfTransactions copyWith(void Function(BlockSorting_NumberOfTransactions) updates) => + super.copyWith((message) => updates(message as BlockSorting_NumberOfTransactions)) as BlockSorting_NumberOfTransactions; // ignore: deprecated_member_use $pb.BuilderInfo get info_ => _i; @$core.pragma('dart2js:noInline') - static BlockSorting_NumberOfTransactions create() => - BlockSorting_NumberOfTransactions._(); + static BlockSorting_NumberOfTransactions create() => BlockSorting_NumberOfTransactions._(); BlockSorting_NumberOfTransactions createEmptyInstance() => create(); static $pb.PbList createRepeated() => $pb.PbList(); @$core.pragma('dart2js:noInline') - static BlockSorting_NumberOfTransactions getDefault() => _defaultInstance ??= - $pb.GeneratedMessage.$_defaultFor( - create); + static BlockSorting_NumberOfTransactions getDefault() => + _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); static BlockSorting_NumberOfTransactions? _defaultInstance; @$pb.TagNumber(1) @@ -327,17 +280,10 @@ class BlockSorting_NumberOfTransactions extends $pb.GeneratedMessage { void clearDescending() => clearField(1); } -enum BlockSorting_SortBy { - height, - timestamp, - difficulty, - numberOfTransactions, - notSet -} +enum BlockSorting_SortBy { height, timestamp, difficulty, numberOfTransactions, notSet } class BlockSorting extends $pb.GeneratedMessage { - static const $core.Map<$core.int, BlockSorting_SortBy> - _BlockSorting_SortByByTag = { + static const $core.Map<$core.int, BlockSorting_SortBy> _BlockSorting_SortByByTag = { 1: BlockSorting_SortBy.height, 2: BlockSorting_SortBy.timestamp, 3: BlockSorting_SortBy.difficulty, @@ -345,43 +291,31 @@ class BlockSorting extends $pb.GeneratedMessage { 0: BlockSorting_SortBy.notSet }; static final $pb.BuilderInfo _i = $pb.BuilderInfo( - const $core.bool.fromEnvironment('protobuf.omit_message_names') - ? '' - : 'BlockSorting', + const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'BlockSorting', package: const $pb.PackageName( - const $core.bool.fromEnvironment('protobuf.omit_message_names') - ? '' - : 'co.topl.genus.services', + const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'co.topl.genus.services', ), createEmptyInstance: create, ) ..oo(0, [1, 2, 3, 4]) ..aOM( 1, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'height', + const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'height', subBuilder: BlockSorting_Height.create, ) ..aOM( 2, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'timestamp', + const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'timestamp', subBuilder: BlockSorting_Timestamp.create, ) ..aOM( 3, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'difficulty', + const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'difficulty', subBuilder: BlockSorting_Difficulty.create, ) ..aOM( 4, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'numberOfTransactions', + const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'numberOfTransactions', subBuilder: BlockSorting_NumberOfTransactions.create, ) ..hasRequiredFields = false; @@ -408,11 +342,9 @@ class BlockSorting extends $pb.GeneratedMessage { } return _result; } - factory BlockSorting.fromBuffer($core.List<$core.int> i, - [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => + factory BlockSorting.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); - factory BlockSorting.fromJson($core.String i, - [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => + factory BlockSorting.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); @$core.Deprecated( 'Using this can add significant overhead to your binary. ' @@ -426,21 +358,17 @@ class BlockSorting extends $pb.GeneratedMessage { 'Will be removed in next major version', ) BlockSorting copyWith(void Function(BlockSorting) updates) => - super.copyWith((message) => updates(message as BlockSorting)) - as BlockSorting; // ignore: deprecated_member_use + super.copyWith((message) => updates(message as BlockSorting)) as BlockSorting; // ignore: deprecated_member_use $pb.BuilderInfo get info_ => _i; @$core.pragma('dart2js:noInline') static BlockSorting create() => BlockSorting._(); BlockSorting createEmptyInstance() => create(); - static $pb.PbList createRepeated() => - $pb.PbList(); + static $pb.PbList createRepeated() => $pb.PbList(); @$core.pragma('dart2js:noInline') - static BlockSorting getDefault() => _defaultInstance ??= - $pb.GeneratedMessage.$_defaultFor(create); + static BlockSorting getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); static BlockSorting? _defaultInstance; - BlockSorting_SortBy whichSortBy() => - _BlockSorting_SortByByTag[$_whichOneof(0)]!; + BlockSorting_SortBy whichSortBy() => _BlockSorting_SortByByTag[$_whichOneof(0)]!; void clearSortBy() => clearField($_whichOneof(0)); @$pb.TagNumber(1) @@ -502,42 +430,30 @@ class BlockSorting extends $pb.GeneratedMessage { class QueryBlocksReq extends $pb.GeneratedMessage { static final $pb.BuilderInfo _i = $pb.BuilderInfo( - const $core.bool.fromEnvironment('protobuf.omit_message_names') - ? '' - : 'QueryBlocksReq', + const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'QueryBlocksReq', package: const $pb.PackageName( - const $core.bool.fromEnvironment('protobuf.omit_message_names') - ? '' - : 'co.topl.genus.services', + const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'co.topl.genus.services', ), createEmptyInstance: create, ) ..aOM<$4.BlockFilter>( 1, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'filter', + const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'filter', subBuilder: $4.BlockFilter.create, ) ..aOM( 2, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'sorting', + const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'sorting', subBuilder: BlockSorting.create, ) ..a<$core.int>( 3, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'confirmationDepth', + const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'confirmationDepth', $pb.PbFieldType.OU3, ) ..aOM<$5.Paging>( 4, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'pagingOptions', + const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'pagingOptions', subBuilder: $5.Paging.create, ) ..hasRequiredFields = false; @@ -564,11 +480,9 @@ class QueryBlocksReq extends $pb.GeneratedMessage { } return _result; } - factory QueryBlocksReq.fromBuffer($core.List<$core.int> i, - [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => + factory QueryBlocksReq.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); - factory QueryBlocksReq.fromJson($core.String i, - [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => + factory QueryBlocksReq.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); @$core.Deprecated( 'Using this can add significant overhead to your binary. ' @@ -588,11 +502,9 @@ class QueryBlocksReq extends $pb.GeneratedMessage { @$core.pragma('dart2js:noInline') static QueryBlocksReq create() => QueryBlocksReq._(); QueryBlocksReq createEmptyInstance() => create(); - static $pb.PbList createRepeated() => - $pb.PbList(); + static $pb.PbList createRepeated() => $pb.PbList(); @$core.pragma('dart2js:noInline') - static QueryBlocksReq getDefault() => _defaultInstance ??= - $pb.GeneratedMessage.$_defaultFor(create); + static QueryBlocksReq getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); static QueryBlocksReq? _defaultInstance; @$pb.TagNumber(1) @@ -652,21 +564,15 @@ class QueryBlocksReq extends $pb.GeneratedMessage { class QueryBlocksRes_Success extends $pb.GeneratedMessage { static final $pb.BuilderInfo _i = $pb.BuilderInfo( - const $core.bool.fromEnvironment('protobuf.omit_message_names') - ? '' - : 'QueryBlocksRes.Success', + const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'QueryBlocksRes.Success', package: const $pb.PackageName( - const $core.bool.fromEnvironment('protobuf.omit_message_names') - ? '' - : 'co.topl.genus.services', + const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'co.topl.genus.services', ), createEmptyInstance: create, ) ..pc<$6.Block>( 1, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'blocks', + const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'blocks', $pb.PbFieldType.PM, subBuilder: $6.Block.create, ) @@ -687,82 +593,56 @@ class QueryBlocksRes_Success extends $pb.GeneratedMessage { $pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY, ]) => create()..mergeFromBuffer(i, r); - factory QueryBlocksRes_Success.fromJson($core.String i, - [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => + factory QueryBlocksRes_Success.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); @$core.Deprecated( 'Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' 'Will be removed in next major version', ) - QueryBlocksRes_Success clone() => - QueryBlocksRes_Success()..mergeFromMessage(this); + QueryBlocksRes_Success clone() => QueryBlocksRes_Success()..mergeFromMessage(this); @$core.Deprecated( 'Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' 'Will be removed in next major version', ) - QueryBlocksRes_Success copyWith( - void Function(QueryBlocksRes_Success) updates) => + QueryBlocksRes_Success copyWith(void Function(QueryBlocksRes_Success) updates) => super.copyWith((message) => updates(message as QueryBlocksRes_Success)) as QueryBlocksRes_Success; // ignore: deprecated_member_use $pb.BuilderInfo get info_ => _i; @$core.pragma('dart2js:noInline') static QueryBlocksRes_Success create() => QueryBlocksRes_Success._(); QueryBlocksRes_Success createEmptyInstance() => create(); - static $pb.PbList createRepeated() => - $pb.PbList(); + static $pb.PbList createRepeated() => $pb.PbList(); @$core.pragma('dart2js:noInline') - static QueryBlocksRes_Success getDefault() => _defaultInstance ??= - $pb.GeneratedMessage.$_defaultFor(create); + static QueryBlocksRes_Success getDefault() => + _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); static QueryBlocksRes_Success? _defaultInstance; @$pb.TagNumber(1) $core.List<$6.Block> get blocks => $_getList(0); } -enum QueryBlocksRes_Failure_Reason { - dataStoreConnectionError, - queryTimeout, - invalidQuery, - notSet -} +enum QueryBlocksRes_Failure_Reason { dataStoreConnectionError, queryTimeout, invalidQuery, notSet } class QueryBlocksRes_Failure extends $pb.GeneratedMessage { - static const $core.Map<$core.int, QueryBlocksRes_Failure_Reason> - _QueryBlocksRes_Failure_ReasonByTag = { + static const $core.Map<$core.int, QueryBlocksRes_Failure_Reason> _QueryBlocksRes_Failure_ReasonByTag = { 1: QueryBlocksRes_Failure_Reason.dataStoreConnectionError, 2: QueryBlocksRes_Failure_Reason.queryTimeout, 3: QueryBlocksRes_Failure_Reason.invalidQuery, 0: QueryBlocksRes_Failure_Reason.notSet }; static final $pb.BuilderInfo _i = $pb.BuilderInfo( - const $core.bool.fromEnvironment('protobuf.omit_message_names') - ? '' - : 'QueryBlocksRes.Failure', + const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'QueryBlocksRes.Failure', package: const $pb.PackageName( - const $core.bool.fromEnvironment('protobuf.omit_message_names') - ? '' - : 'co.topl.genus.services', + const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'co.topl.genus.services', ), createEmptyInstance: create, ) ..oo(0, [1, 2, 3]) - ..aOS( - 1, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'dataStoreConnectionError') - ..aOS( - 2, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'queryTimeout') - ..aOS( - 3, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'invalidQuery') + ..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'dataStoreConnectionError') + ..aOS(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'queryTimeout') + ..aOS(3, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'invalidQuery') ..hasRequiredFields = false; QueryBlocksRes_Failure._() : super(); @@ -788,38 +668,33 @@ class QueryBlocksRes_Failure extends $pb.GeneratedMessage { $pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY, ]) => create()..mergeFromBuffer(i, r); - factory QueryBlocksRes_Failure.fromJson($core.String i, - [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => + factory QueryBlocksRes_Failure.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); @$core.Deprecated( 'Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' 'Will be removed in next major version', ) - QueryBlocksRes_Failure clone() => - QueryBlocksRes_Failure()..mergeFromMessage(this); + QueryBlocksRes_Failure clone() => QueryBlocksRes_Failure()..mergeFromMessage(this); @$core.Deprecated( 'Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' 'Will be removed in next major version', ) - QueryBlocksRes_Failure copyWith( - void Function(QueryBlocksRes_Failure) updates) => + QueryBlocksRes_Failure copyWith(void Function(QueryBlocksRes_Failure) updates) => super.copyWith((message) => updates(message as QueryBlocksRes_Failure)) as QueryBlocksRes_Failure; // ignore: deprecated_member_use $pb.BuilderInfo get info_ => _i; @$core.pragma('dart2js:noInline') static QueryBlocksRes_Failure create() => QueryBlocksRes_Failure._(); QueryBlocksRes_Failure createEmptyInstance() => create(); - static $pb.PbList createRepeated() => - $pb.PbList(); + static $pb.PbList createRepeated() => $pb.PbList(); @$core.pragma('dart2js:noInline') - static QueryBlocksRes_Failure getDefault() => _defaultInstance ??= - $pb.GeneratedMessage.$_defaultFor(create); + static QueryBlocksRes_Failure getDefault() => + _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); static QueryBlocksRes_Failure? _defaultInstance; - QueryBlocksRes_Failure_Reason whichReason() => - _QueryBlocksRes_Failure_ReasonByTag[$_whichOneof(0)]!; + QueryBlocksRes_Failure_Reason whichReason() => _QueryBlocksRes_Failure_ReasonByTag[$_whichOneof(0)]!; void clearReason() => clearField($_whichOneof(0)); @$pb.TagNumber(1) @@ -862,36 +737,27 @@ class QueryBlocksRes_Failure extends $pb.GeneratedMessage { enum QueryBlocksRes_Result { success, failure, notSet } class QueryBlocksRes extends $pb.GeneratedMessage { - static const $core.Map<$core.int, QueryBlocksRes_Result> - _QueryBlocksRes_ResultByTag = { + static const $core.Map<$core.int, QueryBlocksRes_Result> _QueryBlocksRes_ResultByTag = { 1: QueryBlocksRes_Result.success, 2: QueryBlocksRes_Result.failure, 0: QueryBlocksRes_Result.notSet }; static final $pb.BuilderInfo _i = $pb.BuilderInfo( - const $core.bool.fromEnvironment('protobuf.omit_message_names') - ? '' - : 'QueryBlocksRes', + const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'QueryBlocksRes', package: const $pb.PackageName( - const $core.bool.fromEnvironment('protobuf.omit_message_names') - ? '' - : 'co.topl.genus.services', + const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'co.topl.genus.services', ), createEmptyInstance: create, ) ..oo(0, [1, 2]) ..aOM( 1, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'success', + const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'success', subBuilder: QueryBlocksRes_Success.create, ) ..aOM( 2, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'failure', + const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'failure', subBuilder: QueryBlocksRes_Failure.create, ) ..hasRequiredFields = false; @@ -910,11 +776,9 @@ class QueryBlocksRes extends $pb.GeneratedMessage { } return _result; } - factory QueryBlocksRes.fromBuffer($core.List<$core.int> i, - [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => + factory QueryBlocksRes.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); - factory QueryBlocksRes.fromJson($core.String i, - [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => + factory QueryBlocksRes.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); @$core.Deprecated( 'Using this can add significant overhead to your binary. ' @@ -934,15 +798,12 @@ class QueryBlocksRes extends $pb.GeneratedMessage { @$core.pragma('dart2js:noInline') static QueryBlocksRes create() => QueryBlocksRes._(); QueryBlocksRes createEmptyInstance() => create(); - static $pb.PbList createRepeated() => - $pb.PbList(); + static $pb.PbList createRepeated() => $pb.PbList(); @$core.pragma('dart2js:noInline') - static QueryBlocksRes getDefault() => _defaultInstance ??= - $pb.GeneratedMessage.$_defaultFor(create); + static QueryBlocksRes getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); static QueryBlocksRes? _defaultInstance; - QueryBlocksRes_Result whichResult() => - _QueryBlocksRes_ResultByTag[$_whichOneof(0)]!; + QueryBlocksRes_Result whichResult() => _QueryBlocksRes_ResultByTag[$_whichOneof(0)]!; void clearResult() => clearField($_whichOneof(0)); @$pb.TagNumber(1) @@ -976,35 +837,25 @@ class QueryBlocksRes extends $pb.GeneratedMessage { class BlocksQueryStreamReq extends $pb.GeneratedMessage { static final $pb.BuilderInfo _i = $pb.BuilderInfo( - const $core.bool.fromEnvironment('protobuf.omit_message_names') - ? '' - : 'BlocksQueryStreamReq', + const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'BlocksQueryStreamReq', package: const $pb.PackageName( - const $core.bool.fromEnvironment('protobuf.omit_message_names') - ? '' - : 'co.topl.genus.services', + const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'co.topl.genus.services', ), createEmptyInstance: create, ) ..aOM<$4.BlockFilter>( 1, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'filter', + const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'filter', subBuilder: $4.BlockFilter.create, ) ..aOM( 2, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'sorting', + const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'sorting', subBuilder: BlockSorting.create, ) ..a<$core.int>( 3, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'confirmationDepth', + const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'confirmationDepth', $pb.PbFieldType.OU3, ) ..hasRequiredFields = false; @@ -1032,16 +883,14 @@ class BlocksQueryStreamReq extends $pb.GeneratedMessage { $pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY, ]) => create()..mergeFromBuffer(i, r); - factory BlocksQueryStreamReq.fromJson($core.String i, - [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => + factory BlocksQueryStreamReq.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); @$core.Deprecated( 'Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' 'Will be removed in next major version', ) - BlocksQueryStreamReq clone() => - BlocksQueryStreamReq()..mergeFromMessage(this); + BlocksQueryStreamReq clone() => BlocksQueryStreamReq()..mergeFromMessage(this); @$core.Deprecated( 'Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' @@ -1054,11 +903,10 @@ class BlocksQueryStreamReq extends $pb.GeneratedMessage { @$core.pragma('dart2js:noInline') static BlocksQueryStreamReq create() => BlocksQueryStreamReq._(); BlocksQueryStreamReq createEmptyInstance() => create(); - static $pb.PbList createRepeated() => - $pb.PbList(); + static $pb.PbList createRepeated() => $pb.PbList(); @$core.pragma('dart2js:noInline') - static BlocksQueryStreamReq getDefault() => _defaultInstance ??= - $pb.GeneratedMessage.$_defaultFor(create); + static BlocksQueryStreamReq getDefault() => + _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); static BlocksQueryStreamReq? _defaultInstance; @$pb.TagNumber(1) @@ -1102,41 +950,24 @@ class BlocksQueryStreamReq extends $pb.GeneratedMessage { void clearConfirmationDepth() => clearField(3); } -enum BlocksQueryStreamRes_Failure_Reason { - dataStoreConnectionError, - invalidQuery, - notSet -} +enum BlocksQueryStreamRes_Failure_Reason { dataStoreConnectionError, invalidQuery, notSet } class BlocksQueryStreamRes_Failure extends $pb.GeneratedMessage { - static const $core.Map<$core.int, BlocksQueryStreamRes_Failure_Reason> - _BlocksQueryStreamRes_Failure_ReasonByTag = { + static const $core.Map<$core.int, BlocksQueryStreamRes_Failure_Reason> _BlocksQueryStreamRes_Failure_ReasonByTag = { 1: BlocksQueryStreamRes_Failure_Reason.dataStoreConnectionError, 2: BlocksQueryStreamRes_Failure_Reason.invalidQuery, 0: BlocksQueryStreamRes_Failure_Reason.notSet }; static final $pb.BuilderInfo _i = $pb.BuilderInfo( - const $core.bool.fromEnvironment('protobuf.omit_message_names') - ? '' - : 'BlocksQueryStreamRes.Failure', + const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'BlocksQueryStreamRes.Failure', package: const $pb.PackageName( - const $core.bool.fromEnvironment('protobuf.omit_message_names') - ? '' - : 'co.topl.genus.services', + const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'co.topl.genus.services', ), createEmptyInstance: create, ) ..oo(0, [1, 2]) - ..aOS( - 1, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'dataStoreConnectionError') - ..aOS( - 2, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'invalidQuery') + ..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'dataStoreConnectionError') + ..aOS(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'invalidQuery') ..hasRequiredFields = false; BlocksQueryStreamRes_Failure._() : super(); @@ -1168,32 +999,26 @@ class BlocksQueryStreamRes_Failure extends $pb.GeneratedMessage { 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' 'Will be removed in next major version', ) - BlocksQueryStreamRes_Failure clone() => - BlocksQueryStreamRes_Failure()..mergeFromMessage(this); + BlocksQueryStreamRes_Failure clone() => BlocksQueryStreamRes_Failure()..mergeFromMessage(this); @$core.Deprecated( 'Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' 'Will be removed in next major version', ) - BlocksQueryStreamRes_Failure copyWith( - void Function(BlocksQueryStreamRes_Failure) updates) => - super.copyWith( - (message) => updates(message as BlocksQueryStreamRes_Failure)) + BlocksQueryStreamRes_Failure copyWith(void Function(BlocksQueryStreamRes_Failure) updates) => + super.copyWith((message) => updates(message as BlocksQueryStreamRes_Failure)) as BlocksQueryStreamRes_Failure; // ignore: deprecated_member_use $pb.BuilderInfo get info_ => _i; @$core.pragma('dart2js:noInline') - static BlocksQueryStreamRes_Failure create() => - BlocksQueryStreamRes_Failure._(); + static BlocksQueryStreamRes_Failure create() => BlocksQueryStreamRes_Failure._(); BlocksQueryStreamRes_Failure createEmptyInstance() => create(); - static $pb.PbList createRepeated() => - $pb.PbList(); + static $pb.PbList createRepeated() => $pb.PbList(); @$core.pragma('dart2js:noInline') - static BlocksQueryStreamRes_Failure getDefault() => _defaultInstance ??= - $pb.GeneratedMessage.$_defaultFor(create); + static BlocksQueryStreamRes_Failure getDefault() => + _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); static BlocksQueryStreamRes_Failure? _defaultInstance; - BlocksQueryStreamRes_Failure_Reason whichReason() => - _BlocksQueryStreamRes_Failure_ReasonByTag[$_whichOneof(0)]!; + BlocksQueryStreamRes_Failure_Reason whichReason() => _BlocksQueryStreamRes_Failure_ReasonByTag[$_whichOneof(0)]!; void clearReason() => clearField($_whichOneof(0)); @$pb.TagNumber(1) @@ -1224,36 +1049,27 @@ class BlocksQueryStreamRes_Failure extends $pb.GeneratedMessage { enum BlocksQueryStreamRes_Result { block, failure, notSet } class BlocksQueryStreamRes extends $pb.GeneratedMessage { - static const $core.Map<$core.int, BlocksQueryStreamRes_Result> - _BlocksQueryStreamRes_ResultByTag = { + static const $core.Map<$core.int, BlocksQueryStreamRes_Result> _BlocksQueryStreamRes_ResultByTag = { 1: BlocksQueryStreamRes_Result.block, 2: BlocksQueryStreamRes_Result.failure, 0: BlocksQueryStreamRes_Result.notSet }; static final $pb.BuilderInfo _i = $pb.BuilderInfo( - const $core.bool.fromEnvironment('protobuf.omit_message_names') - ? '' - : 'BlocksQueryStreamRes', + const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'BlocksQueryStreamRes', package: const $pb.PackageName( - const $core.bool.fromEnvironment('protobuf.omit_message_names') - ? '' - : 'co.topl.genus.services', + const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'co.topl.genus.services', ), createEmptyInstance: create, ) ..oo(0, [1, 2]) ..aOM<$6.Block>( 1, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'block', + const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'block', subBuilder: $6.Block.create, ) ..aOM( 2, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'failure', + const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'failure', subBuilder: BlocksQueryStreamRes_Failure.create, ) ..hasRequiredFields = false; @@ -1277,16 +1093,14 @@ class BlocksQueryStreamRes extends $pb.GeneratedMessage { $pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY, ]) => create()..mergeFromBuffer(i, r); - factory BlocksQueryStreamRes.fromJson($core.String i, - [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => + factory BlocksQueryStreamRes.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); @$core.Deprecated( 'Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' 'Will be removed in next major version', ) - BlocksQueryStreamRes clone() => - BlocksQueryStreamRes()..mergeFromMessage(this); + BlocksQueryStreamRes clone() => BlocksQueryStreamRes()..mergeFromMessage(this); @$core.Deprecated( 'Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' @@ -1299,15 +1113,13 @@ class BlocksQueryStreamRes extends $pb.GeneratedMessage { @$core.pragma('dart2js:noInline') static BlocksQueryStreamRes create() => BlocksQueryStreamRes._(); BlocksQueryStreamRes createEmptyInstance() => create(); - static $pb.PbList createRepeated() => - $pb.PbList(); + static $pb.PbList createRepeated() => $pb.PbList(); @$core.pragma('dart2js:noInline') - static BlocksQueryStreamRes getDefault() => _defaultInstance ??= - $pb.GeneratedMessage.$_defaultFor(create); + static BlocksQueryStreamRes getDefault() => + _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); static BlocksQueryStreamRes? _defaultInstance; - BlocksQueryStreamRes_Result whichResult() => - _BlocksQueryStreamRes_ResultByTag[$_whichOneof(0)]!; + BlocksQueryStreamRes_Result whichResult() => _BlocksQueryStreamRes_ResultByTag[$_whichOneof(0)]!; void clearResult() => clearField($_whichOneof(0)); @$pb.TagNumber(1) diff --git a/lib/genus/generated/blocks_query.pbgrpc.dart b/lib/genus/generated/blocks_query.pbgrpc.dart index 17a81ce9..9ad16816 100644 --- a/lib/genus/generated/blocks_query.pbgrpc.dart +++ b/lib/genus/generated/blocks_query.pbgrpc.dart @@ -18,14 +18,12 @@ import 'blocks_query.pb.dart' as $1; export 'blocks_query.pb.dart'; class BlocksQueryClient extends $grpc.Client { - static final _$query = - $grpc.ClientMethod<$1.QueryBlocksReq, $1.QueryBlocksRes>( + static final _$query = $grpc.ClientMethod<$1.QueryBlocksReq, $1.QueryBlocksRes>( '/co.topl.genus.services.BlocksQuery/Query', ($1.QueryBlocksReq value) => value.writeToBuffer(), ($core.List<$core.int> value) => $1.QueryBlocksRes.fromBuffer(value), ); - static final _$queryStream = - $grpc.ClientMethod<$1.BlocksQueryStreamReq, $1.BlocksQueryStreamRes>( + static final _$queryStream = $grpc.ClientMethod<$1.BlocksQueryStreamReq, $1.BlocksQueryStreamRes>( '/co.topl.genus.services.BlocksQuery/QueryStream', ($1.BlocksQueryStreamReq value) => value.writeToBuffer(), ($core.List<$core.int> value) => $1.BlocksQueryStreamRes.fromBuffer(value), @@ -76,8 +74,7 @@ abstract class BlocksQueryServiceBase extends $grpc.Service { queryStream_Pre, false, true, - ($core.List<$core.int> value) => - $1.BlocksQueryStreamReq.fromBuffer(value), + ($core.List<$core.int> value) => $1.BlocksQueryStreamReq.fromBuffer(value), ($1.BlocksQueryStreamRes value) => value.writeToBuffer(), ), ); diff --git a/lib/genus/generated/blocks_query.pbjson.dart b/lib/genus/generated/blocks_query.pbjson.dart index 9abd574f..ca4ae191 100644 --- a/lib/genus/generated/blocks_query.pbjson.dart +++ b/lib/genus/generated/blocks_query.pbjson.dart @@ -101,29 +101,9 @@ final $typed_data.Uint8List blockSortingDescriptor = $convert.base64Decode( const QueryBlocksReq$json = const { '1': 'QueryBlocksReq', '2': const [ - const { - '1': 'filter', - '3': 1, - '4': 1, - '5': 11, - '6': '.co.topl.genus.BlockFilter', - '10': 'filter' - }, - const { - '1': 'sorting', - '3': 2, - '4': 1, - '5': 11, - '6': '.co.topl.genus.services.BlockSorting', - '10': 'sorting' - }, - const { - '1': 'confirmation_depth', - '3': 3, - '4': 1, - '5': 13, - '10': 'confirmationDepth' - }, + const {'1': 'filter', '3': 1, '4': 1, '5': 11, '6': '.co.topl.genus.BlockFilter', '10': 'filter'}, + const {'1': 'sorting', '3': 2, '4': 1, '5': 11, '6': '.co.topl.genus.services.BlockSorting', '10': 'sorting'}, + const {'1': 'confirmation_depth', '3': 3, '4': 1, '5': 13, '10': 'confirmationDepth'}, const { '1': 'paging_options', '3': 4, @@ -171,14 +151,7 @@ const QueryBlocksRes$json = const { const QueryBlocksRes_Success$json = const { '1': 'Success', '2': const [ - const { - '1': 'blocks', - '3': 1, - '4': 3, - '5': 11, - '6': '.co.topl.genus.Block', - '10': 'blocks' - }, + const {'1': 'blocks', '3': 1, '4': 3, '5': 11, '6': '.co.topl.genus.Block', '10': 'blocks'}, ], }; @@ -186,30 +159,9 @@ const QueryBlocksRes_Success$json = const { const QueryBlocksRes_Failure$json = const { '1': 'Failure', '2': const [ - const { - '1': 'data_store_connection_error', - '3': 1, - '4': 1, - '5': 9, - '9': 0, - '10': 'dataStoreConnectionError' - }, - const { - '1': 'query_timeout', - '3': 2, - '4': 1, - '5': 9, - '9': 0, - '10': 'queryTimeout' - }, - const { - '1': 'invalid_query', - '3': 3, - '4': 1, - '5': 9, - '9': 0, - '10': 'invalidQuery' - }, + const {'1': 'data_store_connection_error', '3': 1, '4': 1, '5': 9, '9': 0, '10': 'dataStoreConnectionError'}, + const {'1': 'query_timeout', '3': 2, '4': 1, '5': 9, '9': 0, '10': 'queryTimeout'}, + const {'1': 'invalid_query', '3': 3, '4': 1, '5': 9, '9': 0, '10': 'invalidQuery'}, ], '8': const [ const {'1': 'reason'}, @@ -223,29 +175,9 @@ final $typed_data.Uint8List queryBlocksResDescriptor = $convert.base64Decode( const BlocksQueryStreamReq$json = const { '1': 'BlocksQueryStreamReq', '2': const [ - const { - '1': 'filter', - '3': 1, - '4': 1, - '5': 11, - '6': '.co.topl.genus.BlockFilter', - '10': 'filter' - }, - const { - '1': 'sorting', - '3': 2, - '4': 1, - '5': 11, - '6': '.co.topl.genus.services.BlockSorting', - '10': 'sorting' - }, - const { - '1': 'confirmation_depth', - '3': 3, - '4': 1, - '5': 13, - '10': 'confirmationDepth' - }, + const {'1': 'filter', '3': 1, '4': 1, '5': 11, '6': '.co.topl.genus.BlockFilter', '10': 'filter'}, + const {'1': 'sorting', '3': 2, '4': 1, '5': 11, '6': '.co.topl.genus.services.BlockSorting', '10': 'sorting'}, + const {'1': 'confirmation_depth', '3': 3, '4': 1, '5': 13, '10': 'confirmationDepth'}, ], }; @@ -256,15 +188,7 @@ final $typed_data.Uint8List blocksQueryStreamReqDescriptor = $convert.base64Deco const BlocksQueryStreamRes$json = const { '1': 'BlocksQueryStreamRes', '2': const [ - const { - '1': 'block', - '3': 1, - '4': 1, - '5': 11, - '6': '.co.topl.genus.Block', - '9': 0, - '10': 'block' - }, + const {'1': 'block', '3': 1, '4': 1, '5': 11, '6': '.co.topl.genus.Block', '9': 0, '10': 'block'}, const { '1': 'failure', '3': 2, @@ -285,22 +209,8 @@ const BlocksQueryStreamRes$json = const { const BlocksQueryStreamRes_Failure$json = const { '1': 'Failure', '2': const [ - const { - '1': 'data_store_connection_error', - '3': 1, - '4': 1, - '5': 9, - '9': 0, - '10': 'dataStoreConnectionError' - }, - const { - '1': 'invalid_query', - '3': 2, - '4': 1, - '5': 9, - '9': 0, - '10': 'invalidQuery' - }, + const {'1': 'data_store_connection_error', '3': 1, '4': 1, '5': 9, '9': 0, '10': 'dataStoreConnectionError'}, + const {'1': 'invalid_query', '3': 2, '4': 1, '5': 9, '9': 0, '10': 'invalidQuery'}, ], '8': const [ const {'1': 'reason'}, diff --git a/lib/genus/generated/blocks_subscription.pb.dart b/lib/genus/generated/blocks_subscription.pb.dart index ca911396..5dba10b9 100644 --- a/lib/genus/generated/blocks_subscription.pb.dart +++ b/lib/genus/generated/blocks_subscription.pb.dart @@ -18,35 +18,25 @@ import 'types.pb.dart' as $6; class CreateBlocksSubscriptionReq extends $pb.GeneratedMessage { static final $pb.BuilderInfo _i = $pb.BuilderInfo( - const $core.bool.fromEnvironment('protobuf.omit_message_names') - ? '' - : 'CreateBlocksSubscriptionReq', + const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'CreateBlocksSubscriptionReq', package: const $pb.PackageName( - const $core.bool.fromEnvironment('protobuf.omit_message_names') - ? '' - : 'co.topl.genus.services', + const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'co.topl.genus.services', ), createEmptyInstance: create, ) ..aOM<$4.BlockFilter>( 1, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'filter', + const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'filter', subBuilder: $4.BlockFilter.create, ) ..a<$core.int>( 2, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'confirmationDepth', + const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'confirmationDepth', $pb.PbFieldType.OU3, ) ..a<$fixnum.Int64>( 3, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'startHeight', + const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'startHeight', $pb.PbFieldType.OU6, defaultOrMaker: $fixnum.Int64.ZERO, ) @@ -85,28 +75,23 @@ class CreateBlocksSubscriptionReq extends $pb.GeneratedMessage { 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' 'Will be removed in next major version', ) - CreateBlocksSubscriptionReq clone() => - CreateBlocksSubscriptionReq()..mergeFromMessage(this); + CreateBlocksSubscriptionReq clone() => CreateBlocksSubscriptionReq()..mergeFromMessage(this); @$core.Deprecated( 'Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' 'Will be removed in next major version', ) - CreateBlocksSubscriptionReq copyWith( - void Function(CreateBlocksSubscriptionReq) updates) => - super.copyWith( - (message) => updates(message as CreateBlocksSubscriptionReq)) + CreateBlocksSubscriptionReq copyWith(void Function(CreateBlocksSubscriptionReq) updates) => + super.copyWith((message) => updates(message as CreateBlocksSubscriptionReq)) as CreateBlocksSubscriptionReq; // ignore: deprecated_member_use $pb.BuilderInfo get info_ => _i; @$core.pragma('dart2js:noInline') - static CreateBlocksSubscriptionReq create() => - CreateBlocksSubscriptionReq._(); + static CreateBlocksSubscriptionReq create() => CreateBlocksSubscriptionReq._(); CreateBlocksSubscriptionReq createEmptyInstance() => create(); - static $pb.PbList createRepeated() => - $pb.PbList(); + static $pb.PbList createRepeated() => $pb.PbList(); @$core.pragma('dart2js:noInline') - static CreateBlocksSubscriptionReq getDefault() => _defaultInstance ??= - $pb.GeneratedMessage.$_defaultFor(create); + static CreateBlocksSubscriptionReq getDefault() => + _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); static CreateBlocksSubscriptionReq? _defaultInstance; @$pb.TagNumber(1) @@ -148,41 +133,24 @@ class CreateBlocksSubscriptionReq extends $pb.GeneratedMessage { void clearStartHeight() => clearField(3); } -enum BlocksSubscriptionRes_Failure_Reason { - invalidRequest, - dataConnectionError, - notSet -} +enum BlocksSubscriptionRes_Failure_Reason { invalidRequest, dataConnectionError, notSet } class BlocksSubscriptionRes_Failure extends $pb.GeneratedMessage { - static const $core.Map<$core.int, BlocksSubscriptionRes_Failure_Reason> - _BlocksSubscriptionRes_Failure_ReasonByTag = { + static const $core.Map<$core.int, BlocksSubscriptionRes_Failure_Reason> _BlocksSubscriptionRes_Failure_ReasonByTag = { 1: BlocksSubscriptionRes_Failure_Reason.invalidRequest, 2: BlocksSubscriptionRes_Failure_Reason.dataConnectionError, 0: BlocksSubscriptionRes_Failure_Reason.notSet }; static final $pb.BuilderInfo _i = $pb.BuilderInfo( - const $core.bool.fromEnvironment('protobuf.omit_message_names') - ? '' - : 'BlocksSubscriptionRes.Failure', + const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'BlocksSubscriptionRes.Failure', package: const $pb.PackageName( - const $core.bool.fromEnvironment('protobuf.omit_message_names') - ? '' - : 'co.topl.genus.services', + const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'co.topl.genus.services', ), createEmptyInstance: create, ) ..oo(0, [1, 2]) - ..aOS( - 1, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'invalidRequest') - ..aOS( - 2, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'dataConnectionError') + ..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'invalidRequest') + ..aOS(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'dataConnectionError') ..hasRequiredFields = false; BlocksSubscriptionRes_Failure._() : super(); @@ -214,32 +182,26 @@ class BlocksSubscriptionRes_Failure extends $pb.GeneratedMessage { 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' 'Will be removed in next major version', ) - BlocksSubscriptionRes_Failure clone() => - BlocksSubscriptionRes_Failure()..mergeFromMessage(this); + BlocksSubscriptionRes_Failure clone() => BlocksSubscriptionRes_Failure()..mergeFromMessage(this); @$core.Deprecated( 'Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' 'Will be removed in next major version', ) - BlocksSubscriptionRes_Failure copyWith( - void Function(BlocksSubscriptionRes_Failure) updates) => - super.copyWith( - (message) => updates(message as BlocksSubscriptionRes_Failure)) + BlocksSubscriptionRes_Failure copyWith(void Function(BlocksSubscriptionRes_Failure) updates) => + super.copyWith((message) => updates(message as BlocksSubscriptionRes_Failure)) as BlocksSubscriptionRes_Failure; // ignore: deprecated_member_use $pb.BuilderInfo get info_ => _i; @$core.pragma('dart2js:noInline') - static BlocksSubscriptionRes_Failure create() => - BlocksSubscriptionRes_Failure._(); + static BlocksSubscriptionRes_Failure create() => BlocksSubscriptionRes_Failure._(); BlocksSubscriptionRes_Failure createEmptyInstance() => create(); - static $pb.PbList createRepeated() => - $pb.PbList(); + static $pb.PbList createRepeated() => $pb.PbList(); @$core.pragma('dart2js:noInline') - static BlocksSubscriptionRes_Failure getDefault() => _defaultInstance ??= - $pb.GeneratedMessage.$_defaultFor(create); + static BlocksSubscriptionRes_Failure getDefault() => + _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); static BlocksSubscriptionRes_Failure? _defaultInstance; - BlocksSubscriptionRes_Failure_Reason whichReason() => - _BlocksSubscriptionRes_Failure_ReasonByTag[$_whichOneof(0)]!; + BlocksSubscriptionRes_Failure_Reason whichReason() => _BlocksSubscriptionRes_Failure_ReasonByTag[$_whichOneof(0)]!; void clearReason() => clearField($_whichOneof(0)); @$pb.TagNumber(1) @@ -270,36 +232,27 @@ class BlocksSubscriptionRes_Failure extends $pb.GeneratedMessage { enum BlocksSubscriptionRes_Result { success, failure, notSet } class BlocksSubscriptionRes extends $pb.GeneratedMessage { - static const $core.Map<$core.int, BlocksSubscriptionRes_Result> - _BlocksSubscriptionRes_ResultByTag = { + static const $core.Map<$core.int, BlocksSubscriptionRes_Result> _BlocksSubscriptionRes_ResultByTag = { 1: BlocksSubscriptionRes_Result.success, 2: BlocksSubscriptionRes_Result.failure, 0: BlocksSubscriptionRes_Result.notSet }; static final $pb.BuilderInfo _i = $pb.BuilderInfo( - const $core.bool.fromEnvironment('protobuf.omit_message_names') - ? '' - : 'BlocksSubscriptionRes', + const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'BlocksSubscriptionRes', package: const $pb.PackageName( - const $core.bool.fromEnvironment('protobuf.omit_message_names') - ? '' - : 'co.topl.genus.services', + const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'co.topl.genus.services', ), createEmptyInstance: create, ) ..oo(0, [1, 2]) ..aOM<$6.Block>( 1, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'success', + const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'success', subBuilder: $6.Block.create, ) ..aOM( 2, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'failure', + const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'failure', subBuilder: BlocksSubscriptionRes_Failure.create, ) ..hasRequiredFields = false; @@ -323,38 +276,33 @@ class BlocksSubscriptionRes extends $pb.GeneratedMessage { $pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY, ]) => create()..mergeFromBuffer(i, r); - factory BlocksSubscriptionRes.fromJson($core.String i, - [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => + factory BlocksSubscriptionRes.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); @$core.Deprecated( 'Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' 'Will be removed in next major version', ) - BlocksSubscriptionRes clone() => - BlocksSubscriptionRes()..mergeFromMessage(this); + BlocksSubscriptionRes clone() => BlocksSubscriptionRes()..mergeFromMessage(this); @$core.Deprecated( 'Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' 'Will be removed in next major version', ) - BlocksSubscriptionRes copyWith( - void Function(BlocksSubscriptionRes) updates) => + BlocksSubscriptionRes copyWith(void Function(BlocksSubscriptionRes) updates) => super.copyWith((message) => updates(message as BlocksSubscriptionRes)) as BlocksSubscriptionRes; // ignore: deprecated_member_use $pb.BuilderInfo get info_ => _i; @$core.pragma('dart2js:noInline') static BlocksSubscriptionRes create() => BlocksSubscriptionRes._(); BlocksSubscriptionRes createEmptyInstance() => create(); - static $pb.PbList createRepeated() => - $pb.PbList(); + static $pb.PbList createRepeated() => $pb.PbList(); @$core.pragma('dart2js:noInline') - static BlocksSubscriptionRes getDefault() => _defaultInstance ??= - $pb.GeneratedMessage.$_defaultFor(create); + static BlocksSubscriptionRes getDefault() => + _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); static BlocksSubscriptionRes? _defaultInstance; - BlocksSubscriptionRes_Result whichResult() => - _BlocksSubscriptionRes_ResultByTag[$_whichOneof(0)]!; + BlocksSubscriptionRes_Result whichResult() => _BlocksSubscriptionRes_ResultByTag[$_whichOneof(0)]!; void clearResult() => clearField($_whichOneof(0)); @$pb.TagNumber(1) diff --git a/lib/genus/generated/blocks_subscription.pbgrpc.dart b/lib/genus/generated/blocks_subscription.pbgrpc.dart index 9d7c3891..6ea65635 100644 --- a/lib/genus/generated/blocks_subscription.pbgrpc.dart +++ b/lib/genus/generated/blocks_subscription.pbgrpc.dart @@ -18,8 +18,7 @@ import 'blocks_subscription.pb.dart' as $3; export 'blocks_subscription.pb.dart'; class BlocksSubscriptionClient extends $grpc.Client { - static final _$create = $grpc.ClientMethod<$3.CreateBlocksSubscriptionReq, - $3.BlocksSubscriptionRes>( + static final _$create = $grpc.ClientMethod<$3.CreateBlocksSubscriptionReq, $3.BlocksSubscriptionRes>( '/co.topl.genus.services.BlocksSubscription/Create', ($3.CreateBlocksSubscriptionReq value) => value.writeToBuffer(), ($core.List<$core.int> value) => $3.BlocksSubscriptionRes.fromBuffer(value), @@ -48,14 +47,12 @@ abstract class BlocksSubscriptionServiceBase extends $grpc.Service { BlocksSubscriptionServiceBase() { $addMethod( - $grpc.ServiceMethod<$3.CreateBlocksSubscriptionReq, - $3.BlocksSubscriptionRes>( + $grpc.ServiceMethod<$3.CreateBlocksSubscriptionReq, $3.BlocksSubscriptionRes>( 'Create', create_Pre, false, true, - ($core.List<$core.int> value) => - $3.CreateBlocksSubscriptionReq.fromBuffer(value), + ($core.List<$core.int> value) => $3.CreateBlocksSubscriptionReq.fromBuffer(value), ($3.BlocksSubscriptionRes value) => value.writeToBuffer(), ), ); diff --git a/lib/genus/generated/blocks_subscription.pbjson.dart b/lib/genus/generated/blocks_subscription.pbjson.dart index ca0d1d77..c3f07fe8 100644 --- a/lib/genus/generated/blocks_subscription.pbjson.dart +++ b/lib/genus/generated/blocks_subscription.pbjson.dart @@ -14,42 +14,20 @@ import 'dart:typed_data' as $typed_data; const CreateBlocksSubscriptionReq$json = const { '1': 'CreateBlocksSubscriptionReq', '2': const [ - const { - '1': 'filter', - '3': 1, - '4': 1, - '5': 11, - '6': '.co.topl.genus.BlockFilter', - '10': 'filter' - }, - const { - '1': 'confirmation_depth', - '3': 2, - '4': 1, - '5': 13, - '10': 'confirmationDepth' - }, + const {'1': 'filter', '3': 1, '4': 1, '5': 11, '6': '.co.topl.genus.BlockFilter', '10': 'filter'}, + const {'1': 'confirmation_depth', '3': 2, '4': 1, '5': 13, '10': 'confirmationDepth'}, const {'1': 'start_height', '3': 3, '4': 1, '5': 4, '10': 'startHeight'}, ], }; /// Descriptor for `CreateBlocksSubscriptionReq`. Decode as a `google.protobuf.DescriptorProto`. -final $typed_data.Uint8List createBlocksSubscriptionReqDescriptor = - $convert.base64Decode( - 'ChtDcmVhdGVCbG9ja3NTdWJzY3JpcHRpb25SZXESMgoGZmlsdGVyGAEgASgLMhouY28udG9wbC5nZW51cy5CbG9ja0ZpbHRlclIGZmlsdGVyEi0KEmNvbmZpcm1hdGlvbl9kZXB0aBgCIAEoDVIRY29uZmlybWF0aW9uRGVwdGgSIQoMc3RhcnRfaGVpZ2h0GAMgASgEUgtzdGFydEhlaWdodA=='); +final $typed_data.Uint8List createBlocksSubscriptionReqDescriptor = $convert.base64Decode( + 'ChtDcmVhdGVCbG9ja3NTdWJzY3JpcHRpb25SZXESMgoGZmlsdGVyGAEgASgLMhouY28udG9wbC5nZW51cy5CbG9ja0ZpbHRlclIGZmlsdGVyEi0KEmNvbmZpcm1hdGlvbl9kZXB0aBgCIAEoDVIRY29uZmlybWF0aW9uRGVwdGgSIQoMc3RhcnRfaGVpZ2h0GAMgASgEUgtzdGFydEhlaWdodA=='); @$core.Deprecated('Use blocksSubscriptionResDescriptor instead') const BlocksSubscriptionRes$json = const { '1': 'BlocksSubscriptionRes', '2': const [ - const { - '1': 'success', - '3': 1, - '4': 1, - '5': 11, - '6': '.co.topl.genus.Block', - '9': 0, - '10': 'success' - }, + const {'1': 'success', '3': 1, '4': 1, '5': 11, '6': '.co.topl.genus.Block', '9': 0, '10': 'success'}, const { '1': 'failure', '3': 2, @@ -70,22 +48,8 @@ const BlocksSubscriptionRes$json = const { const BlocksSubscriptionRes_Failure$json = const { '1': 'Failure', '2': const [ - const { - '1': 'invalid_request', - '3': 1, - '4': 1, - '5': 9, - '9': 0, - '10': 'invalidRequest' - }, - const { - '1': 'data_connection_error', - '3': 2, - '4': 1, - '5': 9, - '9': 0, - '10': 'dataConnectionError' - }, + const {'1': 'invalid_request', '3': 1, '4': 1, '5': 9, '9': 0, '10': 'invalidRequest'}, + const {'1': 'data_connection_error', '3': 2, '4': 1, '5': 9, '9': 0, '10': 'dataConnectionError'}, ], '8': const [ const {'1': 'reason'}, diff --git a/lib/genus/generated/filters.pb.dart b/lib/genus/generated/filters.pb.dart index f3b57d43..ba16faf2 100644 --- a/lib/genus/generated/filters.pb.dart +++ b/lib/genus/generated/filters.pb.dart @@ -14,20 +14,12 @@ import 'package:protobuf/protobuf.dart' as $pb; class StringSelection extends $pb.GeneratedMessage { static final $pb.BuilderInfo _i = $pb.BuilderInfo( - const $core.bool.fromEnvironment('protobuf.omit_message_names') - ? '' - : 'StringSelection', - package: const $pb.PackageName( - const $core.bool.fromEnvironment('protobuf.omit_message_names') - ? '' - : 'co.topl.genus'), + const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'StringSelection', + package: + const $pb.PackageName(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'co.topl.genus'), createEmptyInstance: create, ) - ..pPS( - 1, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'values') + ..pPS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'values') ..hasRequiredFields = false; StringSelection._() : super(); @@ -45,8 +37,7 @@ class StringSelection extends $pb.GeneratedMessage { $pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY, ]) => create()..mergeFromBuffer(i, r); - factory StringSelection.fromJson($core.String i, - [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => + factory StringSelection.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); @$core.Deprecated( 'Using this can add significant overhead to your binary. ' @@ -66,11 +57,10 @@ class StringSelection extends $pb.GeneratedMessage { @$core.pragma('dart2js:noInline') static StringSelection create() => StringSelection._(); StringSelection createEmptyInstance() => create(); - static $pb.PbList createRepeated() => - $pb.PbList(); + static $pb.PbList createRepeated() => $pb.PbList(); @$core.pragma('dart2js:noInline') - static StringSelection getDefault() => _defaultInstance ??= - $pb.GeneratedMessage.$_defaultFor(create); + static StringSelection getDefault() => + _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); static StringSelection? _defaultInstance; @$pb.TagNumber(1) @@ -80,36 +70,27 @@ class StringSelection extends $pb.GeneratedMessage { enum NumberRange_FilterType { min, max, notSet } class NumberRange extends $pb.GeneratedMessage { - static const $core.Map<$core.int, NumberRange_FilterType> - _NumberRange_FilterTypeByTag = { + static const $core.Map<$core.int, NumberRange_FilterType> _NumberRange_FilterTypeByTag = { 1: NumberRange_FilterType.min, 2: NumberRange_FilterType.max, 0: NumberRange_FilterType.notSet }; static final $pb.BuilderInfo _i = $pb.BuilderInfo( - const $core.bool.fromEnvironment('protobuf.omit_message_names') - ? '' - : 'NumberRange', - package: const $pb.PackageName( - const $core.bool.fromEnvironment('protobuf.omit_message_names') - ? '' - : 'co.topl.genus'), + const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'NumberRange', + package: + const $pb.PackageName(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'co.topl.genus'), createEmptyInstance: create, ) ..oo(0, [1, 2]) ..a<$fixnum.Int64>( 1, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'min', + const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'min', $pb.PbFieldType.OU6, defaultOrMaker: $fixnum.Int64.ZERO, ) ..a<$fixnum.Int64>( 2, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'max', + const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'max', $pb.PbFieldType.OU6, defaultOrMaker: $fixnum.Int64.ZERO, ) @@ -129,11 +110,9 @@ class NumberRange extends $pb.GeneratedMessage { } return _result; } - factory NumberRange.fromBuffer($core.List<$core.int> i, - [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => + factory NumberRange.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); - factory NumberRange.fromJson($core.String i, - [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => + factory NumberRange.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); @$core.Deprecated( 'Using this can add significant overhead to your binary. ' @@ -147,20 +126,17 @@ class NumberRange extends $pb.GeneratedMessage { 'Will be removed in next major version', ) NumberRange copyWith(void Function(NumberRange) updates) => - super.copyWith((message) => updates(message as NumberRange)) - as NumberRange; // ignore: deprecated_member_use + super.copyWith((message) => updates(message as NumberRange)) as NumberRange; // ignore: deprecated_member_use $pb.BuilderInfo get info_ => _i; @$core.pragma('dart2js:noInline') static NumberRange create() => NumberRange._(); NumberRange createEmptyInstance() => create(); static $pb.PbList createRepeated() => $pb.PbList(); @$core.pragma('dart2js:noInline') - static NumberRange getDefault() => _defaultInstance ??= - $pb.GeneratedMessage.$_defaultFor(create); + static NumberRange getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); static NumberRange? _defaultInstance; - NumberRange_FilterType whichFilterType() => - _NumberRange_FilterTypeByTag[$_whichOneof(0)]!; + NumberRange_FilterType whichFilterType() => _NumberRange_FilterTypeByTag[$_whichOneof(0)]!; void clearFilterType() => clearField($_whichOneof(0)); @$pb.TagNumber(1) @@ -190,20 +166,14 @@ class NumberRange extends $pb.GeneratedMessage { class NumberSelection extends $pb.GeneratedMessage { static final $pb.BuilderInfo _i = $pb.BuilderInfo( - const $core.bool.fromEnvironment('protobuf.omit_message_names') - ? '' - : 'NumberSelection', - package: const $pb.PackageName( - const $core.bool.fromEnvironment('protobuf.omit_message_names') - ? '' - : 'co.topl.genus'), + const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'NumberSelection', + package: + const $pb.PackageName(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'co.topl.genus'), createEmptyInstance: create, ) ..p<$fixnum.Int64>( 1, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'values', + const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'values', $pb.PbFieldType.KU6, ) ..hasRequiredFields = false; @@ -223,8 +193,7 @@ class NumberSelection extends $pb.GeneratedMessage { $pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY, ]) => create()..mergeFromBuffer(i, r); - factory NumberSelection.fromJson($core.String i, - [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => + factory NumberSelection.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); @$core.Deprecated( 'Using this can add significant overhead to your binary. ' @@ -244,11 +213,10 @@ class NumberSelection extends $pb.GeneratedMessage { @$core.pragma('dart2js:noInline') static NumberSelection create() => NumberSelection._(); NumberSelection createEmptyInstance() => create(); - static $pb.PbList createRepeated() => - $pb.PbList(); + static $pb.PbList createRepeated() => $pb.PbList(); @$core.pragma('dart2js:noInline') - static NumberSelection getDefault() => _defaultInstance ??= - $pb.GeneratedMessage.$_defaultFor(create); + static NumberSelection getDefault() => + _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); static NumberSelection? _defaultInstance; @$pb.TagNumber(1) @@ -257,20 +225,12 @@ class NumberSelection extends $pb.GeneratedMessage { class BooleanSelection extends $pb.GeneratedMessage { static final $pb.BuilderInfo _i = $pb.BuilderInfo( - const $core.bool.fromEnvironment('protobuf.omit_message_names') - ? '' - : 'BooleanSelection', - package: const $pb.PackageName( - const $core.bool.fromEnvironment('protobuf.omit_message_names') - ? '' - : 'co.topl.genus'), + const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'BooleanSelection', + package: + const $pb.PackageName(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'co.topl.genus'), createEmptyInstance: create, ) - ..aOB( - 1, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'value') + ..aOB(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'value') ..hasRequiredFields = false; BooleanSelection._() : super(); @@ -288,8 +248,7 @@ class BooleanSelection extends $pb.GeneratedMessage { $pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY, ]) => create()..mergeFromBuffer(i, r); - factory BooleanSelection.fromJson($core.String i, - [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => + factory BooleanSelection.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); @$core.Deprecated( 'Using this can add significant overhead to your binary. ' @@ -309,11 +268,10 @@ class BooleanSelection extends $pb.GeneratedMessage { @$core.pragma('dart2js:noInline') static BooleanSelection create() => BooleanSelection._(); BooleanSelection createEmptyInstance() => create(); - static $pb.PbList createRepeated() => - $pb.PbList(); + static $pb.PbList createRepeated() => $pb.PbList(); @$core.pragma('dart2js:noInline') - static BooleanSelection getDefault() => _defaultInstance ??= - $pb.GeneratedMessage.$_defaultFor(create); + static BooleanSelection getDefault() => + _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); static BooleanSelection? _defaultInstance; @$pb.TagNumber(1) @@ -329,51 +287,35 @@ class BooleanSelection extends $pb.GeneratedMessage { void clearValue() => clearField(1); } -enum TokenValueFilter_FilterType { - assetCodeSelection, - quantityRange, - tokenValueTypeSelection, - notSet -} +enum TokenValueFilter_FilterType { assetCodeSelection, quantityRange, tokenValueTypeSelection, notSet } class TokenValueFilter extends $pb.GeneratedMessage { - static const $core.Map<$core.int, TokenValueFilter_FilterType> - _TokenValueFilter_FilterTypeByTag = { + static const $core.Map<$core.int, TokenValueFilter_FilterType> _TokenValueFilter_FilterTypeByTag = { 1: TokenValueFilter_FilterType.assetCodeSelection, 2: TokenValueFilter_FilterType.quantityRange, 3: TokenValueFilter_FilterType.tokenValueTypeSelection, 0: TokenValueFilter_FilterType.notSet }; static final $pb.BuilderInfo _i = $pb.BuilderInfo( - const $core.bool.fromEnvironment('protobuf.omit_message_names') - ? '' - : 'TokenValueFilter', - package: const $pb.PackageName( - const $core.bool.fromEnvironment('protobuf.omit_message_names') - ? '' - : 'co.topl.genus'), + const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'TokenValueFilter', + package: + const $pb.PackageName(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'co.topl.genus'), createEmptyInstance: create, ) ..oo(0, [1, 2, 3]) ..aOM( 1, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'assetCodeSelection', + const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'assetCodeSelection', subBuilder: StringSelection.create, ) ..aOM( 2, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'quantityRange', + const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'quantityRange', subBuilder: NumberRange.create, ) ..aOM( 3, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'tokenValueTypeSelection', + const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'tokenValueTypeSelection', subBuilder: StringSelection.create, ) ..hasRequiredFields = false; @@ -401,8 +343,7 @@ class TokenValueFilter extends $pb.GeneratedMessage { $pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY, ]) => create()..mergeFromBuffer(i, r); - factory TokenValueFilter.fromJson($core.String i, - [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => + factory TokenValueFilter.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); @$core.Deprecated( 'Using this can add significant overhead to your binary. ' @@ -422,15 +363,13 @@ class TokenValueFilter extends $pb.GeneratedMessage { @$core.pragma('dart2js:noInline') static TokenValueFilter create() => TokenValueFilter._(); TokenValueFilter createEmptyInstance() => create(); - static $pb.PbList createRepeated() => - $pb.PbList(); + static $pb.PbList createRepeated() => $pb.PbList(); @$core.pragma('dart2js:noInline') - static TokenValueFilter getDefault() => _defaultInstance ??= - $pb.GeneratedMessage.$_defaultFor(create); + static TokenValueFilter getDefault() => + _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); static TokenValueFilter? _defaultInstance; - TokenValueFilter_FilterType whichFilterType() => - _TokenValueFilter_FilterTypeByTag[$_whichOneof(0)]!; + TokenValueFilter_FilterType whichFilterType() => _TokenValueFilter_FilterTypeByTag[$_whichOneof(0)]!; void clearFilterType() => clearField($_whichOneof(0)); @$pb.TagNumber(1) @@ -478,20 +417,14 @@ class TokenValueFilter extends $pb.GeneratedMessage { class TransactionFilter_AndFilter extends $pb.GeneratedMessage { static final $pb.BuilderInfo _i = $pb.BuilderInfo( - const $core.bool.fromEnvironment('protobuf.omit_message_names') - ? '' - : 'TransactionFilter.AndFilter', - package: const $pb.PackageName( - const $core.bool.fromEnvironment('protobuf.omit_message_names') - ? '' - : 'co.topl.genus'), + const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'TransactionFilter.AndFilter', + package: + const $pb.PackageName(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'co.topl.genus'), createEmptyInstance: create, ) ..pc( 1, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'filters', + const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'filters', $pb.PbFieldType.PM, subBuilder: TransactionFilter.create, ) @@ -522,28 +455,23 @@ class TransactionFilter_AndFilter extends $pb.GeneratedMessage { 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' 'Will be removed in next major version', ) - TransactionFilter_AndFilter clone() => - TransactionFilter_AndFilter()..mergeFromMessage(this); + TransactionFilter_AndFilter clone() => TransactionFilter_AndFilter()..mergeFromMessage(this); @$core.Deprecated( 'Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' 'Will be removed in next major version', ) - TransactionFilter_AndFilter copyWith( - void Function(TransactionFilter_AndFilter) updates) => - super.copyWith( - (message) => updates(message as TransactionFilter_AndFilter)) + TransactionFilter_AndFilter copyWith(void Function(TransactionFilter_AndFilter) updates) => + super.copyWith((message) => updates(message as TransactionFilter_AndFilter)) as TransactionFilter_AndFilter; // ignore: deprecated_member_use $pb.BuilderInfo get info_ => _i; @$core.pragma('dart2js:noInline') - static TransactionFilter_AndFilter create() => - TransactionFilter_AndFilter._(); + static TransactionFilter_AndFilter create() => TransactionFilter_AndFilter._(); TransactionFilter_AndFilter createEmptyInstance() => create(); - static $pb.PbList createRepeated() => - $pb.PbList(); + static $pb.PbList createRepeated() => $pb.PbList(); @$core.pragma('dart2js:noInline') - static TransactionFilter_AndFilter getDefault() => _defaultInstance ??= - $pb.GeneratedMessage.$_defaultFor(create); + static TransactionFilter_AndFilter getDefault() => + _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); static TransactionFilter_AndFilter? _defaultInstance; @$pb.TagNumber(1) @@ -552,20 +480,14 @@ class TransactionFilter_AndFilter extends $pb.GeneratedMessage { class TransactionFilter_OrFilter extends $pb.GeneratedMessage { static final $pb.BuilderInfo _i = $pb.BuilderInfo( - const $core.bool.fromEnvironment('protobuf.omit_message_names') - ? '' - : 'TransactionFilter.OrFilter', - package: const $pb.PackageName( - const $core.bool.fromEnvironment('protobuf.omit_message_names') - ? '' - : 'co.topl.genus'), + const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'TransactionFilter.OrFilter', + package: + const $pb.PackageName(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'co.topl.genus'), createEmptyInstance: create, ) ..pc( 1, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'filters', + const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'filters', $pb.PbFieldType.PM, subBuilder: TransactionFilter.create, ) @@ -596,27 +518,23 @@ class TransactionFilter_OrFilter extends $pb.GeneratedMessage { 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' 'Will be removed in next major version', ) - TransactionFilter_OrFilter clone() => - TransactionFilter_OrFilter()..mergeFromMessage(this); + TransactionFilter_OrFilter clone() => TransactionFilter_OrFilter()..mergeFromMessage(this); @$core.Deprecated( 'Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' 'Will be removed in next major version', ) - TransactionFilter_OrFilter copyWith( - void Function(TransactionFilter_OrFilter) updates) => - super.copyWith( - (message) => updates(message as TransactionFilter_OrFilter)) + TransactionFilter_OrFilter copyWith(void Function(TransactionFilter_OrFilter) updates) => + super.copyWith((message) => updates(message as TransactionFilter_OrFilter)) as TransactionFilter_OrFilter; // ignore: deprecated_member_use $pb.BuilderInfo get info_ => _i; @$core.pragma('dart2js:noInline') static TransactionFilter_OrFilter create() => TransactionFilter_OrFilter._(); TransactionFilter_OrFilter createEmptyInstance() => create(); - static $pb.PbList createRepeated() => - $pb.PbList(); + static $pb.PbList createRepeated() => $pb.PbList(); @$core.pragma('dart2js:noInline') - static TransactionFilter_OrFilter getDefault() => _defaultInstance ??= - $pb.GeneratedMessage.$_defaultFor(create); + static TransactionFilter_OrFilter getDefault() => + _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); static TransactionFilter_OrFilter? _defaultInstance; @$pb.TagNumber(1) @@ -625,20 +543,14 @@ class TransactionFilter_OrFilter extends $pb.GeneratedMessage { class TransactionFilter_NotFilter extends $pb.GeneratedMessage { static final $pb.BuilderInfo _i = $pb.BuilderInfo( - const $core.bool.fromEnvironment('protobuf.omit_message_names') - ? '' - : 'TransactionFilter.NotFilter', - package: const $pb.PackageName( - const $core.bool.fromEnvironment('protobuf.omit_message_names') - ? '' - : 'co.topl.genus'), + const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'TransactionFilter.NotFilter', + package: + const $pb.PackageName(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'co.topl.genus'), createEmptyInstance: create, ) ..aOM( 1, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'filter', + const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'filter', subBuilder: TransactionFilter.create, ) ..hasRequiredFields = false; @@ -668,28 +580,23 @@ class TransactionFilter_NotFilter extends $pb.GeneratedMessage { 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' 'Will be removed in next major version', ) - TransactionFilter_NotFilter clone() => - TransactionFilter_NotFilter()..mergeFromMessage(this); + TransactionFilter_NotFilter clone() => TransactionFilter_NotFilter()..mergeFromMessage(this); @$core.Deprecated( 'Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' 'Will be removed in next major version', ) - TransactionFilter_NotFilter copyWith( - void Function(TransactionFilter_NotFilter) updates) => - super.copyWith( - (message) => updates(message as TransactionFilter_NotFilter)) + TransactionFilter_NotFilter copyWith(void Function(TransactionFilter_NotFilter) updates) => + super.copyWith((message) => updates(message as TransactionFilter_NotFilter)) as TransactionFilter_NotFilter; // ignore: deprecated_member_use $pb.BuilderInfo get info_ => _i; @$core.pragma('dart2js:noInline') - static TransactionFilter_NotFilter create() => - TransactionFilter_NotFilter._(); + static TransactionFilter_NotFilter create() => TransactionFilter_NotFilter._(); TransactionFilter_NotFilter createEmptyInstance() => create(); - static $pb.PbList createRepeated() => - $pb.PbList(); + static $pb.PbList createRepeated() => $pb.PbList(); @$core.pragma('dart2js:noInline') - static TransactionFilter_NotFilter getDefault() => _defaultInstance ??= - $pb.GeneratedMessage.$_defaultFor(create); + static TransactionFilter_NotFilter getDefault() => + _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); static TransactionFilter_NotFilter? _defaultInstance; @$pb.TagNumber(1) @@ -709,13 +616,9 @@ class TransactionFilter_NotFilter extends $pb.GeneratedMessage { class TransactionFilter_AllFilter extends $pb.GeneratedMessage { static final $pb.BuilderInfo _i = $pb.BuilderInfo( - const $core.bool.fromEnvironment('protobuf.omit_message_names') - ? '' - : 'TransactionFilter.AllFilter', - package: const $pb.PackageName( - const $core.bool.fromEnvironment('protobuf.omit_message_names') - ? '' - : 'co.topl.genus'), + const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'TransactionFilter.AllFilter', + package: + const $pb.PackageName(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'co.topl.genus'), createEmptyInstance: create, )..hasRequiredFields = false; @@ -736,28 +639,23 @@ class TransactionFilter_AllFilter extends $pb.GeneratedMessage { 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' 'Will be removed in next major version', ) - TransactionFilter_AllFilter clone() => - TransactionFilter_AllFilter()..mergeFromMessage(this); + TransactionFilter_AllFilter clone() => TransactionFilter_AllFilter()..mergeFromMessage(this); @$core.Deprecated( 'Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' 'Will be removed in next major version', ) - TransactionFilter_AllFilter copyWith( - void Function(TransactionFilter_AllFilter) updates) => - super.copyWith( - (message) => updates(message as TransactionFilter_AllFilter)) + TransactionFilter_AllFilter copyWith(void Function(TransactionFilter_AllFilter) updates) => + super.copyWith((message) => updates(message as TransactionFilter_AllFilter)) as TransactionFilter_AllFilter; // ignore: deprecated_member_use $pb.BuilderInfo get info_ => _i; @$core.pragma('dart2js:noInline') - static TransactionFilter_AllFilter create() => - TransactionFilter_AllFilter._(); + static TransactionFilter_AllFilter create() => TransactionFilter_AllFilter._(); TransactionFilter_AllFilter createEmptyInstance() => create(); - static $pb.PbList createRepeated() => - $pb.PbList(); + static $pb.PbList createRepeated() => $pb.PbList(); @$core.pragma('dart2js:noInline') - static TransactionFilter_AllFilter getDefault() => _defaultInstance ??= - $pb.GeneratedMessage.$_defaultFor(create); + static TransactionFilter_AllFilter getDefault() => + _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); static TransactionFilter_AllFilter? _defaultInstance; } @@ -784,8 +682,7 @@ enum TransactionFilter_FilterType { } class TransactionFilter extends $pb.GeneratedMessage { - static const $core.Map<$core.int, TransactionFilter_FilterType> - _TransactionFilter_FilterTypeByTag = { + static const $core.Map<$core.int, TransactionFilter_FilterType> _TransactionFilter_FilterTypeByTag = { 1: TransactionFilter_FilterType.txTypeSelection, 2: TransactionFilter_FilterType.timestampRange, 3: TransactionFilter_FilterType.inputAddressSelection, @@ -807,119 +704,85 @@ class TransactionFilter extends $pb.GeneratedMessage { 0: TransactionFilter_FilterType.notSet }; static final $pb.BuilderInfo _i = $pb.BuilderInfo( - const $core.bool.fromEnvironment('protobuf.omit_message_names') - ? '' - : 'TransactionFilter', - package: const $pb.PackageName( - const $core.bool.fromEnvironment('protobuf.omit_message_names') - ? '' - : 'co.topl.genus'), + const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'TransactionFilter', + package: + const $pb.PackageName(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'co.topl.genus'), createEmptyInstance: create, ) ..oo(0, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18]) ..aOM( 1, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'txTypeSelection', + const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'txTypeSelection', subBuilder: StringSelection.create, ) ..aOM( 2, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'timestampRange', + const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'timestampRange', subBuilder: NumberRange.create, ) ..aOM( 3, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'inputAddressSelection', + const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'inputAddressSelection', subBuilder: StringSelection.create, ) ..aOM( 4, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'inputNonceSelection', + const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'inputNonceSelection', subBuilder: NumberSelection.create, ) ..aOM( 5, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'outputTokenBoxTypeSelection', + const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'outputTokenBoxTypeSelection', subBuilder: StringSelection.create, ) ..aOM( 6, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'outputTokenValueFilter', + const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'outputTokenValueFilter', subBuilder: TokenValueFilter.create, ) ..aOM( 7, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'outputAddressSelection', + const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'outputAddressSelection', subBuilder: StringSelection.create, ) ..aOM( 8, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'mintingSelection', + const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'mintingSelection', subBuilder: BooleanSelection.create, ) ..aOM( 9, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'txIdSelection', + const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'txIdSelection', subBuilder: StringSelection.create, ) ..aOM( 10, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'boxesToRemoveSelection', + const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'boxesToRemoveSelection', subBuilder: StringSelection.create, ) ..aOM( 11, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'feeRange', + const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'feeRange', subBuilder: NumberRange.create, ) ..aOM( 12, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'propositionSelection', + const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'propositionSelection', subBuilder: StringSelection.create, ) ..aOM( 13, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'blockIdSelection', + const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'blockIdSelection', subBuilder: StringSelection.create, ) ..aOM( 14, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'blockHeightRange', + const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'blockHeightRange', subBuilder: NumberRange.create, ) ..aOM( 15, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'and', + const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'and', subBuilder: TransactionFilter_AndFilter.create, ) ..aOM( @@ -929,16 +792,12 @@ class TransactionFilter extends $pb.GeneratedMessage { ) ..aOM( 17, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'not', + const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'not', subBuilder: TransactionFilter_NotFilter.create, ) ..aOM( 18, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'all', + const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'all', subBuilder: TransactionFilter_AllFilter.create, ) ..hasRequiredFields = false; @@ -1026,8 +885,7 @@ class TransactionFilter extends $pb.GeneratedMessage { $pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY, ]) => create()..mergeFromBuffer(i, r); - factory TransactionFilter.fromJson($core.String i, - [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => + factory TransactionFilter.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); @$core.Deprecated( 'Using this can add significant overhead to your binary. ' @@ -1047,15 +905,13 @@ class TransactionFilter extends $pb.GeneratedMessage { @$core.pragma('dart2js:noInline') static TransactionFilter create() => TransactionFilter._(); TransactionFilter createEmptyInstance() => create(); - static $pb.PbList createRepeated() => - $pb.PbList(); + static $pb.PbList createRepeated() => $pb.PbList(); @$core.pragma('dart2js:noInline') - static TransactionFilter getDefault() => _defaultInstance ??= - $pb.GeneratedMessage.$_defaultFor(create); + static TransactionFilter getDefault() => + _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); static TransactionFilter? _defaultInstance; - TransactionFilter_FilterType whichFilterType() => - _TransactionFilter_FilterTypeByTag[$_whichOneof(0)]!; + TransactionFilter_FilterType whichFilterType() => _TransactionFilter_FilterTypeByTag[$_whichOneof(0)]!; void clearFilterType() => clearField($_whichOneof(0)); @$pb.TagNumber(1) @@ -1313,20 +1169,14 @@ class TransactionFilter extends $pb.GeneratedMessage { class BlockFilter_AndFilter extends $pb.GeneratedMessage { static final $pb.BuilderInfo _i = $pb.BuilderInfo( - const $core.bool.fromEnvironment('protobuf.omit_message_names') - ? '' - : 'BlockFilter.AndFilter', - package: const $pb.PackageName( - const $core.bool.fromEnvironment('protobuf.omit_message_names') - ? '' - : 'co.topl.genus'), + const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'BlockFilter.AndFilter', + package: + const $pb.PackageName(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'co.topl.genus'), createEmptyInstance: create, ) ..pc( 1, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'filters', + const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'filters', $pb.PbFieldType.PM, subBuilder: BlockFilter.create, ) @@ -1347,34 +1197,30 @@ class BlockFilter_AndFilter extends $pb.GeneratedMessage { $pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY, ]) => create()..mergeFromBuffer(i, r); - factory BlockFilter_AndFilter.fromJson($core.String i, - [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => + factory BlockFilter_AndFilter.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); @$core.Deprecated( 'Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' 'Will be removed in next major version', ) - BlockFilter_AndFilter clone() => - BlockFilter_AndFilter()..mergeFromMessage(this); + BlockFilter_AndFilter clone() => BlockFilter_AndFilter()..mergeFromMessage(this); @$core.Deprecated( 'Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' 'Will be removed in next major version', ) - BlockFilter_AndFilter copyWith( - void Function(BlockFilter_AndFilter) updates) => + BlockFilter_AndFilter copyWith(void Function(BlockFilter_AndFilter) updates) => super.copyWith((message) => updates(message as BlockFilter_AndFilter)) as BlockFilter_AndFilter; // ignore: deprecated_member_use $pb.BuilderInfo get info_ => _i; @$core.pragma('dart2js:noInline') static BlockFilter_AndFilter create() => BlockFilter_AndFilter._(); BlockFilter_AndFilter createEmptyInstance() => create(); - static $pb.PbList createRepeated() => - $pb.PbList(); + static $pb.PbList createRepeated() => $pb.PbList(); @$core.pragma('dart2js:noInline') - static BlockFilter_AndFilter getDefault() => _defaultInstance ??= - $pb.GeneratedMessage.$_defaultFor(create); + static BlockFilter_AndFilter getDefault() => + _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); static BlockFilter_AndFilter? _defaultInstance; @$pb.TagNumber(1) @@ -1383,20 +1229,14 @@ class BlockFilter_AndFilter extends $pb.GeneratedMessage { class BlockFilter_OrFilter extends $pb.GeneratedMessage { static final $pb.BuilderInfo _i = $pb.BuilderInfo( - const $core.bool.fromEnvironment('protobuf.omit_message_names') - ? '' - : 'BlockFilter.OrFilter', - package: const $pb.PackageName( - const $core.bool.fromEnvironment('protobuf.omit_message_names') - ? '' - : 'co.topl.genus'), + const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'BlockFilter.OrFilter', + package: + const $pb.PackageName(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'co.topl.genus'), createEmptyInstance: create, ) ..pc( 1, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'filters', + const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'filters', $pb.PbFieldType.PM, subBuilder: BlockFilter.create, ) @@ -1417,16 +1257,14 @@ class BlockFilter_OrFilter extends $pb.GeneratedMessage { $pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY, ]) => create()..mergeFromBuffer(i, r); - factory BlockFilter_OrFilter.fromJson($core.String i, - [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => + factory BlockFilter_OrFilter.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); @$core.Deprecated( 'Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' 'Will be removed in next major version', ) - BlockFilter_OrFilter clone() => - BlockFilter_OrFilter()..mergeFromMessage(this); + BlockFilter_OrFilter clone() => BlockFilter_OrFilter()..mergeFromMessage(this); @$core.Deprecated( 'Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' @@ -1439,11 +1277,10 @@ class BlockFilter_OrFilter extends $pb.GeneratedMessage { @$core.pragma('dart2js:noInline') static BlockFilter_OrFilter create() => BlockFilter_OrFilter._(); BlockFilter_OrFilter createEmptyInstance() => create(); - static $pb.PbList createRepeated() => - $pb.PbList(); + static $pb.PbList createRepeated() => $pb.PbList(); @$core.pragma('dart2js:noInline') - static BlockFilter_OrFilter getDefault() => _defaultInstance ??= - $pb.GeneratedMessage.$_defaultFor(create); + static BlockFilter_OrFilter getDefault() => + _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); static BlockFilter_OrFilter? _defaultInstance; @$pb.TagNumber(1) @@ -1452,20 +1289,14 @@ class BlockFilter_OrFilter extends $pb.GeneratedMessage { class BlockFilter_NotFilter extends $pb.GeneratedMessage { static final $pb.BuilderInfo _i = $pb.BuilderInfo( - const $core.bool.fromEnvironment('protobuf.omit_message_names') - ? '' - : 'BlockFilter.NotFilter', - package: const $pb.PackageName( - const $core.bool.fromEnvironment('protobuf.omit_message_names') - ? '' - : 'co.topl.genus'), + const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'BlockFilter.NotFilter', + package: + const $pb.PackageName(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'co.topl.genus'), createEmptyInstance: create, ) ..aOM( 1, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'filter', + const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'filter', subBuilder: BlockFilter.create, ) ..hasRequiredFields = false; @@ -1485,34 +1316,30 @@ class BlockFilter_NotFilter extends $pb.GeneratedMessage { $pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY, ]) => create()..mergeFromBuffer(i, r); - factory BlockFilter_NotFilter.fromJson($core.String i, - [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => + factory BlockFilter_NotFilter.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); @$core.Deprecated( 'Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' 'Will be removed in next major version', ) - BlockFilter_NotFilter clone() => - BlockFilter_NotFilter()..mergeFromMessage(this); + BlockFilter_NotFilter clone() => BlockFilter_NotFilter()..mergeFromMessage(this); @$core.Deprecated( 'Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' 'Will be removed in next major version', ) - BlockFilter_NotFilter copyWith( - void Function(BlockFilter_NotFilter) updates) => + BlockFilter_NotFilter copyWith(void Function(BlockFilter_NotFilter) updates) => super.copyWith((message) => updates(message as BlockFilter_NotFilter)) as BlockFilter_NotFilter; // ignore: deprecated_member_use $pb.BuilderInfo get info_ => _i; @$core.pragma('dart2js:noInline') static BlockFilter_NotFilter create() => BlockFilter_NotFilter._(); BlockFilter_NotFilter createEmptyInstance() => create(); - static $pb.PbList createRepeated() => - $pb.PbList(); + static $pb.PbList createRepeated() => $pb.PbList(); @$core.pragma('dart2js:noInline') - static BlockFilter_NotFilter getDefault() => _defaultInstance ??= - $pb.GeneratedMessage.$_defaultFor(create); + static BlockFilter_NotFilter getDefault() => + _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); static BlockFilter_NotFilter? _defaultInstance; @$pb.TagNumber(1) @@ -1532,13 +1359,9 @@ class BlockFilter_NotFilter extends $pb.GeneratedMessage { class BlockFilter_AllFilter extends $pb.GeneratedMessage { static final $pb.BuilderInfo _i = $pb.BuilderInfo( - const $core.bool.fromEnvironment('protobuf.omit_message_names') - ? '' - : 'BlockFilter.AllFilter', - package: const $pb.PackageName( - const $core.bool.fromEnvironment('protobuf.omit_message_names') - ? '' - : 'co.topl.genus'), + const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'BlockFilter.AllFilter', + package: + const $pb.PackageName(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'co.topl.genus'), createEmptyInstance: create, )..hasRequiredFields = false; @@ -1549,34 +1372,30 @@ class BlockFilter_AllFilter extends $pb.GeneratedMessage { $pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY, ]) => create()..mergeFromBuffer(i, r); - factory BlockFilter_AllFilter.fromJson($core.String i, - [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => + factory BlockFilter_AllFilter.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); @$core.Deprecated( 'Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' 'Will be removed in next major version', ) - BlockFilter_AllFilter clone() => - BlockFilter_AllFilter()..mergeFromMessage(this); + BlockFilter_AllFilter clone() => BlockFilter_AllFilter()..mergeFromMessage(this); @$core.Deprecated( 'Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' 'Will be removed in next major version', ) - BlockFilter_AllFilter copyWith( - void Function(BlockFilter_AllFilter) updates) => + BlockFilter_AllFilter copyWith(void Function(BlockFilter_AllFilter) updates) => super.copyWith((message) => updates(message as BlockFilter_AllFilter)) as BlockFilter_AllFilter; // ignore: deprecated_member_use $pb.BuilderInfo get info_ => _i; @$core.pragma('dart2js:noInline') static BlockFilter_AllFilter create() => BlockFilter_AllFilter._(); BlockFilter_AllFilter createEmptyInstance() => create(); - static $pb.PbList createRepeated() => - $pb.PbList(); + static $pb.PbList createRepeated() => $pb.PbList(); @$core.pragma('dart2js:noInline') - static BlockFilter_AllFilter getDefault() => _defaultInstance ??= - $pb.GeneratedMessage.$_defaultFor(create); + static BlockFilter_AllFilter getDefault() => + _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); static BlockFilter_AllFilter? _defaultInstance; } @@ -1599,8 +1418,7 @@ enum BlockFilter_FilterType { } class BlockFilter extends $pb.GeneratedMessage { - static const $core.Map<$core.int, BlockFilter_FilterType> - _BlockFilter_FilterTypeByTag = { + static const $core.Map<$core.int, BlockFilter_FilterType> _BlockFilter_FilterTypeByTag = { 1: BlockFilter_FilterType.idSelection, 2: BlockFilter_FilterType.parentIdSelection, 3: BlockFilter_FilterType.timestampRange, @@ -1618,91 +1436,65 @@ class BlockFilter extends $pb.GeneratedMessage { 0: BlockFilter_FilterType.notSet }; static final $pb.BuilderInfo _i = $pb.BuilderInfo( - const $core.bool.fromEnvironment('protobuf.omit_message_names') - ? '' - : 'BlockFilter', - package: const $pb.PackageName( - const $core.bool.fromEnvironment('protobuf.omit_message_names') - ? '' - : 'co.topl.genus'), + const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'BlockFilter', + package: + const $pb.PackageName(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'co.topl.genus'), createEmptyInstance: create, ) ..oo(0, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 15, 16, 17, 18]) ..aOM( 1, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'idSelection', + const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'idSelection', subBuilder: StringSelection.create, ) ..aOM( 2, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'parentIdSelection', + const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'parentIdSelection', subBuilder: StringSelection.create, ) ..aOM( 3, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'timestampRange', + const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'timestampRange', subBuilder: NumberRange.create, ) ..aOM( 4, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'generatorBoxTokenValueFilter', + const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'generatorBoxTokenValueFilter', subBuilder: TokenValueFilter.create, ) ..aOM( 5, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'publicKeySelection', + const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'publicKeySelection', subBuilder: StringSelection.create, ) ..aOM( 6, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'heightRange', + const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'heightRange', subBuilder: NumberRange.create, ) ..aOM( 7, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'heightSelection', + const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'heightSelection', subBuilder: NumberSelection.create, ) ..aOM( 8, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'difficultyRange', + const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'difficultyRange', subBuilder: NumberRange.create, ) ..aOM( 9, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'versionSelection', + const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'versionSelection', subBuilder: NumberSelection.create, ) ..aOM( 10, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'numTransactionRange', + const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'numTransactionRange', subBuilder: NumberRange.create, ) ..aOM( 15, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'and', + const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'and', subBuilder: BlockFilter_AndFilter.create, ) ..aOM( @@ -1712,16 +1504,12 @@ class BlockFilter extends $pb.GeneratedMessage { ) ..aOM( 17, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'not', + const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'not', subBuilder: BlockFilter_NotFilter.create, ) ..aOM( 18, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'all', + const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'all', subBuilder: BlockFilter_AllFilter.create, ) ..hasRequiredFields = false; @@ -1788,11 +1576,9 @@ class BlockFilter extends $pb.GeneratedMessage { } return _result; } - factory BlockFilter.fromBuffer($core.List<$core.int> i, - [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => + factory BlockFilter.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); - factory BlockFilter.fromJson($core.String i, - [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => + factory BlockFilter.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); @$core.Deprecated( 'Using this can add significant overhead to your binary. ' @@ -1806,20 +1592,17 @@ class BlockFilter extends $pb.GeneratedMessage { 'Will be removed in next major version', ) BlockFilter copyWith(void Function(BlockFilter) updates) => - super.copyWith((message) => updates(message as BlockFilter)) - as BlockFilter; // ignore: deprecated_member_use + super.copyWith((message) => updates(message as BlockFilter)) as BlockFilter; // ignore: deprecated_member_use $pb.BuilderInfo get info_ => _i; @$core.pragma('dart2js:noInline') static BlockFilter create() => BlockFilter._(); BlockFilter createEmptyInstance() => create(); static $pb.PbList createRepeated() => $pb.PbList(); @$core.pragma('dart2js:noInline') - static BlockFilter getDefault() => _defaultInstance ??= - $pb.GeneratedMessage.$_defaultFor(create); + static BlockFilter getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); static BlockFilter? _defaultInstance; - BlockFilter_FilterType whichFilterType() => - _BlockFilter_FilterTypeByTag[$_whichOneof(0)]!; + BlockFilter_FilterType whichFilterType() => _BlockFilter_FilterTypeByTag[$_whichOneof(0)]!; void clearFilterType() => clearField($_whichOneof(0)); @$pb.TagNumber(1) diff --git a/lib/genus/generated/filters.pbjson.dart b/lib/genus/generated/filters.pbjson.dart index 7c2f2a02..8d0c8af9 100644 --- a/lib/genus/generated/filters.pbjson.dart +++ b/lib/genus/generated/filters.pbjson.dart @@ -19,8 +19,8 @@ const StringSelection$json = const { }; /// Descriptor for `StringSelection`. Decode as a `google.protobuf.DescriptorProto`. -final $typed_data.Uint8List stringSelectionDescriptor = $convert - .base64Decode('Cg9TdHJpbmdTZWxlY3Rpb24SFgoGdmFsdWVzGAEgAygJUgZ2YWx1ZXM='); +final $typed_data.Uint8List stringSelectionDescriptor = + $convert.base64Decode('Cg9TdHJpbmdTZWxlY3Rpb24SFgoGdmFsdWVzGAEgAygJUgZ2YWx1ZXM='); @$core.Deprecated('Use numberRangeDescriptor instead') const NumberRange$json = const { '1': 'NumberRange', @@ -34,8 +34,8 @@ const NumberRange$json = const { }; /// Descriptor for `NumberRange`. Decode as a `google.protobuf.DescriptorProto`. -final $typed_data.Uint8List numberRangeDescriptor = $convert.base64Decode( - 'CgtOdW1iZXJSYW5nZRISCgNtaW4YASABKARIAFIDbWluEhIKA21heBgCIAEoBEgAUgNtYXhCDQoLZmlsdGVyX3R5cGU='); +final $typed_data.Uint8List numberRangeDescriptor = $convert + .base64Decode('CgtOdW1iZXJSYW5nZRISCgNtaW4YASABKARIAFIDbWluEhIKA21heBgCIAEoBEgAUgNtYXhCDQoLZmlsdGVyX3R5cGU='); @$core.Deprecated('Use numberSelectionDescriptor instead') const NumberSelection$json = const { '1': 'NumberSelection', @@ -45,8 +45,8 @@ const NumberSelection$json = const { }; /// Descriptor for `NumberSelection`. Decode as a `google.protobuf.DescriptorProto`. -final $typed_data.Uint8List numberSelectionDescriptor = $convert - .base64Decode('Cg9OdW1iZXJTZWxlY3Rpb24SFgoGdmFsdWVzGAEgAygEUgZ2YWx1ZXM='); +final $typed_data.Uint8List numberSelectionDescriptor = + $convert.base64Decode('Cg9OdW1iZXJTZWxlY3Rpb24SFgoGdmFsdWVzGAEgAygEUgZ2YWx1ZXM='); @$core.Deprecated('Use booleanSelectionDescriptor instead') const BooleanSelection$json = const { '1': 'BooleanSelection', @@ -56,8 +56,8 @@ const BooleanSelection$json = const { }; /// Descriptor for `BooleanSelection`. Decode as a `google.protobuf.DescriptorProto`. -final $typed_data.Uint8List booleanSelectionDescriptor = $convert - .base64Decode('ChBCb29sZWFuU2VsZWN0aW9uEhQKBXZhbHVlGAEgASgIUgV2YWx1ZQ=='); +final $typed_data.Uint8List booleanSelectionDescriptor = + $convert.base64Decode('ChBCb29sZWFuU2VsZWN0aW9uEhQKBXZhbHVlGAEgASgIUgV2YWx1ZQ=='); @$core.Deprecated('Use tokenValueFilterDescriptor instead') const TokenValueFilter$json = const { '1': 'TokenValueFilter', @@ -192,15 +192,7 @@ const TransactionFilter$json = const { '9': 0, '10': 'boxesToRemoveSelection' }, - const { - '1': 'fee_range', - '3': 11, - '4': 1, - '5': 11, - '6': '.co.topl.genus.NumberRange', - '9': 0, - '10': 'feeRange' - }, + const {'1': 'fee_range', '3': 11, '4': 1, '5': 11, '6': '.co.topl.genus.NumberRange', '9': 0, '10': 'feeRange'}, const { '1': 'proposition_selection', '3': 12, @@ -237,15 +229,7 @@ const TransactionFilter$json = const { '9': 0, '10': 'and' }, - const { - '1': 'or', - '3': 16, - '4': 1, - '5': 11, - '6': '.co.topl.genus.TransactionFilter.OrFilter', - '9': 0, - '10': 'or' - }, + const {'1': 'or', '3': 16, '4': 1, '5': 11, '6': '.co.topl.genus.TransactionFilter.OrFilter', '9': 0, '10': 'or'}, const { '1': 'not', '3': 17, @@ -280,14 +264,7 @@ const TransactionFilter$json = const { const TransactionFilter_AndFilter$json = const { '1': 'AndFilter', '2': const [ - const { - '1': 'filters', - '3': 1, - '4': 3, - '5': 11, - '6': '.co.topl.genus.TransactionFilter', - '10': 'filters' - }, + const {'1': 'filters', '3': 1, '4': 3, '5': 11, '6': '.co.topl.genus.TransactionFilter', '10': 'filters'}, ], }; @@ -295,14 +272,7 @@ const TransactionFilter_AndFilter$json = const { const TransactionFilter_OrFilter$json = const { '1': 'OrFilter', '2': const [ - const { - '1': 'filters', - '3': 1, - '4': 3, - '5': 11, - '6': '.co.topl.genus.TransactionFilter', - '10': 'filters' - }, + const {'1': 'filters', '3': 1, '4': 3, '5': 11, '6': '.co.topl.genus.TransactionFilter', '10': 'filters'}, ], }; @@ -310,14 +280,7 @@ const TransactionFilter_OrFilter$json = const { const TransactionFilter_NotFilter$json = const { '1': 'NotFilter', '2': const [ - const { - '1': 'filter', - '3': 1, - '4': 1, - '5': 11, - '6': '.co.topl.genus.TransactionFilter', - '10': 'filter' - }, + const {'1': 'filter', '3': 1, '4': 1, '5': 11, '6': '.co.topl.genus.TransactionFilter', '10': 'filter'}, ], }; @@ -423,42 +386,10 @@ const BlockFilter$json = const { '9': 0, '10': 'numTransactionRange' }, - const { - '1': 'and', - '3': 15, - '4': 1, - '5': 11, - '6': '.co.topl.genus.BlockFilter.AndFilter', - '9': 0, - '10': 'and' - }, - const { - '1': 'or', - '3': 16, - '4': 1, - '5': 11, - '6': '.co.topl.genus.BlockFilter.OrFilter', - '9': 0, - '10': 'or' - }, - const { - '1': 'not', - '3': 17, - '4': 1, - '5': 11, - '6': '.co.topl.genus.BlockFilter.NotFilter', - '9': 0, - '10': 'not' - }, - const { - '1': 'all', - '3': 18, - '4': 1, - '5': 11, - '6': '.co.topl.genus.BlockFilter.AllFilter', - '9': 0, - '10': 'all' - }, + const {'1': 'and', '3': 15, '4': 1, '5': 11, '6': '.co.topl.genus.BlockFilter.AndFilter', '9': 0, '10': 'and'}, + const {'1': 'or', '3': 16, '4': 1, '5': 11, '6': '.co.topl.genus.BlockFilter.OrFilter', '9': 0, '10': 'or'}, + const {'1': 'not', '3': 17, '4': 1, '5': 11, '6': '.co.topl.genus.BlockFilter.NotFilter', '9': 0, '10': 'not'}, + const {'1': 'all', '3': 18, '4': 1, '5': 11, '6': '.co.topl.genus.BlockFilter.AllFilter', '9': 0, '10': 'all'}, ], '3': const [ BlockFilter_AndFilter$json, @@ -475,14 +406,7 @@ const BlockFilter$json = const { const BlockFilter_AndFilter$json = const { '1': 'AndFilter', '2': const [ - const { - '1': 'filters', - '3': 1, - '4': 3, - '5': 11, - '6': '.co.topl.genus.BlockFilter', - '10': 'filters' - }, + const {'1': 'filters', '3': 1, '4': 3, '5': 11, '6': '.co.topl.genus.BlockFilter', '10': 'filters'}, ], }; @@ -490,14 +414,7 @@ const BlockFilter_AndFilter$json = const { const BlockFilter_OrFilter$json = const { '1': 'OrFilter', '2': const [ - const { - '1': 'filters', - '3': 1, - '4': 3, - '5': 11, - '6': '.co.topl.genus.BlockFilter', - '10': 'filters' - }, + const {'1': 'filters', '3': 1, '4': 3, '5': 11, '6': '.co.topl.genus.BlockFilter', '10': 'filters'}, ], }; @@ -505,14 +422,7 @@ const BlockFilter_OrFilter$json = const { const BlockFilter_NotFilter$json = const { '1': 'NotFilter', '2': const [ - const { - '1': 'filter', - '3': 1, - '4': 1, - '5': 11, - '6': '.co.topl.genus.BlockFilter', - '10': 'filter' - }, + const {'1': 'filter', '3': 1, '4': 1, '5': 11, '6': '.co.topl.genus.BlockFilter', '10': 'filter'}, ], }; diff --git a/lib/genus/generated/services_types.pb.dart b/lib/genus/generated/services_types.pb.dart index a954cea0..a2d43a78 100644 --- a/lib/genus/generated/services_types.pb.dart +++ b/lib/genus/generated/services_types.pb.dart @@ -13,28 +13,20 @@ import 'package:protobuf/protobuf.dart' as $pb; class Paging extends $pb.GeneratedMessage { static final $pb.BuilderInfo _i = $pb.BuilderInfo( - const $core.bool.fromEnvironment('protobuf.omit_message_names') - ? '' - : 'Paging', + const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'Paging', package: const $pb.PackageName( - const $core.bool.fromEnvironment('protobuf.omit_message_names') - ? '' - : 'co.topl.genus.services', + const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'co.topl.genus.services', ), createEmptyInstance: create, ) ..a<$core.int>( 1, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'pageNumber', + const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'pageNumber', $pb.PbFieldType.OU3, ) ..a<$core.int>( 2, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'pageSize', + const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'pageSize', $pb.PbFieldType.OU3, ) ..hasRequiredFields = false; @@ -53,11 +45,9 @@ class Paging extends $pb.GeneratedMessage { } return _result; } - factory Paging.fromBuffer($core.List<$core.int> i, - [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => + factory Paging.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); - factory Paging.fromJson($core.String i, - [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => + factory Paging.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); @$core.Deprecated( 'Using this can add significant overhead to your binary. ' @@ -71,16 +61,14 @@ class Paging extends $pb.GeneratedMessage { 'Will be removed in next major version', ) Paging copyWith(void Function(Paging) updates) => - super.copyWith((message) => updates(message as Paging)) - as Paging; // ignore: deprecated_member_use + super.copyWith((message) => updates(message as Paging)) as Paging; // ignore: deprecated_member_use $pb.BuilderInfo get info_ => _i; @$core.pragma('dart2js:noInline') static Paging create() => Paging._(); Paging createEmptyInstance() => create(); static $pb.PbList createRepeated() => $pb.PbList(); @$core.pragma('dart2js:noInline') - static Paging getDefault() => - _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); + static Paging getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); static Paging? _defaultInstance; @$pb.TagNumber(1) diff --git a/lib/genus/generated/services_types.pbjson.dart b/lib/genus/generated/services_types.pbjson.dart index db9e68cc..647f6271 100644 --- a/lib/genus/generated/services_types.pbjson.dart +++ b/lib/genus/generated/services_types.pbjson.dart @@ -20,5 +20,5 @@ const Paging$json = const { }; /// Descriptor for `Paging`. Decode as a `google.protobuf.DescriptorProto`. -final $typed_data.Uint8List pagingDescriptor = $convert.base64Decode( - 'CgZQYWdpbmcSHwoLcGFnZV9udW1iZXIYASABKA1SCnBhZ2VOdW1iZXISGwoJcGFnZV9zaXplGAIgASgNUghwYWdlU2l6ZQ=='); +final $typed_data.Uint8List pagingDescriptor = $convert + .base64Decode('CgZQYWdpbmcSHwoLcGFnZV9udW1iZXIYASABKA1SCnBhZ2VOdW1iZXISGwoJcGFnZV9zaXplGAIgASgNUghwYWdlU2l6ZQ=='); diff --git a/lib/genus/generated/transactions_query.pb.dart b/lib/genus/generated/transactions_query.pb.dart index dd1174b6..30caf876 100644 --- a/lib/genus/generated/transactions_query.pb.dart +++ b/lib/genus/generated/transactions_query.pb.dart @@ -18,21 +18,13 @@ import 'types.pb.dart' as $6; class TransactionSorting_Height extends $pb.GeneratedMessage { static final $pb.BuilderInfo _i = $pb.BuilderInfo( - const $core.bool.fromEnvironment('protobuf.omit_message_names') - ? '' - : 'TransactionSorting.Height', + const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'TransactionSorting.Height', package: const $pb.PackageName( - const $core.bool.fromEnvironment('protobuf.omit_message_names') - ? '' - : 'co.topl.genus.services', + const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'co.topl.genus.services', ), createEmptyInstance: create, ) - ..aOB( - 1, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'descending') + ..aOB(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'descending') ..hasRequiredFields = false; TransactionSorting_Height._() : super(); @@ -50,34 +42,30 @@ class TransactionSorting_Height extends $pb.GeneratedMessage { $pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY, ]) => create()..mergeFromBuffer(i, r); - factory TransactionSorting_Height.fromJson($core.String i, - [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => + factory TransactionSorting_Height.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); @$core.Deprecated( 'Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' 'Will be removed in next major version', ) - TransactionSorting_Height clone() => - TransactionSorting_Height()..mergeFromMessage(this); + TransactionSorting_Height clone() => TransactionSorting_Height()..mergeFromMessage(this); @$core.Deprecated( 'Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' 'Will be removed in next major version', ) - TransactionSorting_Height copyWith( - void Function(TransactionSorting_Height) updates) => + TransactionSorting_Height copyWith(void Function(TransactionSorting_Height) updates) => super.copyWith((message) => updates(message as TransactionSorting_Height)) as TransactionSorting_Height; // ignore: deprecated_member_use $pb.BuilderInfo get info_ => _i; @$core.pragma('dart2js:noInline') static TransactionSorting_Height create() => TransactionSorting_Height._(); TransactionSorting_Height createEmptyInstance() => create(); - static $pb.PbList createRepeated() => - $pb.PbList(); + static $pb.PbList createRepeated() => $pb.PbList(); @$core.pragma('dart2js:noInline') - static TransactionSorting_Height getDefault() => _defaultInstance ??= - $pb.GeneratedMessage.$_defaultFor(create); + static TransactionSorting_Height getDefault() => + _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); static TransactionSorting_Height? _defaultInstance; @$pb.TagNumber(1) @@ -95,21 +83,13 @@ class TransactionSorting_Height extends $pb.GeneratedMessage { class TransactionSorting_Fee extends $pb.GeneratedMessage { static final $pb.BuilderInfo _i = $pb.BuilderInfo( - const $core.bool.fromEnvironment('protobuf.omit_message_names') - ? '' - : 'TransactionSorting.Fee', + const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'TransactionSorting.Fee', package: const $pb.PackageName( - const $core.bool.fromEnvironment('protobuf.omit_message_names') - ? '' - : 'co.topl.genus.services', + const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'co.topl.genus.services', ), createEmptyInstance: create, ) - ..aOB( - 1, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'descending') + ..aOB(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'descending') ..hasRequiredFields = false; TransactionSorting_Fee._() : super(); @@ -127,34 +107,30 @@ class TransactionSorting_Fee extends $pb.GeneratedMessage { $pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY, ]) => create()..mergeFromBuffer(i, r); - factory TransactionSorting_Fee.fromJson($core.String i, - [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => + factory TransactionSorting_Fee.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); @$core.Deprecated( 'Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' 'Will be removed in next major version', ) - TransactionSorting_Fee clone() => - TransactionSorting_Fee()..mergeFromMessage(this); + TransactionSorting_Fee clone() => TransactionSorting_Fee()..mergeFromMessage(this); @$core.Deprecated( 'Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' 'Will be removed in next major version', ) - TransactionSorting_Fee copyWith( - void Function(TransactionSorting_Fee) updates) => + TransactionSorting_Fee copyWith(void Function(TransactionSorting_Fee) updates) => super.copyWith((message) => updates(message as TransactionSorting_Fee)) as TransactionSorting_Fee; // ignore: deprecated_member_use $pb.BuilderInfo get info_ => _i; @$core.pragma('dart2js:noInline') static TransactionSorting_Fee create() => TransactionSorting_Fee._(); TransactionSorting_Fee createEmptyInstance() => create(); - static $pb.PbList createRepeated() => - $pb.PbList(); + static $pb.PbList createRepeated() => $pb.PbList(); @$core.pragma('dart2js:noInline') - static TransactionSorting_Fee getDefault() => _defaultInstance ??= - $pb.GeneratedMessage.$_defaultFor(create); + static TransactionSorting_Fee getDefault() => + _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); static TransactionSorting_Fee? _defaultInstance; @$pb.TagNumber(1) @@ -172,21 +148,13 @@ class TransactionSorting_Fee extends $pb.GeneratedMessage { class TransactionSorting_Timestamp extends $pb.GeneratedMessage { static final $pb.BuilderInfo _i = $pb.BuilderInfo( - const $core.bool.fromEnvironment('protobuf.omit_message_names') - ? '' - : 'TransactionSorting.Timestamp', + const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'TransactionSorting.Timestamp', package: const $pb.PackageName( - const $core.bool.fromEnvironment('protobuf.omit_message_names') - ? '' - : 'co.topl.genus.services', + const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'co.topl.genus.services', ), createEmptyInstance: create, ) - ..aOB( - 1, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'descending') + ..aOB(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'descending') ..hasRequiredFields = false; TransactionSorting_Timestamp._() : super(); @@ -214,28 +182,23 @@ class TransactionSorting_Timestamp extends $pb.GeneratedMessage { 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' 'Will be removed in next major version', ) - TransactionSorting_Timestamp clone() => - TransactionSorting_Timestamp()..mergeFromMessage(this); + TransactionSorting_Timestamp clone() => TransactionSorting_Timestamp()..mergeFromMessage(this); @$core.Deprecated( 'Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' 'Will be removed in next major version', ) - TransactionSorting_Timestamp copyWith( - void Function(TransactionSorting_Timestamp) updates) => - super.copyWith( - (message) => updates(message as TransactionSorting_Timestamp)) + TransactionSorting_Timestamp copyWith(void Function(TransactionSorting_Timestamp) updates) => + super.copyWith((message) => updates(message as TransactionSorting_Timestamp)) as TransactionSorting_Timestamp; // ignore: deprecated_member_use $pb.BuilderInfo get info_ => _i; @$core.pragma('dart2js:noInline') - static TransactionSorting_Timestamp create() => - TransactionSorting_Timestamp._(); + static TransactionSorting_Timestamp create() => TransactionSorting_Timestamp._(); TransactionSorting_Timestamp createEmptyInstance() => create(); - static $pb.PbList createRepeated() => - $pb.PbList(); + static $pb.PbList createRepeated() => $pb.PbList(); @$core.pragma('dart2js:noInline') - static TransactionSorting_Timestamp getDefault() => _defaultInstance ??= - $pb.GeneratedMessage.$_defaultFor(create); + static TransactionSorting_Timestamp getDefault() => + _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); static TransactionSorting_Timestamp? _defaultInstance; @$pb.TagNumber(1) @@ -254,44 +217,33 @@ class TransactionSorting_Timestamp extends $pb.GeneratedMessage { enum TransactionSorting_SortBy { height, fee, timestamp, notSet } class TransactionSorting extends $pb.GeneratedMessage { - static const $core.Map<$core.int, TransactionSorting_SortBy> - _TransactionSorting_SortByByTag = { + static const $core.Map<$core.int, TransactionSorting_SortBy> _TransactionSorting_SortByByTag = { 1: TransactionSorting_SortBy.height, 2: TransactionSorting_SortBy.fee, 3: TransactionSorting_SortBy.timestamp, 0: TransactionSorting_SortBy.notSet }; static final $pb.BuilderInfo _i = $pb.BuilderInfo( - const $core.bool.fromEnvironment('protobuf.omit_message_names') - ? '' - : 'TransactionSorting', + const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'TransactionSorting', package: const $pb.PackageName( - const $core.bool.fromEnvironment('protobuf.omit_message_names') - ? '' - : 'co.topl.genus.services', + const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'co.topl.genus.services', ), createEmptyInstance: create, ) ..oo(0, [1, 2, 3]) ..aOM( 1, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'height', + const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'height', subBuilder: TransactionSorting_Height.create, ) ..aOM( 2, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'fee', + const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'fee', subBuilder: TransactionSorting_Fee.create, ) ..aOM( 3, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'timestamp', + const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'timestamp', subBuilder: TransactionSorting_Timestamp.create, ) ..hasRequiredFields = false; @@ -319,8 +271,7 @@ class TransactionSorting extends $pb.GeneratedMessage { $pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY, ]) => create()..mergeFromBuffer(i, r); - factory TransactionSorting.fromJson($core.String i, - [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => + factory TransactionSorting.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); @$core.Deprecated( 'Using this can add significant overhead to your binary. ' @@ -340,15 +291,13 @@ class TransactionSorting extends $pb.GeneratedMessage { @$core.pragma('dart2js:noInline') static TransactionSorting create() => TransactionSorting._(); TransactionSorting createEmptyInstance() => create(); - static $pb.PbList createRepeated() => - $pb.PbList(); + static $pb.PbList createRepeated() => $pb.PbList(); @$core.pragma('dart2js:noInline') - static TransactionSorting getDefault() => _defaultInstance ??= - $pb.GeneratedMessage.$_defaultFor(create); + static TransactionSorting getDefault() => + _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); static TransactionSorting? _defaultInstance; - TransactionSorting_SortBy whichSortBy() => - _TransactionSorting_SortByByTag[$_whichOneof(0)]!; + TransactionSorting_SortBy whichSortBy() => _TransactionSorting_SortByByTag[$_whichOneof(0)]!; void clearSortBy() => clearField($_whichOneof(0)); @$pb.TagNumber(1) @@ -396,42 +345,30 @@ class TransactionSorting extends $pb.GeneratedMessage { class QueryTxsReq extends $pb.GeneratedMessage { static final $pb.BuilderInfo _i = $pb.BuilderInfo( - const $core.bool.fromEnvironment('protobuf.omit_message_names') - ? '' - : 'QueryTxsReq', + const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'QueryTxsReq', package: const $pb.PackageName( - const $core.bool.fromEnvironment('protobuf.omit_message_names') - ? '' - : 'co.topl.genus.services', + const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'co.topl.genus.services', ), createEmptyInstance: create, ) ..aOM<$4.TransactionFilter>( 1, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'filter', + const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'filter', subBuilder: $4.TransactionFilter.create, ) ..aOM( 2, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'sorting', + const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'sorting', subBuilder: TransactionSorting.create, ) ..a<$core.int>( 3, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'confirmationDepth', + const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'confirmationDepth', $pb.PbFieldType.OU3, ) ..aOM<$5.Paging>( 4, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'pagingOptions', + const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'pagingOptions', subBuilder: $5.Paging.create, ) ..hasRequiredFields = false; @@ -458,11 +395,9 @@ class QueryTxsReq extends $pb.GeneratedMessage { } return _result; } - factory QueryTxsReq.fromBuffer($core.List<$core.int> i, - [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => + factory QueryTxsReq.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); - factory QueryTxsReq.fromJson($core.String i, - [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => + factory QueryTxsReq.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); @$core.Deprecated( 'Using this can add significant overhead to your binary. ' @@ -476,16 +411,14 @@ class QueryTxsReq extends $pb.GeneratedMessage { 'Will be removed in next major version', ) QueryTxsReq copyWith(void Function(QueryTxsReq) updates) => - super.copyWith((message) => updates(message as QueryTxsReq)) - as QueryTxsReq; // ignore: deprecated_member_use + super.copyWith((message) => updates(message as QueryTxsReq)) as QueryTxsReq; // ignore: deprecated_member_use $pb.BuilderInfo get info_ => _i; @$core.pragma('dart2js:noInline') static QueryTxsReq create() => QueryTxsReq._(); QueryTxsReq createEmptyInstance() => create(); static $pb.PbList createRepeated() => $pb.PbList(); @$core.pragma('dart2js:noInline') - static QueryTxsReq getDefault() => _defaultInstance ??= - $pb.GeneratedMessage.$_defaultFor(create); + static QueryTxsReq getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); static QueryTxsReq? _defaultInstance; @$pb.TagNumber(1) @@ -545,21 +478,15 @@ class QueryTxsReq extends $pb.GeneratedMessage { class QueryTxsRes_Success extends $pb.GeneratedMessage { static final $pb.BuilderInfo _i = $pb.BuilderInfo( - const $core.bool.fromEnvironment('protobuf.omit_message_names') - ? '' - : 'QueryTxsRes.Success', + const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'QueryTxsRes.Success', package: const $pb.PackageName( - const $core.bool.fromEnvironment('protobuf.omit_message_names') - ? '' - : 'co.topl.genus.services', + const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'co.topl.genus.services', ), createEmptyInstance: create, ) ..pc<$6.Transaction>( 1, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'transactions', + const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'transactions', $pb.PbFieldType.PM, subBuilder: $6.Transaction.create, ) @@ -580,8 +507,7 @@ class QueryTxsRes_Success extends $pb.GeneratedMessage { $pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY, ]) => create()..mergeFromBuffer(i, r); - factory QueryTxsRes_Success.fromJson($core.String i, - [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => + factory QueryTxsRes_Success.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); @$core.Deprecated( 'Using this can add significant overhead to your binary. ' @@ -601,59 +527,36 @@ class QueryTxsRes_Success extends $pb.GeneratedMessage { @$core.pragma('dart2js:noInline') static QueryTxsRes_Success create() => QueryTxsRes_Success._(); QueryTxsRes_Success createEmptyInstance() => create(); - static $pb.PbList createRepeated() => - $pb.PbList(); + static $pb.PbList createRepeated() => $pb.PbList(); @$core.pragma('dart2js:noInline') - static QueryTxsRes_Success getDefault() => _defaultInstance ??= - $pb.GeneratedMessage.$_defaultFor(create); + static QueryTxsRes_Success getDefault() => + _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); static QueryTxsRes_Success? _defaultInstance; @$pb.TagNumber(1) $core.List<$6.Transaction> get transactions => $_getList(0); } -enum QueryTxsRes_Failure_Reason { - dataStoreConnectionError, - queryTimeout, - invalidQuery, - notSet -} +enum QueryTxsRes_Failure_Reason { dataStoreConnectionError, queryTimeout, invalidQuery, notSet } class QueryTxsRes_Failure extends $pb.GeneratedMessage { - static const $core.Map<$core.int, QueryTxsRes_Failure_Reason> - _QueryTxsRes_Failure_ReasonByTag = { + static const $core.Map<$core.int, QueryTxsRes_Failure_Reason> _QueryTxsRes_Failure_ReasonByTag = { 1: QueryTxsRes_Failure_Reason.dataStoreConnectionError, 2: QueryTxsRes_Failure_Reason.queryTimeout, 3: QueryTxsRes_Failure_Reason.invalidQuery, 0: QueryTxsRes_Failure_Reason.notSet }; static final $pb.BuilderInfo _i = $pb.BuilderInfo( - const $core.bool.fromEnvironment('protobuf.omit_message_names') - ? '' - : 'QueryTxsRes.Failure', + const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'QueryTxsRes.Failure', package: const $pb.PackageName( - const $core.bool.fromEnvironment('protobuf.omit_message_names') - ? '' - : 'co.topl.genus.services', + const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'co.topl.genus.services', ), createEmptyInstance: create, ) ..oo(0, [1, 2, 3]) - ..aOS( - 1, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'dataStoreConnectionError') - ..aOS( - 2, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'queryTimeout') - ..aOS( - 3, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'invalidQuery') + ..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'dataStoreConnectionError') + ..aOS(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'queryTimeout') + ..aOS(3, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'invalidQuery') ..hasRequiredFields = false; QueryTxsRes_Failure._() : super(); @@ -679,8 +582,7 @@ class QueryTxsRes_Failure extends $pb.GeneratedMessage { $pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY, ]) => create()..mergeFromBuffer(i, r); - factory QueryTxsRes_Failure.fromJson($core.String i, - [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => + factory QueryTxsRes_Failure.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); @$core.Deprecated( 'Using this can add significant overhead to your binary. ' @@ -700,15 +602,13 @@ class QueryTxsRes_Failure extends $pb.GeneratedMessage { @$core.pragma('dart2js:noInline') static QueryTxsRes_Failure create() => QueryTxsRes_Failure._(); QueryTxsRes_Failure createEmptyInstance() => create(); - static $pb.PbList createRepeated() => - $pb.PbList(); + static $pb.PbList createRepeated() => $pb.PbList(); @$core.pragma('dart2js:noInline') - static QueryTxsRes_Failure getDefault() => _defaultInstance ??= - $pb.GeneratedMessage.$_defaultFor(create); + static QueryTxsRes_Failure getDefault() => + _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); static QueryTxsRes_Failure? _defaultInstance; - QueryTxsRes_Failure_Reason whichReason() => - _QueryTxsRes_Failure_ReasonByTag[$_whichOneof(0)]!; + QueryTxsRes_Failure_Reason whichReason() => _QueryTxsRes_Failure_ReasonByTag[$_whichOneof(0)]!; void clearReason() => clearField($_whichOneof(0)); @$pb.TagNumber(1) @@ -751,36 +651,27 @@ class QueryTxsRes_Failure extends $pb.GeneratedMessage { enum QueryTxsRes_Result { success, failure, notSet } class QueryTxsRes extends $pb.GeneratedMessage { - static const $core.Map<$core.int, QueryTxsRes_Result> - _QueryTxsRes_ResultByTag = { + static const $core.Map<$core.int, QueryTxsRes_Result> _QueryTxsRes_ResultByTag = { 1: QueryTxsRes_Result.success, 2: QueryTxsRes_Result.failure, 0: QueryTxsRes_Result.notSet }; static final $pb.BuilderInfo _i = $pb.BuilderInfo( - const $core.bool.fromEnvironment('protobuf.omit_message_names') - ? '' - : 'QueryTxsRes', + const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'QueryTxsRes', package: const $pb.PackageName( - const $core.bool.fromEnvironment('protobuf.omit_message_names') - ? '' - : 'co.topl.genus.services', + const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'co.topl.genus.services', ), createEmptyInstance: create, ) ..oo(0, [1, 2]) ..aOM( 1, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'success', + const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'success', subBuilder: QueryTxsRes_Success.create, ) ..aOM( 2, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'failure', + const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'failure', subBuilder: QueryTxsRes_Failure.create, ) ..hasRequiredFields = false; @@ -799,11 +690,9 @@ class QueryTxsRes extends $pb.GeneratedMessage { } return _result; } - factory QueryTxsRes.fromBuffer($core.List<$core.int> i, - [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => + factory QueryTxsRes.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); - factory QueryTxsRes.fromJson($core.String i, - [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => + factory QueryTxsRes.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); @$core.Deprecated( 'Using this can add significant overhead to your binary. ' @@ -817,20 +706,17 @@ class QueryTxsRes extends $pb.GeneratedMessage { 'Will be removed in next major version', ) QueryTxsRes copyWith(void Function(QueryTxsRes) updates) => - super.copyWith((message) => updates(message as QueryTxsRes)) - as QueryTxsRes; // ignore: deprecated_member_use + super.copyWith((message) => updates(message as QueryTxsRes)) as QueryTxsRes; // ignore: deprecated_member_use $pb.BuilderInfo get info_ => _i; @$core.pragma('dart2js:noInline') static QueryTxsRes create() => QueryTxsRes._(); QueryTxsRes createEmptyInstance() => create(); static $pb.PbList createRepeated() => $pb.PbList(); @$core.pragma('dart2js:noInline') - static QueryTxsRes getDefault() => _defaultInstance ??= - $pb.GeneratedMessage.$_defaultFor(create); + static QueryTxsRes getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); static QueryTxsRes? _defaultInstance; - QueryTxsRes_Result whichResult() => - _QueryTxsRes_ResultByTag[$_whichOneof(0)]!; + QueryTxsRes_Result whichResult() => _QueryTxsRes_ResultByTag[$_whichOneof(0)]!; void clearResult() => clearField($_whichOneof(0)); @$pb.TagNumber(1) @@ -864,35 +750,25 @@ class QueryTxsRes extends $pb.GeneratedMessage { class TxsQueryStreamReq extends $pb.GeneratedMessage { static final $pb.BuilderInfo _i = $pb.BuilderInfo( - const $core.bool.fromEnvironment('protobuf.omit_message_names') - ? '' - : 'TxsQueryStreamReq', + const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'TxsQueryStreamReq', package: const $pb.PackageName( - const $core.bool.fromEnvironment('protobuf.omit_message_names') - ? '' - : 'co.topl.genus.services', + const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'co.topl.genus.services', ), createEmptyInstance: create, ) ..aOM<$4.TransactionFilter>( 1, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'filter', + const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'filter', subBuilder: $4.TransactionFilter.create, ) ..a<$core.int>( 2, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'confirmationDepth', + const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'confirmationDepth', $pb.PbFieldType.OU3, ) ..aOM( 4, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'sorting', + const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'sorting', subBuilder: TransactionSorting.create, ) ..hasRequiredFields = false; @@ -920,8 +796,7 @@ class TxsQueryStreamReq extends $pb.GeneratedMessage { $pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY, ]) => create()..mergeFromBuffer(i, r); - factory TxsQueryStreamReq.fromJson($core.String i, - [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => + factory TxsQueryStreamReq.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); @$core.Deprecated( 'Using this can add significant overhead to your binary. ' @@ -941,11 +816,10 @@ class TxsQueryStreamReq extends $pb.GeneratedMessage { @$core.pragma('dart2js:noInline') static TxsQueryStreamReq create() => TxsQueryStreamReq._(); TxsQueryStreamReq createEmptyInstance() => create(); - static $pb.PbList createRepeated() => - $pb.PbList(); + static $pb.PbList createRepeated() => $pb.PbList(); @$core.pragma('dart2js:noInline') - static TxsQueryStreamReq getDefault() => _defaultInstance ??= - $pb.GeneratedMessage.$_defaultFor(create); + static TxsQueryStreamReq getDefault() => + _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); static TxsQueryStreamReq? _defaultInstance; @$pb.TagNumber(1) @@ -989,41 +863,24 @@ class TxsQueryStreamReq extends $pb.GeneratedMessage { TransactionSorting ensureSorting() => $_ensure(2); } -enum TxsQueryStreamRes_Failure_Reason { - dataStoreConnectionError, - invalidQuery, - notSet -} +enum TxsQueryStreamRes_Failure_Reason { dataStoreConnectionError, invalidQuery, notSet } class TxsQueryStreamRes_Failure extends $pb.GeneratedMessage { - static const $core.Map<$core.int, TxsQueryStreamRes_Failure_Reason> - _TxsQueryStreamRes_Failure_ReasonByTag = { + static const $core.Map<$core.int, TxsQueryStreamRes_Failure_Reason> _TxsQueryStreamRes_Failure_ReasonByTag = { 1: TxsQueryStreamRes_Failure_Reason.dataStoreConnectionError, 2: TxsQueryStreamRes_Failure_Reason.invalidQuery, 0: TxsQueryStreamRes_Failure_Reason.notSet }; static final $pb.BuilderInfo _i = $pb.BuilderInfo( - const $core.bool.fromEnvironment('protobuf.omit_message_names') - ? '' - : 'TxsQueryStreamRes.Failure', + const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'TxsQueryStreamRes.Failure', package: const $pb.PackageName( - const $core.bool.fromEnvironment('protobuf.omit_message_names') - ? '' - : 'co.topl.genus.services', + const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'co.topl.genus.services', ), createEmptyInstance: create, ) ..oo(0, [1, 2]) - ..aOS( - 1, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'dataStoreConnectionError') - ..aOS( - 2, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'invalidQuery') + ..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'dataStoreConnectionError') + ..aOS(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'invalidQuery') ..hasRequiredFields = false; TxsQueryStreamRes_Failure._() : super(); @@ -1045,38 +902,33 @@ class TxsQueryStreamRes_Failure extends $pb.GeneratedMessage { $pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY, ]) => create()..mergeFromBuffer(i, r); - factory TxsQueryStreamRes_Failure.fromJson($core.String i, - [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => + factory TxsQueryStreamRes_Failure.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); @$core.Deprecated( 'Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' 'Will be removed in next major version', ) - TxsQueryStreamRes_Failure clone() => - TxsQueryStreamRes_Failure()..mergeFromMessage(this); + TxsQueryStreamRes_Failure clone() => TxsQueryStreamRes_Failure()..mergeFromMessage(this); @$core.Deprecated( 'Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' 'Will be removed in next major version', ) - TxsQueryStreamRes_Failure copyWith( - void Function(TxsQueryStreamRes_Failure) updates) => + TxsQueryStreamRes_Failure copyWith(void Function(TxsQueryStreamRes_Failure) updates) => super.copyWith((message) => updates(message as TxsQueryStreamRes_Failure)) as TxsQueryStreamRes_Failure; // ignore: deprecated_member_use $pb.BuilderInfo get info_ => _i; @$core.pragma('dart2js:noInline') static TxsQueryStreamRes_Failure create() => TxsQueryStreamRes_Failure._(); TxsQueryStreamRes_Failure createEmptyInstance() => create(); - static $pb.PbList createRepeated() => - $pb.PbList(); + static $pb.PbList createRepeated() => $pb.PbList(); @$core.pragma('dart2js:noInline') - static TxsQueryStreamRes_Failure getDefault() => _defaultInstance ??= - $pb.GeneratedMessage.$_defaultFor(create); + static TxsQueryStreamRes_Failure getDefault() => + _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); static TxsQueryStreamRes_Failure? _defaultInstance; - TxsQueryStreamRes_Failure_Reason whichReason() => - _TxsQueryStreamRes_Failure_ReasonByTag[$_whichOneof(0)]!; + TxsQueryStreamRes_Failure_Reason whichReason() => _TxsQueryStreamRes_Failure_ReasonByTag[$_whichOneof(0)]!; void clearReason() => clearField($_whichOneof(0)); @$pb.TagNumber(1) @@ -1107,20 +959,15 @@ class TxsQueryStreamRes_Failure extends $pb.GeneratedMessage { enum TxsQueryStreamRes_Result { tx, failure, notSet } class TxsQueryStreamRes extends $pb.GeneratedMessage { - static const $core.Map<$core.int, TxsQueryStreamRes_Result> - _TxsQueryStreamRes_ResultByTag = { + static const $core.Map<$core.int, TxsQueryStreamRes_Result> _TxsQueryStreamRes_ResultByTag = { 1: TxsQueryStreamRes_Result.tx, 2: TxsQueryStreamRes_Result.failure, 0: TxsQueryStreamRes_Result.notSet }; static final $pb.BuilderInfo _i = $pb.BuilderInfo( - const $core.bool.fromEnvironment('protobuf.omit_message_names') - ? '' - : 'TxsQueryStreamRes', + const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'TxsQueryStreamRes', package: const $pb.PackageName( - const $core.bool.fromEnvironment('protobuf.omit_message_names') - ? '' - : 'co.topl.genus.services', + const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'co.topl.genus.services', ), createEmptyInstance: create, ) @@ -1132,9 +979,7 @@ class TxsQueryStreamRes extends $pb.GeneratedMessage { ) ..aOM( 2, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'failure', + const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'failure', subBuilder: TxsQueryStreamRes_Failure.create, ) ..hasRequiredFields = false; @@ -1158,8 +1003,7 @@ class TxsQueryStreamRes extends $pb.GeneratedMessage { $pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY, ]) => create()..mergeFromBuffer(i, r); - factory TxsQueryStreamRes.fromJson($core.String i, - [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => + factory TxsQueryStreamRes.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); @$core.Deprecated( 'Using this can add significant overhead to your binary. ' @@ -1179,15 +1023,13 @@ class TxsQueryStreamRes extends $pb.GeneratedMessage { @$core.pragma('dart2js:noInline') static TxsQueryStreamRes create() => TxsQueryStreamRes._(); TxsQueryStreamRes createEmptyInstance() => create(); - static $pb.PbList createRepeated() => - $pb.PbList(); + static $pb.PbList createRepeated() => $pb.PbList(); @$core.pragma('dart2js:noInline') - static TxsQueryStreamRes getDefault() => _defaultInstance ??= - $pb.GeneratedMessage.$_defaultFor(create); + static TxsQueryStreamRes getDefault() => + _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); static TxsQueryStreamRes? _defaultInstance; - TxsQueryStreamRes_Result whichResult() => - _TxsQueryStreamRes_ResultByTag[$_whichOneof(0)]!; + TxsQueryStreamRes_Result whichResult() => _TxsQueryStreamRes_ResultByTag[$_whichOneof(0)]!; void clearResult() => clearField($_whichOneof(0)); @$pb.TagNumber(1) diff --git a/lib/genus/generated/transactions_query.pbgrpc.dart b/lib/genus/generated/transactions_query.pbgrpc.dart index 681aa6fd..42db56d0 100644 --- a/lib/genus/generated/transactions_query.pbgrpc.dart +++ b/lib/genus/generated/transactions_query.pbgrpc.dart @@ -23,8 +23,7 @@ class TransactionsQueryClient extends $grpc.Client { ($0.QueryTxsReq value) => value.writeToBuffer(), ($core.List<$core.int> value) => $0.QueryTxsRes.fromBuffer(value), ); - static final _$queryStreamed = - $grpc.ClientMethod<$0.TxsQueryStreamReq, $0.TxsQueryStreamRes>( + static final _$queryStreamed = $grpc.ClientMethod<$0.TxsQueryStreamReq, $0.TxsQueryStreamRes>( '/co.topl.genus.services.TransactionsQuery/QueryStreamed', ($0.TxsQueryStreamReq value) => value.writeToBuffer(), ($core.List<$core.int> value) => $0.TxsQueryStreamRes.fromBuffer(value), diff --git a/lib/genus/generated/transactions_query.pbjson.dart b/lib/genus/generated/transactions_query.pbjson.dart index e33f1be4..20c50f48 100644 --- a/lib/genus/generated/transactions_query.pbjson.dart +++ b/lib/genus/generated/transactions_query.pbjson.dart @@ -42,11 +42,7 @@ const TransactionSorting$json = const { '10': 'timestamp' }, ], - '3': const [ - TransactionSorting_Height$json, - TransactionSorting_Fee$json, - TransactionSorting_Timestamp$json - ], + '3': const [TransactionSorting_Height$json, TransactionSorting_Fee$json, TransactionSorting_Timestamp$json], '8': const [ const {'1': 'sort_by'}, ], @@ -83,29 +79,9 @@ final $typed_data.Uint8List transactionSortingDescriptor = $convert.base64Decode const QueryTxsReq$json = const { '1': 'QueryTxsReq', '2': const [ - const { - '1': 'filter', - '3': 1, - '4': 1, - '5': 11, - '6': '.co.topl.genus.TransactionFilter', - '10': 'filter' - }, - const { - '1': 'sorting', - '3': 2, - '4': 1, - '5': 11, - '6': '.co.topl.genus.services.TransactionSorting', - '10': 'sorting' - }, - const { - '1': 'confirmation_depth', - '3': 3, - '4': 1, - '5': 13, - '10': 'confirmationDepth' - }, + const {'1': 'filter', '3': 1, '4': 1, '5': 11, '6': '.co.topl.genus.TransactionFilter', '10': 'filter'}, + const {'1': 'sorting', '3': 2, '4': 1, '5': 11, '6': '.co.topl.genus.services.TransactionSorting', '10': 'sorting'}, + const {'1': 'confirmation_depth', '3': 3, '4': 1, '5': 13, '10': 'confirmationDepth'}, const { '1': 'paging_options', '3': 4, @@ -153,14 +129,7 @@ const QueryTxsRes$json = const { const QueryTxsRes_Success$json = const { '1': 'Success', '2': const [ - const { - '1': 'transactions', - '3': 1, - '4': 3, - '5': 11, - '6': '.co.topl.genus.Transaction', - '10': 'transactions' - }, + const {'1': 'transactions', '3': 1, '4': 3, '5': 11, '6': '.co.topl.genus.Transaction', '10': 'transactions'}, ], }; @@ -168,30 +137,9 @@ const QueryTxsRes_Success$json = const { const QueryTxsRes_Failure$json = const { '1': 'Failure', '2': const [ - const { - '1': 'data_store_connection_error', - '3': 1, - '4': 1, - '5': 9, - '9': 0, - '10': 'dataStoreConnectionError' - }, - const { - '1': 'query_timeout', - '3': 2, - '4': 1, - '5': 9, - '9': 0, - '10': 'queryTimeout' - }, - const { - '1': 'invalid_query', - '3': 3, - '4': 1, - '5': 9, - '9': 0, - '10': 'invalidQuery' - }, + const {'1': 'data_store_connection_error', '3': 1, '4': 1, '5': 9, '9': 0, '10': 'dataStoreConnectionError'}, + const {'1': 'query_timeout', '3': 2, '4': 1, '5': 9, '9': 0, '10': 'queryTimeout'}, + const {'1': 'invalid_query', '3': 3, '4': 1, '5': 9, '9': 0, '10': 'invalidQuery'}, ], '8': const [ const {'1': 'reason'}, @@ -205,29 +153,9 @@ final $typed_data.Uint8List queryTxsResDescriptor = $convert.base64Decode( const TxsQueryStreamReq$json = const { '1': 'TxsQueryStreamReq', '2': const [ - const { - '1': 'filter', - '3': 1, - '4': 1, - '5': 11, - '6': '.co.topl.genus.TransactionFilter', - '10': 'filter' - }, - const { - '1': 'sorting', - '3': 4, - '4': 1, - '5': 11, - '6': '.co.topl.genus.services.TransactionSorting', - '10': 'sorting' - }, - const { - '1': 'confirmation_depth', - '3': 2, - '4': 1, - '5': 13, - '10': 'confirmationDepth' - }, + const {'1': 'filter', '3': 1, '4': 1, '5': 11, '6': '.co.topl.genus.TransactionFilter', '10': 'filter'}, + const {'1': 'sorting', '3': 4, '4': 1, '5': 11, '6': '.co.topl.genus.services.TransactionSorting', '10': 'sorting'}, + const {'1': 'confirmation_depth', '3': 2, '4': 1, '5': 13, '10': 'confirmationDepth'}, ], }; @@ -238,15 +166,7 @@ final $typed_data.Uint8List txsQueryStreamReqDescriptor = $convert.base64Decode( const TxsQueryStreamRes$json = const { '1': 'TxsQueryStreamRes', '2': const [ - const { - '1': 'tx', - '3': 1, - '4': 1, - '5': 11, - '6': '.co.topl.genus.Transaction', - '9': 0, - '10': 'tx' - }, + const {'1': 'tx', '3': 1, '4': 1, '5': 11, '6': '.co.topl.genus.Transaction', '9': 0, '10': 'tx'}, const { '1': 'failure', '3': 2, @@ -267,22 +187,8 @@ const TxsQueryStreamRes$json = const { const TxsQueryStreamRes_Failure$json = const { '1': 'Failure', '2': const [ - const { - '1': 'data_store_connection_error', - '3': 1, - '4': 1, - '5': 9, - '9': 0, - '10': 'dataStoreConnectionError' - }, - const { - '1': 'invalid_query', - '3': 2, - '4': 1, - '5': 9, - '9': 0, - '10': 'invalidQuery' - }, + const {'1': 'data_store_connection_error', '3': 1, '4': 1, '5': 9, '9': 0, '10': 'dataStoreConnectionError'}, + const {'1': 'invalid_query', '3': 2, '4': 1, '5': 9, '9': 0, '10': 'invalidQuery'}, ], '8': const [ const {'1': 'reason'}, diff --git a/lib/genus/generated/transactions_subscription.pb.dart b/lib/genus/generated/transactions_subscription.pb.dart index aa0117f0..efa44f7f 100644 --- a/lib/genus/generated/transactions_subscription.pb.dart +++ b/lib/genus/generated/transactions_subscription.pb.dart @@ -18,36 +18,26 @@ import 'types.pb.dart' as $6; class CreateTxsSubscriptionReq extends $pb.GeneratedMessage { static final $pb.BuilderInfo _i = $pb.BuilderInfo( - const $core.bool.fromEnvironment('protobuf.omit_message_names') - ? '' - : 'CreateTxsSubscriptionReq', + const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'CreateTxsSubscriptionReq', package: const $pb.PackageName( - const $core.bool.fromEnvironment('protobuf.omit_message_names') - ? '' - : 'co.topl.genus.services', + const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'co.topl.genus.services', ), createEmptyInstance: create, ) ..aOM<$4.TransactionFilter>( 1, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'filter', + const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'filter', subBuilder: $4.TransactionFilter.create, ) ..a<$fixnum.Int64>( 2, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'startHeight', + const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'startHeight', $pb.PbFieldType.OU6, defaultOrMaker: $fixnum.Int64.ZERO, ) ..a<$core.int>( 3, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'confirmationDepth', + const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'confirmationDepth', $pb.PbFieldType.OU3, ) ..hasRequiredFields = false; @@ -75,34 +65,30 @@ class CreateTxsSubscriptionReq extends $pb.GeneratedMessage { $pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY, ]) => create()..mergeFromBuffer(i, r); - factory CreateTxsSubscriptionReq.fromJson($core.String i, - [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => + factory CreateTxsSubscriptionReq.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); @$core.Deprecated( 'Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' 'Will be removed in next major version', ) - CreateTxsSubscriptionReq clone() => - CreateTxsSubscriptionReq()..mergeFromMessage(this); + CreateTxsSubscriptionReq clone() => CreateTxsSubscriptionReq()..mergeFromMessage(this); @$core.Deprecated( 'Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' 'Will be removed in next major version', ) - CreateTxsSubscriptionReq copyWith( - void Function(CreateTxsSubscriptionReq) updates) => + CreateTxsSubscriptionReq copyWith(void Function(CreateTxsSubscriptionReq) updates) => super.copyWith((message) => updates(message as CreateTxsSubscriptionReq)) as CreateTxsSubscriptionReq; // ignore: deprecated_member_use $pb.BuilderInfo get info_ => _i; @$core.pragma('dart2js:noInline') static CreateTxsSubscriptionReq create() => CreateTxsSubscriptionReq._(); CreateTxsSubscriptionReq createEmptyInstance() => create(); - static $pb.PbList createRepeated() => - $pb.PbList(); + static $pb.PbList createRepeated() => $pb.PbList(); @$core.pragma('dart2js:noInline') - static CreateTxsSubscriptionReq getDefault() => _defaultInstance ??= - $pb.GeneratedMessage.$_defaultFor(create); + static CreateTxsSubscriptionReq getDefault() => + _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); static CreateTxsSubscriptionReq? _defaultInstance; @$pb.TagNumber(1) @@ -144,41 +130,24 @@ class CreateTxsSubscriptionReq extends $pb.GeneratedMessage { void clearConfirmationDepth() => clearField(3); } -enum TxsSubscriptionRes_Failure_Reason { - invalidRequest, - dataConnectionError, - notSet -} +enum TxsSubscriptionRes_Failure_Reason { invalidRequest, dataConnectionError, notSet } class TxsSubscriptionRes_Failure extends $pb.GeneratedMessage { - static const $core.Map<$core.int, TxsSubscriptionRes_Failure_Reason> - _TxsSubscriptionRes_Failure_ReasonByTag = { + static const $core.Map<$core.int, TxsSubscriptionRes_Failure_Reason> _TxsSubscriptionRes_Failure_ReasonByTag = { 1: TxsSubscriptionRes_Failure_Reason.invalidRequest, 2: TxsSubscriptionRes_Failure_Reason.dataConnectionError, 0: TxsSubscriptionRes_Failure_Reason.notSet }; static final $pb.BuilderInfo _i = $pb.BuilderInfo( - const $core.bool.fromEnvironment('protobuf.omit_message_names') - ? '' - : 'TxsSubscriptionRes.Failure', + const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'TxsSubscriptionRes.Failure', package: const $pb.PackageName( - const $core.bool.fromEnvironment('protobuf.omit_message_names') - ? '' - : 'co.topl.genus.services', + const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'co.topl.genus.services', ), createEmptyInstance: create, ) ..oo(0, [1, 2]) - ..aOS( - 1, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'invalidRequest') - ..aOS( - 2, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'dataConnectionError') + ..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'invalidRequest') + ..aOS(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'dataConnectionError') ..hasRequiredFields = false; TxsSubscriptionRes_Failure._() : super(); @@ -210,31 +179,26 @@ class TxsSubscriptionRes_Failure extends $pb.GeneratedMessage { 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' 'Will be removed in next major version', ) - TxsSubscriptionRes_Failure clone() => - TxsSubscriptionRes_Failure()..mergeFromMessage(this); + TxsSubscriptionRes_Failure clone() => TxsSubscriptionRes_Failure()..mergeFromMessage(this); @$core.Deprecated( 'Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' 'Will be removed in next major version', ) - TxsSubscriptionRes_Failure copyWith( - void Function(TxsSubscriptionRes_Failure) updates) => - super.copyWith( - (message) => updates(message as TxsSubscriptionRes_Failure)) + TxsSubscriptionRes_Failure copyWith(void Function(TxsSubscriptionRes_Failure) updates) => + super.copyWith((message) => updates(message as TxsSubscriptionRes_Failure)) as TxsSubscriptionRes_Failure; // ignore: deprecated_member_use $pb.BuilderInfo get info_ => _i; @$core.pragma('dart2js:noInline') static TxsSubscriptionRes_Failure create() => TxsSubscriptionRes_Failure._(); TxsSubscriptionRes_Failure createEmptyInstance() => create(); - static $pb.PbList createRepeated() => - $pb.PbList(); + static $pb.PbList createRepeated() => $pb.PbList(); @$core.pragma('dart2js:noInline') - static TxsSubscriptionRes_Failure getDefault() => _defaultInstance ??= - $pb.GeneratedMessage.$_defaultFor(create); + static TxsSubscriptionRes_Failure getDefault() => + _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); static TxsSubscriptionRes_Failure? _defaultInstance; - TxsSubscriptionRes_Failure_Reason whichReason() => - _TxsSubscriptionRes_Failure_ReasonByTag[$_whichOneof(0)]!; + TxsSubscriptionRes_Failure_Reason whichReason() => _TxsSubscriptionRes_Failure_ReasonByTag[$_whichOneof(0)]!; void clearReason() => clearField($_whichOneof(0)); @$pb.TagNumber(1) @@ -265,36 +229,27 @@ class TxsSubscriptionRes_Failure extends $pb.GeneratedMessage { enum TxsSubscriptionRes_Result { success, failure, notSet } class TxsSubscriptionRes extends $pb.GeneratedMessage { - static const $core.Map<$core.int, TxsSubscriptionRes_Result> - _TxsSubscriptionRes_ResultByTag = { + static const $core.Map<$core.int, TxsSubscriptionRes_Result> _TxsSubscriptionRes_ResultByTag = { 1: TxsSubscriptionRes_Result.success, 2: TxsSubscriptionRes_Result.failure, 0: TxsSubscriptionRes_Result.notSet }; static final $pb.BuilderInfo _i = $pb.BuilderInfo( - const $core.bool.fromEnvironment('protobuf.omit_message_names') - ? '' - : 'TxsSubscriptionRes', + const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'TxsSubscriptionRes', package: const $pb.PackageName( - const $core.bool.fromEnvironment('protobuf.omit_message_names') - ? '' - : 'co.topl.genus.services', + const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'co.topl.genus.services', ), createEmptyInstance: create, ) ..oo(0, [1, 2]) ..aOM<$6.Transaction>( 1, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'success', + const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'success', subBuilder: $6.Transaction.create, ) ..aOM( 2, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'failure', + const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'failure', subBuilder: TxsSubscriptionRes_Failure.create, ) ..hasRequiredFields = false; @@ -318,8 +273,7 @@ class TxsSubscriptionRes extends $pb.GeneratedMessage { $pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY, ]) => create()..mergeFromBuffer(i, r); - factory TxsSubscriptionRes.fromJson($core.String i, - [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => + factory TxsSubscriptionRes.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); @$core.Deprecated( 'Using this can add significant overhead to your binary. ' @@ -339,15 +293,13 @@ class TxsSubscriptionRes extends $pb.GeneratedMessage { @$core.pragma('dart2js:noInline') static TxsSubscriptionRes create() => TxsSubscriptionRes._(); TxsSubscriptionRes createEmptyInstance() => create(); - static $pb.PbList createRepeated() => - $pb.PbList(); + static $pb.PbList createRepeated() => $pb.PbList(); @$core.pragma('dart2js:noInline') - static TxsSubscriptionRes getDefault() => _defaultInstance ??= - $pb.GeneratedMessage.$_defaultFor(create); + static TxsSubscriptionRes getDefault() => + _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); static TxsSubscriptionRes? _defaultInstance; - TxsSubscriptionRes_Result whichResult() => - _TxsSubscriptionRes_ResultByTag[$_whichOneof(0)]!; + TxsSubscriptionRes_Result whichResult() => _TxsSubscriptionRes_ResultByTag[$_whichOneof(0)]!; void clearResult() => clearField($_whichOneof(0)); @$pb.TagNumber(1) diff --git a/lib/genus/generated/transactions_subscription.pbgrpc.dart b/lib/genus/generated/transactions_subscription.pbgrpc.dart index 2fab154c..78161ac2 100644 --- a/lib/genus/generated/transactions_subscription.pbgrpc.dart +++ b/lib/genus/generated/transactions_subscription.pbgrpc.dart @@ -18,8 +18,7 @@ import 'transactions_subscription.pb.dart' as $2; export 'transactions_subscription.pb.dart'; class TransactionsSubscriptionClient extends $grpc.Client { - static final _$create = - $grpc.ClientMethod<$2.CreateTxsSubscriptionReq, $2.TxsSubscriptionRes>( + static final _$create = $grpc.ClientMethod<$2.CreateTxsSubscriptionReq, $2.TxsSubscriptionRes>( '/co.topl.genus.services.TransactionsSubscription/Create', ($2.CreateTxsSubscriptionReq value) => value.writeToBuffer(), ($core.List<$core.int> value) => $2.TxsSubscriptionRes.fromBuffer(value), @@ -53,8 +52,7 @@ abstract class TransactionsSubscriptionServiceBase extends $grpc.Service { create_Pre, false, true, - ($core.List<$core.int> value) => - $2.CreateTxsSubscriptionReq.fromBuffer(value), + ($core.List<$core.int> value) => $2.CreateTxsSubscriptionReq.fromBuffer(value), ($2.TxsSubscriptionRes value) => value.writeToBuffer(), ), ); diff --git a/lib/genus/generated/transactions_subscription.pbjson.dart b/lib/genus/generated/transactions_subscription.pbjson.dart index 69ae8e26..6479fd7a 100644 --- a/lib/genus/generated/transactions_subscription.pbjson.dart +++ b/lib/genus/generated/transactions_subscription.pbjson.dart @@ -14,42 +14,20 @@ import 'dart:typed_data' as $typed_data; const CreateTxsSubscriptionReq$json = const { '1': 'CreateTxsSubscriptionReq', '2': const [ - const { - '1': 'filter', - '3': 1, - '4': 1, - '5': 11, - '6': '.co.topl.genus.TransactionFilter', - '10': 'filter' - }, + const {'1': 'filter', '3': 1, '4': 1, '5': 11, '6': '.co.topl.genus.TransactionFilter', '10': 'filter'}, const {'1': 'start_height', '3': 2, '4': 1, '5': 4, '10': 'startHeight'}, - const { - '1': 'confirmation_depth', - '3': 3, - '4': 1, - '5': 13, - '10': 'confirmationDepth' - }, + const {'1': 'confirmation_depth', '3': 3, '4': 1, '5': 13, '10': 'confirmationDepth'}, ], }; /// Descriptor for `CreateTxsSubscriptionReq`. Decode as a `google.protobuf.DescriptorProto`. -final $typed_data.Uint8List createTxsSubscriptionReqDescriptor = - $convert.base64Decode( - 'ChhDcmVhdGVUeHNTdWJzY3JpcHRpb25SZXESOAoGZmlsdGVyGAEgASgLMiAuY28udG9wbC5nZW51cy5UcmFuc2FjdGlvbkZpbHRlclIGZmlsdGVyEiEKDHN0YXJ0X2hlaWdodBgCIAEoBFILc3RhcnRIZWlnaHQSLQoSY29uZmlybWF0aW9uX2RlcHRoGAMgASgNUhFjb25maXJtYXRpb25EZXB0aA=='); +final $typed_data.Uint8List createTxsSubscriptionReqDescriptor = $convert.base64Decode( + 'ChhDcmVhdGVUeHNTdWJzY3JpcHRpb25SZXESOAoGZmlsdGVyGAEgASgLMiAuY28udG9wbC5nZW51cy5UcmFuc2FjdGlvbkZpbHRlclIGZmlsdGVyEiEKDHN0YXJ0X2hlaWdodBgCIAEoBFILc3RhcnRIZWlnaHQSLQoSY29uZmlybWF0aW9uX2RlcHRoGAMgASgNUhFjb25maXJtYXRpb25EZXB0aA=='); @$core.Deprecated('Use txsSubscriptionResDescriptor instead') const TxsSubscriptionRes$json = const { '1': 'TxsSubscriptionRes', '2': const [ - const { - '1': 'success', - '3': 1, - '4': 1, - '5': 11, - '6': '.co.topl.genus.Transaction', - '9': 0, - '10': 'success' - }, + const {'1': 'success', '3': 1, '4': 1, '5': 11, '6': '.co.topl.genus.Transaction', '9': 0, '10': 'success'}, const { '1': 'failure', '3': 2, @@ -70,22 +48,8 @@ const TxsSubscriptionRes$json = const { const TxsSubscriptionRes_Failure$json = const { '1': 'Failure', '2': const [ - const { - '1': 'invalid_request', - '3': 1, - '4': 1, - '5': 9, - '9': 0, - '10': 'invalidRequest' - }, - const { - '1': 'data_connection_error', - '3': 2, - '4': 1, - '5': 9, - '9': 0, - '10': 'dataConnectionError' - }, + const {'1': 'invalid_request', '3': 1, '4': 1, '5': 9, '9': 0, '10': 'invalidRequest'}, + const {'1': 'data_connection_error', '3': 2, '4': 1, '5': 9, '9': 0, '10': 'dataConnectionError'}, ], '8': const [ const {'1': 'reason'}, diff --git a/lib/genus/generated/types.pb.dart b/lib/genus/generated/types.pb.dart index 2e350a1f..cd347c14 100644 --- a/lib/genus/generated/types.pb.dart +++ b/lib/genus/generated/types.pb.dart @@ -14,25 +14,13 @@ import 'package:protobuf/protobuf.dart' as $pb; class Attestation extends $pb.GeneratedMessage { static final $pb.BuilderInfo _i = $pb.BuilderInfo( - const $core.bool.fromEnvironment('protobuf.omit_message_names') - ? '' - : 'Attestation', - package: const $pb.PackageName( - const $core.bool.fromEnvironment('protobuf.omit_message_names') - ? '' - : 'co.topl.genus'), + const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'Attestation', + package: + const $pb.PackageName(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'co.topl.genus'), createEmptyInstance: create, ) - ..aOS( - 1, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'publicKey') - ..aOS( - 2, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'signature') + ..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'publicKey') + ..aOS(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'signature') ..hasRequiredFields = false; Attestation._() : super(); @@ -49,11 +37,9 @@ class Attestation extends $pb.GeneratedMessage { } return _result; } - factory Attestation.fromBuffer($core.List<$core.int> i, - [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => + factory Attestation.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); - factory Attestation.fromJson($core.String i, - [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => + factory Attestation.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); @$core.Deprecated( 'Using this can add significant overhead to your binary. ' @@ -67,16 +53,14 @@ class Attestation extends $pb.GeneratedMessage { 'Will be removed in next major version', ) Attestation copyWith(void Function(Attestation) updates) => - super.copyWith((message) => updates(message as Attestation)) - as Attestation; // ignore: deprecated_member_use + super.copyWith((message) => updates(message as Attestation)) as Attestation; // ignore: deprecated_member_use $pb.BuilderInfo get info_ => _i; @$core.pragma('dart2js:noInline') static Attestation create() => Attestation._(); Attestation createEmptyInstance() => create(); static $pb.PbList createRepeated() => $pb.PbList(); @$core.pragma('dart2js:noInline') - static Attestation getDefault() => _defaultInstance ??= - $pb.GeneratedMessage.$_defaultFor(create); + static Attestation getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); static Attestation? _defaultInstance; @$pb.TagNumber(1) @@ -106,20 +90,12 @@ class Attestation extends $pb.GeneratedMessage { class SimpleValue extends $pb.GeneratedMessage { static final $pb.BuilderInfo _i = $pb.BuilderInfo( - const $core.bool.fromEnvironment('protobuf.omit_message_names') - ? '' - : 'SimpleValue', - package: const $pb.PackageName( - const $core.bool.fromEnvironment('protobuf.omit_message_names') - ? '' - : 'co.topl.genus'), + const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'SimpleValue', + package: + const $pb.PackageName(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'co.topl.genus'), createEmptyInstance: create, ) - ..aOS( - 1, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'quantity') + ..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'quantity') ..hasRequiredFields = false; SimpleValue._() : super(); @@ -132,11 +108,9 @@ class SimpleValue extends $pb.GeneratedMessage { } return _result; } - factory SimpleValue.fromBuffer($core.List<$core.int> i, - [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => + factory SimpleValue.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); - factory SimpleValue.fromJson($core.String i, - [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => + factory SimpleValue.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); @$core.Deprecated( 'Using this can add significant overhead to your binary. ' @@ -150,16 +124,14 @@ class SimpleValue extends $pb.GeneratedMessage { 'Will be removed in next major version', ) SimpleValue copyWith(void Function(SimpleValue) updates) => - super.copyWith((message) => updates(message as SimpleValue)) - as SimpleValue; // ignore: deprecated_member_use + super.copyWith((message) => updates(message as SimpleValue)) as SimpleValue; // ignore: deprecated_member_use $pb.BuilderInfo get info_ => _i; @$core.pragma('dart2js:noInline') static SimpleValue create() => SimpleValue._(); SimpleValue createEmptyInstance() => create(); static $pb.PbList createRepeated() => $pb.PbList(); @$core.pragma('dart2js:noInline') - static SimpleValue getDefault() => _defaultInstance ??= - $pb.GeneratedMessage.$_defaultFor(create); + static SimpleValue getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); static SimpleValue? _defaultInstance; @$pb.TagNumber(1) @@ -177,35 +149,15 @@ class SimpleValue extends $pb.GeneratedMessage { class AssetValue extends $pb.GeneratedMessage { static final $pb.BuilderInfo _i = $pb.BuilderInfo( - const $core.bool.fromEnvironment('protobuf.omit_message_names') - ? '' - : 'AssetValue', - package: const $pb.PackageName( - const $core.bool.fromEnvironment('protobuf.omit_message_names') - ? '' - : 'co.topl.genus'), + const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'AssetValue', + package: + const $pb.PackageName(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'co.topl.genus'), createEmptyInstance: create, ) - ..aOS( - 1, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'code') - ..aOS( - 2, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'quantity') - ..aOS( - 3, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'securityRoot') - ..aOS( - 4, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'metadata') + ..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'code') + ..aOS(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'quantity') + ..aOS(3, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'securityRoot') + ..aOS(4, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'metadata') ..hasRequiredFields = false; AssetValue._() : super(); @@ -230,11 +182,9 @@ class AssetValue extends $pb.GeneratedMessage { } return _result; } - factory AssetValue.fromBuffer($core.List<$core.int> i, - [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => + factory AssetValue.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); - factory AssetValue.fromJson($core.String i, - [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => + factory AssetValue.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); @$core.Deprecated( 'Using this can add significant overhead to your binary. ' @@ -248,16 +198,14 @@ class AssetValue extends $pb.GeneratedMessage { 'Will be removed in next major version', ) AssetValue copyWith(void Function(AssetValue) updates) => - super.copyWith((message) => updates(message as AssetValue)) - as AssetValue; // ignore: deprecated_member_use + super.copyWith((message) => updates(message as AssetValue)) as AssetValue; // ignore: deprecated_member_use $pb.BuilderInfo get info_ => _i; @$core.pragma('dart2js:noInline') static AssetValue create() => AssetValue._(); AssetValue createEmptyInstance() => create(); static $pb.PbList createRepeated() => $pb.PbList(); @$core.pragma('dart2js:noInline') - static AssetValue getDefault() => _defaultInstance ??= - $pb.GeneratedMessage.$_defaultFor(create); + static AssetValue getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); static AssetValue? _defaultInstance; @$pb.TagNumber(1) @@ -318,28 +266,20 @@ class TokenValue extends $pb.GeneratedMessage { 0: TokenValue_Value.notSet }; static final $pb.BuilderInfo _i = $pb.BuilderInfo( - const $core.bool.fromEnvironment('protobuf.omit_message_names') - ? '' - : 'TokenValue', - package: const $pb.PackageName( - const $core.bool.fromEnvironment('protobuf.omit_message_names') - ? '' - : 'co.topl.genus'), + const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'TokenValue', + package: + const $pb.PackageName(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'co.topl.genus'), createEmptyInstance: create, ) ..oo(0, [1, 2]) ..aOM( 1, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'simple', + const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'simple', subBuilder: SimpleValue.create, ) ..aOM( 2, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'asset', + const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'asset', subBuilder: AssetValue.create, ) ..hasRequiredFields = false; @@ -358,11 +298,9 @@ class TokenValue extends $pb.GeneratedMessage { } return _result; } - factory TokenValue.fromBuffer($core.List<$core.int> i, - [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => + factory TokenValue.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); - factory TokenValue.fromJson($core.String i, - [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => + factory TokenValue.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); @$core.Deprecated( 'Using this can add significant overhead to your binary. ' @@ -376,16 +314,14 @@ class TokenValue extends $pb.GeneratedMessage { 'Will be removed in next major version', ) TokenValue copyWith(void Function(TokenValue) updates) => - super.copyWith((message) => updates(message as TokenValue)) - as TokenValue; // ignore: deprecated_member_use + super.copyWith((message) => updates(message as TokenValue)) as TokenValue; // ignore: deprecated_member_use $pb.BuilderInfo get info_ => _i; @$core.pragma('dart2js:noInline') static TokenValue create() => TokenValue._(); TokenValue createEmptyInstance() => create(); static $pb.PbList createRepeated() => $pb.PbList(); @$core.pragma('dart2js:noInline') - static TokenValue getDefault() => _defaultInstance ??= - $pb.GeneratedMessage.$_defaultFor(create); + static TokenValue getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); static TokenValue? _defaultInstance; TokenValue_Value whichValue() => _TokenValue_ValueByTag[$_whichOneof(0)]!; @@ -422,40 +358,18 @@ class TokenValue extends $pb.GeneratedMessage { class TokenBox extends $pb.GeneratedMessage { static final $pb.BuilderInfo _i = $pb.BuilderInfo( - const $core.bool.fromEnvironment('protobuf.omit_message_names') - ? '' - : 'TokenBox', - package: const $pb.PackageName( - const $core.bool.fromEnvironment('protobuf.omit_message_names') - ? '' - : 'co.topl.genus'), + const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'TokenBox', + package: + const $pb.PackageName(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'co.topl.genus'), createEmptyInstance: create, ) - ..aOS( - 1, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'boxType') - ..aOS( - 2, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'id') - ..aOS( - 3, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'nonce') - ..aOS( - 4, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'evidence') + ..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'boxType') + ..aOS(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'id') + ..aOS(3, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'nonce') + ..aOS(4, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'evidence') ..aOM( 5, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'value', + const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'value', subBuilder: TokenValue.create, ) ..hasRequiredFields = false; @@ -486,8 +400,7 @@ class TokenBox extends $pb.GeneratedMessage { } return _result; } - factory TokenBox.fromBuffer($core.List<$core.int> i, - [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => + factory TokenBox.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); factory TokenBox.fromJson( $core.String i, [ @@ -506,16 +419,14 @@ class TokenBox extends $pb.GeneratedMessage { 'Will be removed in next major version', ) TokenBox copyWith(void Function(TokenBox) updates) => - super.copyWith((message) => updates(message as TokenBox)) - as TokenBox; // ignore: deprecated_member_use + super.copyWith((message) => updates(message as TokenBox)) as TokenBox; // ignore: deprecated_member_use $pb.BuilderInfo get info_ => _i; @$core.pragma('dart2js:noInline') static TokenBox create() => TokenBox._(); TokenBox createEmptyInstance() => create(); static $pb.PbList createRepeated() => $pb.PbList(); @$core.pragma('dart2js:noInline') - static TokenBox getDefault() => - _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); + static TokenBox getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); static TokenBox? _defaultInstance; @$pb.TagNumber(1) @@ -583,25 +494,13 @@ class TokenBox extends $pb.GeneratedMessage { class InputBox extends $pb.GeneratedMessage { static final $pb.BuilderInfo _i = $pb.BuilderInfo( - const $core.bool.fromEnvironment('protobuf.omit_message_names') - ? '' - : 'InputBox', - package: const $pb.PackageName( - const $core.bool.fromEnvironment('protobuf.omit_message_names') - ? '' - : 'co.topl.genus'), + const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'InputBox', + package: + const $pb.PackageName(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'co.topl.genus'), createEmptyInstance: create, ) - ..aOS( - 1, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'address') - ..aOS( - 2, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'nonce') + ..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'address') + ..aOS(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'nonce') ..hasRequiredFields = false; InputBox._() : super(); @@ -618,11 +517,9 @@ class InputBox extends $pb.GeneratedMessage { } return _result; } - factory InputBox.fromBuffer($core.List<$core.int> i, - [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => + factory InputBox.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); - factory InputBox.fromJson($core.String i, - [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => + factory InputBox.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); @$core.Deprecated( 'Using this can add significant overhead to your binary. ' @@ -636,16 +533,14 @@ class InputBox extends $pb.GeneratedMessage { 'Will be removed in next major version', ) InputBox copyWith(void Function(InputBox) updates) => - super.copyWith((message) => updates(message as InputBox)) - as InputBox; // ignore: deprecated_member_use + super.copyWith((message) => updates(message as InputBox)) as InputBox; // ignore: deprecated_member_use $pb.BuilderInfo get info_ => _i; @$core.pragma('dart2js:noInline') static InputBox create() => InputBox._(); InputBox createEmptyInstance() => create(); static $pb.PbList createRepeated() => $pb.PbList(); @$core.pragma('dart2js:noInline') - static InputBox getDefault() => - _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); + static InputBox getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); static InputBox? _defaultInstance; @$pb.TagNumber(1) @@ -675,25 +570,15 @@ class InputBox extends $pb.GeneratedMessage { class OutputBox extends $pb.GeneratedMessage { static final $pb.BuilderInfo _i = $pb.BuilderInfo( - const $core.bool.fromEnvironment('protobuf.omit_message_names') - ? '' - : 'OutputBox', - package: const $pb.PackageName( - const $core.bool.fromEnvironment('protobuf.omit_message_names') - ? '' - : 'co.topl.genus'), + const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'OutputBox', + package: + const $pb.PackageName(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'co.topl.genus'), createEmptyInstance: create, ) - ..aOS( - 1, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'address') + ..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'address') ..aOM( 2, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'value', + const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'value', subBuilder: TokenValue.create, ) ..hasRequiredFields = false; @@ -712,11 +597,9 @@ class OutputBox extends $pb.GeneratedMessage { } return _result; } - factory OutputBox.fromBuffer($core.List<$core.int> i, - [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => + factory OutputBox.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); - factory OutputBox.fromJson($core.String i, - [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => + factory OutputBox.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); @$core.Deprecated( 'Using this can add significant overhead to your binary. ' @@ -730,16 +613,14 @@ class OutputBox extends $pb.GeneratedMessage { 'Will be removed in next major version', ) OutputBox copyWith(void Function(OutputBox) updates) => - super.copyWith((message) => updates(message as OutputBox)) - as OutputBox; // ignore: deprecated_member_use + super.copyWith((message) => updates(message as OutputBox)) as OutputBox; // ignore: deprecated_member_use $pb.BuilderInfo get info_ => _i; @$core.pragma('dart2js:noInline') static OutputBox create() => OutputBox._(); OutputBox createEmptyInstance() => create(); static $pb.PbList createRepeated() => $pb.PbList(); @$core.pragma('dart2js:noInline') - static OutputBox getDefault() => - _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); + static OutputBox getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); static OutputBox? _defaultInstance; @$pb.TagNumber(1) @@ -771,20 +652,14 @@ class OutputBox extends $pb.GeneratedMessage { class BlockHeight extends $pb.GeneratedMessage { static final $pb.BuilderInfo _i = $pb.BuilderInfo( - const $core.bool.fromEnvironment('protobuf.omit_message_names') - ? '' - : 'BlockHeight', - package: const $pb.PackageName( - const $core.bool.fromEnvironment('protobuf.omit_message_names') - ? '' - : 'co.topl.genus'), + const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'BlockHeight', + package: + const $pb.PackageName(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'co.topl.genus'), createEmptyInstance: create, ) ..a<$fixnum.Int64>( 1, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'value', + const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'value', $pb.PbFieldType.OU6, defaultOrMaker: $fixnum.Int64.ZERO, ) @@ -800,11 +675,9 @@ class BlockHeight extends $pb.GeneratedMessage { } return _result; } - factory BlockHeight.fromBuffer($core.List<$core.int> i, - [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => + factory BlockHeight.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); - factory BlockHeight.fromJson($core.String i, - [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => + factory BlockHeight.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); @$core.Deprecated( 'Using this can add significant overhead to your binary. ' @@ -818,16 +691,14 @@ class BlockHeight extends $pb.GeneratedMessage { 'Will be removed in next major version', ) BlockHeight copyWith(void Function(BlockHeight) updates) => - super.copyWith((message) => updates(message as BlockHeight)) - as BlockHeight; // ignore: deprecated_member_use + super.copyWith((message) => updates(message as BlockHeight)) as BlockHeight; // ignore: deprecated_member_use $pb.BuilderInfo get info_ => _i; @$core.pragma('dart2js:noInline') static BlockHeight create() => BlockHeight._(); BlockHeight createEmptyInstance() => create(); static $pb.PbList createRepeated() => $pb.PbList(); @$core.pragma('dart2js:noInline') - static BlockHeight getDefault() => _defaultInstance ??= - $pb.GeneratedMessage.$_defaultFor(create); + static BlockHeight getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); static BlockHeight? _defaultInstance; @$pb.TagNumber(1) @@ -845,97 +716,47 @@ class BlockHeight extends $pb.GeneratedMessage { class Transaction extends $pb.GeneratedMessage { static final $pb.BuilderInfo _i = $pb.BuilderInfo( - const $core.bool.fromEnvironment('protobuf.omit_message_names') - ? '' - : 'Transaction', - package: const $pb.PackageName( - const $core.bool.fromEnvironment('protobuf.omit_message_names') - ? '' - : 'co.topl.genus'), + const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'Transaction', + package: + const $pb.PackageName(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'co.topl.genus'), createEmptyInstance: create, ) - ..aOS( - 1, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'txType') - ..aOS( - 2, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'timestamp') + ..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'txType') + ..aOS(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'timestamp') ..pc( 3, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'signatures', + const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'signatures', $pb.PbFieldType.PM, subBuilder: Attestation.create, ) ..pc( 4, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'newBoxes', + const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'newBoxes', $pb.PbFieldType.PM, subBuilder: TokenBox.create, ) - ..aOS( - 5, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'data') + ..aOS(5, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'data') ..pc( 6, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'inputs', + const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'inputs', $pb.PbFieldType.PM, subBuilder: InputBox.create, ) - ..aOB( - 7, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'minting') - ..aOS( - 8, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'txId') - ..pPS( - 9, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'boxesToRemove') - ..aOS( - 10, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'fee') + ..aOB(7, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'minting') + ..aOS(8, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'txId') + ..pPS(9, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'boxesToRemove') + ..aOS(10, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'fee') ..pc( 11, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'outputs', + const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'outputs', $pb.PbFieldType.PM, subBuilder: OutputBox.create, ) - ..aOS( - 12, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'propositionType') - ..aOS( - 13, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'blockId') + ..aOS(12, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'propositionType') + ..aOS(13, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'blockId') ..a<$fixnum.Int64>( 14, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'blockHeight', + const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'blockHeight', $pb.PbFieldType.OU6, defaultOrMaker: $fixnum.Int64.ZERO, ) @@ -1003,11 +824,9 @@ class Transaction extends $pb.GeneratedMessage { } return _result; } - factory Transaction.fromBuffer($core.List<$core.int> i, - [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => + factory Transaction.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); - factory Transaction.fromJson($core.String i, - [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => + factory Transaction.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); @$core.Deprecated( 'Using this can add significant overhead to your binary. ' @@ -1021,16 +840,14 @@ class Transaction extends $pb.GeneratedMessage { 'Will be removed in next major version', ) Transaction copyWith(void Function(Transaction) updates) => - super.copyWith((message) => updates(message as Transaction)) - as Transaction; // ignore: deprecated_member_use + super.copyWith((message) => updates(message as Transaction)) as Transaction; // ignore: deprecated_member_use $pb.BuilderInfo get info_ => _i; @$core.pragma('dart2js:noInline') static Transaction create() => Transaction._(); Transaction createEmptyInstance() => create(); static $pb.PbList createRepeated() => $pb.PbList(); @$core.pragma('dart2js:noInline') - static Transaction getDefault() => _defaultInstance ??= - $pb.GeneratedMessage.$_defaultFor(create); + static Transaction getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); static Transaction? _defaultInstance; @$pb.TagNumber(1) @@ -1159,82 +976,38 @@ class Transaction extends $pb.GeneratedMessage { class Block extends $pb.GeneratedMessage { static final $pb.BuilderInfo _i = $pb.BuilderInfo( - const $core.bool.fromEnvironment('protobuf.omit_message_names') - ? '' - : 'Block', - package: const $pb.PackageName( - const $core.bool.fromEnvironment('protobuf.omit_message_names') - ? '' - : 'co.topl.genus'), + const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'Block', + package: + const $pb.PackageName(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'co.topl.genus'), createEmptyInstance: create, ) - ..aOS( - 1, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'id') - ..aOS( - 2, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'parentId') - ..aOS( - 3, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'timestamp') + ..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'id') + ..aOS(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'parentId') + ..aOS(3, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'timestamp') ..aOM( 4, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'generator', + const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'generator', subBuilder: TokenBox.create, ) - ..aOS( - 5, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'publicKey') - ..aOS( - 6, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'signature') + ..aOS(5, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'publicKey') + ..aOS(6, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'signature') ..a<$fixnum.Int64>( 7, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'height', + const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'height', $pb.PbFieldType.OU6, defaultOrMaker: $fixnum.Int64.ZERO, ) - ..aOS( - 8, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'difficulty') - ..aOS( - 9, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'txRoot') - ..aOS( - 10, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'bloomFilter') + ..aOS(8, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'difficulty') + ..aOS(9, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'txRoot') + ..aOS(10, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'bloomFilter') ..a<$core.int>( 11, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'version', + const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'version', $pb.PbFieldType.OU3, ) ..a<$core.int>( 12, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'numTransactions', + const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'numTransactions', $pb.PbFieldType.OU3, ) ..hasRequiredFields = false; @@ -1293,11 +1066,9 @@ class Block extends $pb.GeneratedMessage { } return _result; } - factory Block.fromBuffer($core.List<$core.int> i, - [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => + factory Block.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); - factory Block.fromJson($core.String i, - [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => + factory Block.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); @$core.Deprecated( 'Using this can add significant overhead to your binary. ' @@ -1311,16 +1082,14 @@ class Block extends $pb.GeneratedMessage { 'Will be removed in next major version', ) Block copyWith(void Function(Block) updates) => - super.copyWith((message) => updates(message as Block)) - as Block; // ignore: deprecated_member_use + super.copyWith((message) => updates(message as Block)) as Block; // ignore: deprecated_member_use $pb.BuilderInfo get info_ => _i; @$core.pragma('dart2js:noInline') static Block create() => Block._(); Block createEmptyInstance() => create(); static $pb.PbList createRepeated() => $pb.PbList(); @$core.pragma('dart2js:noInline') - static Block getDefault() => - _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); + static Block getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); static Block? _defaultInstance; @$pb.TagNumber(1) diff --git a/lib/genus/generated/types.pbjson.dart b/lib/genus/generated/types.pbjson.dart index a38926d3..f25c6699 100644 --- a/lib/genus/generated/types.pbjson.dart +++ b/lib/genus/generated/types.pbjson.dart @@ -31,8 +31,8 @@ const SimpleValue$json = const { }; /// Descriptor for `SimpleValue`. Decode as a `google.protobuf.DescriptorProto`. -final $typed_data.Uint8List simpleValueDescriptor = $convert - .base64Decode('CgtTaW1wbGVWYWx1ZRIaCghxdWFudGl0eRgBIAEoCVIIcXVhbnRpdHk='); +final $typed_data.Uint8List simpleValueDescriptor = + $convert.base64Decode('CgtTaW1wbGVWYWx1ZRIaCghxdWFudGl0eRgBIAEoCVIIcXVhbnRpdHk='); @$core.Deprecated('Use assetValueDescriptor instead') const AssetValue$json = const { '1': 'AssetValue', @@ -51,24 +51,8 @@ final $typed_data.Uint8List assetValueDescriptor = $convert.base64Decode( const TokenValue$json = const { '1': 'TokenValue', '2': const [ - const { - '1': 'simple', - '3': 1, - '4': 1, - '5': 11, - '6': '.co.topl.genus.SimpleValue', - '9': 0, - '10': 'simple' - }, - const { - '1': 'asset', - '3': 2, - '4': 1, - '5': 11, - '6': '.co.topl.genus.AssetValue', - '9': 0, - '10': 'asset' - }, + const {'1': 'simple', '3': 1, '4': 1, '5': 11, '6': '.co.topl.genus.SimpleValue', '9': 0, '10': 'simple'}, + const {'1': 'asset', '3': 2, '4': 1, '5': 11, '6': '.co.topl.genus.AssetValue', '9': 0, '10': 'asset'}, ], '8': const [ const {'1': 'value'}, @@ -86,14 +70,7 @@ const TokenBox$json = const { const {'1': 'id', '3': 2, '4': 1, '5': 9, '10': 'id'}, const {'1': 'nonce', '3': 3, '4': 1, '5': 9, '10': 'nonce'}, const {'1': 'evidence', '3': 4, '4': 1, '5': 9, '10': 'evidence'}, - const { - '1': 'value', - '3': 5, - '4': 1, - '5': 11, - '6': '.co.topl.genus.TokenValue', - '10': 'value' - }, + const {'1': 'value', '3': 5, '4': 1, '5': 11, '6': '.co.topl.genus.TokenValue', '10': 'value'}, ], }; @@ -110,21 +87,14 @@ const InputBox$json = const { }; /// Descriptor for `InputBox`. Decode as a `google.protobuf.DescriptorProto`. -final $typed_data.Uint8List inputBoxDescriptor = $convert.base64Decode( - 'CghJbnB1dEJveBIYCgdhZGRyZXNzGAEgASgJUgdhZGRyZXNzEhQKBW5vbmNlGAIgASgJUgVub25jZQ=='); +final $typed_data.Uint8List inputBoxDescriptor = + $convert.base64Decode('CghJbnB1dEJveBIYCgdhZGRyZXNzGAEgASgJUgdhZGRyZXNzEhQKBW5vbmNlGAIgASgJUgVub25jZQ=='); @$core.Deprecated('Use outputBoxDescriptor instead') const OutputBox$json = const { '1': 'OutputBox', '2': const [ const {'1': 'address', '3': 1, '4': 1, '5': 9, '10': 'address'}, - const { - '1': 'value', - '3': 2, - '4': 1, - '5': 11, - '6': '.co.topl.genus.TokenValue', - '10': 'value' - }, + const {'1': 'value', '3': 2, '4': 1, '5': 11, '6': '.co.topl.genus.TokenValue', '10': 'value'}, ], }; @@ -148,56 +118,16 @@ const Transaction$json = const { '2': const [ const {'1': 'tx_type', '3': 1, '4': 1, '5': 9, '10': 'txType'}, const {'1': 'timestamp', '3': 2, '4': 1, '5': 9, '10': 'timestamp'}, - const { - '1': 'signatures', - '3': 3, - '4': 3, - '5': 11, - '6': '.co.topl.genus.Attestation', - '10': 'signatures' - }, - const { - '1': 'new_boxes', - '3': 4, - '4': 3, - '5': 11, - '6': '.co.topl.genus.TokenBox', - '10': 'newBoxes' - }, + const {'1': 'signatures', '3': 3, '4': 3, '5': 11, '6': '.co.topl.genus.Attestation', '10': 'signatures'}, + const {'1': 'new_boxes', '3': 4, '4': 3, '5': 11, '6': '.co.topl.genus.TokenBox', '10': 'newBoxes'}, const {'1': 'data', '3': 5, '4': 1, '5': 9, '10': 'data'}, - const { - '1': 'inputs', - '3': 6, - '4': 3, - '5': 11, - '6': '.co.topl.genus.InputBox', - '10': 'inputs' - }, + const {'1': 'inputs', '3': 6, '4': 3, '5': 11, '6': '.co.topl.genus.InputBox', '10': 'inputs'}, const {'1': 'minting', '3': 7, '4': 1, '5': 8, '10': 'minting'}, const {'1': 'tx_id', '3': 8, '4': 1, '5': 9, '10': 'txId'}, - const { - '1': 'boxes_to_remove', - '3': 9, - '4': 3, - '5': 9, - '10': 'boxesToRemove' - }, + const {'1': 'boxes_to_remove', '3': 9, '4': 3, '5': 9, '10': 'boxesToRemove'}, const {'1': 'fee', '3': 10, '4': 1, '5': 9, '10': 'fee'}, - const { - '1': 'outputs', - '3': 11, - '4': 3, - '5': 11, - '6': '.co.topl.genus.OutputBox', - '10': 'outputs' - }, - const { - '1': 'proposition_type', - '3': 12, - '4': 1, - '5': 9, - '10': 'propositionType' - }, + const {'1': 'outputs', '3': 11, '4': 3, '5': 11, '6': '.co.topl.genus.OutputBox', '10': 'outputs'}, + const {'1': 'proposition_type', '3': 12, '4': 1, '5': 9, '10': 'propositionType'}, const {'1': 'block_id', '3': 13, '4': 1, '5': 9, '10': 'blockId'}, const {'1': 'block_height', '3': 14, '4': 1, '5': 4, '10': 'blockHeight'}, ], @@ -213,14 +143,7 @@ const Block$json = const { const {'1': 'id', '3': 1, '4': 1, '5': 9, '10': 'id'}, const {'1': 'parent_id', '3': 2, '4': 1, '5': 9, '10': 'parentId'}, const {'1': 'timestamp', '3': 3, '4': 1, '5': 9, '10': 'timestamp'}, - const { - '1': 'generator', - '3': 4, - '4': 1, - '5': 11, - '6': '.co.topl.genus.TokenBox', - '10': 'generator' - }, + const {'1': 'generator', '3': 4, '4': 1, '5': 11, '6': '.co.topl.genus.TokenBox', '10': 'generator'}, const {'1': 'public_key', '3': 5, '4': 1, '5': 9, '10': 'publicKey'}, const {'1': 'signature', '3': 6, '4': 1, '5': 9, '10': 'signature'}, const {'1': 'height', '3': 7, '4': 1, '5': 4, '10': 'height'}, @@ -228,13 +151,7 @@ const Block$json = const { const {'1': 'tx_root', '3': 9, '4': 1, '5': 9, '10': 'txRoot'}, const {'1': 'bloom_filter', '3': 10, '4': 1, '5': 9, '10': 'bloomFilter'}, const {'1': 'version', '3': 11, '4': 1, '5': 13, '10': 'version'}, - const { - '1': 'num_transactions', - '3': 12, - '4': 1, - '5': 13, - '10': 'numTransactions' - }, + const {'1': 'num_transactions', '3': 12, '4': 1, '5': 13, '10': 'numTransactions'}, ], }; diff --git a/lib/helpers/helper_functions.dart b/lib/helpers/helper_functions.dart index 339097eb..e2fe1704 100644 --- a/lib/helpers/helper_functions.dart +++ b/lib/helpers/helper_functions.dart @@ -28,23 +28,19 @@ Future> fetchTransactionHistory( String filterSelectedItem, List filteredTransactions, ) async { - final List response = - await transactionHistoryViewmodel.getTransactions(pageNum: currentPage); + final List response = await transactionHistoryViewmodel.getTransactions(); // Filters transactions by sent or received if (filterSelectedItem != 'Transaction types') { final List transactions = response; for (var transaction in transactions) { - final String transactionReceiverAddress = - transaction.to.first.toJson()[0].toString(); + final String transactionReceiverAddress = transaction.to.first.toJson()[0].toString(); final Sender transactionSenderAddress = transaction.from![0]; final myRibnAddress = toplAddress.toBase58(); final wasMinted = transaction.minting == true; if (filterSelectedItem == 'All') { filteredTransactions.add(transaction); } - if (filterSelectedItem == 'Received' && - transactionReceiverAddress == myRibnAddress && - !wasMinted) { + if (filterSelectedItem == 'Received' && transactionReceiverAddress == myRibnAddress && !wasMinted) { filteredTransactions.add(transaction); } if (filterSelectedItem == 'Sent' && @@ -58,12 +54,3 @@ Future> fetchTransactionHistory( } return response; } - -extension Unique on List { - List unique([Id Function(E element)? id, bool inplace = true]) { - final ids = {}; - final list = inplace ? this : List.from(this); - list.retainWhere((x) => ids.add(id != null ? id(x) : x as Id)); - return list; - } -} diff --git a/lib/js_workers/generate_keystore_worker.dart b/lib/js_workers/generate_keystore_worker.dart index d2e4008f..c7597326 100644 --- a/lib/js_workers/generate_keystore_worker.dart +++ b/lib/js_workers/generate_keystore_worker.dart @@ -25,8 +25,7 @@ external DedicatedWorkerGlobalScope get self; void main() { self.onMessage.listen((e) { final Map params = jsonDecode(e.data); - final Map results = - const OnboardingRespository().generateKeyStore({ + final Map results = const OnboardingRespository().generateKeyStore({ 'mnemonic': params['mnemonic'], 'password': params['password'], }); diff --git a/lib/js_workers/login_worker.dart b/lib/js_workers/login_worker.dart index 5815b1db..255b1216 100644 --- a/lib/js_workers/login_worker.dart +++ b/lib/js_workers/login_worker.dart @@ -26,8 +26,7 @@ external DedicatedWorkerGlobalScope get self; void main() { self.onMessage.listen((e) { final Map params = jsonDecode(e.data); - final Uint8List toplExtendedPrvKeyUint8List = - const LoginRepository().decryptKeyStore( + final Uint8List toplExtendedPrvKeyUint8List = const LoginRepository().decryptKeyStore( { 'keyStoreJson': params['keyStoreJson'] as String, 'password': params['password'] as String, diff --git a/lib/main.dart b/lib/main.dart index f671f297..58129519 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -5,11 +5,13 @@ import 'dart:convert'; // Flutter imports: import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; + // Package imports: import 'package:flutter_portal/flutter_portal.dart'; import 'package:flutter_redux/flutter_redux.dart'; -import 'package:redux/redux.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:redux/redux.dart'; + // Project imports: import 'package:ribn/actions/internal_message_actions.dart'; import 'package:ribn/constants/keys.dart'; @@ -25,13 +27,13 @@ import 'package:ribn/presentation/external_signing_page.dart'; import 'package:ribn/presentation/home/home_page.dart'; import 'package:ribn/presentation/login/login_page.dart'; import 'package:ribn/presentation/onboarding/create_wallet/welcome_page.dart'; -import 'package:ribn/presentation/transaction_history/service_locator/locator.dart'; import 'package:ribn/providers/store_provider.dart'; import 'package:ribn/redux.dart'; import 'package:ribn/router/root_router.dart'; void main() async { WidgetsFlutterBinding.ensureInitialized(); + await Redux.initStore(initTestStore: kDebugMode ? true : false); final AppViews currentAppView = await PlatformUtils.instance.getCurrentAppView(); final bool needsOnboarding = Redux.store!.state.needsOnboarding(); @@ -43,10 +45,7 @@ void main() async { await initBgConnection(Redux.store!); // Wallet().setJSCallbackFunction(_test()); // initialize(); - } - setupLocator( - Redux.store!, - ); //@dev call this function to setup any singletons required by app + } //@dev call this function to setup any singletons required by app runApp( ProviderScope( child: RibnApp(Redux.store!), @@ -60,6 +59,7 @@ void main() async { class RibnApp extends StatelessWidget { final Store store; final RootRouter rootRouter = RootRouter(); + RibnApp(this.store, {Key? key}) : super(key: key); @override @@ -118,10 +118,7 @@ List onGenerateInitialRoute(initialRoute, Store store) { ) ]; case Routes.home: - return [ - MaterialPageRoute( - builder: (context) => const HomePage(), settings: RouteSettings(name: Routes.home)) - ]; + return [MaterialPageRoute(builder: (context) => const HomePage(), settings: RouteSettings(name: Routes.home))]; case Routes.enable: return [ MaterialPageRoute( diff --git a/lib/middlewares/app_middleware.dart b/lib/middlewares/app_middleware.dart index 13328930..ea75c5a1 100644 --- a/lib/middlewares/app_middleware.dart +++ b/lib/middlewares/app_middleware.dart @@ -6,14 +6,9 @@ import 'package:redux_epics/redux_epics.dart'; import 'package:ribn/middlewares/epic_middleware.dart'; import 'package:ribn/middlewares/internal_message_middleware.dart'; import 'package:ribn/middlewares/keychain_middleware.dart'; -import 'package:ribn/middlewares/login_middleware.dart'; -import 'package:ribn/middlewares/misc_middleware.dart'; -import 'package:ribn/middlewares/onboarding_middleware.dart'; -import 'package:ribn/middlewares/restore_wallet_middleware.dart'; import 'package:ribn/middlewares/transaction_middleware.dart'; import 'package:ribn/models/app_state.dart'; import 'package:ribn/repositories/keychain_repository.dart'; -import 'package:ribn/repositories/login_repository.dart'; import 'package:ribn/repositories/misc_repository.dart'; import 'package:ribn/repositories/onboarding_repository.dart'; import 'package:ribn/repositories/transaction_repository.dart'; @@ -21,19 +16,14 @@ import 'package:ribn/repositories/transaction_repository.dart'; /// All epics and middlewares will be chained here List> createAppMiddleware({ required OnboardingRespository onboardingRepo, - required LoginRepository loginRepo, required MiscRepository miscRepo, required KeychainRepository keychainRepo, required TransactionRepository transactionRepo, }) { return [ - ...(createOnboardingMiddleware(onboardingRepo)), - ...(createLoginMiddleware(loginRepo)), ...(createKeychainMiddleware(keychainRepo)), ...(createTransactionMiddleware(transactionRepo, keychainRepo)), - ...(createRestorewalletMiddleware(onboardingRepo, loginRepo)), ...(createInternalMessageMiddleware(miscRepo)), - ...(createMiscMiddleware(loginRepo, miscRepo)), EpicMiddleware(createEpicMiddleware(miscRepo)) ]; } diff --git a/lib/middlewares/epic_middleware.dart b/lib/middlewares/epic_middleware.dart index b21bd9b9..6c50fd18 100644 --- a/lib/middlewares/epic_middleware.dart +++ b/lib/middlewares/epic_middleware.dart @@ -8,23 +8,18 @@ import 'package:rxdart/rxdart.dart'; // Project imports: import 'package:ribn/actions/keychain_actions.dart'; import 'package:ribn/actions/misc_actions.dart'; -import 'package:ribn/actions/restore_wallet_actions.dart'; import 'package:ribn/actions/user_details_actions.dart'; import 'package:ribn/constants/keys.dart'; import 'package:ribn/constants/routes.dart'; import 'package:ribn/models/app_state.dart'; import 'package:ribn/repositories/misc_repository.dart'; -import 'package:ribn/utils.dart'; +import 'package:ribn/utils/utils.dart'; -Epic createEpicMiddleware(MiscRepository miscRepo) => - combineEpics([ +Epic createEpicMiddleware(MiscRepository miscRepo) => combineEpics([ _persistenceTriggerEpic(), TypedEpic(_onApiError()), TypedEpic(_onPersistAppState(miscRepo)), TypedEpic(_onNavigateToRoute()), - TypedEpic( - _onSuccessfullyRestoredWallet(miscRepo), - ), ]); /// A list of all the actions that should trigger appState persistence @@ -33,12 +28,10 @@ const List persistenceTriggers = [ UpdateCurrentNetworkAction, UpdateBalancesAction, UpdateAssetDetailsAction, - UpdateBiometricsAction, ]; /// If an action that exists in the list [persistenceTriggers] is received, this epic emits the [PersistAppState] action. -Epic _persistenceTriggerEpic() => - (Stream actions, EpicStore store) { +Epic _persistenceTriggerEpic() => (Stream actions, EpicStore store) { return actions .where((action) => (persistenceTriggers.contains(action.runtimeType))) .switchMap((action) => Stream.value(PersistAppState())); @@ -60,8 +53,7 @@ Epic _persistenceTriggerEpic() => // }; /// Redirects to [Routes.error] whenever [ApiErrorAction] is received. -Stream Function(Stream, EpicStore) - _onApiError() { +Stream Function(Stream, EpicStore) _onApiError() { return (actions, store) { return actions.switchMap( (action) => Stream.value( @@ -74,8 +66,7 @@ Stream Function(Stream, EpicStore) /// Handles [PersistAppState] action. /// /// Persists the current [AppState] to local storage. -Stream Function(Stream, EpicStore) - _onPersistAppState(MiscRepository miscRepo) { +Stream Function(Stream, EpicStore) _onPersistAppState(MiscRepository miscRepo) { return (actions, store) { return actions.whereType().switchMap( (action) { @@ -101,44 +92,13 @@ Stream Function(Stream, EpicStore) /// Handles [NavigateToRoute] by pushing [action.route] on the current navigation stack. /// /// Only supports Web platform at this time, i.e. [kIsWeb] should be True. -Stream Function(Stream, EpicStore) - _onNavigateToRoute() { +Stream Function(Stream, EpicStore) _onNavigateToRoute() { return (actions, store) { return actions.switchMap( (action) { - Keys.navigatorKey.currentState - ?.pushNamed(action.route, arguments: action.arguments); + Keys.navigatorKey.currentState?.pushNamed(action.route, arguments: action.arguments); return const Stream.empty(); }, ); }; } - -/// Handles [SuccessfullyRestoredWalletAction] by dispatching actions to reset the current app state, -/// initialize the hd wallet, and navigate to the home page. -/// -/// [navigateToRoute] is selected based on whether the app is open in extension view or full page, i.e. -/// user is restoring wallet during onboarding (fullpage- iew) vs from the login page (extension view). -Stream Function( - Stream, - EpicStore, -) _onSuccessfullyRestoredWallet( - MiscRepository miscRepo, -) { - return (actions, store) { - return actions.switchMap((action) { - const String navigateToRoute = - kIsWeb ? Routes.extensionInfo : Routes.home; - return Stream.fromIterable([ - const ResetAppStateAction(), - InitializeHDWalletAction( - keyStoreJson: action.keyStoreJson, - toplExtendedPrivateKey: action.toplExtendedPrivateKey, - ), - PersistAppState(), - Keys.navigatorKey.currentState - ?.pushNamedAndRemoveUntil(navigateToRoute, (route) => false), - ]); - }); - }; -} diff --git a/lib/middlewares/keychain_middleware.dart b/lib/middlewares/keychain_middleware.dart index 363611ab..ee1d841f 100644 --- a/lib/middlewares/keychain_middleware.dart +++ b/lib/middlewares/keychain_middleware.dart @@ -38,9 +38,7 @@ void Function( final HdWallet hdWallet = store.state.keychainState.hdWallet!; final Map> networkAddresses = {}; store.state.keychainState.networks.forEach((networkName, network) { - networkAddresses[networkName] = [ - keychainRepo.generateAddress(hdWallet, networkId: network.networkId) - ]; + networkAddresses[networkName] = [keychainRepo.generateAddress(hdWallet, networkId: network.networkId)]; }); next(UpdateNetworksWithAddressesAction(networkAddresses)); } catch (e) { @@ -92,8 +90,7 @@ void Function( return (store, action, next) async { try { // get addresses in the wallet - final List currentAddresses = - action.network.addresses.map((addr) => addr.toplAddress).toList(); + final List currentAddresses = action.network.addresses.map((addr) => addr.toplAddress).toList(); // if no address in the wallet, generate a new address if (currentAddresses.isEmpty) { store.dispatch(GenerateAddressAction(0, network: action.network)); @@ -104,12 +101,9 @@ void Function( currentAddresses, ); // map addresses and balances - final Map addrBalanceMap = { - for (Balance bal in balances) bal.address: bal - }; + final Map addrBalanceMap = {for (Balance bal in balances) bal.address: bal}; // addresses with updated balances - final List addressesWithUpdatedBalances = - action.network.addresses.map( + final List addressesWithUpdatedBalances = action.network.addresses.map( (addr) { return addr.copyWith( balance: addrBalanceMap[addr.toplAddress.toBase58()], diff --git a/lib/middlewares/login_middleware.dart b/lib/middlewares/login_middleware.dart deleted file mode 100644 index ecffdb34..00000000 --- a/lib/middlewares/login_middleware.dart +++ /dev/null @@ -1,82 +0,0 @@ -// Dart imports: -import 'dart:convert'; -import 'dart:typed_data'; - -// Package imports: -import 'package:bip_topl/bip_topl.dart'; -import 'package:redux/redux.dart'; - -// Project imports: -import 'package:ribn/actions/keychain_actions.dart'; -import 'package:ribn/actions/login_actions.dart'; -import 'package:ribn/constants/rules.dart'; -import 'package:ribn/models/app_state.dart'; -import 'package:ribn/platform/platform.dart'; -import 'package:ribn/repositories/login_repository.dart'; -import 'package:ribn/utils.dart'; - -List> createLoginMiddleware( - LoginRepository loginRepository, -) { - return >[ - TypedMiddleware( - _verifyPassword(loginRepository), - ), - ]; -} - -/// Verifies that the wallet password is correct by attempting to decrypt the keystore. -void Function( - Store store, - AttemptLoginAction action, - NextDispatcher next, -) _verifyPassword( - LoginRepository loginRepository, -) { - return (store, action, next) async { - try { - final AppViews currAppView = - await PlatformUtils.instance.getCurrentAppView(); - // create isolate/worker to avoid hanging the UI - final List result = jsonDecode( - await PlatformWorkerRunner.instance.runWorker( - workerScript: currAppView == AppViews.webDebug - ? '/web/workers/login_worker.js' - : '/workers/login_worker.js', - function: loginRepository.decryptKeyStore, - params: { - 'keyStoreJson': store.state.keychainState.keyStoreJson, - 'password': action.password, - }, - ), - ); - final Uint8List toplExtendedPrvKeyUint8List = - uint8ListFromDynamic(result); - // if extension: key is temporarily stored in `chrome.storage.session` & session alarm created - // if mobile: key is persisted securely in secure storage - if (currAppView == AppViews.extension || - currAppView == AppViews.extensionTab) { - await PlatformLocalStorage.instance.saveKeyInSessionStorage( - Base58Encoder.instance.encode(toplExtendedPrvKeyUint8List), - ); - PlatformUtils.instance.createLoginSessionAlarm(); - } else if (currAppView == AppViews.mobile) { - await PlatformLocalStorage.instance.saveKeyInSecureStorage( - Base58Encoder.instance.encode(toplExtendedPrvKeyUint8List), - ); - } - // initialize hd wallet on success - next( - InitializeHDWalletAction( - toplExtendedPrivateKey: toplExtendedPrvKeyUint8List, - ), - ); - - //Generate Initial addresses for every network - next(GenerateInitialAddressesAction()); - action.completer.complete(true); - } catch (e) { - action.completer.complete(false); - } - }; -} diff --git a/lib/middlewares/misc_middleware.dart b/lib/middlewares/misc_middleware.dart deleted file mode 100644 index 015fbe92..00000000 --- a/lib/middlewares/misc_middleware.dart +++ /dev/null @@ -1,76 +0,0 @@ -// Flutter imports: -import 'package:flutter/foundation.dart'; - -// Package imports: -import 'package:redux/redux.dart'; - -// Project imports: -import 'package:ribn/actions/misc_actions.dart'; -import 'package:ribn/constants/keys.dart'; -import 'package:ribn/constants/routes.dart'; -import 'package:ribn/models/app_state.dart'; -import 'package:ribn/platform/platform.dart'; -import 'package:ribn/repositories/login_repository.dart'; -import 'package:ribn/repositories/misc_repository.dart'; - -List> createMiscMiddleware( - LoginRepository loginRep, - MiscRepository miscRepo, -) { - return >[ - TypedMiddleware(_onDeleteWallet(loginRep)), - TypedMiddleware( - _onDownloadAsFile(miscRepo), - ), - ]; -} - -void Function( - Store store, - DeleteWalletAction action, - NextDispatcher next, -) _onDeleteWallet( - LoginRepository loginRepo, -) { - return (store, action, next) async { - try { - // Check if correct password was entered - loginRepo.decryptKeyStore( - { - 'keyStoreJson': store.state.keychainState.keyStoreJson!, - 'password': action.password, - }, - ); - // Reset and persist app state - next(const ResetAppStateAction()); - await PlatformLocalStorage.instance.saveState(store.state.toJson()); - if (kIsWeb) { - await PlatformLocalStorage.instance.clearSessionStorage(); - PlatformUtils.instance.closeWindow(); - } else { - await PlatformLocalStorage.instance.clearSecureStorage(); - await Keys.navigatorKey.currentState - ?.pushNamedAndRemoveUntil(Routes.welcome, (_) => false); - } - } catch (e) { - // Complete with false to indicate error, i.e. incorrect password was entered - action.completer.complete(false); - } - }; -} - -void Function( - Store store, - DownloadAsFileAction action, - NextDispatcher next, -) _onDownloadAsFile( - MiscRepository miscRepo, -) { - return (store, action, next) { - try { - miscRepo.downloadAsFile(action.fileName, action.text); - } catch (e) { - next(ApiErrorAction(e.toString())); - } - }; -} diff --git a/lib/middlewares/onboarding_middleware.dart b/lib/middlewares/onboarding_middleware.dart deleted file mode 100644 index 05c5ac25..00000000 --- a/lib/middlewares/onboarding_middleware.dart +++ /dev/null @@ -1,102 +0,0 @@ -// Dart imports: -import 'dart:convert'; -import 'dart:typed_data'; - -// Package imports: -import 'package:bip_topl/bip_topl.dart'; -import 'package:redux/redux.dart'; - -// Project imports: -import 'package:ribn/actions/keychain_actions.dart'; -import 'package:ribn/actions/misc_actions.dart'; -import 'package:ribn/actions/onboarding_actions.dart'; -import 'package:ribn/constants/routes.dart'; -import 'package:ribn/constants/rules.dart'; -import 'package:ribn/models/app_state.dart'; -import 'package:ribn/platform/platform.dart'; -import 'package:ribn/repositories/onboarding_repository.dart'; -import 'package:ribn/utils.dart'; - -List> createOnboardingMiddleware( - OnboardingRespository onboardingRespository, -) { - return >[ - TypedMiddleware( - _generateMnemonic(onboardingRespository), - ), - TypedMiddleware( - _createPassword(onboardingRespository), - ), - ]; -} - -/// Generates mnemonic for the user and redirects to [Routes.onboardingSteps] -void Function( - Store store, - GenerateMnemonicAction action, - NextDispatcher next, -) _generateMnemonic( - OnboardingRespository onboardingRespository, -) { - return (store, action, next) async { - try { - final String mnemonic = onboardingRespository.generateMnemonicForUser(); - next(MnemonicSuccessfullyGeneratedAction(mnemonic)); - } catch (e) { - next(ApiErrorAction(e.toString())); - } - }; -} - -/// Generates a [KeyStore] with the provided password and initializes the HdWallet -void Function( - Store store, - CreatePasswordAction action, - NextDispatcher next, -) _createPassword( - OnboardingRespository onboardingRespository, -) { - return (store, action, next) async { - try { - final AppViews currAppView = - await PlatformUtils.instance.getCurrentAppView(); - // create isolate/worker to avoid hanging the UI - final Map results = jsonDecode( - await PlatformWorkerRunner.instance.runWorker( - workerScript: currAppView == AppViews.webDebug - ? '/web/workers/generate_keystore_worker.js' - : '/workers/generate_keystore_worker.js', - function: onboardingRespository.generateKeyStore, - params: { - 'mnemonic': store.state.onboardingState.mnemonic!, - 'password': action.password, - }, - ), - ); - final Uint8List toplExtendedPrvKeyUint8List = - uint8ListFromDynamic(results['toplExtendedPrvKeyUint8List']); - // if extension: key is temporarily stored in `chrome.storage.session` & session alarm created - // if mobile: key is persisted securely in secure storage - if (currAppView == AppViews.extension || - currAppView == AppViews.extensionTab) { - await PlatformLocalStorage.instance.saveKeyInSessionStorage( - Base58Encoder.instance.encode(toplExtendedPrvKeyUint8List), - ); - PlatformUtils.instance.createLoginSessionAlarm(); - } else if (currAppView == AppViews.mobile) { - await PlatformLocalStorage.instance.saveKeyInSecureStorage( - Base58Encoder.instance.encode(toplExtendedPrvKeyUint8List), - ); - } - next( - InitializeHDWalletAction( - toplExtendedPrivateKey: toplExtendedPrvKeyUint8List, - keyStoreJson: results['keyStoreJson'], - ), - ); - next(PersistAppState()); - } catch (e) { - next(ApiErrorAction(e.toString())); - } - }; -} diff --git a/lib/middlewares/restore_wallet_middleware.dart b/lib/middlewares/restore_wallet_middleware.dart deleted file mode 100644 index 0ea893d2..00000000 --- a/lib/middlewares/restore_wallet_middleware.dart +++ /dev/null @@ -1,97 +0,0 @@ -// Dart imports: -import 'dart:convert'; -import 'dart:typed_data'; - -// Package imports: -import 'package:redux/redux.dart'; - -// Project imports: -import 'package:ribn/actions/misc_actions.dart'; -import 'package:ribn/actions/restore_wallet_actions.dart'; -import 'package:ribn/constants/rules.dart'; -import 'package:ribn/models/app_state.dart'; -import 'package:ribn/platform/platform.dart'; -import 'package:ribn/repositories/login_repository.dart'; -import 'package:ribn/repositories/onboarding_repository.dart'; -import 'package:ribn/utils.dart'; - -/// Creates a list of middlewares to handle logic around the 'Restore Wallet' flow. -List> createRestorewalletMiddleware( - OnboardingRespository onboardingRepo, - LoginRepository loginRepo, -) { - return >[ - TypedMiddleware( - _restoreWalletWithMnemonic(onboardingRepo), - ), - TypedMiddleware( - _restoreWalletWithToplKey(loginRepo), - ), - ]; -} - -/// Handles the [RestoreWalletWithMnemonicAction] action. -/// -/// Uses the [action.mnemonic] and [action.password] to generate a keystore. -/// Dispatches [SuccessfullyRestoredWalletAction] if successfully generated keystore, otherwise [FailedToRestoreWalletAction]. -void Function( - Store store, - RestoreWalletWithMnemonicAction action, - NextDispatcher next, -) _restoreWalletWithMnemonic(OnboardingRespository onboardingRepo) { - return (store, action, next) async { - try { - final AppViews currAppView = - await PlatformUtils.instance.getCurrentAppView(); - final Map results = jsonDecode( - await PlatformWorkerRunner.instance.runWorker( - workerScript: currAppView == AppViews.webDebug - ? '/web/workers/generate_keystore_worker.js' - : '/workers/generate_keystore_worker.js', - function: onboardingRepo.generateKeyStore, - params: { - 'mnemonic': action.mnemonic, - 'password': action.password, - }, - ), - ); - next( - SuccessfullyRestoredWalletAction( - keyStoreJson: results['keyStoreJson'], - toplExtendedPrivateKey: - uint8ListFromDynamic(results['toplExtendedPrvKeyUint8List']), - ), - ); - } catch (e) { - next(ApiErrorAction(e.toString())); - } - }; -} - -/// Handles the [RestoreWalletWithToplKeyAction] action. -/// -/// Attempts to decrypt [action.toplKeyStoreJson] using [action.password]. -/// Dispatches [SuccessfullyRestoredWalletAction] upon success, otherwise [FailedToRestoreWalletAction]. -void Function( - Store store, - RestoreWalletWithToplKeyAction action, - NextDispatcher next, -) _restoreWalletWithToplKey(LoginRepository loginRepo) { - return (store, action, next) async { - try { - final Uint8List toplExtendedPrvKeyUint8List = loginRepo.decryptKeyStore({ - 'keyStoreJson': action.toplKeyStoreJson, - 'password': action.password, - }); - action.completer.complete(true); - next( - SuccessfullyRestoredWalletAction( - keyStoreJson: action.toplKeyStoreJson, - toplExtendedPrivateKey: toplExtendedPrvKeyUint8List, - ), - ); - } catch (e) { - action.completer.complete(false); - } - }; -} diff --git a/lib/middlewares/transaction_middleware.dart b/lib/middlewares/transaction_middleware.dart index c9589bd3..210b1729 100644 --- a/lib/middlewares/transaction_middleware.dart +++ b/lib/middlewares/transaction_middleware.dart @@ -53,8 +53,7 @@ void Function( return (store, action, next) async { try { /// The sender defaults to the first address in the list of locally stored addresses - final RibnAddress sender = - store.state.keychainState.currentNetwork.addresses.first; + final RibnAddress sender = store.state.keychainState.currentNetwork.addresses.first; final RibnNetwork currNetwork = store.state.keychainState.currentNetwork; final TransferDetails transferDetails = action.transferDetails.copyWith( senders: [sender], @@ -85,8 +84,7 @@ void Function( store.state.keychainState.currentNetwork.client!, action.transferDetails, ); - final TransactionReceipt transactionReceipt = - result['rawTx'] as TransactionReceipt; + final TransactionReceipt transactionReceipt = result['rawTx'] as TransactionReceipt; final Uint8List messageToSign = result['messageToSign'] as Uint8List; final TransferDetails transferDetails = action.transferDetails.copyWith( transactionReceipt: transactionReceipt, @@ -123,8 +121,7 @@ void Function( action.transferDetails.transactionReceipt!, action.transferDetails.messageToSign!, ); - final TransferDetails transferDetails = - action.transferDetails.copyWith(transactionId: transactionId); + final TransferDetails transferDetails = action.transferDetails.copyWith(transactionId: transactionId); /// Update the locally stored asset details if minting a new asset if (transferDetails.transferType == TransferType.mintingAsset) { @@ -160,20 +157,16 @@ void Function( action.pendingRequest.data!['messageToSign'] as String, ).value; - final TransactionReceipt transactionReceipt = - TransactionReceipt.fromJson(action.pendingRequest.data!['rawTx']); + final TransactionReceipt transactionReceipt = TransactionReceipt.fromJson(action.pendingRequest.data!['rawTx']); transferDetails['rawTx'] = transactionReceipt; - final List rawTxSenders = transactionReceipt.from! - .map((e) => e.senderAddress.toBase58()) - .toList(); + final List rawTxSenders = transactionReceipt.from!.map((e) => e.senderAddress.toBase58()).toList(); - final List sendersInWallet = - List.from(store.state.keychainState.currentNetwork.addresses) - ..retainWhere( - (addr) => rawTxSenders.contains(addr.toplAddress.toBase58()), - ); + final List sendersInWallet = List.from(store.state.keychainState.currentNetwork.addresses) + ..retainWhere( + (addr) => rawTxSenders.contains(addr.toplAddress.toBase58()), + ); if (sendersInWallet.isEmpty) { final InternalMessage response = InternalMessage( diff --git a/lib/models/app_state.dart b/lib/models/app_state.dart index bd1f56bb..3cfaef6c 100644 --- a/lib/models/app_state.dart +++ b/lib/models/app_state.dart @@ -3,49 +3,38 @@ import 'dart:convert'; // Flutter imports: import 'package:flutter/material.dart'; + // Project imports: import 'package:ribn/models/internal_message.dart'; import 'package:ribn/models/keychain_state.dart'; -import 'package:ribn/models/login_state.dart'; import 'package:ribn/models/onboarding_state.dart'; import 'package:ribn/models/user_details_state.dart'; -import 'package:ribn/platform/platform.dart'; @immutable class AppState { - final OnboardingState onboardingState; - final LoginState loginState; final KeychainState keychainState; final UserDetailsState userDetailsState; final InternalMessage? internalMessage; - final String appVersion; + AppState({ - required this.onboardingState, - required this.loginState, required this.keychainState, required this.userDetailsState, this.internalMessage, - required this.appVersion, }); factory AppState.initial() { return AppState( - onboardingState: OnboardingState.initial(), - loginState: LoginState.initial(), keychainState: KeychainState.initial(), userDetailsState: UserDetailsState.initial(), - appVersion: getAppVersion(), ); } - factory AppState.test() { - final String appVersion = getAppVersion(); + factory AppState.test({ + bool isNewUser = false, + }) { return AppState( - onboardingState: OnboardingState.test(), - loginState: LoginState.initial(), - keychainState: KeychainState.test(), + keychainState: !isNewUser ? KeychainState.test() : KeychainState.initial(), userDetailsState: UserDetailsState.initial(), - appVersion: appVersion, ); } @@ -55,81 +44,55 @@ class AppState { bool needsLogin() => keychainState.hdWallet == null; - static String getAppVersion() { - try { - return PlatformUtils.instance.getCurrentAppVersion(); - } catch (e) { - return 'Dev'; - } - } - @override bool operator ==(Object other) { if (identical(this, other)) return true; return other is AppState && - other.onboardingState == onboardingState && - other.loginState == loginState && other.keychainState == keychainState && other.userDetailsState == userDetailsState && - other.internalMessage == internalMessage && - other.appVersion == appVersion; + other.internalMessage == internalMessage; } @override int get hashCode { - return onboardingState.hashCode ^ - loginState.hashCode ^ - keychainState.hashCode ^ - userDetailsState.hashCode ^ - internalMessage.hashCode ^ - appVersion.hashCode; + return keychainState.hashCode ^ userDetailsState.hashCode ^ internalMessage.hashCode; } AppState copyWith({ OnboardingState? onboardingState, - LoginState? loginState, KeychainState? keychainState, UserDetailsState? userDetailsState, InternalMessage? internalMessage, String? appVersion, }) { return AppState( - onboardingState: onboardingState ?? this.onboardingState, - loginState: loginState ?? this.loginState, keychainState: keychainState ?? this.keychainState, userDetailsState: userDetailsState ?? this.userDetailsState, internalMessage: internalMessage ?? this.internalMessage, - appVersion: appVersion ?? this.appVersion, ); } Map toMap() { return { - 'loginState': loginState.toMap(), 'keychainState': keychainState.toMap(), 'userDetailsState': userDetailsState.toMap(), - 'appVersion': appVersion, }; } factory AppState.fromMap(Map map) { return AppState( - onboardingState: OnboardingState.initial(), - loginState: LoginState.fromMap(map['loginState']), keychainState: KeychainState.fromMap(map['keychainState']), userDetailsState: UserDetailsState.fromMap(map['userDetailsState']), - appVersion: getAppVersion(), ); } String toJson() => json.encode(toMap()); - factory AppState.fromJson(String source) => - AppState.fromMap(json.decode(source)); + factory AppState.fromJson(String source) => AppState.fromMap(json.decode(source)); @override String toString() { - return 'AppState(onboardingState: $onboardingState, loginState: $loginState, keychainState: $keychainState, userDetailsState: $userDetailsState, internalMessage: $internalMessage, appVersion: $appVersion)'; + return 'AppState(keychainState: $keychainState, userDetailsState: $userDetailsState, internalMessage: $internalMessage)'; } } diff --git a/lib/models/asset_details.dart b/lib/models/asset_details.dart index 6f291661..bfd4a0cb 100644 --- a/lib/models/asset_details.dart +++ b/lib/models/asset_details.dart @@ -48,21 +48,16 @@ class AssetDetails { String toJson() => json.encode(toMap()); - factory AssetDetails.fromJson(String source) => - AssetDetails.fromMap(json.decode(source)); + factory AssetDetails.fromJson(String source) => AssetDetails.fromMap(json.decode(source)); @override - String toString() => - 'AssetDetails(longName: $longName, icon: $icon, unit: $unit)'; + String toString() => 'AssetDetails(longName: $longName, icon: $icon, unit: $unit)'; @override bool operator ==(Object other) { if (identical(this, other)) return true; - return other is AssetDetails && - other.longName == longName && - other.icon == icon && - other.unit == unit; + return other is AssetDetails && other.longName == longName && other.icon == icon && other.unit == unit; } @override diff --git a/lib/models/file.dart b/lib/models/file.dart new file mode 100644 index 00000000..dd71eff7 --- /dev/null +++ b/lib/models/file.dart @@ -0,0 +1,12 @@ +// Package imports: +import 'package:freezed_annotation/freezed_annotation.dart'; + +part 'file.freezed.dart'; + +@freezed +class File with _$File { + const factory File({ + @Default("") String fileName, + @Default("") String text, + }) = _FileState; +} diff --git a/lib/models/images/ribn_file_model.dart b/lib/models/images/ribn_file_model.dart new file mode 100644 index 00000000..5077947d --- /dev/null +++ b/lib/models/images/ribn_file_model.dart @@ -0,0 +1,9 @@ +/** + * @dev File contains properties used for storing file information + * @notice This is currently used for uploading screenshots under the feedback section + */ +class RibnFileModel { + final String filePath; + final String fileType; + const RibnFileModel({required this.filePath, required this.fileType}); +} diff --git a/lib/models/internal_message.dart b/lib/models/internal_message.dart index 2cf8df71..8e0b9f65 100644 --- a/lib/models/internal_message.dart +++ b/lib/models/internal_message.dart @@ -11,33 +11,31 @@ class InternalMessage { final String sender; final String id; final String origin; - String additionalNavigation; - InternalMessage( - {required this.method, - this.data, - required this.target, - this.sender = defaultSender, - required this.id, - required this.origin, - this.additionalNavigation = ""}); - - InternalMessage copyWith( - {String? method, - Map? data, - String? target, - String? sender, - String? id, - String? origin, - String? additionalNavigation}) { + InternalMessage({ + required this.method, + this.data, + required this.target, + this.sender = defaultSender, + required this.id, + required this.origin, + }); + + InternalMessage copyWith({ + String? method, + Map? data, + String? target, + String? sender, + String? id, + String? origin, + }) { return InternalMessage( - method: method ?? this.method, - data: data ?? this.data, - target: target ?? this.target, - sender: sender ?? this.sender, - id: id ?? this.id, - origin: origin ?? this.origin, - additionalNavigation: - additionalNavigation ?? this.additionalNavigation); + method: method ?? this.method, + data: data ?? this.data, + target: target ?? this.target, + sender: sender ?? this.sender, + id: id ?? this.id, + origin: origin ?? this.origin, + ); } static const String defaultSender = 'ribn'; @@ -50,21 +48,18 @@ class InternalMessage { 'sender': sender, 'id': id, 'origin': origin, - 'additionalNavigation': additionalNavigation }; } factory InternalMessage.fromMap(Map map) { return InternalMessage( - method: map['method'] as String, - data: map['data'] != null - ? Map.from(map['data'] as Map) - : null, - target: map['target'] as String, - sender: map['sender'] as String, - id: map['id'] as String, - origin: map['origin'] as String, - additionalNavigation: map['additionalNavigation'] as String); + method: map['method'] as String, + data: map['data'] != null ? Map.from(map['data'] as Map) : null, + target: map['target'] as String, + sender: map['sender'] as String, + id: map['id'] as String, + origin: map['origin'] as String, + ); } String toJson() => json.encode(toMap()); @@ -74,7 +69,7 @@ class InternalMessage { @override String toString() { - return 'InternalMessage(method: $method, data: $data, target: $target, sender: $sender, id: $id, origin: $origin,additionalNavigation:$additionalNavigation)'; + return 'InternalMessage(method: $method, data: $data, target: $target, sender: $sender, id: $id, origin: $origin)'; } @override @@ -92,12 +87,7 @@ class InternalMessage { @override int get hashCode { - return method.hashCode ^ - data.hashCode ^ - target.hashCode ^ - sender.hashCode ^ - id.hashCode ^ - origin.hashCode; + return method.hashCode ^ data.hashCode ^ target.hashCode ^ sender.hashCode ^ id.hashCode ^ origin.hashCode; } } diff --git a/lib/models/jira/jira_content_model.dart b/lib/models/jira/jira_content_model.dart new file mode 100644 index 00000000..8dc836f7 --- /dev/null +++ b/lib/models/jira/jira_content_model.dart @@ -0,0 +1,28 @@ +// Project imports: +import 'package:ribn/models/jira/jira_content_type_model.dart'; + +class JiraContentModel { + String? type; + List? content; + + JiraContentModel({this.type = "paragraph", this.content}); + + JiraContentModel.fromJson(Map json) { + type = json['type']; + if (json['content'] != null) { + content = []; + json['content'].forEach((v) { + content!.add(new JiraContentTypeModel.fromJson(v)); + }); + } + } + + Map toJson() { + final Map data = new Map(); + data['type'] = this.type; + if (this.content != null) { + data['content'] = this.content!.map((v) => v.toJson()).toList(); + } + return data; + } +} diff --git a/lib/models/jira/jira_content_type_model.dart b/lib/models/jira/jira_content_type_model.dart new file mode 100644 index 00000000..851a3e67 --- /dev/null +++ b/lib/models/jira/jira_content_type_model.dart @@ -0,0 +1,18 @@ +class JiraContentTypeModel { + String? text; + String? type; + + JiraContentTypeModel({this.text, this.type}); + + JiraContentTypeModel.fromJson(Map json) { + text = json['text']; + type = json['type']; + } + + Map toJson() { + final Map data = new Map(); + data['text'] = this.text; + data['type'] = "text"; + return data; + } +} diff --git a/lib/models/jira/jira_createissue_response_model.dart b/lib/models/jira/jira_createissue_response_model.dart new file mode 100644 index 00000000..7d241ba2 --- /dev/null +++ b/lib/models/jira/jira_createissue_response_model.dart @@ -0,0 +1,23 @@ +class JiraCreateIssueResponseModel { + String? id; + String? key; + String? self; + bool success = false; + + JiraCreateIssueResponseModel({this.id, this.key, this.self, this.success = false}); + + JiraCreateIssueResponseModel.fromJson(Map json) { + id = json['id']; + key = json['key']; + self = json['self']; + success = false; + } + + Map toJson() { + final Map data = new Map(); + data['id'] = this.id; + data['key'] = this.key; + data['self'] = this.self; + return data; + } +} diff --git a/lib/models/jira/jira_description_model.dart b/lib/models/jira/jira_description_model.dart new file mode 100644 index 00000000..3e161708 --- /dev/null +++ b/lib/models/jira/jira_description_model.dart @@ -0,0 +1,31 @@ +// Project imports: +import 'package:ribn/models/jira/jira_content_model.dart'; + +class JiraDescriptionModel { + String? type; + int? version; + List? content; + + JiraDescriptionModel({this.type = "doc", this.version = 1, this.content}); + + JiraDescriptionModel.fromJson(Map json) { + type = json['type']; + version = json['version']; + if (json['content'] != null) { + content = []; + json['content'].forEach((v) { + content!.add(new JiraContentModel.fromJson(v)); + }); + } + } + + Map toJson() { + final Map data = new Map(); + data['type'] = type; + data['version'] = version; + if (this.content != null) { + data['content'] = this.content!.map((v) => v.toJson()).toList(); + } + return data; + } +} diff --git a/lib/models/jira/jira_fields_model.dart b/lib/models/jira/jira_fields_model.dart new file mode 100644 index 00000000..e735d0f9 --- /dev/null +++ b/lib/models/jira/jira_fields_model.dart @@ -0,0 +1,52 @@ +// Project imports: +import 'package:ribn/models/jira/jira_project_model.dart'; +import '../images/ribn_file_model.dart'; +import 'jira_description_model.dart'; +import 'jira_issue_assignee_model.dart'; + +class JiraFieldsModel { + JiraAssigneeModel? assignee; + List? labels; + String? summary; + JiraAssigneeModel? issuetype; + JiraProjectModel? project; + JiraDescriptionModel? description; + List? attachments; + JiraFieldsModel( + {required this.assignee, + required this.labels, + required this.summary, + required this.issuetype, + required this.project, + required this.description, + required this.attachments}); + + JiraFieldsModel.fromJson(Map json) { + assignee = json['assignee'] != null ? new JiraAssigneeModel.fromJson(json['assignee']) : null; + labels = json['labels'].cast(); + summary = json['summary']; + issuetype = json['issuetype'] != null ? new JiraAssigneeModel.fromJson(json['issuetype']) : null; + project = json['project'] != null ? new JiraProjectModel.fromJson(json['project']) : null; + description = json['description'] != null ? new JiraDescriptionModel.fromJson(json['description']) : null; + attachments = []; + } + + Map toJson() { + final Map data = new Map(); + if (this.assignee != null) { + data['assignee'] = this.assignee!.toJson(); + } + data['labels'] = this.labels; + data['summary'] = this.summary; + if (this.issuetype != null) { + data['issuetype'] = this.issuetype!.toJson(); + } + if (this.project != null) { + data['project'] = this.project!.toJson(); + } + if (this.description != null) { + data['description'] = this.description!.toJson(); + } + return data; + } +} diff --git a/lib/models/jira/jira_issue_assignee_model.dart b/lib/models/jira/jira_issue_assignee_model.dart new file mode 100644 index 00000000..b9c36748 --- /dev/null +++ b/lib/models/jira/jira_issue_assignee_model.dart @@ -0,0 +1,15 @@ +class JiraAssigneeModel { + String? id; + + JiraAssigneeModel({this.id}); + + JiraAssigneeModel.fromJson(Map json) { + id = json['id']; + } + + Map toJson() { + final Map data = new Map(); + data['id'] = this.id; + return data; + } +} diff --git a/lib/models/jira/jira_issue_model.dart b/lib/models/jira/jira_issue_model.dart new file mode 100644 index 00000000..b38d6bae --- /dev/null +++ b/lib/models/jira/jira_issue_model.dart @@ -0,0 +1,20 @@ +// Project imports: +import 'package:ribn/models/jira/jira_fields_model.dart'; + +class JiraIssueModel { + JiraFieldsModel? fields; + + JiraIssueModel({this.fields}); + + JiraIssueModel.fromJson(Map json) { + fields = json['fields'] != null ? new JiraFieldsModel.fromJson(json['fields']) : null; + } + + Map toJson() { + final Map data = new Map(); + if (this.fields != null) { + data['fields'] = this.fields!.toJson(); + } + return data; + } +} diff --git a/lib/models/jira/jira_project_model.dart b/lib/models/jira/jira_project_model.dart new file mode 100644 index 00000000..bc8bd46f --- /dev/null +++ b/lib/models/jira/jira_project_model.dart @@ -0,0 +1,15 @@ +class JiraProjectModel { + String? key; + + JiraProjectModel({this.key}); + + JiraProjectModel.fromJson(Map json) { + key = json['key']; + } + + Map toJson() { + final Map data = new Map(); + data['key'] = this.key; + return data; + } +} diff --git a/lib/models/keychain_state.dart b/lib/models/keychain_state.dart index d47a0b5b..d6e69d89 100644 --- a/lib/models/keychain_state.dart +++ b/lib/models/keychain_state.dart @@ -109,10 +109,7 @@ class KeychainState { @override int get hashCode { - return keyStoreJson.hashCode ^ - hdWallet.hashCode ^ - networks.hashCode ^ - currentNetworkName.hashCode; + return keyStoreJson.hashCode ^ hdWallet.hashCode ^ networks.hashCode ^ currentNetworkName.hashCode; } KeychainState copyWith({ diff --git a/lib/models/login_state.dart b/lib/models/login_state.dart deleted file mode 100644 index 414c9176..00000000 --- a/lib/models/login_state.dart +++ /dev/null @@ -1,62 +0,0 @@ -// Dart imports: -import 'dart:convert'; - -class LoginState { - /// True if user is currently logged in. - final bool isLoggedIn; - - /// The time of last login. - final String? lastLogin; - - LoginState({ - this.isLoggedIn = false, - this.lastLogin, - }); - - factory LoginState.initial() { - return LoginState(isLoggedIn: false); - } - - LoginState copyWith({ - bool? isLoggedIn, - String? lastLogin, - }) { - return LoginState( - isLoggedIn: isLoggedIn ?? this.isLoggedIn, - lastLogin: lastLogin ?? this.lastLogin, - ); - } - - Map toMap() { - return { - 'lastLogin': lastLogin, - }; - } - - factory LoginState.fromMap(Map map) { - return LoginState( - lastLogin: map['lastLogin'], - ); - } - - String toJson() => json.encode(toMap()); - - factory LoginState.fromJson(String source) => - LoginState.fromMap(json.decode(source)); - - @override - String toString() => - 'LoginState(isLoggedIn: $isLoggedIn, lastLogin: $lastLogin)'; - - @override - bool operator ==(Object other) { - if (identical(this, other)) return true; - - return other is LoginState && - other.isLoggedIn == isLoggedIn && - other.lastLogin == lastLogin; - } - - @override - int get hashCode => isLoggedIn.hashCode ^ lastLogin.hashCode; -} diff --git a/lib/models/onboarding_state.dart b/lib/models/onboarding_state.dart index a9003815..75bd8045 100644 --- a/lib/models/onboarding_state.dart +++ b/lib/models/onboarding_state.dart @@ -1,29 +1,23 @@ -// Dart imports: -import 'dart:convert'; - // Flutter imports: import 'package:flutter/foundation.dart'; +// Package imports: +import 'package:freezed_annotation/freezed_annotation.dart'; + // Project imports: import 'package:ribn/constants/test_data.dart'; -@immutable -class OnboardingState { - final String? mnemonic; // never persisted - final List? shuffledMnemonic; // never persisted - final List? userSelectedIndices; // never persisted - final List mobileConfirmIdxs; - - const OnboardingState({ - this.mnemonic, - this.shuffledMnemonic, - this.userSelectedIndices, - this.mobileConfirmIdxs = const [8, 10, 14, 13], - }); +part 'onboarding_state.freezed.dart'; +part 'onboarding_state.g.dart'; - factory OnboardingState.initial() { - return const OnboardingState(); - } +@freezed +class OnboardingState with _$OnboardingState { + const factory OnboardingState({ + required String mnemonic, + required List shuffledMnemonic, + List? userSelectedIndices, + @Default([8, 10, 14, 13]) List mobileConfirmIdxs, + }) = _OnboardingState; factory OnboardingState.test() { return const OnboardingState( @@ -32,50 +26,5 @@ class OnboardingState { userSelectedIndices: [], ); } - - OnboardingState copyWith({ - String? mnemonic, - List? shuffledMnemonic, - List? userSelectedIndices, - }) { - return OnboardingState( - mnemonic: mnemonic ?? this.mnemonic, - shuffledMnemonic: shuffledMnemonic ?? this.shuffledMnemonic, - userSelectedIndices: userSelectedIndices ?? this.userSelectedIndices, - ); - } - - Map toMap() { - return {}; - } - - // ignore: avoid_unused_constructor_parameters - factory OnboardingState.fromMap(Map map) { - return const OnboardingState(); - } - - String toJson() => json.encode(toMap()); - - factory OnboardingState.fromJson(String source) => - OnboardingState.fromMap(json.decode(source) as Map); - - @override - String toString() => - 'OnboardingState(mnemonic: $mnemonic, shuffledMnemonic: $shuffledMnemonic, userSelectedIndices: $userSelectedIndices)'; - - @override - bool operator ==(Object other) { - if (identical(this, other)) return true; - - return other is OnboardingState && - other.mnemonic == mnemonic && - listEquals(other.shuffledMnemonic, shuffledMnemonic) && - listEquals(other.userSelectedIndices, userSelectedIndices); - } - - @override - int get hashCode => - mnemonic.hashCode ^ - shuffledMnemonic.hashCode ^ - userSelectedIndices.hashCode; + factory OnboardingState.fromJson(Map json) => _$OnboardingStateFromJson(json); } diff --git a/lib/models/ribn_network.dart b/lib/models/ribn_network.dart index eabdb3cc..dd478bed 100644 --- a/lib/models/ribn_network.dart +++ b/lib/models/ribn_network.dart @@ -121,8 +121,7 @@ class RibnNetwork { List getAssetsIssuedByWallet() { return getAllAssetsInWallet() .where( - (AssetAmount asset) => - asset.assetCode.issuer.toBase58() == myWalletAddress?.toplAddress.toBase58(), + (AssetAmount asset) => asset.assetCode.issuer.toBase58() == myWalletAddress?.toplAddress.toBase58(), ) .toList(); } diff --git a/lib/models/state/analytics_state.dart b/lib/models/state/analytics_state.dart new file mode 100644 index 00000000..668b63c4 --- /dev/null +++ b/lib/models/state/analytics_state.dart @@ -0,0 +1,18 @@ +// Package imports: +import 'package:freezed_annotation/freezed_annotation.dart'; + +// Project imports: +import 'package:ribn/providers/analytics/analytics_events.dart'; + +part 'analytics_state.freezed.dart'; + +@freezed +class AnalyticsState with _$AnalyticsState { + // Added constructor. Must not have any parameter + const AnalyticsState._(); + + const factory AnalyticsState({ + @Default(false) bool isEnabled, + @Default(UserType.Initial) UserType userType, + }) = _AnalyticsState; +} diff --git a/lib/models/state/biometrics_state.dart b/lib/models/state/biometrics_state.dart new file mode 100644 index 00000000..59ceb81b --- /dev/null +++ b/lib/models/state/biometrics_state.dart @@ -0,0 +1,16 @@ +// Package imports: +import 'package:freezed_annotation/freezed_annotation.dart'; + +part 'biometrics_state.freezed.dart'; + +@freezed +class BiometricsState with _$BiometricsState { + // Added constructor. Must not have any parameter + const BiometricsState._(); + + const factory BiometricsState({ + @Default(false) bool isSupported, + @Default(false) bool isEnabled, + @Default(false) bool authorized, + }) = _BiometricsState; +} diff --git a/lib/models/state/login_state.dart b/lib/models/state/login_state.dart new file mode 100644 index 00000000..5090dab6 --- /dev/null +++ b/lib/models/state/login_state.dart @@ -0,0 +1,13 @@ +// Package imports: +import 'package:freezed_annotation/freezed_annotation.dart'; + +part 'login_state.freezed.dart'; + +@freezed +class LoginState with _$LoginState { + const factory LoginState({ + /// True if biometrics authentication is enabled for login + @Default(false) bool isBiometricsEnabled, + @Default(false) bool isLoggedIn, + }) = _LoginState; +} diff --git a/lib/models/state/password_state.dart b/lib/models/state/password_state.dart new file mode 100644 index 00000000..00973cb2 --- /dev/null +++ b/lib/models/state/password_state.dart @@ -0,0 +1,24 @@ +// Package imports: +import 'package:freezed_annotation/freezed_annotation.dart'; + +part 'password_state.freezed.dart'; + +@freezed +class PasswordState with _$PasswordState { + // Added constructor. Must not have any parameter + const PasswordState._(); + + const factory PasswordState({ + @Default(false) bool termsOfUseChecked, + @Default('') String password, + @Default('') String confirmPassword, + }) = _PasswordState; + + get passwordsMatch { + return password == confirmPassword; + } + + get atLeast8Chars { + return password.length > 7; + } +} diff --git a/lib/models/user_details_state.dart b/lib/models/user_details_state.dart index 06281573..1fc6e9c5 100644 --- a/lib/models/user_details_state.dart +++ b/lib/models/user_details_state.dart @@ -15,17 +15,14 @@ import 'package:ribn/models/asset_details.dart'; class UserDetailsState { /// Holds custom asset details that are locally stored. final Map assetDetails; - final bool isBiometricsEnabled; UserDetailsState({ required this.assetDetails, - required this.isBiometricsEnabled, }); factory UserDetailsState.initial() { return UserDetailsState( assetDetails: {}, - isBiometricsEnabled: false, ); } @@ -33,17 +30,12 @@ class UserDetailsState { Map? assetDetails, bool? isBiometricsEnabled, }) { - return UserDetailsState( - assetDetails: assetDetails ?? this.assetDetails, - isBiometricsEnabled: isBiometricsEnabled ?? this.isBiometricsEnabled, - ); + return UserDetailsState(assetDetails: assetDetails ?? this.assetDetails); } Map toMap() { return { - 'assetDetails': - assetDetails.map((key, value) => MapEntry(key, value.toMap())), - 'isBiometricsEnabled': isBiometricsEnabled, + 'assetDetails': assetDetails.map((key, value) => MapEntry(key, value.toMap())), }; } @@ -57,27 +49,23 @@ class UserDetailsState { ), ), ), - isBiometricsEnabled: map['isBiometricsEnabled'], ); } String toJson() => json.encode(toMap()); - factory UserDetailsState.fromJson(String source) => - UserDetailsState.fromMap(json.decode(source)); + factory UserDetailsState.fromJson(String source) => UserDetailsState.fromMap(json.decode(source)); @override - String toString() => - 'UserDetailsState(assetDetails: $assetDetails, isBiometricsEnabled: $isBiometricsEnabled)'; + String toString() => 'UserDetailsState(assetDetails: $assetDetails)'; @override bool operator ==(covariant UserDetailsState other) { if (identical(this, other)) return true; - return mapEquals(other.assetDetails, assetDetails) && - other.isBiometricsEnabled == isBiometricsEnabled; + return mapEquals(other.assetDetails, assetDetails); } @override - int get hashCode => assetDetails.hashCode ^ isBiometricsEnabled.hashCode; + int get hashCode => assetDetails.hashCode; } diff --git a/lib/models/view/poly_transfer_class.dart b/lib/models/view/poly_transfer_class.dart new file mode 100644 index 00000000..8d97be43 --- /dev/null +++ b/lib/models/view/poly_transfer_class.dart @@ -0,0 +1,14 @@ +// Package imports: +import 'package:freezed_annotation/freezed_annotation.dart'; + +part 'poly_transfer_class.freezed.dart'; + +@freezed +class PolyTransferClass with _$PolyTransferClass { + const factory PolyTransferClass({ + required int amount, + required String note, + required String recipientAddress, + required String validRecipientAddress, + }) = _PolyTransferClass; +} diff --git a/lib/platform/interfaces.dart b/lib/platform/interfaces.dart index e7c3632b..8e2b3984 100644 --- a/lib/platform/interfaces.dart +++ b/lib/platform/interfaces.dart @@ -1,3 +1,6 @@ +// Package imports: +import 'package:flutter_secure_storage/flutter_secure_storage.dart'; + // Project imports: import 'package:ribn/constants/rules.dart'; @@ -61,31 +64,43 @@ abstract class IPlatformLocalStorage { /// Get locally stored data. Future getState(); + /// Mobile-only + /// + /// Save any [key] in secure storage for future retrievals. + /// + /// [key] should be a unique string value + Future saveKVInSecureStorage(String key, String value, {FlutterSecureStorage? override}); + + /// Mobile-only + /// + /// Get specified key, if it exists, from FlutterSecureStorage. + Future getKVInSecureStorage(String key, {FlutterSecureStorage? override}); + /// Web-only /// - /// Save [key] in chrome's session storage. + /// Save Topl [value] in chrome's session storage. /// - /// [key] should be the Base58Encoded Topl Main Key. - Future saveKeyInSessionStorage(String key); + /// Topl [value] should be the Base58Encoded Topl Main Key. + Future saveKeyInSessionStorage(String value, {String? key}); /// Mobile-only /// - /// Save [key] in seucre storage for future retrievals. + /// Save [key] in secure storage for future retrievals. /// /// [key] should be the Base58Encoded Topl Main Key. - Future saveKeyInSecureStorage(String key); + Future saveKeyInSecureStorage(String key, {FlutterSecureStorage? override}); /// Web-only /// /// Get key, if it exists, from the session storage. /// /// For chrome, this means accessing session storage using the `chrome.storage.session` API. - Future getKeyFromSessionStorage(); + Future getKeyFromSessionStorage({String? key}); /// Mobile-only /// /// Get key, if it exists, from FlutterSecureStorage. - Future? getKeyFromSecureStorage(); + Future? getKeyFromSecureStorage({FlutterSecureStorage? override}); /// Web-only Future clearSessionStorage(); diff --git a/lib/platform/mobile/genus_config.dart b/lib/platform/mobile/genus_config.dart index 05ce8aa0..fb932584 100644 --- a/lib/platform/mobile/genus_config.dart +++ b/lib/platform/mobile/genus_config.dart @@ -6,10 +6,19 @@ import 'package:ribn/constants/network_utils.dart'; class PlatformGenusConfig { static ClientChannel channel = ClientChannel( + // NetworkUtils.privateIP, NetworkUtils.privateIP, port: 8089, options: const ChannelOptions( credentials: ChannelCredentials.insecure(), ), ); + + static ClientChannel getNetworkConfig(String genusIP) => ClientChannel( + genusIP, + port: 8089, + options: const ChannelOptions( + credentials: ChannelCredentials.insecure(), + ), + ); } diff --git a/lib/platform/mobile/storage.dart b/lib/platform/mobile/storage.dart index f5b42c5a..4cf6673b 100644 --- a/lib/platform/mobile/storage.dart +++ b/lib/platform/mobile/storage.dart @@ -3,25 +3,30 @@ import 'dart:io'; // Package imports: import 'package:flutter_secure_storage/flutter_secure_storage.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:path_provider/path_provider.dart'; // Project imports: import 'package:ribn/constants/keys.dart'; import 'package:ribn/platform/interfaces.dart'; +import 'package:ribn/providers/packages/flutter_secure_storage_provider.dart'; class PlatformLocalStorage implements IPlatformLocalStorage { PlatformLocalStorage._internal(); + static PlatformLocalStorage? _instance; + factory PlatformLocalStorage() { _instance ??= PlatformLocalStorage._internal(); return _instance!; } + static PlatformLocalStorage get instance => PlatformLocalStorage(); /// Allows securely storing credentials on mobile. /// Uses keychain for iOS; AES encryption and KeyStore for android /// Ref: https://pub.dev/packages/flutter_secure_storage - final FlutterSecureStorage secureStorage = const FlutterSecureStorage(); + final FlutterSecureStorage secureStorage = ProviderContainer().read(flutterSecureStorageProvider)(); @override Future getState() async { @@ -41,26 +46,24 @@ class PlatformLocalStorage implements IPlatformLocalStorage { /// Mobile-only: Gets toplKey from encrypted device storage. @override - Future? getKeyFromSecureStorage() { + Future? getKeyFromSecureStorage({FlutterSecureStorage? override}) async { try { - return secureStorage.read(key: 'toplKey'); + return (override != null) ? await override.read(key: 'toplKey') : await secureStorage.read(key: 'toplKey'); } catch (e) { - if (!Keys.isTestingEnvironment) { - rethrow; - } + if (!Keys.isTestingEnvironment) rethrow; } return null; } /// Mobile-only: Saves [key] in encrypted device storage. @override - Future saveKeyInSecureStorage(String key) async { + Future saveKeyInSecureStorage(String key, {FlutterSecureStorage? override}) async { try { - await secureStorage.write(key: 'toplKey', value: key); + return (override != null) + ? override.write(key: 'toplKey', value: key) + : await secureStorage.write(key: 'toplKey', value: key); } catch (e) { - if (!Keys.isTestingEnvironment) { - rethrow; - } + if (!Keys.isTestingEnvironment) rethrow; } } @@ -79,10 +82,30 @@ class PlatformLocalStorage implements IPlatformLocalStorage { /// Web-only @override - Future getKeyFromSessionStorage() => throw UnimplementedError(); + Future getKeyFromSessionStorage({String? key}) => throw UnimplementedError(); /// Web-only @override - Future saveKeyInSessionStorage(String key) => - throw UnimplementedError(); + Future saveKeyInSessionStorage(String value, {String? key}) => throw UnimplementedError(); + + @override + Future getKVInSecureStorage(String key, {FlutterSecureStorage? override}) async { + try { + return (override != null) ? await override.read(key: key) : await secureStorage.read(key: key); + } catch (e) { + if (!Keys.isTestingEnvironment) rethrow; + } + return null; + } + + @override + Future saveKVInSecureStorage(String key, String value, {FlutterSecureStorage? override}) async { + try { + return (override != null) + ? await override.write(key: key, value: value) + : await secureStorage.write(key: key, value: value); + } catch (e) { + rethrow; + } + } } diff --git a/lib/platform/mobile/utils.dart b/lib/platform/mobile/utils.dart index fd6273a0..cd47b6fd 100644 --- a/lib/platform/mobile/utils.dart +++ b/lib/platform/mobile/utils.dart @@ -1,5 +1,7 @@ -// Project imports: +// Flutter imports: import 'package:flutter/cupertino.dart'; + +// Project imports: import 'package:ribn/constants/rules.dart'; import 'package:ribn/platform/interfaces.dart'; diff --git a/lib/platform/web/genus_config.dart b/lib/platform/web/genus_config.dart index a29a1891..292b04dc 100644 --- a/lib/platform/web/genus_config.dart +++ b/lib/platform/web/genus_config.dart @@ -6,6 +6,12 @@ import 'package:ribn/constants/network_utils.dart'; class PlatformGenusConfig { static GrpcWebClientChannel channel = GrpcWebClientChannel.xhr( + // Uri.parse('http://${NetworkUtils.privateIP}:8099'), Uri.parse('http://${NetworkUtils.privateIP}:8099'), ); + + static GrpcWebClientChannel getNetworkConfig(String genusIP) => GrpcWebClientChannel.xhr( + // Uri.parse('http://${NetworkUtils.privateIP}:8099'), + Uri.parse('http://$genusIP:8099'), + ); } diff --git a/lib/platform/web/messenger.dart b/lib/platform/web/messenger.dart index 5b1885ed..97e6715c 100644 --- a/lib/platform/web/messenger.dart +++ b/lib/platform/web/messenger.dart @@ -25,8 +25,7 @@ class Messenger implements IMessenger { void connect() => openConnection(); @override - void initMsgListener(Function msgHandler) => - addPortMessageListener(allowInterop(msgHandler)); + void initMsgListener(Function msgHandler) => addPortMessageListener(allowInterop(msgHandler)); @override void sendMsg(String msg) => sendPortMessage(msg); diff --git a/lib/platform/web/storage.dart b/lib/platform/web/storage.dart index 1bf3d29a..c12761b4 100644 --- a/lib/platform/web/storage.dart +++ b/lib/platform/web/storage.dart @@ -6,6 +6,7 @@ import 'dart:async'; import 'dart:convert'; // Package imports: +import 'package:flutter_secure_storage/flutter_secure_storage.dart'; import 'package:js/js.dart'; import 'package:js/js_util.dart'; @@ -30,17 +31,16 @@ class PlatformLocalStorage implements IPlatformLocalStorage { static PlatformLocalStorage get instance => PlatformLocalStorage(); @override - Future saveState(String data) => - promiseToFuture(persistToLocalStorage(data)); + Future saveState(String data) => promiseToFuture(persistToLocalStorage(data)); @override Future getState() => promiseToFuture(getFromLocalStorage()); /// Web-only: Saves [key] in `chrome.storage.session` @override - Future saveKeyInSessionStorage(String key) async { + Future saveKeyInSessionStorage(String value, {String? key}) async { try { - final String data = jsonEncode({'toplKey': key}); + final String data = (key == null ? jsonEncode({'toplKey': value}) : jsonEncode({key: value})); await saveToSessionStorage(data); } catch (e) { if (!Keys.isTestingEnvironment) { @@ -51,11 +51,10 @@ class PlatformLocalStorage implements IPlatformLocalStorage { /// Web-only: Gets toplKey from `chrome.storage.session` if it exists @override - Future getKeyFromSessionStorage() async { + Future getKeyFromSessionStorage({String? key}) async { try { - final Map sessionStorage = - jsonDecode(await promiseToFuture(getFromSessionStorage())); - return sessionStorage['toplKey']; + final Map sessionStorage = jsonDecode(await promiseToFuture(getFromSessionStorage())); + return key == null ? sessionStorage['toplKey'] : sessionStorage[key]; } catch (e) { if (!Keys.isTestingEnvironment) { rethrow; @@ -79,9 +78,19 @@ class PlatformLocalStorage implements IPlatformLocalStorage { /// Mobile-only @override - Future getKeyFromSecureStorage() => throw UnimplementedError(); + Future getKeyFromSecureStorage({FlutterSecureStorage? override}) => throw UnimplementedError(); - /// Mobile-only + /// Implementation forwards to extension storage feature + @override + Future saveKeyInSecureStorage(String key, {FlutterSecureStorage? override}) => throw UnimplementedError(); + + /// Implementation forwards to extension storage feature + @override + Future getKVInSecureStorage(String key, {FlutterSecureStorage? override}) async => + await getKeyFromSessionStorage(key: key) ?? ""; + + /// Implementation forwards to extension storage feature @override - Future saveKeyInSecureStorage(String key) => throw UnimplementedError(); + Future saveKVInSecureStorage(String key, String value, {FlutterSecureStorage? override}) => + saveKeyInSessionStorage(value, key: key); } diff --git a/lib/platform/web/utils.dart b/lib/platform/web/utils.dart index 47205d04..46b68326 100644 --- a/lib/platform/web/utils.dart +++ b/lib/platform/web/utils.dart @@ -9,6 +9,7 @@ import 'dart:js_util'; // Package imports: import 'package:js/js.dart'; + // Project imports: import 'package:ribn/constants/rules.dart'; import 'package:ribn/platform/interfaces.dart'; @@ -37,8 +38,7 @@ class PlatformUtils implements IPlatformUtils { String getCurrentAppVersion() => getAppVersion(); @override - void downloadFile(String fileName, String text) => - downloadAsFile(fileName, text); + void downloadFile(String fileName, String text) => downloadAsFile(fileName, text); @override void deleteActiveWallet() => deleteWallet(); diff --git a/lib/platform/web/wallet.dart b/lib/platform/web/wallet.dart index c159e674..9638b8c4 100644 --- a/lib/platform/web/wallet.dart +++ b/lib/platform/web/wallet.dart @@ -28,20 +28,18 @@ void initialize() { // JavaScript code may now call `functionName()` or `window.functionName()`. } -String _getBalance() => - StoreProvider.of(Keys.navigatorKey.currentContext!) - .state - .keychainState - .currentNetwork - .getPolysInWallet() - .toString(); - -String _getAddress() => - StoreProvider.of(Keys.navigatorKey.currentContext!) - .state - .keychainState - .currentNetwork - .addresses - .first - .toplAddress - .toBase58(); +String _getBalance() => StoreProvider.of(Keys.navigatorKey.currentContext!) + .state + .keychainState + .currentNetwork + .getPolysInWallet() + .toString(); + +String _getAddress() => StoreProvider.of(Keys.navigatorKey.currentContext!) + .state + .keychainState + .currentNetwork + .addresses + .first + .toplAddress + .toBase58(); diff --git a/lib/presentation/asset_details/asset_detail_edit_sections/asset_icon_edit_section.dart b/lib/presentation/asset_details/asset_detail_edit_sections/asset_icon_edit_section.dart index 31f21b37..10426231 100644 --- a/lib/presentation/asset_details/asset_detail_edit_sections/asset_icon_edit_section.dart +++ b/lib/presentation/asset_details/asset_detail_edit_sections/asset_icon_edit_section.dart @@ -22,6 +22,7 @@ class AssetIconEditSection extends StatefulWidget { /// A callback function for handling save/cancel actions. final VoidCallback onActionTaken; + const AssetIconEditSection({ Key? key, required this.assetCode, @@ -64,8 +65,7 @@ class _AssetIconEditSectionState extends State { buttonHeight: 33, buttonChild: Text( 'Save', - style: RibnToolkitTextStyles.btnMedium - .copyWith(color: Colors.white), + style: RibnToolkitTextStyles.btnMedium.copyWith(color: Colors.white), ), backgroundColor: RibnColors.primary, onPressed: () { @@ -84,8 +84,7 @@ class _AssetIconEditSectionState extends State { buttonHeight: 33, buttonChild: Text( 'Cancel', - style: RibnToolkitTextStyles.btnMedium - .copyWith(color: RibnColors.ghostButtonText), + style: RibnToolkitTextStyles.btnMedium.copyWith(color: RibnColors.ghostButtonText), ), backgroundColor: Colors.transparent, hoverColor: Colors.transparent, @@ -118,13 +117,15 @@ class _AssetIconEditSectionState extends State { ), children: UIConstants.assetIconsList .map( - (icon) => PortalEntry( - portal: Image.asset( + (icon) => PortalTarget( + portalFollower: Image.asset( icon, width: 31, ), - portalAnchor: Alignment.bottomCenter, - childAnchor: Alignment.topCenter, + anchor: Aligned( + follower: Alignment.bottomCenter, + target: Alignment.topCenter, + ), visible: _selectedIcon == icon, child: MaterialButton( padding: EdgeInsets.zero, diff --git a/lib/presentation/asset_details/asset_detail_edit_sections/asset_long_name_edit_section.dart b/lib/presentation/asset_details/asset_detail_edit_sections/asset_long_name_edit_section.dart index 08b6b55f..be9b8ed8 100644 --- a/lib/presentation/asset_details/asset_detail_edit_sections/asset_long_name_edit_section.dart +++ b/lib/presentation/asset_details/asset_detail_edit_sections/asset_long_name_edit_section.dart @@ -32,8 +32,7 @@ class AssetLongNameEditSection extends StatefulWidget { }) : super(key: key); @override - _AssetLongNameEditSectionState createState() => - _AssetLongNameEditSectionState(); + _AssetLongNameEditSectionState createState() => _AssetLongNameEditSectionState(); } class _AssetLongNameEditSectionState extends State { @@ -80,8 +79,7 @@ class _AssetLongNameEditSectionState extends State { buttonHeight: 33, buttonChild: Text( 'Save', - style: RibnToolkitTextStyles.btnMedium - .copyWith(color: Colors.white), + style: RibnToolkitTextStyles.btnMedium.copyWith(color: Colors.white), ), backgroundColor: RibnColors.primary, onPressed: () { @@ -100,8 +98,7 @@ class _AssetLongNameEditSectionState extends State { buttonHeight: 33, buttonChild: Text( 'Cancel', - style: RibnToolkitTextStyles.btnMedium - .copyWith(color: RibnColors.ghostButtonText), + style: RibnToolkitTextStyles.btnMedium.copyWith(color: RibnColors.ghostButtonText), ), backgroundColor: Colors.transparent, hoverColor: Colors.transparent, diff --git a/lib/presentation/asset_details/asset_detail_edit_sections/asset_unit_edit_section.dart b/lib/presentation/asset_details/asset_detail_edit_sections/asset_unit_edit_section.dart index 03c58d7f..85ca2402 100644 --- a/lib/presentation/asset_details/asset_detail_edit_sections/asset_unit_edit_section.dart +++ b/lib/presentation/asset_details/asset_detail_edit_sections/asset_unit_edit_section.dart @@ -13,7 +13,7 @@ import 'package:ribn/actions/user_details_actions.dart'; import 'package:ribn/constants/assets.dart'; import 'package:ribn/constants/ui_constants.dart'; import 'package:ribn/models/app_state.dart'; -import 'package:ribn/utils.dart'; +import 'package:ribn/utils/extensions.dart'; /// The section for editing asset unit. /// @@ -72,7 +72,7 @@ class _AssetUnitEditSectionState extends State { dropDownAlignment: Alignment.topCenter, visible: dropdownOpened, onDismissed: () { - Overlay.of(context)!.setState(() { + Overlay.of(context).setState(() { dropdownOpened = false; }); }, @@ -82,9 +82,7 @@ class _AssetUnitEditSectionState extends State { ), hintText: 'Select Unit', selectedItem: Text( - formatAssetUnit( - selectedUnit ?? widget.currentUnit, - ), + (selectedUnit ?? widget.currentUnit).formatAssetUnit(), style: RibnToolkitTextStyles.dropdownButtonStyle, ), ), @@ -96,8 +94,7 @@ class _AssetUnitEditSectionState extends State { buttonHeight: 33, buttonChild: Text( 'Save', - style: RibnToolkitTextStyles.btnMedium - .copyWith(color: Colors.white), + style: RibnToolkitTextStyles.btnMedium.copyWith(color: Colors.white), ), backgroundColor: RibnColors.primary, onPressed: () { @@ -116,8 +113,7 @@ class _AssetUnitEditSectionState extends State { buttonHeight: 33, buttonChild: Text( 'Cancel', - style: RibnToolkitTextStyles.btnMedium - .copyWith(color: RibnColors.ghostButtonText), + style: RibnToolkitTextStyles.btnMedium.copyWith(color: RibnColors.ghostButtonText), ), backgroundColor: Colors.transparent, hoverColor: Colors.transparent, @@ -165,7 +161,7 @@ class _AssetUnitEditSectionState extends State { setState(() { dropdownOpened = false; }); - Overlay.of(context)!.setState(() { + Overlay.of(context).setState(() { selectedUnit = unit; dropdownOpened = false; }); diff --git a/lib/presentation/asset_details/asset_detail_items/asset_amount_details.dart b/lib/presentation/asset_details/asset_detail_items/asset_amount_details.dart index a9af6ac5..587e5533 100644 --- a/lib/presentation/asset_details/asset_detail_items/asset_amount_details.dart +++ b/lib/presentation/asset_details/asset_detail_items/asset_amount_details.dart @@ -1,9 +1,12 @@ // Flutter imports: import 'package:flutter/material.dart'; -import 'package:ribn/presentation/asset_details/asset_detail_items/asset_column.dart'; + // Package imports: import 'package:ribn_toolkit/constants/styles.dart'; +// Project imports: +import 'package:ribn/presentation/asset_details/asset_detail_items/asset_column.dart'; + /// One of the asset details displayed on [AssetDetailsPage]. /// /// Displays the total amount/quantity of asset owned. diff --git a/lib/presentation/asset_details/asset_detail_items/asset_code_details.dart b/lib/presentation/asset_details/asset_detail_items/asset_code_details.dart index 89875e8e..9618d3a0 100644 --- a/lib/presentation/asset_details/asset_detail_items/asset_code_details.dart +++ b/lib/presentation/asset_details/asset_detail_items/asset_code_details.dart @@ -9,7 +9,7 @@ import 'package:ribn_toolkit/widgets/molecules/custom_tooltip.dart'; // Project imports: import 'package:ribn/constants/assets.dart'; import 'package:ribn/constants/strings.dart'; -import 'package:ribn/utils.dart'; +import 'package:ribn/utils/extensions.dart'; /// One of the asset details displayed on [AssetDetailsPage]. /// @@ -51,7 +51,7 @@ class AssetCodeDetails extends StatelessWidget { Row( children: [ Text( - formatAddrString(assetCode), + assetCode.formatAddressString(), style: RibnToolkitTextStyles.smallBody, ), const SizedBox(width: 8), diff --git a/lib/presentation/asset_details/asset_detail_items/asset_code_short_details.dart b/lib/presentation/asset_details/asset_detail_items/asset_code_short_details.dart index d141cf28..fa923ce3 100644 --- a/lib/presentation/asset_details/asset_detail_items/asset_code_short_details.dart +++ b/lib/presentation/asset_details/asset_detail_items/asset_code_short_details.dart @@ -1,12 +1,14 @@ // Flutter imports: import 'package:flutter/material.dart'; + +// Package imports: +import 'package:ribn_toolkit/constants/styles.dart'; +import 'package:ribn_toolkit/widgets/molecules/custom_tooltip.dart'; + // Project imports: import 'package:ribn/constants/assets.dart'; import 'package:ribn/constants/strings.dart'; import 'package:ribn/presentation/asset_details/asset_detail_items/asset_column.dart'; -// Package imports: -import 'package:ribn_toolkit/constants/styles.dart'; -import 'package:ribn_toolkit/widgets/molecules/custom_tooltip.dart'; /// One of the asset details displayed on [AssetDetailsPage]. /// diff --git a/lib/presentation/asset_details/asset_detail_items/asset_column.dart b/lib/presentation/asset_details/asset_detail_items/asset_column.dart index 87243671..2a6addee 100644 --- a/lib/presentation/asset_details/asset_detail_items/asset_column.dart +++ b/lib/presentation/asset_details/asset_detail_items/asset_column.dart @@ -1,3 +1,4 @@ +// Flutter imports: import 'package:flutter/material.dart'; class AssetColumn extends StatelessWidget { diff --git a/lib/presentation/asset_details/asset_detail_items/asset_icon_details.dart b/lib/presentation/asset_details/asset_detail_items/asset_icon_details.dart new file mode 100644 index 00000000..c2f06e23 --- /dev/null +++ b/lib/presentation/asset_details/asset_detail_items/asset_icon_details.dart @@ -0,0 +1,70 @@ +// Flutter imports: +import 'package:flutter/material.dart'; + +// Package imports: +import 'package:ribn_toolkit/constants/assets.dart'; +import 'package:ribn_toolkit/constants/colors.dart'; +import 'package:ribn_toolkit/constants/styles.dart'; +import 'package:ribn_toolkit/widgets/atoms/hover_icon_button.dart'; + +/// One of the asset details displayed on [AssetDetailsPage]. +/// +/// Displays the icon that's assigned to the asset. +class AssetIconDetails extends StatelessWidget { + /// The current icon assigned to the asset. + final String? currIcon; + + /// True if this is currently being edited. + final bool editingSectionOpened; + + /// Callback for when edit button is pressed. + final VoidCallback onEditPressed; + + const AssetIconDetails({ + Key? key, + required this.currIcon, + required this.editingSectionOpened, + required this.onEditPressed, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SizedBox( + height: 30, + child: Row( + children: [ + const Text('Icon', style: RibnToolkitTextStyles.h4), + const Spacer(), + editingSectionOpened + ? const SizedBox() + : HoverIconButton( + buttonText: Text( + 'Edit', + style: RibnToolkitTextStyles.dropdownButtonStyle.copyWith(color: RibnColors.primary), + ), + buttonIcon: Image.asset(RibnAssets.editIcon), + onPressed: onEditPressed, + ), + ], + ), + ), + Padding( + padding: const EdgeInsets.only(top: 3, bottom: 5), + child: SizedBox( + width: 20, + height: 20, + child: currIcon == null + ? Image.asset(RibnAssets.undefinedIcon) + : Image.asset( + currIcon!, + width: 31, + ), + ), + ), + ], + ); + } +} diff --git a/lib/presentation/asset_details/asset_detail_items/asset_long_name_details.dart b/lib/presentation/asset_details/asset_detail_items/asset_long_name_details.dart index 1c354dc3..e3b830c0 100644 --- a/lib/presentation/asset_details/asset_detail_items/asset_long_name_details.dart +++ b/lib/presentation/asset_details/asset_detail_items/asset_long_name_details.dart @@ -48,8 +48,7 @@ class AssetLongNameDetails extends StatelessWidget { : HoverIconButton( buttonText: Text( 'Edit', - style: RibnToolkitTextStyles.dropdownButtonStyle - .copyWith(color: RibnColors.primary), + style: RibnToolkitTextStyles.dropdownButtonStyle.copyWith(color: RibnColors.primary), ), buttonIcon: Image.asset(RibnAssets.editIcon), onPressed: onEditPressed, diff --git a/lib/presentation/asset_details/asset_detail_items/asset_unit_details.dart b/lib/presentation/asset_details/asset_detail_items/asset_unit_details.dart index 6857de94..d0d0277d 100644 --- a/lib/presentation/asset_details/asset_detail_items/asset_unit_details.dart +++ b/lib/presentation/asset_details/asset_detail_items/asset_unit_details.dart @@ -41,8 +41,7 @@ class AssetUnitDetails extends StatelessWidget { : HoverIconButton( buttonText: Text( 'Edit', - style: RibnToolkitTextStyles.dropdownButtonStyle - .copyWith(color: RibnColors.primary), + style: RibnToolkitTextStyles.dropdownButtonStyle.copyWith(color: RibnColors.primary), ), buttonIcon: Image.asset(RibnAssets.editIcon), onPressed: onEditPressed, diff --git a/lib/presentation/asset_details/asset_detail_items/issuer_address_details.dart b/lib/presentation/asset_details/asset_detail_items/issuer_address_details.dart index 9130d7d7..3424d599 100644 --- a/lib/presentation/asset_details/asset_detail_items/issuer_address_details.dart +++ b/lib/presentation/asset_details/asset_detail_items/issuer_address_details.dart @@ -10,7 +10,7 @@ import 'package:ribn_toolkit/widgets/molecules/custom_tooltip.dart'; // Project imports: import 'package:ribn/constants/assets.dart'; import 'package:ribn/constants/strings.dart'; -import 'package:ribn/utils.dart'; +import 'package:ribn/utils/extensions.dart'; class IssuerAddressDetails extends StatelessWidget { final String issuerAddress; @@ -50,7 +50,7 @@ class IssuerAddressDetails extends StatelessWidget { SvgPicture.asset(RibnAssets.issuerFingerprint), const SizedBox(width: 8), Text( - formatAddrString(issuerAddress), + issuerAddress.formatAddressString(), style: RibnToolkitTextStyles.smallBody, ), const SizedBox(width: 8), diff --git a/lib/presentation/asset_details/asset_detail_items/token_metadata_details.dart b/lib/presentation/asset_details/asset_detail_items/token_metadata_details.dart index 6909c18e..b1dd3ae3 100644 --- a/lib/presentation/asset_details/asset_detail_items/token_metadata_details.dart +++ b/lib/presentation/asset_details/asset_detail_items/token_metadata_details.dart @@ -1,5 +1,6 @@ // Flutter imports: import 'package:flutter/material.dart'; + // Package imports: import 'package:ribn_toolkit/constants/styles.dart'; diff --git a/lib/presentation/asset_details/asset_details_page.dart b/lib/presentation/asset_details/asset_details_page.dart index 3178a76c..bbb1dc8f 100644 --- a/lib/presentation/asset_details/asset_details_page.dart +++ b/lib/presentation/asset_details/asset_details_page.dart @@ -1,10 +1,14 @@ // Flutter imports: -// Package imports: -import 'package:brambldart/brambldart.dart'; // Flutter imports: import 'package:flutter/material.dart'; + +// Package imports: +import 'package:brambldart/brambldart.dart'; import 'package:flutter_redux/flutter_redux.dart'; +import 'package:ribn_toolkit/constants/colors.dart'; +import 'package:ribn_toolkit/widgets/organisms/custom_page_text_title.dart'; + // Project imports: import 'package:ribn/constants/routes.dart'; import 'package:ribn/constants/strings.dart'; @@ -15,9 +19,6 @@ import 'package:ribn/presentation/asset_details/asset_detail_items/asset_code_de import 'package:ribn/presentation/asset_details/asset_detail_items/asset_code_short_details.dart'; import 'package:ribn/presentation/asset_details/asset_detail_items/token_metadata_details.dart'; import 'package:ribn/widgets/custom_divider.dart'; -import 'package:ribn_toolkit/constants/colors.dart'; -import 'package:ribn_toolkit/widgets/organisms/custom_page_text_title.dart'; - import 'asset_detail_items/issuer_address_details.dart'; /// This page presents all details associated with an asset. diff --git a/lib/presentation/authorize_and_sign/connect_dapp.dart b/lib/presentation/authorize_and_sign/connect_dapp.dart index e8262857..1f7f2862 100644 --- a/lib/presentation/authorize_and_sign/connect_dapp.dart +++ b/lib/presentation/authorize_and_sign/connect_dapp.dart @@ -57,8 +57,7 @@ class _ConnectDAppState extends State { Padding( padding: const EdgeInsets.symmetric(horizontal: 13), child: Container( - padding: - const EdgeInsets.symmetric(horizontal: 20, vertical: 10), + padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 10), width: 360, decoration: BoxDecoration( borderRadius: const BorderRadius.all(Radius.circular(11.6)), @@ -281,7 +280,6 @@ class _ConnectDAppState extends State { }, ); } - StoreProvider.of(context) - .dispatch(SendInternalMsgAction(response)); + StoreProvider.of(context).dispatch(SendInternalMsgAction(response)); } } diff --git a/lib/presentation/authorize_and_sign/input_dropdown_wrapper.dart b/lib/presentation/authorize_and_sign/input_dropdown_wrapper.dart index 01131750..aa027f3b 100644 --- a/lib/presentation/authorize_and_sign/input_dropdown_wrapper.dart +++ b/lib/presentation/authorize_and_sign/input_dropdown_wrapper.dart @@ -11,8 +11,7 @@ import 'package:ribn/containers/ribn_app_bar_container.dart'; // import 'package:ribn_toolkit/widgets/organisms/ribn_app_bar.dart'; /// Builds a wrapper around the AppBar from ToplToolkit to provide ViewModel & AppBarContainer -class InputDropdownWrapper extends StatefulWidget - implements PreferredSizeWidget { +class InputDropdownWrapper extends StatefulWidget implements PreferredSizeWidget { const InputDropdownWrapper({ Key? key, }) : preferredSize = const Size.fromHeight(40), diff --git a/lib/presentation/authorize_and_sign/loading_dapp.dart b/lib/presentation/authorize_and_sign/loading_dapp.dart index 9041597c..2bca8af9 100644 --- a/lib/presentation/authorize_and_sign/loading_dapp.dart +++ b/lib/presentation/authorize_and_sign/loading_dapp.dart @@ -30,8 +30,7 @@ class _LoadingDAppState extends State { void initState() { super.initState(); Timer(const Duration(seconds: 10), () { - StoreProvider.of(context) - .dispatch(SignExternalTxAction(widget.response)); + StoreProvider.of(context).dispatch(SignExternalTxAction(widget.response)); Navigator.of(context).pop(); }); } diff --git a/lib/presentation/authorize_and_sign/review_and_sign.dart b/lib/presentation/authorize_and_sign/review_and_sign.dart index 72f6c55e..5fd5ead2 100644 --- a/lib/presentation/authorize_and_sign/review_and_sign.dart +++ b/lib/presentation/authorize_and_sign/review_and_sign.dart @@ -42,9 +42,10 @@ class ReviewAndSignDApp extends StatefulWidget { class _ReviewAndSignDAppState extends State { late final Map transactionDetails; late final String walletAddress; + late final String currentNetworkName; late final RawTx transaction; bool isExpanded = false; - + ScrollController _scrollController = ScrollController(); final TextStyle defaultTextStyle = const TextStyle( @@ -58,14 +59,10 @@ class _ReviewAndSignDAppState extends State { transactionDetails = widget.request.data!['rawTx']; transaction = RawTx.fromJson(widget.request.data!['rawTx']); - walletAddress = StoreProvider.of(context) - .state - .keychainState - .currentNetwork - .addresses - .first - .toplAddress - .toBase58(); + currentNetworkName = StoreProvider.of(context).state.keychainState.currentNetwork.networkName; + + walletAddress = + StoreProvider.of(context).state.keychainState.currentNetwork.addresses.first.toplAddress.toBase58(); super.initState(); } @@ -87,8 +84,7 @@ class _ReviewAndSignDAppState extends State { curve: Curves.easeInOut, duration: const Duration(seconds: 1), clipBehavior: Clip.hardEdge, - padding: - const EdgeInsets.symmetric(horizontal: 20, vertical: 10), + padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 10), width: 360, height: isExpanded ? 388 : 228, decoration: BoxDecoration( @@ -130,14 +126,9 @@ class _ReviewAndSignDAppState extends State { shrinkWrap: true, itemBuilder: (context, index) { return TransactionRowDetails( - quantity: transactionDetails['to'][index][1] - ['quantity'], - wasReceivedToMyWallet: transactionDetails['to'][index] - [0] == - walletAddress, - isPolyTransfer: transactionDetails['to'][index][1] - ['type'] == - 'Simple', + quantity: transactionDetails['to'][index][1]['quantity'], + wasReceivedToMyWallet: transactionDetails['to'][index][0] == walletAddress, + isPolyTransfer: transactionDetails['to'][index][1]['type'] == 'Simple', ); }, ), @@ -184,8 +175,7 @@ class _ReviewAndSignDAppState extends State { thumbColor: RibnColors.primary, thickness: 10, child: ScrollConfiguration( - behavior: ScrollConfiguration.of(context) - .copyWith(scrollbars: false), + behavior: ScrollConfiguration.of(context).copyWith(scrollbars: false), child: ListView.builder( controller: _scrollController, shrinkWrap: true, @@ -214,12 +204,10 @@ class _ReviewAndSignDAppState extends State { height: 27.0, decoration: const BoxDecoration( color: Colors.white, - borderRadius: - BorderRadius.all(Radius.circular(20)), + borderRadius: BorderRadius.all(Radius.circular(20)), ), child: CustomCopyButton( - textToBeCopied: - getPrettyJson(widget.request.data), + textToBeCopied: getPrettyJson(widget.request.data), bubbleText: 'Copied!', icon: Image.asset( RibnAssets.copyIconAlternate, @@ -245,7 +233,10 @@ class _ReviewAndSignDAppState extends State { crossAxisAlignment: CrossAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.center, children: [ - FeeInfo(fee: int.parse(transactionDetails['fee'])), + FeeInfo( + fee: int.parse(transactionDetails['fee']), + currentNetworkName: currentNetworkName, + ), const SizedBox(height: 15), kIsWeb ? Row( @@ -291,8 +282,7 @@ class _ReviewAndSignDAppState extends State { }, ); - StoreProvider.of(context) - .dispatch(SendInternalMsgAction(response)); + StoreProvider.of(context).dispatch(SendInternalMsgAction(response)); }, ); } diff --git a/lib/presentation/authorize_and_sign/transaction_row_details.dart b/lib/presentation/authorize_and_sign/transaction_row_details.dart index 757e8b5b..aab1c3e5 100644 --- a/lib/presentation/authorize_and_sign/transaction_row_details.dart +++ b/lib/presentation/authorize_and_sign/transaction_row_details.dart @@ -66,9 +66,7 @@ class TransactionRowDetails extends StatelessWidget { Row( children: [ Image.asset( - isPolyTransfer - ? RibnAssets.polyIconCircle - : RibnAssets.undefinedIcon, + isPolyTransfer ? RibnAssets.polyIconCircle : RibnAssets.undefinedIcon, width: 23, ), const SizedBox(width: 5), diff --git a/lib/presentation/basic/custom_back_button.dart b/lib/presentation/basic/custom_back_button.dart index ebc42c2c..875359ac 100644 --- a/lib/presentation/basic/custom_back_button.dart +++ b/lib/presentation/basic/custom_back_button.dart @@ -1,3 +1,4 @@ +// Flutter imports: import 'package:flutter/material.dart'; class CustomBackButton extends StatelessWidget { diff --git a/lib/presentation/enable_page.dart b/lib/presentation/enable_page.dart index 36489547..402994ae 100644 --- a/lib/presentation/enable_page.dart +++ b/lib/presentation/enable_page.dart @@ -65,7 +65,6 @@ class EnablePage extends StatelessWidget { }, ); } - StoreProvider.of(context) - .dispatch(SendInternalMsgAction(response)); + StoreProvider.of(context).dispatch(SendInternalMsgAction(response)); } } diff --git a/lib/presentation/error_section.dart b/lib/presentation/error_section.dart index 29631b50..85117bc6 100644 --- a/lib/presentation/error_section.dart +++ b/lib/presentation/error_section.dart @@ -5,11 +5,11 @@ import 'package:flutter/material.dart'; import 'package:ribn_toolkit/constants/colors.dart'; import 'package:ribn_toolkit/constants/styles.dart'; import 'package:ribn_toolkit/widgets/atoms/large_button.dart'; -import 'package:url_launcher/url_launcher_string.dart'; // Project imports: import 'package:ribn/constants/assets.dart'; import 'package:ribn/constants/strings.dart'; +import 'package:ribn/utils/error_handling_utils.dart'; /// A generic error section that is displayed in case of unexpected errors. class ErrorSection extends StatelessWidget { @@ -71,7 +71,7 @@ class ErrorSection extends StatelessWidget { borderColor: const Color(0xff165867), backgroundColor: RibnColors.background, onPressed: () async { - await launchUrlString(Strings.supportEmailLink); + await handleContactSupport(); }, buttonChild: Text( Strings.contactSupport, diff --git a/lib/presentation/external_signing_page.dart b/lib/presentation/external_signing_page.dart index 5b35acf0..18053d4a 100644 --- a/lib/presentation/external_signing_page.dart +++ b/lib/presentation/external_signing_page.dart @@ -41,8 +41,7 @@ class _ExternalSigningPageState extends State { color: Colors.blue, child: const Text(Strings.sign), onPressed: () { - StoreProvider.of(context) - .dispatch(SignExternalTxAction(widget.request)); + StoreProvider.of(context).dispatch(SignExternalTxAction(widget.request)); }, ), ], diff --git a/lib/presentation/home/home_page.dart b/lib/presentation/home/home_page.dart index 9e3875ee..100d4985 100644 --- a/lib/presentation/home/home_page.dart +++ b/lib/presentation/home/home_page.dart @@ -15,7 +15,8 @@ import 'package:ribn/widgets/ribn_app_bar_wapper.dart'; /// /// Builds the [RibnAppBar], [BottomAppBar], and allows navigation to the 3 main pages. class HomePage extends StatefulWidget { - const HomePage({Key? key}) : super(key: key); + static const Key homePageKey = Key('homePageKey'); + const HomePage({Key key = homePageKey}) : super(key: key); @override State createState() => _HomePageState(); @@ -26,14 +27,8 @@ class _HomePageState extends State with TickerProviderStateMixin { const WalletBalancePage(), const TxHistoryPage(), ]; - final List _pageIcons = [ - Image.asset(RibnAssets.walletGrey), - Image.asset(RibnAssets.clockGrey) - ]; - final List _activePageIcons = [ - Image.asset(RibnAssets.walletBlue), - Image.asset(RibnAssets.clockBlue) - ]; + final List _pageIcons = [Image.asset(RibnAssets.walletGrey), Image.asset(RibnAssets.clockGrey)]; + final List _activePageIcons = [Image.asset(RibnAssets.walletBlue), Image.asset(RibnAssets.clockBlue)]; int _currPage = 0; @override diff --git a/lib/presentation/home/wallet_balance_page.dart b/lib/presentation/home/wallet_balance_page.dart index fe9f52b0..afcc7e94 100644 --- a/lib/presentation/home/wallet_balance_page.dart +++ b/lib/presentation/home/wallet_balance_page.dart @@ -5,32 +5,36 @@ import 'package:flutter/material.dart'; // Package imports: import 'package:brambldart/brambldart.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:ribn_toolkit/constants/colors.dart'; import 'package:ribn_toolkit/constants/styles.dart'; import 'package:ribn_toolkit/widgets/atoms/large_button.dart'; import 'package:ribn_toolkit/widgets/molecules/asset_card.dart'; import 'package:ribn_toolkit/widgets/molecules/custom_tooltip.dart'; import 'package:ribn_toolkit/widgets/molecules/wave_container.dart'; +import 'package:url_launcher/url_launcher.dart'; // Project imports: import 'package:ribn/constants/assets.dart'; -import 'package:ribn/constants/keys.dart'; -import 'package:ribn/constants/routes.dart'; +import 'package:ribn/constants/network_utils.dart'; import 'package:ribn/constants/strings.dart'; import 'package:ribn/containers/wallet_balance_container.dart'; import 'package:ribn/models/asset_details.dart'; import 'package:ribn/presentation/empty_state_screen.dart'; import 'package:ribn/presentation/error_section.dart'; import 'package:ribn/presentation/home/wallet_balance_shimmer.dart'; -import 'package:ribn/utils.dart'; - -// import 'package:url_launcher/url_launcher.dart'; +import 'package:ribn/providers/app_bar_provider.dart'; +import 'package:ribn/utils/extensions.dart'; +import 'package:ribn/utils/utils.dart'; /// One of the 3 main pages on the home screen. /// /// Displays poly balance section and the assets list view. class WalletBalancePage extends StatefulWidget { - const WalletBalancePage({Key? key}) : super(key: key); + static const Key walletBalancePageKey = Key('walletBalancePageKey'); + const WalletBalancePage({ + Key key = walletBalancePageKey, + }) : super(key: key); @override State createState() => _WalletBalancePageState(); @@ -70,59 +74,65 @@ class _WalletBalancePageState extends State { @override Widget build(BuildContext context) { - return WalletBalanceContainer( - // refresh balances on initial build - onInitialBuild: refreshBalances, - onWillChange: (prevVm, currVm) { - // refresh balances on network toggle or when new addresses are generated - final bool shouldRefresh = currVm.walletExists && - (prevVm?.currentNetwork.networkName != currVm.currentNetwork.networkName || - prevVm?.currentNetwork.lastCheckedTimestamp != - currVm.currentNetwork.lastCheckedTimestamp || - prevVm?.currentNetwork.addresses.length != currVm.currentNetwork.addresses.length); - if (shouldRefresh) refreshBalances(currVm); - }, - builder: (BuildContext context, WalletBalanceViewModel vm) => _failedToFetchBalances - ? Center( - child: ErrorSection( - onTryAgain: () => refreshBalances(vm), - ), - ) - : RefreshIndicator( - backgroundColor: RibnColors.primary, - color: RibnColors.secondaryDark, - onRefresh: () async { - return refreshBalances(vm); - }, - child: SingleChildScrollView( - child: Listener( - onPointerDown: (_) { - if (mounted) setState(() {}); + return Consumer( + builder: (context, ref, child) { + return WalletBalanceContainer( + // refresh balances on initial build + onInitialBuild: refreshBalances, + onWillChange: (prevVm, currVm) { + // refresh balances on network toggle or when new addresses are generated + final bool shouldRefresh = currVm.walletExists && + (prevVm?.currentNetwork.networkName != currVm.currentNetwork.networkName || + prevVm?.currentNetwork.lastCheckedTimestamp != currVm.currentNetwork.lastCheckedTimestamp || + prevVm?.currentNetwork.addresses.length != currVm.currentNetwork.addresses.length); + if (shouldRefresh) refreshBalances(currVm); + }, + builder: (BuildContext context, WalletBalanceViewModel vm) => _failedToFetchBalances + ? Center( + child: ErrorSection( + onTryAgain: () => refreshBalances(vm), + ), + ) + : RefreshIndicator( + backgroundColor: RibnColors.primary, + color: RibnColors.secondaryDark, + onRefresh: () async { + return refreshBalances(vm); }, - child: Column( - children: _fetchingBalances - ? [const WalletBalanceShimmer()] - : [ - _buildPolyContainer(vm), - _buildAssetsListView(vm), - ], + child: SingleChildScrollView( + child: Listener( + onPointerDown: (_) { + if (mounted) setState(() {}); + }, + child: Column( + children: _fetchingBalances + ? [const WalletBalanceShimmer()] + : [ + _buildPolyContainer(vm, ref), + _buildAssetsListView(vm), + ], + ), + ), ), ), - ), - ), + ); + }, ); } /// Builds the top-half container on the balance page. /// Displays the balance in Polys and send/receive buttons. - Widget _buildPolyContainer(WalletBalanceViewModel vm) { + Widget _buildPolyContainer(WalletBalanceViewModel vm, WidgetRef ref) { // final Uri url = Uri.parse(tooltipUrl); CustomToolTip renderTooltip() { final bool hasPolys = vm.polyBalance > 0; return CustomToolTip( borderColor: Border.all(color: const Color(0xffE9E9E9)), - offsetPositionLeftValue: 180, + offsetPositionLeftValue: 210, + onOpen: (OverlayEntry overlayEntry) { + ref.read(appBarToolTipOverlayEntryProvider.notifier).state = overlayEntry; + }, toolTipIcon: Image.asset( RibnAssets.circleInfo, width: 24, @@ -136,11 +146,7 @@ class _WalletBalancePageState extends State { ), WidgetSpan( child: GestureDetector( - // onTap: () async => await launchUrl(url), - // Temporary add redirect to DApp flow - onTap: () => Keys.navigatorKey.currentState?.pushNamed( - Routes.loadingDApp, - ), + onTap: () async => await launchUrl(Uri.parse(tooltipUrl)), child: Row( children: [ Text( @@ -163,6 +169,7 @@ class _WalletBalancePageState extends State { ); } + final bool isValhalla = vm.currentNetwork.networkName == NetworkUtils.valhalla; return WaveContainer( containerHeight: 183, containerWidth: double.infinity, @@ -181,7 +188,7 @@ class _WalletBalancePageState extends State { mainAxisAlignment: MainAxisAlignment.center, children: [ Text( - '${vm.polyBalance} POLY', + '${vm.polyBalance} ${isValhalla ? 'nanoPOLY' : 'POLY'}', style: RibnToolkitTextStyles.h2.copyWith( color: const Color(0xFFE5E5E5), letterSpacing: 1.42, @@ -229,7 +236,7 @@ class _WalletBalancePageState extends State { if (vm.assets.isEmpty) { return EmptyStateScreen( icon: RibnAssets.walletWithBorder, - title: Strings.noAssetsInWallet, + title: vm.assets.isEmpty && vm.polyBalance == 0 ? Strings.noAssetsAndBalanceInWallet : Strings.noAssetsInWallet, body: emptyStateBody, buttonOneText: 'Share', buttonOneAction: () async => await showReceivingAddress(), @@ -287,8 +294,7 @@ class _WalletBalancePageState extends State { }) { final String assetIcon = assetDetails?.icon ?? RibnAssets.undefinedIcon; - final String assetUnit = - assetDetails?.unit != null ? formatAssetUnit(assetDetails!.unit) : 'Unit'; + final String assetUnit = assetDetails?.unit != null ? (assetDetails!.unit).formatAssetUnit() : 'Unit'; final String assetLongName = assetDetails?.longName ?? ''; final bool isMissingAssetDetails = assetIcon == RibnAssets.undefinedIcon || assetUnit == 'Unit' || assetLongName.isEmpty; diff --git a/lib/presentation/login/login_page.dart b/lib/presentation/login/login_page.dart index a1411b27..ddfde87d 100644 --- a/lib/presentation/login/login_page.dart +++ b/lib/presentation/login/login_page.dart @@ -1,335 +1,226 @@ // Flutter imports: -// Package imports: -import 'package:bip_topl/bip_topl.dart'; // Flutter imports: import 'package:flutter/foundation.dart'; -import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; -import 'package:flutter_redux/flutter_redux.dart'; + +// Package imports: +import 'package:bip_topl/bip_topl.dart'; +import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:loader_overlay/loader_overlay.dart'; -import 'package:local_auth/local_auth.dart'; +import 'package:ribn_toolkit/constants/colors.dart'; +import 'package:ribn_toolkit/constants/styles.dart'; +import 'package:ribn_toolkit/widgets/atoms/large_button.dart'; +import 'package:ribn_toolkit/widgets/molecules/wave_container.dart'; + // Project imports: import 'package:ribn/actions/keychain_actions.dart'; import 'package:ribn/constants/assets.dart'; import 'package:ribn/constants/keys.dart'; import 'package:ribn/constants/routes.dart'; import 'package:ribn/constants/strings.dart'; -import 'package:ribn/containers/login_container.dart'; -import 'package:ribn/models/app_state.dart'; import 'package:ribn/platform/platform.dart'; +import 'package:ribn/presentation/login/widgets/forget_password_link_section.dart'; +import 'package:ribn/presentation/login/widgets/password_section.dart'; +import 'package:ribn/presentation/login/widgets/support_link_section.dart'; import 'package:ribn/presentation/onboarding/utils.dart'; -import 'package:ribn/utils.dart'; -import 'package:ribn_toolkit/constants/colors.dart'; -import 'package:ribn_toolkit/constants/styles.dart'; -import 'package:ribn_toolkit/widgets/atoms/large_button.dart'; -import 'package:ribn_toolkit/widgets/molecules/custom_tooltip.dart'; -import 'package:ribn_toolkit/widgets/molecules/password_text_field.dart'; -import 'package:ribn_toolkit/widgets/molecules/wave_container.dart'; -import 'package:url_launcher/url_launcher.dart'; +import 'package:ribn/providers/biometrics_provider.dart'; +import 'package:ribn/providers/logger_provider.dart'; +import 'package:ribn/providers/login_provider.dart'; +import 'package:ribn/providers/packages/flutter_secure_storage_provider.dart'; +import 'package:ribn/providers/store_provider.dart'; +import 'package:ribn/utils/extensions.dart'; +import 'package:ribn/utils/input_utils.dart'; +import 'package:ribn/utils/utils.dart'; /// Builds the login page. /// /// Prompts the user to unlock their wallet by entering their wallet-locking password. -class LoginPage extends StatefulWidget { +class LoginPage extends HookConsumerWidget { const LoginPage({ Key? key, }) : super(key: key); - - @override - State createState() => _LoginPageState(); -} - -class _LoginPageState extends State { final double _baseWidth = 310; - final TextEditingController _textEditingController = TextEditingController(); - final LocalAuthentication _localAuthentication = LocalAuthentication(); - - /// True if login was attempted with an incorrect password. - bool _incorrectPasswordEntered = false; - - /// True if authentication through biometrics produces an error - bool _biometricsError = false; - - /// True if biometrics authentication is completed successfully - bool _authorized = false; - Future _biometricsLogin() async { + Future _biometricsLogin(WidgetRef ref, ValueNotifier biometricsError) async { bool authenticated = false; try { - authenticated = await authenticateWithBiometrics(_localAuthentication); - final String toplKey = - (await PlatformLocalStorage.instance.getKeyFromSecureStorage())!; + authenticated = await ref.read(biometricsProvider.notifier).authenticateWithBiometrics(); + + final String toplKey = (await PlatformLocalStorage.instance + .getKeyFromSecureStorage(override: ref.read(flutterSecureStorageProvider)()))!; if (authenticated) { - StoreProvider.of(context).dispatch( - InitializeHDWalletAction( - toplExtendedPrivateKey: Base58Encoder.instance.decode(toplKey), - ), - ); + ref.read(storeProvider).dispatch( + InitializeHDWalletAction( + toplExtendedPrivateKey: Base58Encoder.instance.decode(toplKey), + ), + ); } } catch (e) { - setState(() { - _biometricsError = true; - }); - return; - } - if (!mounted) { - return; + ref.read(loggerProvider).log( + logLevel: LogLevel.Severe, + loggerClass: LoggerClass.Authentication, + message: 'Biometrics authentication failed', + error: e, + stackTrace: StackTrace.current); + + biometricsError.value = true; + return false; } + return authenticated; + } - setState(() { - _authorized = authenticated; + void _checkBiometrics(WidgetRef ref, ValueNotifier biometricsError) async { + ref.read(biometricsProvider).whenData((value) { + if (value.isEnabled) + _biometricsLogin(ref, biometricsError).then( + (authorized) => {if (authorized) Keys.navigatorKey.currentState?.pushReplacementNamed(Routes.home)}, + ); }); } - void _checkBiometrics(LoginViewModel vm) { - if (vm.isBiometricsEnabled) { - _biometricsLogin().then( - (value) => { - if (_authorized) - Keys.navigatorKey.currentState?.pushReplacementNamed(Routes.home) - }, - ); - } + void attemptLogin( + WidgetRef ref, BuildContext context, TextEditingController controller, ValueNotifier PasswordEntered) { + context.loaderOverlay.show(); + dismissKeyboard(context); + + ref.read(loginProvider.notifier).attemptLogin( + context: context, + password: controller.text, + onIncorrectPasswordEntered: () { + PasswordEntered.value = true; + context.loaderOverlay.hide(); + }, + ); } @override - void dispose() { - _textEditingController.dispose(); - super.dispose(); - } + Widget build(BuildContext context, WidgetRef ref) { + /// True if login was attempted with an incorrect password. + final _incorrectPasswordEntered = useState(false); - @override - Widget build(BuildContext context) { - return LoginContainer( - onInitialBuild: _checkBiometrics, - builder: (context, vm) { - void attemptLogin() { - context.loaderOverlay.show(); - vm.attemptLogin( - password: _textEditingController.text, - onIncorrectPasswordEntered: () { - setState(() { - _incorrectPasswordEntered = true; - }); - context.loaderOverlay.hide(); - }, - ); - } + /// True if authentication through biometrics produces an error + final _biometricsError = useState(false); - return Listener( - onPointerDown: (_) { - if (mounted) setState(() {}); - }, - child: LoaderOverlay( - child: Scaffold( - body: SingleChildScrollView( - child: WaveContainer( - containerHeight: MediaQuery.of(context).size.height, - containerWidth: MediaQuery.of(context).size.width, - waveAmplitude: 30, - containerChild: Column( - mainAxisAlignment: kIsWeb - ? MainAxisAlignment.start - : MainAxisAlignment.spaceAround, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Column( - children: [ - SizedBox(height: deviceTopPadding()), - renderIfWeb(const SizedBox(height: 40)), - Image.asset( - RibnAssets.newRibnLogo, - width: kIsWeb ? 102 : 138, - ), - Text( - Strings.ribnWallet, - style: RibnToolkitTextStyles.h1.copyWith( - color: Colors.white, - ), + final _textEditingController = useTextEditingController(); + + final biometrics = ref.watch(biometricsProvider); + + final notifier = ref.read(loginProvider.notifier); + + useEffect(() { + Future.delayed(Duration.zero, () { + _checkBiometrics(ref, _biometricsError); + }); + return null; + }, [biometrics]); + + return Listener( + onPointerDown: (_) {}, + child: LoaderOverlay( + child: Scaffold( + body: SingleChildScrollView( + child: WaveContainer( + containerHeight: context.clientHeight, + containerWidth: context.clientWidth, + waveAmplitude: 30, + containerChild: Column( + mainAxisAlignment: kIsWeb ? MainAxisAlignment.start : MainAxisAlignment.spaceAround, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Column( + children: [ + SizedBox(height: deviceTopPadding()), + renderIfWeb(const SizedBox(height: 40)), + Image.asset( + RibnAssets.newRibnLogo, + width: kIsWeb ? 102 : 138, + ), + Text( + Strings.ribnWallet, + style: RibnToolkitTextStyles.h1.copyWith( + color: Colors.white, ), - const SizedBox(height: 5), - Center( - child: SizedBox( - width: kIsWeb ? _baseWidth - 70 : _baseWidth, - child: Center( - child: Text( - Strings.intro, - style: RibnToolkitTextStyles.h3.copyWith( - color: Colors.white, - fontWeight: FontWeight.w300, - height: 1.7, - fontSize: kIsWeb ? 13 : 14, - ), - textAlign: TextAlign.center, + ), + const SizedBox(height: 5), + Center( + child: SizedBox( + width: kIsWeb ? _baseWidth - 70 : _baseWidth, + child: Center( + child: Text( + Strings.intro, + style: RibnToolkitTextStyles.h3.copyWith( + color: Colors.white, + fontWeight: FontWeight.w300, + height: 1.7, + fontSize: kIsWeb ? 13 : 14, ), + textAlign: TextAlign.center, ), ), ), - ], + ), + ], + ), + renderIfWeb(const SizedBox(height: 40)), + PasswordSection( + baseWidth: _baseWidth, + controller: _textEditingController, + onSubmitted: () => attemptLogin(ref, context, _textEditingController, _incorrectPasswordEntered), + ), + kIsWeb ? const SizedBox(height: 40) : const SizedBox(height: 25), + LargeButton( + backgroundColor: RibnColors.primary, + dropShadowColor: RibnColors.whiteButtonShadow, + buttonChild: Text( + Strings.unlock, + style: RibnToolkitTextStyles.btnLarge.copyWith( + color: Colors.white, + ), ), - renderIfWeb(const SizedBox(height: 40)), - Column( + onPressed: () => attemptLogin(ref, context, _textEditingController, _incorrectPasswordEntered), + ), + renderIfWeb(const SizedBox(height: 20)), + ForgetPasswordLinkSection(baseWidth: _baseWidth, onButtonPress: notifier.restoreWallet), + const SizedBox(height: 40), + SizedBox( + height: 50, + child: Column( + mainAxisAlignment: MainAxisAlignment.end, children: [ - _buildTextFieldLabel(), - const SizedBox(height: 8), - PasswordTextField( - onSubmitted: attemptLogin, - hintText: Strings.typeSomething, - controller: _textEditingController, - ), + SupportLinkSection(baseWidth: _baseWidth), + const SizedBox(height: 10), + _incorrectPasswordEntered.value + ? Text( + 'Incorrect Password', + style: const TextStyle( + color: Colors.red, + ).copyWith( + fontWeight: FontWeight.bold, + fontSize: kIsWeb ? 13 : 14, + ), + ) + : const SizedBox(), + _biometricsError.value + ? Text( + 'There was an issue with Face ID, please try again', + style: const TextStyle( + color: Colors.red, + ).copyWith( + fontWeight: FontWeight.bold, + fontSize: kIsWeb ? 13 : 14, + ), + ) + : const SizedBox() ], ), - kIsWeb - ? const SizedBox(height: 40) - : const SizedBox(height: 25), - LargeButton( - backgroundColor: RibnColors.primary, - dropShadowColor: RibnColors.whiteButtonShadow, - buttonChild: Text( - Strings.unlock, - style: RibnToolkitTextStyles.btnLarge.copyWith( - color: Colors.white, - ), - ), - onPressed: attemptLogin, - ), - renderIfWeb(const SizedBox(height: 20)), - _buildForgetPasswordLink(vm.restoreWallet), - const SizedBox(height: 40), - SizedBox( - height: 50, - child: Column( - mainAxisAlignment: MainAxisAlignment.end, - children: [ - _buildSupportLink(), - const SizedBox(height: 10), - _incorrectPasswordEntered - ? Text( - 'Incorrect Password', - style: const TextStyle( - color: Colors.red, - ).copyWith( - fontWeight: FontWeight.bold, - fontSize: kIsWeb ? 13 : 14, - ), - ) - : const SizedBox(), - _biometricsError - ? Text( - 'There was an issue with Face ID, please try again', - style: const TextStyle( - color: Colors.red, - ).copyWith( - fontWeight: FontWeight.bold, - fontSize: kIsWeb ? 13 : 14, - ), - ) - : const SizedBox() - ], - ), - ), - ], - ), + ), + ], ), ), ), ), - ); - }, - ); - } - - Widget _buildTextFieldLabel() { - return SizedBox( - width: _baseWidth, - child: Row( - children: [ - Text( - Strings.enterWalletPassword, - style: RibnToolkitTextStyles.h3.copyWith( - color: Colors.white, - fontSize: kIsWeb ? 13 : 14, - ), - ), - // ignore: prefer_const_constructors - Padding( - padding: const EdgeInsets.symmetric(horizontal: 4.0), - child: CustomToolTip( - borderColor: Border.all(color: const Color(0xffE9E9E9)), - offsetPositionLeftValue: 160, - toolTipIcon: Image.asset( - RibnAssets.greyHelpBubble, - width: 18, - color: Colors.white, - ), - toolTipChild: const Text( - Strings.loginPasswordInfo, - style: RibnToolkitTextStyles.toolTipTextStyle, - ), - ), - ), - ], - ), - ); - } - - /// Builds a link to redirect user to the restore wallet flow. - Widget _buildForgetPasswordLink(onButtonPress) { - return SizedBox( - width: _baseWidth, - child: Center( - child: RichText( - text: TextSpan( - style: RibnToolkitTextStyles.h3.copyWith( - color: RibnColors.secondary, - fontSize: kIsWeb ? 13 : 14, - ), - children: [ - TextSpan( - text: Strings.forgotPassword, - recognizer: TapGestureRecognizer() - ..onTap = () => onButtonPress(), - ) - ], - ), - ), - ), - ); - } - - /// Builds a link to redirect user to the support email. - Widget _buildSupportLink() { - return SizedBox( - width: _baseWidth, - child: Center( - child: RichText( - text: TextSpan( - style: RibnToolkitTextStyles.h3.copyWith( - color: Colors.white, - fontSize: kIsWeb ? 13 : 14, - ), - children: [ - const TextSpan( - text: Strings.needHelp, - ), - TextSpan( - text: Strings.ribnSupport, - style: RibnToolkitTextStyles.h3.copyWith( - color: RibnColors.secondary, - fontSize: kIsWeb ? 13 : 14, - ), - recognizer: TapGestureRecognizer() - ..onTap = () async { - final Uri url = Uri.parse(Strings.supportEmailLink); - - await launchUrl(url); - }, - ) - ], - ), - ), - ), - ); + )); } } diff --git a/lib/presentation/login/widgets/forget_password_link_section.dart b/lib/presentation/login/widgets/forget_password_link_section.dart new file mode 100644 index 00000000..0d885b51 --- /dev/null +++ b/lib/presentation/login/widgets/forget_password_link_section.dart @@ -0,0 +1,42 @@ +// Flutter imports: +import 'package:flutter/foundation.dart'; +import 'package:flutter/gestures.dart'; +import 'package:flutter/material.dart'; + +// Package imports: +import 'package:ribn_toolkit/constants/colors.dart'; +import 'package:ribn_toolkit/constants/styles.dart'; + +// Project imports: +import 'package:ribn/constants/strings.dart'; + +/// Widget to redirect user to the restore wallet flow. +class ForgetPasswordLinkSection extends StatelessWidget { + const ForgetPasswordLinkSection({Key? key, required this.baseWidth, required this.onButtonPress}) : super(key: key); + + final double baseWidth; + final VoidCallback onButtonPress; + + @override + Widget build(BuildContext context) { + return SizedBox( + width: baseWidth, + child: Center( + child: RichText( + text: TextSpan( + style: RibnToolkitTextStyles.h3.copyWith( + color: RibnColors.secondary, + fontSize: kIsWeb ? 13 : 14, + ), + children: [ + TextSpan( + text: Strings.forgotPassword, + recognizer: TapGestureRecognizer()..onTap = () => onButtonPress(), + ) + ], + ), + ), + ), + ); + } +} diff --git a/lib/presentation/login/widgets/password_section.dart b/lib/presentation/login/widgets/password_section.dart new file mode 100644 index 00000000..89db6398 --- /dev/null +++ b/lib/presentation/login/widgets/password_section.dart @@ -0,0 +1,63 @@ +// Flutter imports: +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; + +// Package imports: +import 'package:ribn_toolkit/constants/styles.dart'; +import 'package:ribn_toolkit/widgets/molecules/custom_tooltip.dart'; +import 'package:ribn_toolkit/widgets/molecules/password_text_field.dart'; + +// Project imports: +import 'package:ribn/constants/assets.dart'; +import 'package:ribn/constants/strings.dart'; + +class PasswordSection extends StatelessWidget { + const PasswordSection({Key? key, required this.baseWidth, required this.controller, this.onSubmitted}) + : super(key: key); + + final double baseWidth; + final Function? onSubmitted; + final TextEditingController controller; + + @override + Widget build(BuildContext context) { + return Column(children: [ + SizedBox( + width: baseWidth, + child: Wrap( + children: [ + Text( + Strings.enterWalletPassword, + style: RibnToolkitTextStyles.h3.copyWith( + color: Colors.white, + fontSize: kIsWeb ? 13 : 14, + ), + ), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 4.0), + child: CustomToolTip( + borderColor: Border.all(color: const Color(0xffE9E9E9)), + offsetPositionLeftValue: 160, + toolTipIcon: Image.asset( + RibnAssets.greyHelpBubble, + width: 18, + color: Colors.white, + ), + toolTipChild: const Text( + Strings.loginPasswordInfo, + style: RibnToolkitTextStyles.toolTipTextStyle, + ), + ), + ), + ], + ), + ), + const SizedBox(height: 8), + PasswordTextField( + onSubmitted: onSubmitted, + hintText: Strings.typeSomething, + controller: controller, + ), + ]); + } +} diff --git a/lib/presentation/login/widgets/support_link_section.dart b/lib/presentation/login/widgets/support_link_section.dart new file mode 100644 index 00000000..01bc439d --- /dev/null +++ b/lib/presentation/login/widgets/support_link_section.dart @@ -0,0 +1,52 @@ +// Flutter imports: +import 'package:flutter/foundation.dart'; +import 'package:flutter/gestures.dart'; +import 'package:flutter/material.dart'; + +// Package imports: +import 'package:ribn_toolkit/constants/colors.dart'; +import 'package:ribn_toolkit/constants/styles.dart'; + +// Project imports: +import 'package:ribn/constants/strings.dart'; +import 'package:ribn/utils/error_handling_utils.dart'; + +/// Widget to redirect user to the support email. +class SupportLinkSection extends StatelessWidget { + const SupportLinkSection({Key? key, required this.baseWidth}) : super(key: key); + + final double baseWidth; + + @override + Widget build(BuildContext context) { + return SizedBox( + width: baseWidth, + child: Center( + child: RichText( + text: TextSpan( + style: RibnToolkitTextStyles.h3.copyWith( + color: Colors.white, + fontSize: kIsWeb ? 13 : 14, + ), + children: [ + const TextSpan( + text: Strings.needHelp, + ), + TextSpan( + text: Strings.ribnSupport, + style: RibnToolkitTextStyles.h3.copyWith( + color: RibnColors.secondary, + fontSize: kIsWeb ? 13 : 14, + ), + recognizer: TapGestureRecognizer() + ..onTap = () async { + await handleContactSupport(); + }, + ) + ], + ), + ), + ), + ); + } +} diff --git a/lib/presentation/onboarding/create_wallet/create_password_page.dart b/lib/presentation/onboarding/create_wallet/create_password_page.dart index 4e819e8e..ef7fbb1b 100644 --- a/lib/presentation/onboarding/create_wallet/create_password_page.dart +++ b/lib/presentation/onboarding/create_wallet/create_password_page.dart @@ -1,83 +1,59 @@ // Flutter imports: -import 'package:flutter/foundation.dart'; -import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; // Package imports: +import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:loader_overlay/loader_overlay.dart'; -import 'package:ribn_toolkit/constants/colors.dart'; import 'package:ribn_toolkit/constants/styles.dart'; -import 'package:ribn_toolkit/widgets/molecules/checkbox_wrappable_text.dart'; -import 'package:ribn_toolkit/widgets/molecules/password_text_field.dart'; -import 'package:url_launcher/url_launcher.dart'; // Project imports: import 'package:ribn/constants/assets.dart'; import 'package:ribn/constants/routes.dart'; import 'package:ribn/constants/strings.dart'; -import 'package:ribn/containers/create_password_container.dart'; import 'package:ribn/presentation/onboarding/utils.dart'; import 'package:ribn/presentation/onboarding/widgets/confirmation_button.dart'; import 'package:ribn/presentation/onboarding/widgets/mobile_onboarding_progress_bar.dart'; import 'package:ribn/presentation/onboarding/widgets/onboarding_container.dart'; +import 'package:ribn/presentation/onboarding/widgets/password_section.dart'; import 'package:ribn/presentation/onboarding/widgets/web_onboarding_app_bar.dart'; -import 'package:ribn/utils.dart'; +import 'package:ribn/providers/onboarding_provider.dart'; +import 'package:ribn/providers/password_provider.dart'; +import 'package:ribn/utils/navigation_utils.dart'; +import 'package:ribn/utils/utils.dart'; -class CreatePasswordPage extends StatefulWidget { - const CreatePasswordPage({Key? key}) : super(key: key); +// import 'package:ribn/constants/routes.dart'; +// import 'package:ribn/containers/create_password_container.dart'; - @override - _CreatePasswordPageState createState() => _CreatePasswordPageState(); -} +class CreatePasswordPage extends HookConsumerWidget { + static const Key createPasswordPageKey = Key('createPasswordPageKey'); + static const Key createPasswordConfirmationButtonKey = Key('createPasswordConfirmationButtonKey'); + CreatePasswordPage({ + Key key = createPasswordPageKey, + }) : super(key: key); -class _CreatePasswordPageState extends State { - final FocusNode _newPasswordFocus = FocusNode(); - final FocusNode _confirmPasswordFocus = FocusNode(); - final TextEditingController _newPasswordController = TextEditingController(); - final TextEditingController _confirmPasswordController = TextEditingController(); - bool _termsOfUseChecked = false; - bool _atLeast8Chars = false; - bool _passwordsMatch = false; + final _formKey = GlobalKey(); @override - void initState() { - [_newPasswordFocus, _newPasswordController].toList().forEach((elem) { - elem.addListener(() { - if (!_newPasswordFocus.hasPrimaryFocus || _newPasswordController.text.length >= 8) { - _atLeast8Chars = - _newPasswordController.text.isNotEmpty && _newPasswordController.text.length >= 8; - setState(() {}); - } - }); - }); - [_confirmPasswordFocus, _confirmPasswordController].toList().forEach((elem) { - elem.addListener(() { - if (!_confirmPasswordFocus.hasPrimaryFocus || - _confirmPasswordController.text == _newPasswordController.text) { - _passwordsMatch = _confirmPasswordController.text.isNotEmpty && - _confirmPasswordController.text == _newPasswordController.text; - setState(() {}); - } - }); - }); - super.initState(); - } + Widget build(BuildContext context, WidgetRef ref) { + useEffect(() { + return () { + // ignore: invalid_use_of_protected_member + _formKey.currentState?.dispose(); + }; + }, []); - @override - Widget build(BuildContext context) { - return CreatePasswordContainer( - onDidChange: (prevVm, newVm) { - if (prevVm?.keyStoreJson != newVm.keyStoreJson && newVm.passwordSuccessfullyCreated) { - context.loaderOverlay.hide(); - navigateToRoute(context, Routes.walletInfoChecklist); - } - }, - builder: (context, vm) => LoaderOverlay( - child: Scaffold( - resizeToAvoidBottomInset: true, - body: OnboardingContainer( - child: SingleChildScrollView( - clipBehavior: Clip.none, + final onboardingNotifier = ref.read(onboardingProvider.notifier); + final passwordState = ref.watch(passwordProvider); + + return LoaderOverlay( + child: Scaffold( + resizeToAvoidBottomInset: true, + body: OnboardingContainer( + child: SingleChildScrollView( + clipBehavior: Clip.none, + child: Form( + key: _formKey, child: Column( children: [ renderIfWeb(const WebOnboardingAppBar(currStep: 2)), @@ -108,51 +84,7 @@ class _CreatePasswordPageState extends State { ), ), SizedBox(height: adaptHeight(0.02)), - _buildNewPasswordSection(), - SizedBox(height: adaptHeight(0.02)), - _buildConfirmPasswordSection(), - SizedBox(height: adaptHeight(0.02)), - CheckboxWrappableText( - wrapText: false, - borderColor: _termsOfUseChecked - ? const Color(0xff80FF00) - : RibnColors.lightGreyTitle, - value: _termsOfUseChecked, - onChanged: (bool? checked) { - setState(() { - _termsOfUseChecked = checked ?? false; - }); - }, - label: RichText( - maxLines: 2, - key: GlobalKey(), - text: TextSpan( - children: [ - TextSpan( - text: Strings.readAndAgreedToU, - style: RibnToolkitTextStyles.h3.copyWith( - color: RibnColors.lightGreyTitle, - fontSize: 15, - ), - ), - TextSpan( - text: Strings.termsOfUse, - style: RibnToolkitTextStyles.h3.copyWith( - color: const Color(0xff00FFC5), - fontSize: 15, - ), - recognizer: TapGestureRecognizer() - ..onTap = () async { - final Uri url = Uri.parse(Strings.termsOfUseUrl); - - await launchUrl(url); - }, - ), - ], - ), - ), - activeText: true, - ), + PasswordSection(), ], ), ), @@ -162,10 +94,15 @@ class _CreatePasswordPageState extends State { ), ConfirmationButton( text: Strings.done, - disabled: !_atLeast8Chars || !_passwordsMatch || !_termsOfUseChecked, - onPressed: () { + key: createPasswordConfirmationButtonKey, + disabled: !passwordState.atLeast8Chars || + !passwordState.passwordsMatch || + !passwordState.termsOfUseChecked, + onPressed: () async { context.loaderOverlay.show(); - vm.attemptCreatePassword(_confirmPasswordController.text); + await onboardingNotifier.createPassword(password: passwordState.password); + context.loaderOverlay.hide(); + navigateToRoute(route: Routes.walletInfoChecklist); }, ), ], @@ -176,101 +113,4 @@ class _CreatePasswordPageState extends State { ), ); } - - Widget _buildNewPasswordSection() { - return Column( - children: [ - Align( - alignment: Alignment.centerLeft, - child: Text( - Strings.newWalletPassword, - textAlign: TextAlign.left, - style: RibnToolkitTextStyles.h3.copyWith( - fontWeight: FontWeight.bold, - color: RibnColors.lightGreyTitle, - ), - ), - ), - const SizedBox(height: 8), - Align( - alignment: Alignment.centerLeft, - child: PasswordTextField( - focusNode: _newPasswordFocus, - width: kIsWeb ? 350 : adaptWidth(0.9), - fillColor: RibnColors.whiteButtonShadow, - controller: _newPasswordController, - hintText: '', - obscurePassword: true, - textInputAction: TextInputAction.next, - ), - ), - const SizedBox(height: 8), - Align( - alignment: Alignment.centerLeft, - child: Text( - Strings.atLeast8Chars, - textAlign: TextAlign.left, - style: RibnToolkitTextStyles.h3.copyWith( - color: !_atLeast8Chars && _newPasswordController.text.isNotEmpty - ? Colors.red - : Colors.white, - ), - ), - ), - Align( - alignment: Alignment.centerLeft, - child: Text( - Strings.passwordExample, - textAlign: TextAlign.left, - style: RibnToolkitTextStyles.h3.copyWith( - color: Colors.white, - ), - ), - ), - ], - ); - } - - _buildConfirmPasswordSection() { - return Column( - children: [ - Align( - alignment: Alignment.centerLeft, - child: Text( - Strings.confirmWalletPassword, - textAlign: TextAlign.left, - style: RibnToolkitTextStyles.h3.copyWith( - fontWeight: FontWeight.bold, - color: RibnColors.lightGreyTitle, - ), - ), - ), - const SizedBox(height: 8), - Align( - alignment: Alignment.centerLeft, - child: PasswordTextField( - focusNode: _confirmPasswordFocus, - width: kIsWeb ? 350 : adaptWidth(0.9), - fillColor: RibnColors.whiteButtonShadow, - controller: _confirmPasswordController, - hintText: '', - obscurePassword: true, - ), - ), - const SizedBox(height: 8), - Align( - alignment: Alignment.centerLeft, - child: Text( - Strings.passwordsMustMatch, - textAlign: TextAlign.left, - style: RibnToolkitTextStyles.h3.copyWith( - color: !_passwordsMatch && _confirmPasswordController.text.isNotEmpty - ? Colors.red - : Colors.white, - ), - ), - ), - ], - ); - } } diff --git a/lib/presentation/onboarding/create_wallet/enable_biometrics_page.dart b/lib/presentation/onboarding/create_wallet/enable_biometrics_page.dart index 5fea4fe8..96d29d7f 100644 --- a/lib/presentation/onboarding/create_wallet/enable_biometrics_page.dart +++ b/lib/presentation/onboarding/create_wallet/enable_biometrics_page.dart @@ -7,62 +7,46 @@ import 'package:flutter/material.dart'; // Package imports: import 'package:app_settings/app_settings.dart'; -import 'package:flutter_redux/flutter_redux.dart'; -import 'package:local_auth/local_auth.dart'; +import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:ribn_toolkit/constants/colors.dart'; import 'package:ribn_toolkit/constants/styles.dart'; -import 'package:ribn_toolkit/widgets/atoms/custom_icon_button.dart'; import 'package:ribn_toolkit/widgets/atoms/large_button.dart'; // Project imports: -import 'package:ribn/actions/user_details_actions.dart'; import 'package:ribn/constants/assets.dart'; import 'package:ribn/constants/keys.dart'; import 'package:ribn/constants/routes.dart'; import 'package:ribn/constants/strings.dart'; -import 'package:ribn/models/app_state.dart'; import 'package:ribn/presentation/onboarding/widgets/onboarding_container.dart'; import 'package:ribn/presentation/transfers/bottom_review_action.dart'; -import 'package:ribn/utils.dart'; +import 'package:ribn/providers/biometrics_provider.dart'; -class EnableBiometrics extends StatefulWidget { - const EnableBiometrics({Key? key}) : super(key: key); +class EnableBiometrics extends HookConsumerWidget { + static const Key enableBiometricsKey = Key('enableBiometricsKey'); - @override - State createState() => _EnableBiometricsState(); -} + const EnableBiometrics({Key key = enableBiometricsKey}) : super(key: key); -class _EnableBiometricsState extends State { - final LocalAuthentication _localAuthentication = LocalAuthentication(); - bool _authorized = false; + Future runBiometrics(WidgetRef ref, BuildContext context, ValueNotifier authorized) async { + final notifier = ref.read(biometricsProvider.notifier); - Future runBiometrics(auth) async { bool authenticated = false; - await isBiometricsAuthenticationEnrolled(auth); + await notifier.isBiometricsAuthenticationEnrolled(); try { - authenticated = await authenticateWithBiometrics(auth); + authenticated = await notifier.authenticateWithBiometrics(); } catch (e) { - if (Platform.isAndroid) await _showMyDialog(); + if (Platform.isAndroid) await _showMyDialog(context); return; } - if (!mounted || !authenticated) { - return; + if (authenticated) { + authorized.value = authenticated; + ref.read(biometricsProvider.notifier).toggleBiometrics(overrideValue: true); } - - setState(() { - _authorized = authenticated ? true : false; - }); - - StoreProvider.of(context).dispatch( - UpdateBiometricsAction( - isBiometricsEnabled: true, - ), - ); } - Future _showMyDialog() async { + Future _showMyDialog(context) async { return showDialog( context: context, barrierDismissible: false, @@ -95,7 +79,9 @@ class _EnableBiometricsState extends State { } @override - Widget build(BuildContext context) { + Widget build(BuildContext context, WidgetRef ref) { + final authorized = useState(false); + return Scaffold( extendBody: true, body: OnboardingContainer( @@ -103,17 +89,11 @@ class _EnableBiometricsState extends State { children: [ Row( mainAxisAlignment: MainAxisAlignment.end, + mainAxisSize: MainAxisSize.max, children: [ - CustomIconButton( - onPressed: () { - Keys.navigatorKey.currentState - ?.pushNamed(Routes.walletCreated); - }, - icon: const Icon( - Icons.close, - color: RibnColors.lightGreyTitle, - ), - ), + Container( + height: 50, + ) ], ), Text( @@ -126,9 +106,7 @@ class _EnableBiometricsState extends State { Padding( padding: const EdgeInsets.only(top: 30.0, bottom: 45), child: Image.asset( - Platform.isIOS - ? RibnAssets.iosBiometrics - : RibnAssets.andriodBiometrics, + Platform.isIOS ? RibnAssets.iosBiometrics : RibnAssets.andriodBiometrics, width: 111, ), ), @@ -147,9 +125,6 @@ class _EnableBiometricsState extends State { transparentBackground: true, children: Column( children: [ - const SizedBox( - height: 15, - ), LargeButton( buttonHeight: 50, buttonWidth: double.infinity, @@ -160,12 +135,8 @@ class _EnableBiometricsState extends State { ), ), onPressed: () { - runBiometrics(_localAuthentication).then( - (value) => { - if (_authorized) - Keys.navigatorKey.currentState - ?.pushNamed(Routes.walletCreated) - }, + runBiometrics(ref, context, authorized).then( + (value) => {if (authorized.value) Keys.navigatorKey.currentState?.pushNamed(Routes.walletCreated)}, ); }, backgroundColor: RibnColors.primary, diff --git a/lib/presentation/onboarding/create_wallet/getting_started_page.dart b/lib/presentation/onboarding/create_wallet/getting_started_page.dart index 96b22aa4..8e8b7c62 100644 --- a/lib/presentation/onboarding/create_wallet/getting_started_page.dart +++ b/lib/presentation/onboarding/create_wallet/getting_started_page.dart @@ -17,7 +17,9 @@ import 'package:ribn/presentation/onboarding/widgets/onboarding_container.dart'; import 'package:ribn/presentation/onboarding/widgets/web_onboarding_app_bar.dart'; class GettingStartedPage extends StatelessWidget { - const GettingStartedPage({Key? key}) : super(key: key); + static const Key gettingStartedPageKey = Key('gettingStartedPageKey'); + static const Key gettingStartedConfirmationButtonKey = Key('gettingStartedConfirmationButtonKey'); + const GettingStartedPage({Key key = gettingStartedPageKey}) : super(key: key); @override Widget build(BuildContext context) { @@ -49,12 +51,15 @@ class GettingStartedPage extends StatelessWidget { ), ), kIsWeb ? const SizedBox(height: 150) : const Spacer(), - ConfirmationButton( - text: Strings.okLetsGo, - onPressed: () { - Keys.navigatorKey.currentState - ?.pushNamed(Routes.seedPhraseInfoChecklist); - }, + Padding( + padding: EdgeInsets.only(bottom: 50), + child: ConfirmationButton( + key: gettingStartedConfirmationButtonKey, + text: Strings.okLetsGo, + onPressed: () { + Keys.navigatorKey.currentState?.pushNamed(Routes.seedPhraseInfoChecklist); + }, + ), ), ], ), diff --git a/lib/presentation/onboarding/create_wallet/seed_phrase_confirmation_page.dart b/lib/presentation/onboarding/create_wallet/seed_phrase_confirmation_page.dart index eb050370..c82f7469 100644 --- a/lib/presentation/onboarding/create_wallet/seed_phrase_confirmation_page.dart +++ b/lib/presentation/onboarding/create_wallet/seed_phrase_confirmation_page.dart @@ -4,6 +4,8 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; // Package imports: +import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:ribn_toolkit/constants/styles.dart'; import 'package:ribn_toolkit/widgets/atoms/custom_text_field.dart'; import 'package:ribn_toolkit/widgets/organisms/onboarding_progress_bar.dart'; @@ -13,114 +15,122 @@ import 'package:ribn/constants/assets.dart'; import 'package:ribn/constants/keys.dart'; import 'package:ribn/constants/routes.dart'; import 'package:ribn/constants/strings.dart'; -import 'package:ribn/containers/seed_phrase_confirmation_container.dart'; import 'package:ribn/presentation/onboarding/utils.dart'; import 'package:ribn/presentation/onboarding/widgets/confirmation_button.dart'; import 'package:ribn/presentation/onboarding/widgets/onboarding_container.dart'; import 'package:ribn/presentation/onboarding/widgets/web_onboarding_app_bar.dart'; -import 'package:ribn/utils.dart'; +import 'package:ribn/providers/onboarding_provider.dart'; +import 'package:ribn/utils/utils.dart'; -class SeedPhraseConfirmationPage extends StatefulWidget { - const SeedPhraseConfirmationPage({Key? key}) : super(key: key); +class SeedPhraseConfirmationPage extends HookConsumerWidget { + static const Key seedPhraseConfirmationPageKey = Key('seedPhraseConfirmationPageKey'); + static const Key seedPhraseConfirmationConfirmationButtonKey = Key('seedPhraseConfirmationConfirmationButtonKey'); - @override - State createState() => _SeedPhraseConfirmationPageState(); -} + static Key confirmationTextFieldKey(int index) => Key('confirmationTextFieldKey$index'); -class _SeedPhraseConfirmationPageState extends State { - final Map idxControllerMap = {}; - final Map controllerErrorMap = {}; + SeedPhraseConfirmationPage({Key key = seedPhraseConfirmationPageKey}) : super(key: key); - @override - Widget build(BuildContext context) { - return SeedPhraseConfirmationContainer( - onInit: (store) { - // populate [controllers] and [hasErrors] maps - store.state.onboardingState.mobileConfirmIdxs.toList().forEach((idx) { - final TextEditingController controller = TextEditingController(); - idxControllerMap[idx] = controller; - controllerErrorMap[controller] = false; - }); - }, - builder: (context, vm) { - return Scaffold( - body: OnboardingContainer( - child: SingleChildScrollView( - clipBehavior: Clip.none, - child: Column( - children: [ - renderIfWeb(const WebOnboardingAppBar(currStep: 1)), - SizedBox( - width: 200, - child: Text( - Strings.writeDownSeedPhrase, - style: RibnToolkitTextStyles.onboardingH1.copyWith(letterSpacing: 0.5), - textAlign: TextAlign.center, - ), + final _formKey = GlobalKey(); + Widget build(BuildContext context, WidgetRef ref) { + final onboardingState = ref.watch(onboardingProvider); + + useEffect(() { + return () { + // ignore: invalid_use_of_protected_member + _formKey.currentState?.dispose(); + }; + }); + + final List mnemonicWordsList = onboardingState.shuffledMnemonic; + final List confirmeIdxs = onboardingState.mobileConfirmIdxs; + + return Scaffold( + body: OnboardingContainer( + child: SingleChildScrollView( + clipBehavior: Clip.none, + child: Form( + key: _formKey, + child: Column( + children: [ + renderIfWeb(const WebOnboardingAppBar(currStep: 1)), + SizedBox( + width: 200, + child: Text( + Strings.writeDownSeedPhrase, + style: RibnToolkitTextStyles.onboardingH1.copyWith(letterSpacing: 0.5), + textAlign: TextAlign.center, ), - Image.asset(RibnAssets.penPaperPng, width: 70), - Padding( - padding: EdgeInsets.only( - top: adaptHeight(0.04), - bottom: adaptHeight(0.02), - ), - child: const Text( - Strings.ensureYourWordsAreCorrect, - style: RibnToolkitTextStyles.onboardingH3, - ), + ), + Image.asset(RibnAssets.penPaperPng, width: 70), + Padding( + padding: EdgeInsets.only( + top: adaptHeight(0.04), + bottom: adaptHeight(0.02), ), - _buildSeedphraseConfirmationGrid( - vm.confirmeIdxs, - vm.mnemonicWordsList, + child: const Text( + Strings.ensureYourWordsAreCorrect, + style: RibnToolkitTextStyles.onboardingH3, ), - const SizedBox(height: 40), - renderIfMobile( - const Padding( - padding: EdgeInsets.only(bottom: 20.0), - child: OnboardingProgressBar(numSteps: 4, currStep: 1), - ), + ), + _SeedPhraseConfirmationGrid( + confirmIdxs: confirmeIdxs, + mnemonicWordsList: mnemonicWordsList, + ), + const SizedBox(height: 40), + renderIfMobile( + const Padding( + padding: EdgeInsets.only(bottom: 20.0), + child: OnboardingProgressBar(numSteps: 4, currStep: 1), ), - ConfirmationButton( + ), + Padding( + padding: EdgeInsets.only(bottom: 30), + child: ConfirmationButton( + key: seedPhraseConfirmationConfirmationButtonKey, text: Strings.done, onPressed: () { - // Update errors if text entered does not match mnemonic word at specified idx - idxControllerMap.forEach((idx, controller) { - final bool wordsMatch = controller.text.trim() == vm.mnemonicWordsList[idx]; - controllerErrorMap[controller] = !wordsMatch; - }); - setState(() {}); - if (!controllerErrorMap.values.contains(true)) { + if (_formKey.currentState!.validate()) { Keys.navigatorKey.currentState?.pushNamed(Routes.createPassword); } }, ), - ], - ), + ), + ], ), ), - ); - }, + ), + ), ); } +} - Widget _buildSeedphraseConfirmationGrid( - List confirmIdxs, - List mnemonicWordsList, - ) { +class _SeedPhraseConfirmationGrid extends StatelessWidget { + final List confirmIdxs; + final List mnemonicWordsList; + const _SeedPhraseConfirmationGrid({ + required this.confirmIdxs, + required this.mnemonicWordsList, + Key? key, + }) : super(key: key); + + @override + Widget build(BuildContext context) { final List mobileRows = []; List webRowChildren = []; final List> webRows = []; for (int i = 0; i < confirmIdxs.length; i++) { mobileRows.add( - _buildConfirmationTextField( - confirmIdxs[i], - mnemonicWordsList[confirmIdxs[i]], + ConfirmationTextField( + textFieldKey: SeedPhraseConfirmationPage.confirmationTextFieldKey(i), + idx: confirmIdxs[i], + word: mnemonicWordsList[confirmIdxs[i]], ), ); webRowChildren.add( - _buildConfirmationTextField( - confirmIdxs[i], - mnemonicWordsList[confirmIdxs[i]], + ConfirmationTextField( + textFieldKey: SeedPhraseConfirmationPage.confirmationTextFieldKey(i), + idx: confirmIdxs[i], + word: mnemonicWordsList[confirmIdxs[i]], ), ); if ((i + 1) % 2 == 0) { @@ -148,8 +158,23 @@ class _SeedPhraseConfirmationPageState extends State : mobileRows, ); } +} + +class ConfirmationTextField extends HookWidget { + final int idx; + final String word; + final Key textFieldKey; + const ConfirmationTextField({ + required this.idx, + required this.word, + required this.textFieldKey, + Key? key, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + final textController = useTextEditingController(); - Widget _buildConfirmationTextField(int idx, String word) { return Padding( padding: const EdgeInsets.symmetric(vertical: 5, horizontal: kIsWeb ? 20 : 0), child: Align( @@ -163,16 +188,15 @@ class _SeedPhraseConfirmationPageState extends State ), const SizedBox(height: 5), CustomTextField( - controller: idxControllerMap[idx]!, + key: textFieldKey, + controller: textController, hintText: Strings.typeSomething, - hasError: controllerErrorMap[idxControllerMap[idx]!]!, inputFormatters: [LowerCaseTextFormatter()], - onChanged: (String text) { - if (text == word) { - setState(() { - controllerErrorMap[idxControllerMap[idx]!] = false; - }); + validator: (String? text) { + if (text == null || text.isEmpty || text != word) { + return ''; } + return null; }, ), ], diff --git a/lib/presentation/onboarding/create_wallet/seed_phrase_display_page.dart b/lib/presentation/onboarding/create_wallet/seed_phrase_display_page.dart index 0b0f07b5..6e90f479 100644 --- a/lib/presentation/onboarding/create_wallet/seed_phrase_display_page.dart +++ b/lib/presentation/onboarding/create_wallet/seed_phrase_display_page.dart @@ -4,146 +4,156 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; // Package imports: -import 'package:flutter_redux/flutter_redux.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:ribn_toolkit/constants/colors.dart'; import 'package:ribn_toolkit/constants/styles.dart'; // Project imports: -import 'package:ribn/actions/misc_actions.dart'; import 'package:ribn/constants/assets.dart'; import 'package:ribn/constants/keys.dart'; import 'package:ribn/constants/routes.dart'; import 'package:ribn/constants/strings.dart'; -import 'package:ribn/models/app_state.dart'; import 'package:ribn/presentation/onboarding/utils.dart'; import 'package:ribn/presentation/onboarding/widgets/confirmation_button.dart'; import 'package:ribn/presentation/onboarding/widgets/mobile_onboarding_progress_bar.dart'; import 'package:ribn/presentation/onboarding/widgets/onboarding_container.dart'; import 'package:ribn/presentation/onboarding/widgets/web_onboarding_app_bar.dart'; -import 'package:ribn/utils.dart'; +import 'package:ribn/providers/onboarding_provider.dart'; +import 'package:ribn/providers/utility_provider.dart'; +import 'package:ribn/utils/utils.dart'; -class SeedPhraseDisplayPage extends StatelessWidget { - const SeedPhraseDisplayPage({Key? key}) : super(key: key); +class SeedPhraseDisplayPage extends HookConsumerWidget { + static const Key copyKey = Key('copyKey'); + static const Key seedPhraseDisplayPageKey = Key('seedPhraseDisplayPageKey'); + static const Key seedPhraseDisplayConfirmationButtonKey = Key('seedPhraseDisplayConfirmationButtonKey'); + + const SeedPhraseDisplayPage({Key key = seedPhraseDisplayPageKey}) : super(key: key); @override - Widget build(BuildContext context) { - return StoreConnector( - converter: (store) => store.state.onboardingState.mnemonic!, - builder: (context, seedPhrase) { - final double width = MediaQuery.of(context).size.width; - final double height = MediaQuery.of(context).size.height; - final bool isXsWidth = width < 375.0 ? true : false; - final bool isXsHeight = height < 667.0 ? true : false; - final bool isXsScreenSize = isXsWidth && isXsHeight ? true : false; + Widget build(BuildContext context, WidgetRef ref) { + final double width = MediaQuery.of(context).size.width; + final double height = MediaQuery.of(context).size.height; + final bool isXsWidth = width < 375.0 ? true : false; + final bool isXsHeight = height < 667.0 ? true : false; + final bool isXsScreenSize = isXsWidth && isXsHeight ? true : false; - final List seedPhraseWordsList = seedPhrase.split(' ').toList(); - return Scaffold( - body: OnboardingContainer( - isXsScreenSize: isXsScreenSize, - child: Column( - mainAxisAlignment: MainAxisAlignment.start, - children: [ - kIsWeb ? const WebOnboardingAppBar(currStep: 0) : const SizedBox(), - SizedBox( - width: 200, - child: Text( - Strings.writeDownSeedPhrase, - style: RibnToolkitTextStyles.onboardingH1.copyWith(letterSpacing: 0.5), - textAlign: TextAlign.center, - ), - ), - Image.asset(RibnAssets.penPaperPng, width: 70), - Padding( - padding: EdgeInsets.symmetric( - vertical: kIsWeb ? 40 : adaptHeight(0.03), + final onboardingState = ref.watch(onboardingProvider); + + final seedPhrase = onboardingState.mnemonic; + + final List seedPhraseWordsList = seedPhrase.split(' ').toList(); + return Scaffold( + body: OnboardingContainer( + isXsScreenSize: isXsScreenSize, + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + kIsWeb ? const WebOnboardingAppBar(currStep: 0) : const SizedBox(), + SizedBox( + width: 200, + child: Text( + Strings.writeDownSeedPhrase, + style: RibnToolkitTextStyles.onboardingH1.copyWith(letterSpacing: 0.5), + textAlign: TextAlign.center, + ), + ), + Image.asset(RibnAssets.penPaperPng, width: 70), + Padding( + padding: EdgeInsets.symmetric( + vertical: kIsWeb ? 40 : adaptHeight(0.03), + ), + child: const Text( + Strings.writeDownSeedPhraseInExactOrder, + style: RibnToolkitTextStyles.onboardingH3, + ), + ), + Expanded( + child: Center( + child: Container( + constraints: BoxConstraints( + maxHeight: 280, + maxWidth: 674, ), - child: const Text( - Strings.writeDownSeedPhraseInExactOrder, - style: RibnToolkitTextStyles.onboardingH3, + decoration: BoxDecoration( + color: RibnColors.greyText.withOpacity(0.24), + borderRadius: BorderRadius.circular(5), ), - ), - Expanded( - child: Center( - child: Container( - constraints: BoxConstraints( - maxHeight: 280, - maxWidth: 674, - ), - decoration: BoxDecoration( - color: RibnColors.greyText.withOpacity(0.24), - borderRadius: BorderRadius.circular(5), - ), - padding: EdgeInsets.all(15), - child: Column( - children: [ - _buildGrid(seedPhraseWordsList), - kIsWeb - ? const SizedBox() - : Padding( - padding: const EdgeInsets.only(right: 20), - child: Align( - alignment: Alignment.bottomRight, - child: _buildButton( - Strings.copy, - onPressed: () => Clipboard.setData( - ClipboardData(text: seedPhrase), - ), - width: 19, - height: 15, - ), - ), - ), - ], + child: Stack( + children: [ + Container( + margin: EdgeInsets.only( + left: 15, + right: 15, + top: 10, + bottom: 25, + ), + child: _buildGrid(seedPhraseWordsList), ), - ), - ), - ), - SizedBox( - width: 674, - child: kIsWeb - ? Align( - alignment: Alignment.bottomRight, - child: Padding( - padding: const EdgeInsets.only(top: 8.0), - child: _buildButton( - Strings.download, - onPressed: () => StoreProvider.of(context).dispatch( - DownloadAsFileAction( - Strings.seedPhraseFileName, - seedPhrase, - ), + kIsWeb + ? const SizedBox() + : Positioned( + bottom: 0, + right: 10, + child: _buildButton( + Strings.copy, + onPressed: () { + Clipboard.setData( + ClipboardData(text: seedPhrase), + ); + }, + width: 19, + height: 15, ), - width: 30, - height: 23, ), - ), - ) - : const SizedBox(), - ), - Padding( - padding: EdgeInsets.only( - top: 20, - ), - child: Column( - mainAxisAlignment: MainAxisAlignment.end, - children: [ - renderIfMobile( - const MobileOnboardingProgressBar(currStep: 0), - ), - ConfirmationButton( - text: Strings.done, - onPressed: () { - Keys.navigatorKey.currentState?.pushNamed(Routes.seedPhraseConfirm); - }, - ), ], ), ), - ], + ), ), - ), - ); - }, + SizedBox( + width: 674, + child: kIsWeb + ? Align( + alignment: Alignment.bottomRight, + child: Padding( + padding: const EdgeInsets.only(top: 8.0), + child: _buildButton( + Strings.download, + onPressed: () => ref + .read(downloadFileProvider(File(fileName: Strings.seedPhraseFileName, text: seedPhrase))), + width: 30, + height: 23, + ), + ), + ) + : const SizedBox(), + ), + Padding( + padding: EdgeInsets.only( + top: 20, + ), + child: Column( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + renderIfMobile( + const MobileOnboardingProgressBar(currStep: 0), + ), + Padding( + padding: EdgeInsets.only(bottom: 30), + child: ConfirmationButton( + key: seedPhraseDisplayConfirmationButtonKey, + text: Strings.done, + onPressed: () { + Keys.navigatorKey.currentState?.pushNamed(Routes.seedPhraseConfirm); + }, + ), + ), + ], + ), + ), + ], + ), + ), ); } @@ -159,7 +169,7 @@ class SeedPhraseDisplayPage extends StatelessWidget { children.add(_buildGridItem(idx, word)); } }); - return Expanded( + return SingleChildScrollView( child: Column( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ @@ -188,8 +198,7 @@ class SeedPhraseDisplayPage extends StatelessWidget { width: 25, child: Text( '${idx + 1}. ', - style: RibnToolkitTextStyles.h3 - .copyWith(color: const Color(0xff00FFC5), letterSpacing: 0.5), + style: RibnToolkitTextStyles.h3.copyWith(color: const Color(0xff00FFC5), letterSpacing: 0.5), ), ), Expanded( @@ -210,9 +219,9 @@ class SeedPhraseDisplayPage extends StatelessWidget { required double width, required double height, }) { - final String icon = - buttonText == Strings.download ? RibnAssets.downloadPng : RibnAssets.contentCopyPng; + final String icon = buttonText == Strings.download ? RibnAssets.downloadPng : RibnAssets.contentCopyPng; return TextButton( + key: copyKey, onPressed: onPressed, child: RichText( text: TextSpan( diff --git a/lib/presentation/onboarding/create_wallet/seed_phrase_generating_page.dart b/lib/presentation/onboarding/create_wallet/seed_phrase_generating_page.dart index af08c14c..fbe26546 100644 --- a/lib/presentation/onboarding/create_wallet/seed_phrase_generating_page.dart +++ b/lib/presentation/onboarding/create_wallet/seed_phrase_generating_page.dart @@ -3,65 +3,58 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; // Package imports: -import 'package:flutter_redux/flutter_redux.dart'; +import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:ribn_toolkit/constants/colors.dart'; import 'package:ribn_toolkit/constants/styles.dart'; import 'package:ribn_toolkit/widgets/molecules/animated_circle_step_loader.dart'; // Project imports: -import 'package:ribn/actions/onboarding_actions.dart'; import 'package:ribn/constants/assets.dart'; import 'package:ribn/constants/keys.dart'; import 'package:ribn/constants/routes.dart'; import 'package:ribn/constants/strings.dart'; -import 'package:ribn/models/app_state.dart'; import 'package:ribn/presentation/onboarding/utils.dart'; import 'package:ribn/presentation/onboarding/widgets/confirmation_button.dart'; import 'package:ribn/presentation/onboarding/widgets/onboarding_container.dart'; import 'package:ribn/presentation/onboarding/widgets/web_onboarding_app_bar.dart'; -import 'package:ribn/utils.dart'; +import 'package:ribn/utils/utils.dart'; /// This page shows a loading animation to indicate seed phrase generation. -class SeedPhraseGeneratingPage extends StatefulWidget { - const SeedPhraseGeneratingPage({Key? key}) : super(key: key); +class SeedPhraseGeneratingPage extends HookConsumerWidget { + static const Key seedPhraseGeneratingPageKey = Key('seedPhraseGeneratingPageKey'); + static const Key seedPhraseGeneratingConfirmationButtonKey = Key('seedPhraseGeneratingConfirmationButtonKey'); + const SeedPhraseGeneratingPage({Key key = seedPhraseGeneratingPageKey}) : super(key: key); - @override - _SeedPhraseGeneratingPageState createState() => _SeedPhraseGeneratingPageState(); -} - -class _SeedPhraseGeneratingPageState extends State { /// True if animated loader needs to be shown. - bool seedPhraseGenerating = true; final double descriptionBoxWidth = kIsWeb ? 640 : 350; @override - Widget build(BuildContext context) { - return StoreConnector( - converter: (store) => store.state, - onInit: (store) => store.dispatch(GenerateMnemonicAction()), - builder: (context, vm) { - return Scaffold( - body: OnboardingContainer( - showBackButton: seedPhraseGenerating ? false : true, - child: SingleChildScrollView( - clipBehavior: Clip.none, - child: Center( - child: Column( - children: seedPhraseGenerating - ? seedPhraseGeneratingSection() - : seedPhraseGeneratedSection(), - ), - ), + Widget build(BuildContext context, WidgetRef ref) { + final seedPhraseGenerating = useState(true); + + return Scaffold( + body: OnboardingContainer( + showBackButton: seedPhraseGenerating.value ? false : true, + child: SingleChildScrollView( + clipBehavior: Clip.none, + child: Center( + child: Column( + children: seedPhraseGenerating.value + ? seedPhraseGeneratingSection(() { + seedPhraseGenerating.value = false; + }) + : seedPhraseGeneratedSection(), ), ), - ); - }, + ), + ), ); } /// List of widgets displayed when seed phrase is being generated. - List seedPhraseGeneratingSection() { + List seedPhraseGeneratingSection(Function showStepLoader) { return [ AnimatedCircleStepLoader( stepLabels: const { @@ -72,9 +65,7 @@ class _SeedPhraseGeneratingPageState extends State { 4: Strings.seedPhraseGenerating, }, showStepLoader: () { - setState(() { - seedPhraseGenerating = false; - }); + showStepLoader(); }, activeCircleColor: RibnColors.primary, inactiveCircleColor: RibnColors.inactive, @@ -118,6 +109,7 @@ class _SeedPhraseGeneratingPageState extends State { ), SizedBox(height: adaptHeight(0.1)), ConfirmationButton( + key: seedPhraseGeneratingConfirmationButtonKey, text: Strings.cont, onPressed: () { Keys.navigatorKey.currentState?.pushNamed(Routes.displaySeedphrase); diff --git a/lib/presentation/onboarding/create_wallet/seed_phrase_info_checklist_page.dart b/lib/presentation/onboarding/create_wallet/seed_phrase_info_checklist_page.dart index 93adbc1d..5f3f5dfe 100644 --- a/lib/presentation/onboarding/create_wallet/seed_phrase_info_checklist_page.dart +++ b/lib/presentation/onboarding/create_wallet/seed_phrase_info_checklist_page.dart @@ -3,6 +3,7 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; // Package imports: +import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:ribn_toolkit/constants/colors.dart'; import 'package:ribn_toolkit/constants/styles.dart'; import 'package:ribn_toolkit/widgets/molecules/checkbox_wrappable_text.dart'; @@ -16,27 +17,23 @@ import 'package:ribn/presentation/onboarding/utils.dart'; import 'package:ribn/presentation/onboarding/widgets/confirmation_button.dart'; import 'package:ribn/presentation/onboarding/widgets/onboarding_container.dart'; import 'package:ribn/presentation/onboarding/widgets/web_onboarding_app_bar.dart'; -import 'package:ribn/utils.dart'; +import 'package:ribn/utils/utils.dart'; /// Builds checks to ensure that the user understands the importance of the seed phrase. -class SeedPhraseInfoChecklistPage extends StatefulWidget { - const SeedPhraseInfoChecklistPage({Key? key}) : super(key: key); +class SeedPhraseInfoChecklistPage extends HookWidget { + static const Key seedPhraseInfoChecklistPageKey = Key('seedPhraseInfoChecklistPageKey'); + static const Key seedPhraseInfoChecklistConfirmationButtonKey = Key('seedPhraseInfoChecklistConfirmationButtonKey'); + static const Key neverShareMySeedPhraseKey = Key('neverShareMySeedPhraseKey'); + static const Key walletRecoveryUsingSeedPhraseKey = Key('walletRecoveryUsingSeedPhraseKey'); - @override - State createState() => - _SeedPhraseInfoChecklistPageState(); -} - -class _SeedPhraseInfoChecklistPageState - extends State { - /// Checkboxes and their corresponding checked value - final Map checkboxesState = { - Strings.neverShareMySeedPhrase: false, - Strings.walletRecoveryUsingSeedPhrase: false, - }; + const SeedPhraseInfoChecklistPage({Key key = seedPhraseInfoChecklistPageKey}) : super(key: key); @override Widget build(BuildContext context) { + /// Checkboxes and their corresponding checked value + final neverShareMySeedPhrase = useState(false); + final walletRecoveryUsingSeedPhrase = useState(false); + return Scaffold( body: OnboardingContainer( child: SingleChildScrollView( @@ -55,33 +52,30 @@ class _SeedPhraseInfoChecklistPageState child: Image.asset(RibnAssets.warningPng, width: 76), ), _buildCheckboxListTile( - checked: checkboxesState[Strings.neverShareMySeedPhrase]!, + checked: neverShareMySeedPhrase.value, activeText: true, text: Strings.neverShareMySeedPhrase, - onChanged: (bool? val) => - onChecked(val ?? false, Strings.neverShareMySeedPhrase), + onChanged: (bool? val) => neverShareMySeedPhrase.value = val ?? false, + checkboxKey: neverShareMySeedPhraseKey, ), const SizedBox(height: 40), _buildCheckboxListTile( - checked: - checkboxesState[Strings.walletRecoveryUsingSeedPhrase]!, - activeText: checkboxesState[Strings.neverShareMySeedPhrase]!, + checked: walletRecoveryUsingSeedPhrase.value, + activeText: neverShareMySeedPhrase.value, text: Strings.walletRecoveryUsingSeedPhrase, - onChanged: checkboxesState[Strings.neverShareMySeedPhrase]! - ? (bool? val) => onChecked( - val ?? false, - Strings.walletRecoveryUsingSeedPhrase, - ) + onChanged: neverShareMySeedPhrase.value + ? (bool? val) => walletRecoveryUsingSeedPhrase.value = val ?? false : null, + checkboxKey: walletRecoveryUsingSeedPhraseKey, ), SizedBox(height: adaptHeight(0.1)), ConfirmationButton( + key: seedPhraseInfoChecklistConfirmationButtonKey, text: Strings.iUnderstand, onPressed: () { - Keys.navigatorKey.currentState - ?.pushNamed(Routes.seedPhraseInstructions); + Keys.navigatorKey.currentState?.pushNamed(Routes.seedPhraseInstructions); }, - disabled: checkboxesState.containsValue(false), + disabled: !walletRecoveryUsingSeedPhrase.value || !neverShareMySeedPhrase.value, ) ], ), @@ -96,10 +90,12 @@ class _SeedPhraseInfoChecklistPageState required bool activeText, required String text, required Function(bool?)? onChanged, + required Key checkboxKey, }) { return SizedBox( width: kIsWeb ? 600 : 350, child: CheckboxWrappableText( + checkboxKey: checkboxKey, fillColor: Colors.transparent, checkColor: const Color(0xff80FF00), borderColor: checked @@ -115,19 +111,4 @@ class _SeedPhraseInfoChecklistPageState ), ); } - - void onChecked(bool val, String key) { - setState(() { - // Uncheck all checkboxes underneath if unselected - if (!val) { - bool shouldUncheck = false; - checkboxesState.keys.toList().forEach((element) { - if (element == key) shouldUncheck = true; - if (shouldUncheck) checkboxesState[element] = false; - }); - } else { - checkboxesState[key] = true; - } - }); - } } diff --git a/lib/presentation/onboarding/create_wallet/seed_phrase_instructions_page.dart b/lib/presentation/onboarding/create_wallet/seed_phrase_instructions_page.dart index e73afe92..cd753b84 100644 --- a/lib/presentation/onboarding/create_wallet/seed_phrase_instructions_page.dart +++ b/lib/presentation/onboarding/create_wallet/seed_phrase_instructions_page.dart @@ -3,6 +3,7 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; // Package imports: +import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:ribn_toolkit/constants/colors.dart'; import 'package:ribn_toolkit/constants/styles.dart'; @@ -15,14 +16,16 @@ import 'package:ribn/presentation/onboarding/utils.dart'; import 'package:ribn/presentation/onboarding/widgets/confirmation_button.dart'; import 'package:ribn/presentation/onboarding/widgets/onboarding_container.dart'; import 'package:ribn/presentation/onboarding/widgets/web_onboarding_app_bar.dart'; -import 'package:ribn/utils.dart'; +import 'package:ribn/utils/utils.dart'; /// This page shows intructions on how to keep the seed phrase secure. -class SeedPhraseInstructionsPage extends StatelessWidget { - const SeedPhraseInstructionsPage({Key? key}) : super(key: key); +class SeedPhraseInstructionsPage extends HookConsumerWidget { + static const Key seedPhraseInstructionsPageKey = Key('SeedPhraseInstructionsPageKey'); + static const Key seedPhraseInstructionsConfirmationButtonKey = Key('seedPhraseInstructionsConfirmationButtonKey'); + const SeedPhraseInstructionsPage({Key key = seedPhraseInstructionsPageKey}) : super(key: key); @override - Widget build(BuildContext context) { + Widget build(BuildContext context, WidgetRef ref) { return Scaffold( body: OnboardingContainer( child: SingleChildScrollView( @@ -72,10 +75,10 @@ class SeedPhraseInstructionsPage extends StatelessWidget { ), SizedBox(height: adaptHeight(0.1)), ConfirmationButton( + key: seedPhraseInstructionsConfirmationButtonKey, text: Strings.iUnderstand, onPressed: () { - Keys.navigatorKey.currentState - ?.pushNamed(Routes.generateSeedPhrase); + Keys.navigatorKey.currentState?.pushNamed(Routes.generateSeedPhrase); }, ) ], @@ -119,8 +122,7 @@ class SeedPhraseInstructionsPage extends StatelessWidget { width: kIsWeb ? 500 : 295, child: Text( text, - textHeightBehavior: - const TextHeightBehavior(applyHeightToFirstAscent: false), + textHeightBehavior: const TextHeightBehavior(applyHeightToFirstAscent: false), style: RibnToolkitTextStyles.h3.copyWith( color: RibnColors.lightGreyTitle, fontSize: 18, diff --git a/lib/presentation/onboarding/create_wallet/select_action_page.dart b/lib/presentation/onboarding/create_wallet/select_action_page.dart index 014646fd..e1a0034b 100644 --- a/lib/presentation/onboarding/create_wallet/select_action_page.dart +++ b/lib/presentation/onboarding/create_wallet/select_action_page.dart @@ -15,17 +15,21 @@ import 'package:ribn/constants/strings.dart'; import 'package:ribn/presentation/onboarding/utils.dart'; import 'package:ribn/presentation/onboarding/widgets/onboarding_container.dart'; import 'package:ribn/presentation/onboarding/widgets/web_onboarding_app_bar.dart'; -import 'package:ribn/utils.dart'; +import 'package:ribn/utils/utils.dart'; /// This page allows the user to select between creating a new wallet or importing an existing wallet. class SelectActionPage extends StatelessWidget { - const SelectActionPage({Key? key}) : super(key: key); + static const selectActionPageKey = Key('selectActionPageKey'); + static const createWalletActionButtonKey = Key('createWalletActionButtonKey'); + static const importWalletActionButtonKey = Key('importWalletActionButtonKey'); + const SelectActionPage({Key key = selectActionPageKey}) : super(key: key); @override Widget build(BuildContext context) { final List actionButtons = [ Expanded( child: OnboardingActionButton( + key: createWalletActionButtonKey, backgroundColor: RibnColors.primary, icon: Image.asset(RibnAssets.createWalletPng), title: Strings.createWallet, @@ -38,6 +42,7 @@ class SelectActionPage extends StatelessWidget { kIsWeb ? const SizedBox(width: 100, height: 50) : const SizedBox(height: 25), Expanded( child: OnboardingActionButton( + key: importWalletActionButtonKey, backgroundColor: RibnColors.primary, icon: Image.asset(RibnAssets.importWalletPng), description: Strings.importWalletUsingSeedPhrase, diff --git a/lib/presentation/onboarding/create_wallet/wallet_created_page.dart b/lib/presentation/onboarding/create_wallet/wallet_created_page.dart index 9e69abdd..81c311ed 100644 --- a/lib/presentation/onboarding/create_wallet/wallet_created_page.dart +++ b/lib/presentation/onboarding/create_wallet/wallet_created_page.dart @@ -3,6 +3,7 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; // Package imports: +import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:ribn_toolkit/constants/colors.dart'; import 'package:ribn_toolkit/constants/styles.dart'; import 'package:ribn_toolkit/widgets/molecules/accordion.dart'; @@ -17,27 +18,23 @@ import 'package:ribn/presentation/onboarding/widgets/confirmation_button.dart'; import 'package:ribn/presentation/onboarding/widgets/mobile_onboarding_progress_bar.dart'; import 'package:ribn/presentation/onboarding/widgets/onboarding_container.dart'; import 'package:ribn/presentation/onboarding/widgets/web_onboarding_app_bar.dart'; -import 'package:ribn/utils.dart'; +import 'package:ribn/utils/navigation_utils.dart'; +import 'package:ribn/utils/utils.dart'; /// This page is displayed when user successfully creates their wallet. -class WalletCreatedPage extends StatefulWidget { - const WalletCreatedPage({Key? key}) : super(key: key); +class WalletCreatedPage extends HookWidget { + static const Key walletCreatedPageKey = Key('walletCreatedPageKey'); + static const Key walletCreatedConfirmationButtonKey = Key('walletCreatedConfirmationButtonKey'); + const WalletCreatedPage({Key key = walletCreatedPageKey}) : super(key: key); - @override - State createState() => _WalletCreatedPageState(); -} - -class _WalletCreatedPageState extends State { - /// FAQs and their corresponding answeres - final Map faqs = { - Strings.howCanIKeepMySeedPhraseSecure: - Strings.howCanIKeepMySeedPhraseSecureAns, - Strings.howIsASeedPhraseDifferent: Strings.howIsASeedPhraseDifferentAns, - Strings.howIsMySeedPhraseUnrecoverable: - Strings.howIsMySeedPhraseUnrecoverableAns, - }; @override Widget build(BuildContext context) { + /// FAQs and their corresponding answeres + final ValueNotifier> faqs = useState({ + Strings.howCanIKeepMySeedPhraseSecure: Strings.howCanIKeepMySeedPhraseSecureAns, + Strings.howIsASeedPhraseDifferent: Strings.howIsASeedPhraseDifferentAns, + Strings.howIsMySeedPhraseUnrecoverable: Strings.howIsMySeedPhraseUnrecoverableAns, + }); return Scaffold( body: OnboardingContainer( child: SingleChildScrollView( @@ -82,7 +79,7 @@ class _WalletCreatedPageState extends State { ), ), SizedBox(height: adaptHeight(0.01)), - ...faqs.keys + ...faqs.value.keys .map( (q) => Accordion( header: Text( @@ -93,7 +90,7 @@ class _WalletCreatedPageState extends State { ), ), description: Text( - faqs[q]!, + faqs.value[q]!, style: RibnToolkitTextStyles.h4.copyWith( color: Colors.white, fontSize: 18, @@ -112,13 +109,13 @@ class _WalletCreatedPageState extends State { SizedBox(height: adaptHeight(0.01)), renderIfMobile(const MobileOnboardingProgressBar(currStep: 3)), ConfirmationButton( + key: walletCreatedConfirmationButtonKey, text: Strings.done, onPressed: () { if (kIsWeb) { - navigateToRoute(context, Routes.extensionInfo); + navigateToRoute(route: Routes.extensionInfo); } else { - Keys.navigatorKey.currentState - ?.pushNamedAndRemoveUntil(Routes.home, (_) => false); + Keys.navigatorKey.currentState?.pushNamedAndRemoveUntil(Routes.home, (_) => false); } }, ), diff --git a/lib/presentation/onboarding/create_wallet/wallet_info_checklist_page.dart b/lib/presentation/onboarding/create_wallet/wallet_info_checklist_page.dart index aee88f87..2936a648 100644 --- a/lib/presentation/onboarding/create_wallet/wallet_info_checklist_page.dart +++ b/lib/presentation/onboarding/create_wallet/wallet_info_checklist_page.dart @@ -3,7 +3,8 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; // Package imports: -import 'package:local_auth/local_auth.dart'; +import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:ribn_toolkit/constants/colors.dart'; import 'package:ribn_toolkit/constants/styles.dart'; import 'package:ribn_toolkit/widgets/molecules/checkbox_wrappable_text.dart'; @@ -18,46 +19,53 @@ import 'package:ribn/presentation/onboarding/widgets/confirmation_button.dart'; import 'package:ribn/presentation/onboarding/widgets/mobile_onboarding_progress_bar.dart'; import 'package:ribn/presentation/onboarding/widgets/onboarding_container.dart'; import 'package:ribn/presentation/onboarding/widgets/web_onboarding_app_bar.dart'; -import 'package:ribn/utils.dart'; +import 'package:ribn/providers/biometrics_provider.dart'; +import 'package:ribn/utils/utils.dart'; -class WalletInfoChecklistPage extends StatefulWidget { - const WalletInfoChecklistPage({Key? key}) : super(key: key); +class WalletInfoChecklistPage extends HookConsumerWidget { + static const walletInfoChecklistPageKey = Key('walletInfoChecklistPageKey'); - @override - State createState() => - _WalletInfoChecklistPageState(); -} + const WalletInfoChecklistPage({Key key = walletInfoChecklistPageKey}) : super(key: key); + static const Key savedMyWalletPasswordSafelyKey = Key('savedMyWalletPasswordSafelyKey'); + static const Key toplCannotRecoverForMeKey = Key('toplCannotRecoverForMeKey'); + static const Key spAndPasswordUnrecoverableKey = Key('spAndPasswordUnrecoverableKey'); + static const Key walletInfoChecklistConfirmationButtonKey = Key('walletInfoChecklistConfirmationButtonKey'); -class _WalletInfoChecklistPageState extends State { - /// Checkboxes and their corresponding checked value - final Map checkboxesState = { - Strings.savedMyWalletPasswordSafely: false, - Strings.toplCannotRecoverForMe: false, - Strings.spAndPasswordUnrecoverable: false, - }; - - bool isBioSupported = false; + Future runBiometrics(isBioSupported, ref) => + ref.watch(biometricsProvider).whenData((value) => isBioSupported.value = value.isSupported); @override - void initState() { - runBiometrics(); + Widget build(BuildContext context, WidgetRef ref) { + final savedMyWalletPasswordSafely = useState(false); + final toplCannotRecoverForMe = useState(false); + final spAndPasswordUnrecoverable = useState(false); - super.initState(); - } + final isBioSupported = useState(false); - Future runBiometrics() async { - final LocalAuthentication localAuthentication = LocalAuthentication(); + useEffect(() { + BiometricsNotifier.isBiometricsEnabled(ref).then((value) { + isBioSupported.value = value; + }); + return null; + }, []); - final bool isBioAuthenticationSupported = - await isBiometricsAuthenticationSupported(localAuthentication); + // Use value changed for the first check box. + // If going from true to false, then uncheck the other 2 values + useValueChanged(savedMyWalletPasswordSafely.value, (oldValue, __) { + if (!savedMyWalletPasswordSafely.value && oldValue) { + toplCannotRecoverForMe.value = false; + spAndPasswordUnrecoverable.value = false; + } + }); - setState(() { - isBioSupported = isBioAuthenticationSupported ? true : false; + // Use value changed for the second check box. + // If going from true to false, then uncheck the last box too + useValueChanged(toplCannotRecoverForMe.value, (oldValue, __) { + if (!toplCannotRecoverForMe.value && oldValue) { + spAndPasswordUnrecoverable.value = false; + } }); - } - @override - Widget build(BuildContext context) { return Scaffold( body: OnboardingContainer( child: SingleChildScrollView( @@ -77,50 +85,44 @@ class _WalletInfoChecklistPageState extends State { child: Image.asset(RibnAssets.warningPng, width: 76), ), _buildCheckboxListTile( - checked: checkboxesState[Strings.savedMyWalletPasswordSafely]!, + checkboxKey: savedMyWalletPasswordSafelyKey, + checked: savedMyWalletPasswordSafely.value, activeText: true, text: Strings.savedMyWalletPasswordSafely, - onChanged: (bool? val) => onChecked( - val ?? false, - Strings.savedMyWalletPasswordSafely, - ), + onChanged: (bool? val) => savedMyWalletPasswordSafely.value = val ?? false, ), SizedBox(height: adaptHeight(0.03)), _buildCheckboxListTile( - checked: checkboxesState[Strings.toplCannotRecoverForMe]!, - activeText: - checkboxesState[Strings.savedMyWalletPasswordSafely]!, + checkboxKey: toplCannotRecoverForMeKey, + checked: toplCannotRecoverForMe.value, + activeText: savedMyWalletPasswordSafely.value, text: Strings.toplCannotRecoverForMe, - onChanged: checkboxesState[Strings.savedMyWalletPasswordSafely]! - ? (bool? val) => - onChecked(val ?? false, Strings.toplCannotRecoverForMe) + onChanged: savedMyWalletPasswordSafely.value + ? (bool? val) => toplCannotRecoverForMe.value = val ?? false : null, ), SizedBox(height: adaptHeight(0.03)), _buildCheckboxListTile( - checked: checkboxesState[Strings.spAndPasswordUnrecoverable]!, - activeText: checkboxesState[Strings.toplCannotRecoverForMe]!, + checkboxKey: spAndPasswordUnrecoverableKey, + checked: spAndPasswordUnrecoverable.value, + activeText: toplCannotRecoverForMe.value, text: Strings.spAndPasswordUnrecoverable, - onChanged: checkboxesState[Strings.toplCannotRecoverForMe]! - ? (bool? val) => onChecked( - val ?? false, - Strings.spAndPasswordUnrecoverable, - ) + onChanged: toplCannotRecoverForMe.value + ? (bool? val) => spAndPasswordUnrecoverable.value = val ?? false : null, renderTooltipIcon: true, ), SizedBox(height: adaptHeight(0.1)), renderIfMobile(const MobileOnboardingProgressBar(currStep: 2)), ConfirmationButton( + key: walletInfoChecklistConfirmationButtonKey, text: Strings.iUnderstand, onPressed: () { Keys.navigatorKey.currentState?.pushNamed( - isBioSupported - ? Routes.onboardingEnableBiometrics - : Routes.walletCreated, + isBioSupported.value ? Routes.onboardingEnableBiometrics : Routes.walletCreated, ); }, - disabled: checkboxesState.containsValue(false), + disabled: !spAndPasswordUnrecoverable.value, ) ], ), @@ -134,11 +136,13 @@ class _WalletInfoChecklistPageState extends State { required bool activeText, required String text, required Function(bool?)? onChanged, + required Key checkboxKey, renderTooltipIcon = false, }) { return SizedBox( width: kIsWeb ? 600 : 330, child: CheckboxWrappableText( + checkboxKey: checkboxKey, borderColor: checked ? const Color(0xff80FF00) : activeText @@ -153,19 +157,4 @@ class _WalletInfoChecklistPageState extends State { ), ); } - - void onChecked(bool val, String key) { - setState(() { - // Uncheck all checkboxes underneath if unselected - if (!val) { - bool shouldUncheck = false; - checkboxesState.keys.toList().forEach((element) { - if (element == key) shouldUncheck = true; - if (shouldUncheck) checkboxesState[element] = false; - }); - } else { - checkboxesState[key] = true; - } - }); - } } diff --git a/lib/presentation/onboarding/create_wallet/welcome_page.dart b/lib/presentation/onboarding/create_wallet/welcome_page.dart index 9b91e2dc..ad18dadb 100644 --- a/lib/presentation/onboarding/create_wallet/welcome_page.dart +++ b/lib/presentation/onboarding/create_wallet/welcome_page.dart @@ -17,7 +17,11 @@ import 'package:ribn/presentation/onboarding/widgets/confirmation_button.dart'; /// The initial welcome page displayed during onboarding on mobile. class WelcomePage extends StatelessWidget { - const WelcomePage({Key? key}) : super(key: key); + static const welcomePageKey = Key('welcomePageKey'); + static const welcomePageConfirmationButtonKey = Key('welcomePageConfirmationButtonKey'); + const WelcomePage({ + Key key = welcomePageKey, + }) : super(key: key); @override Widget build(BuildContext context) { @@ -57,12 +61,15 @@ class WelcomePage extends StatelessWidget { ), ), adaptableSpacer(), - ConfirmationButton( - text: Strings.getStarted, - onPressed: () { - Keys.navigatorKey.currentState - ?.pushNamed(Routes.selectAction); - }, + Padding( + padding: EdgeInsets.only(bottom: 50), + child: ConfirmationButton( + key: welcomePageConfirmationButtonKey, + text: Strings.getStarted, + onPressed: () { + Keys.navigatorKey.currentState?.pushNamed(Routes.optIn); + }, + ), ), ], ), diff --git a/lib/presentation/onboarding/restore_wallet/create_new_wallet_password_page.dart b/lib/presentation/onboarding/restore_wallet/create_new_wallet_password_page.dart index 1b140026..a22c1d4d 100644 --- a/lib/presentation/onboarding/restore_wallet/create_new_wallet_password_page.dart +++ b/lib/presentation/onboarding/restore_wallet/create_new_wallet_password_page.dart @@ -1,91 +1,41 @@ // Flutter imports: import 'package:flutter/foundation.dart'; -import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; // Package imports: -import 'package:flutter_redux/flutter_redux.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:loader_overlay/loader_overlay.dart'; -import 'package:ribn_toolkit/constants/colors.dart'; import 'package:ribn_toolkit/constants/styles.dart'; -import 'package:ribn_toolkit/widgets/molecules/checkbox_wrappable_text.dart'; -import 'package:ribn_toolkit/widgets/molecules/password_text_field.dart'; import 'package:ribn_toolkit/widgets/organisms/onboarding_progress_bar.dart'; -import 'package:url_launcher/url_launcher.dart'; // Project imports: -import 'package:ribn/actions/restore_wallet_actions.dart'; import 'package:ribn/constants/strings.dart'; -import 'package:ribn/models/app_state.dart'; import 'package:ribn/presentation/onboarding/utils.dart'; import 'package:ribn/presentation/onboarding/widgets/confirmation_button.dart'; import 'package:ribn/presentation/onboarding/widgets/onboarding_container.dart'; +import 'package:ribn/presentation/onboarding/widgets/password_section.dart'; import 'package:ribn/presentation/onboarding/widgets/warning_section.dart'; import 'package:ribn/presentation/onboarding/widgets/web_onboarding_app_bar.dart'; -import 'package:ribn/utils.dart'; +import 'package:ribn/providers/password_provider.dart'; +import 'package:ribn/providers/restore_wallet_provider.dart'; /// Page for creating a new wallet password, when restoring wallet with a [seedPhrase]. -class NewWalletPasswordPage extends StatefulWidget { +class NewWalletPasswordPage extends HookConsumerWidget { + static const Key newWalletPasswordPageKey = Key('newWalletPasswordPageKey'); + static const Key newWalletPasswordConfirmationButtonKey = Key('newWalletPasswordConfirmationButtonKey'); + /// The seed phrase being used for wallet restoration. final String seedPhrase; const NewWalletPasswordPage({ required this.seedPhrase, - Key? key, + Key key = newWalletPasswordPageKey, }) : super(key: key); @override - _NewWalletPasswordPageState createState() => _NewWalletPasswordPageState(); -} - -class _NewWalletPasswordPageState extends State { - /// Controllers for password textfields. - final TextEditingController _newPasswordController = TextEditingController(); - final TextEditingController _confirmPasswordController = - TextEditingController(); - - /// True if the password entered is at least 8 characters. - bool _atLeast8Chars = false; - - /// True if both passwords match. - bool _passwordsMatch = false; - - /// Map to keep track of any textfield errors. - Map hasErrors = {}; - - bool _termsOfUseChecked = false; - - @override - void initState() { - // Initialize listeners for each controller. - [_newPasswordController, _confirmPasswordController] - .toList() - .forEach((controller) { - controller.addListener(() { - setState(() { - hasErrors[controller] = false; - _atLeast8Chars = _newPasswordController.text.length >= 8; - _passwordsMatch = - _newPasswordController.text == _confirmPasswordController.text; - }); - }); - }); - super.initState(); - } - - @override - void dispose() { - // Dispose listeners for each controller. - [_newPasswordController, _confirmPasswordController] - .toList() - .forEach((controller) { - controller.dispose(); - }); - super.dispose(); - } - - @override - Widget build(BuildContext context) { + Widget build(BuildContext context, WidgetRef ref) { + final passwordState = ref.watch(passwordProvider); + final restoreWalletNotifer = ref.watch(restoreWalletProvider.notifier); return LoaderOverlay( child: Scaffold( extendBody: true, @@ -112,11 +62,7 @@ class _NewWalletPasswordPageState extends State { child: Column( mainAxisSize: MainAxisSize.min, children: [ - _buildNewPasswordSection(), - SizedBox(height: adaptHeight(0.02)), - _buildConfirmPasswordSection(), - SizedBox(height: adaptHeight(0.02)), - _buildTermsOfAgreementCheck(), + PasswordSection(), ], ), ), @@ -126,17 +72,15 @@ class _NewWalletPasswordPageState extends State { ), const SizedBox(height: 20), ConfirmationButton( + key: newWalletPasswordConfirmationButtonKey, text: Strings.done, - disabled: !_atLeast8Chars || - !_passwordsMatch || - !_termsOfUseChecked, + disabled: + !passwordState.atLeast8Chars || !passwordState.passwordsMatch || !passwordState.termsOfUseChecked, onPressed: () { context.loaderOverlay.show(); - StoreProvider.of(context).dispatch( - RestoreWalletWithMnemonicAction( - mnemonic: widget.seedPhrase, - password: _confirmPasswordController.text, - ), + restoreWalletNotifer.restoreWalletWithMnemonic( + password: passwordState.password, + mnemonic: seedPhrase, ); }, ), @@ -147,143 +91,4 @@ class _NewWalletPasswordPageState extends State { ), ); } - - Widget _buildNewPasswordSection() { - return Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Align( - alignment: Alignment.centerLeft, - child: Text( - Strings.newWalletPassword, - textAlign: TextAlign.left, - style: RibnToolkitTextStyles.h3.copyWith( - fontWeight: FontWeight.bold, - color: RibnColors.lightGreyTitle, - ), - ), - ), - const SizedBox(height: 8), - Align( - alignment: Alignment.centerLeft, - child: PasswordTextField( - width: kIsWeb ? 350 : adaptWidth(0.9), - fillColor: RibnColors.whiteButtonShadow, - controller: _newPasswordController, - hintText: '', - obscurePassword: true, - ), - ), - const SizedBox(height: 8), - Align( - alignment: Alignment.centerLeft, - child: Text( - Strings.atLeast8Chars, - textAlign: TextAlign.left, - style: RibnToolkitTextStyles.h3.copyWith( - color: !_atLeast8Chars && _newPasswordController.text.isNotEmpty - ? Colors.red - : Colors.white, - ), - ), - ), - Align( - alignment: Alignment.centerLeft, - child: Text( - Strings.passwordExample, - textAlign: TextAlign.left, - style: RibnToolkitTextStyles.h3.copyWith( - color: Colors.white, - ), - ), - ), - ], - ); - } - - _buildConfirmPasswordSection() { - return Column( - children: [ - Align( - alignment: Alignment.centerLeft, - child: Text( - Strings.confirmWalletPassword, - textAlign: TextAlign.left, - style: RibnToolkitTextStyles.h3.copyWith( - fontWeight: FontWeight.bold, - color: RibnColors.lightGreyTitle, - ), - ), - ), - const SizedBox(height: 8), - Align( - alignment: Alignment.centerLeft, - child: PasswordTextField( - width: kIsWeb ? 350 : adaptWidth(0.9), - fillColor: RibnColors.whiteButtonShadow, - controller: _confirmPasswordController, - hintText: '', - obscurePassword: true, - ), - ), - const SizedBox(height: 8), - Align( - alignment: Alignment.centerLeft, - child: Text( - Strings.passwordsMustMatch, - textAlign: TextAlign.left, - style: RibnToolkitTextStyles.h3.copyWith( - color: - !_passwordsMatch && _confirmPasswordController.text.isNotEmpty - ? Colors.red - : Colors.white, - ), - ), - ), - ], - ); - } - - Widget _buildTermsOfAgreementCheck() { - final url = Uri.parse(Strings.termsOfUseUrl); - return CheckboxWrappableText( - wrapText: false, - borderColor: _termsOfUseChecked - ? const Color(0xff80FF00) - : RibnColors.lightGreyTitle, - value: _termsOfUseChecked, - onChanged: (bool? checked) { - setState(() { - _termsOfUseChecked = checked ?? false; - }); - }, - label: RichText( - maxLines: 2, - key: GlobalKey(), - text: TextSpan( - children: [ - TextSpan( - text: Strings.readAndAgreedToU, - style: RibnToolkitTextStyles.h3.copyWith( - color: RibnColors.lightGreyTitle, - fontSize: 15, - ), - ), - TextSpan( - text: Strings.termsOfUse, - style: RibnToolkitTextStyles.h3.copyWith( - color: const Color(0xff00FFC5), - fontSize: 15, - ), - recognizer: TapGestureRecognizer() - ..onTap = () async { - await launchUrl(url); - }, - ), - ], - ), - ), - activeText: true, - ); - } } diff --git a/lib/presentation/onboarding/restore_wallet/enter_wallet_password_page.dart b/lib/presentation/onboarding/restore_wallet/enter_wallet_password_page.dart index cb756046..f23a6186 100644 --- a/lib/presentation/onboarding/restore_wallet/enter_wallet_password_page.dart +++ b/lib/presentation/onboarding/restore_wallet/enter_wallet_password_page.dart @@ -5,23 +5,23 @@ import 'dart:async'; import 'package:flutter/material.dart'; // Package imports: -import 'package:flutter_redux/flutter_redux.dart'; +import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:ribn_toolkit/constants/colors.dart'; import 'package:ribn_toolkit/constants/styles.dart'; import 'package:ribn_toolkit/widgets/molecules/password_text_field.dart'; // Project imports: -import 'package:ribn/actions/restore_wallet_actions.dart'; import 'package:ribn/constants/strings.dart'; -import 'package:ribn/models/app_state.dart'; import 'package:ribn/presentation/onboarding/utils.dart'; import 'package:ribn/presentation/onboarding/widgets/confirmation_button.dart'; import 'package:ribn/presentation/onboarding/widgets/onboarding_container.dart'; import 'package:ribn/presentation/onboarding/widgets/warning_section.dart'; import 'package:ribn/presentation/onboarding/widgets/web_onboarding_app_bar.dart'; +import 'package:ribn/providers/restore_wallet_provider.dart'; /// Allows the user to enter their wallet password to decrypt the Topl Key in [toplKeyStoreJson]. -class EnterWalletPasswordPage extends StatefulWidget { +class EnterWalletPasswordPage extends HookConsumerWidget { final String toplKeyStoreJson; const EnterWalletPasswordPage({ @@ -29,26 +29,14 @@ class EnterWalletPasswordPage extends StatefulWidget { Key? key, }) : super(key: key); - @override - _EnterWalletPasswordPageState createState() => - _EnterWalletPasswordPageState(); -} - -class _EnterWalletPasswordPageState extends State { final double maxWidth = 734; - final TextEditingController _passwordController = TextEditingController(); - bool _failedToRestoreWallet = false; @override - void initState() { - _passwordController.addListener(() { - setState(() {}); - }); - super.initState(); - } + Widget build(BuildContext context, WidgetRef ref) { + final TextEditingController _passwordController = useTextEditingController(); + final _failedToRestoreWallet = useState(false); - @override - Widget build(BuildContext context) { + final restoreWalletNotifier = ref.watch(restoreWalletProvider.notifier); return Scaffold( body: OnboardingContainer( child: SingleChildScrollView( @@ -65,29 +53,25 @@ class _EnterWalletPasswordPageState extends State { padding: EdgeInsets.symmetric(vertical: 24.0), child: WarningSection(), ), - _buildEnterWalletPassword(), + _buildEnterWalletPassword(_passwordController), const SizedBox(height: 50), ConfirmationButton( text: Strings.next, onPressed: () async { final Completer actionCompleter = Completer(); - StoreProvider.of(context).dispatch( - RestoreWalletWithToplKeyAction( - toplKeyStoreJson: widget.toplKeyStoreJson, - password: _passwordController.text, - completer: actionCompleter, - ), + restoreWalletNotifier.restoreWalletWithToplKey( + toplKeyStoreJson: toplKeyStoreJson, + password: _passwordController.text, + completer: actionCompleter, ); await actionCompleter.future.then((value) { - setState(() { - _failedToRestoreWallet = !value; - }); + _failedToRestoreWallet.value = !value; }); }, ), const SizedBox(height: 10), - _failedToRestoreWallet + _failedToRestoreWallet.value ? const Text( 'Failed to restore wallet.', style: TextStyle(color: Colors.red), @@ -100,7 +84,7 @@ class _EnterWalletPasswordPageState extends State { ); } - Widget _buildEnterWalletPassword() { + Widget _buildEnterWalletPassword(TextEditingController _passwordController) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ diff --git a/lib/presentation/onboarding/restore_wallet/restore_wallet_page.dart b/lib/presentation/onboarding/restore_wallet/restore_wallet_page.dart index ad774ea6..7e2b02b1 100644 --- a/lib/presentation/onboarding/restore_wallet/restore_wallet_page.dart +++ b/lib/presentation/onboarding/restore_wallet/restore_wallet_page.dart @@ -1,55 +1,53 @@ -import 'package:bip_topl/bip_topl.dart'; +// Flutter imports: import 'package:flutter/material.dart'; -import 'package:flutter_redux/flutter_redux.dart'; -import 'package:ribn/actions/misc_actions.dart'; + +// Package imports: +import 'package:bip_topl/bip_topl.dart'; +import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:ribn_toolkit/constants/styles.dart'; +import 'package:ribn_toolkit/widgets/atoms/custom_text_field.dart'; +import 'package:ribn_toolkit/widgets/atoms/large_button.dart'; +import 'package:ribn_toolkit/widgets/organisms/onboarding_progress_bar.dart'; + +// Project imports: import 'package:ribn/constants/routes.dart'; import 'package:ribn/constants/strings.dart'; -import 'package:ribn/models/app_state.dart'; import 'package:ribn/presentation/onboarding/utils.dart'; import 'package:ribn/presentation/onboarding/widgets/confirmation_button.dart'; import 'package:ribn/presentation/onboarding/widgets/onboarding_container.dart'; import 'package:ribn/presentation/onboarding/widgets/web_onboarding_app_bar.dart'; -import 'package:ribn_toolkit/constants/styles.dart'; -import 'package:ribn_toolkit/widgets/atoms/custom_text_field.dart'; -import 'package:ribn_toolkit/widgets/atoms/large_button.dart'; -import 'package:ribn_toolkit/widgets/organisms/onboarding_progress_bar.dart'; +import 'package:ribn/utils/navigation_utils.dart'; /// This page allows the user to enter a known mnemonic / seed phrase in order to restore a wallet. /// /// This page is used in the 'restore wallet' flow when initiated from the login page, /// hence the widget name is prefixed with 'Login'. -class RestoreWalletPage extends StatefulWidget { - const RestoreWalletPage({Key? key}) : super(key: key); +class RestoreWalletPage extends HookWidget { + static const Key restoreWalletPageKey = Key('restoreWalletPageKey'); + static const Key restoreWalletConfirmationButtonKey = Key('restoreWalletConfirmationButtonKey'); + static const Key mnemonicTextFieldKey = Key('mnemonicTextFieldKey'); - @override - _RestoreWalletPageState createState() => _RestoreWalletPageState(); -} - -class _RestoreWalletPageState extends State { - final double maxWidth = 309; + const RestoreWalletPage({Key key = restoreWalletPageKey}) : super(key: key); - /// Controller for the seed phrase text field. - final TextEditingController controller = TextEditingController(); + @override + Widget build(BuildContext context) { + /// Controller for the seed phrase text field. + final TextEditingController controller = useTextEditingController(); - /// Seed phrase entered by the user. - String seedPhrase = ''; + /// Seed phrase entered by the user. + final seedPhrase = useState(controller.text); - /// True if an invalid seed phrase is entered. - bool invalidSeedPhraseEntered = false; + /// True if an invalid seed phrase is entered. + final invalidSeedPhraseEntered = useState(false); - @override - void initState() { - controller.addListener(() { - setState(() { - seedPhrase = controller.text; - invalidSeedPhraseEntered = false; + useEffect(() { + controller.addListener(() { + seedPhrase.value = controller.text; + invalidSeedPhraseEntered.value = false; }); - }); - super.initState(); - } - @override - Widget build(BuildContext context) { + return () {}; + }, []); return Scaffold( extendBody: true, body: OnboardingContainer( @@ -86,11 +84,12 @@ class _RestoreWalletPageState extends State { Align( alignment: Alignment.centerLeft, child: CustomTextField( + textFieldKey: mnemonicTextFieldKey, width: 500, height: 70, controller: controller, hintText: Strings.hintSeedPhrase, - hasError: invalidSeedPhraseEntered, + hasError: invalidSeedPhraseEntered.value, ), ), @@ -101,11 +100,20 @@ class _RestoreWalletPageState extends State { ), adaptableSpacer(), renderIfMobile( - const OnboardingProgressBar(numSteps: 2, currStep: 0)), + const OnboardingProgressBar(numSteps: 2, currStep: 0), + ), const SizedBox(height: 20), - ConfirmationButton( - text: Strings.next, - onPressed: onNextPressed, + Padding( + padding: EdgeInsets.only(bottom: 30), + child: ConfirmationButton( + key: restoreWalletConfirmationButtonKey, + text: Strings.next, + onPressed: () => onNextPressed( + seedPhrase, + context, + invalidSeedPhraseEntered, + ), + ), ), ], ), @@ -116,19 +124,19 @@ class _RestoreWalletPageState extends State { /// Handler for when [LargeButton] is pressed. /// /// Validates the seedphrase entered and if valid, navigates to the next page, i.e. [Routes.restoreWalletNewPassword]. - void onNextPressed() { - final bool isSeedPhraseValid = validateMnemonic(seedPhrase, 'english'); + void onNextPressed( + ValueNotifier seedPhrase, + BuildContext context, + ValueNotifier invalidSeedPhraseEntered, + ) { + final bool isSeedPhraseValid = validateMnemonic(seedPhrase.value, 'english'); if (isSeedPhraseValid) { - StoreProvider.of(context).dispatch( - NavigateToRoute( - Routes.restoreWalletNewPassword, - arguments: seedPhrase, - ), + navigateToRoute( + route: Routes.restoreWalletNewPassword, + arguments: seedPhrase.value, ); } else { - setState(() { - invalidSeedPhraseEntered = true; - }); + invalidSeedPhraseEntered.value = true; } } diff --git a/lib/presentation/onboarding/restore_wallet/restore_with_topl_key_page.dart b/lib/presentation/onboarding/restore_wallet/restore_with_topl_key_page.dart index 795c4bbb..fb588acf 100644 --- a/lib/presentation/onboarding/restore_wallet/restore_with_topl_key_page.dart +++ b/lib/presentation/onboarding/restore_wallet/restore_with_topl_key_page.dart @@ -61,9 +61,7 @@ class _RestoreWithToplKeyPageState extends State { _buildUploadFileButton(), SizedBox( height: 150, - child: uploadedFileName.isNotEmpty - ? _buildUploadedFileContainer() - : const SizedBox(), + child: uploadedFileName.isNotEmpty ? _buildUploadedFileContainer() : const SizedBox(), ), errorUploadingFile ? const Text( @@ -126,8 +124,7 @@ class _RestoreWithToplKeyPageState extends State { ), onPressed: () async { try { - final FilePickerResult? result = - await FilePicker.platform.pickFiles(); + final FilePickerResult? result = await FilePicker.platform.pickFiles(); if (result != null) { final PlatformFile file = result.files.first; // utf8.decode the file bytes to get the file content as a string @@ -157,8 +154,7 @@ class _RestoreWithToplKeyPageState extends State { children: [ Text( 'Uploaded file', - style: - RibnToolkitTextStyles.body1Bold.copyWith(color: Colors.white), + style: RibnToolkitTextStyles.body1Bold.copyWith(color: Colors.white), ), const SizedBox(height: 5), UploadedFileContainer( diff --git a/lib/presentation/onboarding/utils.dart b/lib/presentation/onboarding/utils.dart index fda3773b..0dfe2f7f 100644 --- a/lib/presentation/onboarding/utils.dart +++ b/lib/presentation/onboarding/utils.dart @@ -5,5 +5,4 @@ import 'package:flutter/material.dart'; Widget adaptableSpacer() => kIsWeb ? const SizedBox(height: 100) : const Spacer(); Widget renderIfMobile(Widget widget) => kIsWeb ? const SizedBox() : widget; Widget renderIfWeb(Widget widget) => kIsWeb ? widget : const SizedBox(); -Widget scrollableIfWeb(Widget child) => - kIsWeb ? SingleChildScrollView(child: child) : SizedBox(child: child); +Widget scrollableIfWeb(Widget child) => kIsWeb ? SingleChildScrollView(child: child) : SizedBox(child: child); diff --git a/lib/presentation/onboarding/widgets/onboarding_container.dart b/lib/presentation/onboarding/widgets/onboarding_container.dart index 1c77dc6b..513b2600 100644 --- a/lib/presentation/onboarding/widgets/onboarding_container.dart +++ b/lib/presentation/onboarding/widgets/onboarding_container.dart @@ -1,11 +1,13 @@ // Flutter imports: import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; -import 'package:ribn/presentation/basic/custom_back_button.dart'; // Package imports: import 'package:ribn_toolkit/constants/colors.dart'; +// Project imports: +import 'package:ribn/presentation/basic/custom_back_button.dart'; + class OnboardingContainer extends StatelessWidget { final Widget child; final bool isXsScreenSize; @@ -20,7 +22,7 @@ class OnboardingContainer extends StatelessWidget { @override Widget build(BuildContext context) { - final double topPadding = kIsWeb ? 50 : MediaQuery.of(context).size.height * 0.12; + final double topPadding = kIsWeb ? 50 : MediaQuery.of(context).size.height * 0.10; return Container( height: double.infinity, width: double.infinity, diff --git a/lib/presentation/onboarding/widgets/opt_in_tracker_page.dart b/lib/presentation/onboarding/widgets/opt_in_tracker_page.dart new file mode 100644 index 00000000..9ac2e5d1 --- /dev/null +++ b/lib/presentation/onboarding/widgets/opt_in_tracker_page.dart @@ -0,0 +1,305 @@ +// Flutter imports: +import 'package:flutter/foundation.dart'; +import 'package:flutter/gestures.dart'; +import 'package:flutter/material.dart'; + +// Package imports: +import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:ribn_toolkit/constants/colors.dart'; +import 'package:ribn_toolkit/constants/styles.dart'; +import 'package:ribn_toolkit/widgets/atoms/large_button.dart'; + +// Project imports: +import 'package:ribn/constants/assets.dart'; +import 'package:ribn/constants/keys.dart'; +import 'package:ribn/constants/routes.dart'; +import 'package:ribn/constants/strings.dart'; +import 'package:ribn/presentation/onboarding/widgets/onboarding_container.dart'; +import 'package:ribn/providers/analytics/analytics_provider.dart'; +import 'package:ribn/utils/url_utils.dart'; + +class OptInTracker extends HookConsumerWidget { + static const Key optInTrackerKey = Key('optInTrackerKey'); + static const Key noThanksKey = Key('noThanksKey'); + static const Key iAgreeKey = Key('iAgreeKey'); + static const Key readMoreKey = Key('readMoreKey'); + static const Key privacyPolicyKey = Key('privacyPolicyKey'); + + const OptInTracker({Key key = optInTrackerKey}) : super(key: key); + + _handleNoThanks() { + Keys.navigatorKey.currentState?.pushNamed(Routes.selectAction); + } + + _handleIAgree(AnalyticsNotifier analyticsNotifier) async { + await analyticsNotifier.toggleAnalytics(overrideValue: true); + Keys.navigatorKey.currentState?.pushNamed(Routes.selectAction); + } + + @override + Widget build(BuildContext context, WidgetRef ref) { + final AnalyticsNotifier analyticsNotifier = ref.watch(analyticsProvider.notifier); + return Scaffold( + body: OnboardingContainer( + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + Expanded( + child: SizedBox( + width: 700, + child: ListView( + padding: EdgeInsets.only(bottom: 20), + children: [ + _Header(), + _TopParagraph(), + SizedBox(height: 10), + _BulletPoints(), + SizedBox(height: 10), + _ReadMoreSection(), + ], + ), + ), + ), + _BottomButtons( + iAgreePressed: () => _handleIAgree(analyticsNotifier), + noThanksPressed: _handleNoThanks, + ), + ], + ), + ), + ); + } +} + +class _BottomButtons extends StatelessWidget { + final void Function() noThanksPressed; + final void Function() iAgreePressed; + const _BottomButtons({ + required this.iAgreePressed, + required this.noThanksPressed, + Key? key, + }) : super(key: key); + + List _buttons() { + return [ + LargeButton( + key: OptInTracker.noThanksKey, + buttonWidth: kIsWeb ? 220 : 135, + buttonHeight: 40, + backgroundColor: Colors.transparent, + borderColor: kIsWeb ? Colors.transparent : RibnColors.greyOutline, + dropShadowColor: kIsWeb ? Colors.transparent : RibnColors.primaryButtonShadow, + hoverColor: kIsWeb ? Colors.transparent : RibnColors.primaryButtonHover, + onPressed: noThanksPressed, + buttonChild: Text( + Strings.noThanks, + style: RibnToolkitTextStyles.btnMedium.copyWith(color: Colors.white), + ), + ), + LargeButton( + key: OptInTracker.iAgreeKey, + buttonWidth: kIsWeb ? 220 : 135, + buttonHeight: 40, + backgroundColor: RibnColors.primary, + dropShadowColor: RibnColors.whiteButtonShadow, + onPressed: iAgreePressed, + buttonChild: Text( + Strings.iAgree, + style: RibnToolkitTextStyles.btnMedium.copyWith(color: Colors.white), + ), + ), + ]; + } + + @override + Widget build(BuildContext context) { + return kIsWeb + ? Container( + height: 120, + padding: EdgeInsets.only(bottom: 20), + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + crossAxisAlignment: CrossAxisAlignment.center, + children: _buttons().reversed.toList(), + ), + ) + : Container( + height: 100, + padding: EdgeInsets.only(bottom: 20), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + crossAxisAlignment: CrossAxisAlignment.center, + children: _buttons(), + ), + ); + } +} + +class _Header extends StatelessWidget { + const _Header({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return Container( + padding: EdgeInsets.only( + bottom: 30, + ), + height: 200, + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Container( + width: kIsWeb ? MediaQuery.of(context).size.width : 200, + child: Text( + Strings.helpUsImprove, + style: RibnToolkitTextStyles.onboardingH1, + softWrap: true, + textAlign: TextAlign.center, + overflow: TextOverflow.ellipsis, + maxLines: 2, + ), + ), + Container( + decoration: BoxDecoration( + color: RibnColors.primary, + borderRadius: BorderRadius.circular(10), + ), + height: 50, + width: 50, + padding: EdgeInsets.only( + top: 8, + bottom: 10, + left: 10, + right: 8, + ), + child: Image.asset( + RibnAssets.improvePng, + ), + ), + ], + ), + ); + } +} + +class _TopParagraph extends StatelessWidget { + const _TopParagraph({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + Strings.ribnWalletGatherUsage, + style: RibnToolkitTextStyles.onboardingH3, + ), + SizedBox(height: 10), + Text( + Strings.optOut, + style: RibnToolkitTextStyles.onboardingH3, + ), + ], + ); + } +} + +class _BulletPoints extends StatelessWidget { + const _BulletPoints({Key? key}) : super(key: key); + + Widget _bulletPoint(String text, BuildContext context) { + return Container( + padding: EdgeInsets.symmetric( + vertical: 5, + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Container( + padding: EdgeInsets.only( + top: 10, + left: 10, + right: 10, + ), + child: Image.asset( + RibnAssets.bulletPointPng, + height: 11, + ), + ), + Flexible( + child: Text( + text, + style: RibnToolkitTextStyles.onboardingH3, + ), + ), + ], + ), + ); + } + + @override + Widget build(BuildContext context) { + return Column( + children: [ + _bulletPoint(Strings.neverCollectKeys, context), + _bulletPoint(Strings.neverCollectIP, context), + _bulletPoint(Strings.neverSellData, context), + ], + ); + } +} + +class _ReadMoreSection extends HookConsumerWidget { + const _ReadMoreSection({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context, WidgetRef ref) { + final showReadMore = useState(false); + return Column( + children: [ + Row( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Text( + Strings.readMore, + style: RibnToolkitTextStyles.onboardingH3, + ), + IconButton( + key: OptInTracker.readMoreKey, + onPressed: () { + showReadMore.value = !showReadMore.value; + }, + icon: Icon(showReadMore.value ? Icons.expand_less : Icons.expand_more), + padding: EdgeInsets.zero, + iconSize: 30, + color: Colors.white, + constraints: BoxConstraints(), + ), + ], + ), + if (showReadMore.value) + RichText( + text: TextSpan( + children: [ + TextSpan( + text: '${Strings.readMorePrivacy} ', + style: RibnToolkitTextStyles.onboardingH3, + ), + TextSpan( + text: Strings.privacyPolicyLink, + style: RibnToolkitTextStyles.linkText, + recognizer: new TapGestureRecognizer() + ..onTap = () async { + await launchPrivacyPolicyUrl(ref); + }, + ), + ], + ), + ), + ], + ); + } +} diff --git a/lib/presentation/onboarding/widgets/password_section.dart b/lib/presentation/onboarding/widgets/password_section.dart new file mode 100644 index 00000000..9fc4f156 --- /dev/null +++ b/lib/presentation/onboarding/widgets/password_section.dart @@ -0,0 +1,254 @@ +// Flutter imports: +import 'package:flutter/foundation.dart'; +import 'package:flutter/gestures.dart'; +import 'package:flutter/material.dart'; + +// Package imports: +import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:ribn_toolkit/constants/colors.dart'; +import 'package:ribn_toolkit/constants/styles.dart'; +import 'package:ribn_toolkit/widgets/molecules/checkbox_wrappable_text.dart'; +import 'package:ribn_toolkit/widgets/molecules/password_text_field.dart'; + +// Project imports: +import 'package:ribn/constants/strings.dart'; +import 'package:ribn/providers/password_provider.dart'; +import 'package:ribn/utils/url_utils.dart'; +import 'package:ribn/utils/utils.dart'; + +class PasswordSection extends HookConsumerWidget { + static const passwordSectionKey = Key('passwordSectionKey'); + static const newPasswordTextFieldKey = Key('newPasswordTextFieldKey'); + static const confirmPasswordTextFieldKey = Key('confirmPasswordTextFieldKey'); + static const termsOfAgreementCheckboxKey = Key('termsOfAgreementCheckboxKey'); + const PasswordSection({ + Key key = passwordSectionKey, + }) : super(key: key); + + @override + Widget build(BuildContext context, WidgetRef ref) { + final passwordNotifier = ref.watch(passwordProvider.notifier); + final passwordState = ref.watch(passwordProvider); + + final TextEditingController _newPasswordController = useTextEditingController(); + final TextEditingController _confirmPasswordController = useTextEditingController(); + + /// Adds listeners to update provider + /// You have to read inside useEffect, otherwise it will have a cached value of all inputs at widget load + useEffect(() { + _newPasswordController.addListener( + () { + final _passwordState = ref.read(passwordProvider); + passwordNotifier.state = _passwordState.copyWith(password: _newPasswordController.text); + }, + ); + _confirmPasswordController.addListener( + () { + final _passwordState = ref.read(passwordProvider); + passwordNotifier.state = _passwordState.copyWith(confirmPassword: _confirmPasswordController.text); + }, + ); + + return () {}; + }, []); + + return Column( + children: [ + _NewPasswordSection( + textEditingController: _newPasswordController, + atLeast8Chars: passwordState.atLeast8Chars, + textFieldKey: newPasswordTextFieldKey, + ), + SizedBox(height: adaptHeight(0.02)), + _ConfirmPasswordSection( + textEditingController: _confirmPasswordController, + passwordsMatch: passwordState.passwordsMatch, + textFieldKey: confirmPasswordTextFieldKey, + ), + SizedBox(height: adaptHeight(0.02)), + _TermsOfAgreementSection( + termsOfUseChecked: passwordState.termsOfUseChecked, + checkboxKey: termsOfAgreementCheckboxKey, + updateTermsOfUseChecked: (val) { + passwordNotifier.state = passwordState.copyWith(termsOfUseChecked: val); + }, + ), + ], + ); + } +} + +class _NewPasswordSection extends StatelessWidget { + final TextEditingController textEditingController; + final bool atLeast8Chars; + final Key textFieldKey; + const _NewPasswordSection({ + required this.textEditingController, + required this.atLeast8Chars, + required this.textFieldKey, + Key? key, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + return Column( + children: [ + Align( + alignment: Alignment.centerLeft, + child: Text( + Strings.newWalletPassword, + textAlign: TextAlign.left, + style: RibnToolkitTextStyles.h3.copyWith( + fontWeight: FontWeight.bold, + color: RibnColors.lightGreyTitle, + ), + ), + ), + const SizedBox(height: 8), + Align( + alignment: Alignment.centerLeft, + child: PasswordTextField( + key: textFieldKey, + // focusNode: _newPasswordFocus, + width: kIsWeb ? 350 : adaptWidth(0.9), + fillColor: RibnColors.whiteButtonShadow, + controller: textEditingController, + hintText: '', + obscurePassword: true, + textInputAction: TextInputAction.next, + ), + ), + const SizedBox(height: 8), + Align( + alignment: Alignment.centerLeft, + child: Text( + Strings.atLeast8Chars, + textAlign: TextAlign.left, + style: RibnToolkitTextStyles.h3.copyWith( + color: !atLeast8Chars && textEditingController.text.isNotEmpty ? Colors.red : Colors.white, + ), + ), + ), + Align( + alignment: Alignment.centerLeft, + child: Text( + Strings.passwordExample, + textAlign: TextAlign.left, + style: RibnToolkitTextStyles.h3.copyWith( + color: Colors.white, + ), + ), + ), + ], + ); + } +} + +class _ConfirmPasswordSection extends StatelessWidget { + final TextEditingController textEditingController; + final bool passwordsMatch; + final Key textFieldKey; + + const _ConfirmPasswordSection({ + required this.textEditingController, + required this.passwordsMatch, + required this.textFieldKey, + Key? key, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + return Column( + children: [ + Align( + alignment: Alignment.centerLeft, + child: Text( + Strings.confirmWalletPassword, + textAlign: TextAlign.left, + style: RibnToolkitTextStyles.h3.copyWith( + fontWeight: FontWeight.bold, + color: RibnColors.lightGreyTitle, + ), + ), + ), + const SizedBox(height: 8), + Align( + alignment: Alignment.centerLeft, + child: PasswordTextField( + key: textFieldKey, + // focusNode: _confirmPasswordFocus, + width: kIsWeb ? 350 : adaptWidth(0.9), + fillColor: RibnColors.whiteButtonShadow, + controller: textEditingController, + hintText: '', + obscurePassword: true, + ), + ), + const SizedBox(height: 8), + Align( + alignment: Alignment.centerLeft, + child: Text( + Strings.passwordsMustMatch, + textAlign: TextAlign.left, + style: RibnToolkitTextStyles.h3.copyWith( + color: !passwordsMatch && textEditingController.value.text.isNotEmpty ? Colors.red : Colors.white, + ), + ), + ), + ], + ); + } +} + +class _TermsOfAgreementSection extends HookConsumerWidget { + final bool termsOfUseChecked; + final Function(bool) updateTermsOfUseChecked; + final Key checkboxKey; + const _TermsOfAgreementSection({ + required this.termsOfUseChecked, + required this.updateTermsOfUseChecked, + required this.checkboxKey, + Key? key, + }) : super(key: key); + + @override + Widget build(BuildContext context, WidgetRef ref) { + return CheckboxWrappableText( + checkboxKey: checkboxKey, + wrapText: false, + borderColor: termsOfUseChecked ? const Color(0xff80FF00) : RibnColors.lightGreyTitle, + value: termsOfUseChecked, + onChanged: (bool? checked) { + updateTermsOfUseChecked(checked ?? false); + }, + label: RichText( + maxLines: 2, + key: GlobalKey(), + text: TextSpan( + children: [ + TextSpan( + text: Strings.readAndAgreedToU, + style: RibnToolkitTextStyles.h3.copyWith( + color: RibnColors.lightGreyTitle, + fontSize: 15, + ), + ), + TextSpan( + text: Strings.termsOfUse, + style: RibnToolkitTextStyles.h3.copyWith( + color: const Color(0xff00FFC5), + fontSize: 15, + ), + recognizer: TapGestureRecognizer() + ..onTap = () async { + await launchTermsOfUse(ref); + }, + ), + ], + ), + ), + activeText: true, + ); + } +} diff --git a/lib/presentation/onboarding/widgets/uploaded_file_container.dart b/lib/presentation/onboarding/widgets/uploaded_file_container.dart index 5e29a0e3..3dcf79e9 100644 --- a/lib/presentation/onboarding/widgets/uploaded_file_container.dart +++ b/lib/presentation/onboarding/widgets/uploaded_file_container.dart @@ -45,8 +45,7 @@ class UploadedFileContainer extends StatelessWidget { const SizedBox(width: 8), Text( uploadedFileName, - style: - RibnToolkitTextStyles.onboardingH3.copyWith(fontSize: 15), + style: RibnToolkitTextStyles.onboardingH3.copyWith(fontSize: 15), ), const Spacer(), Image.asset(RibnAssets.checkCircleIcon, width: 20), diff --git a/lib/presentation/onboarding/widgets/warning_section.dart b/lib/presentation/onboarding/widgets/warning_section.dart index 61566322..03a8d82d 100644 --- a/lib/presentation/onboarding/widgets/warning_section.dart +++ b/lib/presentation/onboarding/widgets/warning_section.dart @@ -61,8 +61,7 @@ class WarningSection extends StatelessWidget { Strings.restoreWalletWarning, style: kIsWeb ? RibnToolkitTextStyles.onboardingH3 - : RibnToolkitTextStyles.smallBody - .copyWith(fontSize: 15, color: Colors.white), + : RibnToolkitTextStyles.smallBody.copyWith(fontSize: 15, color: Colors.white), ), ), ), diff --git a/lib/presentation/settings/sections/analytics_section.dart b/lib/presentation/settings/sections/analytics_section.dart new file mode 100644 index 00000000..a252158f --- /dev/null +++ b/lib/presentation/settings/sections/analytics_section.dart @@ -0,0 +1,53 @@ +// Flutter imports: +import 'package:flutter/material.dart'; + +// Package imports: +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:ribn_toolkit/constants/styles.dart'; +import 'package:ribn_toolkit/widgets/atoms/custom_toggle.dart'; + +// Project imports: +import 'package:ribn/constants/strings.dart'; +import 'package:ribn/providers/analytics/analytics_provider.dart'; + +class AnalyticsSection extends ConsumerWidget { + const AnalyticsSection({ + Key? key, + }) : super(key: key); + + @override + Widget build(BuildContext context, WidgetRef ref) { + final analytics = ref.watch(analyticsProvider); + final notifier = ref.watch(analyticsProvider.notifier); + + return Row( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Text( + Strings.participateInAnalytics, + style: RibnToolkitTextStyles.extH3, + ), + const Padding( + padding: EdgeInsets.only(top: 6, bottom: 8), + child: Text( + Strings.participateInAnalyticsDescription, + style: RibnToolkitTextStyles.settingsSmallText, + ), + ), + ], + ), + Spacer(), + Padding( + padding: const EdgeInsets.only(right: 8.0), + child: CustomToggle( + onChanged: (value) => notifier.toggleAnalytics(), + value: analytics.isEnabled, + ), + ), + ], + ); + } +} diff --git a/lib/presentation/settings/sections/biometrics_section.dart b/lib/presentation/settings/sections/biometrics_section.dart index dbbec720..8864b93b 100644 --- a/lib/presentation/settings/sections/biometrics_section.dart +++ b/lib/presentation/settings/sections/biometrics_section.dart @@ -1,71 +1,54 @@ // Dart imports: import 'dart:io' show Platform; -import 'dart:io'; // Flutter imports: import 'package:flutter/material.dart'; // Package imports: import 'package:app_settings/app_settings.dart'; -import 'package:flutter_redux/flutter_redux.dart'; -import 'package:local_auth/local_auth.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:ribn_toolkit/constants/styles.dart'; import 'package:ribn_toolkit/widgets/atoms/custom_toggle.dart'; // Project imports: -import 'package:ribn/actions/user_details_actions.dart'; import 'package:ribn/constants/assets.dart'; import 'package:ribn/constants/strings.dart'; -import 'package:ribn/models/app_state.dart'; -import 'package:ribn/utils.dart'; +import 'package:ribn/providers/biometrics_provider.dart'; +import 'package:ribn/providers/logger_provider.dart'; /// The section allows for users to toggle biometrics authentication on/off. -class BiometricsSection extends StatefulWidget { - /// True if biometrics authentication is enabled - final bool isBiometricsEnabled; - - const BiometricsSection({ - required this.isBiometricsEnabled, +class BiometricsSection extends ConsumerWidget { + BiometricsSection({ Key? key, }) : super(key: key); - @override - State createState() => _BiometricsSectionState(); -} + Future runBiometrics(BuildContext context, WidgetRef ref, bool value) async { + final notifier = ref.read(biometricsProvider.notifier); -class _BiometricsSectionState extends State { - final LocalAuthentication _localAuthentication = LocalAuthentication(); + if (!await notifier.isBiometricsAuthenticationEnrolled()) return; - /// True if biometrics authentication is completed successfully - bool _authorized = false; + try { + final authorized = await notifier.authenticateWithBiometrics(); + notifier.setAuthorization(authorized); - Future runBiometrics(value) async { - bool authenticated = false; - await isBiometricsAuthenticationEnrolled(_localAuthentication); + if (!authorized) { + // TODO: add some kind of UX feature to let the user know this failed - try { - authenticated = await authenticateWithBiometrics(_localAuthentication); + ref.read(loggerProvider).log( + logLevel: LogLevel.Info, + loggerClass: LoggerClass.Authentication, + message: 'Biometrics Identity not recognized', + ); + return; + } + notifier.toggleBiometrics(); } catch (e) { - if (Platform.isAndroid) await _showMyDialog(); + if (Platform.isAndroid) await _showMyDialog(context); return; } - - if (!mounted || !authenticated) { - return; - } - - setState(() { - _authorized = authenticated ? true : false; - }); - - StoreProvider.of(context).dispatch( - UpdateBiometricsAction( - isBiometricsEnabled: value, - ), - ); } - Future _showMyDialog() async { + Future _showMyDialog(BuildContext context) async { return showDialog( context: context, barrierDismissible: false, @@ -80,7 +63,7 @@ class _BiometricsSectionState extends State { ], ), ), - actions: [ + actions: [ TextButton( child: const Text('Ok'), onPressed: () { @@ -98,47 +81,49 @@ class _BiometricsSectionState extends State { } @override - Widget build(BuildContext context) { - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - children: [ - const Text( - Strings.enableBiometrics, - style: RibnToolkitTextStyles.extH3, - ), - Padding( - padding: const EdgeInsets.only(left: 10), - child: Image.asset( - Platform.isIOS - ? RibnAssets.iosBiometricsOutline - : RibnAssets.andriodBiometricsOutline, - width: 40, - ), - ), - ], - ), - const Padding( - padding: EdgeInsets.only(top: 6, bottom: 8), - child: Text( - Strings.enableBiometricsDescription, - style: RibnToolkitTextStyles.settingsSmallText, - ), - ), - Transform.scale( - alignment: Alignment.centerLeft, - scale: 0.7, - child: CustomToggle( - onChanged: (value) { - runBiometrics(value).then( - (value) => {if (_authorized) setState(() {})}, - ); - }, - value: widget.isBiometricsEnabled, - ), - ), - ], - ); + Widget build(BuildContext context, WidgetRef ref) { + final biometrics = ref.watch(biometricsProvider); + + return biometrics.when( + error: (_, __) => const SizedBox(), + loading: () => const SizedBox(), + data: (data) => data.isSupported + ? Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + const Text( + Strings.enableBiometrics, + style: RibnToolkitTextStyles.extH3, + ), + Padding( + padding: const EdgeInsets.only(left: 10), + child: Image.asset( + Platform.isIOS ? RibnAssets.iosBiometricsOutline : RibnAssets.andriodBiometricsOutline, + width: 40, + ), + ), + ], + ), + const Padding( + padding: EdgeInsets.only(top: 6, bottom: 8), + child: Text( + Strings.enableBiometricsDescription, + style: RibnToolkitTextStyles.settingsSmallText, + ), + ), + Transform.scale( + alignment: Alignment.centerLeft, + scale: 0.7, + child: CustomToggle( + onChanged: (value) { + runBiometrics(context, ref, value); + }, + value: data.isEnabled), + ), + ], + ) + : const SizedBox()); } } diff --git a/lib/presentation/settings/sections/danger_container_section.dart b/lib/presentation/settings/sections/danger_container_section.dart new file mode 100644 index 00000000..3af9d787 --- /dev/null +++ b/lib/presentation/settings/sections/danger_container_section.dart @@ -0,0 +1,45 @@ +// Flutter imports: +import 'package:flutter/material.dart'; + +// Package imports: +import 'package:ribn_toolkit/constants/styles.dart'; + +// Project imports: +import 'package:ribn/constants/strings.dart'; + +/// The section on the settings page that allows user to delete their wallet. +class DangerContainerSection extends StatelessWidget { + final List children; + + const DangerContainerSection({ + required this.children, + Key? key, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Text( + Strings.dangerZone, + style: TextStyle( + fontFamily: 'DM Sans', + fontWeight: FontWeight.w700, + fontSize: 16, + color: Color(0xFFE80E00), + ), + ), + const SizedBox(height: 10), + const Text( + Strings.actionNotReversible, + style: RibnToolkitTextStyles.settingsSmallText, + ), + const SizedBox( + height: 10, + ), + ...children + ], + ); + } +} diff --git a/lib/presentation/settings/sections/delete_wallet_confirmation_dialog.dart b/lib/presentation/settings/sections/delete_wallet_confirmation_dialog.dart index 3a729651..b8c1c407 100644 --- a/lib/presentation/settings/sections/delete_wallet_confirmation_dialog.dart +++ b/lib/presentation/settings/sections/delete_wallet_confirmation_dialog.dart @@ -10,6 +10,7 @@ import 'package:ribn_toolkit/widgets/molecules/password_text_field.dart'; // Project imports: import 'package:ribn/constants/strings.dart'; +import 'package:ribn/utils/input_utils.dart'; /// The confimation dialog that is displayed before deleting the wallet. /// @@ -27,12 +28,10 @@ class DeleteWalletConfirmationDialog extends StatefulWidget { }) : super(key: key); @override - _DeleteWalletConfirmationDialogState createState() => - _DeleteWalletConfirmationDialogState(); + _DeleteWalletConfirmationDialogState createState() => _DeleteWalletConfirmationDialogState(); } -class _DeleteWalletConfirmationDialogState - extends State { +class _DeleteWalletConfirmationDialogState extends State { final TextEditingController _passwordController = TextEditingController(); /// True if incorrect password was entered. @@ -44,7 +43,7 @@ class _DeleteWalletConfirmationDialogState Widget build(BuildContext context) { return CustomModal.renderCustomModal( title: const Text( - Strings.deleteRibnWallet, + Strings.removeFromDevice, style: RibnToolkitTextStyles.extH2, ), context: context, @@ -52,9 +51,9 @@ class _DeleteWalletConfirmationDialogState children: [ SizedBox( width: 228, - height: 125, + height: 160, child: Text( - Strings.deleteRibnWalletDesc, + Strings.removeRibnWalletDesc, style: RibnToolkitTextStyles.smallBody.copyWith(fontSize: 15), ), ), @@ -96,12 +95,13 @@ class _DeleteWalletConfirmationDialogState // confirm delete LargeButton( buttonChild: Text( - Strings.yesIWantToDelete, + Strings.yesIWantToRemove, style: RibnToolkitTextStyles.btnMedium.copyWith( color: Colors.white, ), ), onPressed: () { + dismissKeyboard(context); widget.onConfirmDeletePressed( _passwordController.text, () { diff --git a/lib/presentation/settings/sections/delete_wallet_section.dart b/lib/presentation/settings/sections/delete_wallet_section.dart index e4143977..0e8909d8 100644 --- a/lib/presentation/settings/sections/delete_wallet_section.dart +++ b/lib/presentation/settings/sections/delete_wallet_section.dart @@ -14,14 +14,8 @@ class DeleteWalletSection extends StatelessWidget { /// Handler for when user confirms wallet deletion. final Function(BuildContext context) onDeletePressed; - final Function(BuildContext context) onDisconnectPressed; - - final bool canDisconnect; - const DeleteWalletSection({ required this.onDeletePressed, - required this.onDisconnectPressed, - required this.canDisconnect, Key? key, }) : super(key: key); @@ -30,77 +24,15 @@ class DeleteWalletSection extends StatelessWidget { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - const Text( - Strings.dangerZone, - style: TextStyle( - fontFamily: 'DM Sans', - fontWeight: FontWeight.w700, - fontSize: 16, - color: Color(0xFFE80E00), - ), - ), - const SizedBox(height: 10), - const Text( - Strings.actionNotReversible, - style: RibnToolkitTextStyles.settingsSmallText, - ), - const SizedBox(height: 10), - Container( - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(4), - color: RibnColors.paleGrey, - ), - width: 291, - height: 67, - child: Padding( - padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 10), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text( - Strings.disconnectDApps, - style: RibnToolkitTextStyles.settingsSmallText, - ), - const SizedBox(height: 10), - SizedBox( - width: 107, - height: 22, - child: LargeButton( - buttonChild: Text( - Strings.disconnect, - style: RibnToolkitTextStyles.btnLarge.copyWith( - color: RibnColors.primary - .withOpacity(canDisconnect == true ? 1.0 : 0.3), - fontSize: 10, - ), - ), - backgroundColor: Colors.transparent, - hoverColor: Colors.transparent, - dropShadowColor: Colors.transparent, - borderColor: RibnColors.primary - .withOpacity(canDisconnect == true ? 1.0 : 0.3), - onPressed: () => - canDisconnect ? onDisconnectPressed(context) : null, - ), - ), - ], - ), - ), - ), - const SizedBox( - height: 5, - ), Container( decoration: BoxDecoration( borderRadius: BorderRadius.circular(4), color: const Color(0xffE80E00).withOpacity(0.09), ), - width: 291, - height: 67, child: Padding( padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 10), child: Column( - crossAxisAlignment: CrossAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.stretch, children: [ const Text( Strings.removeWallet, @@ -112,7 +44,7 @@ class DeleteWalletSection extends StatelessWidget { height: 22, child: LargeButton( buttonChild: Text( - Strings.delete, + Strings.remove, style: RibnToolkitTextStyles.btnLarge.copyWith( color: RibnColors.primary, fontSize: 10, diff --git a/lib/presentation/settings/sections/disconnect_dapps_section.dart b/lib/presentation/settings/sections/disconnect_dapps_section.dart new file mode 100644 index 00000000..cd2808d9 --- /dev/null +++ b/lib/presentation/settings/sections/disconnect_dapps_section.dart @@ -0,0 +1,68 @@ +// Flutter imports: +import 'package:flutter/material.dart'; + +// Package imports: +import 'package:ribn_toolkit/constants/colors.dart'; +import 'package:ribn_toolkit/constants/styles.dart'; +import 'package:ribn_toolkit/widgets/atoms/large_button.dart'; + +// Project imports: +import 'package:ribn/constants/strings.dart'; + +/// The section on the settings page that allows user to delete their wallet. +class DisconnectDAppsSection extends StatelessWidget { + /// Handler for when user confirms wallet deletion. + + final Function(BuildContext context) onDisconnectPressed; + + final bool canDisconnect; + + const DisconnectDAppsSection({ + required this.onDisconnectPressed, + required this.canDisconnect, + Key? key, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + return Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(4), + color: RibnColors.paleGrey, + ), + height: 67, + child: Padding( + padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 10), + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + const Text( + Strings.disconnectDApps, + style: RibnToolkitTextStyles.settingsSmallText, + ), + Padding( + padding: const EdgeInsets.only(top: 8.0), + child: Container( + constraints: BoxConstraints(maxWidth: 30, maxHeight: 22), + child: LargeButton( + buttonChild: Text( + Strings.disconnect, + style: RibnToolkitTextStyles.btnLarge.copyWith( + color: RibnColors.primary.withOpacity(canDisconnect == true ? 1.0 : 0.3), + fontSize: 10, + ), + ), + backgroundColor: Colors.transparent, + hoverColor: Colors.transparent, + dropShadowColor: Colors.transparent, + borderColor: RibnColors.primary.withOpacity(canDisconnect == true ? 1.0 : 0.3), + onPressed: () => canDisconnect ? onDisconnectPressed(context) : null, + ), + ), + ), + ], + ), + ), + ); + } +} diff --git a/lib/presentation/settings/sections/disconnect_wallet_confirmation_dialog.dart b/lib/presentation/settings/sections/disconnect_wallet_confirmation_dialog.dart index 43681774..bd34c9b4 100644 --- a/lib/presentation/settings/sections/disconnect_wallet_confirmation_dialog.dart +++ b/lib/presentation/settings/sections/disconnect_wallet_confirmation_dialog.dart @@ -13,19 +13,15 @@ import 'package:ribn/platform/platform.dart'; /// The confirmation dialog that is displayed before disconnecting the wallet. class DisconnectWalletConfirmationDialog extends StatefulWidget { - const DisconnectWalletConfirmationDialog({Key? key, required this.dApps}) - : super(key: key); + const DisconnectWalletConfirmationDialog({Key? key, required this.dApps}) : super(key: key); final List dApps; @override - _DisconnectWalletConfirmationDialogState createState() => - _DisconnectWalletConfirmationDialogState(); + _DisconnectWalletConfirmationDialogState createState() => _DisconnectWalletConfirmationDialogState(); } -class _DisconnectWalletConfirmationDialogState - extends State { - +class _DisconnectWalletConfirmationDialogState extends State { ScrollController _scrollController = ScrollController(); @override @@ -63,8 +59,7 @@ class _DisconnectWalletConfirmationDialogState thumbColor: RibnColors.primary, thickness: 10, child: ScrollConfiguration( - behavior: - ScrollConfiguration.of(context).copyWith(scrollbars: false), + behavior: ScrollConfiguration.of(context).copyWith(scrollbars: false), child: ListView.builder( controller: _scrollController, shrinkWrap: true, @@ -101,8 +96,7 @@ class _DisconnectWalletConfirmationDialogState ), onPressed: () async { // Disconnect action to go here - await PlatformUtils.instance - .convertToFuture(PlatformUtils.instance.clearDAppList()); + await PlatformUtils.instance.convertToFuture(PlatformUtils.instance.clearDAppList()); Navigator.of(context, rootNavigator: true).pop(true); }, buttonWidth: 285, diff --git a/lib/presentation/settings/sections/export_topl_main_key_section.dart b/lib/presentation/settings/sections/export_topl_main_key_section.dart deleted file mode 100644 index f8f2b029..00000000 --- a/lib/presentation/settings/sections/export_topl_main_key_section.dart +++ /dev/null @@ -1,58 +0,0 @@ -// Flutter imports: -import 'package:flutter/material.dart'; - -// Package imports: -import 'package:ribn_toolkit/constants/colors.dart'; -import 'package:ribn_toolkit/constants/styles.dart'; -import 'package:ribn_toolkit/widgets/atoms/large_button.dart'; - -// Project imports: -import 'package:ribn/constants/strings.dart'; - -/// The section that allows for downloading the Topl Main Key. -class ExportToplMainKeySection extends StatelessWidget { - /// Callback for when export button is pressed. - final VoidCallback onExportPressed; - - const ExportToplMainKeySection({ - required this.onExportPressed, - Key? key, - }) : super(key: key); - - @override - Widget build(BuildContext context) { - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text( - Strings.exportToplMainKey, - style: RibnToolkitTextStyles.extH3, - ), - const Padding( - padding: EdgeInsets.only(top: 6, bottom: 8), - child: Text( - Strings.exportToplMainKeyDesc, - style: RibnToolkitTextStyles.settingsSmallText, - ), - ), - SizedBox( - width: 110, - height: 22, - child: LargeButton( - buttonChild: Text( - Strings.exportWallet, - style: RibnToolkitTextStyles.btnLarge.copyWith( - color: Colors.white, - fontSize: 10, - ), - ), - backgroundColor: RibnColors.primary, - hoverColor: RibnColors.primaryButtonHover, - dropShadowColor: RibnColors.primaryButtonShadow, - onPressed: onExportPressed, - ), - ), - ], - ); - } -} diff --git a/lib/presentation/settings/sections/links_section.dart b/lib/presentation/settings/sections/links_section.dart index 99d5c206..3f51e8f7 100644 --- a/lib/presentation/settings/sections/links_section.dart +++ b/lib/presentation/settings/sections/links_section.dart @@ -3,15 +3,16 @@ import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; // Package imports: +import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:ribn_toolkit/constants/colors.dart'; import 'package:ribn_toolkit/constants/styles.dart'; -import 'package:url_launcher/url_launcher.dart'; // Project imports: import 'package:ribn/constants/strings.dart'; +import 'package:ribn/utils/url_utils.dart'; /// The section for displaying helpful links. -class LinksSection extends StatelessWidget { +class LinksSection extends HookConsumerWidget { const LinksSection({Key? key}) : super(key: key); final TextStyle linkStyle = const TextStyle( fontSize: 10.5, @@ -21,10 +22,7 @@ class LinksSection extends StatelessWidget { ); @override - Widget build(BuildContext context) { - final Uri url1 = Uri.parse(Strings.privacyPolicyUrl); - final Uri url2 = Uri.parse(Strings.termsOfUseUrl); - + Widget build(BuildContext context, WidgetRef ref) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ @@ -36,8 +34,7 @@ class LinksSection extends StatelessWidget { RichText( text: TextSpan( text: Strings.privacyPolicy, - recognizer: TapGestureRecognizer() - ..onTap = () async => await launchUrl(url1), + recognizer: TapGestureRecognizer()..onTap = () async => await launchPrivacyPolicyUrl(ref), style: linkStyle, ), ), @@ -45,8 +42,7 @@ class LinksSection extends StatelessWidget { RichText( text: TextSpan( text: Strings.termsOfUse, - recognizer: TapGestureRecognizer() - ..onTap = () async => await launchUrl(url2), + recognizer: TapGestureRecognizer()..onTap = () async => await launchTermsOfUse(ref), style: linkStyle, ), ), diff --git a/lib/presentation/settings/settings_page.dart b/lib/presentation/settings/settings_page.dart index 06f99053..0e2e3501 100644 --- a/lib/presentation/settings/settings_page.dart +++ b/lib/presentation/settings/settings_page.dart @@ -1,132 +1,114 @@ +// Dart imports: +import 'dart:async'; + // Flutter imports: -import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; // Package imports: -import 'package:local_auth/local_auth.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:ribn_toolkit/constants/colors.dart'; import 'package:ribn_toolkit/widgets/organisms/custom_page_text_title.dart'; // Project imports: import 'package:ribn/constants/strings.dart'; -import 'package:ribn/containers/settings_container.dart'; import 'package:ribn/platform/platform.dart'; +import 'package:ribn/presentation/settings/sections/analytics_section.dart'; import 'package:ribn/presentation/settings/sections/biometrics_section.dart'; +import 'package:ribn/presentation/settings/sections/danger_container_section.dart'; +import 'package:ribn/presentation/settings/sections/delete_wallet_confirmation_dialog.dart'; import 'package:ribn/presentation/settings/sections/delete_wallet_section.dart'; -import 'package:ribn/presentation/settings/sections/export_topl_main_key_section.dart'; +import 'package:ribn/presentation/settings/sections/disconnect_dapps_section.dart'; +import 'package:ribn/presentation/settings/sections/disconnect_wallet_confirmation_dialog.dart'; import 'package:ribn/presentation/settings/sections/links_section.dart'; import 'package:ribn/presentation/settings/sections/ribn_version_section.dart'; -import 'package:ribn/utils.dart'; +import 'package:ribn/providers/biometrics_provider.dart'; +import 'package:ribn/providers/settings_provider.dart'; +import 'package:ribn/providers/utility_provider.dart'; +import 'package:ribn/utils/extensions.dart'; /// The settings page of the application. -class SettingsPage extends StatefulWidget { +class SettingsPage extends StatelessWidget { const SettingsPage({Key? key}) : super(key: key); - @override - State createState() => _SettingsPageState(); -} - -class _SettingsPageState extends State { - bool isBioSupported = false; - - bool canDisconnect = false; - - late VoidCallback onUpdated; - - @override - initState() { - if (!kIsWeb) { - runBiometrics(); - } else { - loadDApps(); - } - super.initState(); - } - - loadDApps() async { - final List dApps = - await PlatformUtils.instance.convertToFuture(PlatformUtils.instance.getDAppList()); - await PlatformUtils.instance.consoleLog(dApps.toString()); - - setState(() { - canDisconnect = dApps.isNotEmpty; - }); - } - - runBiometrics() async { - final LocalAuthentication localAuthentication = LocalAuthentication(); - - final bool isBioAuthenticationSupported = - await isBiometricsAuthenticationSupported(localAuthentication); - - setState(() { - isBioSupported = isBioAuthenticationSupported ? true : false; - }); - } - @override Widget build(BuildContext context) { - return SettingsContainer( - builder: (BuildContext context, SettingsViewModel vm) { - vm.canDisconnect = canDisconnect; - return Scaffold( - body: SingleChildScrollView( - child: Column( - children: [ - const CustomPageTextTitle( - title: Strings.settings, - hideBackArrow: true, - ), - _buildSettingsListItems(vm, context), - ], + return Scaffold( + body: SingleChildScrollView( + child: Column( + children: [ + const CustomPageTextTitle( + title: Strings.settings, + hideBackArrow: true, ), - ), - ); - }, + SettingsListItems() + ], + ), + ), ); } +} - /// Builds the divider intended for separating the items on the settings page. - Widget _buildDivider() => Padding( - padding: const EdgeInsets.symmetric(vertical: 15.0), - child: Container( - height: 1, - color: const Color(0xFFE9E9E9), - ), - ); +/// Builds the list of items on the settings page. +class SettingsListItems extends ConsumerWidget { + const SettingsListItems({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context, WidgetRef ref) { + final canDisconnectDApp = ref.watch(canDisconnectDAppsProvider); + final biometrics = ref.watch(biometricsProvider); + final appVersion = ref.watch(appVersionProvider); - /// Builds the list of items on the settings page. - Widget _buildSettingsListItems(SettingsViewModel vm, BuildContext context) { return Container( - color: RibnColors.background, - child: Padding( + color: RibnColors.background, padding: const EdgeInsets.symmetric(horizontal: 25, vertical: 15), child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - RibnVersionSection(appVersion: vm.appVersion), - _buildDivider(), - const LinksSection(), - kIsWeb ? _buildDivider() : const SizedBox(), - kIsWeb - ? ExportToplMainKeySection( - onExportPressed: vm.exportToplMainKey, - ) - : const SizedBox(), - isBioSupported ? _buildDivider() : const SizedBox(), - isBioSupported - ? BiometricsSection(isBiometricsEnabled: vm.isBiometricsEnabled) - : const SizedBox(), - _buildDivider(), - DeleteWalletSection( - onDeletePressed: vm.onDeletePressed, - onDisconnectPressed: vm.onDisconnectPressed, - canDisconnect: canDisconnect, - ), - const SizedBox(height: 20), - ], - ), + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + RibnVersionSection(appVersion: appVersion), + const LinksSection(), + AnalyticsSection(), + if (biometrics.value?.isSupported ?? false) BiometricsSection(), + DangerContainerSection(children: [ + //Disconnect DApps + canDisconnectDApp.when( + data: (data) => data + ? DisconnectDAppsSection(onDisconnectPressed: _onDisconnectPressed, canDisconnect: data) + : Container(), + error: (_, __) => Container(), + loading: () => Container()), + SizedBox(height: 10), + //Delete Wallet Section + DeleteWalletSection(onDeletePressed: (_) => onDeletePressed(_, ref)), + ]), + ].separator(element: const Divider(height: 32)).toList())); + } + + void onDeletePressed(BuildContext context, ref) async { + final settingsNotifier = ref.read(settingsProvider); + + await showDialog( + context: context, + builder: (context) => DeleteWalletConfirmationDialog( + onConfirmDeletePressed: ( + String password, + VoidCallback onIncorrectPasswordEntered, + ) async { + final Completer completer = Completer(); + settingsNotifier.DeleteWallet(password, completer); + // onIncorrectPasswordEntered called if response returned is false + await completer.future.then((value) { + if (!value) onIncorrectPasswordEntered(); + }); + }, ), ); } + + static Future _onDisconnectPressed(BuildContext context) async { + final dApps = await PlatformUtils.instance.convertToFuture(PlatformUtils.instance.getDAppList()); + await showDialog( + context: context, + builder: (context) => DisconnectWalletConfirmationDialog(dApps: dApps), + ); + } } diff --git a/lib/presentation/transaction_history/service_locator/locator.dart b/lib/presentation/transaction_history/service_locator/locator.dart deleted file mode 100644 index bdeb7328..00000000 --- a/lib/presentation/transaction_history/service_locator/locator.dart +++ /dev/null @@ -1,11 +0,0 @@ -/// @dev File contains function that setups any singletons required within the app -import 'package:get_it/get_it.dart'; -import 'package:redux/redux.dart'; - -// Project imports: -import '../../../models/app_state.dart'; - -final locator = GetIt.instance; -void setupLocator(Store store) { - locator.registerSingleton>(store, signalsReady: true); -} diff --git a/lib/presentation/transaction_history/transaction_data_row/transaction_data_row.dart b/lib/presentation/transaction_history/transaction_data_row/transaction_data_row.dart index 89c93cf1..7491876d 100644 --- a/lib/presentation/transaction_history/transaction_data_row/transaction_data_row.dart +++ b/lib/presentation/transaction_history/transaction_data_row/transaction_data_row.dart @@ -1,21 +1,22 @@ // Dart imports: +// Flutter imports: +import 'package:flutter/material.dart'; + // Package imports: import 'package:brambldart/model.dart'; import 'package:brambldart/utils.dart'; -// Flutter imports: -import 'package:flutter/material.dart'; import 'package:flutter_redux/flutter_redux.dart'; import 'package:intl/intl.dart'; +import 'package:ribn_toolkit/constants/colors.dart'; +import 'package:ribn_toolkit/widgets/molecules/ribn_activity_tile.dart'; + // Project imports: import 'package:ribn/constants/assets.dart'; +import 'package:ribn/constants/routes.dart'; import 'package:ribn/models/app_state.dart'; import 'package:ribn/models/asset_details.dart'; -import 'package:ribn/utils.dart'; -import 'package:ribn_toolkit/constants/colors.dart'; -import 'package:ribn_toolkit/widgets/molecules/ribn_activity_tile.dart'; - -import '../../../constants/routes.dart'; +import 'package:ribn/utils/extensions.dart'; class TransactionDataRow extends StatefulWidget { final List assets; @@ -68,8 +69,7 @@ class _TransactionDataRowState extends State { final DateFormat dateFormatAlternate = DateFormat('MM-dd-yyyy'); final String formattedDate = dateFormat.format(date); final String formattedDateAlternate = dateFormatAlternate.format(date); - final String transactionReceiverAddress = - widget.transactionReceipt.to.first.toJson()[0].toString(); + final String transactionReceiverAddress = widget.transactionReceipt.to.first.toJson()[0].toString(); final String transactionQuantity = isPolyTransaction ? widget.transactionReceipt.to.first.toJson()[1] : widget.transactionReceipt.to.first.toJson()[1]['quantity']; @@ -77,28 +77,22 @@ class _TransactionDataRowState extends State { final String fee = '${widget.transactionReceipt.fee!.quantity} nanoPOLYs'; final Latin1Data? note = widget.transactionReceipt.data; - final String securityRoot = - isPolyTransaction ? '' : widget.transactionReceipt.to.first.toJson()[1]['securityRoot']; - final String assetCode = isPolyTransaction - ? '' - : widget.transactionReceipt.to.first.toJson()[1]['assetCode'].toString(); + final String securityRoot = isPolyTransaction ? '' : widget.transactionReceipt.to.first.toJson()[1]['securityRoot']; + final String assetCode = + isPolyTransaction ? '' : widget.transactionReceipt.to.first.toJson()[1]['assetCode'].toString(); final ModifierId? blockId = widget.transactionReceipt.blockId; final BlockNum? blockNumber = widget.transactionReceipt.blockNumber; final ModifierId transactionId = widget.transactionReceipt.id; final String renderPlusOrMinusPolyTransfer = transactionReceiverAddress == widget.myRibnWalletAddress && isPolyTransaction ? '+' : '-'; - final String transactionAmountForPolyTransfer = - '$renderPlusOrMinusPolyTransfer$transactionQuantity'; + final String transactionAmountForPolyTransfer = '$renderPlusOrMinusPolyTransfer$transactionQuantity'; String? transactionAmountForAssetTransfer() { - if (transactionReceiverAddress == widget.myRibnWalletAddress && - !transactionQuantity.contains('-')) { + if (transactionReceiverAddress == widget.myRibnWalletAddress && !transactionQuantity.contains('-')) { return '+$transactionQuantity'; - } else if (transactionReceiverAddress == widget.myRibnWalletAddress && - transactionQuantity.contains('-')) { + } else if (transactionReceiverAddress == widget.myRibnWalletAddress && transactionQuantity.contains('-')) { return transactionQuantity; - } else if (transactionReceiverAddress != widget.myRibnWalletAddress && - transactionQuantity.contains('-')) { + } else if (transactionReceiverAddress != widget.myRibnWalletAddress && transactionQuantity.contains('-')) { return transactionQuantity; } else if (transactionReceiverAddress != widget.myRibnWalletAddress && widget.transactionReceipt.minting == true) { @@ -108,8 +102,7 @@ class _TransactionDataRowState extends State { } String? renderSentReceivedMintedText() { - if (transactionReceiverAddress == widget.myRibnWalletAddress && - !transactionQuantity.contains('-')) { + if (transactionReceiverAddress == widget.myRibnWalletAddress && !transactionQuantity.contains('-')) { return 'Received'; } return 'Sent'; @@ -128,8 +121,7 @@ class _TransactionDataRowState extends State { return RibnActivityTile( tileColor: RibnColors.whiteColor, assetIcon: isPolyTransaction ? renderPolyIcon() : renderAssetIcon(assetDetails?.icon), - assetBalance: - '${transactionAmountForAssetTransfer()} ${formatAssetUnit(assetDetails?.unit ?? 'Unit')}', + assetBalance: '${transactionAmountForAssetTransfer()} ${(assetDetails?.unit ?? 'Unit').formatAssetUnit()}', assetShortName: isPolyTransaction ? 'POLY' : filteredAsset.isNotEmpty @@ -142,9 +134,7 @@ class _TransactionDataRowState extends State { 'isPolyTransaction': isPolyTransaction, 'transactionType': renderSentReceivedMintedText(), 'timestamp': formattedDateAlternate, - 'assetDetails': isPolyTransaction - ? {} - : assetDetails ?? {'unit': transactionAmountForAssetTransfer()}, + 'assetDetails': isPolyTransaction ? {} : assetDetails ?? {'unit': transactionAmountForAssetTransfer()}, 'icon': isPolyTransaction ? renderPolyIcon() : renderAssetIcon(assetDetails?.icon), 'shortName': isPolyTransaction ? 'POLY' @@ -154,7 +144,7 @@ class _TransactionDataRowState extends State { 'transactionStatus': transactionStatus, 'transactionAmount': isPolyTransaction ? transactionAmountForPolyTransfer - : '${transactionAmountForAssetTransfer()} ${formatAssetUnit(assetDetails?.unit ?? 'Unit')}', + : '${transactionAmountForAssetTransfer()} ${(assetDetails?.unit ?? 'Unit').formatAssetUnit()}', 'fee': fee, 'myRibnWalletAddress': widget.myRibnWalletAddress, 'transactionSenderAddress': transactionSenderAddress.senderAddress.toBase58(), diff --git a/lib/presentation/transaction_history/transaction_history_details_page/transaction_history_data_tile.dart b/lib/presentation/transaction_history/transaction_history_details_page/transaction_history_data_tile.dart index 60c65da4..545432a1 100644 --- a/lib/presentation/transaction_history/transaction_history_details_page/transaction_history_data_tile.dart +++ b/lib/presentation/transaction_history/transaction_history_details_page/transaction_history_data_tile.dart @@ -19,9 +19,7 @@ class TransactionHistoryDataTile extends StatelessWidget { @override Widget build(BuildContext context) { return ConstrainedBox( - constraints: reducedWidth == true - ? const BoxConstraints(minWidth: 70) - : const BoxConstraints(minWidth: 163), + constraints: reducedWidth == true ? const BoxConstraints(minWidth: 70) : const BoxConstraints(minWidth: 163), child: Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.spaceAround, diff --git a/lib/presentation/transaction_history/transaction_history_details_page/transaction_history_details_page.dart b/lib/presentation/transaction_history/transaction_history_details_page/transaction_history_details_page.dart index 18defb45..cfda3cc7 100644 --- a/lib/presentation/transaction_history/transaction_history_details_page/transaction_history_details_page.dart +++ b/lib/presentation/transaction_history/transaction_history_details_page/transaction_history_details_page.dart @@ -8,6 +8,8 @@ import 'package:ribn_toolkit/widgets/molecules/ribn_activity_details.dart'; // Project imports: +// Project imports: + class TxHistoryDetailsPage extends StatefulWidget { final RibnActivityDetailsModel ribnActivityDetailsModel; diff --git a/lib/presentation/transaction_history/transaction_history_page.dart b/lib/presentation/transaction_history/transaction_history_page.dart index bc3bf100..f3dcf4ff 100644 --- a/lib/presentation/transaction_history/transaction_history_page.dart +++ b/lib/presentation/transaction_history/transaction_history_page.dart @@ -6,7 +6,6 @@ import 'package:flutter/material.dart'; // Package imports: import 'package:brambldart/brambldart.dart'; import 'package:loader_overlay/loader_overlay.dart'; -import 'package:ribn/utils/transaction_utils.dart'; import 'package:ribn_toolkit/constants/colors.dart'; import 'package:ribn_toolkit/widgets/organisms/custom_page_dropdown_title.dart'; @@ -17,7 +16,8 @@ import 'package:ribn/containers/transaction_history_container.dart'; import 'package:ribn/presentation/empty_state_screen.dart'; import 'package:ribn/presentation/transaction_history/dashed_list_separator/dashed_list_separator.dart'; import 'package:ribn/presentation/transaction_history/transaction_data_row/transaction_data_row.dart'; -import 'package:ribn/utils.dart'; +import 'package:ribn/utils/transaction_utils.dart'; +import 'package:ribn/utils/utils.dart'; class TxHistoryPage extends StatefulWidget { final Future? blockHeight; @@ -44,26 +44,11 @@ class _TxHistoryPageState extends State { }); } - final _scrollController = ScrollController(); - - int pageNum = 0; - String startingFilterValue = 'Transaction types'; @override void initState() { super.initState(); - - _scrollController.addListener(() { - if (_scrollController.position.atEdge) { - final bool isTop = _scrollController.position.pixels == 0; - if (!isTop) { - setState(() { - pageNum += 1; - }); - } - } - }); } Future fetchTxHistory( @@ -72,8 +57,7 @@ class _TxHistoryPageState extends State { int networkId, TransactionHistoryViewmodel vm, ) async { - final List response = - filterOutChangeUTxO(await vm.getTransactions(pageNum: pageNum)); + final List response = filterOutChangeUTxO(await vm.getTransactions()); // Filters transactions by sent or received if (filterSelectedItem != 'Transaction types') { @@ -89,9 +73,7 @@ class _TxHistoryPageState extends State { filteredTransactions.add(transaction); } - if (filterSelectedItem == 'Received' && - transactionReceiverAddress == myRibnAddress && - !wasMinted) { + if (filterSelectedItem == 'Received' && transactionReceiverAddress == myRibnAddress && !wasMinted) { filteredTransactions.add(transaction); } @@ -116,115 +98,105 @@ class _TxHistoryPageState extends State { overlayColor: Colors.transparent, child: Scaffold( backgroundColor: RibnColors.background, - body: RefreshIndicator( - backgroundColor: RibnColors.primary, - color: RibnColors.secondaryDark, - onRefresh: () async { - setState(() {}); - }, - child: Scrollbar( - thumbVisibility: true, - controller: _scrollController, - child: SingleChildScrollView( - controller: _scrollController, - child: Column( - children: [ - CustomPageDropdownTitle( - title: Strings.recentActivity, - chevronIconLink: RibnAssets.chevronDown, - currentSelectedItem: filterSelectedItem, - itemsToSelectFrom: itemsToSelectFrom, - updateSelectedItem: updateSelectedItem, + body: Scrollbar( + thumbVisibility: true, + child: SingleChildScrollView( + child: Column( + children: [ + CustomPageDropdownTitle( + title: Strings.recentActivity, + chevronIconLink: RibnAssets.chevronDown, + currentSelectedItem: filterSelectedItem, + itemsToSelectFrom: itemsToSelectFrom, + updateSelectedItem: updateSelectedItem, + ), + FutureBuilder( + future: fetchTxHistory( + context, + vm.toplAddress, + vm.networkId, + vm, ), - FutureBuilder( - future: fetchTxHistory( - context, - vm.toplAddress, - vm.networkId, - vm, - ), - builder: (context, AsyncSnapshot snapshot) { - switch (snapshot.connectionState) { - case ConnectionState.done: - context.loaderOverlay.hide(); - - if (!snapshot.hasData || snapshot.data.isEmpty) { - return EmptyStateScreen( - icon: RibnAssets.clockWithBorder, - title: Strings.noActivityToReview, - body: emptyStateBody, - buttonOneText: 'Share', - buttonOneAction: () async => await showReceivingAddress(), - mobileHeight: MediaQuery.of(context).size.height * 0.63, - desktopHeight: 360, - ); - } - - return Padding( - padding: const EdgeInsets.only(top: 20, bottom: 20), - child: Container( - width: MediaQuery.of(context).size.width - 40, - padding: const EdgeInsets.symmetric( - horizontal: 8, - vertical: 8, - ), - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(11.6), - color: RibnColors.whiteBackground, - border: Border.all( - color: RibnColors.lightGrey, - width: 1, - ), - boxShadow: const [ - BoxShadow( - color: RibnColors.greyShadow, - spreadRadius: 0, - blurRadius: 37.5, - offset: Offset(0, -6), - ), - ], + builder: (context, AsyncSnapshot snapshot) { + switch (snapshot.connectionState) { + case ConnectionState.done: + context.loaderOverlay.hide(); + + if (!snapshot.hasData || snapshot.data.isEmpty) { + return EmptyStateScreen( + icon: RibnAssets.clockWithBorder, + title: Strings.noActivityToReview, + body: emptyStateBody, + buttonOneText: 'Share', + buttonOneAction: () async => await showReceivingAddress(), + mobileHeight: MediaQuery.of(context).size.height * 0.63, + desktopHeight: 360, + ); + } + + return Padding( + padding: const EdgeInsets.only(top: 20, bottom: 20), + child: Container( + width: MediaQuery.of(context).size.width - 40, + padding: const EdgeInsets.symmetric( + horizontal: 8, + vertical: 8, + ), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(11.6), + color: RibnColors.whiteBackground, + border: Border.all( + color: RibnColors.lightGrey, + width: 1, ), - child: SingleChildScrollView( - child: ListView.separated( - reverse: true, - physics: const NeverScrollableScrollPhysics(), - scrollDirection: Axis.vertical, - itemCount: filterSelectedItem == startingFilterValue - ? snapshot.data?.length - : filteredTransactions.length, - shrinkWrap: true, - itemBuilder: (context, index) { - final TransactionReceipt transaction = - filterSelectedItem == startingFilterValue - ? snapshot.data[index] - : filteredTransactions[index]; - - return TransactionDataRow( - transactionReceipt: transaction, - assets: vm.assets, - myRibnWalletAddress: vm.toplAddress.toBase58(), - blockHeight: vm.blockHeight, - networkId: vm.networkId, - ); - }, - separatorBuilder: (context, index) { - return const DashedListSeparator( - color: RibnColors.lightGreyDivider, - ); - }, + boxShadow: const [ + BoxShadow( + color: RibnColors.greyShadow, + spreadRadius: 0, + blurRadius: 37.5, + offset: Offset(0, -6), ), + ], + ), + child: SingleChildScrollView( + child: ListView.separated( + reverse: true, + physics: const NeverScrollableScrollPhysics(), + scrollDirection: Axis.vertical, + itemCount: filterSelectedItem == startingFilterValue + ? snapshot.data?.length + : filteredTransactions.length, + shrinkWrap: true, + itemBuilder: (context, index) { + final TransactionReceipt transaction = filterSelectedItem == startingFilterValue + ? snapshot.data[index] + : filteredTransactions[index]; + + return TransactionDataRow( + transactionReceipt: transaction, + assets: vm.assets, + myRibnWalletAddress: vm.toplAddress.toBase58(), + blockHeight: vm.blockHeight, + networkId: vm.networkId, + ); + }, + separatorBuilder: (context, index) { + return const DashedListSeparator( + color: RibnColors.lightGreyDivider, + ); + }, ), ), - ); - - default: - context.loaderOverlay.show(); - return const SizedBox(); - } - }, - ), - ], - ), + ), + ); + + default: + context.loaderOverlay.show(); + return const SizedBox(); + } + }, + ), + ], ), ), ), diff --git a/lib/presentation/transaction_history/widgets/misc/keep_alive_future_builder.dart b/lib/presentation/transaction_history/widgets/misc/keep_alive_future_builder.dart index b09e87b5..be9ee4e5 100644 --- a/lib/presentation/transaction_history/widgets/misc/keep_alive_future_builder.dart +++ b/lib/presentation/transaction_history/widgets/misc/keep_alive_future_builder.dart @@ -13,8 +13,7 @@ class KeepAliveFutureBuilder extends StatefulWidget { _KeepAliveFutureBuilderState createState() => _KeepAliveFutureBuilderState(); } -class _KeepAliveFutureBuilderState extends State - with AutomaticKeepAliveClientMixin { +class _KeepAliveFutureBuilderState extends State with AutomaticKeepAliveClientMixin { @override Widget build(BuildContext context) { super.build(context); diff --git a/lib/presentation/transfers/asset_transfer_page.dart b/lib/presentation/transfers/asset_transfer_page.dart index 5d143f2a..69a0db67 100644 --- a/lib/presentation/transfers/asset_transfer_page.dart +++ b/lib/presentation/transfers/asset_transfer_page.dart @@ -74,16 +74,14 @@ class _AssetTransferPageState extends State { padding: const EdgeInsets.symmetric(horizontal: 10), child: Text( Strings.sendAssets, - style: RibnToolkitTextStyles.btnMedium - .copyWith(color: RibnColors.defaultText), + style: RibnToolkitTextStyles.btnMedium.copyWith(color: RibnColors.defaultText), ), ), 1: Padding( padding: const EdgeInsets.symmetric(horizontal: 10), child: Text( Strings.sendNativeCoins, - style: RibnToolkitTextStyles.btnMedium - .copyWith(color: RibnColors.defaultText), + style: RibnToolkitTextStyles.btnMedium.copyWith(color: RibnColors.defaultText), ), ), }, @@ -94,15 +92,13 @@ class _AssetTransferPageState extends State { ? AssetTransferInputContainer( builder: (context, vm) => AssetTransferSection( vm: vm, - updateButton: (val) => - setState(() => bottomButton = val), + updateButton: (val) => setState(() => bottomButton = val), ), ) : PolyTransferInputContainer( builder: (context, vm) => PolyTransferSection( vm: vm, - updateButton: (val) => - setState(() => bottomButton = val), + updateButton: (val) => setState(() => bottomButton = val), ), ), const SizedBox(height: 18), diff --git a/lib/presentation/transfers/asset_transfer_section.dart b/lib/presentation/transfers/asset_transfer_section.dart index fbfb343a..87fac143 100644 --- a/lib/presentation/transfers/asset_transfer_section.dart +++ b/lib/presentation/transfers/asset_transfer_section.dart @@ -23,7 +23,7 @@ import 'package:ribn/presentation/empty_state_screen.dart'; import 'package:ribn/presentation/transfers/bottom_review_action.dart'; import 'package:ribn/presentation/transfers/transfer_utils.dart'; import 'package:ribn/presentation/transfers/widgets/from_address_field.dart'; -import 'package:ribn/utils.dart'; +import 'package:ribn/utils/utils.dart'; import 'package:ribn/widgets/address_display_container.dart'; import 'package:ribn/widgets/fee_info.dart'; @@ -88,20 +88,22 @@ class _AssetTransferSectionState extends State { }); } - void disposeController(TextEditingController controller) => - controller.dispose(); + void disposeController(TextEditingController controller) => controller.dispose(); void renderBottomButton() { return WidgetsBinding.instance.addPostFrameCallback((_) { widget.updateButton( BottomReviewAction( - maxHeight: kIsWeb ? 120 : 143, + maxHeight: kIsWeb ? 120 : 150, children: Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.center, children: [ // fee info for the tx - FeeInfo(fee: widget.vm.networkFee), + FeeInfo( + fee: widget.vm.networkFee, + currentNetworkName: widget.vm.currentNetwork.networkName, + ), _buildReviewButton(widget.vm), ], ), @@ -137,25 +139,15 @@ class _AssetTransferSectionState extends State { AssetSelectionField( formattedSelectedAsset: { 'assetCode': _selectedAsset?.assetCode.toString(), - 'longName': widget - .vm - .assetDetails[_selectedAsset?.assetCode.toString()] - ?.longName, + 'longName': widget.vm.assetDetails[_selectedAsset?.assetCode.toString()]?.longName, 'shortName': _selectedAsset?.assetCode.shortName.show, - 'assetIcon': widget - .vm - .assetDetails[_selectedAsset?.assetCode.toString()] - ?.icon, + 'assetIcon': widget.vm.assetDetails[_selectedAsset?.assetCode.toString()]?.icon, }, formattedAsset: (asset) { return { - 'longName': widget - .vm - .assetDetails[asset!.assetCode.toString()] - ?.longName, + 'longName': widget.vm.assetDetails[asset!.assetCode.toString()]?.longName, 'shortName': asset.assetCode.shortName.show, - 'assetIcon': widget - .vm.assetDetails[asset!.assetCode.toString()]?.icon, + 'assetIcon': widget.vm.assetDetails[asset!.assetCode.toString()]?.icon, }; }, assets: widget.vm.assets, @@ -164,7 +156,7 @@ class _AssetTransferSectionState extends State { setState(() { _selectedAsset = asset!; _validAmount = TransferUtils.validateAmount( - _amountController.text, + int.parse(_amountController.text), widget.vm.getAssetBalance(asset.assetCode.toString()), ); }); @@ -182,23 +174,20 @@ class _AssetTransferSectionState extends State { onChanged: (String amount) { setState(() { _validAmount = TransferUtils.validateAmount( - amount, + int.parse(amount), widget.vm.getAssetBalance( _selectedAsset?.assetCode.toString(), ), ); }); }, - selectedUnit: widget - .vm - .assetDetails[_selectedAsset?.assetCode.toString()] - ?.unit, + selectedUnit: widget.vm.assetDetails[_selectedAsset?.assetCode.toString()]?.unit, controller: _amountController, allowEditingUnit: false, onUnitSelected: (String amount) { setState(() { _validAmount = TransferUtils.validateAmount( - amount, + int.parse(amount), widget.vm.getAssetBalance( _selectedAsset?.assetCode.toString(), ), @@ -209,8 +198,7 @@ class _AssetTransferSectionState extends State { RibnAssets.chevronDownDark, width: 24, ), - maxTransferrableAmount: widget.vm - .getAssetBalance(_selectedAsset?.assetCode.toString()), + maxTransferrableAmount: widget.vm.getAssetBalance(_selectedAsset?.assetCode.toString()), ), // Displays the sender address. const FromAddressField(), @@ -226,8 +214,7 @@ class _AssetTransferSectionState extends State { if (mounted) { setState(() { if (result) { - _validRecipientAddress = - _recipientController.text; + _validRecipientAddress = _recipientController.text; _recipientController.text = ''; } else { _validRecipientAddress = ''; @@ -248,8 +235,7 @@ class _AssetTransferSectionState extends State { if (_validRecipientAddress.isNotEmpty) { _recipientController.text = _validRecipientAddress; _recipientController - ..text = _recipientController.text - .substring(0, _recipientController.text.length) + ..text = _recipientController.text.substring(0, _recipientController.text.length) ..selection = TextSelection.collapsed( offset: _recipientController.text.length, ); @@ -277,9 +263,8 @@ class _AssetTransferSectionState extends State { } Widget _buildReviewButton(AssetTransferInputViewModel vm) { - final bool enteredValidInputs = _validRecipientAddress.isNotEmpty && - _amountController.text.isNotEmpty && - _validAmount; + final bool enteredValidInputs = + _validRecipientAddress.isNotEmpty && _amountController.text.isNotEmpty && _validAmount; return Padding( padding: const EdgeInsets.only(top: 10, bottom: 10), @@ -300,8 +285,7 @@ class _AssetTransferSectionState extends State { amount: _amountController.text, note: _noteController.text, assetCode: _selectedAsset!.assetCode, - assetDetails: - vm.assetDetails[_selectedAsset!.assetCode.toString()], + assetDetails: vm.assetDetails[_selectedAsset!.assetCode.toString()], onRawTxCreated: (bool success) async { context.loaderOverlay.hide(); // Display error dialog if failed to create raw tx diff --git a/lib/presentation/transfers/mint_input_page.dart b/lib/presentation/transfers/mint_input_page.dart index ca7af2ef..042179b3 100644 --- a/lib/presentation/transfers/mint_input_page.dart +++ b/lib/presentation/transfers/mint_input_page.dart @@ -31,7 +31,7 @@ import 'package:ribn/presentation/empty_state_screen.dart'; import 'package:ribn/presentation/transfers/bottom_review_action.dart'; import 'package:ribn/presentation/transfers/transfer_utils.dart'; import 'package:ribn/presentation/transfers/widgets/issuer_address_field.dart'; -import 'package:ribn/utils.dart'; +import 'package:ribn/utils/utils.dart'; import 'package:ribn/widgets/address_display_container.dart'; import 'package:ribn/widgets/fee_info.dart'; @@ -45,10 +45,8 @@ class MintInputPage extends StatefulWidget { class _MintInputPageState extends State { final TextEditingController _noteController = TextEditingController(); - final TextEditingController _assetLongNameController = - TextEditingController(); - final TextEditingController _assetShortNameController = - TextEditingController(); + final TextEditingController _assetLongNameController = TextEditingController(); + final TextEditingController _assetShortNameController = TextEditingController(); final TextEditingController _amountController = TextEditingController(); final TextEditingController _recipientController = TextEditingController(); late List _controllers; @@ -187,8 +185,7 @@ class _MintInputPageState extends State { if (_validRecipientAddress.isNotEmpty) { _recipientController.text = _validRecipientAddress; _recipientController - ..text = _recipientController.text - .substring(0, _recipientController.text.length) + ..text = _recipientController.text.substring(0, _recipientController.text.length) ..selection = TextSelection.collapsed( offset: _recipientController.text.length, ); @@ -249,16 +246,14 @@ class _MintInputPageState extends State { padding: const EdgeInsets.symmetric(horizontal: 10), child: Text( Strings.mintAsset, - style: RibnToolkitTextStyles.btnMedium - .copyWith(color: RibnColors.defaultText), + style: RibnToolkitTextStyles.btnMedium.copyWith(color: RibnColors.defaultText), ), ), 1: Padding( padding: const EdgeInsets.symmetric(horizontal: 10), child: Text( Strings.mintExistingAsset, - style: RibnToolkitTextStyles.btnMedium - .copyWith(color: RibnColors.defaultText), + style: RibnToolkitTextStyles.btnMedium.copyWith(color: RibnColors.defaultText), ), ), }, @@ -281,7 +276,10 @@ class _MintInputPageState extends State { mainAxisAlignment: MainAxisAlignment.center, children: [ // fee info for the tx - FeeInfo(fee: vm.networkFee), + FeeInfo( + fee: vm.networkFee, + currentNetworkName: vm.currentNetwork.networkName, + ), _buildReviewButton(vm), ], ), @@ -321,16 +319,13 @@ class _MintInputPageState extends State { : AssetSelectionField( formattedSelectedAsset: { 'assetCode': _selectedAsset?.assetCode.toString(), - 'longName': vm - .assetDetails[_selectedAsset?.assetCode.toString()]?.longName, + 'longName': vm.assetDetails[_selectedAsset?.assetCode.toString()]?.longName, 'shortName': _selectedAsset?.assetCode.shortName.show, - 'assetIcon': - vm.assetDetails[_selectedAsset?.assetCode.toString()]?.icon, + 'assetIcon': vm.assetDetails[_selectedAsset?.assetCode.toString()]?.icon, }, formattedAsset: (asset) { return { - 'longName': - vm.assetDetails[asset!.assetCode.toString()]?.longName, + 'longName': vm.assetDetails[asset!.assetCode.toString()]?.longName, 'shortName': asset.assetCode.shortName.show, 'assetIcon': vm.assetDetails[asset!.assetCode.toString()]?.icon, }; @@ -339,8 +334,7 @@ class _MintInputPageState extends State { onSelected: (AssetAmount? asset) { setState(() { _selectedAsset = asset; - _selectedUnit = - vm.assetDetails[asset!.assetCode.toString()]?.unit; + _selectedUnit = vm.assetDetails[asset!.assetCode.toString()]?.unit; _assetShortNameController.text = asset.assetCode.shortName.show; }); }, diff --git a/lib/presentation/transfers/poly_transfer_section.dart b/lib/presentation/transfers/poly_transfer_section.dart index 597ae405..ca3430fb 100644 --- a/lib/presentation/transfers/poly_transfer_section.dart +++ b/lib/presentation/transfers/poly_transfer_section.dart @@ -1,15 +1,17 @@ // Flutter imports: import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; // Package imports: +import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:flutter_svg/flutter_svg.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:loader_overlay/loader_overlay.dart'; +import 'package:ribn/constants/network_utils.dart'; import 'package:ribn_toolkit/constants/colors.dart'; import 'package:ribn_toolkit/constants/styles.dart'; -import 'package:ribn_toolkit/widgets/atoms/custom_text_field.dart'; import 'package:ribn_toolkit/widgets/atoms/large_button.dart'; +import 'package:ribn_toolkit/widgets/molecules/asset_amount_field.dart'; import 'package:ribn_toolkit/widgets/molecules/note_field.dart'; import 'package:ribn_toolkit/widgets/molecules/recipient_field.dart'; @@ -21,7 +23,7 @@ import 'package:ribn/presentation/transfers/bottom_review_action.dart'; import 'package:ribn/presentation/transfers/transfer_utils.dart'; import 'package:ribn/presentation/transfers/widgets/custom_input_field.dart'; import 'package:ribn/presentation/transfers/widgets/from_address_field.dart'; -import 'package:ribn/utils.dart'; +import 'package:ribn/providers/transactions/poly_transfer_provider.dart'; import 'package:ribn/widgets/address_display_container.dart'; import 'package:ribn/widgets/fee_info.dart'; @@ -29,7 +31,7 @@ import 'package:ribn/widgets/fee_info.dart'; /// /// Builds the necessary input fields needed for a poly transfer. // ignore: must_be_immutable -class PolyTransferSection extends StatefulWidget { +class PolyTransferSection extends HookConsumerWidget { PolyTransferInputViewModel vm; final Function updateButton; @@ -39,69 +41,26 @@ class PolyTransferSection extends StatefulWidget { Key? key, }) : super(key: key); - @override - _PolyTransferSectionState createState() => _PolyTransferSectionState(); -} - -class _PolyTransferSectionState extends State { - final TextEditingController _noteController = TextEditingController(); - final TextEditingController _amountController = TextEditingController(); - final TextEditingController _recipientController = TextEditingController(); - late List _controllers; final GlobalKey _formKey = GlobalKey(); - /// Assigned the valid recipient address - String _validRecipientAddress = ''; - - /// True if amount is valid. - // ignore: prefer_final_fields - bool _validAmount = false; - - int currentTabIndex = 1; - - @override - void initState() { - _controllers = [ - _noteController, - _amountController, - _recipientController, - ]; - - // initialize listeners for each of the TextEditingControllers - _controllers.forEach(initListener); - renderBottomButton(); - super.initState(); - } - - @override - void dispose() { - _controllers.forEach(disposeController); - super.dispose(); - } - - initListener(TextEditingController controller) { - controller.addListener(() { - renderBottomButton(); - setState(() {}); - }); - } - - disposeController(TextEditingController controller) { - controller.dispose(); - } - + // TODO, Update this so that it's not causing a render in another widget void renderBottomButton() { return WidgetsBinding.instance.addPostFrameCallback((_) { - widget.updateButton( + updateButton( BottomReviewAction( - maxHeight: kIsWeb ? 120 : 143, + maxHeight: kIsWeb ? 120 : 150, children: Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.center, children: [ // fee info for the tx - FeeInfo(fee: widget.vm.networkFee), - _buildReviewButton(widget.vm), + FeeInfo( + fee: vm.networkFee, + currentNetworkName: vm.currentNetwork.networkName, + ), + _ReviewButton( + vm: vm, + ), ], ), ), @@ -110,7 +69,19 @@ class _PolyTransferSectionState extends State { } @override - Widget build(BuildContext context) { + Widget build(BuildContext context, WidgetRef ref) { + // Have to keep watch here otherwise the controller will dispose + // ignore: unused_local_variable + final polyTransfer = ref.watch(polyTransferProvider); + final polyTransferNotifier = ref.watch(polyTransferProvider.notifier); + final _recipientController = useTextEditingController(); + final _noteController = useTextEditingController(); + + useEffect(() { + renderBottomButton(); + return null; + }, []); + return Column( children: [ SizedBox( @@ -121,43 +92,25 @@ class _PolyTransferSectionState extends State { crossAxisAlignment: CrossAxisAlignment.start, children: [ // UI to indicate poly transfer - _buildPolyDisplay(), + _PolyDisplay( + vm: vm, + ), // field for entering amount of polys needed for transfer - _buildAmountField(widget.vm), - // field for displaying the sender addresss + _AmountField( + vm: vm, + ), + // field for displaying the sender addresses const FromAddressField(), // field for entering the recipient address RecipientField( controller: _recipientController, - validRecipientAddress: _validRecipientAddress, + validRecipientAddress: polyTransfer.validRecipientAddress, // validate the address entered on text change - onChanged: (text) => validateRecipientAddress( - networkName: widget.vm.currentNetwork.networkName, - address: _recipientController.text, - handleResult: (bool result) { - setState(() { - if (result) { - _validRecipientAddress = _recipientController.text; - _recipientController.text = ''; - } else { - _validRecipientAddress = ''; - } - }); - }, - ), + onChanged: (recipient) { + polyTransferNotifier.validateRecipient(recipient, vm.currentNetwork, _recipientController); + }, onBackspacePressed: () { - setState(() { - if (_validRecipientAddress.isNotEmpty) { - _recipientController.text = _validRecipientAddress; - _recipientController - ..text = _recipientController.text - .substring(0, _recipientController.text.length) - ..selection = TextSelection.collapsed( - offset: _recipientController.text.length, - ); - } - _validRecipientAddress = ''; - }); + polyTransferNotifier.onRecipientBackspacePressed(_recipientController); }, icon: SvgPicture.asset(RibnAssets.recipientFingerprint), alternativeDisplayChild: const AddressDisplayContainer( @@ -174,6 +127,9 @@ class _PolyTransferSectionState extends State { RibnAssets.greyHelpBubble, width: 18, ), + onChanged: (String note) { + polyTransferNotifier.updateNote(note); + }, ), ], ), @@ -182,9 +138,19 @@ class _PolyTransferSectionState extends State { ], ); } +} + +/// Builds the UI for indicating poly transfer. +class _PolyDisplay extends StatelessWidget { + final PolyTransferInputViewModel vm; + const _PolyDisplay({ + required this.vm, + Key? key, + }) : super(key: key); - /// Builds the UI for indicating poly transfer. - Widget _buildPolyDisplay() { + @override + Widget build(BuildContext context) { + final bool isValhalla = vm.currentNetwork.networkName == NetworkUtils.valhalla; return CustomInputField( itemLabel: Strings.sending, item: Container( @@ -206,40 +172,58 @@ class _PolyTransferSectionState extends State { padding: const EdgeInsets.symmetric(horizontal: 7.0), child: Image.asset(RibnAssets.polysIcon), ), - const Text('POLY'), + Text('${isValhalla ? 'nanoPOLY' : 'POLY'}'), ], ), ), ); } +} - /// Builds the TextField for entering amount needed for the transfer. - Widget _buildAmountField(vm) { - return CustomInputField( - itemLabel: Strings.amount, - item: CustomTextField( - width: 310, - height: 36, - controller: _amountController, - hintText: Strings.amountHint, - keyboardType: TextInputType.number, - inputFormatters: [FilteringTextInputFormatter.digitsOnly], - onChanged: (String amount) { - setState(() { - _validAmount = TransferUtils.validateAmount( - amount, - vm.maxTransferrableAmount, - ); - }); - }, - ), +/// Builds the TextField for entering amount needed for the transfer. +class _AmountField extends HookConsumerWidget { + final PolyTransferInputViewModel vm; + + const _AmountField({ + required this.vm, + Key? key, + }) : super(key: key); + + @override + Widget build(BuildContext context, WidgetRef ref) { + final amountController = useTextEditingController(); + final maxPolys = vm.maxTransferrableAmount; + + return AssetAmountField( + controller: amountController, + maxTransferrableAmount: maxPolys, + errorString: Strings.overMaxPolys(maxPolys.toInt()), + selectedUnit: 'POLY', + onChanged: (String amount) { + ref.read(polyTransferProvider.notifier).updateAmount(amount); + }, ); } +} + +class _ReviewButton extends HookConsumerWidget { + final PolyTransferInputViewModel vm; - Widget _buildReviewButton(PolyTransferInputViewModel vm) { - final bool enteredValidInputs = _validRecipientAddress.isNotEmpty && - _amountController.text.isNotEmpty && - _validAmount; + const _ReviewButton({ + required this.vm, + Key? key, + }) : super(key: key); + + @override + Widget build(BuildContext context, WidgetRef ref) { + final polyTransfer = ref.watch(polyTransferProvider); + + bool _validAmount = TransferUtils.validateAmount( + polyTransfer.amount, + vm.maxTransferrableAmount, + ); + final bool enteredValidInputs = + polyTransfer.validRecipientAddress.isNotEmpty && polyTransfer.amount > 0 && _validAmount; return Padding( padding: const EdgeInsets.only(top: 10, bottom: 10), @@ -256,9 +240,9 @@ class _PolyTransferSectionState extends State { ? () { context.loaderOverlay.show(); vm.initiateTx( - amount: _amountController.text, - recipient: _validRecipientAddress, - note: _noteController.text, + amount: polyTransfer.amount.toString(), + recipient: polyTransfer.recipientAddress, + note: polyTransfer.note, onRawTxCreated: (bool success) async { context.loaderOverlay.hide(); // Display error dialog if failed to create raw tx diff --git a/lib/presentation/transfers/transfer_utils.dart b/lib/presentation/transfers/transfer_utils.dart index a9ec6a3a..44cdd6e6 100644 --- a/lib/presentation/transfers/transfer_utils.dart +++ b/lib/presentation/transfers/transfer_utils.dart @@ -32,11 +32,13 @@ class TransferUtils { } /// Returns true if [amount] is valid. - static bool validateAmount(String amount, maxAmount) { + static bool validateAmount(int amount, maxAmount) { try { - return int.parse(amount) <= maxAmount; + return amount <= maxAmount; } catch (e) { return false; } } + + /// Gets a valid address from } diff --git a/lib/presentation/transfers/tx_confirmation_page.dart b/lib/presentation/transfers/tx_confirmation_page.dart index 2078f68d..aa9b0694 100644 --- a/lib/presentation/transfers/tx_confirmation_page.dart +++ b/lib/presentation/transfers/tx_confirmation_page.dart @@ -16,7 +16,7 @@ import 'package:ribn/constants/routes.dart'; import 'package:ribn/constants/rules.dart'; import 'package:ribn/constants/strings.dart'; import 'package:ribn/models/transfer_details.dart'; -import 'package:ribn/utils.dart'; +import 'package:ribn/utils/extensions.dart'; /// The transaction confirmation page. /// @@ -112,15 +112,13 @@ class TxConfirmationPage extends StatelessWidget { /// /// Different for minting asset and asset/poly transfer. Widget _buildsPageTitle() { - final String text = - mintedAsset ? Strings.assetIsBeingMinted : Strings.txWasBroadcasted; + final String text = mintedAsset ? Strings.assetIsBeingMinted : Strings.txWasBroadcasted; return SizedBox( width: 220, child: Text( text, - style: - RibnToolkitTextStyles.h2.copyWith(color: RibnColors.lightGreyTitle), + style: RibnToolkitTextStyles.h2.copyWith(color: RibnColors.lightGreyTitle), textAlign: TextAlign.center, ), ); @@ -128,8 +126,7 @@ class TxConfirmationPage extends StatelessWidget { /// Displays information about the tx that was broadcasted. Widget _buildTxInfo() { - final String txInfo = transferDetails.transferType == - TransferType.polyTransfer + final String txInfo = transferDetails.transferType == TransferType.polyTransfer ? '${transferDetails.amount} ${'POLY'}' : '${transferDetails.amount} of ${transferDetails.assetCode!.shortName.show}'; @@ -181,7 +178,7 @@ class TxConfirmationPage extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.center, children: [ Text( - 'Transaction ID: ${formatAddrString(transferDetails.transactionId!, charsToDisplay: 4)}', + 'Transaction ID: ${transferDetails.transactionId!.formatAddressString(charsToDisplay: 4)}', style: RibnToolkitTextStyles.h4.copyWith( fontWeight: FontWeight.w400, color: RibnColors.lightGreyTitle, diff --git a/lib/presentation/transfers/tx_review_page.dart b/lib/presentation/transfers/tx_review_page.dart index 907a59e0..76974837 100644 --- a/lib/presentation/transfers/tx_review_page.dart +++ b/lib/presentation/transfers/tx_review_page.dart @@ -26,7 +26,7 @@ import 'package:ribn/models/app_state.dart'; import 'package:ribn/models/transfer_details.dart'; import 'package:ribn/presentation/transfers/bottom_review_action.dart'; import 'package:ribn/presentation/transfers/transfer_utils.dart'; -import 'package:ribn/utils.dart'; +import 'package:ribn/utils/extensions.dart'; import 'package:ribn/widgets/asset_info.dart'; import 'package:ribn/widgets/custom_divider.dart'; import 'package:ribn/widgets/fee_info.dart'; @@ -77,8 +77,7 @@ class TxReviewPage extends StatelessWidget { decoration: BoxDecoration( borderRadius: BorderRadius.circular(11.6), color: RibnColors.whiteBackground, - border: - Border.all(color: RibnColors.lightGrey, width: 1), + border: Border.all(color: RibnColors.lightGrey, width: 1), boxShadow: const [ BoxShadow( color: RibnColors.greyShadow, @@ -108,8 +107,9 @@ class TxReviewPage extends StatelessWidget { child: SizedBox( width: 310, child: FeeInfo( - fee: transferDetails - .transactionReceipt!.fee!.getInNanopoly, + fee: transferDetails.transactionReceipt!.fee!.getInNanopoly, + currentNetworkName: + StoreProvider.of(context).state.keychainState.currentNetwork.networkName, ), ), ), @@ -140,8 +140,7 @@ class TxReviewPage extends StatelessWidget { StoreProvider.of(context).dispatch( SignAndBroadcastTxAction(transferDetails, txCompleter), ); - await txCompleter.future - .then((TransferDetails? transferDetails) { + await txCompleter.future.then((TransferDetails? transferDetails) { if (transferDetails != null) { Keys.navigatorKey.currentState?.pushNamed( Routes.txConfirmation, @@ -170,8 +169,7 @@ class TxReviewPage extends StatelessWidget { dropShadowColor: Colors.transparent, borderColor: RibnColors.ghostButtonText, onPressed: () { - Keys.navigatorKey.currentState! - .popUntil((route) => route.settings.name == Routes.home); + Keys.navigatorKey.currentState!.popUntil((route) => route.settings.name == Routes.home); }, ), const SizedBox(height: 13), @@ -267,8 +265,7 @@ class TxReviewPage extends StatelessWidget { ), ), CustomCopyButton( - textToBeCopied: - transferDetails.senders.first.toplAddress.toBase58(), + textToBeCopied: transferDetails.senders.first.toplAddress.toBase58(), icon: Image.asset( RibnAssets.copyIcon, width: 26, @@ -296,13 +293,12 @@ class TxReviewPage extends StatelessWidget { Padding( padding: const EdgeInsets.symmetric(horizontal: 10), child: Text( - formatAddrString(transferDetails.recipient), + transferDetails.recipient.formatAddressString(), style: defaultTextStyle, ), ), CustomCopyButton( - textToBeCopied: - transferDetails.senders.first.toplAddress.toBase58(), + textToBeCopied: transferDetails.senders.first.toplAddress.toBase58(), icon: Image.asset( RibnAssets.copyIcon, width: 26, diff --git a/lib/presentation/transfers/widgets/from_address_field.dart b/lib/presentation/transfers/widgets/from_address_field.dart index c0965284..f7a72e14 100644 --- a/lib/presentation/transfers/widgets/from_address_field.dart +++ b/lib/presentation/transfers/widgets/from_address_field.dart @@ -1,14 +1,16 @@ // Flutter imports: import 'package:flutter/material.dart'; + +// Package imports: import 'package:flutter_redux/flutter_redux.dart'; +import 'package:ribn_toolkit/constants/assets.dart'; + // Project imports: import 'package:ribn/constants/strings.dart'; import 'package:ribn/models/app_state.dart'; import 'package:ribn/models/ribn_address.dart'; import 'package:ribn/presentation/transfers/widgets/custom_input_field.dart'; import 'package:ribn/widgets/address_display_container.dart'; -// Package imports: -import 'package:ribn_toolkit/constants/assets.dart'; /// Custom display for the sender's address. /// @@ -19,8 +21,7 @@ class FromAddressField extends StatelessWidget { @override Widget build(BuildContext context) { return StoreConnector( - converter: (store) => - store.state.keychainState.currentNetwork.addresses.first, + converter: (store) => store.state.keychainState.currentNetwork.addresses.first, builder: (context, ribnAddress) => CustomInputField( itemLabel: Strings.from, item: AddressDisplayContainer( @@ -34,8 +35,7 @@ class FromAddressField extends StatelessWidget { } String toShortAddress(String base) { - if (base.isEmpty) - throw FormatException("WalletAddress was returned as empty"); + if (base.isEmpty) throw FormatException("WalletAddress was returned as empty"); final start = base.substring(0, 4); final end = base.substring(base.length - 5); diff --git a/lib/providers/analytics/analytics_events.dart b/lib/providers/analytics/analytics_events.dart new file mode 100644 index 00000000..570e25a5 --- /dev/null +++ b/lib/providers/analytics/analytics_events.dart @@ -0,0 +1,184 @@ +// Package imports: +import 'package:hooks_riverpod/hooks_riverpod.dart'; + +// Project imports: +import 'package:ribn/providers/analytics/analytics_provider.dart'; +import 'package:ribn/providers/utility_provider.dart'; +import 'package:ribn/utils/extensions.dart'; +import 'package:ribn/utils/platform_utils.dart'; + +enum AnalyticsEvents { + AbandonTransactionEvent("Abandon"), // Abandon Cart + SessionDurationEvent("Session Duration"), + TransactionEvent("Transaction"), + + // dApp Events + BounceEvent("Bounce"), + DAppAuthenticatedEvent("DApp Authenticated"), + UserInteractionEvents("User Interaction Event"); + + const AnalyticsEvents(this.name); + + final String name; +} + +enum UserType { Initial, New, Returning } + +/** + * This class is used to build the parameters for the [AnalyticsEvents] + * This needs to be in the same file as [AnalyticsEventBuilders] due to the private constructor, + * This is to ensure that the [AnalyticsEventBuilders] is the only way to create an instance of this class + */ +class AnalyticsEventData { + final AnalyticsEvents event; + final Map _value; + + // Private constructor + AnalyticsEventData._(this.event, this._value); + + //to map + Map toMap() => _value; +} + +class AnalyticsEventBuilders { + Ref _ref; + AnalyticsEvents _event; + + AnalyticsEventBuilders(this._ref, this._event); + + AnalyticsEventData buildDAppAuthenticatedEvent( + {String dAppName = 'Unknown', String dAppUrl = 'Unknown', bool authenticatedState = false}) => + AnalyticsEventData._( + _event, + _optionsBuilder(walletAddress: true, userType: true, parameters: { + "dAppName": dAppName, + "dAppUrl": dAppUrl, + "authenticated": authenticatedState, + })); + + AnalyticsEventData buildTransactionEvent({ + String dAppName = 'Unknown', + String dAppUrl = 'Unknown', + int? authTime, + String transactionType = 'Unknown', + String assetType = 'Unknown', + double transferAmount = 0, + String destinationAddress = 'Unknown', + bool transactionSent = false, + double fee = 0, + double gasPrice = 0, + }) => + AnalyticsEventData._( + _event, + _optionsBuilder(walletAddress: true, userType: true, parameters: { + "dAppName": dAppName, + "dAppUrl": dAppUrl, + "authTime": authTime ?? DateTime.now().millisecondsSinceEpoch, + "transactionType": transactionType, + "assetType": assetType, + "transferAmount": transferAmount, + "destinationAddress": destinationAddress, + "transactionSent": transactionSent, + "fee": fee, + "gasPrice": gasPrice, + })); + + AnalyticsEventData buildSessionDurationEvent({ + required int startTime, + required int endTime, + String sessionType = "Active", + int contractInteractions = 0, + double totalAmountTransferred = 0, //TODO: consider refactoring to a Map that will hold multiple currencies + }) => + AnalyticsEventData._( + _event, + _optionsBuilder(walletAddress: true, userType: true, screens: true, parameters: { + "startTime": startTime, + "endTime": endTime, + "duration": endTime - startTime, + "sessionType": sessionType, + "totalAmountTransferred": totalAmountTransferred, + "contractInteractions": contractInteractions, + })); + + AnalyticsEventData buildBounceRateEvent({ + String sessionType = "Active", + int contractInteractions = 0, + double totalAmountTransferred = 0, //TODO: consider refactoring to a Map that will hold multiple currencies + }) => + AnalyticsEventData._( + _event, + _optionsBuilder(walletAddress: true, userType: true, screens: true, parameters: { + "sessionType": sessionType, + "totalAmountTransferred": totalAmountTransferred, + "contractInteractions": contractInteractions, + })); + + AnalyticsEventData buildAbandonTransactionEvent( + {int contractInteractions = 0, + assetType = 'Unknown', + double transferAmount = 0, + bool transactionSent = false}) => + AnalyticsEventData._( + _event, + _optionsBuilder(walletAddress: true, userType: true, parameters: { + "transactionSent": transactionSent, + "contractInteractions": contractInteractions, + "assetType": assetType, + "transferAmount": transferAmount, + })); + + AnalyticsEventData buildUserInteractionEvent( + {required int startTime, required int endTime, int contractInteractions = 0}) { + return AnalyticsEventData._( + _event, + _optionsBuilder(walletAddress: true, userType: true, userInteractions: true, parameters: { + "startTime": startTime, + "endTime": endTime, + "duration": endTime - startTime, + "contractInteractions": contractInteractions, + })); + } + + Map _optionsBuilder( + {bool defaultMetrics = true, + bool eventName = true, + bool walletAddress = false, + bool userType = false, + bool network = false, + bool screens = false, + bool userInteractions = false, + Map parameters = const {}}) => + parameters + .addIf(eventName, _addEventName()) + .addIf(defaultMetrics, _addDefaultMetrics()) + .addIf(walletAddress, _addWalletAddress()) + .addIf(userType, _addUserType()) + .addIf(network, _addNetwork()); + + static Map _addDefaultMetrics({Map parameters = const {}}) => { + 'timestamp': DateTime.now().millisecondsSinceEpoch, + 'platform': getOperatingSystem(), + ...parameters, + }; + + Map _addWalletAddress({Map parameters = const {}}) => { + 'walletAddress': _ref.read(currentWalletAddressProvider).toHashSha256(), + ...parameters, + }; + + Map _addUserType({Map parameters = const {}}) => { + 'userType': _ref.read(analyticsProvider).userType.name, + ...parameters, + }; + + Map _addEventName({Map parameters = const {}}) => { + 'event': _event.name.toString(), + ...parameters, + }; + + Map _addNetwork({Map parameters = const {}}) => { + 'network': _ref.read(currentNetworkProvider), + ...parameters, + }; +} diff --git a/lib/providers/analytics/analytics_provider.dart b/lib/providers/analytics/analytics_provider.dart new file mode 100644 index 00000000..5b93bc10 --- /dev/null +++ b/lib/providers/analytics/analytics_provider.dart @@ -0,0 +1,93 @@ +// Dart imports: +import 'dart:async'; + +// Package imports: +import 'package:hooks_riverpod/hooks_riverpod.dart'; + +// Project imports: +import 'package:ribn/models/state/analytics_state.dart'; +import 'package:ribn/platform/platform.dart'; +import 'package:ribn/providers/analytics/analytics_events.dart'; +import 'package:ribn/providers/analytics/analytics_service.dart'; +import 'package:ribn/providers/logger_provider.dart'; +import 'package:ribn/providers/packages/flutter_secure_storage_provider.dart'; +import 'package:ribn/utils/extensions.dart'; + +final analyticsProvider = StateNotifierProvider((ref) { + return AnalyticsNotifier(ref); +}); + +class AnalyticsNotifier extends StateNotifier { + final Ref ref; + + // Load no analytics tracking as default + AnalyticsService _service = VoidAnalyticsService(); + + AnalyticsNotifier(this.ref) : super(AnalyticsState()) { + _isAnalyticsEnabled().then((isEnabled) { + state = state.copyWith(isEnabled: isEnabled); + if (isEnabled) { + _service = FirebaseAnalyticsService(ref); + } + }); + } + + Future log(String name, Map parameters) async { + if (_service is VoidAnalyticsService) return; + await _service.logCustomEvent(name, parameters); + } + + Future logEventWithBuilder(AnalyticsEventData data) async { + if (_service is VoidAnalyticsService) return; + await _service.logEventWithBuilder(data); + } + + static const _analyticsEnabledKey = "biometricsEnabled"; + + /*** + * Toggles analytics and persists it to storage. + * Allows you to set an override value + */ + Future toggleAnalytics({bool? overrideValue}) async { + final logger = ref.read(loggerProvider); + + final isEnabled = overrideValue ?? !state.isEnabled; + + await PlatformLocalStorage.instance.saveKVInSecureStorage(_analyticsEnabledKey, (isEnabled).toString(), + override: ref.read(flutterSecureStorageProvider)()); + + if (isEnabled) { + _service = FirebaseAnalyticsService(ref); + logger.log( + logLevel: LogLevel.Info, + loggerClass: LoggerClass.Analytics, + message: "Analytics enabled", + ); + } else { + _service = VoidAnalyticsService(); + logger.log( + logLevel: LogLevel.Info, + loggerClass: LoggerClass.Analytics, + message: "Analytics disabled", + ); + } + + state = state.copyWith(isEnabled: isEnabled); + } + + Future _isAnalyticsEnabled() async { + return (await PlatformLocalStorage.instance + .getKVInSecureStorage(_analyticsEnabledKey, override: ref.read(flutterSecureStorageProvider)())) + .toBooleanWithNullableDefault(false); + } + + void setUserType(UserType type) { + ref.read(loggerProvider).log( + logLevel: LogLevel.Info, + loggerClass: LoggerClass.Analytics, + message: "User type set to: ${type.toString()}", + ); + + state = state.copyWith(userType: type); + } +} diff --git a/lib/providers/analytics/analytics_service.dart b/lib/providers/analytics/analytics_service.dart new file mode 100644 index 00000000..19914630 --- /dev/null +++ b/lib/providers/analytics/analytics_service.dart @@ -0,0 +1,55 @@ +// Package imports: +import 'package:firebase_analytics/firebase_analytics.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; + +// Project imports: +import 'package:ribn/providers/analytics/analytics_events.dart'; + +abstract class AnalyticsService { + AnalyticsService(); + + Future logCustomEvent(String name, Map parameters); + + Future logEventWithBuilder(AnalyticsEventData data); +} + +// This class acts as a dummy class, It should do nothing. +// I have this class here so that we can be absolutely sure nothing gets logged +// unless we consciously load a different analytics service +class VoidAnalyticsService implements AnalyticsService { + VoidAnalyticsService(); + + Future logCustomEvent(String name, Map parameters) async { + // do nothing + } + + @override + Future logEventWithBuilder(AnalyticsEventData data) async { + // do nothing + } +} + +class FirebaseAnalyticsService implements AnalyticsService { + FirebaseAnalytics analytics = FirebaseAnalytics.instance; + final Ref ref; + + // Initializes firebase for this application + FirebaseAnalyticsService(this.ref); + + /*** + * Logs an event to firebase analytics + * Use the AnalyticsEventBuilders to build the parameters + */ + Future logCustomEvent(String name, Map parameters) async { + // log event to firebase + await FirebaseAnalytics.instance.logEvent(name: name, parameters: parameters); + } + + /** Logs an event to firebase analytics + * Use the [AnalyticsEventBuilders] to build the [AnalyticsEventData] parameters + */ + Future logEventWithBuilder(AnalyticsEventData data) async { + // log event to firebase + await FirebaseAnalytics.instance.logEvent(name: data.event.name, parameters: data.toMap()); + } +} diff --git a/lib/providers/app_bar_provider.dart b/lib/providers/app_bar_provider.dart new file mode 100644 index 00000000..f63f3157 --- /dev/null +++ b/lib/providers/app_bar_provider.dart @@ -0,0 +1,9 @@ +// Flutter imports: +import 'package:flutter/material.dart'; + +// Package imports: +import 'package:hooks_riverpod/hooks_riverpod.dart'; + +final appBarToolTipOverlayEntryProvider = StateProvider((ref) { + return null; +}); diff --git a/lib/providers/app_state_provider.dart b/lib/providers/app_state_provider.dart new file mode 100644 index 00000000..e05efdc7 --- /dev/null +++ b/lib/providers/app_state_provider.dart @@ -0,0 +1,28 @@ +// Package imports: +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:redux/redux.dart'; + +// Project imports: +import 'package:ribn/actions/misc_actions.dart'; +import 'package:ribn/models/app_state.dart'; +import 'package:ribn/providers/store_provider.dart'; + +final appStateProvider = StateNotifierProvider((ref) { + return AppStateNotifier(ref); +}); + +class AppStateNotifier extends StateNotifier { + final Ref ref; + AppStateNotifier(this.ref) : super(null); + + // TODO: for now this will just reach out to redux. Move to using this provider only in the future + Future persistAppState() async { + final Store store = ref.read(storeProvider); + await store.dispatch(PersistAppState()); + } + + Future resetAppState() async { + final Store store = ref.read(storeProvider); + await store.dispatch(ResetAppStateAction()); + } +} diff --git a/lib/providers/biometrics_provider.dart b/lib/providers/biometrics_provider.dart new file mode 100644 index 00000000..26f63e76 --- /dev/null +++ b/lib/providers/biometrics_provider.dart @@ -0,0 +1,130 @@ +// Flutter imports: +import 'package:flutter/foundation.dart'; + +// Package imports: +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:local_auth/local_auth.dart'; + +// Project imports: +import 'package:ribn/models/state/biometrics_state.dart'; +import 'package:ribn/platform/platform.dart'; +import 'package:ribn/providers/packages/flutter_secure_storage_provider.dart'; +import 'package:ribn/providers/packages/local_authentication_provider.dart'; +import 'package:ribn/utils/extensions.dart'; +import 'logger_provider.dart'; + +/// Provides biometrics state and functions +final biometricsProvider = StateNotifierProvider>((ref) { + final localAuthentication = ref.read(localAuthenticationProvider)(); + return BiometricsNotifier(ref, localAuthentication); +}); + +class BiometricsNotifier extends StateNotifier> { + final Ref ref; + + BiometricsNotifier(this.ref, this._auth) : super(AsyncLoading()) { + _init(); + } + + Future _init() async { + final isSupported = await _isBiometricsAuthenticationSupported(); + + if (!isSupported) { + state = AsyncData(BiometricsState()); + return false; + } + + final isEnabled = await isBiometricsEnabled(ref); + state = AsyncData(BiometricsState(isSupported: isSupported, isEnabled: isEnabled)); + return true; + } + + final LocalAuthentication _auth; + + static const _biometricsEnabledKey = "biometricsEnabled"; + + /*** + * Toggles [state.isEnabled] and resets [state.authorized] + * @requires [state.authorized] to be true + */ + Future toggleBiometrics({bool? overrideValue}) async { + final biometrics = state.value; // setup for type promotion + if (biometrics == null) { + ref.read(loggerProvider).log( + logLevel: LogLevel.Warning, + loggerClass: LoggerClass.ApiError, + message: "Tried to modify biometrics state, before initialization was completed", + ); + state = AsyncError(Exception("Biometrics not initialized"), StackTrace.current); + return; + } + + // guard clause for authorization + if (!biometrics.authorized) { + ref.read(loggerProvider).log( + logLevel: LogLevel.Warning, + loggerClass: LoggerClass.ApiError, + message: "Tried to modify biometrics state without authorization", + ); + return; + } + + // sets value to Override value, if not supplied default to toggle behaviour + final isEnabled = overrideValue ?? !biometrics.isEnabled; + + await PlatformLocalStorage.instance.saveKVInSecureStorage(_biometricsEnabledKey, isEnabled.toString(), + override: ref.read(flutterSecureStorageProvider)()); + + // resets authorized value + state = AsyncValue.data(biometrics.copyWith(isEnabled: isEnabled, authorized: false)); + } + + void setAuthorization(bool value) { + final biometrics = state.value; // setup for type promotion + if (biometrics != null) { + state = AsyncValue.data(biometrics.copyWith(authorized: value)); + } + } + + Future isBiometricsAuthenticationEnrolled() async { + final bool canCheckBiometrics = await _auth.canCheckBiometrics; + final bool isDeviceSupported = await _auth.isDeviceSupported(); + final List enrolledBiometrics = await _auth.getAvailableBiometrics(); + + return canCheckBiometrics && isDeviceSupported && enrolledBiometrics.isNotEmpty; + } + + Future authenticateWithBiometrics() async { + return await _auth.authenticate( + localizedReason: 'To authenticate with biometrics', + options: const AuthenticationOptions( + stickyAuth: true, + biometricOnly: true, + sensitiveTransaction: true, + useErrorDialogs: true, + ), + ); + } + + Future isBiometricsTypeFingerprint() async { + final List enrolledBiometrics = await _auth.getAvailableBiometrics(); + + return enrolledBiometrics.contains(BiometricType.fingerprint) && enrolledBiometrics.isNotEmpty; + } + + Future _isBiometricsAuthenticationSupported() async { + // If is web, return false by default + if (kIsWeb) return false; + + final bool canCheckBiometrics = await _auth.canCheckBiometrics; + final bool isDeviceSupported = await _auth.isDeviceSupported(); + + return canCheckBiometrics && isDeviceSupported; + } + + static Future isBiometricsEnabled(ref) async { + return (await PlatformLocalStorage.instance + .getKVInSecureStorage(_biometricsEnabledKey, override: ref.read(flutterSecureStorageProvider)())) + .toBooleanWithNullableDefault(false); + } +} diff --git a/lib/providers/keychain_provider.dart b/lib/providers/keychain_provider.dart new file mode 100644 index 00000000..8a6240ee --- /dev/null +++ b/lib/providers/keychain_provider.dart @@ -0,0 +1,41 @@ +// Flutter imports: +import 'package:flutter/foundation.dart'; + +// Package imports: +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:redux/redux.dart'; + +// Project imports: +import 'package:ribn/actions/keychain_actions.dart'; +import 'package:ribn/constants/network_utils.dart'; +import 'package:ribn/models/app_state.dart'; +import 'package:ribn/models/keychain_state.dart'; +import 'package:ribn/models/ribn_network.dart'; +import 'package:ribn/providers/store_provider.dart'; + +final keychainProvider = StateNotifierProvider((ref) { + return KeychainNotifier(ref); +}); + +class KeychainNotifier extends StateNotifier { + final Ref ref; + KeychainNotifier(this.ref) + : super(KeychainState( + networks: Map.unmodifiable(RibnNetwork.initializeToplNetworks()), + currentNetworkName: NetworkUtils.valhalla, + )); + + Future initializeHdWallet({ + required Uint8List toplExtendedPrivateKey, + String? keyStoreJson, + }) async { + final Store store = ref.read(storeProvider); + + await store.dispatch( + InitializeHDWalletAction( + toplExtendedPrivateKey: toplExtendedPrivateKey, + keyStoreJson: keyStoreJson, + ), + ); + } +} diff --git a/lib/providers/logger_provider.dart b/lib/providers/logger_provider.dart index 73b873bb..6f59e7b3 100644 --- a/lib/providers/logger_provider.dart +++ b/lib/providers/logger_provider.dart @@ -1,13 +1,51 @@ +// Package imports: import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:logging/logging.dart'; + +// Project imports: import 'package:ribn/constants/loggers.dart'; -final loggerProvider = - Provider((ref) => (String loggerName) => Logger(loggerName)); +export 'package:ribn/constants/loggers.dart'; // export so dependent files can use the enums + +final loggerPackageProvider = Provider((ref) { + return (String loggerClass) => Logger(loggerClass); +}); + +final loggerProvider = Provider((ref) { + return LoggerNotifier(ref); +}); + +class LoggerNotifier { + final Ref ref; -final Logger Function() transactionLogger = () { - // Allows to get riverpod state without ref - final container = ProviderContainer(); + LoggerNotifier(this.ref) { + Logger.root.level = Level.ALL; // defaults to Level.INFO + Logger.root.onRecord.listen((record) { + print('${record.level.name}: ${record.time}: ${record.message}'); + }); + } - return container.read(loggerProvider)(kTransactionLogger); -}; + void log({ + required LogLevel logLevel, + required LoggerClass loggerClass, + required String message, + Object? error, + StackTrace? stackTrace, + }) { + final Logger logger = ref.read(loggerPackageProvider)(loggerClass.string); + switch (logLevel) { + case LogLevel.Info: + logger.info(message, error, stackTrace); + break; + case LogLevel.Warning: + logger.warning(message, error, stackTrace); + break; + case LogLevel.Severe: + logger.severe(message, error, stackTrace); + break; + case LogLevel.Shout: + logger.shout(message, error, stackTrace); + break; + } + } +} diff --git a/lib/providers/login_provider.dart b/lib/providers/login_provider.dart new file mode 100644 index 00000000..46fbc148 --- /dev/null +++ b/lib/providers/login_provider.dart @@ -0,0 +1,138 @@ +// Dart imports: +import 'dart:async'; +import 'dart:convert'; + +// Flutter imports: +import 'package:flutter/foundation.dart'; +import 'package:flutter/widgets.dart'; + +// Package imports: +import 'package:bip_topl/bip_topl.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:redux/src/store.dart'; + +// Project imports: +import 'package:ribn/actions/keychain_actions.dart'; +import 'package:ribn/actions/misc_actions.dart'; +import 'package:ribn/constants/keys.dart'; +import 'package:ribn/constants/routes.dart'; +import 'package:ribn/constants/rules.dart'; +import 'package:ribn/models/app_state.dart'; +import 'package:ribn/models/state/login_state.dart'; +import 'package:ribn/platform/platform.dart'; +import 'package:ribn/providers/analytics/analytics_events.dart'; +import 'package:ribn/providers/analytics/analytics_provider.dart'; +import 'package:ribn/providers/biometrics_provider.dart'; +import 'package:ribn/providers/logger_provider.dart'; +import 'package:ribn/providers/packages/flutter_secure_storage_provider.dart'; +import 'package:ribn/providers/store_provider.dart'; +import 'package:ribn/repositories/login_repository.dart'; +import 'package:ribn/utils/extensions.dart'; + +final loginProvider = StateNotifierProvider((ref) { + final store = ref.read(storeProvider); + return LoginNotifier(ref, store); +}); + +class LoginNotifier extends StateNotifier { + final Ref ref; + Store store; + + LoginNotifier(this.ref, this.store) : super(LoginState()) { + // check if biometrics is enabled + BiometricsNotifier.isBiometricsEnabled(ref).then((value) => state = state.copyWith(isBiometricsEnabled: value)); + } + + // Verifies that the wallet password is correct by attempting to decrypt the keystore. + Future _verifyPassword(AttemptLoginAction action) async { + try { + final AppViews currAppView = await PlatformUtils.instance.getCurrentAppView(); + + // create isolate/worker to avoid hanging the UI + final List result = jsonDecode( + await PlatformWorkerRunner.instance.runWorker( + workerScript: currAppView == AppViews.webDebug ? '/web/workers/login_worker.js' : '/workers/login_worker.js', + function: LoginRepository().decryptKeyStore, + params: { + 'keyStoreJson': store.state.keychainState.keyStoreJson, + 'password': action.password, + }, + ), + ); + + final Uint8List toplExtendedPrvKeyUint8List = result.toUint8List(); + // if extension: key is temporarily stored in `chrome.storage.session` & session alarm created + // if mobile: key is persisted securely in secure storage + if (currAppView == AppViews.extension || currAppView == AppViews.extensionTab) { + await PlatformLocalStorage.instance.saveKeyInSessionStorage( + Base58Encoder.instance.encode(toplExtendedPrvKeyUint8List), + ); + PlatformUtils.instance.createLoginSessionAlarm(); + } else if (currAppView == AppViews.mobile) { + await PlatformLocalStorage.instance.saveKeyInSecureStorage( + Base58Encoder.instance.encode(toplExtendedPrvKeyUint8List), + override: ref.read(flutterSecureStorageProvider)()); + } + + _onLogin(toplExtendedPrvKeyUint8List); + + action.completer.complete(true); + } catch (e) { + ref + .read(loggerProvider) + .log(logLevel: LogLevel.Severe, loggerClass: LoggerClass.Authentication, message: e.toString()); + action.completer.complete(false); + } + } + + void _onLogin(Uint8List toplExtendedPrvKeyUint8List) { + // initialize hd wallet on success + store.dispatch(InitializeHDWalletAction( + toplExtendedPrivateKey: toplExtendedPrvKeyUint8List, + )); + + //Generate Initial addresses for every network + store.dispatch(GenerateInitialAddressesAction()); + + state = state.copyWith(isLoggedIn: true); + + // Send To analytics + ref.read(analyticsProvider.notifier).setUserType(UserType.Returning); + } + + /// Handler for when there is an attempt to login using [password]. + Future attemptLogin( + {required String password, + required VoidCallback onIncorrectPasswordEntered, + required BuildContext context}) async { + final Completer loginCompleter = Completer(); + _verifyPassword(AttemptLoginAction(password, loginCompleter)); + + await loginCompleter.future.then((bool loginSuccess) async { + if (!loginSuccess) { + onIncorrectPasswordEntered(); + return; + } + // + // if (store.state.internalMessage?.additionalNavigation == Routes.connectDApp && + // store.state.internalMessage != null) { + // await MiscRepository().persistAppState(StoreProvider.of(context).state.toJson()); + // Keys.navigatorKey.currentState?.pushNamed(Routes.connectDApp, arguments: store.state.internalMessage); + // } else { + Keys.navigatorKey.currentState?.pushReplacementNamed(Routes.home); + // } + }); + } + + /// Handler for when there is attempt to restore wallet from the login page. + void restoreWallet() { + store.dispatch(NavigateToRoute(Routes.restoreWallet)); + } +} + +class AttemptLoginAction { + final String password; + final Completer completer; + + const AttemptLoginAction(this.password, this.completer); +} diff --git a/lib/providers/onboarding_provider.dart b/lib/providers/onboarding_provider.dart new file mode 100644 index 00000000..99bbe484 --- /dev/null +++ b/lib/providers/onboarding_provider.dart @@ -0,0 +1,104 @@ +// import 'dart:math'; + +// Dart imports: +import 'dart:convert'; +import 'dart:math'; +import 'dart:typed_data'; + +// Package imports: +import 'package:bip_topl/bip_topl.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; + +// Project imports: +import 'package:ribn/constants/rules.dart'; +import 'package:ribn/models/onboarding_state.dart'; +import 'package:ribn/platform/mobile/storage.dart'; +import 'package:ribn/platform/mobile/utils.dart'; +import 'package:ribn/platform/mobile/worker_runner.dart'; +import 'package:ribn/providers/app_state_provider.dart'; +import 'package:ribn/providers/keychain_provider.dart'; +import 'package:ribn/providers/packages/entropy_provider.dart'; +import 'package:ribn/providers/packages/flutter_secure_storage_provider.dart'; +import 'package:ribn/providers/packages/random_provider.dart'; +import 'package:ribn/repositories/onboarding_repository.dart'; +import 'package:ribn/utils/error_handling_utils.dart'; +import 'package:ribn/utils/extensions.dart'; + +final onboardingProvider = StateNotifierProvider((ref) { + return OnboardingNotifier(ref); +}); + +class OnboardingNotifier extends StateNotifier { + final Ref ref; + OnboardingNotifier(this.ref) : super(_generateOnboardingState(ref)) {} + + static OnboardingState _generateOnboardingState(ref) { + final String mnemonic = _generateMnemonic(ref); + final List splitMnemonic = mnemonic.split(' ').toList(); + return OnboardingState( + mnemonic: mnemonic, + shuffledMnemonic: splitMnemonic, + ); + } + + static String _generateMnemonic(Ref ref) { + final Random random = ref.read(randomProvider)(); + + final Entropy entropy = ref.read(entropyProvider)(random); + return ref.read(entropyFuncProvider)(entropy); + } + + regenerateMnemonic() { + final OnboardingState onboardingState = _generateOnboardingState(ref); + state = state.copyWith( + mnemonic: onboardingState.mnemonic, + shuffledMnemonic: onboardingState.shuffledMnemonic, + ); + } + + Future createPassword({ + required String password, + }) async { + try { + final AppViews currAppView = await PlatformUtils.instance.getCurrentAppView(); + // create isolate/worker to avoid hanging the UI + final Map results = jsonDecode( + await PlatformWorkerRunner.instance.runWorker( + workerScript: currAppView == AppViews.webDebug + ? '/web/workers/generate_keystore_worker.js' + : '/workers/generate_keystore_worker.js', + function: OnboardingRespository().generateKeyStore, + params: { + 'mnemonic': state.mnemonic, + 'password': password, + }, + ), + ); + + final Uint8List toplExtendedPrvKeyUint8List = + (results['toplExtendedPrvKeyUint8List'] as List).toUint8List(); + + // if extension: key is temporarily stored in `chrome.storage.session` & session alarm created + // if mobile: key is persisted securely in secure storage + if (currAppView == AppViews.extension || currAppView == AppViews.extensionTab) { + await PlatformLocalStorage.instance.saveKeyInSessionStorage( + Base58Encoder.instance.encode(toplExtendedPrvKeyUint8List), + ); + PlatformUtils.instance.createLoginSessionAlarm(); + } else if (currAppView == AppViews.mobile) { + await PlatformLocalStorage.instance.saveKeyInSecureStorage( + Base58Encoder.instance.encode(toplExtendedPrvKeyUint8List), + override: ref.read(flutterSecureStorageProvider)()); + } + + await ref.read(keychainProvider.notifier).initializeHdWallet( + toplExtendedPrivateKey: toplExtendedPrvKeyUint8List, + keyStoreJson: results['keyStoreJson'], + ); + + await ref.read(appStateProvider.notifier).persistAppState(); + } catch (e) { + handleApiError(errorMessage: e.toString()); + } + } +} diff --git a/lib/providers/packages/entropy_provider.dart b/lib/providers/packages/entropy_provider.dart new file mode 100644 index 00000000..b17467bc --- /dev/null +++ b/lib/providers/packages/entropy_provider.dart @@ -0,0 +1,12 @@ +// Package imports: +import 'package:bip_topl/bip_topl.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:pinenacl/encoding.dart'; + +final entropyProvider = Provider((ref) { + return (random) => Entropy.generate(from_entropy_size(160), RandomBridge(random).nextUint8); +}); + +final entropyFuncProvider = Provider((ref) { + return (entropy) => entropyToMnemonic(HexCoder.instance.encode(entropy.bytes), language: 'english'); +}); diff --git a/lib/providers/packages/flutter_secure_storage_provider.dart b/lib/providers/packages/flutter_secure_storage_provider.dart new file mode 100644 index 00000000..8dc40371 --- /dev/null +++ b/lib/providers/packages/flutter_secure_storage_provider.dart @@ -0,0 +1,7 @@ +// Package imports: +import 'package:flutter_secure_storage/flutter_secure_storage.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; + +final flutterSecureStorageProvider = Provider((ref) { + return () => FlutterSecureStorage(aOptions: AndroidOptions(encryptedSharedPreferences: true)); +}); diff --git a/lib/providers/packages/local_authentication_provider.dart b/lib/providers/packages/local_authentication_provider.dart new file mode 100644 index 00000000..8de73efe --- /dev/null +++ b/lib/providers/packages/local_authentication_provider.dart @@ -0,0 +1,7 @@ +// Package imports: +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:local_auth/local_auth.dart'; + +final localAuthenticationProvider = Provider((ref) { + return () => LocalAuthentication(); +}); diff --git a/lib/providers/packages/random_provider.dart b/lib/providers/packages/random_provider.dart new file mode 100644 index 00000000..dcdba962 --- /dev/null +++ b/lib/providers/packages/random_provider.dart @@ -0,0 +1,9 @@ +// Dart imports: +import 'dart:math'; + +// Package imports: +import 'package:hooks_riverpod/hooks_riverpod.dart'; + +final randomProvider = Provider((ref) { + return () => Random.secure(); +}); diff --git a/lib/providers/packages/url_launcher_provider.dart b/lib/providers/packages/url_launcher_provider.dart new file mode 100644 index 00000000..43297067 --- /dev/null +++ b/lib/providers/packages/url_launcher_provider.dart @@ -0,0 +1,7 @@ +// Package imports: +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:url_launcher/url_launcher.dart'; + +final Provider Function(Uri)> urlLauncherProvider = Provider Function(Uri)>((ref) { + return (Uri uri) => launchUrl(uri); +}); diff --git a/lib/providers/password_provider.dart b/lib/providers/password_provider.dart new file mode 100644 index 00000000..e91ef7f4 --- /dev/null +++ b/lib/providers/password_provider.dart @@ -0,0 +1,11 @@ +// Package imports: +import 'package:hooks_riverpod/hooks_riverpod.dart'; + +// Project imports: +import 'package:ribn/models/state/password_state.dart'; + +/// Provides password state +/// AutoDispose so that when provider is stopped being listened too, all values reset +final AutoDisposeStateProvider passwordProvider = StateProvider.autoDispose((ref) { + return PasswordState(); +}); diff --git a/lib/providers/restore_wallet_provider.dart b/lib/providers/restore_wallet_provider.dart new file mode 100644 index 00000000..74403565 --- /dev/null +++ b/lib/providers/restore_wallet_provider.dart @@ -0,0 +1,97 @@ +// Dart imports: +import 'dart:async'; +import 'dart:convert'; + +// Flutter imports: +import 'package:flutter/foundation.dart'; + +// Package imports: +import 'package:hooks_riverpod/hooks_riverpod.dart'; + +// Project imports: +import 'package:ribn/constants/keys.dart'; +import 'package:ribn/constants/routes.dart'; +import 'package:ribn/constants/rules.dart'; +import 'package:ribn/platform/mobile/utils.dart'; +import 'package:ribn/platform/mobile/worker_runner.dart'; +import 'package:ribn/providers/app_state_provider.dart'; +import 'package:ribn/providers/keychain_provider.dart'; +import 'package:ribn/repositories/login_repository.dart'; +import 'package:ribn/repositories/onboarding_repository.dart'; +import 'package:ribn/utils/error_handling_utils.dart'; +import 'package:ribn/utils/extensions.dart'; + +final restoreWalletProvider = StateNotifierProvider((ref) { + return RestoreWalletNotifier(ref); +}); + +class RestoreWalletNotifier extends StateNotifier { + final Ref ref; + RestoreWalletNotifier(this.ref) : super(null); + + /// Uses the [mnemonic] and [password] to generate a keystore. + Future restoreWalletWithMnemonic({ + required String password, + required String mnemonic, + }) async { + try { + final AppViews currAppView = await PlatformUtils.instance.getCurrentAppView(); + final Map results = jsonDecode( + await PlatformWorkerRunner.instance.runWorker( + workerScript: currAppView == AppViews.webDebug + ? '/web/workers/generate_keystore_worker.js' + : '/workers/generate_keystore_worker.js', + function: OnboardingRespository().generateKeyStore, + params: { + 'mnemonic': mnemonic, + 'password': password, + }, + ), + ); + await _restoreFlow( + toplExtendedPrivateKey: (results['toplExtendedPrvKeyUint8List'] as List).toUint8List(), + keyStoreJson: results['keyStoreJson'], + ); + const String navigateToRoute = kIsWeb ? Routes.extensionInfo : Routes.home; + + Keys.navigatorKey.currentState?.pushNamedAndRemoveUntil(navigateToRoute, (route) => false); + } catch (e) { + handleApiError(errorMessage: e.toString()); + } + } + + /// Attempts to decrypt [toplKeyStoreJson] using [password]. + Future restoreWalletWithToplKey({ + required String toplKeyStoreJson, + required String password, + required Completer completer, + }) async { + try { + final Uint8List toplExtendedPrvKeyUint8List = LoginRepository().decryptKeyStore({ + 'keyStoreJson': toplKeyStoreJson, + 'password': password, + }); + completer.complete(true); + await _restoreFlow( + keyStoreJson: toplKeyStoreJson, + toplExtendedPrivateKey: toplExtendedPrvKeyUint8List, + ); + } catch (e) { + completer.complete(false); + } + } + + Future _restoreFlow({ + required toplExtendedPrivateKey, + required keyStoreJson, + }) async { + await ref.read(appStateProvider.notifier).resetAppState(); + + await ref.read(keychainProvider.notifier).initializeHdWallet( + toplExtendedPrivateKey: toplExtendedPrivateKey, + keyStoreJson: keyStoreJson, + ); + + await ref.read(appStateProvider.notifier).persistAppState(); + } +} diff --git a/lib/providers/settings_provider.dart b/lib/providers/settings_provider.dart new file mode 100644 index 00000000..3e0ef6f1 --- /dev/null +++ b/lib/providers/settings_provider.dart @@ -0,0 +1,68 @@ +// Dart imports: +import 'dart:async'; + +// Flutter imports: +import 'package:flutter/foundation.dart'; + +// Package imports: +import 'package:hooks_riverpod/hooks_riverpod.dart'; + +// Project imports: +import 'package:ribn/platform/platform.dart'; +import 'package:ribn/providers/app_state_provider.dart'; +import 'package:ribn/providers/store_provider.dart'; +import 'package:ribn/providers/utility_provider.dart'; +import 'package:ribn/repositories/login_repository.dart'; +import '../constants/keys.dart'; +import '../constants/routes.dart'; + +final canDisconnectDAppsProvider = FutureProvider.autoDispose((ref) async { + if (!kIsWeb) return false; + + final List dApps = await PlatformUtils.instance.convertToFuture(PlatformUtils.instance.getDAppList()); + await PlatformUtils.instance.consoleLog(dApps.toString()); + + return dApps.isNotEmpty; +}); + +final settingsProvider = Provider((ref) => SettingsNotifier(ref)); + +class SettingsNotifier { + final Ref ref; + + SettingsNotifier(this.ref); + + void ExportToplMainKey() { + final store = ref.read(storeProvider); + ref.read(downloadFileProvider(File(fileName: 'topl_main_key.json', text: store.state.keychainState.keyStoreJson!))); + } + + Future DeleteWallet(String password, Completer completer) async { + final store = ref.read(storeProvider); + + try { + // Check if correct password was entered + LoginRepository().decryptKeyStore( + { + 'keyStoreJson': store.state.keychainState.keyStoreJson!, + 'password': password, + }, + ); + + // Reset and persist app state + ref.read(appStateProvider.notifier).resetAppState(); + + await PlatformLocalStorage.instance.saveState(store.state.toJson()); + if (kIsWeb) { + await PlatformLocalStorage.instance.clearSessionStorage(); + PlatformUtils.instance.closeWindow(); + } else { + await PlatformLocalStorage.instance.clearSecureStorage(); + await Keys.navigatorKey.currentState?.pushNamedAndRemoveUntil(Routes.welcome, (_) => false); + } + } catch (e) { + // Complete with false to indicate error, i.e. incorrect password was entered + completer.complete(false); + } + } +} diff --git a/lib/providers/store_provider.dart b/lib/providers/store_provider.dart index 28852b46..5dd9da9c 100644 --- a/lib/providers/store_provider.dart +++ b/lib/providers/store_provider.dart @@ -1,5 +1,8 @@ +// Package imports: import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:redux/redux.dart'; + +// Project imports: import 'package:ribn/models/app_state.dart'; import 'package:ribn/redux.dart'; diff --git a/lib/providers/transactions/poly_transfer_provider.dart b/lib/providers/transactions/poly_transfer_provider.dart new file mode 100644 index 00000000..c2e0e78d --- /dev/null +++ b/lib/providers/transactions/poly_transfer_provider.dart @@ -0,0 +1,67 @@ +// Flutter imports: +import 'package:flutter/material.dart'; + +// Package imports: +import 'package:hooks_riverpod/hooks_riverpod.dart'; + +// Project imports: +import 'package:ribn/models/ribn_network.dart'; +import 'package:ribn/models/view/poly_transfer_class.dart'; +import 'package:ribn/utils/utils.dart'; + +final polyTransferProvider = StateNotifierProvider.autoDispose((ref) { + return PolyTransferNotifier(ref); +}); + +class PolyTransferNotifier extends StateNotifier { + final Ref ref; + + PolyTransferNotifier(this.ref) + : super(PolyTransferClass( + amount: 0, + note: '', + recipientAddress: '', + validRecipientAddress: '', + )); + + // Updates recipient and validates it + void validateRecipient(String recipient, RibnNetwork network, TextEditingController controller) { + state = state.copyWith(recipientAddress: recipient); + + validateRecipientAddress( + networkName: network.networkName, + address: recipient, + handleResult: (bool result) { + if (result) { + state = state.copyWith(validRecipientAddress: recipient); + controller.text = ''; + } else { + state = state.copyWith(validRecipientAddress: ''); + } + }, + ); + } + + void onRecipientBackspacePressed(TextEditingController controller) { + final validRecipientAddress = state.validRecipientAddress; + + if (validRecipientAddress.isNotEmpty) { + controller.text = validRecipientAddress; + controller + ..text = controller.text.substring(0, controller.text.length) + ..selection = TextSelection.collapsed( + offset: controller.text.length, + ); + } + + state = state.copyWith(validRecipientAddress: ''); + } + + void updateNote(String note) { + state = state.copyWith(note: note); + } + + void updateAmount(String amount) { + state = state.copyWith(amount: int.parse(amount)); + } +} diff --git a/lib/providers/utility_provider.dart b/lib/providers/utility_provider.dart new file mode 100644 index 00000000..7202ca4c --- /dev/null +++ b/lib/providers/utility_provider.dart @@ -0,0 +1,41 @@ +// Package imports: +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:redux/redux.dart'; + +// Project imports: +import 'package:ribn/constants/environment_config.dart'; +import 'package:ribn/models/app_state.dart'; +import 'package:ribn/models/file.dart'; +import 'package:ribn/platform/platform.dart'; +import 'package:ribn/providers/store_provider.dart'; + +// makes calling provider easier +export 'package:ribn/models/file.dart'; + +final appVersionProvider = Provider((ref) { + if (EnvironmentConfig.nightlyBuildVersion == "") { + try { + return PlatformUtils.instance.getCurrentAppVersion(); + } catch (e) { + return 'Dev'; + } + } + + // Returns Nightly Build version supplies via compile time variables + return "Nightly Build ${EnvironmentConfig.nightlyBuildVersion}"; +}); + +final downloadFileProvider = Provider.autoDispose.family((ref, File) { + return PlatformUtils.instance.downloadFile(File.fileName, File.text); +}); + +// TODO requires rewrite after keychain refactor +final currentNetworkProvider = Provider((ref) { + final Store store = ref.read(storeProvider); + return store.state.keychainState.currentNetwork.networkName; +}); + +final currentWalletAddressProvider = Provider((ref) { + final Store store = ref.read(storeProvider); + return store.state.keychainState.currentNetwork.addresses.first.toplAddress.toBase58(); +}); diff --git a/lib/reducers/app_reducer.dart b/lib/reducers/app_reducer.dart index 431e7aca..a7b1229d 100644 --- a/lib/reducers/app_reducer.dart +++ b/lib/reducers/app_reducer.dart @@ -3,8 +3,6 @@ import 'package:ribn/actions/misc_actions.dart'; import 'package:ribn/models/app_state.dart'; import 'package:ribn/reducers/internal_message_reducer.dart'; import 'package:ribn/reducers/keychain_reducer.dart'; -import 'package:ribn/reducers/login_reducer.dart'; -import 'package:ribn/reducers/onboarding_reducer.dart'; import 'package:ribn/reducers/user_details_reducer.dart'; /// Main reducer for [AppState] @@ -13,12 +11,9 @@ AppState appReducer(AppState state, dynamic action) { return AppState.initial(); } else { return AppState( - onboardingState: onboardingReducer(state.onboardingState, action), - loginState: loginReducer(state.loginState, action), keychainState: keychainReducer(state.keychainState, action), userDetailsState: userDetailsReducer(state.userDetailsState, action), internalMessage: internalMessageReducer(state.internalMessage, action), - appVersion: state.appVersion, ); } } diff --git a/lib/reducers/login_reducer.dart b/lib/reducers/login_reducer.dart deleted file mode 100644 index f2f6d143..00000000 --- a/lib/reducers/login_reducer.dart +++ /dev/null @@ -1,20 +0,0 @@ -// Package imports: -import 'package:redux/redux.dart'; - -// Project imports: -import 'package:ribn/actions/login_actions.dart'; -import 'package:ribn/models/login_state.dart'; - -/// Reducer responsible for updating [LoginState] -final loginReducer = combineReducers( - [ - TypedReducer(_onLoginSuccess), - ], -); - -LoginState _onLoginSuccess(LoginState loginState, LoginSuccessAction action) { - return loginState.copyWith( - isLoggedIn: true, - lastLogin: DateTime.now().toUtc().toString(), - ); -} diff --git a/lib/reducers/onboarding_reducer.dart b/lib/reducers/onboarding_reducer.dart deleted file mode 100644 index ee7d87a5..00000000 --- a/lib/reducers/onboarding_reducer.dart +++ /dev/null @@ -1,41 +0,0 @@ -// Dart imports: -import 'dart:math'; - -// Package imports: -import 'package:redux/redux.dart'; - -// Project imports: -import 'package:ribn/actions/onboarding_actions.dart'; -import 'package:ribn/models/onboarding_state.dart'; - -/// Reducer responsible for updating [OnboardingState] -final onboardingReducer = combineReducers( - [ - TypedReducer(_onUserSelectedWord), - TypedReducer( - _onMnemonicGenerated, - ), - ], -); - -/// Updates the mnemonic in [AppState] -OnboardingState _onMnemonicGenerated( - OnboardingState onboardingState, - MnemonicSuccessfullyGeneratedAction action, -) { - return onboardingState.copyWith( - mnemonic: action.mnemonic, - shuffledMnemonic: List.from(action.mnemonic.split(' '))..shuffle(Random()), - userSelectedIndices: [], - ); -} - -OnboardingState _onUserSelectedWord( - OnboardingState onboardingState, - UserSelectedWordAction action, -) { - return onboardingState.copyWith( - userSelectedIndices: List.from(onboardingState.userSelectedIndices ?? []) - ..add(action.idx), - ); -} diff --git a/lib/reducers/user_details_reducer.dart b/lib/reducers/user_details_reducer.dart index b074c636..688ac451 100644 --- a/lib/reducers/user_details_reducer.dart +++ b/lib/reducers/user_details_reducer.dart @@ -11,9 +11,6 @@ final userDetailsReducer = combineReducers( TypedReducer( _updateAssetDetails, ), - TypedReducer( - _updateBiometricsAction, - ), ], ); @@ -23,8 +20,7 @@ UserDetailsState _updateAssetDetails( UserDetailsState userDetails, UpdateAssetDetailsAction action, ) { - final AssetDetails? currAssetDetails = - userDetails.assetDetails[action.assetCode]; + final AssetDetails? currAssetDetails = userDetails.assetDetails[action.assetCode]; return userDetails.copyWith( assetDetails: { ...userDetails.assetDetails, @@ -36,13 +32,3 @@ UserDetailsState _updateAssetDetails( }, ); } - -/// Handles [UpdateBiometricsAction] and updates [isBiometricsEnabled] that is stored locally -UserDetailsState _updateBiometricsAction( - UserDetailsState userDetails, - UpdateBiometricsAction action, -) { - return userDetails.copyWith( - isBiometricsEnabled: action.isBiometricsEnabled, - ); -} diff --git a/lib/redux.dart b/lib/redux.dart index a595732d..aee02739 100644 --- a/lib/redux.dart +++ b/lib/redux.dart @@ -21,13 +21,11 @@ import 'package:ribn/repositories/transaction_repository.dart'; class Redux { static Store? _store; - static const OnboardingRespository onboardingRespository = - OnboardingRespository(); + static const OnboardingRespository onboardingRepository = OnboardingRespository(); static const LoginRepository loginRepository = LoginRepository(); static const MiscRepository miscRepository = MiscRepository(); static const KeychainRepository keychainRepository = KeychainRepository(); - static const TransactionRepository transactionRepository = - TransactionRepository(); + static const TransactionRepository transactionRepository = TransactionRepository(); static Store? get store { if (_store == null) { @@ -40,7 +38,7 @@ class Redux { /// Fetches [AppState] from the extension's storage and initializes the Redux [_store] static Future initStore({ bool initTestStore = false, - OnboardingRespository onboardingRepo = onboardingRespository, + OnboardingRespository onboardingRepo = onboardingRepository, LoginRepository loginRepo = loginRepository, MiscRepository miscRepo = miscRepository, KeychainRepository keychainRepo = keychainRepository, @@ -51,7 +49,6 @@ class Redux { appReducer, middleware: createAppMiddleware( onboardingRepo: onboardingRepo, - loginRepo: loginRepo, miscRepo: miscRepo, keychainRepo: keychainRepo, transactionRepo: transactionRepo, @@ -63,10 +60,8 @@ class Redux { static Future> getPersistedAppState() async { try { - final String persistedAppState = - await PlatformLocalStorage.instance.getState(); - final Map mappedAppState = - jsonDecode(persistedAppState) as Map; + final String persistedAppState = await PlatformLocalStorage.instance.getState(); + final Map mappedAppState = jsonDecode(persistedAppState) as Map; return mappedAppState; } catch (e) { return {}; @@ -79,8 +74,7 @@ class Redux { try { final Map appState = await getPersistedAppState(); if (kIsWeb) { - final String? toplKey = - await PlatformLocalStorage.instance.getKeyFromSessionStorage(); + final String? toplKey = await PlatformLocalStorage.instance.getKeyFromSessionStorage(); appState['keychainState']['toplKey'] = toplKey; } return AppState.fromMap(appState); diff --git a/lib/repositories/keychain_repository.dart b/lib/repositories/keychain_repository.dart index 37545f1e..fb476fff 100644 --- a/lib/repositories/keychain_repository.dart +++ b/lib/repositories/keychain_repository.dart @@ -31,8 +31,7 @@ class KeychainRepository { change: change, address: addr, ); - final ToplAddress toplAddress = - hdWallet.toBaseAddress(spend: keyPair.publicKey!, networkId: networkId); + final ToplAddress toplAddress = hdWallet.toBaseAddress(spend: keyPair.publicKey!, networkId: networkId); final String keyPath = getKeyPath(purpose, coinType, account, change, addr); final RibnAddress newAddress = RibnAddress( toplAddress: toplAddress, @@ -54,19 +53,11 @@ class KeychainRepository { int address, ) { String keyPath = 'm/'; - keyPath += isHardened(purpose) - ? "${purpose - Rules.hardenedOffset}'/" - : '$purpose/'; - keyPath += isHardened(coinType) - ? "${coinType - Rules.hardenedOffset}'/" - : '$coinType/'; - keyPath += isHardened(account) - ? "${account - Rules.hardenedOffset}'/" - : '$account/'; - keyPath += - isHardened(change) ? "${change - Rules.hardenedOffset}'/" : '$change/'; - keyPath += - isHardened(address) ? "${address - Rules.hardenedOffset}'" : '$address'; + keyPath += isHardened(purpose) ? "${purpose - Rules.hardenedOffset}'/" : '$purpose/'; + keyPath += isHardened(coinType) ? "${coinType - Rules.hardenedOffset}'/" : '$coinType/'; + keyPath += isHardened(account) ? "${account - Rules.hardenedOffset}'/" : '$account/'; + keyPath += isHardened(change) ? "${change - Rules.hardenedOffset}'/" : '$change/'; + keyPath += isHardened(address) ? "${address - Rules.hardenedOffset}'" : '$address'; return keyPath; } diff --git a/lib/repositories/login_repository.dart b/lib/repositories/login_repository.dart index d12448a8..145902c0 100644 --- a/lib/repositories/login_repository.dart +++ b/lib/repositories/login_repository.dart @@ -15,10 +15,8 @@ class LoginRepository { /// [params] must have a `keyStoreJson` and `password`. Uint8List decryptKeyStore(Map params) { const Base58Encoder base58Encoder = Base58Encoder.instance; - final KeyStore keyStore = - KeyStore.fromV1Json(params['keyStoreJson'], params['password']); - final Uint8List toplExtendedPrvKeyUint8List = - base58Encoder.decode(keyStore.privateKey); + final KeyStore keyStore = KeyStore.fromV1Json(params['keyStoreJson'], params['password']); + final Uint8List toplExtendedPrvKeyUint8List = base58Encoder.decode(keyStore.privateKey); return toplExtendedPrvKeyUint8List; } } diff --git a/lib/repositories/onboarding_repository.dart b/lib/repositories/onboarding_repository.dart index 8fb7ab29..99db29ae 100644 --- a/lib/repositories/onboarding_repository.dart +++ b/lib/repositories/onboarding_repository.dart @@ -24,10 +24,8 @@ class OnboardingRespository { const Base58Encoder base58Encoder = Base58Encoder.instance; final String mnemonic = generateMnemonic(random); final Bip32KeyPair toplExtendedKeyPair = deriveToplExtendedKeys(mnemonic); - final Uint8List toplExtendedPrvKeyUint8List = - Uint8List.fromList(toplExtendedKeyPair.privateKey!); - final String base58EncodedToplExtendedPrvKey = - base58Encoder.encode(toplExtendedPrvKeyUint8List); + final Uint8List toplExtendedPrvKeyUint8List = Uint8List.fromList(toplExtendedKeyPair.privateKey!); + final String base58EncodedToplExtendedPrvKey = base58Encoder.encode(toplExtendedPrvKeyUint8List); final KeyStore keyStore = KeyStore.createNew( base58EncodedToplExtendedPrvKey, password, @@ -52,18 +50,16 @@ class OnboardingRespository { Map generateKeyStore(Map params) { const Base58Encoder base58Encoder = Base58Encoder.instance; final Random random = Random.secure(); - final Bip32KeyPair toplExtendedKeyPair = - deriveToplExtendedKeys(params['mnemonic']); - final Uint8List toplExtendedPrvKeyUint8List = - Uint8List.fromList(toplExtendedKeyPair.privateKey!); - final String base58EncodedToplExtendedPrvKey = - base58Encoder.encode(toplExtendedPrvKeyUint8List); + final Bip32KeyPair toplExtendedKeyPair = deriveToplExtendedKeys(params['mnemonic']); + final Uint8List toplExtendedPrvKeyUint8List = Uint8List.fromList(toplExtendedKeyPair.privateKey!); + final String base58EncodedToplExtendedPrvKey = base58Encoder.encode(toplExtendedPrvKeyUint8List); final KeyStore keyStore = KeyStore.createNew( base58EncodedToplExtendedPrvKey, params['password'], random, scryptN: Rules.scryptN, ); + final String keyStoreJson = keyStore.toJson(); return { 'keyStoreJson': keyStoreJson, diff --git a/lib/repositories/transaction_repository.dart b/lib/repositories/transaction_repository.dart index c1a4c4e2..e585af47 100644 --- a/lib/repositories/transaction_repository.dart +++ b/lib/repositories/transaction_repository.dart @@ -24,10 +24,8 @@ class TransactionRepository { switch (transferDetails.transferType) { case TransferType.polyTransfer: { - final List senders = - transferDetails.senders.map((e) => e.toplAddress).toList(); - final ToplAddress recipient = - ToplAddress.fromBase58(transferDetails.recipient); + final List senders = transferDetails.senders.map((e) => e.toplAddress).toList(); + final ToplAddress recipient = ToplAddress.fromBase58(transferDetails.recipient); final PolyTransaction polyTransaction = PolyTransaction( recipients: [ SimpleRecipient( @@ -48,10 +46,8 @@ class TransactionRepository { } case TransferType.assetTransfer: { - final List senders = - transferDetails.senders.map((e) => e.toplAddress).toList(); - final ToplAddress recipient = - ToplAddress.fromBase58(transferDetails.recipient); + final List senders = transferDetails.senders.map((e) => e.toplAddress).toList(); + final ToplAddress recipient = ToplAddress.fromBase58(transferDetails.recipient); final AssetValue assetValue = AssetValue( transferDetails.amount, transferDetails.assetCode!, @@ -79,8 +75,7 @@ class TransactionRepository { case (TransferType.remintingAsset): { final ToplAddress issuer = transferDetails.assetCode!.issuer; - final ToplAddress recipient = - ToplAddress.fromBase58(transferDetails.recipient); + final ToplAddress recipient = ToplAddress.fromBase58(transferDetails.recipient); final AssetValue assetValue = AssetValue( transferDetails.amount, transferDetails.assetCode!, diff --git a/lib/router/root_router.dart b/lib/router/root_router.dart index b90ec054..dd940f08 100644 --- a/lib/router/root_router.dart +++ b/lib/router/root_router.dart @@ -4,6 +4,10 @@ import 'dart:convert'; // Flutter imports: import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; + +// Package imports: +import 'package:ribn_toolkit/models/transactions/ribn_activity_details_model.dart'; + // Project imports: import 'package:ribn/constants/routes.dart'; import 'package:ribn/models/internal_message.dart'; @@ -33,6 +37,7 @@ import 'package:ribn/presentation/onboarding/restore_wallet/create_new_wallet_pa import 'package:ribn/presentation/onboarding/restore_wallet/enter_wallet_password_page.dart'; import 'package:ribn/presentation/onboarding/restore_wallet/restore_wallet_page.dart'; import 'package:ribn/presentation/onboarding/restore_wallet/restore_with_topl_key_page.dart'; +import 'package:ribn/presentation/onboarding/widgets/opt_in_tracker_page.dart'; import 'package:ribn/presentation/settings/settings_page.dart'; import 'package:ribn/presentation/transaction_history/transaction_history_details_page/transaction_history_details_page.dart'; import 'package:ribn/presentation/transaction_history/transaction_history_page.dart'; @@ -40,8 +45,8 @@ import 'package:ribn/presentation/transfers/asset_transfer_page.dart'; import 'package:ribn/presentation/transfers/mint_input_page.dart'; import 'package:ribn/presentation/transfers/tx_confirmation_page.dart'; import 'package:ribn/presentation/transfers/tx_review_page.dart'; -// Package imports: -import 'package:ribn_toolkit/models/transactions/ribn_activity_details_model.dart'; + +// import 'package:ribn/models/transaction_history_entry.dart'; // import 'package:ribn/models/transaction_history_entry.dart'; @@ -57,6 +62,13 @@ class RootRouter { } return pageRoute(const WelcomePage(), settings); } + case Routes.optIn: + { + if (kIsWeb) { + return pageRouteNotAnimated(const OptInTracker(), settings); + } + return pageRoute(const OptInTracker(), settings); + } case Routes.selectAction: { if (kIsWeb) { @@ -75,12 +87,12 @@ class RootRouter { { if (kIsWeb) { return pageRouteNotAnimated( - const SeedPhraseInfoChecklistPage(), + SeedPhraseInfoChecklistPage(), settings, ); } return pageRoute( - const SeedPhraseInfoChecklistPage(), + SeedPhraseInfoChecklistPage(), settings, ); } @@ -118,11 +130,11 @@ class RootRouter { { if (kIsWeb) { return pageRouteNotAnimated( - const SeedPhraseConfirmationPage(), + SeedPhraseConfirmationPage(), settings, ); } - return pageRoute(const SeedPhraseConfirmationPage(), settings); + return pageRoute(SeedPhraseConfirmationPage(), settings); } case Routes.walletInfoChecklist: { @@ -137,9 +149,9 @@ class RootRouter { case Routes.createPassword: { if (kIsWeb) { - return pageRouteNotAnimated(const CreatePasswordPage(), settings); + return pageRouteNotAnimated(CreatePasswordPage(), settings); } - return pageRoute(const CreatePasswordPage(), settings); + return pageRoute(CreatePasswordPage(), settings); } case Routes.extensionInfo: { @@ -232,8 +244,7 @@ class RootRouter { } case Routes.txReview: { - final TransferDetails transferDetails = - settings.arguments as TransferDetails; + final TransferDetails transferDetails = settings.arguments as TransferDetails; if (kIsWeb) { return pageRouteNotAnimated( @@ -248,8 +259,7 @@ class RootRouter { } case Routes.txConfirmation: { - final TransferDetails transferDetails = - settings.arguments as TransferDetails; + final TransferDetails transferDetails = settings.arguments as TransferDetails; if (kIsWeb) { return pageRouteNotAnimated( TxConfirmationPage(transferDetails: transferDetails), @@ -273,8 +283,7 @@ class RootRouter { } case Routes.txHistoryDetails: final Map transactionDetailsMap = settings.arguments as Map; - final RibnActivityDetailsModel transactionDetails = - RibnActivityDetailsModel.fromJson( + final RibnActivityDetailsModel transactionDetails = RibnActivityDetailsModel.fromJson( jsonEncode(transactionDetailsMap), ); { @@ -285,8 +294,7 @@ class RootRouter { } case Routes.assetDetails: { - final Map assetDetailsPageArgs = - settings.arguments as Map; + final Map assetDetailsPageArgs = settings.arguments as Map; if (kIsWeb) { return pageRouteNotAnimated( AssetDetailsPage(asset: assetDetailsPageArgs['assetAmount']!), @@ -312,8 +320,7 @@ class RootRouter { } case Routes.enable: { - final InternalMessage pendingRequest = - settings.arguments as InternalMessage; + final InternalMessage pendingRequest = settings.arguments as InternalMessage; if (kIsWeb) { return pageRouteNotAnimated(EnablePage(pendingRequest), settings); } @@ -321,8 +328,7 @@ class RootRouter { } case Routes.externalSigning: { - final InternalMessage pendingRequest = - settings.arguments as InternalMessage; + final InternalMessage pendingRequest = settings.arguments as InternalMessage; if (kIsWeb) { return pageRouteNotAnimated( ExternalSigningPage(pendingRequest), @@ -333,20 +339,17 @@ class RootRouter { } case Routes.error: { - final String errorMessage = - (settings.arguments ?? 'Unknown error occurred') as String; + final String errorMessage = (settings.arguments ?? 'Unknown error occurred') as String; return errorRoute(errorMsg: errorMessage); } case Routes.connectDApp: { - final InternalMessage pendingRequest = - settings.arguments as InternalMessage; + final InternalMessage pendingRequest = settings.arguments as InternalMessage; return pageRouteNotAnimated(ConnectDApp(pendingRequest), settings); } case Routes.reviewAndSignDApp: { - final InternalMessage pendingRequest = - settings.arguments as InternalMessage; + final InternalMessage pendingRequest = settings.arguments as InternalMessage; if (kIsWeb) { return pageRouteNotAnimated( ReviewAndSignDApp(pendingRequest), @@ -357,8 +360,7 @@ class RootRouter { } case Routes.loadingDApp: { - final InternalMessage response = - settings.arguments as InternalMessage; + final InternalMessage response = settings.arguments as InternalMessage; return pageRouteNotAnimated( LoadingDApp(response: response), settings, diff --git a/lib/utils/error_handling_utils.dart b/lib/utils/error_handling_utils.dart new file mode 100644 index 00000000..59d5e629 --- /dev/null +++ b/lib/utils/error_handling_utils.dart @@ -0,0 +1,37 @@ +// Flutter imports: +import 'package:flutter/foundation.dart'; + +// Package imports: +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:url_launcher/url_launcher_string.dart'; + +// Project imports: +import 'package:ribn/constants/routes.dart'; +import 'package:ribn/constants/strings.dart'; +import 'package:ribn/providers/logger_provider.dart'; +import 'package:ribn/utils/navigation_utils.dart'; + +/// This will handle an error and navigate to an error page +Future handleApiError({ + required String errorMessage, +}) async { + final ProviderContainer container = ProviderContainer(); + + container.read(loggerProvider).log( + logLevel: LogLevel.Severe, + loggerClass: LoggerClass.ApiError, + message: errorMessage, + ); + + await navigateToRoute( + route: Routes.error, + arguments: errorMessage, + ); +} + +Future handleContactSupport() async { + kIsWeb + //Go to google docs link + ? await launchUrlString(Strings.supportDocsURL) + : await launchUrlString(Strings.supportEmailLink); +} diff --git a/lib/utils/extensions.dart b/lib/utils/extensions.dart new file mode 100644 index 00000000..6bcf55ee --- /dev/null +++ b/lib/utils/extensions.dart @@ -0,0 +1,105 @@ +// Dart imports: +import 'dart:convert'; +import 'dart:typed_data'; + +// Flutter imports: +import 'package:flutter/cupertino.dart'; + +// Package imports: +import 'package:crypto/crypto.dart'; + +extension StringExtensions on String { + bool toBoolean() { + return (this.toLowerCase() == "true" || this.toLowerCase() == "1") + ? true + : (this.toLowerCase() == "false" || this.toLowerCase() == "0" + ? false + : throw UnsupportedError("Cannot convert $this [${this.runtimeType}] to boolean")); + } + + /// Formats an address string to only dispaly its first and last 10 characters. + String formatAddressString({int charsToDisplay = 10}) { + const numDots = 3; + final String dotsString = List.filled(numDots, '.').join(); + final String leftSubstring = this.substring(0, charsToDisplay); + final String rightSubstring = this.substring(this.length - charsToDisplay); + return '$leftSubstring$dotsString$rightSubstring'; + } + + String capitalize() => this[0].toUpperCase() + this.substring(1); + + // TODO: Evaluate lifting this functionality to BramblDart to remove direct dependencies on crypto in Ribn + /// Returns a Hashed representation of the [String] object. + String toHashSha256() { + var bytes = utf8.encode(this); // Convert the string to UTF8-encoded bytes + var digest = sha256.convert(bytes); // Hash the bytes using SHA-256 + return digest.toString(); // Return the hexadecimal representation of the hash + } +} + +extension NullableStringExtension on String? { + bool toBooleanWithNullableDefault(bool defaultValue) { + // define local variable to be eligible for type promotion + final String? val = this; + + // if not null [val] is promoted to String + if (val == null || val.isEmpty || val == "") { + return defaultValue; + } + + return val.toBoolean(); + } + + /// Formats [unit] to only display the first part of the string. + String formatAssetUnit() { + return this?.split(' ').first ?? 'Select Unit'; + } +} + +extension ContextExtensions on BuildContext { + double get clientWidth => MediaQuery.of(this).size.width; + + double get clientHeight => MediaQuery.of(this).size.height; +} + +extension IterableWidgetExtension on Iterable { + /** + * Returns a new lazy [Iterable] with [element] inserted between each element of this [Iterable]. + * uses Generator language feature [https://dart.dev/guides/language/language-tour#generators] + */ + Iterable separator({required Widget element}) sync* { + final iterator = this.iterator; + if (iterator.moveNext()) { + yield iterator.current; + while (iterator.moveNext()) { + yield element; + yield iterator.current; + } + } + } +} + +extension Unique on List { + List unique([Id Function(E element)? id, bool inplace = true]) { + final ids = {}; + final list = inplace ? this : List.from(this); + list.retainWhere((x) => ids.add(id != null ? id(x) : x as Id)); + return list; + } +} + +extension dynamicExtensions on dynamic { + Uint8List toUint8List() { + return Uint8List.fromList((this as List).cast()); + } +} + +extension MapExtensions on Map { + /** + * Returns a new [Map] with [toAdd] added if [condition] is true. + */ + Map addIf(bool condition, Map toAdd) { + if (!condition) return this; + return {...this, ...toAdd}; + } +} diff --git a/lib/utils/input_utils.dart b/lib/utils/input_utils.dart new file mode 100644 index 00000000..29cca8bc --- /dev/null +++ b/lib/utils/input_utils.dart @@ -0,0 +1,8 @@ +// Flutter imports: +import 'package:flutter/widgets.dart'; + +/// Dismisses the keyboard +void dismissKeyboard(BuildContext context) { + FocusScopeNode currentFocus = FocusScope.of(context); + if (!currentFocus.hasPrimaryFocus) currentFocus.unfocus(); +} diff --git a/lib/utils/navigation_utils.dart b/lib/utils/navigation_utils.dart new file mode 100644 index 00000000..5a0e524f --- /dev/null +++ b/lib/utils/navigation_utils.dart @@ -0,0 +1,12 @@ +// Project imports: +import 'package:ribn/constants/keys.dart'; + +Future navigateToRoute({ + required String route, + Object? arguments, +}) async { + await Keys.navigatorKey.currentState?.pushNamed( + route, + arguments: arguments, + ); +} diff --git a/lib/utils/platform_utils.dart b/lib/utils/platform_utils.dart new file mode 100644 index 00000000..a3372915 --- /dev/null +++ b/lib/utils/platform_utils.dart @@ -0,0 +1,26 @@ +// Dart imports: +import 'dart:io' show Platform; + +// Flutter imports: +import 'package:flutter/foundation.dart'; + +String getOperatingSystem() { + if (kIsWeb) return "Web"; + + switch (Platform.operatingSystem) { + case "android": + return "Android"; + case "ios": + return "iOS"; + case "macos": + return "MacOS"; + case "windows": + return "Windows"; + case "linux": + return "Linux"; + case "fuchsia": + return "Fuchsia"; + default: + return "Unknown"; + } +} diff --git a/lib/utils/transaction_utils.dart b/lib/utils/transaction_utils.dart index 8aa1e43d..17db1104 100644 --- a/lib/utils/transaction_utils.dart +++ b/lib/utils/transaction_utils.dart @@ -1,4 +1,8 @@ +// Package imports: import 'package:brambldart/brambldart.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; + +// Project imports: import 'package:ribn/providers/logger_provider.dart'; /// This filters out Change UTxOs @@ -11,17 +15,27 @@ List filterOutChangeUTxO(List txs) { // Get the senders address final Sender? transactionSenderAddress = tx.from?[0]; + final ProviderContainer container = ProviderContainer(); + // If there is no sender, filter out and log issue if (transactionSenderAddress == null) { - transactionLogger().severe('Transaction does not have a sender'); + container.read(loggerProvider).log( + logLevel: LogLevel.Severe, + loggerClass: LoggerClass.Transaction, + message: 'Transaction does not have a sender', + ); return false; } - // Get teh recievers address + // Get the receivers address final String? transactionReceiverAddress = tx.to.first?.toJson()?[0].toString(); // If there is no receiver, filter out and log issue if (transactionReceiverAddress == null) { - transactionLogger().severe('Transaction does not have a receiver'); + container.read(loggerProvider).log( + logLevel: LogLevel.Severe, + loggerClass: LoggerClass.Transaction, + message: 'Transaction does not have a receiver', + ); return false; } diff --git a/lib/utils/url_utils.dart b/lib/utils/url_utils.dart new file mode 100644 index 00000000..c59773fb --- /dev/null +++ b/lib/utils/url_utils.dart @@ -0,0 +1,14 @@ +// Package imports: +import 'package:hooks_riverpod/hooks_riverpod.dart'; + +// Project imports: +import 'package:ribn/constants/strings.dart'; +import 'package:ribn/providers/packages/url_launcher_provider.dart'; + +Future launchPrivacyPolicyUrl(WidgetRef ref) async { + await ref.read(urlLauncherProvider)(Uri.parse(Strings.privacyPolicyUrl)); +} + +Future launchTermsOfUse(WidgetRef ref) async { + await ref.read(urlLauncherProvider)(Uri.parse(Strings.termsOfUseUrl)); +} diff --git a/lib/utils.dart b/lib/utils/utils.dart similarity index 59% rename from lib/utils.dart rename to lib/utils/utils.dart index 1ab37cbb..39d61884 100644 --- a/lib/utils.dart +++ b/lib/utils/utils.dart @@ -9,14 +9,12 @@ import 'package:flutter/material.dart'; import 'package:barcode_widget/barcode_widget.dart'; import 'package:brambldart/utils.dart'; import 'package:flutter_redux/flutter_redux.dart'; -import 'package:local_auth/local_auth.dart'; import 'package:ribn_toolkit/constants/colors.dart'; import 'package:ribn_toolkit/constants/styles.dart'; import 'package:ribn_toolkit/widgets/atoms/custom_copy_button.dart'; import 'package:ribn_toolkit/widgets/molecules/custom_modal.dart'; // Project imports: -import 'package:ribn/actions/misc_actions.dart'; import 'package:ribn/constants/assets.dart'; import 'package:ribn/constants/keys.dart'; import 'package:ribn/constants/rules.dart'; @@ -24,24 +22,9 @@ import 'package:ribn/constants/strings.dart'; import 'package:ribn/models/app_state.dart'; import 'package:ribn/models/ribn_address.dart'; import 'package:ribn/platform/platform.dart'; +import 'package:ribn/utils/extensions.dart'; import 'package:ribn/widgets/custom_divider.dart'; -/// Formats an address string to only dispaly its first and last 10 characters. -String formatAddrString(String addr, {int charsToDisplay = 10}) { - const numDots = 3; - final String dotsString = List.filled(numDots, '.').join(); - final String leftSubstring = addr.substring(0, charsToDisplay); - final String rightSubstring = addr.substring(addr.length - charsToDisplay); - return '$leftSubstring$dotsString$rightSubstring'; -} - -String capitalize(String s) => s[0].toUpperCase() + s.substring(1); - -/// Formats [unit] to only display the first part of the string. -String formatAssetUnit(String? unit) { - return unit?.split(' ').first ?? 'Select Unit'; -} - /// Validates the [address] passed in by the user. /// /// Based on the current network, i.e. [networkId], and the [address], [validateAddressByNetwork] validates the address, @@ -60,57 +43,11 @@ void validateRecipientAddress({ handleResult(result['success']); } -Future isBiometricsAuthenticationSupported( - LocalAuthentication auth, -) async { - final bool canCheckBiometrics = await auth.canCheckBiometrics; - final bool isDeviceSupported = await auth.isDeviceSupported(); - - return canCheckBiometrics && isDeviceSupported; -} - -Future isBiometricsAuthenticationEnrolled( - LocalAuthentication auth, -) async { - final bool canCheckBiometrics = await auth.canCheckBiometrics; - final bool isDeviceSupported = await auth.isDeviceSupported(); - final List enrolledBiometrics = await auth.getAvailableBiometrics(); - - return canCheckBiometrics && - isDeviceSupported && - enrolledBiometrics.isNotEmpty; -} - -Future authenticateWithBiometrics(LocalAuthentication auth) async { - return await auth.authenticate( - localizedReason: 'To authenticate with biometrics', - options: const AuthenticationOptions( - stickyAuth: true, - biometricOnly: true, - sensitiveTransaction: true, - useErrorDialogs: true, - ), - ); -} - -Future isBiometricsTypeFingerprint(LocalAuthentication auth) async { - final List enrolledBiometrics = await auth.getAvailableBiometrics(); - - return enrolledBiometrics.contains(BiometricType.fingerprint) && - enrolledBiometrics.isNotEmpty; -} - -void navigateToRoute(BuildContext context, String route) { - StoreProvider.of(context).dispatch(NavigateToRoute(route)); -} - /// Adapt to screen height based on [scaleFactor]. -double adaptHeight(double scaleFactor) => - MediaQueryData.fromWindow(window).size.height * scaleFactor; +double adaptHeight(double scaleFactor) => MediaQueryData.fromWindow(window).size.height * scaleFactor; /// Adapt to screen width based on [scaleFactor]. -double adaptWidth(double scaleFactor) => - MediaQueryData.fromWindow(window).size.width * scaleFactor; +double adaptWidth(double scaleFactor) => MediaQueryData.fromWindow(window).size.width * scaleFactor; double deviceTopPadding() => MediaQueryData.fromWindow(window).padding.top; @@ -122,17 +59,12 @@ Future isAppOpenedInDebugView() async { return await PlatformUtils.instance.getCurrentAppView() == AppViews.webDebug; } -Uint8List uint8ListFromDynamic(dynamic list) { - return Uint8List.fromList((list as List).cast()); -} - Future showReceivingAddress() async { await showDialog( context: Keys.navigatorKey.currentContext!, builder: (context) { return StoreConnector( - converter: (store) => - store.state.keychainState.currentNetwork.addresses.first, + converter: (store) => store.state.keychainState.currentNetwork.addresses.first, builder: (context, ribnAddress) { return CustomModal.renderCustomModal( context: Keys.navigatorKey.currentContext!, @@ -154,7 +86,7 @@ Future showReceivingAddress() async { ), const SizedBox(height: 16), Text( - formatAddrString(ribnAddress.toplAddress.toBase58()), + ribnAddress.toplAddress.toBase58().formatAddressString(), style: const TextStyle( fontFamily: 'DM Sans', fontWeight: FontWeight.w400, @@ -200,14 +132,9 @@ Future showReceivingAddress() async { final emptyStateBody = RichText( text: TextSpan( - style: RibnToolkitTextStyles.h4 - .copyWith(fontSize: kIsWeb ? 12 : 14, color: RibnColors.defaultText), + style: RibnToolkitTextStyles.h4.copyWith(fontSize: kIsWeb ? 12 : 14, color: RibnColors.defaultText), children: [ - TextSpan( - text: Strings.emptyStateBody.substring(0, 30), - style: const TextStyle(fontWeight: FontWeight.w500), - ), - TextSpan(text: Strings.emptyStateBody.substring(31, 111)), + TextSpan(text: Strings.emptyStateBody), ], ), ); diff --git a/lib/widgets/address_display_container.dart b/lib/widgets/address_display_container.dart index 45a63edc..de98be40 100644 --- a/lib/widgets/address_display_container.dart +++ b/lib/widgets/address_display_container.dart @@ -23,16 +23,14 @@ class AddressDisplayContainer extends StatefulWidget { final double width; @override - State createState() => - _AddressDisplayContainerState(); + State createState() => _AddressDisplayContainerState(); } class _AddressDisplayContainerState extends State { @override Widget build(BuildContext context) { return StoreConnector( - converter: (store) => - store.state.keychainState.currentNetwork.addresses.first, + converter: (store) => store.state.keychainState.currentNetwork.addresses.first, builder: (context, ribnAddress) => RoundedCopyTextField( text: widget.text, icon: SvgPicture.asset(widget.icon), diff --git a/lib/widgets/fee_info.dart b/lib/widgets/fee_info.dart index 9a418039..ff292fa1 100644 --- a/lib/widgets/fee_info.dart +++ b/lib/widgets/fee_info.dart @@ -2,19 +2,32 @@ import 'package:flutter/material.dart'; // Package imports: +import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:ribn_toolkit/constants/colors.dart'; import 'package:ribn_toolkit/constants/styles.dart'; // Project imports: +import 'package:ribn/constants/network_utils.dart'; import 'package:ribn/constants/strings.dart'; /// A widget that displays the fee info during the transfer flows in Ribn. -class FeeInfo extends StatelessWidget { - const FeeInfo({required this.fee, Key? key}) : super(key: key); +class FeeInfo extends HookWidget { + final String currentNetworkName; + const FeeInfo({ + required this.fee, + required this.currentNetworkName, + Key? key, + }) : super(key: key); final num fee; @override Widget build(BuildContext context) { + final bool isValhalla = currentNetworkName == NetworkUtils.valhalla; + final bool isMainnet = currentNetworkName == NetworkUtils.toplNet; + + final feeState = useState(isMainnet ? fee ~/ 1000000000 : fee); + final unitState = useState(isValhalla ? 'nanoPOLY' : 'POLY'); + return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ @@ -25,26 +38,28 @@ class FeeInfo extends StatelessWidget { const SizedBox( height: 5, ), - Row(children: [ - Text( - '$fee POLY', - style: const TextStyle( - fontFamily: 'DM Sans', - fontSize: 11, - color: RibnColors.primary, - fontWeight: FontWeight.w600, + Row( + children: [ + Text( + '${feeState.value} ${unitState.value}', + style: const TextStyle( + fontFamily: 'DM Sans', + fontSize: 11, + color: RibnColors.primary, + fontWeight: FontWeight.w600, + ), ), - ), - // Spacer(), - // Text('${convertPolyToUsd(fee)} USD', - // style: const TextStyle( - // fontFamily: 'DM Sans', - // fontSize: 11, - // color: RibnColors.greyText, - // fontWeight: FontWeight.w600, - // ), - // ), - ],) + // Spacer(), + // Text('${convertPolyToUsd(fee)} USD', + // style: const TextStyle( + // fontFamily: 'DM Sans', + // fontSize: 11, + // color: RibnColors.greyText, + // fontWeight: FontWeight.w600, + // ), + // ), + ], + ) ], ); } diff --git a/lib/widgets/ribn_app_bar_wapper.dart b/lib/widgets/ribn_app_bar_wapper.dart index cdab31e5..6c9f8597 100644 --- a/lib/widgets/ribn_app_bar_wapper.dart +++ b/lib/widgets/ribn_app_bar_wapper.dart @@ -2,11 +2,13 @@ import 'package:flutter/material.dart'; // Package imports: +import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:ribn_toolkit/widgets/organisms/ribn_app_bar.dart'; // Project imports: import 'package:ribn/constants/assets.dart'; import 'package:ribn/containers/ribn_app_bar_container.dart'; +import 'package:ribn/providers/app_bar_provider.dart'; /// Builds a wrapper around the AppBar from ToplToolkit to provide ViewModel & AppBarContainer class RibnAppBarWrapper extends StatefulWidget implements PreferredSizeWidget { @@ -25,17 +27,25 @@ class RibnAppBarWrapper extends StatefulWidget implements PreferredSizeWidget { class _RibnAppBarWrapperState extends State { @override Widget build(BuildContext context) { - return RibnAppBarContainer( - builder: (BuildContext context, RibnAppBarViewModel vm) => RibnAppBar( - currentNetworkName: vm.currentNetworkName, - networks: vm.networks, - updateNetwork: vm.updateNetwork, - settingsOptions: vm.settingsOptions, - selectSettingsOption: vm.selectSettingsOption, - chevronIconLink: RibnAssets.chevronDown, - ribnLogoIconLink: RibnAssets.newRibnLogo, - hamburgerIconLink: RibnAssets.hamburgerMenu, - ), - ); + return Consumer(builder: (context, ref, child) { + return RibnAppBarContainer( + builder: (BuildContext context, RibnAppBarViewModel vm) => RibnAppBar( + currentNetworkName: vm.currentNetworkName, + networks: vm.networks, + updateNetwork: vm.updateNetwork, + settingsOptions: vm.settingsOptions, + selectSettingsOption: vm.selectSettingsOption, + chevronIconLink: RibnAssets.chevronDown, + ribnLogoIconLink: RibnAssets.newRibnLogo, + hamburgerIconLink: RibnAssets.hamburgerMenu, + onSelectChainDropdownOpen: () { + final overlayState = ref.read(appBarToolTipOverlayEntryProvider); + if (overlayState != null && overlayState.mounted) { + overlayState.remove(); + } + }, + ), + ); + }); } } diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift new file mode 100644 index 00000000..b3dd8ae0 --- /dev/null +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -0,0 +1,20 @@ +// +// Generated file. Do not edit. +// + +import FlutterMacOS +import Foundation + +import firebase_analytics +import firebase_core +import flutter_secure_storage_macos +import path_provider_macos +import url_launcher_macos + +func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { + FLTFirebaseAnalyticsPlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseAnalyticsPlugin")) + FLTFirebaseCorePlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseCorePlugin")) + FlutterSecureStoragePlugin.register(with: registry.registrar(forPlugin: "FlutterSecureStoragePlugin")) + PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) + UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin")) +} diff --git a/pubspec.yaml b/pubspec.yaml index 4eb27113..b26f2388 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -15,10 +15,10 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev # 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: 0.5.0 +version: 1.0.0+6 environment: - sdk: ">=2.12.0 <3.0.0" + sdk: ">=2.17.0 <3.0.0" # Dependencies specify other packages that your package needs in order to work. # To automatically upgrade your package dependencies to the latest versions @@ -30,65 +30,74 @@ dependencies: flutter: sdk: flutter - # The following adds the Cupertino Icons font to your application. - # Use with the CupertinoIcons class for iOS style icons. - cupertino_icons: ^1.0.5 - mockito: ^5.3.2 - built_value: ^8.4.2 + #state flutter_redux: ^0.10.0 redux: ^5.0.0 redux_epics: ^0.15.0 - rxdart: ^0.27.7 - step_progress_indicator: ^1.0.1 - steps_indicator: ^1.3.0 - bip_topl: ^0.0.2 - google_fonts: ^3.0.1 + hooks_riverpod: ^2.1.3 + flutter_hooks: ^0.18.5+1 + + # UI flutter_svg: ^1.0.3 - dotted_border: ^2.0.0+1 - accordion: ^2.1.1 - progress_indicators: ^1.0.0 url_launcher: ^6.0.12 barcode_widget: ^2.0.1 - flutter_portal: ^0.4.0 + flutter_keyboard_visibility: ^5.3.0 + loader_overlay: ^2.0.7 + flutter_native_splash: #^2.2.3+1 + + # Code generation + grpc: ^3.0.2 + freezed_annotation: ^2.2.0 + json_annotation: ^4.7.0 + + # Firebase + firebase_core: ^2.9.0 + firebase_analytics: ^10.1.6 + + + #Utilities + logging: ^1.1.1 + intl: ^0.18.0 + local_auth: ^2.0.0 file_picker: ^4.3.3 - import_sorter: ^4.6.0 + path_provider: ^2.0.9 + flutter_secure_storage: ^7.0.1 + app_settings: ^4.1.8 + + # Topl + bip_topl: ^0.0.2 ribn_toolkit: git: url: https://github.com/Topl/ribn-toolkit - ref: main + ref: 8121ad9 # Hash of 1.0 tag brambldart: git: url: https://github.com/Topl/BramblDart - ref: TSDK-133 - # Remove the ref once Selby's branch above has been merged into main - shimmer_animation: ^2.1.0+1 - grpc: ^3.0.2 - path_provider: ^2.0.9 - flutter_secure_storage: ^7.0.1 - local_auth: ^2.0.0 - url_strategy: ^0.2.0 - flutter_native_splash: #^2.2.3+1 - app_settings: ^4.1.8 - loader_overlay: ^2.0.7 - flutter_keyboard_visibility: ^5.3.0 - intl: ^0.17.0 - lazy_load_scrollview: ^1.3.0 - get_it: ^7.2.0 - loading_overlay: ^0.3.0 - logging: ^1.1.1 - hooks_riverpod: ^2.1.3 - freezed_annotation: ^2.2.0 - json_annotation: ^4.7.0 - + ref: 1f73931 # Hash of 1.0 tag + + dev_dependencies: flutter_test: sdk: flutter + + # Code generation build_runner: ^2.1.1 - built_value_generator: ^8.1.2 - flutter_launcher_icons: ^0.11.0 freezed: ^2.0.3+1 json_serializable: ^6.1.4 + # Testing + mockito: ^5.3.2 + + # Utilities + flutter_launcher_icons: ^0.11.0 + import_sorter: ^4.6.0 + dependency_validator: ^3.2.2 + + + # custom_lint: ^0.2.5 + # riverpod_lint: ^1.0.1 + + # The "flutter_lints" package below contains a set of recommended lints to # encourage good coding practices. The lint set provided by the package is # activated in the `analysis_options.yaml` file located at the root of your diff --git a/test/constants/onboarding_constants.dart b/test/constants/onboarding_constants.dart new file mode 100644 index 00000000..2bd03267 --- /dev/null +++ b/test/constants/onboarding_constants.dart @@ -0,0 +1 @@ +const String testPassword = 'Topl1234'; diff --git a/test/essential_test_provider_widget.dart b/test/essential_test_provider_widget.dart new file mode 100644 index 00000000..48e2c457 --- /dev/null +++ b/test/essential_test_provider_widget.dart @@ -0,0 +1,113 @@ +// Dart imports: +import 'dart:convert'; + +// Flutter imports: +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; + +// Package imports: +import 'package:flutter_test/flutter_test.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; + +// Project imports: +import 'package:ribn/main.dart'; +import 'package:ribn/providers/packages/local_authentication_provider.dart'; +import 'package:ribn/providers/store_provider.dart'; +import 'mocks/local_authentication_mocks.dart'; +import 'mocks/store_mocks.dart'; + +class TestAssetBundle extends CachingAssetBundle { + @override + Future loadString(String key, {bool cache = true}) async { + final ByteData data = await load(key); + return utf8.decode(data.buffer.asUint8List()); + } + + @override + Future load(String key) async => rootBundle.load(key); +} + +Future main({ + List overrides = const [], +}) async { + runApp(DefaultAssetBundle( + bundle: TestAssetBundle(), + child: await essentialTestProviderWidget(overrides: overrides), + )); +} + +/// The entire application, wrapped in a [ProviderScope]. +/// This function exposts a named parameter called [overrides] +/// which is fed forward to the [ProviderScope]. +Future essentialTestProviderWidget({ + List overrides = const [], + MockStore? mockStore, +}) async { + if (mockStore == null) mockStore = getStoreMocks(); + overrides = [ + localAuthenticationProvider.overrideWithValue(() => getMockLocalAuthentication()), + storeProvider.overrideWith((ref) => mockStore!), + ...overrides, + ]; + WidgetsFlutterBinding.ensureInitialized(); + TestWidgetsFlutterBinding.ensureInitialized(); + + return ProviderScope( + overrides: overrides, + child: MaterialApp( + debugShowCheckedModeBanner: false, + home: DefaultAssetBundle( + bundle: TestAssetBundle(), + child: RibnApp(mockStore), + ), + ), + ); +} + +/// This will call [tester.pump] for a duration and loops. Useful for when [pumpAndSettle] is timing out +/// +/// Optional Parameters [loops] and [duration can be supplied] +/// +/// [loops] is defaulted to 5 +/// +/// [duration] is defaulted to 0 and is in seconds +Future pumpTester(WidgetTester tester, {int loops = 5, int duration = 0}) async { + try { + for (int i = 0; i <= loops; i++) { + await tester.pump( + Duration(seconds: duration), + ); + } + } catch (e) { + await tester.pumpAndSettle(); + } +} + +/// [delayDuration] is in milliseconds +/// [loopDuration] is in seconds +Future customRunAsync( + WidgetTester tester, { + required Future Function() test, + int delayDuration = 500, + int loops = 5, + int loopDuration = 0, +}) async { + await tester.runAsync(() async { + await test(); + await Future.delayed(Duration(milliseconds: delayDuration)); + await pumpTester( + tester, + duration: loopDuration, + loops: loops, + ); + }); +} + +// Timers Pending fix +Future pendingTimersFix(WidgetTester tester) async { + await customRunAsync(tester, test: () async { + await Future.delayed(Duration(milliseconds: 500)); + await pumpTester(tester, duration: 10, loops: 100); + await Future.delayed(Duration(milliseconds: 500)); + }); +} diff --git a/test/main_test.dart b/test/main_test.dart index 98458b7a..81e5120c 100644 --- a/test/main_test.dart +++ b/test/main_test.dart @@ -2,11 +2,9 @@ import 'package:flutter_test/flutter_test.dart'; // Project imports: -import 'middleware_test.dart' as middleware_test; import 'reducer_test.dart' as reducer_test; void main() { TestWidgetsFlutterBinding.ensureInitialized(); - middleware_test.main(); reducer_test.main(); } diff --git a/test/middleware_test.dart b/test/middleware_test.dart deleted file mode 100644 index ffaa63c7..00000000 --- a/test/middleware_test.dart +++ /dev/null @@ -1,212 +0,0 @@ -// Dart imports: -import 'dart:async'; -import 'dart:typed_data'; - -// Package imports: -import 'package:brambldart/brambldart.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:mockito/mockito.dart'; -import 'package:redux/redux.dart'; - -// Project imports: -import 'package:ribn/actions/keychain_actions.dart'; -import 'package:ribn/actions/login_actions.dart'; -import 'package:ribn/actions/onboarding_actions.dart'; -import 'package:ribn/constants/test_data.dart'; -import 'package:ribn/models/app_state.dart'; -import 'package:ribn/models/ribn_address.dart'; -import 'package:ribn/redux.dart'; -import 'package:ribn/repositories/login_repository.dart'; -import 'package:ribn/repositories/onboarding_repository.dart'; -import 'shared_mocks.mocks.dart'; -import 'test_data.dart'; - -void main() { - final MockOnboardingRespository onboardingRepo = MockOnboardingRespository(); - final MockLoginRepository loginRepo = MockLoginRepository(); - final MockKeychainRepository keychainRepo = MockKeychainRepository(); - final MockMiscRepository miscRepo = MockMiscRepository(); - final MockTransactionRepository transactionRepo = MockTransactionRepository(); - - final String testMnemonic = testData['mnemonic']!; - final String validPassword = testData['validPassword']!; - final String invalidPassword = testData['invalidPassword']!; - final String testKeyStore = testData['keyStoreJson']!; - final RibnAddress testAddress = testData['address']; - final Uint8List testToplExtendedPrivKey = - Uint8List.fromList(toList(testData['toplExtendedPrvKey']!)); - - late Store testStore; - - Future reset() async { - TestWidgetsFlutterBinding.ensureInitialized(); - resetMockitoState(); - await Redux.initStore( - onboardingRepo: onboardingRepo, - loginRepo: loginRepo, - keychainRepo: keychainRepo, - miscRepo: miscRepo, - transactionRepo: transactionRepo, - ); - testStore = Redux.store!; - } - - group('App middleware', () { - setUp(reset); - group('Onboarding middleware', () { - test('should generate mnemonic', () { - when(onboardingRepo.generateMnemonicForUser()) - .thenAnswer((_) => testMnemonic); - testStore.dispatch(GenerateMnemonicAction()); - verify(onboardingRepo.generateMnemonicForUser()).called(1); - expect(testStore.state.onboardingState.mnemonic, testMnemonic); - expect( - testStore.state.onboardingState.shuffledMnemonic, - unorderedEquals(testMnemonic.split(' ')), - ); - }); - test('should generate keystore and initialize hd wallet', () async { - when(onboardingRepo.generateMnemonicForUser()) - .thenAnswer((_) => testMnemonic); - testStore.dispatch(GenerateMnemonicAction()); - // mnemonic: captureAnyNamed('mnemonic'), - // password: captureAnyNamed('password'), - when( - onboardingRepo.generateKeyStore(argThat(isNotNull)), - ).thenReturn( - { - 'keyStoreJson': testKeyStore, - 'toplExtendedPrvKeyUint8List': testToplExtendedPrivKey, - }, - ); - testStore.dispatch(CreatePasswordAction(validPassword)); - // verifyas( - // onboardingRepo.generateKeyStore(argThat(isNotNull) - // // mnemonic: captureAnyNamed('mnemonic'), - // // password: captureAnyNamed('password'), - // ), - // ).called(1); - await Future.delayed( - const Duration(seconds: 1), - (() { - expect(testStore.state.keychainState.keyStoreJson, testKeyStore); - expect(testStore.state.keychainState.hdWallet, isNotNull); - }), - ); - }); - }); - group('Login middleware', () { - setUp(() { - // generate mnemonic - when(onboardingRepo.generateMnemonicForUser()) - .thenAnswer((_) => testMnemonic); - testStore.dispatch(GenerateMnemonicAction()); - // generate keystore - when( - onboardingRepo.generateKeyStore(argThat(isNotNull)), - ).thenAnswer((_) { - return const OnboardingRespository().generateKeyStore({ - 'mnemonic': _.positionalArguments[0]['mnemonic'], - 'password': _.positionalArguments[0]['password'], - }); - }); - testStore.dispatch(CreatePasswordAction(validPassword)); - }); - test('should decrypt keystore', () async { - when( - loginRepo.decryptKeyStore(argThat(isNotNull)), - ).thenAnswer((_) { - return const LoginRepository().decryptKeyStore({ - 'keyStoreJson': testKeyStore, - 'password': validPassword, - }); - }); - final Completer completer = Completer(); - testStore.dispatch(AttemptLoginAction(validPassword, completer)); - await expectLater(completer.future, completion(true)); - }); - test('should not decrypt keysotre', () { - when( - loginRepo.decryptKeyStore(argThat(isNotNull)), - ).thenAnswer( - (_) => const LoginRepository().decryptKeyStore( - {'keyStoreJson': testKeyStore, 'password': invalidPassword}, - ), - ); - final Completer completer = Completer(); - testStore.dispatch(AttemptLoginAction(invalidPassword, completer)); - verify( - loginRepo.decryptKeyStore(argThat(isNotNull)), - ).called(1); - expect(completer.future, completion(false)); - }); - }); - - group('Keychain middleware', () { - setUp(() { - // generate mnemonic - when(onboardingRepo.generateMnemonicForUser()) - .thenAnswer((_) => testMnemonic); - testStore.dispatch(GenerateMnemonicAction()); - // generate keystore - when(onboardingRepo.generateKeyStore(argThat(isNotNull))).thenReturn({ - 'keyStoreJson': testKeyStore, - 'toplExtendedPrvKeyUint8List': testToplExtendedPrivKey - }); - testStore.dispatch(CreatePasswordAction(validPassword)); - // login - when(loginRepo.decryptKeyStore(captureAny)) - .thenReturn(testToplExtendedPrivKey); - }); - test('Should refresh balances', () async { - const testPolys = 10000; - await Future.delayed( - Duration.zero, - () => testStore.dispatch( - InitializeHDWalletAction( - toplExtendedPrivateKey: TestData.toplExtendedPrvKeyUint8List, - ), - ), - ); - when( - keychainRepo.generateAddress( - argThat(isNotNull), - networkId: captureAnyNamed('networkId'), - ), - ).thenAnswer((_) => testAddress); - testStore.dispatch( - GenerateAddressAction( - 0, - network: testStore.state.keychainState.currentNetwork, - ), - ); - when(keychainRepo.getBalances(captureAny, captureAny)).thenAnswer((_) { - return Future.value( - (_.positionalArguments[1] as List) - .map( - (e) => Balance( - address: e.toBase58(), - polys: PolyAmount.inNanopoly(quantity: testPolys), - arbits: ArbitAmount.zero(), - ), - ) - .toList(), - ); - }); - final Completer completer = Completer(); - testStore.dispatch( - RefreshBalancesAction( - completer, - testStore.state.keychainState.currentNetwork, - ), - ); - await expectLater(completer.future, completion(true)); - expect( - testStore - .state.keychainState.currentNetwork.addresses.first.balance.polys, - PolyAmount.inNanopoly(quantity: testPolys), - ); - }); - }); - }); -} diff --git a/test/mocks/flutter_secure_storage_mocks.dart b/test/mocks/flutter_secure_storage_mocks.dart new file mode 100644 index 00000000..208d5d03 --- /dev/null +++ b/test/mocks/flutter_secure_storage_mocks.dart @@ -0,0 +1,19 @@ +// Package imports: +import 'package:flutter_secure_storage/flutter_secure_storage.dart'; +import 'package:mockito/annotations.dart'; +import 'package:mockito/mockito.dart'; + +// Project imports: +import 'flutter_secure_storage_mocks.mocks.dart'; + +@GenerateMocks([FlutterSecureStorage]) +MockFlutterSecureStorage getMockFlutterSecureStorage() { + final MockFlutterSecureStorage _mock = MockFlutterSecureStorage(); + + when(_mock.write(key: anyNamed('key'), value: anyNamed('value'))).thenAnswer((realInvocation) async { + return; + }); + when(_mock.read(key: anyNamed('key'))).thenAnswer((realInvocation) async => ""); + + return _mock; +} diff --git a/test/mocks/local_authentication_mocks.dart b/test/mocks/local_authentication_mocks.dart new file mode 100644 index 00000000..31bb66ce --- /dev/null +++ b/test/mocks/local_authentication_mocks.dart @@ -0,0 +1,17 @@ +// Package imports: +import 'package:local_auth/local_auth.dart'; +import 'package:mockito/annotations.dart'; +import 'package:mockito/mockito.dart'; + +// Project imports: +import 'local_authentication_mocks.mocks.dart'; + +@GenerateMocks([LocalAuthentication]) +MockLocalAuthentication getMockLocalAuthentication() { + final MockLocalAuthentication _mock = MockLocalAuthentication(); + + when(_mock.canCheckBiometrics).thenAnswer((realInvocation) async => false); + when(_mock.isDeviceSupported()).thenAnswer((realInvocation) async => false); + + return _mock; +} diff --git a/test/mocks/random_mocks.dart b/test/mocks/random_mocks.dart new file mode 100644 index 00000000..f5b720bd --- /dev/null +++ b/test/mocks/random_mocks.dart @@ -0,0 +1,24 @@ +// Dart imports: +import 'dart:math'; + +// Package imports: +import 'package:mockito/annotations.dart'; +import 'package:mockito/mockito.dart'; + +// Project imports: +import 'random_mocks.mocks.dart'; + +@GenerateMocks([Random]) +MockRandom getRandomMocks() { + MockRandom _mockRandom = MockRandom(); + + when(_mockRandom.nextBool()).thenAnswer((realInvocation) => false); + + return _mockRandom; +} + +getBadMock() { + MockRandom _mockRandom = MockRandom(); + + return _mockRandom; +} diff --git a/test/mocks/store_mocks.dart b/test/mocks/store_mocks.dart new file mode 100644 index 00000000..adc9474b --- /dev/null +++ b/test/mocks/store_mocks.dart @@ -0,0 +1,32 @@ +// Package imports: +import 'package:mockito/mockito.dart' as _i1; +import 'package:mockito/mockito.dart'; +import 'package:redux/redux.dart'; + +// Project imports: +import 'package:ribn/models/app_state.dart'; + +MockStore getStoreMocks({ + bool isNewUser = false, +}) { + final _mockStore = MockStore(isNewUser); + return _mockStore; +} + +class MockStore extends Mock implements Store { + final bool isNewUser; + MockStore(this.isNewUser) { + _i1.throwOnMissingStub(this); + } + + @override + AppState get state => AppState.test(isNewUser: isNewUser); + + @override + Stream get onChange => Stream.value(AppState.test()); + + @override + dispatch(action) { + return ''; + } +} diff --git a/test/onboarding/create_wallet_test.dart b/test/onboarding/create_wallet_test.dart new file mode 100644 index 00000000..19ddb54f --- /dev/null +++ b/test/onboarding/create_wallet_test.dart @@ -0,0 +1,138 @@ +// Flutter imports: +import 'package:flutter/material.dart'; + +// Package imports: +import 'package:flutter_test/flutter_test.dart'; + +// Project imports: +import 'package:ribn/models/onboarding_state.dart'; +import 'package:ribn/presentation/home/home_page.dart'; +import 'package:ribn/presentation/onboarding/create_wallet/create_password_page.dart'; +import 'package:ribn/presentation/onboarding/create_wallet/getting_started_page.dart'; +import 'package:ribn/presentation/onboarding/create_wallet/seed_phrase_confirmation_page.dart'; +import 'package:ribn/presentation/onboarding/create_wallet/seed_phrase_display_page.dart'; +import 'package:ribn/presentation/onboarding/create_wallet/seed_phrase_generating_page.dart'; +import 'package:ribn/presentation/onboarding/create_wallet/seed_phrase_info_checklist_page.dart'; +import 'package:ribn/presentation/onboarding/create_wallet/seed_phrase_instructions_page.dart'; +import 'package:ribn/presentation/onboarding/create_wallet/select_action_page.dart'; +import 'package:ribn/presentation/onboarding/create_wallet/wallet_created_page.dart'; +import 'package:ribn/presentation/onboarding/create_wallet/wallet_info_checklist_page.dart'; +import 'package:ribn/presentation/onboarding/create_wallet/welcome_page.dart'; +import 'package:ribn/presentation/onboarding/widgets/opt_in_tracker_page.dart'; +import 'package:ribn/providers/packages/entropy_provider.dart'; +import 'package:ribn/providers/packages/flutter_secure_storage_provider.dart'; +import '../essential_test_provider_widget.dart'; +import '../mocks/flutter_secure_storage_mocks.dart'; +import '../mocks/store_mocks.dart'; +import '../utils/onboarding_utils.dart'; + +void main() { + testWidgets('Test Successful Create Wallet Flow', (WidgetTester tester) async { + // TODO: Refactor styling so we don't have to override window size + tester.binding.window.physicalSizeTestValue = Size(10000, 10000); + await tester.pumpWidget( + await essentialTestProviderWidget( + overrides: [ + entropyFuncProvider.overrideWith((ref) => (_) => OnboardingState.test().mnemonic), + flutterSecureStorageProvider.overrideWith((ref) { + return () => getMockFlutterSecureStorage(); + }), + ], + mockStore: getStoreMocks(isNewUser: true), + ), + ); + + /// Welcome Page Section + expect(find.byKey(WelcomePage.welcomePageKey), findsOneWidget); + await tester.tap(find.byKey(WelcomePage.welcomePageConfirmationButtonKey)); + await tester.pumpAndSettle(); + + /// Opt In + expect(find.byKey(OptInTracker.optInTrackerKey), findsOneWidget); + await tester.tap(find.byKey(OptInTracker.noThanksKey)); + await tester.pumpAndSettle(); + + /// Select Action + expect(find.byKey(SelectActionPage.selectActionPageKey), findsOneWidget); + await tester.tap(find.byKey(SelectActionPage.createWalletActionButtonKey)); + await tester.pumpAndSettle(); + + /// Getting Started + expect(find.byKey(GettingStartedPage.gettingStartedPageKey), findsOneWidget); + await tester.tap(find.byKey(GettingStartedPage.gettingStartedConfirmationButtonKey)); + await tester.pumpAndSettle(); + + /// Seed phrase info checklist + expect(find.byKey(SeedPhraseInfoChecklistPage.seedPhraseInfoChecklistPageKey), findsOneWidget); + // Try to tap confirm button and make sure the page does not change + await tester.tap(find.byKey(SeedPhraseInfoChecklistPage.seedPhraseInfoChecklistConfirmationButtonKey)); + await tester.pumpAndSettle(); + expect(find.byKey(SeedPhraseInfoChecklistPage.seedPhraseInfoChecklistPageKey), findsOneWidget); + + // Now try and tap the first checkbox and attempt to move pages, should stay on same page + await tester.tap(find.byKey(SeedPhraseInfoChecklistPage.neverShareMySeedPhraseKey)); + await tester.pumpAndSettle(); + await tester.tap(find.byKey(SeedPhraseInfoChecklistPage.seedPhraseInfoChecklistConfirmationButtonKey)); + await tester.pumpAndSettle(); + expect(find.byKey(SeedPhraseInfoChecklistPage.seedPhraseInfoChecklistPageKey), findsOneWidget); + + // Now tap the second checkbox and page should move to next page + await tester.tap(find.byKey(SeedPhraseInfoChecklistPage.walletRecoveryUsingSeedPhraseKey)); + await tester.pumpAndSettle(); + await tester.tap(find.byKey(SeedPhraseInfoChecklistPage.seedPhraseInfoChecklistConfirmationButtonKey)); + await tester.pumpAndSettle(); + expect(find.byKey(SeedPhraseInstructionsPage.seedPhraseInstructionsPageKey), findsOneWidget); + await tester.tap(find.byKey(SeedPhraseInstructionsPage.seedPhraseInstructionsConfirmationButtonKey)); + await tester.pumpAndSettle(); + + /// Seed phrase generation + expect(find.byKey(SeedPhraseGeneratingPage.seedPhraseGeneratingPageKey), findsOneWidget); + // The seed generation page has a set time delay and this will make time pass so that the confirm button will appear + await pumpTester(tester, duration: 1, loops: 10); + await tester.tap(find.byKey(SeedPhraseGeneratingPage.seedPhraseGeneratingConfirmationButtonKey)); + await tester.pumpAndSettle(); + + /// Seed phrase Display + expect(find.byKey(SeedPhraseDisplayPage.seedPhraseDisplayPageKey), findsOneWidget); + await tester.tap(find.byKey(SeedPhraseDisplayPage.seedPhraseDisplayConfirmationButtonKey)); + await tester.pumpAndSettle(); + + /// Seed phrase confirmation section + expect(find.byKey(SeedPhraseConfirmationPage.seedPhraseConfirmationPageKey), findsOneWidget); + await fillOutSeedPhraseConfirmation(tester: tester); + await tester.tap(find.byKey(SeedPhraseConfirmationPage.seedPhraseConfirmationConfirmationButtonKey)); + await tester.pumpAndSettle(); + + /// Create Password section + expect(find.byKey(CreatePasswordPage.createPasswordPageKey), findsOneWidget); + await fillOutCreatePassword(tester: tester); + await tester.pumpAndSettle(); + await clickCreatePasswordConfirm( + tester: tester, + buttonKey: CreatePasswordPage.createPasswordConfirmationButtonKey, + ); + + /// Wallet Info Checklist Section + expect(find.byKey(WalletInfoChecklistPage.walletInfoChecklistPageKey), findsOneWidget); + await tester.tap(find.byKey(WalletInfoChecklistPage.savedMyWalletPasswordSafelyKey)); + await tester.pumpAndSettle(); + await tester.tap(find.byKey(WalletInfoChecklistPage.toplCannotRecoverForMeKey)); + await tester.pumpAndSettle(); + await tester.tap(find.byKey(WalletInfoChecklistPage.spAndPasswordUnrecoverableKey)); + await tester.pumpAndSettle(); + await tester.tap(find.byKey(WalletInfoChecklistPage.walletInfoChecklistConfirmationButtonKey)); + await tester.pumpAndSettle(); + + /// Wallet Page Created Section + expect(find.byKey(WalletCreatedPage.walletCreatedPageKey), findsOneWidget); + await tester.ensureVisible(find.byKey(WalletCreatedPage.walletCreatedConfirmationButtonKey)); + await tester.pumpAndSettle(); + await tester.tap(find.byKey(WalletCreatedPage.walletCreatedConfirmationButtonKey)); + await tester.pumpAndSettle(); + + /// Make it to wallet balance screen + expect(find.byKey(HomePage.homePageKey), findsOneWidget); + + await pendingTimersFix(tester); + }); +} diff --git a/test/onboarding/import_wallet_test.dart b/test/onboarding/import_wallet_test.dart new file mode 100644 index 00000000..9e4251df --- /dev/null +++ b/test/onboarding/import_wallet_test.dart @@ -0,0 +1,73 @@ +// Flutter imports: +import 'package:flutter/material.dart'; + +// Package imports: +import 'package:flutter_test/flutter_test.dart'; + +// Project imports: +import 'package:ribn/models/onboarding_state.dart'; +import 'package:ribn/presentation/home/home_page.dart'; +import 'package:ribn/presentation/onboarding/create_wallet/select_action_page.dart'; +import 'package:ribn/presentation/onboarding/create_wallet/welcome_page.dart'; +import 'package:ribn/presentation/onboarding/restore_wallet/create_new_wallet_password_page.dart'; +import 'package:ribn/presentation/onboarding/restore_wallet/restore_wallet_page.dart'; +import 'package:ribn/presentation/onboarding/widgets/opt_in_tracker_page.dart'; +import 'package:ribn/providers/packages/entropy_provider.dart'; +import 'package:ribn/providers/packages/flutter_secure_storage_provider.dart'; +import '../essential_test_provider_widget.dart'; +import '../mocks/flutter_secure_storage_mocks.dart'; +import '../mocks/store_mocks.dart'; +import '../utils/onboarding_utils.dart'; + +void main() { + testWidgets('Test Successful Import Wallet Flow', (WidgetTester tester) async { + // TODO: Refactor styling so we don't have to override window size + tester.binding.window.physicalSizeTestValue = Size(10000, 10000); + + final _mockStore = getStoreMocks(isNewUser: true); + await tester.pumpWidget( + await essentialTestProviderWidget( + overrides: [ + entropyFuncProvider.overrideWith((ref) { + return (_) => OnboardingState.test().mnemonic; + }), + flutterSecureStorageProvider.overrideWith((ref) { + return () => getMockFlutterSecureStorage(); + }), + ], + mockStore: _mockStore, + ), + ); + + /// Welcome Page Section + expect(find.byKey(WelcomePage.welcomePageKey), findsOneWidget); + await tester.tap(find.byKey(WelcomePage.welcomePageConfirmationButtonKey)); + await tester.pumpAndSettle(); + + /// Opt In + expect(find.byKey(OptInTracker.optInTrackerKey), findsOneWidget); + await tester.tap(find.byKey(OptInTracker.noThanksKey)); + await tester.pumpAndSettle(); + + /// Select Action + expect(find.byKey(SelectActionPage.selectActionPageKey), findsOneWidget); + await tester.tap(find.byKey(SelectActionPage.importWalletActionButtonKey)); + await tester.pumpAndSettle(); + + /// Wallet Restore + await fillOutRestoreWalletMnemonic(tester: tester); + await tester.tap(find.byKey(RestoreWalletPage.restoreWalletConfirmationButtonKey)); + await tester.pumpAndSettle(); + + /// Create password + expect(find.byKey(NewWalletPasswordPage.newWalletPasswordPageKey), findsOneWidget); + await fillOutCreatePassword(tester: tester); + await clickCreatePasswordConfirm( + tester: tester, + buttonKey: NewWalletPasswordPage.newWalletPasswordConfirmationButtonKey, + ); + + /// Make it to wallet balance screen + expect(find.byKey(HomePage.homePageKey), findsOneWidget); + }); +} diff --git a/test/onboarding/opt_in_page_test.dart b/test/onboarding/opt_in_page_test.dart new file mode 100644 index 00000000..d1c70abb --- /dev/null +++ b/test/onboarding/opt_in_page_test.dart @@ -0,0 +1,102 @@ +// Flutter imports: +import 'package:flutter/material.dart'; + +// Package imports: +import 'package:flutter_test/flutter_test.dart'; + +// Project imports: +import 'package:ribn/constants/strings.dart'; +import 'package:ribn/presentation/onboarding/create_wallet/select_action_page.dart'; +import 'package:ribn/presentation/onboarding/create_wallet/welcome_page.dart'; +import 'package:ribn/presentation/onboarding/widgets/opt_in_tracker_page.dart'; +import 'package:ribn/providers/packages/url_launcher_provider.dart'; +import '../essential_test_provider_widget.dart'; +import '../mocks/store_mocks.dart'; +import '../utils/text_utils.dart'; + +void main() { + testWidgets('Clicking No Thanks Brings you to the next page', (WidgetTester tester) async { + tester.binding.window.physicalSizeTestValue = Size(10000, 10000); + await tester.pumpWidget( + await essentialTestProviderWidget( + overrides: [], + mockStore: getStoreMocks(isNewUser: true), + ), + ); + + /// Welcome Page Section + expect(find.byKey(WelcomePage.welcomePageKey), findsOneWidget); + await tester.tap(find.byKey(WelcomePage.welcomePageConfirmationButtonKey)); + await tester.pumpAndSettle(); + + /// Opt In + expect(find.byKey(OptInTracker.optInTrackerKey), findsOneWidget); + await tester.tap(find.byKey(OptInTracker.noThanksKey)); + await tester.pumpAndSettle(); + + /// Expect next page + expect(find.byKey(SelectActionPage.selectActionPageKey), findsOneWidget); + }); + + testWidgets('Clicking I Agree Brings you to the next page and inits analytics', (WidgetTester tester) async { + tester.binding.window.physicalSizeTestValue = Size(10000, 10000); + await tester.pumpWidget( + await essentialTestProviderWidget( + overrides: [], + mockStore: getStoreMocks(isNewUser: true), + ), + ); + + /// Welcome Page Section + expect(find.byKey(WelcomePage.welcomePageKey), findsOneWidget); + await tester.tap(find.byKey(WelcomePage.welcomePageConfirmationButtonKey)); + await tester.pumpAndSettle(); + + /// Opt In + expect(find.byKey(OptInTracker.optInTrackerKey), findsOneWidget); + await tester.tap(find.byKey(OptInTracker.iAgreeKey)); + await tester.pumpAndSettle(); + + // TODO: Implement check for opt in + + /// Expect next page + expect(find.byKey(SelectActionPage.selectActionPageKey), findsOneWidget); + }); + + testWidgets('Clicking Read more and privacy policy works', (WidgetTester tester) async { + tester.binding.window.physicalSizeTestValue = Size(10000, 10000); + + bool clicked = false; + await tester.pumpWidget( + await essentialTestProviderWidget( + overrides: [ + urlLauncherProvider.overrideWithValue((p0) async { + clicked = true; + return true; + }) + ], + mockStore: getStoreMocks(isNewUser: true), + ), + ); + + /// Welcome Page Section + expect(find.byKey(WelcomePage.welcomePageKey), findsOneWidget); + await tester.tap(find.byKey(WelcomePage.welcomePageConfirmationButtonKey)); + await tester.pumpAndSettle(); + + /// Opt In + expect(clicked, false); + expect(find.byKey(OptInTracker.optInTrackerKey), findsOneWidget); + // Expect no privacy policy yet + final textTap = find.byWidgetPredicate( + (widget) => widget is RichText && tapTextSpan(widget, Strings.privacyPolicyLink), + ); + expect(textTap, findsNothing); + await tester.tap(find.byKey(OptInTracker.readMoreKey)); + await tester.pumpAndSettle(); + expect(textTap, findsOneWidget); + await tester.tap(textTap); + await tester.pumpAndSettle(); + expect(clicked, true); + }); +} diff --git a/test/reducer_test.dart b/test/reducer_test.dart index ceb15a50..7773849d 100644 --- a/test/reducer_test.dart +++ b/test/reducer_test.dart @@ -11,7 +11,6 @@ import 'package:redux/redux.dart'; // Project imports: import 'package:ribn/actions/keychain_actions.dart'; -import 'package:ribn/actions/onboarding_actions.dart'; import 'package:ribn/constants/network_utils.dart'; import 'package:ribn/constants/rules.dart'; import 'package:ribn/models/app_state.dart'; @@ -22,26 +21,15 @@ import 'test_data.dart'; void main() { group('AppState reducer', () { - final String testMnemonic = testData['mnemonic']!; final String testKeyStore = testData['keyStoreJson']!; - final Uint8List testToplExtendedPrivKey = - Uint8List.fromList(toList(testData['toplExtendedPrvKey']!)); + final Uint8List testToplExtendedPrivKey = Uint8List.fromList(toList(testData['toplExtendedPrvKey']!)); late Store testStore; setUp(() async { await Redux.initStore(initTestStore: false); testStore = Redux.store!; }); - group('Onboarding reducer', () { - test('mnemonic generation', () { - testStore.dispatch(MnemonicSuccessfullyGeneratedAction(testMnemonic)); - expect(testMnemonic, testStore.state.onboardingState.mnemonic); - expect( - testStore.state.onboardingState.shuffledMnemonic, - unorderedEquals(List.from(testMnemonic.split(' '))), - ); - }); - }); + group('Onboarding reducer', () {}); group('Keychain reducer', () { test('keyStoreJson and hd wallet initialization', () async { final HdWallet hdWallet = HdWallet( @@ -72,9 +60,7 @@ void main() { ); final Map> networkAddresses = {}; testStore.state.keychainState.networks.forEach((networkName, network) { - networkAddresses[networkName] = [ - keychainRepo.generateAddress(hdWallet, networkId: network.networkId) - ]; + networkAddresses[networkName] = [keychainRepo.generateAddress(hdWallet, networkId: network.networkId)]; }); testStore.dispatch(UpdateNetworksWithAddressesAction(networkAddresses)); testStore.state.keychainState.networks.forEach((networkName, network) { diff --git a/test/shared_mocks.mocks.dart b/test/shared_mocks.mocks.dart deleted file mode 100644 index b8cc13e4..00000000 --- a/test/shared_mocks.mocks.dart +++ /dev/null @@ -1,271 +0,0 @@ -// Mocks generated by Mockito 5.2.0 from annotations -// in ribn/test/shared_mocks.dart. -// Do not manually edit this file. - -// Dart imports: -import 'dart:async' as _i6; -import 'dart:typed_data' as _i8; - -// Package imports: -import 'package:brambldart/brambldart.dart' as _i4; -import 'package:brambldart/credentials.dart' as _i2; -import 'package:mockito/mockito.dart' as _i1; - -// Project imports: -import 'package:ribn/models/internal_message.dart' as _i10; -import 'package:ribn/models/ribn_address.dart' as _i3; -import 'package:ribn/models/transfer_details.dart' as _i13; -import 'package:ribn/repositories/keychain_repository.dart' as _i11; -import 'package:ribn/repositories/login_repository.dart' as _i7; -import 'package:ribn/repositories/misc_repository.dart' as _i9; -import 'package:ribn/repositories/onboarding_repository.dart' as _i5; -import 'package:ribn/repositories/transaction_repository.dart' as _i12; - -// 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 _FakeBip32KeyPair_0 extends _i1.Fake implements _i2.Bip32KeyPair {} - -class _FakeRibnAddress_1 extends _i1.Fake implements _i3.RibnAddress {} - -class _FakeTransactionReceipt_2 extends _i1.Fake - implements _i4.TransactionReceipt {} - -class _FakeToplAddress_3 extends _i1.Fake implements _i2.ToplAddress {} - -class _FakeBalance_4 extends _i1.Fake implements _i4.Balance {} - -/// A class which mocks [OnboardingRespository]. -/// -/// See the documentation for Mockito's code generation for more information. -class MockOnboardingRespository extends _i1.Mock - implements _i5.OnboardingRespository { - MockOnboardingRespository() { - _i1.throwOnMissingStub(this); - } - - @override - _i6.Future> generateMnemonicAndKeystore( - String? password) => - (super.noSuchMethod( - Invocation.method(#generateMnemonicAndKeystore, [password]), - returnValue: - Future>.value({})) - as _i6.Future>); - @override - String generateMnemonicForUser() => - (super.noSuchMethod(Invocation.method(#generateMnemonicForUser, []), - returnValue: '') as String); - @override - Map generateKeyStore(Map? params) => - (super.noSuchMethod(Invocation.method(#generateKeyStore, [params]), - returnValue: {}) as Map); - @override - _i2.Bip32KeyPair deriveToplExtendedKeys(String? mnemonic) => (super - .noSuchMethod(Invocation.method(#deriveToplExtendedKeys, [mnemonic]), - returnValue: _FakeBip32KeyPair_0()) as _i2.Bip32KeyPair); -} - -/// A class which mocks [LoginRepository]. -/// -/// See the documentation for Mockito's code generation for more information. -class MockLoginRepository extends _i1.Mock implements _i7.LoginRepository { - MockLoginRepository() { - _i1.throwOnMissingStub(this); - } - - @override - _i8.Uint8List decryptKeyStore(Map? params) => - (super.noSuchMethod(Invocation.method(#decryptKeyStore, [params]), - returnValue: _i8.Uint8List(0)) as _i8.Uint8List); -} - -/// A class which mocks [MiscRepository]. -/// -/// See the documentation for Mockito's code generation for more information. -class MockMiscRepository extends _i1.Mock implements _i9.MiscRepository { - MockMiscRepository() { - _i1.throwOnMissingStub(this); - } - - @override - _i6.Future persistAppState(String? appState) => - (super.noSuchMethod(Invocation.method(#persistAppState, [appState]), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i6.Future); - @override - void sendInternalMessage(_i10.InternalMessage? msg) => - super.noSuchMethod(Invocation.method(#sendInternalMessage, [msg]), - returnValueForMissingStub: null); - @override - void downloadAsFile(String? fileName, String? text) => - super.noSuchMethod(Invocation.method(#downloadAsFile, [fileName, text]), - returnValueForMissingStub: null); -} - -/// A class which mocks [KeychainRepository]. -/// -/// See the documentation for Mockito's code generation for more information. -class MockKeychainRepository extends _i1.Mock - implements _i11.KeychainRepository { - MockKeychainRepository() { - _i1.throwOnMissingStub(this); - } - - @override - _i3.RibnAddress generateAddress(_i2.HdWallet? hdWallet, - {int? purpose = 2147485500, - int? coinType = 2147490739, - int? account = 2147483648, - int? change = 0, - int? addr = 0, - int? networkId}) => - (super.noSuchMethod( - Invocation.method(#generateAddress, [ - hdWallet - ], { - #purpose: purpose, - #coinType: coinType, - #account: account, - #change: change, - #addr: addr, - #networkId: networkId - }), - returnValue: _FakeRibnAddress_1()) as _i3.RibnAddress); - @override - String getKeyPath(int? purpose, int? coinType, int? account, int? change, - int? address) => - (super.noSuchMethod( - Invocation.method( - #getKeyPath, [purpose, coinType, account, change, address]), - returnValue: '') as String); - @override - _i6.Future> getBalances( - _i4.BramblClient? client, List<_i2.ToplAddress>? addresses) => - (super.noSuchMethod(Invocation.method(#getBalances, [client, addresses]), - returnValue: Future>.value(<_i4.Balance>[])) - as _i6.Future>); - @override - List<_i2.Credentials> getCredentials( - _i2.HdWallet? hdWallet, List<_i3.RibnAddress>? addresses) => - (super.noSuchMethod( - Invocation.method(#getCredentials, [hdWallet, addresses]), - returnValue: <_i2.Credentials>[]) as List<_i2.Credentials>); -} - -/// A class which mocks [TransactionRepository]. -/// -/// See the documentation for Mockito's code generation for more information. -class MockTransactionRepository extends _i1.Mock - implements _i12.TransactionRepository { - MockTransactionRepository() { - _i1.throwOnMissingStub(this); - } - - @override - _i6.Future> createRawTx( - _i4.BramblClient? client, _i13.TransferDetails? transferDetails) => - (super.noSuchMethod( - Invocation.method(#createRawTx, [client, transferDetails]), - returnValue: - Future>.value({})) - as _i6.Future>); - @override - _i6.Future<_i4.TransactionReceipt> signTx( - _i4.BramblClient? client, - List<_i2.Credentials>? creds, - Map? transferDetails) => - (super.noSuchMethod( - Invocation.method(#signTx, [client, creds, transferDetails]), - returnValue: Future<_i4.TransactionReceipt>.value( - _FakeTransactionReceipt_2())) - as _i6.Future<_i4.TransactionReceipt>); - @override - _i6.Future broadcastTx( - _i4.BramblClient? client, _i4.TransactionReceipt? signedTx) => - (super.noSuchMethod(Invocation.method(#broadcastTx, [client, signedTx]), - returnValue: Future.value('')) as _i6.Future); - @override - _i6.Future signAndBroadcastTx( - _i4.BramblClient? client, - List<_i2.Credentials>? creds, - _i4.TransactionReceipt? rawTx, - _i8.Uint8List? messageToSign) => - (super.noSuchMethod( - Invocation.method( - #signAndBroadcastTx, [client, creds, rawTx, messageToSign]), - returnValue: Future.value('')) as _i6.Future); -} - -/// A class which mocks [RibnAddress]. -/// -/// See the documentation for Mockito's code generation for more information. -// ignore: must_be_immutable -class MockRibnAddress extends _i1.Mock implements _i3.RibnAddress { - MockRibnAddress() { - _i1.throwOnMissingStub(this); - } - - @override - _i2.ToplAddress get toplAddress => - (super.noSuchMethod(Invocation.getter(#toplAddress), - returnValue: _FakeToplAddress_3()) as _i2.ToplAddress); - @override - String get keyPath => - (super.noSuchMethod(Invocation.getter(#keyPath), returnValue: '') - as String); - @override - int get addressIndex => - (super.noSuchMethod(Invocation.getter(#addressIndex), returnValue: 0) - as int); - @override - int get accountIndex => - (super.noSuchMethod(Invocation.getter(#accountIndex), returnValue: 0) - as int); - @override - int get changeIndex => - (super.noSuchMethod(Invocation.getter(#changeIndex), returnValue: 0) - as int); - @override - _i4.Balance get balance => (super.noSuchMethod(Invocation.getter(#balance), - returnValue: _FakeBalance_4()) as _i4.Balance); - @override - int get networkId => - (super.noSuchMethod(Invocation.getter(#networkId), returnValue: 0) - as int); - @override - _i3.RibnAddress copyWith( - {_i2.ToplAddress? toplAddress, - String? keyPath, - int? addressIndex, - int? accountIndex, - int? changeIndex, - _i4.Balance? balance, - int? networkId}) => - (super.noSuchMethod( - Invocation.method(#copyWith, [], { - #toplAddress: toplAddress, - #keyPath: keyPath, - #addressIndex: addressIndex, - #accountIndex: accountIndex, - #changeIndex: changeIndex, - #balance: balance, - #networkId: networkId - }), - returnValue: _FakeRibnAddress_1()) as _i3.RibnAddress); - @override - Map toMap() => - (super.noSuchMethod(Invocation.method(#toMap, []), - returnValue: {}) as Map); - @override - String toJson() => - (super.noSuchMethod(Invocation.method(#toJson, []), returnValue: '') - as String); -} diff --git a/test/test_data.dart b/test/test_data.dart index 9c82ec3f..a172905a 100644 --- a/test/test_data.dart +++ b/test/test_data.dart @@ -7,8 +7,7 @@ import 'package:ribn/constants/rules.dart'; import 'package:ribn/models/ribn_address.dart'; Map testData = { - 'mnemonic': - 'napkin they pupil disorder junior tonight harsh mobile equal explain allow fancy', + 'mnemonic': 'napkin they pupil disorder junior tonight harsh mobile equal explain allow fancy', 'rootExtendedPrvKey': '64, 152, 147, 162, 27, 218, 199, 183, 63, 203, 225, 8, 66, 19, 70, 136, 195, 167, 2, 80, 205, 2, 101, 184, 123, 4, 1, 243, 211, 71, 151, 94, 55, 233, 205, 8, 240, 57, 245, 113, 25, 135, 174, 17, 19, 89, 46, 188, 137, 86, 233, 16, 223, 41, 177, 217, 128, 221, 55, 128, 147, 74, 229, 221, 235, 233, 231, 45, 1, 34, 13, 37, 45, 17, 170, 166, 208, 154, 59, 17, 179, 13, 219, 191, 21, 64, 115, 19, 223, 133, 72, 255, 45, 171, 47, 108', 'toplExtendedPrvKey': diff --git a/test/utils/onboarding_utils.dart b/test/utils/onboarding_utils.dart new file mode 100644 index 00000000..628c2f14 --- /dev/null +++ b/test/utils/onboarding_utils.dart @@ -0,0 +1,86 @@ +// Flutter imports: +import 'package:flutter/material.dart'; + +// Package imports: +import 'package:flutter_test/flutter_test.dart'; + +// Project imports: +import 'package:ribn/models/onboarding_state.dart'; +import 'package:ribn/presentation/onboarding/create_wallet/seed_phrase_confirmation_page.dart'; +import 'package:ribn/presentation/onboarding/restore_wallet/restore_wallet_page.dart'; +import 'package:ribn/presentation/onboarding/widgets/password_section.dart'; +import '../constants/onboarding_constants.dart'; +import '../essential_test_provider_widget.dart'; + +/// This will fill out the seed phase confirmation text fields +/// +/// Can pass in [mobileConfirmIdxs] +/// Can pass in [mnemonic]. If you want to check negative cases, +/// you may pass in a mnemonic that does not match the users initial sign uo mnemonic +Future fillOutSeedPhraseConfirmation({ + required WidgetTester tester, + List? mobileConfirmIdxs, + List? mnemonic, +}) async { + if (mobileConfirmIdxs == null) { + mobileConfirmIdxs = OnboardingState.test().mobileConfirmIdxs; + } + + if (mnemonic == null) { + mnemonic = OnboardingState.test().shuffledMnemonic; + } + expect(find.byKey(SeedPhraseConfirmationPage.seedPhraseConfirmationPageKey), findsOneWidget); + + for (var i = 0; i < mobileConfirmIdxs.length; i++) { + final textFieldKey = find.byKey(SeedPhraseConfirmationPage.confirmationTextFieldKey(i)); + + final int index = mobileConfirmIdxs[i]; + + await tester.enterText(textFieldKey, mnemonic[index]); + await tester.pumpAndSettle(); + } +} + +Future fillOutCreatePassword({ + required WidgetTester tester, + String password = testPassword, + String? confirmPassword, +}) async { + if (confirmPassword == null) confirmPassword = password; + + expect(find.byKey(PasswordSection.passwordSectionKey), findsOneWidget); + + await tester.enterText(find.byKey(PasswordSection.newPasswordTextFieldKey), testPassword); + await tester.pumpAndSettle(); + + await tester.enterText(find.byKey(PasswordSection.confirmPasswordTextFieldKey), confirmPassword); + await tester.pumpAndSettle(); + + await tester.tap(find.byKey(PasswordSection.termsOfAgreementCheckboxKey)); + await tester.pumpAndSettle(); +} + +Future clickCreatePasswordConfirm({ + required WidgetTester tester, + required Key buttonKey, +}) async { + await customRunAsync(tester, test: () async { + await tester.tap(find.byKey(buttonKey)); + await Future.delayed(Duration(milliseconds: 200)); + await pumpTester(tester, duration: 10, loops: 1000); + await Future.delayed(Duration(milliseconds: 200)); + }); +} + +Future fillOutRestoreWalletMnemonic({ + required WidgetTester tester, + String? mnemonic, +}) async { + if (mnemonic == null) { + mnemonic = OnboardingState.test().mnemonic; + } + expect(find.byKey(RestoreWalletPage.restoreWalletPageKey), findsOneWidget); + + await tester.enterText(find.byKey(RestoreWalletPage.mnemonicTextFieldKey), mnemonic); + await tester.pumpAndSettle(); +} diff --git a/test/utils/text_utils.dart b/test/utils/text_utils.dart new file mode 100644 index 00000000..9e106ba2 --- /dev/null +++ b/test/utils/text_utils.dart @@ -0,0 +1,21 @@ +// Flutter imports: +import 'package:flutter/gestures.dart'; +import 'package:flutter/material.dart'; + +bool findTextAndTap(InlineSpan visitor, String text) { + if (visitor is TextSpan && visitor.text == text) { + (visitor.recognizer as TapGestureRecognizer).onTap!(); + + return false; + } + + return true; +} + +bool tapTextSpan(RichText richText, String text) { + final isTapped = !richText.text.visitChildren( + (visitor) => findTextAndTap(visitor, text), + ); + + return isTapped; +} diff --git a/web/interop/ext_utils.js b/web/interop/ext_utils.js index c9546ddd..75230dea 100644 --- a/web/interop/ext_utils.js +++ b/web/interop/ext_utils.js @@ -22,15 +22,15 @@ var ext_utils = { * Clears AllowList */ deleteAllowList: async () => { - await chrome.storage.local.set({ 'allowList': [] }); + await chrome.storage.local.set({'allowList': []}); }, /** * Gets full AllowList */ retrieveAllowList: async () => { - let storage = await chrome.storage.local.get(undefined); - storage = storage ? storage.allowList : []; - return (storage); + let storage = await chrome.storage.local.get(undefined); + storage = storage ? storage.allowList : []; + return(storage); }, /** * diff --git a/web/manifest.json b/web/manifest.json index 89ed62db..135873d3 100644 --- a/web/manifest.json +++ b/web/manifest.json @@ -1,7 +1,7 @@ { "name": "Ribn", "description": "Web wallet for Topl Blockchain", - "version": "0.5.0", + "version": "1.0.0", "content_security_policy": { "extension_pages": "script-src 'self'; object-src 'self'" }, diff --git a/web/src/api/messenger.ts b/web/src/api/messenger.ts index 4efd4c07..0291658e 100644 --- a/web/src/api/messenger.ts +++ b/web/src/api/messenger.ts @@ -1,7 +1,7 @@ -import { API_ERRORS, API_METHODS, INTERNAL_METHODS, SENDERS, TARGET } from "../utils/configs"; -import { APIRequest, InternalMessage } from "../utils/types"; -import { createPopup } from "./popup"; -import { ExtensionStorage } from "./storage"; +import {API_ERRORS, API_METHODS, INTERNAL_METHODS, SENDERS, TARGET} from "../utils/configs"; +import {APIRequest, InternalMessage} from "../utils/types"; +import {createPopup} from "./popup"; +import {ExtensionStorage} from "./storage"; export const Messenger = { @@ -9,7 +9,7 @@ export const Messenger = { * Forwards request from the web-page to the content-script. * Attaches a listener to listen for response from the content-script. */ - forwardToContentScript: ({ method, data }: APIRequest): Promise => { + forwardToContentScript: ({method, data}: APIRequest): Promise => { return new Promise((resolve, reject) => { const requestId: string = Math.random().toString(36).substr(2); // listen for message-events from the content-script @@ -99,7 +99,6 @@ class ContentMessenger { }); const isOriginAllowed = (isEnabledResponse.data as Record)["enabled"]; const permissionRequired = ![API_METHODS.enable, API_METHODS.isEnabled, API_METHODS.authorize].includes(request.method); - if (request.method == API_METHODS.isEnabled) { window.postMessage(isEnabledResponse); } else if (!isOriginAllowed && permissionRequired) { @@ -170,14 +169,12 @@ class BackgroundMessenger { authorize: (request: InternalMessage, sendResponse: (response?: InternalMessage) => void) => { ExtensionStorage.isOriginAllowed(request.origin as string).then((isAllowed) => { if (!isAllowed) { - request.additionalNavigation = "/connect-dapp" createPopup() .then((tab) => this.handlePopupConnection(request, tab)) .then(async (result) => { if (result.data && result.data["enabled"] == true) { await ExtensionStorage.addToAllowList(request.origin as string); } - result.additionalNavigation = "/connect-dapp" sendResponse(result); }); } else { @@ -203,10 +200,9 @@ class BackgroundMessenger { ...request, sender: SENDERS.ribn, data: { - // message: window.randomFunctionName(), +// message: window.randomFunctionName(), message: "", - } - }); + }}); }, signTransaction: async (request: InternalMessage, sendResponse: (response?: InternalMessage) => void) => { createPopup() @@ -305,7 +301,6 @@ class BackgroundMessenger { } // v2 case API_METHODS.authorize: { - request.additionalNavigation = "" this.responders.authorize(request, sendResponse); break; } diff --git a/web/src/api/storage.ts b/web/src/api/storage.ts index 11af573d..ba853200 100644 --- a/web/src/api/storage.ts +++ b/web/src/api/storage.ts @@ -1,4 +1,4 @@ -import { API_ERRORS } from "../utils/configs"; +import { API_ERRORS, TOPL_URLS } from "../utils/configs"; export const ExtensionStorage = { addToAllowList: async (url: string) => { @@ -18,10 +18,15 @@ export const ExtensionStorage = { }, getAllowList: async (): Promise => { const storage = await ExtensionStorage.getStorage(); - return storage.allowList ?? []; + let allowList = []; + if (storage.allowList) { + allowList = storage.allowList.filter((url: string) => !TOPL_URLS.includes(url)); + } + return allowList ?? []; }, getAllowedString: async (): Promise => { const storage = await ExtensionStorage.getStorage(); + console.log("allow list: ", storage.allowList.toString()); return storage.allowList.toString() ?? ""; }, clearAllowList: async () => { @@ -45,5 +50,5 @@ export const ExtensionStorage = { isOriginAllowed: async (originUrl: string) => { const currentAllowList: string[] = await ExtensionStorage.getAllowList(); return currentAllowList.some((allowedUrl) => allowedUrl.includes(originUrl)); - } + }, }; diff --git a/web/src/scripts/background.ts b/web/src/scripts/background.ts index dc2322d7..4c38979c 100644 --- a/web/src/scripts/background.ts +++ b/web/src/scripts/background.ts @@ -1,5 +1,15 @@ import { Messenger } from "../api/messenger"; +import { ExtensionStorage } from "../api/storage"; +import { TOPL_URLS } from "../utils/configs"; +/** + * Event fired upon initial installation of the extension + */ +chrome.runtime.onInstalled.addListener(async () => { + for (const url of TOPL_URLS) { + await ExtensionStorage.addToAllowList(url); + } +}); const messenger = Messenger.createBackgroundMessagingController(); messenger.initListener(); diff --git a/web/src/utils/types.ts b/web/src/utils/types.ts index 6ab83c5a..3adc417b 100644 --- a/web/src/utils/types.ts +++ b/web/src/utils/types.ts @@ -12,5 +12,4 @@ export type InternalMessage = { error?: Record; event?: string; origin?: string; - additionalNavigation?:string }; \ No newline at end of file