Fix lint warnings.

This commit is contained in:
Dain Nilsson 2022-05-12 08:34:51 +02:00
parent f80bb8f591
commit 0641418e34
No known key found for this signature in database
GPG Key ID: F04367096FBA95E8
30 changed files with 242 additions and 196 deletions

View File

@ -25,11 +25,11 @@ String randomPadded() {
}
String generateRandomIssuer() {
return 'i' + randomPadded();
return 'i${randomPadded()}';
}
String generateRandomName() {
return 'n' + randomPadded();
return 'n${randomPadded()}';
}
String generateRandomSecret() {

View File

@ -5,6 +5,7 @@ import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:logging/logging.dart';
import 'package:yubico_authenticator/app/state.dart';
import 'app/logging.dart';
import 'app/message.dart';
@ -43,8 +44,12 @@ class AboutPage extends ConsumerWidget {
final data = response['diagnostics'];
final text = const JsonEncoder.withIndent(' ').convert(data);
await Clipboard.setData(ClipboardData(text: text));
await ref.read(withContextProvider)(
(context) async {
showMessage(context, 'Diagnostic data copied to clipboard');
},
);
},
child: const Text('Run diagnostics...'),
),
]
@ -86,8 +91,12 @@ class LoggingPanel extends ConsumerWidget {
final logs =
ref.read(logLevelProvider.notifier).getLogs().join('\n');
await Clipboard.setData(ClipboardData(text: logs));
await ref.read(withContextProvider)(
(context) async {
showMessage(context, 'Log copied to clipboard');
},
);
},
),
],
);

View File

@ -27,11 +27,11 @@ class OverlayClipper extends CustomClipper<Path> {
bool shouldReclip(covariant CustomClipper<Path> oldClipper) => true;
}
class MobileScannerWrapper extends StatelessWidget {
class _MobileScannerWrapper extends StatelessWidget {
final Function(String) onDetect;
final _ScanStatus status;
const MobileScannerWrapper({
const _MobileScannerWrapper({
Key? key,
required this.onDetect,
required this.status,
@ -93,7 +93,7 @@ class QrScannerView extends StatefulWidget {
const QrScannerView({Key? key}) : super(key: key);
@override
_QrScannerViewState createState() => _QrScannerViewState();
State<QrScannerView> createState() => _QrScannerViewState();
}
class _QrScannerViewState extends State<QrScannerView> {
@ -166,7 +166,7 @@ class _QrScannerViewState extends State<QrScannerView> {
),
),
body: Stack(children: [
MobileScannerWrapper(
_MobileScannerWrapper(
status: _status,
onDetect: (scannedData) => handleResult(scannedData),
),

View File

@ -39,8 +39,8 @@ class FDialogApiImpl extends FDialogApi {
size: 64,
),
onCancel: () {
HDialogApi _api = HDialogApi();
_api.dialogClosed();
HDialogApi api = HDialogApi();
api.dialogClosed();
},
));
}

View File

@ -13,9 +13,9 @@ class DeviceAvatar extends StatelessWidget {
factory DeviceAvatar.yubiKeyData(YubiKeyData data, {bool selected = false}) =>
DeviceAvatar(
child: getProductImage(data.info, data.name),
badge: data.node is NfcReaderNode ? Icons.wifi : null,
selected: selected,
child: getProductImage(data.info, data.name),
);
factory DeviceAvatar.deviceNode(DeviceNode node, {bool selected = false}) =>
@ -29,13 +29,13 @@ class DeviceAvatar extends StatelessWidget {
);
}
return DeviceAvatar(
child: const Icon(Icons.device_unknown),
selected: selected,
child: const Icon(Icons.device_unknown),
);
},
nfcReader: (_) => DeviceAvatar(
child: const Icon(Icons.wifi),
selected: selected,
child: const Icon(Icons.wifi),
),
);

View File

@ -20,6 +20,7 @@ class MessagePage extends StatelessWidget {
Widget build(BuildContext context) => AppPage(
title: title,
centered: true,
floatingActionButton: floatingActionButton,
child: Column(
children: [
Text(header, style: Theme.of(context).textTheme.headline6),
@ -27,6 +28,5 @@ class MessagePage extends StatelessWidget {
Text(message, textAlign: TextAlign.center),
],
),
floatingActionButton: floatingActionButton,
);
}

View File

@ -40,8 +40,8 @@ class NoDeviceScreen extends ConsumerWidget {
}),
]
.map((e) => Padding(
child: e,
padding: const EdgeInsets.symmetric(vertical: 8.0),
child: e,
))
.toList();
}

View File

@ -64,7 +64,7 @@ Future<Widget> initialize(List<String> argv) async {
if (exe?.isEmpty ?? true) {
var relativePath = 'helper/authenticator-helper';
if (Platform.isMacOS) {
relativePath = '../Resources/' + relativePath;
relativePath = '../Resources/$relativePath';
} else if (Platform.isWindows) {
relativePath += '.exe';
}

View File

@ -1,3 +1,5 @@
// ignore_for_file: sort_child_properties_last
import 'dart:async';
import 'package:flutter/material.dart';
@ -110,6 +112,7 @@ class _AddFingerprintDialogState extends ConsumerState<AddFingerprintDialog>
await ref
.read(fingerprintProvider(widget.devicePath).notifier)
.renameFingerprint(_fingerprint!, _label);
if (!mounted) return;
Navigator.of(context).pop(true);
showMessage(context, 'Fingerprint added');
}

View File

@ -1,3 +1,5 @@
// ignore_for_file: sort_child_properties_last
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
@ -43,9 +45,13 @@ class DeleteCredentialDialog extends ConsumerWidget {
await ref
.read(credentialProvider(devicePath).notifier)
.deleteCredential(credential);
await ref.read(withContextProvider)(
(context) async {
Navigator.of(context).pop(true);
showMessage(context, 'Credential deleted');
},
);
},
child: const Text('Delete'),
),
],

View File

@ -25,6 +25,20 @@ class DeleteFingerprintDialog extends ConsumerWidget {
return ResponsiveDialog(
title: const Text('Delete fingerprint'),
actions: [
TextButton(
onPressed: () async {
await ref
.read(fingerprintProvider(devicePath).notifier)
.deleteFingerprint(fingerprint);
await ref.read(withContextProvider)((context) async {
Navigator.of(context).pop(true);
showMessage(context, 'Fingerprint deleted');
});
},
child: const Text('Delete'),
),
],
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
@ -32,23 +46,11 @@ class DeleteFingerprintDialog extends ConsumerWidget {
Text('Fingerprint: $label'),
]
.map((e) => Padding(
child: e,
padding: const EdgeInsets.symmetric(vertical: 8.0),
child: e,
))
.toList(),
),
actions: [
TextButton(
onPressed: () async {
await ref
.read(fingerprintProvider(devicePath).notifier)
.deleteFingerprint(fingerprint);
Navigator.of(context).pop(true);
showMessage(context, 'Fingerprint deleted');
},
child: const Text('Delete'),
),
],
);
}
}

View File

@ -85,9 +85,9 @@ class FidoScreen extends ConsumerWidget {
}),
]
.map((e) => Padding(
child: e,
padding:
const EdgeInsets.symmetric(vertical: 8.0),
child: e,
))
.toList(),
));

View File

@ -191,9 +191,9 @@ class _PinEntryFormState extends ConsumerState<_PinEntryForm> {
contentPadding: const EdgeInsets.symmetric(horizontal: 0),
minLeadingWidth: 0,
trailing: ElevatedButton(
child: const Text('Unlock'),
onPressed:
_pinController.text.isNotEmpty && !_blocked ? _submit : null,
child: const Text('Unlock'),
),
),
],

View File

@ -39,6 +39,12 @@ class _FidoPinDialogState extends ConsumerState<FidoPinDialog> {
return ResponsiveDialog(
title: Text(hasPin ? 'Change PIN' : 'Set PIN'),
actions: [
TextButton(
onPressed: isValid ? _submit : null,
child: const Text('Save'),
),
],
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
@ -109,12 +115,6 @@ class _FidoPinDialogState extends ConsumerState<FidoPinDialog> {
))
.toList(),
),
actions: [
TextButton(
child: const Text('Save'),
onPressed: isValid ? _submit : null,
),
],
);
}

View File

@ -33,6 +33,7 @@ class _RenameAccountDialogState extends ConsumerState<RenameFingerprintDialog> {
final renamed = await ref
.read(fingerprintProvider(widget.devicePath).notifier)
.renameFingerprint(widget.fingerprint, _label);
if (!mounted) return;
Navigator.of(context).pop(renamed);
showMessage(context, 'Fingerprint renamed');
}
@ -46,6 +47,12 @@ class _RenameAccountDialogState extends ConsumerState<RenameFingerprintDialog> {
return ResponsiveDialog(
title: const Text('Rename fingerprint'),
actions: [
TextButton(
onPressed: _label.isNotEmpty ? _submit : null,
child: const Text('Save'),
),
],
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
@ -71,17 +78,11 @@ class _RenameAccountDialogState extends ConsumerState<RenameFingerprintDialog> {
),
]
.map((e) => Padding(
child: e,
padding: const EdgeInsets.symmetric(vertical: 8.0),
child: e,
))
.toList(),
),
actions: [
TextButton(
onPressed: _label.isNotEmpty ? _submit : null,
child: const Text('Save'),
),
],
);
}
}

View File

@ -55,26 +55,6 @@ class _ResetDialogState extends ConsumerState<ResetDialog> {
return ResponsiveDialog(
title: const Text('Factory reset'),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'Warning! This will irrevocably delete all U2F and FIDO2 accounts from your YubiKey.'),
Text(
'Your credentials, as well as any PIN set, will be removed from this YubiKey. Make sure to first disable these from their respective web sites to avoid being locked out of your accounts.',
style: Theme.of(context).textTheme.bodyText1,
),
Center(
child: Text(_getMessage(),
style: Theme.of(context).textTheme.headline6),
),
]
.map((e) => Padding(
child: e,
padding: const EdgeInsets.symmetric(vertical: 8.0),
))
.toList(),
),
onCancel: () {
_subscription?.cancel();
},
@ -103,6 +83,26 @@ class _ResetDialogState extends ConsumerState<ResetDialog> {
child: const Text('Reset'),
),
],
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'Warning! This will irrevocably delete all U2F and FIDO2 accounts from your YubiKey.'),
Text(
'Your credentials, as well as any PIN set, will be removed from this YubiKey. Make sure to first disable these from their respective web sites to avoid being locked out of your accounts.',
style: Theme.of(context).textTheme.bodyText1,
),
Center(
child: Text(_getMessage(),
style: Theme.of(context).textTheme.headline6),
),
]
.map((e) => Padding(
padding: const EdgeInsets.symmetric(vertical: 8.0),
child: e,
))
.toList(),
),
);
}
}

View File

@ -97,10 +97,10 @@ class FidoUnlockedPage extends ConsumerWidget {
if (children.isNotEmpty) {
return AppPage(
title: const Text('WebAuthn'),
floatingActionButton: _buildFab(context),
child: Column(
children: children,
),
floatingActionButton: _buildFab(context),
);
}

View File

@ -31,10 +31,10 @@ void main(List<String> argv) async {
_log.warning('Platform initialization failed: $e');
runApp(
ProviderScope(
child: YubicoAuthenticatorApp(page: ErrorPage(error: e.toString())),
overrides: [
prefProvider.overrideWithValue(await SharedPreferences.getInstance())
],
child: YubicoAuthenticatorApp(page: ErrorPage(error: e.toString())),
),
);
}

View File

@ -129,6 +129,7 @@ class ManagementScreen extends ConsumerStatefulWidget {
class _ManagementScreenState extends ConsumerState<ManagementScreen> {
late Map<Transport, int> _enabled;
late int _interfaces;
bool _canSave = false;
@override
void initState() {
@ -182,6 +183,7 @@ class _ManagementScreenState extends ConsumerState<ManagementScreen> {
.copyWith(enabledCapabilities: _enabled),
reboot: reboot,
);
if (!mounted) return;
if (!reboot) Navigator.pop(context);
showMessage(context, 'Configuration updated');
} finally {
@ -203,6 +205,7 @@ class _ManagementScreenState extends ConsumerState<ManagementScreen> {
await ref
.read(managementStateProvider(widget.deviceData.node.path).notifier)
.setMode(interfaces: _interfaces);
if (!mounted) return;
showMessage(
context,
widget.deviceData.node.maybeMap(
@ -227,24 +230,28 @@ class _ManagementScreenState extends ConsumerState<ManagementScreen> {
Navigator.of(context).popUntil((route) => route.isFirst);
});
bool canSave = false;
return ResponsiveDialog(
title: const Text('Toggle applications'),
actions: [
TextButton(
onPressed: _canSave ? _submitForm : null,
child: const Text('Save'),
),
],
child:
ref.watch(managementStateProvider(widget.deviceData.node.path)).when(
loading: () => const AppLoadingScreen(),
error: (error, _) => AppFailureScreen('$error'),
data: (info) {
bool hasConfig = info.version.major > 4;
// TODO: Check mode for < YK5 intead
setState(() {
if (hasConfig) {
canSave = !_mapEquals(
_canSave = !_mapEquals(
_enabled,
info.config.enabledCapabilities,
);
} else {
canSave = _interfaces != 0 &&
_canSave = _interfaces != 0 &&
_interfaces !=
UsbInterfaces.forCapabilites(widget
.deviceData
@ -253,6 +260,7 @@ class _ManagementScreenState extends ConsumerState<ManagementScreen> {
.enabledCapabilities[Transport.usb] ??
0);
}
});
return Column(
children: [
hasConfig
@ -262,12 +270,6 @@ class _ManagementScreenState extends ConsumerState<ManagementScreen> {
);
},
),
actions: [
TextButton(
onPressed: canSave ? _submitForm : null,
child: const Text('Save'),
),
],
);
}
}

View File

@ -3,6 +3,7 @@ import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import '../../app/state.dart';
import '../../core/state.dart';
import '../../widgets/dialog_frame.dart';
import '../models.dart';
@ -19,6 +20,7 @@ class AccountDialog extends ConsumerWidget with AccountMixin {
final renamed = await super.renameCredential(context, ref);
if (renamed != null) {
// Replace this dialog with a new one, for the renamed credential.
await ref.read(withContextProvider)((context) async {
Navigator.of(context).pop();
await showDialog(
context: context,
@ -26,6 +28,7 @@ class AccountDialog extends ConsumerWidget with AccountMixin {
return AccountDialog(renamed);
},
);
});
}
return renamed;
}
@ -34,7 +37,9 @@ class AccountDialog extends ConsumerWidget with AccountMixin {
Future<bool> deleteCredential(BuildContext context, WidgetRef ref) async {
final deleted = await super.deleteCredential(context, ref);
if (deleted) {
await ref.read(withContextProvider)((context) async {
Navigator.of(context).pop();
});
}
return deleted;
}

View File

@ -81,7 +81,7 @@ mixin AccountMixin {
return value;
} else {
var i = value.length ~/ 2;
return value.substring(0, i) + ' ' + value.substring(i);
return '${value.substring(0, i)} ${value.substring(i)}';
}
}

View File

@ -2,6 +2,7 @@ import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:yubico_authenticator/app/state.dart';
import '../models.dart';
import '../state.dart';
@ -43,12 +44,6 @@ class AccountView extends ConsumerWidget with AccountMixin {
return buildActions(context, ref).map((e) {
final action = e.action;
return PopupMenuItem(
child: ListTile(
leading: e.icon,
title: Text(e.text),
dense: true,
contentPadding: EdgeInsets.zero,
),
enabled: action != null,
onTap: () {
// As soon as onTap returns, the Navigator is popped,
@ -58,6 +53,12 @@ class AccountView extends ConsumerWidget with AccountMixin {
action?.call(context);
});
},
child: ListTile(
leading: e.icon,
title: Text(e.text),
dense: true,
contentPadding: EdgeInsets.zero,
),
);
}).toList();
}
@ -104,8 +105,12 @@ class AccountView extends ConsumerWidget with AccountMixin {
ref,
);
}
await ref.read(withContextProvider)(
(context) async {
copyToClipboard(context, ref);
},
);
},
leading: CircleAvatar(
foregroundColor: darkMode ? Colors.black : Colors.white,
backgroundColor: _iconColor(darkMode ? 300 : 400),

View File

@ -144,6 +144,45 @@ class _OathAddAccountPageState extends ConsumerState<OathAddAccountPage> {
return ResponsiveDialog(
title: const Text('Add account'),
actions: [
TextButton(
onPressed: isValid
? () async {
if (secretLengthValid) {
final issuer = _issuerController.text;
final cred = CredentialData(
issuer: issuer.isEmpty ? null : issuer,
name: _accountController.text,
secret: secret,
oathType: _oathType,
hashAlgorithm: _hashAlgorithm,
digits: _digits,
period: period,
);
try {
await ref
.read(credentialListProvider(widget.devicePath)
.notifier)
.addAccount(cred.toUri(), requireTouch: _touch);
if (!mounted) return;
Navigator.of(context).pop();
showMessage(context, 'Account added');
} catch (e) {
_log.error('Failed to add account', e);
showMessage(context, 'Failed adding account');
}
} else {
setState(() {
_validateSecretLength = true;
});
}
}
: null,
child: const Text('Save', key: Key('save_btn')),
),
],
child: FileDropTarget(
onFileDropped: (fileData) async {
if (qrScanner != null) {
@ -359,44 +398,6 @@ class _OathAddAccountPageState extends ConsumerState<OathAddAccountPage> {
.toList(),
),
),
actions: [
TextButton(
onPressed: isValid
? () async {
if (secretLengthValid) {
final issuer = _issuerController.text;
final cred = CredentialData(
issuer: issuer.isEmpty ? null : issuer,
name: _accountController.text,
secret: secret,
oathType: _oathType,
hashAlgorithm: _hashAlgorithm,
digits: _digits,
period: period,
);
try {
await ref
.read(credentialListProvider(widget.devicePath)
.notifier)
.addAccount(cred.toUri(), requireTouch: _touch);
Navigator.of(context).pop();
showMessage(context, 'Account added');
} catch (e) {
_log.error('Failed to add account', e);
showMessage(context, 'Failed adding account');
}
} else {
setState(() {
_validateSecretLength = true;
});
}
}
: null,
child: const Text('Save', key: Key('save_btn')),
),
],
);
}
}

View File

@ -27,6 +27,22 @@ class DeleteAccountDialog extends ConsumerWidget {
return ResponsiveDialog(
title: const Text('Delete account'),
actions: [
TextButton(
onPressed: () async {
await ref
.read(credentialListProvider(device.path).notifier)
.deleteAccount(credential);
await ref.read(withContextProvider)(
(context) async {
Navigator.of(context).pop();
showMessage(context, 'Account deleted');
},
);
},
child: const Text('Delete'),
),
],
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
@ -39,23 +55,11 @@ class DeleteAccountDialog extends ConsumerWidget {
Text('Account: $label'),
]
.map((e) => Padding(
child: e,
padding: const EdgeInsets.symmetric(vertical: 8.0),
child: e,
))
.toList(),
),
actions: [
TextButton(
onPressed: () async {
await ref
.read(credentialListProvider(device.path).notifier)
.deleteAccount(credential);
Navigator.of(context).pop(true);
showMessage(context, 'Account deleted');
},
child: const Text('Delete'),
),
],
);
}
}

View File

@ -30,6 +30,7 @@ class _ManagePasswordDialogState extends ConsumerState<ManagePasswordDialog> {
.read(oathStateProvider(widget.path).notifier)
.setPassword(_currentPassword, _newPassword);
if (result) {
if (!mounted) return;
Navigator.of(context).pop();
showMessage(context, 'Password set');
} else {
@ -52,6 +53,12 @@ class _ManagePasswordDialogState extends ConsumerState<ManagePasswordDialog> {
return ResponsiveDialog(
title: const Text('Manage password'),
actions: [
TextButton(
onPressed: isValid ? _submit : null,
child: const Text('Save'),
)
],
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
@ -78,13 +85,13 @@ class _ManagePasswordDialogState extends ConsumerState<ManagePasswordDialog> {
runSpacing: 8.0,
children: [
OutlinedButton(
child: const Text('Remove password'),
onPressed: _currentPassword.isNotEmpty
? () async {
final result = await ref
.read(oathStateProvider(widget.path).notifier)
.unsetPassword(_currentPassword);
if (result) {
if (!mounted) return;
Navigator.of(context).pop();
showMessage(context, 'Password removed');
} else {
@ -94,6 +101,7 @@ class _ManagePasswordDialogState extends ConsumerState<ManagePasswordDialog> {
}
}
: null,
child: const Text('Remove password'),
),
if (widget.state.remembered)
OutlinedButton(
@ -102,6 +110,7 @@ class _ManagePasswordDialogState extends ConsumerState<ManagePasswordDialog> {
await ref
.read(oathStateProvider(widget.path).notifier)
.forgetPassword();
if (!mounted) return;
Navigator.of(context).pop();
showMessage(context, 'Password forgotten');
},
@ -153,12 +162,6 @@ class _ManagePasswordDialogState extends ConsumerState<ManagePasswordDialog> {
))
.toList(),
),
actions: [
TextButton(
onPressed: isValid ? _submit : null,
child: const Text('Save'),
)
],
);
}
}

View File

@ -112,8 +112,8 @@ class _UnlockedView extends ConsumerWidget {
);
}),
),
child: AccountList(devicePath, oathState),
floatingActionButton: _buildFab(context),
child: AccountList(devicePath, oathState),
);
}
@ -188,6 +188,7 @@ class _UnlockFormState extends ConsumerState<_UnlockForm> {
final result = await ref
.read(oathStateProvider(widget._devicePath).notifier)
.unlock(_passwordController.text, remember: _remember);
if (!mounted) return;
if (!result.first) {
setState(() {
_wrong = true;
@ -283,8 +284,8 @@ class _UnlockFormState extends ConsumerState<_UnlockForm> {
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16.0),
child: ElevatedButton(
child: const Text('Unlock'),
onPressed: _passwordController.text.isNotEmpty ? _submit : null,
child: const Text('Unlock'),
),
)
],

View File

@ -56,6 +56,22 @@ class _RenameAccountDialogState extends ConsumerState<RenameAccountDialog> {
return ResponsiveDialog(
title: const Text('Rename account'),
actions: [
TextButton(
onPressed: isValid
? () async {
final renamed = await ref
.read(credentialListProvider(widget.device.path).notifier)
.renameAccount(credential,
_issuer.isNotEmpty ? _issuer : null, _account);
if (!mounted) return;
Navigator.of(context).pop(renamed);
showMessage(context, 'Account renamed');
}
: null,
child: const Text('Save'),
),
],
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
@ -94,26 +110,11 @@ class _RenameAccountDialogState extends ConsumerState<RenameAccountDialog> {
),
]
.map((e) => Padding(
child: e,
padding: const EdgeInsets.symmetric(vertical: 8.0),
child: e,
))
.toList(),
),
actions: [
TextButton(
onPressed: isValid
? () async {
final renamed = await ref
.read(credentialListProvider(widget.device.path).notifier)
.renameAccount(credential,
_issuer.isNotEmpty ? _issuer : null, _account);
Navigator.of(context).pop(renamed);
showMessage(context, 'Account renamed');
}
: null,
child: const Text('Save'),
),
],
);
}
}

View File

@ -20,6 +20,18 @@ class ResetDialog extends ConsumerWidget {
return ResponsiveDialog(
title: const Text('Factory reset'),
actions: [
TextButton(
onPressed: () async {
await ref.read(oathStateProvider(devicePath).notifier).reset();
await ref.read(withContextProvider)((context) async {
Navigator.of(context).pop();
showMessage(context, 'OATH application reset');
});
},
child: const Text('Reset'),
),
],
child: Column(
children: [
const Text(
@ -30,21 +42,11 @@ class ResetDialog extends ConsumerWidget {
),
]
.map((e) => Padding(
child: e,
padding: const EdgeInsets.symmetric(vertical: 8.0),
child: e,
))
.toList(),
),
actions: [
TextButton(
onPressed: () async {
await ref.read(oathStateProvider(devicePath).notifier).reset();
Navigator.of(context).pop();
showMessage(context, 'OATH application reset');
},
child: const Text('Reset'),
),
],
);
}
}

View File

@ -142,7 +142,7 @@ packages:
source: hosted
version: "4.1.0"
collection:
dependency: transitive
dependency: "direct main"
description:
name: collection
url: "https://pub.dartlang.org"

View File

@ -37,6 +37,7 @@ dependencies:
async: ^2.8.2
logging: ^1.0.2
collection: ^1.16.0
shared_preferences: ^2.0.12
flutter_riverpod: ^1.0.0
json_annotation: ^4.4.0