Cw 858 ledger enhancements (#2034)

* feat: Redesign HW Account select screen

* fix: Avoid "Bluetooth disabled" Exception on dispose of HW Connection screen

* feat: Proceed on Ledger Modal is not dismissible by tapping out

* feat: Gracefully ignore errors thrown by monero ledger keep alive function

* feat: Close a monero ledger wallet on wallet change

* fix: Leave connect screen without connecting
This commit is contained in:
Konstantin Ullrich
2025-02-19 00:23:03 +02:00
committed by GitHub
parent 99338a0532
commit 9d6f985a59
36 changed files with 79 additions and 32 deletions
@@ -67,6 +67,7 @@ void startAuthenticationStateChange(
alertTitle: S.of(context).proceed_on_device,
alertContent: S.of(context).proceed_on_device_description,
buttonText: S.of(context).cancel,
alertBarrierDismissible: false,
buttonAction: () => Navigator.of(context).pop()),
);
await loadCurrentWallet();
@@ -190,6 +190,7 @@ class _MoneroHardwareWalletOptionsFormState
alertTitle: S.of(context).proceed_on_device,
alertContent: S.of(context).proceed_on_device_description,
buttonText: S.of(context).cancel,
alertBarrierDismissible: false,
buttonAction: () => Navigator.of(context).pop(),
),
);
@@ -147,7 +147,7 @@ class _SelectHardwareWalletAccountFormState extends State<SelectHardwareWalletAc
child: Container(
width: double.infinity,
child: Text(
"Available accounts",
S.of(context).select_hw_account_below,
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w500,
@@ -159,6 +159,7 @@ class _SelectHardwareWalletAccountFormState extends State<SelectHardwareWalletAc
Observer(
builder: (context) => Column(
children: _walletHardwareRestoreVM.availableAccounts.map((acc) {
final address = acc.address;
return Padding(
padding: EdgeInsets.only(top: 10),
@@ -170,7 +171,7 @@ class _SelectHardwareWalletAccountFormState extends State<SelectHardwareWalletAc
width: 24,
),
text:
"${address.substring(0, 6)}...${address.substring(address.length - 6)}",
"${acc.accountIndex} - ${address.substring(0, 6)}...${address.substring(address.length - 6)}",
showTrailingIcon: false,
height: 54,
isSelected: _walletHardwareRestoreVM.selectedAccount == acc,
+1
View File
@@ -599,6 +599,7 @@ class SendPage extends BasePage {
alertTitle: S.of(context).proceed_on_device,
alertContent: S.of(context).proceed_on_device_description,
buttonText: S.of(context).cancel,
alertBarrierDismissible: false,
buttonAction: () {
sendViewModel.state = InitialExecutionState();
Navigator.of(context).pop();
@@ -31,8 +31,6 @@ import 'package:cw_core/wallet_type.dart';
import 'package:flutter/material.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
import '../../../themes/extensions/dashboard_page_theme.dart';
class WalletListPage extends BasePage {
WalletListPage({
required this.walletListViewModel,
@@ -506,23 +504,28 @@ class WalletListBodyState extends State<WalletListBody> {
final requireHardwareWalletConnection = widget.walletListViewModel
.requireHardwareWalletConnection(wallet);
if (requireHardwareWalletConnection) {
bool didConnect = false;
await Navigator.of(context).pushNamed(
Routes.connectDevices,
arguments: ConnectDevicePageParams(
walletType: WalletType.monero,
onConnectDevice: (context, ledgerVM) async {
monero!.setGlobalLedgerConnection(ledgerVM.connection);
didConnect = true;
Navigator.of(context).pop();
},
),
);
if (!didConnect) return;
showPopUp<void>(
context: context,
builder: (BuildContext context) => AlertWithOneAction(
alertTitle: S.of(context).proceed_on_device,
alertContent: S.of(context).proceed_on_device_description,
buttonText: S.of(context).cancel,
alertBarrierDismissible: false,
buttonAction: () => Navigator.of(context).pop()),
);
}
@@ -16,7 +16,6 @@ import 'package:cw_core/utils/print_verbose.dart';
import 'package:cw_core/wallet_base.dart';
import 'package:cw_core/wallet_type.dart';
import 'package:flutter/widgets.dart';
import 'package:ledger_flutter_plus/ledger_flutter_plus.dart' as sdk;
import 'package:mobx/mobx.dart';
import 'package:permission_handler/permission_handler.dart';
@@ -61,20 +60,21 @@ abstract class LedgerViewModelBase with Store {
bool bleIsEnabled = false;
bool _bleIsInitialized = false;
Future<void> _initBLE() async {
if (bleIsEnabled && !_bleIsInitialized) {
ledgerPlusBLE = sdk.LedgerInterface.ble(
onPermissionRequest: (_) async {
Map<Permission, PermissionStatus> statuses = await [
Permission.bluetoothScan,
Permission.bluetoothConnect,
Permission.bluetoothAdvertise,
].request();
onPermissionRequest: (_) async {
Map<Permission, PermissionStatus> statuses = await [
Permission.bluetoothScan,
Permission.bluetoothConnect,
Permission.bluetoothAdvertise,
].request();
return statuses.values.where((status) => status.isDenied).isEmpty;
},
bleOptions:
sdk.BluetoothOptions(maxScanDuration: Duration(minutes: 5)));
return statuses.values.where((status) => status.isDenied).isEmpty;
},
bleOptions: sdk.BluetoothOptions(maxScanDuration: Duration(minutes: 5)),
);
_bleIsInitialized = true;
}
}
@@ -92,10 +92,8 @@ abstract class LedgerViewModelBase with Store {
Stream<sdk.LedgerDevice> scanForUsbDevices() => ledgerPlusUSB.scan();
Future<void> stopScanning() async {
await ledgerPlusBLE.stopScanning();
if (!Platform.isIOS) {
await ledgerPlusUSB.stopScanning();
}
if (_bleIsInitialized) await ledgerPlusBLE.stopScanning();
if (!Platform.isIOS) await ledgerPlusUSB.stopScanning();
}
Future<void> connectLedger(sdk.LedgerDevice device, WalletType type) async {
@@ -112,8 +110,8 @@ abstract class LedgerViewModelBase with Store {
: ledgerPlusUSB;
if (_connectionChangeSubscription == null) {
_connectionChangeSubscription = ledger.deviceStateChanges
.listen(_connectionChangeListener);
_connectionChangeSubscription =
ledger.deviceStateChanges.listen(_connectionChangeListener);
}
_connection = await ledger.connect(device);
@@ -125,8 +123,7 @@ abstract class LedgerViewModelBase with Store {
bool _isConnecting = true;
WalletType? _connectingWalletType;
void _connectionChangeListener(
sdk.BleConnectionState event, ) {
void _connectionChangeListener(sdk.BleConnectionState event) {
printV('Ledger Device State Changed: $event');
if (event == sdk.BleConnectionState.disconnected && !_isConnecting) {
_connection = null;