2022-04-04 10:56:34 +03:00
|
|
|
import 'dart:io';
|
|
|
|
|
2021-12-02 13:44:17 +03:00
|
|
|
import 'package:flutter/material.dart';
|
|
|
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|
|
|
|
2022-04-04 11:24:29 +03:00
|
|
|
import '../../management/models.dart';
|
2021-12-02 13:44:17 +03:00
|
|
|
import '../models.dart';
|
|
|
|
import '../state.dart';
|
|
|
|
import 'device_avatar.dart';
|
|
|
|
|
2022-03-31 12:41:28 +03:00
|
|
|
class DevicePickerDialog extends ConsumerWidget {
|
|
|
|
const DevicePickerDialog({Key? key}) : super(key: key);
|
2021-12-02 13:44:17 +03:00
|
|
|
|
|
|
|
@override
|
|
|
|
Widget build(BuildContext context, WidgetRef ref) {
|
2022-01-12 14:49:04 +03:00
|
|
|
final devices = ref.watch(attachedDevicesProvider).toList();
|
|
|
|
final currentNode = ref.watch(currentDeviceProvider);
|
|
|
|
final data = ref.watch(currentDeviceDataProvider);
|
|
|
|
|
|
|
|
if (currentNode != null) {
|
2022-02-08 15:44:35 +03:00
|
|
|
devices.removeWhere((e) => e.path == currentNode.path);
|
2022-01-12 14:49:04 +03:00
|
|
|
}
|
2021-12-02 13:44:17 +03:00
|
|
|
|
|
|
|
return SimpleDialog(
|
|
|
|
children: [
|
2022-04-04 10:56:34 +03:00
|
|
|
currentNode == null
|
|
|
|
? ListTile(
|
|
|
|
leading: const DeviceAvatar(child: Icon(Icons.no_cell)),
|
|
|
|
title: const Text('No YubiKey'),
|
|
|
|
subtitle: Text(Platform.isAndroid
|
|
|
|
? 'Insert or tap a YubiKey'
|
|
|
|
: (devices.isEmpty
|
|
|
|
? 'Insert a YubiKey'
|
|
|
|
: 'Insert a YubiKey, or select an item below')),
|
|
|
|
)
|
|
|
|
: _CurrentDeviceRow(
|
|
|
|
currentNode,
|
|
|
|
data: data,
|
|
|
|
onTap: () {
|
|
|
|
Navigator.of(context).pop();
|
|
|
|
},
|
|
|
|
),
|
2022-03-31 12:41:28 +03:00
|
|
|
if (devices.isNotEmpty) const Divider(),
|
2022-01-12 14:49:04 +03:00
|
|
|
...devices.map(
|
2022-02-01 15:30:03 +03:00
|
|
|
(e) => _DeviceRow(
|
2022-01-12 14:49:04 +03:00
|
|
|
e,
|
2022-02-01 15:30:03 +03:00
|
|
|
info: e.map(
|
|
|
|
usbYubiKey: (node) => node.info,
|
|
|
|
nfcReader: (_) => null,
|
2022-01-12 14:49:04 +03:00
|
|
|
),
|
|
|
|
onTap: () {
|
|
|
|
Navigator.of(context).pop();
|
|
|
|
ref.read(currentDeviceProvider.notifier).setCurrentDevice(e);
|
|
|
|
},
|
|
|
|
),
|
|
|
|
),
|
2021-12-02 13:44:17 +03:00
|
|
|
],
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-02-01 15:30:03 +03:00
|
|
|
class _CurrentDeviceRow extends StatelessWidget {
|
2022-01-12 14:49:04 +03:00
|
|
|
final DeviceNode node;
|
2022-02-01 15:30:03 +03:00
|
|
|
final YubiKeyData? data;
|
2022-01-12 14:49:04 +03:00
|
|
|
final Function() onTap;
|
|
|
|
|
2022-02-01 15:30:03 +03:00
|
|
|
const _CurrentDeviceRow(
|
|
|
|
this.node, {
|
|
|
|
this.data,
|
2022-01-12 14:49:04 +03:00
|
|
|
required this.onTap,
|
|
|
|
Key? key,
|
|
|
|
}) : super(key: key);
|
|
|
|
|
|
|
|
@override
|
|
|
|
Widget build(BuildContext context) {
|
2022-03-07 17:36:49 +03:00
|
|
|
return node.when(usbYubiKey: (path, name, pid, info) {
|
|
|
|
if (info != null) {
|
|
|
|
return ListTile(
|
|
|
|
leading: DeviceAvatar.yubiKeyData(
|
|
|
|
data!,
|
|
|
|
selected: true,
|
|
|
|
),
|
|
|
|
title: Text(name),
|
|
|
|
subtitle: Text('S/N: ${info.serial} F/W: ${info.version}'),
|
|
|
|
onTap: onTap,
|
|
|
|
);
|
|
|
|
} else {
|
|
|
|
{
|
|
|
|
return ListTile(
|
|
|
|
leading: DeviceAvatar.deviceNode(
|
2022-02-01 15:30:03 +03:00
|
|
|
node,
|
|
|
|
selected: true,
|
|
|
|
),
|
2022-03-07 17:36:49 +03:00
|
|
|
title: Text(name),
|
|
|
|
subtitle: const Text('Device inaccessible'),
|
|
|
|
onTap: onTap,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}, nfcReader: (path, name) {
|
|
|
|
final info = data?.info;
|
|
|
|
if (info != null) {
|
|
|
|
return ListTile(
|
|
|
|
leading: DeviceAvatar.yubiKeyData(
|
|
|
|
data!,
|
|
|
|
selected: true,
|
|
|
|
),
|
|
|
|
title: Text(data!.name),
|
|
|
|
isThreeLine: true,
|
|
|
|
subtitle: Text('$name\nS/N: ${info.serial} F/W: ${info.version}'),
|
|
|
|
onTap: onTap,
|
|
|
|
);
|
|
|
|
} else {
|
|
|
|
return ListTile(
|
|
|
|
leading: DeviceAvatar.deviceNode(
|
|
|
|
node,
|
|
|
|
selected: true,
|
|
|
|
),
|
|
|
|
title: const Text('No YubiKey present'),
|
|
|
|
subtitle: Text(name),
|
|
|
|
onTap: onTap,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
});
|
2022-01-12 14:49:04 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-02-01 15:30:03 +03:00
|
|
|
class _DeviceRow extends StatelessWidget {
|
2022-01-12 14:49:04 +03:00
|
|
|
final DeviceNode node;
|
|
|
|
final DeviceInfo? info;
|
|
|
|
final Function() onTap;
|
|
|
|
|
2022-02-01 15:30:03 +03:00
|
|
|
const _DeviceRow(
|
|
|
|
this.node, {
|
2022-01-12 14:49:04 +03:00
|
|
|
required this.info,
|
|
|
|
required this.onTap,
|
2021-12-02 13:44:17 +03:00
|
|
|
Key? key,
|
|
|
|
}) : super(key: key);
|
|
|
|
|
|
|
|
@override
|
|
|
|
Widget build(BuildContext context) {
|
2022-01-12 14:49:04 +03:00
|
|
|
return ListTile(
|
2022-02-01 15:30:03 +03:00
|
|
|
leading: DeviceAvatar.deviceNode(node),
|
|
|
|
title: Text(node.name),
|
2022-01-12 14:49:04 +03:00
|
|
|
subtitle: Text(
|
2022-02-01 15:30:03 +03:00
|
|
|
node.when(
|
2022-03-07 17:36:49 +03:00
|
|
|
usbYubiKey: (_, __, ___, info) => info == null
|
|
|
|
? 'Device inaccessible'
|
|
|
|
: 'S/N: ${info.serial} F/W: ${info.version}',
|
2022-02-01 15:30:03 +03:00
|
|
|
nfcReader: (_, __) => 'Select to scan',
|
|
|
|
),
|
2021-12-02 13:44:17 +03:00
|
|
|
),
|
2022-01-12 14:49:04 +03:00
|
|
|
onTap: onTap,
|
2021-12-02 13:44:17 +03:00
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|