diff --git a/README.md b/README.md index fe477448..214c8eff 100644 --- a/README.md +++ b/README.md @@ -9,12 +9,12 @@ The Oxen Wallet is a Fork of the Cake Wallet. flutter pub get ``` -2. Run the build_runner +2. Run the build_runner to create generated dependency files: ```shell script - flutter pub run build_runner build + flutter pub run build_runner build --delete-conflicting-outputs ``` -3. To download the latest build of the Oxen Dependencies run +3. To download the latest build of the Oxen Dependencies run: ``` ./tool/download-android-deps.sh https://oxen.rocks/oxen-io/oxen-core/oxen-stable-android-deps-LATEST.tar.xz ./tool/download-ios-deps.sh https://oxen.rocks/oxen-io/oxen-core/oxen-stable-ios-deps-LATEST.tar.xz @@ -42,6 +42,16 @@ The Oxen Wallet is a Fork of the Cake Wallet. flutter run ``` + or build APKs with: + ```shell script + flutter build apk --split-per-abi + ``` + + or build an .aab (for Google Play Store) with: + ```shell script + flutter build appbundle + ``` + ## Copyright Copyright (c) 2020 Konstantin Ullrich.\ Copyright (c) 2020 Cake Technologies LLC. diff --git a/analysis_options.yaml b/analysis_options.yaml index 3f170e61..663d41f8 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -11,47 +11,48 @@ analyzer: linter: rules: - - always_declare_return_types - - annotate_overrides - - avoid_empty_else - - avoid_init_to_null - - avoid_return_types_on_setters - - await_only_futures - - camel_case_types - - cancel_subscriptions - - close_sinks - - comment_references - - constant_identifier_names - - control_flow_in_finally - - empty_catches - - empty_constructor_bodies - - empty_statements - - hash_and_equals - - implementation_imports - - invariant_booleans - - iterable_contains_unrelated_type - - library_names - - library_prefixes - - list_remove_unrelated_type - - literal_only_boolean_expressions - - non_constant_identifier_names - - one_member_abstracts - - only_throw_errors - - overridden_fields - - package_api_docs - - package_names - - package_prefixed_library_names - - parameter_assignments - - prefer_final_fields - - prefer_final_locals - - prefer_is_not_empty - - slash_for_doc_comments - - sort_constructors_first - - sort_unnamed_constructors_first - - test_types_in_equals - - throw_in_finally - - type_init_formals - - unawaited_futures - - unnecessary_getters_setters - - unrelated_type_equality_checks - - valid_regexps \ No newline at end of file + always_declare_return_types: true + annotate_overrides: true + avoid_empty_else: true + avoid_init_to_null: true + avoid_return_types_on_setters: true + await_only_futures: true + camel_case_types: true + cancel_subscriptions: true + close_sinks: true + comment_references: true + constant_identifier_names: true + control_flow_in_finally: true + curly_braces_in_flow_control_structures: false + empty_catches: true + empty_constructor_bodies: true + empty_statements: true + hash_and_equals: true + implementation_imports: true + invariant_booleans: true + iterable_contains_unrelated_type: true + library_names: true + library_prefixes: true + list_remove_unrelated_type: true + literal_only_boolean_expressions: true + non_constant_identifier_names: true + one_member_abstracts: true + only_throw_errors: true + overridden_fields: true + package_api_docs: true + package_names: true + package_prefixed_library_names: true + parameter_assignments: true + prefer_final_fields: true + prefer_final_locals: true + prefer_is_not_empty: true + slash_for_doc_comments: true + sort_constructors_first: true + sort_unnamed_constructors_first: true + test_types_in_equals: true + throw_in_finally: true + type_init_formals: true + unawaited_futures: true + unnecessary_getters_setters: true + unrelated_type_equality_checks: true + valid_regexps: true \ No newline at end of file diff --git a/android/app/build.gradle b/android/app/build.gradle index f0879166..52b6efd7 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -32,7 +32,7 @@ apply plugin: 'kotlin-android' apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" android { - compileSdkVersion 29 + compileSdkVersion 31 sourceSets { main.java.srcDirs += 'src/main/kotlin' @@ -51,11 +51,25 @@ android { externalNativeBuild { cmake { - cppFlags "-std=c++11" - arguments '-DANDROID_STL=c++_shared', '-DBUILD_TESTING=OFF' - version "3.10.2" + cppFlags "-std=c++17" + arguments '-DANDROID_STL=c++_shared' + version "3.18.0+" } } + + ndk { + abiFilters.clear() +// abiFilters 'x86_64', 'armeabi-v7a', 'arm64-v8a' + } + } + + splits { + abi { + enable true //enables the ABIs split mechanism + reset() //reset the list of ABIs to be included to an empty string + include 'arm64-v8a', 'armeabi-v7a', 'x86_64' + universalApk true + } } signingConfigs { @@ -73,9 +87,6 @@ android { signingConfig signingConfigs.release minifyEnabled true - useProguard true - - proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } } diff --git a/android/build.gradle b/android/build.gradle index 7087ad19..2ed02f9a 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -1,12 +1,12 @@ buildscript { - ext.kotlin_version = '1.4.10' + ext.kotlin_version = '1.6.20' repositories { google() jcenter() } dependencies { - classpath 'com.android.tools.build:gradle:3.5.0' + classpath 'com.android.tools.build:gradle:7.1.3' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" } } diff --git a/android/gradle.properties b/android/gradle.properties index 38c8d454..3a661474 100644 --- a/android/gradle.properties +++ b/android/gradle.properties @@ -1,4 +1,5 @@ org.gradle.jvmargs=-Xmx1536M -android.enableR8=true android.useAndroidX=true android.enableJetifier=true +android.native.buildOutput=verbose +android.bundle.enableUncompressedNativeLibs = false diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties index 296b146b..b776d4b5 100644 --- a/android/gradle/wrapper/gradle-wrapper.properties +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-all.zip diff --git a/assets/faq/faq_de.json b/assets/faq/faq_de.json index 61542016..2bada99f 100644 --- a/assets/faq/faq_de.json +++ b/assets/faq/faq_de.json @@ -1,50 +1,50 @@ [ { "question" : "Was ist der Unterschied zwischen verfügbarem Guthaben und vollständigem Guthaben?", - "answer" : "Nachdem Sie eine Transaktion getätigt oder Oxen erhalten haben, muss die Transaktion noch bestätigt werden. In ungefähr 20 Minuten sollte Ihr \"verfügbares Guthaben\" aktualisiert werden!\nWenn Sie Oxen senden, verringert sich manchmal Ihr verfügbares Guthaben um mehr als den Betrag, den Sie gesendet haben. Dies ist normal und zum Schutz Ihrer Privatsphäre erforderlich. Ihr \"vollständiges Gleichgewicht\" sollte in 20 Minuten wieder normal sein.\n" + "answer" : "Nachdem Sie eine Transaktion getätigt oder Oxen erhalten haben, muss die Transaktion noch bestätigt werden. In ungefähr 20 Minuten sollte Ihr \"verfügbares Guthaben\" aktualisiert werden!\n\nWenn Sie Oxen senden, verringert sich manchmal Ihr verfügbares Guthaben um mehr als den Betrag, den Sie gesendet haben. Dies ist normal und zum Schutz Ihrer Privatsphäre erforderlich. Ihr \"vollständiges Gleichgewicht\" sollte in 20 Minuten wieder normal sein." }, { "question" : "Was bedeuten \"Seed\" und \"Schlüssel\"?", - "answer" : "Ihre Schlüssel verschlüsseln die privaten Informationen in Ihres Wallets und ermöglichen es Ihnen, Coins auszugeben und eingehende Transaktionen anzuzeigen.\nIhr Seed ist nur eine Version Ihres privaten Schlüssels, die so geschrieben wurde, dass Sie sie leichter notieren können. Ihr Seed und Schlüssel sind tatsächlich dasselbe, nur in verschiedenen Formen!\nGeben Sie niemals Ihren Seed oder Schlüssel an jemanden weiter. Ihr Geld wird gestohlen, wenn Sie Ihren Seed oder Schlüssel herausgeben. Bitte notieren Sie sich jedoch Ihren Seed und bewahren Sie ihn an einem sicheren Ort auf (so können Sie Ihr Wallet wiederherstellen, wenn Sie Ihr Telefon verlieren.)\n" + "answer" : "Ihre Schlüssel verschlüsseln die privaten Informationen in Ihres Wallets und ermöglichen es Ihnen, Coins auszugeben und eingehende Transaktionen anzuzeigen.\n\nIhr Seed ist nur eine Version Ihres privaten Schlüssels, die so geschrieben wurde, dass Sie sie leichter notieren können. Ihr Seed und Schlüssel sind tatsächlich dasselbe, nur in verschiedenen Formen!\n\nGeben Sie niemals Ihren Seed oder Schlüssel an jemanden weiter. Ihr Geld wird gestohlen, wenn Sie Ihren Seed oder Schlüssel herausgeben. Bitte notieren Sie sich jedoch Ihren Seed und bewahren Sie ihn an einem sicheren Ort auf (so können Sie Ihr Wallet wiederherstellen, wenn Sie Ihr Telefon verlieren.)" }, { "question" : "Wie viele Wallets kann ich erstellen?", - "answer" : "Es gibt keine Grenzen! Sie können so viele Wallets erstellen, wie Sie möchten.\n" + "answer" : "Es gibt keine Grenzen! Sie können so viele Wallets erstellen, wie Sie möchten." }, { "question" : "Wie kann ich mein Wallet wiederherstellen?", - "answer" : "Tippen Sie auf das Profil Icon auf ihrem Dashboard (oben rechts), wählen Sie „Wallets“ und dann „Wallet wiederherstellen“. Geben Sie dann Ihren Seed (oder Ihre Schlüssel) und optional ein Datum vor der ersten Transaktion in Ihrer Brieftasche ein (dies beschleunigt den Synchronisierungsvorgang) .) Möglicherweise müssen Sie die App 15 bis 30 Minuten geöffnet lassen, um Ihr Wallet vollständig wiederherzustellen.\n" + "answer" : "Tippen Sie auf das Profil Icon auf ihrem Dashboard (oben rechts), wählen Sie „Wallets“ und dann „Wallet wiederherstellen“. Geben Sie dann Ihren Seed (oder Ihre Schlüssel) und optional ein Datum vor der ersten Transaktion in Ihrer Brieftasche ein (dies beschleunigt den Synchronisierungsvorgang) .) Möglicherweise müssen Sie die App 15 bis 30 Minuten geöffnet lassen, um Ihr Wallet vollständig wiederherzustellen." }, { "question" : "Was kann ich tun, wenn ich meinen Seed verliere?", - "answer" : "Wenn Sie Ihren Seed vergessen haben, haben Sie ihn wahrscheinlich irgendwo aufgeschrieben. Bitte überprüfen Sie Ihre Notizen und schauen Sie sich auf Ihrem Computer um. Wenn Sie es nirgendwo finden, haben Sie möglicherweise Oxen Wallet gesichert (in diesem Fall können Sie es aus diesem Backup wiederherstellen.) Wenn keines von beidem der Fall ist, können wir leider nichts tun.\n" + "answer" : "Wenn Sie Ihren Seed vergessen haben, haben Sie ihn wahrscheinlich irgendwo aufgeschrieben. Bitte überprüfen Sie Ihre Notizen und schauen Sie sich auf Ihrem Computer um. Wenn Sie es nirgendwo finden, haben Sie möglicherweise Oxen Wallet gesichert (in diesem Fall können Sie es aus diesem Backup wiederherstellen.) Wenn keines von beidem der Fall ist, können wir leider nichts tun." }, { "question" : "Sammeln Sie Informationen zu mir oder meinem Wallet?", - "answer" : "Oxen Wallet sammelt oder zeichnet keine Informationen über Sie oder Ihr Wallet auf. Ihre Privatsphäre ist uns wichtig.\nIhre Privatsphäre kann aber duch die Verbindung zu einem bösarigem Knoten kompromitiert werden. Deshalb empfehlen wir, die Standart Knoten oder ihren eigenen zu verwenden. " + "answer" : "Oxen Wallet sammelt oder zeichnet keine Informationen über Sie oder Ihr Wallet auf. Ihre Privatsphäre ist uns wichtig.\n\nIhre Privatsphäre kann aber duch die Verbindung zu einem bösarigem Knoten kompromitiert werden. Deshalb empfehlen wir, die Standart Knoten oder ihren eigenen zu verwenden. " }, { "question" : "Woher die Fiat-Daten?", - "answer" : "Die Fiat-Daten werden durch ein Gateway von CoinGecko geladen.\nDer code des Gateways ist open-source und sammelt oder zeichnet keine Informationen auf, durch das Anfragen der Daten durch das Gateway enthüllen sie Ihre IP und Fiat-Währung.\nDie Fiat Umrechnung ist standartmäßig deaktiviert." + "answer" : "Die Fiat-Daten werden durch ein Gateway von CoinGecko geladen.\n\nDer code des Gateways ist open-source und sammelt oder zeichnet keine Informationen auf, durch das Anfragen der Daten durch das Gateway enthüllen sie Ihre IP und Fiat-Währung.\n\nDie Fiat Umrechnung ist standartmäßig deaktiviert." }, { "question" : "Kann ich eine Transaktion stornieren?", - "answer" : "Sobald eine Transaktion an die Blockchain gesendet wurde, kann sie leider nicht mehr rückgängig gemacht werden. Sie können die Transaktion jederzeit abbrechen, bevor sie gesendet wird. Überprüfen Sie die Adresse daher immer, bevor Sie eine Transaktion senden.\n" + "answer" : "Sobald eine Transaktion an die Blockchain gesendet wurde, kann sie leider nicht mehr rückgängig gemacht werden. Sie können die Transaktion jederzeit abbrechen, bevor sie gesendet wird. Überprüfen Sie die Adresse daher immer, bevor Sie eine Transaktion senden." }, { "question" : "Was sind Subadressen und wie verwende ich sie?", - "answer" : "Eine Unteradresse ist im Grunde eine eindeutige Adresse, die Sie jederzeit generieren können. An sie gesendete Coins landen weiterhin in Ihrem Wallet, aber die Person, die die Coins sendet, kann Ihre Hauptadresse nicht ermitteln.\nSie können eine neue Unteradresse im Empfangsbildschirm erstellen, indem Sie auf das „+“ neben der Schaltfläche Unteradressen tippen. Geben Sie einen Namen für die Unteradresse ein und tippen Sie auf \"Hinzufügen\". Dann tippen Sie einfach auf den Namen der Subadresse, wenn Sie ihn verwenden möchten!\nWenn Sie paranoid sind, sollten Sie wahrscheinlich jedes Mal, wenn Sie Oxen erhalten, eine neue Unteradresse erstellen.\n" + "answer" : "Eine Unteradresse ist im Grunde eine eindeutige Adresse, die Sie jederzeit generieren können. An sie gesendete Coins landen weiterhin in Ihrem Wallet, aber die Person, die die Coins sendet, kann Ihre Hauptadresse nicht ermitteln.\n\nSie können eine neue Unteradresse im Empfangsbildschirm erstellen, indem Sie auf das „+“ neben der Schaltfläche Unteradressen tippen. Geben Sie einen Namen für die Unteradresse ein und tippen Sie auf \"Hinzufügen\". Dann tippen Sie einfach auf den Namen der Subadresse, wenn Sie ihn verwenden möchten!\n\nWenn Sie paranoid sind, sollten Sie wahrscheinlich jedes Mal, wenn Sie Oxen erhalten, eine neue Unteradresse erstellen." }, { "question" : "Ich habe meine OXEN nicht erhalten! Was kann ich tun?", - "answer" : "Wenn Sie Ihr Oxen nicht erhalten haben, möchten Sie möglicherweise auf das Synchonisations Icon auf auf ihrem Dashboard (oben links) tippen und auf Reconnect (Neu verbinden) klicken. Wenn dies nicht funktioniert, gehen Sie in das Einstellungsmenü, tippen Sie auf das Feld \"Aktueller Knoten\" und wählen Sie einen Knoten mit einem grünen Punkt daneben aus.\n" + "answer" : "Wenn Sie Ihr Oxen nicht erhalten haben, möchten Sie möglicherweise auf das Synchonisations Icon auf auf ihrem Dashboard (oben links) tippen und auf Reconnect (Neu verbinden) klicken. Wenn dies nicht funktioniert, gehen Sie in das Einstellungsmenü, tippen Sie auf das Feld \"Aktueller Knoten\" und wählen Sie einen Knoten mit einem grünen Punkt daneben aus." }, { "question" : "Wie kontaktiere ich den Oxen Wallet-Support?", - "answer" : "Senden Sie eine E-Mail an team@oxen.io, schließen Sie sich dem Telegram unter @LokiCommunity an oder twittern Sie @Oxen_io!\n" + "answer" : "Senden Sie eine E-Mail an team@oxen.io, schließen Sie sich dem Telegram unter @LokiCommunity an oder twittern Sie @Oxen_io!" }, { "question" : "Macht mich der Besitz von Oxen zu einem Investor?", - "answer" : "Nein, macht es nicht. Es macht sie zu einer coolen Person mit Oxen.\n" + "answer" : "Nein, macht es nicht. Es macht sie zu einer coolen Person mit Oxen." } -] \ No newline at end of file +] diff --git a/assets/faq/faq_en.json b/assets/faq/faq_en.json index a271e820..37f48484 100644 --- a/assets/faq/faq_en.json +++ b/assets/faq/faq_en.json @@ -1,50 +1,50 @@ [ { "question" : "What’s the difference between Available Balance and Full Balance?", - "answer" : "After you make a transaction or receive some Oxen, the transaction still needs to be confirmed. In about 20 minutes your available balance should update!\nSometimes, when you send Oxen, your available balance will decrease by more than the amount you’ve sent. This is normal, and it’s necessary in order to protect your privacy. Your full balance should be back to normal in 20 minutes.\n" + "answer" : "After you make a transaction or receive some Oxen, the transaction still needs to be confirmed. In about 20 minutes your available balance should update!\n\nSometimes, when you send Oxen, your available balance will decrease by more than the amount you’ve sent. This is normal, and it’s necessary in order to protect your privacy. Your full balance should be back to normal in 20 minutes.\n\nYour Oxen is also locked by the contributed amount when you contribute to a Service Node for the duration of the stake." }, { "question" : "What do \"seed\" and \"keys\" mean?", - "answer" : "Your keys encode the private information in your wallet, and are what allow you to spend coins and see incoming transactions.\nYour seed is just a version of your private key written in a way that’s easier for you to write down. Your seed and keys are actually the same thing, just in different forms!\nDO NOT ever give your seed or keys to anyone. Your funds will be stolen if you give out your seed or keys. Please write down your seed, however, and store it in a safe place (this will allow you to restore your wallet if you lose your phone.)\n" + "answer" : "Your keys encode the private information in your wallet, and are what allow you to spend coins and see incoming transactions.\n\nYour seed is just a version of your private key written in a way that’s easier for you to write down. Your seed and keys are actually the same thing, just in different forms!\n\nDO NOT ever give your seed or keys to anyone. Your funds will be stolen if you give out your seed or keys. Please write down your seed, however, and store it in a safe place (this will allow you to restore your wallet if you lose your phone)." }, { "question" : "How many wallets can I create?", - "answer" : "There is no limit! You can create as many wallets as you want.\n" + "answer" : "There is no limit! You can create as many wallets as you want." }, { "question" : "How can I restore my wallet?", - "answer" : "Tap the profile icon on your dashboard (upper right), select Wallets, and then choose Restore Wallet. Then enter your seed (or your keys), and optionally enter a date before the first transaction in your wallet (this will speed up the syncing process.) You may need to keep the app open for 15-30 minutes in order to completely restore your wallet.\n" + "answer" : "Tap the profile icon on your dashboard (upper right), select Wallets, and then choose Restore Wallet. Then enter your seed (or your keys), and optionally enter a date before the first transaction in your wallet (this will speed up the syncing process.) You may need to keep the app open for 15-30 minutes in order to completely restore your wallet." }, { "question" : "What can I do if I lose my seed?", - "answer" : "If you forgot your seed, you likely wrote it down somewhere. Please check your notes and look around on your computer. If you can’t find it anywhere, you may have backed up Oxen Wallet (in which case you would be able to restore from that backup.) If none of these work, there is unfortunately nothing that we can do.\n" + "answer" : "If you forgot your seed, you likely wrote it down somewhere. Please check your notes and look around on your computer. If you can’t find it anywhere, you may have backed up Oxen Wallet (in which case you would be able to restore from that backup.) If none of these work, there is unfortunately nothing that we can do." }, { "question" : "Do you collect any information about me or my wallet?", - "answer" : "Oxen Wallet DOES NOT collect or record any information about you or your wallet. We care about your privacy.\nYour privacy can be compromised by connecting to a malicious node, so we recommend to use either the default nodes or your own.\n" + "answer" : "Oxen Wallet DOES NOT collect or record any information about you or your wallet. We care about your privacy.\n\nYour privacy can be compromised by connecting to a malicious node, so we recommend to use either the default nodes or your own." }, { "question" : "Where do you get the fiat data from?", - "answer" : "The fiat data is pulled trough a gateway from CoinGecko.\nThe code of the gateway is open-source and does not collect or record any data, but by requesting data from the gateway you are exposing your IP and Fiat.\nThe Fiat conversation is disabled by default.\n" + "answer" : "The fiat data is pulled trough a gateway from CoinGecko.\n\nThe code of the gateway is open-source and does not collect or record any data, but by requesting data from the gateway you are exposing your IP and fiat currency selection.\n\nThe fiat conversation is disabled by default." }, { "question" : "Is it possible to reverse a transaction?", - "answer" : "Unfortunately, as soon as a transaction has been submitted to the blockchain, there is no way to undo it. You can always cancel the transaction before it’s sent though, so always double-check the address before you send a transaction.\n" + "answer" : "Unfortunately, as soon as a transaction has been submitted to the blockchain, there is no way to undo it. You can always cancel the transaction before it’s sent though, so always double-check the address before you send a transaction." }, { "question" : "What are subaddresses, and how do I use them?", - "answer" : "A subaddress is basically a unique address that you can generate at any time. Coins sent to it will still arrive in your main wallet, but the person sending the coins can’t tell what your main address is.\nYou can make a new subaddress in the Receive screen by tapping the + next to the Subaddresses button. Enter a name for the subaddress and tap Add. Then just tap on the subaddress name when you want to use it!\nIf you’re paranoid, you should probably create a new subaddress every time you receive Oxen.\n" + "answer" : "A subaddress is basically a unique address that you can generate at any time. Coins sent to it will still arrive in your main wallet, but the person sending the coins can’t tell what your main address is.\n\nYou can make a new subaddress in the Receive screen by tapping the + next to the Subaddresses button. Enter a name for the subaddress and tap Add. Then just tap on the subaddress name when you want to use it!\n\nIf you’re paranoid, you should probably create a new subaddress every time you receive Oxen." }, { "question" : "I didn't receive my OXEN! What can I do?", - "answer" : "If you didn't receive your Oxen, you might want to tap the Synchronize Icon on your dashboard (upper left) and hit Reconnect. If that doesn't work, go into the settings menu, tap the 'Current Node' box, and select a node with a green dot next to it.\n" + "answer" : "If you didn't receive your Oxen, you might want to tap the Synchronize Icon on your dashboard (upper left) and hit Reconnect. If that doesn't work, go into the settings menu, tap the 'Current Node' box, and select a node with a green dot next to it." }, { "question" : "How do I contact Oxen Wallet support?", - "answer" : "Email team@oxen.io, join the Telegram at @LokiCommunity, or tweet @Oxen_io!\n" + "answer" : "Email team@oxen.io, join the Telegram at @LokiCommunity, or tweet @Oxen_io!" }, { "question" : "Does owning Oxen make me an Investor?", - "answer" : "No, it does not. It makes you a cool person, but with Oxen.\n" + "answer" : "No, it does not. It makes you a cool person, but with Oxen." } -] \ No newline at end of file +] diff --git a/assets/images/2.0x/Session.png b/assets/images/2.0x/Session.png new file mode 100644 index 00000000..81669b9e Binary files /dev/null and b/assets/images/2.0x/Session.png differ diff --git a/assets/images/3.0x/Session.png b/assets/images/3.0x/Session.png new file mode 100644 index 00000000..1d544a11 Binary files /dev/null and b/assets/images/3.0x/Session.png differ diff --git a/assets/images/Session.png b/assets/images/Session.png new file mode 100644 index 00000000..0fb22a9e Binary files /dev/null and b/assets/images/Session.png differ diff --git a/assets/node_list.yml b/assets/node_list.yml index d18d87d7..92a29480 100644 --- a/assets/node_list.yml +++ b/assets/node_list.yml @@ -1,12 +1,8 @@ - uri: public.loki.foundation:22023 - is_default: true +- + uri: freyr.imaginary.stream:22023 - uri: nodes.hashvault.pro:22023 - is_default: false - uri: node.loki-pool.com:18081 - is_default: false -- - uri: freyr.imaginary.stream:22023 - is_default: false diff --git a/assets/testnet_node_list.yml b/assets/testnet_node_list.yml index 85a00653..d48b4aad 100644 --- a/assets/testnet_node_list.yml +++ b/assets/testnet_node_list.yml @@ -1,3 +1,2 @@ - uri: public.loki.foundation:38157 - is_default: true diff --git a/ios/Podfile.lock b/ios/Podfile.lock index acd4b34e..a47d8839 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -1,11 +1,10 @@ PODS: - - barcode_scan (0.0.1): + - barcode_scan2 (0.0.1): - Flutter - MTBBarcodeScanner + - SwiftProtobuf - devicelocale (0.0.1): - Flutter - - esys_flutter_share (0.0.1): - - Flutter - Flutter (1.0.0) - flutter_secure_storage (3.3.1): - Flutter @@ -19,37 +18,39 @@ PODS: - Flutter - package_info (0.0.1): - Flutter - - path_provider (0.0.1): + - path_provider_ios (0.0.1): + - Flutter + - share_plus (0.0.1): - Flutter - - shared_preferences (0.0.1): + - shared_preferences_ios (0.0.1): - Flutter - - url_launcher (0.0.1): + - SwiftProtobuf (1.15.0) + - url_launcher_ios (0.0.1): - Flutter DEPENDENCIES: - - barcode_scan (from `.symlinks/plugins/barcode_scan/ios`) + - barcode_scan2 (from `.symlinks/plugins/barcode_scan2/ios`) - devicelocale (from `.symlinks/plugins/devicelocale/ios`) - - esys_flutter_share (from `.symlinks/plugins/esys_flutter_share/ios`) - Flutter (from `Flutter`) - flutter_secure_storage (from `.symlinks/plugins/flutter_secure_storage/ios`) - local_auth (from `.symlinks/plugins/local_auth/ios`) - oxen_coin (from `.symlinks/plugins/oxen_coin/ios`) - package_info (from `.symlinks/plugins/package_info/ios`) - - path_provider (from `.symlinks/plugins/path_provider/ios`) - - shared_preferences (from `.symlinks/plugins/shared_preferences/ios`) - - url_launcher (from `.symlinks/plugins/url_launcher/ios`) + - path_provider_ios (from `.symlinks/plugins/path_provider_ios/ios`) + - share_plus (from `.symlinks/plugins/share_plus/ios`) + - shared_preferences_ios (from `.symlinks/plugins/shared_preferences_ios/ios`) + - url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`) SPEC REPOS: trunk: - MTBBarcodeScanner + - SwiftProtobuf EXTERNAL SOURCES: - barcode_scan: - :path: ".symlinks/plugins/barcode_scan/ios" + barcode_scan2: + :path: ".symlinks/plugins/barcode_scan2/ios" devicelocale: :path: ".symlinks/plugins/devicelocale/ios" - esys_flutter_share: - :path: ".symlinks/plugins/esys_flutter_share/ios" Flutter: :path: Flutter flutter_secure_storage: @@ -60,27 +61,30 @@ EXTERNAL SOURCES: :path: ".symlinks/plugins/oxen_coin/ios" package_info: :path: ".symlinks/plugins/package_info/ios" - path_provider: - :path: ".symlinks/plugins/path_provider/ios" - shared_preferences: - :path: ".symlinks/plugins/shared_preferences/ios" - url_launcher: - :path: ".symlinks/plugins/url_launcher/ios" + path_provider_ios: + :path: ".symlinks/plugins/path_provider_ios/ios" + share_plus: + :path: ".symlinks/plugins/share_plus/ios" + shared_preferences_ios: + :path: ".symlinks/plugins/shared_preferences_ios/ios" + url_launcher_ios: + :path: ".symlinks/plugins/url_launcher_ios/ios" SPEC CHECKSUMS: - barcode_scan: 33f586d02270046fc6559135038b34b5754eaa4f + barcode_scan2: 0af2bb63c81b4565aab6cd78278e4c0fa136dbb0 devicelocale: b22617f40038496deffba44747101255cee005b0 - esys_flutter_share: 403498dab005b36ce1f8d7aff377e81f0621b0b4 - Flutter: 434fef37c0980e73bb6479ef766c45957d4b510c + Flutter: 50d75fe2f02b26cc09d224853bb45737f8b3214a flutter_secure_storage: 7953c38a04c3fdbb00571bcd87d8e3b5ceb9daec - local_auth: 25938960984c3a7f6e3253e3f8d962fdd16852bd + local_auth: 1740f55d7af0a2e2a8684ce225fe79d8931e808c MTBBarcodeScanner: f453b33c4b7dfe545d8c6484ed744d55671788cb oxen_coin: a5a9e565bab069b0d5670ecb7bfd5d605b1c055a package_info: 873975fc26034f0b863a300ad47e7f1ac6c7ec62 - path_provider: abfe2b5c733d04e238b0d8691db0cfd63a27a93c - shared_preferences: af6bfa751691cdc24be3045c43ec037377ada40d - url_launcher: 6fef411d543ceb26efce54b05a0a40bfd74cbbef + path_provider_ios: 14f3d2fd28c4fdb42f44e0f751d12861c43cee02 + share_plus: 056a1e8ac890df3e33cb503afffaf1e9b4fbae68 + shared_preferences_ios: 548a61f8053b9b8a49ac19c1ffbc8b92c50d68ad + SwiftProtobuf: 3320217e9d8fb75f36b40282e78c482640fd75dd + url_launcher_ios: 839c58cdb4279282219f5e248c3321761ff3c4de PODFILE CHECKSUM: f10c0438b63bc24e6bbc207956dc27d16c4408f2 -COCOAPODS: 1.10.0 +COCOAPODS: 1.11.3 diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index a81e9508..95b999a3 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -168,7 +168,7 @@ 97C146E61CF9000F007C117D /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 1020; + LastUpgradeCheck = 1300; ORGANIZATIONNAME = ""; TargetAttributes = { 97C146ED1CF9000F007C117D = { diff --git a/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata index 1d526a16..919434a6 100644 --- a/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata +++ b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -2,6 +2,6 @@ + location = "self:"> diff --git a/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index f9dd4970..d57d2d29 100644 --- a/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -1,6 +1,6 @@ CFBundlePackageType APPL CFBundleShortVersionString - $(MARKETING_VERSION) + $(FLUTTER_BUILD_NAME) CFBundleSignature ???? CFBundleVersion - $(CURRENT_PROJECT_VERSION) + $(FLUTTER_BUILD_NUMBER) ITSAppUsesNonExemptEncryption LSRequiresIPhoneOS diff --git a/l10n.yaml b/l10n.yaml new file mode 100644 index 00000000..4f4c96e2 --- /dev/null +++ b/l10n.yaml @@ -0,0 +1,4 @@ +arb-dir: lib/l10n +template-arb-file: app_en.arb +output-localization-file: app_localizations.dart +#output-dir: lib/generated diff --git a/lib/generated/intl/messages_all.dart b/lib/generated/intl/messages_all.dart deleted file mode 100644 index f6bf2b15..00000000 --- a/lib/generated/intl/messages_all.dart +++ /dev/null @@ -1,71 +0,0 @@ -// DO NOT EDIT. This is code generated via package:intl/generate_localized.dart -// This is a library that looks up messages for specific locales by -// delegating to the appropriate library. - -// Ignore issues from commonly used lints in this file. -// ignore_for_file:implementation_imports, file_names, unnecessary_new -// ignore_for_file:unnecessary_brace_in_string_interps, directives_ordering -// ignore_for_file:argument_type_not_assignable, invalid_assignment -// ignore_for_file:prefer_single_quotes, prefer_generic_function_type_aliases -// ignore_for_file:comment_references - -import 'dart:async'; - -import 'package:intl/intl.dart'; -import 'package:intl/message_lookup_by_library.dart'; -import 'package:intl/src/intl_helpers.dart'; - -import 'messages_de.dart' as messages_de; -import 'messages_en.dart' as messages_en; -import 'messages_fr.dart' as messages_fr; - -typedef Future LibraryLoader(); -Map _deferredLibraries = { - 'de': () => new Future.value(null), - 'en': () => new Future.value(null), - 'fr': () => new Future.value(null), -}; - -MessageLookupByLibrary _findExact(String localeName) { - switch (localeName) { - case 'de': - return messages_de.messages; - case 'en': - return messages_en.messages; - case 'fr': - return messages_fr.messages; - default: - return null; - } -} - -/// User programs should call this before using [localeName] for messages. -Future initializeMessages(String localeName) async { - var availableLocale = Intl.verifiedLocale( - localeName, - (locale) => _deferredLibraries[locale] != null, - onFailure: (_) => null); - if (availableLocale == null) { - return new Future.value(false); - } - var lib = _deferredLibraries[availableLocale]; - await (lib == null ? new Future.value(false) : lib()); - initializeInternalMessageLookup(() => new CompositeMessageLookup()); - messageLookup.addLocale(availableLocale, _findGeneratedMessagesFor); - return new Future.value(true); -} - -bool _messagesExistFor(String locale) { - try { - return _findExact(locale) != null; - } catch (e) { - return false; - } -} - -MessageLookupByLibrary _findGeneratedMessagesFor(String locale) { - var actualLocale = Intl.verifiedLocale(locale, _messagesExistFor, - onFailure: (_) => null); - if (actualLocale == null) return null; - return _findExact(actualLocale); -} diff --git a/lib/generated/intl/messages_de.dart b/lib/generated/intl/messages_de.dart deleted file mode 100644 index 9d9e2958..00000000 --- a/lib/generated/intl/messages_de.dart +++ /dev/null @@ -1,305 +0,0 @@ -// DO NOT EDIT. This is code generated via package:intl/generate_localized.dart -// This is a library that provides messages for a de locale. All the -// messages from the main program should be duplicated here with the same -// function name. - -// Ignore issues from commonly used lints in this file. -// ignore_for_file:unnecessary_brace_in_string_interps, unnecessary_new -// ignore_for_file:prefer_single_quotes,comment_references, directives_ordering -// ignore_for_file:annotate_overrides,prefer_generic_function_type_aliases -// ignore_for_file:unused_import, file_names - -import 'package:intl/intl.dart'; -import 'package:intl/message_lookup_by_library.dart'; - -final messages = new MessageLookup(); - -typedef String MessageIfAbsent(String messageStr, List args); - -class MessageLookup extends MessageLookupByLibrary { - String get localeName => 'de'; - - static m0(status) => "${status} verbleibende Blöcke"; - - static m1(serviceNodeKey) => "Möchtest du wirkklich dein Stake von ${serviceNodeKey} entsperren?"; - - static m2(node) => "Möchten Sie den aktuellen Knoten wirklich auf ändern? ${node}?"; - - static m3(language) => "Ändern Sie die Sprache zu ${language}?"; - - static m4(amount, fee) => "Transaktion festschreiben\nMenge: ${amount}\nGebühr: ${fee}"; - - static m5(key) => "Kopiert ${key} in die Zwischenablage"; - - static m6(item, app_store) => "Geben sie NIEMALS ihren Oxen wallet ${item} in einer andere software oder website außer den OFFIZIELLEN Oxen wallets aus dem ${app_store}, der Oxen website, der dem Oxen GitHub.\nMöchtest du wirklich fortfahren?"; - - static m7(state_error) => "Authentifizierung fehlgeschlagen. ${state_error}"; - - static m8(item) => "Geben sie NIEMALS ihren Oxen wallet ${item} weiter!"; - - static m9(recipient_name) => "Sie senden Geld an\n${recipient_name}"; - - static m10(name) => "Keine Route definiert für ${name}"; - - static m11(transactionPriority) => "Derzeit ist die Priorität auf ${transactionPriority} festgelegt.\nDie Transaktionspriorität kann in den Einstellungen angepasst werden"; - - static m12(title) => "${title} in die Zwischenablage kopiert"; - - static m13(currentVersion) => "Ausführung ${currentVersion}"; - - static m14(wallet_name, error) => "Laden fehlgeschlagen ${wallet_name} Wallet. ${error}"; - - static m15(wallet_name, error) => "Fehler beim Entfernen ${wallet_name} Wallet. ${error}"; - - static m16(wallet_name) => "Wallet ${wallet_name} wird geladen"; - - static m17(wallet_name) => "Wallet ${wallet_name} entfernen"; - - final messages = _notInlinedMessages(_notInlinedMessages); - static _notInlinedMessages(_) => { - "Blocks_remaining" : m0, - "account" : MessageLookupByLibrary.simpleMessage("Konto"), - "accounts" : MessageLookupByLibrary.simpleMessage("Konten"), - "add" : MessageLookupByLibrary.simpleMessage("Hinzufügen"), - "add_new_word" : MessageLookupByLibrary.simpleMessage("Neues Wort hinzufügen"), - "address_book" : MessageLookupByLibrary.simpleMessage("Adressbuch"), - "address_book_menu" : MessageLookupByLibrary.simpleMessage("Adressbuch"), - "all" : MessageLookupByLibrary.simpleMessage("ALLE"), - "amount" : MessageLookupByLibrary.simpleMessage("Menge: "), - "amount_detail_detailed" : MessageLookupByLibrary.simpleMessage("4 - Detailliert"), - "amount_detail_none" : MessageLookupByLibrary.simpleMessage("0 - Keine"), - "amount_detail_normal" : MessageLookupByLibrary.simpleMessage("2 - Normal"), - "amount_detail_ultra" : MessageLookupByLibrary.simpleMessage("9 - Ultra"), - "auth_store_ban_timeout" : MessageLookupByLibrary.simpleMessage("Auszeit verbieten"), - "auth_store_banned_for" : MessageLookupByLibrary.simpleMessage("Gebannt für "), - "auth_store_banned_minutes" : MessageLookupByLibrary.simpleMessage(" Protokoll"), - "auth_store_incorrect_password" : MessageLookupByLibrary.simpleMessage("Falsches PIN"), - "authenticated" : MessageLookupByLibrary.simpleMessage("Authentifiziert"), - "authentication" : MessageLookupByLibrary.simpleMessage("Authentifizierung"), - "available_balance" : MessageLookupByLibrary.simpleMessage("Verfügbares Guthaben"), - "biometric_auth_reason" : MessageLookupByLibrary.simpleMessage("Scannen Sie Ihren Fingerabdruck zur Authentifizierung"), - "body_confirm_unlock_stake" : m1, - "cancel" : MessageLookupByLibrary.simpleMessage("Abbrechen"), - "change" : MessageLookupByLibrary.simpleMessage("Veränderung"), - "change_current_node" : m2, - "change_language" : MessageLookupByLibrary.simpleMessage("Sprache ändern"), - "change_language_to" : m3, - "changelog" : MessageLookupByLibrary.simpleMessage("Änderungsprotokoll"), - "clear" : MessageLookupByLibrary.simpleMessage("Löschen"), - "commit_transaction_amount_fee" : m4, - "confirm" : MessageLookupByLibrary.simpleMessage("Bestätigen"), - "confirm_sending" : MessageLookupByLibrary.simpleMessage("Bestätigen Sie das Senden"), - "contact" : MessageLookupByLibrary.simpleMessage("Kontakt"), - "contact_name" : MessageLookupByLibrary.simpleMessage("Name des Ansprechpartners"), - "continue_text" : MessageLookupByLibrary.simpleMessage("Fortsetzen"), - "copied_key_to_clipboard" : m5, - "copied_to_clipboard" : MessageLookupByLibrary.simpleMessage("In die Zwischenablage kopiert"), - "copy" : MessageLookupByLibrary.simpleMessage("Kopieren"), - "create_new" : MessageLookupByLibrary.simpleMessage("Neu erstellen"), - "dangerzone" : MessageLookupByLibrary.simpleMessage("Gefahrenzone"), - "dangerzone_warning" : m6, - "delete" : MessageLookupByLibrary.simpleMessage("Löschen"), - "digit_pin" : MessageLookupByLibrary.simpleMessage("-stelliger PIN"), - "edit" : MessageLookupByLibrary.simpleMessage("Bearbeiten"), - "enter_your_pin" : MessageLookupByLibrary.simpleMessage("PIN eingeben"), - "enter_your_pin_again" : MessageLookupByLibrary.simpleMessage("Geben Sie Ihre PIN erneut ein"), - "error" : MessageLookupByLibrary.simpleMessage("Error"), - "error_text_account_name" : MessageLookupByLibrary.simpleMessage("Der Kontoname darf nur Buchstaben und Zahlen enthalten\nund muss zwischen 1 und 15 Zeichen lang sein"), - "error_text_address" : MessageLookupByLibrary.simpleMessage("Die Walletadresse muss dem Typ der Kryptowährung\nentsprechen"), - "error_text_amount" : MessageLookupByLibrary.simpleMessage("Betrag kann nur Zahlen enthalten"), - "error_text_contact_name" : MessageLookupByLibrary.simpleMessage("Im Kontaktname könne die Symbole ` , \' \" nicht enthalten sein\nund muss zwischen 1 und 32 Zeichen lang sein"), - "error_text_crypto_currency" : MessageLookupByLibrary.simpleMessage("Die Anzahl der Nachkommastellen\nmuss kleiner oder gleich 12 sein."), - "error_text_fiat" : MessageLookupByLibrary.simpleMessage("Der Wert des Betrags darf den verfügbaren Kontostand nicht überschreiten.\nDie Anzahl der Nachkommastellen muss kleiner oder gleich 2 sein"), - "error_text_keys" : MessageLookupByLibrary.simpleMessage("Walletschlüssel können nur 64 hexadezimale Zeichen enthalten"), - "error_text_node_address" : MessageLookupByLibrary.simpleMessage("Bitte geben Sie eine iPv4-Adresse ein"), - "error_text_node_port" : MessageLookupByLibrary.simpleMessage("Der Knotenport kann nur Nummern zwischen 0 und 65535 enthalten"), - "error_text_oxen" : MessageLookupByLibrary.simpleMessage("Der OXEN-Wert kann das verfügbare Guthaben nicht überschreiten.\nDie Anzahl der Nachkommastellen muss kleiner oder gleich 12 sein"), - "error_text_payment_id" : MessageLookupByLibrary.simpleMessage("Die Zahlungs-ID kann nur 16 bis 64 hexadezimale Zeichen enthalten"), - "error_text_service_node" : MessageLookupByLibrary.simpleMessage("Service Node Schlüssel können nur 64 hexadezimale Zeichen enthalten"), - "error_text_subaddress_name" : MessageLookupByLibrary.simpleMessage("Im Namen der Unteradresse könne die Symbole ` , \' \" nicht enthalten sein\nund muss zwischen 1 und 20 Zeichen lang sein"), - "error_text_wallet_name" : MessageLookupByLibrary.simpleMessage("Der Walletname darf nur Buchstaben und Zahlen enthalten\nund muss zwischen 1 und 15 Zeichen lang sein"), - "failed_authentication" : m7, - "faq" : MessageLookupByLibrary.simpleMessage("FAQ"), - "fetching" : MessageLookupByLibrary.simpleMessage("aktualisieren"), - "filters" : MessageLookupByLibrary.simpleMessage("Filter"), - "first_wallet_text" : MessageLookupByLibrary.simpleMessage("Das tolle Wallet\nfür Oxen"), - "full_balance" : MessageLookupByLibrary.simpleMessage("Volles Guthaben"), - "hidden_balance" : MessageLookupByLibrary.simpleMessage("Verstecktes Guthaben"), - "id" : MessageLookupByLibrary.simpleMessage("ID: "), - "incoming" : MessageLookupByLibrary.simpleMessage("Eingehend"), - "incorrect_seed" : MessageLookupByLibrary.simpleMessage("Der eingegebene Text ist ungültig."), - "keys_title" : MessageLookupByLibrary.simpleMessage("Schlüssel"), - "loading_your_wallet" : MessageLookupByLibrary.simpleMessage("Wallet wird geladen"), - "login" : MessageLookupByLibrary.simpleMessage("Einloggen"), - "never_give_your" : m8, - "new_subaddress_create" : MessageLookupByLibrary.simpleMessage("Erstellen"), - "new_subaddress_label_name" : MessageLookupByLibrary.simpleMessage("Name"), - "new_subaddress_title" : MessageLookupByLibrary.simpleMessage("Neue Unteradresse"), - "new_wallet" : MessageLookupByLibrary.simpleMessage("Neues Wallet"), - "node_address" : MessageLookupByLibrary.simpleMessage("Knotenadresse"), - "node_new" : MessageLookupByLibrary.simpleMessage("Neuer Knoten"), - "node_port" : MessageLookupByLibrary.simpleMessage("Knotenport"), - "node_reset_settings_title" : MessageLookupByLibrary.simpleMessage("Einstellungen zurücksetzen"), - "nodes" : MessageLookupByLibrary.simpleMessage("Knoten"), - "nodes_list_reset_to_default_message" : MessageLookupByLibrary.simpleMessage("Möchten Sie die Einstellungen wirklich auf die Standardeinstellungen zurücksetzen?"), - "nothing_staked" : MessageLookupByLibrary.simpleMessage("Noch nichts gestaked"), - "ok" : MessageLookupByLibrary.simpleMessage("OK"), - "openalias_alert_content" : m9, - "openalias_alert_title" : MessageLookupByLibrary.simpleMessage("OXEN-Empfänger erkannt"), - "outgoing" : MessageLookupByLibrary.simpleMessage("Ausgehend"), - "oxen_available_balance" : MessageLookupByLibrary.simpleMessage("OXEN verfügbares Guthaben"), - "oxen_full_balance" : MessageLookupByLibrary.simpleMessage("OXEN volles Guthaben"), - "oxen_hidden" : MessageLookupByLibrary.simpleMessage("OXEN versteckt"), - "password" : MessageLookupByLibrary.simpleMessage("Passwort"), - "paste" : MessageLookupByLibrary.simpleMessage("Einfügen"), - "pending" : MessageLookupByLibrary.simpleMessage(" (steht aus)"), - "pin_is_incorrect" : MessageLookupByLibrary.simpleMessage("PIN ist falsch"), - "please_make_selection" : MessageLookupByLibrary.simpleMessage("Bitte treffen Sie unten eine Auswahl zu\nErstellen oder Wiederherstellen Ihres Wallets."), - "please_select" : MessageLookupByLibrary.simpleMessage("Bitte auswählen:"), - "please_try_to_connect_to_another_node" : MessageLookupByLibrary.simpleMessage("Bitte versuchen Sie, eine Verbindung zu einem anderen Knoten herzustellen"), - "receive" : MessageLookupByLibrary.simpleMessage("Erhalten"), - "receive_amount" : MessageLookupByLibrary.simpleMessage("Menge"), - "received" : MessageLookupByLibrary.simpleMessage("Empfangen"), - "reconnect" : MessageLookupByLibrary.simpleMessage("Erneut verbinden"), - "reconnect_alert_text" : MessageLookupByLibrary.simpleMessage("Sind Sie sicher, dass Sie die Verbindung wiederherstellen möchten?"), - "reconnection" : MessageLookupByLibrary.simpleMessage("Wiederverbindung"), - "reload_fiat" : MessageLookupByLibrary.simpleMessage("Fiat-Kurs neuladen"), - "remove" : MessageLookupByLibrary.simpleMessage("Löschen"), - "remove_node" : MessageLookupByLibrary.simpleMessage("Knoten entfernen"), - "remove_node_message" : MessageLookupByLibrary.simpleMessage("Möchten Sie den ausgewählten Knoten wirklich entfernen?"), - "rescan" : MessageLookupByLibrary.simpleMessage("Erneut scannen"), - "reset" : MessageLookupByLibrary.simpleMessage("Zurücksetzen"), - "restore_address" : MessageLookupByLibrary.simpleMessage("Adresse"), - "restore_description_from_backup" : MessageLookupByLibrary.simpleMessage("Sie können die gesamte Oxen Wallet-App aus ihrer Sicherungsdatei wiederherstellen."), - "restore_description_from_keys" : MessageLookupByLibrary.simpleMessage("Stellen Sie Ihr Wallet von generiert wieder her Tastenanschläge, die von Ihren privaten Schlüsseln gespeichert wurden"), - "restore_description_from_seed" : MessageLookupByLibrary.simpleMessage("Stellen Sie Ihr Wallet aus den 25 Wörtern wieder her oder 13-Wort-Kombinationscode"), - "restore_description_from_seed_keys" : MessageLookupByLibrary.simpleMessage("Stellen sie Ihr Wallet mit Seed / Schlüsseln, welche Sie an einem sicheren Ort aufbewahrt haben, wieder her"), - "restore_from_seed_placeholder" : MessageLookupByLibrary.simpleMessage("Bitte geben Sie hier Ihren Code ein"), - "restore_next" : MessageLookupByLibrary.simpleMessage("Weiter"), - "restore_recover" : MessageLookupByLibrary.simpleMessage("Wiederherstellen"), - "restore_restore_wallet" : MessageLookupByLibrary.simpleMessage("Wallet wiederherstellen"), - "restore_seed_keys_restore" : MessageLookupByLibrary.simpleMessage("Seed / Schlüssel wiederherstellen"), - "restore_spend_key_private" : MessageLookupByLibrary.simpleMessage("Ausgabe-Schlüssel (geheim)"), - "restore_title_from_backup" : MessageLookupByLibrary.simpleMessage("Aus einer Sicherungsdatei wiederherstellen"), - "restore_title_from_keys" : MessageLookupByLibrary.simpleMessage("Wiederherstellen von Schlüsseln"), - "restore_title_from_seed" : MessageLookupByLibrary.simpleMessage("Aus Seed wiederherstellen"), - "restore_title_from_seed_keys" : MessageLookupByLibrary.simpleMessage("Vom Seed / Schlüssel wiederherstellen"), - "restore_view_key_private" : MessageLookupByLibrary.simpleMessage("Anzeige-Schlüssel (geheim)"), - "restore_wallet" : MessageLookupByLibrary.simpleMessage("Wallet wiederherstellen"), - "restore_wallet_name" : MessageLookupByLibrary.simpleMessage("Walletname"), - "restore_wallet_restore_description" : MessageLookupByLibrary.simpleMessage("Beschreibung zur Wiederherstellung des Wallets"), - "router_no_route" : m10, - "save" : MessageLookupByLibrary.simpleMessage("Speichern"), - "seed_language_chinese" : MessageLookupByLibrary.simpleMessage("Chinesisch"), - "seed_language_choose" : MessageLookupByLibrary.simpleMessage("Bitte wählen Sie die Ausgangssprache"), - "seed_language_dutch" : MessageLookupByLibrary.simpleMessage("Niederländisch"), - "seed_language_english" : MessageLookupByLibrary.simpleMessage("Englisch"), - "seed_language_french" : MessageLookupByLibrary.simpleMessage("Französisch"), - "seed_language_german" : MessageLookupByLibrary.simpleMessage("Deutsch"), - "seed_language_italian" : MessageLookupByLibrary.simpleMessage("Italienisch"), - "seed_language_japanese" : MessageLookupByLibrary.simpleMessage("Japanisch"), - "seed_language_next" : MessageLookupByLibrary.simpleMessage("Weiter"), - "seed_language_portuguese" : MessageLookupByLibrary.simpleMessage("Portugiesisch"), - "seed_language_russian" : MessageLookupByLibrary.simpleMessage("Russisch"), - "seed_language_spanish" : MessageLookupByLibrary.simpleMessage("Spanisch"), - "seed_share" : MessageLookupByLibrary.simpleMessage("Teilen Sie Seed"), - "seed_title" : MessageLookupByLibrary.simpleMessage("Seed"), - "send" : MessageLookupByLibrary.simpleMessage("Senden"), - "send_creating_transaction" : MessageLookupByLibrary.simpleMessage("Transaktion erstellen"), - "send_error_currency" : MessageLookupByLibrary.simpleMessage("Die Währung kann nur Zahlen enthalten"), - "send_estimated_fee" : MessageLookupByLibrary.simpleMessage("Geschätzte Gebühr:"), - "send_oxen" : MessageLookupByLibrary.simpleMessage("OXEN Senden"), - "send_oxen_address" : MessageLookupByLibrary.simpleMessage("Oxen-Adresse"), - "send_priority" : m11, - "send_title" : MessageLookupByLibrary.simpleMessage("Senden Sie Oxen"), - "send_your_wallet" : MessageLookupByLibrary.simpleMessage("Dein Wallet"), - "sending" : MessageLookupByLibrary.simpleMessage("Senden"), - "sent" : MessageLookupByLibrary.simpleMessage("Geschickt"), - "service_node_key" : MessageLookupByLibrary.simpleMessage("Service Node Schlüssel"), - "settings_all" : MessageLookupByLibrary.simpleMessage("ALLE"), - "settings_allow_biometric_authentication" : MessageLookupByLibrary.simpleMessage("Biometrische Authentifizierung"), - "settings_balance_detail" : MessageLookupByLibrary.simpleMessage("Dezimalstellen"), - "settings_change_language" : MessageLookupByLibrary.simpleMessage("Sprache ändern"), - "settings_change_pin" : MessageLookupByLibrary.simpleMessage("PIN ändern"), - "settings_currency" : MessageLookupByLibrary.simpleMessage("Währung"), - "settings_current_node" : MessageLookupByLibrary.simpleMessage("Aktueller Knoten"), - "settings_dark_mode" : MessageLookupByLibrary.simpleMessage("Dunkler Modus"), - "settings_display_balance_as" : MessageLookupByLibrary.simpleMessage("Kontostand anzeigen als"), - "settings_display_on_dashboard_list" : MessageLookupByLibrary.simpleMessage("Anzeige in der Dashboard-Liste"), - "settings_enable_fiat_currency" : MessageLookupByLibrary.simpleMessage("In Fiat Währung umrechnen"), - "settings_fee_priority" : MessageLookupByLibrary.simpleMessage("Gebührenpriorität"), - "settings_nodes" : MessageLookupByLibrary.simpleMessage("Knoten"), - "settings_none" : MessageLookupByLibrary.simpleMessage("Keiner"), - "settings_personal" : MessageLookupByLibrary.simpleMessage("Persönlich"), - "settings_save_recipient_address" : MessageLookupByLibrary.simpleMessage("Empfängeradresse speichern"), - "settings_support" : MessageLookupByLibrary.simpleMessage("Unterstützung"), - "settings_terms_and_conditions" : MessageLookupByLibrary.simpleMessage("Geschäftsbedingungen"), - "settings_title" : MessageLookupByLibrary.simpleMessage("Einstellungen"), - "settings_transactions" : MessageLookupByLibrary.simpleMessage("Transaktionen"), - "settings_wallets" : MessageLookupByLibrary.simpleMessage("Wallets"), - "setup_pin" : MessageLookupByLibrary.simpleMessage("PIN einrichten"), - "setup_successful" : MessageLookupByLibrary.simpleMessage("Ihre PIN wurde erfolgreich eingerichtet!"), - "share_address" : MessageLookupByLibrary.simpleMessage("Adresse teilen "), - "show_keys" : MessageLookupByLibrary.simpleMessage("Schlüssel anzeigen"), - "show_seed" : MessageLookupByLibrary.simpleMessage("Seed zeigen"), - "spend_key_private" : MessageLookupByLibrary.simpleMessage("Ausgabe-Schlüssel (geheim)"), - "spend_key_public" : MessageLookupByLibrary.simpleMessage("Ausgabe-Schlüssel (öffentlich)"), - "stake_more" : MessageLookupByLibrary.simpleMessage("Mehr staken"), - "stake_oxen" : MessageLookupByLibrary.simpleMessage("Oxen staken"), - "start_staking" : MessageLookupByLibrary.simpleMessage("Starte zu staken"), - "status" : MessageLookupByLibrary.simpleMessage("Status: "), - "subaddress_title" : MessageLookupByLibrary.simpleMessage("Unteradressenliste"), - "subaddresses" : MessageLookupByLibrary.simpleMessage("Unteradressen"), - "sync_status_connected" : MessageLookupByLibrary.simpleMessage("IN VERBINDUNG GEBRACHT"), - "sync_status_connecting" : MessageLookupByLibrary.simpleMessage("ANSCHLUSS"), - "sync_status_failed_connect" : MessageLookupByLibrary.simpleMessage("Verbindung zum Knoten fehlgeschlagen"), - "sync_status_not_connected" : MessageLookupByLibrary.simpleMessage("NICHT VERBUNDEN"), - "sync_status_starting_sync" : MessageLookupByLibrary.simpleMessage("STARTEN DER SYNCHRONISIERUNG"), - "sync_status_synchronized" : MessageLookupByLibrary.simpleMessage("SYNCHRONISIERT"), - "sync_status_synchronizing" : MessageLookupByLibrary.simpleMessage("SYNCHRONISIERUNG"), - "title_confirm_unlock_stake" : MessageLookupByLibrary.simpleMessage("Stake entsperren"), - "title_new_stake" : MessageLookupByLibrary.simpleMessage("Neuer Stake"), - "title_stakes" : MessageLookupByLibrary.simpleMessage("Stakes"), - "today" : MessageLookupByLibrary.simpleMessage("Heute"), - "transaction_details_amount" : MessageLookupByLibrary.simpleMessage("Betrag"), - "transaction_details_copied" : m12, - "transaction_details_date" : MessageLookupByLibrary.simpleMessage("Datum"), - "transaction_details_height" : MessageLookupByLibrary.simpleMessage("Höhe"), - "transaction_details_recipient_address" : MessageLookupByLibrary.simpleMessage("Empfängeradresse"), - "transaction_details_title" : MessageLookupByLibrary.simpleMessage("Transaktionsdetails"), - "transaction_details_transaction_id" : MessageLookupByLibrary.simpleMessage("Transaktions-ID"), - "transaction_priority_blink" : MessageLookupByLibrary.simpleMessage("Blink"), - "transaction_priority_slow" : MessageLookupByLibrary.simpleMessage("Langsam"), - "transaction_sent" : MessageLookupByLibrary.simpleMessage("Transaktion gesendet!"), - "transactions" : MessageLookupByLibrary.simpleMessage("Transaktionen"), - "transactions_by_date" : MessageLookupByLibrary.simpleMessage("Transaktionen nach Datum"), - "unable_unlock_stake" : MessageLookupByLibrary.simpleMessage("Stake Entsperrung nicht möglich"), - "unlock_stake_requested" : MessageLookupByLibrary.simpleMessage("Stake Entsperrung angefragt"), - "use" : MessageLookupByLibrary.simpleMessage("Wechseln zu "), - "version" : m13, - "view_key_private" : MessageLookupByLibrary.simpleMessage("Anzeige-Schlüssel (geheim)"), - "view_key_public" : MessageLookupByLibrary.simpleMessage("Anzeige-Schlüssel (öffentlich)"), - "wallet_keys" : MessageLookupByLibrary.simpleMessage("Wallet Schlüssel"), - "wallet_list_create_new_wallet" : MessageLookupByLibrary.simpleMessage("Neues Wallet erstellen"), - "wallet_list_failed_to_load" : m14, - "wallet_list_failed_to_remove" : m15, - "wallet_list_load_wallet" : MessageLookupByLibrary.simpleMessage("Wallet laden"), - "wallet_list_loading_wallet" : m16, - "wallet_list_removing_wallet" : m17, - "wallet_list_restore_wallet" : MessageLookupByLibrary.simpleMessage("Wallet wiederherstellen"), - "wallet_list_title" : MessageLookupByLibrary.simpleMessage("Oxen Wallet"), - "wallet_menu" : MessageLookupByLibrary.simpleMessage("Wallet-Menü"), - "wallet_name" : MessageLookupByLibrary.simpleMessage("Walletname"), - "wallet_restoration_store_incorrect_seed_length" : MessageLookupByLibrary.simpleMessage("Falsche Seed-länge"), - "wallets" : MessageLookupByLibrary.simpleMessage("Wallets"), - "welcome" : MessageLookupByLibrary.simpleMessage("Willkommen\nim OXEN WALLET"), - "widgets_address" : MessageLookupByLibrary.simpleMessage("Adresse"), - "widgets_or" : MessageLookupByLibrary.simpleMessage("oder"), - "widgets_restore_from_blockheight" : MessageLookupByLibrary.simpleMessage("Aus Blockhöhe wiederherstellen"), - "widgets_restore_from_date" : MessageLookupByLibrary.simpleMessage("Vom Datum wiederherstellen"), - "widgets_seed" : MessageLookupByLibrary.simpleMessage("Seed"), - "yes_im_sure" : MessageLookupByLibrary.simpleMessage("Ja, Ich bin mir sicher!"), - "yesterday" : MessageLookupByLibrary.simpleMessage("Gestern"), - "your_contributions" : MessageLookupByLibrary.simpleMessage("Deine Anteile") - }; -} diff --git a/lib/generated/intl/messages_en.dart b/lib/generated/intl/messages_en.dart deleted file mode 100644 index cf290252..00000000 --- a/lib/generated/intl/messages_en.dart +++ /dev/null @@ -1,305 +0,0 @@ -// DO NOT EDIT. This is code generated via package:intl/generate_localized.dart -// This is a library that provides messages for a en locale. All the -// messages from the main program should be duplicated here with the same -// function name. - -// Ignore issues from commonly used lints in this file. -// ignore_for_file:unnecessary_brace_in_string_interps, unnecessary_new -// ignore_for_file:prefer_single_quotes,comment_references, directives_ordering -// ignore_for_file:annotate_overrides,prefer_generic_function_type_aliases -// ignore_for_file:unused_import, file_names - -import 'package:intl/intl.dart'; -import 'package:intl/message_lookup_by_library.dart'; - -final messages = new MessageLookup(); - -typedef String MessageIfAbsent(String messageStr, List args); - -class MessageLookup extends MessageLookupByLibrary { - String get localeName => 'en'; - - static m0(status) => "${status} Blocks Remaining"; - - static m1(serviceNodeKey) => "Do you really want to unlock your stake from ${serviceNodeKey}?"; - - static m2(node) => "Are you sure to change current node to ${node}?"; - - static m3(language) => "Change language to ${language}?"; - - static m4(amount, fee) => "Commit transaction\nAmount: ${amount}\nFee: ${fee}"; - - static m5(key) => "Copied ${key} to Clipboard"; - - static m6(item, app_store) => "NEVER input your Oxen wallet ${item} into any software or website other than the OFFICIAL Oxen wallets downloaded directly from the ${app_store}, the Oxen website, or the Oxen GitHub.\nAre you sure you want to access your wallet ${item}?"; - - static m7(state_error) => "Failed authentication. ${state_error}"; - - static m8(item) => "NEVER give your Oxen wallet ${item} to ANYONE!"; - - static m9(recipient_name) => "You will be sending funds to\n${recipient_name}"; - - static m10(name) => "No route defined for ${name}"; - - static m11(transactionPriority) => "Currently the fee is set at ${transactionPriority} priority.\nTransaction priority can be adjusted in the settings"; - - static m12(title) => "${title} copied to Clipboard"; - - static m13(currentVersion) => "Version ${currentVersion}"; - - static m14(wallet_name, error) => "Failed to load ${wallet_name} wallet. ${error}"; - - static m15(wallet_name, error) => "Failed to remove ${wallet_name} wallet. ${error}"; - - static m16(wallet_name) => "Loading ${wallet_name} wallet"; - - static m17(wallet_name) => "Removing ${wallet_name} wallet"; - - final messages = _notInlinedMessages(_notInlinedMessages); - static _notInlinedMessages(_) => { - "Blocks_remaining" : m0, - "account" : MessageLookupByLibrary.simpleMessage("Account"), - "accounts" : MessageLookupByLibrary.simpleMessage("Accounts"), - "add" : MessageLookupByLibrary.simpleMessage("Add"), - "add_new_word" : MessageLookupByLibrary.simpleMessage("Add new word"), - "address_book" : MessageLookupByLibrary.simpleMessage("Address Book"), - "address_book_menu" : MessageLookupByLibrary.simpleMessage("Address book"), - "all" : MessageLookupByLibrary.simpleMessage("ALL"), - "amount" : MessageLookupByLibrary.simpleMessage("Amount: "), - "amount_detail_detailed" : MessageLookupByLibrary.simpleMessage("4 - Detailed"), - "amount_detail_none" : MessageLookupByLibrary.simpleMessage("0 - None"), - "amount_detail_normal" : MessageLookupByLibrary.simpleMessage("2 - Normal"), - "amount_detail_ultra" : MessageLookupByLibrary.simpleMessage("9 - Ultra"), - "auth_store_ban_timeout" : MessageLookupByLibrary.simpleMessage("ban_timeout"), - "auth_store_banned_for" : MessageLookupByLibrary.simpleMessage("Banned for "), - "auth_store_banned_minutes" : MessageLookupByLibrary.simpleMessage(" minutes"), - "auth_store_incorrect_password" : MessageLookupByLibrary.simpleMessage("Wrong PIN"), - "authenticated" : MessageLookupByLibrary.simpleMessage("Authenticated"), - "authentication" : MessageLookupByLibrary.simpleMessage("Authentication"), - "available_balance" : MessageLookupByLibrary.simpleMessage("Available Balance"), - "biometric_auth_reason" : MessageLookupByLibrary.simpleMessage("Scan your fingerprint to authenticate"), - "body_confirm_unlock_stake" : m1, - "cancel" : MessageLookupByLibrary.simpleMessage("Cancel"), - "change" : MessageLookupByLibrary.simpleMessage("Change"), - "change_current_node" : m2, - "change_language" : MessageLookupByLibrary.simpleMessage("Change language"), - "change_language_to" : m3, - "changelog" : MessageLookupByLibrary.simpleMessage("Changelog"), - "clear" : MessageLookupByLibrary.simpleMessage("Clear"), - "commit_transaction_amount_fee" : m4, - "confirm" : MessageLookupByLibrary.simpleMessage("Confirm"), - "confirm_sending" : MessageLookupByLibrary.simpleMessage("Confirm sending"), - "contact" : MessageLookupByLibrary.simpleMessage("Contact"), - "contact_name" : MessageLookupByLibrary.simpleMessage("Contact Name"), - "continue_text" : MessageLookupByLibrary.simpleMessage("Continue"), - "copied_key_to_clipboard" : m5, - "copied_to_clipboard" : MessageLookupByLibrary.simpleMessage("Copied to Clipboard"), - "copy" : MessageLookupByLibrary.simpleMessage("Copy"), - "create_new" : MessageLookupByLibrary.simpleMessage("Create new"), - "dangerzone" : MessageLookupByLibrary.simpleMessage("Dangerzone"), - "dangerzone_warning" : m6, - "delete" : MessageLookupByLibrary.simpleMessage("Delete"), - "digit_pin" : MessageLookupByLibrary.simpleMessage("-digit PIN"), - "edit" : MessageLookupByLibrary.simpleMessage("Edit"), - "enter_your_pin" : MessageLookupByLibrary.simpleMessage("Enter your PIN"), - "enter_your_pin_again" : MessageLookupByLibrary.simpleMessage("Enter your pin again"), - "error" : MessageLookupByLibrary.simpleMessage("Error"), - "error_text_account_name" : MessageLookupByLibrary.simpleMessage("Account name can only contain letters, numbers\nand must be between 1 and 15 characters long"), - "error_text_address" : MessageLookupByLibrary.simpleMessage("Wallet address must correspond to the type\nof cryptocurrency"), - "error_text_amount" : MessageLookupByLibrary.simpleMessage("Amount can only contain numbers"), - "error_text_contact_name" : MessageLookupByLibrary.simpleMessage("Contact name can\'t contain ` , \' \" symbols\nand must be between 1 and 32 characters long"), - "error_text_crypto_currency" : MessageLookupByLibrary.simpleMessage("The number of fraction digits\nmust be less or equal to 12"), - "error_text_fiat" : MessageLookupByLibrary.simpleMessage("Value of amount can\'t exceed available balance.\nThe number of fraction digits must be less or equal to 2"), - "error_text_keys" : MessageLookupByLibrary.simpleMessage("Wallet keys can only contain 64 chars in hex"), - "error_text_node_address" : MessageLookupByLibrary.simpleMessage("Please enter a iPv4 address"), - "error_text_node_port" : MessageLookupByLibrary.simpleMessage("Node port can only contain numbers between 0 and 65535"), - "error_text_oxen" : MessageLookupByLibrary.simpleMessage("OXEN value can\'t exceed available balance.\nThe number of fraction digits must be less or equal to 12"), - "error_text_payment_id" : MessageLookupByLibrary.simpleMessage("Payment ID can only contain from 16 to 64 chars in hex"), - "error_text_service_node" : MessageLookupByLibrary.simpleMessage("A Service Node key can only contain 64 chars in hex"), - "error_text_subaddress_name" : MessageLookupByLibrary.simpleMessage("Subaddress name can\'t contain ` , \' \" symbols\nand must be between 1 and 20 characters long"), - "error_text_wallet_name" : MessageLookupByLibrary.simpleMessage("Wallet name can only contain letters, numbers\nand must be between 1 and 15 characters long"), - "failed_authentication" : m7, - "faq" : MessageLookupByLibrary.simpleMessage("FAQ"), - "fetching" : MessageLookupByLibrary.simpleMessage("Fetching"), - "filters" : MessageLookupByLibrary.simpleMessage("Filters"), - "first_wallet_text" : MessageLookupByLibrary.simpleMessage("Awesome wallet\nfor Oxen"), - "full_balance" : MessageLookupByLibrary.simpleMessage("Full Balance"), - "hidden_balance" : MessageLookupByLibrary.simpleMessage("Hidden Balance"), - "id" : MessageLookupByLibrary.simpleMessage("ID: "), - "incoming" : MessageLookupByLibrary.simpleMessage("Incoming"), - "incorrect_seed" : MessageLookupByLibrary.simpleMessage("The text entered is not valid."), - "keys_title" : MessageLookupByLibrary.simpleMessage("Keys"), - "loading_your_wallet" : MessageLookupByLibrary.simpleMessage("Loading your wallet"), - "login" : MessageLookupByLibrary.simpleMessage("Login"), - "never_give_your" : m8, - "new_subaddress_create" : MessageLookupByLibrary.simpleMessage("Create"), - "new_subaddress_label_name" : MessageLookupByLibrary.simpleMessage("Label name"), - "new_subaddress_title" : MessageLookupByLibrary.simpleMessage("New subaddress"), - "new_wallet" : MessageLookupByLibrary.simpleMessage("New Wallet"), - "node_address" : MessageLookupByLibrary.simpleMessage("Node Address"), - "node_new" : MessageLookupByLibrary.simpleMessage("New Node"), - "node_port" : MessageLookupByLibrary.simpleMessage("Node port"), - "node_reset_settings_title" : MessageLookupByLibrary.simpleMessage("Reset settings"), - "nodes" : MessageLookupByLibrary.simpleMessage("Nodes"), - "nodes_list_reset_to_default_message" : MessageLookupByLibrary.simpleMessage("Are you sure that you want to reset settings to default?"), - "nothing_staked" : MessageLookupByLibrary.simpleMessage("Nothing staked yet"), - "ok" : MessageLookupByLibrary.simpleMessage("OK"), - "openalias_alert_content" : m9, - "openalias_alert_title" : MessageLookupByLibrary.simpleMessage("OXEN Recipient Detected"), - "outgoing" : MessageLookupByLibrary.simpleMessage("Outgoing"), - "oxen_available_balance" : MessageLookupByLibrary.simpleMessage("OXEN Available Balance"), - "oxen_full_balance" : MessageLookupByLibrary.simpleMessage("OXEN Full Balance"), - "oxen_hidden" : MessageLookupByLibrary.simpleMessage("OXEN Hidden"), - "password" : MessageLookupByLibrary.simpleMessage("Password"), - "paste" : MessageLookupByLibrary.simpleMessage("Paste"), - "pending" : MessageLookupByLibrary.simpleMessage(" (pending)"), - "pin_is_incorrect" : MessageLookupByLibrary.simpleMessage("PIN is incorrect"), - "please_make_selection" : MessageLookupByLibrary.simpleMessage("Please make selection below to\ncreate or recover your wallet."), - "please_select" : MessageLookupByLibrary.simpleMessage("Please select:"), - "please_try_to_connect_to_another_node" : MessageLookupByLibrary.simpleMessage("Please try to connect to another node"), - "receive" : MessageLookupByLibrary.simpleMessage("Receive"), - "receive_amount" : MessageLookupByLibrary.simpleMessage("Amount"), - "received" : MessageLookupByLibrary.simpleMessage("Received"), - "reconnect" : MessageLookupByLibrary.simpleMessage("Reconnect"), - "reconnect_alert_text" : MessageLookupByLibrary.simpleMessage("Are you sure to reconnect?"), - "reconnection" : MessageLookupByLibrary.simpleMessage("Reconnection"), - "reload_fiat" : MessageLookupByLibrary.simpleMessage("Reload Fiat data"), - "remove" : MessageLookupByLibrary.simpleMessage("Remove"), - "remove_node" : MessageLookupByLibrary.simpleMessage("Remove node"), - "remove_node_message" : MessageLookupByLibrary.simpleMessage("Are you sure that you want to remove selected node?"), - "rescan" : MessageLookupByLibrary.simpleMessage("Rescan"), - "reset" : MessageLookupByLibrary.simpleMessage("Reset"), - "restore_address" : MessageLookupByLibrary.simpleMessage("Address"), - "restore_description_from_backup" : MessageLookupByLibrary.simpleMessage("You can restore the whole Oxen Wallet app from your back-up file"), - "restore_description_from_keys" : MessageLookupByLibrary.simpleMessage("Restore your wallet from generated keystrokes saved from your private keys"), - "restore_description_from_seed" : MessageLookupByLibrary.simpleMessage("Restore your wallet from either the 25 word or 13 word combination code"), - "restore_description_from_seed_keys" : MessageLookupByLibrary.simpleMessage("Get back your wallet from seed/keys that you\'ve saved to secure place"), - "restore_from_seed_placeholder" : MessageLookupByLibrary.simpleMessage("Please enter or paste your seed here"), - "restore_next" : MessageLookupByLibrary.simpleMessage("Next"), - "restore_recover" : MessageLookupByLibrary.simpleMessage("Restore"), - "restore_restore_wallet" : MessageLookupByLibrary.simpleMessage("Restore Wallet"), - "restore_seed_keys_restore" : MessageLookupByLibrary.simpleMessage("Seed/Keys Restore"), - "restore_spend_key_private" : MessageLookupByLibrary.simpleMessage("Spend key (private)"), - "restore_title_from_backup" : MessageLookupByLibrary.simpleMessage("Restore from a back-up file"), - "restore_title_from_keys" : MessageLookupByLibrary.simpleMessage("Restore from keys"), - "restore_title_from_seed" : MessageLookupByLibrary.simpleMessage("Restore from seed"), - "restore_title_from_seed_keys" : MessageLookupByLibrary.simpleMessage("Restore from seed/keys"), - "restore_view_key_private" : MessageLookupByLibrary.simpleMessage("View key (private)"), - "restore_wallet" : MessageLookupByLibrary.simpleMessage("Restore wallet"), - "restore_wallet_name" : MessageLookupByLibrary.simpleMessage("Wallet name"), - "restore_wallet_restore_description" : MessageLookupByLibrary.simpleMessage("Wallet restore description"), - "router_no_route" : m10, - "save" : MessageLookupByLibrary.simpleMessage("Save"), - "seed_language_chinese" : MessageLookupByLibrary.simpleMessage("Chinese"), - "seed_language_choose" : MessageLookupByLibrary.simpleMessage("Please choose seed language"), - "seed_language_dutch" : MessageLookupByLibrary.simpleMessage("Dutch"), - "seed_language_english" : MessageLookupByLibrary.simpleMessage("English"), - "seed_language_french" : MessageLookupByLibrary.simpleMessage("French"), - "seed_language_german" : MessageLookupByLibrary.simpleMessage("German"), - "seed_language_italian" : MessageLookupByLibrary.simpleMessage("Italian"), - "seed_language_japanese" : MessageLookupByLibrary.simpleMessage("Japanese"), - "seed_language_next" : MessageLookupByLibrary.simpleMessage("Next"), - "seed_language_portuguese" : MessageLookupByLibrary.simpleMessage("Portuguese"), - "seed_language_russian" : MessageLookupByLibrary.simpleMessage("Russian"), - "seed_language_spanish" : MessageLookupByLibrary.simpleMessage("Spanish"), - "seed_share" : MessageLookupByLibrary.simpleMessage("Share seed"), - "seed_title" : MessageLookupByLibrary.simpleMessage("Seed"), - "send" : MessageLookupByLibrary.simpleMessage("Send"), - "send_creating_transaction" : MessageLookupByLibrary.simpleMessage("Creating transaction"), - "send_error_currency" : MessageLookupByLibrary.simpleMessage("Currency can only contain numbers"), - "send_estimated_fee" : MessageLookupByLibrary.simpleMessage("Estimated fee:"), - "send_oxen" : MessageLookupByLibrary.simpleMessage("Send OXEN"), - "send_oxen_address" : MessageLookupByLibrary.simpleMessage("Oxen address"), - "send_priority" : m11, - "send_title" : MessageLookupByLibrary.simpleMessage("Send Oxen"), - "send_your_wallet" : MessageLookupByLibrary.simpleMessage("Your wallet"), - "sending" : MessageLookupByLibrary.simpleMessage("Sending"), - "sent" : MessageLookupByLibrary.simpleMessage("Sent"), - "service_node_key" : MessageLookupByLibrary.simpleMessage("Service Node Key"), - "settings_all" : MessageLookupByLibrary.simpleMessage("ALL"), - "settings_allow_biometric_authentication" : MessageLookupByLibrary.simpleMessage("Allow biometric authentication"), - "settings_balance_detail" : MessageLookupByLibrary.simpleMessage("Decimals"), - "settings_change_language" : MessageLookupByLibrary.simpleMessage("Change language"), - "settings_change_pin" : MessageLookupByLibrary.simpleMessage("Change PIN"), - "settings_currency" : MessageLookupByLibrary.simpleMessage("Currency"), - "settings_current_node" : MessageLookupByLibrary.simpleMessage("Current node"), - "settings_dark_mode" : MessageLookupByLibrary.simpleMessage("Dark mode"), - "settings_display_balance_as" : MessageLookupByLibrary.simpleMessage("Display balance as"), - "settings_display_on_dashboard_list" : MessageLookupByLibrary.simpleMessage("Display on dashboard list"), - "settings_enable_fiat_currency" : MessageLookupByLibrary.simpleMessage("Enable Fiat Currency conversion"), - "settings_fee_priority" : MessageLookupByLibrary.simpleMessage("Fee priority"), - "settings_nodes" : MessageLookupByLibrary.simpleMessage("Nodes"), - "settings_none" : MessageLookupByLibrary.simpleMessage("None"), - "settings_personal" : MessageLookupByLibrary.simpleMessage("Personal"), - "settings_save_recipient_address" : MessageLookupByLibrary.simpleMessage("Save recipient address"), - "settings_support" : MessageLookupByLibrary.simpleMessage("Support"), - "settings_terms_and_conditions" : MessageLookupByLibrary.simpleMessage("Terms and conditions"), - "settings_title" : MessageLookupByLibrary.simpleMessage("Settings"), - "settings_transactions" : MessageLookupByLibrary.simpleMessage("Transactions"), - "settings_wallets" : MessageLookupByLibrary.simpleMessage("Wallets"), - "setup_pin" : MessageLookupByLibrary.simpleMessage("Setup PIN"), - "setup_successful" : MessageLookupByLibrary.simpleMessage("Your PIN has been set up successfully!"), - "share_address" : MessageLookupByLibrary.simpleMessage("Share address"), - "show_keys" : MessageLookupByLibrary.simpleMessage("Show keys"), - "show_seed" : MessageLookupByLibrary.simpleMessage("Show seed"), - "spend_key_private" : MessageLookupByLibrary.simpleMessage("Spend key (private)"), - "spend_key_public" : MessageLookupByLibrary.simpleMessage("Spend key (public)"), - "stake_more" : MessageLookupByLibrary.simpleMessage("Stake more"), - "stake_oxen" : MessageLookupByLibrary.simpleMessage("Stake Oxen"), - "start_staking" : MessageLookupByLibrary.simpleMessage("Start staking"), - "status" : MessageLookupByLibrary.simpleMessage("Status: "), - "subaddress_title" : MessageLookupByLibrary.simpleMessage("Subaddress list"), - "subaddresses" : MessageLookupByLibrary.simpleMessage("Subaddresses"), - "sync_status_connected" : MessageLookupByLibrary.simpleMessage("CONNECTED"), - "sync_status_connecting" : MessageLookupByLibrary.simpleMessage("CONNECTING"), - "sync_status_failed_connect" : MessageLookupByLibrary.simpleMessage("FAILED CONNECT TO THE NODE"), - "sync_status_not_connected" : MessageLookupByLibrary.simpleMessage("NOT CONNECTED"), - "sync_status_starting_sync" : MessageLookupByLibrary.simpleMessage("STARTING SYNC"), - "sync_status_synchronized" : MessageLookupByLibrary.simpleMessage("SYNCHRONIZED"), - "sync_status_synchronizing" : MessageLookupByLibrary.simpleMessage("SYNCHRONIZING"), - "title_confirm_unlock_stake" : MessageLookupByLibrary.simpleMessage("Unlock Stake"), - "title_new_stake" : MessageLookupByLibrary.simpleMessage("New Stake"), - "title_stakes" : MessageLookupByLibrary.simpleMessage("Stakes"), - "today" : MessageLookupByLibrary.simpleMessage("Today"), - "transaction_details_amount" : MessageLookupByLibrary.simpleMessage("Amount"), - "transaction_details_copied" : m12, - "transaction_details_date" : MessageLookupByLibrary.simpleMessage("Date"), - "transaction_details_height" : MessageLookupByLibrary.simpleMessage("Height"), - "transaction_details_recipient_address" : MessageLookupByLibrary.simpleMessage("Recipient address"), - "transaction_details_title" : MessageLookupByLibrary.simpleMessage("Transaction Details"), - "transaction_details_transaction_id" : MessageLookupByLibrary.simpleMessage("Transaction ID"), - "transaction_priority_blink" : MessageLookupByLibrary.simpleMessage("Blink"), - "transaction_priority_slow" : MessageLookupByLibrary.simpleMessage("Slow"), - "transaction_sent" : MessageLookupByLibrary.simpleMessage("Transaction sent!"), - "transactions" : MessageLookupByLibrary.simpleMessage("Transactions"), - "transactions_by_date" : MessageLookupByLibrary.simpleMessage("Transactions by date"), - "unable_unlock_stake" : MessageLookupByLibrary.simpleMessage("Unable to unlock stake"), - "unlock_stake_requested" : MessageLookupByLibrary.simpleMessage("Stake unlock requested"), - "use" : MessageLookupByLibrary.simpleMessage("Switch to "), - "version" : m13, - "view_key_private" : MessageLookupByLibrary.simpleMessage("View key (private)"), - "view_key_public" : MessageLookupByLibrary.simpleMessage("View key (public)"), - "wallet_keys" : MessageLookupByLibrary.simpleMessage("Wallet keys"), - "wallet_list_create_new_wallet" : MessageLookupByLibrary.simpleMessage("Create New Wallet"), - "wallet_list_failed_to_load" : m14, - "wallet_list_failed_to_remove" : m15, - "wallet_list_load_wallet" : MessageLookupByLibrary.simpleMessage("Load wallet"), - "wallet_list_loading_wallet" : m16, - "wallet_list_removing_wallet" : m17, - "wallet_list_restore_wallet" : MessageLookupByLibrary.simpleMessage("Restore Wallet"), - "wallet_list_title" : MessageLookupByLibrary.simpleMessage("Oxen Wallet"), - "wallet_menu" : MessageLookupByLibrary.simpleMessage("Menu"), - "wallet_name" : MessageLookupByLibrary.simpleMessage("Wallet name"), - "wallet_restoration_store_incorrect_seed_length" : MessageLookupByLibrary.simpleMessage("Incorrect seed length"), - "wallets" : MessageLookupByLibrary.simpleMessage("Wallets"), - "welcome" : MessageLookupByLibrary.simpleMessage("WELCOME\nTO OXEN WALLET"), - "widgets_address" : MessageLookupByLibrary.simpleMessage("Address"), - "widgets_or" : MessageLookupByLibrary.simpleMessage("or"), - "widgets_restore_from_blockheight" : MessageLookupByLibrary.simpleMessage("Restore from blockheight"), - "widgets_restore_from_date" : MessageLookupByLibrary.simpleMessage("Restore from date"), - "widgets_seed" : MessageLookupByLibrary.simpleMessage("Seed"), - "yes_im_sure" : MessageLookupByLibrary.simpleMessage("Yes, I\'m sure!"), - "yesterday" : MessageLookupByLibrary.simpleMessage("Yesterday"), - "your_contributions" : MessageLookupByLibrary.simpleMessage("Your Contributions") - }; -} diff --git a/lib/generated/intl/messages_fr.dart b/lib/generated/intl/messages_fr.dart deleted file mode 100644 index c16f9e66..00000000 --- a/lib/generated/intl/messages_fr.dart +++ /dev/null @@ -1,305 +0,0 @@ -// DO NOT EDIT. This is code generated via package:intl/generate_localized.dart -// This is a library that provides messages for a fr locale. All the -// messages from the main program should be duplicated here with the same -// function name. - -// Ignore issues from commonly used lints in this file. -// ignore_for_file:unnecessary_brace_in_string_interps, unnecessary_new -// ignore_for_file:prefer_single_quotes,comment_references, directives_ordering -// ignore_for_file:annotate_overrides,prefer_generic_function_type_aliases -// ignore_for_file:unused_import, file_names - -import 'package:intl/intl.dart'; -import 'package:intl/message_lookup_by_library.dart'; - -final messages = new MessageLookup(); - -typedef String MessageIfAbsent(String messageStr, List args); - -class MessageLookup extends MessageLookupByLibrary { - String get localeName => 'fr'; - - static m0(status) => "${status} blocs restants"; - - static m1(serviceNodeKey) => "Voulez-vous vraiment débloquer votre mise de${serviceNodeKey}?"; - - static m2(node) => "Voulez-vous vraiment changer le Node actuel vers ${node}?"; - - static m3(language) => "Changez la langue en ${language}?"; - - static m4(amount, fee) => "Valider la transaction\nMontant: ${amount}\nFee: ${fee}"; - - static m5(key) => "Clé ${key} dans le presse-papiers"; - - static m6(item, app_store) => "Ne JAMAIS saisir vos identifiants de votre Wallet Oxen ${item} dans tout logiciel ou site Web autre que les portefeuilles OFFICIELS Oxen téléchargés directement à partir du ${app_store}, le site internet Oxen, ou Oxen sur GitHub.\nÊtes-vous sûr de vouloir accéder à votre portefeuille ${item}?"; - - static m7(state_error) => "Échec de l\'authentification. ${state_error}"; - - static m8(item) => "Ne donnez JAMAIS votre Wallet Oxen à qui que ce soit! ${item} à qui que ce soit!"; - - static m9(recipient_name) => "Vous envoyez de l\'argent à\n${recipient_name}"; - - static m10(name) => "Aucun itinéraire défini pour ${name}"; - - static m11(transactionPriority) => "Actuellement, la priorité est définie sur ${transactionPriority}.\nLa priorité de transaction peut être ajustée dans les paramètres"; - - static m12(title) => "${title} copié dans le presse-papiers"; - - static m13(currentVersion) => "Version ${currentVersion}"; - - static m14(wallet_name, error) => "Échec du chargement du portefeuille ${wallet_name}. ${error}"; - - static m15(wallet_name, error) => "Erreur lors de la suppression ${wallet_name} Wallet. ${error}"; - - static m16(wallet_name) => "chargement du ${wallet_name} wallet"; - - static m17(wallet_name) => "Wallet ${wallet_name}"; - - final messages = _notInlinedMessages(_notInlinedMessages); - static _notInlinedMessages(_) => { - "Blocks_remaining" : m0, - "account" : MessageLookupByLibrary.simpleMessage("Compte"), - "accounts" : MessageLookupByLibrary.simpleMessage("Comptes"), - "add" : MessageLookupByLibrary.simpleMessage("Ajouter"), - "add_new_word" : MessageLookupByLibrary.simpleMessage("Ajouter un nouveau mot"), - "address_book" : MessageLookupByLibrary.simpleMessage("Carnet d\'adresses"), - "address_book_menu" : MessageLookupByLibrary.simpleMessage("Carnet d\'adresses"), - "all" : MessageLookupByLibrary.simpleMessage("TOUT"), - "amount" : MessageLookupByLibrary.simpleMessage("Montant: "), - "amount_detail_detailed" : MessageLookupByLibrary.simpleMessage("4 - Détaillé"), - "amount_detail_none" : MessageLookupByLibrary.simpleMessage("0 - Aucun"), - "amount_detail_normal" : MessageLookupByLibrary.simpleMessage("2 - Normal"), - "amount_detail_ultra" : MessageLookupByLibrary.simpleMessage("9 - Ultra"), - "auth_store_ban_timeout" : MessageLookupByLibrary.simpleMessage("Interdire le délai d\'expiration"), - "auth_store_banned_for" : MessageLookupByLibrary.simpleMessage("Interdit pour "), - "auth_store_banned_minutes" : MessageLookupByLibrary.simpleMessage(" Protocole"), - "auth_store_incorrect_password" : MessageLookupByLibrary.simpleMessage("mauvais code PIN"), - "authenticated" : MessageLookupByLibrary.simpleMessage("Authentifié"), - "authentication" : MessageLookupByLibrary.simpleMessage("Authentification"), - "available_balance" : MessageLookupByLibrary.simpleMessage("Solde disponible"), - "biometric_auth_reason" : MessageLookupByLibrary.simpleMessage("Scannez votre empreinte digitale pour l\'authentification"), - "body_confirm_unlock_stake" : m1, - "cancel" : MessageLookupByLibrary.simpleMessage("Annuler"), - "change" : MessageLookupByLibrary.simpleMessage("Changement"), - "change_current_node" : m2, - "change_language" : MessageLookupByLibrary.simpleMessage("changer la langue"), - "change_language_to" : m3, - "changelog" : MessageLookupByLibrary.simpleMessage("Journal des modifications"), - "clear" : MessageLookupByLibrary.simpleMessage("clair"), - "commit_transaction_amount_fee" : m4, - "confirm" : MessageLookupByLibrary.simpleMessage("confirmer"), - "confirm_sending" : MessageLookupByLibrary.simpleMessage("confirmer l\'envoi"), - "contact" : MessageLookupByLibrary.simpleMessage("Contact"), - "contact_name" : MessageLookupByLibrary.simpleMessage("Nom du contact"), - "continue_text" : MessageLookupByLibrary.simpleMessage("Continuez"), - "copied_key_to_clipboard" : m5, - "copied_to_clipboard" : MessageLookupByLibrary.simpleMessage("Copié dans le presse-papiers"), - "copy" : MessageLookupByLibrary.simpleMessage("copier"), - "create_new" : MessageLookupByLibrary.simpleMessage("Créer un nouveau portefeuille"), - "dangerzone" : MessageLookupByLibrary.simpleMessage("zone de danger"), - "dangerzone_warning" : m6, - "delete" : MessageLookupByLibrary.simpleMessage("effacer"), - "digit_pin" : MessageLookupByLibrary.simpleMessage("-chiffre PIN"), - "edit" : MessageLookupByLibrary.simpleMessage("Éditer"), - "enter_your_pin" : MessageLookupByLibrary.simpleMessage("entrez le code PIN"), - "enter_your_pin_again" : MessageLookupByLibrary.simpleMessage("Saisissez à nouveau votre code PIN"), - "error" : MessageLookupByLibrary.simpleMessage("erreur"), - "error_text_account_name" : MessageLookupByLibrary.simpleMessage("Le nom du compte ne peut contenir que des lettres et des chiffres\net doit comporter entre 1 et 15 caractères"), - "error_text_address" : MessageLookupByLibrary.simpleMessage("L\'adresse du portefeuille doit correspondre au type de crypto-monnaie"), - "error_text_amount" : MessageLookupByLibrary.simpleMessage("Le montant ne peut contenir que des nombres"), - "error_text_contact_name" : MessageLookupByLibrary.simpleMessage("Dans le nom du contact, les symboles ` , \' \" ne doivent pas être inclus\net doit comporter entre 1 et 32 ​​caractères"), - "error_text_crypto_currency" : MessageLookupByLibrary.simpleMessage("Le nombre de décimales\nm doit être inférieur ou égal à 12."), - "error_text_fiat" : MessageLookupByLibrary.simpleMessage("La valeur du montant ne peut pas dépasser le solde disponible du compte.\nLe nombre de décimales doit être inférieur ou égal à 2"), - "error_text_keys" : MessageLookupByLibrary.simpleMessage("Les clés de portefeuille ne peuvent contenir que 64 caractères hexadécimaux"), - "error_text_node_address" : MessageLookupByLibrary.simpleMessage("Veuillez saisir une adresse iPv4"), - "error_text_node_port" : MessageLookupByLibrary.simpleMessage("Le port du Node ne peut contenir que des nombres compris entre 0 et 65535"), - "error_text_oxen" : MessageLookupByLibrary.simpleMessage("La valeur OXEN ne peut pas dépasser le solde disponible.\nLe nombre de décimales doit être inférieur ou égal à 12"), - "error_text_payment_id" : MessageLookupByLibrary.simpleMessage("L\'ID de paiement ne peut contenir que 16 à 64 caractères hexadécimaux"), - "error_text_service_node" : MessageLookupByLibrary.simpleMessage("Une clé de nœud de service ne peut contenir que 64 caractères maximum"), - "error_text_subaddress_name" : MessageLookupByLibrary.simpleMessage("Au nom de la sous-adresse, les symboles ` , \' \" ne pas être inclus\net doit comporter entre 1 et 20 caractères"), - "error_text_wallet_name" : MessageLookupByLibrary.simpleMessage("Le nom du portefeuille ne peut contenir que des lettres et des chiffres\net doit comporter entre 1 et 15 caractères"), - "failed_authentication" : m7, - "faq" : MessageLookupByLibrary.simpleMessage("FAQ"), - "fetching" : MessageLookupByLibrary.simpleMessage("Récupération"), - "filters" : MessageLookupByLibrary.simpleMessage("filtres"), - "first_wallet_text" : MessageLookupByLibrary.simpleMessage("Super Wallet\npour Oxen"), - "full_balance" : MessageLookupByLibrary.simpleMessage("Solde complet"), - "hidden_balance" : MessageLookupByLibrary.simpleMessage("solde caché"), - "id" : MessageLookupByLibrary.simpleMessage("ID: "), - "incoming" : MessageLookupByLibrary.simpleMessage("entrant"), - "incorrect_seed" : MessageLookupByLibrary.simpleMessage("Le texte saisi n\'est pas valide."), - "keys_title" : MessageLookupByLibrary.simpleMessage("Clés"), - "loading_your_wallet" : MessageLookupByLibrary.simpleMessage("chargement du portefeuille"), - "login" : MessageLookupByLibrary.simpleMessage("Login"), - "never_give_your" : m8, - "new_subaddress_create" : MessageLookupByLibrary.simpleMessage("Créer"), - "new_subaddress_label_name" : MessageLookupByLibrary.simpleMessage("Nom"), - "new_subaddress_title" : MessageLookupByLibrary.simpleMessage("Nouvelle sous-adresse"), - "new_wallet" : MessageLookupByLibrary.simpleMessage("Nouveau portefeuille"), - "node_address" : MessageLookupByLibrary.simpleMessage("L\'adresse du Node"), - "node_new" : MessageLookupByLibrary.simpleMessage("Nouveau Node"), - "node_port" : MessageLookupByLibrary.simpleMessage("Port du Node"), - "node_reset_settings_title" : MessageLookupByLibrary.simpleMessage("Réinitialiser les paramètres"), - "nodes" : MessageLookupByLibrary.simpleMessage("Nodes"), - "nodes_list_reset_to_default_message" : MessageLookupByLibrary.simpleMessage("Êtes-vous sûr de vouloir réinitialiser les paramètres par défaut?"), - "nothing_staked" : MessageLookupByLibrary.simpleMessage("Aucune contribution pour le moment"), - "ok" : MessageLookupByLibrary.simpleMessage("OK"), - "openalias_alert_content" : m9, - "openalias_alert_title" : MessageLookupByLibrary.simpleMessage("OXEN-destinataire reconnu"), - "outgoing" : MessageLookupByLibrary.simpleMessage("sortant"), - "oxen_available_balance" : MessageLookupByLibrary.simpleMessage("OXEN solde disponible"), - "oxen_full_balance" : MessageLookupByLibrary.simpleMessage("OXEN solde complet"), - "oxen_hidden" : MessageLookupByLibrary.simpleMessage("OXEN caché"), - "password" : MessageLookupByLibrary.simpleMessage("Mot de Passe"), - "paste" : MessageLookupByLibrary.simpleMessage("Coller"), - "pending" : MessageLookupByLibrary.simpleMessage(" (en attente)"), - "pin_is_incorrect" : MessageLookupByLibrary.simpleMessage("Le code PIN est faux"), - "please_make_selection" : MessageLookupByLibrary.simpleMessage("Veuillez faire un choix ci-dessous\nCréez ou restaurez votre portefeuille."), - "please_select" : MessageLookupByLibrary.simpleMessage("Veuillez sélectionner:"), - "please_try_to_connect_to_another_node" : MessageLookupByLibrary.simpleMessage("veuillez essayer de vous connecter à un autre node"), - "receive" : MessageLookupByLibrary.simpleMessage("recevoir"), - "receive_amount" : MessageLookupByLibrary.simpleMessage("Montant"), - "received" : MessageLookupByLibrary.simpleMessage("a reçu"), - "reconnect" : MessageLookupByLibrary.simpleMessage("se reconnecter"), - "reconnect_alert_text" : MessageLookupByLibrary.simpleMessage("Voulez-vous vraiment vous reconnecter?"), - "reconnection" : MessageLookupByLibrary.simpleMessage("reconnexion"), - "reload_fiat" : MessageLookupByLibrary.simpleMessage("Actualiser le taux fiat"), - "remove" : MessageLookupByLibrary.simpleMessage("supprimer"), - "remove_node" : MessageLookupByLibrary.simpleMessage("supprimer le Node"), - "remove_node_message" : MessageLookupByLibrary.simpleMessage("Vous voulez vraiment supprimer le Node sélectionné?"), - "rescan" : MessageLookupByLibrary.simpleMessage("réanalyser"), - "reset" : MessageLookupByLibrary.simpleMessage("Réinitialiser"), - "restore_address" : MessageLookupByLibrary.simpleMessage("Adresse"), - "restore_description_from_backup" : MessageLookupByLibrary.simpleMessage("Vous pouvez restaurer l\'intégralité de l\'application Oxen Wallet à partir de son fichier de sauvegarde."), - "restore_description_from_keys" : MessageLookupByLibrary.simpleMessage("Restaurez votre portefeuille à partir du mnemonic généré à partir de vos clés privées"), - "restore_description_from_seed" : MessageLookupByLibrary.simpleMessage("Récupérez votre portefeuille à partir du code de combinaison de 25 ou 13 mots"), - "restore_description_from_seed_keys" : MessageLookupByLibrary.simpleMessage("Restaurez votre portefeuille avec le Seed ou les clées que vous avez conservées dans un endroit sûr"), - "restore_from_seed_placeholder" : MessageLookupByLibrary.simpleMessage("Veuillez entrer votre code ici"), - "restore_next" : MessageLookupByLibrary.simpleMessage("Continuer"), - "restore_recover" : MessageLookupByLibrary.simpleMessage("Restaurer"), - "restore_restore_wallet" : MessageLookupByLibrary.simpleMessage("Restauration du portefeuille"), - "restore_seed_keys_restore" : MessageLookupByLibrary.simpleMessage("Restaurer depuis le Seed ou les clés"), - "restore_spend_key_private" : MessageLookupByLibrary.simpleMessage("Clé de dépense (secret)"), - "restore_title_from_backup" : MessageLookupByLibrary.simpleMessage("Restaurer à partir d\'un fichier de sauvegarde"), - "restore_title_from_keys" : MessageLookupByLibrary.simpleMessage("Récupération des clés"), - "restore_title_from_seed" : MessageLookupByLibrary.simpleMessage("Restaurer à partir du Seed"), - "restore_title_from_seed_keys" : MessageLookupByLibrary.simpleMessage("Restaurer à partir du seed ou des clés"), - "restore_view_key_private" : MessageLookupByLibrary.simpleMessage("Clé d\'observation (secret)"), - "restore_wallet" : MessageLookupByLibrary.simpleMessage("Restaurer un portefeuille"), - "restore_wallet_name" : MessageLookupByLibrary.simpleMessage("Nom du portefeuille"), - "restore_wallet_restore_description" : MessageLookupByLibrary.simpleMessage("Description de la restauration du portefeuille"), - "router_no_route" : m10, - "save" : MessageLookupByLibrary.simpleMessage("Sauvegarder"), - "seed_language_chinese" : MessageLookupByLibrary.simpleMessage("Chinois"), - "seed_language_choose" : MessageLookupByLibrary.simpleMessage("Veuillez sélectionner la langue source"), - "seed_language_dutch" : MessageLookupByLibrary.simpleMessage("Néerlandais"), - "seed_language_english" : MessageLookupByLibrary.simpleMessage("Anglais"), - "seed_language_french" : MessageLookupByLibrary.simpleMessage("Français"), - "seed_language_german" : MessageLookupByLibrary.simpleMessage("Allemand"), - "seed_language_italian" : MessageLookupByLibrary.simpleMessage("Italien"), - "seed_language_japanese" : MessageLookupByLibrary.simpleMessage("Japonais"), - "seed_language_next" : MessageLookupByLibrary.simpleMessage("Continuer"), - "seed_language_portuguese" : MessageLookupByLibrary.simpleMessage("Portugais"), - "seed_language_russian" : MessageLookupByLibrary.simpleMessage("Russe"), - "seed_language_spanish" : MessageLookupByLibrary.simpleMessage("Espagnol"), - "seed_share" : MessageLookupByLibrary.simpleMessage("Partager Seed"), - "seed_title" : MessageLookupByLibrary.simpleMessage("Seed"), - "send" : MessageLookupByLibrary.simpleMessage("envoyer"), - "send_creating_transaction" : MessageLookupByLibrary.simpleMessage("Créer une transaction"), - "send_error_currency" : MessageLookupByLibrary.simpleMessage("La devise ne peut contenir que des nombres"), - "send_estimated_fee" : MessageLookupByLibrary.simpleMessage("Frais estimés:"), - "send_oxen" : MessageLookupByLibrary.simpleMessage("Envoyer OXEN"), - "send_oxen_address" : MessageLookupByLibrary.simpleMessage("Adresse Oxen"), - "send_priority" : m11, - "send_title" : MessageLookupByLibrary.simpleMessage("Envoyer des OXEN"), - "send_your_wallet" : MessageLookupByLibrary.simpleMessage("Votre portefeuille"), - "sending" : MessageLookupByLibrary.simpleMessage("Envoyer"), - "sent" : MessageLookupByLibrary.simpleMessage("expédié"), - "service_node_key" : MessageLookupByLibrary.simpleMessage("Clé de nœud de service"), - "settings_all" : MessageLookupByLibrary.simpleMessage("TOUT"), - "settings_allow_biometric_authentication" : MessageLookupByLibrary.simpleMessage("Authentification biométrique"), - "settings_balance_detail" : MessageLookupByLibrary.simpleMessage("Décimales"), - "settings_change_language" : MessageLookupByLibrary.simpleMessage("changer de langue"), - "settings_change_pin" : MessageLookupByLibrary.simpleMessage("changer le code PIN"), - "settings_currency" : MessageLookupByLibrary.simpleMessage("Devise"), - "settings_current_node" : MessageLookupByLibrary.simpleMessage("Node actuel"), - "settings_dark_mode" : MessageLookupByLibrary.simpleMessage("Mode Sombre"), - "settings_display_balance_as" : MessageLookupByLibrary.simpleMessage("Afficher la balance comme"), - "settings_display_on_dashboard_list" : MessageLookupByLibrary.simpleMessage("Afficher dans la liste du tableau de bord"), - "settings_enable_fiat_currency" : MessageLookupByLibrary.simpleMessage("Convertir la devise en fiat"), - "settings_fee_priority" : MessageLookupByLibrary.simpleMessage("Priorité des frais"), - "settings_nodes" : MessageLookupByLibrary.simpleMessage("Node"), - "settings_none" : MessageLookupByLibrary.simpleMessage("Rien"), - "settings_personal" : MessageLookupByLibrary.simpleMessage("personnel"), - "settings_save_recipient_address" : MessageLookupByLibrary.simpleMessage("Enregistrer l\'adresse du destinataire"), - "settings_support" : MessageLookupByLibrary.simpleMessage("Soutien"), - "settings_terms_and_conditions" : MessageLookupByLibrary.simpleMessage("Termes et conditions"), - "settings_title" : MessageLookupByLibrary.simpleMessage("Paramètres"), - "settings_transactions" : MessageLookupByLibrary.simpleMessage("Transactions"), - "settings_wallets" : MessageLookupByLibrary.simpleMessage("Portefeuilles"), - "setup_pin" : MessageLookupByLibrary.simpleMessage("Configurer le code PIN"), - "setup_successful" : MessageLookupByLibrary.simpleMessage("Votre code PIN a été configuré avec succès!"), - "share_address" : MessageLookupByLibrary.simpleMessage("Partager l\'adresse "), - "show_keys" : MessageLookupByLibrary.simpleMessage("Afficher les clés"), - "show_seed" : MessageLookupByLibrary.simpleMessage("Afficher le seed"), - "spend_key_private" : MessageLookupByLibrary.simpleMessage("Clé de dépense (secret)"), - "spend_key_public" : MessageLookupByLibrary.simpleMessage("Clé de dépense (publique)"), - "stake_more" : MessageLookupByLibrary.simpleMessage("Staker plus"), - "stake_oxen" : MessageLookupByLibrary.simpleMessage("Stake Oxen"), - "start_staking" : MessageLookupByLibrary.simpleMessage("Commencer le staking"), - "status" : MessageLookupByLibrary.simpleMessage("Statut: "), - "subaddress_title" : MessageLookupByLibrary.simpleMessage("Liste des sous-adresses"), - "subaddresses" : MessageLookupByLibrary.simpleMessage("Sous-adresses"), - "sync_status_connected" : MessageLookupByLibrary.simpleMessage("CONNECTÉ"), - "sync_status_connecting" : MessageLookupByLibrary.simpleMessage("CONNEXION"), - "sync_status_failed_connect" : MessageLookupByLibrary.simpleMessage("ÉCHEC DE LA CONNEXION AU NODE"), - "sync_status_not_connected" : MessageLookupByLibrary.simpleMessage("PAS CONNECTÉ"), - "sync_status_starting_sync" : MessageLookupByLibrary.simpleMessage("DÉBUT DE LA SYNCHRONISATION"), - "sync_status_synchronized" : MessageLookupByLibrary.simpleMessage("SYNCHRONISÉ"), - "sync_status_synchronizing" : MessageLookupByLibrary.simpleMessage("SYNCHRONISATION"), - "title_confirm_unlock_stake" : MessageLookupByLibrary.simpleMessage("Déverrouiller Stake"), - "title_new_stake" : MessageLookupByLibrary.simpleMessage("Nouveau Stake"), - "title_stakes" : MessageLookupByLibrary.simpleMessage("Stakes"), - "today" : MessageLookupByLibrary.simpleMessage("aujourd\'hui"), - "transaction_details_amount" : MessageLookupByLibrary.simpleMessage("Montant"), - "transaction_details_copied" : m12, - "transaction_details_date" : MessageLookupByLibrary.simpleMessage("Date"), - "transaction_details_height" : MessageLookupByLibrary.simpleMessage("Taille"), - "transaction_details_recipient_address" : MessageLookupByLibrary.simpleMessage("Adresse du destinataire"), - "transaction_details_title" : MessageLookupByLibrary.simpleMessage("détails de la transaction"), - "transaction_details_transaction_id" : MessageLookupByLibrary.simpleMessage("ID Transaction"), - "transaction_priority_blink" : MessageLookupByLibrary.simpleMessage("Blink"), - "transaction_priority_slow" : MessageLookupByLibrary.simpleMessage("Lente"), - "transaction_sent" : MessageLookupByLibrary.simpleMessage("Transaction envoyé!"), - "transactions" : MessageLookupByLibrary.simpleMessage("transactions"), - "transactions_by_date" : MessageLookupByLibrary.simpleMessage("transactions par date"), - "unable_unlock_stake" : MessageLookupByLibrary.simpleMessage("Impossible de déverrouiller le Stake"), - "unlock_stake_requested" : MessageLookupByLibrary.simpleMessage("Déverrouillage du Stake demandé"), - "use" : MessageLookupByLibrary.simpleMessage("Basculer vers "), - "version" : m13, - "view_key_private" : MessageLookupByLibrary.simpleMessage("Clé d\'observation (secret)"), - "view_key_public" : MessageLookupByLibrary.simpleMessage("Clé d\'observation (publique)"), - "wallet_keys" : MessageLookupByLibrary.simpleMessage("Clés du portefeuille"), - "wallet_list_create_new_wallet" : MessageLookupByLibrary.simpleMessage("Créer un nouveau portefeuille"), - "wallet_list_failed_to_load" : m14, - "wallet_list_failed_to_remove" : m15, - "wallet_list_load_wallet" : MessageLookupByLibrary.simpleMessage("Charger le portefeuille"), - "wallet_list_loading_wallet" : m16, - "wallet_list_removing_wallet" : m17, - "wallet_list_restore_wallet" : MessageLookupByLibrary.simpleMessage("Restaurer le portefeuille"), - "wallet_list_title" : MessageLookupByLibrary.simpleMessage("Oxen Wallet"), - "wallet_menu" : MessageLookupByLibrary.simpleMessage("Menu du portefeuille"), - "wallet_name" : MessageLookupByLibrary.simpleMessage("Nom du portefeuille"), - "wallet_restoration_store_incorrect_seed_length" : MessageLookupByLibrary.simpleMessage("mauvaise longueur du Seed"), - "wallets" : MessageLookupByLibrary.simpleMessage("Wallets"), - "welcome" : MessageLookupByLibrary.simpleMessage("Bienvenu sur\nOXEN WALLET"), - "widgets_address" : MessageLookupByLibrary.simpleMessage("Adresse"), - "widgets_or" : MessageLookupByLibrary.simpleMessage("ou"), - "widgets_restore_from_blockheight" : MessageLookupByLibrary.simpleMessage("restaurer à partir du blockheight"), - "widgets_restore_from_date" : MessageLookupByLibrary.simpleMessage("Restaurer à partir de la date"), - "widgets_seed" : MessageLookupByLibrary.simpleMessage("Seed"), - "yes_im_sure" : MessageLookupByLibrary.simpleMessage("Oui, je suis sûr!"), - "yesterday" : MessageLookupByLibrary.simpleMessage("hier"), - "your_contributions" : MessageLookupByLibrary.simpleMessage("Vos contributions") - }; -} diff --git a/lib/generated/l10n.dart b/lib/generated/l10n.dart deleted file mode 100644 index 791e85bb..00000000 --- a/lib/generated/l10n.dart +++ /dev/null @@ -1,2527 +0,0 @@ -// GENERATED CODE - DO NOT MODIFY BY HAND -import 'package:flutter/material.dart'; -import 'package:intl/intl.dart'; -import 'intl/messages_all.dart'; - -// ************************************************************************** -// Generator: Flutter Intl IDE plugin -// Made by Localizely -// ************************************************************************** - -// ignore_for_file: non_constant_identifier_names, lines_longer_than_80_chars -// ignore_for_file: join_return_with_assignment, prefer_final_in_for_each -// ignore_for_file: avoid_redundant_argument_values - -class S { - S(); - - static S current; - - static const AppLocalizationDelegate delegate = - AppLocalizationDelegate(); - - static Future load(Locale locale) { - final name = (locale.countryCode?.isEmpty ?? false) ? locale.languageCode : locale.toString(); - final localeName = Intl.canonicalizedLocale(name); - return initializeMessages(localeName).then((_) { - Intl.defaultLocale = localeName; - S.current = S(); - - return S.current; - }); - } - - static S of(BuildContext context) { - return Localizations.of(context, S); - } - - /// `WELCOME\nTO OXEN WALLET` - String get welcome { - return Intl.message( - 'WELCOME\nTO OXEN WALLET', - name: 'welcome', - desc: '', - args: [], - ); - } - - /// `Awesome wallet\nfor Oxen` - String get first_wallet_text { - return Intl.message( - 'Awesome wallet\nfor Oxen', - name: 'first_wallet_text', - desc: '', - args: [], - ); - } - - /// `Please make selection below to\ncreate or recover your wallet.` - String get please_make_selection { - return Intl.message( - 'Please make selection below to\ncreate or recover your wallet.', - name: 'please_make_selection', - desc: '', - args: [], - ); - } - - /// `Create new` - String get create_new { - return Intl.message( - 'Create new', - name: 'create_new', - desc: '', - args: [], - ); - } - - /// `Restore wallet` - String get restore_wallet { - return Intl.message( - 'Restore wallet', - name: 'restore_wallet', - desc: '', - args: [], - ); - } - - /// `Accounts` - String get accounts { - return Intl.message( - 'Accounts', - name: 'accounts', - desc: '', - args: [], - ); - } - - /// `Edit` - String get edit { - return Intl.message( - 'Edit', - name: 'edit', - desc: '', - args: [], - ); - } - - /// `Account` - String get account { - return Intl.message( - 'Account', - name: 'account', - desc: '', - args: [], - ); - } - - /// `Add` - String get add { - return Intl.message( - 'Add', - name: 'add', - desc: '', - args: [], - ); - } - - /// `Address Book` - String get address_book { - return Intl.message( - 'Address Book', - name: 'address_book', - desc: '', - args: [], - ); - } - - /// `Contact` - String get contact { - return Intl.message( - 'Contact', - name: 'contact', - desc: '', - args: [], - ); - } - - /// `Please select:` - String get please_select { - return Intl.message( - 'Please select:', - name: 'please_select', - desc: '', - args: [], - ); - } - - /// `Cancel` - String get cancel { - return Intl.message( - 'Cancel', - name: 'cancel', - desc: '', - args: [], - ); - } - - /// `OK` - String get ok { - return Intl.message( - 'OK', - name: 'ok', - desc: '', - args: [], - ); - } - - /// `Contact Name` - String get contact_name { - return Intl.message( - 'Contact Name', - name: 'contact_name', - desc: '', - args: [], - ); - } - - /// `Reset` - String get reset { - return Intl.message( - 'Reset', - name: 'reset', - desc: '', - args: [], - ); - } - - /// `Save` - String get save { - return Intl.message( - 'Save', - name: 'save', - desc: '', - args: [], - ); - } - - /// `Authenticated` - String get authenticated { - return Intl.message( - 'Authenticated', - name: 'authenticated', - desc: '', - args: [], - ); - } - - /// `Authentication` - String get authentication { - return Intl.message( - 'Authentication', - name: 'authentication', - desc: '', - args: [], - ); - } - - /// `Failed authentication. {state_error}` - String failed_authentication(Object state_error) { - return Intl.message( - 'Failed authentication. $state_error', - name: 'failed_authentication', - desc: '', - args: [state_error], - ); - } - - /// `Menu` - String get wallet_menu { - return Intl.message( - 'Menu', - name: 'wallet_menu', - desc: '', - args: [], - ); - } - - /// `{status} Blocks Remaining` - String Blocks_remaining(Object status) { - return Intl.message( - '$status Blocks Remaining', - name: 'Blocks_remaining', - desc: '', - args: [status], - ); - } - - /// `Please try to connect to another node` - String get please_try_to_connect_to_another_node { - return Intl.message( - 'Please try to connect to another node', - name: 'please_try_to_connect_to_another_node', - desc: '', - args: [], - ); - } - - /// `OXEN Hidden` - String get oxen_hidden { - return Intl.message( - 'OXEN Hidden', - name: 'oxen_hidden', - desc: '', - args: [], - ); - } - - /// `OXEN Available Balance` - String get oxen_available_balance { - return Intl.message( - 'OXEN Available Balance', - name: 'oxen_available_balance', - desc: '', - args: [], - ); - } - - /// `OXEN Full Balance` - String get oxen_full_balance { - return Intl.message( - 'OXEN Full Balance', - name: 'oxen_full_balance', - desc: '', - args: [], - ); - } - - /// `Send` - String get send { - return Intl.message( - 'Send', - name: 'send', - desc: '', - args: [], - ); - } - - /// `Receive` - String get receive { - return Intl.message( - 'Receive', - name: 'receive', - desc: '', - args: [], - ); - } - - /// `Transactions` - String get transactions { - return Intl.message( - 'Transactions', - name: 'transactions', - desc: '', - args: [], - ); - } - - /// `Incoming` - String get incoming { - return Intl.message( - 'Incoming', - name: 'incoming', - desc: '', - args: [], - ); - } - - /// `Outgoing` - String get outgoing { - return Intl.message( - 'Outgoing', - name: 'outgoing', - desc: '', - args: [], - ); - } - - /// `Transactions by date` - String get transactions_by_date { - return Intl.message( - 'Transactions by date', - name: 'transactions_by_date', - desc: '', - args: [], - ); - } - - /// `Filters` - String get filters { - return Intl.message( - 'Filters', - name: 'filters', - desc: '', - args: [], - ); - } - - /// `Today` - String get today { - return Intl.message( - 'Today', - name: 'today', - desc: '', - args: [], - ); - } - - /// `Yesterday` - String get yesterday { - return Intl.message( - 'Yesterday', - name: 'yesterday', - desc: '', - args: [], - ); - } - - /// `Received` - String get received { - return Intl.message( - 'Received', - name: 'received', - desc: '', - args: [], - ); - } - - /// `Sent` - String get sent { - return Intl.message( - 'Sent', - name: 'sent', - desc: '', - args: [], - ); - } - - /// ` (pending)` - String get pending { - return Intl.message( - ' (pending)', - name: 'pending', - desc: '', - args: [], - ); - } - - /// `Rescan` - String get rescan { - return Intl.message( - 'Rescan', - name: 'rescan', - desc: '', - args: [], - ); - } - - /// `Reconnect` - String get reconnect { - return Intl.message( - 'Reconnect', - name: 'reconnect', - desc: '', - args: [], - ); - } - - /// `Wallets` - String get wallets { - return Intl.message( - 'Wallets', - name: 'wallets', - desc: '', - args: [], - ); - } - - /// `Show seed` - String get show_seed { - return Intl.message( - 'Show seed', - name: 'show_seed', - desc: '', - args: [], - ); - } - - /// `Show keys` - String get show_keys { - return Intl.message( - 'Show keys', - name: 'show_keys', - desc: '', - args: [], - ); - } - - /// `Address book` - String get address_book_menu { - return Intl.message( - 'Address book', - name: 'address_book_menu', - desc: '', - args: [], - ); - } - - /// `Reconnection` - String get reconnection { - return Intl.message( - 'Reconnection', - name: 'reconnection', - desc: '', - args: [], - ); - } - - /// `Are you sure to reconnect?` - String get reconnect_alert_text { - return Intl.message( - 'Are you sure to reconnect?', - name: 'reconnect_alert_text', - desc: '', - args: [], - ); - } - - /// `Reload Fiat data` - String get reload_fiat { - return Intl.message( - 'Reload Fiat data', - name: 'reload_fiat', - desc: '', - args: [], - ); - } - - /// `Clear` - String get clear { - return Intl.message( - 'Clear', - name: 'clear', - desc: '', - args: [], - ); - } - - /// `Error` - String get error { - return Intl.message( - 'Error', - name: 'error', - desc: '', - args: [], - ); - } - - /// `Copied to Clipboard` - String get copied_to_clipboard { - return Intl.message( - 'Copied to Clipboard', - name: 'copied_to_clipboard', - desc: '', - args: [], - ); - } - - /// `Fetching` - String get fetching { - return Intl.message( - 'Fetching', - name: 'fetching', - desc: '', - args: [], - ); - } - - /// `ID: ` - String get id { - return Intl.message( - 'ID: ', - name: 'id', - desc: '', - args: [], - ); - } - - /// `Amount: ` - String get amount { - return Intl.message( - 'Amount: ', - name: 'amount', - desc: '', - args: [], - ); - } - - /// `Status: ` - String get status { - return Intl.message( - 'Status: ', - name: 'status', - desc: '', - args: [], - ); - } - - /// `Confirm` - String get confirm { - return Intl.message( - 'Confirm', - name: 'confirm', - desc: '', - args: [], - ); - } - - /// `Confirm sending` - String get confirm_sending { - return Intl.message( - 'Confirm sending', - name: 'confirm_sending', - desc: '', - args: [], - ); - } - - /// `Commit transaction\nAmount: {amount}\nFee: {fee}` - String commit_transaction_amount_fee(Object amount, Object fee) { - return Intl.message( - 'Commit transaction\nAmount: $amount\nFee: $fee', - name: 'commit_transaction_amount_fee', - desc: '', - args: [amount, fee], - ); - } - - /// `Sending` - String get sending { - return Intl.message( - 'Sending', - name: 'sending', - desc: '', - args: [], - ); - } - - /// `Transaction sent!` - String get transaction_sent { - return Intl.message( - 'Transaction sent!', - name: 'transaction_sent', - desc: '', - args: [], - ); - } - - /// `Send OXEN` - String get send_oxen { - return Intl.message( - 'Send OXEN', - name: 'send_oxen', - desc: '', - args: [], - ); - } - - /// `FAQ` - String get faq { - return Intl.message( - 'FAQ', - name: 'faq', - desc: '', - args: [], - ); - } - - /// `Changelog` - String get changelog { - return Intl.message( - 'Changelog', - name: 'changelog', - desc: '', - args: [], - ); - } - - /// `Enter your PIN` - String get enter_your_pin { - return Intl.message( - 'Enter your PIN', - name: 'enter_your_pin', - desc: '', - args: [], - ); - } - - /// `Loading your wallet` - String get loading_your_wallet { - return Intl.message( - 'Loading your wallet', - name: 'loading_your_wallet', - desc: '', - args: [], - ); - } - - /// `New Wallet` - String get new_wallet { - return Intl.message( - 'New Wallet', - name: 'new_wallet', - desc: '', - args: [], - ); - } - - /// `Wallet name` - String get wallet_name { - return Intl.message( - 'Wallet name', - name: 'wallet_name', - desc: '', - args: [], - ); - } - - /// `Continue` - String get continue_text { - return Intl.message( - 'Continue', - name: 'continue_text', - desc: '', - args: [], - ); - } - - /// `New Node` - String get node_new { - return Intl.message( - 'New Node', - name: 'node_new', - desc: '', - args: [], - ); - } - - /// `Node Address` - String get node_address { - return Intl.message( - 'Node Address', - name: 'node_address', - desc: '', - args: [], - ); - } - - /// `Node port` - String get node_port { - return Intl.message( - 'Node port', - name: 'node_port', - desc: '', - args: [], - ); - } - - /// `Login` - String get login { - return Intl.message( - 'Login', - name: 'login', - desc: '', - args: [], - ); - } - - /// `Password` - String get password { - return Intl.message( - 'Password', - name: 'password', - desc: '', - args: [], - ); - } - - /// `Nodes` - String get nodes { - return Intl.message( - 'Nodes', - name: 'nodes', - desc: '', - args: [], - ); - } - - /// `Reset settings` - String get node_reset_settings_title { - return Intl.message( - 'Reset settings', - name: 'node_reset_settings_title', - desc: '', - args: [], - ); - } - - /// `Are you sure that you want to reset settings to default?` - String get nodes_list_reset_to_default_message { - return Intl.message( - 'Are you sure that you want to reset settings to default?', - name: 'nodes_list_reset_to_default_message', - desc: '', - args: [], - ); - } - - /// `Are you sure to change current node to {node}?` - String change_current_node(Object node) { - return Intl.message( - 'Are you sure to change current node to $node?', - name: 'change_current_node', - desc: '', - args: [node], - ); - } - - /// `Change` - String get change { - return Intl.message( - 'Change', - name: 'change', - desc: '', - args: [], - ); - } - - /// `Remove node` - String get remove_node { - return Intl.message( - 'Remove node', - name: 'remove_node', - desc: '', - args: [], - ); - } - - /// `Are you sure that you want to remove selected node?` - String get remove_node_message { - return Intl.message( - 'Are you sure that you want to remove selected node?', - name: 'remove_node_message', - desc: '', - args: [], - ); - } - - /// `Remove` - String get remove { - return Intl.message( - 'Remove', - name: 'remove', - desc: '', - args: [], - ); - } - - /// `Delete` - String get delete { - return Intl.message( - 'Delete', - name: 'delete', - desc: '', - args: [], - ); - } - - /// `Switch to ` - String get use { - return Intl.message( - 'Switch to ', - name: 'use', - desc: '', - args: [], - ); - } - - /// `-digit PIN` - String get digit_pin { - return Intl.message( - '-digit PIN', - name: 'digit_pin', - desc: '', - args: [], - ); - } - - /// `Share address` - String get share_address { - return Intl.message( - 'Share address', - name: 'share_address', - desc: '', - args: [], - ); - } - - /// `Amount` - String get receive_amount { - return Intl.message( - 'Amount', - name: 'receive_amount', - desc: '', - args: [], - ); - } - - /// `Subaddresses` - String get subaddresses { - return Intl.message( - 'Subaddresses', - name: 'subaddresses', - desc: '', - args: [], - ); - } - - /// `Restore Wallet` - String get restore_restore_wallet { - return Intl.message( - 'Restore Wallet', - name: 'restore_restore_wallet', - desc: '', - args: [], - ); - } - - /// `Restore from seed/keys` - String get restore_title_from_seed_keys { - return Intl.message( - 'Restore from seed/keys', - name: 'restore_title_from_seed_keys', - desc: '', - args: [], - ); - } - - /// `Get back your wallet from seed/keys that you've saved to secure place` - String get restore_description_from_seed_keys { - return Intl.message( - 'Get back your wallet from seed/keys that you\'ve saved to secure place', - name: 'restore_description_from_seed_keys', - desc: '', - args: [], - ); - } - - /// `Next` - String get restore_next { - return Intl.message( - 'Next', - name: 'restore_next', - desc: '', - args: [], - ); - } - - /// `Restore from a back-up file` - String get restore_title_from_backup { - return Intl.message( - 'Restore from a back-up file', - name: 'restore_title_from_backup', - desc: '', - args: [], - ); - } - - /// `You can restore the whole Oxen Wallet app from your back-up file` - String get restore_description_from_backup { - return Intl.message( - 'You can restore the whole Oxen Wallet app from your back-up file', - name: 'restore_description_from_backup', - desc: '', - args: [], - ); - } - - /// `Seed/Keys Restore` - String get restore_seed_keys_restore { - return Intl.message( - 'Seed/Keys Restore', - name: 'restore_seed_keys_restore', - desc: '', - args: [], - ); - } - - /// `Restore from seed` - String get restore_title_from_seed { - return Intl.message( - 'Restore from seed', - name: 'restore_title_from_seed', - desc: '', - args: [], - ); - } - - /// `Restore your wallet from either the 25 word or 13 word combination code` - String get restore_description_from_seed { - return Intl.message( - 'Restore your wallet from either the 25 word or 13 word combination code', - name: 'restore_description_from_seed', - desc: '', - args: [], - ); - } - - /// `Restore from keys` - String get restore_title_from_keys { - return Intl.message( - 'Restore from keys', - name: 'restore_title_from_keys', - desc: '', - args: [], - ); - } - - /// `Restore your wallet from generated keystrokes saved from your private keys` - String get restore_description_from_keys { - return Intl.message( - 'Restore your wallet from generated keystrokes saved from your private keys', - name: 'restore_description_from_keys', - desc: '', - args: [], - ); - } - - /// `Wallet name` - String get restore_wallet_name { - return Intl.message( - 'Wallet name', - name: 'restore_wallet_name', - desc: '', - args: [], - ); - } - - /// `Address` - String get restore_address { - return Intl.message( - 'Address', - name: 'restore_address', - desc: '', - args: [], - ); - } - - /// `View key (private)` - String get restore_view_key_private { - return Intl.message( - 'View key (private)', - name: 'restore_view_key_private', - desc: '', - args: [], - ); - } - - /// `Spend key (private)` - String get restore_spend_key_private { - return Intl.message( - 'Spend key (private)', - name: 'restore_spend_key_private', - desc: '', - args: [], - ); - } - - /// `Restore` - String get restore_recover { - return Intl.message( - 'Restore', - name: 'restore_recover', - desc: '', - args: [], - ); - } - - /// `Wallet restore description` - String get restore_wallet_restore_description { - return Intl.message( - 'Wallet restore description', - name: 'restore_wallet_restore_description', - desc: '', - args: [], - ); - } - - /// `Seed` - String get seed_title { - return Intl.message( - 'Seed', - name: 'seed_title', - desc: '', - args: [], - ); - } - - /// `Share seed` - String get seed_share { - return Intl.message( - 'Share seed', - name: 'seed_share', - desc: '', - args: [], - ); - } - - /// `Copy` - String get copy { - return Intl.message( - 'Copy', - name: 'copy', - desc: '', - args: [], - ); - } - - /// `Please choose seed language` - String get seed_language_choose { - return Intl.message( - 'Please choose seed language', - name: 'seed_language_choose', - desc: '', - args: [], - ); - } - - /// `Next` - String get seed_language_next { - return Intl.message( - 'Next', - name: 'seed_language_next', - desc: '', - args: [], - ); - } - - /// `English` - String get seed_language_english { - return Intl.message( - 'English', - name: 'seed_language_english', - desc: '', - args: [], - ); - } - - /// `Chinese` - String get seed_language_chinese { - return Intl.message( - 'Chinese', - name: 'seed_language_chinese', - desc: '', - args: [], - ); - } - - /// `Dutch` - String get seed_language_dutch { - return Intl.message( - 'Dutch', - name: 'seed_language_dutch', - desc: '', - args: [], - ); - } - - /// `German` - String get seed_language_german { - return Intl.message( - 'German', - name: 'seed_language_german', - desc: '', - args: [], - ); - } - - /// `Japanese` - String get seed_language_japanese { - return Intl.message( - 'Japanese', - name: 'seed_language_japanese', - desc: '', - args: [], - ); - } - - /// `Portuguese` - String get seed_language_portuguese { - return Intl.message( - 'Portuguese', - name: 'seed_language_portuguese', - desc: '', - args: [], - ); - } - - /// `Russian` - String get seed_language_russian { - return Intl.message( - 'Russian', - name: 'seed_language_russian', - desc: '', - args: [], - ); - } - - /// `Spanish` - String get seed_language_spanish { - return Intl.message( - 'Spanish', - name: 'seed_language_spanish', - desc: '', - args: [], - ); - } - - /// `French` - String get seed_language_french { - return Intl.message( - 'French', - name: 'seed_language_french', - desc: '', - args: [], - ); - } - - /// `Italian` - String get seed_language_italian { - return Intl.message( - 'Italian', - name: 'seed_language_italian', - desc: '', - args: [], - ); - } - - /// `Send Oxen` - String get send_title { - return Intl.message( - 'Send Oxen', - name: 'send_title', - desc: '', - args: [], - ); - } - - /// `Your wallet` - String get send_your_wallet { - return Intl.message( - 'Your wallet', - name: 'send_your_wallet', - desc: '', - args: [], - ); - } - - /// `Oxen address` - String get send_oxen_address { - return Intl.message( - 'Oxen address', - name: 'send_oxen_address', - desc: '', - args: [], - ); - } - - /// `ALL` - String get all { - return Intl.message( - 'ALL', - name: 'all', - desc: '', - args: [], - ); - } - - /// `Currency can only contain numbers` - String get send_error_currency { - return Intl.message( - 'Currency can only contain numbers', - name: 'send_error_currency', - desc: '', - args: [], - ); - } - - /// `Estimated fee:` - String get send_estimated_fee { - return Intl.message( - 'Estimated fee:', - name: 'send_estimated_fee', - desc: '', - args: [], - ); - } - - /// `Currently the fee is set at {transactionPriority} priority.\nTransaction priority can be adjusted in the settings` - String send_priority(Object transactionPriority) { - return Intl.message( - 'Currently the fee is set at $transactionPriority priority.\nTransaction priority can be adjusted in the settings', - name: 'send_priority', - desc: '', - args: [transactionPriority], - ); - } - - /// `Creating transaction` - String get send_creating_transaction { - return Intl.message( - 'Creating transaction', - name: 'send_creating_transaction', - desc: '', - args: [], - ); - } - - /// `Stakes` - String get title_stakes { - return Intl.message( - 'Stakes', - name: 'title_stakes', - desc: '', - args: [], - ); - } - - /// `New Stake` - String get title_new_stake { - return Intl.message( - 'New Stake', - name: 'title_new_stake', - desc: '', - args: [], - ); - } - - /// `Your Contributions` - String get your_contributions { - return Intl.message( - 'Your Contributions', - name: 'your_contributions', - desc: '', - args: [], - ); - } - - /// `Start staking` - String get start_staking { - return Intl.message( - 'Start staking', - name: 'start_staking', - desc: '', - args: [], - ); - } - - /// `Stake more` - String get stake_more { - return Intl.message( - 'Stake more', - name: 'stake_more', - desc: '', - args: [], - ); - } - - /// `Nothing staked yet` - String get nothing_staked { - return Intl.message( - 'Nothing staked yet', - name: 'nothing_staked', - desc: '', - args: [], - ); - } - - /// `Service Node Key` - String get service_node_key { - return Intl.message( - 'Service Node Key', - name: 'service_node_key', - desc: '', - args: [], - ); - } - - /// `Stake Oxen` - String get stake_oxen { - return Intl.message( - 'Stake Oxen', - name: 'stake_oxen', - desc: '', - args: [], - ); - } - - /// `Unlock Stake` - String get title_confirm_unlock_stake { - return Intl.message( - 'Unlock Stake', - name: 'title_confirm_unlock_stake', - desc: '', - args: [], - ); - } - - /// `Do you really want to unlock your stake from {serviceNodeKey}?` - String body_confirm_unlock_stake(Object serviceNodeKey) { - return Intl.message( - 'Do you really want to unlock your stake from $serviceNodeKey?', - name: 'body_confirm_unlock_stake', - desc: '', - args: [serviceNodeKey], - ); - } - - /// `Stake unlock requested` - String get unlock_stake_requested { - return Intl.message( - 'Stake unlock requested', - name: 'unlock_stake_requested', - desc: '', - args: [], - ); - } - - /// `Unable to unlock stake` - String get unable_unlock_stake { - return Intl.message( - 'Unable to unlock stake', - name: 'unable_unlock_stake', - desc: '', - args: [], - ); - } - - /// `Settings` - String get settings_title { - return Intl.message( - 'Settings', - name: 'settings_title', - desc: '', - args: [], - ); - } - - /// `Nodes` - String get settings_nodes { - return Intl.message( - 'Nodes', - name: 'settings_nodes', - desc: '', - args: [], - ); - } - - /// `Current node` - String get settings_current_node { - return Intl.message( - 'Current node', - name: 'settings_current_node', - desc: '', - args: [], - ); - } - - /// `Wallets` - String get settings_wallets { - return Intl.message( - 'Wallets', - name: 'settings_wallets', - desc: '', - args: [], - ); - } - - /// `Display balance as` - String get settings_display_balance_as { - return Intl.message( - 'Display balance as', - name: 'settings_display_balance_as', - desc: '', - args: [], - ); - } - - /// `Decimals` - String get settings_balance_detail { - return Intl.message( - 'Decimals', - name: 'settings_balance_detail', - desc: '', - args: [], - ); - } - - /// `Currency` - String get settings_currency { - return Intl.message( - 'Currency', - name: 'settings_currency', - desc: '', - args: [], - ); - } - - /// `Fee priority` - String get settings_fee_priority { - return Intl.message( - 'Fee priority', - name: 'settings_fee_priority', - desc: '', - args: [], - ); - } - - /// `Save recipient address` - String get settings_save_recipient_address { - return Intl.message( - 'Save recipient address', - name: 'settings_save_recipient_address', - desc: '', - args: [], - ); - } - - /// `Personal` - String get settings_personal { - return Intl.message( - 'Personal', - name: 'settings_personal', - desc: '', - args: [], - ); - } - - /// `Change PIN` - String get settings_change_pin { - return Intl.message( - 'Change PIN', - name: 'settings_change_pin', - desc: '', - args: [], - ); - } - - /// `Change language` - String get settings_change_language { - return Intl.message( - 'Change language', - name: 'settings_change_language', - desc: '', - args: [], - ); - } - - /// `Allow biometric authentication` - String get settings_allow_biometric_authentication { - return Intl.message( - 'Allow biometric authentication', - name: 'settings_allow_biometric_authentication', - desc: '', - args: [], - ); - } - - /// `Dark mode` - String get settings_dark_mode { - return Intl.message( - 'Dark mode', - name: 'settings_dark_mode', - desc: '', - args: [], - ); - } - - /// `Transactions` - String get settings_transactions { - return Intl.message( - 'Transactions', - name: 'settings_transactions', - desc: '', - args: [], - ); - } - - /// `Display on dashboard list` - String get settings_display_on_dashboard_list { - return Intl.message( - 'Display on dashboard list', - name: 'settings_display_on_dashboard_list', - desc: '', - args: [], - ); - } - - /// `ALL` - String get settings_all { - return Intl.message( - 'ALL', - name: 'settings_all', - desc: '', - args: [], - ); - } - - /// `None` - String get settings_none { - return Intl.message( - 'None', - name: 'settings_none', - desc: '', - args: [], - ); - } - - /// `Support` - String get settings_support { - return Intl.message( - 'Support', - name: 'settings_support', - desc: '', - args: [], - ); - } - - /// `Terms and conditions` - String get settings_terms_and_conditions { - return Intl.message( - 'Terms and conditions', - name: 'settings_terms_and_conditions', - desc: '', - args: [], - ); - } - - /// `Enable Fiat Currency conversion` - String get settings_enable_fiat_currency { - return Intl.message( - 'Enable Fiat Currency conversion', - name: 'settings_enable_fiat_currency', - desc: '', - args: [], - ); - } - - /// `PIN is incorrect` - String get pin_is_incorrect { - return Intl.message( - 'PIN is incorrect', - name: 'pin_is_incorrect', - desc: '', - args: [], - ); - } - - /// `9 - Ultra` - String get amount_detail_ultra { - return Intl.message( - '9 - Ultra', - name: 'amount_detail_ultra', - desc: '', - args: [], - ); - } - - /// `0 - None` - String get amount_detail_none { - return Intl.message( - '0 - None', - name: 'amount_detail_none', - desc: '', - args: [], - ); - } - - /// `4 - Detailed` - String get amount_detail_detailed { - return Intl.message( - '4 - Detailed', - name: 'amount_detail_detailed', - desc: '', - args: [], - ); - } - - /// `2 - Normal` - String get amount_detail_normal { - return Intl.message( - '2 - Normal', - name: 'amount_detail_normal', - desc: '', - args: [], - ); - } - - /// `Setup PIN` - String get setup_pin { - return Intl.message( - 'Setup PIN', - name: 'setup_pin', - desc: '', - args: [], - ); - } - - /// `Enter your pin again` - String get enter_your_pin_again { - return Intl.message( - 'Enter your pin again', - name: 'enter_your_pin_again', - desc: '', - args: [], - ); - } - - /// `Your PIN has been set up successfully!` - String get setup_successful { - return Intl.message( - 'Your PIN has been set up successfully!', - name: 'setup_successful', - desc: '', - args: [], - ); - } - - /// `Wallet keys` - String get wallet_keys { - return Intl.message( - 'Wallet keys', - name: 'wallet_keys', - desc: '', - args: [], - ); - } - - /// `View key (private)` - String get view_key_private { - return Intl.message( - 'View key (private)', - name: 'view_key_private', - desc: '', - args: [], - ); - } - - /// `View key (public)` - String get view_key_public { - return Intl.message( - 'View key (public)', - name: 'view_key_public', - desc: '', - args: [], - ); - } - - /// `Spend key (private)` - String get spend_key_private { - return Intl.message( - 'Spend key (private)', - name: 'spend_key_private', - desc: '', - args: [], - ); - } - - /// `Spend key (public)` - String get spend_key_public { - return Intl.message( - 'Spend key (public)', - name: 'spend_key_public', - desc: '', - args: [], - ); - } - - /// `Copied {key} to Clipboard` - String copied_key_to_clipboard(Object key) { - return Intl.message( - 'Copied $key to Clipboard', - name: 'copied_key_to_clipboard', - desc: '', - args: [key], - ); - } - - /// `New subaddress` - String get new_subaddress_title { - return Intl.message( - 'New subaddress', - name: 'new_subaddress_title', - desc: '', - args: [], - ); - } - - /// `Label name` - String get new_subaddress_label_name { - return Intl.message( - 'Label name', - name: 'new_subaddress_label_name', - desc: '', - args: [], - ); - } - - /// `Create` - String get new_subaddress_create { - return Intl.message( - 'Create', - name: 'new_subaddress_create', - desc: '', - args: [], - ); - } - - /// `Subaddress list` - String get subaddress_title { - return Intl.message( - 'Subaddress list', - name: 'subaddress_title', - desc: '', - args: [], - ); - } - - /// `Transaction Details` - String get transaction_details_title { - return Intl.message( - 'Transaction Details', - name: 'transaction_details_title', - desc: '', - args: [], - ); - } - - /// `Transaction ID` - String get transaction_details_transaction_id { - return Intl.message( - 'Transaction ID', - name: 'transaction_details_transaction_id', - desc: '', - args: [], - ); - } - - /// `Date` - String get transaction_details_date { - return Intl.message( - 'Date', - name: 'transaction_details_date', - desc: '', - args: [], - ); - } - - /// `Height` - String get transaction_details_height { - return Intl.message( - 'Height', - name: 'transaction_details_height', - desc: '', - args: [], - ); - } - - /// `Amount` - String get transaction_details_amount { - return Intl.message( - 'Amount', - name: 'transaction_details_amount', - desc: '', - args: [], - ); - } - - /// `{title} copied to Clipboard` - String transaction_details_copied(Object title) { - return Intl.message( - '$title copied to Clipboard', - name: 'transaction_details_copied', - desc: '', - args: [title], - ); - } - - /// `Recipient address` - String get transaction_details_recipient_address { - return Intl.message( - 'Recipient address', - name: 'transaction_details_recipient_address', - desc: '', - args: [], - ); - } - - /// `Oxen Wallet` - String get wallet_list_title { - return Intl.message( - 'Oxen Wallet', - name: 'wallet_list_title', - desc: '', - args: [], - ); - } - - /// `Create New Wallet` - String get wallet_list_create_new_wallet { - return Intl.message( - 'Create New Wallet', - name: 'wallet_list_create_new_wallet', - desc: '', - args: [], - ); - } - - /// `Restore Wallet` - String get wallet_list_restore_wallet { - return Intl.message( - 'Restore Wallet', - name: 'wallet_list_restore_wallet', - desc: '', - args: [], - ); - } - - /// `Load wallet` - String get wallet_list_load_wallet { - return Intl.message( - 'Load wallet', - name: 'wallet_list_load_wallet', - desc: '', - args: [], - ); - } - - /// `Loading {wallet_name} wallet` - String wallet_list_loading_wallet(Object wallet_name) { - return Intl.message( - 'Loading $wallet_name wallet', - name: 'wallet_list_loading_wallet', - desc: '', - args: [wallet_name], - ); - } - - /// `Failed to load {wallet_name} wallet. {error}` - String wallet_list_failed_to_load(Object wallet_name, Object error) { - return Intl.message( - 'Failed to load $wallet_name wallet. $error', - name: 'wallet_list_failed_to_load', - desc: '', - args: [wallet_name, error], - ); - } - - /// `Removing {wallet_name} wallet` - String wallet_list_removing_wallet(Object wallet_name) { - return Intl.message( - 'Removing $wallet_name wallet', - name: 'wallet_list_removing_wallet', - desc: '', - args: [wallet_name], - ); - } - - /// `Failed to remove {wallet_name} wallet. {error}` - String wallet_list_failed_to_remove(Object wallet_name, Object error) { - return Intl.message( - 'Failed to remove $wallet_name wallet. $error', - name: 'wallet_list_failed_to_remove', - desc: '', - args: [wallet_name, error], - ); - } - - /// `Address` - String get widgets_address { - return Intl.message( - 'Address', - name: 'widgets_address', - desc: '', - args: [], - ); - } - - /// `Restore from blockheight` - String get widgets_restore_from_blockheight { - return Intl.message( - 'Restore from blockheight', - name: 'widgets_restore_from_blockheight', - desc: '', - args: [], - ); - } - - /// `Restore from date` - String get widgets_restore_from_date { - return Intl.message( - 'Restore from date', - name: 'widgets_restore_from_date', - desc: '', - args: [], - ); - } - - /// `or` - String get widgets_or { - return Intl.message( - 'or', - name: 'widgets_or', - desc: '', - args: [], - ); - } - - /// `Seed` - String get widgets_seed { - return Intl.message( - 'Seed', - name: 'widgets_seed', - desc: '', - args: [], - ); - } - - /// `No route defined for {name}` - String router_no_route(Object name) { - return Intl.message( - 'No route defined for $name', - name: 'router_no_route', - desc: '', - args: [name], - ); - } - - /// `Account name can only contain letters, numbers\nand must be between 1 and 15 characters long` - String get error_text_account_name { - return Intl.message( - 'Account name can only contain letters, numbers\nand must be between 1 and 15 characters long', - name: 'error_text_account_name', - desc: '', - args: [], - ); - } - - /// `Contact name can't contain ' , ' " symbols\nand must be between 1 and 32 characters long` - String get error_text_contact_name { - return Intl.message( - 'Contact name can\'t contain ` , \' " symbols\nand must be between 1 and 32 characters long', - name: 'error_text_contact_name', - desc: '', - args: [], - ); - } - - /// `Wallet address must correspond to the type\nof cryptocurrency` - String get error_text_address { - return Intl.message( - 'Wallet address must correspond to the type\nof cryptocurrency', - name: 'error_text_address', - desc: '', - args: [], - ); - } - - /// `Please enter a iPv4 address` - String get error_text_node_address { - return Intl.message( - 'Please enter a iPv4 address', - name: 'error_text_node_address', - desc: '', - args: [], - ); - } - - /// `Node port can only contain numbers between 0 and 65535` - String get error_text_node_port { - return Intl.message( - 'Node port can only contain numbers between 0 and 65535', - name: 'error_text_node_port', - desc: '', - args: [], - ); - } - - /// `Payment ID can only contain from 16 to 64 chars in hex` - String get error_text_payment_id { - return Intl.message( - 'Payment ID can only contain from 16 to 64 chars in hex', - name: 'error_text_payment_id', - desc: '', - args: [], - ); - } - - /// `OXEN value can't exceed available balance.\nThe number of fraction digits must be less or equal to 12` - String get error_text_oxen { - return Intl.message( - 'OXEN value can\'t exceed available balance.\nThe number of fraction digits must be less or equal to 12', - name: 'error_text_oxen', - desc: '', - args: [], - ); - } - - /// `Value of amount can't exceed available balance.\nThe number of fraction digits must be less or equal to 2` - String get error_text_fiat { - return Intl.message( - 'Value of amount can\'t exceed available balance.\nThe number of fraction digits must be less or equal to 2', - name: 'error_text_fiat', - desc: '', - args: [], - ); - } - - /// `Subaddress name can't contain ' , ' " symbols\nand must be between 1 and 20 characters long` - String get error_text_subaddress_name { - return Intl.message( - 'Subaddress name can\'t contain ` , \' " symbols\nand must be between 1 and 20 characters long', - name: 'error_text_subaddress_name', - desc: '', - args: [], - ); - } - - /// `Amount can only contain numbers` - String get error_text_amount { - return Intl.message( - 'Amount can only contain numbers', - name: 'error_text_amount', - desc: '', - args: [], - ); - } - - /// `Wallet name can only contain letters, numbers\nand must be between 1 and 15 characters long` - String get error_text_wallet_name { - return Intl.message( - 'Wallet name can only contain letters, numbers\nand must be between 1 and 15 characters long', - name: 'error_text_wallet_name', - desc: '', - args: [], - ); - } - - /// `Wallet keys can only contain 64 chars in hex` - String get error_text_keys { - return Intl.message( - 'Wallet keys can only contain 64 chars in hex', - name: 'error_text_keys', - desc: '', - args: [], - ); - } - - /// `The number of fraction digits\nmust be less or equal to 12` - String get error_text_crypto_currency { - return Intl.message( - 'The number of fraction digits\nmust be less or equal to 12', - name: 'error_text_crypto_currency', - desc: '', - args: [], - ); - } - - /// `A Service Node key can only contain 64 chars in hex` - String get error_text_service_node { - return Intl.message( - 'A Service Node key can only contain 64 chars in hex', - name: 'error_text_service_node', - desc: '', - args: [], - ); - } - - /// `ban_timeout` - String get auth_store_ban_timeout { - return Intl.message( - 'ban_timeout', - name: 'auth_store_ban_timeout', - desc: '', - args: [], - ); - } - - /// `Banned for ` - String get auth_store_banned_for { - return Intl.message( - 'Banned for ', - name: 'auth_store_banned_for', - desc: '', - args: [], - ); - } - - /// ` minutes` - String get auth_store_banned_minutes { - return Intl.message( - ' minutes', - name: 'auth_store_banned_minutes', - desc: '', - args: [], - ); - } - - /// `Wrong PIN` - String get auth_store_incorrect_password { - return Intl.message( - 'Wrong PIN', - name: 'auth_store_incorrect_password', - desc: '', - args: [], - ); - } - - /// `Incorrect seed length` - String get wallet_restoration_store_incorrect_seed_length { - return Intl.message( - 'Incorrect seed length', - name: 'wallet_restoration_store_incorrect_seed_length', - desc: '', - args: [], - ); - } - - /// `Full Balance` - String get full_balance { - return Intl.message( - 'Full Balance', - name: 'full_balance', - desc: '', - args: [], - ); - } - - /// `Available Balance` - String get available_balance { - return Intl.message( - 'Available Balance', - name: 'available_balance', - desc: '', - args: [], - ); - } - - /// `Hidden Balance` - String get hidden_balance { - return Intl.message( - 'Hidden Balance', - name: 'hidden_balance', - desc: '', - args: [], - ); - } - - /// `SYNCHRONIZING` - String get sync_status_synchronizing { - return Intl.message( - 'SYNCHRONIZING', - name: 'sync_status_synchronizing', - desc: '', - args: [], - ); - } - - /// `SYNCHRONIZED` - String get sync_status_synchronized { - return Intl.message( - 'SYNCHRONIZED', - name: 'sync_status_synchronized', - desc: '', - args: [], - ); - } - - /// `NOT CONNECTED` - String get sync_status_not_connected { - return Intl.message( - 'NOT CONNECTED', - name: 'sync_status_not_connected', - desc: '', - args: [], - ); - } - - /// `STARTING SYNC` - String get sync_status_starting_sync { - return Intl.message( - 'STARTING SYNC', - name: 'sync_status_starting_sync', - desc: '', - args: [], - ); - } - - /// `FAILED CONNECT TO THE NODE` - String get sync_status_failed_connect { - return Intl.message( - 'FAILED CONNECT TO THE NODE', - name: 'sync_status_failed_connect', - desc: '', - args: [], - ); - } - - /// `CONNECTING` - String get sync_status_connecting { - return Intl.message( - 'CONNECTING', - name: 'sync_status_connecting', - desc: '', - args: [], - ); - } - - /// `CONNECTED` - String get sync_status_connected { - return Intl.message( - 'CONNECTED', - name: 'sync_status_connected', - desc: '', - args: [], - ); - } - - /// `Slow` - String get transaction_priority_slow { - return Intl.message( - 'Slow', - name: 'transaction_priority_slow', - desc: '', - args: [], - ); - } - - /// `Blink` - String get transaction_priority_blink { - return Intl.message( - 'Blink', - name: 'transaction_priority_blink', - desc: '', - args: [], - ); - } - - /// `Change language` - String get change_language { - return Intl.message( - 'Change language', - name: 'change_language', - desc: '', - args: [], - ); - } - - /// `Change language to {language}?` - String change_language_to(Object language) { - return Intl.message( - 'Change language to $language?', - name: 'change_language_to', - desc: '', - args: [language], - ); - } - - /// `Paste` - String get paste { - return Intl.message( - 'Paste', - name: 'paste', - desc: '', - args: [], - ); - } - - /// `Please enter or paste your seed here` - String get restore_from_seed_placeholder { - return Intl.message( - 'Please enter or paste your seed here', - name: 'restore_from_seed_placeholder', - desc: '', - args: [], - ); - } - - /// `Add new word` - String get add_new_word { - return Intl.message( - 'Add new word', - name: 'add_new_word', - desc: '', - args: [], - ); - } - - /// `The text entered is not valid.` - String get incorrect_seed { - return Intl.message( - 'The text entered is not valid.', - name: 'incorrect_seed', - desc: '', - args: [], - ); - } - - /// `Scan your fingerprint to authenticate` - String get biometric_auth_reason { - return Intl.message( - 'Scan your fingerprint to authenticate', - name: 'biometric_auth_reason', - desc: '', - args: [], - ); - } - - /// `Version {currentVersion}` - String version(Object currentVersion) { - return Intl.message( - 'Version $currentVersion', - name: 'version', - desc: '', - args: [currentVersion], - ); - } - - /// `OXEN Recipient Detected` - String get openalias_alert_title { - return Intl.message( - 'OXEN Recipient Detected', - name: 'openalias_alert_title', - desc: '', - args: [], - ); - } - - /// `You will be sending funds to\n{recipient_name}` - String openalias_alert_content(Object recipient_name) { - return Intl.message( - 'You will be sending funds to\n$recipient_name', - name: 'openalias_alert_content', - desc: '', - args: [recipient_name], - ); - } - - /// `Dangerzone` - String get dangerzone { - return Intl.message( - 'Dangerzone', - name: 'dangerzone', - desc: '', - args: [], - ); - } - - /// `Yes, I'm sure!` - String get yes_im_sure { - return Intl.message( - 'Yes, I\'m sure!', - name: 'yes_im_sure', - desc: '', - args: [], - ); - } - - /// `NEVER give your Oxen wallet {item} to ANYONE!` - String never_give_your(Object item) { - return Intl.message( - 'NEVER give your Oxen wallet $item to ANYONE!', - name: 'never_give_your', - desc: '', - args: [item], - ); - } - - /// `NEVER input your Oxen wallet {item} into any software or website other than the OFFICIAL Oxen wallets downloaded directly from the {app_store}, the Oxen website, or the Oxen GitHub.\nAre you sure you want to access your wallet {item}?` - String dangerzone_warning(Object item, Object app_store) { - return Intl.message( - 'NEVER input your Oxen wallet $item into any software or website other than the OFFICIAL Oxen wallets downloaded directly from the $app_store, the Oxen website, or the Oxen GitHub.\nAre you sure you want to access your wallet $item?', - name: 'dangerzone_warning', - desc: '', - args: [item, app_store], - ); - } - - /// `Are you sure you want to delete this wallet?` - String get remove_wallet_confirmation { - return Intl.message( - 'Are you sure you want to delete this wallet?', - name: 'remove_wallet_confirmation', - desc: '', - args: [], - ); - } - - /// `Are you sure you want to delete this wallet? If you have not saved your seed phrase then any funds sent to this wallet will be lost forever!` - String get dangerzone_remove_wallet_warning { - return Intl.message( - 'If you have not saved your seed phrase then any funds sent to this wallet will be lost forever!', - name: 'dangerzone_remove_wallet_warning', - desc: '', - args: [], - ); - } - - /// `Keys` - String get keys_title { - return Intl.message( - 'Keys', - name: 'keys_title', - desc: '', - args: [], - ); - } -} - -class AppLocalizationDelegate extends LocalizationsDelegate { - const AppLocalizationDelegate(); - - List get supportedLocales { - return const [ - Locale.fromSubtags(languageCode: 'en'), - Locale.fromSubtags(languageCode: 'de'), - Locale.fromSubtags(languageCode: 'fr'), - ]; - } - - @override - bool isSupported(Locale locale) => _isSupported(locale); - @override - Future load(Locale locale) => S.load(locale); - @override - bool shouldReload(AppLocalizationDelegate old) => false; - - bool _isSupported(Locale locale) { - if (locale != null) { - for (var supportedLocale in supportedLocales) { - if (supportedLocale.languageCode == locale.languageCode) { - return true; - } - } - } - return false; - } -} \ No newline at end of file diff --git a/lib/l10n.dart b/lib/l10n.dart new file mode 100644 index 00000000..7aab1bf0 --- /dev/null +++ b/lib/l10n.dart @@ -0,0 +1,8 @@ +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; +import 'package:flutter/material.dart'; + +export 'package:flutter_gen/gen_l10n/app_localizations.dart' show AppLocalizations; + +AppLocalizations tr(BuildContext ctx) { + return AppLocalizations.of(ctx) ?? lookupAppLocalizations(Locale('en', '')); +} diff --git a/lib/l10n/intl_de.arb b/lib/l10n/app_de.arb similarity index 91% rename from lib/l10n/intl_de.arb rename to lib/l10n/app_de.arb index f16df0fb..7974a7df 100644 --- a/lib/l10n/intl_de.arb +++ b/lib/l10n/app_de.arb @@ -20,6 +20,12 @@ "contact_name" : "Name des Ansprechpartners", "reset" : "Zurücksetzen", "save" : "Speichern", + "remove_contact" : "Kontakt entfernen", + "remove_contact_confirm" : "Bist du sicher dass du den ausgewählten Kontakt entfernen möchtest?", + + + "remove_wallet_confirmation": "Bist du sicher dass du dieses Wallet löschen möchtest?", + "dangerzone_remove_wallet_warning": "Wenn du deine Seed-Phrase nicht gespeichert hast, wird alles Kapital dass zu diesem Wallet gesendet wurde für immer verloren sein.", "authenticated" : "Authentifiziert", @@ -28,7 +34,7 @@ "wallet_menu" : "Wallet-Menü", - "Blocks_remaining" : "{status} verbleibende Blöcke", + "blocks_remaining" : "{status} verbleibende Blöcke", "please_try_to_connect_to_another_node" : "Bitte versuchen Sie, eine Verbindung zu einem anderen Knoten herzustellen", "oxen_hidden" : "OXEN versteckt", "oxen_available_balance" : "OXEN verfügbares Guthaben", @@ -44,6 +50,7 @@ "yesterday" : "Gestern", "received" : "Empfangen", "sent" : "Geschickt", + "stake" : "Stake", "pending" : " (steht aus)", "rescan" : "Erneut scannen", "reconnect" : "Erneut verbinden", @@ -67,7 +74,8 @@ "status" : "Status: ", "confirm" : "Bestätigen", "confirm_sending" : "Bestätigen Sie das Senden", - "commit_transaction_amount_fee" : "Transaktion festschreiben\nMenge: {amount}\nGebühr: {fee}", + "confirm_stake" : "Bestätigen Sie der Stake", + "confirm_transaction_amount_fee" : "Menge: {amount} OXEN\nGebühr: {fee} OXEN", "sending" : "Senden", "transaction_sent" : "Transaktion gesendet!", "send_oxen" : "OXEN Senden", @@ -101,8 +109,7 @@ "delete" : "Löschen", - "use" : "Wechseln zu ", - "digit_pin" : "-stelliger PIN", + "use_n_digit_pin" : "Wechseln zu {n}-stelliger PIN", "share_address" : "Adresse teilen ", @@ -118,7 +125,7 @@ "restore_description_from_backup" : "Sie können die gesamte Oxen Wallet-App aus ihrer Sicherungsdatei wiederherstellen.", "restore_seed_keys_restore" : "Seed / Schlüssel wiederherstellen", "restore_title_from_seed" : "Aus Seed wiederherstellen", - "restore_description_from_seed" : "Stellen Sie Ihr Wallet aus den 25 Wörtern wieder her oder 13-Wort-Kombinationscode", + "restore_description_from_seed" : "Stellen Sie Ihr Wallet aus dem 25-Wörter-Kombinationscode", "restore_title_from_keys" : "Wiederherstellen von Schlüsseln", "restore_description_from_keys" : "Stellen Sie Ihr Wallet von generiert wieder her Tastenanschläge, die von Ihren privaten Schlüsseln gespeichert wurden", "restore_wallet_name" : "Walletname", @@ -251,25 +258,20 @@ "router_no_route" : "Keine Route definiert für {name}", - "error_text_account_name" : "Der Kontoname darf nur Buchstaben und Zahlen enthalten\nund muss zwischen 1 und 15 Zeichen lang sein", - "error_text_contact_name" : "Im Kontaktname könne die Symbole ` , ' \" nicht enthalten sein\nund muss zwischen 1 und 32 Zeichen lang sein", + "error_text_empty": "Kann nicht leer sein", "error_text_address" : "Die Walletadresse muss dem Typ der Kryptowährung\nentsprechen", - "error_text_node_address" : "Bitte geben Sie eine iPv4-Adresse ein", + "error_text_node_address" : "Bitte geben Sie eine IP-Adresse ein", "error_text_node_port" : "Der Knotenport kann nur Nummern zwischen 0 und 65535 enthalten", "error_text_payment_id" : "Die Zahlungs-ID kann nur 16 bis 64 hexadezimale Zeichen enthalten", - "error_text_oxen" : "Der OXEN-Wert kann das verfügbare Guthaben nicht überschreiten.\nDie Anzahl der Nachkommastellen muss kleiner oder gleich 12 sein", + "error_text_oxen" : "Der OXEN-Wert kann das verfügbare Guthaben nicht überschreiten.\nDie Anzahl der Nachkommastellen muss kleiner oder gleich 9 sein", "error_text_fiat" : "Der Wert des Betrags darf den verfügbaren Kontostand nicht überschreiten.\nDie Anzahl der Nachkommastellen muss kleiner oder gleich 2 sein", - "error_text_subaddress_name" : "Im Namen der Unteradresse könne die Symbole ` , ' \" nicht enthalten sein\nund muss zwischen 1 und 20 Zeichen lang sein", "error_text_amount" : "Betrag kann nur Zahlen enthalten", - "error_text_wallet_name" : "Der Walletname darf nur Buchstaben und Zahlen enthalten\nund muss zwischen 1 und 15 Zeichen lang sein", "error_text_keys" : "Walletschlüssel können nur 64 hexadezimale Zeichen enthalten", - "error_text_crypto_currency" : "Die Anzahl der Nachkommastellen\nmuss kleiner oder gleich 12 sein.", + "error_text_crypto_currency" : "Die Anzahl der Nachkommastellen\nmuss kleiner oder gleich 9 sein.", "error_text_service_node": "Service Node Schlüssel können nur 64 hexadezimale Zeichen enthalten", - "auth_store_ban_timeout" : "Auszeit verbieten", - "auth_store_banned_for" : "Gebannt für ", - "auth_store_banned_minutes" : " Protokoll", + "auth_store_banned_for" : "{mins} Minuten gebannt.", "auth_store_incorrect_password" : "Falsches PIN", "wallet_restoration_store_incorrect_seed_length" : "Falsche Seed-länge", @@ -298,6 +300,7 @@ "restore_from_seed_placeholder" : "Bitte geben Sie hier Ihren Code ein", "add_new_word" : "Neues Wort hinzufügen", "incorrect_seed" : "Der eingegebene Text ist ungültig.", + "invalid_seed_words": "\nUngültige Wörter: {words}.", "biometric_auth_reason" : "Scannen Sie Ihren Fingerabdruck zur Authentifizierung", "version" : "Ausführung {currentVersion}", diff --git a/lib/l10n/intl_en.arb b/lib/l10n/app_en.arb similarity index 79% rename from lib/l10n/intl_en.arb rename to lib/l10n/app_en.arb index 72a08498..f38d4a2d 100644 --- a/lib/l10n/intl_en.arb +++ b/lib/l10n/app_en.arb @@ -20,15 +20,19 @@ "contact_name" : "Contact Name", "reset" : "Reset", "save" : "Save", + "remove_contact" : "Remove Contact", + "remove_contact_confirm" : "Are you sure that you want to remove the selected contact?", "authenticated" : "Authenticated", "authentication" : "Authentication", "failed_authentication" : "Failed authentication. {state_error}", + "@failed_authentication" : { "placeholders": { "state_error": {} } }, "wallet_menu" : "Menu", - "Blocks_remaining" : "{status} Blocks Remaining", + "blocks_remaining" : "{status} Blocks Remaining", + "@blocks_remaining" : { "placeholders": { "status": {} } }, "please_try_to_connect_to_another_node" : "Please try to connect to another node", "oxen_hidden" : "OXEN Hidden", "oxen_available_balance" : "OXEN Available Balance", @@ -44,6 +48,7 @@ "yesterday" : "Yesterday", "received" : "Received", "sent" : "Sent", + "stake" : "Stake", "pending" : " (pending)", "rescan" : "Rescan", "reconnect" : "Reconnect", @@ -67,7 +72,9 @@ "status" : "Status: ", "confirm" : "Confirm", "confirm_sending" : "Confirm sending", - "commit_transaction_amount_fee" : "Commit transaction\nAmount: {amount}\nFee: {fee}", + "confirm_stake" : "Confirm stake", + "confirm_transaction_amount_fee" : "Amount: {amount}\nFee: {fee}", + "@confirm_transaction_amount_fee" : { "placeholders": { "amount": {}, "fee": {} } }, "sending" : "Sending", "transaction_sent" : "Transaction sent!", "send_oxen" : "Send OXEN", @@ -85,6 +92,10 @@ "continue_text" : "Continue", + "remove_wallet_confirmation": "Are you sure you want to delete this wallet?", + "dangerzone_remove_wallet_warning": "If you have not saved your seed phrase then any funds sent to this wallet will be lost forever!", + + "node_new" : "New Node", "node_address" : "Node Address", "node_port" : "Node port", @@ -94,6 +105,7 @@ "node_reset_settings_title" : "Reset settings", "nodes_list_reset_to_default_message" : "Are you sure that you want to reset settings to default?", "change_current_node" : "Are you sure to change current node to {node}?", + "@change_current_node" : { "placeholders": { "node": {} }}, "change" : "Change", "remove_node" : "Remove node", "remove_node_message" : "Are you sure that you want to remove selected node?", @@ -101,8 +113,8 @@ "delete" : "Delete", - "use" : "Switch to ", - "digit_pin" : "-digit PIN", + "use_n_digit_pin" : "Switch to {n}-digit PIN", + "@use_n_digit_pin" : { "placeholders": { "n": {} }}, "share_address" : "Share address", @@ -118,7 +130,7 @@ "restore_description_from_backup" : "You can restore the whole Oxen Wallet app from your back-up file", "restore_seed_keys_restore" : "Seed/Keys Restore", "restore_title_from_seed" : "Restore from seed", - "restore_description_from_seed" : "Restore your wallet from either the 25 word or 13 word combination code", + "restore_description_from_seed" : "Restore your wallet from the 25 word combination code", "restore_title_from_keys" : "Restore from keys", "restore_description_from_keys" : "Restore your wallet from generated keystrokes saved from your private keys", "restore_wallet_name" : "Wallet name", @@ -155,6 +167,7 @@ "send_error_currency" : "Currency can only contain numbers", "send_estimated_fee" : "Estimated fee:", "send_priority" : "Currently the fee is set at {transactionPriority} priority.\nTransaction priority can be adjusted in the settings", + "@send_priority" : { "placeholders": { "transactionPriority": {} }}, "send_creating_transaction" : "Creating transaction", @@ -168,6 +181,7 @@ "stake_oxen": "Stake Oxen", "title_confirm_unlock_stake": "Unlock Stake", "body_confirm_unlock_stake": "Do you really want to unlock your stake from {serviceNodeKey}?", + "@body_confirm_unlock_stake" : { "placeholders": { "serviceNodeKey": {} }}, "unlock_stake_requested": "Stake unlock requested", "unable_unlock_stake": "Unable to unlock stake", @@ -202,7 +216,7 @@ "setup_pin" : "Setup PIN", - "enter_your_pin_again" : "Enter your pin again", + "enter_your_pin_again" : "Enter your PIN again", "setup_successful" : "Your PIN has been set up successfully!", @@ -212,6 +226,7 @@ "spend_key_private" : "Spend key (private)", "spend_key_public" : "Spend key (public)", "copied_key_to_clipboard" : "Copied {key} to Clipboard", + "@copied_key_to_clipboard" : { "placeholders": { "key": {} }}, "new_subaddress_title" : "New subaddress", @@ -228,6 +243,7 @@ "transaction_details_height" : "Height", "transaction_details_amount" : "Amount", "transaction_details_copied" : "{title} copied to Clipboard", + "@transaction_details_copied" : { "placeholders": { "title": {} }}, "transaction_details_recipient_address" : "Recipient address", @@ -236,9 +252,13 @@ "wallet_list_restore_wallet" : "Restore Wallet", "wallet_list_load_wallet" : "Load wallet", "wallet_list_loading_wallet" : "Loading {wallet_name} wallet", + "@wallet_list_loading_wallet" : { "placeholders": { "wallet_name": {} }}, "wallet_list_failed_to_load" : "Failed to load {wallet_name} wallet. {error}", + "@wallet_list_failed_to_load" : { "placeholders": { "wallet_name": {}, "error": {} }}, "wallet_list_removing_wallet" : "Removing {wallet_name} wallet", - "wallet_list_failed_to_remove" : "Failed to remove {wallet_name} wallet. {error}", + "@wallet_list_removing_wallet" : { "placeholders": { "wallet_name": {} }}, + "wallet_list_failed_to_remove" : "Failed to remove {wallet_name} wallet: {error}", + "@wallet_list_failed_to_remove" : { "placeholders": { "wallet_name": {}, "error": {} }}, "widgets_address" : "Address", @@ -249,27 +269,24 @@ "router_no_route" : "No route defined for {name}", + "@router_no_route" : { "placeholders": { "name": {} }}, - "error_text_account_name" : "Account name can only contain letters, numbers\nand must be between 1 and 15 characters long", - "error_text_contact_name" : "Contact name can't contain ` , ' \" symbols\nand must be between 1 and 32 characters long", - "error_text_address" : "Wallet address must correspond to the type\nof cryptocurrency", - "error_text_node_address" : "Please enter a iPv4 address", - "error_text_node_port" : "Node port can only contain numbers between 0 and 65535", + "error_text_empty": "Cannot be empty", + "error_text_address" : "Invalid OXEN wallet address!", + "error_text_node_address" : "Please enter a valid hostname or IP address", + "error_text_node_port" : "Node port can only contain numbers between 1 and 65535", "error_text_payment_id" : "Payment ID can only contain from 16 to 64 chars in hex", - "error_text_oxen" : "OXEN value can't exceed available balance.\nThe number of fraction digits must be less or equal to 12", + "error_text_oxen" : "OXEN value can't exceed available balance.\nThe number of fraction digits must be less or equal to 9", "error_text_fiat" : "Value of amount can't exceed available balance.\nThe number of fraction digits must be less or equal to 2", - "error_text_subaddress_name" : "Subaddress name can't contain ` , ' \" symbols\nand must be between 1 and 20 characters long", "error_text_amount" : "Amount can only contain numbers", - "error_text_wallet_name" : "Wallet name can only contain letters, numbers\nand must be between 1 and 15 characters long", "error_text_keys" : "Wallet keys can only contain 64 chars in hex", - "error_text_crypto_currency" : "The number of fraction digits\nmust be less or equal to 12", + "error_text_crypto_currency" : "The number of fraction digits\nmust be less or equal to 9", "error_text_service_node" : "A Service Node key can only contain 64 chars in hex", - "auth_store_ban_timeout" : "ban_timeout", - "auth_store_banned_for" : "Banned for ", - "auth_store_banned_minutes" : " minutes", + "auth_store_banned_for" : "Banned for {mins} minutes", + "@auth_store_banned_for": { "placeholders": {"mins": {}}}, "auth_store_incorrect_password" : "Wrong PIN", "wallet_restoration_store_incorrect_seed_length" : "Incorrect seed length", @@ -294,21 +311,28 @@ "change_language" : "Change language", "change_language_to" : "Change language to {language}?", + "@change_language_to" : { "placeholders": { "language": {} }}, "paste" : "Paste", "restore_from_seed_placeholder" : "Please enter or paste your seed here", "add_new_word" : "Add new word", "incorrect_seed" : "The text entered is not valid.", + "invalid_seed_words" : "\nInvalid seed words: {words}.", + "@invalid_seed_words" : { "placeholders": {"words": {}}}, "biometric_auth_reason" : "Scan your fingerprint to authenticate", "version" : "Version {currentVersion}", + "@version" : { "placeholders": { "currentVersion": {} }}, "openalias_alert_title" : "OXEN Recipient Detected", "openalias_alert_content" : "You will be sending funds to\n{recipient_name}", + "@openalias_alert_content" : { "placeholders": { "recipient_name": {} }}, "dangerzone": "Dangerzone", "yes_im_sure": "Yes, I'm sure!", "never_give_your": "NEVER give your Oxen wallet {item} to ANYONE!", + "@never_give_your" : { "placeholders": { "item": {} }}, "dangerzone_warning": "NEVER input your Oxen wallet {item} into any software or website other than the OFFICIAL Oxen wallets downloaded directly from the {app_store}, the Oxen website, or the Oxen GitHub.\nAre you sure you want to access your wallet {item}?", + "@dangerzone_warning" : { "placeholders": { "item": {}, "app_store": {} }}, "keys_title": "Keys" } diff --git a/lib/l10n/intl_fr.arb b/lib/l10n/app_fr.arb similarity index 90% rename from lib/l10n/intl_fr.arb rename to lib/l10n/app_fr.arb index 907b2db3..db063f6c 100644 --- a/lib/l10n/intl_fr.arb +++ b/lib/l10n/app_fr.arb @@ -20,6 +20,8 @@ "contact_name" : "Nom du contact", "reset" : "Réinitialiser", "save" : "Sauvegarder", + "remove_contact" : "Supprimer le Contact", + "remove_contact_confirm" : "Êtes vous sûr de vouloir supprimer le contact sélectionné?", "authenticated" : "Authentifié", @@ -28,7 +30,7 @@ "wallet_menu" : "Menu du portefeuille", - "Blocks_remaining" : "{status} blocs restants", + "blocks_remaining" : "{status} blocs restants", "please_try_to_connect_to_another_node" : "veuillez essayer de vous connecter à un autre node", "oxen_hidden" : "OXEN caché", "oxen_available_balance" : "OXEN solde disponible", @@ -44,6 +46,7 @@ "yesterday" : "hier", "received" : "a reçu", "sent" : "expédié", + "stake" : "Stake", "pending" : " (en attente)", "rescan" : "réanalyser", "reconnect" : "se reconnecter", @@ -66,8 +69,9 @@ "amount" : "Montant: ", "status" : "Statut: ", "confirm" : "confirmer", - "confirm_sending" : "confirmer l'envoi", - "commit_transaction_amount_fee" : "Valider la transaction\nMontant: {amount}\nFee: {fee}", + "confirm_sending" : "Confirmer l'envoi", + "confirm_stake" : "Confirmer le Stake", + "confirm_transaction_amount_fee" : "Montant: {amount} OXEN\nFee: {fee} OXEN", "sending" : "Envoyer", "transaction_sent" : "Transaction envoyé!", "send_oxen" : "Envoyer OXEN", @@ -85,6 +89,10 @@ "continue_text" : "Continuez", + "remove_wallet_confirmation": "Êtes vous sûr de vouloir supprimer ce wallet?", + "dangerzone_remove_wallet_warning": "Si vous n'avez pas sauvegardé votre phrase de récupération tous les fonds envoyés sur ce wallet seront perdus pour toujours!", + + "node_new" : "Nouveau Node", "node_address" : "L'adresse du Node", "node_port" : "Port du Node", @@ -101,8 +109,7 @@ "delete" : "effacer", - "use" : "Basculer vers ", - "digit_pin" : "-chiffre PIN", + "use_n_digit_pin" : "Basculer vers {n}-chiffre PIN", "share_address" : "Partager l'adresse ", @@ -118,7 +125,7 @@ "restore_description_from_backup" : "Vous pouvez restaurer l'intégralité de l'application Oxen Wallet à partir de son fichier de sauvegarde.", "restore_seed_keys_restore" : "Restaurer depuis le Seed ou les clés", "restore_title_from_seed" : "Restaurer à partir du Seed", - "restore_description_from_seed" : "Récupérez votre portefeuille à partir du code de combinaison de 25 ou 13 mots", + "restore_description_from_seed" : "Récupérez votre portefeuille à partir du code de combinaison de 25 mots", "restore_title_from_keys" : "Récupération des clés", "restore_description_from_keys" : "Restaurez votre portefeuille à partir du mnemonic généré à partir de vos clés privées", "restore_wallet_name" : "Nom du portefeuille", @@ -251,25 +258,20 @@ "router_no_route" : "Aucun itinéraire défini pour {name}", - "error_text_account_name" : "Le nom du compte ne peut contenir que des lettres et des chiffres\net doit comporter entre 1 et 15 caractères", - "error_text_contact_name" : "Dans le nom du contact, les symboles ` , ' \" ne doivent pas être inclus\net doit comporter entre 1 et 32 ​​caractères", - "error_text_address" : "L'adresse du portefeuille doit correspondre au type de crypto-monnaie", - "error_text_node_address" : "Veuillez saisir une adresse iPv4", + "error_text_empty": "Ne peux pas être vide", + "error_text_address" : "Adresse de portefeuille OXEN invalide!", + "error_text_node_address" : "Veuillez saisir une adresse IP", "error_text_node_port" : "Le port du Node ne peut contenir que des nombres compris entre 0 et 65535", "error_text_payment_id" : "L'ID de paiement ne peut contenir que 16 à 64 caractères hexadécimaux", - "error_text_oxen" : "La valeur OXEN ne peut pas dépasser le solde disponible.\nLe nombre de décimales doit être inférieur ou égal à 12", + "error_text_oxen" : "La valeur OXEN ne peut pas dépasser le solde disponible.\nLe nombre de décimales doit être inférieur ou égal à 9", "error_text_fiat" : "La valeur du montant ne peut pas dépasser le solde disponible du compte.\nLe nombre de décimales doit être inférieur ou égal à 2", - "error_text_subaddress_name" : "Au nom de la sous-adresse, les symboles ` , ' \" ne pas être inclus\net doit comporter entre 1 et 20 caractères", "error_text_amount" : "Le montant ne peut contenir que des nombres", - "error_text_wallet_name" : "Le nom du portefeuille ne peut contenir que des lettres et des chiffres\net doit comporter entre 1 et 15 caractères", "error_text_keys" : "Les clés de portefeuille ne peuvent contenir que 64 caractères hexadécimaux", - "error_text_crypto_currency" : "Le nombre de décimales\nm doit être inférieur ou égal à 12.", + "error_text_crypto_currency" : "Le nombre de décimales\nm doit être inférieur ou égal à 9.", "error_text_service_node" : "Une clé de nœud de service ne peut contenir que 64 caractères maximum", - "auth_store_ban_timeout" : "Interdire le délai d'expiration", - "auth_store_banned_for" : "Interdit pour ", - "auth_store_banned_minutes" : " Protocole", + "auth_store_banned_for" : "Interdit pendant {mins} minutes", "auth_store_incorrect_password" : "mauvais code PIN", "wallet_restoration_store_incorrect_seed_length" : "mauvaise longueur du Seed", @@ -299,6 +301,7 @@ "restore_from_seed_placeholder" : "Veuillez entrer votre code ici", "add_new_word" : "Ajouter un nouveau mot", "incorrect_seed" : "Le texte saisi n'est pas valide.", + "invalid_seed_words": "\nMots invalide: {words}.", "biometric_auth_reason" : "Scannez votre empreinte digitale pour l'authentification", "version" : "Version {currentVersion}", diff --git a/lib/main.dart b/lib/main.dart index 051a44da..b547f114 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,4 +1,3 @@ -import 'package:flutter_localizations/flutter_localizations.dart'; import 'package:oxen_wallet/src/wallet/oxen/transaction/transaction_priority.dart'; import 'package:path_provider/path_provider.dart'; import 'package:shared_preferences/shared_preferences.dart'; @@ -32,8 +31,7 @@ import 'package:oxen_wallet/src/domain/common/default_settings_migration.dart'; import 'package:oxen_wallet/src/domain/common/fiat_currency.dart'; import 'package:oxen_wallet/src/wallet/wallet_type.dart'; import 'package:oxen_wallet/src/domain/services/wallet_service.dart'; -import 'package:oxen_wallet/generated/l10n.dart'; -import 'package:oxen_wallet/src/domain/common/language.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:oxen_wallet/src/stores/seed_language/seed_language_store.dart'; void main() async { @@ -57,7 +55,7 @@ void main() async { final nodes = await Hive.openBox(Node.boxName); final transactionDescriptions = await Hive.openBox( TransactionDescription.boxName, - encryptionKey: transactionDescriptionsBoxKey); + encryptionCipher: HiveAesCipher(transactionDescriptionsBoxKey)); final walletInfoSource = await Hive.openBox(WalletInfo.boxName); final sharedPreferences = await SharedPreferences.getInstance(); @@ -121,7 +119,7 @@ void main() async { Provider(create: (_) => transactionDescriptions), Provider(create: (_) => seedLanguageStore) ], child: OxenWalletApp())); - } catch (e) { + } catch (e, trace) { runApp(MaterialApp( debugShowCheckedModeBanner: true, home: Scaffold( @@ -129,7 +127,7 @@ void main() async { margin: EdgeInsets.only(top: 50, left: 20, right: 20, bottom: 20), child: Text( - 'Error:\n${e.toString()}', + 'Error:\n${e.toString()}\n${trace.toString()}', style: TextStyle(fontSize: 22), ) ) @@ -139,13 +137,11 @@ void main() async { } Future initialSetup( - {WalletListService walletListService, - SharedPreferences sharedPreferences, - Box nodes, - AuthenticationStore authStore, - int initialMigrationVersion = 1, - WalletType initialWalletType = WalletType.oxen}) async { - await walletListService.changeWalletManger(walletType: initialWalletType); + {required WalletListService walletListService, + required SharedPreferences sharedPreferences, + required Box nodes, + required AuthenticationStore authStore, + required int initialMigrationVersion}) async { await defaultSettingsMigration( version: initialMigrationVersion, sharedPreferences: sharedPreferences, @@ -167,9 +163,7 @@ class OxenWalletApp extends StatelessWidget { return ChangeNotifierProvider( create: (_) => ThemeChanger( settingsStore.isDarkTheme ? Themes.darkTheme : Themes.lightTheme), - child: ChangeNotifierProvider( - create: (_) => Language(settingsStore.languageCode), - child: MaterialAppWithTheme())); + child: MaterialAppWithTheme()); } } @@ -188,7 +182,6 @@ class MaterialAppWithTheme extends StatelessWidget { final theme = Provider.of(context); final statusBarColor = settingsStore.isDarkTheme ? Colors.black : Colors.white; - final currentLanguage = Provider.of(context); final contacts = Provider.of>(context); final nodes = Provider.of>(context); final transactionDescriptions = @@ -200,14 +193,8 @@ class MaterialAppWithTheme extends StatelessWidget { return MaterialApp( debugShowCheckedModeBanner: false, theme: theme.getTheme(), - localizationsDelegates: [ - S.delegate, - GlobalCupertinoLocalizations.delegate, - GlobalMaterialLocalizations.delegate, - GlobalWidgetsLocalizations.delegate, - ], - supportedLocales: S.delegate.supportedLocales, - locale: Locale(currentLanguage.getCurrentLanguage()), + localizationsDelegates: AppLocalizations.localizationsDelegates, + supportedLocales: AppLocalizations.supportedLocales, onGenerateRoute: (settings) => oxenroute.Router.generateRoute( sharedPreferences: sharedPreferences, walletListService: walletListService, diff --git a/lib/palette.dart b/lib/palette.dart index de71f3eb..a1652624 100644 --- a/lib/palette.dart +++ b/lib/palette.dart @@ -83,6 +83,7 @@ class OxenPalette { static const Color black = Color.fromRGBO(0, 0, 0, 1.0); // #000000 // Opacity + static const Color navyWithOpacity = Color.fromRGBO(31, 28, 71, 0.8); static const Color tealWithOpacity = Color.fromRGBO(18, 199, 186, 0.2); static const Color lightRedWithOpacity = Color.fromRGBO(255, 122, 135, 0.5); static const Color limeWithOpacity = Color.fromRGBO(195, 245, 58, 0.5); diff --git a/lib/router.dart b/lib/router.dart index a5ba9114..3b315284 100644 --- a/lib/router.dart +++ b/lib/router.dart @@ -1,9 +1,8 @@ -import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_secure_storage/flutter_secure_storage.dart'; import 'package:hive/hive.dart'; -import 'package:oxen_wallet/generated/l10n.dart'; import 'package:oxen_wallet/routes.dart'; +import 'package:oxen_wallet/l10n.dart'; // MARK: Import domains import 'package:oxen_wallet/src/domain/common/contact.dart'; @@ -40,7 +39,6 @@ import 'package:oxen_wallet/src/screens/restore/restore_wallet_options_page.dart import 'package:oxen_wallet/src/screens/seed/create_seed_page.dart'; import 'package:oxen_wallet/src/screens/seed_language/seed_language_page.dart'; import 'package:oxen_wallet/src/screens/send/send_page.dart'; -import 'package:oxen_wallet/src/screens/settings/change_language.dart'; import 'package:oxen_wallet/src/screens/settings/settings.dart'; import 'package:oxen_wallet/src/screens/setup_pin_code/setup_pin_code.dart'; import 'package:oxen_wallet/src/screens/show_keys/show_keys_page.dart'; @@ -72,7 +70,7 @@ import 'package:oxen_wallet/src/stores/wallet/wallet_store.dart'; import 'package:oxen_wallet/src/stores/wallet_creation/wallet_creation_store.dart'; import 'package:oxen_wallet/src/stores/wallet_list/wallet_list_store.dart'; import 'package:oxen_wallet/src/stores/wallet_restoration/wallet_restoration_store.dart'; -import 'package:oxen_wallet/src/wallet/mnemotic_item.dart'; +import 'package:oxen_wallet/src/wallet/mnemonic_item.dart'; import 'package:oxen_wallet/src/wallet/oxen/account.dart'; import 'package:oxen_wallet/src/wallet/oxen/subaddress.dart'; import 'package:oxen_wallet/src/wallet/oxen/transaction/transaction_description.dart'; @@ -82,19 +80,19 @@ import 'package:shared_preferences/shared_preferences.dart'; class Router { static Route generateRoute( - {SharedPreferences sharedPreferences, - WalletListService walletListService, - WalletService walletService, - UserService userService, - RouteSettings settings, - PriceStore priceStore, - WalletStore walletStore, - SyncStore syncStore, - BalanceStore balanceStore, - SettingsStore settingsStore, - Box contacts, - Box nodes, - Box transactionDescriptions}) { + {required SharedPreferences sharedPreferences, + required WalletListService walletListService, + required WalletService walletService, + required UserService userService, + required RouteSettings settings, + required PriceStore priceStore, + required WalletStore walletStore, + required SyncStore syncStore, + required BalanceStore balanceStore, + required SettingsStore settingsStore, + required Box contacts, + required Box nodes, + required Box transactionDescriptions}) { switch (settings.name) { case Routes.welcome: return MaterialPageRoute(builder: (_) => WelcomePage()); @@ -125,7 +123,7 @@ class Router { sharedPreferences: sharedPreferences))); case Routes.setupPin: - Function(BuildContext, String) callback; + Function(BuildContext, String)? callback; if (settings.arguments is Function(BuildContext, String)) { callback = settings.arguments as Function(BuildContext, String); @@ -164,7 +162,7 @@ class Router { builder: (_) => createSeedPage( settingsStore: settingsStore, walletService: walletService, - callback: settings.arguments as void Function())); + callback: settings.arguments as void Function()?)); case Routes.restoreWalletFromSeed: return MaterialPageRoute( @@ -218,6 +216,7 @@ class Router { create: (_) => SendStore( walletService: walletService, priceStore: priceStore, + settingsStore: settingsStore, transactionDescriptions: transactionDescriptions)), ], child: SendPage())); @@ -324,7 +323,7 @@ class Router { return MaterialPageRoute(builder: (context) { return Provider( create: (_) => AccountListStore(walletService: walletService), - child: AccountPage(account: settings.arguments as Account)); + child: AccountPage(account: settings.arguments as Account?)); }); case Routes.addressBook: @@ -357,12 +356,10 @@ class Router { return MaterialPageRoute(builder: (context) { return MultiProvider( providers: [ - Provider( - create: (_) => - AccountListStore(walletService: walletService)), + Provider(create: (_) => AccountListStore(walletService: walletService)), Provider(create: (_) => AddressBookStore(contacts: contacts)) ], - child: ContactPage(contact: settings.arguments as Contact), + child: ContactPage(contact: settings.arguments as Contact?), ); }); @@ -413,7 +410,7 @@ class Router { authStore: authStore, sharedPreferences: sharedPreferences, walletListService: walletListService, - seed: settings.arguments as List), + seed: settings.arguments as List), child: RestoreWalletFromSeedDetailsPage())); case Routes.settings: @@ -434,9 +431,6 @@ class Router { case Routes.changelog: return MaterialPageRoute(builder: (_) => ChangelogPage()); - case Routes.changeLanguage: - return MaterialPageRoute(builder: (_) => ChangeLanguage()); - case Routes.profile: return MaterialPageRoute(builder: (_) => ProfilePage()); @@ -459,15 +453,16 @@ class Router { Provider( create: (_) => SendStore( walletService: walletService, + settingsStore: settingsStore, priceStore: priceStore, transactionDescriptions: transactionDescriptions)), ], child: NewStakePage())); default: return MaterialPageRoute( - builder: (_) => Scaffold( + builder: (context) => Scaffold( body: Center( - child: Text(S.current.router_no_route(settings.name))), + child: Text(tr(context).router_no_route(settings.name ?? 'null'))), )); } } diff --git a/lib/src/domain/common/balance_display_mode.dart b/lib/src/domain/common/balance_display_mode.dart index 50c85db1..cd78075f 100644 --- a/lib/src/domain/common/balance_display_mode.dart +++ b/lib/src/domain/common/balance_display_mode.dart @@ -1,46 +1,41 @@ -import 'package:flutter/foundation.dart'; -import 'package:oxen_wallet/generated/l10n.dart'; +import 'package:oxen_wallet/l10n.dart'; import 'package:oxen_wallet/src/domain/common/enumerable_item.dart'; class BalanceDisplayMode extends EnumerableItem with Serializable { - const BalanceDisplayMode({@required String title, @required int raw}) - : super(title: title, raw: raw); + const BalanceDisplayMode({required int raw}) + : super(raw: raw); static const all = [ BalanceDisplayMode.fullBalance, BalanceDisplayMode.availableBalance, BalanceDisplayMode.hiddenBalance ]; - static const fullBalance = BalanceDisplayMode(raw: 0, title: 'Full Balance'); - static const availableBalance = - BalanceDisplayMode(raw: 1, title: 'Available Balance'); - static const hiddenBalance = - BalanceDisplayMode(raw: 2, title: 'Hidden Balance'); + static const fullBalance = BalanceDisplayMode(raw: 0); + static const availableBalance = BalanceDisplayMode(raw: 1); + static const hiddenBalance = BalanceDisplayMode(raw: 2); - static BalanceDisplayMode deserialize({int raw}) { + static BalanceDisplayMode deserialize({required int? raw}) { switch (raw) { case 0: return fullBalance; - case 1: - return availableBalance; case 2: return hiddenBalance; + case 1: default: - return null; + return availableBalance; } } @override - String toString() { + String getTitle(AppLocalizations l10n) { switch (this) { case BalanceDisplayMode.fullBalance: - return S.current.oxen_full_balance; - case BalanceDisplayMode.availableBalance: - return S.current.oxen_available_balance; + return l10n.oxen_full_balance; case BalanceDisplayMode.hiddenBalance: - return S.current.oxen_hidden; + return l10n.oxen_hidden; + case BalanceDisplayMode.availableBalance: default: - return ''; + return l10n.oxen_available_balance; } } } diff --git a/lib/src/domain/common/biometric_auth.dart b/lib/src/domain/common/biometric_auth.dart index 01d04c62..b9a351ca 100644 --- a/lib/src/domain/common/biometric_auth.dart +++ b/lib/src/domain/common/biometric_auth.dart @@ -1,14 +1,15 @@ import 'package:flutter/services.dart'; import 'package:local_auth/local_auth.dart'; -import 'package:oxen_wallet/generated/l10n.dart'; +import 'package:oxen_wallet/l10n.dart'; class BiometricAuth { - Future isAuthenticated() async { + Future isAuthenticated(AppLocalizations t) async { final _localAuth = LocalAuthentication(); try { - return await _localAuth.authenticateWithBiometrics( - localizedReason: S.current.biometric_auth_reason, + return await _localAuth.authenticate( + biometricOnly: true, + localizedReason: t.biometric_auth_reason, useErrorDialogs: true, stickyAuth: false); } on PlatformException catch (e) { diff --git a/lib/src/domain/common/calculate_fiat_amount.dart b/lib/src/domain/common/calculate_fiat_amount.dart index f35844a0..1257d3ff 100644 --- a/lib/src/domain/common/calculate_fiat_amount.dart +++ b/lib/src/domain/common/calculate_fiat_amount.dart @@ -1,9 +1,8 @@ import 'package:oxen_wallet/src/wallet/oxen/oxen_amount_format.dart'; -String calculateFiatAmount({double price, int cryptoAmount}) { - if (price == null || cryptoAmount == null) { +String calculateFiatAmount({required double price, required int cryptoAmount}) { + if (price.isNaN || price <= 0.0 || cryptoAmount <= 0) return '0.00'; - } final result = price * oxenAmountToDouble(cryptoAmount); if (result == 0.0) { @@ -11,4 +10,4 @@ String calculateFiatAmount({double price, int cryptoAmount}) { } return result > 0.01 ? result.toStringAsFixed(2) : '< 0.01'; -} \ No newline at end of file +} diff --git a/lib/src/domain/common/calculate_fiat_amount_raw.dart b/lib/src/domain/common/calculate_fiat_amount_raw.dart index 30db2af6..1ca93f8b 100644 --- a/lib/src/domain/common/calculate_fiat_amount_raw.dart +++ b/lib/src/domain/common/calculate_fiat_amount_raw.dart @@ -1,13 +1,9 @@ -String calculateFiatAmountRaw({double price, double cryptoAmount}) { - if (price == null) { - return '0.00'; - } - - final result = price * cryptoAmount; +String calculateFiatAmountRaw({required double? price, required double cryptoAmount}) { + final result = (price ?? 0.0) * cryptoAmount; if (result == 0.0) { return '0.00'; } return result > 0.01 ? result.toStringAsFixed(2) : '< 0.01'; -} \ No newline at end of file +} diff --git a/lib/src/domain/common/contact.dart b/lib/src/domain/common/contact.dart index 8fdaf9fa..55dca4ca 100644 --- a/lib/src/domain/common/contact.dart +++ b/lib/src/domain/common/contact.dart @@ -1,13 +1,10 @@ -import 'package:flutter/foundation.dart'; import 'package:hive/hive.dart'; -import 'package:oxen_wallet/src/domain/common/crypto_currency.dart'; part 'contact.g.dart'; @HiveType(typeId: 0) class Contact extends HiveObject { - Contact({@required this.name, @required this.address, CryptoCurrency type}) - : raw = type?.raw; + Contact({required this.name, required this.address, this.raw = 0}); static const boxName = 'Contacts'; @@ -17,11 +14,7 @@ class Contact extends HiveObject { @HiveField(1) String address; + // unused @HiveField(2) int raw; - - CryptoCurrency get type => CryptoCurrency.deserialize(raw: raw); - - void updateCryptoCurrency({@required CryptoCurrency currency}) => - raw = currency.raw; } diff --git a/lib/src/domain/common/crypto_currency.dart b/lib/src/domain/common/crypto_currency.dart deleted file mode 100644 index 48d99df4..00000000 --- a/lib/src/domain/common/crypto_currency.dart +++ /dev/null @@ -1,122 +0,0 @@ -import 'package:oxen_wallet/src/domain/common/enumerable_item.dart'; -import 'package:hive/hive.dart'; - -part 'crypto_currency.g.dart'; - -@HiveType(typeId: 0) -class CryptoCurrency extends EnumerableItem with Serializable { - const CryptoCurrency({final String title, final int raw}) - : super(title: title, raw: raw); - - static const all = [ - CryptoCurrency.oxen, - CryptoCurrency.ada, - CryptoCurrency.bch, - CryptoCurrency.bnb, - CryptoCurrency.btc, - CryptoCurrency.dash, - CryptoCurrency.eos, - CryptoCurrency.eth, - CryptoCurrency.ltc, - CryptoCurrency.nano, - CryptoCurrency.trx, - CryptoCurrency.usdt, - CryptoCurrency.xlm, - CryptoCurrency.xrp, - CryptoCurrency.xmr - ]; - - static const oxen = CryptoCurrency(title: 'OXEN', raw: 0); - static const ada = CryptoCurrency(title: 'ADA', raw: 1); - static const bch = CryptoCurrency(title: 'BCH', raw: 2); - static const bnb = CryptoCurrency(title: 'BNB', raw: 3); - static const btc = CryptoCurrency(title: 'BTC', raw: 4); - static const dash = CryptoCurrency(title: 'DASH', raw: 5); - static const eos = CryptoCurrency(title: 'EOS', raw: 6); - static const eth = CryptoCurrency(title: 'ETH', raw: 7); - static const ltc = CryptoCurrency(title: 'LTC', raw: 8); - static const nano = CryptoCurrency(title: 'NANO', raw: 9); - static const trx = CryptoCurrency(title: 'TRX', raw: 10); - static const usdt = CryptoCurrency(title: 'USDT', raw: 11); - static const xlm = CryptoCurrency(title: 'XLM', raw: 12); - static const xrp = CryptoCurrency(title: 'XRP', raw: 13); - static const xmr = CryptoCurrency(title: 'XMR', raw: 14); - - - static CryptoCurrency deserialize({int raw}) { - switch (raw) { - case 0: - return CryptoCurrency.oxen; - case 1: - return CryptoCurrency.ada; - case 2: - return CryptoCurrency.bch; - case 3: - return CryptoCurrency.bnb; - case 4: - return CryptoCurrency.btc; - case 5: - return CryptoCurrency.dash; - case 6: - return CryptoCurrency.eos; - case 7: - return CryptoCurrency.eth; - case 8: - return CryptoCurrency.ltc; - case 9: - return CryptoCurrency.nano; - case 10: - return CryptoCurrency.trx; - case 11: - return CryptoCurrency.usdt; - case 12: - return CryptoCurrency.xlm; - case 13: - return CryptoCurrency.xrp; - case 14: - return CryptoCurrency.xmr; - default: - return null; - } - } - - static CryptoCurrency fromString(String raw) { - switch (raw.toLowerCase()) { - case 'oxen': - return CryptoCurrency.oxen; - case 'xmr': - return CryptoCurrency.xmr; - case 'ada': - return CryptoCurrency.ada; - case 'bch': - return CryptoCurrency.bch; - case 'bnb': - return CryptoCurrency.bnb; - case 'btc': - return CryptoCurrency.btc; - case 'dash': - return CryptoCurrency.dash; - case 'eos': - return CryptoCurrency.eos; - case 'eth': - return CryptoCurrency.eth; - case 'ltc': - return CryptoCurrency.ltc; - case 'nano': - return CryptoCurrency.nano; - case 'trx': - return CryptoCurrency.trx; - case 'usdt': - return CryptoCurrency.usdt; - case 'xlm': - return CryptoCurrency.xlm; - case 'xrp': - return CryptoCurrency.xrp; - default: - return null; - } - } - - @override - String toString() => title; -} diff --git a/lib/src/domain/common/default_settings_migration.dart b/lib/src/domain/common/default_settings_migration.dart index 905aa3fa..41f08676 100644 --- a/lib/src/domain/common/default_settings_migration.dart +++ b/lib/src/domain/common/default_settings_migration.dart @@ -1,4 +1,3 @@ -import 'package:flutter/foundation.dart'; import 'package:hive/hive.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:oxen_wallet/src/node/node.dart'; @@ -8,9 +7,9 @@ import 'package:oxen_wallet/src/node/node_list.dart'; import 'package:oxen_wallet/src/wallet/oxen/transaction/transaction_priority.dart'; Future defaultSettingsMigration( - {@required int version, - @required SharedPreferences sharedPreferences, - @required Box nodes}) async { + {required int version, + required SharedPreferences sharedPreferences, + required Box nodes}) async { final currentVersion = sharedPreferences.getInt('current_default_settings_migration_version') ?? 0; @@ -60,13 +59,12 @@ Future defaultSettingsMigration( 'current_default_settings_migration_version', version); } -Future replaceNodesMigration({@required Box nodes}) async { +Future replaceNodesMigration({required Box nodes}) async { final replaceNodes = { - 'public.loki.foundation:22023': - Node(uri: 'public.loki.foundation:22023'), - 'nodes.hashvault.pro:22023': - Node(uri: 'nodes.hashvault.pro:22023'), - 'node.loki-pool.com:18081': Node(uri: 'node.loki-pool.com:18081') + /* + 'OLD-public.loki.foundation:22023': + Node(uri: 'NEW-public.loki.foundation:22023'), + */ }; nodes.values.forEach((Node node) async { @@ -82,42 +80,39 @@ Future replaceNodesMigration({@required Box nodes}) async { } Future changeCurrentNodeToDefault( - {@required SharedPreferences sharedPreferences, - @required Box nodes}) async { - final timeZone = DateTime.now().timeZoneOffset.inHours; - var nodeUri = ''; + {required SharedPreferences sharedPreferences, + required Box nodes}) async { + late String nodeUri; - if (timeZone >= 1) { // Eurasia + final timeZone = DateTime.now().timeZoneOffset.inHours; + if (timeZone >= -1) { // Europe, Africa, Asia, Australia -- prefer OPTF EU public server nodeUri = 'public.loki.foundation:22023'; - } else if (timeZone <= -4) { // America + } else { // Americas -- prefer OPTF NA public server nodeUri = 'freyr.imaginary.stream:22023'; } - final node = nodes.values.firstWhere((Node node) => node.uri == nodeUri) ?? - nodes.values.first; - final nodeId = node != null ? node.key as int : 0; // 0 - England + final node = nodes.values.firstWhere((Node node) => node.uri == nodeUri, + orElse: () => nodes.values.first); - await sharedPreferences.setInt('current_node_id', nodeId); + await sharedPreferences.setInt('current_node_id', node.key as int); } Future replaceDefaultNode( - {@required SharedPreferences sharedPreferences, - @required Box nodes}) async { + {required SharedPreferences sharedPreferences, + required Box nodes}) async { const nodesForReplace = [ + /* 'public.loki.foundation:22023', - 'nodes.hashvault.pro:22023', - 'node.loki-pool.com:18081' + */ ]; final currentNodeId = sharedPreferences.getInt('current_node_id'); - final currentNode = - nodes.values.firstWhere((Node node) => node.key == currentNodeId); - final needToReplace = - currentNode == null ? true : nodesForReplace.contains(currentNode.uri); - - if (!needToReplace) { - return; + Node? currentNode; + try { + currentNode = + nodes.values.firstWhere((Node node) => node.key == currentNodeId); + } catch (_) {} + if (currentNode == null || nodesForReplace.contains(currentNode.uri)) { + await changeCurrentNodeToDefault( + sharedPreferences: sharedPreferences, nodes: nodes); } - - await changeCurrentNodeToDefault( - sharedPreferences: sharedPreferences, nodes: nodes); } diff --git a/lib/src/domain/common/encrypt.dart b/lib/src/domain/common/encrypt.dart index 8d83f0fc..cd9d1469 100644 --- a/lib/src/domain/common/encrypt.dart +++ b/lib/src/domain/common/encrypt.dart @@ -1,7 +1,7 @@ import 'package:encrypt/encrypt.dart'; import 'package:oxen_wallet/.secrets.g.dart' as secrets; -String encrypt({String source, String key, int keyLength = 16}) { +String encrypt({required String source, required String key, int keyLength = 16}) { final _key = Key.fromUtf8(key); final iv = IV.fromLength(keyLength); final encrypter = Encrypter(AES(_key)); @@ -10,7 +10,7 @@ String encrypt({String source, String key, int keyLength = 16}) { return encrypted.base64; } -String decrypt({String source, String key, int keyLength = 16}) { +String decrypt({required String source, required String key, int keyLength = 16}) { final _key = Key.fromUtf8(key); final iv = IV.fromLength(keyLength); final encrypter = Encrypter(AES(_key)); @@ -19,26 +19,26 @@ String decrypt({String source, String key, int keyLength = 16}) { return decrypted; } -String encodedPinCode({String pin}) { +String encodedPinCode({required String pin}) { final source = '${secrets.salt}$pin'; return encrypt(source: source, key: secrets.key); } -String decodedPinCode({String pin}) { +String decodedPinCode({required String pin}) { final decrypted = decrypt(source: pin, key: secrets.key); return decrypted.substring(secrets.key.length, decrypted.length); } -String encodeWalletPassword({String password}) { +String encodeWalletPassword({required String password}) { final source = password; final _key = secrets.shortKey + secrets.walletSalt; return encrypt(source: source, key: _key); } -String decodeWalletPassword({String password}) { +String decodeWalletPassword({required String password}) { final source = password; final _key = secrets.shortKey + secrets.walletSalt; diff --git a/lib/src/domain/common/enumerable_item.dart b/lib/src/domain/common/enumerable_item.dart index f91bff87..f9566a60 100644 --- a/lib/src/domain/common/enumerable_item.dart +++ b/lib/src/domain/common/enumerable_item.dart @@ -1,17 +1,15 @@ -import 'package:flutter/foundation.dart'; +import 'package:oxen_wallet/l10n.dart'; abstract class EnumerableItem { - const EnumerableItem({@required this.title, @required this.raw}); + const EnumerableItem({required this.raw}); final T raw; - final String title; - @override - String toString() => title; + String getTitle(AppLocalizations t); } mixin Serializable on EnumerableItem { - static Serializable deserialize({T raw}) => null; + static Serializable? deserialize({required T raw}) => null; T serialize() => raw; } diff --git a/lib/src/domain/common/fetch_price.dart b/lib/src/domain/common/fetch_price.dart index 688af15d..6a6607a8 100644 --- a/lib/src/domain/common/fetch_price.dart +++ b/lib/src/domain/common/fetch_price.dart @@ -1,12 +1,11 @@ import 'dart:convert'; -import 'package:oxen_wallet/src/domain/common/crypto_currency.dart'; import 'package:oxen_wallet/src/domain/common/fiat_currency.dart'; import 'package:http/http.dart'; const fiatApiAuthority = 'oxen.observer'; -Future fetchPriceFor({CryptoCurrency crypto, FiatCurrency fiat}) async { +Future fetchPriceFor({required FiatCurrency fiat}) async { var price = 0.0; try { diff --git a/lib/src/domain/common/fiat_currency.dart b/lib/src/domain/common/fiat_currency.dart index 88fff068..124d07c1 100644 --- a/lib/src/domain/common/fiat_currency.dart +++ b/lib/src/domain/common/fiat_currency.dart @@ -1,11 +1,18 @@ import 'package:oxen_wallet/src/domain/common/enumerable_item.dart'; +import 'package:oxen_wallet/l10n.dart'; class FiatCurrency extends EnumerableItem with Serializable { - const FiatCurrency({String symbol}) : super(title: symbol, raw: symbol); + const FiatCurrency({required String? symbol}) : super(raw: symbol ?? 'USD'); @override bool operator ==(Object other) => other is FiatCurrency && other.raw == raw; + @override + String toString() => raw; + + @override + String getTitle(AppLocalizations l10n) => raw; + static const all = [ FiatCurrency.aud, FiatCurrency.bgn, @@ -77,5 +84,5 @@ class FiatCurrency extends EnumerableItem with Serializable { static const vef = FiatCurrency(symbol: 'VEF'); @override - int get hashCode => raw.hashCode ^ title.hashCode; + int get hashCode => raw.hashCode; } diff --git a/lib/src/domain/common/get_encryption_key.dart b/lib/src/domain/common/get_encryption_key.dart index 7a940070..3798cfbc 100644 --- a/lib/src/domain/common/get_encryption_key.dart +++ b/lib/src/domain/common/get_encryption_key.dart @@ -2,7 +2,7 @@ import 'package:flutter_secure_storage/flutter_secure_storage.dart'; import 'package:hive/hive.dart'; Future> getEncryptionKey( - {String forKey, FlutterSecureStorage secureStorage}) async { + {required String forKey, required FlutterSecureStorage secureStorage}) async { final keyFromStorage = await secureStorage.read(key: forKey); List key; diff --git a/lib/src/domain/common/language.dart b/lib/src/domain/common/language.dart deleted file mode 100644 index 9a702d8d..00000000 --- a/lib/src/domain/common/language.dart +++ /dev/null @@ -1,39 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:devicelocale/devicelocale.dart'; -import 'package:intl/intl.dart'; - -const Map languages = { - 'en': 'English', - 'de': 'Deutsch (German)', - 'fr': 'Français (French)', - // 'es': 'Español (Spanish)', - // 'hi': 'हिंदी (Hindi)', - // 'ja': '日本 (Japanese)', - // 'ko': '한국어 (Korean)', - // 'nl': 'Nederlands (Dutch)', - // 'pl': 'Polski (Polish)', - // 'pt': 'Português (Portuguese)', - // 'ru': 'Русский (Russian)', - // 'uk': 'Українська (Ukrainian)', - // 'zh': '中文 (Chinese)' -}; - -class Language with ChangeNotifier { - Language(this._currentLanguage); - - String _currentLanguage; - - String getCurrentLanguage() => _currentLanguage; - - void setCurrentLanguage(String language) { - _currentLanguage = language; - notifyListeners(); - } - - static Future localeDetection() async { - var locale = await Devicelocale.currentLocale; - locale = Intl.shortLocale(locale); - - return languages.keys.contains(locale) ? locale : 'en'; - } -} \ No newline at end of file diff --git a/lib/src/domain/common/openalias_record.dart b/lib/src/domain/common/openalias_record.dart index ec2fc6ef..28bd2795 100644 --- a/lib/src/domain/common/openalias_record.dart +++ b/lib/src/domain/common/openalias_record.dart @@ -2,7 +2,7 @@ import 'package:basic_utils/basic_utils.dart'; class OpenaliasRecord { - OpenaliasRecord({this.address, this.name}); + OpenaliasRecord({required this.address, required this.name}); final String name; final String address; diff --git a/lib/src/domain/common/qr_scanner.dart b/lib/src/domain/common/qr_scanner.dart index 4a26bdde..b4d53735 100644 --- a/lib/src/domain/common/qr_scanner.dart +++ b/lib/src/domain/common/qr_scanner.dart @@ -1,15 +1,31 @@ -import 'package:barcode_scan/barcode_scan.dart'; +import 'package:barcode_scan2/barcode_scan2.dart'; var isQrScannerShown = false; -Future presentQRScanner() async { +class QRScanException implements Exception { + QRScanException(this.message); + + String message; + + @override + String toString() => message; +} + +/// Shows the QR scanner to the user; this sets the future once the user either scans a QR code (we +/// return the string value), cancels (we return null), or an error occurs (we throw a +/// QRScanException). +Future presentQRScanner() async { isQrScannerShown = true; try { final result = await BarcodeScanner.scan(); isQrScannerShown = false; - return result; + if (result.type == ResultType.Error) + throw QRScanException(result.rawContent); + if (result.type == ResultType.Cancelled) + return null; + return result.rawContent; } catch (e) { isQrScannerShown = false; - rethrow; + throw QRScanException(e.toString()); } } diff --git a/lib/src/domain/common/secret_store_key.dart b/lib/src/domain/common/secret_store_key.dart index a42d79f1..e0c10377 100644 --- a/lib/src/domain/common/secret_store_key.dart +++ b/lib/src/domain/common/secret_store_key.dart @@ -3,7 +3,7 @@ enum SecretStoreKey { moneroWalletPassword, pinCodePassword } const moneroWalletPassword = 'MONERO_WALLET_PASSWORD'; const pinCodePassword = 'PIN_CODE_PASSWORD'; -String generateStoreKeyFor({SecretStoreKey key, String walletName = '',}) { +String generateStoreKeyFor({required SecretStoreKey key, String walletName = '',}) { var _key = ''; switch (key) { @@ -19,4 +19,4 @@ String generateStoreKeyFor({SecretStoreKey key, String walletName = '',}) { } return _key; -} \ No newline at end of file +} diff --git a/lib/src/domain/services/user_service.dart b/lib/src/domain/services/user_service.dart index add962c9..ed19c281 100644 --- a/lib/src/domain/services/user_service.dart +++ b/lib/src/domain/services/user_service.dart @@ -4,7 +4,7 @@ import 'package:oxen_wallet/src/domain/common/secret_store_key.dart'; import 'package:oxen_wallet/src/domain/common/encrypt.dart'; class UserService { - UserService({this.sharedPreferences, this.secureStorage}); + UserService({required this.sharedPreferences, required this.secureStorage}); final FlutterSecureStorage secureStorage; final SharedPreferences sharedPreferences; @@ -24,21 +24,24 @@ class UserService { Future canAuthenticate() async { final key = generateStoreKeyFor(key: SecretStoreKey.pinCodePassword); final sharedPreferences = await SharedPreferences.getInstance(); - final walletName = sharedPreferences.getString('current_wallet_name') ?? ''; - var password = ''; + final walletName = sharedPreferences.getString('current_wallet_name'); + if (!(walletName?.isNotEmpty ?? false)) + return false; + String? password; try { password = await secureStorage.read(key: key); } catch (e) { print(e); } - - return walletName.isNotEmpty && password.isNotEmpty; + return password?.isNotEmpty ?? false; } Future authenticate(String pin) async { final key = generateStoreKeyFor(key: SecretStoreKey.pinCodePassword); final encodedPin = await secureStorage.read(key: key); + if (encodedPin == null) + return false; final decodedPin = decodedPinCode(pin: encodedPin); return decodedPin == pin; diff --git a/lib/src/domain/services/wallet_list_service.dart b/lib/src/domain/services/wallet_list_service.dart index f23fc4ed..bfb4bc10 100644 --- a/lib/src/domain/services/wallet_list_service.dart +++ b/lib/src/domain/services/wallet_list_service.dart @@ -1,6 +1,5 @@ import 'dart:async'; -import 'package:flutter/foundation.dart'; import 'package:flutter_secure_storage/flutter_secure_storage.dart'; import 'package:hive/hive.dart'; import 'package:oxen_wallet/src/domain/common/encrypt.dart'; @@ -10,7 +9,6 @@ import 'package:oxen_wallet/src/wallet/oxen/oxen_wallets_manager.dart'; import 'package:oxen_wallet/src/wallet/wallet.dart'; import 'package:oxen_wallet/src/wallet/wallet_description.dart'; import 'package:oxen_wallet/src/wallet/wallet_info.dart'; -import 'package:oxen_wallet/src/wallet/wallet_type.dart'; import 'package:oxen_wallet/src/wallet/wallets_manager.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:uuid/uuid.dart'; @@ -26,11 +24,12 @@ class WalletIsExistException implements Exception { class WalletListService { WalletListService( - {this.secureStorage, - this.walletInfoSource, - this.walletsManager, - @required this.walletService, - @required this.sharedPreferences}); + {required this.secureStorage, + required this.walletInfoSource, + WalletsManager? walletsManager, + required this.walletService, + required this.sharedPreferences}) + : walletsManager = walletsManager ?? OxenWalletsManager(walletInfoSource: walletInfoSource); final FlutterSecureStorage secureStorage; final WalletService walletService; @@ -107,18 +106,6 @@ class WalletListService { await onWalletChange(wallet); } - Future changeWalletManger({WalletType walletType}) async { - switch (walletType) { - case WalletType.oxen: - walletsManager = OxenWalletsManager(walletInfoSource: walletInfoSource); - break; - case WalletType.monero: - case WalletType.none: - walletsManager = null; - break; - } - } - Future onWalletChange(Wallet wallet) async { walletService.currentWallet = wallet; final walletName = await wallet.getName(); @@ -128,15 +115,15 @@ class WalletListService { Future remove(WalletDescription wallet) async => await walletsManager.remove(wallet); - Future getWalletPassword({String walletName}) async { + Future getWalletPassword({required String walletName}) async { final key = generateStoreKeyFor( key: SecretStoreKey.moneroWalletPassword, walletName: walletName); final encodedPassword = await secureStorage.read(key: key); - return decodeWalletPassword(password: encodedPassword); + return decodeWalletPassword(password: encodedPassword!); } - Future saveWalletPassword({String walletName, String password}) async { + Future saveWalletPassword({required String walletName, required String password}) async { final key = generateStoreKeyFor( key: SecretStoreKey.moneroWalletPassword, walletName: walletName); final encodedPassword = encodeWalletPassword(password: password); diff --git a/lib/src/domain/services/wallet_service.dart b/lib/src/domain/services/wallet_service.dart index 653fcb44..1d7f8c45 100644 --- a/lib/src/domain/services/wallet_service.dart +++ b/lib/src/domain/services/wallet_service.dart @@ -2,7 +2,6 @@ import 'package:oxen_wallet/src/node/node.dart'; import 'package:oxen_wallet/src/node/sync_status.dart'; import 'package:oxen_wallet/src/wallet/balance.dart'; import 'package:oxen_wallet/src/wallet/transaction/pending_transaction.dart'; -import 'package:oxen_wallet/src/wallet/transaction/transaction_creation_credentials.dart'; import 'package:oxen_wallet/src/wallet/transaction/transaction_history.dart'; import 'package:oxen_wallet/src/wallet/wallet.dart'; import 'package:oxen_wallet/src/wallet/wallet_description.dart'; @@ -10,130 +9,132 @@ import 'package:oxen_wallet/src/wallet/wallet_type.dart'; import 'package:rxdart/rxdart.dart'; class WalletService extends Wallet { - WalletService() { - _currentWallet = null; - walletType = WalletType.none; - _syncStatus = BehaviorSubject(); - _onBalanceChange = BehaviorSubject(); + WalletService() : + _currentWallet = null, + _syncStatus = BehaviorSubject(), + _onBalanceChange = BehaviorSubject(), _onWalletChanged = BehaviorSubject(); - } @override - Observable get onBalanceChange => _onBalanceChange.stream; + Stream get onBalanceChange => _onBalanceChange.stream; @override - Observable get syncStatus => _syncStatus.stream; + Stream get syncStatus => _syncStatus.stream; @override - Observable get onAddressChange => _currentWallet.onAddressChange; + Stream get onAddressChange => _currentWallet!.onAddressChange; @override - Observable get onNameChange => _currentWallet.onNameChange; + Stream get onNameChange => _currentWallet!.onNameChange; @override - String get address => _currentWallet.address; + String get address => _currentWallet!.address; @override - String get name => _currentWallet.name; + String get name => _currentWallet!.name; @override - WalletType get walletType => _currentWallet.walletType; + WalletType get walletType => _currentWallet?.walletType ?? WalletType.none; - Observable get onWalletChange => _onWalletChanged.stream; + Stream get onWalletChange => _onWalletChanged.stream; SyncStatus get syncStatusValue => _syncStatus.value; - Wallet get currentWallet => _currentWallet; + Wallet? get currentWallet => _currentWallet; - set currentWallet(Wallet wallet) { + set currentWallet(Wallet? wallet) { _currentWallet = wallet; if (wallet == null) { return; } - _currentWallet.onBalanceChange + _currentWallet!.onBalanceChange .listen((wallet) => _onBalanceChange.add(wallet)); - _currentWallet.syncStatus.listen((status) => _syncStatus.add(status)); + _currentWallet!.syncStatus.listen((status) => _syncStatus.add(status)); _onWalletChanged.add(wallet); - final type = wallet.getType(); + final type = wallet.walletType; wallet.getName().then( (name) => description = WalletDescription(name: name, type: type)); } - BehaviorSubject _onWalletChanged; - BehaviorSubject _onBalanceChange; - BehaviorSubject _syncStatus; - Wallet _currentWallet; + final BehaviorSubject _onWalletChanged; + final BehaviorSubject _onBalanceChange; + final BehaviorSubject _syncStatus; + Wallet? _currentWallet; - WalletDescription description; + WalletDescription? description; @override - WalletType getType() => WalletType.monero; + Future getFilename() => _currentWallet!.getFilename(); @override - Future getFilename() => _currentWallet.getFilename(); + Future getName() => _currentWallet!.getName(); @override - Future getName() => _currentWallet.getName(); + Future getAddress() => _currentWallet!.getAddress(); @override - Future getAddress() => _currentWallet.getAddress(); + Future getSeed() => _currentWallet!.getSeed(); @override - Future getSeed() => _currentWallet.getSeed(); + Future> getKeys() => _currentWallet!.getKeys(); @override - Future> getKeys() => _currentWallet.getKeys(); + Future getFullBalance() => _currentWallet!.getFullBalance(); @override - Future getFullBalance() => _currentWallet.getFullBalance(); + Future getUnlockedBalance() => _currentWallet!.getUnlockedBalance(); @override - Future getUnlockedBalance() => _currentWallet.getUnlockedBalance(); + int getCurrentHeight() => _currentWallet!.getCurrentHeight(); @override - int getCurrentHeight() => _currentWallet.getCurrentHeight(); + bool isRefreshing() => currentWallet!.isRefreshing(); @override - bool isRefreshing() => currentWallet.isRefreshing(); + Future getNodeHeight() => _currentWallet!.getNodeHeight(); @override - Future getNodeHeight() => _currentWallet.getNodeHeight(); + Future isConnected() => _currentWallet!.isConnected(); @override - Future isConnected() => _currentWallet.isConnected(); + Future close() => _currentWallet!.close(); @override - Future close() => _currentWallet.close(); + Future connectToNode( + {required Node? node, bool useSSL = false, bool isLightWallet = false}) async { + if (node == null) + return; - @override - Future connectToNode( - {Node node, bool useSSL = false, bool isLightWallet = false}) => - _currentWallet.connectToNode( + await _currentWallet!.connectToNode( node: node, useSSL: useSSL, isLightWallet: isLightWallet); + } @override - Future startSync() => _currentWallet.startSync(); + Future startSync() => _currentWallet!.startSync(); @override - TransactionHistory getHistory() => _currentWallet.getHistory(); + TransactionHistory getHistory() => _currentWallet!.getHistory(); @override - Future createStake( - TransactionCreationCredentials credentials) => - _currentWallet.createStake(credentials); + Future createStake({ + required String snPubkey, + required String? amount}) + => _currentWallet!.createStake(snPubkey: snPubkey, amount: amount); @override - Future createTransaction( - TransactionCreationCredentials credentials) => - _currentWallet.createTransaction(credentials); + Future createTransaction({ + required String recipient, + required String? amount, + OxenTransactionPriority priority = OxenTransactionPriority.blink}) + => _currentWallet!.createTransaction(recipient: recipient, amount: amount, priority: priority); @override - Future updateInfo() async => _currentWallet.updateInfo(); + Future updateInfo() async => _currentWallet!.updateInfo(); @override Future rescan({int restoreHeight = 0}) async => - _currentWallet.rescan(restoreHeight: restoreHeight); + _currentWallet!.rescan(restoreHeight: restoreHeight); } diff --git a/lib/src/node/digest_request.dart b/lib/src/node/digest_request.dart deleted file mode 100644 index 91e40a58..00000000 --- a/lib/src/node/digest_request.dart +++ /dev/null @@ -1,96 +0,0 @@ -import 'dart:convert'; -import 'package:dio/dio.dart' as __dio; -import 'package:crypto/crypto.dart' as crypto; -import 'dart:math' as math; - -class DigestRequest { - final md5 = crypto.md5; - - String generateCnonce() { - final rnd = math.Random.secure(); - final values = List.generate(32, (i) => rnd.nextInt(256)); - return base64Url.encode(values).substring(0, 8); - } - - String generateHA1({String realm, String username, String password}) { - final ha1CredentialsData = - Utf8Encoder().convert('$username:$realm:$password'); - final ha1 = md5.convert(ha1CredentialsData).toString(); - - return ha1; - } - - String generateHA2({String method, String uri}) { - final ha2Data = Utf8Encoder().convert('$method:$uri'); - final ha2 = md5.convert(ha2Data).toString(); - - return ha2; - } - - String generateResponseString( - {String ha1, - String ha2, - String nonce, - String nonceCount, - String cnonce, - String qop}) { - final responseData = - Utf8Encoder().convert('$ha1:$nonce:$nonceCount:$cnonce:$qop:$ha2'); - final response = md5.convert(responseData).toString(); - - return response; - } - - Map parsetAuthorizationHeader({String source}) { - final authHeaderParts = - source.substring(7).split(',').map((item) => item.trim()); - final authenticate = {}; - - for (final part in authHeaderParts) { - final kv = part.split('='); - authenticate[kv[0]] = - kv.getRange(1, kv.length).join('=').replaceAll('"', ''); - } - - return authenticate; - } - - Future<__dio.Response> request( - {String uri, String login, String password, Map requestBody}) async { - const path = '/json_rpc'; - const method = 'POST'; - final url = Uri.http(uri, path); - final dio = __dio.Dio(); - final headers = {'Content-type': 'application/json'}; - final body = - json.encode(requestBody); - final credentialsResponse = await dio.post(url.toString(), - options: __dio.Options(headers: headers, validateStatus: (_) => true)); - final authenticate = parsetAuthorizationHeader( - source: credentialsResponse.headers['www-authenticate'].first); - final qop = authenticate['qop']; - final algorithm = 'MD5'; - final realm = 'monero-rpc'; - final nonce = authenticate['nonce']; - final cnonce = generateCnonce(); - final nonceCount = '00000001'; - final ha1 = generateHA1(realm: realm, username: login, password: password); - final ha2 = generateHA2(method: method, uri: path); - final response = generateResponseString( - ha1: ha1, - ha2: ha2, - nonce: nonce, - nonceCount: nonceCount, - cnonce: cnonce, - qop: qop); - - final authorizationHeaders = { - 'Content-type': 'application/json', - 'Authorization': - 'Digest username="$login",realm="$realm",nonce="$nonce",uri="$path",algorithm="$algorithm",qop=$qop,nc=$nonceCount,cnonce="$cnonce",response="$response"' - }; - - return await dio.post(url.toString(), - options: __dio.Options(headers: authorizationHeaders), data: body); - } -} diff --git a/lib/src/node/node.dart b/lib/src/node/node.dart index ec9cd277..e34f2c32 100644 --- a/lib/src/node/node.dart +++ b/lib/src/node/node.dart @@ -1,20 +1,18 @@ import 'dart:convert'; -import 'package:flutter/foundation.dart'; import 'package:hive/hive.dart'; import 'package:http/http.dart' as http; -import 'package:oxen_wallet/src/node/digest_request.dart'; part 'node.g.dart'; @HiveType(typeId: 1) class Node extends HiveObject { - Node({@required this.uri, this.login, this.password}); + Node({required this.uri, this.login, this.password}); Node.fromMap(Map map) : uri = (map['uri'] ?? '') as String, - login = map['login'] as String, - password = map['password'] as String; + login = map['login'] as String?, + password = map['password'] as String?; static const boxName = 'Nodes'; @@ -22,10 +20,10 @@ class Node extends HiveObject { String uri; @HiveField(1) - String login; + String? login; @HiveField(2) - String password; + String? password; Future isOnline() async { final resBody = await sendRPCRequest('get_info'); @@ -33,19 +31,21 @@ class Node extends HiveObject { } Future> sendRPCRequest(String method, - {Map params}) async { + {Map? params}) async { Map resultBody; final requestBody = params != null ? {'jsonrpc': '2.0', 'id': '0', 'method': method, 'params': params} : {'jsonrpc': '2.0', 'id': '0', 'method': method}; + // Disable: the auth code was removed as it only supported Digest-MD5 auth, which is insecure and deprecated. + /* if (login != null && password != null) { final digestRequest = DigestRequest(); final response = await digestRequest.request( - uri: uri, login: login, password: password, requestBody: requestBody); + uri: uri, login: login!, password: password!, requestBody: requestBody); resultBody = response.data as Map; - } else { + } else */ { final url = Uri.http(uri, '/json_rpc'); final headers = {'Content-type': 'application/json'}; final body = json.encode(requestBody); diff --git a/lib/src/node/node_list.dart b/lib/src/node/node_list.dart index 149db2c6..4d088112 100644 --- a/lib/src/node/node_list.dart +++ b/lib/src/node/node_list.dart @@ -10,13 +10,12 @@ Future> loadDefaultNodes() async { final nodesRaw = await rootBundle.loadString('assets/$nodeListFileName'); final nodes = loadYaml(nodesRaw) as YamlList; - return nodes.map((dynamic raw) { - if (raw is Map) { - return Node.fromMap(raw); - } - - return null; - }).toList(); + final n = []; + nodes.forEach((dynamic raw) { + if (raw is Map) + n.add(Node.fromMap(raw)); + }); + return n; } Future resetToDefault(Box nodeSource) async { diff --git a/lib/src/node/sync_status.dart b/lib/src/node/sync_status.dart index 27e005c4..58ad767c 100644 --- a/lib/src/node/sync_status.dart +++ b/lib/src/node/sync_status.dart @@ -1,11 +1,11 @@ -import 'package:oxen_wallet/generated/l10n.dart'; +import 'package:oxen_wallet/l10n.dart'; abstract class SyncStatus { const SyncStatus(); double progress(); - String title(); + String title(AppLocalizations t); } class SyncingSyncStatus extends SyncStatus { @@ -18,7 +18,7 @@ class SyncingSyncStatus extends SyncStatus { double progress() => ptc; @override - String title() => S.current.Blocks_remaining('$blocksLeft'); + String title(AppLocalizations t) => t.blocks_remaining('$blocksLeft'); @override String toString() => '$blocksLeft'; @@ -29,7 +29,7 @@ class SyncedSyncStatus extends SyncStatus { double progress() => 1.0; @override - String title() => S.current.sync_status_synchronized; + String title(AppLocalizations t) => t.sync_status_synchronized; } class NotConnectedSyncStatus extends SyncStatus { @@ -39,7 +39,7 @@ class NotConnectedSyncStatus extends SyncStatus { double progress() => 0.0; @override - String title() => S.current.sync_status_not_connected; + String title(AppLocalizations t) => t.sync_status_not_connected; } class StartingSyncStatus extends SyncStatus { @@ -47,7 +47,7 @@ class StartingSyncStatus extends SyncStatus { double progress() => 0.0; @override - String title() => S.current.sync_status_starting_sync; + String title(AppLocalizations t) => t.sync_status_starting_sync; } class FailedSyncStatus extends SyncStatus { @@ -55,7 +55,7 @@ class FailedSyncStatus extends SyncStatus { double progress() => 1.0; @override - String title() => S.current.sync_status_failed_connect; + String title(AppLocalizations t) => t.sync_status_failed_connect; } class ConnectingSyncStatus extends SyncStatus { @@ -63,7 +63,7 @@ class ConnectingSyncStatus extends SyncStatus { double progress() => 0.0; @override - String title() => S.current.sync_status_connecting; + String title(AppLocalizations t) => t.sync_status_connecting; } class ConnectedSyncStatus extends SyncStatus { @@ -71,5 +71,5 @@ class ConnectedSyncStatus extends SyncStatus { double progress() => 0.0; @override - String title() => S.current.sync_status_connected; + String title(AppLocalizations t) => t.sync_status_connected; } diff --git a/lib/src/reactions/set_reactions.dart b/lib/src/reactions/set_reactions.dart index 5eb52262..d046b525 100644 --- a/lib/src/reactions/set_reactions.dart +++ b/lib/src/reactions/set_reactions.dart @@ -1,5 +1,4 @@ import 'dart:async'; -import 'package:flutter/foundation.dart'; import 'package:mobx/mobx.dart'; import 'package:oxen_wallet/src/node/node.dart'; import 'package:oxen_wallet/src/node/sync_status.dart'; @@ -12,19 +11,19 @@ import 'package:oxen_wallet/src/stores/price/price_store.dart'; import 'package:oxen_wallet/src/stores/authentication/authentication_store.dart'; import 'package:oxen_wallet/src/stores/login/login_store.dart'; -Timer _reconnectionTimer; -ReactionDisposer _connectToNodeDisposer; -ReactionDisposer _onSyncStatusChangeDisposer; -ReactionDisposer _onCurrentWalletChangeDisposer; +Timer? _reconnectionTimer; +ReactionDisposer? _connectToNodeDisposer; +ReactionDisposer? _onSyncStatusChangeDisposer; +ReactionDisposer? _onCurrentWalletChangeDisposer; void setReactions( - {@required SettingsStore settingsStore, - @required PriceStore priceStore, - @required SyncStore syncStore, - @required WalletStore walletStore, - @required WalletService walletService, - @required AuthenticationStore authenticationStore, - @required LoginStore loginStore}) { + {required SettingsStore settingsStore, + required PriceStore priceStore, + required SyncStore syncStore, + required WalletStore walletStore, + required WalletService walletService, + required AuthenticationStore authenticationStore, + required LoginStore loginStore}) { connectToNode(settingsStore: settingsStore, walletStore: walletStore); onSyncStatusChange( syncStore: syncStore, @@ -42,17 +41,17 @@ void setReactions( }); } -void connectToNode({SettingsStore settingsStore, WalletStore walletStore}) { +void connectToNode({required SettingsStore settingsStore, required WalletStore walletStore}) { _connectToNodeDisposer?.call(); _connectToNodeDisposer = reaction((_) => settingsStore.node, - (Node node) async => await walletStore.connectToNode(node: node)); + (Node? node) async => await walletStore.connectToNode(node: node)); } void onCurrentWalletChange( - {WalletStore walletStore, - SettingsStore settingsStore, - PriceStore priceStore}) { + {required WalletStore walletStore, + required SettingsStore settingsStore, + required PriceStore priceStore}) { _onCurrentWalletChangeDisposer?.call(); reaction((_) => walletStore.name, (String _) { @@ -62,9 +61,9 @@ void onCurrentWalletChange( } void onSyncStatusChange( - {SyncStore syncStore, - WalletStore walletStore, - SettingsStore settingsStore}) { + {required SyncStore syncStore, + required WalletStore walletStore, + required SettingsStore settingsStore}) { _onSyncStatusChangeDisposer?.call(); reaction((_) => syncStore.status, (SyncStatus status) async { @@ -79,7 +78,7 @@ void onSyncStatusChange( }); } -void startReconnectionObserver({SyncStore syncStore, WalletStore walletStore}) { +void startReconnectionObserver({required SyncStore syncStore, required WalletStore walletStore}) { _reconnectionTimer?.cancel(); _reconnectionTimer = Timer.periodic(Duration(seconds: 1060), (_) async { try { diff --git a/lib/src/screens/accounts/account_list_page.dart b/lib/src/screens/accounts/account_list_page.dart index 7c8ba35f..a98e1c60 100644 --- a/lib/src/screens/accounts/account_list_page.dart +++ b/lib/src/screens/accounts/account_list_page.dart @@ -1,18 +1,17 @@ import 'package:provider/provider.dart'; import 'package:flutter/material.dart'; -import 'package:flutter/cupertino.dart'; import 'package:flutter_mobx/flutter_mobx.dart'; import 'package:flutter_slidable/flutter_slidable.dart'; import 'package:oxen_wallet/palette.dart'; import 'package:oxen_wallet/routes.dart'; -import 'package:oxen_wallet/generated/l10n.dart'; +import 'package:oxen_wallet/l10n.dart'; import 'package:oxen_wallet/src/stores/account_list/account_list_store.dart'; import 'package:oxen_wallet/src/stores/wallet/wallet_store.dart'; import 'package:oxen_wallet/src/screens/base_page.dart'; class AccountListPage extends BasePage { @override - String get title => S.current.accounts; + String getTitle(AppLocalizations t) => t.accounts; @override Widget trailing(BuildContext context) { @@ -56,7 +55,7 @@ class AccountListPage extends BasePage { child: Observer(builder: (_) { final accounts = accountListStore.accounts; return ListView.builder( - itemCount: accounts == null ? 0 : accounts.length, + itemCount: accounts.length, itemBuilder: (BuildContext context, int index) { final account = accounts[index]; @@ -65,7 +64,24 @@ class AccountListPage extends BasePage { return Slidable( key: Key(account.id.toString()), - actionPane: SlidableDrawerActionPane(), + endActionPane: ActionPane( + motion: const DrawerMotion(), + children: [ + SlidableAction( + label: tr(context).edit, + backgroundColor: Colors.blue, + icon: Icons.edit, + onPressed: (context) async { + await Navigator.of(context).pushNamed( + Routes.accountCreation, + arguments: account); + // await accountListStore.updateAccountList().then((_) { + // if (isCurrent) walletStore.setAccount(accountListStore.accounts[index]); + // }); + }, + ) + ], + ), child: Container( color: isCurrent ? currentColor : notCurrentColor, child: Column( @@ -78,7 +94,7 @@ class AccountListPage extends BasePage { color: Theme.of(context) .primaryTextTheme .headline5 - .color), + ?.color), ), onTap: () { if (isCurrent) return; @@ -94,21 +110,6 @@ class AccountListPage extends BasePage { ], ), ), - secondaryActions: [ - IconSlideAction( - caption: S.of(context).edit, - color: Colors.blue, - icon: Icons.edit, - onTap: () async { - await Navigator.of(context).pushNamed( - Routes.accountCreation, - arguments: account); - // await accountListStore.updateAccountList().then((_) { - // if (isCurrent) walletStore.setAccount(accountListStore.accounts[index]); - // }); - }, - ) - ], ); }); }); diff --git a/lib/src/screens/accounts/account_page.dart b/lib/src/screens/accounts/account_page.dart index 8ecefce6..0cd814e1 100644 --- a/lib/src/screens/accounts/account_page.dart +++ b/lib/src/screens/accounts/account_page.dart @@ -1,7 +1,6 @@ -import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_mobx/flutter_mobx.dart'; -import 'package:oxen_wallet/generated/l10n.dart'; +import 'package:oxen_wallet/l10n.dart'; import 'package:oxen_wallet/src/screens/base_page.dart'; import 'package:oxen_wallet/src/stores/account_list/account_list_store.dart'; import 'package:oxen_wallet/src/wallet/oxen/account.dart'; @@ -13,10 +12,10 @@ import 'package:provider/provider.dart'; class AccountPage extends BasePage { AccountPage({this.account}); - final Account account; + final Account? account; @override - String get title => 'Account'; + String getTitle(AppLocalizations t) => t.account; @override Widget body(BuildContext context) => AccountForm(account); @@ -25,7 +24,7 @@ class AccountPage extends BasePage { class AccountForm extends StatefulWidget { AccountForm(this.account); - final Account account; + final Account? account; @override AccountFormState createState() => AccountFormState(); @@ -37,7 +36,7 @@ class AccountFormState extends State { @override void initState() { - if (widget.account != null) _textController.text = widget.account.label; + if (widget.account != null) _textController.text = widget.account!.label; super.initState(); } @@ -60,10 +59,10 @@ class AccountFormState extends State { children: [ Center( child: OxenTextField( - hintText: S.of(context).account, + hintText: tr(context).account, controller: _textController, validator: (value) { - accountListStore.validateAccountName(value); + accountListStore.validateAccountName(value ?? '', tr(context)); return accountListStore.errorMessage; }, ), @@ -74,24 +73,24 @@ class AccountFormState extends State { bottomSection: Observer( builder: (_) => LoadingPrimaryButton( onPressed: () async { - if (!_formKey.currentState.validate()) { + if (!(_formKey.currentState?.validate() ?? false)) { return; } if (widget.account != null) { await accountListStore.renameAccount( - index: widget.account.id, label: _textController.text); + index: widget.account!.id, label: _textController.text); } else { await accountListStore.addAccount( label: _textController.text); } Navigator.of(context).pop(_textController.text); }, - text: widget.account != null ? 'Rename' : S.of(context).add, + text: widget.account != null ? 'Rename' : tr(context).add, color: - Theme.of(context).primaryTextTheme.button.backgroundColor, + Theme.of(context).primaryTextTheme.button?.backgroundColor, borderColor: - Theme.of(context).primaryTextTheme.button.decorationColor, + Theme.of(context).primaryTextTheme.button?.decorationColor, isLoading: accountListStore.isAccountCreating, )), ); diff --git a/lib/src/screens/address_book/address_book_page.dart b/lib/src/screens/address_book/address_book_page.dart index 7efbca25..3b2d573b 100644 --- a/lib/src/screens/address_book/address_book_page.dart +++ b/lib/src/screens/address_book/address_book_page.dart @@ -3,10 +3,9 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_mobx/flutter_mobx.dart'; import 'package:flutter_slidable/flutter_slidable.dart'; -import 'package:oxen_wallet/generated/l10n.dart'; +import 'package:oxen_wallet/l10n.dart'; import 'package:oxen_wallet/palette.dart'; import 'package:oxen_wallet/routes.dart'; -import 'package:oxen_wallet/src/domain/common/crypto_currency.dart'; import 'package:oxen_wallet/src/screens/base_page.dart'; import 'package:oxen_wallet/src/stores/address_book/address_book_store.dart'; import 'package:oxen_wallet/src/widgets/oxen_dialog.dart'; @@ -18,10 +17,10 @@ class AddressBookPage extends BasePage { final bool isEditable; @override - String get title => S.current.address_book; + String getTitle(AppLocalizations t) => t.address_book; @override - Widget trailing(BuildContext context) { + Widget? trailing(BuildContext context) { if (!isEditable) return null; final addressBookStore = Provider.of(context); @@ -63,9 +62,7 @@ class AddressBookPage extends BasePage { color: Theme.of(context).dividerTheme.color, height: 1.0, ), - itemCount: addressBookStore.contactList == null - ? 0 - : addressBookStore.contactList.length, + itemCount: addressBookStore.contactList.length, itemBuilder: (BuildContext context, int index) { final contact = addressBookStore.contactList[index]; @@ -82,7 +79,7 @@ class AddressBookPage extends BasePage { if (isCopied) { await Clipboard.setData( ClipboardData(text: contact.address)); - Scaffold.of(context).showSnackBar( + ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text('Copied to Clipboard'), backgroundColor: Colors.green, @@ -96,14 +93,14 @@ class AddressBookPage extends BasePage { width: 48.0, alignment: Alignment.center, decoration: BoxDecoration( - color: _getCurrencyBackgroundColor(contact.type), + color: OxenPalette.tealWithOpacity, borderRadius: BorderRadius.circular(6.0), ), child: Text( - contact.type.toString(), + 'OXEN', style: TextStyle( fontSize: 11.0, - color: _getCurrencyTextColor(contact.type), + color: OxenPalette.teal, ), ), ), @@ -112,7 +109,7 @@ class AddressBookPage extends BasePage { style: TextStyle( fontSize: 16.0, color: - Theme.of(context).primaryTextTheme.headline6.color), + Theme.of(context).primaryTextTheme.headline6?.color), ), ); @@ -120,128 +117,63 @@ class AddressBookPage extends BasePage { ? content : Slidable( key: Key('${contact.key}'), - actionPane: SlidableDrawerActionPane(), - child: content, - secondaryActions: [ - IconSlideAction( - caption: 'Edit', - color: Colors.blue, - icon: Icons.edit, - onTap: () async { - await Navigator.of(context).pushNamed( - Routes.addressBookAddContact, - arguments: contact); + endActionPane: ActionPane( + motion: const DrawerMotion(), + children: [ + SlidableAction( + label: 'Edit', + backgroundColor: Colors.blue, + icon: Icons.edit, + onPressed: (context) async { + await Navigator.of(context).pushNamed( + Routes.addressBookAddContact, + arguments: contact); + await addressBookStore.updateContactList(); + }, + ), + SlidableAction( + label: 'Delete', + backgroundColor: Colors.red, + icon: CupertinoIcons.delete, + onPressed: (context) async { + await showAlertDialog(context).then( + (isDelete) async { + if (isDelete) { + await addressBookStore.delete(contact: contact); + await addressBookStore.updateContactList(); + } + }); + }, + ), + ] + ), + startActionPane: ActionPane( + motion: const DrawerMotion(), + dismissible: DismissiblePane( + onDismissed: () async { + await addressBookStore.delete(contact: contact); await addressBookStore.updateContactList(); }, - ), - IconSlideAction( - caption: 'Delete', - color: Colors.red, - icon: CupertinoIcons.delete, - onTap: () async { - await showAlertDialog(context) - .then((isDelete) async { - if (isDelete != null && isDelete) { - await addressBookStore.delete( - contact: contact); - await addressBookStore.updateContactList(); - } - }); + confirmDismiss: () async { + return await showAlertDialog(context); }, ), - ], - dismissal: SlidableDismissal( - child: SlidableDrawerDismissal(), - onDismissed: (actionType) async { - await addressBookStore.delete(contact: contact); - await addressBookStore.updateContactList(); - }, - onWillDismiss: (actionType) async { - return await showAlertDialog(context); - }, + children: [], ), + child: content, ); }), )); } - Color _getCurrencyBackgroundColor(CryptoCurrency currency) { - Color color; - switch (currency) { - case CryptoCurrency.oxen: - color = OxenPalette.tealWithOpacity; - break; - case CryptoCurrency.ada: - color = Colors.blue[200]; - break; - case CryptoCurrency.bch: - color = Colors.orangeAccent; - break; - case CryptoCurrency.bnb: - color = Colors.blue; - break; - case CryptoCurrency.btc: - color = Colors.orange; - break; - case CryptoCurrency.dash: - color = Colors.blue; - break; - case CryptoCurrency.eos: - color = Colors.orangeAccent; - break; - case CryptoCurrency.eth: - color = Colors.black; - break; - case CryptoCurrency.ltc: - color = Colors.blue[200]; - break; - case CryptoCurrency.nano: - color = Colors.orange; - break; - case CryptoCurrency.trx: - color = Colors.black; - break; - case CryptoCurrency.usdt: - color = Colors.blue[200]; - break; - case CryptoCurrency.xlm: - color = color = Colors.blue; - break; - case CryptoCurrency.xrp: - color = Colors.orangeAccent; - break; - default: - color = Colors.white; - } - return color; - } - - Color _getCurrencyTextColor(CryptoCurrency currency) { - Color color; - switch (currency) { - case CryptoCurrency.xmr: - color = OxenPalette.teal; - break; - case CryptoCurrency.ltc: - case CryptoCurrency.ada: - case CryptoCurrency.usdt: - color = Palette.lightBlue; - break; - default: - color = Colors.white; - } - return color; - } - Future showAlertDialog(BuildContext context) async { var result = false; - await showConfirmOxenDialog(context, 'Remove contact', - 'Are you sure that you want to remove selected contact?', + await showConfirmOxenDialog(context, tr(context).remove_contact, + tr(context).remove_contact_confirm, onDismiss: (context) => Navigator.pop(context, false), onConfirm: (context) { result = true; Navigator.pop(context, true); - return true; }); return result; } diff --git a/lib/src/screens/address_book/contact_page.dart b/lib/src/screens/address_book/contact_page.dart index 6118b963..7b19fa62 100644 --- a/lib/src/screens/address_book/contact_page.dart +++ b/lib/src/screens/address_book/contact_page.dart @@ -1,12 +1,9 @@ -import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; -import 'package:oxen_wallet/generated/l10n.dart'; +import 'package:oxen_wallet/l10n.dart'; import 'package:oxen_wallet/src/domain/common/contact.dart'; -import 'package:oxen_wallet/src/domain/common/crypto_currency.dart'; import 'package:oxen_wallet/src/screens/base_page.dart'; import 'package:oxen_wallet/src/stores/address_book/address_book_store.dart'; import 'package:oxen_wallet/src/widgets/address_text_field.dart'; -import 'package:oxen_wallet/src/widgets/oxen_dialog.dart'; import 'package:oxen_wallet/src/widgets/oxen_text_field.dart'; import 'package:oxen_wallet/src/widgets/primary_button.dart'; import 'package:oxen_wallet/src/widgets/scollable_with_bottom_section.dart'; @@ -15,10 +12,10 @@ import 'package:provider/provider.dart'; class ContactPage extends BasePage { ContactPage({this.contact}); - final Contact contact; + final Contact? contact; @override - String get title => S.current.contact; + String getTitle(AppLocalizations t) => t.contact; @override Widget body(BuildContext context) => ContactForm(contact); @@ -27,7 +24,7 @@ class ContactPage extends BasePage { class ContactForm extends StatefulWidget { ContactForm(this.contact); - final Contact contact; + final Contact? contact; @override State createState() => ContactFormState(); @@ -36,99 +33,24 @@ class ContactForm extends StatefulWidget { class ContactFormState extends State { final _formKey = GlobalKey(); final _contactNameController = TextEditingController(); - final _currencyTypeController = TextEditingController(); final _addressController = TextEditingController(); - CryptoCurrency _selectedCrypto = CryptoCurrency.oxen; - @override void initState() { super.initState(); - if (widget.contact == null) { - _currencyTypeController.text = _selectedCrypto.toString(); - } else { - _selectedCrypto = widget.contact.type; - _contactNameController.text = widget.contact.name; - _currencyTypeController.text = _selectedCrypto.toString(); - _addressController.text = widget.contact.address; + if (widget.contact != null) { + _contactNameController.text = widget.contact!.name; + _addressController.text = widget.contact!.address; } } @override void dispose() { _contactNameController.dispose(); - _currencyTypeController.dispose(); _addressController.dispose(); super.dispose(); } - Future _setCurrencyType(BuildContext context) async { - var currencyType = CryptoCurrency.all[0].toString(); - var selectedCurrency = CryptoCurrency.all[0]; - - await showDialog( - context: context, - builder: (BuildContext context) { - return OxenDialog( - body: Container( - padding: EdgeInsets.all(30), - child: Column( - children: [ - Padding( - padding: EdgeInsets.all(15), - child: Text(S.of(context).please_select, - textAlign: TextAlign.center, - style: TextStyle( - fontSize: 18, - decoration: TextDecoration.none, - color: Theme.of(context) - .primaryTextTheme - .caption - .color))), - Padding( - padding: EdgeInsets.only(top: 15, bottom: 30), - child: Container( - height: 150.0, - child: CupertinoPicker( - backgroundColor: Theme.of(context).backgroundColor, - itemExtent: 45.0, - onSelectedItemChanged: (int index) { - selectedCurrency = CryptoCurrency.all[index]; - currencyType = CryptoCurrency.all[index].toString(); - }, - children: List.generate(CryptoCurrency.all.length, - (int index) { - return Center( - child: Text( - CryptoCurrency.all[index].toString(), - style: TextStyle( - color: Theme.of(context) - .primaryTextTheme - .caption - .color), - ), - ); - })), - ), - ), - PrimaryButton( - text: S.of(context).ok, - color: - Theme.of(context).primaryTextTheme.button.backgroundColor, - borderColor: - Theme.of(context).primaryTextTheme.button.decorationColor, - onPressed: () { - _selectedCrypto = selectedCurrency; - _currencyTypeController.text = currencyType; - Navigator.of(context).pop(); - }, - ) - ], - ), - )); - }); - } - @override Widget build(BuildContext context) { final addressBookStore = Provider.of(context); @@ -140,31 +62,20 @@ class ContactFormState extends State { mainAxisSize: MainAxisSize.min, children: [ OxenTextField( - hintText: S.of(context).contact_name, + hintText: tr(context).contact_name, controller: _contactNameController, validator: (value) { - addressBookStore.validateContactName(value); + addressBookStore.validateContactName(value ?? '', tr(context)); return addressBookStore.errorMessage; }, ), SizedBox(height: 14.0), - Container( - child: InkWell( - onTap: () => _setCurrencyType(context), - child: IgnorePointer( - child: OxenTextField( - controller: _currencyTypeController, - ), - ), - ), - ), - SizedBox(height: 14.0), AddressTextField( controller: _addressController, options: [AddressTextFieldOption.qrCode], validator: (value) { - addressBookStore.validateAddress(value, - cryptoCurrency: _selectedCrypto); + addressBookStore.validateAddress(value ?? '', + l10n: tr(context)); return addressBookStore.errorMessage; }, ) @@ -177,40 +88,34 @@ class ContactFormState extends State { child: PrimaryButton( onPressed: () { setState(() { - _selectedCrypto = CryptoCurrency.xmr; _contactNameController.text = ''; - _currencyTypeController.text = _selectedCrypto.toString(); _addressController.text = ''; }); }, - text: S.of(context).reset, + text: tr(context).reset, color: - Theme.of(context).accentTextTheme.button.backgroundColor, + Theme.of(context).accentTextTheme.button?.backgroundColor, borderColor: - Theme.of(context).accentTextTheme.button.decorationColor), + Theme.of(context).accentTextTheme.button?.decorationColor), ), SizedBox(width: 20), Expanded( child: PrimaryButton( onPressed: () async { - if (!_formKey.currentState.validate()) return; + if (!(_formKey.currentState?.validate() ?? false)) return; try { if (widget.contact == null) { final newContact = Contact( name: _contactNameController.text, - address: _addressController.text, - type: _selectedCrypto); + address: _addressController.text); await addressBookStore.add(contact: newContact); } else { - widget.contact.name = _contactNameController.text; - widget.contact.address = _addressController.text; - widget.contact - .updateCryptoCurrency(currency: _selectedCrypto); + widget.contact!.name = _contactNameController.text; + widget.contact!.address = _addressController.text; - await addressBookStore.update( - contact: widget.contact); + await addressBookStore.update(contact: widget.contact!); } Navigator.pop(context); } catch (e) { @@ -226,21 +131,21 @@ class ContactFormState extends State { FlatButton( onPressed: () => Navigator.of(context).pop(), - child: Text(S.of(context).ok)) + child: Text(tr(context).ok)) ], ); }); } }, - text: S.of(context).save, + text: tr(context).save, color: Theme.of(context) .primaryTextTheme .button - .backgroundColor, + ?.backgroundColor, borderColor: Theme.of(context) .primaryTextTheme .button - .decorationColor)) + ?.decorationColor)) ], )); } diff --git a/lib/src/screens/auth/auth_page.dart b/lib/src/screens/auth/auth_page.dart index 877bdba0..2b8597f1 100644 --- a/lib/src/screens/auth/auth_page.dart +++ b/lib/src/screens/auth/auth_page.dart @@ -2,7 +2,7 @@ import 'package:mobx/mobx.dart'; import 'package:provider/provider.dart'; import 'package:flutter/material.dart'; import 'package:flutter/cupertino.dart'; -import 'package:oxen_wallet/generated/l10n.dart'; +import 'package:oxen_wallet/l10n.dart'; import 'package:oxen_wallet/src/stores/auth/auth_state.dart'; import 'package:oxen_wallet/src/stores/auth/auth_store.dart'; import 'package:oxen_wallet/src/screens/pin_code/pin_code.dart'; @@ -14,7 +14,7 @@ typedef OnAuthenticationFinished = void Function(bool, AuthPageState); class AuthPage extends StatefulWidget { AuthPage({this.onAuthenticationFinished, this.closable = true}); - final OnAuthenticationFinished onAuthenticationFinished; + final OnAuthenticationFinished? onAuthenticationFinished; final bool closable; @override @@ -25,12 +25,15 @@ class AuthPageState extends State { final _key = GlobalKey(); final _pinCodeKey = GlobalKey(); - void changeProcessText(String text) { - _key.currentState.showSnackBar( + void changeProcessText(BuildContext context, String text) { + ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text(text), backgroundColor: Colors.green)); } - void close() => Navigator.of(_key.currentContext).pop(); + void close() { + if (_key.currentContext != null) + Navigator.of(_key.currentContext!).pop(); + } @override Widget build(BuildContext context) { @@ -38,15 +41,15 @@ class AuthPageState extends State { final settingsStore = Provider.of(context); if (settingsStore.allowBiometricAuthentication) { - WidgetsBinding.instance.addPostFrameCallback((_) { + WidgetsBinding.instance?.addPostFrameCallback((_) { final biometricAuth = BiometricAuth(); - biometricAuth.isAuthenticated().then( + biometricAuth.isAuthenticated(tr(context)).then( (isAuth) { if (isAuth) { authStore.biometricAuth(); - _key.currentState.showSnackBar( + ScaffoldMessenger.of(context).showSnackBar( SnackBar( - content: Text(S.of(context).authenticated), + content: Text(tr(context).authenticated), backgroundColor: Colors.green, ), ); @@ -58,61 +61,46 @@ class AuthPageState extends State { reaction((_) => authStore.state, (AuthState state) { if (state is AuthenticatedSuccessfully) { - WidgetsBinding.instance.addPostFrameCallback((_) { + WidgetsBinding.instance?.addPostFrameCallback((_) { if (widget.onAuthenticationFinished != null) { - widget.onAuthenticationFinished(true, this); + widget.onAuthenticationFinished!(true, this); } else { - _key.currentState.showSnackBar( + ScaffoldMessenger.of(context).showSnackBar( SnackBar( - content: Text(S.of(context).authenticated), + content: Text(tr(context).authenticated), backgroundColor: Colors.green, ), ); } }); - } - - if (state is AuthenticationInProgress) { - WidgetsBinding.instance.addPostFrameCallback((_) { - _key.currentState.showSnackBar( + } else if (state is AuthenticationFailure) { + WidgetsBinding.instance?.addPostFrameCallback((_) { + _pinCodeKey.currentState?.clear(); + ScaffoldMessenger.of(context).hideCurrentSnackBar(); + ScaffoldMessenger.of(context).showSnackBar( SnackBar( - content: Text(S.of(context).authentication), - backgroundColor: Colors.green, - ), - ); - }); - } - - if (state is AuthenticationFailure) { - WidgetsBinding.instance.addPostFrameCallback((_) { - _pinCodeKey.currentState.clear(); - _key.currentState.hideCurrentSnackBar(); - _key.currentState.showSnackBar( - SnackBar( - content: Text(S.of(context).failed_authentication(state.error)), + content: Text(tr(context).failed_authentication(state.error)), backgroundColor: Colors.red, ), ); if (widget.onAuthenticationFinished != null) { - widget.onAuthenticationFinished(false, this); + widget.onAuthenticationFinished!(false, this); } }); - } - - if (state is AuthenticationBanned) { - WidgetsBinding.instance.addPostFrameCallback((_) { - _pinCodeKey.currentState.clear(); - _key.currentState.hideCurrentSnackBar(); - _key.currentState.showSnackBar( + } else if (state is AuthenticationBanned) { + WidgetsBinding.instance?.addPostFrameCallback((_) { + _pinCodeKey.currentState?.clear(); + ScaffoldMessenger.of(context).hideCurrentSnackBar(); + ScaffoldMessenger.of(context).showSnackBar( SnackBar( - content: Text(S.of(context).failed_authentication(state.error)), + content: Text(tr(context).failed_authentication(state.error)), backgroundColor: Colors.red, ), ); if (widget.onAuthenticationFinished != null) { - widget.onAuthenticationFinished(false, this); + widget.onAuthenticationFinished!(false, this); } }); } @@ -128,6 +116,7 @@ class AuthPageState extends State { resizeToAvoidBottomInset: false, body: PinCode( (pin, _) => authStore.auth( + l10n: tr(context), password: pin.fold('', (ac, val) => ac + '$val')), false, _pinCodeKey)); diff --git a/lib/src/screens/auth/create_login_page.dart b/lib/src/screens/auth/create_login_page.dart index daa7e527..f4677cc1 100644 --- a/lib/src/screens/auth/create_login_page.dart +++ b/lib/src/screens/auth/create_login_page.dart @@ -9,11 +9,11 @@ import 'package:provider/provider.dart'; import 'package:shared_preferences/shared_preferences.dart'; Widget createLoginPage( - {@required SharedPreferences sharedPreferences, - @required UserService userService, - @required WalletService walletService, - @required WalletListService walletListService, - @required AuthenticationStore authenticationStore}) => + {required SharedPreferences sharedPreferences, + required UserService userService, + required WalletService walletService, + required WalletListService walletListService, + required AuthenticationStore authenticationStore}) => Provider( create: (_) => AuthStore( sharedPreferences: sharedPreferences, diff --git a/lib/src/screens/auth/create_unlock_page.dart b/lib/src/screens/auth/create_unlock_page.dart index 0ffa0e86..2852fe18 100644 --- a/lib/src/screens/auth/create_unlock_page.dart +++ b/lib/src/screens/auth/create_unlock_page.dart @@ -7,10 +7,10 @@ import 'package:oxen_wallet/src/screens/auth/auth_page.dart'; import 'package:oxen_wallet/src/stores/auth/auth_store.dart'; Widget createUnlockPage( - {@required SharedPreferences sharedPreferences, - @required UserService userService, - @required WalletService walletService, - @required Function(bool, AuthPageState) onAuthenticationFinished}) => + {required SharedPreferences sharedPreferences, + required UserService userService, + required WalletService walletService, + required Function(bool, AuthPageState) onAuthenticationFinished}) => WillPopScope( onWillPop: () async => false, child: Provider( @@ -20,4 +20,4 @@ Widget createUnlockPage( walletService: walletService), child: AuthPage( onAuthenticationFinished: onAuthenticationFinished, - closable: false))); \ No newline at end of file + closable: false))); diff --git a/lib/src/screens/base_page.dart b/lib/src/screens/base_page.dart index 39962b62..01f9f090 100644 --- a/lib/src/screens/base_page.dart +++ b/lib/src/screens/base_page.dart @@ -4,11 +4,12 @@ import 'package:oxen_wallet/src/widgets/nav_bar.dart'; import 'package:provider/provider.dart'; import 'package:oxen_wallet/themes.dart'; import 'package:oxen_wallet/theme_changer.dart'; +import 'package:oxen_wallet/l10n.dart'; enum AppBarStyle { regular, withShadow } abstract class BasePage extends StatelessWidget { - String get title => null; + String? getTitle(AppLocalizations t) { return null; } bool get isModalBackButton => false; @@ -20,8 +21,8 @@ abstract class BasePage extends StatelessWidget { void onClose(BuildContext context) => Navigator.of(context).pop(); - Widget leading(BuildContext context) { - if (ModalRoute.of(context).isFirst) { + Widget? leading(BuildContext context) { + if (ModalRoute.of(context)?.isFirst ?? false) { return null; } @@ -43,7 +44,8 @@ abstract class BasePage extends StatelessWidget { ); } - Widget middle(BuildContext context) { + Widget? middle(BuildContext context) { + final title = getTitle(tr(context)); return title == null ? null : Text( @@ -51,13 +53,13 @@ abstract class BasePage extends StatelessWidget { style: TextStyle( fontSize: 16.0, fontWeight: FontWeight.w600, - color: Theme.of(context).primaryTextTheme.headline6.color), + color: Theme.of(context).primaryTextTheme.headline6?.color), ); } - Widget trailing(BuildContext context) => null; + Widget? trailing(BuildContext context) => null; - Widget floatingActionButton(BuildContext context) => null; + Widget? floatingActionButton(BuildContext context) => null; ObstructingPreferredSizeWidget appBar(BuildContext context) { final _themeChanger = Provider.of(context); @@ -98,7 +100,7 @@ abstract class BasePage extends StatelessWidget { Widget body(BuildContext context); - Widget bottomNavigationBar(BuildContext context) => null; + Widget? bottomNavigationBar(BuildContext context) => null; @override Widget build(BuildContext context) { diff --git a/lib/src/screens/changelog/changelog_page.dart b/lib/src/screens/changelog/changelog_page.dart index c0f1a3ff..02e89235 100644 --- a/lib/src/screens/changelog/changelog_page.dart +++ b/lib/src/screens/changelog/changelog_page.dart @@ -1,6 +1,6 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; -import 'package:oxen_wallet/generated/l10n.dart'; +import 'package:oxen_wallet/l10n.dart'; import 'package:oxen_wallet/src/screens/base_page.dart'; import 'package:yaml/yaml.dart'; @@ -8,7 +8,7 @@ class ChangelogPage extends BasePage { final String changelogPath = 'assets/changelog.yml'; @override - String get title => S.current.changelog; + String getTitle(AppLocalizations t) => t.changelog; @override Widget body(BuildContext context) { @@ -41,7 +41,7 @@ class ChangelogPage extends BasePage { }, separatorBuilder: (_, __) => Divider(color: Theme.of(context).dividerTheme.color, height: 1.0), - itemCount: changelogs == null ? 0 : changelogs.length, + itemCount: changelogs.length, ); }, future: rootBundle.loadString(changelogPath), diff --git a/lib/src/screens/dangerzone/dangerzone_page.dart b/lib/src/screens/dangerzone/dangerzone_page.dart index beadc1b5..8a1fbc4d 100644 --- a/lib/src/screens/dangerzone/dangerzone_page.dart +++ b/lib/src/screens/dangerzone/dangerzone_page.dart @@ -1,15 +1,14 @@ import 'dart:io'; -import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; -import 'package:oxen_wallet/generated/l10n.dart'; +import 'package:oxen_wallet/l10n.dart'; import 'package:oxen_wallet/palette.dart'; import 'package:oxen_wallet/routes.dart'; import 'package:oxen_wallet/src/screens/base_page.dart'; import 'package:oxen_wallet/src/widgets/primary_button.dart'; class DangerzonePage extends BasePage { - DangerzonePage({this.nextPage}); + DangerzonePage({required this.nextPage}); final String nextPage; @@ -20,8 +19,8 @@ class DangerzonePage extends BasePage { final textScaleFactor = _screenWidth < _baseWidth ? 0.76 : 1.0; final appStore = Platform.isAndroid ? 'Play Store' : 'AppStore'; final item = nextPage == Routes.dangerzoneSeed - ? S.of(context).seed_title - : S.of(context).keys_title; + ? tr(context).seed_title + : tr(context).keys_title; return Column(children: [ Expanded( @@ -36,7 +35,7 @@ class DangerzonePage extends BasePage { Padding( padding: EdgeInsets.all(10), child: Text( - S.of(context).dangerzone, + tr(context).dangerzone, style: TextStyle( fontSize: 30.0, fontWeight: FontWeight.bold, @@ -48,7 +47,7 @@ class DangerzonePage extends BasePage { Padding( padding: EdgeInsets.all(10), child: Text( - S.of(context).never_give_your(item), + tr(context).never_give_your(item), style: TextStyle( fontSize: 22.0, color: Palette.lightBlue, @@ -59,7 +58,7 @@ class DangerzonePage extends BasePage { Padding( padding: EdgeInsets.all(10), child: Text( - S.of(context).dangerzone_warning( + tr(context).dangerzone_warning( item, appStore ), style: TextStyle( @@ -77,10 +76,10 @@ class DangerzonePage extends BasePage { onPressed: () { Navigator.popAndPushNamed(context, nextPage); }, - text: S.of(context).yes_im_sure, - color: Theme.of(context).primaryTextTheme.button.backgroundColor, + text: tr(context).yes_im_sure, + color: Theme.of(context).primaryTextTheme.button?.backgroundColor, borderColor: - Theme.of(context).primaryTextTheme.button.decorationColor), + Theme.of(context).primaryTextTheme.button?.decorationColor), ) ]); } diff --git a/lib/src/screens/dangerzone/dangerzone_remove_wallet.dart b/lib/src/screens/dangerzone/dangerzone_remove_wallet.dart index 915cfcbe..2282351c 100644 --- a/lib/src/screens/dangerzone/dangerzone_remove_wallet.dart +++ b/lib/src/screens/dangerzone/dangerzone_remove_wallet.dart @@ -1,15 +1,11 @@ -import 'dart:io'; - -import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; -import 'package:oxen_wallet/generated/l10n.dart'; +import 'package:oxen_wallet/l10n.dart'; import 'package:oxen_wallet/palette.dart'; -import 'package:oxen_wallet/routes.dart'; import 'package:oxen_wallet/src/screens/base_page.dart'; import 'package:oxen_wallet/src/widgets/primary_button.dart'; class DangerzoneRemoveWalletPage extends BasePage { - DangerzoneRemoveWalletPage({this.onConfirmed}); + DangerzoneRemoveWalletPage({required this.onConfirmed}); final void Function() onConfirmed; @@ -32,7 +28,7 @@ class DangerzoneRemoveWalletPage extends BasePage { Padding( padding: EdgeInsets.all(10), child: Text( - S.of(context).dangerzone, + tr(context).dangerzone, style: TextStyle( fontSize: 30.0, fontWeight: FontWeight.bold, @@ -44,7 +40,7 @@ class DangerzoneRemoveWalletPage extends BasePage { Padding( padding: EdgeInsets.all(10), child: Text( - S.of(context).remove_wallet_confirmation, + tr(context).remove_wallet_confirmation, style: TextStyle( fontSize: 22.0, color: Palette.lightBlue, @@ -55,7 +51,7 @@ class DangerzoneRemoveWalletPage extends BasePage { Padding( padding: EdgeInsets.all(10), child: Text( - S.of(context).dangerzone_remove_wallet_warning, + tr(context).dangerzone_remove_wallet_warning, style: TextStyle( fontSize: 16.0, color: Palette.lightBlue, @@ -72,10 +68,9 @@ class DangerzoneRemoveWalletPage extends BasePage { onConfirmed(); Navigator.of(context).pop(); }, - text: S.of(context).yes_im_sure, - color: Theme.of(context).primaryTextTheme.button.backgroundColor, - borderColor: - Theme.of(context).primaryTextTheme.button.decorationColor), + text: tr(context).yes_im_sure, + color: Theme.of(context).primaryTextTheme.button?.backgroundColor, + borderColor: Theme.of(context).primaryTextTheme.button?.decorationColor), ) ]); } diff --git a/lib/src/screens/dashboard/create_dashboard_page.dart b/lib/src/screens/dashboard/create_dashboard_page.dart index b8c9ee81..29a21910 100644 --- a/lib/src/screens/dashboard/create_dashboard_page.dart +++ b/lib/src/screens/dashboard/create_dashboard_page.dart @@ -11,11 +11,11 @@ import 'package:oxen_wallet/src/stores/wallet/wallet_store.dart'; import 'package:provider/provider.dart'; Widget createDashboardPage( - {@required WalletService walletService, - @required PriceStore priceStore, - @required Box transactionDescriptions, - @required SettingsStore settingsStore, - @required WalletStore walletStore}) => + {required WalletService walletService, + required PriceStore priceStore, + required Box transactionDescriptions, + required SettingsStore settingsStore, + required WalletStore walletStore}) => Provider( create: (_) => ActionListStore( walletService: walletService, diff --git a/lib/src/screens/dashboard/dashboard_page.dart b/lib/src/screens/dashboard/dashboard_page.dart index 4e7828f2..83e6c567 100644 --- a/lib/src/screens/dashboard/dashboard_page.dart +++ b/lib/src/screens/dashboard/dashboard_page.dart @@ -1,8 +1,6 @@ -import 'package:date_range_picker/date_range_picker.dart' as date_rage_picker; -import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_mobx/flutter_mobx.dart'; -import 'package:oxen_wallet/generated/l10n.dart'; +import 'package:oxen_wallet/l10n.dart'; import 'package:oxen_wallet/palette.dart'; import 'package:oxen_wallet/routes.dart'; import 'package:oxen_wallet/src/domain/common/balance_display_mode.dart'; @@ -20,6 +18,7 @@ import 'package:oxen_wallet/src/stores/sync/sync_store.dart'; import 'package:oxen_wallet/src/stores/wallet/wallet_store.dart'; import 'package:oxen_wallet/src/widgets/picker.dart'; import 'package:provider/provider.dart'; +import 'package:intl/intl.dart'; class DashboardPage extends BasePage { final _bodyKey = GlobalKey(); @@ -32,7 +31,7 @@ class DashboardPage extends BasePage { padding: EdgeInsets.all(0), onPressed: () => _presentWalletMenu(context), child: Icon(Icons.sync_rounded, - color: Theme.of(context).primaryTextTheme.caption.color, + color: Theme.of(context).primaryTextTheme.caption?.color, size: 30))); } @@ -47,15 +46,17 @@ class DashboardPage extends BasePage { Text( walletStore.name, style: TextStyle( - color: Theme.of(context).primaryTextTheme.headline6.color), + color: Theme.of(context).primaryTextTheme.headline6?.color), + overflow: TextOverflow.ellipsis, ), SizedBox(height: 5), Text( - walletStore.account != null ? '${walletStore.account.label}' : '', + '${walletStore.account.label}', style: TextStyle( fontWeight: FontWeight.w400, fontSize: 10, - color: Theme.of(context).primaryTextTheme.headline6.color), + color: Theme.of(context).primaryTextTheme.headline6?.color), + overflow: TextOverflow.ellipsis, ), ]); }); @@ -69,7 +70,7 @@ class DashboardPage extends BasePage { padding: EdgeInsets.all(0), onPressed: () => Navigator.of(context).pushNamed(Routes.profile), child: Icon(Icons.account_circle_rounded, - color: Theme.of(context).primaryTextTheme.caption.color, + color: Theme.of(context).primaryTextTheme.caption?.color, size: 30)), ); } @@ -84,7 +85,7 @@ class DashboardPage extends BasePage { builder: (_) => Picker( items: walletMenu.items, selectedAtIndex: -1, - title: S.of(bodyContext).wallet_menu, + title: tr(bodyContext).wallet_menu, pickerHeight: 300, onItemSelected: (String item) => walletMenu.action(walletMenu.items.indexOf(item))), @@ -93,7 +94,7 @@ class DashboardPage extends BasePage { } class DashboardPageBody extends StatefulWidget { - DashboardPageBody({Key key}) : super(key: key); + DashboardPageBody({required Key key}) : super(key: key); @override DashboardPageBodyState createState() => DashboardPageBodyState(); @@ -113,13 +114,13 @@ class DashboardPageBodyState extends State { final actionListStore = Provider.of(context); final syncStore = Provider.of(context); final settingsStore = Provider.of(context); - final transactionDateFormat = settingsStore.getCurrentDateFormat( - formatUSA: 'MMMM d, yyyy, HH:mm', formatDefault: 'd MMMM yyyy, HH:mm'); + final t = tr(context); + final transactionDateFormat = DateFormat.yMMMMd(t.localeName).add_jm(); return Observer( key: _listObserverKey, builder: (_) { - final items = actionListStore.items ?? []; + final items = actionListStore.items; final itemsCount = items.length + 2; return ListView.builder( @@ -144,23 +145,18 @@ class DashboardPageBodyState extends State { key: _syncingObserverKey, builder: (_) { final status = syncStore.status; - final statusText = status.title(); + final statusText = status.title(t); final progress = syncStore.status.progress(); final isFailure = status is FailedSyncStatus; var descriptionText = ''; if (status is SyncingSyncStatus) { - descriptionText = S - .of(context) - .Blocks_remaining( - syncStore.status.toString()); + descriptionText = t.blocks_remaining(syncStore.status.toString()); } if (status is FailedSyncStatus) { - descriptionText = S - .of(context) - .please_try_to_connect_to_another_node; + descriptionText = t.please_try_to_connect_to_another_node; } return Container( @@ -209,15 +205,12 @@ class DashboardPageBodyState extends State { settingsStore.balanceDisplayMode; final displayMode = balanceStore .isReversing - ? (savedDisplayMode == - BalanceDisplayMode - .availableBalance + ? (savedDisplayMode == BalanceDisplayMode.availableBalance ? BalanceDisplayMode.fullBalance - : BalanceDisplayMode - .availableBalance) + : BalanceDisplayMode.availableBalance) : savedDisplayMode; - return Text(displayMode.toString(), + return Text(displayMode.getTitle(t), style: TextStyle( color: OxenPalette.teal, fontSize: 16)); @@ -228,29 +221,16 @@ class DashboardPageBodyState extends State { final savedDisplayMode = settingsStore.balanceDisplayMode; var balance = '---'; - final displayMode = balanceStore - .isReversing - ? (savedDisplayMode == - BalanceDisplayMode - .availableBalance + final displayMode = balanceStore.isReversing + ? (savedDisplayMode == BalanceDisplayMode.availableBalance ? BalanceDisplayMode.fullBalance - : BalanceDisplayMode - .availableBalance) + : BalanceDisplayMode.availableBalance) : savedDisplayMode; - if (displayMode == - BalanceDisplayMode.availableBalance) { - balance = balanceStore - .unlockedBalanceString ?? - '0.0'; - } - - if (displayMode == - BalanceDisplayMode.fullBalance) { - balance = - balanceStore.fullBalanceString ?? - '0.0'; - } + if (displayMode == BalanceDisplayMode.availableBalance) + balance = balanceStore.unlockedBalanceString; + else if (displayMode == BalanceDisplayMode.fullBalance) + balance = balanceStore.fullBalanceString; return Text( balance, @@ -258,7 +238,7 @@ class DashboardPageBodyState extends State { color: Theme.of(context) .primaryTextTheme .caption - .color, + ?.color, fontSize: 42), ); }), @@ -272,32 +252,20 @@ class DashboardPageBodyState extends State { final displayMode = settingsStore .enableFiatCurrency ? (balanceStore.isReversing - ? (savedDisplayMode == - BalanceDisplayMode - .availableBalance - ? BalanceDisplayMode - .fullBalance - : BalanceDisplayMode - .availableBalance) + ? (savedDisplayMode == BalanceDisplayMode.availableBalance + ? BalanceDisplayMode.fullBalance + : BalanceDisplayMode.availableBalance) : savedDisplayMode) - : BalanceDisplayMode - .hiddenBalance; - final symbol = settingsStore - .fiatCurrency - .toString(); + : BalanceDisplayMode.hiddenBalance; + final symbol = settingsStore.fiatCurrency.toString(); var balance = '---'; - if (displayMode == - BalanceDisplayMode - .availableBalance) { - balance = - '${balanceStore.fiatUnlockedBalance} $symbol'; + if (displayMode == BalanceDisplayMode.availableBalance) { + balance = '${balanceStore.fiatUnlockedBalance} $symbol'; } - if (displayMode == - BalanceDisplayMode.fullBalance) { - balance = - '${balanceStore.fiatFullBalance} $symbol'; + if (displayMode == BalanceDisplayMode.fullBalance) { + balance = '${balanceStore.fiatFullBalance} $symbol'; } return Text(balance, @@ -326,7 +294,7 @@ class DashboardPageBodyState extends State { rootNavigator: true) .pushNamed(Routes.send), ), - Text(S.of(context).send) + Text(t.send) ], ), Column( @@ -339,7 +307,7 @@ class DashboardPageBodyState extends State { rootNavigator: true) .pushNamed(Routes.receive), ), - Text(S.of(context).receive) + Text(t.receive) ], ) ], @@ -359,83 +327,74 @@ class DashboardPageBodyState extends State { PopupMenuButton( itemBuilder: (context) => [ PopupMenuItem( - enabled: false, - value: -1, - child: Text(S.of(context).transactions, - style: TextStyle( - fontWeight: FontWeight.bold, - color: Theme.of(context) - .primaryTextTheme - .caption - .color))), + enabled: false, + value: -1, + child: Text(t.transactions, + style: TextStyle( + fontWeight: FontWeight.bold, + color: Theme.of(context).primaryTextTheme.caption?.color + ) + ) + ), PopupMenuItem( - value: 0, - child: Observer( - builder: (_) => Row( - mainAxisAlignment: - MainAxisAlignment - .spaceBetween, - children: [ - Text(S.of(context).incoming), - Checkbox( - value: actionListStore - .transactionFilterStore - .displayIncoming, - onChanged: (value) => - actionListStore - .transactionFilterStore - .toggleIncoming(), - ) - ]))), + value: 0, + child: Observer( + builder: (_) => Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text(t.incoming), + Checkbox( + value: actionListStore.transactionFilterStore.displayIncoming, + onChanged: (value) => actionListStore.transactionFilterStore.toggleIncoming(), + ) + ] + ) + ) + ), PopupMenuItem( - value: 1, - child: Observer( - builder: (_) => Row( - mainAxisAlignment: - MainAxisAlignment - .spaceBetween, - children: [ - Text(S.of(context).outgoing), - Checkbox( - value: actionListStore - .transactionFilterStore - .displayOutgoing, - onChanged: (value) => - actionListStore - .transactionFilterStore - .toggleOutgoing(), - ) - ]))), + value: 1, + child: Observer( + builder: (_) => Row( + mainAxisAlignment:MainAxisAlignment.spaceBetween, + children: [ + Text(t.outgoing), + Checkbox( + value: actionListStore.transactionFilterStore.displayOutgoing, + onChanged: (value) => actionListStore.transactionFilterStore.toggleOutgoing(), + ) + ] + ) + ) + ), PopupMenuItem( - value: 2, - child: - Text(S.of(context).transactions_by_date)), + value: 2, + child: Text(t.transactions_by_date) + ), ], - child: Text(S.of(context).filters, - style: TextStyle( - fontSize: 16.0, - color: Theme.of(context) - .primaryTextTheme - .subtitle2 - .color)), + child: Text(t.filters, + style: TextStyle( + fontSize: 16.0, + color: Theme.of(context).primaryTextTheme.subtitle2?.color + ) + ), onSelected: (item) async { if (item == 2) { - final picked = - await date_rage_picker.showDatePicker( - context: context, - initialFirstDate: DateTime.now() - .subtract(Duration(days: 1)), - initialLastDate: (DateTime.now()), - firstDate: DateTime(2015), - lastDate: DateTime.now() - .add(Duration(days: 1))); - - if (picked != null && picked.length == 2) { - actionListStore.transactionFilterStore - .changeStartDate(picked.first); - actionListStore.transactionFilterStore - .changeEndDate(picked.last); - } + final picked = await showDateRangePicker( + context: context, + initialDateRange: DateTimeRange( + start: DateTime.now().subtract(Duration(days: 1)), + end: DateTime.now() + ), + firstDate: DateTime(2018), + lastDate: DateTime.now() + ); + + actionListStore.transactionFilterStore.changeStartDate(picked?.start); + // Add 1d to the end date because we want the picker returns the + // DateTime of the beginning of the end date, but we want to include + // everything on that date as well. + actionListStore.transactionFilterStore.changeEndDate( + picked == null ? null : picked.end.add(Duration(days: 1))); } }, ) @@ -476,7 +435,8 @@ class DashboardPageBodyState extends State { transactionDateFormat.format(transaction.date), formattedAmount: formattedAmount, formattedFiatAmount: formattedFiatAmount, - isPending: transaction.isPending); + isPending: transaction.isPending, + isStake: transaction.isStake); } return Container(); diff --git a/lib/src/screens/dashboard/date_section_row.dart b/lib/src/screens/dashboard/date_section_row.dart index dec5acd4..aa26ce30 100644 --- a/lib/src/screens/dashboard/date_section_row.dart +++ b/lib/src/screens/dashboard/date_section_row.dart @@ -1,38 +1,56 @@ import 'package:flutter/material.dart'; import 'package:intl/intl.dart'; -import 'package:oxen_wallet/generated/l10n.dart'; +import 'package:oxen_wallet/l10n.dart'; import 'package:oxen_wallet/palette.dart'; -import 'package:oxen_wallet/src/stores/settings/settings_store.dart'; -import 'package:provider/provider.dart'; + +extension RelativeDateHelpers on DateTime { + bool isToday([DateTime? now]) { + now ??= DateTime.now(); + return now.day == day && now.month == month && now.year == year; + } + + bool isYesterday([DateTime? now]) { + now ??= DateTime.now(); + return isToday(now.subtract(Duration(days: 1))); + } + + bool isPastWeek([DateTime? now]) { + now ??= DateTime.now(); + // diffDays gives us the integer days difference, but that is a pain because a value of 6 could + // be anywhere from 6.00 to 6.99 days ago, while the date 6 days before now will only partially + // overlap with that range, so we have to muck around a bit to deal with those edge cases. + final diffDays = difference(now).inDays; + if (diffDays >= -5 && diffDays <= -1) + return true; + if (diffDays == 0) // if diff is 0 then this is anywhere from -0.99 to 0.99: allow yesterday and today but not tomorrow + return isToday(now) || isYesterday(now); + if (diffDays == -6) // if -6 then allow the date that was 6 days ago but not the one that was 7 days ago + return isToday(now.subtract(Duration(days: 6))); + return false; + } +} class DateSectionRow extends StatelessWidget { - DateSectionRow({this.date}); + DateSectionRow({required this.date}); - static final nowDate = DateTime.now(); final DateTime date; @override Widget build(BuildContext context) { - final diffDays = date.difference(nowDate).inDays; - final isToday = nowDate.day == date.day && - nowDate.month == date.month && - nowDate.year == date.year; - final settingsStore = Provider.of(context); - final currentLanguage = settingsStore.languageCode; - final dateSectionDateFormat = settingsStore.getCurrentDateFormat( - formatUSA: 'MMM d', formatDefault: 'd MMM'); - var title = ''; - - if (isToday) { - title = S.of(context).today; - } else if (diffDays == 0) { - title = S.of(context).yesterday; - } else if (diffDays > -7 && diffDays < 0) { - final dateFormat = DateFormat.EEEE(currentLanguage); - title = dateFormat.format(date); - } else { - title = dateSectionDateFormat.format(date); - } + final t = tr(context); + + String title; + if (date.isToday()) + title = t.today; + else if (date.isYesterday()) + title = t.yesterday; + else if (date.isPastWeek()) + title = DateFormat.EEEE(t.localeName).format(date); + else if (date.isAfter(DateTime.now().subtract(Duration(days: 304)))) + // If within (approximately) the last 10 months then don't include the year + title = DateFormat.MMMd(t.localeName).format(date); + else + title = DateFormat.yMMMd(t.localeName).format(date); return Padding( padding: const EdgeInsets.only(top: 10, bottom: 10), diff --git a/lib/src/screens/dashboard/transaction_row.dart b/lib/src/screens/dashboard/transaction_row.dart index 9188dd6d..47f33b0c 100644 --- a/lib/src/screens/dashboard/transaction_row.dart +++ b/lib/src/screens/dashboard/transaction_row.dart @@ -1,16 +1,17 @@ import 'package:flutter/material.dart'; -import 'package:oxen_wallet/generated/l10n.dart'; +import 'package:oxen_wallet/l10n.dart'; import 'package:oxen_wallet/palette.dart'; import 'package:oxen_wallet/src/wallet/transaction/transaction_direction.dart'; class TransactionRow extends StatelessWidget { TransactionRow( - {this.direction, - this.formattedDate, - this.formattedAmount, - this.formattedFiatAmount, - this.isPending, - @required this.onTap}); + {required this.direction, + required this.formattedDate, + required this.formattedAmount, + required this.formattedFiatAmount, + required this.isPending, + required this.isStake, + required this.onTap}); final VoidCallback onTap; final TransactionDirection direction; @@ -18,6 +19,7 @@ class TransactionRow extends StatelessWidget { final String formattedAmount; final String formattedFiatAmount; final bool isPending; + final bool isStake; @override Widget build(BuildContext context) { @@ -35,19 +37,23 @@ class TransactionRow extends StatelessWidget { Container( height: 27, width: 27, + decoration: BoxDecoration( + color: direction == TransactionDirection.incoming + ? OxenPalette.limeWithOpacity + : isStake + ? OxenPalette.navyWithOpacity + : OxenPalette.lightRedWithOpacity, + shape: BoxShape.circle, + ), child: Icon( direction == TransactionDirection.incoming ? Icons.arrow_downward_rounded : Icons.arrow_upward_rounded, color: direction == TransactionDirection.incoming ? OxenPalette.lime - : OxenPalette.lightRed, - ), - decoration: BoxDecoration( - color: direction == TransactionDirection.incoming - ? OxenPalette.limeWithOpacity - : OxenPalette.lightRedWithOpacity, - shape: BoxShape.circle, + : isStake + ? OxenPalette.teal + : OxenPalette.lightRed, ), ), Expanded( @@ -60,15 +66,17 @@ class TransactionRow extends StatelessWidget { children: [ Text( (direction == TransactionDirection.incoming - ? S.of(context).received - : S.of(context).sent) + - (isPending ? S.of(context).pending : ''), + ? tr(context).received + : isStake + ? tr(context).stake + : tr(context).sent) + + (isPending ? tr(context).pending : ''), style: TextStyle( fontSize: 16, color: Theme.of(context) .primaryTextTheme .subtitle1 - .color)), + ?.color)), Text(formattedAmount, style: const TextStyle( fontSize: 16, color: Palette.purpleBlue)) diff --git a/lib/src/screens/dashboard/wallet_menu.dart b/lib/src/screens/dashboard/wallet_menu.dart index 8138e3bb..50ca78d0 100644 --- a/lib/src/screens/dashboard/wallet_menu.dart +++ b/lib/src/screens/dashboard/wallet_menu.dart @@ -1,5 +1,5 @@ import 'package:flutter/material.dart'; -import 'package:oxen_wallet/generated/l10n.dart'; +import 'package:oxen_wallet/l10n.dart'; import 'package:oxen_wallet/routes.dart'; import 'package:oxen_wallet/src/stores/balance/balance_store.dart'; import 'package:oxen_wallet/src/stores/wallet/wallet_store.dart'; @@ -7,13 +7,14 @@ import 'package:oxen_wallet/src/widgets/oxen_dialog.dart'; import 'package:provider/provider.dart'; class WalletMenu { - WalletMenu(this.context); + WalletMenu(this.context) + : items = [ + tr(context).reconnect, + tr(context).rescan, + tr(context).reload_fiat + ]; - final List items = [ - S.current.reconnect, - S.current.rescan, - S.current.reload_fiat - ]; + final List items; final BuildContext context; @@ -35,7 +36,7 @@ class WalletMenu { final walletStore = context.read(); await showSimpleOxenDialog( - context, S.of(context).reconnection, S.of(context).reconnect_alert_text, + context, tr(context).reconnection, tr(context).reconnect_alert_text, onPressed: (context) { walletStore.reconnect(); Navigator.of(context).pop(); diff --git a/lib/src/screens/disclaimer/disclaimer_page.dart b/lib/src/screens/disclaimer/disclaimer_page.dart index 2c570904..78de7ee7 100644 --- a/lib/src/screens/disclaimer/disclaimer_page.dart +++ b/lib/src/screens/disclaimer/disclaimer_page.dart @@ -1,7 +1,7 @@ import 'dart:ui'; import 'package:flutter/material.dart'; -import 'package:flutter/cupertino.dart'; import 'package:flutter/services.dart'; +import 'package:oxen_wallet/l10n.dart'; import 'package:oxen_wallet/palette.dart'; import 'package:url_launcher/url_launcher.dart'; import 'package:oxen_wallet/src/screens/base_page.dart'; @@ -16,7 +16,7 @@ class DisclaimerPage extends BasePage { bool get isModalBackButton => false; @override - String get title => 'Terms of Use'; + String getTitle(AppLocalizations t) => t.settings_terms_and_conditions; @override Widget body(BuildContext context) => DisclaimerPageBody(isReadOnly: true); @@ -77,7 +77,7 @@ class DisclaimerBodyState extends State { void initState() { super.initState(); getFileLines(); - if (_isAccepted) WidgetsBinding.instance.addPostFrameCallback(_afterLayout); + if (_isAccepted) WidgetsBinding.instance?.addPostFrameCallback(_afterLayout); } @override @@ -222,16 +222,16 @@ class DisclaimerBodyState extends State { padding: EdgeInsets.only(left: 25.0, right: 25.0, bottom: 25.0), child: PrimaryButton( - onPressed: _checked ? () {} : null, + onPressed: () {}, text: 'Accept', color: Theme.of(context) .primaryTextTheme .button - .backgroundColor, + ?.backgroundColor, borderColor: Theme.of(context) .primaryTextTheme .button - .decorationColor, + ?.decorationColor, ), ) : Offstage(), diff --git a/lib/src/screens/faq/faq_page.dart b/lib/src/screens/faq/faq_page.dart index a95c1d6c..ad670da9 100644 --- a/lib/src/screens/faq/faq_page.dart +++ b/lib/src/screens/faq/faq_page.dart @@ -1,25 +1,25 @@ import 'dart:convert'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; -import 'package:provider/provider.dart'; -import 'package:oxen_wallet/generated/l10n.dart'; -import 'package:oxen_wallet/src/stores/settings/settings_store.dart'; +import 'package:oxen_wallet/l10n.dart'; import 'package:oxen_wallet/src/screens/base_page.dart'; class FaqPage extends BasePage { @override - String get title => S.current.faq; + String getTitle(AppLocalizations t) => t.faq; @override Widget body(BuildContext context) { return FutureBuilder( builder: (context, snapshot) { + if (!snapshot.hasData) + return SizedBox.shrink(); final faqItems = jsonDecode(snapshot.data.toString()) as List; return ListView.separated( itemBuilder: (BuildContext context, int index) { final itemTitle = faqItems[index]['question'].toString(); - final itemChild = faqItems[index]['answer'].toString(); + final itemChild = faqItems[index]['answer'].toString() + '\n'; return ExpansionTile( title: Text(itemTitle), @@ -41,7 +41,7 @@ class FaqPage extends BasePage { }, separatorBuilder: (_, __) => Divider(color: Theme.of(context).dividerTheme.color, height: 1.0), - itemCount: faqItems == null ? 0 : faqItems.length, + itemCount: faqItems.length, ); }, future: rootBundle.loadString(getFaqPath(context)), @@ -49,13 +49,10 @@ class FaqPage extends BasePage { } String getFaqPath(BuildContext context) { - final settingsStore = context.read(); - - switch (settingsStore.languageCode) { - case 'en': - return 'assets/faq/faq_en.json'; + switch (tr(context).localeName) { case 'de': return 'assets/faq/faq_de.json'; + case 'en': default: return 'assets/faq/faq_en.json'; } diff --git a/lib/src/screens/new_wallet/new_wallet_page.dart b/lib/src/screens/new_wallet/new_wallet_page.dart index 8fa3ff78..bc67fae4 100644 --- a/lib/src/screens/new_wallet/new_wallet_page.dart +++ b/lib/src/screens/new_wallet/new_wallet_page.dart @@ -3,8 +3,7 @@ import 'package:provider/provider.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:flutter_mobx/flutter_mobx.dart'; import 'package:flutter/material.dart'; -import 'package:flutter/cupertino.dart'; -import 'package:oxen_wallet/generated/l10n.dart'; +import 'package:oxen_wallet/l10n.dart'; import 'package:oxen_wallet/src/stores/wallet_creation/wallet_creation_store.dart'; import 'package:oxen_wallet/src/stores/wallet_creation/wallet_creation_state.dart'; import 'package:oxen_wallet/src/domain/services/wallet_list_service.dart'; @@ -19,16 +18,16 @@ import 'package:oxen_wallet/src/util/generate_name.dart'; class NewWalletPage extends BasePage { NewWalletPage( - {@required this.walletsService, - @required this.walletService, - @required this.sharedPreferences}); + {required this.walletsService, + required this.walletService, + required this.sharedPreferences}); final WalletListService walletsService; final WalletService walletService; final SharedPreferences sharedPreferences; @override - String get title => S.current.new_wallet; + String getTitle(AppLocalizations t) => t.new_wallet; @override Widget body(BuildContext context) => WalletNameForm(); @@ -64,7 +63,7 @@ class _WalletNameFormState extends State { } if (state is WalletCreationFailure) { - WidgetsBinding.instance.addPostFrameCallback((_) { + WidgetsBinding.instance?.addPostFrameCallback((_) { showDialog( context: context, builder: (BuildContext context) { @@ -72,7 +71,7 @@ class _WalletNameFormState extends State { content: Text(state.error), actions: [ FlatButton( - child: Text(S.of(context).ok), + child: Text(tr(context).ok), onPressed: () => Navigator.of(context).pop(), ), ], @@ -96,12 +95,12 @@ class _WalletNameFormState extends State { child: TextFormField( style: TextStyle( fontSize: 24.0, - color: Theme.of(context).accentTextTheme.subtitle2.color), + color: Theme.of(context).accentTextTheme.subtitle2?.color), controller: nameController, decoration: InputDecoration( hintStyle: TextStyle( fontSize: 24.0, color: Theme.of(context).hintColor), - hintText: S.of(context).wallet_name, + hintText: tr(context).wallet_name, focusedBorder: UnderlineInputBorder( borderSide: BorderSide(color: OxenPalette.teal, width: 2.0)), @@ -110,14 +109,14 @@ class _WalletNameFormState extends State { color: Theme.of(context).focusColor, width: 1.0))), validator: (value) { - walletCreationStore.validateWalletName(value); + walletCreationStore.validateWalletName(value ?? '', tr(context)); return walletCreationStore.errorMessage; }, )), ), Padding(padding: EdgeInsets.only(bottom: 20), child: Text( - S.of(context).seed_language_choose, + tr(context).seed_language_choose, textAlign: TextAlign.center, style: TextStyle(fontSize: 16.0), ), @@ -130,15 +129,15 @@ class _WalletNameFormState extends State { builder: (context) { return LoadingPrimaryButton( onPressed: () { - if (_formKey.currentState.validate()) { + if (_formKey.currentState?.validate() ?? false) { walletCreationStore.create(name: nameController.text, language: seedLanguageStore.selectedSeedLanguage); } }, - text: S.of(context).continue_text, - color: Theme.of(context).primaryTextTheme.button.backgroundColor, + text: tr(context).continue_text, + color: Theme.of(context).primaryTextTheme.button?.backgroundColor, borderColor: - Theme.of(context).primaryTextTheme.button.decorationColor, + Theme.of(context).primaryTextTheme.button?.decorationColor, isLoading: walletCreationStore.state is WalletIsCreating, ); }, diff --git a/lib/src/screens/nodes/new_node_page.dart b/lib/src/screens/nodes/new_node_page.dart index 8b72bd2d..13ec42ef 100644 --- a/lib/src/screens/nodes/new_node_page.dart +++ b/lib/src/screens/nodes/new_node_page.dart @@ -1,6 +1,5 @@ -import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; -import 'package:oxen_wallet/generated/l10n.dart'; +import 'package:oxen_wallet/l10n.dart'; import 'package:oxen_wallet/src/screens/base_page.dart'; import 'package:oxen_wallet/src/stores/node_list/node_list_store.dart'; import 'package:oxen_wallet/src/widgets/oxen_text_field.dart'; @@ -10,7 +9,7 @@ import 'package:provider/provider.dart'; class NewNodePage extends BasePage { @override - String get title => S.current.node_new; + String getTitle(AppLocalizations t) => t.node_new; @override Widget body(BuildContext context) => NewNodePageForm(); @@ -51,39 +50,42 @@ class NewNodeFormState extends State { child: Column( children: [ OxenTextField( - hintText: S.of(context).node_address, + hintText: tr(context).node_address, controller: _nodeAddressController, validator: (value) { - nodeList.validateNodeAddress(value); + nodeList.validateNodeAddress(value ?? '', tr(context)); return nodeList.errorMessage; }, ), Padding( padding: EdgeInsets.only(top: 20), child: OxenTextField( - hintText: S.of(context).node_port, + hintText: tr(context).node_port, controller: _nodePortController, keyboardType: TextInputType.numberWithOptions( signed: false, decimal: false), validator: (value) { - nodeList.validateNodePort(value); + nodeList.validateNodePort(value ?? '', tr(context)); return nodeList.errorMessage; }, )), + // Disable login/password fields for now: oxend currently doesn't support + // Digest MD5 auth (because it is deprecated and insecure), and the wallet2 + // code *only* supports Digest MD5 auth. + /* Padding( padding: EdgeInsets.only(top: 20), child: OxenTextField( - hintText: S.of(context).login, + hintText: tr(context).login, controller: _loginController, - validator: (value) => null, )), Padding( padding: EdgeInsets.only(top: 20), child: OxenTextField( - hintText: S.of(context).password, + hintText: tr(context).password, controller: _passwordController, - validator: (value) => null, )), + */ ], ))), bottomSection: Container( @@ -99,18 +101,18 @@ class NewNodeFormState extends State { _loginController.text = ''; _passwordController.text = ''; }, - text: S.of(context).reset, + text: tr(context).reset, color: - Theme.of(context).accentTextTheme.button.backgroundColor, + Theme.of(context).accentTextTheme.button?.backgroundColor, borderColor: - Theme.of(context).accentTextTheme.button.decorationColor), + Theme.of(context).accentTextTheme.button?.decorationColor), )), Flexible( child: Container( padding: EdgeInsets.only(left: 8.0), child: PrimaryButton( onPressed: () async { - if (!_formKey.currentState.validate()) { + if (!(_formKey.currentState?.validate() ?? false)) { return; } @@ -122,11 +124,11 @@ class NewNodeFormState extends State { Navigator.of(context).pop(); }, - text: S.of(context).save, + text: tr(context).save, color: - Theme.of(context).primaryTextTheme.button.backgroundColor, + Theme.of(context).primaryTextTheme.button?.backgroundColor, borderColor: - Theme.of(context).primaryTextTheme.button.decorationColor, + Theme.of(context).primaryTextTheme.button?.decorationColor, ), )), ], diff --git a/lib/src/screens/nodes/nodes_list_page.dart b/lib/src/screens/nodes/nodes_list_page.dart index d64b9cfc..5dbadf2e 100644 --- a/lib/src/screens/nodes/nodes_list_page.dart +++ b/lib/src/screens/nodes/nodes_list_page.dart @@ -1,7 +1,7 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_mobx/flutter_mobx.dart'; -import 'package:oxen_wallet/generated/l10n.dart'; +import 'package:oxen_wallet/l10n.dart'; import 'package:oxen_wallet/palette.dart'; import 'package:oxen_wallet/routes.dart'; import 'package:oxen_wallet/src/screens/base_page.dart'; @@ -15,7 +15,7 @@ class NodeListPage extends BasePage { NodeListPage(); @override - String get title => S.current.nodes; + String getTitle(AppLocalizations t) => t.nodes; @override Widget trailing(context) { @@ -31,8 +31,8 @@ class NodeListPage extends BasePage { onPressed: () async { await showConfirmOxenDialog( context, - S.of(context).node_reset_settings_title, - S.of(context).nodes_list_reset_to_default_message, + tr(context).node_reset_settings_title, + tr(context).nodes_list_reset_to_default_message, onFutureConfirm: (context) async { Navigator.pop(context); await nodeList.reset(); @@ -41,10 +41,10 @@ class NodeListPage extends BasePage { }); }, child: Text( - S.of(context).reset, + tr(context).reset, style: TextStyle( fontSize: 16.0, - color: Theme.of(context).primaryTextTheme.subtitle2.color), + color: Theme.of(context).primaryTextTheme.subtitle2?.color), )), ), Container( @@ -105,7 +105,7 @@ class NodeListPageBodyState extends State { return Observer(builder: (_) { final isCurrent = settings.node == null ? false - : node.key == settings.node.key; + : node.key == settings.node!.key; final content = Container( color: isCurrent ? currentColor : notCurrentColor, @@ -117,7 +117,7 @@ class NodeListPageBodyState extends State { color: Theme.of(context) .primaryTextTheme .headline6 - .color), + ?.color), ), trailing: FutureBuilder( future: nodeList.isNodeOnline(node), @@ -133,7 +133,7 @@ class NodeListPageBodyState extends State { onTap: () async { if (!isCurrent) { await showSimpleOxenDialog(context, '', - S.of(context).change_current_node(node.uri), + tr(context).change_current_node(node.uri), onPressed: (context) async { Navigator.of(context).pop(); await settings.setCurrentNode(node: node); @@ -150,14 +150,13 @@ class NodeListPageBodyState extends State { var result = false; await showConfirmOxenDialog( context, - S.of(context).remove_node, - S.of(context).remove_node_message, + tr(context).remove_node, + tr(context).remove_node_message, onDismiss: (context) => Navigator.pop(context, false), onConfirm: (context) { result = true; Navigator.pop(context, true); - return true; }); return result; }, @@ -177,7 +176,7 @@ class NodeListPageBodyState extends State { color: Colors.white, ), Text( - S.of(context).delete, + tr(context).delete, style: TextStyle(color: Colors.white), ) ], diff --git a/lib/src/screens/oxen_amount.dart b/lib/src/screens/oxen_amount.dart new file mode 100644 index 00000000..408918c5 --- /dev/null +++ b/lib/src/screens/oxen_amount.dart @@ -0,0 +1,61 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:oxen_wallet/l10n.dart'; +import 'package:oxen_wallet/palette.dart'; + +Widget oxenAmountField({ + required GestureTapCallback setAll, + required TextEditingController controller, + required BuildContext context, + FormFieldValidator? validator, +}) { + + final theme = Theme.of(context); + + return Padding( + padding: const EdgeInsets.only(top: 20), + child: TextFormField( + style: TextStyle( + fontSize: 18.0, + color: theme.accentTextTheme.overline?.color), + controller: controller, + keyboardType: TextInputType.numberWithOptions(signed: false, decimal: true), + inputFormatters: [ + FilteringTextInputFormatter.deny(RegExp('[- ]')) + ], + validator: validator, + decoration: InputDecoration( + prefixIcon: SizedBox( + width: 75, + child: Padding( + padding: EdgeInsets.only(left: 8, top: 12), + child: Text( + 'OXEN:', + style: TextStyle(fontSize: 18, color: theme.accentTextTheme.overline?.color) + ) + ), + ), + suffixIcon: Container( + width: 1, + padding: EdgeInsets.only(top: 0), + child: Center( + child: InkWell( + onTap: setAll, + child: Text( + tr(context).all, + style: TextStyle(fontSize: 14, color: theme.accentTextTheme.overline?.decorationColor) + ) + ) + ), + ), + hintStyle: TextStyle(fontSize: 18.0, color: theme.hintColor), + hintText: '0.0000', + focusedBorder: OutlineInputBorder(borderSide: BorderSide(color: OxenPalette.teal, width: 2.0)), + enabledBorder: OutlineInputBorder(borderSide: BorderSide(color: theme.focusColor, width: 1.0)), + errorBorder: OutlineInputBorder(borderSide: BorderSide(color: OxenPalette.red, width: 1.0)), + focusedErrorBorder: OutlineInputBorder(borderSide: BorderSide(color: OxenPalette.red, width: 1.0)), + errorStyle: TextStyle(color: OxenPalette.red) + ), + ), + ); +} diff --git a/lib/src/screens/pin_code/pin_code.dart b/lib/src/screens/pin_code/pin_code.dart index afe11ea7..109a071f 100644 --- a/lib/src/screens/pin_code/pin_code.dart +++ b/lib/src/screens/pin_code/pin_code.dart @@ -1,15 +1,14 @@ import 'package:provider/provider.dart'; import 'package:flutter/material.dart'; -import 'package:flutter/cupertino.dart'; import 'package:oxen_wallet/palette.dart'; import 'package:oxen_wallet/src/stores/settings/settings_store.dart'; -import 'package:oxen_wallet/generated/l10n.dart'; +import 'package:oxen_wallet/l10n.dart'; abstract class PinCodeWidget extends StatefulWidget { - PinCodeWidget({Key key, this.onPinCodeEntered, this.hasLengthSwitcher}) + PinCodeWidget({Key? key, this.onPinCodeEntered, required this.hasLengthSwitcher}) : super(key: key); - final Function(List pin, PinCodeState state) onPinCodeEntered; + final Function(List pin, PinCodeState state)? onPinCodeEntered; final bool hasLengthSwitcher; } @@ -27,29 +26,24 @@ class PinCode extends PinCodeWidget { class PinCodeState extends State { static const defaultPinLength = 4; - static const sixPinLength = 6; - static const fourPinLength = 4; static final deleteIcon = Icon(Icons.backspace, color: Palette.blueGrey); final _gridViewKey = GlobalKey(); int pinLength = defaultPinLength; - List pin = List.filled(defaultPinLength, null); - String title = S.current.enter_your_pin; + List pin = []; + String title = ''; double _aspectRatio = 0; void setTitle(String title) => setState(() => this.title = title); - void clear() => setState(() => pin = List.filled(pinLength, null)); + void clear() => setState(() => pin.clear()); - void onPinCodeEntered(PinCodeState state) => - widget.onPinCodeEntered(state.pin, this); + void onPinCodeEntered(PinCodeState state) => widget.onPinCodeEntered?.call(state.pin, this); void changePinLength(int length) { - final newPin = List.filled(length, null); - setState(() { pinLength = length; - pin = newPin; + pin.clear(); }); } @@ -61,8 +55,12 @@ class PinCodeState extends State { } void calculateAspectRatio() { + if (_gridViewKey.currentContext == null) { + _aspectRatio = 0; + return; + } final renderBox = - _gridViewKey.currentContext.findRenderObject() as RenderBox; + _gridViewKey.currentContext!.findRenderObject() as RenderBox; final cellWidth = renderBox.size.width / 3; final cellHeight = renderBox.size.height / 4; @@ -76,7 +74,7 @@ class PinCodeState extends State { @override void initState() { super.initState(); - WidgetsBinding.instance.addPostFrameCallback(afterLayout); + WidgetsBinding.instance?.addPostFrameCallback(afterLayout); } void afterLayout(dynamic _) { @@ -94,7 +92,7 @@ class PinCodeState extends State { padding: EdgeInsets.only(left: 40.0, right: 40.0, bottom: 40.0), child: Column(children: [ Spacer(flex: 2), - Text(title, + Text(title.isNotEmpty ? title : tr(context).enter_your_pin, style: TextStyle(fontSize: 24, color: Palette.wildDarkBlue)), Spacer(flex: 3), Container( @@ -103,7 +101,7 @@ class PinCodeState extends State { mainAxisAlignment: MainAxisAlignment.spaceBetween, children: List.generate(pinLength, (index) { const size = 10.0; - final isFilled = pin[index] != null; + final isFilled = index < pin.length; return Container( width: size, @@ -120,12 +118,10 @@ class PinCodeState extends State { if (widget.hasLengthSwitcher) ...[ FlatButton( onPressed: () { - changePinLength(pinLength == PinCodeState.fourPinLength - ? PinCodeState.sixPinLength - : PinCodeState.fourPinLength); + changePinLength(pinLength == 4 ? 6 : 4); }, child: Text( - _changePinLengthText(), + _changePinLengthText(tr(context)), style: TextStyle(fontSize: 16.0, color: Palette.wildDarkBlue), )) ], @@ -190,52 +186,24 @@ class PinCodeState extends State { } void _push(int num) { - if (currentPinLength() >= pinLength) { + if (pin.length >= pinLength) return; - } - for (var i = 0; i < pin.length; i++) { - if (pin[i] == null) { - setState(() => pin[i] = num); - break; - } - } - - final _currentPinLength = currentPinLength(); + setState(() => pin.add(num)); - if (_currentPinLength == pinLength) { + // ignore: invariant_booleans + if (pin.length == pinLength) onPinCodeEntered(this); - } } void _pop() { - if (currentPinLength() == 0) { + if (pin.isEmpty) return; - } - - for (var i = pin.length - 1; i >= 0; i--) { - if (pin[i] != null) { - setState(() => pin[i] = null); - break; - } - } - } - - int currentPinLength() { - return pin.fold(0, (v, e) { - if (e != null) { - return v + 1; - } - return v; - }); + pin.removeLast(); } - String _changePinLengthText() { - return S.current.use + - (pinLength == PinCodeState.fourPinLength - ? '${PinCodeState.sixPinLength}' - : '${PinCodeState.fourPinLength}') + - S.current.digit_pin; + String _changePinLengthText(AppLocalizations l10n) { + return l10n.use_n_digit_pin(pinLength == 4 ? '6' : '4'); } } diff --git a/lib/src/screens/profile/profile_page.dart b/lib/src/screens/profile/profile_page.dart index 7edbad99..61ddc01b 100644 --- a/lib/src/screens/profile/profile_page.dart +++ b/lib/src/screens/profile/profile_page.dart @@ -1,6 +1,5 @@ -import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; -import 'package:oxen_wallet/generated/l10n.dart'; +import 'package:oxen_wallet/l10n.dart'; import 'package:oxen_wallet/routes.dart'; import 'package:oxen_wallet/src/screens/base_page.dart'; import 'package:oxen_wallet/src/screens/auth/auth_page.dart'; @@ -18,7 +17,7 @@ class ProfilePage extends BasePage { padding: EdgeInsets.all(0), onPressed: () => Navigator.of(context).pushNamed(Routes.settings), child: Icon(Icons.settings_rounded, - color: Theme.of(context).primaryTextTheme.caption.color, + color: Theme.of(context).primaryTextTheme.caption?.color, size: 25)), ); } @@ -28,7 +27,7 @@ class ProfilePage extends BasePage { } class ProfilePageBody extends StatefulWidget { - ProfilePageBody({Key key}) : super(key: key); + ProfilePageBody({required Key key}) : super(key: key); @override ProfilePageBodyState createState() => ProfilePageBodyState(); @@ -37,6 +36,7 @@ class ProfilePageBody extends StatefulWidget { class ProfilePageBodyState extends State { @override Widget build(BuildContext context) { + final t = tr(context); return SingleChildScrollView( child: Column( children: [ @@ -46,40 +46,40 @@ class ProfilePageBodyState extends State { children: [ NavListArrow( leading: Icon(Icons.account_balance_wallet_rounded, - color: Theme.of(context).primaryTextTheme.headline6.color), - text: S.current.wallets, + color: Theme.of(context).primaryTextTheme.headline6?.color), + text: t.wallets, onTap: () => Navigator.of(context).pushNamed(Routes.walletList)), NavListArrow( leading: Icon(Icons.settings_rounded, - color: Theme.of(context).primaryTextTheme.headline6.color), - text: S.current.settings_title, + color: Theme.of(context).primaryTextTheme.headline6?.color), + text: t.settings_title, onTap: () => Navigator.of(context).pushNamed(Routes.settings)), - NavListHeader(title: S.current.wallet_menu), + NavListHeader(title: t.wallet_menu), NavListArrow( leading: Icon(Icons.attach_money_rounded, - color: Theme.of(context).primaryTextTheme.headline6.color), - text: S.current.title_stakes, + color: Theme.of(context).primaryTextTheme.headline6?.color), + text: t.title_stakes, onTap: () => Navigator.of(context).pushNamed(Routes.stake)), NavListArrow( leading: Icon(Icons.contacts_rounded, - color: Theme.of(context).primaryTextTheme.headline6.color), - text: S.current.address_book_menu, + color: Theme.of(context).primaryTextTheme.headline6?.color), + text: t.address_book_menu, onTap: () => Navigator.of(context).pushNamed(Routes.addressBook)), NavListArrow( leading: Icon(Icons.account_circle_rounded, - color: Theme.of(context).primaryTextTheme.headline6.color), - text: S.current.accounts, + color: Theme.of(context).primaryTextTheme.headline6?.color), + text: t.accounts, onTap: () => Navigator.of(context).pushNamed(Routes.accountList)), - NavListHeader(title: S.current.dangerzone), + NavListHeader(title: t.dangerzone), NavListArrow( leading: Icon(Icons.vpn_key_rounded, - color: Theme.of(context).primaryTextTheme.headline6.color), - text: S.current.show_keys, + color: Theme.of(context).primaryTextTheme.headline6?.color), + text: t.show_keys, onTap: () => Navigator.of(context).pushNamed(Routes.auth, arguments: (bool isAuthenticatedSuccessfully, AuthPageState auth) => @@ -89,8 +89,8 @@ class ProfilePageBodyState extends State { : null)), NavListArrow( leading: Icon(Icons.vpn_key_rounded, - color: Theme.of(context).primaryTextTheme.headline6.color), - text: S.current.show_seed, + color: Theme.of(context).primaryTextTheme.headline6?.color), + text: t.show_seed, onTap: () => Navigator.of(context).pushNamed(Routes.auth, arguments: (bool isAuthenticatedSuccessfully, AuthPageState auth) => diff --git a/lib/src/screens/receive/qr_image.dart b/lib/src/screens/receive/qr_image.dart deleted file mode 100644 index 7087fc40..00000000 --- a/lib/src/screens/receive/qr_image.dart +++ /dev/null @@ -1,30 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:qr/qr.dart'; -import 'package:oxen_wallet/src/screens/receive/qr_painter.dart'; - -class QrImage extends StatelessWidget { - QrImage({ - @required String data, - this.size = 100.0, - this.backgroundColor, - Color foregroundColor = Colors.black, - int version = 7, - int errorCorrectionLevel = QrErrorCorrectLevel.L, - }) : _painter = QrPainter(data, foregroundColor, version, errorCorrectionLevel); - - final QrPainter _painter; - final Color backgroundColor; - final double size; - - @override - Widget build(BuildContext context) { - return Container( - width: size, - height: size, - color: backgroundColor, - child: CustomPaint( - painter: _painter, - ), - ); - } -} \ No newline at end of file diff --git a/lib/src/screens/receive/qr_painter.dart b/lib/src/screens/receive/qr_painter.dart deleted file mode 100644 index 9a08205b..00000000 --- a/lib/src/screens/receive/qr_painter.dart +++ /dev/null @@ -1,48 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:qr/qr.dart'; - -class QrPainter extends CustomPainter { - QrPainter( - String data, - this.color, - this.version, - this.errorCorrectionLevel, - ) : _qr = QrCode(version, errorCorrectionLevel) { - _p.color = color; - - _qr.addData(data); - _qr.make(); - } - - final int version; - final int errorCorrectionLevel; - final Color color; - - final QrCode _qr; - final _p = Paint()..style = PaintingStyle.fill; - - @override - void paint(Canvas canvas, Size size) { - final squareSize = size.shortestSide / _qr.moduleCount; - for (var x = 0; x < _qr.moduleCount; x++) { - for (var y = 0; y < _qr.moduleCount; y++) { - if (_qr.isDark(y, x)) { - final squareRect = Rect.fromLTWH( - x * squareSize, y * squareSize, squareSize, squareSize); - canvas.drawRect(squareRect, _p); - } - } - } - } - - @override - bool shouldRepaint(CustomPainter oldDelegate) { - if (oldDelegate is QrPainter) { - return color != oldDelegate.color || - errorCorrectionLevel != oldDelegate.errorCorrectionLevel || - version != oldDelegate.version; - } - - return false; - } -} diff --git a/lib/src/screens/receive/receive_page.dart b/lib/src/screens/receive/receive_page.dart index 10499262..6fd49348 100644 --- a/lib/src/screens/receive/receive_page.dart +++ b/lib/src/screens/receive/receive_page.dart @@ -1,24 +1,23 @@ -import 'package:esys_flutter_share/esys_flutter_share.dart'; -import 'package:flutter/cupertino.dart'; +import 'package:share_plus/share_plus.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_mobx/flutter_mobx.dart'; -import 'package:oxen_wallet/generated/l10n.dart'; +import 'package:oxen_wallet/l10n.dart'; import 'package:oxen_wallet/palette.dart'; import 'package:oxen_wallet/routes.dart'; import 'package:oxen_wallet/src/screens/base_page.dart'; -import 'package:oxen_wallet/src/screens/receive/qr_image.dart'; import 'package:oxen_wallet/src/stores/subaddress_list/subaddress_list_store.dart'; import 'package:oxen_wallet/src/stores/wallet/wallet_store.dart'; import 'package:oxen_wallet/src/widgets/oxen_text_field.dart'; import 'package:provider/provider.dart'; +import 'package:qr_flutter/qr_flutter.dart'; class ReceivePage extends BasePage { @override bool get isModalBackButton => true; @override - String get title => S.current.receive; + String getTitle(AppLocalizations t) => t.receive; @override Widget trailing(BuildContext context) { @@ -33,8 +32,7 @@ class ReceivePage extends BasePage { highlightColor: Colors.transparent, splashColor: Colors.transparent, padding: EdgeInsets.all(0), - onPressed: () => Share.text( - 'Share address', walletStore.subaddress.address, 'text/plain'), + onPressed: () => Share.share(walletStore.subaddress.address), child: Icon( Icons.share, size: 30.0, @@ -72,7 +70,7 @@ class ReceiveBodyState extends State { final notCurrentColor = Theme.of(context).scaffoldBackgroundColor; amountController.addListener(() { - if (_formKey.currentState.validate()) { + if (_formKey.currentState?.validate() ?? false) { walletStore.onChangedAmountValue(amountController.text); } else { walletStore.onChangedAmountValue(''); @@ -100,14 +98,15 @@ class ReceiveBodyState extends State { flex: 2, child: AspectRatio( aspectRatio: 1.0, - child: Container( - padding: EdgeInsets.all(5), - color: Colors.white, - child: QrImage( - data: walletStore.subaddress.address + - walletStore.amountValue, - backgroundColor: Colors.transparent, - ), + child: QrImage( + size: 100.0, + version: QrVersions.auto, + errorCorrectionLevel: QrErrorCorrectLevel.M, + data: walletStore.subaddress.address + walletStore.amountValue, + embeddedImage: AssetImage('assets/images/oxen.png'), + embeddedImageStyle: QrEmbeddedImageStyle(size: Size(40, 40)), + backgroundColor: OxenPalette.whiteBlue, + foregroundColor: OxenPalette.navy, ), )), Spacer(flex: 1) @@ -125,9 +124,9 @@ class ReceiveBodyState extends State { onTap: () { Clipboard.setData(ClipboardData( text: walletStore.subaddress.address)); - Scaffold.of(context).showSnackBar(SnackBar( + ScaffoldMessenger.of(context).showSnackBar(SnackBar( content: Text( - S.of(context).copied_to_clipboard, + tr(context).copied_to_clipboard, style: TextStyle(color: Colors.white), ), backgroundColor: Colors.green, @@ -142,7 +141,7 @@ class ReceiveBodyState extends State { color: Theme.of(context) .primaryTextTheme .headline6 - .color) + ?.color) ) ) ) @@ -161,9 +160,9 @@ class ReceiveBodyState extends State { inputFormatters: [ FilteringTextInputFormatter.deny(RegExp('[- ]')) ], - hintText: S.of(context).amount, + hintText: tr(context).amount, validator: (value) { - walletStore.validateAmount(value); + walletStore.validateAmount(value ?? '', tr(context)); return walletStore.errorMessage; }, controller: amountController @@ -177,18 +176,18 @@ class ReceiveBodyState extends State { children: [ Expanded( child: Container( - color: Theme.of(context).accentTextTheme.headline5.color, + color: Theme.of(context).accentTextTheme.headline5?.color, child: Column( children: [ ListTile( title: Text( - S.of(context).subaddresses, + tr(context).subaddresses, style: TextStyle( fontSize: 16.0, color: Theme.of(context) .primaryTextTheme .headline5 - .color), + ?.color), ), trailing: Container( width: 28.0, @@ -252,7 +251,7 @@ class ReceiveBodyState extends State { color: Theme.of(context) .primaryTextTheme .headline5 - .color), + ?.color), ), ) ]), diff --git a/lib/src/screens/rescan/rescan_page.dart b/lib/src/screens/rescan/rescan_page.dart index 43248dca..9be94020 100644 --- a/lib/src/screens/rescan/rescan_page.dart +++ b/lib/src/screens/rescan/rescan_page.dart @@ -5,12 +5,12 @@ import 'package:oxen_wallet/src/screens/base_page.dart'; import 'package:oxen_wallet/src/widgets/blockchain_height_widget.dart'; import 'package:oxen_wallet/src/widgets/primary_button.dart'; import 'package:oxen_wallet/src/stores/rescan/rescan_wallet_store.dart'; -import 'package:oxen_wallet/generated/l10n.dart'; +import 'package:oxen_wallet/l10n.dart'; class RescanPage extends BasePage { final blockchainKey = GlobalKey(); @override - String get title => S.current.rescan; + String getTitle(AppLocalizations t) => t.rescan; @override Widget body(BuildContext context) { @@ -25,16 +25,17 @@ class RescanPage extends BasePage { builder: (_) => LoadingPrimaryButton( isLoading: rescanWalletStore.state == RescanWalletState.rescaning, - text: S.of(context).rescan, + text: tr(context).rescan, onPressed: () async { - await rescanWalletStore.rescanCurrentWallet( - restoreHeight: blockchainKey.currentState.height); + if (blockchainKey.currentState != null) + await rescanWalletStore.rescanCurrentWallet( + restoreHeight: blockchainKey.currentState!.height); Navigator.of(context).pop(); }, color: - Theme.of(context).primaryTextTheme.button.backgroundColor, + Theme.of(context).primaryTextTheme.button?.backgroundColor, borderColor: - Theme.of(context).primaryTextTheme.button.decorationColor)) + Theme.of(context).primaryTextTheme.button?.decorationColor)) ]), ); } diff --git a/lib/src/screens/restore/restore_options_page.dart b/lib/src/screens/restore/restore_options_page.dart index d302bf66..a7bd0ca6 100644 --- a/lib/src/screens/restore/restore_options_page.dart +++ b/lib/src/screens/restore/restore_options_page.dart @@ -6,13 +6,13 @@ import 'package:oxen_wallet/src/screens/restore/widgets/restore_button.dart'; import 'package:oxen_wallet/src/screens/restore/widgets/image_widget.dart'; import 'package:oxen_wallet/src/screens/restore/widgets/base_restore_widget.dart'; import 'package:oxen_wallet/src/screens/base_page.dart'; -import 'package:oxen_wallet/generated/l10n.dart'; +import 'package:oxen_wallet/l10n.dart'; class RestoreOptionsPage extends BasePage { static const _aspectRatioImage = 2.086; @override - String get title => S.current.restore_restore_wallet; + String getTitle(AppLocalizations t) => t.restore_restore_wallet; @override Color get backgroundColor => Palette.creamyGrey; @@ -24,6 +24,8 @@ class RestoreOptionsPage extends BasePage { Widget body(BuildContext context) { final isLargeScreen = MediaQuery.of(context).size.height > largeHeight; + final t = tr(context); + return BaseRestoreWidget( firstRestoreButton: RestoreButton( onPressed: () => @@ -36,9 +38,9 @@ class RestoreOptionsPage extends BasePage { ), titleColor: Palette.lightViolet, color: Palette.lightViolet, - title: S.of(context).restore_title_from_seed_keys, - description: S.of(context).restore_description_from_seed_keys, - textButton: S.of(context).restore_next, + title: t.restore_title_from_seed_keys, + description: t.restore_description_from_seed_keys, + textButton: t.restore_next, ), secondRestoreButton: RestoreButton( onPressed: () {}, @@ -49,9 +51,9 @@ class RestoreOptionsPage extends BasePage { ), titleColor: OxenPalette.teal, color: OxenPalette.teal, - title: S.of(context).restore_title_from_backup, - description: S.of(context).restore_description_from_backup, - textButton: S.of(context).restore_next, + title: t.restore_title_from_backup, + description: t.restore_description_from_backup, + textButton: t.restore_next, ), isLargeScreen: isLargeScreen, ); diff --git a/lib/src/screens/restore/restore_wallet_from_keys_page.dart b/lib/src/screens/restore/restore_wallet_from_keys_page.dart index 092000c9..21880df6 100644 --- a/lib/src/screens/restore/restore_wallet_from_keys_page.dart +++ b/lib/src/screens/restore/restore_wallet_from_keys_page.dart @@ -1,11 +1,9 @@ import 'package:mobx/mobx.dart'; import 'package:provider/provider.dart'; import 'package:shared_preferences/shared_preferences.dart'; -import 'package:flutter/services.dart'; -import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_mobx/flutter_mobx.dart'; -import 'package:oxen_wallet/generated/l10n.dart'; +import 'package:oxen_wallet/l10n.dart'; import 'package:oxen_wallet/src/domain/services/wallet_list_service.dart'; import 'package:oxen_wallet/src/domain/services/wallet_service.dart'; import 'package:oxen_wallet/src/stores/wallet_restoration/wallet_restoration_store.dart'; @@ -19,16 +17,16 @@ import 'package:oxen_wallet/src/stores/seed_language/seed_language_store.dart'; class RestoreWalletFromKeysPage extends BasePage { RestoreWalletFromKeysPage( - {@required this.walletsService, - @required this.sharedPreferences, - @required this.walletService}); + {required this.walletsService, + required this.sharedPreferences, + required this.walletService}); final WalletListService walletsService; final WalletService walletService; final SharedPreferences sharedPreferences; @override - String get title => S.current.restore_title_from_keys; + String getTitle(AppLocalizations t) => t.restore_title_from_keys; @override Widget body(BuildContext context) => RestoreFromKeysFrom(); @@ -58,7 +56,7 @@ class _RestoreFromKeysFromState extends State { } if (state is WalletRestorationFailure) { - WidgetsBinding.instance.addPostFrameCallback((_) { + WidgetsBinding.instance?.addPostFrameCallback((_) { showDialog( context: context, builder: (BuildContext context) { @@ -66,7 +64,7 @@ class _RestoreFromKeysFromState extends State { content: Text(state.error), actions: [ FlatButton( - child: Text(S.of(context).ok), + child: Text(tr(context).ok), onPressed: () => Navigator.of(context).pop(), ), ], @@ -97,7 +95,7 @@ class _RestoreFromKeysFromState extends State { decoration: InputDecoration( hintStyle: TextStyle(color: Theme.of(context).hintColor), - hintText: S.of(context).restore_wallet_name, + hintText: tr(context).restore_wallet_name, focusedBorder: UnderlineInputBorder( borderSide: BorderSide( color: OxenPalette.teal, width: 2.0)), @@ -106,7 +104,7 @@ class _RestoreFromKeysFromState extends State { color: Theme.of(context).focusColor, width: 1.0))), validator: (value) { - walletRestorationStore.validateWalletName(value); + walletRestorationStore.validateWalletName(value ?? '', tr(context)); return walletRestorationStore.errorMessage; }, ), @@ -126,7 +124,7 @@ class _RestoreFromKeysFromState extends State { decoration: InputDecoration( hintStyle: TextStyle(color: Theme.of(context).hintColor), - hintText: S.of(context).restore_address, + hintText: tr(context).restore_address, focusedBorder: UnderlineInputBorder( borderSide: BorderSide( color: OxenPalette.teal, width: 2.0)), @@ -135,7 +133,7 @@ class _RestoreFromKeysFromState extends State { color: Theme.of(context).focusColor, width: 1.0))), validator: (value) { - walletRestorationStore.validateAddress(value); + walletRestorationStore.validateAddress(value ?? '', l10n: tr(context)); return walletRestorationStore.errorMessage; }, ), @@ -153,7 +151,7 @@ class _RestoreFromKeysFromState extends State { decoration: InputDecoration( hintStyle: TextStyle(color: Theme.of(context).hintColor), - hintText: S.of(context).restore_view_key_private, + hintText: tr(context).restore_view_key_private, focusedBorder: UnderlineInputBorder( borderSide: BorderSide( color: OxenPalette.teal, width: 2.0)), @@ -162,7 +160,7 @@ class _RestoreFromKeysFromState extends State { color: Theme.of(context).focusColor, width: 1.0))), validator: (value) { - walletRestorationStore.validateKeys(value); + walletRestorationStore.validateKeys(value ?? '', tr(context)); return walletRestorationStore.errorMessage; }, ), @@ -180,7 +178,7 @@ class _RestoreFromKeysFromState extends State { decoration: InputDecoration( hintStyle: TextStyle(color: Theme.of(context).hintColor), - hintText: S.of(context).restore_spend_key_private, + hintText: tr(context).restore_spend_key_private, focusedBorder: UnderlineInputBorder( borderSide: BorderSide( color: OxenPalette.teal, width: 2.0)), @@ -189,7 +187,7 @@ class _RestoreFromKeysFromState extends State { color: Theme.of(context).focusColor, width: 1.0))), validator: (value) { - walletRestorationStore.validateKeys(value); + walletRestorationStore.validateKeys(value ?? '', tr(context)); return walletRestorationStore.errorMessage; }, ), @@ -205,20 +203,22 @@ class _RestoreFromKeysFromState extends State { bottomSection: Observer(builder: (_) { return LoadingPrimaryButton( onPressed: () { - if (_formKey.currentState.validate()) { + if (_formKey.currentState == null || _blockchainHeightKey.currentState == null) + return; + if (_formKey.currentState!.validate()) { walletRestorationStore.restoreFromKeys( name: _nameController.text, language: seedLanguageStore.selectedSeedLanguage, address: _addressController.text, viewKey: _viewKeyController.text, spendKey: _spendKeyController.text, - restoreHeight: _blockchainHeightKey.currentState.height); + restoreHeight: _blockchainHeightKey.currentState!.height); } }, - text: S.of(context).restore_recover, - color: Theme.of(context).primaryTextTheme.button.backgroundColor, + text: tr(context).restore_recover, + color: Theme.of(context).primaryTextTheme.button?.backgroundColor, borderColor: - Theme.of(context).primaryTextTheme.button.decorationColor); + Theme.of(context).primaryTextTheme.button?.decorationColor); }), ); } diff --git a/lib/src/screens/restore/restore_wallet_from_seed_details.dart b/lib/src/screens/restore/restore_wallet_from_seed_details.dart index 5beefbbc..b59bb79e 100644 --- a/lib/src/screens/restore/restore_wallet_from_seed_details.dart +++ b/lib/src/screens/restore/restore_wallet_from_seed_details.dart @@ -1,9 +1,8 @@ import 'package:mobx/mobx.dart'; import 'package:provider/provider.dart'; import 'package:flutter/material.dart'; -import 'package:flutter/cupertino.dart'; import 'package:flutter_mobx/flutter_mobx.dart'; -import 'package:oxen_wallet/generated/l10n.dart'; +import 'package:oxen_wallet/l10n.dart'; import 'package:oxen_wallet/src/stores/wallet_restoration/wallet_restoration_store.dart'; import 'package:oxen_wallet/src/stores/wallet_restoration/wallet_restoration_state.dart'; import 'package:oxen_wallet/src/screens/base_page.dart'; @@ -14,7 +13,7 @@ import 'package:oxen_wallet/palette.dart'; class RestoreWalletFromSeedDetailsPage extends BasePage { @override - String get title => S.current.restore_wallet_restore_description; + String getTitle(AppLocalizations t) => t.restore_wallet_restore_description; @override Widget body(BuildContext context) => RestoreFromSeedDetailsForm(); @@ -42,7 +41,7 @@ class _RestoreFromSeedDetailsFormState } if (state is WalletRestorationFailure) { - WidgetsBinding.instance.addPostFrameCallback((_) { + WidgetsBinding.instance?.addPostFrameCallback((_) { showDialog( context: context, builder: (BuildContext context) { @@ -50,7 +49,7 @@ class _RestoreFromSeedDetailsFormState content: Text(state.error), actions: [ FlatButton( - child: Text(S.of(context).ok), + child: Text(tr(context).ok), onPressed: () => Navigator.of(context).pop(), ), ], @@ -83,7 +82,7 @@ class _RestoreFromSeedDetailsFormState decoration: InputDecoration( hintStyle: TextStyle( color: Theme.of(context).hintColor), - hintText: S.of(context).restore_wallet_name, + hintText: tr(context).restore_wallet_name, focusedBorder: UnderlineInputBorder( borderSide: BorderSide( color: OxenPalette.teal, @@ -94,7 +93,7 @@ class _RestoreFromSeedDetailsFormState width: 1.0))), validator: (value) { walletRestorationStore - .validateWalletName(value); + .validateWalletName(value ?? '', tr(context)); return walletRestorationStore.errorMessage; }, ), @@ -109,17 +108,17 @@ class _RestoreFromSeedDetailsFormState bottomSection: Observer(builder: (_) { return LoadingPrimaryButton( onPressed: () { - if (_formKey.currentState.validate()) { + if (_formKey.currentState!.validate()) { walletRestorationStore.restoreFromSeed( name: _nameController.text, - restoreHeight: _blockchainHeightKey.currentState.height); + restoreHeight: _blockchainHeightKey.currentState!.height); } }, isLoading: walletRestorationStore.state is WalletIsRestoring, - text: S.of(context).restore_recover, - color: Theme.of(context).primaryTextTheme.button.backgroundColor, + text: tr(context).restore_recover, + color: Theme.of(context).primaryTextTheme.button?.backgroundColor, borderColor: - Theme.of(context).primaryTextTheme.button.decorationColor); + Theme.of(context).primaryTextTheme.button?.decorationColor); }), ); } diff --git a/lib/src/screens/restore/restore_wallet_from_seed_page.dart b/lib/src/screens/restore/restore_wallet_from_seed_page.dart index 96316b66..00df3653 100644 --- a/lib/src/screens/restore/restore_wallet_from_seed_page.dart +++ b/lib/src/screens/restore/restore_wallet_from_seed_page.dart @@ -1,10 +1,9 @@ import 'package:provider/provider.dart'; import 'package:flutter/material.dart'; -import 'package:flutter/cupertino.dart'; import 'package:flutter/services.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:oxen_wallet/routes.dart'; -import 'package:oxen_wallet/generated/l10n.dart'; +import 'package:oxen_wallet/l10n.dart'; import 'package:oxen_wallet/src/domain/services/wallet_list_service.dart'; import 'package:oxen_wallet/src/domain/services/wallet_service.dart'; import 'package:oxen_wallet/src/screens/base_page.dart'; @@ -14,9 +13,9 @@ import 'package:oxen_wallet/src/stores/seed_language/seed_language_store.dart'; class RestoreWalletFromSeedPage extends BasePage { RestoreWalletFromSeedPage( - {@required this.walletsService, - @required this.walletService, - @required this.sharedPreferences}); + {required this.walletsService, + required this.walletService, + required this.sharedPreferences}); final WalletListService walletsService; final WalletService walletService; @@ -24,23 +23,23 @@ class RestoreWalletFromSeedPage extends BasePage { final formKey = GlobalKey<_RestoreFromSeedFormState>(); @override - String get title => S.current.restore_title_from_seed; + String getTitle(AppLocalizations t) => t.restore_title_from_seed; @override Widget trailing(BuildContext context) => SizedBox( width: 80, height: 20, child: FlatButton( - child: Text(S.of(context).clear), padding: EdgeInsets.all(0), - onPressed: () => formKey?.currentState?.clear())); + onPressed: () => formKey.currentState?.clear(), + child: Text(tr(context).clear))); @override Widget body(BuildContext context) => RestoreFromSeedForm(key: formKey); } class RestoreFromSeedForm extends StatefulWidget { - RestoreFromSeedForm({Key key}) : super(key: key); + RestoreFromSeedForm({required Key key}) : super(key: key); @override _RestoreFromSeedFormState createState() => _RestoreFromSeedFormState(); @@ -48,7 +47,7 @@ class RestoreFromSeedForm extends StatefulWidget { class _RestoreFromSeedFormState extends State { final _seedKey = GlobalKey(); - void clear() => _seedKey.currentState.clear(); + void clear() => _seedKey.currentState?.clear(); @override Widget build(BuildContext context) { @@ -62,10 +61,10 @@ class _RestoreFromSeedFormState extends State { padding: EdgeInsets.only(left: 20.0, right: 20.0), child: SeedWidget( key: _seedKey, - onMnemoticChange: (seed) => walletRestorationStore.setSeed(seed), + onMnemonicChange: (seed) => walletRestorationStore.setSeed(seed), onFinish: () => Navigator.of(context).pushNamed( Routes.restoreWalletFromSeedDetails, - arguments: _seedKey.currentState.items), + arguments: _seedKey.currentState?.items), seedLanguage: seedLanguageStore.selectedSeedLanguage, ), ), diff --git a/lib/src/screens/restore/restore_wallet_options_page.dart b/lib/src/screens/restore/restore_wallet_options_page.dart index 7ecdbff2..632ca414 100644 --- a/lib/src/screens/restore/restore_wallet_options_page.dart +++ b/lib/src/screens/restore/restore_wallet_options_page.dart @@ -6,7 +6,7 @@ import 'package:oxen_wallet/src/screens/restore/widgets/restore_button.dart'; import 'package:oxen_wallet/src/screens/restore/widgets/image_widget.dart'; import 'package:oxen_wallet/src/screens/restore/widgets/base_restore_widget.dart'; import 'package:oxen_wallet/src/screens/base_page.dart'; -import 'package:oxen_wallet/generated/l10n.dart'; +import 'package:oxen_wallet/l10n.dart'; import 'package:oxen_wallet/src/stores/seed_language/seed_language_store.dart'; import 'package:provider/provider.dart'; @@ -14,7 +14,7 @@ class RestoreWalletOptionsPage extends BasePage { static const _aspectRatioImage = 2.086; @override - String get title => S.current.restore_seed_keys_restore; + String getTitle(AppLocalizations t) => t.restore_seed_keys_restore; @override Color get backgroundColor => Palette.creamyGrey; @@ -39,9 +39,9 @@ class RestoreWalletOptionsPage extends BasePage { isLargeScreen: isLargeScreen), titleColor: Palette.lightViolet, color: Palette.lightViolet, - title: S.of(context).restore_title_from_seed, - description: S.of(context).restore_description_from_seed, - textButton: S.of(context).restore_next, + title: tr(context).restore_title_from_seed, + description: tr(context).restore_description_from_seed, + textButton: tr(context).restore_next, ), secondRestoreButton: RestoreButton( onPressed: () { @@ -54,9 +54,9 @@ class RestoreWalletOptionsPage extends BasePage { isLargeScreen: isLargeScreen), titleColor: OxenPalette.teal, color: OxenPalette.teal, - title: S.of(context).restore_title_from_keys, - description: S.of(context).restore_description_from_keys, - textButton: S.of(context).restore_next, + title: tr(context).restore_title_from_keys, + description: tr(context).restore_description_from_keys, + textButton: tr(context).restore_next, ), isLargeScreen: isLargeScreen, ); diff --git a/lib/src/screens/restore/widgets/base_restore_widget.dart b/lib/src/screens/restore/widgets/base_restore_widget.dart index 6fa1f040..f3e9288d 100644 --- a/lib/src/screens/restore/widgets/base_restore_widget.dart +++ b/lib/src/screens/restore/widgets/base_restore_widget.dart @@ -4,8 +4,8 @@ const largeHeight = 700; class BaseRestoreWidget extends StatelessWidget { BaseRestoreWidget({ - @required this.firstRestoreButton, - @required this.secondRestoreButton, + required this.firstRestoreButton, + required this.secondRestoreButton, this.isLargeScreen = false }); @@ -42,4 +42,4 @@ class BaseRestoreWidget extends StatelessWidget { ) ); } -} \ No newline at end of file +} diff --git a/lib/src/screens/restore/widgets/image_widget.dart b/lib/src/screens/restore/widgets/image_widget.dart index 016bd9ce..43fb0cd2 100644 --- a/lib/src/screens/restore/widgets/image_widget.dart +++ b/lib/src/screens/restore/widgets/image_widget.dart @@ -2,8 +2,8 @@ import 'package:flutter/material.dart'; class ImageWidget extends StatelessWidget { ImageWidget({ - @required this.image, - @required this.aspectRatioImage, + required this.image, + required this.aspectRatioImage, this.isLargeScreen = false}); final Image image; @@ -26,4 +26,4 @@ class ImageWidget extends StatelessWidget { ) : image; } -} \ No newline at end of file +} diff --git a/lib/src/screens/restore/widgets/restore_button.dart b/lib/src/screens/restore/widgets/restore_button.dart index 86e6606e..79967216 100644 --- a/lib/src/screens/restore/widgets/restore_button.dart +++ b/lib/src/screens/restore/widgets/restore_button.dart @@ -4,10 +4,10 @@ import 'package:auto_size_text/auto_size_text.dart'; class RestoreButton extends StatelessWidget { const RestoreButton( - {@required this.onPressed, - @required this.imageWidget, - @required this.color, - @required this.titleColor, + {required this.onPressed, + required this.imageWidget, + required this.color, + required this.titleColor, this.title = '', this.description = '', this.textButton = ''}); @@ -25,7 +25,7 @@ class RestoreButton extends StatelessWidget { return Container( margin: EdgeInsets.only(top: 20.0, bottom: 20.0), decoration: BoxDecoration( - color: Theme.of(context).accentTextTheme.headline5.backgroundColor, + color: Theme.of(context).accentTextTheme.headline5?.backgroundColor, borderRadius: BorderRadius.all(Radius.circular(20.0)), boxShadow: [ BoxShadow( @@ -63,7 +63,7 @@ class RestoreButton extends StatelessWidget { description, textAlign: TextAlign.center, style: TextStyle( - color: Theme.of(context).accentTextTheme.subtitle1.color, + color: Theme.of(context).accentTextTheme.subtitle1?.color, ), maxLines: 2, ) @@ -81,7 +81,7 @@ class RestoreButton extends StatelessWidget { color: Theme.of(context) .accentTextTheme .headline5 - .decorationColor, + ?.decorationColor ?? OxenPalette.teal, width: 1.15)), color: Colors.transparent, ), diff --git a/lib/src/screens/root/root.dart b/lib/src/screens/root/root.dart index 6a4bddee..1fa8ce61 100644 --- a/lib/src/screens/root/root.dart +++ b/lib/src/screens/root/root.dart @@ -20,22 +20,22 @@ import 'package:provider/provider.dart'; import 'package:shared_preferences/shared_preferences.dart'; class Root extends StatefulWidget { - Root({Key key}) : super(key: key); + Root({Key? key}) : super(key: key); @override RootState createState() => RootState(); } class RootState extends State with WidgetsBindingObserver { - bool _isInactive; - bool _postFrameCallback; - AuthenticationStore _authenticationStore; + bool _isInactive = false; + bool _postFrameCallback = false; + AuthenticationStore? _authenticationStore; @override void initState() { _isInactive = false; _postFrameCallback = false; - WidgetsBinding.instance.addObserver(this); + WidgetsBinding.instance?.addObserver(this); super.initState(); } @@ -45,10 +45,9 @@ class RootState extends State with WidgetsBindingObserver { case AppLifecycleState.paused: if (isQrScannerShown) return; - if (!_isInactive && - _authenticationStore.state == - AuthenticationState.authenticated || - _authenticationStore.state == AuthenticationState.active) { + if (!_isInactive && _authenticationStore != null && + (_authenticationStore!.state == AuthenticationState.authenticated || + _authenticationStore!.state == AuthenticationState.active)) { setState(() => _isInactive = true); } @@ -75,7 +74,7 @@ class RootState extends State with WidgetsBindingObserver { if (_isInactive && !_postFrameCallback) { _postFrameCallback = true; - WidgetsBinding.instance.addPostFrameCallback((_) { + WidgetsBinding.instance?.addPostFrameCallback((_) { Navigator.of(context).pushNamed(Routes.unlock, arguments: (bool isAuthenticatedSuccessfully, AuthPageState auth) { if (!isAuthenticatedSuccessfully) return; @@ -90,7 +89,7 @@ class RootState extends State with WidgetsBindingObserver { } return Observer(builder: (_) { - final state = _authenticationStore.state; + final state = _authenticationStore!.state; if (state == AuthenticationState.denied) return WelcomePage(); if (state == AuthenticationState.readyToLogin) { @@ -117,7 +116,7 @@ class RootState extends State with WidgetsBindingObserver { settingsStore: settingsStore, walletService: walletService, callback: () => - _authenticationStore.state = AuthenticationState.authenticated); + _authenticationStore?.state = AuthenticationState.authenticated); } return Container(color: Colors.white); diff --git a/lib/src/screens/seed/create_seed_page.dart b/lib/src/screens/seed/create_seed_page.dart index a379599a..5782ea64 100644 --- a/lib/src/screens/seed/create_seed_page.dart +++ b/lib/src/screens/seed/create_seed_page.dart @@ -6,9 +6,9 @@ import 'package:oxen_wallet/src/stores/settings/settings_store.dart'; import 'package:oxen_wallet/src/stores/wallet_seed/wallet_seed_store.dart'; Widget createSeedPage( - {@required SettingsStore settingsStore, - @required WalletService walletService, - @required void Function() callback}) => + {required SettingsStore settingsStore, + required WalletService walletService, + required void Function()? callback}) => Provider( create: (_) => WalletSeedStore(walletService: walletService), - child: SeedPage(onCloseCallback: callback)); \ No newline at end of file + child: SeedPage(onCloseCallback: callback)); diff --git a/lib/src/screens/seed/seed_page.dart b/lib/src/screens/seed/seed_page.dart index 2ead2c89..fbd2abd7 100644 --- a/lib/src/screens/seed/seed_page.dart +++ b/lib/src/screens/seed/seed_page.dart @@ -1,11 +1,10 @@ import 'package:provider/provider.dart'; -import 'package:esys_flutter_share/esys_flutter_share.dart'; +import 'package:share_plus/share_plus.dart'; import 'package:flutter/material.dart'; -import 'package:flutter/cupertino.dart'; import 'package:flutter/services.dart'; import 'package:flutter_mobx/flutter_mobx.dart'; import 'package:oxen_wallet/palette.dart'; -import 'package:oxen_wallet/generated/l10n.dart'; +import 'package:oxen_wallet/l10n.dart'; import 'package:oxen_wallet/src/widgets/primary_button.dart'; import 'package:oxen_wallet/src/stores/wallet_seed/wallet_seed_store.dart'; import 'package:oxen_wallet/src/screens/base_page.dart'; @@ -20,23 +19,23 @@ class SeedPage extends BasePage { bool get isModalBackButton => true; @override - String get title => S.current.seed_title; + String getTitle(AppLocalizations t) => t.seed_title; - final VoidCallback onCloseCallback; + final VoidCallback? onCloseCallback; @override void onClose(BuildContext context) => - onCloseCallback != null ? onCloseCallback() : Navigator.of(context).pop(); + onCloseCallback != null ? onCloseCallback!() : Navigator.of(context).pop(); @override - Widget leading(BuildContext context) { + Widget? leading(BuildContext context) { return onCloseCallback != null ? Offstage() : super.leading(context); } @override Widget body(BuildContext context) { final walletSeedStore = Provider.of(context); - String _seed; + var _seed = ''; return Container( padding: EdgeInsets.all(30.0), @@ -67,14 +66,14 @@ class SeedPage extends BasePage { padding: EdgeInsets.only(bottom: 20.0), margin: EdgeInsets.only(bottom: 10.0), child: Text( - walletSeedStore.name ?? '', + walletSeedStore.name, textAlign: TextAlign.center, style: TextStyle( fontSize: 18.0, color: Theme.of(context) .primaryTextTheme .button - .color), + ?.color), ), )) ], @@ -90,7 +89,7 @@ class SeedPage extends BasePage { color: Theme.of(context) .primaryTextTheme .headline6 - .color), + ?.color), ) ], ); @@ -104,19 +103,16 @@ class SeedPage extends BasePage { child: Container( padding: EdgeInsets.only(right: 8.0), child: PrimaryButton( - onPressed: () => Share.text( - S.of(context).seed_share, - _seed, - 'text/plain'), + onPressed: () => Share.share(_seed), color: Theme.of(context) .primaryTextTheme .button - .backgroundColor, + ?.backgroundColor, borderColor: Theme.of(context) .primaryTextTheme .button - .decorationColor, - text: S.of(context).save), + ?.decorationColor, + text: tr(context).save), )), Flexible( child: Container( @@ -128,24 +124,21 @@ class SeedPage extends BasePage { ClipboardData(text: _seed)); Scaffold.of(context).showSnackBar( SnackBar( - content: Text(S - .of(context) - .copied_to_clipboard), + content: Text(tr(context).copied_to_clipboard), backgroundColor: Colors.green, - duration: - Duration(milliseconds: 1500), + duration: Duration(milliseconds: 1500), ), ); }, - text: S.of(context).copy, + text: tr(context).copy, color: Theme.of(context) .accentTextTheme .caption - .backgroundColor, + ?.backgroundColor, borderColor: Theme.of(context) .accentTextTheme .caption - .decorationColor), + ?.decorationColor), ))) ], ), @@ -157,7 +150,7 @@ class SeedPage extends BasePage { onCloseCallback != null ? PrimaryButton( onPressed: () => onClose(context), - text: S.of(context).restore_next, + text: tr(context).restore_next, color: Palette.darkGrey, borderColor: Palette.darkGrey) : Offstage() diff --git a/lib/src/screens/seed_language/seed_language_page.dart b/lib/src/screens/seed_language/seed_language_page.dart index 5a01dec1..74ac5734 100644 --- a/lib/src/screens/seed_language/seed_language_page.dart +++ b/lib/src/screens/seed_language/seed_language_page.dart @@ -1,6 +1,5 @@ import 'package:flutter/material.dart'; -import 'package:flutter/cupertino.dart'; -import 'package:oxen_wallet/generated/l10n.dart'; +import 'package:oxen_wallet/l10n.dart'; import 'package:oxen_wallet/src/widgets/primary_button.dart'; import 'package:oxen_wallet/src/screens/base_page.dart'; import 'package:oxen_wallet/src/screens/seed_language/widgets/seed_language_picker.dart'; @@ -25,7 +24,7 @@ class SeedLanguage extends BasePage { children: [ imageSeed, Text( - S.of(context).seed_language_choose, + tr(context).seed_language_choose, textAlign: TextAlign.center, style: TextStyle(fontSize: 16.0), ), @@ -40,11 +39,11 @@ class SeedLanguage extends BasePage { PrimaryButton( onPressed: () => Navigator.of(context).popAndPushNamed(seedLanguageStore.currentRoute), - text: S.of(context).seed_language_next, + text: tr(context).seed_language_next, color: - Theme.of(context).primaryTextTheme.button.backgroundColor, + Theme.of(context).primaryTextTheme.button?.backgroundColor, borderColor: - Theme.of(context).primaryTextTheme.button.decorationColor), + Theme.of(context).primaryTextTheme.button?.decorationColor), ], ), ); diff --git a/lib/src/screens/seed_language/widgets/seed_language_picker.dart b/lib/src/screens/seed_language/widgets/seed_language_picker.dart index 6b08b67e..da0e62d9 100644 --- a/lib/src/screens/seed_language/widgets/seed_language_picker.dart +++ b/lib/src/screens/seed_language/widgets/seed_language_picker.dart @@ -4,24 +4,27 @@ import 'package:flutter_mobx/flutter_mobx.dart'; import 'package:provider/provider.dart'; import 'package:oxen_wallet/src/stores/seed_language/seed_language_store.dart'; import 'package:oxen_wallet/src/widgets/present_picker.dart'; -import 'package:oxen_wallet/generated/l10n.dart'; +import 'package:oxen_wallet/l10n.dart'; class SeedLanguagePicker extends StatelessWidget { - final List seedLocales = [ - S.current.seed_language_english, - S.current.seed_language_chinese, - S.current.seed_language_dutch, - S.current.seed_language_german, - S.current.seed_language_japanese, - S.current.seed_language_portuguese, - S.current.seed_language_russian, - S.current.seed_language_spanish, - S.current.seed_language_french, - S.current.seed_language_italian - ]; + List getSeedLocales(AppLocalizations l10n) { + return [ + l10n.seed_language_english, + l10n.seed_language_chinese, + l10n.seed_language_dutch, + l10n.seed_language_german, + l10n.seed_language_japanese, + l10n.seed_language_portuguese, + l10n.seed_language_russian, + l10n.seed_language_spanish, + l10n.seed_language_french, + l10n.seed_language_italian + ]; + } @override Widget build(BuildContext context) { + final seedLocales = getSeedLocales(tr(context)); final seedLanguageStore = Provider.of(context); return Observer( @@ -32,7 +35,7 @@ class SeedLanguagePicker extends StatelessWidget { //width: double.infinity, decoration: BoxDecoration( border: Border.all( - color: Theme.of(context).dividerTheme.color + color: Theme.of(context).dividerTheme.color ?? Palette.lightGrey ), borderRadius: BorderRadius.circular(8.0) ), @@ -45,6 +48,7 @@ class SeedLanguagePicker extends StatelessWidget { } Future _setSeedLanguage(BuildContext context) async { + final seedLocales = getSeedLocales(tr(context)); final seedLanguageStore = context.read(); var selectedSeedLanguage = await presentPicker(context, seedLocales); diff --git a/lib/src/screens/send/send_page.dart b/lib/src/screens/send/send_page.dart index d01db2d7..dd3e67f8 100644 --- a/lib/src/screens/send/send_page.dart +++ b/lib/src/screens/send/send_page.dart @@ -1,16 +1,15 @@ -import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_mobx/flutter_mobx.dart'; import 'package:mobx/mobx.dart'; -import 'package:oxen_wallet/generated/l10n.dart'; +import 'package:oxen_wallet/l10n.dart'; import 'package:oxen_wallet/palette.dart'; import 'package:oxen_wallet/routes.dart'; import 'package:oxen_wallet/src/domain/common/balance_display_mode.dart'; -import 'package:oxen_wallet/src/domain/common/crypto_currency.dart'; import 'package:oxen_wallet/src/node/sync_status.dart'; import 'package:oxen_wallet/src/screens/auth/auth_page.dart'; import 'package:oxen_wallet/src/screens/base_page.dart'; +import 'package:oxen_wallet/src/screens/oxen_amount.dart'; import 'package:oxen_wallet/src/stores/balance/balance_store.dart'; import 'package:oxen_wallet/src/stores/send/send_store.dart'; import 'package:oxen_wallet/src/stores/send/sending_state.dart'; @@ -26,7 +25,7 @@ import 'package:provider/provider.dart'; class SendPage extends BasePage { @override - String get title => S.current.send_title; + String getTitle(AppLocalizations t) => t.send_title; @override bool get isModalBackButton => true; @@ -71,10 +70,10 @@ class SendFormState extends State { await sendStore.isOpenaliasRecord(_addressController.text); if (isOpenAlias) { - _addressController.text = sendStore.recordAddress; + _addressController.text = sendStore.recordAddress ?? ''; - await showSimpleOxenDialog(context, S.of(context).openalias_alert_title, - S.of(context).openalias_alert_content(sendStore.recordName), + await showSimpleOxenDialog(context, tr(context).openalias_alert_title, + tr(context).openalias_alert_content(sendStore.recordName ?? ''), onPressed: (_) => Navigator.of(context).pop()); } } @@ -90,6 +89,8 @@ class SendFormState extends State { _setEffects(context); + final t = tr(context); + return ScrollableWithBottomSection( contentPadding: EdgeInsets.all(0), content: GestureDetector( @@ -115,7 +116,7 @@ class SendFormState extends State { color: Theme.of(context) .accentTextTheme .subtitle2 - .backgroundColor))), + ?.backgroundColor ?? OxenPalette.black))), child: SizedBox( height: 56, width: double.infinity, @@ -127,7 +128,7 @@ class SendFormState extends State { crossAxisAlignment: CrossAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.center, children: [ - Text(S.of(context).send_your_wallet, + Text(t.send_your_wallet, style: TextStyle( fontSize: 12, color: OxenPalette.teal)), Text(walletStore.name, @@ -136,7 +137,7 @@ class SendFormState extends State { color: Theme.of(context) .accentTextTheme .overline - .color, + ?.color, height: 1.25)), ]); }), @@ -151,13 +152,13 @@ class SendFormState extends State { return Column( mainAxisAlignment: MainAxisAlignment.center, children: [ - Text(S.current.oxen_available_balance, + Text(t.oxen_available_balance, style: TextStyle( fontSize: 12, color: Theme.of(context) .accentTextTheme .overline - .backgroundColor, + ?.backgroundColor, )), Text(availableBalance, style: TextStyle( @@ -165,7 +166,7 @@ class SendFormState extends State { color: Theme.of(context) .accentTextTheme .overline - .color, + ?.color, height: 1.1)), ]); }) @@ -181,107 +182,39 @@ class SendFormState extends State { child: Column(children: [ AddressTextField( controller: _addressController, - placeholder: S.of(context).send_oxen_address, + placeholder: t.send_oxen_address, focusNode: _focusNodeAddress, onURIScanned: (uri) { - var address = ''; - var amount = ''; - - if (uri != null) { - address = uri.path; - amount = uri.queryParameters['tx_amount']; - } else { - address = uri.toString(); - } - - _addressController.text = address; - _cryptoAmountController.text = amount; + _addressController.text = uri.path; + _cryptoAmountController.text = uri.queryParameters['tx_amount'] ?? ''; }, options: [ AddressTextFieldOption.qrCode, AddressTextFieldOption.addressBook ], validator: (value) { - sendStore.validateAddress(value, - cryptoCurrency: CryptoCurrency.oxen); + sendStore.validateAddress(value ?? '', l10n: t); return sendStore.errorMessage; }, ), - Padding( - padding: const EdgeInsets.only(top: 20), - child: TextFormField( - style: TextStyle( - fontSize: 18.0, - color: Theme.of(context) - .accentTextTheme - .overline - .color), - controller: _cryptoAmountController, - keyboardType: TextInputType.numberWithOptions( - signed: false, decimal: true), - inputFormatters: [ - FilteringTextInputFormatter.deny(RegExp('[- ]')) - ], - decoration: InputDecoration( - prefixIcon: SizedBox( - width: 75, - child: Padding( - padding: EdgeInsets.only(left: 8, top: 12), - child: Text('OXEN:', - style: TextStyle( - fontSize: 18, - color: Theme.of(context) - .accentTextTheme - .overline - .color))), - ), - suffixIcon: Container( - width: 1, - padding: EdgeInsets.only(top: 0), - child: Center( - child: InkWell( - onTap: () => sendStore.setSendAll(), - child: Text(S.of(context).all, - style: TextStyle( - fontSize: 10, - color: Theme.of(context) - .accentTextTheme - .overline - .decorationColor)))), - ), - hintStyle: TextStyle( - fontSize: 18.0, - color: Theme.of(context).hintColor), - hintText: '0.0000', - focusedBorder: OutlineInputBorder( - borderSide: BorderSide( - color: OxenPalette.teal, width: 2.0)), - enabledBorder: OutlineInputBorder( - borderSide: BorderSide( - color: Theme.of(context).focusColor, - width: 1.0)), - errorBorder: OutlineInputBorder( - borderSide: BorderSide( - color: OxenPalette.red, width: 1.0)), - focusedErrorBorder: OutlineInputBorder( - borderSide: BorderSide( - color: OxenPalette.red, width: 1.0)), - errorStyle: TextStyle(color: OxenPalette.red)), - validator: (value) { - sendStore.validateOXEN( - value, balanceStore.unlockedBalance); - return sendStore.errorMessage; - }), + oxenAmountField( + context: context, + setAll: () => sendStore.setSendAll(t), + controller: _cryptoAmountController, + validator: (value) { + sendStore.validateOXEN(value ?? '', balanceStore.unlockedBalance, t); + return sendStore.errorMessage; + }, ), Padding( padding: const EdgeInsets.only(top: 20), - child: TextFormField( + child: !settingsStore.enableFiatCurrency ? null : TextFormField( style: TextStyle( fontSize: 18.0, color: Theme.of(context) .accentTextTheme .overline - .color), + ?.color), controller: _fiatAmountController, keyboardType: TextInputType.numberWithOptions( signed: false, decimal: true), @@ -300,7 +233,7 @@ class SendFormState extends State { color: Theme.of(context) .accentTextTheme .overline - .color))), + ?.color))), ), hintStyle: TextStyle( fontSize: 18.0, @@ -326,14 +259,14 @@ class SendFormState extends State { child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Text(S.of(context).send_estimated_fee, + Text(t.send_estimated_fee, style: TextStyle( fontSize: 14, fontWeight: FontWeight.w500, color: Theme.of(context) .accentTextTheme .overline - .backgroundColor, + ?.backgroundColor, )), Text( '${calculateEstimatedFee(priority: settingsStore.transactionPriority)} OXEN', @@ -343,7 +276,7 @@ class SendFormState extends State { color: Theme.of(context) .primaryTextTheme .overline - .backgroundColor, + ?.backgroundColor, )) ], ), @@ -351,15 +284,14 @@ class SendFormState extends State { SizedBox( width: double.infinity, child: Text( - S.of(context).send_priority( - settingsStore.transactionPriority.toString()), + t.send_priority(settingsStore.transactionPriority.getTitle(t)), style: TextStyle( fontSize: 12, fontWeight: FontWeight.w500, color: Theme.of(context) .primaryTextTheme .subtitle2 - .color, + ?.color, height: 1.3)), ), ]), @@ -370,12 +302,12 @@ class SendFormState extends State { ), bottomSection: Observer(builder: (_) { return SlideToAct( - text: S.of(context).send_title, - outerColor: Theme.of(context).primaryTextTheme.subtitle2.color, + text: t.send_title, + outerColor: Theme.of(context).primaryTextTheme.subtitle2?.color, innerColor: OxenPalette.teal, onFutureSubmit: syncStore.status is SyncedSyncStatus ? () async { - if (_formKey.currentState.validate()) { + if (_formKey.currentState?.validate() ?? false) { var isSuccessful = false; await Navigator.of(context).pushNamed(Routes.auth, @@ -387,7 +319,8 @@ class SendFormState extends State { } await sendStore.createTransaction( - address: _addressController.text); + recipient: _addressController.text, + l10n: t); Navigator.of(auth.context).pop(); isSuccessful = true; @@ -437,30 +370,32 @@ class SendFormState extends State { reaction((_) => sendStore.state, (SendingState state) { if (state is SendingFailed) { - WidgetsBinding.instance.addPostFrameCallback((_) { - showSimpleOxenDialog(context, S.of(context).error, state.error, + WidgetsBinding.instance?.addPostFrameCallback((_) { + showSimpleOxenDialog(context, tr(context).error, state.error, onPressed: (_) => Navigator.of(context).pop()); }); } - if (state is TransactionCreatedSuccessfully) { - WidgetsBinding.instance.addPostFrameCallback((_) { - showSimpleOxenDialog( - context, - S.of(context).confirm_sending, - S.of(context).commit_transaction_amount_fee( - sendStore.pendingTransaction.amount, - sendStore.pendingTransaction.fee), onPressed: (_) { - Navigator.of(context).pop(); - sendStore.commitTransaction(); - }); + if (state is TransactionCreatedSuccessfully && sendStore.pendingTransaction != null) { + WidgetsBinding.instance?.addPostFrameCallback((_) { + showConfirmOxenDialog( + context, + tr(context).confirm_sending, + tr(context).confirm_transaction_amount_fee( + sendStore.pendingTransaction!.amount, + sendStore.pendingTransaction!.fee), + onConfirm: (_) { + Navigator.of(context).pop(); + sendStore.commitTransaction(); + } + ); }); } if (state is TransactionCommitted) { - WidgetsBinding.instance.addPostFrameCallback((_) { + WidgetsBinding.instance?.addPostFrameCallback((_) { showSimpleOxenDialog( - context, S.of(context).sending, S.of(context).transaction_sent, + context, tr(context).sending, tr(context).transaction_sent, onPressed: (_) { _addressController.text = ''; _cryptoAmountController.text = ''; diff --git a/lib/src/screens/settings/change_language.dart b/lib/src/screens/settings/change_language.dart deleted file mode 100644 index 2a8e3102..00000000 --- a/lib/src/screens/settings/change_language.dart +++ /dev/null @@ -1,65 +0,0 @@ -import 'package:flutter/cupertino.dart'; -import 'package:flutter/material.dart'; -import 'package:oxen_wallet/generated/l10n.dart'; -import 'package:oxen_wallet/src/domain/common/language.dart'; -import 'package:oxen_wallet/src/screens/base_page.dart'; -import 'package:oxen_wallet/src/stores/settings/settings_store.dart'; -import 'package:oxen_wallet/src/widgets/oxen_dialog.dart'; -import 'package:provider/provider.dart'; - -class ChangeLanguage extends BasePage { - @override - String get title => S.current.settings_change_language; - - @override - Widget body(BuildContext context) { - final settingsStore = Provider.of(context); - final currentLanguage = Provider.of(context); - - final currentColor = Theme.of(context).selectedRowColor; - final notCurrentColor = - Theme.of(context).accentTextTheme.subtitle1.backgroundColor; - - return Container( - padding: EdgeInsets.only(top: 10.0, bottom: 10.0), - child: ListView.builder( - itemCount: languages.values.length, - itemBuilder: (BuildContext context, int index) { - final isCurrent = settingsStore.languageCode == null - ? false - : languages.keys.elementAt(index) == settingsStore.languageCode; - - return Container( - margin: EdgeInsets.only(top: 10.0, bottom: 10.0), - color: isCurrent ? currentColor : notCurrentColor, - child: ListTile( - title: Text( - languages.values.elementAt(index), - style: TextStyle( - fontSize: 16.0, - color: - Theme.of(context).primaryTextTheme.headline6.color), - ), - onTap: () async { - if (!isCurrent) { - await showSimpleOxenDialog( - context, - S.of(context).change_language, - S.of(context).change_language_to( - languages.values.elementAt(index)), - onPressed: (context) { - settingsStore.saveLanguageCode( - languageCode: languages.keys.elementAt(index)); - currentLanguage.setCurrentLanguage( - languages.keys.elementAt(index)); - Navigator.of(context).pop(); - }, - ); - } - }, - ), - ); - }, - )); - } -} diff --git a/lib/src/screens/settings/items/settings_item.dart b/lib/src/screens/settings/items/settings_item.dart index 0d96806f..fcf08489 100644 --- a/lib/src/screens/settings/items/settings_item.dart +++ b/lib/src/screens/settings/items/settings_item.dart @@ -4,18 +4,18 @@ import 'package:oxen_wallet/src/screens/settings/attributes.dart'; class SettingsItem { SettingsItem( {this.onTaped, - this.title, + required this.title, this.link, this.image, this.widget, - this.attribute, + required this.attribute, this.widgetBuilder}); - final VoidCallback onTaped; + final VoidCallback? onTaped; final String title; - final String link; - final Image image; - final Widget widget; + final String? link; + final Image? image; + final Widget? widget; final Attributes attribute; - final WidgetBuilder widgetBuilder; + final WidgetBuilder? widgetBuilder; } diff --git a/lib/src/screens/settings/settings.dart b/lib/src/screens/settings/settings.dart index 7209498c..a5d0ca29 100644 --- a/lib/src/screens/settings/settings.dart +++ b/lib/src/screens/settings/settings.dart @@ -1,7 +1,6 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_mobx/flutter_mobx.dart'; -import 'package:oxen_wallet/generated/l10n.dart'; import 'package:oxen_wallet/palette.dart'; import 'package:oxen_wallet/routes.dart'; import 'package:oxen_wallet/src/domain/common/balance_display_mode.dart'; @@ -11,6 +10,7 @@ import 'package:oxen_wallet/src/screens/base_page.dart'; import 'package:oxen_wallet/src/screens/disclaimer/disclaimer_page.dart'; import 'package:oxen_wallet/src/screens/settings/attributes.dart'; import 'package:oxen_wallet/src/screens/settings/items/settings_item.dart'; +import 'package:oxen_wallet/l10n.dart'; // Settings widgets import 'package:oxen_wallet/src/screens/settings/widgets/settings_link_list_row.dart'; @@ -28,7 +28,7 @@ import 'package:url_launcher/url_launcher.dart'; class SettingsPage extends BasePage { @override - String get title => S.current.settings_title; + String getTitle(AppLocalizations l10n) => l10n.settings_title; @override Color get backgroundColor => Palette.lightGrey2; @@ -45,18 +45,21 @@ class SettingsForm extends StatefulWidget { } class SettingsFormState extends State { + final _sessionImage = Image.asset('assets/images/Session.png'); final _telegramImage = Image.asset('assets/images/Telegram.png'); final _twitterImage = Image.asset('assets/images/Twitter.png'); final _emailText = 'team@oxen.io'; + final _sessionText = 'getsession.org'; + final _githubText = 'github.com/oxen-io'; final _telegramText = 't.me/Oxen_Community'; final _twitterText = 'twitter.com/Oxen_io'; - final _githubText = 'github.com/oxen-io'; final _emailUrl = 'mailto:team@oxen.io'; - final _telegramUrl = 'https:t.me/Oxen_Community'; - final _twitterUrl = 'https:twitter.com/Oxen_io'; - final _githubUrl = 'https:github.com/oxen-io'; + final _sessionUrl = 'https://getsession.org'; + final _githubUrl = 'https://github.com/oxen-io'; + final _telegramUrl = 'https://t.me/Oxen_Community'; + final _twitterUrl = 'https://twitter.com/Oxen_io'; final _items = []; @@ -66,84 +69,85 @@ class SettingsFormState extends State { void _setSettingsList() { final settingsStore = context.read(); + final t = tr(context); _items.addAll([ SettingsItem( - title: S.current.settings_nodes, attribute: Attributes.header), + title: t.settings_nodes, attribute: Attributes.header), SettingsItem( onTaped: () => Navigator.of(context).pushNamed(Routes.nodeList), - title: S.current.settings_current_node, + title: t.settings_current_node, widget: Observer( builder: (_) => Text( - settingsStore.node == null ? '' : settingsStore.node.uri, + settingsStore.node?.uri ?? '', textAlign: TextAlign.right, style: TextStyle( fontSize: 16.0, color: - Theme.of(context).primaryTextTheme.subtitle2.color), + Theme.of(context).primaryTextTheme.subtitle2?.color), )), attribute: Attributes.widget), SettingsItem( - title: S.current.settings_wallets, attribute: Attributes.header), + title: t.settings_wallets, attribute: Attributes.header), SettingsItem( onTaped: () => _setBalance(context), - title: S.current.settings_display_balance_as, + title: t.settings_display_balance_as, widget: Observer( builder: (_) => Text( - settingsStore.balanceDisplayMode.toString(), + settingsStore.balanceDisplayMode.getTitle(t), textAlign: TextAlign.right, style: TextStyle( fontSize: 16.0, color: - Theme.of(context).primaryTextTheme.subtitle2.color), + Theme.of(context).primaryTextTheme.subtitle2?.color), )), attribute: Attributes.widget), SettingsItem( onTaped: () => _setBalanceDetail(context), - title: S.current.settings_balance_detail, + title: t.settings_balance_detail, widget: Observer( builder: (_) => Text( - settingsStore.balanceDetail.toString(), + settingsStore.balanceDetail.getTitle(t), textAlign: TextAlign.right, style: TextStyle( fontSize: 16.0, color: - Theme.of(context).primaryTextTheme.subtitle2.color), + Theme.of(context).primaryTextTheme.subtitle2?.color), )), attribute: Attributes.widget), SettingsItem( - title: S.current.settings_enable_fiat_currency, + title: t.settings_enable_fiat_currency, attribute: Attributes.switcher), SettingsItem( onTaped: () => _setCurrency(context), - title: S.current.settings_currency, + title: t.settings_currency, widget: Observer( builder: (_) => Text( - settingsStore.fiatCurrency.toString(), + settingsStore.fiatCurrency.getTitle(t), textAlign: TextAlign.right, style: TextStyle( fontSize: 16.0, color: - Theme.of(context).primaryTextTheme.subtitle2.color), + Theme.of(context).primaryTextTheme.subtitle2?.color), )), attribute: Attributes.widget), SettingsItem( onTaped: () => _setTransactionPriority(context), - title: S.current.settings_fee_priority, + title: t.settings_fee_priority, widget: Observer( builder: (_) => Text( - settingsStore.transactionPriority.toString(), + settingsStore.transactionPriority.getTitle(t), textAlign: TextAlign.right, style: TextStyle( fontSize: 16.0, color: - Theme.of(context).primaryTextTheme.subtitle2.color), + Theme.of(context).primaryTextTheme.subtitle2?.color), )), attribute: Attributes.widget), SettingsItem( - title: S.current.settings_save_recipient_address, + title: t.settings_save_recipient_address, attribute: Attributes.switcher), SettingsItem( - title: S.current.settings_personal, attribute: Attributes.header), + title: t.settings_personal, attribute: Attributes.header), SettingsItem( onTaped: () { Navigator.of(context).pushNamed(Routes.auth, @@ -156,19 +160,19 @@ class SettingsFormState extends State { Navigator.of(context).pop()) : null); }, - title: S.current.settings_change_pin, + title: t.settings_change_pin, attribute: Attributes.arrow), SettingsItem( onTaped: () => Navigator.pushNamed(context, Routes.changeLanguage), - title: S.current.settings_change_language, + title: t.settings_change_language, attribute: Attributes.arrow), SettingsItem( - title: S.current.settings_allow_biometric_authentication, + title: t.settings_allow_biometric_authentication, attribute: Attributes.switcher), SettingsItem( - title: S.current.settings_dark_mode, attribute: Attributes.switcher), + title: t.settings_dark_mode, attribute: Attributes.switcher), SettingsItem( - title: S.current.settings_support, attribute: Attributes.header), + title: t.settings_support, attribute: Attributes.header), SettingsItem( onTaped: () => _launchUrl(_emailUrl), title: 'Email', @@ -181,6 +185,12 @@ class SettingsFormState extends State { link: _githubText, image: null, attribute: Attributes.link), + SettingsItem( + onTaped: () => _launchUrl(_sessionUrl), + title: 'Session', + link: _sessionText, + image: _sessionImage, + attribute: Attributes.link), SettingsItem( onTaped: () => _launchUrl(_telegramUrl), title: 'Telegram', @@ -200,15 +210,15 @@ class SettingsFormState extends State { CupertinoPageRoute( builder: (BuildContext context) => DisclaimerPage())); }, - title: S.current.settings_terms_and_conditions, + title: t.settings_terms_and_conditions, attribute: Attributes.arrow), SettingsItem( onTaped: () => Navigator.pushNamed(context, Routes.faq), - title: S.current.faq, + title: t.faq, attribute: Attributes.arrow), SettingsItem( onTaped: () => Navigator.pushNamed(context, Routes.changelog), - title: S.current.changelog, + title: t.changelog, attribute: Attributes.arrow) ]); setState(() {}); @@ -219,7 +229,7 @@ class SettingsFormState extends State { @override void initState() { super.initState(); - WidgetsBinding.instance.addPostFrameCallback(_afterLayout); + WidgetsBinding.instance?.addPostFrameCallback(_afterLayout); } Widget _getWidget(SettingsItem item) { @@ -246,7 +256,7 @@ class SettingsFormState extends State { return SettingsTextListRow( onTaped: item.onTaped, title: item.title, - widget: item.widget, + widget: item.widget ?? Offstage(), ); case Attributes.rawWidget: return SettingRawWidgetListRow(widgetBuilder: item.widgetBuilder); @@ -286,7 +296,7 @@ class SettingsFormState extends State { color: Theme.of(context) .accentTextTheme .headline5 - .backgroundColor, + ?.backgroundColor, padding: EdgeInsets.only( left: 20.0, right: 20.0, @@ -302,7 +312,7 @@ class SettingsFormState extends State { }), ListTile( contentPadding: EdgeInsets.only(left: 20.0), - title: Text(S.current.version(settingsStore.currentVersion), + title: Text(tr(context).version(settingsStore.currentVersion), style: TextStyle(fontSize: 14.0, color: Palette.wildDarkBlue)), ) ], @@ -312,7 +322,7 @@ class SettingsFormState extends State { Future _setBalance(BuildContext context) async { final settingsStore = context.read(); final selectedDisplayMode = - await presentPicker(context, BalanceDisplayMode.all); + await presentPicker(context, BalanceDisplayMode.all, initial: settingsStore.balanceDisplayMode); if (selectedDisplayMode != null) { await settingsStore.setCurrentBalanceDisplayMode( @@ -322,7 +332,7 @@ class SettingsFormState extends State { Future _setBalanceDetail(BuildContext context) async { final settingsStore = context.read(); - final balanceDetail = await presentPicker(context, AmountDetail.all); + final balanceDetail = await presentPicker(context, AmountDetail.all, initial: settingsStore.balanceDetail); if (balanceDetail != null) { await settingsStore.setCurrentBalanceDetail(balanceDetail: balanceDetail); @@ -331,7 +341,7 @@ class SettingsFormState extends State { Future _setCurrency(BuildContext context) async { final settingsStore = context.read(); - final selectedCurrency = await presentPicker(context, FiatCurrency.all); + final selectedCurrency = await presentPicker(context, FiatCurrency.all, initial: settingsStore.fiatCurrency); if (selectedCurrency != null) { await settingsStore.setCurrentFiatCurrency(currency: selectedCurrency); @@ -341,7 +351,7 @@ class SettingsFormState extends State { Future _setTransactionPriority(BuildContext context) async { final settingsStore = context.read(); final selectedPriority = - await presentPicker(context, OxenTransactionPriority.all); + await presentPicker(context, OxenTransactionPriority.all, initial: settingsStore.transactionPriority); if (selectedPriority != null) { await settingsStore.setCurrentTransactionPriority( diff --git a/lib/src/screens/settings/widgets/settings_link_list_row.dart b/lib/src/screens/settings/widgets/settings_link_list_row.dart index 5d5b1dbb..33eeef7b 100644 --- a/lib/src/screens/settings/widgets/settings_link_list_row.dart +++ b/lib/src/screens/settings/widgets/settings_link_list_row.dart @@ -3,17 +3,17 @@ import 'package:oxen_wallet/palette.dart'; class SettingsLinktListRow extends StatelessWidget { SettingsLinktListRow( - {@required this.onTaped, this.title, this.link, this.image}); + {this.onTaped, required this.title, this.link, this.image}); - final VoidCallback onTaped; + final VoidCallback? onTaped; final String title; - final String link; - final Image image; + final String? link; + final Image? image; @override Widget build(BuildContext context) { return Container( - color: Theme.of(context).accentTextTheme.headline5.backgroundColor, + color: Theme.of(context).accentTextTheme.headline5?.backgroundColor, child: ListTile( contentPadding: EdgeInsets.only(left: 20.0, right: 20.0), title: Row( @@ -28,13 +28,13 @@ class SettingsLinktListRow extends StatelessWidget { style: TextStyle( fontSize: 15.0, fontWeight: FontWeight.w500, - color: Theme.of(context).primaryTextTheme.headline6.color), + color: Theme.of(context).primaryTextTheme.headline6?.color), ), ) ], ), - trailing: Text( - link, + trailing: link == null ? null : Text( + link!, style: TextStyle(fontSize: 14.0, color: OxenPalette.teal), ), onTap: onTaped, diff --git a/lib/src/screens/settings/widgets/settings_raw_widget_list_row.dart b/lib/src/screens/settings/widgets/settings_raw_widget_list_row.dart index 330cb153..28798c5f 100644 --- a/lib/src/screens/settings/widgets/settings_raw_widget_list_row.dart +++ b/lib/src/screens/settings/widgets/settings_raw_widget_list_row.dart @@ -1,15 +1,15 @@ import 'package:flutter/material.dart'; class SettingRawWidgetListRow extends StatelessWidget { - SettingRawWidgetListRow({@required this.widgetBuilder}); + SettingRawWidgetListRow({this.widgetBuilder}); - final WidgetBuilder widgetBuilder; + final WidgetBuilder? widgetBuilder; @override Widget build(BuildContext context) { return Container( - color: Theme.of(context).accentTextTheme.headline5.backgroundColor, - child: widgetBuilder(context) ?? Container(), + color: Theme.of(context).accentTextTheme.headline5?.backgroundColor, + child: widgetBuilder?.call(context) ?? Container(), ); } } diff --git a/lib/src/screens/settings/widgets/settings_switch_list_row.dart b/lib/src/screens/settings/widgets/settings_switch_list_row.dart index ca722f38..9402ab80 100644 --- a/lib/src/screens/settings/widgets/settings_switch_list_row.dart +++ b/lib/src/screens/settings/widgets/settings_switch_list_row.dart @@ -1,6 +1,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_mobx/flutter_mobx.dart'; -import 'package:oxen_wallet/generated/l10n.dart'; +import 'package:oxen_wallet/l10n.dart'; import 'package:oxen_wallet/src/stores/settings/settings_store.dart'; import 'package:oxen_wallet/src/widgets/standart_switch.dart'; import 'package:oxen_wallet/theme_changer.dart'; @@ -8,15 +8,15 @@ import 'package:oxen_wallet/themes.dart'; import 'package:provider/provider.dart'; class SettingsSwitchListRow extends StatelessWidget { - SettingsSwitchListRow({@required this.title}); + SettingsSwitchListRow({required this.title}); final String title; - Widget _getSwitch(BuildContext context) { + Widget? _getSwitch(BuildContext context) { final settingsStore = Provider.of(context); final _themeChanger = Provider.of(context); - if (title == S.of(context).settings_save_recipient_address) { + if (title == tr(context).settings_save_recipient_address) { return Observer( builder: (_) => StandartSwitch( value: settingsStore.shouldSaveRecipientAddress, @@ -27,7 +27,7 @@ class SettingsSwitchListRow extends StatelessWidget { })); } - if (title == S.of(context).settings_allow_biometric_authentication) { + if (title == tr(context).settings_allow_biometric_authentication) { return Observer( builder: (_) => StandartSwitch( value: settingsStore.allowBiometricAuthentication, @@ -39,7 +39,7 @@ class SettingsSwitchListRow extends StatelessWidget { })); } - if (title == S.of(context).settings_dark_mode) { + if (title == tr(context).settings_dark_mode) { return Observer( builder: (_) => StandartSwitch( value: settingsStore.isDarkTheme, @@ -51,7 +51,7 @@ class SettingsSwitchListRow extends StatelessWidget { })); } - if (title == S.of(context).settings_enable_fiat_currency) { + if (title == tr(context).settings_enable_fiat_currency) { return Observer( builder: (_) => StandartSwitch( value: settingsStore.enableFiatCurrency, @@ -68,13 +68,13 @@ class SettingsSwitchListRow extends StatelessWidget { @override Widget build(BuildContext context) { return Container( - color: Theme.of(context).accentTextTheme.headline5.backgroundColor, + color: Theme.of(context).accentTextTheme.headline5?.backgroundColor, child: ListTile( contentPadding: EdgeInsets.only(left: 20.0, right: 20.0), title: Text(title, style: TextStyle( fontSize: 16.0, - color: Theme.of(context).primaryTextTheme.headline6.color)), + color: Theme.of(context).primaryTextTheme.headline6?.color)), trailing: _getSwitch(context)), ); } diff --git a/lib/src/screens/settings/widgets/settings_text_list_row.dart b/lib/src/screens/settings/widgets/settings_text_list_row.dart index 4405f8f2..644f7978 100644 --- a/lib/src/screens/settings/widgets/settings_text_list_row.dart +++ b/lib/src/screens/settings/widgets/settings_text_list_row.dart @@ -1,16 +1,16 @@ import 'package:flutter/material.dart'; class SettingsTextListRow extends StatelessWidget { - SettingsTextListRow({@required this.onTaped, this.title, this.widget}); + SettingsTextListRow({this.onTaped, required this.title, required this.widget}); - final VoidCallback onTaped; + final VoidCallback? onTaped; final String title; final Widget widget; @override Widget build(BuildContext context) { return Container( - color: Theme.of(context).accentTextTheme.headline5.backgroundColor, + color: Theme.of(context).accentTextTheme.headline5?.backgroundColor, child: ListTile( contentPadding: EdgeInsets.only(left: 20.0, right: 20.0), title: Row( @@ -21,7 +21,7 @@ class SettingsTextListRow extends StatelessWidget { title, style: TextStyle( fontSize: 16.0, - color: Theme.of(context).primaryTextTheme.headline6.color), + color: Theme.of(context).primaryTextTheme.headline6?.color), ), ), Flexible(child: widget) diff --git a/lib/src/screens/setup_pin_code/setup_pin_code.dart b/lib/src/screens/setup_pin_code/setup_pin_code.dart index 645155bc..25508a18 100644 --- a/lib/src/screens/setup_pin_code/setup_pin_code.dart +++ b/lib/src/screens/setup_pin_code/setup_pin_code.dart @@ -1,20 +1,19 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; -import 'package:flutter/cupertino.dart'; import 'package:provider/provider.dart'; import 'package:oxen_wallet/src/stores/user/user_store.dart'; import 'package:oxen_wallet/src/screens/pin_code/pin_code.dart'; import 'package:oxen_wallet/src/screens/base_page.dart'; import 'package:oxen_wallet/src/stores/settings/settings_store.dart'; -import 'package:oxen_wallet/generated/l10n.dart'; +import 'package:oxen_wallet/l10n.dart'; class SetupPinCodePage extends BasePage { - SetupPinCodePage({this.onPinCodeSetup}); + SetupPinCodePage({required this.onPinCodeSetup}); final Function(BuildContext, String) onPinCodeSetup; @override - String get title => S.current.setup_pin; + String getTitle(AppLocalizations t) => t.setup_pin; @override Widget body(BuildContext context) => @@ -23,7 +22,7 @@ class SetupPinCodePage extends BasePage { class SetupPinCodeForm extends PinCodeWidget { SetupPinCodeForm( - {@required this.onPinCodeSetup, @required bool hasLengthSwitcher}) + {required this.onPinCodeSetup, required bool hasLengthSwitcher}) : super(hasLengthSwitcher: hasLengthSwitcher); final Function(BuildContext, String) onPinCodeSetup; @@ -34,41 +33,37 @@ class SetupPinCodeForm extends PinCodeWidget { class _SetupPinCodeFormState extends PinCodeState { - _SetupPinCodeFormState() { - title = S.current.enter_your_pin; - } bool isEnteredOriginalPin() => _originalPin.isNotEmpty; - Function(BuildContext) onPinCodeSetup; List _originalPin = []; - UserStore _userStore; - SettingsStore _settingsStore; + UserStore? _userStore; + SettingsStore? _settingsStore; @override void onPinCodeEntered(PinCodeState state) { if (!isEnteredOriginalPin()) { - _originalPin = state.pin; - state.title = S.current.enter_your_pin_again; + _originalPin = [...state.pin]; + state.setTitle(tr(context).enter_your_pin_again); state.clear(); } else { if (listEquals(state.pin, _originalPin)) { - final String pin = state.pin.fold('', (ac, val) => ac + '$val'); - _userStore.set(password: pin); - _settingsStore.setDefaultPinLength(pinLength: state.pinLength); + final pin = state.pin.join(); + _userStore?.set(password: pin); + _settingsStore?.setDefaultPinLength(pinLength: state.pinLength); showDialog( context: context, barrierDismissible: false, builder: (BuildContext context) { return AlertDialog( - content: Text(S.of(context).setup_successful), + content: Text(tr(context).setup_successful), actions: [ FlatButton( - child: Text(S.of(context).ok), + child: Text(tr(context).ok), onPressed: () { Navigator.of(context).pop(); widget.onPinCodeSetup(context, pin); - reset(); + reset(tr(context)); }, ), ], @@ -79,10 +74,10 @@ class _SetupPinCodeFormState context: context, builder: (BuildContext context) { return AlertDialog( - content: Text(S.of(context).pin_is_incorrect), + content: Text(tr(context).pin_is_incorrect), actions: [ FlatButton( - child: Text(S.of(context).ok), + child: Text(tr(context).ok), onPressed: () { Navigator.of(context).pop(); }, @@ -91,14 +86,14 @@ class _SetupPinCodeFormState ); }); - reset(); + reset(tr(context)); } } } - void reset() { + void reset(AppLocalizations l10n) { clear(); - setTitle(S.current.enter_your_pin); + setTitle(l10n.enter_your_pin); _originalPin = []; } diff --git a/lib/src/screens/show_keys/show_keys_page.dart b/lib/src/screens/show_keys/show_keys_page.dart index ac3718ec..aa2a76d9 100644 --- a/lib/src/screens/show_keys/show_keys_page.dart +++ b/lib/src/screens/show_keys/show_keys_page.dart @@ -1,10 +1,9 @@ import 'package:provider/provider.dart'; import 'package:flutter/material.dart'; -import 'package:flutter/cupertino.dart'; import 'package:flutter/services.dart'; import 'package:flutter_mobx/flutter_mobx.dart'; import 'package:oxen_wallet/palette.dart'; -import 'package:oxen_wallet/generated/l10n.dart'; +import 'package:oxen_wallet/l10n.dart'; import 'package:oxen_wallet/src/stores/wallet/wallet_keys_store.dart'; import 'package:oxen_wallet/src/screens/base_page.dart'; @@ -13,7 +12,7 @@ class ShowKeysPage extends BasePage { bool get isModalBackButton => true; @override - String get title => S.current.wallet_keys; + String getTitle(AppLocalizations t) => t.wallet_keys; @override Widget body(BuildContext context) { @@ -24,10 +23,10 @@ class ShowKeysPage extends BasePage { child: Observer( builder: (_) { final keysMap = { - S.of(context).view_key_public: walletKeysStore.publicViewKey, - S.of(context).view_key_private: walletKeysStore.privateViewKey, - S.of(context).spend_key_public: walletKeysStore.publicSpendKey, - S.of(context).spend_key_private: walletKeysStore.privateSpendKey + tr(context).view_key_public: walletKeysStore.publicViewKey, + tr(context).view_key_private: walletKeysStore.privateViewKey, + tr(context).spend_key_public: walletKeysStore.publicSpendKey, + tr(context).spend_key_private: walletKeysStore.privateSpendKey }; return ListView.separated( @@ -47,9 +46,9 @@ class ShowKeysPage extends BasePage { onTap: () { Clipboard.setData(ClipboardData( text: keysMap.values.elementAt(index))); - Scaffold.of(context).showSnackBar(SnackBar( + ScaffoldMessenger.of(context).showSnackBar(SnackBar( content: Text( - S.of(context).copied_key_to_clipboard(key), + tr(context).copied_key_to_clipboard(key), textAlign: TextAlign.center, style: TextStyle(color: Colors.white), ), diff --git a/lib/src/screens/stake/new_stake_page.dart b/lib/src/screens/stake/new_stake_page.dart index cc8f97fc..9ca37ec1 100644 --- a/lib/src/screens/stake/new_stake_page.dart +++ b/lib/src/screens/stake/new_stake_page.dart @@ -1,15 +1,14 @@ -import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; import 'package:flutter_mobx/flutter_mobx.dart'; import 'package:mobx/mobx.dart'; -import 'package:oxen_wallet/generated/l10n.dart'; +import 'package:oxen_wallet/l10n.dart'; import 'package:oxen_wallet/palette.dart'; import 'package:oxen_wallet/routes.dart'; import 'package:oxen_wallet/src/domain/common/balance_display_mode.dart'; import 'package:oxen_wallet/src/node/sync_status.dart'; import 'package:oxen_wallet/src/screens/auth/auth_page.dart'; import 'package:oxen_wallet/src/screens/base_page.dart'; +import 'package:oxen_wallet/src/screens/oxen_amount.dart'; import 'package:oxen_wallet/src/stores/balance/balance_store.dart'; import 'package:oxen_wallet/src/stores/send/send_store.dart'; import 'package:oxen_wallet/src/stores/send/sending_state.dart'; @@ -18,14 +17,16 @@ import 'package:oxen_wallet/src/stores/sync/sync_store.dart'; import 'package:oxen_wallet/src/stores/wallet/wallet_store.dart'; import 'package:oxen_wallet/src/wallet/oxen/calculate_estimated_fee.dart'; import 'package:oxen_wallet/src/wallet/oxen/transaction/transaction_priority.dart'; -import 'package:oxen_wallet/src/widgets/oxen_text_field.dart'; import 'package:oxen_wallet/src/widgets/scollable_with_bottom_section.dart'; import 'package:oxen_wallet/src/widgets/slide_to_act.dart'; +import 'package:oxen_wallet/src/widgets/address_text_field.dart'; +import 'package:oxen_wallet/src/widgets/oxen_dialog.dart'; +import 'package:oxen_wallet/src/util/validators.dart'; import 'package:provider/provider.dart'; class NewStakePage extends BasePage { @override - String get title => S.current.title_new_stake; + String getTitle(AppLocalizations t) => t.title_new_stake; @override bool get isModalBackButton => true; @@ -43,7 +44,7 @@ class NewStakeForm extends StatefulWidget { } class NewStakeFormState extends State { - final _addressController = TextEditingController(); + final _snpkController = TextEditingController(); final _cryptoAmountController = TextEditingController(); final _focusNode = FocusNode(); @@ -68,6 +69,8 @@ class NewStakeFormState extends State { _setEffects(context); + final t = tr(context); + return ScrollableWithBottomSection( contentPadding: EdgeInsets.all(0), content: Column( @@ -89,7 +92,7 @@ class NewStakeFormState extends State { color: Theme.of(context) .accentTextTheme .subtitle2 - .backgroundColor))), + ?.backgroundColor ?? Colors.white))), child: SizedBox( height: 56, width: double.infinity, @@ -101,7 +104,7 @@ class NewStakeFormState extends State { crossAxisAlignment: CrossAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.center, children: [ - Text(S.of(context).send_your_wallet, + Text(t.send_your_wallet, style: TextStyle( fontSize: 12, color: OxenPalette.teal)), Text(walletStore.name, @@ -110,7 +113,7 @@ class NewStakeFormState extends State { color: Theme.of(context) .accentTextTheme .overline - .color, + ?.color, height: 1.25)), ]); }), @@ -124,13 +127,13 @@ class NewStakeFormState extends State { return Column( mainAxisAlignment: MainAxisAlignment.center, children: [ - Text(S.current.oxen_available_balance, + Text(t.oxen_available_balance, style: TextStyle( fontSize: 12, color: Theme.of(context) .accentTextTheme .overline - .backgroundColor, + ?.backgroundColor, )), Text(availableBalance, style: TextStyle( @@ -138,7 +141,7 @@ class NewStakeFormState extends State { color: Theme.of(context) .accentTextTheme .overline - .color, + ?.color, height: 1.1)), ]); }) @@ -152,64 +155,35 @@ class NewStakeFormState extends State { padding: EdgeInsets.only(left: 18, right: 18, top: 10, bottom: 30), child: Column(children: [ - OxenTextField( - controller: _addressController, - hintText: S.of(context).service_node_key, + AddressTextField( + controller: _snpkController, + placeholder: t.service_node_key, focusNode: _focusNode, + validator: (value) => isHexKey(value) ? null : t.error_text_service_node, + options: [AddressTextFieldOption.qrCode], + ), + oxenAmountField( + context: context, + setAll: () => sendStore.setSendAll(t), + controller: _cryptoAmountController, validator: (value) { - final pattern = RegExp('[0-9a-fA-F]{64}'); - if (!pattern.hasMatch(value)) { - return S.of(context).error_text_service_node; - } - return null; + sendStore.validateOXEN(value ?? '', balanceStore.unlockedBalance, t); + return sendStore.errorMessage; }, ), - Padding( - padding: const EdgeInsets.only(top: 20), - child: OxenTextField( - controller: _cryptoAmountController, - validator: (value) { - sendStore.validateOXEN( - value, balanceStore.unlockedBalance); - return sendStore.errorMessage; - }, - hintText: '0.0000 OXEN', - keyboardType: TextInputType.numberWithOptions( - signed: false, decimal: true), - inputFormatters: [ - FilteringTextInputFormatter.deny( - RegExp('[\\-|\\ |\\,]')) - ], - suffixIcon: Container( - width: 1, - padding: EdgeInsets.only(top: 0), - child: Center( - child: InkWell( - onTap: () => sendStore.setSendAll(), - child: Text(S.of(context).all, - style: TextStyle( - fontSize: 10, - color: Theme.of(context) - .accentTextTheme - .overline - .decorationColor))), - ), - ), - ), - ), Padding( padding: const EdgeInsets.only(top: 12.0, bottom: 10), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Text(S.of(context).send_estimated_fee, + Text(t.send_estimated_fee, style: TextStyle( fontSize: 14, fontWeight: FontWeight.w500, color: Theme.of(context) .accentTextTheme .overline - .backgroundColor, + ?.backgroundColor, )), Text( '${calculateEstimatedFee(priority: OxenTransactionPriority.slow)} OXEN', @@ -219,7 +193,7 @@ class NewStakeFormState extends State { color: Theme.of(context) .primaryTextTheme .overline - .backgroundColor, + ?.backgroundColor, )) ], ), @@ -231,12 +205,12 @@ class NewStakeFormState extends State { ), bottomSection: Observer(builder: (_) { return SlideToAct( - text: S.of(context).stake_oxen, - outerColor: Theme.of(context).primaryTextTheme.subtitle2.color, + text: t.stake_oxen, + outerColor: Theme.of(context).primaryTextTheme.subtitle2?.color, innerColor: OxenPalette.teal, onFutureSubmit: syncStore.status is SyncedSyncStatus ? () async { - if (_formKey.currentState.validate()) { + if (_formKey.currentState?.validate() ?? false) { var isSuccessful = false; await Navigator.of(context).pushNamed(Routes.auth, @@ -248,7 +222,8 @@ class NewStakeFormState extends State { } await sendStore.createStake( - address: _addressController.text); + snPubkey: _snpkController.text, + l10n: t); Navigator.of(auth.context).pop(); isSuccessful = true; @@ -269,6 +244,7 @@ class NewStakeFormState extends State { } final sendStore = Provider.of(context); + final t = tr(context); reaction((_) => sendStore.cryptoAmount, (String amount) { if (amount != _cryptoAmountController.text) { @@ -286,16 +262,16 @@ class NewStakeFormState extends State { reaction((_) => sendStore.state, (SendingState state) { if (state is SendingFailed) { - WidgetsBinding.instance.addPostFrameCallback((_) { + WidgetsBinding.instance?.addPostFrameCallback((_) { showDialog( context: context, builder: (BuildContext context) { return AlertDialog( - title: Text(S.of(context).error), + title: Text(t.error), content: Text(state.error), actions: [ FlatButton( - child: Text(S.of(context).ok), + child: Text(t.ok), onPressed: () => Navigator.of(context).pop()) ], ); @@ -303,46 +279,36 @@ class NewStakeFormState extends State { }); } - if (state is TransactionCreatedSuccessfully) { - WidgetsBinding.instance.addPostFrameCallback((_) { - showDialog( - context: context, - builder: (BuildContext context) { - return AlertDialog( - title: Text(S.of(context).confirm_sending), - content: Text(S.of(context).commit_transaction_amount_fee( - sendStore.pendingTransaction.amount, - sendStore.pendingTransaction.fee)), - actions: [ - FlatButton( - child: Text(S.of(context).ok), - onPressed: () { - Navigator.of(context).pop(); - sendStore.commitTransaction(); - }), - FlatButton( - child: Text(S.of(context).cancel), - onPressed: () => Navigator.of(context).pop(), - ) - ], - ); - }); + if (state is TransactionCreatedSuccessfully && sendStore.pendingTransaction != null) { + WidgetsBinding.instance?.addPostFrameCallback((_) { + showConfirmOxenDialog( + context, + tr(context).confirm_stake, + tr(context).confirm_transaction_amount_fee( + sendStore.pendingTransaction!.amount, + sendStore.pendingTransaction!.fee), + onConfirm: (_) { + Navigator.of(context).pop(); + sendStore.commitTransaction(); + }, + onDismiss: (_) { Navigator.of(context).pop(); }, + ); }); } if (state is TransactionCommitted) { - WidgetsBinding.instance.addPostFrameCallback((_) { + WidgetsBinding.instance?.addPostFrameCallback((_) { showDialog( context: context, builder: (BuildContext context) { return AlertDialog( - title: Text(S.of(context).sending), - content: Text(S.of(context).transaction_sent), + title: Text(t.sending), + content: Text(t.transaction_sent), actions: [ FlatButton( - child: Text(S.of(context).ok), + child: Text(t.ok), onPressed: () { - _addressController.text = ''; + _snpkController.text = ''; _cryptoAmountController.text = ''; Navigator.of(context)..pop()..pop(); }) diff --git a/lib/src/screens/stake/stake_page.dart b/lib/src/screens/stake/stake_page.dart index 4372611f..c8885898 100644 --- a/lib/src/screens/stake/stake_page.dart +++ b/lib/src/screens/stake/stake_page.dart @@ -1,10 +1,9 @@ import 'dart:math'; -import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:oxen_coin/oxen_coin_structs.dart'; import 'package:oxen_coin/stake.dart'; -import 'package:oxen_wallet/generated/l10n.dart'; +import 'package:oxen_wallet/l10n.dart'; import 'package:oxen_wallet/palette.dart'; import 'package:oxen_wallet/routes.dart'; import 'package:oxen_wallet/src/screens/auth/auth_page.dart'; @@ -14,10 +13,13 @@ import 'package:oxen_wallet/src/wallet/oxen/oxen_amount_format.dart'; import 'package:oxen_wallet/src/widgets/nav/nav_list_header.dart'; import 'package:oxen_wallet/src/widgets/nav/nav_list_trailing.dart'; import 'package:oxen_wallet/src/widgets/oxen_dialog.dart'; +import 'package:oxen_wallet/devtools.dart'; + +const double fullSNStake = isTestnet ? 100 : 15000; extension StakeParsing on StakeRow { double get ownedPercentage { - final percentage = oxenAmountToDouble(amount) / 15000; + final percentage = oxenAmountToDouble(amount) / fullSNStake; if (percentage > 1) return 1; return percentage; } @@ -31,7 +33,7 @@ class StakePage extends BasePage { } class StakePageBody extends StatefulWidget { - StakePageBody({Key key}) : super(key: key); + StakePageBody({required Key key}) : super(key: key); @override StakePageBodyState createState() => StakePageBodyState(); @@ -45,24 +47,24 @@ class StakePageBodyState extends State { future: getAllStakes(), builder: (BuildContext context, AsyncSnapshot> snapshot) { if (snapshot.connectionState == ConnectionState.done) { - if (snapshot.hasError) { + if (snapshot.hasError || !snapshot.hasData) { return Center( child: Container( width: 200, height: 400, child: Center( - child: Text(snapshot.error.toString()), + child: Text(snapshot.error?.toString() ?? 'No snapshot stake data'), ) ), ); } - final allStakes = snapshot.data; + final allStakes = snapshot.data!; final stakeColor = allStakes.isEmpty ? OxenPalette.lightRed : OxenPalette.lime; var totalAmountStaked = 0; for (final stake in allStakes) { totalAmountStaked += stake.amount; } - final stakePercentage = allStakes.isEmpty ? 1.0 : min(oxenAmountToDouble(totalAmountStaked) / 15000, 1.0); + final stakePercentage = allStakes.isEmpty ? 1.0 : min(oxenAmountToDouble(totalAmountStaked) / fullSNStake, 1.0); return ListView( shrinkWrap: true, physics: NeverScrollableScrollPhysics(), @@ -84,9 +86,8 @@ class StakePageBodyState extends State { ), Center( child: Text(allStakes.isNotEmpty - ? oxenAmountToString(totalAmountStaked, - detail: AmountDetail.none) - : S.current.nothing_staked)), + ? oxenAmountToString(totalAmountStaked, detail: AmountDetail.none) + : tr(context).nothing_staked)), ], ), ), @@ -101,13 +102,13 @@ class StakePageBodyState extends State { .pushNamed(Routes.newStake), ), Text(allStakes.isEmpty - ? S.current.start_staking - : S.current.stake_more) + ? tr(context).start_staking + : tr(context).stake_more) ], ), ), if (allStakes.isNotEmpty) - NavListHeader(title: S.current.your_contributions), + NavListHeader(title: tr(context).your_contributions), if (allStakes.isNotEmpty) ListView.builder( shrinkWrap: true, @@ -116,14 +117,14 @@ class StakePageBodyState extends State { final stake = allStakes[index]; final serviceNodeKey = stake.serviceNodeKey; final nodeName = - '${serviceNodeKey.substring(0, 12)}...${serviceNodeKey.substring(serviceNodeKey.length - 4)}'; + '${serviceNodeKey.substring(0, 10)}...${serviceNodeKey.substring(serviceNodeKey.length - 3)}'; return Dismissible( key: Key(stake.serviceNodeKey), confirmDismiss: (direction) async { if (!canRequestUnstake(stake.serviceNodeKey)) { - Scaffold.of(context).showSnackBar(SnackBar( - content: Text(S.of(context).unable_unlock_stake), + ScaffoldMessenger.of(context).showSnackBar(SnackBar( + content: Text(tr(context).unable_unlock_stake), backgroundColor: Colors.red, )); return false; @@ -143,24 +144,25 @@ class StakePageBodyState extends State { if (isAuthenticated) { await showConfirmOxenDialog( context, - S.of(context).title_confirm_unlock_stake, - S.of(context).body_confirm_unlock_stake( - stake.serviceNodeKey), + tr(context).title_confirm_unlock_stake, + tr(context).body_confirm_unlock_stake(stake.serviceNodeKey), onDismiss: (buildContext) { isSuccessful = false; Navigator.of(buildContext).pop(); - }, onConfirm: (buildContext) { - isSuccessful = true; - Navigator.of(buildContext).pop(); - }); + }, + onConfirm: (buildContext) { + isSuccessful = true; + Navigator.of(buildContext).pop(); + }, + ); } return isSuccessful; }, onDismissed: (direction) async { await submitStakeUnlock(stake.serviceNodeKey); - Scaffold.of(context).showSnackBar(SnackBar( - content: Text(S.of(context).unlock_stake_requested), + ScaffoldMessenger.of(context).showSnackBar(SnackBar( + content: Text(tr(context).unlock_stake_requested), backgroundColor: Colors.green, )); }, diff --git a/lib/src/screens/subaddress/new_subaddress_page.dart b/lib/src/screens/subaddress/new_subaddress_page.dart index 5ee0d062..e798a458 100644 --- a/lib/src/screens/subaddress/new_subaddress_page.dart +++ b/lib/src/screens/subaddress/new_subaddress_page.dart @@ -1,8 +1,7 @@ -import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_mobx/flutter_mobx.dart'; import 'package:mobx/mobx.dart'; -import 'package:oxen_wallet/generated/l10n.dart'; +import 'package:oxen_wallet/l10n.dart'; import 'package:oxen_wallet/src/screens/base_page.dart'; import 'package:oxen_wallet/src/stores/subaddress_creation/subaddress_creation_state.dart'; import 'package:oxen_wallet/src/stores/subaddress_creation/subaddress_creation_store.dart'; @@ -13,7 +12,7 @@ import 'package:provider/provider.dart'; class NewSubaddressPage extends BasePage { @override - String get title => S.current.new_subaddress_title; + String getTitle(AppLocalizations t) => t.new_subaddress_title; @override Widget body(BuildContext context) => NewSubaddressForm(); @@ -27,7 +26,7 @@ class NewSubaddressPage extends BasePage { (SubaddressCreationState state) { if (state is SubaddressCreatedSuccessfully) { WidgetsBinding.instance - .addPostFrameCallback((_) => Navigator.of(context).pop()); + ?.addPostFrameCallback((_) => Navigator.of(context).pop()); } }); @@ -57,9 +56,9 @@ class NewSubaddressFormState extends State { Center( child: OxenTextField( controller: _labelController, - hintText: S.of(context).new_subaddress_label_name, + hintText: tr(context).new_subaddress_label_name, validator: (value) { - subaddressCreationStore.validateSubaddressName(value); + subaddressCreationStore.validateSubaddressName(value ?? '', tr(context)); return subaddressCreationStore.errorMessage; }), ), @@ -67,15 +66,15 @@ class NewSubaddressFormState extends State { bottomSection: Observer( builder: (_) => LoadingPrimaryButton( onPressed: () async { - if (_formKey.currentState.validate()) { + if (_formKey.currentState?.validate() ?? false) { await subaddressCreationStore.add(label: _labelController.text); Navigator.of(context).pop(); } }, - text: S.of(context).new_subaddress_create, - color: Theme.of(context).accentTextTheme.button.backgroundColor, + text: tr(context).new_subaddress_create, + color: Theme.of(context).accentTextTheme.button?.backgroundColor, borderColor: - Theme.of(context).accentTextTheme.button.decorationColor, + Theme.of(context).accentTextTheme.button?.decorationColor, isLoading: subaddressCreationStore.state is SubaddressIsCreating), ), ); diff --git a/lib/src/screens/subaddress/subaddress_list_page.dart b/lib/src/screens/subaddress/subaddress_list_page.dart index 965d4df2..078904d7 100644 --- a/lib/src/screens/subaddress/subaddress_list_page.dart +++ b/lib/src/screens/subaddress/subaddress_list_page.dart @@ -1,8 +1,7 @@ import 'package:provider/provider.dart'; import 'package:flutter/material.dart'; -import 'package:flutter/cupertino.dart'; import 'package:flutter_mobx/flutter_mobx.dart'; -import 'package:oxen_wallet/generated/l10n.dart'; +import 'package:oxen_wallet/l10n.dart'; import 'package:oxen_wallet/src/stores/subaddress_list/subaddress_list_store.dart'; import 'package:oxen_wallet/src/stores/wallet/wallet_store.dart'; import 'package:oxen_wallet/src/screens/base_page.dart'; @@ -14,7 +13,7 @@ class SubaddressListPage extends BasePage { bool get isModalBackButton => true; @override - String get title => S.current.subaddress_title; + String getTitle(AppLocalizations t) => t.subaddress_title; @override AppBarStyle get appBarStyle => AppBarStyle.withShadow; @@ -35,14 +34,12 @@ class SubaddressListPage extends BasePage { color: Theme.of(context).dividerTheme.color, height: 1.0, ), - itemCount: subaddressListStore.subaddresses == null - ? 0 - : subaddressListStore.subaddresses.length, + itemCount: subaddressListStore.subaddresses.length, itemBuilder: (BuildContext context, int index) { final subaddress = subaddressListStore.subaddresses[index]; final isCurrent = walletStore.subaddress.address == subaddress.address; - final label = subaddress.label ?? subaddress.address; + final label = subaddress.label; return InkWell( onTap: () => Navigator.of(context).pop(subaddress), @@ -57,7 +54,7 @@ class SubaddressListPage extends BasePage { color: Theme.of(context) .primaryTextTheme .headline5 - .color), + ?.color), ), ) ]), diff --git a/lib/src/screens/transaction_details/standart_list_item.dart b/lib/src/screens/transaction_details/standart_list_item.dart index 9cf23eeb..d245aa85 100644 --- a/lib/src/screens/transaction_details/standart_list_item.dart +++ b/lib/src/screens/transaction_details/standart_list_item.dart @@ -1,5 +1,5 @@ class StandartListItem { - StandartListItem({this.title, this.value}); + StandartListItem({required this.title, required this.value}); final String title; final String value; diff --git a/lib/src/screens/transaction_details/standart_list_row.dart b/lib/src/screens/transaction_details/standart_list_row.dart index 3da65efb..2db7e068 100644 --- a/lib/src/screens/transaction_details/standart_list_row.dart +++ b/lib/src/screens/transaction_details/standart_list_row.dart @@ -2,7 +2,7 @@ import 'package:flutter/material.dart'; import 'package:oxen_wallet/palette.dart'; class StandartListRow extends StatelessWidget { - StandartListRow({this.title, this.value}); + StandartListRow({required this.title, required this.value}); final String title; final String value; @@ -17,7 +17,7 @@ class StandartListRow extends StatelessWidget { Text(title, style: TextStyle( fontSize: 14, - color: Theme.of(context).primaryTextTheme.overline.color), + color: Theme.of(context).primaryTextTheme.overline?.color), textAlign: TextAlign.left), Padding( padding: const EdgeInsets.only(top: 5), diff --git a/lib/src/screens/transaction_details/transaction_details_page.dart b/lib/src/screens/transaction_details/transaction_details_page.dart index 506e894b..203f472b 100644 --- a/lib/src/screens/transaction_details/transaction_details_page.dart +++ b/lib/src/screens/transaction_details/transaction_details_page.dart @@ -1,8 +1,8 @@ import 'package:provider/provider.dart'; import 'package:flutter/material.dart'; -import 'package:flutter/cupertino.dart'; import 'package:flutter/services.dart'; -import 'package:oxen_wallet/generated/l10n.dart'; +import 'package:intl/intl.dart'; +import 'package:oxen_wallet/l10n.dart'; import 'package:oxen_wallet/src/wallet/transaction/transaction_info.dart'; import 'package:oxen_wallet/src/stores/settings/settings_store.dart'; import 'package:oxen_wallet/src/screens/transaction_details/standart_list_item.dart'; @@ -10,12 +10,12 @@ import 'package:oxen_wallet/src/screens/transaction_details/standart_list_row.da import 'package:oxen_wallet/src/screens/base_page.dart'; class TransactionDetailsPage extends BasePage { - TransactionDetailsPage({this.transactionInfo}); + TransactionDetailsPage({required this.transactionInfo}); final TransactionInfo transactionInfo; @override - String get title => S.current.transaction_details_title; + String getTitle(AppLocalizations t) => t.transaction_details_title; @override Widget body(BuildContext context) { @@ -28,7 +28,7 @@ class TransactionDetailsPage extends BasePage { class TransactionDetailsForm extends StatefulWidget { TransactionDetailsForm( - {@required this.transactionInfo, @required this.settingsStore}); + {required this.transactionInfo, required this.settingsStore}); final TransactionInfo transactionInfo; final SettingsStore settingsStore; @@ -38,41 +38,38 @@ class TransactionDetailsForm extends StatefulWidget { } class TransactionDetailsFormState extends State { - final _items = []; - @override - void initState() { - final _dateFormat = widget.settingsStore.getCurrentDateFormat( - formatUSA: 'yyyy.MM.dd, HH:mm', - formatDefault: 'dd.MM.yyyy, HH:mm'); - final items = [ + List getItems(AppLocalizations t) { + final _dateFormat = DateFormat.yMMMd(t.localeName).add_jm(); + final items = [ StandartListItem( - title: S.current.transaction_details_transaction_id, + title: t.transaction_details_transaction_id, value: widget.transactionInfo.id), StandartListItem( - title: S.current.transaction_details_date, + title: t.transaction_details_date, value: _dateFormat.format(widget.transactionInfo.date)), StandartListItem( - title: S.current.transaction_details_height, + title: t.transaction_details_height, value: '${widget.transactionInfo.height}'), StandartListItem( - title: S.current.transaction_details_amount, + title: t.transaction_details_amount, value: widget.transactionInfo.amountFormatted()) ]; if (widget.settingsStore.shouldSaveRecipientAddress && widget.transactionInfo.recipientAddress != null) { items.add(StandartListItem( - title: S.current.transaction_details_recipient_address, - value: widget.transactionInfo.recipientAddress)); + title: t.transaction_details_recipient_address, + value: widget.transactionInfo.recipientAddress!)); } - - _items.addAll(items); - super.initState(); + return items; } @override Widget build(BuildContext context) { + + final items = getItems(tr(context)); + return Container( padding: EdgeInsets.only(left: 20, right: 15, top: 10, bottom: 10), child: ListView.separated( @@ -81,17 +78,17 @@ class TransactionDetailsFormState extends State { color: Theme.of(context).dividerTheme.color, ), padding: EdgeInsets.only(left: 25, top: 10, right: 25, bottom: 15), - itemCount: _items.length, + itemCount: items.length, itemBuilder: (context, index) { - final item = _items[index]; + final item = items[index]; return GestureDetector( onTap: () { Clipboard.setData(ClipboardData(text: item.value)); - Scaffold.of(context).showSnackBar( + ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text( - S.of(context).transaction_details_copied(item.title)), + tr(context).transaction_details_copied(item.title)), backgroundColor: Colors.green, duration: Duration(milliseconds: 1500), ), diff --git a/lib/src/screens/wallet_list/wallet_list_page.dart b/lib/src/screens/wallet_list/wallet_list_page.dart index c3c9fcce..f0efcf3d 100644 --- a/lib/src/screens/wallet_list/wallet_list_page.dart +++ b/lib/src/screens/wallet_list/wallet_list_page.dart @@ -1,10 +1,9 @@ import 'package:flutter/material.dart'; -import 'package:flutter/cupertino.dart'; import 'package:flutter_mobx/flutter_mobx.dart'; import 'package:provider/provider.dart'; import 'package:oxen_wallet/routes.dart'; import 'package:oxen_wallet/palette.dart'; -import 'package:oxen_wallet/generated/l10n.dart'; +import 'package:oxen_wallet/l10n.dart'; import 'package:oxen_wallet/src/widgets/primary_button.dart'; import 'package:oxen_wallet/src/wallet/wallet_description.dart'; import 'package:oxen_wallet/src/screens/base_page.dart'; @@ -16,7 +15,7 @@ import 'package:oxen_wallet/src/widgets/picker.dart'; class WalletListPage extends BasePage { @override - String get title => S.current.wallet_list_title; + String getTitle(AppLocalizations t) => t.wallet_list_title; @override Widget body(BuildContext context) => WalletListBody(); @@ -28,24 +27,20 @@ class WalletListBody extends StatefulWidget { } class WalletListBodyState extends State { - WalletListStore _walletListStore; + WalletListStore? _walletListStore; void presetMenuForWallet(WalletDescription wallet, BuildContext bodyContext) { - final isCurrentWallet = false; final walletMenu = WalletMenu(bodyContext); - final items = walletMenu.generateItemsForWalletMenu(isCurrentWallet); + final items = walletMenu.generateItemsForWalletMenu(); showDialog( context: bodyContext, - builder: (_) => - Picker( - items: items, - selectedAtIndex: -1, - title: S.of(context).wallet_menu, - onItemSelected: (String item) => - walletMenu.action( - walletMenu.listItems.indexOf(item), wallet, - isCurrentWallet)), + builder: (_) => Picker( + items: items, + selectedAtIndex: -1, + title: tr(context).wallet_menu, + onItemSelected: (String item) => walletMenu.action(items.indexOf(item), wallet), + ), ); } @@ -66,11 +61,11 @@ class WalletListBodyState extends State { .of(context) .dividerTheme .color, height: 1.0), - itemCount: _walletListStore.wallets.length, + itemCount: _walletListStore!.wallets.length, itemBuilder: (__, index) { - final wallet = _walletListStore.wallets[index]; + final wallet = _walletListStore!.wallets[index]; final isCurrentWallet = - _walletListStore.isCurrentWallet(wallet); + _walletListStore!.isCurrentWallet(wallet); return InkWell( onTap: () => @@ -84,11 +79,7 @@ class WalletListBodyState extends State { style: TextStyle( color: isCurrentWallet ? OxenPalette.teal - : Theme - .of(context) - .primaryTextTheme - .headline5 - .color, + : Theme.of(context).primaryTextTheme.headline5?.color, fontSize: 18.0, fontWeight: FontWeight.w600), ), @@ -107,53 +98,21 @@ class WalletListBodyState extends State { onPressed: () => Navigator.of(context).pushNamed(Routes.newWallet), iconData: Icons.add_rounded, - color: Theme - .of(context) - .primaryTextTheme - .button - .backgroundColor, - borderColor: - Theme - .of(context) - .primaryTextTheme - .button - .decorationColor, + color: Theme.of(context).primaryTextTheme.button?.backgroundColor, + borderColor: Theme.of(context).primaryTextTheme.button?.decorationColor, iconColor: OxenPalette.teal, - iconBackgroundColor: Theme - .of(context) - .primaryIconTheme - .color, - text: S - .of(context) - .wallet_list_create_new_wallet), + iconBackgroundColor: Theme.of(context).primaryIconTheme.color, + text: tr(context).wallet_list_create_new_wallet), SizedBox(height: 10.0), PrimaryIconButton( onPressed: () => Navigator.of(context).pushNamed(Routes.restoreWalletOptions), iconData: Icons.refresh_rounded, - text: S - .of(context) - .wallet_list_restore_wallet, - color: Theme - .of(context) - .accentTextTheme - .button - .backgroundColor, - borderColor: - Theme - .of(context) - .accentTextTheme - .button - .decorationColor, - iconColor: Theme - .of(context) - .primaryTextTheme - .caption - .color, - iconBackgroundColor: Theme - .of(context) - .accentIconTheme - .color) + text: tr(context).wallet_list_restore_wallet, + color: Theme.of(context).accentTextTheme.button?.backgroundColor, + borderColor: Theme.of(context).accentTextTheme.button?.decorationColor, + iconColor: Theme.of(context).primaryTextTheme.caption?.color, + iconBackgroundColor: Theme.of(context).accentIconTheme.color) ])); } } diff --git a/lib/src/screens/wallet_list/wallet_menu.dart b/lib/src/screens/wallet_list/wallet_menu.dart index d90fbd3e..fd234a58 100644 --- a/lib/src/screens/wallet_list/wallet_menu.dart +++ b/lib/src/screens/wallet_list/wallet_menu.dart @@ -1,7 +1,7 @@ import 'package:flutter/material.dart'; import 'package:oxen_wallet/routes.dart'; import 'package:provider/provider.dart'; -import 'package:oxen_wallet/generated/l10n.dart'; +import 'package:oxen_wallet/l10n.dart'; import 'package:oxen_wallet/src/stores/wallet_list/wallet_list_store.dart'; import 'package:oxen_wallet/src/wallet/wallet_description.dart'; import 'package:oxen_wallet/src/screens/auth/auth_page.dart'; @@ -11,85 +11,58 @@ class WalletMenu { final BuildContext context; - final List listItems = [ - S.current.wallet_list_load_wallet, - S.current.show_seed, - S.current.remove, - S.current.rescan - ]; - - List generateItemsForWalletMenu(bool isCurrentWallet) { - final items = []; - - if (!isCurrentWallet) items.add(listItems[0]); - if (isCurrentWallet) items.add(listItems[1]); - if (!isCurrentWallet) items.add(listItems[2]); - if (isCurrentWallet) items.add(listItems[3]); - - return items; + List generateItemsForWalletMenu() { + final l10n = tr(context); + return [ + l10n.wallet_list_load_wallet, + l10n.remove + ]; } - void action(int index, WalletDescription wallet, bool isCurrentWallet) { + void action(int index, WalletDescription wallet) { final _walletListStore = context.read(); + final t = tr(context); + final nav = Navigator.of(context); - switch (index) { - case 0: - Navigator.of(context).pushNamed(Routes.auth, arguments: - (bool isAuthenticatedSuccessfully, AuthPageState auth) async { - if (!isAuthenticatedSuccessfully) { - return; - } + nav.pushNamed( + Routes.auth, + arguments: (bool authSuccessful, AuthPageState auth) async { + if (!authSuccessful) + return; - try { - auth.changeProcessText( - S.of(context).wallet_list_loading_wallet(wallet.name)); - await _walletListStore.loadWallet(wallet); + switch (index) { + case 0: + try { + auth.changeProcessText(context, t.wallet_list_loading_wallet(wallet.name)); + await _walletListStore.loadWallet(wallet); + auth.close(); + nav.pop(); + } catch (e) { + auth.changeProcessText(context, t.wallet_list_failed_to_load(wallet.name, e.toString())); + } + break; + case 1: auth.close(); - Navigator.of(context).pop(); - } catch (e) { - auth.changeProcessText(S - .of(context) - .wallet_list_failed_to_load(wallet.name, e.toString())); - } - }); - break; - case 1: - Navigator.of(context).pushNamed(Routes.auth, arguments: - (bool isAuthenticatedSuccessfully, AuthPageState auth) async { - if (!isAuthenticatedSuccessfully) { - return; - } - auth.close(); - await Navigator.of(context).pushNamed(Routes.seed); - }); - break; - case 2: - Navigator.of(context).pushNamed(Routes.auth, arguments: - (bool isAuthenticatedSuccessfully, AuthPageState auth) async { - if (!isAuthenticatedSuccessfully) { - return; - } - - await Navigator.of(context).pushNamed(Routes.dangerzoneRemoveWallet, arguments: - () async { - try { - auth.changeProcessText( - S.of(context).wallet_list_removing_wallet(wallet.name)); - await _walletListStore.remove(wallet); - auth.close(); - } catch (e) { - auth.changeProcessText(S - .of(context) - .wallet_list_failed_to_remove(wallet.name, e.toString())); + await nav.pushNamed( + Routes.dangerzoneRemoveWallet, + arguments: () async { + try { + ScaffoldMessenger.of(context).showSnackBar(SnackBar( + content: Text(t.wallet_list_removing_wallet(wallet.name)), + backgroundColor: Colors.green + )); + await _walletListStore.remove(wallet); + } catch (e) { + ScaffoldMessenger.of(context).showSnackBar(SnackBar( + content: Text(t.wallet_list_failed_to_remove(wallet.name, e.toString())), + backgroundColor: Colors.red + )); + } } - }); - }); - break; - case 3: - Navigator.of(context).pushNamed(Routes.rescan); - break; - default: - break; - } + ); + break; + } + }, + ); } } diff --git a/lib/src/screens/welcome/welcome_page.dart b/lib/src/screens/welcome/welcome_page.dart index 90129c4c..8d91860c 100644 --- a/lib/src/screens/welcome/welcome_page.dart +++ b/lib/src/screens/welcome/welcome_page.dart @@ -1,5 +1,5 @@ import 'package:flutter/material.dart'; -import 'package:oxen_wallet/generated/l10n.dart'; +import 'package:oxen_wallet/l10n.dart'; import 'package:oxen_wallet/palette.dart'; import 'package:oxen_wallet/routes.dart'; import 'package:oxen_wallet/src/screens/base_page.dart'; @@ -33,7 +33,7 @@ class WelcomePage extends BasePage { Padding( padding: EdgeInsets.all(10), child: Text( - S.of(context).welcome, + tr(context).welcome, style: TextStyle( fontSize: 30.0, fontWeight: FontWeight.bold, @@ -45,7 +45,7 @@ class WelcomePage extends BasePage { Padding( padding: EdgeInsets.all(10), child: Text( - S.of(context).first_wallet_text, + tr(context).first_wallet_text, style: TextStyle( fontSize: 22.0, color: Palette.lightBlue, @@ -56,7 +56,7 @@ class WelcomePage extends BasePage { Padding( padding: EdgeInsets.all(10), child: Text( - S.of(context).please_make_selection, + tr(context).please_make_selection, style: TextStyle( fontSize: 16.0, color: Palette.lightBlue, @@ -73,20 +73,20 @@ class WelcomePage extends BasePage { onPressed: () { Navigator.pushNamed(context, Routes.newWalletFromWelcome); }, - text: S.of(context).create_new, + text: tr(context).create_new, color: - Theme.of(context).primaryTextTheme.button.backgroundColor, + Theme.of(context).primaryTextTheme.button?.backgroundColor, borderColor: - Theme.of(context).primaryTextTheme.button.decorationColor), + Theme.of(context).primaryTextTheme.button?.decorationColor), SizedBox(height: 10), PrimaryButton( onPressed: () { Navigator.pushNamed(context, Routes.restoreOptions); }, - color: Theme.of(context).accentTextTheme.caption.backgroundColor, + color: Theme.of(context).accentTextTheme.caption?.backgroundColor, borderColor: - Theme.of(context).accentTextTheme.caption.decorationColor, - text: S.of(context).restore_wallet, + Theme.of(context).accentTextTheme.caption?.decorationColor, + text: tr(context).restore_wallet, ) ])) ]); diff --git a/lib/src/start_updating_price.dart b/lib/src/start_updating_price.dart index 8ee10e5a..1757b889 100644 --- a/lib/src/start_updating_price.dart +++ b/lib/src/start_updating_price.dart @@ -1,7 +1,6 @@ import 'dart:async'; import 'package:oxen_wallet/src/domain/common/fiat_currency.dart'; import 'package:flutter/foundation.dart'; -import 'package:oxen_wallet/src/domain/common/crypto_currency.dart'; import 'package:oxen_wallet/src/domain/common/fetch_price.dart'; import 'package:oxen_wallet/src/stores/price/price_store.dart'; import 'package:oxen_wallet/src/stores/settings/settings_store.dart'; @@ -9,29 +8,27 @@ import 'package:oxen_wallet/src/stores/settings/settings_store.dart'; bool _startedUpdatingPrice = false; Future _updatePrice(Map args) async => await fetchPriceFor( - fiat: args['fiat'] as FiatCurrency, - crypto: args['crypto'] as CryptoCurrency); + fiat: args['fiat'] as FiatCurrency); Future updatePrice(Map args) async => compute(_updatePrice, args); Future startUpdatingPrice( - {SettingsStore settingsStore, PriceStore priceStore}) async { + {required SettingsStore settingsStore, required PriceStore priceStore}) async { if (_startedUpdatingPrice || !settingsStore.enableFiatCurrency) { return; } - const currentCrypto = CryptoCurrency.oxen; _startedUpdatingPrice = true; final price = await updatePrice( - {'fiat': settingsStore.fiatCurrency, 'crypto': currentCrypto}); - priceStore.changePriceForPair( - fiat: settingsStore.fiatCurrency, crypto: currentCrypto, price: price); + {'fiat': settingsStore.fiatCurrency}); + priceStore.changePriceForFiat( + fiat: settingsStore.fiatCurrency, price: price); Timer.periodic(Duration(seconds: 30), (_) async { final price = await updatePrice( - {'fiat': settingsStore.fiatCurrency, 'crypto': currentCrypto}); - priceStore.changePriceForPair( - fiat: settingsStore.fiatCurrency, crypto: currentCrypto, price: price); + {'fiat': settingsStore.fiatCurrency}); + priceStore.changePriceForFiat( + fiat: settingsStore.fiatCurrency, price: price); }); } diff --git a/lib/src/stores/account_list/account_list_store.dart b/lib/src/stores/account_list/account_list_store.dart index e5c1304b..e3cb8f15 100644 --- a/lib/src/stores/account_list/account_list_store.dart +++ b/lib/src/stores/account_list/account_list_store.dart @@ -1,24 +1,21 @@ import 'dart:async'; -import 'package:flutter/foundation.dart'; import 'package:mobx/mobx.dart'; import 'package:oxen_wallet/src/wallet/wallet.dart'; import 'package:oxen_wallet/src/wallet/oxen/oxen_wallet.dart'; import 'package:oxen_wallet/src/wallet/oxen/account.dart'; import 'package:oxen_wallet/src/wallet/oxen/account_list.dart'; import 'package:oxen_wallet/src/domain/services/wallet_service.dart'; -import 'package:oxen_wallet/generated/l10n.dart'; +import 'package:oxen_wallet/src/util/validators.dart'; +import 'package:oxen_wallet/l10n.dart'; part 'account_list_store.g.dart'; class AccountListStore = AccountListStoreBase with _$AccountListStore; abstract class AccountListStoreBase with Store { - AccountListStoreBase({@required WalletService walletService}) { - accounts = []; - isAccountCreating = false; - + AccountListStoreBase({required WalletService walletService}) { if (walletService.currentWallet != null) { - _onWalletChanged(walletService.currentWallet); + _onWalletChanged(walletService.currentWallet!); } _onWalletChangeSubscription = @@ -26,20 +23,17 @@ abstract class AccountListStoreBase with Store { } @observable - List accounts; - - @observable - bool isValid; + List accounts = []; @observable - String errorMessage; + String? errorMessage; @observable - bool isAccountCreating; + bool isAccountCreating = false; - AccountList _accountList; - StreamSubscription _onWalletChangeSubscription; - StreamSubscription> _onAccountsChangeSubscription; + AccountList _accountList = AccountList(); + late StreamSubscription _onWalletChangeSubscription; + StreamSubscription>? _onAccountsChangeSubscription; // @override // void dispose() { @@ -57,7 +51,7 @@ abstract class AccountListStoreBase with Store { accounts = _accountList.getAll(); } - Future addAccount({String label}) async { + Future addAccount({required String label}) async { try { isAccountCreating = true; await _accountList.addAccount(label: label); @@ -68,14 +62,14 @@ abstract class AccountListStoreBase with Store { } } - Future renameAccount({int index, String label}) async { + Future renameAccount({required int index, required String label}) async { await _accountList.setLabelSubaddress(accountIndex: index, label: label); updateAccountList(); } Future _onWalletChanged(Wallet wallet) async { if (_onAccountsChangeSubscription != null) { - await _onAccountsChangeSubscription.cancel(); + await _onAccountsChangeSubscription!.cancel(); } if (wallet is OxenWallet) { @@ -90,10 +84,7 @@ abstract class AccountListStoreBase with Store { print('Incorrect wallet type for this operation (AccountList)'); } - void validateAccountName(String value) { - const pattern = '^[a-zA-Z0-9_]{1,15}\$'; - final regExp = RegExp(pattern); - isValid = regExp.hasMatch(value); - errorMessage = isValid ? null : S.current.error_text_account_name; + void validateAccountName(String? value, AppLocalizations t) { + errorMessage = hasNonWhitespace(value) ? null : t.error_text_empty; } } diff --git a/lib/src/stores/action_list/action_list_store.dart b/lib/src/stores/action_list/action_list_store.dart index 0be357ac..b9c38f48 100644 --- a/lib/src/stores/action_list/action_list_store.dart +++ b/lib/src/stores/action_list/action_list_store.dart @@ -1,10 +1,8 @@ import 'dart:async'; -import 'package:flutter/foundation.dart'; import 'package:hive/hive.dart'; import 'package:mobx/mobx.dart'; import 'package:oxen_wallet/src/domain/common/calculate_fiat_amount_raw.dart'; -import 'package:oxen_wallet/src/domain/common/crypto_currency.dart'; import 'package:oxen_wallet/src/wallet/transaction/transaction_history.dart'; import 'package:oxen_wallet/src/wallet/transaction/transaction_info.dart'; import 'package:oxen_wallet/src/wallet/wallet.dart'; @@ -26,19 +24,20 @@ class ActionListStore = ActionListBase with _$ActionListStore; abstract class ActionListBase with Store { ActionListBase( - {@required WalletService walletService, - @required SettingsStore settingsStore, - @required PriceStore priceStore, - @required this.transactionFilterStore, - @required this.transactionDescriptions}) { - _transactions = []; - _walletService = walletService; - _settingsStore = settingsStore; - _priceStore = priceStore; - - if (walletService.currentWallet != null) { - _onWalletChanged(walletService.currentWallet); - } + {required WalletService walletService, + required SettingsStore settingsStore, + required PriceStore priceStore, + required this.transactionFilterStore, + required this.transactionDescriptions}) + : + _transactions = [], + _walletService = walletService, + _settingsStore = settingsStore, + _priceStore = priceStore + { + + if (walletService.currentWallet != null) + _onWalletChanged(walletService.currentWallet!); _onWalletChangeSubscription = walletService.onWalletChange.listen(_onWalletChanged); @@ -50,7 +49,7 @@ abstract class ActionListBase with Store { static List formattedItemsList(List items) { final formattedList = []; - DateTime lastDate; + DateTime? lastDate; items.sort((a, b) => b.date.compareTo(a.date)); for (var i = 0; i < items.length; i++) { @@ -82,8 +81,8 @@ abstract class ActionListBase with Store { @computed List get transactions { - final symbol = PriceStoreBase.generateSymbolForPair( - fiat: _settingsStore.fiatCurrency, crypto: CryptoCurrency.oxen); + final symbol = PriceStoreBase.generateSymbolForFiat( + fiat: _settingsStore.fiatCurrency); final price = _priceStore.prices[symbol]; _transactions.forEach((item) { @@ -114,15 +113,15 @@ abstract class ActionListBase with Store { TransactionFilterStore transactionFilterStore; Box transactionDescriptions; - WalletService _walletService; - TransactionHistory _history; - SettingsStore _settingsStore; - PriceStore _priceStore; - Account _account; - StreamSubscription _onWalletChangeSubscription; - StreamSubscription> _onTransactionsChangeSubscription; - StreamSubscription _onAccountChangeSubscription; - StreamSubscription _onTransactionDescriptions; + final WalletService _walletService; + TransactionHistory? _history; + final SettingsStore _settingsStore; + final PriceStore _priceStore; + Account _account = Account(id: 0); + late StreamSubscription _onWalletChangeSubscription; + StreamSubscription>? _onTransactionsChangeSubscription; + StreamSubscription? _onAccountChangeSubscription; + late StreamSubscription _onTransactionDescriptions; // @override // void dispose() { @@ -141,22 +140,24 @@ abstract class ActionListBase with Store { // } Future _updateTransactionsList() async { + if (_history == null) + return; // await _history.refresh(); - final _transactions = await _history.getAll(); + final _transactions = await _history!.getAll(); await _setTransactions(_transactions); } Future _onWalletChanged(Wallet wallet) async { if (_onTransactionsChangeSubscription != null) { - await _onTransactionsChangeSubscription.cancel(); + await _onTransactionsChangeSubscription!.cancel(); } if (_onAccountChangeSubscription != null) { - await _onAccountChangeSubscription.cancel(); + await _onAccountChangeSubscription!.cancel(); } _history = wallet.getHistory(); - _onTransactionsChangeSubscription = _history.transactions + _onTransactionsChangeSubscription = _history!.transactions .listen((transactions) => _setTransactions(transactions)); if (wallet is OxenWallet) { @@ -174,11 +175,13 @@ abstract class ActionListBase with Store { final wallet = _walletService.currentWallet; var sortedTransactions = transactions.map((transaction) { if (transactionDescriptions.values.isNotEmpty) { - final description = transactionDescriptions.values.firstWhere( - (desc) => desc.id == transaction.id, - orElse: () => null); + TransactionDescription? description; + try { + description = transactionDescriptions.values.firstWhere( + (desc) => desc.id == transaction.id); + } on StateError catch (_) {} - if (description != null && description.recipientAddress != null) { + if (description != null) { transaction.recipientAddress = description.recipientAddress; } } diff --git a/lib/src/stores/action_list/transaction_filter_store.dart b/lib/src/stores/action_list/transaction_filter_store.dart index 03ca1820..48e9df26 100644 --- a/lib/src/stores/action_list/transaction_filter_store.dart +++ b/lib/src/stores/action_list/transaction_filter_store.dart @@ -18,10 +18,10 @@ abstract class TransactionFilterStoreBase with Store { bool displayOutgoing; @observable - DateTime startDate; + DateTime? startDate; @observable - DateTime endDate; + DateTime? endDate; @action void toggleIncoming() => displayIncoming = !displayIncoming; @@ -30,12 +30,12 @@ abstract class TransactionFilterStoreBase with Store { void toggleOutgoing() => displayOutgoing = !displayOutgoing; @action - void changeStartDate(DateTime date) => startDate = date; + void changeStartDate(DateTime? date) => startDate = date; @action - void changeEndDate(DateTime date) => endDate = date; + void changeEndDate(DateTime? date) => endDate = date; - List filtered({List transactions}) { + List filtered({required List transactions}) { var _transactions = []; final needToFilter = !displayOutgoing || !displayIncoming || @@ -46,8 +46,8 @@ abstract class TransactionFilterStoreBase with Store { var allowed = true; if (allowed && startDate != null && endDate != null) { - allowed = startDate.isBefore(item.transaction.date) && - endDate.isAfter(item.transaction.date); + allowed = startDate!.isBefore(item.transaction.date) && + endDate!.isAfter(item.transaction.date); } if (allowed && (!displayOutgoing || !displayIncoming)) { diff --git a/lib/src/stores/action_list/transaction_list_item.dart b/lib/src/stores/action_list/transaction_list_item.dart index 3e28009a..1bddb89b 100644 --- a/lib/src/stores/action_list/transaction_list_item.dart +++ b/lib/src/stores/action_list/transaction_list_item.dart @@ -2,10 +2,10 @@ import 'package:oxen_wallet/src/wallet/transaction/transaction_info.dart'; import 'package:oxen_wallet/src/stores/action_list/action_list_item.dart'; class TransactionListItem extends ActionListItem { - TransactionListItem({this.transaction}); + TransactionListItem({required this.transaction}); final TransactionInfo transaction; @override DateTime get date => transaction.date; -} \ No newline at end of file +} diff --git a/lib/src/stores/address_book/address_book_store.dart b/lib/src/stores/address_book/address_book_store.dart index a088851d..0988e13e 100644 --- a/lib/src/stores/address_book/address_book_store.dart +++ b/lib/src/stores/address_book/address_book_store.dart @@ -1,102 +1,43 @@ import 'package:mobx/mobx.dart'; -import 'package:flutter/foundation.dart'; -import 'package:oxen_wallet/generated/l10n.dart'; +import 'package:oxen_wallet/l10n.dart'; import 'package:oxen_wallet/src/domain/common/contact.dart'; -import 'package:oxen_wallet/src/domain/common/crypto_currency.dart'; import 'package:hive/hive.dart'; +import 'package:oxen_wallet/src/util/validators.dart'; part 'address_book_store.g.dart'; class AddressBookStore = AddressBookStoreBase with _$AddressBookStore; abstract class AddressBookStoreBase with Store { - AddressBookStoreBase({@required this.contacts}) { + AddressBookStoreBase({required this.contacts}) { updateContactList(); } @observable - List contactList; + List contactList = []; @observable - bool isValid; - - @observable - String errorMessage; + String? errorMessage; Box contacts; @action - Future add({Contact contact}) async => contacts.add(contact); + Future add({required Contact contact}) async => contacts.add(contact); @action Future updateContactList() async => contactList = contacts.values.toList(); @action - Future update({Contact contact}) async => contact.save(); + Future update({required Contact contact}) async => contact.save(); @action - Future delete({Contact contact}) async => await contact.delete(); + Future delete({required Contact contact}) async => await contact.delete(); - void validateContactName(String value) { - const pattern = '''^[^`,'"]{1,32}\$'''; - final regExp = RegExp(pattern); - isValid = regExp.hasMatch(value); - errorMessage = isValid ? null : S.current.error_text_contact_name; + void validateContactName(String? value, AppLocalizations l10n) { + errorMessage = hasNonWhitespace(value) ? null : l10n.error_text_empty; } - void validateAddress(String value, {CryptoCurrency cryptoCurrency}) { - // XMR (95, 106), ADA (59, 92, 105), BCH (42), BNB (42), BTC (34, 42), DASH (34), EOS (42), - // ETH (42), LTC (34), NANO (64, 65), TRX (34), USDT (42), XLM (56), XRP (34) - const pattern = '^[0-9a-zA-Z]{95}\$|^[0-9a-zA-Z]{34}\$|^[0-9a-zA-Z]{42}\$|^[0-9a-zA-Z]{56}\$|^[0-9a-zA-Z]{59}\$|^[0-9a-zA-Z_]{64}\$|^[0-9a-zA-Z_]{65}\$|^[0-9a-zA-Z]{92}\$|^[0-9a-zA-Z]{105}\$|^[0-9a-zA-Z]{106}\$'; - final regExp = RegExp(pattern); - isValid = regExp.hasMatch(value); - if (isValid && cryptoCurrency != null) { - switch (cryptoCurrency) { - case CryptoCurrency.xmr: - isValid = (value.length == 95)||(value.length == 106); - break; - case CryptoCurrency.ada: - isValid = (value.length == 59)||(value.length == 92)||(value.length == 105); - break; - case CryptoCurrency.bch: - isValid = (value.length == 42); - break; - case CryptoCurrency.bnb: - isValid = (value.length == 42); - break; - case CryptoCurrency.btc: - isValid = (value.length == 34)||(value.length == 42); - break; - case CryptoCurrency.dash: - isValid = (value.length == 34); - break; - case CryptoCurrency.eos: - isValid = (value.length == 42); - break; - case CryptoCurrency.eth: - isValid = (value.length == 42); - break; - case CryptoCurrency.ltc: - isValid = (value.length == 34); - break; - case CryptoCurrency.nano: - isValid = (value.length == 64)||(value.length == 65); - break; - case CryptoCurrency.trx: - isValid = (value.length == 34); - break; - case CryptoCurrency.usdt: - isValid = (value.length == 42); - break; - case CryptoCurrency.xlm: - isValid = (value.length == 56); - break; - case CryptoCurrency.xrp: - isValid = (value.length == 34); - break; - } - } - - errorMessage = isValid ? null : S.current.error_text_address; + void validateAddress(String value, {required AppLocalizations l10n}) { + errorMessage = isValidOxenAddress(value) ? null : l10n.error_text_address; } } diff --git a/lib/src/stores/auth/auth_state.dart b/lib/src/stores/auth/auth_state.dart index 01e4c257..44d83eb3 100644 --- a/lib/src/stores/auth/auth_state.dart +++ b/lib/src/stores/auth/auth_state.dart @@ -7,13 +7,13 @@ class AuthenticationInProgress extends AuthState {} class AuthenticatedSuccessfully extends AuthState {} class AuthenticationFailure extends AuthState { - AuthenticationFailure({this.error}); + AuthenticationFailure({required this.error}); final String error; } class AuthenticationBanned extends AuthState { - AuthenticationBanned({this.error}); + AuthenticationBanned({required this.error}); final String error; } diff --git a/lib/src/stores/auth/auth_store.dart b/lib/src/stores/auth/auth_store.dart index c2bafd5e..c54459a4 100644 --- a/lib/src/stores/auth/auth_store.dart +++ b/lib/src/stores/auth/auth_store.dart @@ -1,11 +1,10 @@ import 'dart:async'; -import 'package:flutter/foundation.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:mobx/mobx.dart'; import 'package:oxen_wallet/src/domain/services/user_service.dart'; import 'package:oxen_wallet/src/domain/services/wallet_service.dart'; import 'package:oxen_wallet/src/stores/auth/auth_state.dart'; -import 'package:oxen_wallet/generated/l10n.dart'; +import 'package:oxen_wallet/l10n.dart'; part 'auth_store.g.dart'; @@ -13,16 +12,13 @@ class AuthStore = AuthStoreBase with _$AuthStore; abstract class AuthStoreBase with Store { AuthStoreBase( - {@required this.userService, - @required this.walletService, - @required this.sharedPreferences}) { - state = AuthenticationStateInitial(); - _failureCounter = 0; - } + {required this.userService, + required this.walletService, + required this.sharedPreferences}); static const maxFailedLogins = 3; static const banTimeout = 180; // 3 minutes - final banTimeoutKey = S.current.auth_store_ban_timeout; + static const banTimeoutKey = 'ban_timeout'; final UserService userService; final WalletService walletService; @@ -30,19 +26,19 @@ abstract class AuthStoreBase with Store { final SharedPreferences sharedPreferences; @observable - AuthState state; + AuthState state = AuthenticationStateInitial(); @observable - int _failureCounter; + int _failureCounter = 0; @action - Future auth({String password}) async { + Future auth({required String password, required AppLocalizations l10n}) async { state = AuthenticationStateInitial(); final _banDuration = banDuration(); if (_banDuration != null) { state = AuthenticationBanned( - error: S.current.auth_store_banned_for + '${_banDuration.inMinutes}' + S.current.auth_store_banned_minutes); + error: l10n.auth_store_banned_for(_banDuration.inMinutes)); return; } @@ -58,15 +54,15 @@ abstract class AuthStoreBase with Store { if (_failureCounter >= maxFailedLogins) { final banDuration = await ban(); state = AuthenticationBanned( - error: S.current.auth_store_banned_for + '${banDuration.inMinutes}' + S.current.auth_store_banned_minutes); + error: l10n.auth_store_banned_for(banDuration.inMinutes)); return; } - state = AuthenticationFailure(error: S.current.auth_store_incorrect_password); + state = AuthenticationFailure(error: l10n.auth_store_incorrect_password); } } - Duration banDuration() { + Duration? banDuration() { final unbanTimestamp = sharedPreferences.getInt(banTimeoutKey); if (unbanTimestamp == null) { diff --git a/lib/src/stores/authentication/authentication_store.dart b/lib/src/stores/authentication/authentication_store.dart index 99152077..76b25751 100644 --- a/lib/src/stores/authentication/authentication_store.dart +++ b/lib/src/stores/authentication/authentication_store.dart @@ -1,5 +1,4 @@ import 'dart:async'; -import 'package:flutter/foundation.dart'; import 'package:mobx/mobx.dart'; import 'package:oxen_wallet/src/domain/services/user_service.dart'; @@ -21,18 +20,14 @@ enum AuthenticationState { } abstract class AuthenticationStoreBase with Store { - AuthenticationStoreBase({@required this.userService}) { + AuthenticationStoreBase({required this.userService}) : state = AuthenticationState.uninitialized; - } final UserService userService; @observable AuthenticationState state; - @observable - String errorMessage; - Future started() async { final canAuth = await userService.canAuthenticate(); state = canAuth ? AuthenticationState.allowed : AuthenticationState.denied; diff --git a/lib/src/stores/balance/balance_store.dart b/lib/src/stores/balance/balance_store.dart index 5e840abb..f9842588 100644 --- a/lib/src/stores/balance/balance_store.dart +++ b/lib/src/stores/balance/balance_store.dart @@ -2,11 +2,9 @@ import 'dart:async'; import 'package:oxen_wallet/src/wallet/oxen/oxen_amount_format.dart'; import 'package:oxen_wallet/src/wallet/oxen/oxen_balance.dart'; import 'package:mobx/mobx.dart'; -import 'package:flutter/foundation.dart'; import 'package:oxen_wallet/src/wallet/wallet.dart'; import 'package:oxen_wallet/src/wallet/balance.dart'; import 'package:oxen_wallet/src/domain/services/wallet_service.dart'; -import 'package:oxen_wallet/src/domain/common/crypto_currency.dart'; import 'package:oxen_wallet/src/domain/common/calculate_fiat_amount.dart'; import 'package:oxen_wallet/src/stores/price/price_store.dart'; import 'package:oxen_wallet/src/stores/settings/settings_store.dart'; @@ -17,18 +15,14 @@ part 'balance_store.g.dart'; class BalanceStore = BalanceStoreBase with _$BalanceStore; abstract class BalanceStoreBase with Store { - BalanceStoreBase( - {String fullBalance = '0.0', - String unlockedBalance = '0.0', - @required WalletService walletService, - @required SettingsStore settingsStore, - @required PriceStore priceStore}) { - fullBalance = fullBalance; - unlockedBalance = unlockedBalance; - isReversing = false; - _walletService = walletService; - _settingsStore = settingsStore; - _priceStore = priceStore; + BalanceStoreBase({ + required WalletService walletService, + required SettingsStore settingsStore, + required PriceStore priceStore}) + : isReversing = false, + _walletService = walletService, + _settingsStore = settingsStore, + _priceStore = priceStore { if (_walletService.currentWallet != null) { _onWalletChanged(_walletService.currentWallet); @@ -39,61 +33,45 @@ abstract class BalanceStoreBase with Store { } @observable - int fullBalance; + int fullBalance = 0; @observable - int unlockedBalance; + int unlockedBalance = 0; @computed String get fullBalanceString { - if (fullBalance == null) { - return oxenAmountToString(0, detail: _settingsStore.balanceDetail); - } - return oxenAmountToString(fullBalance, detail: _settingsStore.balanceDetail); } @computed String get unlockedBalanceString { - if (unlockedBalance == null) { - return oxenAmountToString(0, detail: _settingsStore.balanceDetail); - } - return oxenAmountToString(unlockedBalance, detail: _settingsStore.balanceDetail); } @computed String get fiatFullBalance { - if (fullBalance == null) { - return '0.00'; - } - - final symbol = PriceStoreBase.generateSymbolForPair( - fiat: _settingsStore.fiatCurrency, crypto: CryptoCurrency.oxen); - final price = _priceStore.prices[symbol]; + final symbol = PriceStoreBase.generateSymbolForFiat( + fiat: _settingsStore.fiatCurrency); + final price = _priceStore.prices[symbol] ?? double.nan; return calculateFiatAmount(price: price, cryptoAmount: fullBalance); } @computed String get fiatUnlockedBalance { - if (unlockedBalance == null) { - return '0.00'; - } - - final symbol = PriceStoreBase.generateSymbolForPair( - fiat: _settingsStore.fiatCurrency, crypto: CryptoCurrency.oxen); - final price = _priceStore.prices[symbol]; + final symbol = PriceStoreBase.generateSymbolForFiat( + fiat: _settingsStore.fiatCurrency); + final price = _priceStore.prices[symbol] ?? double.nan; return calculateFiatAmount(price: price, cryptoAmount: unlockedBalance); } @observable bool isReversing; - WalletService _walletService; - StreamSubscription _onWalletChangeSubscription; - StreamSubscription _onBalanceChangeSubscription; - SettingsStore _settingsStore; - PriceStore _priceStore; + final WalletService _walletService; + late StreamSubscription _onWalletChangeSubscription; + StreamSubscription? _onBalanceChangeSubscription; + final SettingsStore _settingsStore; + final PriceStore _priceStore; // @override // void dispose() { @@ -118,9 +96,9 @@ abstract class BalanceStoreBase with Store { } } - Future _onWalletChanged(Wallet wallet) async { + Future _onWalletChanged(Wallet? wallet) async { if (_onBalanceChangeSubscription != null) { - await _onBalanceChangeSubscription.cancel(); + await _onBalanceChangeSubscription!.cancel(); } _onBalanceChangeSubscription = _walletService.onBalanceChange @@ -129,7 +107,7 @@ abstract class BalanceStoreBase with Store { await _updateBalances(wallet); } - Future _updateBalances(Wallet wallet) async { + Future _updateBalances(Wallet? wallet) async { if (wallet == null) { return; } diff --git a/lib/src/stores/login/login_store.dart b/lib/src/stores/login/login_store.dart index bb6401ff..57339d7b 100644 --- a/lib/src/stores/login/login_store.dart +++ b/lib/src/stores/login/login_store.dart @@ -1,4 +1,3 @@ -import 'package:flutter/foundation.dart'; import 'package:mobx/mobx.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:oxen_wallet/src/domain/services/wallet_list_service.dart'; @@ -14,7 +13,7 @@ class LoadingCurrentWallet extends LoginState {} class LoadedCurrentWalletSuccessfully extends LoginState {} class LoadedCurrentWalletFailure extends LoginState { - LoadedCurrentWalletFailure({this.errorMessage}); + LoadedCurrentWalletFailure({required this.errorMessage}); final String errorMessage; } @@ -23,9 +22,8 @@ class LoginStore = LoginStoreBase with _$LoginStore; abstract class LoginStoreBase with Store { LoginStoreBase( - {@required this.sharedPreferences, @required this.walletsService}) { - state = InitialLoginState(); - } + {required this.sharedPreferences, required this.walletsService}) + : state = InitialLoginState(); final SharedPreferences sharedPreferences; final WalletListService walletsService; @@ -39,7 +37,7 @@ abstract class LoginStoreBase with Store { try { state = LoadingCurrentWallet(); - final walletName = sharedPreferences.getString('current_wallet_name'); + final walletName = sharedPreferences.getString('current_wallet_name') ?? ''; await walletsService.openWallet(walletName); state = LoadedCurrentWalletSuccessfully(); } catch (e) { diff --git a/lib/src/stores/node_list/node_list_store.dart b/lib/src/stores/node_list/node_list_store.dart index ed9006f7..1b5bbb39 100644 --- a/lib/src/stores/node_list/node_list_store.dart +++ b/lib/src/stores/node_list/node_list_store.dart @@ -3,15 +3,15 @@ import 'package:mobx/mobx.dart'; import 'package:hive/hive.dart'; import 'package:oxen_wallet/src/node/node.dart'; import 'package:oxen_wallet/src/node/node_list.dart'; -import 'package:oxen_wallet/generated/l10n.dart'; +import 'package:oxen_wallet/l10n.dart'; part 'node_list_store.g.dart'; class NodeListStore = NodeListBase with _$NodeListStore; abstract class NodeListBase with Store { - NodeListBase({this.nodesSource}) { - nodes = ObservableList(); + NodeListBase({required this.nodesSource}) : + nodes = ObservableList() { _onNodesChangeSubscription = nodesSource.watch().listen((e) => update()); update(); } @@ -20,14 +20,14 @@ abstract class NodeListBase with Store { ObservableList nodes; @observable - bool isValid; + bool isValid = false; @observable - String errorMessage; + String? errorMessage; Box nodesSource; - StreamSubscription _onNodesChangeSubscription; + late StreamSubscription _onNodesChangeSubscription; // @override // void dispose() { @@ -44,19 +44,18 @@ abstract class NodeListBase with Store { @action Future addNode( - {String address, String port, String login, String password}) async { + {required String address, String? port, required String login, required String password}) async { var uri = address; - if (port != null && port.isNotEmpty) { + if (port != null && port.isNotEmpty) uri += ':' + port; - } final node = Node(uri: uri, login: login, password: password); await nodesSource.add(node); } @action - Future remove({Node node}) async => await node.delete(); + Future remove({required Node node}) async => await node.delete(); @action Future reset() async => await resetToDefault(nodesSource); @@ -69,22 +68,19 @@ abstract class NodeListBase with Store { } } - void validateNodeAddress(String value) { - const pattern = - '^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\$|^[0-9a-zA-Z.]+\$'; - final regExp = RegExp(pattern); - isValid = regExp.hasMatch(value); - errorMessage = isValid ? null : S.current.error_text_node_address; - } + static final nodeAddrRE = RegExp('^[0-9a-zA-Z.]+\$'); + static final nodePortRE = RegExp('^[0-9]{1,5}\$'); - void validateNodePort(String value) { - const pattern = '^[0-9]{1,5}'; - final regExp = RegExp(pattern); + void validateNodeAddress(String value, AppLocalizations l10n) { + isValid = nodeAddrRE.hasMatch(value); + errorMessage = isValid ? null : l10n.error_text_node_address; + } - if (regExp.hasMatch(value)) { + void validateNodePort(String value, AppLocalizations l10n) { + if (nodePortRE.hasMatch(value)) { try { final intValue = int.parse(value); - isValid = (intValue >= 0 && intValue <= 65535); + isValid = (intValue > 0 && intValue <= 65535); } catch (e) { isValid = false; } @@ -92,6 +88,6 @@ abstract class NodeListBase with Store { isValid = false; } - errorMessage = isValid ? null : S.current.error_text_node_port; + errorMessage = isValid ? null : l10n.error_text_node_port; } } diff --git a/lib/src/stores/price/price_store.dart b/lib/src/stores/price/price_store.dart index 2d6c2e00..2dd46a14 100644 --- a/lib/src/stores/price/price_store.dart +++ b/lib/src/stores/price/price_store.dart @@ -1,5 +1,4 @@ import 'package:mobx/mobx.dart'; -import 'package:oxen_wallet/src/domain/common/crypto_currency.dart'; import 'package:oxen_wallet/src/domain/common/fiat_currency.dart'; part 'price_store.g.dart'; @@ -9,24 +8,16 @@ class PriceStore = PriceStoreBase with _$PriceStore; abstract class PriceStoreBase with Store { PriceStoreBase() : prices = ObservableMap(); - static String generateSymbolForPair( - {FiatCurrency fiat, CryptoCurrency crypto}) => - crypto.toString().toUpperCase() + fiat.toString().toUpperCase(); + static String generateSymbolForFiat({required FiatCurrency fiat}) => + 'OXEN' + fiat.toString().toUpperCase(); @observable ObservableMap prices; - // @action - // Future updatePrice({FiatCurrency fiat, CryptoCurrency crypto}) async { - // final symbol = generateSymbolForPair(fiat: fiat, crypto: crypto); - // final price = await fetchPriceFor(fiat: fiat, crypto: crypto); - // prices[symbol] = price; - // } - @action - void changePriceForPair( - {FiatCurrency fiat, CryptoCurrency crypto, double price}) { - final symbol = generateSymbolForPair(fiat: fiat, crypto: crypto); + void changePriceForFiat( + {required FiatCurrency fiat, required double price}) { + final symbol = generateSymbolForFiat(fiat: fiat); prices[symbol] = price; } } diff --git a/lib/src/stores/rescan/rescan_wallet_store.dart b/lib/src/stores/rescan/rescan_wallet_store.dart index ef2dffc5..835fd932 100644 --- a/lib/src/stores/rescan/rescan_wallet_store.dart +++ b/lib/src/stores/rescan/rescan_wallet_store.dart @@ -1,4 +1,3 @@ -import 'package:flutter/foundation.dart'; import 'package:mobx/mobx.dart'; import 'package:oxen_wallet/src/domain/services/wallet_service.dart'; @@ -9,18 +8,16 @@ class RescanWalletStore = RescanWalletStoreBase with _$RescanWalletStore; enum RescanWalletState { rescaning, none } abstract class RescanWalletStoreBase with Store { - RescanWalletStoreBase({@required WalletService walletService}) { - _walletService = walletService; - state = RescanWalletState.none; - } + RescanWalletStoreBase({required WalletService walletService}) : + _walletService = walletService; @observable - RescanWalletState state; + RescanWalletState state = RescanWalletState.none; - WalletService _walletService; + final WalletService _walletService; @action - Future rescanCurrentWallet({int restoreHeight}) async { + Future rescanCurrentWallet({required int restoreHeight}) async { state = RescanWalletState.rescaning; await _walletService.rescan(restoreHeight: restoreHeight); state = RescanWalletState.none; diff --git a/lib/src/stores/seed_language/seed_language_store.dart b/lib/src/stores/seed_language/seed_language_store.dart index 903b807e..dd192d38 100644 --- a/lib/src/stores/seed_language/seed_language_store.dart +++ b/lib/src/stores/seed_language/seed_language_store.dart @@ -18,10 +18,9 @@ const List seedLanguages = [ class SeedLanguageStore = SeedLanguageStoreBase with _$SeedLanguageStore; abstract class SeedLanguageStoreBase with Store { - SeedLanguageStoreBase() { - selectedSeedLanguage = seedLanguages[0]; + SeedLanguageStoreBase() : + selectedSeedLanguage = seedLanguages[0], currentRoute = ''; - } @observable String selectedSeedLanguage; diff --git a/lib/src/stores/send/send_store.dart b/lib/src/stores/send/send_store.dart index 366f5010..35aba301 100644 --- a/lib/src/stores/send/send_store.dart +++ b/lib/src/stores/send/send_store.dart @@ -1,18 +1,15 @@ -import 'package:flutter/foundation.dart'; import 'package:hive/hive.dart'; import 'package:intl/intl.dart'; import 'package:mobx/mobx.dart'; -import 'package:oxen_wallet/generated/l10n.dart'; -import 'package:oxen_wallet/src/domain/common/crypto_currency.dart'; +import 'package:oxen_wallet/l10n.dart'; import 'package:oxen_wallet/src/domain/common/openalias_record.dart'; import 'package:oxen_wallet/src/domain/services/wallet_service.dart'; import 'package:oxen_wallet/src/stores/price/price_store.dart'; import 'package:oxen_wallet/src/stores/send/sending_state.dart'; import 'package:oxen_wallet/src/stores/settings/settings_store.dart'; -import 'package:oxen_wallet/src/wallet/oxen/transaction/oxen_stake_transaction_creation_credentials.dart'; -import 'package:oxen_wallet/src/wallet/oxen/transaction/oxen_transaction_creation_credentials.dart'; import 'package:oxen_wallet/src/wallet/oxen/transaction/transaction_description.dart'; import 'package:oxen_wallet/src/wallet/transaction/pending_transaction.dart'; +import 'package:oxen_wallet/src/util/validators.dart'; part 'send_store.g.dart'; @@ -20,57 +17,47 @@ class SendStore = SendStoreBase with _$SendStore; abstract class SendStoreBase with Store { SendStoreBase( - {@required this.walletService, - this.settingsStore, - this.transactionDescriptions, - this.priceStore}) { - state = SendingStateInitial(); - _pendingTransaction = null; - _cryptoNumberFormat = NumberFormat()..maximumFractionDigits = 12; + {required this.walletService, + required this.settingsStore, + required this.transactionDescriptions, + required this.priceStore}) : + _cryptoNumberFormat = NumberFormat()..maximumFractionDigits = 9, _fiatNumberFormat = NumberFormat()..maximumFractionDigits = 2; - } WalletService walletService; SettingsStore settingsStore; PriceStore priceStore; Box transactionDescriptions; - String recordName; - String recordAddress; - - @observable - SendingState state; + String? recordName; + String? recordAddress; @observable - String fiatAmount; + SendingState state = SendingStateInitial(); @observable - String cryptoAmount; + String fiatAmount = ''; @observable - bool isValid; + String cryptoAmount = ''; @observable - String errorMessage; + String? errorMessage; - PendingTransaction get pendingTransaction => _pendingTransaction; - PendingTransaction _pendingTransaction; - NumberFormat _cryptoNumberFormat; - NumberFormat _fiatNumberFormat; - String _lastRecipientAddress; + PendingTransaction? get pendingTransaction => _pendingTransaction; + PendingTransaction? _pendingTransaction; + final NumberFormat _cryptoNumberFormat; + final NumberFormat _fiatNumberFormat; + String _lastRecipientAddress = ''; @action - Future createStake({String address, String amount}) async { + Future createStake({required String snPubkey, String? amount, required AppLocalizations l10n}) async { state = CreatingTransaction(); try { final _amount = amount ?? - (cryptoAmount == S.current.all - ? null - : cryptoAmount.replaceAll(',', '.')); - final credentials = OxenStakeTransactionCreationCredentials( - address: address, amount: _amount); + (cryptoAmount == l10n.all ? null : cryptoAmount.replaceAll(',', '.')); - _pendingTransaction = await walletService.createStake(credentials); + _pendingTransaction = await walletService.createStake(snPubkey: snPubkey, amount: _amount); state = TransactionCreatedSuccessfully(); } catch (e) { state = SendingFailed(error: e.toString()); @@ -78,22 +65,20 @@ abstract class SendStoreBase with Store { } @action - Future createTransaction({String address, String amount}) async { + Future createTransaction({required String recipient, String? amount, required AppLocalizations l10n}) async { state = CreatingTransaction(); try { final _amount = amount ?? - (cryptoAmount == S.current.all - ? null - : cryptoAmount.replaceAll(',', '.')); - final credentials = OxenTransactionCreationCredentials( - address: address, + (cryptoAmount == l10n.all ? null : cryptoAmount.replaceAll(',', '.')); + + _pendingTransaction = await walletService.createTransaction( + recipient: recipient, amount: _amount, priority: settingsStore.transactionPriority); - _pendingTransaction = await walletService.createTransaction(credentials); state = TransactionCreatedSuccessfully(); - _lastRecipientAddress = address; + _lastRecipientAddress = recipient; } catch (e) { state = SendingFailed(error: e.toString()); } @@ -101,10 +86,16 @@ abstract class SendStoreBase with Store { @action Future commitTransaction() async { + if (_pendingTransaction == null) { + // Handle this here, but don't worry about translation because this is a logic error in the + // caller that shouldn't happen. + state = SendingFailed(error: 'No pending transaction'); + return; + } try { - final transactionId = _pendingTransaction.hash; + final transactionId = _pendingTransaction!.hash; state = TransactionCommitting(); - await _pendingTransaction.commit(); + await _pendingTransaction!.commit(); state = TransactionCommitted(); if (settingsStore.shouldSaveRecipientAddress) { @@ -119,8 +110,8 @@ abstract class SendStoreBase with Store { } @action - void setSendAll() { - cryptoAmount = S.current.all; + void setSendAll(AppLocalizations l10n) { + cryptoAmount = l10n.all; fiatAmount = ''; } @@ -128,28 +119,26 @@ abstract class SendStoreBase with Store { void changeCryptoAmount(String amount) { cryptoAmount = amount; - if (cryptoAmount != null && cryptoAmount.isNotEmpty) { + if (cryptoAmount.isNotEmpty) _calculateFiatAmount(); - } else { + else fiatAmount = ''; - } } @action void changeFiatAmount(String amount) { fiatAmount = amount; - if (fiatAmount != null && fiatAmount.isNotEmpty) { + if (fiatAmount.isNotEmpty) _calculateCryptoAmount(); - } else { + else cryptoAmount = ''; - } } @action Future _calculateFiatAmount() async { - final symbol = PriceStoreBase.generateSymbolForPair( - fiat: settingsStore.fiatCurrency, crypto: CryptoCurrency.oxen); + final symbol = PriceStoreBase.generateSymbolForFiat( + fiat: settingsStore.fiatCurrency); final price = priceStore.prices[symbol] ?? 0; try { @@ -162,8 +151,8 @@ abstract class SendStoreBase with Store { @action Future _calculateCryptoAmount() async { - final symbol = PriceStoreBase.generateSymbolForPair( - fiat: settingsStore.fiatCurrency, crypto: CryptoCurrency.oxen); + final symbol = PriceStoreBase.generateSymbolForFiat( + fiat: settingsStore.fiatCurrency); final price = priceStore.prices[symbol] ?? 0; try { @@ -184,120 +173,29 @@ abstract class SendStoreBase with Store { return recordAddress != name; } - void validateAddress(String value, {CryptoCurrency cryptoCurrency}) { - // XMR (95, 106), ADA (59, 92, 105), BCH (42), BNB (42), BTC (34, 42), DASH (34), EOS (42), - // ETH (42), LTC (34), NANO (64, 65), TRX (34), USDT (42), XLM (56), XRP (34) - const pattern = - '^[0-9a-zA-Z]{95}\$|^[0-9a-zA-Z]{34}\$|^[0-9a-zA-Z]{42}\$|^[0-9a-zA-Z]{56}\$|^[0-9a-zA-Z]{59}\$|^[0-9a-zA-Z_]{64}\$|^[0-9a-zA-Z_]{65}\$|^[0-9a-zA-Z]{92}\$|^[0-9a-zA-Z]{105}\$|^[0-9a-zA-Z]{106}\$'; - final regExp = RegExp(pattern); - isValid = regExp.hasMatch(value); - if (isValid && cryptoCurrency != null) { - switch (cryptoCurrency) { - case CryptoCurrency.oxen: - case CryptoCurrency.xmr: - isValid = (value.length == 95) || - (value.length == 97) || // Testnet addresses have 2 extra bits indicating the network id - (value.length == 106); - break; - case CryptoCurrency.ada: - isValid = (value.length == 59) || - (value.length == 92) || - (value.length == 105); - break; - case CryptoCurrency.bch: - isValid = (value.length == 42); - break; - case CryptoCurrency.bnb: - isValid = (value.length == 42); - break; - case CryptoCurrency.btc: - isValid = (value.length == 34) || (value.length == 42); - break; - case CryptoCurrency.dash: - isValid = (value.length == 34); - break; - case CryptoCurrency.eos: - isValid = (value.length == 42); - break; - case CryptoCurrency.eth: - isValid = (value.length == 42); - break; - case CryptoCurrency.ltc: - isValid = (value.length == 34); - break; - case CryptoCurrency.nano: - isValid = (value.length == 64) || (value.length == 65); - break; - case CryptoCurrency.trx: - isValid = (value.length == 34); - break; - case CryptoCurrency.usdt: - isValid = (value.length == 42); - break; - case CryptoCurrency.xlm: - isValid = (value.length == 56); - break; - case CryptoCurrency.xrp: - isValid = (value.length == 34); - break; - } - } - - isValid = true; - errorMessage = isValid ? null : S.current.error_text_address; - } - - void validateOXEN(String amount, int availableBalance) { - const maxValue = 18446744.073709551616; - const pattern = '^([0-9]+([.][0-9]{0,12})?|[.][0-9]{1,12})\$|ALL'; - final value = amount.replaceAll(',', '.'); - final regExp = RegExp(pattern); - - if (regExp.hasMatch(value)) { - if (value == 'ALL') { - isValid = true; - } else { - try { - final dValue = double.parse(value); - final maxAvailable = availableBalance; - isValid = - (dValue <= maxAvailable && dValue <= maxValue && dValue > 0); - } catch (e) { - isValid = false; - } - } - } else { - isValid = false; - } - - errorMessage = isValid ? null : S.current.error_text_oxen; + void validateAddress(String value, {required AppLocalizations l10n}) { + errorMessage = isValidOxenAddress(value) ? null : l10n.error_text_address; } - void validateFiat(String amount, {double maxValue}) { - const minValue = 0.01; + final oxenAmountRE = RegExp('^([0-9]+([.][0-9]{0,9})?|[.][0-9]{1,9})\$'); + void validateOXEN(String amount, int availableBalance, AppLocalizations l10n) { final value = amount.replaceAll(',', '.'); - if (value.isEmpty && cryptoAmount == 'ALL') { + var isValid = false; + if (value == l10n.all) { isValid = true; - } else { - const pattern = '^([0-9]+([.][0-9]{0,2})?|[.][0-9]{1,2})\$'; - final regExp = RegExp(pattern); - - if (regExp.hasMatch(value)) { - try { - final dValue = double.parse(value); - isValid = (dValue >= minValue && dValue <= maxValue); - } catch (e) { - isValid = false; - } - } else { + } else if (oxenAmountRE.hasMatch(value)) { + try { + final dValue = double.parse(value); + final maxAvailable = availableBalance; + isValid = (dValue <= maxAvailable && dValue > 0); + } catch (e) { isValid = false; } + } else { + isValid = false; } - errorMessage = isValid - ? null - : 'Value of amount can\'t exceed available balance.\n' - 'The number of fraction digits must be less or equal to 2'; + errorMessage = isValid ? null : l10n.error_text_oxen; } } diff --git a/lib/src/stores/send/sending_state.dart b/lib/src/stores/send/sending_state.dart index 1c9936df..91303747 100644 --- a/lib/src/stores/send/sending_state.dart +++ b/lib/src/stores/send/sending_state.dart @@ -1,5 +1,3 @@ -import 'package:flutter/foundation.dart'; - abstract class SendingState {} class SendingStateInitial extends SendingState {} @@ -13,7 +11,7 @@ class TransactionCommitting extends SendingState {} class TransactionCommitted extends SendingState {} class SendingFailed extends SendingState { - SendingFailed({@required this.error}); + SendingFailed({required this.error}); String error; } diff --git a/lib/src/stores/settings/settings_store.dart b/lib/src/stores/settings/settings_store.dart index 4862cd3a..b6539dae 100644 --- a/lib/src/stores/settings/settings_store.dart +++ b/lib/src/stores/settings/settings_store.dart @@ -1,15 +1,11 @@ -import 'package:devicelocale/devicelocale.dart'; -import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/scheduler.dart'; import 'package:flutter/services.dart'; import 'package:hive/hive.dart'; -import 'package:intl/intl.dart'; import 'package:mobx/mobx.dart'; import 'package:oxen_wallet/src/domain/common/balance_display_mode.dart'; import 'package:oxen_wallet/src/domain/common/default_settings_migration.dart'; import 'package:oxen_wallet/src/domain/common/fiat_currency.dart'; -import 'package:oxen_wallet/src/domain/common/language.dart'; import 'package:oxen_wallet/src/node/node.dart'; import 'package:oxen_wallet/src/wallet/crypto_amount_format.dart'; import 'package:oxen_wallet/src/wallet/oxen/transaction/transaction_priority.dart'; @@ -22,33 +18,29 @@ class SettingsStore = SettingsStoreBase with _$SettingsStore; abstract class SettingsStoreBase with Store { SettingsStoreBase( - {@required SharedPreferences sharedPreferences, - @required Box nodes, - @required FiatCurrency initialFiatCurrency, - @required OxenTransactionPriority initialTransactionPriority, - @required BalanceDisplayMode initialBalanceDisplayMode, - @required AmountDetail initialBalanceDetail, - @required bool initialSaveRecipientAddress, - @required bool allowBiometricAuthenticationKey, - @required bool enableFiatCurrencyKey, - @required bool initialDarkTheme, - @required int initialPinLength, - @required String initialLanguageCode, - @required String initialCurrentLocale}) { - fiatCurrency = initialFiatCurrency; - transactionPriority = initialTransactionPriority; - balanceDisplayMode = initialBalanceDisplayMode; - balanceDetail = initialBalanceDetail; - shouldSaveRecipientAddress = initialSaveRecipientAddress; - _sharedPreferences = sharedPreferences; - _nodes = nodes; - allowBiometricAuthentication = allowBiometricAuthenticationKey; - enableFiatCurrency = enableFiatCurrencyKey; - isDarkTheme = initialDarkTheme; - defaultPinLength = initialPinLength; - languageCode = initialLanguageCode; - currentLocale = initialCurrentLocale; - + {required SharedPreferences sharedPreferences, + required Box nodes, + required FiatCurrency initialFiatCurrency, + required OxenTransactionPriority initialTransactionPriority, + required BalanceDisplayMode initialBalanceDisplayMode, + required AmountDetail initialBalanceDetail, + required bool initialSaveRecipientAddress, + required bool allowBiometricAuthenticationKey, + required bool enableFiatCurrencyKey, + required bool initialDarkTheme, + required int initialPinLength}) : + fiatCurrency = initialFiatCurrency, + transactionPriority = initialTransactionPriority, + balanceDisplayMode = initialBalanceDisplayMode, + balanceDetail = initialBalanceDetail, + shouldSaveRecipientAddress = initialSaveRecipientAddress, + _sharedPreferences = sharedPreferences, + _nodes = nodes, + allowBiometricAuthentication = allowBiometricAuthenticationKey, + enableFiatCurrency = enableFiatCurrencyKey, + isDarkTheme = initialDarkTheme, + defaultPinLength = initialPinLength + { PackageInfo.fromPlatform().then( (PackageInfo packageInfo) => currentVersion = packageInfo.version); } @@ -63,15 +55,14 @@ abstract class SettingsStoreBase with Store { 'allow_biometric_authentication'; static const currentDarkTheme = 'dark_theme'; static const currentPinLength = 'current_pin_length'; - static const currentLanguageCode = 'language_code'; static const enableFiatCurrencyKey = 'enable_fiat_currency'; static Future load( - {@required SharedPreferences sharedPreferences, - @required Box nodes, - @required FiatCurrency initialFiatCurrency, - @required OxenTransactionPriority initialTransactionPriority, - @required BalanceDisplayMode initialBalanceDisplayMode}) async { + {required SharedPreferences sharedPreferences, + required Box nodes, + required FiatCurrency initialFiatCurrency, + required OxenTransactionPriority initialTransactionPriority, + required BalanceDisplayMode initialBalanceDisplayMode}) async { final currentFiatCurrency = FiatCurrency( symbol: sharedPreferences.getString(currentFiatCurrencyKey)); final currentTransactionPriority = OxenTransactionPriority.deserialize( @@ -79,25 +70,20 @@ abstract class SettingsStoreBase with Store { final currentBalanceDisplayMode = BalanceDisplayMode.deserialize( raw: sharedPreferences.getInt(currentBalanceDisplayModeKey)); final currentBalanceDetail = AmountDetail.deserialize( - sharedPreferences.getInt(currentBalanceDetailKey)) ?? - AmountDetail.ultra; + sharedPreferences.getInt(currentBalanceDetailKey)); final shouldSaveRecipientAddress = - sharedPreferences.getBool(shouldSaveRecipientAddressKey); + sharedPreferences.getBool(shouldSaveRecipientAddressKey) ?? true; final allowBiometricAuthentication = sharedPreferences.getBool(allowBiometricAuthenticationKey) ?? false; final enableFiatCurrency = sharedPreferences.getBool(enableFiatCurrencyKey) ?? false; final initialCurrentDarkMode = - SchedulerBinding.instance.window.platformBrightness == Brightness.dark; + SchedulerBinding.instance?.window.platformBrightness == Brightness.dark; final savedDarkTheme = sharedPreferences.getBool(currentDarkTheme) ?? initialCurrentDarkMode; final defaultPinLength = sharedPreferences.getInt(currentPinLength) ?? 4; - final savedLanguageCode = - sharedPreferences.getString(currentLanguageCode) ?? - await Language.localeDetection(); - final initialCurrentLocale = await Devicelocale.currentLocale; final store = SettingsStore( sharedPreferences: sharedPreferences, @@ -110,9 +96,7 @@ abstract class SettingsStoreBase with Store { allowBiometricAuthenticationKey: allowBiometricAuthentication, enableFiatCurrencyKey: enableFiatCurrency, initialDarkTheme: savedDarkTheme, - initialPinLength: defaultPinLength, - initialLanguageCode: savedLanguageCode, - initialCurrentLocale: initialCurrentLocale); + initialPinLength: defaultPinLength); await store.loadSettings(); @@ -120,7 +104,7 @@ abstract class SettingsStoreBase with Store { } @observable - Node node; + Node? node; @observable FiatCurrency fiatCurrency; @@ -149,30 +133,26 @@ abstract class SettingsStoreBase with Store { @observable int defaultPinLength; - String languageCode; - - String currentLocale; - - SharedPreferences _sharedPreferences; - Box _nodes; - String currentVersion; + final SharedPreferences _sharedPreferences; + final Box _nodes; + late String currentVersion; @action Future setAllowBiometricAuthentication( - {@required bool allowBiometricAuthentication}) async { + {required bool allowBiometricAuthentication}) async { this.allowBiometricAuthentication = allowBiometricAuthentication; await _sharedPreferences.setBool( allowBiometricAuthenticationKey, allowBiometricAuthentication); } @action - Future setEnableFiatCurrency({@required bool enableFiatCurrency}) async { + Future setEnableFiatCurrency({required bool enableFiatCurrency}) async { this.enableFiatCurrency = enableFiatCurrency; await _sharedPreferences.setBool(enableFiatCurrencyKey, enableFiatCurrency); } @action - Future saveDarkTheme({@required bool isDarkTheme}) async { + Future saveDarkTheme({required bool isDarkTheme}) async { this.isDarkTheme = isDarkTheme; SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle( statusBarColor: isDarkTheme ? Colors.black : Colors.white)); @@ -180,19 +160,13 @@ abstract class SettingsStoreBase with Store { } @action - Future saveLanguageCode({@required String languageCode}) async { - this.languageCode = languageCode; - await _sharedPreferences.setString(currentLanguageCode, languageCode); - } - - @action - Future setCurrentNode({@required Node node}) async { + Future setCurrentNode({required Node node}) async { this.node = node; - await _sharedPreferences.setInt(currentNodeIdKey, node.key as int); + await _sharedPreferences.setInt(currentNodeIdKey, this.node!.key as int); } @action - Future setCurrentFiatCurrency({@required FiatCurrency currency}) async { + Future setCurrentFiatCurrency({required FiatCurrency currency}) async { fiatCurrency = currency; await _sharedPreferences.setString( currentFiatCurrencyKey, fiatCurrency.serialize()); @@ -200,7 +174,7 @@ abstract class SettingsStoreBase with Store { @action Future setCurrentTransactionPriority( - {@required OxenTransactionPriority priority}) async { + {required OxenTransactionPriority priority}) async { transactionPriority = priority; await _sharedPreferences.setInt( currentTransactionPriorityKey, priority.serialize()); @@ -208,14 +182,14 @@ abstract class SettingsStoreBase with Store { @action Future setCurrentBalanceDisplayMode( - {@required BalanceDisplayMode balanceDisplayMode}) async { + {required BalanceDisplayMode balanceDisplayMode}) async { this.balanceDisplayMode = balanceDisplayMode; await _sharedPreferences.setInt( currentBalanceDisplayModeKey, balanceDisplayMode.serialize()); } @action - Future setCurrentBalanceDetail({@required AmountDetail balanceDetail}) async { + Future setCurrentBalanceDetail({required AmountDetail balanceDetail}) async { this.balanceDetail = balanceDetail; await _sharedPreferences.setInt( currentBalanceDetailKey, balanceDetail.index); @@ -223,7 +197,7 @@ abstract class SettingsStoreBase with Store { @action Future setSaveRecipientAddress( - {@required bool shouldSaveRecipientAddress}) async { + {required bool shouldSaveRecipientAddress}) async { this.shouldSaveRecipientAddress = shouldSaveRecipientAddress; await _sharedPreferences.setBool( shouldSaveRecipientAddressKey, shouldSaveRecipientAddress); @@ -232,14 +206,14 @@ abstract class SettingsStoreBase with Store { Future loadSettings() async => node = await _fetchCurrentNode(); @action - Future setDefaultPinLength({@required int pinLength}) async { + Future setDefaultPinLength({required int pinLength}) async { defaultPinLength = pinLength; await _sharedPreferences.setInt(currentPinLength, pinLength); } Future _fetchCurrentNode() async { final id = _sharedPreferences.getInt(currentNodeIdKey); - return _nodes.get(id); + return _nodes.get(id)!; } Future setCurrentNodeToDefault() async { @@ -247,10 +221,4 @@ abstract class SettingsStoreBase with Store { sharedPreferences: _sharedPreferences, nodes: _nodes); await loadSettings(); } - - DateFormat getCurrentDateFormat( - {@required String formatUSA, @required String formatDefault}) => - currentLocale == 'en_US' - ? DateFormat(formatUSA, languageCode) - : DateFormat(formatDefault, languageCode); } diff --git a/lib/src/stores/subaddress_creation/subaddress_creation_state.dart b/lib/src/stores/subaddress_creation/subaddress_creation_state.dart index 0d8adaae..30289482 100644 --- a/lib/src/stores/subaddress_creation/subaddress_creation_state.dart +++ b/lib/src/stores/subaddress_creation/subaddress_creation_state.dart @@ -7,7 +7,7 @@ class SubaddressIsCreating extends SubaddressCreationState {} class SubaddressCreatedSuccessfully extends SubaddressCreationState {} class SubaddressCreationFailure extends SubaddressCreationState { - SubaddressCreationFailure({this.error}); + SubaddressCreationFailure({required this.error}); String error; -} \ No newline at end of file +} diff --git a/lib/src/stores/subaddress_creation/subaddress_creation_store.dart b/lib/src/stores/subaddress_creation/subaddress_creation_store.dart index 1507df68..b0993343 100644 --- a/lib/src/stores/subaddress_creation/subaddress_creation_store.dart +++ b/lib/src/stores/subaddress_creation/subaddress_creation_store.dart @@ -1,5 +1,4 @@ import 'dart:async'; -import 'package:flutter/foundation.dart'; import 'package:mobx/mobx.dart'; import 'package:oxen_wallet/src/wallet/wallet.dart'; import 'package:oxen_wallet/src/wallet/oxen/oxen_wallet.dart'; @@ -7,7 +6,8 @@ import 'package:oxen_wallet/src/wallet/oxen/subaddress_list.dart'; import 'package:oxen_wallet/src/domain/services/wallet_service.dart'; import 'package:oxen_wallet/src/stores/subaddress_creation/subaddress_creation_state.dart'; import 'package:oxen_wallet/src/wallet/oxen/account.dart'; -import 'package:oxen_wallet/generated/l10n.dart'; +import 'package:oxen_wallet/src/util/validators.dart'; +import 'package:oxen_wallet/l10n.dart'; part 'subaddress_creation_store.g.dart'; @@ -15,29 +15,24 @@ class SubadrressCreationStore = SubadrressCreationStoreBase with _$SubadrressCreationStore; abstract class SubadrressCreationStoreBase with Store { - SubadrressCreationStoreBase({@required WalletService walletService}) { - state = SubaddressCreationStateInitial(); - + SubadrressCreationStoreBase({required WalletService walletService}) { if (walletService.currentWallet != null) { - _onWalletChanged(walletService.currentWallet); + _onWalletChanged(walletService.currentWallet!); } _onWalletChangeSubscription = walletService.onWalletChange.listen(_onWalletChanged); } - SubaddressCreationState state; - - @observable - bool isValid; + SubaddressCreationState state = SubaddressCreationStateInitial(); @observable - String errorMessage; + String? errorMessage; - SubaddressList _subaddressList; - StreamSubscription _onWalletChangeSubscription; - StreamSubscription _onAccountChangeSubscription; - Account _account; + SubaddressList _subaddressList = SubaddressList(); + late StreamSubscription _onWalletChangeSubscription; + StreamSubscription? _onAccountChangeSubscription; + Account _account = Account(id: 0); // @override // void dispose() { @@ -50,7 +45,7 @@ abstract class SubadrressCreationStoreBase with Store { // super.dispose(); // } - Future add({String label}) async { + Future add({required String label}) async { try { state = SubaddressIsCreating(); await _subaddressList.addSubaddress( @@ -77,10 +72,7 @@ abstract class SubadrressCreationStoreBase with Store { print('Incorrect wallet type for this operation (SubaddressList)'); } - void validateSubaddressName(String value) { - const pattern = '''^[^`,'"]{1,20}\$'''; - final regExp = RegExp(pattern); - isValid = regExp.hasMatch(value); - errorMessage = isValid ? null : S.current.error_text_subaddress_name; + void validateSubaddressName(String? value, AppLocalizations l10n) { + errorMessage = hasNonWhitespace(value) ? null : l10n.error_text_empty; } } diff --git a/lib/src/stores/subaddress_list/subaddress_list_store.dart b/lib/src/stores/subaddress_list/subaddress_list_store.dart index 1e381a81..97d4dab6 100644 --- a/lib/src/stores/subaddress_list/subaddress_list_store.dart +++ b/lib/src/stores/subaddress_list/subaddress_list_store.dart @@ -1,5 +1,4 @@ import 'dart:async'; -import 'package:flutter/foundation.dart'; import 'package:mobx/mobx.dart'; import 'package:oxen_wallet/src/wallet/wallet.dart'; import 'package:oxen_wallet/src/wallet/oxen/oxen_wallet.dart'; @@ -13,11 +12,11 @@ part 'subaddress_list_store.g.dart'; class SubaddressListStore = SubaddressListStoreBase with _$SubaddressListStore; abstract class SubaddressListStoreBase with Store { - SubaddressListStoreBase({@required WalletService walletService}) { - subaddresses = ObservableList(); - + SubaddressListStoreBase({required WalletService walletService}) : + subaddresses = ObservableList() + { if (walletService.currentWallet != null) { - _onWalletChanged(walletService.currentWallet); + _onWalletChanged(walletService.currentWallet!); } _onWalletChangeSubscription = @@ -27,11 +26,11 @@ abstract class SubaddressListStoreBase with Store { @observable ObservableList subaddresses; - SubaddressList _subaddressList; - StreamSubscription _onWalletChangeSubscription; - StreamSubscription> _onSubaddressesChangeSubscription; - StreamSubscription _onAccountChangeSubscription; - Account _account; + SubaddressList _subaddressList = SubaddressList(); + late StreamSubscription _onWalletChangeSubscription; + StreamSubscription>? _onSubaddressesChangeSubscription; + StreamSubscription? _onAccountChangeSubscription; + Account _account = Account(id: 0); // @override // void dispose() { @@ -47,14 +46,14 @@ abstract class SubaddressListStoreBase with Store { // super.dispose(); // } - Future _updateSubaddressList({int accountIndex}) async { + Future _updateSubaddressList({required int accountIndex}) async { await _subaddressList.refresh(accountIndex: accountIndex); subaddresses = ObservableList.of(_subaddressList.getAll()); } Future _onWalletChanged(Wallet wallet) async { if (_onSubaddressesChangeSubscription != null) { - await _onSubaddressesChangeSubscription.cancel(); + await _onSubaddressesChangeSubscription!.cancel(); } if (wallet is OxenWallet) { diff --git a/lib/src/stores/sync/sync_store.dart b/lib/src/stores/sync/sync_store.dart index ac680494..12fc9f9d 100644 --- a/lib/src/stores/sync/sync_store.dart +++ b/lib/src/stores/sync/sync_store.dart @@ -1,5 +1,4 @@ import 'dart:async'; -import 'package:flutter/foundation.dart'; import 'package:mobx/mobx.dart'; import 'package:oxen_wallet/src/node/sync_status.dart'; import 'package:oxen_wallet/src/wallet/wallet.dart'; @@ -12,11 +11,11 @@ class SyncStore = SyncStoreBase with _$SyncStore; abstract class SyncStoreBase with Store { SyncStoreBase( {SyncStatus syncStatus = const NotConnectedSyncStatus(), - @required WalletService walletService}) { - status = syncStatus; - + required WalletService walletService}) + : status = syncStatus + { if (walletService.currentWallet != null) { - _onWalletChanged(walletService.currentWallet); + _onWalletChanged(walletService.currentWallet!); } _onWalletChangeSubscription = @@ -26,8 +25,8 @@ abstract class SyncStoreBase with Store { @observable SyncStatus status; - StreamSubscription _onWalletChangeSubscription; - StreamSubscription _onSyncStatusChangeSubscription; + late StreamSubscription _onWalletChangeSubscription; + StreamSubscription? _onSyncStatusChangeSubscription; // @override // void dispose() { @@ -41,7 +40,7 @@ abstract class SyncStoreBase with Store { void _onWalletChanged(Wallet wallet) { if (_onSyncStatusChangeSubscription != null) { - _onSyncStatusChangeSubscription.cancel(); + _onSyncStatusChangeSubscription!.cancel(); } _onSyncStatusChangeSubscription = diff --git a/lib/src/stores/user/user_store.dart b/lib/src/stores/user/user_store.dart index 4af93139..835ac0ae 100644 --- a/lib/src/stores/user/user_store.dart +++ b/lib/src/stores/user/user_store.dart @@ -1,5 +1,4 @@ import 'package:mobx/mobx.dart'; -import 'package:flutter/foundation.dart'; import 'package:oxen_wallet/src/domain/services/user_service.dart'; import 'package:oxen_wallet/src/stores/user/user_store_state.dart'; @@ -8,18 +7,15 @@ part 'user_store.g.dart'; class UserStore = UserStoreBase with _$UserStore; abstract class UserStoreBase with Store { - UserStoreBase({@required this.accountService}); + UserStoreBase({required this.accountService}); UserService accountService; @observable - UserStoreState state; - - @observable - String errorMessage; + UserStoreState state = UserStoreStateInitial(); @action - Future set({String password}) async { + Future set({required String password}) async { state = UserStoreStateInitial(); try { diff --git a/lib/src/stores/user/user_store_state.dart b/lib/src/stores/user/user_store_state.dart index fe982de2..b544beb1 100644 --- a/lib/src/stores/user/user_store_state.dart +++ b/lib/src/stores/user/user_store_state.dart @@ -1,4 +1,3 @@ -import 'package:flutter/foundation.dart'; abstract class UserStoreState {} @@ -7,7 +6,7 @@ class UserStoreStateInitial extends UserStoreState {} class PinCodeSetSuccessfully extends UserStoreState {} class PinCodeSetFailed extends UserStoreState { - PinCodeSetFailed({@required this.error}); + PinCodeSetFailed({required this.error}); String error; } diff --git a/lib/src/stores/wallet/wallet_keys_store.dart b/lib/src/stores/wallet/wallet_keys_store.dart index 778245ca..464be87d 100644 --- a/lib/src/stores/wallet/wallet_keys_store.dart +++ b/lib/src/stores/wallet/wallet_keys_store.dart @@ -1,4 +1,3 @@ -import 'package:flutter/foundation.dart'; import 'package:mobx/mobx.dart'; import 'package:oxen_wallet/src/domain/services/wallet_service.dart'; @@ -7,18 +6,18 @@ part 'wallet_keys_store.g.dart'; class WalletKeysStore = WalletKeysStoreBase with _$WalletKeysStore; abstract class WalletKeysStoreBase with Store { - WalletKeysStoreBase({@required WalletService walletService}) { - publicViewKey = ''; - privateViewKey = ''; - publicSpendKey = ''; - privateSpendKey = ''; + WalletKeysStoreBase({required WalletService walletService}) : + publicViewKey = '', + privateViewKey = '', + publicSpendKey = '', + privateSpendKey = '' { if (walletService.currentWallet != null) { walletService.getKeys().then((keys) { - publicViewKey = keys['publicViewKey']; - privateViewKey = keys['privateViewKey']; - publicSpendKey = keys['publicSpendKey']; - privateSpendKey = keys['privateSpendKey']; + publicViewKey = keys['publicViewKey'] ?? ''; + privateViewKey = keys['privateViewKey'] ?? ''; + publicSpendKey = keys['publicSpendKey'] ?? ''; + privateSpendKey = keys['privateSpendKey'] ?? ''; }); } } diff --git a/lib/src/stores/wallet/wallet_store.dart b/lib/src/stores/wallet/wallet_store.dart index 8790a64f..2fc56908 100644 --- a/lib/src/stores/wallet/wallet_store.dart +++ b/lib/src/stores/wallet/wallet_store.dart @@ -6,24 +6,22 @@ import 'package:oxen_wallet/src/wallet/oxen/account.dart'; import 'package:oxen_wallet/src/wallet/oxen/oxen_wallet.dart'; import 'package:oxen_wallet/src/wallet/oxen/subaddress.dart'; import 'package:oxen_wallet/src/domain/services/wallet_service.dart'; -import 'package:oxen_wallet/src/domain/common/crypto_currency.dart'; import 'package:oxen_wallet/src/stores/settings/settings_store.dart'; -import 'package:oxen_wallet/generated/l10n.dart'; +import 'package:oxen_wallet/l10n.dart'; part 'wallet_store.g.dart'; class WalletStore = WalletStoreBase with _$WalletStore; abstract class WalletStoreBase with Store { - WalletStoreBase({WalletService walletService, SettingsStore settingsStore}) { - _walletService = walletService; - _settingsStore = settingsStore; - name = ''; - type = CryptoCurrency.oxen; - amountValue = ''; - + WalletStoreBase({required WalletService walletService, required SettingsStore settingsStore}) + : _walletService = walletService, + _settingsStore = settingsStore, + name = '', + amountValue = '' + { if (_walletService.currentWallet != null) { - _onWalletChanged(_walletService.currentWallet); + _onWalletChanged(_walletService.currentWallet!); } _onWalletChangeSubscription = _walletService.onWalletChange @@ -31,36 +29,30 @@ abstract class WalletStoreBase with Store { } @observable - String address; + String? address; @observable String name; @observable - Subaddress subaddress; - - @observable - Account account; + Subaddress subaddress = Subaddress(id: 0, address: '', label: ''); @observable - CryptoCurrency type; + Account account = Account(id: 0); @observable String amountValue; @observable - bool isValid; + String? errorMessage; - @observable - String errorMessage; + String get id => name + 'oxen'; - String get id => name + type.toString().toLowerCase(); - - WalletService _walletService; - SettingsStore _settingsStore; - StreamSubscription _onWalletChangeSubscription; - StreamSubscription _onAccountChangeSubscription; - StreamSubscription _onSubaddressChangeSubscription; + final WalletService _walletService; + final SettingsStore _settingsStore; + late StreamSubscription _onWalletChangeSubscription; + StreamSubscription? _onAccountChangeSubscription; + StreamSubscription? _onSubaddressChangeSubscription; // @override // void dispose() { @@ -104,21 +96,17 @@ abstract class WalletStoreBase with Store { await _walletService.connectToNode(node: _settingsStore.node); @action - Future rescan({int restoreHeight}) async => + Future rescan({required int restoreHeight}) async => await _walletService.rescan(restoreHeight: restoreHeight); @action Future startSync() async => await _walletService.startSync(); @action - Future connectToNode({Node node}) async => + Future connectToNode({required Node? node}) async => await _walletService.connectToNode(node: node); Future _onWalletChanged(Wallet wallet) async { - if (this == null) { - return; - } - wallet.onNameChange.listen((name) => this.name = name); wallet.onAddressChange.listen((address) => this.address = address); @@ -135,10 +123,11 @@ abstract class WalletStoreBase with Store { amountValue = value.isNotEmpty ? '?tx_amount=$value' : ''; @action - void validateAmount(String amount) { - const maxValue = 18446744.073709551616; + void validateAmount(String amount, AppLocalizations t) { + const maxValue = 18446744073.0; final value = amount.replaceAll(',', '.'); + bool isValid; if (value.isEmpty) { isValid = true; } else { @@ -157,7 +146,7 @@ abstract class WalletStoreBase with Store { } } - errorMessage = isValid ? null : S.current.error_text_amount; + errorMessage = isValid ? null : t.error_text_amount; } Future isConnected() async => await _walletService.isConnected(); diff --git a/lib/src/stores/wallet_creation/wallet_creation_state.dart b/lib/src/stores/wallet_creation/wallet_creation_state.dart index 43223a1d..d0d7f958 100644 --- a/lib/src/stores/wallet_creation/wallet_creation_state.dart +++ b/lib/src/stores/wallet_creation/wallet_creation_state.dart @@ -1,5 +1,3 @@ -import 'package:flutter/foundation.dart'; - abstract class WalletCreationState {} class WalletCreationStateInitial extends WalletCreationState {} @@ -9,7 +7,7 @@ class WalletIsCreating extends WalletCreationState {} class WalletCreatedSuccessfully extends WalletCreationState {} class WalletCreationFailure extends WalletCreationState { - WalletCreationFailure({@required this.error}); + WalletCreationFailure({required this.error}); String error; -} \ No newline at end of file +} diff --git a/lib/src/stores/wallet_creation/wallet_creation_store.dart b/lib/src/stores/wallet_creation/wallet_creation_store.dart index 309afbf1..bcd641b4 100644 --- a/lib/src/stores/wallet_creation/wallet_creation_store.dart +++ b/lib/src/stores/wallet_creation/wallet_creation_store.dart @@ -1,10 +1,10 @@ import 'package:mobx/mobx.dart'; -import 'package:flutter/foundation.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:oxen_wallet/src/domain/services/wallet_list_service.dart'; import 'package:oxen_wallet/src/stores/wallet_creation/wallet_creation_state.dart'; import 'package:oxen_wallet/src/stores/authentication/authentication_store.dart'; -import 'package:oxen_wallet/generated/l10n.dart'; +import 'package:oxen_wallet/src/util/validators.dart'; +import 'package:oxen_wallet/l10n.dart'; part 'wallet_creation_store.g.dart'; @@ -12,11 +12,11 @@ class WalletCreationStore = WalletCreationStoreBase with _$WalletCreationStore; abstract class WalletCreationStoreBase with Store { WalletCreationStoreBase( - {@required this.authStore, - @required this.walletListService, - @required this.sharedPreferences}) { - state = WalletCreationStateInitial(); - } + {required this.authStore, + required this.walletListService, + required this.sharedPreferences}) + : + state = WalletCreationStateInitial(); final AuthenticationStore authStore; final WalletListService walletListService; @@ -26,13 +26,10 @@ abstract class WalletCreationStoreBase with Store { WalletCreationState state; @observable - String errorMessage; - - @observable - bool isValid; + String? errorMessage; @action - Future create({String name, String language}) async { + Future create({required String name, required String language}) async { state = WalletCreationStateInitial(); try { @@ -45,10 +42,7 @@ abstract class WalletCreationStoreBase with Store { } } - void validateWalletName(String value) { - const pattern = '^[a-zA-Z0-9_]{1,255}\$'; - final regExp = RegExp(pattern); - isValid = regExp.hasMatch(value); - errorMessage = isValid ? null : S.current.error_text_wallet_name; + void validateWalletName(String? value, AppLocalizations l10n) { + errorMessage = hasNonWhitespace(value) ? null : l10n.error_text_empty; } } diff --git a/lib/src/stores/wallet_list/wallet_list_store.dart b/lib/src/stores/wallet_list/wallet_list_store.dart index 50c9f7e1..e143b833 100644 --- a/lib/src/stores/wallet_list/wallet_list_store.dart +++ b/lib/src/stores/wallet_list/wallet_list_store.dart @@ -1,4 +1,3 @@ -import 'package:flutter/foundation.dart'; import 'package:mobx/mobx.dart'; import 'package:oxen_wallet/src/wallet/wallet_description.dart'; import 'package:oxen_wallet/src/domain/services/wallet_list_service.dart'; @@ -10,19 +9,19 @@ class WalletListStore = WalletListStoreBase with _$WalletListStore; abstract class WalletListStoreBase with Store { WalletListStoreBase( - {@required WalletListService walletListService, - @required WalletService walletService}) { - _walletListService = walletListService; - _walletService = walletService; - wallets = []; + {required WalletListService walletListService, + required WalletService walletService}) + : _walletListService = walletListService, + _walletService = walletService + { walletListService.getAll().then((walletList) => wallets = walletList); } @observable - List wallets; + List wallets = []; - WalletListService _walletListService; - WalletService _walletService; + final WalletListService _walletListService; + final WalletService _walletService; bool isCurrentWallet(WalletDescription wallet) => _walletService.description?.name == wallet.name; diff --git a/lib/src/stores/wallet_restoration/wallet_restoration_state.dart b/lib/src/stores/wallet_restoration/wallet_restoration_state.dart index afd6649e..9a89b191 100644 --- a/lib/src/stores/wallet_restoration/wallet_restoration_state.dart +++ b/lib/src/stores/wallet_restoration/wallet_restoration_state.dart @@ -1,5 +1,3 @@ -import 'package:flutter/foundation.dart'; - abstract class WalletRestorationState {} class WalletRestorationStateInitial extends WalletRestorationState {} @@ -9,7 +7,7 @@ class WalletIsRestoring extends WalletRestorationState {} class WalletRestoredSuccessfully extends WalletRestorationState {} class WalletRestorationFailure extends WalletRestorationState { - WalletRestorationFailure({@required this.error}); + WalletRestorationFailure({required this.error}); String error; } diff --git a/lib/src/stores/wallet_restoration/wallet_restoration_store.dart b/lib/src/stores/wallet_restoration/wallet_restoration_store.dart index a05c5c33..967f0644 100644 --- a/lib/src/stores/wallet_restoration/wallet_restoration_store.dart +++ b/lib/src/stores/wallet_restoration/wallet_restoration_store.dart @@ -1,12 +1,11 @@ import 'package:mobx/mobx.dart'; -import 'package:flutter/foundation.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:oxen_wallet/src/domain/services/wallet_list_service.dart'; -import 'package:oxen_wallet/src/wallet/mnemotic_item.dart'; +import 'package:oxen_wallet/src/wallet/mnemonic_item.dart'; import 'package:oxen_wallet/src/stores/wallet_restoration/wallet_restoration_state.dart'; import 'package:oxen_wallet/src/stores/authentication/authentication_store.dart'; -import 'package:oxen_wallet/src/domain/common/crypto_currency.dart'; -import 'package:oxen_wallet/generated/l10n.dart'; +import 'package:oxen_wallet/l10n.dart'; +import 'package:oxen_wallet/src/util/validators.dart'; part 'wallet_restoration_store.g.dart'; @@ -16,30 +15,25 @@ class WalletRestorationStore = WalletRestorationStoreBase abstract class WalletRestorationStoreBase with Store { WalletRestorationStoreBase( {this.seed, - @required this.authStore, - @required this.walletListService, - @required this.sharedPreferences}) { - state = WalletRestorationStateInitial(); - } + required this.authStore, + required this.walletListService, + required this.sharedPreferences}); final AuthenticationStore authStore; final WalletListService walletListService; final SharedPreferences sharedPreferences; @observable - WalletRestorationState state; + WalletRestorationState state = WalletRestorationStateInitial(); @observable - String errorMessage; + String? errorMessage; @observable - bool isValid; - - @observable - List seed; + List? seed; @action - Future restoreFromSeed({String name, String seed, int restoreHeight}) async { + Future restoreFromSeed({required String name, String? seed, required int restoreHeight}) async { state = WalletRestorationStateInitial(); final _seed = seed ?? _seedText(); @@ -55,12 +49,12 @@ abstract class WalletRestorationStoreBase with Store { @action Future restoreFromKeys( - {String name, - String language, - String address, - String viewKey, - String spendKey, - int restoreHeight}) async { + {required String name, + required String language, + required String address, + required String viewKey, + required String spendKey, + required int restoreHeight}) async { state = WalletRestorationStateInitial(); try { @@ -75,95 +69,43 @@ abstract class WalletRestorationStoreBase with Store { } @action - void setSeed(List seed) { + void setSeed(List seed) { this.seed = seed; } @action - void validateSeed(List seed) { + void validateSeed(List? seed, AppLocalizations l10n) { final _seed = seed ?? this.seed; - var isValid = _seed != null ? _seed.length == 25 : false; - if (!isValid) { - errorMessage = S.current.wallet_restoration_store_incorrect_seed_length; - this.isValid = isValid; + if (_seed == null || _seed.length != 25) { + errorMessage = l10n.wallet_restoration_store_incorrect_seed_length; return; } for (final item in _seed) { if (!item.isCorrect()) { - isValid = false; - break; + errorMessage = l10n.incorrect_seed; + return; } } - if (isValid) { - errorMessage = null; - } - - this.isValid = isValid; + errorMessage = null; return; } String _seedText() { - return seed.fold('', (acc, item) => acc + ' ' + item.toString()); + return seed?.join(' ') ?? ''; } - void validateWalletName(String value) { - const pattern = '^[a-zA-Z0-9_]{1,15}\$'; - final regExp = RegExp(pattern); - isValid = regExp.hasMatch(value); - errorMessage = isValid ? null : S.current.error_text_wallet_name; + void validateWalletName(String value, AppLocalizations l10n) { + errorMessage = hasNonWhitespace(value) ? null : l10n.error_text_empty; } - void validateAddress(String value, {CryptoCurrency cryptoCurrency}) { - // OXEN (95, 106), XMR (95, 106), ADA (59, 92, 105), BCH (42), BNB (42), - // BTC (34, 42), DASH (34), EOS (42), ETH (42), LTC (34), NANO (64, 65), - // TRX (34), USDT (42), XLM (56), XRP (34) - const pattern = '^[0-9a-zA-Z]{95}\$|^[0-9a-zA-Z]{34}\$|^[0-9a-zA-Z]{42}\$|^[0-9a-zA-Z]{56}\$|^[0-9a-zA-Z]{59}\$|^[0-9a-zA-Z_]{64}\$|^[0-9a-zA-Z_]{65}\$|^[0-9a-zA-Z]{92}\$|^[0-9a-zA-Z]{105}\$|^[0-9a-zA-Z]{106}\$'; - final regExp = RegExp(pattern); - isValid = regExp.hasMatch(value); - if (isValid && cryptoCurrency != null) { - switch (cryptoCurrency) { - case CryptoCurrency.xmr: - case CryptoCurrency.oxen: - isValid = (value.length == 95)||(value.length == 106); - break; - case CryptoCurrency.bch: - case CryptoCurrency.bnb: - case CryptoCurrency.usdt: - case CryptoCurrency.eos: - case CryptoCurrency.eth: - isValid = (value.length == 42); - break; - case CryptoCurrency.dash: - case CryptoCurrency.ltc: - case CryptoCurrency.trx: - case CryptoCurrency.xrp: - isValid = (value.length == 34); - break; - case CryptoCurrency.ada: - isValid = (value.length == 59)||(value.length == 92)||(value.length == 105); - break; - case CryptoCurrency.btc: - isValid = (value.length == 34)||(value.length == 42); - break; - case CryptoCurrency.nano: - isValid = (value.length == 64)||(value.length == 65); - break; - case CryptoCurrency.xlm: - isValid = (value.length == 56); - break; - } - } - - errorMessage = isValid ? null : S.current.error_text_address; + void validateAddress(String value, {required AppLocalizations l10n}) { + errorMessage = isValidOxenAddress(value) ? null : l10n.error_text_address; } - void validateKeys(String value) { - const pattern = '^[A-Fa-f0-9]{64}\$'; - final regExp = RegExp(pattern); - isValid = regExp.hasMatch(value); - errorMessage = isValid ? null : S.current.error_text_keys; + void validateKeys(String value, AppLocalizations l10n) { + errorMessage = isHexKey(value) ? null : l10n.error_text_keys; } } diff --git a/lib/src/stores/wallet_seed/wallet_seed_store.dart b/lib/src/stores/wallet_seed/wallet_seed_store.dart index 39946b98..bbfa2884 100644 --- a/lib/src/stores/wallet_seed/wallet_seed_store.dart +++ b/lib/src/stores/wallet_seed/wallet_seed_store.dart @@ -1,4 +1,3 @@ -import 'package:flutter/foundation.dart'; import 'package:mobx/mobx.dart'; import 'package:oxen_wallet/src/domain/services/wallet_service.dart'; @@ -7,9 +6,7 @@ part 'wallet_seed_store.g.dart'; class WalletSeedStore = WalletSeedStoreBase with _$WalletSeedStore; abstract class WalletSeedStoreBase with Store { - WalletSeedStoreBase({@required WalletService walletService}) { - seed = ''; - + WalletSeedStoreBase({required WalletService walletService}) { if (walletService.currentWallet != null) { walletService.getSeed().then((seed) => this.seed = seed); walletService.getName().then((name) => this.name = name); @@ -17,8 +14,8 @@ abstract class WalletSeedStoreBase with Store { } @observable - String name; + String name = ''; @observable - String seed; + String seed = ''; } diff --git a/lib/src/util/generate_name.dart b/lib/src/util/generate_name.dart index a6da92c7..d30a6517 100644 --- a/lib/src/util/generate_name.dart +++ b/lib/src/util/generate_name.dart @@ -8,17 +8,17 @@ extension StringExtension on String { } } +Future> loadWordList(String path) async { + final raw = await rootBundle.loadString(path); + final list = List.from(raw.split(RegExp(' *\n *'))); + list.removeWhere((i) => i.isEmpty); + return list; +} + Future generateName() async { final randomThing = Random(); - final adjectiveStringRaw = - await rootBundle.loadString('assets/text/Wallet_Adjectives.txt'); - final nounStringRaw = - await rootBundle.loadString('assets/text/Wallet_Nouns.txt'); - final adjectives = List.from(adjectiveStringRaw.split('\n')); - final nouns = List.from(nounStringRaw.split('\n')); - final chosenAdjective = adjectives[randomThing.nextInt(adjectives.length)]; - final chosenNoun = nouns[randomThing.nextInt(nouns.length)]; - final returnString = - '${chosenAdjective.capitalized().trim()}${chosenNoun.capitalized().trim()}'; - return returnString; + final adjectives = await loadWordList('assets/text/Wallet_Adjectives.txt'); + final nouns = await loadWordList('assets/text/Wallet_Nouns.txt'); + return adjectives[randomThing.nextInt(adjectives.length)].capitalized() + + nouns[randomThing.nextInt(nouns.length)].capitalized(); } diff --git a/lib/src/util/parseBoolFromString.dart b/lib/src/util/parseBoolFromString.dart index dbcbdedd..a1c0a4fd 100644 --- a/lib/src/util/parseBoolFromString.dart +++ b/lib/src/util/parseBoolFromString.dart @@ -1,3 +1,3 @@ -bool parseBoolFromString(String string) { - return string.toString() == 'true'; -} \ No newline at end of file +bool parseBoolFromString(String? string) { + return string == 'true'; +} diff --git a/lib/src/util/validators.dart b/lib/src/util/validators.dart new file mode 100644 index 00000000..ce2210a9 --- /dev/null +++ b/lib/src/util/validators.dart @@ -0,0 +1,20 @@ +import 'package:oxen_wallet/devtools.dart'; + +final _base58RE = RegExp('[1-9A-HJ-NP-Za-km-z]+\$'); +const int _addrLen = isTestnet ? 97 : 95; +const int _addrLenIntegrated = _addrLen + 11; +final _regPrefixRE = isTestnet ? RegExp('^T6[STU]') : RegExp('^L[4-9A-E]'); +final _intPrefixRE = isTestnet ? RegExp('^TG[89AB]') : RegExp('^L[E-HJ-NPQ]'); +final _subPrefixRE = isTestnet ? RegExp('^TR[qrs]') : RegExp('^L[Q-Za]'); + +bool isValidOxenAddress(String? value) => + value != null && _base58RE.hasMatch(value) && ( + (value.length == _addrLen && (_regPrefixRE.hasMatch(value) || _subPrefixRE.hasMatch(value))) + || + (value.length == _addrLenIntegrated && _intPrefixRE.hasMatch(value))); + +final _hexKeyRE = RegExp('^[0-9a-fA-F]{64}\$'); +bool isHexKey(String? value) => value != null && _hexKeyRE.hasMatch(value); + +final _nonWhitespaceRE = RegExp('\\S'); +bool hasNonWhitespace(String? value) => value != null && _nonWhitespaceRE.hasMatch(value); diff --git a/lib/src/wallet/crypto_amount_format.dart b/lib/src/wallet/crypto_amount_format.dart index d10e321a..de475226 100644 --- a/lib/src/wallet/crypto_amount_format.dart +++ b/lib/src/wallet/crypto_amount_format.dart @@ -1,4 +1,4 @@ -import 'package:oxen_wallet/generated/l10n.dart'; +import 'package:oxen_wallet/l10n.dart'; class AmountDetail { const AmountDetail(this.index, this.fraction); @@ -17,59 +17,26 @@ class AmountDetail { static const AmountDetail normal = AmountDetail(2, 2); static const AmountDetail none = AmountDetail(3, 0); - static AmountDetail deserialize(int index) { - return all.firstWhere((element) => element.index == index, - orElse: () => AmountDetail.ultra); + static AmountDetail deserialize(int? index) { + if (index == null) + return ultra; + for (var i = 0; i < all.length; i++) + if (all[i].index == index) + return all[i]; + return ultra; } - @override - String toString() { + String getTitle(AppLocalizations l10n) { switch (index) { - case (0): - return S.current.amount_detail_ultra; - case (1): - return S.current.amount_detail_detailed; - case (2): - return S.current.amount_detail_normal; - case (3): - return S.current.amount_detail_none; + case 1: + return l10n.amount_detail_detailed; + case 2: + return l10n.amount_detail_normal; + case 3: + return l10n.amount_detail_none; + case 0: default: - return ''; + return l10n.amount_detail_ultra; } } } - -double cryptoAmountToDouble({num amount, num divider}) => amount / divider; - -int doubleToCryptoAmount({double amount, num divider}) => - (amount * divider).toInt(); - -// Litecoin -const litecoinAmountDivider = 100000000; - -double litecoinAmountToDouble({int amount}) => - cryptoAmountToDouble(amount: amount, divider: litecoinAmountDivider); - -// Ethereum -const ethereumAmountDivider = 1000000000000000000; - -double ethereumAmountToDouble({num amount}) => - cryptoAmountToDouble(amount: amount, divider: ethereumAmountDivider); - -// Dash -const dashAmountDivider = 100000000; - -double dashAmountToDouble({int amount}) => - cryptoAmountToDouble(amount: amount, divider: dashAmountDivider); - -// Bitcoin Cash -const bitcoinCashAmountDivider = 100000000; - -double bitcoinCashAmountToDouble({int amount}) => - cryptoAmountToDouble(amount: amount, divider: bitcoinCashAmountDivider); - -// Bitcoin -const bitcoinAmountDivider = 100000000; - -double bitcoinAmountToDouble({int amount}) => - cryptoAmountToDouble(amount: amount, divider: bitcoinAmountDivider); diff --git a/lib/src/wallet/mnemotic_item.dart b/lib/src/wallet/mnemonic_item.dart similarity index 69% rename from lib/src/wallet/mnemotic_item.dart rename to lib/src/wallet/mnemonic_item.dart index 6f7690b4..48bac109 100644 --- a/lib/src/wallet/mnemotic_item.dart +++ b/lib/src/wallet/mnemonic_item.dart @@ -1,5 +1,5 @@ -class MnemoticItem { - MnemoticItem({String text, this.dic}) : _text = text; +class MnemonicItem { + MnemonicItem({required String text, required this.dic}) : _text = text; String get text => _text; final List dic; diff --git a/lib/src/wallet/oxen/account.dart b/lib/src/wallet/oxen/account.dart index a7239aeb..b152bb66 100644 --- a/lib/src/wallet/oxen/account.dart +++ b/lib/src/wallet/oxen/account.dart @@ -1,7 +1,7 @@ import 'package:oxen_coin/oxen_coin_structs.dart'; class Account { - Account({this.id, this.label}); + Account({required this.id, this.label = ''}); Account.fromMap(Map map) : id = map['id'] == null ? 0 : int.parse(map['id'] as String), diff --git a/lib/src/wallet/oxen/account_list.dart b/lib/src/wallet/oxen/account_list.dart index 3c7e8ede..a00269d5 100644 --- a/lib/src/wallet/oxen/account_list.dart +++ b/lib/src/wallet/oxen/account_list.dart @@ -3,15 +3,14 @@ import 'package:oxen_coin/account_list.dart' as account_list; import 'package:oxen_wallet/src/wallet/oxen/account.dart'; class AccountList { - AccountList() { - _isRefreshing = false; - _isUpdating = false; + AccountList() : + _isRefreshing = false, + _isUpdating = false, _accounts = BehaviorSubject>(); - } - Observable> get accounts => _accounts.stream; + Stream> get accounts => _accounts.stream; - BehaviorSubject> _accounts; + final BehaviorSubject> _accounts; bool _isRefreshing; bool _isUpdating; @@ -39,12 +38,12 @@ class AccountList { .toList(); } - Future addAccount({String label}) async { + Future addAccount({required String label}) async { await account_list.addAccount(label: label); await update(); } - Future setLabelSubaddress({int accountIndex, String label}) async { + Future setLabelSubaddress({required int accountIndex, required String label}) async { await account_list.setLabelForAccount( accountIndex: accountIndex, label: label); await update(); diff --git a/lib/src/wallet/oxen/calculate_estimated_fee.dart b/lib/src/wallet/oxen/calculate_estimated_fee.dart index d3532fc3..f4649b12 100644 --- a/lib/src/wallet/oxen/calculate_estimated_fee.dart +++ b/lib/src/wallet/oxen/calculate_estimated_fee.dart @@ -2,6 +2,6 @@ import 'package:oxen_coin/transaction_history.dart'; import 'package:oxen_wallet/src/wallet/oxen/oxen_amount_format.dart'; import 'package:oxen_wallet/src/wallet/oxen/transaction/transaction_priority.dart'; -double calculateEstimatedFee({OxenTransactionPriority priority}) { +double calculateEstimatedFee({required OxenTransactionPriority priority}) { return oxenAmountToDouble(estimateTransactionFee(priority.raw)); } diff --git a/lib/src/wallet/oxen/get_height_by_date.dart b/lib/src/wallet/oxen/get_height_by_date.dart index a94431a8..162efeb9 100644 --- a/lib/src/wallet/oxen/get_height_by_date.dart +++ b/lib/src/wallet/oxen/get_height_by_date.dart @@ -39,7 +39,7 @@ final dates = { '2021-04': 764159 }; -int getHeightByDate({DateTime date}) { +int getHeightByDate({required DateTime date}) { final raw = '${date.year}-${date.month < 10 ? '0${date.month}' : date.month}'; final firstDate = dateFormat.parse(dates.keys.first); var height = dates[raw] ?? 0; diff --git a/lib/src/wallet/oxen/oxen_amount_format.dart b/lib/src/wallet/oxen/oxen_amount_format.dart index 6b36a99b..97c0e119 100644 --- a/lib/src/wallet/oxen/oxen_amount_format.dart +++ b/lib/src/wallet/oxen/oxen_amount_format.dart @@ -1,7 +1,7 @@ import 'package:intl/intl.dart'; import 'package:oxen_wallet/src/wallet/crypto_amount_format.dart'; -const oxenAmountDivider = 1000000000; +const oxenAmountDivisor = 1000000000; String oxenAmountToString(int amount, {AmountDetail detail = AmountDetail.ultra}) { @@ -11,5 +11,4 @@ String oxenAmountToString(int amount, return oxenAmountFormat.format(oxenAmountToDouble(amount)); } -double oxenAmountToDouble(int amount) => - cryptoAmountToDouble(amount: amount, divider: oxenAmountDivider); +double oxenAmountToDouble(int amount) => amount.toDouble() / oxenAmountDivisor; diff --git a/lib/src/wallet/oxen/oxen_balance.dart b/lib/src/wallet/oxen/oxen_balance.dart index 39942d7e..67ef9b90 100644 --- a/lib/src/wallet/oxen/oxen_balance.dart +++ b/lib/src/wallet/oxen/oxen_balance.dart @@ -1,8 +1,7 @@ -import 'package:flutter/foundation.dart'; import 'package:oxen_wallet/src/wallet/balance.dart'; class OxenBalance extends Balance { - OxenBalance({@required this.fullBalance, @required this.unlockedBalance}); + OxenBalance({required this.fullBalance, required this.unlockedBalance}); final int fullBalance; final int unlockedBalance; diff --git a/lib/src/wallet/oxen/oxen_wallet.dart b/lib/src/wallet/oxen/oxen_wallet.dart index b3af722c..76bea31e 100644 --- a/lib/src/wallet/oxen/oxen_wallet.dart +++ b/lib/src/wallet/oxen/oxen_wallet.dart @@ -1,7 +1,5 @@ import 'dart:async'; -import 'dart:developer'; -import 'package:flutter/foundation.dart'; import 'package:hive/hive.dart'; import 'package:oxen_coin/stake.dart' as oxen_stake; import 'package:oxen_coin/transaction_history.dart' as transaction_history; @@ -14,11 +12,8 @@ import 'package:oxen_wallet/src/wallet/oxen/account_list.dart'; import 'package:oxen_wallet/src/wallet/oxen/oxen_balance.dart'; import 'package:oxen_wallet/src/wallet/oxen/subaddress.dart'; import 'package:oxen_wallet/src/wallet/oxen/subaddress_list.dart'; -import 'package:oxen_wallet/src/wallet/oxen/transaction/oxen_stake_transaction_creation_credentials.dart'; -import 'package:oxen_wallet/src/wallet/oxen/transaction/oxen_transaction_creation_credentials.dart'; import 'package:oxen_wallet/src/wallet/oxen/transaction/oxen_transaction_history.dart'; import 'package:oxen_wallet/src/wallet/transaction/pending_transaction.dart'; -import 'package:oxen_wallet/src/wallet/transaction/transaction_creation_credentials.dart'; import 'package:oxen_wallet/src/wallet/transaction/transaction_history.dart'; import 'package:oxen_wallet/src/wallet/wallet.dart'; import 'package:oxen_wallet/src/wallet/wallet_info.dart'; @@ -28,23 +23,22 @@ import 'package:rxdart/rxdart.dart'; const oxenBlockSize = 1000; class OxenWallet extends Wallet { - OxenWallet({this.walletInfoSource, this.walletInfo}) { - _cachedBlockchainHeight = 0; - _name = BehaviorSubject(); - _address = BehaviorSubject(); - _syncStatus = BehaviorSubject(); - _onBalanceChange = BehaviorSubject(); - _account = BehaviorSubject()..add(Account(id: 0)); + OxenWallet({required this.walletInfoSource, required this.walletInfo}) : + _cachedBlockchainHeight = 0, + _name = BehaviorSubject(), + _address = BehaviorSubject(), + _syncStatus = BehaviorSubject(), + _onBalanceChange = BehaviorSubject(), + _account = BehaviorSubject()..add(Account(id: 0)), _subaddress = BehaviorSubject(); - } static Future createdWallet( - {Box walletInfoSource, - String name, + {required Box walletInfoSource, + required String name, bool isRecovery = false, int restoreHeight = 0}) async { const type = WalletType.oxen; - final id = walletTypeToString(type).toLowerCase() + '_' + name; + final id = (walletTypeToString(type)?.toLowerCase() ?? 'unknown') + '_' + name; final walletInfo = WalletInfo( id: id, name: name, @@ -60,25 +54,21 @@ class OxenWallet extends Wallet { static Future load( Box walletInfoSource, String name, WalletType type) async { - final id = walletTypeToString(type).toLowerCase() + '_' + name; - final walletInfo = walletInfoSource.values - .firstWhere((info) => info.id == id, orElse: () => null); + final id = (walletTypeToString(type)?.toLowerCase() ?? 'unknown') + '_' + name; + final walletInfo = walletInfoSource.values.firstWhere((info) => info.id == id); return await configured( walletInfoSource: walletInfoSource, walletInfo: walletInfo); } static Future configured( - {@required Box walletInfoSource, - @required WalletInfo walletInfo}) async { + {required Box walletInfoSource, + required WalletInfo walletInfo}) async { final wallet = OxenWallet(walletInfoSource: walletInfoSource, walletInfo: walletInfo); if (walletInfo.isRecovery) { wallet.setRecoveringFromSeed(); - - if (walletInfo.restoreHeight != null) { - wallet.setRefreshFromBlockHeight(height: walletInfo.restoreHeight); - } + wallet.setRefreshFromBlockHeight(height: walletInfo.restoreHeight); } return wallet; @@ -91,23 +81,23 @@ class OxenWallet extends Wallet { String get name => _name.value; @override - WalletType getType() => WalletType.oxen; + WalletType get walletType => WalletType.oxen; @override - Observable get syncStatus => _syncStatus.stream; + Stream get syncStatus => _syncStatus.stream; @override - Observable get onBalanceChange => _onBalanceChange.stream; + Stream get onBalanceChange => _onBalanceChange.stream; @override - Observable get onNameChange => _name.stream; + Stream get onNameChange => _name.stream; @override - Observable get onAddressChange => _address.stream; + Stream get onAddressChange => _address.stream; - Observable get onAccountChange => _account.stream; + Stream get onAccountChange => _account.stream; - Observable get subaddress => _subaddress.stream; + Stream get subaddress => _subaddress.stream; bool get isRecovery => walletInfo.isRecovery; @@ -116,19 +106,19 @@ class OxenWallet extends Wallet { Box walletInfoSource; WalletInfo walletInfo; - oxen_wallet.SyncListener _listener; - BehaviorSubject _account; - BehaviorSubject _onBalanceChange; - BehaviorSubject _syncStatus; - BehaviorSubject _name; - BehaviorSubject _address; - BehaviorSubject _subaddress; + oxen_wallet.SyncListener? _listener; + final BehaviorSubject _account; + final BehaviorSubject _onBalanceChange; + final BehaviorSubject _syncStatus; + final BehaviorSubject _name; + final BehaviorSubject _address; + final BehaviorSubject _subaddress; int _cachedBlockchainHeight; - TransactionHistory _cachedTransactionHistory; - SubaddressList _cachedSubaddressList; - AccountList _cachedAccountList; - Future _cachedGetNodeHeightOrUpdateRequest; + TransactionHistory? _cachedTransactionHistory; + SubaddressList? _cachedSubaddressList; + AccountList? _cachedAccountList; + Future? _cachedGetNodeHeightOrUpdateRequest; @override Future updateInfo() async { @@ -137,8 +127,7 @@ class OxenWallet extends Wallet { acccountList.refresh(); _account.value = acccountList.getAll().first; final subaddressList = getSubaddress(); - await subaddressList.refresh( - accountIndex: _account.value != null ? _account.value.id : 0); + await subaddressList.refresh(accountIndex: _account.value.id); final subaddresses = subaddressList.getAll(); _subaddress.value = subaddresses.first; _address.value = await getAddress(); @@ -186,7 +175,7 @@ class OxenWallet extends Wallet { return value; }); - return _cachedGetNodeHeightOrUpdateRequest; + return _cachedGetNodeHeightOrUpdateRequest!; } @override @@ -204,19 +193,19 @@ class OxenWallet extends Wallet { TransactionHistory getHistory() { _cachedTransactionHistory ??= OxenTransactionHistory(); - return _cachedTransactionHistory; + return _cachedTransactionHistory!; } SubaddressList getSubaddress() { _cachedSubaddressList ??= SubaddressList(); - return _cachedSubaddressList; + return _cachedSubaddressList!; } AccountList getAccountList() { _cachedAccountList ??= AccountList(); - return _cachedAccountList; + return _cachedAccountList!; } @override @@ -229,8 +218,8 @@ class OxenWallet extends Wallet { } @override - Future connectToNode( - {Node node, bool useSSL = false, bool isLightWallet = false}) async { + Future connectToNode( + {required Node node, bool useSSL = false, bool isLightWallet = false}) async { try { _syncStatus.value = ConnectingSyncStatus(); @@ -243,8 +232,10 @@ class OxenWallet extends Wallet { await oxen_wallet.setupNode( address: node.uri, + /* login: node.login, password: node.password, + */ useSSL: useSSL, isLightWallet: isLightWallet); _syncStatus.value = ConnectedSyncStatus(); @@ -283,31 +274,28 @@ class OxenWallet extends Wallet { } @override - Future createStake( - TransactionCreationCredentials credentials) async { - final _credentials = credentials as OxenStakeTransactionCreationCredentials; - if (_credentials.amount == null || _credentials.address == null) { - return Future.error('Amount and address cannot be null.'); - } + Future createStake({ + required String snPubkey, + required String? amount}) async { final transactionDescription = - await oxen_stake.createStake(_credentials.address, _credentials.amount); + await oxen_stake.createStake(snPubkey, amount); return PendingTransaction.fromTransactionDescription( transactionDescription); } @override - Future createTransaction( - TransactionCreationCredentials credentials) async { - final _credentials = credentials as OxenTransactionCreationCredentials; + Future createTransaction({ + required String recipient, + required String? amount, + OxenTransactionPriority priority = OxenTransactionPriority.blink}) async { final transactionDescription = await transaction_history.createTransaction( - address: _credentials.address, - amount: _credentials.amount, - priorityRaw: _credentials.priority.serialize(), + recipient: recipient, + amount: amount, + priorityRaw: priority.raw, accountIndex: _account.value.id); - return PendingTransaction.fromTransactionDescription( - transactionDescription); + return PendingTransaction.fromTransactionDescription(transactionDescription); } @override @@ -321,7 +309,7 @@ class OxenWallet extends Wallet { void setRecoveringFromSeed() => oxen_wallet.setRecoveringFromSeed(isRecovery: true); - void setRefreshFromBlockHeight({int height}) => + void setRefreshFromBlockHeight({required int height}) => oxen_wallet.setRefreshFromBlockHeight(height: height); Future setAsRecovered() async { @@ -332,10 +320,9 @@ class OxenWallet extends Wallet { Future askForUpdateBalance() async { final fullBalance = await getFullBalance(); final unlockedBalance = await getUnlockedBalance(); - final needToChange = _onBalanceChange.value != null - ? _onBalanceChange.value.fullBalance != fullBalance || - _onBalanceChange.value.unlockedBalance != unlockedBalance - : true; + final needToChange = !_onBalanceChange.hasValue ? true : + _onBalanceChange.value.fullBalance != fullBalance || + _onBalanceChange.value.unlockedBalance != unlockedBalance; if (!needToChange) { return; @@ -386,7 +373,7 @@ class OxenWallet extends Wallet { } } } catch (e) { - print(e.toString()); + print('new block error: $e'); } } diff --git a/lib/src/wallet/oxen/oxen_wallets_manager.dart b/lib/src/wallet/oxen/oxen_wallets_manager.dart index e14abbba..989afca8 100644 --- a/lib/src/wallet/oxen/oxen_wallets_manager.dart +++ b/lib/src/wallet/oxen/oxen_wallets_manager.dart @@ -1,6 +1,5 @@ import 'dart:async'; import 'dart:io'; -import 'package:flutter/foundation.dart'; import 'package:hive/hive.dart'; import 'package:path_provider/path_provider.dart'; import 'package:oxen_coin/wallet_manager.dart' as oxen_wallet_manager; @@ -13,7 +12,7 @@ import 'package:oxen_wallet/src/wallet/wallet_description.dart'; import 'package:oxen_wallet/src/wallet/oxen/oxen_wallet.dart'; import 'package:oxen_wallet/devtools.dart'; -Future pathForWallet({String name}) async { +Future pathForWallet({required String name}) async { final directory = await getApplicationDocumentsDirectory(); final pathDir = directory.path + '/$name'; final dir = Directory(pathDir); @@ -26,7 +25,7 @@ Future pathForWallet({String name}) async { } class OxenWalletsManager extends WalletsManager { - OxenWalletsManager({@required this.walletInfoSource}); + OxenWalletsManager({required this.walletInfoSource}); static const type = WalletType.oxen; static const nettype = isTestnet ? 1 : 0; // Mainnet: 0 Testnet: 1 @@ -170,10 +169,11 @@ class OxenWalletsManager extends WalletsManager { } final id = - walletTypeToString(wallet.type).toLowerCase() + '_' + wallet.name; - final info = walletInfoSource.values - .firstWhere((info) => info.id == id, orElse: () => null); - - await info?.delete(); + (walletTypeToString(wallet.type)?.toLowerCase() ?? 'unknown') + '_' + wallet.name; + try { + await walletInfoSource.values.firstWhere((info) => info.id == id).delete(); + } on StateError catch (_) { + // id not found; ignore + } } } diff --git a/lib/src/wallet/oxen/subaddress.dart b/lib/src/wallet/oxen/subaddress.dart index b9e6581d..9288cfa0 100644 --- a/lib/src/wallet/oxen/subaddress.dart +++ b/lib/src/wallet/oxen/subaddress.dart @@ -1,7 +1,7 @@ import 'package:oxen_coin/oxen_coin_structs.dart'; class Subaddress { - Subaddress({this.id, this.address, this.label}); + Subaddress({required this.id, required this.address, required this.label}); Subaddress.fromMap(Map map) : id = map['id'] == null ? 0 : int.parse(map['id'] as String), diff --git a/lib/src/wallet/oxen/subaddress_list.dart b/lib/src/wallet/oxen/subaddress_list.dart index e7504b42..d5214a8b 100644 --- a/lib/src/wallet/oxen/subaddress_list.dart +++ b/lib/src/wallet/oxen/subaddress_list.dart @@ -4,19 +4,18 @@ import 'package:oxen_coin/subaddress_list.dart' as subaddress_list; import 'package:oxen_wallet/src/wallet/oxen/subaddress.dart'; class SubaddressList { - SubaddressList() { - _isRefreshing = false; - _isUpdating = false; + SubaddressList() : + _isRefreshing = false, + _isUpdating = false, _subaddress = BehaviorSubject>(); - } - Observable> get subaddresses => _subaddress.stream; + Stream> get subaddresses => _subaddress.stream; - BehaviorSubject> _subaddress; + final BehaviorSubject> _subaddress; bool _isRefreshing; bool _isUpdating; - Future update({int accountIndex}) async { + Future update({required int accountIndex}) async { if (_isUpdating) { return; } @@ -40,20 +39,20 @@ class SubaddressList { .toList(); } - Future addSubaddress({int accountIndex, String label}) async { + Future addSubaddress({required int accountIndex, required String label}) async { await subaddress_list.addSubaddress( accountIndex: accountIndex, label: label); await update(accountIndex: accountIndex); } Future setLabelSubaddress( - {int accountIndex, int addressIndex, String label}) async { + {required int accountIndex, required int addressIndex, required String label}) async { await subaddress_list.setLabelForSubaddress( accountIndex: accountIndex, addressIndex: addressIndex, label: label); - await update(); + await update(accountIndex: accountIndex); } - Future refresh({int accountIndex}) async { + Future refresh({required int accountIndex}) async { if (_isRefreshing) { return; } diff --git a/lib/src/wallet/oxen/transaction/oxen_stake_transaction_creation_credentials.dart b/lib/src/wallet/oxen/transaction/oxen_stake_transaction_creation_credentials.dart deleted file mode 100644 index d1f34c97..00000000 --- a/lib/src/wallet/oxen/transaction/oxen_stake_transaction_creation_credentials.dart +++ /dev/null @@ -1,9 +0,0 @@ -import 'package:oxen_wallet/src/wallet/transaction/transaction_creation_credentials.dart'; - -class OxenStakeTransactionCreationCredentials - extends TransactionCreationCredentials { - OxenStakeTransactionCreationCredentials({this.address, this.amount}); - - final String address; - final String amount; -} diff --git a/lib/src/wallet/oxen/transaction/oxen_transaction_creation_credentials.dart b/lib/src/wallet/oxen/transaction/oxen_transaction_creation_credentials.dart deleted file mode 100644 index b5815bfb..00000000 --- a/lib/src/wallet/oxen/transaction/oxen_transaction_creation_credentials.dart +++ /dev/null @@ -1,12 +0,0 @@ -import 'package:oxen_wallet/src/wallet/oxen/transaction/transaction_priority.dart'; -import 'package:oxen_wallet/src/wallet/transaction/transaction_creation_credentials.dart'; - -class OxenTransactionCreationCredentials - extends TransactionCreationCredentials { - OxenTransactionCreationCredentials( - {this.address, this.priority, this.amount}); - - final String address; - final String amount; - final OxenTransactionPriority priority; -} diff --git a/lib/src/wallet/oxen/transaction/oxen_transaction_history.dart b/lib/src/wallet/oxen/transaction/oxen_transaction_history.dart index 530d85d4..2991679c 100644 --- a/lib/src/wallet/oxen/transaction/oxen_transaction_history.dart +++ b/lib/src/wallet/oxen/transaction/oxen_transaction_history.dart @@ -16,7 +16,7 @@ class OxenTransactionHistory extends TransactionHistory { : _transactions = BehaviorSubject>.seeded([]); @override - Observable> get transactions => _transactions.stream; + Stream> get transactions => _transactions.stream; final BehaviorSubject> _transactions; bool _isUpdating = false; diff --git a/lib/src/wallet/oxen/transaction/transaction_description.dart b/lib/src/wallet/oxen/transaction/transaction_description.dart index 51f01e21..3135dfc5 100644 --- a/lib/src/wallet/oxen/transaction/transaction_description.dart +++ b/lib/src/wallet/oxen/transaction/transaction_description.dart @@ -4,7 +4,7 @@ part 'transaction_description.g.dart'; @HiveType(typeId: 2) class TransactionDescription extends HiveObject { - TransactionDescription({this.id, this.recipientAddress}); + TransactionDescription({required this.id, required this.recipientAddress}); static const boxName = 'TransactionDescriptions'; diff --git a/lib/src/wallet/oxen/transaction/transaction_priority.dart b/lib/src/wallet/oxen/transaction/transaction_priority.dart index c30feaad..4bdfe51a 100644 --- a/lib/src/wallet/oxen/transaction/transaction_priority.dart +++ b/lib/src/wallet/oxen/transaction/transaction_priority.dart @@ -1,39 +1,37 @@ -import 'package:oxen_wallet/generated/l10n.dart'; +import 'package:oxen_wallet/l10n.dart'; import 'package:oxen_wallet/src/domain/common/enumerable_item.dart'; class OxenTransactionPriority extends EnumerableItem with Serializable { - const OxenTransactionPriority({String title, int raw}) - : super(title: title, raw: raw); + const OxenTransactionPriority({required int raw}) + : super(raw: raw); static const all = [ OxenTransactionPriority.slow, OxenTransactionPriority.blink ]; - static const slow = OxenTransactionPriority(title: 'Slow', raw: 1); - static const blink = OxenTransactionPriority(title: 'Blink', raw: 5); + static const slow = OxenTransactionPriority(raw: 1); + static const blink = OxenTransactionPriority(raw: 5); static const standard = blink; - static OxenTransactionPriority deserialize({int raw}) { + static OxenTransactionPriority deserialize({required int? raw}) { switch (raw) { case 1: return slow; case 5: - return blink; default: - return null; + return blink; } } @override - String toString() { + String getTitle(AppLocalizations l10n) { switch (this) { case OxenTransactionPriority.slow: - return S.current.transaction_priority_slow; + return l10n.transaction_priority_slow; case OxenTransactionPriority.blink: - return S.current.transaction_priority_blink; default: - return ''; + return l10n.transaction_priority_blink; } } } diff --git a/lib/src/wallet/transaction/pending_transaction.dart b/lib/src/wallet/transaction/pending_transaction.dart index 0901a65b..1f3779b5 100644 --- a/lib/src/wallet/transaction/pending_transaction.dart +++ b/lib/src/wallet/transaction/pending_transaction.dart @@ -1,12 +1,8 @@ -import 'package:flutter/foundation.dart'; import 'package:oxen_coin/transaction_history.dart' as transaction_history; import 'package:oxen_coin/oxen_coin_structs.dart'; import 'package:oxen_wallet/src/wallet/oxen/oxen_amount_format.dart'; class PendingTransaction { - PendingTransaction( - {@required this.amount, @required this.fee, @required this.hash}); - PendingTransaction.fromTransactionDescription( PendingTransactionDescription transactionDescription) : amount = oxenAmountToString(transactionDescription.amount), @@ -18,7 +14,7 @@ class PendingTransaction { final String fee; final String hash; - int _pointerAddress; + final int _pointerAddress; Future commit() async => transaction_history .commitTransactionFromPointerAddress(address: _pointerAddress); diff --git a/lib/src/wallet/transaction/transaction_creation_credentials.dart b/lib/src/wallet/transaction/transaction_creation_credentials.dart deleted file mode 100644 index 6437cc81..00000000 --- a/lib/src/wallet/transaction/transaction_creation_credentials.dart +++ /dev/null @@ -1 +0,0 @@ -abstract class TransactionCreationCredentials {} \ No newline at end of file diff --git a/lib/src/wallet/transaction/transaction_direction.dart b/lib/src/wallet/transaction/transaction_direction.dart index 50ca4df6..7220d955 100644 --- a/lib/src/wallet/transaction/transaction_direction.dart +++ b/lib/src/wallet/transaction/transaction_direction.dart @@ -1,6 +1,6 @@ enum TransactionDirection { incoming, outgoing } -TransactionDirection parseTransactionDirectionFromInt(int raw) { +TransactionDirection? parseTransactionDirectionFromInt(int? raw) { switch (raw) { case 0: return TransactionDirection.incoming; case 1: return TransactionDirection.outgoing; @@ -8,10 +8,10 @@ TransactionDirection parseTransactionDirectionFromInt(int raw) { } } -TransactionDirection parseTransactionDirectionFromNumber(String raw) { +TransactionDirection? parseTransactionDirectionFromNumber(String? raw) { switch (raw) { case '0': return TransactionDirection.incoming; case '1': return TransactionDirection.outgoing; default: return null; } -} \ No newline at end of file +} diff --git a/lib/src/wallet/transaction/transaction_history.dart b/lib/src/wallet/transaction/transaction_history.dart index 6529df73..e5876fa8 100644 --- a/lib/src/wallet/transaction/transaction_history.dart +++ b/lib/src/wallet/transaction/transaction_history.dart @@ -1,8 +1,7 @@ -import 'package:rxdart/rxdart.dart'; import 'package:oxen_wallet/src/wallet/transaction/transaction_info.dart'; abstract class TransactionHistory { - Observable> transactions; + Stream> get transactions; Future> getAll(); Future count(); Future refresh(); diff --git a/lib/src/wallet/transaction/transaction_info.dart b/lib/src/wallet/transaction/transaction_info.dart index 12045a5c..7a02cbb9 100644 --- a/lib/src/wallet/transaction/transaction_info.dart +++ b/lib/src/wallet/transaction/transaction_info.dart @@ -5,20 +5,21 @@ import 'package:oxen_wallet/src/wallet/transaction/transaction_direction.dart'; import 'package:oxen_wallet/src/domain/common/format_amount.dart'; class TransactionInfo { - TransactionInfo(this.id, this.height, this.direction, this.date, - this.isPending, this.amount, this.accountIndex); +// TransactionInfo(this.id, this.height, this.direction, this.date, +// this.isPending, this.amount, this.accountIndex); TransactionInfo.fromMap(Map map) : id = (map['hash'] ?? '') as String, height = (map['height'] ?? 0) as int, direction = - parseTransactionDirectionFromNumber(map['direction'] as String) ?? + parseTransactionDirectionFromNumber(map['direction'] as String?) ?? TransactionDirection.incoming, date = DateTime.fromMillisecondsSinceEpoch( - (int.parse(map['timestamp'] as String) ?? 0) * 1000), - isPending = parseBoolFromString(map['isPending'] as String), - amount = map['amount'] as int, - accountIndex = int.parse(map['accountIndex'] as String); + (int.tryParse(map['timestamp'] as String? ?? '0') ?? 0) * 1000), + isPending = parseBoolFromString(map['isPending'] as String?), + isStake = parseBoolFromString(map['isStake'] as String?), + amount = (map['amount'] ?? 0) as int, + accountIndex = int.tryParse(map['accountIndex'] as String? ?? '0') ?? 0; TransactionInfo.fromRow(TransactionInfoRow row) : id = row.getHash(), @@ -27,6 +28,7 @@ class TransactionInfo { TransactionDirection.incoming, date = DateTime.fromMillisecondsSinceEpoch(row.getDatetime() * 1000), isPending = row.isPending != 0, + isStake = row.isStake != 0, amount = row.getAmount(), accountIndex = row.subaddrAccount; @@ -36,10 +38,11 @@ class TransactionInfo { final DateTime date; final int accountIndex; final bool isPending; + final bool isStake; final int amount; - String recipientAddress; + String? recipientAddress; - String _fiatAmount; + String? _fiatAmount; String amountFormatted() => '${oxenAmountToString(amount)} OXEN'; diff --git a/lib/src/wallet/wallet.dart b/lib/src/wallet/wallet.dart index 029c0bb2..a415e357 100644 --- a/lib/src/wallet/wallet.dart +++ b/lib/src/wallet/wallet.dart @@ -1,24 +1,23 @@ -import 'package:rxdart/rxdart.dart'; import 'package:oxen_wallet/src/node/sync_status.dart'; import 'package:oxen_wallet/src/wallet/transaction/transaction_history.dart'; import 'package:oxen_wallet/src/wallet/wallet_type.dart'; -import 'package:oxen_wallet/src/wallet/transaction/transaction_creation_credentials.dart'; import 'package:oxen_wallet/src/wallet/transaction/pending_transaction.dart'; import 'package:oxen_wallet/src/wallet/balance.dart'; +import 'package:oxen_wallet/src/wallet/oxen/transaction/transaction_priority.dart'; import 'package:oxen_wallet/src/node/node.dart'; -abstract class Wallet { - WalletType getType(); +export 'package:oxen_wallet/src/wallet/oxen/transaction/transaction_priority.dart' show OxenTransactionPriority; - WalletType walletType; +abstract class Wallet { + WalletType get walletType; - Observable onBalanceChange; + Stream get onBalanceChange; - Observable syncStatus; + Stream get syncStatus; - Observable get onNameChange; + Stream get onNameChange; - Observable get onAddressChange; + Stream get onAddressChange; String get name; @@ -52,16 +51,19 @@ abstract class Wallet { TransactionHistory getHistory(); - Future connectToNode( - {Node node, bool useSSL = false, bool isLightWallet = false}); + Future connectToNode( + {required Node node, bool useSSL = false, bool isLightWallet = false}); Future startSync(); - Future createStake( - TransactionCreationCredentials credentials); + Future createStake({ + required String snPubkey, + required String? amount}); - Future createTransaction( - TransactionCreationCredentials credentials); + Future createTransaction({ + required String recipient, + required String? amount, + OxenTransactionPriority priority = OxenTransactionPriority.blink}); Future rescan({int restoreHeight = 0}); } diff --git a/lib/src/wallet/wallet_description.dart b/lib/src/wallet/wallet_description.dart index e72d2a7f..d480763a 100644 --- a/lib/src/wallet/wallet_description.dart +++ b/lib/src/wallet/wallet_description.dart @@ -1,8 +1,8 @@ import 'package:oxen_wallet/src/wallet/wallet_type.dart'; class WalletDescription { - WalletDescription({this.name, this.type}); + WalletDescription({required this.name, required this.type}); final String name; final WalletType type; -} \ No newline at end of file +} diff --git a/lib/src/wallet/wallet_info.dart b/lib/src/wallet/wallet_info.dart index 5f2adad5..8a8f9773 100644 --- a/lib/src/wallet/wallet_info.dart +++ b/lib/src/wallet/wallet_info.dart @@ -6,12 +6,12 @@ part 'wallet_info.g.dart'; @HiveType(typeId: 4) class WalletInfo extends HiveObject { WalletInfo( - {this.id, - this.name, - this.type, - this.isRecovery, - this.restoreHeight, - this.timestamp, + {required this.id, + required this.name, + required this.type, + required this.isRecovery, + required this.restoreHeight, + required this.timestamp, this.hasTestnet = false}); static const boxName = 'WalletInfo'; diff --git a/lib/src/wallet/wallet_type.dart b/lib/src/wallet/wallet_type.dart index c33a0bc3..3cc1494e 100644 --- a/lib/src/wallet/wallet_type.dart +++ b/lib/src/wallet/wallet_type.dart @@ -25,7 +25,7 @@ int serializeToInt(WalletType type) { } } -WalletType deserializeToInt(int raw) { +WalletType? deserializeToInt(int raw) { switch (raw) { case 0: return WalletType.monero; @@ -36,7 +36,7 @@ WalletType deserializeToInt(int raw) { } } -String walletTypeToString(WalletType type) { +String? walletTypeToString(WalletType type) { switch (type) { case WalletType.monero: return 'Monero'; @@ -45,4 +45,4 @@ String walletTypeToString(WalletType type) { default: return ''; } -} \ No newline at end of file +} diff --git a/lib/src/widgets/address_text_field.dart b/lib/src/widgets/address_text_field.dart index 2c91f04a..9d0ae78e 100644 --- a/lib/src/widgets/address_text_field.dart +++ b/lib/src/widgets/address_text_field.dart @@ -1,6 +1,5 @@ -import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; -import 'package:oxen_wallet/generated/l10n.dart'; +import 'package:oxen_wallet/l10n.dart'; import 'package:oxen_wallet/palette.dart'; import 'package:oxen_wallet/routes.dart'; import 'package:oxen_wallet/src/domain/common/contact.dart'; @@ -12,7 +11,7 @@ enum AddressTextFieldOption { qrCode, addressBook, subaddressList } class AddressTextField extends StatelessWidget { AddressTextField( - {@required this.controller, + {required this.controller, this.isActive = true, this.placeholder, this.options = const [ @@ -21,7 +20,7 @@ class AddressTextField extends StatelessWidget { ], this.onURIScanned, this.focusNode, - this.validator}); + required this.validator}); static const prefixIconWidth = 34.0; static const prefixIconHeight = 34.0; @@ -29,11 +28,11 @@ class AddressTextField extends StatelessWidget { final TextEditingController controller; final bool isActive; - final String placeholder; - final Function(Uri) onURIScanned; + final String? placeholder; + final Function(Uri)? onURIScanned; final List options; final FormFieldValidator validator; - final FocusNode focusNode; + final FocusNode? focusNode; @override Widget build(BuildContext context) { @@ -42,61 +41,65 @@ class AddressTextField extends StatelessWidget { controller: controller, focusNode: focusNode, suffixIcon: Padding( - padding: EdgeInsets.only(right: 10), - child: SizedBox( - width: prefixIconWidth * options.length + - (spaceBetweenPrefixIcons * options.length), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - SizedBox(width: 5), - if (options.contains(AddressTextFieldOption.qrCode)) ...[ - Container( - width: prefixIconWidth, - height: prefixIconHeight, - child: InkWell( - onTap: () async => _presentQRScanner(context), - child: Container( - decoration: BoxDecoration( - color: Palette.wildDarkBlueWithOpacity, - borderRadius: - BorderRadius.all(Radius.circular(8))), - child: Icon(Icons.qr_code_outlined)), - )) - ], - if (options.contains(AddressTextFieldOption.addressBook)) ...[ - Container( - width: prefixIconWidth, - height: prefixIconHeight, - child: InkWell( - onTap: () async => _presetAddressBookPicker(context), - child: Container( - decoration: BoxDecoration( - color: Palette.wildDarkBlueWithOpacity, - borderRadius: - BorderRadius.all(Radius.circular(8))), - child: Icon(Icons.contacts_rounded)), - )) - ], - if (options - .contains(AddressTextFieldOption.subaddressList)) ...[ - Container( - width: prefixIconWidth, - height: prefixIconHeight, - child: InkWell( - onTap: () async => _presetSubaddressListPicker(context), - child: Container( - decoration: BoxDecoration( - color: Palette.wildDarkBlueWithOpacity, - borderRadius: - BorderRadius.all(Radius.circular(8))), - child: Icon(Icons.arrow_downward_rounded)), - )) - ], + padding: EdgeInsets.only(right: 10), + child: SizedBox( + width: prefixIconWidth * options.length + spaceBetweenPrefixIcons * options.length, + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + SizedBox(width: 5), + if (options.contains(AddressTextFieldOption.qrCode)) ...[ + Container( + width: prefixIconWidth, + height: prefixIconHeight, + child: InkWell( + onTap: () async => _presentQRScanner(context), + child: Container( + decoration: BoxDecoration( + color: Palette.wildDarkBlueWithOpacity, + borderRadius: BorderRadius.all(Radius.circular(8))), + child: Icon(Icons.qr_code_outlined) + ), + ), + ), ], - ), - )), - hintText: placeholder ?? S.current.widgets_address, + if (options.contains(AddressTextFieldOption.addressBook)) ...[ + Container( + width: prefixIconWidth, + height: prefixIconHeight, + child: InkWell( + onTap: () async => _presetAddressBookPicker(context), + child: Container( + decoration: BoxDecoration( + color: Palette.wildDarkBlueWithOpacity, + borderRadius: BorderRadius.all(Radius.circular(8)) + ), + child: Icon(Icons.contacts_rounded), + ), + ), + ), + ], + if (options.contains(AddressTextFieldOption.subaddressList)) ...[ + Container( + width: prefixIconWidth, + height: prefixIconHeight, + child: InkWell( + onTap: () async => _presetSubaddressListPicker(context), + child: Container( + decoration: BoxDecoration( + color: Palette.wildDarkBlueWithOpacity, + borderRadius: BorderRadius.all(Radius.circular(8)) + ), + child: Icon(Icons.arrow_downward_rounded) + ), + ), + ), + ], + ], + ), + ), + ), + hintText: placeholder ?? tr(context).widgets_address, validator: validator, ); } @@ -104,19 +107,20 @@ class AddressTextField extends StatelessWidget { Future _presentQRScanner(BuildContext context) async { try { final code = await presentQRScanner(); - final uri = Uri.parse(code); - var address = ''; + if (code == null) // Cancelled, do nothing. + return; - if (uri == null) { + final Uri uri; + try { + uri = Uri.parse(code); + } catch (e) { controller.text = code; return; } - - address = uri.path; - controller.text = address; + controller.text = uri.path; if (onURIScanned != null) { - onURIScanned(uri); + onURIScanned!(uri); } } catch (e) { print('Error $e'); @@ -127,17 +131,15 @@ class AddressTextField extends StatelessWidget { final contact = await Navigator.of(context, rootNavigator: true) .pushNamed(Routes.pickerAddressBook); - if (contact is Contact && contact.address != null) { + if (contact is Contact) controller.text = contact.address; - } } Future _presetSubaddressListPicker(BuildContext context) async { final subaddress = await Navigator.of(context, rootNavigator: true) .pushNamed(Routes.subaddressList); - if (subaddress is Subaddress && subaddress.address != null) { + if (subaddress is Subaddress) controller.text = subaddress.address; - } } } diff --git a/lib/src/widgets/blockchain_height_widget.dart b/lib/src/widgets/blockchain_height_widget.dart index 9cb34786..c9b9bf18 100644 --- a/lib/src/widgets/blockchain_height_widget.dart +++ b/lib/src/widgets/blockchain_height_widget.dart @@ -1,11 +1,11 @@ import 'package:flutter/material.dart'; import 'package:intl/intl.dart'; -import 'package:oxen_wallet/generated/l10n.dart'; +import 'package:oxen_wallet/l10n.dart'; import 'package:oxen_wallet/src/wallet/oxen/get_height_by_date.dart'; import 'package:oxen_wallet/palette.dart'; class BlockchainHeightWidget extends StatefulWidget { - BlockchainHeightWidget({GlobalKey key}) : super(key: key); + BlockchainHeightWidget({required GlobalKey key}) : super(key: key); @override State createState() => BlockchainHeightState(); @@ -19,10 +19,8 @@ class BlockchainHeightState extends State { @override void initState() { - restoreHeightController.addListener(() => _height = - restoreHeightController.text != null - ? int.parse(restoreHeightController.text) - : 0); + restoreHeightController.addListener( + () => _height = int.parse(restoreHeightController.text)); super.initState(); } @@ -43,7 +41,7 @@ class BlockchainHeightState extends State { signed: false, decimal: false), decoration: InputDecoration( hintStyle: TextStyle(color: Theme.of(context).hintColor), - hintText: S.of(context).widgets_restore_from_blockheight, + hintText: tr(context).widgets_restore_from_blockheight, focusedBorder: UnderlineInputBorder( borderSide: BorderSide( color: OxenPalette.teal, width: 2.0)), @@ -57,11 +55,11 @@ class BlockchainHeightState extends State { Padding( padding: EdgeInsets.only(top: 15, bottom: 15), child: Text( - S.of(context).widgets_or, + tr(context).widgets_or, style: TextStyle( fontSize: 16.0, fontWeight: FontWeight.bold, - color: Theme.of(context).primaryTextTheme.headline6.color), + color: Theme.of(context).primaryTextTheme.headline6?.color), ), ), Row( @@ -76,7 +74,7 @@ class BlockchainHeightState extends State { decoration: InputDecoration( hintStyle: TextStyle(color: Theme.of(context).hintColor), - hintText: S.of(context).widgets_restore_from_date, + hintText: tr(context).widgets_restore_from_date, focusedBorder: UnderlineInputBorder( borderSide: BorderSide( color: OxenPalette.teal, diff --git a/lib/src/widgets/nav/nav_list_arrow.dart b/lib/src/widgets/nav/nav_list_arrow.dart index 904d2535..79fb7821 100644 --- a/lib/src/widgets/nav/nav_list_arrow.dart +++ b/lib/src/widgets/nav/nav_list_arrow.dart @@ -2,11 +2,11 @@ import 'package:flutter/material.dart'; import 'package:oxen_wallet/src/widgets/nav/nav_list_trailing.dart'; class NavListArrow extends StatelessWidget { - NavListArrow({this.text, this.leading, this.onTap}); + NavListArrow({required this.text, this.leading, this.onTap}); final String text; - final Widget leading; - final GestureTapCallback onTap; + final Widget? leading; + final GestureTapCallback? onTap; @override Widget build(BuildContext context) { @@ -14,7 +14,7 @@ class NavListArrow extends StatelessWidget { leading: leading, text: text, trailing: Icon(Icons.arrow_forward_ios_rounded, - color: Theme.of(context).primaryTextTheme.headline6.color, + color: Theme.of(context).primaryTextTheme.headline6?.color, size: 20), onTap: onTap); } diff --git a/lib/src/widgets/nav/nav_list_header.dart b/lib/src/widgets/nav/nav_list_header.dart index e6bf09a4..dcd5176b 100644 --- a/lib/src/widgets/nav/nav_list_header.dart +++ b/lib/src/widgets/nav/nav_list_header.dart @@ -2,7 +2,7 @@ import 'package:flutter/material.dart'; import 'package:oxen_wallet/palette.dart'; class NavListHeader extends StatelessWidget { - NavListHeader({this.title}); + NavListHeader({required this.title}); final String title; diff --git a/lib/src/widgets/nav/nav_list_trailing.dart b/lib/src/widgets/nav/nav_list_trailing.dart index 013dc9b0..14d3a515 100644 --- a/lib/src/widgets/nav/nav_list_trailing.dart +++ b/lib/src/widgets/nav/nav_list_trailing.dart @@ -1,24 +1,24 @@ import 'package:flutter/material.dart'; class NavListTrailing extends StatelessWidget { - NavListTrailing({this.text, this.leading, this.onTap, this.trailing}); + NavListTrailing({required this.text, required this.leading, this.onTap, this.trailing}); final String text; - final Widget leading; - final Widget trailing; - final GestureTapCallback onTap; + final Widget? leading; + final Widget? trailing; + final GestureTapCallback? onTap; @override Widget build(BuildContext context) { return Container( - color: Theme.of(context).accentTextTheme.headline5.backgroundColor, + color: Theme.of(context).accentTextTheme.headline5?.backgroundColor, child: ListTile( contentPadding: EdgeInsets.only(left: 20.0, right: 20.0), leading: leading, title: Text(text, style: TextStyle( fontSize: 16.0, - color: Theme.of(context).primaryTextTheme.headline6.color)), + color: Theme.of(context).primaryTextTheme.headline6?.color)), trailing: trailing, onTap: onTap, ), diff --git a/lib/src/widgets/nav_bar.dart b/lib/src/widgets/nav_bar.dart index 00514546..6e1984f1 100644 --- a/lib/src/widgets/nav_bar.dart +++ b/lib/src/widgets/nav_bar.dart @@ -6,11 +6,11 @@ import 'package:provider/provider.dart'; class NavBar extends StatelessWidget implements ObstructingPreferredSizeWidget { factory NavBar( - {BuildContext context, - Widget leading, - Widget middle, - Widget trailing, - Color backgroundColor}) { + {required BuildContext context, + Widget? leading, + Widget? middle, + Widget? trailing, + required Color backgroundColor}) { final _themeChanger = Provider.of(context); final _isDarkTheme = _themeChanger.getTheme() == Themes.darkTheme; @@ -24,11 +24,11 @@ class NavBar extends StatelessWidget implements ObstructingPreferredSizeWidget { } factory NavBar.withShadow( - {BuildContext context, - Widget leading, - Widget middle, - Widget trailing, - Color backgroundColor}) { + {required BuildContext context, + Widget? leading, + Widget? middle, + Widget? trailing, + required Color backgroundColor}) { final _themeChanger = Provider.of(context); final _isDarkTheme = _themeChanger.getTheme() == Themes.darkTheme; @@ -56,18 +56,18 @@ class NavBar extends StatelessWidget implements ObstructingPreferredSizeWidget { {this.leading, this.middle, this.trailing, - this.backgroundColor, + required this.backgroundColor, this.decoration, this.height = _height}); static const _originalHeight = 44.0; // iOS nav bar height static const _height = 60.0; - final Widget leading; - final Widget middle; - final Widget trailing; + final Widget? leading; + final Widget? middle; + final Widget? trailing; final Color backgroundColor; - final BoxDecoration decoration; + final BoxDecoration? decoration; final double height; @override diff --git a/lib/src/widgets/oxen_dialog.dart b/lib/src/widgets/oxen_dialog.dart index 87300f65..76457551 100644 --- a/lib/src/widgets/oxen_dialog.dart +++ b/lib/src/widgets/oxen_dialog.dart @@ -1,22 +1,22 @@ import 'dart:ui'; import 'package:flutter/material.dart'; -import 'package:oxen_wallet/generated/l10n.dart'; +import 'package:oxen_wallet/l10n.dart'; import 'package:oxen_wallet/palette.dart'; import 'package:oxen_wallet/src/widgets/primary_button.dart'; import 'package:oxen_wallet/src/widgets/slide_to_act.dart'; Future showOxenDialog(BuildContext context, Widget child, - {void Function(BuildContext context) onDismiss}) { + {required void Function(BuildContext context) onDismiss}) { return showDialog( builder: (_) => OxenDialog(body: child, onDismiss: onDismiss), context: context); } Future showSimpleOxenDialog(BuildContext context, String title, String body, - {String buttonText, - void Function(BuildContext context) onPressed, - void Function(BuildContext context) onDismiss}) { + {String? buttonText, + required void Function(BuildContext context) onPressed, + void Function(BuildContext context)? onDismiss}) { return showDialog( builder: (_) => SimpleOxenDialog(title, body, buttonText: buttonText, onDismiss: onDismiss, onPressed: onPressed), @@ -24,9 +24,9 @@ Future showSimpleOxenDialog(BuildContext context, String title, String body, } Future showConfirmOxenDialog(BuildContext context, String title, String body, - {void Function(BuildContext context) onConfirm, - Future Function(BuildContext context) onFutureConfirm, - void Function(BuildContext context) onDismiss}) { + {void Function(BuildContext context)? onConfirm, + Future Function(BuildContext context)? onFutureConfirm, + void Function(BuildContext context)? onDismiss}) { return showDialog( builder: (_) => ConfirmOxenDialog(title, body, onDismiss: onDismiss, @@ -36,16 +36,16 @@ Future showConfirmOxenDialog(BuildContext context, String title, String body, } class OxenDialog extends StatelessWidget { - OxenDialog({this.body, this.onDismiss}); + OxenDialog({required this.body, this.onDismiss}); - final void Function(BuildContext context) onDismiss; + final void Function(BuildContext context)? onDismiss; final Widget body; void _onDismiss(BuildContext context) { if (onDismiss == null) { Navigator.of(context).pop(); } else { - onDismiss(context); + onDismiss!(context); } } @@ -81,13 +81,13 @@ class OxenDialog extends StatelessWidget { class SimpleOxenDialog extends StatelessWidget { SimpleOxenDialog(this.title, this.body, - {this.buttonText, this.onPressed, this.onDismiss}); + {this.buttonText, required this.onPressed, this.onDismiss}); final String title; final String body; - final String buttonText; + final String? buttonText; final void Function(BuildContext context) onPressed; - final void Function(BuildContext context) onDismiss; + final void Function(BuildContext context)? onDismiss; @override Widget build(BuildContext context) { @@ -107,7 +107,7 @@ class SimpleOxenDialog extends StatelessWidget { color: Theme.of(context) .primaryTextTheme .caption - .color))), + ?.color))), Padding( padding: EdgeInsets.only(top: 15, bottom: 30), child: Text(body, @@ -117,15 +117,15 @@ class SimpleOxenDialog extends StatelessWidget { color: Theme.of(context) .primaryTextTheme .caption - .color))), + ?.color))), PrimaryButton( - text: buttonText ?? S.of(context).ok, + text: buttonText ?? tr(context).ok, color: - Theme.of(context).primaryTextTheme.button.backgroundColor, + Theme.of(context).primaryTextTheme.button?.backgroundColor, borderColor: - Theme.of(context).primaryTextTheme.button.decorationColor, + Theme.of(context).primaryTextTheme.button?.decorationColor, onPressed: () { - if (onPressed != null) onPressed(context); + onPressed(context); }) ], ), @@ -139,9 +139,9 @@ class ConfirmOxenDialog extends StatelessWidget { final String title; final String body; - final Future Function(BuildContext context) onFutureConfirm; - final void Function(BuildContext context) onConfirm; - final void Function(BuildContext context) onDismiss; + final Future Function(BuildContext context)? onFutureConfirm; + final void Function(BuildContext context)? onConfirm; + final void Function(BuildContext context)? onDismiss; @override Widget build(BuildContext context) { @@ -161,7 +161,7 @@ class ConfirmOxenDialog extends StatelessWidget { color: Theme.of(context) .primaryTextTheme .caption - .color))), + ?.color))), Padding( padding: EdgeInsets.only(top: 15, bottom: 30), child: Text(body, @@ -171,15 +171,15 @@ class ConfirmOxenDialog extends StatelessWidget { color: Theme.of(context) .primaryTextTheme .caption - .color))), + ?.color))), SlideToAct( - text: S.of(context).ok, - outerColor: Theme.of(context).primaryTextTheme.subtitle2.color, + text: tr(context).ok, + outerColor: Theme.of(context).primaryTextTheme.subtitle2?.color, innerColor: OxenPalette.teal, onFutureSubmit: onFutureConfirm != null - ? () async => await onFutureConfirm(context) + ? () async => await onFutureConfirm!(context) : null, - onSubmit: onConfirm != null ? () => onConfirm(context) : null, + onSubmit: onConfirm != null ? () => onConfirm!(context) : null, ) ], ), diff --git a/lib/src/widgets/oxen_text_field.dart b/lib/src/widgets/oxen_text_field.dart index dc031126..75cb1de8 100644 --- a/lib/src/widgets/oxen_text_field.dart +++ b/lib/src/widgets/oxen_text_field.dart @@ -7,7 +7,7 @@ class OxenTextField extends StatelessWidget { {this.enabled = true, this.hintText, this.keyboardType, - this.controller, + required this.controller, this.validator, this.inputFormatters, this.prefixIcon, @@ -15,14 +15,14 @@ class OxenTextField extends StatelessWidget { this.focusNode}); final bool enabled; - final String hintText; - final TextInputType keyboardType; + final String? hintText; + final TextInputType? keyboardType; final TextEditingController controller; - final String Function(String) validator; - final List inputFormatters; - final Widget prefixIcon; - final Widget suffixIcon; - final FocusNode focusNode; + final String? Function(String?)? validator; + final List? inputFormatters; + final Widget? prefixIcon; + final Widget? suffixIcon; + final FocusNode? focusNode; @override Widget build(BuildContext context) { @@ -33,7 +33,7 @@ class OxenTextField extends StatelessWidget { focusNode: focusNode, style: TextStyle( fontSize: 18.0, - color: Theme.of(context).accentTextTheme.overline.color), + color: Theme.of(context).accentTextTheme.overline?.color), keyboardType: keyboardType, inputFormatters: inputFormatters, decoration: InputDecoration( diff --git a/lib/src/widgets/picker.dart b/lib/src/widgets/picker.dart index a7e56bfe..5cb9fc72 100644 --- a/lib/src/widgets/picker.dart +++ b/lib/src/widgets/picker.dart @@ -4,11 +4,11 @@ import 'package:flutter/material.dart'; class Picker extends StatelessWidget { Picker( - {@required this.selectedAtIndex, - @required this.items, - @required this.title, + {required this.selectedAtIndex, + required this.items, + required this.title, this.pickerHeight = 300, - this.onItemSelected}); + required this.onItemSelected}); final int selectedAtIndex; final List items; @@ -63,7 +63,7 @@ class Picker extends StatelessWidget { color: Theme.of(context) .primaryTextTheme .caption - .color), + ?.color), ), ), ); @@ -74,9 +74,6 @@ class Picker extends StatelessWidget { return GestureDetector( onTap: () { - if (onItemSelected == null) { - return; - } Navigator.of(context).pop(); onItemSelected(item); }, @@ -96,7 +93,7 @@ class Picker extends StatelessWidget { : Theme.of(context) .primaryTextTheme .caption - .color), + ?.color), )), ), ); diff --git a/lib/src/widgets/present_picker.dart b/lib/src/widgets/present_picker.dart index 70ed63c5..840fb32a 100644 --- a/lib/src/widgets/present_picker.dart +++ b/lib/src/widgets/present_picker.dart @@ -1,13 +1,25 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; -import 'package:oxen_wallet/generated/l10n.dart'; +import 'package:oxen_wallet/l10n.dart'; import 'package:oxen_wallet/src/widgets/primary_button.dart'; import 'oxen_dialog.dart'; -Future presentPicker( - BuildContext context, List list) async { - var _value = list[0]; +Future presentPicker( + BuildContext context, List list, {T? initial}) async { + var initialIndex = 0; + if (initial != null) { + for (var i = 0; i < list.length; i++) { + if (list[i] == initial) { + initialIndex = i; + break; + } + } + } + + var _value = list[initialIndex]; + + final t = tr(context); return await showDialog( context: context, @@ -19,7 +31,7 @@ Future presentPicker( children: [ Padding( padding: EdgeInsets.all(15), - child: Text(S.of(context).please_select, + child: Text(tr(context).please_select, textAlign: TextAlign.center, style: TextStyle( fontSize: 18, @@ -27,7 +39,7 @@ Future presentPicker( color: Theme.of(context) .primaryTextTheme .caption - .color))), + ?.color))), Padding( padding: EdgeInsets.only(top: 15, bottom: 30), child: Container( @@ -35,32 +47,33 @@ Future presentPicker( child: CupertinoPicker( backgroundColor: Theme.of(context).backgroundColor, itemExtent: 45.0, + scrollController: FixedExtentScrollController(initialItem: initialIndex), onSelectedItemChanged: (int index) => _value = list[index], children: List.generate( list.length, (index) => Center( child: Text( - list[index].toString(), + (list[index] is String ? list[index] : list[index].getTitle(t)) as String, style: TextStyle( color: Theme.of(context) .primaryTextTheme .caption - .color), + ?.color), ), ))), ), ), PrimaryButton( - text: S.of(context).ok, + text: tr(context).ok, color: Theme.of(context) .primaryTextTheme .button - .backgroundColor, + ?.backgroundColor, borderColor: Theme.of(context) .primaryTextTheme .button - .decorationColor, + ?.decorationColor, onPressed: () => Navigator.of(context).pop(_value), ) ], diff --git a/lib/src/widgets/primary_button.dart b/lib/src/widgets/primary_button.dart index e17973d5..e3bb28c9 100644 --- a/lib/src/widgets/primary_button.dart +++ b/lib/src/widgets/primary_button.dart @@ -4,17 +4,17 @@ import 'package:oxen_wallet/palette.dart'; class PrimaryButton extends StatelessWidget { const PrimaryButton( - {@required this.onPressed, - @required this.text, - @required this.color, - @required this.borderColor, + {required this.onPressed, + required this.text, + this.color, + this.borderColor, this.isDisabled = false, this.onDisabledPressed}); final VoidCallback onPressed; - final VoidCallback onDisabledPressed; - final Color color; - final Color borderColor; + final VoidCallback? onDisabledPressed; + final Color? color; + final Color? borderColor; final String text; final bool isDisabled; @@ -27,32 +27,32 @@ class PrimaryButton extends StatelessWidget { onPressed: isDisabled ? onDisabledPressed : onPressed, - color: isDisabled ? Colors.transparent : color, + color: isDisabled ? Colors.transparent : color ?? OxenPalette.tealWithOpacity, shape: RoundedRectangleBorder( - side: BorderSide(color: borderColor), + side: BorderSide(color: borderColor ?? OxenPalette.teal), borderRadius: BorderRadius.circular(10.0)), child: Text(text, style: TextStyle( fontSize: 16.0, color: isDisabled ? Palette.darkGrey - : Theme.of(context).primaryTextTheme.button.color)), + : Theme.of(context).primaryTextTheme.button?.color)), )); } } class LoadingPrimaryButton extends StatelessWidget { const LoadingPrimaryButton( - {@required this.onPressed, - @required this.text, - @required this.color, - @required this.borderColor, + {required this.onPressed, + required this.text, + this.color, + this.borderColor, this.isDisabled = false, this.isLoading = false}); final VoidCallback onPressed; - final Color color; - final Color borderColor; + final Color? color; + final Color? borderColor; final bool isLoading; final bool isDisabled; final String text; @@ -64,37 +64,37 @@ class LoadingPrimaryButton extends StatelessWidget { height: 56.0, child: FlatButton( onPressed: (isLoading || isDisabled) ? null : onPressed, - color: color, + color: color ?? OxenPalette.tealWithOpacity, shape: RoundedRectangleBorder( - side: BorderSide(color: borderColor), + side: BorderSide(color: borderColor ?? OxenPalette.teal), borderRadius: BorderRadius.circular(10.0)), child: isLoading ? CupertinoActivityIndicator(animating: true) : Text(text, style: TextStyle( fontSize: 16.0, - color: Theme.of(context).primaryTextTheme.button.color)), + color: Theme.of(context).primaryTextTheme.button?.color)), )); } } class PrimaryIconButton extends StatelessWidget { const PrimaryIconButton({ - @required this.onPressed, - @required this.iconData, - @required this.text, - @required this.color, - @required this.borderColor, - @required this.iconColor, - @required this.iconBackgroundColor, + required this.onPressed, + required this.iconData, + required this.text, + this.color, + this.borderColor, + this.iconColor, + this.iconBackgroundColor, }); final VoidCallback onPressed; final IconData iconData; - final Color color; - final Color borderColor; - final Color iconColor; - final Color iconBackgroundColor; + final Color? color; + final Color? borderColor; + final Color? iconColor; + final Color? iconBackgroundColor; final String text; @override @@ -104,9 +104,9 @@ class PrimaryIconButton extends StatelessWidget { height: 56.0, child: FlatButton( onPressed: onPressed, - color: color, + color: color ?? OxenPalette.tealWithOpacity, shape: RoundedRectangleBorder( - side: BorderSide(color: borderColor), + side: BorderSide(color: borderColor ?? OxenPalette.teal), borderRadius: BorderRadius.circular(10.0)), child: Stack( children: [ @@ -129,7 +129,7 @@ class PrimaryIconButton extends StatelessWidget { style: TextStyle( fontSize: 16.0, color: - Theme.of(context).primaryTextTheme.button.color)), + Theme.of(context).primaryTextTheme.button?.color ?? OxenPalette.tealWithOpacity)), ), ) ], @@ -140,9 +140,9 @@ class PrimaryIconButton extends StatelessWidget { class PrimaryImageButton extends StatelessWidget { const PrimaryImageButton( - {@required this.onPressed, - @required this.image, - @required this.text, + {required this.onPressed, + required this.image, + required this.text, this.color = Palette.purple, this.borderColor = Palette.deepPink, this.iconColor = Colors.black}); @@ -187,7 +187,7 @@ class PrimaryImageButton extends StatelessWidget { color: Theme.of(context) .primaryTextTheme .button - .color)), + ?.color)), ), ) ])) diff --git a/lib/src/widgets/scollable_with_bottom_section.dart b/lib/src/widgets/scollable_with_bottom_section.dart index a653ff58..53f56716 100644 --- a/lib/src/widgets/scollable_with_bottom_section.dart +++ b/lib/src/widgets/scollable_with_bottom_section.dart @@ -3,15 +3,15 @@ import 'package:flutter/material.dart'; class ScrollableWithBottomSection extends StatefulWidget { ScrollableWithBottomSection( - {this.content, - this.bottomSection, + {required this.content, + required this.bottomSection, this.contentPadding, this.bottomSectionPadding}); final Widget content; final Widget bottomSection; - final EdgeInsets contentPadding; - final EdgeInsets bottomSectionPadding; + final EdgeInsets? contentPadding; + final EdgeInsets? bottomSectionPadding; @override ScrollableWithBottomSectionState createState() => diff --git a/lib/src/widgets/seed_widget.dart b/lib/src/widgets/seed_widget.dart index c4f7fe54..cc4ca27a 100644 --- a/lib/src/widgets/seed_widget.dart +++ b/lib/src/widgets/seed_widget.dart @@ -1,9 +1,8 @@ -import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; -import 'package:oxen_wallet/generated/l10n.dart'; +import 'package:oxen_wallet/l10n.dart'; import 'package:oxen_wallet/palette.dart'; -import 'package:oxen_wallet/src/wallet/mnemotic_item.dart'; +import 'package:oxen_wallet/src/wallet/mnemonic_item.dart'; import 'package:oxen_wallet/src/wallet/oxen/mnemonics/chinese_simplified.dart'; import 'package:oxen_wallet/src/wallet/oxen/mnemonics/dutch.dart'; import 'package:oxen_wallet/src/wallet/oxen/mnemonics/english.dart'; @@ -21,12 +20,9 @@ final List _englishWords = EnglishMnemonics.words + EnglishOldMnemonics.words; class SeedWidget extends StatefulWidget { - SeedWidget({Key key, this.onMnemoticChange, this.onFinish, this.seedLanguage}) + SeedWidget({required Key key, required this.onMnemonicChange, required this.onFinish, required this.seedLanguage}) : super(key: key) { switch (seedLanguage) { - case 'English': - words = _englishWords; - break; case 'Chinese (simplified)': words = ChineseSimplifiedMnemonics.words; break; @@ -54,15 +50,16 @@ class SeedWidget extends StatefulWidget { case 'Italian': words = ItalianMnemonics.words; break; + case 'English': default: words = _englishWords; } } - final Function(List) onMnemoticChange; + final Function(List) onMnemonicChange; final Function() onFinish; final String seedLanguage; - List words; + late final List words; @override SeedWidgetState createState() => SeedWidgetState(); @@ -71,37 +68,34 @@ class SeedWidget extends StatefulWidget { class SeedWidgetState extends State { static const maxLength = 25; - List items = []; + List items = []; final _seedController = TextEditingController(); final _seedTextFieldKey = GlobalKey(); - MnemoticItem selectedItem; - bool isValid; - String errorMessage; + MnemonicItem? selectedItem; - List currentMnemotics; - bool isCurrentMnemoticValid; - String _errorMessage; + List currentMnemonics = []; + List invalidWords = []; + bool isCurrentMnemonicValid = false; + String? _errorMessage; @override void initState() { super.initState(); - isValid = false; - isCurrentMnemoticValid = false; + isCurrentMnemonicValid = false; + invalidWords = []; _seedController - .addListener(() => changeCurrentMnemotic(_seedController.text)); + .addListener(() => changeCurrentMnemonic(_seedController.text)); } - void addMnemotic(String text) { + void addMnemonic(String text) { setState(() => items - .add(MnemoticItem(text: text.trim(), dic: widget.words))); + .add(MnemonicItem(text: text.trim(), dic: widget.words))); _seedController.text = ''; - if (widget.onMnemoticChange != null) { - widget.onMnemoticChange(items); - } + widget.onMnemonicChange(items); } - void mnemoticFromText(String text) { + void mnemonicFromText(String text) { final splitted = text.split(' '); if (splitted.length >= 2) { @@ -111,18 +105,18 @@ class SeedWidgetState extends State { } if (selectedItem != null) { - editTextOfSelectedMnemotic(text); + editTextOfSelectedMnemonic(text); } else { - addMnemotic(text); + addMnemonic(text); } } } } - void selectMnemotic(MnemoticItem item) { + void selectMnemonic(MnemonicItem item) { setState(() { selectedItem = item; - currentMnemotics = [item]; + currentMnemonics = [item]; _seedController ..text = item.text @@ -130,24 +124,22 @@ class SeedWidgetState extends State { }); } - void onMnemoticTap(MnemoticItem item) { + void onMnemonicTap(MnemonicItem item) { if (selectedItem == item) { setState(() => selectedItem = null); _seedController.text = ''; return; } - selectMnemotic(item); + selectMnemonic(item); } - void editTextOfSelectedMnemotic(String text) { - setState(() => selectedItem.changeText(text)); + void editTextOfSelectedMnemonic(String text) { + setState(() => selectedItem?.changeText(text)); selectedItem = null; _seedController.text = ''; - if (widget.onMnemoticChange != null) { - widget.onMnemoticChange(items); - } + widget.onMnemonicChange(items); } void clear() { @@ -156,94 +148,79 @@ class SeedWidgetState extends State { selectedItem = null; _seedController.text = ''; - if (widget.onMnemoticChange != null) { - widget.onMnemoticChange(items); - } + widget.onMnemonicChange(items); }); } - void invalidate() { - setState(() => isValid = false); - } - - void validated() { - setState(() => isValid = true); - } - - void setErrorMessage(String errorMessage) { - setState(() => this.errorMessage = errorMessage); - } - void replaceText(String text) { setState(() => items = []); - mnemoticFromText(text); + mnemonicFromText(text); } - void changeCurrentMnemotic(String text) { + void changeCurrentMnemonic(String text) { setState(() { final trimmedText = text.trim(); final splitted = trimmedText.split(' '); _errorMessage = null; - if (text == null) { - currentMnemotics = []; - isCurrentMnemoticValid = false; + invalidWords = []; + + if (text.isEmpty) { + currentMnemonics = []; + isCurrentMnemonicValid = false; return; } - currentMnemotics = splitted - .map((text) => MnemoticItem(text: text, dic: widget.words)) + currentMnemonics = splitted + .map((text) => MnemonicItem(text: text, dic: widget.words)) .toList(); var isValid = true; - for (final word in currentMnemotics) { - isValid = word.isCorrect(); - - if (!isValid) { - break; + for (final word in currentMnemonics) { + if (!word.isCorrect()) { + isValid = false; + invalidWords.add(word.text); } } - isCurrentMnemoticValid = isValid; + isCurrentMnemonicValid = isValid; }); } - void saveCurrentMnemoticToItems() { + void saveCurrentMnemonicToItems() { setState(() { if (selectedItem != null) { - selectedItem.changeText(currentMnemotics.first.text.trim()); + selectedItem!.changeText(currentMnemonics.first.text.trim()); selectedItem = null; } else { - items.addAll(currentMnemotics); + items.addAll(currentMnemonics); } - currentMnemotics = []; + currentMnemonics = []; _seedController.text = ''; }); } - void showErrorIfExist() { + void showErrorIfExist(AppLocalizations t) { setState(() => _errorMessage = - !isCurrentMnemoticValid ? S.current.incorrect_seed : null); + isCurrentMnemonicValid + ? null + : t.incorrect_seed + (invalidWords.isNotEmpty ? t.invalid_seed_words(invalidWords.join(", ")) : "")); } bool isSeedValid() { - bool isValid; - for (final item in items) { - isValid = item.isCorrect(); - - if (!isValid) { - break; - } + if (!item.isCorrect()) + return false; } - return isValid; + return true; } @override Widget build(BuildContext context) { + final t = tr(context); return Container( child: Column(children: [ Flexible( @@ -256,7 +233,7 @@ class SeedWidgetState extends State { final isSelected = selectedItem == item; return InkWell( - onTap: () => onMnemoticTap(item), + onTap: () => onMnemonicTap(item), child: Container( decoration: BoxDecoration( color: @@ -286,12 +263,14 @@ class SeedWidgetState extends State { Column(children: [ TextFormField( key: _seedTextFieldKey, - onFieldSubmitted: (text) => isCurrentMnemoticValid - ? saveCurrentMnemoticToItems() + onFieldSubmitted: (text) => isCurrentMnemonicValid + ? saveCurrentMnemonicToItems() : null, style: TextStyle(fontSize: 14.0), controller: _seedController, textInputAction: TextInputAction.done, + autocorrect: false, + enableSuggestions: false, decoration: InputDecoration( suffixIcon: GestureDetector( behavior: HitTestBehavior.opaque, @@ -304,29 +283,13 @@ class SeedWidgetState extends State { '${items.length}/${SeedWidgetState.maxLength}', style: TextStyle( color: Colors.grey, fontSize: 12)), - SizedBox(width: 10), - InkWell( - onTap: () async => - Clipboard.getData('text/plain').then( - (clipboard) => - replaceText(clipboard.text)), - child: Container( - height: 35, - padding: EdgeInsets.all(7), - decoration: BoxDecoration( - color: - Palette.wildDarkBlueWithOpacity, - borderRadius: - BorderRadius.circular(10.0)), - child: Text(S.of(context).paste)), - ) ], ), ), ), hintStyle: TextStyle(color: Theme.of(context).hintColor), - hintText: S.of(context).restore_from_seed_placeholder, + hintText: t.restore_from_seed_placeholder, errorText: _errorMessage, focusedBorder: UnderlineInputBorder( borderSide: BorderSide( @@ -335,35 +298,32 @@ class SeedWidgetState extends State { borderSide: BorderSide( color: Theme.of(context).focusColor, width: 1.0))), - enableInteractiveSelection: false, ), ]), Padding( padding: EdgeInsets.only(bottom: 20), child: (selectedItem == null && items.length == maxLength) ? PrimaryButton( - text: S.of(context).restore_next, + text: t.restore_next, isDisabled: !isSeedValid(), - onPressed: () => widget.onFinish != null - ? widget.onFinish() - : null, + onPressed: widget.onFinish, color: Theme.of(context) .primaryTextTheme .button - .backgroundColor, + ?.backgroundColor, borderColor: Theme.of(context) .primaryTextTheme .button - .decorationColor) + ?.decorationColor) : PrimaryButton( text: selectedItem != null - ? S.of(context).save - : S.of(context).add_new_word, - onPressed: () => isCurrentMnemoticValid - ? saveCurrentMnemoticToItems() + ? t.save + : t.add_new_word, + onPressed: () => isCurrentMnemonicValid + ? saveCurrentMnemonicToItems() : null, - onDisabledPressed: () => showErrorIfExist(), - isDisabled: !isCurrentMnemoticValid, + onDisabledPressed: () => showErrorIfExist(t), + isDisabled: !isCurrentMnemonicValid, color: PaletteDark.darkThemeBlueButton, borderColor: Palette.brightBlue)) ])) diff --git a/lib/src/widgets/slide_to_act.dart b/lib/src/widgets/slide_to_act.dart index c6fc84b0..42310f3a 100644 --- a/lib/src/widgets/slide_to_act.dart +++ b/lib/src/widgets/slide_to_act.dart @@ -4,12 +4,12 @@ import 'package:flutter/material.dart'; class SlideToAct extends StatefulWidget { const SlideToAct({ - Key key, + Key? key, this.sliderButtonIconSize = 24, this.sliderButtonIconPadding = 16, this.sliderButtonYOffset = 0, this.height = 70, - this.outerColor, + required this.outerColor, this.borderRadius = 52, this.elevation = 6, this.animationDuration = const Duration(milliseconds: 300), @@ -20,7 +20,7 @@ class SlideToAct extends StatefulWidget { this.onSubmit, this.child, this.innerColor, - this.text, + required this.text, this.sliderButtonIcon, }) : super(key: key); @@ -34,18 +34,18 @@ class SlideToAct extends StatefulWidget { final double sliderButtonYOffset; /// The child that is rendered instead of the default Text widget - final Widget child; + final Widget? child; /// The height of the component final double height; /// The color of the inner circular button, of the tick icon of the text. /// If not set, this attribute defaults to primaryIconTheme. - final Color innerColor; + final Color? innerColor; /// The color of the external area and of the arrow icon. /// If not set, this attribute defaults to accentColor from your theme. - final Color outerColor; + final Color? outerColor; /// The text showed in the default Text widget final String text; @@ -54,17 +54,17 @@ class SlideToAct extends StatefulWidget { final double borderRadius; /// Callback called on submit - final Future Function() onFutureSubmit; - final VoidCallback onSubmit; + final Future Function()? onFutureSubmit; + final VoidCallback? onSubmit; /// Elevation of the component final double elevation; /// The widget to render instead of the default icon - final Widget sliderButtonIcon; + final Widget? sliderButtonIcon; /// The widget to render instead of the default submitted icon - final Widget submittedIcon; + final Widget? submittedIcon; /// The duration of the animations final Duration animationDuration; @@ -88,13 +88,9 @@ class SlideToActState extends State with TickerProviderStateMixin { double get _progress => _dx == 0 ? 0 : _dx / _maxDx; double _endDx = 0; - double _dz = 1; - double _initialContainerWidth, _containerWidth; - double _checkAnimationDx = 0; + double? _containerWidth; bool submitted = false; - AnimationController _checkAnimationController, - _shrinkAnimationController, - _resizeAnimationController, + late AnimationController _cancelAnimationController; @override @@ -135,15 +131,10 @@ class SlideToActState extends State with TickerProviderStateMixin { ), Positioned.fill( right: 0, - child: Transform( - transform: Matrix4.rotationY( - _checkAnimationDx * (pi / 2)), - alignment: Alignment.centerRight, - child: Container( + child: Container( color: widget.outerColor ?? Theme.of(context).accentColor, ), - ), ), ], ), @@ -161,7 +152,7 @@ class SlideToActState extends State with TickerProviderStateMixin { Matrix4.rotationY(widget.reversed ? pi : 0), child: widget.child ?? Text( - widget.text ?? 'Slide to act', + widget.text, textAlign: TextAlign.center, style: TextStyle( color: widget.innerColor ?? @@ -173,56 +164,52 @@ class SlideToActState extends State with TickerProviderStateMixin { ), Positioned( left: widget.sliderButtonYOffset, - child: Transform.scale( - scale: _dz, - origin: Offset(_dx, 0), - child: Transform.translate( - offset: Offset(_dx, 0), - child: Container( - key: _sliderKey, - child: GestureDetector( - onHorizontalDragUpdate: onHorizontalDragUpdate, - onHorizontalDragEnd: (details) async { - _endDx = _dx; - if (_progress <= 0.8) { - await _cancelAnimation(); - } else { - if (widget.onFutureSubmit != null) { - await widget.onFutureSubmit(); - } else if (widget.onSubmit != null) { - widget.onSubmit(); - } - await _cancelAnimation(); + child: Transform.translate( + offset: Offset(_dx, 0), + child: Container( + key: _sliderKey, + child: GestureDetector( + onHorizontalDragUpdate: onHorizontalDragUpdate, + onHorizontalDragEnd: (details) async { + _endDx = _dx; + if (_progress <= 0.8) { + await _cancelAnimation(); + } else { + if (widget.onFutureSubmit != null) { + await widget.onFutureSubmit!.call(); + } else if (widget.onSubmit != null) { + widget.onSubmit!.call(); } - }, - child: Padding( - padding: const EdgeInsets.symmetric( - horizontal: 8.0), - child: Material( - borderRadius: BorderRadius.circular( - widget.borderRadius), - child: Container( - padding: EdgeInsets.all( - widget.sliderButtonIconPadding), - child: Transform.rotate( - angle: -pi * _progress, - child: Center( - child: widget.sliderButtonIcon ?? - Icon( - Icons.arrow_forward, - size: - widget.sliderButtonIconSize, - color: widget.outerColor ?? - Theme.of(context) - .accentColor, - ), - ), + await _cancelAnimation(); + } + }, + child: Padding( + padding: const EdgeInsets.symmetric( + horizontal: 8.0), + child: Material( + borderRadius: BorderRadius.circular( + widget.borderRadius), + color: widget.innerColor ?? + Theme.of(context) + .primaryIconTheme + .color, + child: Container( + padding: EdgeInsets.all( + widget.sliderButtonIconPadding), + child: Transform.rotate( + angle: -pi * _progress, + child: Center( + child: widget.sliderButtonIcon ?? + Icon( + Icons.arrow_forward, + size: + widget.sliderButtonIconSize, + color: widget.outerColor ?? + Theme.of(context) + .accentColor, + ), ), ), - color: widget.innerColor ?? - Theme.of(context) - .primaryIconTheme - .color, ), ), ), @@ -240,91 +227,16 @@ class SlideToActState extends State with TickerProviderStateMixin { void onHorizontalDragUpdate(DragUpdateDetails details) { setState(() { - _dx = (_dx + details.delta.dx).clamp(0.0, _maxDx) as double; + _dx = (_dx + details.delta.dx).clamp(0.0, _maxDx); }); } /// Call this method to revert the animations Future reset() async { - await _checkAnimationController.reverse().orCancel; - submitted = false; - - await _shrinkAnimationController.reverse().orCancel; - - await _resizeAnimationController.reverse().orCancel; - await _cancelAnimation(); } - Future _checkAnimation() async { - _checkAnimationController.reset(); - - final animation = Tween( - begin: 0, - end: 1, - ).animate(CurvedAnimation( - parent: _checkAnimationController, - curve: Curves.slowMiddle, - )); - - animation.addListener(() { - if (mounted) { - setState(() { - _checkAnimationDx = animation.value; - }); - } - }); - await _checkAnimationController.forward().orCancel; - } - - Future _shrinkAnimation() async { - _shrinkAnimationController.reset(); - - final diff = _initialContainerWidth - widget.height; - final animation = Tween( - begin: 0, - end: 1, - ).animate(CurvedAnimation( - parent: _shrinkAnimationController, - curve: Curves.easeOutCirc, - )); - - animation.addListener(() { - if (mounted) { - setState(() { - _containerWidth = _initialContainerWidth - (diff * animation.value); - }); - } - }); - - setState(() { - submitted = true; - }); - await _shrinkAnimationController.forward().orCancel; - } - - Future _resizeAnimation() async { - _resizeAnimationController.reset(); - - final animation = Tween( - begin: 0, - end: 1, - ).animate(CurvedAnimation( - parent: _resizeAnimationController, - curve: Curves.easeInBack, - )); - - animation.addListener(() { - if (mounted) { - setState(() { - _dz = 1 - animation.value; - }); - } - }); - await _resizeAnimationController.forward().orCancel; - } - Future _cancelAnimation() async { _cancelAnimationController.reset(); final animation = Tween( @@ -353,41 +265,22 @@ class SlideToActState extends State with TickerProviderStateMixin { vsync: this, duration: widget.animationDuration, ); - _checkAnimationController = AnimationController( - vsync: this, - duration: widget.animationDuration, - ); - _shrinkAnimationController = AnimationController( - vsync: this, - duration: widget.animationDuration, - ); - - _resizeAnimationController = AnimationController( - vsync: this, - duration: widget.animationDuration, - ); - WidgetsBinding.instance.addPostFrameCallback((_) { - final containerBox = - _containerKey.currentContext.findRenderObject() as RenderBox; + WidgetsBinding.instance!.addPostFrameCallback((_) { + final containerBox = _containerKey.currentContext!.findRenderObject() as RenderBox; _containerWidth = containerBox.size.width; - _initialContainerWidth = _containerWidth; - final sliderBox = - _sliderKey.currentContext.findRenderObject() as RenderBox; + final sliderBox = _sliderKey.currentContext!.findRenderObject() as RenderBox; final sliderWidth = sliderBox.size.width; _maxDx = - _containerWidth - (sliderWidth / 2) - 40 - widget.sliderButtonYOffset; + _containerWidth! - (sliderWidth / 2) - 40 - widget.sliderButtonYOffset; }); } @override void dispose() { _cancelAnimationController.dispose(); - _checkAnimationController.dispose(); - _shrinkAnimationController.dispose(); - _resizeAnimationController.dispose(); super.dispose(); } } diff --git a/lib/src/widgets/standart_switch.dart b/lib/src/widgets/standart_switch.dart index 1232fe57..552ef8f3 100644 --- a/lib/src/widgets/standart_switch.dart +++ b/lib/src/widgets/standart_switch.dart @@ -1,10 +1,11 @@ import 'package:flutter/material.dart'; +import 'package:oxen_wallet/palette.dart'; class StandartSwitch extends StatefulWidget { - const StandartSwitch({@required this.value, @required this.onTaped}); + const StandartSwitch({required this.value, this.onTaped}); final bool value; - final VoidCallback onTaped; + final VoidCallback? onTaped; @override StandartSwitchState createState() => StandartSwitchState(); @@ -24,7 +25,7 @@ class StandartSwitchState extends State { decoration: BoxDecoration( color: Theme.of(context).toggleButtonsTheme.color, border: Border.all( - color: Theme.of(context).toggleButtonsTheme.borderColor), + color: Theme.of(context).toggleButtonsTheme.borderColor ?? Palette.switchBorder), borderRadius: BorderRadius.all(Radius.circular(10.0))), child: Container( width: 25.0, diff --git a/oxen_coin/android/CMakeLists.txt b/oxen_coin/android/CMakeLists.txt index 7970cdf5..06264ccf 100644 --- a/oxen_coin/android/CMakeLists.txt +++ b/oxen_coin/android/CMakeLists.txt @@ -1,11 +1,17 @@ cmake_minimum_required(VERSION 3.10) + +project(oxen_coin + VERSION 0.0.1 + DESCRIPTION "Oxen wallet wrapper for mobile wallets" + LANGUAGES C CXX) + set (CMAKE_CXX_STANDARD 17) add_library( oxen_coin SHARED ./jni/oxen_jni.cpp) -set(CMAKE_BUILD_TYPE Debug) +set(CMAKE_BUILD_TYPE Release) set(EXTERNAL_LIBS_DIR ${CMAKE_SOURCE_DIR}/../ios/External/android) @@ -16,4 +22,4 @@ set_target_properties(wallet_api PROPERTIES IMPORTED_LOCATION include_directories( ${EXTERNAL_LIBS_DIR}/oxen/include ) target_link_libraries( oxen_coin PRIVATE wallet_api ) -target_include_directories( oxen_coin PRIVATE wallet_api ) \ No newline at end of file +target_include_directories( oxen_coin PRIVATE wallet_api ) diff --git a/oxen_coin/android/build.gradle b/oxen_coin/android/build.gradle index 9a28b200..684dfb79 100644 --- a/oxen_coin/android/build.gradle +++ b/oxen_coin/android/build.gradle @@ -2,14 +2,14 @@ group 'io.oxen.coin' version '1.0-SNAPSHOT' buildscript { - ext.kotlin_version = '1.4.10' + ext.kotlin_version = '1.6.20' repositories { google() jcenter() } dependencies { - classpath 'com.android.tools.build:gradle:3.5.0' + classpath 'com.android.tools.build:gradle:7.1.3' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" } } @@ -25,7 +25,7 @@ apply plugin: 'com.android.library' apply plugin: 'kotlin-android' android { - compileSdkVersion 28 + compileSdkVersion 31 sourceSets { main.java.srcDirs += 'src/main/kotlin' @@ -36,7 +36,7 @@ android { externalNativeBuild { // Encapsulates your CMake build configurations. cmake { - //version "3.10.0+" + version "3.18.0+" cppFlags "-std=c++17" arguments '-DANDROID_STL=c++_shared' } @@ -53,7 +53,7 @@ android { // Encapsulates your CMake build configurations. cmake { // Provides a relative path to your CMake build script. - version "3.10.0+" + version "3.18.0+" path "CMakeLists.txt" } } diff --git a/oxen_coin/android/gradle.properties b/oxen_coin/android/gradle.properties index 38c8d454..3a661474 100644 --- a/oxen_coin/android/gradle.properties +++ b/oxen_coin/android/gradle.properties @@ -1,4 +1,5 @@ org.gradle.jvmargs=-Xmx1536M -android.enableR8=true android.useAndroidX=true android.enableJetifier=true +android.native.buildOutput=verbose +android.bundle.enableUncompressedNativeLibs = false diff --git a/oxen_coin/ios/Classes/oxen_api.cpp b/oxen_coin/ios/Classes/oxen_api.cpp index b0e29d6b..ccd9db44 100644 --- a/oxen_coin/ios/Classes/oxen_api.cpp +++ b/oxen_coin/ios/Classes/oxen_api.cpp @@ -1,5 +1,6 @@ #include #include +#include #include #include #include @@ -19,15 +20,29 @@ namespace Oxen = Wallet; extern "C" { - struct Utf8Box + typedef struct { - char *value; + bool good; + char error[1023]; + } status_and_error; - Utf8Box(char *_value) - { - value = _value; - } - }; + void set_error(status_and_error& sae, std::string_view error) { + size_t len = std::min(error.size(), sizeof(sae.error)-1); + std::memcpy(sae.error, error.data(), len); + sae.error[len] = '\0'; + } + status_and_error make_status_and_error(bool good, std::string_view error) { + status_and_error sae; + sae.good = good; + set_error(sae, error); + return sae; + } + status_and_error make_good_status() { + return make_status_and_error(true, ""); + } + status_and_error make_fail_status(std::string_view error) { + return make_status_and_error(false, error); + } struct SubaddressRow { @@ -133,6 +148,7 @@ extern "C" uint32_t subaddrAccount; int8_t direction; int8_t isPending; + int8_t isStake; char *hash; char *paymentId; @@ -149,6 +165,7 @@ extern "C" datetime = static_cast(transaction->timestamp()); direction = transaction->direction(); isPending = static_cast(transaction->isPending()); + isStake = static_cast(transaction->isStake()); std::string *hash_str = new std::string(transaction->hash()); hash = strdup(hash_str->c_str()); paymentId = strdup(transaction->paymentId().c_str()); @@ -248,7 +265,7 @@ extern "C" } EXPORT - bool create_wallet(char *path, char *password, char *language, int32_t networkType, char *error) + status_and_error create_wallet(char *path, char *password, char *language, int32_t networkType) { Oxen::NetworkType _networkType = static_cast(networkType); Oxen::WalletManagerBase *walletManager = Oxen::WalletManagerFactory::getWalletManager(); @@ -256,55 +273,42 @@ extern "C" auto stat = wallet->status(); - auto& [status, errorString] = stat; - - if (status != Oxen::Wallet::Status_Ok) - { - error = strdup(errorString.c_str()); - return false; - } + if (stat.first != Oxen::Wallet::Status_Ok) + return make_fail_status(stat.second); walletManager->closeWallet(wallet); - wallet = walletManager->openWallet(std::string(path), std::string(password), _networkType); + wallet = walletManager->openWallet(path, password, _networkType); stat = wallet->status(); - if (status != Oxen::Wallet::Status_Ok) - { - error = strdup(errorString.c_str()); - return false; - } + if (stat.first != Oxen::Wallet::Status_Ok) + return make_fail_status(stat.second); change_current_wallet(wallet); - return true; + return make_good_status(); } EXPORT - bool restore_wallet_from_seed(char *path, char *password, char *seed, int32_t networkType, uint64_t restoreHeight, char *error) + status_and_error restore_wallet_from_seed(char *path, char *password, char *seed, int32_t networkType, uint64_t restoreHeight) { Oxen::NetworkType _networkType = static_cast(networkType); Oxen::Wallet *wallet = Oxen::WalletManagerFactory::getWalletManager()->recoveryWallet( - std::string(path), - std::string(password), - std::string(seed), - _networkType, - (uint64_t)restoreHeight); + path, password, seed, _networkType, restoreHeight); auto [status, errorString] = wallet->status(); if (status != Oxen::Wallet::Status_Ok) { - error = strdup(errorString.c_str()); - return false; + return make_fail_status(errorString); } change_current_wallet(wallet); - return true; + return make_good_status(); } EXPORT - bool restore_wallet_from_keys(char *path, char *password, char *language, char *address, char *viewKey, char *spendKey, int32_t networkType, uint64_t restoreHeight, char *error) + status_and_error restore_wallet_from_keys(char *path, char *password, char *language, char *address, char *viewKey, char *spendKey, int32_t networkType, uint64_t restoreHeight) { Oxen::NetworkType _networkType = static_cast(networkType); Oxen::Wallet *wallet = Oxen::WalletManagerFactory::getWalletManager()->createWalletFromKeys( @@ -321,13 +325,10 @@ extern "C" auto [status, errorString] = wallet->status(); if (status != Oxen::Wallet::Status_Ok || !errorString.empty()) - { - error = strdup(errorString.c_str()); - return false; - } + return make_fail_status(errorString); change_current_wallet(wallet); - return true; + return make_good_status(); } EXPORT @@ -425,21 +426,19 @@ extern "C" } EXPORT - bool connect_to_node(char *error) + status_and_error connect_to_node() { nice(19); bool is_connected = get_current_wallet()->connectToDaemon(); if (!is_connected) - { - error = strdup(get_current_wallet()->status().second.c_str()); - } + return make_fail_status(get_current_wallet()->status().second); - return is_connected; + return make_good_status(); } EXPORT - bool setup_node(char *address, char *login, char *password, bool use_ssl, bool is_light_wallet, char *error) + status_and_error setup_node(char *address, char *login, char *password, bool use_ssl) { nice(19); Oxen::Wallet *wallet = get_current_wallet(); @@ -448,25 +447,17 @@ extern "C" std::string _password = ""; if (login != nullptr) - { - _login = std::string(login); - } + _login = login; if (password != nullptr) - { - _password = std::string(password); - } + _password = password; - bool inited = wallet->init(std::string(address), 0, _login, _password, use_ssl, is_light_wallet); + bool inited = wallet->init(address, 0, _login, _password, use_ssl); - if (!inited) - { - error = strdup(wallet->status().second.c_str()); - } else if (!wallet->connectToDaemon()) { - error = strdup(wallet->status().second.c_str()); - } + if (!inited || !wallet->connectToDaemon()) + return make_fail_status(wallet->status().second); - return inited; + return make_good_status(); } EXPORT @@ -527,25 +518,26 @@ extern "C" } EXPORT - bool stake_create(char *service_node_key, char *amount, Utf8Box &error, PendingTransactionRaw &pendingTransaction) + status_and_error stake_create(char *service_node_key, char *amount, PendingTransactionRaw &pendingTransaction) { nice(19); Oxen::PendingTransaction *transaction; - uint64_t _amount = Oxen::Wallet::amountFromString(std::string(amount)); - transaction = m_wallet->stakePending(std::string(service_node_key), _amount); + uint64_t _amount = amount != nullptr + ? Oxen::Wallet::amountFromString(amount) + : get_unlocked_balance(0); + transaction = m_wallet->stakePending(service_node_key, _amount); int status = transaction->status().first; if (status == Oxen::PendingTransaction::Status::Status_Error || status == Oxen::PendingTransaction::Status::Status_Critical) { - error = Utf8Box(strdup(transaction->status().second.c_str())); - return false; + return make_fail_status(transaction->status().second); } pendingTransaction = PendingTransactionRaw(transaction); - return true; + return make_good_status(); } EXPORT @@ -556,20 +548,16 @@ extern "C" } EXPORT - bool submit_stake_unlock(char *service_node_key, Utf8Box &error, PendingTransactionRaw &pendingTransaction) + status_and_error submit_stake_unlock(char *service_node_key, PendingTransactionRaw &pendingTransaction) { std::unique_ptr stakeUnlockResult{m_wallet->requestStakeUnlock(service_node_key)}; if (stakeUnlockResult->success()) { pendingTransaction = stakeUnlockResult->ptx(); - return true; - } - else - { - error = Utf8Box(strdup(stakeUnlockResult->msg().c_str())); - return false; + return make_good_status(); } + return make_fail_status(stakeUnlockResult->msg()); } EXPORT @@ -579,55 +567,48 @@ extern "C" } EXPORT - bool transaction_create(char *address, char *amount, uint8_t priority, uint32_t subaddr_account, Utf8Box &error, + status_and_error transaction_create(char *address, char *amount, uint8_t priority, uint32_t subaddr_account, PendingTransactionRaw &pendingTransaction) { nice(19); Oxen::PendingTransaction *transaction; + std::optional amt; if (amount != nullptr) - { - uint64_t _amount = Oxen::Wallet::amountFromString(std::string(amount)); - transaction = m_wallet->createTransaction(std::string(address), _amount, priority, subaddr_account); - } - else - { - transaction = m_wallet->createTransaction(std::string(address), std::optional(), priority, subaddr_account); - } + amt = Oxen::Wallet::amountFromString(amount); + + transaction = m_wallet->createTransaction(address, amt, priority, subaddr_account); int status = transaction->status().first; if (status == Oxen::PendingTransaction::Status::Status_Error || status == Oxen::PendingTransaction::Status::Status_Critical) { - error = Utf8Box(strdup(transaction->status().second.c_str())); - return false; + return make_fail_status(transaction->status().second); } pendingTransaction = PendingTransactionRaw(transaction); - return true; + return make_good_status(); } EXPORT - bool transaction_commit(PendingTransactionRaw *transaction, Utf8Box &error) + status_and_error transaction_commit(PendingTransactionRaw *transaction) { - bool committed = transaction->transaction->commit(); + status_and_error result = make_status_and_error(transaction->transaction->commit(), ""); - if (!committed) - { - error = Utf8Box(strdup(transaction->transaction->status().second.c_str())); - } else if (m_listener != nullptr) { + if (!result.good) + set_error(result, transaction->transaction->status().second); + else if (m_listener) m_listener->m_new_transaction = true; - } - return committed; + return result; } EXPORT - uint64_t get_node_height_or_update(uint64_t base_eight) + uint64_t get_node_height_or_update(uint64_t base_height) { - if (m_cached_syncing_blockchain_height < base_eight) { - m_cached_syncing_blockchain_height = base_eight; + if (m_cached_syncing_blockchain_height < base_height) { + m_cached_syncing_blockchain_height = base_height; } return m_cached_syncing_blockchain_height; diff --git a/oxen_coin/lib/account_list.dart b/oxen_coin/lib/account_list.dart index 9620f6f7..e7b37029 100644 --- a/oxen_coin/lib/account_list.dart +++ b/oxen_coin/lib/account_list.dart @@ -25,8 +25,8 @@ void _setLabelForAccount(Map args) { account_list.setLabelForAccountSync(label: label, accountIndex: accountIndex); } -Future addAccount({String label}) async => compute(_addAccount, label); +Future addAccount({required String label}) async => compute(_addAccount, label); -Future setLabelForAccount({int accountIndex, String label}) async => +Future setLabelForAccount({required int accountIndex, required String label}) async => compute( _setLabelForAccount, {'accountIndex': accountIndex, 'label': label}); diff --git a/oxen_coin/lib/src/exceptions/connection_to_node_exception.dart b/oxen_coin/lib/src/exceptions/connection_to_node_exception.dart index 6ee272b8..483b0a17 100644 --- a/oxen_coin/lib/src/exceptions/connection_to_node_exception.dart +++ b/oxen_coin/lib/src/exceptions/connection_to_node_exception.dart @@ -1,5 +1,5 @@ class ConnectionToNodeException implements Exception { - ConnectionToNodeException({this.message}); + ConnectionToNodeException({required this.message}); final String message; } \ No newline at end of file diff --git a/oxen_coin/lib/src/exceptions/creation_transaction_exception.dart b/oxen_coin/lib/src/exceptions/creation_transaction_exception.dart index bb477d67..dcd41c5c 100644 --- a/oxen_coin/lib/src/exceptions/creation_transaction_exception.dart +++ b/oxen_coin/lib/src/exceptions/creation_transaction_exception.dart @@ -1,8 +1,8 @@ class CreationTransactionException implements Exception { - CreationTransactionException({this.message}); + CreationTransactionException({required this.message}); final String message; @override String toString() => message; -} \ No newline at end of file +} diff --git a/oxen_coin/lib/src/exceptions/setup_wallet_exception.dart b/oxen_coin/lib/src/exceptions/setup_wallet_exception.dart index ce43c0ec..eaa77236 100644 --- a/oxen_coin/lib/src/exceptions/setup_wallet_exception.dart +++ b/oxen_coin/lib/src/exceptions/setup_wallet_exception.dart @@ -1,5 +1,5 @@ class SetupWalletException implements Exception { - SetupWalletException({this.message}); + SetupWalletException({required this.message}); final String message; -} \ No newline at end of file +} diff --git a/oxen_coin/lib/src/exceptions/wallet_creation_exception.dart b/oxen_coin/lib/src/exceptions/wallet_creation_exception.dart index a3555338..c63a7230 100644 --- a/oxen_coin/lib/src/exceptions/wallet_creation_exception.dart +++ b/oxen_coin/lib/src/exceptions/wallet_creation_exception.dart @@ -1,5 +1,5 @@ class WalletCreationException implements Exception { - WalletCreationException({this.message}); + WalletCreationException({required this.message}); final String message; -} \ No newline at end of file +} diff --git a/oxen_coin/lib/src/exceptions/wallet_restore_from_keys_exception.dart b/oxen_coin/lib/src/exceptions/wallet_restore_from_keys_exception.dart index 5f08437d..6379c404 100644 --- a/oxen_coin/lib/src/exceptions/wallet_restore_from_keys_exception.dart +++ b/oxen_coin/lib/src/exceptions/wallet_restore_from_keys_exception.dart @@ -1,5 +1,5 @@ class WalletRestoreFromKeysException implements Exception { - WalletRestoreFromKeysException({this.message}); + WalletRestoreFromKeysException({required this.message}); final String message; -} \ No newline at end of file +} diff --git a/oxen_coin/lib/src/exceptions/wallet_restore_from_seed_exception.dart b/oxen_coin/lib/src/exceptions/wallet_restore_from_seed_exception.dart index fd89e416..4145da40 100644 --- a/oxen_coin/lib/src/exceptions/wallet_restore_from_seed_exception.dart +++ b/oxen_coin/lib/src/exceptions/wallet_restore_from_seed_exception.dart @@ -1,5 +1,5 @@ class WalletRestoreFromSeedException implements Exception { - WalletRestoreFromSeedException({this.message}); + WalletRestoreFromSeedException({required this.message}); final String message; -} \ No newline at end of file +} diff --git a/oxen_coin/lib/src/native/account_list.dart b/oxen_coin/lib/src/native/account_list.dart index 942abca7..ae6e4ed1 100644 --- a/oxen_coin/lib/src/native/account_list.dart +++ b/oxen_coin/lib/src/native/account_list.dart @@ -25,14 +25,14 @@ final accountSetLabelNative = oxenApi .lookup>('account_set_label_row') .asFunction(); -void addAccountSync({String label}) { - final labelPointer = Utf8.toUtf8(label); +void addAccountSync({required String label}) { + final labelPointer = label.toNativeUtf8(); accountAddNewNative(labelPointer); - free(labelPointer); + calloc.free(labelPointer); } -void setLabelForAccountSync({int accountIndex, String label}) { - final labelPointer = Utf8.toUtf8(label); +void setLabelForAccountSync({required int accountIndex, required String label}) { + final labelPointer = label.toNativeUtf8(); accountSetLabelNative(accountIndex, labelPointer); - free(labelPointer); + calloc.free(labelPointer); } diff --git a/oxen_coin/lib/src/native/stake.dart b/oxen_coin/lib/src/native/stake.dart index bf982ba3..2a6a5d34 100644 --- a/oxen_coin/lib/src/native/stake.dart +++ b/oxen_coin/lib/src/native/stake.dart @@ -4,7 +4,6 @@ import 'package:ffi/ffi.dart'; import 'package:oxen_coin/oxen_coin_structs.dart'; import 'package:oxen_coin/src/exceptions/creation_transaction_exception.dart'; import 'package:oxen_coin/src/oxen_api.dart'; -import 'package:oxen_coin/src/structs/ut8_box.dart'; import 'package:oxen_coin/src/util/signatures.dart'; import 'package:oxen_coin/src/util/types.dart'; @@ -29,25 +28,18 @@ final submitStakeUnlockNative = oxenApi .asFunction(); PendingTransactionDescription createStakeSync( - String serviceNodeKey, String amount) { - final serviceNodeKeyPointer = Utf8.toUtf8(serviceNodeKey); - final amountPointer = Utf8.toUtf8(amount); - final errorMessagePointer = allocate(); - final pendingTransactionRawPointer = allocate(); + String serviceNodeKey, String? amount) { + final serviceNodeKeyPointer = serviceNodeKey.toNativeUtf8(); + final amountPointer = amount != null ? amount.toNativeUtf8() : nullptr; + final pendingTransactionRawPointer = calloc(); final created = stakeCreateNative(serviceNodeKeyPointer, amountPointer, - errorMessagePointer, pendingTransactionRawPointer) != - 0; + pendingTransactionRawPointer); - free(serviceNodeKeyPointer); + calloc.free(serviceNodeKeyPointer); + calloc.free(amountPointer); - if (amountPointer != nullptr) { - free(amountPointer); - } - - if (!created) { - final message = errorMessagePointer.ref.getValue(); - free(errorMessagePointer); - throw CreationTransactionException(message: message); + if (!created.good) { + throw CreationTransactionException(message: created.errorString()); } return PendingTransactionDescription( @@ -57,25 +49,15 @@ PendingTransactionDescription createStakeSync( pointerAddress: pendingTransactionRawPointer.address); } -PendingTransactionDescription submitStakeUnlockSync(String serviceNodeKey) { - final serviceNodeKeyPointer = Utf8.toUtf8(serviceNodeKey); - final errorMessagePointer = allocate(); - final pendingTransactionRawPointer = allocate(); - final created = submitStakeUnlockNative(serviceNodeKeyPointer, - errorMessagePointer, pendingTransactionRawPointer) != - 0; +void submitStakeUnlockSync(String serviceNodeKey) { + final serviceNodeKeyPointer = serviceNodeKey.toNativeUtf8(); + final pendingTransactionRawPointer = calloc(); + final result = submitStakeUnlockNative(serviceNodeKeyPointer, pendingTransactionRawPointer); - free(serviceNodeKeyPointer); + calloc.free(serviceNodeKeyPointer); - if (!created) { - final message = errorMessagePointer.ref.getValue(); - free(errorMessagePointer); - throw CreationTransactionException(message: message); - } + if (!result.good) + throw CreationTransactionException(message: result.errorString()); - return PendingTransactionDescription( - amount: pendingTransactionRawPointer.ref.amount, - fee: pendingTransactionRawPointer.ref.fee, - hash: pendingTransactionRawPointer.ref.getHash(), - pointerAddress: pendingTransactionRawPointer.address); + calloc.free(pendingTransactionRawPointer); } diff --git a/oxen_coin/lib/src/native/subaddress_list.dart b/oxen_coin/lib/src/native/subaddress_list.dart index 5bdc3c9e..3b77e187 100644 --- a/oxen_coin/lib/src/native/subaddress_list.dart +++ b/oxen_coin/lib/src/native/subaddress_list.dart @@ -25,16 +25,16 @@ final subaddressSetLabelNative = oxenApi .lookup>('subaddress_set_label') .asFunction(); -void addSubaddressSync({int accountIndex, String label}) { - final labelPointer = Utf8.toUtf8(label); +void addSubaddressSync({required int accountIndex, required String label}) { + final labelPointer = label.toNativeUtf8(); subaddressAddNewNative(accountIndex, labelPointer); - free(labelPointer); + calloc.free(labelPointer); } void setLabelForSubaddressSync( - {int accountIndex, int addressIndex, String label}) { - final labelPointer = Utf8.toUtf8(label); + {required int accountIndex, required int addressIndex, required String label}) { + final labelPointer = label.toNativeUtf8(); subaddressSetLabelNative(accountIndex, addressIndex, labelPointer); - free(labelPointer); + calloc.free(labelPointer); } diff --git a/oxen_coin/lib/src/native/transaction_history.dart b/oxen_coin/lib/src/native/transaction_history.dart index aebd9a81..6a80769a 100644 --- a/oxen_coin/lib/src/native/transaction_history.dart +++ b/oxen_coin/lib/src/native/transaction_history.dart @@ -4,7 +4,6 @@ import 'package:ffi/ffi.dart'; import 'package:oxen_coin/oxen_coin_structs.dart'; import 'package:oxen_coin/src/exceptions/creation_transaction_exception.dart'; import 'package:oxen_coin/src/oxen_api.dart'; -import 'package:oxen_coin/src/structs/ut8_box.dart'; import 'package:oxen_coin/src/util/signatures.dart'; import 'package:oxen_coin/src/util/types.dart'; @@ -34,47 +33,35 @@ final transactionEstimateFeeNative = oxenApi .asFunction(); PendingTransactionDescription createTransactionSync( - {String address, String amount, int priorityRaw, int accountIndex = 0}) { - final addressPointer = Utf8.toUtf8(address); - final amountPointer = amount != null ? Utf8.toUtf8(amount) : nullptr; - final errorMessagePointer = allocate(); - final pendingTransactionRawPointer = allocate(); - final created = transactionCreateNative( + {required String address, required String? amount, required int priorityRaw, int accountIndex = 0}) { + final addressPointer = address.toNativeUtf8(); + final amountPointer = amount != null ? amount.toNativeUtf8() : nullptr; + final pendingTransactionRawPointer = calloc(); + final result = transactionCreateNative( addressPointer, amountPointer, priorityRaw, accountIndex, - errorMessagePointer, - pendingTransactionRawPointer) != - 0; + pendingTransactionRawPointer); - free(addressPointer); + calloc.free(addressPointer); + if (amountPointer != nullptr) + calloc.free(amountPointer); - if (amountPointer != nullptr) { - free(amountPointer); - } - - if (!created) { - final message = errorMessagePointer.ref.getValue(); - free(errorMessagePointer); - throw CreationTransactionException(message: message); - } - - return PendingTransactionDescription( + if (result.good) + return PendingTransactionDescription( amount: pendingTransactionRawPointer.ref.amount, fee: pendingTransactionRawPointer.ref.fee, hash: pendingTransactionRawPointer.ref.getHash(), pointerAddress: pendingTransactionRawPointer.address); + + calloc.free(pendingTransactionRawPointer); + throw CreationTransactionException(message: result.errorString()); } -void commitTransaction({Pointer transactionPointer}) { - final errorMessagePointer = allocate(); - final isCommited = - transactionCommitNative(transactionPointer, errorMessagePointer) != 0; +void commitTransaction({required Pointer transactionPointer}) { + final result = transactionCommitNative(transactionPointer); - if (!isCommited) { - final message = errorMessagePointer.ref.getValue(); - free(errorMessagePointer); - throw CreationTransactionException(message: message); - } + if (!result.good) + throw CreationTransactionException(message: result.errorString()); } diff --git a/oxen_coin/lib/src/native/wallet.dart b/oxen_coin/lib/src/native/wallet.dart index 1285e026..0e224b8e 100644 --- a/oxen_coin/lib/src/native/wallet.dart +++ b/oxen_coin/lib/src/native/wallet.dart @@ -1,12 +1,10 @@ import 'dart:async'; import 'dart:ffi'; -import 'dart:typed_data'; import 'package:ffi/ffi.dart'; import 'package:flutter/services.dart'; import 'package:oxen_coin/src/exceptions/setup_wallet_exception.dart'; import 'package:oxen_coin/src/oxen_api.dart'; -import 'package:oxen_coin/src/util/convert_utf8_to_string.dart'; import 'package:oxen_coin/src/util/signatures.dart'; import 'package:oxen_coin/src/util/types.dart'; @@ -106,7 +104,7 @@ final getSecretSpendKeyNative = oxenApi .asFunction(); final getPublicSpendKeyNative = oxenApi - .lookup>('public_spend_key') + .lookup>('public_spend_key') .asFunction(); final closeCurrentWalletNative = oxenApi @@ -128,57 +126,52 @@ bool isRefreshingSync() => isRefreshingNative() != 0; bool isConnectedSync() => isConnectedNative() != 0; bool setupNodeSync( - {String address, - String login, - String password, + {required String address, + String? login, + String? password, bool useSSL = false, bool isLightWallet = false}) { - final addressPointer = Utf8.toUtf8(address); - Pointer loginPointer; - Pointer passwordPointer; + final addressPointer = address.toNativeUtf8(); + Pointer loginPointer = nullptr; + Pointer passwordPointer = nullptr; - if (login != null) { - loginPointer = Utf8.toUtf8(login); - } + if (login != null) + loginPointer = login.toNativeUtf8(); - if (password != null) { - passwordPointer = Utf8.toUtf8(password); - } + if (password != null) + passwordPointer = password.toNativeUtf8(); - final errorMessagePointer = allocate(); final isSetupNode = setupNodeNative( addressPointer, loginPointer, passwordPointer, _boolToInt(useSSL), - _boolToInt(isLightWallet), - errorMessagePointer) != - 0; + _boolToInt(isLightWallet)); - free(addressPointer); - free(loginPointer); - free(passwordPointer); + calloc.free(addressPointer); + if (loginPointer != nullptr) + calloc.free(loginPointer); + if (passwordPointer != nullptr) + calloc.free(passwordPointer); - if (!isSetupNode) { - throw SetupWalletException( - message: convertUTF8ToString(pointer: errorMessagePointer)); - } + if (isSetupNode.good) + return true; - return isSetupNode; + throw SetupWalletException(message: isSetupNode.errorString()); } void startRefreshSync() => startRefreshNative(); -Future connectToNode() async => connecToNodeNative() != 0; +Future connectToNode() async => connecToNodeNative().good; -void setRefreshFromBlockHeight({int height}) => +void setRefreshFromBlockHeight({required int height}) => setRefreshFromBlockHeightNative(height); -void setRecoveringFromSeed({bool isRecovery}) => +void setRecoveringFromSeed({required bool isRecovery}) => setRecoveringFromSeedNative(_boolToInt(isRecovery)); void storeSync() { - final pathPointer = Utf8.toUtf8(''); + final pathPointer = ''.toNativeUtf8(); storeNative(pathPointer); - free(pathPointer); + calloc.free(pathPointer); } diff --git a/oxen_coin/lib/src/native/wallet_manager.dart b/oxen_coin/lib/src/native/wallet_manager.dart index 4c74dff3..0ff39b88 100644 --- a/oxen_coin/lib/src/native/wallet_manager.dart +++ b/oxen_coin/lib/src/native/wallet_manager.dart @@ -1,7 +1,6 @@ import 'dart:ffi'; import 'package:ffi/ffi.dart'; import 'package:oxen_coin/src/oxen_api.dart'; -import 'package:oxen_coin/src/util/convert_utf8_to_string.dart'; import 'package:oxen_coin/src/util/signatures.dart'; import 'package:oxen_coin/src/util/types.dart'; import 'package:oxen_coin/src/exceptions/wallet_creation_exception.dart'; @@ -31,80 +30,69 @@ final loadWalletNative = oxenApi .asFunction(); void createWalletSync( - {String path, String password, String language, int nettype = 0}) { - final pathPointer = Utf8.toUtf8(path); - final passwordPointer = Utf8.toUtf8(password); - final languagePointer = Utf8.toUtf8(language); - final errorMessagePointer = allocate(); - final isWalletCreated = createWalletNative(pathPointer, passwordPointer, - languagePointer, nettype, errorMessagePointer) != - 0; - - free(pathPointer); - free(passwordPointer); - free(languagePointer); - - if (!isWalletCreated) { - throw WalletCreationException( - message: convertUTF8ToString(pointer: errorMessagePointer)); - } + {required String path, required String password, required String language, int nettype = 0}) { + final pathPointer = path.toNativeUtf8(); + final passwordPointer = password.toNativeUtf8(); + final languagePointer = language.toNativeUtf8(); + final result = createWalletNative(pathPointer, passwordPointer, languagePointer, nettype); + + calloc.free(pathPointer); + calloc.free(passwordPointer); + calloc.free(languagePointer); + + if (!result.good) + throw WalletCreationException(message: result.errorString()); } -bool isWalletExistSync({String path}) { - final pathPointer = Utf8.toUtf8(path); +bool isWalletExistSync({required String path}) { + final pathPointer = path.toNativeUtf8(); final isExist = isWalletExistNative(pathPointer) != 0; - free(pathPointer); + calloc.free(pathPointer); return isExist; } void restoreWalletFromSeedSync( - {String path, - String password, - String seed, + {required String path, + required String password, + required String seed, int nettype = 0, int restoreHeight = 0}) { - final pathPointer = Utf8.toUtf8(path); - final passwordPointer = Utf8.toUtf8(password); - final seedPointer = Utf8.toUtf8(seed); - final errorMessagePointer = allocate(); - final isWalletRestored = restoreWalletFromSeedNative( + final pathPointer = path.toNativeUtf8(); + final passwordPointer = password.toNativeUtf8(); + final seedPointer = seed.toNativeUtf8(); + final result = restoreWalletFromSeedNative( pathPointer, passwordPointer, seedPointer, nettype, - restoreHeight, - errorMessagePointer) != - 0; - - free(pathPointer); - free(passwordPointer); - free(seedPointer); - - if (!isWalletRestored) { - throw WalletRestoreFromSeedException( - message: convertUTF8ToString(pointer: errorMessagePointer)); - } + restoreHeight); + + calloc.free(pathPointer); + calloc.free(passwordPointer); + calloc.free(seedPointer); + + if (!result.good) + throw WalletRestoreFromSeedException(message: result.errorString()); } void restoreWalletFromKeysSync( - {String path, - String password, - String language, - String address, - String viewKey, - String spendKey, + {required String path, + required String password, + required String language, + required String address, + required String viewKey, + required String spendKey, int nettype = 0, int restoreHeight = 0}) { - final pathPointer = Utf8.toUtf8(path); - final passwordPointer = Utf8.toUtf8(password); - final languagePointer = Utf8.toUtf8(language); - final addressPointer = Utf8.toUtf8(address); - final viewKeyPointer = Utf8.toUtf8(viewKey); - final spendKeyPointer = Utf8.toUtf8(spendKey); - final errorMessagePointer = allocate(); - final isWalletRestored = restoreWalletFromKeysNative( + final pathPointer = path.toNativeUtf8(); + final passwordPointer = password.toNativeUtf8(); + final languagePointer = language.toNativeUtf8(); + final addressPointer = address.toNativeUtf8(); + final viewKeyPointer = viewKey.toNativeUtf8(); + final spendKeyPointer = spendKey.toNativeUtf8(); + final result = restoreWalletFromKeysNative( pathPointer, passwordPointer, languagePointer, @@ -112,19 +100,15 @@ void restoreWalletFromKeysSync( viewKeyPointer, spendKeyPointer, nettype, - restoreHeight, - errorMessagePointer) != - 0; - - free(pathPointer); - free(passwordPointer); - free(languagePointer); - free(addressPointer); - free(viewKeyPointer); - free(spendKeyPointer); - - if (!isWalletRestored) { - throw WalletRestoreFromKeysException( - message: convertUTF8ToString(pointer: errorMessagePointer)); - } + restoreHeight); + + calloc.free(pathPointer); + calloc.free(passwordPointer); + calloc.free(languagePointer); + calloc.free(addressPointer); + calloc.free(viewKeyPointer); + calloc.free(spendKeyPointer); + + if (!result.good) + throw WalletRestoreFromKeysException(message: result.errorString()); } diff --git a/oxen_coin/lib/src/structs/account_row.dart b/oxen_coin/lib/src/structs/account_row.dart index c3fc22de..5675e787 100644 --- a/oxen_coin/lib/src/structs/account_row.dart +++ b/oxen_coin/lib/src/structs/account_row.dart @@ -3,9 +3,10 @@ import 'package:ffi/ffi.dart'; class AccountRow extends Struct { @Int64() - int id; - Pointer label; + external int id; - String getLabel() => Utf8.fromUtf8(label); + external Pointer label; + + String getLabel() => label.toDartString(); int getId() => id; } diff --git a/oxen_coin/lib/src/structs/pending_transaction.dart b/oxen_coin/lib/src/structs/pending_transaction.dart index e25bd659..ed4027cf 100644 --- a/oxen_coin/lib/src/structs/pending_transaction.dart +++ b/oxen_coin/lib/src/structs/pending_transaction.dart @@ -3,19 +3,19 @@ import 'package:ffi/ffi.dart'; class PendingTransactionRaw extends Struct { @Int64() - int amount; + external int amount; @Int64() - int fee; + external int fee; - Pointer hash; + external Pointer hash; - String getHash() => Utf8.fromUtf8(hash); + String getHash() => hash.toDartString(); } class PendingTransactionDescription { PendingTransactionDescription( - {this.amount, this.fee, this.hash, this.pointerAddress}); + {required this.amount, required this.fee, required this.hash, required this.pointerAddress}); final int amount; final int fee; diff --git a/oxen_coin/lib/src/structs/stake_row.dart b/oxen_coin/lib/src/structs/stake_row.dart index aece5162..500bca5d 100644 --- a/oxen_coin/lib/src/structs/stake_row.dart +++ b/oxen_coin/lib/src/structs/stake_row.dart @@ -2,20 +2,19 @@ import 'dart:ffi'; import 'package:ffi/ffi.dart'; class StakeRowPointer extends Struct { - Pointer _serviceNodeKey; + external Pointer _serviceNodeKey; @Uint64() - int _amount; + external int _amount; - String get serviceNodeKey => Utf8.fromUtf8(_serviceNodeKey); + String get serviceNodeKey => _serviceNodeKey.toDartString(); int get amount => _amount; } class StakeRow { - StakeRow(StakeRowPointer pointer) { - amount = pointer.amount; + StakeRow(StakeRowPointer pointer) : + amount = pointer.amount, serviceNodeKey = pointer.serviceNodeKey; - } int amount; String serviceNodeKey; diff --git a/oxen_coin/lib/src/structs/status_and_error.dart b/oxen_coin/lib/src/structs/status_and_error.dart new file mode 100644 index 00000000..fbad0197 --- /dev/null +++ b/oxen_coin/lib/src/structs/status_and_error.dart @@ -0,0 +1,20 @@ +// ignore_for_file: camel_case_types + +import 'dart:ffi'; +import 'dart:convert'; + +class status_and_error extends Struct { + @Bool() + external bool good; + + @Array(1023) + external Array error; + + String errorString() { + final list = []; + for (var i = 0; error[i] != 0; i++) { + list.add(error[i]); + } + return utf8.decode(list); + } +} diff --git a/oxen_coin/lib/src/structs/subaddress_row.dart b/oxen_coin/lib/src/structs/subaddress_row.dart index 6c610e09..54e5d814 100644 --- a/oxen_coin/lib/src/structs/subaddress_row.dart +++ b/oxen_coin/lib/src/structs/subaddress_row.dart @@ -3,11 +3,11 @@ import 'package:ffi/ffi.dart'; class SubaddressRow extends Struct { @Int64() - int id; - Pointer address; - Pointer label; + external int id; + external Pointer address; + external Pointer label; - String getLabel() => Utf8.fromUtf8(label); - String getAddress() => Utf8.fromUtf8(address); + String getLabel() => label.toDartString(); + String getAddress() => address.toDartString(); int getId() => id; } diff --git a/oxen_coin/lib/src/structs/transaction_info_row.dart b/oxen_coin/lib/src/structs/transaction_info_row.dart index c6de6308..db49269c 100644 --- a/oxen_coin/lib/src/structs/transaction_info_row.dart +++ b/oxen_coin/lib/src/structs/transaction_info_row.dart @@ -4,36 +4,39 @@ import 'package:ffi/ffi.dart'; class TransactionInfoRow extends Struct { @Uint64() - int amount; + external int amount; @Uint64() - int fee; + external int fee; @Uint64() - int blockHeight; + external int blockHeight; @Uint64() - int confirmations; + external int confirmations; @Uint32() - int subaddrAccount; + external int subaddrAccount; @Int8() - int direction; + external int direction; @Int8() - int isPending; + external int isPending; - Pointer hash; + @Int8() + external int isStake; + + external Pointer hash; - Pointer paymentId; + external Pointer paymentId; @Int64() - int datetime; + external int datetime; int getDatetime() => datetime; int getAmount() => amount >= 0 ? amount : amount * -1; bool getIsPending() => isPending != 0; - String getHash() => Utf8.fromUtf8(hash); - String getPaymentId() => Utf8.fromUtf8(paymentId); + String getHash() => hash.toDartString(); + String getPaymentId() => paymentId.toDartString(); } diff --git a/oxen_coin/lib/src/structs/ut8_box.dart b/oxen_coin/lib/src/structs/ut8_box.dart deleted file mode 100644 index a6f41bc7..00000000 --- a/oxen_coin/lib/src/structs/ut8_box.dart +++ /dev/null @@ -1,8 +0,0 @@ -import 'dart:ffi'; -import 'package:ffi/ffi.dart'; - -class Utf8Box extends Struct { - Pointer value; - - String getValue() => Utf8.fromUtf8(value); -} diff --git a/oxen_coin/lib/src/util/convert_utf8_to_string.dart b/oxen_coin/lib/src/util/convert_utf8_to_string.dart index d7ac88d0..25ed88a3 100644 --- a/oxen_coin/lib/src/util/convert_utf8_to_string.dart +++ b/oxen_coin/lib/src/util/convert_utf8_to_string.dart @@ -2,8 +2,8 @@ import 'dart:ffi'; import 'package:ffi/ffi.dart'; -String convertUTF8ToString({Pointer pointer}) { - final str = Utf8.fromUtf8(pointer); - free(pointer); +String convertUTF8ToString({required Pointer pointer}) { + final str = pointer.toDartString(); + calloc.free(pointer); return str; } diff --git a/oxen_coin/lib/src/util/signatures.dart b/oxen_coin/lib/src/util/signatures.dart index 112dc3a4..19d5a9cd 100644 --- a/oxen_coin/lib/src/util/signatures.dart +++ b/oxen_coin/lib/src/util/signatures.dart @@ -1,16 +1,18 @@ +// ignore_for_file: camel_case_types + import 'dart:ffi'; import 'package:ffi/ffi.dart'; import 'package:oxen_coin/oxen_coin_structs.dart'; -import 'package:oxen_coin/src/structs/ut8_box.dart'; +import 'package:oxen_coin/src/structs/status_and_error.dart'; -typedef create_wallet = Int8 Function( - Pointer, Pointer, Pointer, Int32, Pointer); +typedef create_wallet = status_and_error Function( + Pointer, Pointer, Pointer, Int32); -typedef restore_wallet_from_seed = Int8 Function( - Pointer, Pointer, Pointer, Int32, Int64, Pointer); +typedef restore_wallet_from_seed = status_and_error Function( + Pointer, Pointer, Pointer, Int32, Int64); -typedef restore_wallet_from_keys = Int8 Function( +typedef restore_wallet_from_keys = status_and_error Function( Pointer, Pointer, Pointer, @@ -18,8 +20,7 @@ typedef restore_wallet_from_keys = Int8 Function( Pointer, Pointer, Int32, - Int64, - Pointer); + Int64); typedef is_wallet_exist = Int8 Function(Pointer); @@ -43,12 +44,12 @@ typedef is_refreshing = Int8 Function(); typedef is_connected = Int8 Function(); -typedef setup_node = Int8 Function( - Pointer, Pointer, Pointer, Int8, Int8, Pointer); +typedef setup_node = status_and_error Function( + Pointer, Pointer, Pointer, Int8, Int8); typedef start_refresh = Void Function(); -typedef connect_to_node = Int8 Function(); +typedef connect_to_node = status_and_error Function(); typedef set_refresh_from_block_height = Void Function(Int64); @@ -93,16 +94,14 @@ typedef transactions_count = Int64 Function(); typedef transactions_get_all = Pointer Function(); -typedef transaction_create = Int8 Function( +typedef transaction_create = status_and_error Function( Pointer address, Pointer amount, Int8 priorityRaw, Int32 subaddrAccount, - Pointer error, Pointer pendingTransaction); -typedef transaction_commit = Int8 Function( - Pointer, Pointer); +typedef transaction_commit = status_and_error Function(Pointer); typedef transaction_estimate_fee = Int64 Function(Int32, Int32); @@ -110,16 +109,15 @@ typedef stake_count = Int32 Function(); typedef stake_get_all = Pointer Function(); -typedef stake_create = Int8 Function( +typedef stake_create = status_and_error Function( Pointer serviceNodeKey, Pointer amount, - Pointer error, Pointer pendingTransaction); typedef can_request_unstake = Int8 Function(Pointer serviceNodeKey); -typedef submit_stake_unlock = Int8 Function(Pointer serviceNodeKey, - Pointer error, Pointer pendingTransaction); +typedef submit_stake_unlock = status_and_error Function(Pointer serviceNodeKey, + Pointer pendingTransaction); typedef secret_view_key = Pointer Function(); diff --git a/oxen_coin/lib/src/util/types.dart b/oxen_coin/lib/src/util/types.dart index 43ecc79a..0db12f0a 100644 --- a/oxen_coin/lib/src/util/types.dart +++ b/oxen_coin/lib/src/util/types.dart @@ -2,15 +2,15 @@ import 'dart:ffi'; import 'package:ffi/ffi.dart'; import 'package:oxen_coin/oxen_coin_structs.dart'; -import 'package:oxen_coin/src/structs/ut8_box.dart'; +import 'package:oxen_coin/src/structs/status_and_error.dart'; -typedef CreateWallet = int Function( - Pointer, Pointer, Pointer, int, Pointer); +typedef CreateWallet = status_and_error Function( + Pointer, Pointer, Pointer, int); -typedef RestoreWalletFromSeed = int Function( - Pointer, Pointer, Pointer, int, int, Pointer); +typedef RestoreWalletFromSeed = status_and_error Function( + Pointer, Pointer, Pointer, int, int); -typedef RestoreWalletFromKeys = int Function( +typedef RestoreWalletFromKeys = status_and_error Function( Pointer, Pointer, Pointer, @@ -18,8 +18,7 @@ typedef RestoreWalletFromKeys = int Function( Pointer, Pointer, int, - int, - Pointer); + int); typedef IsWalletExist = int Function(Pointer); @@ -43,12 +42,12 @@ typedef IsRefreshing = int Function(); typedef IsConnected = int Function(); -typedef SetupNode = int Function( - Pointer, Pointer, Pointer, int, int, Pointer); +typedef SetupNode = status_and_error Function( + Pointer, Pointer, Pointer, int, int); typedef StartRefresh = void Function(); -typedef ConnectToNode = int Function(); +typedef ConnectToNode = status_and_error Function(); typedef SetRefreshFromBlockHeight = void Function(int); @@ -91,16 +90,15 @@ typedef TransactionsCount = int Function(); typedef TransactionsGetAll = Pointer Function(); -typedef TransactionCreate = int Function( +typedef TransactionCreate = status_and_error Function( Pointer address, Pointer amount, int priorityRaw, int subaddrAccount, - Pointer error, Pointer pendingTransaction); -typedef TransactionCommit = int Function( - Pointer, Pointer); +typedef TransactionCommit = status_and_error Function( + Pointer); typedef TransactionEstimateFee = int Function(int priorityRaw, int recipients); @@ -108,16 +106,15 @@ typedef StakeCount = int Function(); typedef StakeGetAll = Pointer Function(); -typedef StakeCreate = int Function( +typedef StakeCreate = status_and_error Function( Pointer serviceNodeKey, Pointer amount, - Pointer error, Pointer pendingTransaction); typedef CanRequestUnstake = int Function(Pointer serviceNodeKey); -typedef SubmitStakeUnlock = int Function(Pointer serviceNodeKey, - Pointer error, Pointer pendingTransaction); +typedef SubmitStakeUnlock = status_and_error Function(Pointer serviceNodeKey, + Pointer pendingTransaction); typedef SecretViewKey = Pointer Function(); diff --git a/oxen_coin/lib/stake.dart b/oxen_coin/lib/stake.dart index 081404ff..453f178d 100644 --- a/oxen_coin/lib/stake.dart +++ b/oxen_coin/lib/stake.dart @@ -28,19 +28,21 @@ PendingTransactionDescription _createStakeSync(Map args) { } Future createStake( - String serviceNodeKey, String amount) => + String serviceNodeKey, String? amount) => compute(_createStakeSync, {'service_node_key': serviceNodeKey, 'amount': amount}); bool canRequestUnstake(String serviceNodeKey) { - final serviceNodeKeyPointer = Utf8.toUtf8(serviceNodeKey); - return stake_native.canRequestUnstakeNative(serviceNodeKeyPointer) != 0; + final serviceNodeKeyPointer = serviceNodeKey.toNativeUtf8(); + final result = stake_native.canRequestUnstakeNative(serviceNodeKeyPointer) != 0; + calloc.free(serviceNodeKeyPointer); + return result; } -PendingTransactionDescription _submitStakeUnlockSync(Map args) { +void _submitStakeUnlockSync(Map args) { final serviceNodeKey = args['service_node_key'] as String; - return stake_native.submitStakeUnlockSync(serviceNodeKey); + stake_native.submitStakeUnlockSync(serviceNodeKey); } -Future submitStakeUnlock(String serviceNodeKey) => +Future submitStakeUnlock(String serviceNodeKey) => compute(_submitStakeUnlockSync, {'service_node_key': serviceNodeKey}); diff --git a/oxen_coin/lib/subaddress_list.dart b/oxen_coin/lib/subaddress_list.dart index d426a6e2..455d2338 100644 --- a/oxen_coin/lib/subaddress_list.dart +++ b/oxen_coin/lib/subaddress_list.dart @@ -4,7 +4,7 @@ import 'package:flutter/foundation.dart'; import 'package:oxen_coin/src/native/subaddress_list.dart' as subaddress_list; import 'package:oxen_coin/oxen_coin_structs.dart'; -void refreshSubaddresses({int accountIndex}) => +void refreshSubaddresses({required int accountIndex}) => subaddress_list.subaddressRefreshNative(accountIndex); List getAllSubaddresses() { @@ -33,12 +33,12 @@ void _setLabelForSubaddress(Map args) { accountIndex: accountIndex, addressIndex: addressIndex, label: label); } -Future addSubaddress({int accountIndex, String label}) async => +Future addSubaddress({required int accountIndex, required String label}) async => compute, void>( _addSubaddress, {'accountIndex': accountIndex, 'label': label}); Future setLabelForSubaddress( - {int accountIndex, int addressIndex, String label}) => + {required int accountIndex, required int addressIndex, required String label}) => compute, void>(_setLabelForSubaddress, { 'accountIndex': accountIndex, 'addressIndex': addressIndex, diff --git a/oxen_coin/lib/transaction_history.dart b/oxen_coin/lib/transaction_history.dart index f92cca03..fea7459d 100644 --- a/oxen_coin/lib/transaction_history.dart +++ b/oxen_coin/lib/transaction_history.dart @@ -22,14 +22,14 @@ List getAllTransactions() { .toList(); } -void commitTransactionFromPointerAddress({int address}) => +void commitTransactionFromPointerAddress({required int address}) => transaction_history.commitTransaction( transactionPointer: Pointer.fromAddress(address)); PendingTransactionDescription _createTransactionSync(Map args) { final address = args['address'] as String; - final amount = args['amount'] as String; + final amount = args['amount'] as String?; final priorityRaw = args['priorityRaw'] as int; final accountIndex = args['accountIndex'] as int; @@ -41,12 +41,12 @@ PendingTransactionDescription _createTransactionSync(Map args) { } Future createTransaction( - {String address, - String amount, - int priorityRaw, + {required String recipient, + required String? amount, + required int priorityRaw, int accountIndex = 0}) => compute(_createTransactionSync, { - 'address': address, + 'address': recipient, 'amount': amount, 'priorityRaw': priorityRaw, 'accountIndex': accountIndex diff --git a/oxen_coin/lib/wallet.dart b/oxen_coin/lib/wallet.dart index e767838a..92116709 100644 --- a/oxen_coin/lib/wallet.dart +++ b/oxen_coin/lib/wallet.dart @@ -1,6 +1,4 @@ import 'dart:async'; -import 'dart:ffi'; -import 'dart:typed_data'; import 'package:ffi/ffi.dart'; import 'package:flutter/foundation.dart'; @@ -52,53 +50,41 @@ bool isRefreshingSync() => oxen_wallet.isRefreshingNative() != 0; bool isConnectedSync() => oxen_wallet.isConnectedNative() != 0; bool setupNodeSync( - {String address, - String login, - String password, + {required String address, + String? login, + String? password, bool useSSL = false, bool isLightWallet = false}) { - final addressPointer = Utf8.toUtf8(address); - Pointer loginPointer; - Pointer passwordPointer; + final addressPointer = address.toNativeUtf8(); + final loginPointer = (login ?? '').toNativeUtf8(); + final passwordPointer = (password ?? '').toNativeUtf8(); - if (login != null) { - loginPointer = Utf8.toUtf8(login); - } - - if (password != null) { - passwordPointer = Utf8.toUtf8(password); - } - - final errorMessagePointer = allocate(); final isSetupNode = oxen_wallet.setupNodeNative( addressPointer, loginPointer, passwordPointer, _boolToInt(useSSL), - _boolToInt(isLightWallet), - errorMessagePointer) != - 0; + _boolToInt(isLightWallet)); - free(addressPointer); - free(loginPointer); - free(passwordPointer); + calloc.free(addressPointer); + calloc.free(loginPointer); + calloc.free(passwordPointer); - if (!isSetupNode) { - throw SetupWalletException( - message: convertUTF8ToString(pointer: errorMessagePointer)); + if (!isSetupNode.good) { + throw SetupWalletException(message: isSetupNode.errorString()); } - return isSetupNode; + return true; } void startRefreshSync() => oxen_wallet.startRefreshNative(); -Future connectToNode() async => oxen_wallet.connecToNodeNative() != 0; +Future connectToNode() async => oxen_wallet.connecToNodeNative().good; -void setRefreshFromBlockHeight({int height}) => +void setRefreshFromBlockHeight({required int height}) => oxen_wallet.setRefreshFromBlockHeightNative(height); -void setRecoveringFromSeed({bool isRecovery}) => +void setRecoveringFromSeed({required bool isRecovery}) => oxen_wallet.setRecoveringFromSeedNative(_boolToInt(isRecovery)); void closeCurrentWallet() => oxen_wallet.closeCurrentWalletNative(); @@ -116,19 +102,15 @@ String getPublicSpendKey() => convertUTF8ToString(pointer: oxen_wallet.getPublicSpendKeyNative()); class SyncListener { - SyncListener(this.onNewBlock, this.onNewTransaction) { - _cachedBlockchainHeight = 0; - _lastKnownBlockHeight = 0; - _initialSyncHeight = 0; - } + SyncListener(this.onNewBlock, this.onNewTransaction); void Function(int, int, double, bool) onNewBlock; void Function() onNewTransaction; - Timer _updateSyncInfoTimer; - int _cachedBlockchainHeight; - int _lastKnownBlockHeight; - int _initialSyncHeight; + Timer? _updateSyncInfoTimer; + int _cachedBlockchainHeight = 0; + int _lastKnownBlockHeight = 0; + int _initialSyncHeight = 0; Future getNodeHeightOrUpdate(int baseHeight) async { if (_cachedBlockchainHeight < baseHeight || _cachedBlockchainHeight == 0) { @@ -158,7 +140,7 @@ class SyncListener { final bchHeight = await getNodeHeightOrUpdate(syncHeight); - if (_lastKnownBlockHeight == syncHeight || syncHeight == null) { + if (_lastKnownBlockHeight == syncHeight) { return; } @@ -175,12 +157,12 @@ class SyncListener { final refreshing = isRefreshing(); if (!refreshing) { if (isNewTransactionExist()) { - onNewTransaction?.call(); + onNewTransaction.call(); } } // 1. Actual new height; 2. Blocks left to finish; 3. Progress in percents; - onNewBlock?.call(syncHeight, left, ptc, refreshing); + onNewBlock.call(syncHeight, left, ptc, refreshing); }); } @@ -222,15 +204,19 @@ int _getNodeHeight(Object _) => getNodeHeightSync(); void startRefresh() => startRefreshSync(); Future setupNode( - {String address, - String login, - String password, + {required String address, + /* + required String login, + required String password, + */ bool useSSL = false, bool isLightWallet = false}) => compute, void>(_setupNodeSync, { 'address': address, + /* 'login': login, 'password': password, + */ 'useSSL': useSSL, 'isLightWallet': isLightWallet }); diff --git a/oxen_coin/lib/wallet_manager.dart b/oxen_coin/lib/wallet_manager.dart index 30b6868c..3ed20da7 100644 --- a/oxen_coin/lib/wallet_manager.dart +++ b/oxen_coin/lib/wallet_manager.dart @@ -2,13 +2,13 @@ import 'package:ffi/ffi.dart'; import 'package:flutter/foundation.dart'; import 'package:oxen_coin/src/native/wallet_manager.dart' as wallet_manager; -void loadWallet({String path, String password, int nettype = 0}) { - final pathPointer = Utf8.toUtf8(path); - final passwordPointer = Utf8.toUtf8(password); +void loadWallet({required String path, required String password, int nettype = 0}) { + final pathPointer = path.toNativeUtf8(); + final passwordPointer = password.toNativeUtf8(); wallet_manager.loadWalletNative(pathPointer, passwordPointer, nettype); - free(pathPointer); - free(passwordPointer); + calloc.free(pathPointer); + calloc.free(passwordPointer); } void _createWallet(Map args) { @@ -58,21 +58,21 @@ void _restoreFromKeys(Map args) { } Future _openWallet(Map args) async => - loadWallet(path: args['path'], password: args['password']); + loadWallet(path: args['path'] as String, password: args['password'] as String); bool _isWalletExist(String path) => wallet_manager.isWalletExistSync(path: path); -void openWallet({String path, String password, int nettype = 0}) async => +void openWallet({required String path, required String password, int nettype = 0}) async => loadWallet(path: path, password: password, nettype: nettype); Future openWalletAsync(Map args) async => compute(_openWallet, args); Future createWallet( - {String path, - String password, - String language, + {required String path, + required String password, + required String language, int nettype = 0}) async => compute(_createWallet, { 'path': path, @@ -82,9 +82,9 @@ Future createWallet( }); Future restoreFromSeed( - {String path, - String password, - String seed, + {required String path, + required String password, + required String seed, int nettype = 0, int restoreHeight = 0}) async => compute, void>(_restoreFromSeed, { @@ -96,12 +96,12 @@ Future restoreFromSeed( }); Future restoreFromKeys( - {String path, - String password, - String language, - String address, - String viewKey, - String spendKey, + {required String path, + required String password, + required String language, + required String address, + required String viewKey, + required String spendKey, int nettype = 0, int restoreHeight = 0}) async => compute, void>(_restoreFromKeys, { @@ -115,4 +115,4 @@ Future restoreFromKeys( 'restoreHeight': restoreHeight }); -Future isWalletExist({String path}) => compute(_isWalletExist, path); +Future isWalletExist({required String path}) => compute(_isWalletExist, path); diff --git a/oxen_coin/pubspec.yaml b/oxen_coin/pubspec.yaml index 36fe914c..89279d84 100644 --- a/oxen_coin/pubspec.yaml +++ b/oxen_coin/pubspec.yaml @@ -2,13 +2,13 @@ name: oxen_coin version: 0.0.1 environment: - sdk: ">=2.7.0 <3.0.0" - flutter: ">=1.12.13+hotfix.6 <2.0.0" + sdk: ">=2.12.0 <3.0.0" + #flutter: ">=1.12.13+hotfix.6 <2.0.0" dependencies: flutter: sdk: flutter - ffi: ^0.1.3 + ffi: ^1.1.2 dev_dependencies: flutter_test: @@ -21,4 +21,4 @@ flutter: package: io.oxen.coin pluginClass: OxenCoinPlugin ios: - pluginClass: OxenCoinPlugin \ No newline at end of file + pluginClass: OxenCoinPlugin diff --git a/pubspec.lock b/pubspec.lock index d34fb6e2..7a2938d1 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -7,63 +7,63 @@ packages: name: _fe_analyzer_shared url: "https://pub.dartlang.org" source: hosted - version: "14.0.0" + version: "38.0.0" analyzer: dependency: transitive description: name: analyzer url: "https://pub.dartlang.org" source: hosted - version: "0.41.2" + version: "3.4.1" archive: dependency: transitive description: name: archive url: "https://pub.dartlang.org" source: hosted - version: "3.1.2" + version: "3.3.0" args: dependency: transitive description: name: args url: "https://pub.dartlang.org" source: hosted - version: "2.0.0" + version: "2.3.0" asn1lib: dependency: transitive description: name: asn1lib url: "https://pub.dartlang.org" source: hosted - version: "1.0.0" + version: "1.1.0" async: dependency: transitive description: name: async url: "https://pub.dartlang.org" source: hosted - version: "2.5.0" + version: "2.8.2" auto_size_text: dependency: "direct main" description: name: auto_size_text url: "https://pub.dartlang.org" source: hosted - version: "2.1.0" - barcode_scan: + version: "3.0.0" + barcode_scan2: dependency: "direct main" description: - name: barcode_scan + name: barcode_scan2 url: "https://pub.dartlang.org" source: hosted - version: "2.0.2" + version: "4.2.0" basic_utils: dependency: "direct main" description: name: basic_utils url: "https://pub.dartlang.org" source: hosted - version: "3.0.0-nullsafety.3" + version: "4.2.0" boolean_selector: dependency: transitive description: @@ -77,84 +77,77 @@ packages: name: build url: "https://pub.dartlang.org" source: hosted - version: "1.6.2" + version: "2.2.1" build_config: dependency: transitive description: name: build_config url: "https://pub.dartlang.org" source: hosted - version: "0.4.6" + version: "1.0.0" build_daemon: dependency: transitive description: name: build_daemon url: "https://pub.dartlang.org" source: hosted - version: "2.1.10" + version: "3.0.1" build_resolvers: dependency: "direct dev" description: name: build_resolvers url: "https://pub.dartlang.org" source: hosted - version: "1.5.3" + version: "2.0.6" build_runner: dependency: "direct dev" description: name: build_runner url: "https://pub.dartlang.org" source: hosted - version: "1.11.5" + version: "2.1.8" build_runner_core: dependency: transitive description: name: build_runner_core url: "https://pub.dartlang.org" source: hosted - version: "6.1.10" + version: "7.2.3" built_collection: dependency: transitive description: name: built_collection url: "https://pub.dartlang.org" source: hosted - version: "5.0.0" + version: "5.1.1" built_value: dependency: transitive description: name: built_value url: "https://pub.dartlang.org" source: hosted - version: "8.0.4" + version: "8.1.4" characters: dependency: transitive description: name: characters url: "https://pub.dartlang.org" source: hosted - version: "1.1.0" + version: "1.2.0" charcode: dependency: transitive description: name: charcode url: "https://pub.dartlang.org" source: hosted - version: "1.2.0" + version: "1.3.1" checked_yaml: dependency: transitive description: name: checked_yaml url: "https://pub.dartlang.org" source: hosted - version: "1.0.4" - cli_util: - dependency: transitive - description: - name: cli_util - url: "https://pub.dartlang.org" - source: hosted - version: "0.3.0" + version: "2.0.1" clock: dependency: transitive description: @@ -168,7 +161,7 @@ packages: name: code_builder url: "https://pub.dartlang.org" source: hosted - version: "3.7.0" + version: "4.1.0" collection: dependency: transitive description: @@ -182,7 +175,7 @@ packages: name: convert url: "https://pub.dartlang.org" source: hosted - version: "3.0.0" + version: "3.0.1" crypto: dependency: transitive description: @@ -196,56 +189,35 @@ packages: name: cupertino_icons url: "https://pub.dartlang.org" source: hosted - version: "1.0.2" + version: "1.0.4" dart_style: dependency: transitive description: name: dart_style url: "https://pub.dartlang.org" source: hosted - version: "1.3.12" - dartx: - dependency: transitive - description: - name: dartx - url: "https://pub.dartlang.org" - source: hosted - version: "0.7.1" - date_range_picker: - dependency: "direct main" - description: - name: date_range_picker - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.7" + version: "2.2.2" devicelocale: dependency: "direct main" description: name: devicelocale url: "https://pub.dartlang.org" source: hosted - version: "0.4.1" + version: "0.5.0" dio: dependency: "direct main" description: name: dio url: "https://pub.dartlang.org" source: hosted - version: "4.0.0" + version: "4.0.6" encrypt: dependency: "direct main" description: name: encrypt url: "https://pub.dartlang.org" source: hosted - version: "5.0.0" - esys_flutter_share: - dependency: "direct main" - description: - name: esys_flutter_share - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.2" + version: "5.0.1" fake_async: dependency: transitive description: @@ -259,14 +231,14 @@ packages: name: ffi url: "https://pub.dartlang.org" source: hosted - version: "0.1.3" + version: "1.1.2" file: dependency: transitive description: name: file url: "https://pub.dartlang.org" source: hosted - version: "6.1.0" + version: "6.1.2" fixnum: dependency: transitive description: @@ -292,7 +264,7 @@ packages: name: flutter_launcher_icons url: "https://pub.dartlang.org" source: hosted - version: "0.9.0" + version: "0.9.2" flutter_localizations: dependency: "direct main" description: flutter @@ -304,28 +276,63 @@ packages: name: flutter_mobx url: "https://pub.dartlang.org" source: hosted - version: "1.1.0+2" + version: "2.0.4" flutter_plugin_android_lifecycle: dependency: transitive description: name: flutter_plugin_android_lifecycle url: "https://pub.dartlang.org" source: hosted - version: "2.0.1" + version: "2.0.5" flutter_secure_storage: dependency: "direct main" description: name: flutter_secure_storage url: "https://pub.dartlang.org" source: hosted - version: "4.1.0" + version: "5.0.2" + flutter_secure_storage_linux: + dependency: transitive + description: + name: flutter_secure_storage_linux + url: "https://pub.dartlang.org" + source: hosted + version: "1.1.0" + flutter_secure_storage_macos: + dependency: transitive + description: + name: flutter_secure_storage_macos + url: "https://pub.dartlang.org" + source: hosted + version: "1.1.0" + flutter_secure_storage_platform_interface: + dependency: transitive + description: + name: flutter_secure_storage_platform_interface + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.0" + flutter_secure_storage_web: + dependency: transitive + description: + name: flutter_secure_storage_web + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.2" + flutter_secure_storage_windows: + dependency: transitive + description: + name: flutter_secure_storage_windows + url: "https://pub.dartlang.org" + source: hosted + version: "1.1.2" flutter_slidable: dependency: "direct main" description: name: flutter_slidable url: "https://pub.dartlang.org" source: hosted - version: "0.5.7" + version: "1.2.0" flutter_test: dependency: "direct dev" description: flutter @@ -336,55 +343,62 @@ packages: description: flutter source: sdk version: "0.0.0" + frontend_server_client: + dependency: transitive + description: + name: frontend_server_client + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.2" glob: dependency: transitive description: name: glob url: "https://pub.dartlang.org" source: hosted - version: "2.0.1" + version: "2.0.2" graphs: dependency: transitive description: name: graphs url: "https://pub.dartlang.org" source: hosted - version: "0.2.0" + version: "2.1.0" hive: dependency: "direct main" description: name: hive url: "https://pub.dartlang.org" source: hosted - version: "1.6.0-nullsafety.2" + version: "2.1.0" hive_flutter: dependency: "direct main" description: name: hive_flutter url: "https://pub.dartlang.org" source: hosted - version: "0.3.1" + version: "1.1.0" hive_generator: dependency: "direct dev" description: name: hive_generator url: "https://pub.dartlang.org" source: hosted - version: "0.8.2" + version: "1.1.2" http: dependency: "direct main" description: name: http url: "https://pub.dartlang.org" source: hosted - version: "0.13.1" + version: "0.13.4" http_multi_server: dependency: transitive description: name: http_multi_server url: "https://pub.dartlang.org" source: hosted - version: "2.2.0" + version: "3.2.0" http_parser: dependency: transitive description: @@ -398,7 +412,7 @@ packages: name: image url: "https://pub.dartlang.org" source: hosted - version: "3.0.2" + version: "3.1.3" intl: dependency: "direct main" description: @@ -412,7 +426,7 @@ packages: name: io url: "https://pub.dartlang.org" source: hosted - version: "0.3.5" + version: "1.0.3" js: dependency: transitive description: @@ -426,56 +440,63 @@ packages: name: json_annotation url: "https://pub.dartlang.org" source: hosted - version: "4.0.1" + version: "4.4.0" local_auth: dependency: "direct main" description: name: local_auth url: "https://pub.dartlang.org" source: hosted - version: "1.1.2" + version: "1.1.11" logging: dependency: transitive description: name: logging url: "https://pub.dartlang.org" source: hosted - version: "1.0.1" + version: "1.0.2" matcher: dependency: transitive description: name: matcher url: "https://pub.dartlang.org" source: hosted - version: "0.12.10" + version: "0.12.11" + material_color_utilities: + dependency: transitive + description: + name: material_color_utilities + url: "https://pub.dartlang.org" + source: hosted + version: "0.1.3" meta: dependency: transitive description: name: meta url: "https://pub.dartlang.org" source: hosted - version: "1.3.0" + version: "1.7.0" mime: dependency: transitive description: name: mime url: "https://pub.dartlang.org" source: hosted - version: "1.0.0" + version: "1.0.1" mobx: dependency: "direct main" description: name: mobx url: "https://pub.dartlang.org" source: hosted - version: "1.2.1+4" + version: "2.0.6+1" mobx_codegen: dependency: "direct dev" description: name: mobx_codegen url: "https://pub.dartlang.org" source: hosted - version: "1.1.2" + version: "2.0.5+2" nested: dependency: transitive description: @@ -496,14 +517,14 @@ packages: name: package_config url: "https://pub.dartlang.org" source: hosted - version: "1.9.3" + version: "2.0.2" package_info: dependency: "direct main" description: name: package_info url: "https://pub.dartlang.org" source: hosted - version: "2.0.0" + version: "2.0.2" path: dependency: transitive description: @@ -517,70 +538,84 @@ packages: name: path_provider url: "https://pub.dartlang.org" source: hosted - version: "1.6.28" + version: "2.0.9" + path_provider_android: + dependency: transitive + description: + name: path_provider_android + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.12" + path_provider_ios: + dependency: transitive + description: + name: path_provider_ios + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.8" path_provider_linux: dependency: transitive description: name: path_provider_linux url: "https://pub.dartlang.org" source: hosted - version: "0.0.1+2" + version: "2.1.5" path_provider_macos: dependency: transitive description: name: path_provider_macos url: "https://pub.dartlang.org" source: hosted - version: "0.0.4+8" + version: "2.0.5" path_provider_platform_interface: dependency: transitive description: name: path_provider_platform_interface url: "https://pub.dartlang.org" source: hosted - version: "1.0.4" + version: "2.0.3" path_provider_windows: dependency: transitive description: name: path_provider_windows url: "https://pub.dartlang.org" source: hosted - version: "0.0.4+3" + version: "2.0.5" pedantic: dependency: "direct dev" description: name: pedantic url: "https://pub.dartlang.org" source: hosted - version: "1.11.0" + version: "1.11.1" petitparser: dependency: transitive description: name: petitparser url: "https://pub.dartlang.org" source: hosted - version: "4.0.2" + version: "4.4.0" platform: dependency: transitive description: name: platform url: "https://pub.dartlang.org" source: hosted - version: "3.0.0" + version: "3.1.0" plugin_platform_interface: dependency: transitive description: name: plugin_platform_interface url: "https://pub.dartlang.org" source: hosted - version: "1.0.3" + version: "2.1.2" pointycastle: dependency: transitive description: name: pointycastle url: "https://pub.dartlang.org" source: hosted - version: "3.0.1" + version: "3.5.2" pool: dependency: transitive description: @@ -594,98 +629,168 @@ packages: name: process url: "https://pub.dartlang.org" source: hosted - version: "4.2.1" + version: "4.2.4" + protobuf: + dependency: transitive + description: + name: protobuf + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.1" provider: dependency: "direct main" description: name: provider url: "https://pub.dartlang.org" source: hosted - version: "5.0.0" + version: "6.0.2" pub_semver: dependency: transitive description: name: pub_semver url: "https://pub.dartlang.org" source: hosted - version: "2.0.0" + version: "2.1.1" pubspec_parse: dependency: transitive description: name: pubspec_parse url: "https://pub.dartlang.org" source: hosted - version: "0.1.8" + version: "1.2.0" qr: - dependency: "direct main" + dependency: transitive description: name: qr url: "https://pub.dartlang.org" source: hosted - version: "2.0.0" + version: "2.1.0" + qr_flutter: + dependency: "direct main" + description: + name: qr_flutter + url: "https://pub.dartlang.org" + source: hosted + version: "4.0.0" rxdart: dependency: "direct main" description: name: rxdart url: "https://pub.dartlang.org" source: hosted - version: "0.22.6" + version: "0.27.3" + share_plus: + dependency: "direct main" + description: + name: share_plus + url: "https://pub.dartlang.org" + source: hosted + version: "4.0.3" + share_plus_linux: + dependency: transitive + description: + name: share_plus_linux + url: "https://pub.dartlang.org" + source: hosted + version: "3.0.0" + share_plus_macos: + dependency: transitive + description: + name: share_plus_macos + url: "https://pub.dartlang.org" + source: hosted + version: "3.0.0" + share_plus_platform_interface: + dependency: transitive + description: + name: share_plus_platform_interface + url: "https://pub.dartlang.org" + source: hosted + version: "3.0.2" + share_plus_web: + dependency: transitive + description: + name: share_plus_web + url: "https://pub.dartlang.org" + source: hosted + version: "3.0.0" + share_plus_windows: + dependency: transitive + description: + name: share_plus_windows + url: "https://pub.dartlang.org" + source: hosted + version: "3.0.0" shared_preferences: dependency: "direct main" description: name: shared_preferences url: "https://pub.dartlang.org" source: hosted - version: "0.5.12+4" + version: "2.0.13" + shared_preferences_android: + dependency: transitive + description: + name: shared_preferences_android + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.11" + shared_preferences_ios: + dependency: transitive + description: + name: shared_preferences_ios + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.0" shared_preferences_linux: dependency: transitive description: name: shared_preferences_linux url: "https://pub.dartlang.org" source: hosted - version: "0.0.2+4" + version: "2.1.0" shared_preferences_macos: dependency: transitive description: name: shared_preferences_macos url: "https://pub.dartlang.org" source: hosted - version: "0.0.1+11" + version: "2.0.3" shared_preferences_platform_interface: dependency: transitive description: name: shared_preferences_platform_interface url: "https://pub.dartlang.org" source: hosted - version: "1.0.4" + version: "2.0.0" shared_preferences_web: dependency: transitive description: name: shared_preferences_web url: "https://pub.dartlang.org" source: hosted - version: "0.1.2+7" + version: "2.0.3" shared_preferences_windows: dependency: transitive description: name: shared_preferences_windows url: "https://pub.dartlang.org" source: hosted - version: "0.0.2+3" + version: "2.1.0" shelf: dependency: transitive description: name: shelf url: "https://pub.dartlang.org" source: hosted - version: "1.1.0" + version: "1.3.0" shelf_web_socket: dependency: transitive description: name: shelf_web_socket url: "https://pub.dartlang.org" source: hosted - version: "0.2.4+1" + version: "1.0.1" sky_engine: dependency: transitive description: flutter @@ -697,14 +802,21 @@ packages: name: source_gen url: "https://pub.dartlang.org" source: hosted - version: "0.9.10+3" + version: "1.2.1" + source_helper: + dependency: transitive + description: + name: source_helper + url: "https://pub.dartlang.org" + source: hosted + version: "1.3.1" source_span: dependency: transitive description: name: source_span url: "https://pub.dartlang.org" source: hosted - version: "1.8.0" + version: "1.8.1" stack_trace: dependency: transitive description: @@ -733,6 +845,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.1.0" + synchronized: + dependency: "direct main" + description: + name: synchronized + url: "https://pub.dartlang.org" + source: hosted + version: "3.0.0+2" term_glyph: dependency: transitive description: @@ -746,21 +865,14 @@ packages: name: test_api url: "https://pub.dartlang.org" source: hosted - version: "0.2.19" - time: - dependency: transitive - description: - name: time - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.0" + version: "0.4.8" timing: dependency: transitive description: name: timing url: "https://pub.dartlang.org" source: hosted - version: "0.1.1+3" + version: "1.0.0" typed_data: dependency: transitive description: @@ -774,91 +886,105 @@ packages: name: url_launcher url: "https://pub.dartlang.org" source: hosted - version: "6.0.3" + version: "6.0.20" + url_launcher_android: + dependency: transitive + description: + name: url_launcher_android + url: "https://pub.dartlang.org" + source: hosted + version: "6.0.15" + url_launcher_ios: + dependency: transitive + description: + name: url_launcher_ios + url: "https://pub.dartlang.org" + source: hosted + version: "6.0.15" url_launcher_linux: dependency: transitive description: name: url_launcher_linux url: "https://pub.dartlang.org" source: hosted - version: "2.0.0" + version: "3.0.0" url_launcher_macos: dependency: transitive description: name: url_launcher_macos url: "https://pub.dartlang.org" source: hosted - version: "2.0.0" + version: "3.0.0" url_launcher_platform_interface: dependency: transitive description: name: url_launcher_platform_interface url: "https://pub.dartlang.org" source: hosted - version: "2.0.1" + version: "2.0.5" url_launcher_web: dependency: transitive description: name: url_launcher_web url: "https://pub.dartlang.org" source: hosted - version: "2.0.0" + version: "2.0.9" url_launcher_windows: dependency: transitive description: name: url_launcher_windows url: "https://pub.dartlang.org" source: hosted - version: "2.0.0" + version: "3.0.0" uuid: dependency: "direct main" description: name: uuid url: "https://pub.dartlang.org" source: hosted - version: "3.0.3" + version: "3.0.6" vector_math: dependency: transitive description: name: vector_math url: "https://pub.dartlang.org" source: hosted - version: "2.1.0" + version: "2.1.1" watcher: dependency: transitive description: name: watcher url: "https://pub.dartlang.org" source: hosted - version: "1.0.0" + version: "1.0.1" web_socket_channel: dependency: transitive description: name: web_socket_channel url: "https://pub.dartlang.org" source: hosted - version: "1.2.0" + version: "2.1.0" win32: dependency: transitive description: name: win32 url: "https://pub.dartlang.org" source: hosted - version: "1.7.4+1" + version: "2.5.1" xdg_directories: dependency: transitive description: name: xdg_directories url: "https://pub.dartlang.org" source: hosted - version: "0.1.2" + version: "0.2.0+1" xml: dependency: transitive description: name: xml url: "https://pub.dartlang.org" source: hosted - version: "5.0.2" + version: "5.3.1" yaml: dependency: "direct main" description: @@ -867,5 +993,5 @@ packages: source: hosted version: "3.1.0" sdks: - dart: ">=2.12.0 <3.0.0" - flutter: ">=1.26.0-17.6.pre" + dart: ">=2.16.0 <3.0.0" + flutter: ">=2.10.0" diff --git a/pubspec.yaml b/pubspec.yaml index e7e6f9d7..a2e7a741 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,5 +1,6 @@ name: oxen_wallet description: A Wallet for Oxen. +publish_to: none # The following defines the version and build number for your application. # A version number is three numbers separated by dots, like 1.2.43 @@ -11,13 +12,13 @@ description: A Wallet for Oxen. # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. # Read more about iOS versioning at # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html -version: 1.0.7+9 +version: 1.0.8+10 # keytool -genkey -v -keystore c:\Users\konst\key.jks -storetype JKS -keyalg RSA -keysize 2048 -validity 10000 -alias key environment: - sdk: ">=2.7.0 <3.0.0" + sdk: ">=2.12.0 <3.0.0" flutter: ">=1.22.6" dependencies: @@ -27,47 +28,45 @@ dependencies: sdk: flutter flutter_cupertino_localizations: ^1.0.1 intl: ^0.17.0 - url_launcher: ^6.0.3 - qr: ^2.0.0 + url_launcher: ^6.0.20 + qr_flutter: ^4.0.0 uuid: ^3.0.3 - shared_preferences: ^0.5.12+4 - flutter_secure_storage: ^4.1.0 - provider: ^5.0.0 - rxdart: ^0.22.2 + shared_preferences: ^2.0.13 + flutter_secure_storage: ^5.0.2 + provider: ^6.0.2 + rxdart: ^0.27.3 yaml: ^3.1.0 - barcode_scan: any # outdated and should be replaced + barcode_scan2: ^4.2.0 http: ^0.13.1 - path_provider: ^1.6.28 - mobx: ^1.2.1+1 - flutter_mobx: ^1.1.0+2 - flutter_slidable: ^0.5.7 - # share: ^0.6.2+1 - esys_flutter_share: ^1.0.2 - date_range_picker: ^1.0.7 + path_provider: ^2.0.9 + mobx: ^2.0.6 + flutter_mobx: ^2.0.4 + flutter_slidable: ^1.2.0 + share_plus: ^4.0.3 dio: ^4.0.0 oxen_coin: path: ./oxen_coin - hive: ^1.4.4+1 - hive_flutter: ^0.3.1 + hive: ^2.1.0 + hive_flutter: ^1.1.0 local_auth: ^1.1.0 package_info: ^2.0.0 - devicelocale: ^0.4.1 - auto_size_text: ^2.1.0 + devicelocale: ^0.5.0 + auto_size_text: ^3.0.0 synchronized: ^3.0.0 # The following adds the Cupertino Icons font to your application. # Use with the CupertinoIcons class for iOS style icons. cupertino_icons: ^1.0.2 encrypt: ^5.0.0 - basic_utils: ^3.0.0-nullsafety.3 + basic_utils: ^4.2.0 dev_dependencies: flutter_test: sdk: flutter - build_runner: ^1.10.11 - build_resolvers: ^1.5.1 - mobx_codegen: ^1.1.0+1 - hive_generator: ^0.8.1 + build_runner: ^2.1.8 + build_resolvers: ^2.0.6 + mobx_codegen: ^2.0.5+2 + hive_generator: ^1.1.2 flutter_launcher_icons: ^0.9.0 pedantic: ^1.8.0 @@ -92,6 +91,8 @@ flutter: # the material Icons class. uses-material-design: true + generate: true + assets: - assets/images/ - assets/node_list.yml @@ -139,9 +140,9 @@ flutter: # For details regarding fonts from package dependencies, # see https://flutter.dev/custom-fonts/#from-packages -flutter_intl: - enabled: true # Required. Must be set to true to activate the package. Default: false - class_name: S # Optional. Sets the name for the generated localization class. Default: S - main_locale: en # Optional. Sets the main locale used for generating localization files. Provided value should consist of language code and optional script and country codes separated with underscore (e.g. 'en', 'en_GB', 'zh_Hans', 'zh_Hans_CN'). Default: en - arb_dir: lib/l10n # Optional. Sets the directory of your ARB resource files. Provided value should be a valid path on your system. Default: lib/l10n - output_dir: lib/generated # Optional. Sets the directory of generated localization files. Provided value should be a valid path on your system. Default: lib/generated +#flutter_intl: +# enabled: true # Required. Must be set to true to activate the package. Default: false +# class_name: S # Optional. Sets the name for the generated localization class. Default: S +# main_locale: en # Optional. Sets the main locale used for generating localization files. Provided value should consist of language code and optional script and country codes separated with underscore (e.g. 'en', 'en_GB', 'zh_Hans', 'zh_Hans_CN'). Default: en +# arb_dir: lib/l10n # Optional. Sets the directory of your ARB resource files. Provided value should be a valid path on your system. Default: lib/l10n +# output_dir: lib/generated # Optional. Sets the directory of generated localization files. Provided value should be a valid path on your system. Default: lib/generated