This commit is contained in:
Dain Nilsson 2022-01-19 11:15:19 +01:00
commit edc488985a
No known key found for this signature in database
GPG Key ID: F04367096FBA95E8
18 changed files with 1025 additions and 393 deletions

View File

@ -3,22 +3,21 @@ import 'package:freezed_annotation/freezed_annotation.dart';
import '../../management/models.dart';
part 'models.freezed.dart';
part 'models.g.dart';
enum SubPage { authenticator, yubikey }
@freezed
class DeviceNode with _$DeviceNode {
factory DeviceNode(
List<String> path,
int pid,
Transport transport,
String name,
DeviceInfo info,
) = _DeviceNode;
class YubiKeyData with _$YubiKeyData {
factory YubiKeyData(DeviceNode node, String name, DeviceInfo info) =
_YubiKeyData;
}
factory DeviceNode.fromJson(Map<String, dynamic> json) =>
_$DeviceNodeFromJson(json);
@freezed
class DeviceNode with _$DeviceNode {
factory DeviceNode.usbYubiKey(
List<String> path, String name, int pid, DeviceInfo info) =
UsbYubiKeyNode;
factory DeviceNode.nfcReader(List<String> path, String name) = NfcReaderNode;
}
@freezed

View File

@ -1,5 +1,6 @@
// coverage:ignore-file
// GENERATED CODE - DO NOT MODIFY BY HAND
// ignore_for_file: type=lint
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target
part of 'models.dart';
@ -13,27 +14,212 @@ T _$identity<T>(T value) => value;
final _privateConstructorUsedError = UnsupportedError(
'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more informations: https://github.com/rrousselGit/freezed#custom-getters-and-methods');
DeviceNode _$DeviceNodeFromJson(Map<String, dynamic> json) {
return _DeviceNode.fromJson(json);
/// @nodoc
class _$YubiKeyDataTearOff {
const _$YubiKeyDataTearOff();
_YubiKeyData call(DeviceNode node, String name, DeviceInfo info) {
return _YubiKeyData(
node,
name,
info,
);
}
}
/// @nodoc
const $YubiKeyData = _$YubiKeyDataTearOff();
/// @nodoc
mixin _$YubiKeyData {
DeviceNode get node => throw _privateConstructorUsedError;
String get name => throw _privateConstructorUsedError;
DeviceInfo get info => throw _privateConstructorUsedError;
@JsonKey(ignore: true)
$YubiKeyDataCopyWith<YubiKeyData> get copyWith =>
throw _privateConstructorUsedError;
}
/// @nodoc
abstract class $YubiKeyDataCopyWith<$Res> {
factory $YubiKeyDataCopyWith(
YubiKeyData value, $Res Function(YubiKeyData) then) =
_$YubiKeyDataCopyWithImpl<$Res>;
$Res call({DeviceNode node, String name, DeviceInfo info});
$DeviceNodeCopyWith<$Res> get node;
$DeviceInfoCopyWith<$Res> get info;
}
/// @nodoc
class _$YubiKeyDataCopyWithImpl<$Res> implements $YubiKeyDataCopyWith<$Res> {
_$YubiKeyDataCopyWithImpl(this._value, this._then);
final YubiKeyData _value;
// ignore: unused_field
final $Res Function(YubiKeyData) _then;
@override
$Res call({
Object? node = freezed,
Object? name = freezed,
Object? info = freezed,
}) {
return _then(_value.copyWith(
node: node == freezed
? _value.node
: node // ignore: cast_nullable_to_non_nullable
as DeviceNode,
name: name == freezed
? _value.name
: name // ignore: cast_nullable_to_non_nullable
as String,
info: info == freezed
? _value.info
: info // ignore: cast_nullable_to_non_nullable
as DeviceInfo,
));
}
@override
$DeviceNodeCopyWith<$Res> get node {
return $DeviceNodeCopyWith<$Res>(_value.node, (value) {
return _then(_value.copyWith(node: value));
});
}
@override
$DeviceInfoCopyWith<$Res> get info {
return $DeviceInfoCopyWith<$Res>(_value.info, (value) {
return _then(_value.copyWith(info: value));
});
}
}
/// @nodoc
abstract class _$YubiKeyDataCopyWith<$Res>
implements $YubiKeyDataCopyWith<$Res> {
factory _$YubiKeyDataCopyWith(
_YubiKeyData value, $Res Function(_YubiKeyData) then) =
__$YubiKeyDataCopyWithImpl<$Res>;
@override
$Res call({DeviceNode node, String name, DeviceInfo info});
@override
$DeviceNodeCopyWith<$Res> get node;
@override
$DeviceInfoCopyWith<$Res> get info;
}
/// @nodoc
class __$YubiKeyDataCopyWithImpl<$Res> extends _$YubiKeyDataCopyWithImpl<$Res>
implements _$YubiKeyDataCopyWith<$Res> {
__$YubiKeyDataCopyWithImpl(
_YubiKeyData _value, $Res Function(_YubiKeyData) _then)
: super(_value, (v) => _then(v as _YubiKeyData));
@override
_YubiKeyData get _value => super._value as _YubiKeyData;
@override
$Res call({
Object? node = freezed,
Object? name = freezed,
Object? info = freezed,
}) {
return _then(_YubiKeyData(
node == freezed
? _value.node
: node // ignore: cast_nullable_to_non_nullable
as DeviceNode,
name == freezed
? _value.name
: name // ignore: cast_nullable_to_non_nullable
as String,
info == freezed
? _value.info
: info // ignore: cast_nullable_to_non_nullable
as DeviceInfo,
));
}
}
/// @nodoc
class _$_YubiKeyData implements _YubiKeyData {
_$_YubiKeyData(this.node, this.name, this.info);
@override
final DeviceNode node;
@override
final String name;
@override
final DeviceInfo info;
@override
String toString() {
return 'YubiKeyData(node: $node, name: $name, info: $info)';
}
@override
bool operator ==(dynamic other) {
return identical(this, other) ||
(other.runtimeType == runtimeType &&
other is _YubiKeyData &&
const DeepCollectionEquality().equals(other.node, node) &&
const DeepCollectionEquality().equals(other.name, name) &&
const DeepCollectionEquality().equals(other.info, info));
}
@override
int get hashCode => Object.hash(
runtimeType,
const DeepCollectionEquality().hash(node),
const DeepCollectionEquality().hash(name),
const DeepCollectionEquality().hash(info));
@JsonKey(ignore: true)
@override
_$YubiKeyDataCopyWith<_YubiKeyData> get copyWith =>
__$YubiKeyDataCopyWithImpl<_YubiKeyData>(this, _$identity);
}
abstract class _YubiKeyData implements YubiKeyData {
factory _YubiKeyData(DeviceNode node, String name, DeviceInfo info) =
_$_YubiKeyData;
@override
DeviceNode get node;
@override
String get name;
@override
DeviceInfo get info;
@override
@JsonKey(ignore: true)
_$YubiKeyDataCopyWith<_YubiKeyData> get copyWith =>
throw _privateConstructorUsedError;
}
/// @nodoc
class _$DeviceNodeTearOff {
const _$DeviceNodeTearOff();
_DeviceNode call(List<String> path, int pid, Transport transport, String name,
DeviceInfo info) {
return _DeviceNode(
UsbYubiKeyNode usbYubiKey(
List<String> path, String name, int pid, DeviceInfo info) {
return UsbYubiKeyNode(
path,
pid,
transport,
name,
pid,
info,
);
}
DeviceNode fromJson(Map<String, Object?> json) {
return DeviceNode.fromJson(json);
NfcReaderNode nfcReader(List<String> path, String name) {
return NfcReaderNode(
path,
name,
);
}
}
@ -43,12 +229,51 @@ const $DeviceNode = _$DeviceNodeTearOff();
/// @nodoc
mixin _$DeviceNode {
List<String> get path => throw _privateConstructorUsedError;
int get pid => throw _privateConstructorUsedError;
Transport get transport => throw _privateConstructorUsedError;
String get name => throw _privateConstructorUsedError;
DeviceInfo get info => throw _privateConstructorUsedError;
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function(
List<String> path, String name, int pid, DeviceInfo info)
usbYubiKey,
required TResult Function(List<String> path, String name) nfcReader,
}) =>
throw _privateConstructorUsedError;
@optionalTypeArgs
TResult? whenOrNull<TResult extends Object?>({
TResult Function(List<String> path, String name, int pid, DeviceInfo info)?
usbYubiKey,
TResult Function(List<String> path, String name)? nfcReader,
}) =>
throw _privateConstructorUsedError;
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function(List<String> path, String name, int pid, DeviceInfo info)?
usbYubiKey,
TResult Function(List<String> path, String name)? nfcReader,
required TResult orElse(),
}) =>
throw _privateConstructorUsedError;
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(UsbYubiKeyNode value) usbYubiKey,
required TResult Function(NfcReaderNode value) nfcReader,
}) =>
throw _privateConstructorUsedError;
@optionalTypeArgs
TResult? mapOrNull<TResult extends Object?>({
TResult Function(UsbYubiKeyNode value)? usbYubiKey,
TResult Function(NfcReaderNode value)? nfcReader,
}) =>
throw _privateConstructorUsedError;
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(UsbYubiKeyNode value)? usbYubiKey,
TResult Function(NfcReaderNode value)? nfcReader,
required TResult orElse(),
}) =>
throw _privateConstructorUsedError;
@JsonKey(ignore: true)
$DeviceNodeCopyWith<DeviceNode> get copyWith =>
throw _privateConstructorUsedError;
@ -59,14 +284,7 @@ abstract class $DeviceNodeCopyWith<$Res> {
factory $DeviceNodeCopyWith(
DeviceNode value, $Res Function(DeviceNode) then) =
_$DeviceNodeCopyWithImpl<$Res>;
$Res call(
{List<String> path,
int pid,
Transport transport,
String name,
DeviceInfo info});
$DeviceInfoCopyWith<$Res> get info;
$Res call({List<String> path, String name});
}
/// @nodoc
@ -80,29 +298,64 @@ class _$DeviceNodeCopyWithImpl<$Res> implements $DeviceNodeCopyWith<$Res> {
@override
$Res call({
Object? path = freezed,
Object? pid = freezed,
Object? transport = freezed,
Object? name = freezed,
Object? info = freezed,
}) {
return _then(_value.copyWith(
path: path == freezed
? _value.path
: path // ignore: cast_nullable_to_non_nullable
as List<String>,
pid: pid == freezed
? _value.pid
: pid // ignore: cast_nullable_to_non_nullable
as int,
transport: transport == freezed
? _value.transport
: transport // ignore: cast_nullable_to_non_nullable
as Transport,
name: name == freezed
? _value.name
: name // ignore: cast_nullable_to_non_nullable
as String,
info: info == freezed
));
}
}
/// @nodoc
abstract class $UsbYubiKeyNodeCopyWith<$Res>
implements $DeviceNodeCopyWith<$Res> {
factory $UsbYubiKeyNodeCopyWith(
UsbYubiKeyNode value, $Res Function(UsbYubiKeyNode) then) =
_$UsbYubiKeyNodeCopyWithImpl<$Res>;
@override
$Res call({List<String> path, String name, int pid, DeviceInfo info});
$DeviceInfoCopyWith<$Res> get info;
}
/// @nodoc
class _$UsbYubiKeyNodeCopyWithImpl<$Res> extends _$DeviceNodeCopyWithImpl<$Res>
implements $UsbYubiKeyNodeCopyWith<$Res> {
_$UsbYubiKeyNodeCopyWithImpl(
UsbYubiKeyNode _value, $Res Function(UsbYubiKeyNode) _then)
: super(_value, (v) => _then(v as UsbYubiKeyNode));
@override
UsbYubiKeyNode get _value => super._value as UsbYubiKeyNode;
@override
$Res call({
Object? path = freezed,
Object? name = freezed,
Object? pid = freezed,
Object? info = freezed,
}) {
return _then(UsbYubiKeyNode(
path == freezed
? _value.path
: path // ignore: cast_nullable_to_non_nullable
as List<String>,
name == freezed
? _value.name
: name // ignore: cast_nullable_to_non_nullable
as String,
pid == freezed
? _value.pid
: pid // ignore: cast_nullable_to_non_nullable
as int,
info == freezed
? _value.info
: info // ignore: cast_nullable_to_non_nullable
as DeviceInfo,
@ -118,137 +371,282 @@ class _$DeviceNodeCopyWithImpl<$Res> implements $DeviceNodeCopyWith<$Res> {
}
/// @nodoc
abstract class _$DeviceNodeCopyWith<$Res> implements $DeviceNodeCopyWith<$Res> {
factory _$DeviceNodeCopyWith(
_DeviceNode value, $Res Function(_DeviceNode) then) =
__$DeviceNodeCopyWithImpl<$Res>;
@override
$Res call(
{List<String> path,
int pid,
Transport transport,
String name,
DeviceInfo info});
@override
$DeviceInfoCopyWith<$Res> get info;
}
/// @nodoc
class __$DeviceNodeCopyWithImpl<$Res> extends _$DeviceNodeCopyWithImpl<$Res>
implements _$DeviceNodeCopyWith<$Res> {
__$DeviceNodeCopyWithImpl(
_DeviceNode _value, $Res Function(_DeviceNode) _then)
: super(_value, (v) => _then(v as _DeviceNode));
@override
_DeviceNode get _value => super._value as _DeviceNode;
@override
$Res call({
Object? path = freezed,
Object? pid = freezed,
Object? transport = freezed,
Object? name = freezed,
Object? info = freezed,
}) {
return _then(_DeviceNode(
path == freezed
? _value.path
: path // ignore: cast_nullable_to_non_nullable
as List<String>,
pid == freezed
? _value.pid
: pid // ignore: cast_nullable_to_non_nullable
as int,
transport == freezed
? _value.transport
: transport // ignore: cast_nullable_to_non_nullable
as Transport,
name == freezed
? _value.name
: name // ignore: cast_nullable_to_non_nullable
as String,
info == freezed
? _value.info
: info // ignore: cast_nullable_to_non_nullable
as DeviceInfo,
));
}
}
/// @nodoc
@JsonSerializable()
class _$_DeviceNode implements _DeviceNode {
_$_DeviceNode(this.path, this.pid, this.transport, this.name, this.info);
factory _$_DeviceNode.fromJson(Map<String, dynamic> json) =>
_$$_DeviceNodeFromJson(json);
class _$UsbYubiKeyNode implements UsbYubiKeyNode {
_$UsbYubiKeyNode(this.path, this.name, this.pid, this.info);
@override
final List<String> path;
@override
final int pid;
@override
final Transport transport;
@override
final String name;
@override
final int pid;
@override
final DeviceInfo info;
@override
String toString() {
return 'DeviceNode(path: $path, pid: $pid, transport: $transport, name: $name, info: $info)';
return 'DeviceNode.usbYubiKey(path: $path, name: $name, pid: $pid, info: $info)';
}
@override
bool operator ==(dynamic other) {
return identical(this, other) ||
(other.runtimeType == runtimeType &&
other is _DeviceNode &&
other is UsbYubiKeyNode &&
const DeepCollectionEquality().equals(other.path, path) &&
(identical(other.pid, pid) || other.pid == pid) &&
(identical(other.transport, transport) ||
other.transport == transport) &&
(identical(other.name, name) || other.name == name) &&
(identical(other.info, info) || other.info == info));
const DeepCollectionEquality().equals(other.name, name) &&
const DeepCollectionEquality().equals(other.pid, pid) &&
const DeepCollectionEquality().equals(other.info, info));
}
@override
int get hashCode => Object.hash(runtimeType,
const DeepCollectionEquality().hash(path), pid, transport, name, info);
int get hashCode => Object.hash(
runtimeType,
const DeepCollectionEquality().hash(path),
const DeepCollectionEquality().hash(name),
const DeepCollectionEquality().hash(pid),
const DeepCollectionEquality().hash(info));
@JsonKey(ignore: true)
@override
_$DeviceNodeCopyWith<_DeviceNode> get copyWith =>
__$DeviceNodeCopyWithImpl<_DeviceNode>(this, _$identity);
$UsbYubiKeyNodeCopyWith<UsbYubiKeyNode> get copyWith =>
_$UsbYubiKeyNodeCopyWithImpl<UsbYubiKeyNode>(this, _$identity);
@override
Map<String, dynamic> toJson() {
return _$$_DeviceNodeToJson(this);
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function(
List<String> path, String name, int pid, DeviceInfo info)
usbYubiKey,
required TResult Function(List<String> path, String name) nfcReader,
}) {
return usbYubiKey(path, name, pid, info);
}
@override
@optionalTypeArgs
TResult? whenOrNull<TResult extends Object?>({
TResult Function(List<String> path, String name, int pid, DeviceInfo info)?
usbYubiKey,
TResult Function(List<String> path, String name)? nfcReader,
}) {
return usbYubiKey?.call(path, name, pid, info);
}
@override
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function(List<String> path, String name, int pid, DeviceInfo info)?
usbYubiKey,
TResult Function(List<String> path, String name)? nfcReader,
required TResult orElse(),
}) {
if (usbYubiKey != null) {
return usbYubiKey(path, name, pid, info);
}
return orElse();
}
@override
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(UsbYubiKeyNode value) usbYubiKey,
required TResult Function(NfcReaderNode value) nfcReader,
}) {
return usbYubiKey(this);
}
@override
@optionalTypeArgs
TResult? mapOrNull<TResult extends Object?>({
TResult Function(UsbYubiKeyNode value)? usbYubiKey,
TResult Function(NfcReaderNode value)? nfcReader,
}) {
return usbYubiKey?.call(this);
}
@override
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(UsbYubiKeyNode value)? usbYubiKey,
TResult Function(NfcReaderNode value)? nfcReader,
required TResult orElse(),
}) {
if (usbYubiKey != null) {
return usbYubiKey(this);
}
return orElse();
}
}
abstract class _DeviceNode implements DeviceNode {
factory _DeviceNode(List<String> path, int pid, Transport transport,
String name, DeviceInfo info) = _$_DeviceNode;
factory _DeviceNode.fromJson(Map<String, dynamic> json) =
_$_DeviceNode.fromJson;
abstract class UsbYubiKeyNode implements DeviceNode {
factory UsbYubiKeyNode(
List<String> path, String name, int pid, DeviceInfo info) =
_$UsbYubiKeyNode;
@override
List<String> get path;
@override
int get pid;
@override
Transport get transport;
@override
String get name;
@override
int get pid;
DeviceInfo get info;
@override
@JsonKey(ignore: true)
_$DeviceNodeCopyWith<_DeviceNode> get copyWith =>
$UsbYubiKeyNodeCopyWith<UsbYubiKeyNode> get copyWith =>
throw _privateConstructorUsedError;
}
/// @nodoc
abstract class $NfcReaderNodeCopyWith<$Res>
implements $DeviceNodeCopyWith<$Res> {
factory $NfcReaderNodeCopyWith(
NfcReaderNode value, $Res Function(NfcReaderNode) then) =
_$NfcReaderNodeCopyWithImpl<$Res>;
@override
$Res call({List<String> path, String name});
}
/// @nodoc
class _$NfcReaderNodeCopyWithImpl<$Res> extends _$DeviceNodeCopyWithImpl<$Res>
implements $NfcReaderNodeCopyWith<$Res> {
_$NfcReaderNodeCopyWithImpl(
NfcReaderNode _value, $Res Function(NfcReaderNode) _then)
: super(_value, (v) => _then(v as NfcReaderNode));
@override
NfcReaderNode get _value => super._value as NfcReaderNode;
@override
$Res call({
Object? path = freezed,
Object? name = freezed,
}) {
return _then(NfcReaderNode(
path == freezed
? _value.path
: path // ignore: cast_nullable_to_non_nullable
as List<String>,
name == freezed
? _value.name
: name // ignore: cast_nullable_to_non_nullable
as String,
));
}
}
/// @nodoc
class _$NfcReaderNode implements NfcReaderNode {
_$NfcReaderNode(this.path, this.name);
@override
final List<String> path;
@override
final String name;
@override
String toString() {
return 'DeviceNode.nfcReader(path: $path, name: $name)';
}
@override
bool operator ==(dynamic other) {
return identical(this, other) ||
(other.runtimeType == runtimeType &&
other is NfcReaderNode &&
const DeepCollectionEquality().equals(other.path, path) &&
const DeepCollectionEquality().equals(other.name, name));
}
@override
int get hashCode => Object.hash(
runtimeType,
const DeepCollectionEquality().hash(path),
const DeepCollectionEquality().hash(name));
@JsonKey(ignore: true)
@override
$NfcReaderNodeCopyWith<NfcReaderNode> get copyWith =>
_$NfcReaderNodeCopyWithImpl<NfcReaderNode>(this, _$identity);
@override
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function(
List<String> path, String name, int pid, DeviceInfo info)
usbYubiKey,
required TResult Function(List<String> path, String name) nfcReader,
}) {
return nfcReader(path, name);
}
@override
@optionalTypeArgs
TResult? whenOrNull<TResult extends Object?>({
TResult Function(List<String> path, String name, int pid, DeviceInfo info)?
usbYubiKey,
TResult Function(List<String> path, String name)? nfcReader,
}) {
return nfcReader?.call(path, name);
}
@override
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function(List<String> path, String name, int pid, DeviceInfo info)?
usbYubiKey,
TResult Function(List<String> path, String name)? nfcReader,
required TResult orElse(),
}) {
if (nfcReader != null) {
return nfcReader(path, name);
}
return orElse();
}
@override
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(UsbYubiKeyNode value) usbYubiKey,
required TResult Function(NfcReaderNode value) nfcReader,
}) {
return nfcReader(this);
}
@override
@optionalTypeArgs
TResult? mapOrNull<TResult extends Object?>({
TResult Function(UsbYubiKeyNode value)? usbYubiKey,
TResult Function(NfcReaderNode value)? nfcReader,
}) {
return nfcReader?.call(this);
}
@override
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(UsbYubiKeyNode value)? usbYubiKey,
TResult Function(NfcReaderNode value)? nfcReader,
required TResult orElse(),
}) {
if (nfcReader != null) {
return nfcReader(this);
}
return orElse();
}
}
abstract class NfcReaderNode implements DeviceNode {
factory NfcReaderNode(List<String> path, String name) = _$NfcReaderNode;
@override
List<String> get path;
@override
String get name;
@override
@JsonKey(ignore: true)
$NfcReaderNodeCopyWith<NfcReaderNode> get copyWith =>
throw _privateConstructorUsedError;
}
@ -383,13 +781,17 @@ class _$_MenuAction implements _MenuAction {
return identical(this, other) ||
(other.runtimeType == runtimeType &&
other is _MenuAction &&
(identical(other.text, text) || other.text == text) &&
(identical(other.icon, icon) || other.icon == icon) &&
const DeepCollectionEquality().equals(other.text, text) &&
const DeepCollectionEquality().equals(other.icon, icon) &&
(identical(other.action, action) || other.action == action));
}
@override
int get hashCode => Object.hash(runtimeType, text, icon, action);
int get hashCode => Object.hash(
runtimeType,
const DeepCollectionEquality().hash(text),
const DeepCollectionEquality().hash(icon),
action);
@JsonKey(ignore: true)
@override
@ -548,13 +950,17 @@ class _$_WindowState implements _WindowState {
return identical(this, other) ||
(other.runtimeType == runtimeType &&
other is _WindowState &&
(identical(other.focused, focused) || other.focused == focused) &&
(identical(other.visible, visible) || other.visible == visible) &&
(identical(other.active, active) || other.active == active));
const DeepCollectionEquality().equals(other.focused, focused) &&
const DeepCollectionEquality().equals(other.visible, visible) &&
const DeepCollectionEquality().equals(other.active, active));
}
@override
int get hashCode => Object.hash(runtimeType, focused, visible, active);
int get hashCode => Object.hash(
runtimeType,
const DeepCollectionEquality().hash(focused),
const DeepCollectionEquality().hash(visible),
const DeepCollectionEquality().hash(active));
@JsonKey(ignore: true)
@override

View File

@ -1,30 +0,0 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'models.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
_$_DeviceNode _$$_DeviceNodeFromJson(Map<String, dynamic> json) =>
_$_DeviceNode(
(json['path'] as List<dynamic>).map((e) => e as String).toList(),
json['pid'] as int,
$enumDecode(_$TransportEnumMap, json['transport']),
json['name'] as String,
DeviceInfo.fromJson(json['info'] as Map<String, dynamic>),
);
Map<String, dynamic> _$$_DeviceNodeToJson(_$_DeviceNode instance) =>
<String, dynamic>{
'path': instance.path,
'pid': instance.pid,
'transport': _$TransportEnumMap[instance.transport],
'name': instance.name,
'info': instance.info,
};
const _$TransportEnumMap = {
Transport.usb: 'usb',
Transport.nfc: 'nfc',
};

View File

@ -6,6 +6,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:logging/logging.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:window_manager/window_manager.dart';
import 'package:yubico_authenticator/management/models.dart';
import '../core/models.dart';
import '../core/state.dart';
@ -13,6 +14,12 @@ import '../core/rpc.dart';
import '../oath/menu_actions.dart';
import 'models.dart';
const _usbPollDelay = Duration(milliseconds: 500);
const _nfcPollDelay = Duration(milliseconds: 2500);
const _nfcAttachPollDelay = Duration(seconds: 1);
const _nfcDetachPollDelay = Duration(seconds: 5);
final log = Logger('app.state');
final windowStateProvider =
@ -118,24 +125,24 @@ class SearchNotifier extends StateNotifier<String> {
}
}
final attachedDevicesProvider =
StateNotifierProvider<AttachedDeviceNotifier, List<DeviceNode>>((ref) {
final notifier = AttachedDeviceNotifier(ref.watch(rpcProvider));
final _usbDevicesProvider =
StateNotifierProvider<UsbDeviceNotifier, List<UsbYubiKeyNode>>((ref) {
final notifier = UsbDeviceNotifier(ref.watch(rpcProvider));
ref.listen<WindowState>(windowStateProvider, (_, windowState) {
notifier._notifyWindowState(windowState);
}, fireImmediately: true);
return notifier;
});
class AttachedDeviceNotifier extends StateNotifier<List<DeviceNode>> {
class UsbDeviceNotifier extends StateNotifier<List<UsbYubiKeyNode>> {
final RpcSession _rpc;
Timer? _pollTimer;
int _usbState = -1;
AttachedDeviceNotifier(this._rpc) : super([]);
UsbDeviceNotifier(this._rpc) : super([]);
void _notifyWindowState(WindowState windowState) {
if (windowState.active) {
_pollUsb();
_pollDevices();
} else {
_pollTimer?.cancel();
// Release any held device
@ -149,37 +156,110 @@ class AttachedDeviceNotifier extends StateNotifier<List<DeviceNode>> {
super.dispose();
}
void _pollUsb() async {
void _pollDevices() async {
_pollTimer?.cancel();
try {
var scan = await _rpc.command('scan', ['usb']);
if (_usbState != scan['state'] || state.length != scan['pids'].length) {
var usbResult = await _rpc.command('get', ['usb']);
log.info('USB state change', jsonEncode(usbResult));
_usbState = usbResult['data']['state'];
List<UsbYubiKeyNode> usbDevices = [];
List<DeviceNode> devices = [];
for (String id in (usbResult['children'] as Map).keys) {
var path = ['usb', id];
var deviceResult = await _rpc.command('get', path);
devices.add(
DeviceNode.fromJson({'path': path, ...deviceResult['data']}));
var deviceData = deviceResult['data'];
usbDevices.add(DeviceNode.usbYubiKey(
path,
deviceData['name'],
deviceData['pid'],
DeviceInfo.fromJson(deviceData['info']),
) as UsbYubiKeyNode);
}
_usbState = usbResult['data']['state'];
log.info('USB state updated');
if (mounted) {
state = devices;
state = usbDevices;
}
}
} on RpcError catch (e) {
log.severe('Error polling USB', jsonEncode(e));
}
if (mounted) {
_pollTimer = Timer(const Duration(milliseconds: 500), _pollUsb);
_pollTimer = Timer(_usbPollDelay, _pollDevices);
}
}
}
final _nfcDevicesProvider =
StateNotifierProvider<NfcDeviceNotifier, List<NfcReaderNode>>((ref) {
final notifier = NfcDeviceNotifier(ref.watch(rpcProvider));
ref.listen<WindowState>(windowStateProvider, (_, windowState) {
notifier._notifyWindowState(windowState);
}, fireImmediately: true);
return notifier;
});
class NfcDeviceNotifier extends StateNotifier<List<NfcReaderNode>> {
final RpcSession _rpc;
Timer? _pollTimer;
String _nfcState = '';
NfcDeviceNotifier(this._rpc) : super([]);
void _notifyWindowState(WindowState windowState) {
if (windowState.active) {
_pollReaders();
} else {
_pollTimer?.cancel();
// Release any held device
_rpc.command('get', ['nfc']);
}
}
@override
void dispose() {
_pollTimer?.cancel();
super.dispose();
}
void _pollReaders() async {
_pollTimer?.cancel();
try {
var children = await _rpc.command('scan', ['nfc']);
var newState = children.keys.join(':');
if (mounted && newState != _nfcState) {
log.info('NFC state change', jsonEncode(children));
_nfcState = newState;
state = children.entries
.map((e) =>
DeviceNode.nfcReader(['nfc', e.key], e.value['name'] as String)
as NfcReaderNode)
.toList();
}
} on RpcError catch (e) {
log.severe('Error polling NFC', jsonEncode(e));
}
if (mounted) {
_pollTimer = Timer(_nfcPollDelay, _pollReaders);
}
}
}
final attachedDevicesProvider = Provider<List<DeviceNode>>((ref) {
final usbDevices = ref.watch(_usbDevicesProvider).toList();
final nfcDevices = ref.watch(_nfcDevicesProvider).toList();
usbDevices.sort((a, b) => a.name.compareTo(b.name));
nfcDevices.sort((a, b) => a.name.compareTo(b.name));
return [...usbDevices, ...nfcDevices];
});
final currentDeviceProvider =
StateNotifierProvider<CurrentDeviceNotifier, DeviceNode?>((ref) {
final provider = CurrentDeviceNotifier(ref.watch(prefProvider));
@ -188,42 +268,112 @@ final currentDeviceProvider =
});
class CurrentDeviceNotifier extends StateNotifier<DeviceNode?> {
static const String _lastDeviceSerial = 'APP_STATE_LAST_SERIAL';
static const String _lastDevice = 'APP_STATE_LAST_DEVICE';
final SharedPreferences _prefs;
CurrentDeviceNotifier(this._prefs) : super(null);
_updateAttachedDevices(List<DeviceNode>? previous, List<DeviceNode> devices) {
if (devices.isEmpty) {
state = null;
} else if (!devices.contains(state)) {
// Prefer last selected device
final serial = _prefs.getInt(_lastDeviceSerial) ?? -1;
state = devices.firstWhere(
(element) => element.info.serial == serial,
orElse: () => devices.first,
);
if (!devices.contains(state)) {
final lastDevice = _prefs.getString(_lastDevice) ?? '';
try {
state = devices.firstWhere(
(dev) => dev.when(
usbYubiKey: (path, name, pid, info) =>
lastDevice == 'serial:${info.serial}',
nfcReader: (path, name) => lastDevice == 'name:$name',
),
orElse: () => devices.whereType<UsbYubiKeyNode>().first);
} on StateError {
state = null;
}
}
}
setCurrentDevice(DeviceNode device) {
state = device;
final serial = device.info.serial;
if (serial != null) {
_prefs.setInt(_lastDeviceSerial, serial);
}
device.when(
usbYubiKey: (path, name, pid, info) {
final serial = info.serial;
if (serial != null) {
_prefs.setString(_lastDevice, 'serial:$serial');
}
},
nfcReader: (path, name) {
_prefs.setString(_lastDevice, 'name:$name');
},
);
}
}
final sortedDevicesProvider = Provider<List<DeviceNode>>((ref) {
final devices = ref.watch(attachedDevicesProvider).toList();
devices.sort((a, b) => a.name.compareTo(b.name));
final device = ref.watch(currentDeviceProvider);
if (device != null) {
return [device, ...devices.where((e) => e != device)];
final currentDeviceDataProvider =
StateNotifierProvider<CurrentDeviceDataNotifier, YubiKeyData?>((ref) {
final notifier = CurrentDeviceDataNotifier(
ref.watch(rpcProvider),
ref.watch(currentDeviceProvider),
);
if (notifier._deviceNode is NfcReaderNode) {
// If this is an NFC reader, listen on WindowState.
ref.listen<WindowState>(windowStateProvider, (_, windowState) {
notifier._notifyWindowState(windowState);
}, fireImmediately: true);
}
return devices;
return notifier;
});
class CurrentDeviceDataNotifier extends StateNotifier<YubiKeyData?> {
final RpcSession _rpc;
final DeviceNode? _deviceNode;
Timer? _pollTimer;
CurrentDeviceDataNotifier(this._rpc, this._deviceNode) : super(null) {
final dev = _deviceNode;
if (dev is UsbYubiKeyNode) {
state = YubiKeyData(dev, dev.name, dev.info);
}
}
void _notifyWindowState(WindowState windowState) {
if (windowState.active) {
_pollReader();
} else {
_pollTimer?.cancel();
// TODO: Should we clear the key here?
/*if (mounted) {
state = null;
}*/
}
}
@override
void dispose() {
_pollTimer?.cancel();
super.dispose();
}
void _pollReader() async {
_pollTimer?.cancel();
final node = _deviceNode!;
try {
var result = await _rpc.command('get', node.path);
if (mounted) {
if (result['data']['present']) {
state = YubiKeyData(node, result['data']['name'],
DeviceInfo.fromJson(result['data']['info']));
} else {
state = null;
}
}
} on RpcError catch (e) {
log.severe('Error polling NFC', jsonEncode(e));
}
if (mounted) {
_pollTimer = Timer(
state == null ? _nfcAttachPollDelay : _nfcDetachPollDelay,
_pollReader);
}
}
}
final subPageProvider = StateNotifierProvider<SubPageNotifier, SubPage>(
(ref) => SubPageNotifier(SubPage.authenticator));

View File

@ -1,20 +1,29 @@
import 'package:flutter/material.dart';
import 'package:yubico_authenticator/management/models.dart';
import '../models.dart';
import 'device_images.dart';
/*
TODO: This class should be refactored once we settle more on the final design.
We may want to have two separate implementations depending on if it's an NFC reader or a USB YubiKey.
*/
class DeviceAvatar extends StatelessWidget {
final DeviceNode device;
final DeviceNode node;
final String name;
final DeviceInfo? info;
final bool selected;
const DeviceAvatar(this.device, {this.selected = false, Key? key})
const DeviceAvatar(this.node, this.name, this.info,
{this.selected = false, Key? key})
: super(key: key);
@override
Widget build(BuildContext context) {
return CircleAvatar(
child: CircleAvatar(
child: getProductImage(device),
child:
info != null ? getProductImage(info!, name) : const Icon(Icons.nfc),
backgroundColor: Theme.of(context).colorScheme.background,
),
radius: 22,

View File

@ -1,7 +1,6 @@
import 'package:flutter/material.dart';
import '../../management/models.dart';
import '../models.dart';
const _imagesForName = {
'YubiKey 4': 'yk4series',
@ -30,11 +29,11 @@ const _imagesForFormFactorNfc = {
FormFactor.usbCKeychain: 'yk5cnfc',
};
Image getProductImage(DeviceNode device) {
var image = _imagesForName[device.name];
image ??= device.info.supportedCapabilities.containsKey(Transport.nfc)
? _imagesForFormFactorNfc[device.info.formFactor]
: _imagesForFormFactor[device.info.formFactor];
Image getProductImage(DeviceInfo info, String name) {
var image = _imagesForName[name];
image ??= info.supportedCapabilities.containsKey(Transport.nfc)
? _imagesForFormFactorNfc[info.formFactor]
: _imagesForFormFactor[info.formFactor];
image ??= 'yk5series';
return Image.asset('assets/product-images/$image.png');

View File

@ -3,7 +3,7 @@ import 'package:flutter/material.dart';
import '../models.dart';
class DeviceInfoScreen extends StatelessWidget {
final DeviceNode device;
final YubiKeyData device;
const DeviceInfoScreen(this.device, {Key? key}) : super(key: key);
@override

View File

@ -1,32 +1,54 @@
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:yubico_authenticator/management/models.dart';
import 'package:collection/collection.dart';
import '../models.dart';
import '../state.dart';
import 'device_avatar.dart';
Function _listEquals = const ListEquality().equals;
class MainActionsDialog extends ConsumerWidget {
const MainActionsDialog({Key? key}) : super(key: key);
@override
Widget build(BuildContext context, WidgetRef ref) {
final devices = ref.watch(sortedDevicesProvider);
final device = ref.watch(currentDeviceProvider);
final devices = ref.watch(attachedDevicesProvider).toList();
final currentNode = ref.watch(currentDeviceProvider);
final data = ref.watch(currentDeviceDataProvider);
final actions = ref.watch(menuActionsProvider)(context);
if (currentNode != null) {
devices.removeWhere((e) => _listEquals(e.path, currentNode.path));
}
return SimpleDialog(
children: [
...devices.map((e) => Padding(
padding: const EdgeInsets.all(8.0),
child: DeviceRow(
e,
selected: e == device,
onPressed: () {
Navigator.of(context).pop();
ref.read(currentDeviceProvider.notifier).setCurrentDevice(e);
},
),
)),
if (currentNode != null)
CurrentDeviceRow(
currentNode,
data?.name,
info: data?.info,
onTap: () {
Navigator.of(context).pop();
},
),
...devices.map(
(e) => DeviceRow(
e,
e.name,
info: e.when(
usbYubiKey: (path, name, pid, info) => info,
nfcReader: (path, name) => null,
),
selected: false,
onTap: () {
Navigator.of(context).pop();
ref.read(currentDeviceProvider.notifier).setCurrentDevice(e);
},
),
),
if (actions.isNotEmpty) const Divider(),
...actions.map((a) => ListTile(
dense: true,
@ -42,43 +64,74 @@ class MainActionsDialog extends ConsumerWidget {
}
}
class DeviceRow extends StatelessWidget {
final DeviceNode device;
final bool selected;
final Function() onPressed;
const DeviceRow(
this.device, {
this.selected = false,
required this.onPressed,
class CurrentDeviceRow extends StatelessWidget {
final DeviceNode node;
final String? name;
final DeviceInfo? info;
final Function() onTap;
const CurrentDeviceRow(
this.node,
this.name, {
required this.info,
required this.onTap,
Key? key,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return TextButton(
onPressed: onPressed,
child: Row(
children: [
DeviceAvatar(
device,
selected: selected,
),
const SizedBox(width: 16.0),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
device.name,
style: Theme.of(context).textTheme.headline6,
),
Text(
'S/N: ${device.info.serial} F/W: ${device.info.version}',
style: Theme.of(context).textTheme.bodyText1,
),
],
),
],
final subtitle = node is NfcReaderNode
? info != null
? '${node.name}\nS/N: ${info!.serial} F/W: ${info!.version}'
: node.name
: 'S/N: ${info!.serial} F/W: ${info!.version}';
return ListTile(
leading: DeviceAvatar(
node,
name ?? '',
info,
selected: true,
),
title: Text(name ?? 'No YubiKey present'),
isThreeLine: subtitle.contains('\n'),
subtitle: Text(subtitle),
onTap: onTap,
);
}
}
class DeviceRow extends StatelessWidget {
final DeviceNode node;
final String name;
final DeviceInfo? info;
final bool selected;
final Function() onTap;
const DeviceRow(
this.node,
this.name, {
required this.info,
required this.onTap,
this.selected = false,
Key? key,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return ListTile(
leading: DeviceAvatar(
node,
name,
info,
selected: selected,
),
title: Text(name),
subtitle: Text(
info == null
? (selected ? 'No YubiKey present' : 'Select to scan')
: 'S/N: ${info!.serial} F/W: ${info!.version}',
),
onTap: onTap,
);
}
}

View File

@ -13,7 +13,7 @@ import '../../oath/views/oath_screen.dart';
class MainPage extends ConsumerWidget {
const MainPage({Key? key}) : super(key: key);
Widget _buildSubPage(SubPage subPage, DeviceNode? device) {
Widget _buildSubPage(SubPage subPage, YubiKeyData? device) {
if (device == null) {
return const NoDeviceScreen();
}
@ -28,7 +28,7 @@ class MainPage extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final currentDevice = ref.watch(currentDeviceProvider);
final deviceData = ref.watch(currentDeviceDataProvider);
final subPage = ref.watch(subPageProvider);
return Scaffold(
@ -59,7 +59,7 @@ class MainPage extends ConsumerWidget {
InkWell(
child: Padding(
padding: const EdgeInsets.all(4.0),
child: currentDevice == null
child: deviceData == null
? SizedBox.square(
dimension: 44,
child: Icon(
@ -67,7 +67,12 @@ class MainPage extends ConsumerWidget {
color: Theme.of(context).colorScheme.background,
),
)
: DeviceAvatar(currentDevice, selected: true),
: DeviceAvatar(
deviceData.node,
deviceData.name,
deviceData.info,
selected: true,
),
),
onTap: () {
showDialog(
@ -79,7 +84,7 @@ class MainPage extends ConsumerWidget {
],
),
drawer: const MainPageDrawer(),
body: _buildSubPage(subPage, currentDevice),
body: _buildSubPage(subPage, deviceData),
);
}
}

View File

@ -1,5 +1,6 @@
// coverage:ignore-file
// GENERATED CODE - DO NOT MODIFY BY HAND
// ignore_for_file: type=lint
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target
part of 'models.dart';
@ -134,13 +135,17 @@ class _$_Version extends _Version {
return identical(this, other) ||
(other.runtimeType == runtimeType &&
other is _Version &&
(identical(other.major, major) || other.major == major) &&
(identical(other.minor, minor) || other.minor == minor) &&
(identical(other.patch, patch) || other.patch == patch));
const DeepCollectionEquality().equals(other.major, major) &&
const DeepCollectionEquality().equals(other.minor, minor) &&
const DeepCollectionEquality().equals(other.patch, patch));
}
@override
int get hashCode => Object.hash(runtimeType, major, minor, patch);
int get hashCode => Object.hash(
runtimeType,
const DeepCollectionEquality().hash(major),
const DeepCollectionEquality().hash(minor),
const DeepCollectionEquality().hash(patch));
@JsonKey(ignore: true)
@override
@ -516,13 +521,15 @@ class _$Signal implements Signal {
return identical(this, other) ||
(other.runtimeType == runtimeType &&
other is Signal &&
(identical(other.status, status) || other.status == status) &&
const DeepCollectionEquality().equals(other.status, status) &&
const DeepCollectionEquality().equals(other.body, body));
}
@override
int get hashCode => Object.hash(
runtimeType, status, const DeepCollectionEquality().hash(body));
runtimeType,
const DeepCollectionEquality().hash(status),
const DeepCollectionEquality().hash(body));
@JsonKey(ignore: true)
@override
@ -689,14 +696,17 @@ class _$RpcError implements RpcError {
return identical(this, other) ||
(other.runtimeType == runtimeType &&
other is RpcError &&
(identical(other.status, status) || other.status == status) &&
(identical(other.message, message) || other.message == message) &&
const DeepCollectionEquality().equals(other.status, status) &&
const DeepCollectionEquality().equals(other.message, message) &&
const DeepCollectionEquality().equals(other.body, body));
}
@override
int get hashCode => Object.hash(
runtimeType, status, message, const DeepCollectionEquality().hash(body));
runtimeType,
const DeepCollectionEquality().hash(status),
const DeepCollectionEquality().hash(message),
const DeepCollectionEquality().hash(body));
@JsonKey(ignore: true)
@override
@ -896,11 +906,12 @@ class _$_RpcState implements _RpcState {
return identical(this, other) ||
(other.runtimeType == runtimeType &&
other is _RpcState &&
(identical(other.version, version) || other.version == version));
const DeepCollectionEquality().equals(other.version, version));
}
@override
int get hashCode => Object.hash(runtimeType, version);
int get hashCode =>
Object.hash(runtimeType, const DeepCollectionEquality().hash(version));
@JsonKey(ignore: true)
@override

View File

@ -1,5 +1,6 @@
// coverage:ignore-file
// GENERATED CODE - DO NOT MODIFY BY HAND
// ignore_for_file: type=lint
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target
part of 'models.dart';
@ -183,22 +184,21 @@ class _$_DeviceConfig implements _DeviceConfig {
other is _DeviceConfig &&
const DeepCollectionEquality()
.equals(other.enabledCapabilities, enabledCapabilities) &&
(identical(other.autoEjectTimeout, autoEjectTimeout) ||
other.autoEjectTimeout == autoEjectTimeout) &&
(identical(
other.challengeResponseTimeout, challengeResponseTimeout) ||
other.challengeResponseTimeout == challengeResponseTimeout) &&
(identical(other.deviceFlags, deviceFlags) ||
other.deviceFlags == deviceFlags));
const DeepCollectionEquality()
.equals(other.autoEjectTimeout, autoEjectTimeout) &&
const DeepCollectionEquality().equals(
other.challengeResponseTimeout, challengeResponseTimeout) &&
const DeepCollectionEquality()
.equals(other.deviceFlags, deviceFlags));
}
@override
int get hashCode => Object.hash(
runtimeType,
const DeepCollectionEquality().hash(enabledCapabilities),
autoEjectTimeout,
challengeResponseTimeout,
deviceFlags);
const DeepCollectionEquality().hash(autoEjectTimeout),
const DeepCollectionEquality().hash(challengeResponseTimeout),
const DeepCollectionEquality().hash(deviceFlags));
@JsonKey(ignore: true)
@override
@ -495,30 +495,29 @@ class _$_DeviceInfo implements _DeviceInfo {
return identical(this, other) ||
(other.runtimeType == runtimeType &&
other is _DeviceInfo &&
(identical(other.config, config) || other.config == config) &&
(identical(other.serial, serial) || other.serial == serial) &&
(identical(other.version, version) || other.version == version) &&
(identical(other.formFactor, formFactor) ||
other.formFactor == formFactor) &&
const DeepCollectionEquality().equals(other.config, config) &&
const DeepCollectionEquality().equals(other.serial, serial) &&
const DeepCollectionEquality().equals(other.version, version) &&
const DeepCollectionEquality()
.equals(other.formFactor, formFactor) &&
const DeepCollectionEquality()
.equals(other.supportedCapabilities, supportedCapabilities) &&
(identical(other.isLocked, isLocked) ||
other.isLocked == isLocked) &&
(identical(other.isFips, isFips) || other.isFips == isFips) &&
(identical(other.isSky, isSky) || other.isSky == isSky));
const DeepCollectionEquality().equals(other.isLocked, isLocked) &&
const DeepCollectionEquality().equals(other.isFips, isFips) &&
const DeepCollectionEquality().equals(other.isSky, isSky));
}
@override
int get hashCode => Object.hash(
runtimeType,
config,
serial,
version,
formFactor,
const DeepCollectionEquality().hash(config),
const DeepCollectionEquality().hash(serial),
const DeepCollectionEquality().hash(version),
const DeepCollectionEquality().hash(formFactor),
const DeepCollectionEquality().hash(supportedCapabilities),
isLocked,
isFips,
isSky);
const DeepCollectionEquality().hash(isLocked),
const DeepCollectionEquality().hash(isFips),
const DeepCollectionEquality().hash(isSky));
@JsonKey(ignore: true)
@override

View File

@ -1,5 +1,6 @@
// coverage:ignore-file
// GENERATED CODE - DO NOT MODIFY BY HAND
// ignore_for_file: type=lint
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target
part of 'models.dart';
@ -230,21 +231,26 @@ class _$_OathCredential implements _OathCredential {
return identical(this, other) ||
(other.runtimeType == runtimeType &&
other is _OathCredential &&
(identical(other.deviceId, deviceId) ||
other.deviceId == deviceId) &&
(identical(other.id, id) || other.id == id) &&
(identical(other.issuer, issuer) || other.issuer == issuer) &&
(identical(other.name, name) || other.name == name) &&
(identical(other.oathType, oathType) ||
other.oathType == oathType) &&
(identical(other.period, period) || other.period == period) &&
(identical(other.touchRequired, touchRequired) ||
other.touchRequired == touchRequired));
const DeepCollectionEquality().equals(other.deviceId, deviceId) &&
const DeepCollectionEquality().equals(other.id, id) &&
const DeepCollectionEquality().equals(other.issuer, issuer) &&
const DeepCollectionEquality().equals(other.name, name) &&
const DeepCollectionEquality().equals(other.oathType, oathType) &&
const DeepCollectionEquality().equals(other.period, period) &&
const DeepCollectionEquality()
.equals(other.touchRequired, touchRequired));
}
@override
int get hashCode => Object.hash(
runtimeType, deviceId, id, issuer, name, oathType, period, touchRequired);
runtimeType,
const DeepCollectionEquality().hash(deviceId),
const DeepCollectionEquality().hash(id),
const DeepCollectionEquality().hash(issuer),
const DeepCollectionEquality().hash(name),
const DeepCollectionEquality().hash(oathType),
const DeepCollectionEquality().hash(period),
const DeepCollectionEquality().hash(touchRequired));
@JsonKey(ignore: true)
@override
@ -429,14 +435,17 @@ class _$_OathCode implements _OathCode {
return identical(this, other) ||
(other.runtimeType == runtimeType &&
other is _OathCode &&
(identical(other.value, value) || other.value == value) &&
(identical(other.validFrom, validFrom) ||
other.validFrom == validFrom) &&
(identical(other.validTo, validTo) || other.validTo == validTo));
const DeepCollectionEquality().equals(other.value, value) &&
const DeepCollectionEquality().equals(other.validFrom, validFrom) &&
const DeepCollectionEquality().equals(other.validTo, validTo));
}
@override
int get hashCode => Object.hash(runtimeType, value, validFrom, validTo);
int get hashCode => Object.hash(
runtimeType,
const DeepCollectionEquality().hash(value),
const DeepCollectionEquality().hash(validFrom),
const DeepCollectionEquality().hash(validTo));
@JsonKey(ignore: true)
@override
@ -605,13 +614,16 @@ class _$_OathPair implements _OathPair {
return identical(this, other) ||
(other.runtimeType == runtimeType &&
other is _OathPair &&
(identical(other.credential, credential) ||
other.credential == credential) &&
(identical(other.code, code) || other.code == code));
const DeepCollectionEquality()
.equals(other.credential, credential) &&
const DeepCollectionEquality().equals(other.code, code));
}
@override
int get hashCode => Object.hash(runtimeType, credential, code);
int get hashCode => Object.hash(
runtimeType,
const DeepCollectionEquality().hash(credential),
const DeepCollectionEquality().hash(code));
@JsonKey(ignore: true)
@override
@ -772,14 +784,17 @@ class _$_OathState implements _OathState {
return identical(this, other) ||
(other.runtimeType == runtimeType &&
other is _OathState &&
(identical(other.deviceId, deviceId) ||
other.deviceId == deviceId) &&
(identical(other.hasKey, hasKey) || other.hasKey == hasKey) &&
(identical(other.locked, locked) || other.locked == locked));
const DeepCollectionEquality().equals(other.deviceId, deviceId) &&
const DeepCollectionEquality().equals(other.hasKey, hasKey) &&
const DeepCollectionEquality().equals(other.locked, locked));
}
@override
int get hashCode => Object.hash(runtimeType, deviceId, hasKey, locked);
int get hashCode => Object.hash(
runtimeType,
const DeepCollectionEquality().hash(deviceId),
const DeepCollectionEquality().hash(hasKey),
const DeepCollectionEquality().hash(locked));
@JsonKey(ignore: true)
@override
@ -1037,19 +1052,19 @@ class _$_CredentialData extends _CredentialData {
final String name;
@override
final String secret;
@JsonKey(defaultValue: OathType.totp)
@JsonKey()
@override
final OathType oathType;
@JsonKey(defaultValue: HashAlgorithm.sha1)
@JsonKey()
@override
final HashAlgorithm hashAlgorithm;
@JsonKey(defaultValue: 6)
@JsonKey()
@override
final int digits;
@JsonKey(defaultValue: 30)
@JsonKey()
@override
final int period;
@JsonKey(defaultValue: 0)
@JsonKey()
@override
final int counter;
@ -1063,21 +1078,28 @@ class _$_CredentialData extends _CredentialData {
return identical(this, other) ||
(other.runtimeType == runtimeType &&
other is _CredentialData &&
(identical(other.issuer, issuer) || other.issuer == issuer) &&
(identical(other.name, name) || other.name == name) &&
(identical(other.secret, secret) || other.secret == secret) &&
(identical(other.oathType, oathType) ||
other.oathType == oathType) &&
(identical(other.hashAlgorithm, hashAlgorithm) ||
other.hashAlgorithm == hashAlgorithm) &&
(identical(other.digits, digits) || other.digits == digits) &&
(identical(other.period, period) || other.period == period) &&
(identical(other.counter, counter) || other.counter == counter));
const DeepCollectionEquality().equals(other.issuer, issuer) &&
const DeepCollectionEquality().equals(other.name, name) &&
const DeepCollectionEquality().equals(other.secret, secret) &&
const DeepCollectionEquality().equals(other.oathType, oathType) &&
const DeepCollectionEquality()
.equals(other.hashAlgorithm, hashAlgorithm) &&
const DeepCollectionEquality().equals(other.digits, digits) &&
const DeepCollectionEquality().equals(other.period, period) &&
const DeepCollectionEquality().equals(other.counter, counter));
}
@override
int get hashCode => Object.hash(runtimeType, issuer, name, secret, oathType,
hashAlgorithm, digits, period, counter);
int get hashCode => Object.hash(
runtimeType,
const DeepCollectionEquality().hash(issuer),
const DeepCollectionEquality().hash(name),
const DeepCollectionEquality().hash(secret),
const DeepCollectionEquality().hash(oathType),
const DeepCollectionEquality().hash(hashAlgorithm),
const DeepCollectionEquality().hash(digits),
const DeepCollectionEquality().hash(period),
const DeepCollectionEquality().hash(counter));
@JsonKey(ignore: true)
@override

View File

@ -5,10 +5,11 @@ import '../models.dart';
import 'account_view.dart';
class AccountList extends StatelessWidget {
final DeviceNode device;
final YubiKeyData deviceData;
final List<OathPair> credentials;
final List<String> favorites;
const AccountList(this.device, this.credentials, this.favorites, {Key? key})
const AccountList(this.deviceData, this.credentials, this.favorites,
{Key? key})
: super(key: key);
@override
@ -34,7 +35,7 @@ class AccountList extends StatelessWidget {
),
),
...favCreds.map(
(entry) => AccountView(device, entry.credential, entry.code),
(entry) => AccountView(deviceData, entry.credential, entry.code),
),
if (creds.isNotEmpty)
ListTile(
@ -44,7 +45,7 @@ class AccountList extends StatelessWidget {
),
),
...creds.map(
(entry) => AccountView(device, entry.credential, entry.code),
(entry) => AccountView(deviceData, entry.credential, entry.code),
),
],
);

View File

@ -35,10 +35,10 @@ class _ExpireNotifier extends StateNotifier<bool> {
}
class AccountView extends ConsumerWidget {
final DeviceNode device;
final YubiKeyData deviceData;
final OathCredential credential;
final OathCode? code;
const AccountView(this.device, this.credential, this.code, {Key? key})
const AccountView(this.deviceData, this.credential, this.code, {Key? key})
: super(key: key);
String formatCode() {
@ -73,7 +73,8 @@ class AccountView extends ConsumerWidget {
ref.read(favoritesProvider.notifier).toggleFavorite(credential.id);
},
),
if (device.info.version.major >= 5 && device.info.version.minor >= 3)
if (deviceData.info.version.major >= 5 &&
deviceData.info.version.minor >= 3)
PopupMenuItem(
child: const ListTile(
leading: Icon(Icons.edit),
@ -117,7 +118,7 @@ class AccountView extends ConsumerWidget {
}
try {
await ref
.read(credentialListProvider(device.path).notifier)
.read(credentialListProvider(deviceData.node.path).notifier)
.calculate(credential);
} finally {
close?.call();

View File

@ -6,12 +6,12 @@ import '../state.dart';
import 'account_list.dart';
class OathScreen extends ConsumerWidget {
final DeviceNode device;
const OathScreen(this.device, {Key? key}) : super(key: key);
final YubiKeyData deviceData;
const OathScreen(this.deviceData, {Key? key}) : super(key: key);
@override
Widget build(BuildContext context, WidgetRef ref) {
final state = ref.watch(oathStateProvider(device.path));
final state = ref.watch(oathStateProvider(deviceData.node.path));
if (state == null) {
return Column(
@ -35,7 +35,7 @@ class OathScreen extends ConsumerWidget {
decoration: const InputDecoration(labelText: 'Password'),
onSubmitted: (value) async {
final result = await ref
.read(oathStateProvider(device.path).notifier)
.read(oathStateProvider(deviceData.node.path).notifier)
.unlock(value);
if (!result) {
ScaffoldMessenger.of(context).showSnackBar(
@ -51,7 +51,7 @@ class OathScreen extends ConsumerWidget {
),
);
} else {
final accounts = ref.watch(credentialListProvider(device.path));
final accounts = ref.watch(credentialListProvider(deviceData.node.path));
if (accounts == null) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
@ -61,7 +61,7 @@ class OathScreen extends ConsumerWidget {
);
}
return AccountList(
device,
deviceData,
ref.watch(filteredCredentialsProvider(accounts)),
ref.watch(favoritesProvider),
);

View File

@ -7,14 +7,14 @@ packages:
name: _fe_analyzer_shared
url: "https://pub.dartlang.org"
source: hosted
version: "31.0.0"
version: "32.0.0"
analyzer:
dependency: transitive
description:
name: analyzer
url: "https://pub.dartlang.org"
source: hosted
version: "2.8.0"
version: "3.0.0"
args:
dependency: transitive
description:
@ -42,7 +42,7 @@ packages:
name: build
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.1"
version: "2.2.1"
build_config:
dependency: transitive
description:
@ -63,21 +63,21 @@ packages:
name: build_resolvers
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.5"
version: "2.0.6"
build_runner:
dependency: "direct dev"
description:
name: build_runner
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.5"
version: "2.1.7"
build_runner_core:
dependency: transitive
description:
name: build_runner_core
url: "https://pub.dartlang.org"
source: hosted
version: "7.2.2"
version: "7.2.3"
built_collection:
dependency: transitive
description:
@ -161,7 +161,7 @@ packages:
name: dart_style
url: "https://pub.dartlang.org"
source: hosted
version: "2.2.0"
version: "2.2.1"
fake_async:
dependency: transitive
description:
@ -208,7 +208,7 @@ packages:
name: flutter_riverpod
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.1"
version: "1.0.3"
flutter_test:
dependency: "direct dev"
description: flutter
@ -225,14 +225,14 @@ packages:
name: freezed
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.0"
version: "1.1.1"
freezed_annotation:
dependency: "direct main"
description:
name: freezed_annotation
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.0"
version: "1.1.0"
frontend_server_client:
dependency: transitive
description:
@ -295,7 +295,7 @@ packages:
name: json_serializable
url: "https://pub.dartlang.org"
source: hosted
version: "6.1.0"
version: "6.1.3"
lints:
dependency: transitive
description:
@ -317,6 +317,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "0.12.11"
material_color_utilities:
dependency: transitive
description:
name: material_color_utilities
url: "https://pub.dartlang.org"
source: hosted
version: "0.1.3"
meta:
dependency: transitive
description:
@ -351,35 +358,35 @@ packages:
name: path_provider_linux
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.2"
version: "2.1.5"
path_provider_platform_interface:
dependency: transitive
description:
name: path_provider_platform_interface
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.1"
version: "2.0.3"
path_provider_windows:
dependency: transitive
description:
name: path_provider_windows
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.4"
version: "2.0.5"
platform:
dependency: transitive
description:
name: platform
url: "https://pub.dartlang.org"
source: hosted
version: "3.0.2"
version: "3.1.0"
plugin_platform_interface:
dependency: transitive
description:
name: plugin_platform_interface
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.2"
version: "2.1.2"
pool:
dependency: transitive
description:
@ -407,42 +414,42 @@ packages:
name: pubspec_parse
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.0"
version: "1.2.0"
riverpod:
dependency: transitive
description:
name: riverpod
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.1"
version: "1.0.3"
shared_preferences:
dependency: "direct main"
description:
name: shared_preferences
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.9"
version: "2.0.12"
shared_preferences_android:
dependency: transitive
description:
name: shared_preferences_android
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.9"
version: "2.0.10"
shared_preferences_ios:
dependency: transitive
description:
name: shared_preferences_ios
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.8"
version: "2.0.9"
shared_preferences_linux:
dependency: transitive
description:
name: shared_preferences_linux
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.3"
version: "2.0.4"
shared_preferences_macos:
dependency: transitive
description:
@ -463,14 +470,14 @@ packages:
name: shared_preferences_web
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.2"
version: "2.0.3"
shared_preferences_windows:
dependency: transitive
description:
name: shared_preferences_windows
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.3"
version: "2.0.4"
shelf:
dependency: transitive
description:
@ -496,14 +503,14 @@ packages:
name: source_gen
url: "https://pub.dartlang.org"
source: hosted
version: "1.2.0"
version: "1.2.1"
source_helper:
dependency: transitive
description:
name: source_helper
url: "https://pub.dartlang.org"
source: hosted
version: "1.3.0"
version: "1.3.1"
source_span:
dependency: transitive
description:
@ -559,7 +566,7 @@ packages:
name: test_api
url: "https://pub.dartlang.org"
source: hosted
version: "0.4.3"
version: "0.4.8"
timing:
dependency: transitive
description:
@ -601,14 +608,14 @@ packages:
name: win32
url: "https://pub.dartlang.org"
source: hosted
version: "2.3.1"
version: "2.3.3"
window_manager:
dependency: "direct main"
description:
name: window_manager
url: "https://pub.dartlang.org"
source: hosted
version: "0.1.1"
version: "0.1.4"
xdg_directories:
dependency: transitive
description:

View File

@ -37,11 +37,11 @@ dependencies:
async: ^2.8.2
logging: ^1.0.2
shared_preferences: ^2.0.8
shared_preferences: ^2.0.12
flutter_riverpod: ^1.0.0
json_annotation: ^4.3.0
freezed_annotation: ^1.0.0
window_manager: ^0.1.1
window_manager: ^0.1.4
dev_dependencies:
flutter_test:

@ -1 +1 @@
Subproject commit d161b31898e834eb085365a73f349a5b4683da17
Subproject commit 765ccf63d9ccc972858d71730b9712514a9b0e0d