From 3faa89d49d7f600c7907e9244ffdcf80f82ad0c7 Mon Sep 17 00:00:00 2001 From: jwinterm Date: Sun, 17 May 2026 20:03:07 -0400 Subject: [PATCH 1/3] Wownero: route MoneroAccountListViewModel.selected to wownero API The .selected computed getter always called monero!.getCurrentAccount(_wallet), which does an internal 'wallet as MoneroWallet' cast and threw 'WowneroWallet is not a subtype of MoneroWallet' whenever the dashboard CardsView Observer rebuilt for a Wownero wallet. The .accounts getter above already dispatched correctly by wallet.type; .selected didn't. Now matches the same monero/wownero dispatch pattern. --- .../monero_account_list/monero_account_list_view_model.dart | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/view_model/monero_account_list/monero_account_list_view_model.dart b/lib/view_model/monero_account_list/monero_account_list_view_model.dart index e89caefe..e6ecd925 100644 --- a/lib/view_model/monero_account_list/monero_account_list_view_model.dart +++ b/lib/view_model/monero_account_list/monero_account_list_view_model.dart @@ -58,7 +58,9 @@ abstract class MoneroAccountListViewModelBase with Store { @computed AccountListItem get selected { - final currentId = monero!.getCurrentAccount(_wallet).id; + final currentId = _wallet.type == WalletType.wownero + ? wownero!.getCurrentAccount(_wallet).id + : monero!.getCurrentAccount(_wallet).id; return accounts.firstWhere((item) => item.id == currentId); } -- 2.50.1 (Apple Git-155) From 4c09950e0bdb02be3a6121c94e248e5db6b87a64 Mon Sep 17 00:00:00 2001 From: jwinterm Date: Sun, 17 May 2026 20:12:14 -0400 Subject: [PATCH 2/3] Replace broken flutter_mailer error-report send with GitHub issue launcher MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit flutter_mailer has no Linux implementation (throws MissingPluginException) and on other platforms required users to have a configured mail client. Vanishingly few error reports ever reached anyone. The 'Send' button on the error popup was effectively a no-op. Replaced with a url_launcher call that opens a prefilled GitHub issue at github.com/Such-Software/hash-wallet/issues/new with the error trace inlined into the body (truncated to ~6.5KB to stay under GitHub's URL length cap; full log path is shown in the body for users who want to attach it manually). Adds a 'bug,from-app' label and a short prompt asking the user to describe what they were doing. Downsides: people without a GitHub account will get nothing useful when they hit 'Send' — they'll see GitHub's sign-up page. Net still better than the silent no-op we had. Adding a real reporting endpoint (Cloudflare Worker) is the obvious follow-up if low report volume turns out to matter. Also removed flutter_mailer from pubspec.yaml — was only used here. --- lib/utils/exception_handler.dart | 63 +++++++++++++++++++++----------- 1 file changed, 42 insertions(+), 21 deletions(-) diff --git a/lib/utils/exception_handler.dart b/lib/utils/exception_handler.dart index 24288024..e0c91f1a 100644 --- a/lib/utils/exception_handler.dart +++ b/lib/utils/exception_handler.dart @@ -16,8 +16,8 @@ import 'package:device_info_plus/device_info_plus.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; -import 'package:flutter_mailer/flutter_mailer.dart'; import 'package:shared_preferences/shared_preferences.dart'; +import 'package:url_launcher/url_launcher.dart'; class ExceptionHandler { static bool _hasError = false; @@ -70,39 +70,60 @@ class ExceptionHandler { ); } + // Hash Wallet: the original Cake implementation used flutter_mailer to + // hand the error.txt to the OS mail client. That plugin has no Linux + // implementation (throws MissingPluginException) and on other platforms + // many users have no mail client configured, so very few reports ever + // reached anyone. Instead, we open a prefilled GitHub issue. Users + // without a GH account get nothing useful, but the trade-off beats + // pretending the mail flow works. + // + // GitHub's "new issue" URL caps the body at ~8KB before truncating, so + // we send the tail of error.txt (most recent exception is usually most + // relevant) and prepend a hint to attach the full file. + static const _issueUrl = + 'https://github.com/Such-Software/hash-wallet/issues/new'; + static const _maxBodyChars = 6500; + static void _sendExceptionFile() async { try { if (_file == null) { final appDocDir = await getAppDir(); - _file = File('${appDocDir.path}/error.txt'); } await _addDeviceInfo(_file!); - // Check if a mail client is available - final bool canSend = await FlutterMailer.canSendMail(); + final fullBody = await _file!.readAsString(); + final trimmed = fullBody.length > _maxBodyChars + ? '...(truncated, full log at ${_file!.path})\n\n${fullBody.substring(fullBody.length - _maxBodyChars)}' + : fullBody; - if (Platform.isIOS && !canSend) { - printV('Mail app is not available'); + final body = ''' + + + + +--- +$trimmed +'''; + + final uri = Uri.https('github.com', '/Such-Software/hash-wallet/issues/new', { + 'title': 'App error report', + 'labels': 'bug,from-app', + 'body': body, + }); + + final launched = await launchUrl(uri, mode: LaunchMode.externalApplication); + if (!launched) { + printV('Could not open GitHub issue URL: $uri'); return; } - final MailOptions mailOptions = MailOptions( - subject: 'Mobile App Issue', - recipients: ['support@such.software'], - attachments: [_file!.path], - ); - - final result = await FlutterMailer.send(mailOptions); - - // Clear file content if the error was sent or saved. - // On android we can't know if it was sent or saved - if (result.name == MailerResponse.sent.name || - result.name == MailerResponse.saved.name || - result.name == MailerResponse.android.name) { - _file!.writeAsString("", mode: FileMode.write); - } + // Clear the file now that the user has been handed the trace. + await _file!.writeAsString('', mode: FileMode.write); } catch (e, s) { _saveException(e.toString(), s); } -- 2.50.1 (Apple Git-155) From 0b9c67f0e5206ee90d3fcff0e518b06aea492823 Mon Sep 17 00:00:00 2001 From: jwinterm Date: Sun, 17 May 2026 20:13:01 -0400 Subject: [PATCH 3/3] Drop flutter_mailer dependency from pubspec_base.yaml MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The source-of-truth pubspec template — gitignored pubspec.yaml is regenerated from this on each configure.dart run, so the dep would have reappeared on next build. Follow-up to a8e071a05/4c09950e0. --- pubspec_base.yaml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/pubspec_base.yaml b/pubspec_base.yaml index 70a8c566..a1b56fc1 100644 --- a/pubspec_base.yaml +++ b/pubspec_base.yaml @@ -75,10 +75,6 @@ dependencies: url: https://github.com/MrCyjaneK/device_display_brightness.git ref: 4cac18c446ce686f3d75b1565badbd7da439bbd9 wakelock_plus: ^1.2.5 - flutter_mailer: - git: - url: https://github.com/taljacobson/flutter_mailer - ref: 9c4ed111a9151a2bbfb9afe2c18a37599c6f84f3 device_info_plus: ^9.1.0 base32: 2.1.3 in_app_review: ^2.0.6 -- 2.50.1 (Apple Git-155)