Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/pull-request.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -70,15 +70,15 @@ jobs:
- run: dart run tool/generate_localization.dart
- run: dart run tool/generate_release_info.dart
- run: flutter pub run build_runner build
- run: flutter analyze
- run: flutter analyze --fatal-warnings
# Excludes the `golden` tag: visual-regression tests live under
# `test/goldens/` and are validated on the dfx01 self-hosted runner
# in the parallel `golden-tests` job (Hardware-Determinismus, see
# `docs/visual-regression-tests.md`). Running them here too would
# both duplicate work and erroneously red this job on macos-latest
# where the Skia/font-rendering does not match the committed
# baselines.
- run: flutter test --coverage --exclude-tags golden
- run: ulimit -n 16384 && flutter test --coverage --exclude-tags golden

# Narrow the coverage report to the README-defined activated surface:
# lib/packages/** — services, repositories, signers, utils
Expand Down
13 changes: 13 additions & 0 deletions analysis_options.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,22 @@ formatter:
page_width: 100
trailing_commas: preserve

analyzer:
language:
strict-casts: true
strict-inference: true
strict-raw-types: true

linter:
rules:
annotate_overrides: true
avoid_print: true
prefer_const_constructors: true
prefer_single_quotes: true
unawaited_futures: true
discarded_futures: true
avoid_dynamic_calls: true
cast_nullable_to_non_nullable: true
null_check_on_nullable_type_parameter: true
unnecessary_null_checks: true
prefer_final_locals: true
18 changes: 9 additions & 9 deletions assets/languages/strings_de.arb
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@
"buyPaymentConfirmFailedAktionariat": "Es gibt ein technisches Problem. Bitte überprüfen Sie Ihr E-Mail-Postfach, möglicherweise fehlt noch eine Bestätigung Ihrer Blockchain-Adresse. Andernfalls versuchen Sie es später erneut. Falls der Fehler weiterhin besteht, kontaktieren Sie unseren Support.",
"buyPaymentInformation": "Zahlungsinformationen",
"buyPaymentInformationDescription": "Bitte überweisen Sie den Kaufbetrag mit diesen Angaben über Ihre Bankanwendung. Der Verwendungszweck ist wichtig!",
"buyRealUnit": "RealUnit kaufen",
"buyRealu": "RealUnit Token kaufen",
"buyRealUnit": "RealUnit kaufen",
"cancel": "Abbrechen",
"changeAddress": "Adresse ändern",
"changeInReview": "Änderung in Prüfung",
Expand All @@ -53,11 +53,11 @@
"connectBitboxContent": "Bitte verbinden Sie Ihre BitBox mit Ihrem Smartphone.",
"connectBitboxContentIos": "Bitte verbinden Sie Ihre BitBox mit Ihrem Smartphone und aktivieren Sie zusätzlich Bluetooth.",
"connectBitboxFailed": "Es ist ein Fehler aufgetreten. Bitte versuchen Sie es erneut.",
"connectBitboxSignInHint": "Nach der Code-Überprüfung wird die BitBox um eine zusätzliche Bestätigung zur Anmeldung gebeten.",
"connectBitboxSignatureCapturing": "Bitte bestätigen Sie die Anmeldeanfrage auf Ihrem BitBox-Gerät. Diese Signatur wird einmalig erfasst, damit künftige Käufe Ihre BitBox nicht erneut benötigen.",
"connectBitboxSignatureCapturingTitle": "Anmeldung bestätigen",
"connectBitboxSignatureFailed": "Ihre Anmeldesignatur konnte nicht erfasst werden. Sie können es erneut versuchen oder trotzdem fortfahren – Ihre BitBox wird dann möglicherweise für Ihren ersten Kauf erneut benötigt.",
"connectBitboxSignatureFailedTitle": "Anmeldung nicht abgeschlossen",
"connectBitboxSignInHint": "Nach der Code-Überprüfung wird die BitBox um eine zusätzliche Bestätigung zur Anmeldung gebeten.",
"connectBitboxTitle": "BitBox verbinden",
"connected": "Verbunden",
"connectedBitboxContent": "Bitte bestätigen Sie und folgen nun den letzten Anweisungen auf Ihrer BitBox.",
Expand Down Expand Up @@ -197,8 +197,8 @@
"proofDocument": "Nachweis-Dokument",
"purposeOfPayment": "Verwendungszweck",
"qrCode": "QR-Code",
"realunitStockToken": "RealUnit Aktientoken",
"realunitStockprice": "RealUnit Aktienkurs",
"realunitStockToken": "RealUnit Aktientoken",
"realunitWallet": "RealUnit Wallet",
"realunitWalletLogout": "Aus REALU Wallet abmelden",
"realunitWalletLogoutCheck": "Ich habe meine Wiederherstellungsphrase gesichert.",
Expand Down Expand Up @@ -246,18 +246,18 @@
"sellBitboxCheckingEth": "Wallet-Guthaben wird geprüft",
"sellBitboxDepositDescription": "Bestätigen Sie auf der BitBox, um ZCHF an die DFX-Einzahlungsadresse zu überweisen.",
"sellBitboxDepositFrom": "Sie senden",
"sellBitboxDepositing": "ZCHF wird gesendet. Bestätigen Sie auf der Bitbox",
"sellBitboxDepositRetryDescription": "Der Tausch wurde abgeschlossen, aber die ZCHF-Einzahlung konnte nicht gesendet werden. Ihre Mittel sind sicher. Tippen Sie auf Wiederholen.",
"sellBitboxDepositRetryTitle": "Einzahlung fehlgeschlagen",
"sellBitboxDepositTitle": "ZCHF an DFX senden",
"sellBitboxDepositTo": "DFX-Einzahlung",
"sellBitboxDepositing": "ZCHF wird gesendet. Bestätigen Sie auf der Bitbox",
"sellBitboxEthReady": "Wallet bereit",
"sellBitboxEthReadyDescription": "Ihr Wallet hat genug ETH, um mit dem Verkauf fortzufahren.",
"sellBitboxSwapDescription": "Bestätigen Sie auf Ihrem BitBox, um REALU über den BrokerBot in ZCHF zu tauschen.",
"sellBitboxSwapFrom": "Sie senden",
"sellBitboxSwapping": "Tausch on-chain. Bestätigen Sie auf der Bitbox.",
"sellBitboxSwapTitle": "REALU → ZCHF tauschen",
"sellBitboxSwapTo": "Sie erhalten",
"sellBitboxSwapping": "Tausch on-chain. Bestätigen Sie auf der Bitbox.",
"sellBitboxWaitingForEth": "Gasgebühren werden angefordert",
"sellBitboxWaitingForEthDescription": "Ein kleiner ETH-Betrag wird an Ihr Wallet gesendet, um die Transaktionsgebühren zu decken. Dies kann einige Minuten dauern.",
"sellMinAmount": "Mindestbetrag: ${amount} ${currency}",
Expand All @@ -282,10 +282,10 @@
"settingsWalletBackupSubtitle1": "Bitte notieren Sie Ihre 12 Wiederherstellungs-Wörter in der exakten Reihenfolge auf einem Blatt Papier und bewahren Sie sie absolut sicher auf.",
"settingsWalletBackupSubtitle2": "Dies ist die einzige Möglichkeit, Ihre Wallet wiederherzustellen.",
"showSeed": "Seed anzeigen",
"signMessage": "Signierte Nachricht",
"signMessageGet": "Signierte Nachricht abrufen",
"signature": "Signatur",
"signingCancelled": "Signatur abgebrochen — bitte BitBox erneut bestätigen",
"signMessage": "Signierte Nachricht",
"signMessageGet": "Signierte Nachricht abrufen",
"skip": "Überspringen",
"softwareTermsText": "Mit der Nutzung dieser App akzeptieren Sie die Nutzungsbedingungen dieser Software.",
"softwareTermsTextHighlighted": "Nutzungsbedingungen",
Expand Down Expand Up @@ -329,9 +329,9 @@
"transactionBuy": "Kauf",
"transactionHistory": "Transaktionshistorie",
"transactionPending": "In Bearbeitung",
"transactions": "Transaktionen",
"transactionSell": "Verkauf",
"transactionWaitingForPayment": "Warte auf Zahlung",
"transactions": "Transaktionen",
"twoFa": "2-Faktor Authentifizierung",
"twoFaCodeRequired": "Code ist erforderlich",
"twoFaCodeTooShort": "Der Code sollte 6 Ziffern lang sein",
Expand All @@ -356,4 +356,4 @@
"youPay": "Sie bezahlen",
"youReceive": "Sie erhalten",
"youSell": "Sie verkaufen"
}
}
18 changes: 9 additions & 9 deletions assets/languages/strings_en.arb
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@
"buyPaymentConfirmFailedAktionariat": "There is a technical problem. Please check your email inbox — you may still need to confirm your blockchain address. Otherwise, please try again later. If the error persists, contact our support team.",
"buyPaymentInformation": "Payment information",
"buyPaymentInformationDescription": "Please transfer the purchase amount using your banking app with these details. The purpose of payment is important!",
"buyRealUnit": "Buy RealUnit",
"buyRealu": "Buy RealUnit Token",
"buyRealUnit": "Buy RealUnit",
"cancel": "Cancel",
"changeAddress": "Change address",
"changeInReview": "Change in review",
Expand All @@ -53,11 +53,11 @@
"connectBitboxContent": "Please connect your BitBox with your Smartphone.",
"connectBitboxContentIos": "Please connect your BitBox with your Smartphone and activate Bluetooth.",
"connectBitboxFailed": "Something went wrong. Please try to connect again.",
"connectBitboxSignInHint": "After verifying the code, the BitBox will ask for one additional confirmation to sign you in.",
"connectBitboxSignatureCapturing": "Please confirm the sign-in request on your BitBox device. This signature is captured once so future purchases won't need your BitBox again.",
"connectBitboxSignatureCapturingTitle": "Confirm sign-in",
"connectBitboxSignatureFailed": "We couldn't capture your sign-in signature. You can retry, or continue anyway – your BitBox may then be needed again for your first purchase.",
"connectBitboxSignatureFailedTitle": "Sign-in not completed",
"connectBitboxSignInHint": "After verifying the code, the BitBox will ask for one additional confirmation to sign you in.",
"connectBitboxTitle": "Connect BitBox",
"connected": "Connected",
"connectedBitboxContent": "Please confirm and follow the last steps on your BitBox.",
Expand Down Expand Up @@ -197,8 +197,8 @@
"proofDocument": "Proof document",
"purposeOfPayment": "Purpose of payment",
"qrCode": "QR code",
"realunitStockToken": "RealUnit Stock Token",
"realunitStockprice": "RealUnit Stockprice",
"realunitStockToken": "RealUnit Stock Token",
"realunitWallet": "RealUnit Wallet",
"realunitWalletLogout": "Log out of REALU Wallet",
"realunitWalletLogoutCheck": "I have backed up my recovery phrase.",
Expand Down Expand Up @@ -246,18 +246,18 @@
"sellBitboxCheckingEth": "Checking your wallet balance",
"sellBitboxDepositDescription": "Confirm on your BitBox to transfer ZCHF to the DFX deposit address.",
"sellBitboxDepositFrom": "You send",
"sellBitboxDepositing": "Sending ZCHF. Please confirm on the Bitbox.",
"sellBitboxDepositRetryDescription": "The swap was completed but the ZCHF deposit could not be sent. Your funds are safe. Tap retry to try again.",
"sellBitboxDepositRetryTitle": "Deposit failed",
"sellBitboxDepositTitle": "Send ZCHF to DFX",
"sellBitboxDepositTo": "DFX deposit",
"sellBitboxDepositing": "Sending ZCHF. Please confirm on the Bitbox.",
"sellBitboxEthReady": "Wallet ready",
"sellBitboxEthReadyDescription": "Your wallet has enough ETH to proceed with the sale.",
"sellBitboxSwapDescription": "Confirm on your BitBox to swap REALU for ZCHF via the BrokerBot.",
"sellBitboxSwapFrom": "You send",
"sellBitboxSwapping": "Swapping on-chain. Please confirm on the Bitbox.",
"sellBitboxSwapTitle": "Swap REALU → ZCHF",
"sellBitboxSwapTo": "You receive",
"sellBitboxSwapping": "Swapping on-chain. Please confirm on the Bitbox.",
"sellBitboxWaitingForEth": "Requesting gas funds",
"sellBitboxWaitingForEthDescription": "A small amount of ETH is being sent to your wallet to cover transaction fees. This may take a few minutes.",
"sellMinAmount": "Minimum amount: ${amount} ${currency}",
Expand All @@ -282,10 +282,10 @@
"settingsWalletBackupSubtitle1": "Please write down your 12 recovery words in the exact order on a piece of paper and keep them in a completely safe place.",
"settingsWalletBackupSubtitle2": "This is the only way to recover your wallet.",
"showSeed": "Show Seed",
"signMessage": "Sign Message",
"signMessageGet": "Get Sign Message",
"signature": "Signature",
"signingCancelled": "Signature cancelled — please confirm on the BitBox again",
"signMessage": "Sign Message",
"signMessageGet": "Get Sign Message",
"skip": "Skip",
"softwareTermsText": "By using this app, you accept the terms of use of this software.",
"softwareTermsTextHighlighted": "terms of use",
Expand Down Expand Up @@ -329,9 +329,9 @@
"transactionBuy": "Buy",
"transactionHistory": "Transaction history",
"transactionPending": "Processing",
"transactions": "Transactions",
"transactionSell": "Sell",
"transactionWaitingForPayment": "Waiting for payment",
"transactions": "Transactions",
"twoFa": "Two-factor authentication",
"twoFaCodeRequired": "Code is required",
"twoFaCodeTooShort": "Code should be 6 digits",
Expand All @@ -356,4 +356,4 @@
"youPay": "You pay",
"youReceive": "You receive",
"youSell": "You sell"
}
}
2 changes: 1 addition & 1 deletion lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ Future<void> _initialize() async {
Future<void> _initializeWithSplashDuration() async {
await Future.wait([
_initialize(),
Future.delayed(const Duration(seconds: 3)),
Future<void>.delayed(const Duration(seconds: 3)),
]);
}

Expand Down
16 changes: 10 additions & 6 deletions lib/packages/config/legal_documents_config.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import 'dart:async';

import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:go_router/go_router.dart';
Expand Down Expand Up @@ -144,13 +146,15 @@ class WebDocumentConfig implements DocumentConfig {
@override
void onTap(BuildContext context) {
if (openExternally) {
launchUrl(Uri.parse(url(context)), mode: LaunchMode.externalApplication);
unawaited(launchUrl(Uri.parse(url(context)), mode: LaunchMode.externalApplication));
} else {
context.pushNamed(
AppRoutes.webView,
extra: WebViewRouteParams(
title: title(context),
url: Uri.parse(url(context)),
unawaited(
context.pushNamed(
AppRoutes.webView,
extra: WebViewRouteParams(
title: title(context),
url: Uri.parse(url(context)),
),
),
);
}
Expand Down
3 changes: 2 additions & 1 deletion lib/packages/repository/supported_fiat_repository.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import 'dart:developer' as developer;

import 'package:realunit_wallet/packages/service/dfx/dfx_fiat_service.dart';
import 'package:realunit_wallet/packages/service/dfx/models/fiat/dto/dfx_fiat_dto.dart';
import 'package:realunit_wallet/styles/currency.dart';

/// Translates the backend's per-user fiat list into the local [Currency]
Expand All @@ -23,7 +24,7 @@ class SupportedFiatRepository {

Future<List<Currency>> getAll() => _resolve((_) => true);

Future<List<Currency>> _resolve(bool Function(dynamic) filter) async {
Future<List<Currency>> _resolve(bool Function(DfxFiatDto) filter) async {
final fiats = await _fiatService.getAllFiats();
final result = <Currency>[];
for (final fiat in fiats) {
Expand Down
2 changes: 1 addition & 1 deletion lib/packages/service/balance_service.dart
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ class BalanceService {
final response = await _appStore.httpClient.get(uri);

if (response.statusCode == 200) {
final json = jsonDecode(response.body);
final json = jsonDecode(response.body) as Map<String, dynamic>;
final balanceString = json['balance'] as String?;

if (balanceString != null) {
Expand Down
2 changes: 1 addition & 1 deletion lib/packages/service/debug_auth_service.dart
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ class DebugAuthService {
);

if (response.statusCode == 200) {
final body = jsonDecode(response.body);
final body = jsonDecode(response.body) as Map<String, dynamic>;
return body['message'] as String;
}
throw Exception('Failed to fetch sign message (${response.statusCode})');
Expand Down
5 changes: 3 additions & 2 deletions lib/packages/service/dfx/dfx_auth_service.dart
Original file line number Diff line number Diff line change
Expand Up @@ -146,8 +146,9 @@ abstract class DFXAuthService {
final responseBody = jsonDecode(response.body);
return responseBody as Map<String, dynamic>;
} else if (response.statusCode == 403) {
final responseBody = jsonDecode(response.body);
final message = responseBody['message'] ?? 'Service unavailable in your country';
final responseBody = jsonDecode(response.body) as Map<String, dynamic>;
final message =
responseBody['message'] ?? 'Service unavailable in your country';
throw Exception(message);
} else {
throw Exception('Failed to sign up. Status: ${response.statusCode} ${response.body}');
Expand Down
9 changes: 5 additions & 4 deletions lib/packages/service/dfx/dfx_bank_account_service.dart
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,9 @@ class DfxBankAccountService extends DFXAuthService {
throw ApiException.fromJson(errorJson, httpStatusCode: response.statusCode);
}

final List<dynamic> jsonList = jsonDecode(response.body);
final bankAccounts = jsonList.map((json) => BankAccountDto.fromJson(json)).toList();
final jsonList = jsonDecode(response.body) as List<dynamic>;
final bankAccounts =
jsonList.map((json) => BankAccountDto.fromJson(json as Map<String, dynamic>)).toList();
return bankAccounts;
}

Expand All @@ -47,7 +48,7 @@ class DfxBankAccountService extends DFXAuthService {
throw ApiException.fromJson(errorJson, httpStatusCode: response.statusCode);
}

return BankAccountDto.fromJson(jsonDecode(response.body));
return BankAccountDto.fromJson(jsonDecode(response.body) as Map<String, dynamic>);
}

Future<BankAccountDto> updateBankAccount({
Expand All @@ -74,6 +75,6 @@ class DfxBankAccountService extends DFXAuthService {
throw ApiException.fromJson(errorJson, httpStatusCode: response.statusCode);
}

return BankAccountDto.fromJson(jsonDecode(response.body));
return BankAccountDto.fromJson(jsonDecode(response.body) as Map<String, dynamic>);
}
}
8 changes: 4 additions & 4 deletions lib/packages/service/dfx/dfx_brokerbot_service.dart
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ class DfxBrokerbotService extends DFXAuthService {
throw Exception('BuyPrice request failed: ${res.body}');
}

return BrokerbotBuyPriceDto.fromJson(jsonDecode(res.body));
return BrokerbotBuyPriceDto.fromJson(jsonDecode(res.body) as Map<String, dynamic>);
}

/// Convert CHF → REALU shares
Expand All @@ -54,7 +54,7 @@ class DfxBrokerbotService extends DFXAuthService {
throw Exception('Shares request failed: ${res.body}');
}

return BrokerbotBuySharesDto.fromJson(jsonDecode(res.body));
return BrokerbotBuySharesDto.fromJson(jsonDecode(res.body) as Map<String, dynamic>);
}

/// Convert REALU shares → CHF (with fees)
Expand All @@ -75,7 +75,7 @@ class DfxBrokerbotService extends DFXAuthService {
throw ApiException.fromJson(errorJson, httpStatusCode: res.statusCode);
}

return BrokerbotSellPriceDto.fromJson(jsonDecode(res.body));
return BrokerbotSellPriceDto.fromJson(jsonDecode(res.body) as Map<String, dynamic>);
}

/// Convert CHF → REALU shares (with fees)
Expand All @@ -96,6 +96,6 @@ class DfxBrokerbotService extends DFXAuthService {
throw ApiException.fromJson(errorJson, httpStatusCode: res.statusCode);
}

return BrokerbotSellSharesDto.fromJson(jsonDecode(res.body));
return BrokerbotSellSharesDto.fromJson(jsonDecode(res.body) as Map<String, dynamic>);
}
}
4 changes: 2 additions & 2 deletions lib/packages/service/dfx/dfx_country_service.dart
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@ class DfxCountryService {
final response = await _appStore.httpClient.get(uri);

if (response.statusCode == 200) {
final List<dynamic> jsonList = jsonDecode(response.body);
final jsonList = jsonDecode(response.body) as List<dynamic>;
final countries = jsonList
.map((json) => DfxCountryDto.fromJson(json))
.map((json) => DfxCountryDto.fromJson(json as Map<String, dynamic>))
.map((dto) => dto.toCountry())
.toList();
cachedCountries = countries;
Expand Down
5 changes: 3 additions & 2 deletions lib/packages/service/dfx/dfx_fiat_service.dart
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,9 @@ class DfxFiatService {
throw Exception('Failed to fetch fiats: ${response.statusCode}');
}

final List<dynamic> jsonList = jsonDecode(response.body);
final fiats = jsonList.map((json) => DfxFiatDto.fromJson(json)).toList();
final jsonList = jsonDecode(response.body) as List<dynamic>;
final fiats =
jsonList.map((json) => DfxFiatDto.fromJson(json as Map<String, dynamic>)).toList();
_cachedFiats = fiats;
_cachedAt = clock.now();
return fiats;
Expand Down
Loading
Loading