mirror of
https://github.com/Such-Software/hash-wallet.git
synced 2026-10-17 05:41:29 +02:00
CW-1045-Ledger-Bugs-Enhancements (#2278)
* feat: prepare ledger.dart to use callbacks * feat: set ledger callback using monero_c * fix(cw_monero): async ledger * build: Bump monero_c dependencies * feat: Add "How to connect" to HW Device selection screen * refactor: use monero_c free to clean pointer * fix: use new monero_c deps * fix: merge conflicts regarding new theming * feat: add status bottomsheet indicating an ongoing signing process * fix: getLastLedgerCommand monero.dart generation * reformat send_view_model.dart [skip ci] --------- Co-authored-by: Czarek Nakamoto <cyjan@mrcyjanek.net> Co-authored-by: Omar Hatem <omarh.ismail1@gmail.com>
This commit is contained in:
co-authored by
Czarek Nakamoto
Omar Hatem
parent
e03dcc7fe9
commit
90aee053cd
@@ -5,7 +5,9 @@ import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/routes.dart';
|
||||
import 'package:cake_wallet/src/screens/base_page.dart';
|
||||
import 'package:cake_wallet/src/screens/connect_device/widgets/device_tile.dart';
|
||||
import 'package:cake_wallet/src/widgets/bottom_sheet/info_steps_bottom_sheet_widget.dart';
|
||||
import 'package:cake_wallet/src/widgets/primary_button.dart';
|
||||
import 'package:cake_wallet/themes/core/material_base_theme.dart';
|
||||
import 'package:cake_wallet/utils/responsive_layout_util.dart';
|
||||
import 'package:cake_wallet/view_model/hardware_wallet/ledger_view_model.dart';
|
||||
import 'package:cw_core/utils/print_verbose.dart';
|
||||
@@ -60,6 +62,7 @@ class ConnectDevicePage extends BasePage {
|
||||
onConnectDevice,
|
||||
allowChangeWallet,
|
||||
ledgerVM,
|
||||
currentTheme,
|
||||
));
|
||||
}
|
||||
|
||||
@@ -68,12 +71,14 @@ class ConnectDevicePageBody extends StatefulWidget {
|
||||
final OnConnectDevice onConnectDevice;
|
||||
final bool allowChangeWallet;
|
||||
final LedgerViewModel ledgerVM;
|
||||
final MaterialThemeBase currentTheme;
|
||||
|
||||
const ConnectDevicePageBody(
|
||||
this.walletType,
|
||||
this.onConnectDevice,
|
||||
this.allowChangeWallet,
|
||||
this.ledgerVM,
|
||||
this.currentTheme,
|
||||
);
|
||||
|
||||
@override
|
||||
@@ -179,109 +184,126 @@ class ConnectDevicePageBodyState extends State<ConnectDevicePageBody> {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Center(
|
||||
child: Container(
|
||||
width: ResponsiveLayoutUtilBase.kDesktopMaxWidthConstraint,
|
||||
height: double.infinity,
|
||||
padding: EdgeInsets.symmetric(vertical: 24, horizontal: 24),
|
||||
child: SingleChildScrollView(
|
||||
child: Column(
|
||||
children: [
|
||||
Padding(
|
||||
padding: EdgeInsets.only(left: 20, right: 20, bottom: 20),
|
||||
child: Text(
|
||||
Platform.isIOS
|
||||
? S.of(context).connect_your_hardware_wallet_ios
|
||||
: S.of(context).connect_your_hardware_wallet,
|
||||
style: Theme.of(context).textTheme.titleMedium,
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
),
|
||||
Offstage(
|
||||
offstage: !longWait,
|
||||
child: Padding(
|
||||
padding: EdgeInsets.only(left: 20, right: 20, bottom: 20),
|
||||
child: Text(
|
||||
S.of(context).if_you_dont_see_your_device,
|
||||
style: Theme.of(context).textTheme.titleMedium,
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
),
|
||||
),
|
||||
Observer(
|
||||
builder: (_) => Offstage(
|
||||
offstage: widget.ledgerVM.bleIsEnabled,
|
||||
child: Padding(
|
||||
return Container(
|
||||
width: ResponsiveLayoutUtilBase.kDesktopMaxWidthConstraint,
|
||||
padding: EdgeInsets.symmetric(vertical: 24, horizontal: 24),
|
||||
child: Column(
|
||||
children: [
|
||||
Expanded(
|
||||
child: SingleChildScrollView(
|
||||
child: Column(
|
||||
children: [
|
||||
Padding(
|
||||
padding: EdgeInsets.only(left: 20, right: 20, bottom: 20),
|
||||
child: Text(
|
||||
S.of(context).ledger_please_enable_bluetooth,
|
||||
style: Theme.of(context).textTheme.titleMedium,
|
||||
Platform.isIOS
|
||||
? S.of(context).connect_your_hardware_wallet_ios
|
||||
: S.of(context).connect_your_hardware_wallet,
|
||||
style: Theme.of(context)
|
||||
.textTheme.titleMedium,
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
),
|
||||
),
|
||||
Offstage(
|
||||
offstage: !longWait,
|
||||
child: Padding(
|
||||
padding: EdgeInsets.only(left: 20, right: 20, bottom: 20),
|
||||
child: Text(
|
||||
S.of(context).if_you_dont_see_your_device,
|
||||
style: Theme.of(context)
|
||||
.textTheme.titleMedium,
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
),
|
||||
),
|
||||
Observer(
|
||||
builder: (_) => Offstage(
|
||||
offstage: widget.ledgerVM.bleIsEnabled,
|
||||
child: Padding(
|
||||
padding:
|
||||
EdgeInsets.only(left: 20, right: 20, bottom: 20),
|
||||
child: Text(
|
||||
S.of(context).ledger_please_enable_bluetooth,
|
||||
style: Theme.of(context)
|
||||
.textTheme.titleMedium,
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
if (bleDevices.length > 0) ...[
|
||||
Padding(
|
||||
padding: EdgeInsets.only(left: 20, right: 20, bottom: 20),
|
||||
child: Container(
|
||||
width: double.infinity,
|
||||
child: Text(
|
||||
S.of(context).bluetooth,
|
||||
style: Theme.of(context)
|
||||
.textTheme.bodyMedium,
|
||||
),
|
||||
),
|
||||
),
|
||||
...bleDevices
|
||||
.map(
|
||||
(device) => Padding(
|
||||
padding: EdgeInsets.only(bottom: 20),
|
||||
child: DeviceTile(
|
||||
onPressed: () => _connectToDevice(device),
|
||||
title: device.name,
|
||||
leading: _getDeviceTileLeading(device.deviceInfo),
|
||||
connectionType: device.connectionType,
|
||||
),
|
||||
),
|
||||
)
|
||||
.toList()
|
||||
],
|
||||
if (usbDevices.length > 0) ...[
|
||||
Padding(
|
||||
padding: EdgeInsets.only(left: 20, right: 20, bottom: 20),
|
||||
child: Container(
|
||||
width: double.infinity,
|
||||
child: Text(
|
||||
S.of(context).usb,
|
||||
style: Theme.of(context)
|
||||
.textTheme.bodyMedium,
|
||||
),
|
||||
),
|
||||
),
|
||||
...usbDevices
|
||||
.map(
|
||||
(device) => Padding(
|
||||
padding: EdgeInsets.only(bottom: 20),
|
||||
child: DeviceTile(
|
||||
onPressed: () => _connectToDevice(device),
|
||||
title: device.name,
|
||||
leading: _getDeviceTileLeading(device.deviceInfo),
|
||||
connectionType: device.connectionType,
|
||||
),
|
||||
),
|
||||
)
|
||||
.toList(),
|
||||
],
|
||||
if (widget.allowChangeWallet) ...[
|
||||
PrimaryButton(
|
||||
text: S.of(context).wallets,
|
||||
color: Theme.of(context)
|
||||
.colorScheme.primary,
|
||||
textColor: Theme.of(context)
|
||||
.colorScheme.onPrimary,
|
||||
onPressed: _onChangeWallet,
|
||||
)
|
||||
],
|
||||
],
|
||||
),
|
||||
if (bleDevices.length > 0) ...[
|
||||
Padding(
|
||||
padding: EdgeInsets.only(left: 20, right: 20, bottom: 20),
|
||||
child: Container(
|
||||
width: double.infinity,
|
||||
child: Text(
|
||||
S.of(context).bluetooth,
|
||||
style: Theme.of(context).textTheme.bodyMedium,
|
||||
),
|
||||
),
|
||||
),
|
||||
...bleDevices
|
||||
.map(
|
||||
(device) => Padding(
|
||||
padding: EdgeInsets.only(bottom: 20),
|
||||
child: DeviceTile(
|
||||
onPressed: () => _connectToDevice(device),
|
||||
title: device.name,
|
||||
leading: _getDeviceTileLeading(device.deviceInfo),
|
||||
connectionType: device.connectionType,
|
||||
),
|
||||
),
|
||||
)
|
||||
.toList()
|
||||
],
|
||||
if (usbDevices.length > 0) ...[
|
||||
Padding(
|
||||
padding: EdgeInsets.only(left: 20, right: 20, bottom: 20),
|
||||
child: Container(
|
||||
width: double.infinity,
|
||||
child: Text(
|
||||
S.of(context).usb,
|
||||
style: Theme.of(context).textTheme.bodyMedium,
|
||||
),
|
||||
),
|
||||
),
|
||||
...usbDevices
|
||||
.map(
|
||||
(device) => Padding(
|
||||
padding: EdgeInsets.only(bottom: 20),
|
||||
child: DeviceTile(
|
||||
onPressed: () => _connectToDevice(device),
|
||||
title: device.name,
|
||||
leading: _getDeviceTileLeading(device.deviceInfo),
|
||||
connectionType: device.connectionType,
|
||||
),
|
||||
),
|
||||
)
|
||||
.toList(),
|
||||
],
|
||||
if (widget.allowChangeWallet) ...[
|
||||
PrimaryButton(
|
||||
text: S.of(context).wallets,
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
textColor: Theme.of(context).colorScheme.onPrimary,
|
||||
onPressed: _onChangeWallet,
|
||||
)
|
||||
],
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
PrimaryButton(
|
||||
text: S.of(context).how_to_connect,
|
||||
color: Theme.of(context).colorScheme.surfaceContainer,
|
||||
textColor: Theme.of(context).colorScheme.onSecondaryContainer,
|
||||
onPressed: () => _onHowToConnect(context),
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -293,4 +315,21 @@ class ConnectDevicePageBodyState extends State<ConnectDevicePageBody> {
|
||||
.pushNamedAndRemoveUntil(Routes.dashboard, (route) => false),
|
||||
);
|
||||
}
|
||||
|
||||
void _onHowToConnect(BuildContext context) {
|
||||
showModalBottomSheet(
|
||||
context: context,
|
||||
isScrollControlled: true,
|
||||
builder: (BuildContext bottomSheetContext) => InfoStepsBottomSheet(
|
||||
titleText: S.of(context).how_to_connect,
|
||||
currentTheme: widget.currentTheme,
|
||||
steps: [
|
||||
InfoStep('${S.of(context).step} 1', S.of(context).connect_hw_info_step_1),
|
||||
InfoStep('${S.of(context).step} 2', S.of(context).connect_hw_info_step_2),
|
||||
InfoStep('${S.of(context).step} 3', S.of(context).connect_hw_info_step_3),
|
||||
InfoStep('${S.of(context).step} 4', S.of(context).connect_hw_info_step_4),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -684,29 +684,47 @@ class SendPage extends BasePage {
|
||||
});
|
||||
}
|
||||
|
||||
if (state is IsAwaitingDeviceResponseState) {
|
||||
if (state is IsDeviceSigningResponseState) {
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
if (!context.mounted) return;
|
||||
|
||||
showModalBottomSheet<void>(
|
||||
context: context,
|
||||
isDismissible: false,
|
||||
builder: (BuildContext bottomSheetContext) => InfoBottomSheet(
|
||||
currentTheme: currentTheme,
|
||||
titleText: S.of(bottomSheetContext).proceed_on_device,
|
||||
contentImage: 'assets/images/hardware_wallet/ledger_nano_x.png',
|
||||
contentImageColor: Theme.of(context).colorScheme.onSurface,
|
||||
content: S.of(bottomSheetContext).proceed_on_device_description,
|
||||
isTwoAction: false,
|
||||
actionButtonText: S.of(context).cancel,
|
||||
actionButton: () {
|
||||
sendViewModel.state = InitialExecutionState();
|
||||
Navigator.of(bottomSheetContext).pop();
|
||||
},
|
||||
),
|
||||
builder: (context) {
|
||||
dialogContext = context;
|
||||
return LoadingBottomSheet(titleText: S.of(context).device_is_signing);
|
||||
},
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
if (state is IsAwaitingDeviceResponseState) {
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
if (!context.mounted) return;
|
||||
|
||||
showModalBottomSheet<void>(
|
||||
context: context,
|
||||
isDismissible: false,
|
||||
builder: (context) {
|
||||
dialogContext = context;
|
||||
return InfoBottomSheet(
|
||||
currentTheme: currentTheme,
|
||||
titleText: S.of(context).proceed_on_device,
|
||||
contentImage:
|
||||
'assets/images/hardware_wallet/ledger_nano_x.png',
|
||||
contentImageColor: Theme.of(context).colorScheme.onSurface,
|
||||
content: S.of(context).proceed_on_device_description,
|
||||
isTwoAction: false,
|
||||
actionButtonText: S.of(context).cancel,
|
||||
actionButton: () {
|
||||
sendViewModel.state = InitialExecutionState();
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
);
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
_effectsInstalled = true;
|
||||
|
||||
@@ -0,0 +1,114 @@
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/src/widgets/primary_button.dart';
|
||||
import 'package:cake_wallet/themes/core/material_base_theme.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'base_bottom_sheet_widget.dart';
|
||||
|
||||
class InfoStep {
|
||||
final String title;
|
||||
final String description;
|
||||
|
||||
const InfoStep(this.title, this.description);
|
||||
}
|
||||
|
||||
class InfoStepsBottomSheet extends BaseBottomSheet {
|
||||
final MaterialThemeBase currentTheme;
|
||||
final List<InfoStep> steps;
|
||||
|
||||
InfoStepsBottomSheet({
|
||||
required String titleText,
|
||||
required this.steps,
|
||||
String? titleIconPath,
|
||||
required this.currentTheme,
|
||||
}) : super(titleText: titleText, titleIconPath: titleIconPath);
|
||||
|
||||
@override
|
||||
Widget contentWidget(BuildContext context) => SizedBox(
|
||||
height: 500,
|
||||
child: Column(
|
||||
children: [
|
||||
Expanded(
|
||||
child: SingleChildScrollView(
|
||||
child: Column(
|
||||
children: steps
|
||||
.map((step) => Container(
|
||||
margin: EdgeInsets.only(
|
||||
bottom: 15, left: 20, right: 20),
|
||||
padding: EdgeInsets.all(10),
|
||||
alignment: Alignment.center,
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
color: Theme.of(context).cardColor,
|
||||
),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: Padding(
|
||||
padding: EdgeInsets.only(left: 16),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.start,
|
||||
crossAxisAlignment:
|
||||
CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
Text(
|
||||
step.title,
|
||||
style: Theme.of(context)
|
||||
.textTheme
|
||||
.bodyMedium!
|
||||
.copyWith(
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Theme.of(context)
|
||||
.colorScheme
|
||||
.onSurface,
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: 5),
|
||||
child: Text(
|
||||
step.description,
|
||||
style: Theme.of(context)
|
||||
.textTheme
|
||||
.bodyMedium!
|
||||
.copyWith(
|
||||
color: Theme.of(context)
|
||||
.colorScheme
|
||||
.onSurfaceVariant,
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
))
|
||||
.toList(),
|
||||
),
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: PrimaryButton(
|
||||
text: S.of(context).close,
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
textColor: currentTheme.isDark
|
||||
? Theme.of(context).colorScheme.onSurfaceVariant
|
||||
: Theme.of(context).colorScheme.onPrimary,
|
||||
onPressed: () => Navigator.of(context).pop(),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
@override
|
||||
Widget footerWidget(BuildContext context) => SizedBox.shrink();
|
||||
}
|
||||
Reference in New Issue
Block a user