1
import 'dart:async';
2
import 'dart:io';
3
4
+import 'package:cake_wallet/entities/hardware_wallet/hardware_wallet_device.dart';
5
import 'package:cake_wallet/generated/i18n.dart';
6
import 'package:cake_wallet/routes.dart';
7
import 'package:cake_wallet/src/screens/base_page.dart';
10
import 'package:cake_wallet/src/widgets/primary_button.dart';
11
import 'package:cake_wallet/themes/core/material_base_theme.dart';
12
import 'package:cake_wallet/utils/responsive_layout_util.dart';
12
-import 'package:cake_wallet/view_model/hardware_wallet/ledger_view_model.dart';
13
+import 'package:cake_wallet/view_model/hardware_wallet/hardware_wallet_view_model.dart';
14
import 'package:cw_core/utils/print_verbose.dart';
15
+import 'package:cw_core/wallet_info.dart';
16
import 'package:cw_core/wallet_type.dart';
17
import 'package:flutter/material.dart';
18
import 'package:flutter_mobx/flutter_mobx.dart';
17
-import 'package:ledger_flutter_plus/ledger_flutter_plus.dart';
19
19
-typedef OnConnectDevice = void Function(BuildContext, LedgerViewModel);
20
+typedef OnConnectDevice = void Function(BuildContext, HardwareWalletViewModel);
21
22
class ConnectDevicePageParams {
23
final WalletType walletType;
24
final OnConnectDevice onConnectDevice;
25
final bool allowChangeWallet;
26
final bool isReconnect;
27
+ final HardwareWalletType hardwareWalletType;
28
29
ConnectDevicePageParams({
30
required this.walletType,
31
+ required this.hardwareWalletType,
32
required this.onConnectDevice,
33
this.allowChangeWallet = false,
34
this.isReconnect = true,
40
final OnConnectDevice onConnectDevice;
41
final bool allowChangeWallet;
42
final bool isReconnect;
40
- final LedgerViewModel ledgerVM;
43
+ final HardwareWalletViewModel hardwareWalletVM;
44
42
- ConnectDevicePage(ConnectDevicePageParams params, this.ledgerVM)
45
+ ConnectDevicePage(ConnectDevicePageParams params, this.hardwareWalletVM)
46
: walletType = params.walletType,
47
onConnectDevice = params.onConnectDevice,
48
allowChangeWallet = params.allowChangeWallet,
54
: S.current.restore_title_from_hardware_wallet;
55
56
@override
54
- Widget? leading(BuildContext context) =>
55
- !isReconnect ? super.leading(context) : null;
57
+ Widget? leading(BuildContext context) => !isReconnect ? super.leading(context) : null;
58
59
@override
60
Widget body(BuildContext context) => PopScope(
63
walletType,
64
onConnectDevice,
65
allowChangeWallet,
64
- ledgerVM,
66
+ hardwareWalletVM,
67
currentTheme,
68
));
69
}
72
final WalletType walletType;
73
final OnConnectDevice onConnectDevice;
74
final bool allowChangeWallet;
73
- final LedgerViewModel ledgerVM;
75
+ final HardwareWalletViewModel hardwareWalletVM;
76
final MaterialThemeBase currentTheme;
77
78
const ConnectDevicePageBody(
79
this.walletType,
80
this.onConnectDevice,
81
this.allowChangeWallet,
80
- this.ledgerVM,
82
+ this.hardwareWalletVM,
83
this.currentTheme,
84
);
85
88
}
89
90
class ConnectDevicePageBodyState extends State<ConnectDevicePageBody> {
89
- var bleDevices = <LedgerDevice>[];
90
- var usbDevices = <LedgerDevice>[];
91
+ var bleDevices = <HardwareWalletDevice>[];
92
+ var usbDevices = <HardwareWalletDevice>[];
93
94
late Timer? _usbRefreshTimer = null;
95
late Timer? _bleRefreshTimer = null;
96
late Timer? _bleStateTimer = null;
95
- late StreamSubscription<LedgerDevice>? _bleRefresh = null;
97
+ late StreamSubscription<HardwareWalletDevice>? _bleRefresh = null;
98
99
bool longWait = false;
100
Timer? _longWaitTimer;
103
void initState() {
104
super.initState();
105
WidgetsBinding.instance.addPostFrameCallback((_) {
104
- _bleStateTimer = Timer.periodic(
105
- Duration(seconds: 1), (_) => widget.ledgerVM.updateBleState());
106
+ _bleStateTimer =
107
+ Timer.periodic(Duration(seconds: 1), (_) => widget.hardwareWalletVM.updateBleState());
108
107
- _bleRefreshTimer =
108
- Timer.periodic(Duration(seconds: 1), (_) => _refreshBleDevices());
109
+ _bleRefreshTimer = Timer.periodic(Duration(seconds: 1), (_) => _refreshBleDevices());
110
111
if (Platform.isAndroid) {
111
- _usbRefreshTimer =
112
- Timer.periodic(Duration(seconds: 1), (_) => _refreshUsbDevices());
112
+ _usbRefreshTimer = Timer.periodic(Duration(seconds: 1), (_) => _refreshUsbDevices());
113
}
114
115
- _longWaitTimer = Timer(Duration(seconds: 10), () {
116
- if (widget.ledgerVM.bleIsEnabled && bleDevices.isEmpty)
117
- setState(() => longWait = true);
118
- });
115
+ if (widget.hardwareWalletVM.hasBluetooth) {
116
+ _longWaitTimer = Timer(Duration(seconds: 10), () {
117
+ if (widget.hardwareWalletVM.isBleEnabled && bleDevices.isEmpty)
118
+ setState(() => longWait = true);
119
+ });
120
+ }
121
});
122
}
123
129
_bleRefresh?.cancel();
130
_longWaitTimer?.cancel();
131
130
- widget.ledgerVM.stopScanning();
132
+ widget.hardwareWalletVM.stopScanning();
133
super.dispose();
134
}
135
136
Future<void> _refreshUsbDevices() async {
135
- final dev = await widget.ledgerVM.ledgerPlusUSB.devices;
137
+ final dev = await widget.hardwareWalletVM.getAllUsbDevices();
138
if (usbDevices.length != dev.length) setState(() => usbDevices = dev);
137
- // _usbRefresh = widget.ledgerVM
138
- // .scanForUsbDevices()
139
- // .listen((device) => setState(() => usbDevices.add(device)))
140
- // ..onError((e) {
141
- // throw e.toString();
142
- // });
143
- // Keep polling until the lfp lib gets updated
144
- // _usbRefreshTimer?.cancel();
145
- // _usbRefreshTimer = null;
139
}
140
141
Future<void> _refreshBleDevices() async {
142
try {
150
- if (widget.ledgerVM.bleIsEnabled) {
151
- _bleRefresh =
152
- widget.ledgerVM.scanForBleDevices().listen((device) => setState(() {
153
- bleDevices.add(device);
154
- if (longWait) longWait = false;
155
- }))
156
- ..onError((e) {
157
- throw e.toString();
158
- });
143
+ if (widget.hardwareWalletVM.isBleEnabled) {
144
+ _bleRefresh = widget.hardwareWalletVM.scanForBleDevices().listen((device) => setState(() {
145
+ bleDevices.add(device);
146
+ if (longWait) longWait = false;
147
+ }))
148
+ ..onError((e) {
149
+ throw e.toString();
150
+ });
151
_bleRefreshTimer?.cancel();
152
_bleRefreshTimer = null;
153
}
156
}
157
}
158
167
- Future<void> _connectToDevice(LedgerDevice device) async {
168
- final isConnected =
169
- await widget.ledgerVM.connectLedger(device, widget.walletType);
170
- if (isConnected) widget.onConnectDevice(context, widget.ledgerVM);
159
+ Future<void> _connectToDevice(HardwareWalletDevice device) async {
160
+ final isConnected = await widget.hardwareWalletVM.connectDevice(device, widget.walletType);
161
+ if (isConnected) widget.onConnectDevice(context, widget.hardwareWalletVM);
162
}
163
173
- String _getDeviceTileLeading(LedgerDeviceType deviceInfo) {
174
- switch (deviceInfo) {
175
- case LedgerDeviceType.nanoX:
164
+ String _getDeviceTileLeading(HardwareWalletDeviceType deviceType) {
165
+ switch (deviceType) {
166
+ case HardwareWalletDeviceType.ledgerNanoX:
167
return 'assets/images/hardware_wallet/ledger_nano_x.png';
177
- case LedgerDeviceType.stax:
168
+ case HardwareWalletDeviceType.ledgerStax:
169
return 'assets/images/hardware_wallet/ledger_stax.png';
179
- case LedgerDeviceType.flex:
170
+ case HardwareWalletDeviceType.ledgerFlex:
171
return 'assets/images/hardware_wallet/ledger_flex.png';
172
+ case HardwareWalletDeviceType.BitBox02:
173
+ return 'assets/images/hardware_wallet/device_bitbox.svg';
174
+
175
default:
176
return 'assets/images/hardware_wallet/ledger_nano_x.png';
177
}
178
}
179
180
+ String get description {
181
+ if (!Platform.isAndroid) return S.of(context).connect_your_hardware_wallet_ble;
182
+
183
+ if (widget.hardwareWalletVM.hasBluetooth) return S.of(context).connect_your_hardware_wallet;
184
+
185
+ return S.of(context).connect_your_hardware_wallet_usb;
186
+ }
187
+
188
@override
189
Widget build(BuildContext context) {
190
return Container(
199
Padding(
200
padding: EdgeInsets.only(left: 20, right: 20, bottom: 20),
201
child: Text(
200
- Platform.isAndroid
201
- ? S.of(context).connect_your_hardware_wallet
202
- : S.of(context).connect_your_hardware_wallet_ios,
203
- style: Theme.of(context)
204
- .textTheme.titleMedium,
202
+ description,
203
+ style: Theme.of(context).textTheme.titleMedium,
204
textAlign: TextAlign.center,
205
),
206
),
210
padding: EdgeInsets.only(left: 20, right: 20, bottom: 20),
211
child: Text(
212
S.of(context).if_you_dont_see_your_device,
214
- style: Theme.of(context)
215
- .textTheme.titleMedium,
213
+ style: Theme.of(context).textTheme.titleMedium,
214
textAlign: TextAlign.center,
215
),
216
),
217
),
218
Observer(
219
builder: (_) => Offstage(
222
- offstage: widget.ledgerVM.bleIsEnabled,
220
+ offstage: widget.hardwareWalletVM.isBleEnabled ||
221
+ !widget.hardwareWalletVM.hasBluetooth,
222
child: Padding(
224
- padding:
225
- EdgeInsets.only(left: 20, right: 20, bottom: 20),
223
+ padding: EdgeInsets.only(left: 20, right: 20, bottom: 20),
224
child: Text(
225
S.of(context).ledger_please_enable_bluetooth,
228
- style: Theme.of(context)
229
- .textTheme.titleMedium,
226
+ style: Theme.of(context).textTheme.titleMedium,
227
textAlign: TextAlign.center,
228
),
229
),
236
width: double.infinity,
237
child: Text(
238
S.of(context).bluetooth,
242
- style: Theme.of(context)
243
- .textTheme.bodyMedium,
239
+ style: Theme.of(context).textTheme.bodyMedium,
240
),
241
),
242
),
247
child: DeviceTile(
248
onPressed: () => _connectToDevice(device),
249
title: device.name,
254
- leading: _getDeviceTileLeading(device.deviceInfo),
250
+ leading: _getDeviceTileLeading(device.type),
251
connectionType: device.connectionType,
252
),
253
),
261
width: double.infinity,
262
child: Text(
263
S.of(context).usb,
268
- style: Theme.of(context)
269
- .textTheme.bodyMedium,
264
+ style: Theme.of(context).textTheme.bodyMedium,
265
),
266
),
267
),
272
child: DeviceTile(
273
onPressed: () => _connectToDevice(device),
274
title: device.name,
280
- leading: _getDeviceTileLeading(device.deviceInfo),
275
+ leading: _getDeviceTileLeading(device.type),
276
connectionType: device.connectionType,
277
),
278
),
282
if (widget.allowChangeWallet) ...[
283
PrimaryButton(
284
text: S.of(context).wallets,
290
- color: Theme.of(context)
291
- .colorScheme.primary,
292
- textColor: Theme.of(context)
293
- .colorScheme.onPrimary,
285
+ color: Theme.of(context).colorScheme.primary,
286
+ textColor: Theme.of(context).colorScheme.onPrimary,
287
onPressed: _onChangeWallet,
288
)
289
],
305
void _onChangeWallet() {
306
Navigator.of(context).pushNamed(
307
Routes.walletList,
315
- arguments: (BuildContext context) => Navigator.of(context)
316
- .pushNamedAndRemoveUntil(Routes.dashboard, (route) => false),
308
+ arguments: (BuildContext context) =>
309
+ Navigator.of(context).pushNamedAndRemoveUntil(Routes.dashboard, (route) => false),
310
);
311
}
312