Change various MessagePage views.

This commit is contained in:
Elias Bonnici 2024-01-26 10:36:10 +01:00
parent 2198f02184
commit 5fdb34f343
No known key found for this signature in database
GPG Key ID: 5EAC28EA3F980CCF
11 changed files with 112 additions and 50 deletions

View File

@ -65,6 +65,18 @@ enum Application {
_ => name.substring(0, 1).toUpperCase() + name.substring(1),
};
Capability? getCapability() => switch (this) {
Application.accounts => Capability.oath,
Application.webauthn => Capability.u2f,
Application.passkeys => Capability.fido2,
Application.fingerprints => Capability.fido2,
Application.certificates => Capability.piv,
Application.slots => Capability.otp,
Application.hsmauth => Capability.hsmauth,
Application.openpgp => Capability.openpgp,
_ => null
};
Availability getAvailability(YubiKeyData data) {
if (this == Application.management) {
final version = data.info.version;

View File

@ -44,7 +44,7 @@ class AppPage extends StatelessWidget {
final Widget Function(BuildContext context)? actionButtonBuilder;
final Widget? fileDropOverlay;
final Function(File file)? onFileDropped;
final List<Capability>? capabilities;
final Capability? capability;
const AppPage({
super.key,
this.title,
@ -55,7 +55,7 @@ class AppPage extends StatelessWidget {
this.detailViewBuilder,
this.actionButtonBuilder,
this.fileDropOverlay,
this.capabilities,
this.capability,
this.onFileDropped,
this.delayedContent = false,
this.keyActionsBadge = false,
@ -169,12 +169,7 @@ class AppPage extends StatelessWidget {
.colorScheme
.primary
.withOpacity(0.9))),
if (capabilities != null)
Wrap(
spacing: 4.0,
runSpacing: 8.0,
children: [...capabilities!.map((c) => _CapabilityBadge(c))],
)
if (capability != null) _CapabilityBadge(capability!)
])
],
);
@ -182,7 +177,8 @@ class AppPage extends StatelessWidget {
Widget _buildMainContent(BuildContext context, bool expanded) {
final content = Column(
crossAxisAlignment: CrossAxisAlignment.start,
crossAxisAlignment:
centered ? CrossAxisAlignment.center : CrossAxisAlignment.start,
children: [
if (title != null)
Padding(

View File

@ -25,7 +25,6 @@ import '../../desktop/state.dart';
import '../message.dart';
import '../models.dart';
import '../state.dart';
import 'device_avatar.dart';
import 'message_page.dart';
class DeviceErrorScreen extends ConsumerWidget {
@ -72,8 +71,13 @@ class DeviceErrorScreen extends ConsumerWidget {
}
return MessagePage(
centered: true,
graphic: const DeviceAvatar(child: Icon(Icons.usb_off)),
message: l10n.l_yk_no_access,
graphic: Image.asset(
'assets/product-images/generic.png',
filterQuality: FilterQuality.medium,
scale: 3,
color: Theme.of(context).colorScheme.error,
),
header: l10n.l_yk_no_access,
);
}
@ -86,11 +90,11 @@ class DeviceErrorScreen extends ConsumerWidget {
'unknown-device' => MessagePage(
centered: true,
graphic: Icon(
Icons.help_outline,
Icons.help_outlined,
size: 96,
color: Theme.of(context).colorScheme.primary,
color: Theme.of(context).colorScheme.error,
),
message: l10n.s_unknown_device,
header: l10n.s_unknown_device,
),
_ => MessagePage(
centered: true,

View File

@ -26,10 +26,12 @@ import '../../exception/cancellation_exception.dart';
import '../../fido/views/fingerprints_screen.dart';
import '../../fido/views/passkeys_screen.dart';
import '../../fido/views/webauthn_page.dart';
import '../../management/views/management_screen.dart';
import '../../oath/views/oath_screen.dart';
import '../../otp/views/otp_screen.dart';
import '../../piv/views/piv_screen.dart';
import '../../widgets/custom_icons.dart';
import '../message.dart';
import '../models.dart';
import '../state.dart';
import 'device_error_screen.dart';
@ -131,21 +133,48 @@ class MainPage extends ConsumerWidget {
return ref.watch(currentDeviceDataProvider).when(
data: (data) {
final app = ref.watch(currentAppProvider);
final capability = app.getCapability();
if (data.info.supportedCapabilities.isEmpty &&
data.name == 'Unrecognized device') {
return MessagePage(
centered: true,
graphic: Icon(
Icons.help_outlined,
size: 96,
color: Theme.of(context).colorScheme.error,
),
header: l10n.s_yk_not_recognized,
);
} else if (app.getAvailability(data) ==
Availability.unsupported) {
return MessagePage(
title: app.getDisplayName(l10n),
capability: capability,
header: l10n.s_app_not_supported,
message: l10n.l_app_not_supported_on_yk(app.name),
message: l10n.l_app_not_supported_on_yk(
capability?.getDisplayName(l10n) ?? app.name),
);
} else if (app.getAvailability(data) != Availability.enabled) {
return MessagePage(
title: app.getDisplayName(l10n),
capability: capability,
header: l10n.s_app_disabled,
message: l10n.l_app_disabled_desc(app.name),
message: l10n.l_app_disabled_desc(
capability?.getDisplayName(l10n) ?? app.name),
actions: [
ActionChip(
label: Text(data.info.version.major > 4
? l10n.s_toggle_applications
: l10n.s_toggle_interfaces),
onPressed: () async {
await showBlurDialog(
context: context,
builder: (context) => ManagementScreen(data),
);
},
avatar: const Icon(Icons.construction),
)
],
);
}

View File

@ -32,9 +32,9 @@ class MessagePage extends StatelessWidget {
final Widget Function(BuildContext context)? actionButtonBuilder;
final Widget? fileDropOverlay;
final Function(File file)? onFileDropped;
final List<Capability>? capabilities;
final Capability? capability;
final bool keyActionsBadge;
final bool? centered;
final bool centered;
const MessagePage({
super.key,
@ -49,15 +49,15 @@ class MessagePage extends StatelessWidget {
this.onFileDropped,
this.delayedContent = false,
this.keyActionsBadge = false,
this.capabilities,
this.centered,
this.capability,
this.centered = false,
});
@override
Widget build(BuildContext context) => AppPage(
title: title,
capabilities: capabilities,
centered: centered ?? false,
capability: capability,
centered: centered,
actions: actions,
keyActionsBuilder: keyActionsBuilder,
keyActionsBadge: keyActionsBadge,
@ -70,11 +70,11 @@ class MessagePage extends StatelessWidget {
left: 16.0,
top: 0.0,
right: 16.0,
bottom: centered ?? false ? 96 : 0),
bottom: centered && actions.isEmpty ? 96 : 0),
child: SizedBox(
width: 350,
child: Column(
crossAxisAlignment: centered ?? false
crossAxisAlignment: centered
? CrossAxisAlignment.center
: CrossAxisAlignment.start,
children: [
@ -84,17 +84,14 @@ class MessagePage extends StatelessWidget {
],
if (header != null)
Text(header!,
textAlign:
centered ?? false ? TextAlign.center : TextAlign.left,
textAlign: centered ? TextAlign.center : TextAlign.left,
style: Theme.of(context).textTheme.titleLarge),
if (message != null) ...[
const SizedBox(height: 12.0),
Container(
constraints: const BoxConstraints(maxWidth: 300),
child: Text(message!,
textAlign: centered ?? false
? TextAlign.center
: TextAlign.left,
textAlign: centered ? TextAlign.center : TextAlign.left,
style: Theme.of(context).textTheme.titleSmall?.apply(
color: Theme.of(context)
.colorScheme

View File

@ -61,7 +61,7 @@ class FingerprintsScreen extends ConsumerWidget {
if (Capability.fido2.value & enabled == 0) {
return MessagePage(
title: l10n.s_fingerprints,
capabilities: const [Capability.fido2],
capability: Capability.fido2,
header: l10n.s_fido_disabled,
message: l10n.l_webauthn_req_fido2,
);
@ -105,7 +105,7 @@ class _FidoLockedPage extends ConsumerWidget {
)
],
title: l10n.s_fingerprints,
capabilities: const [Capability.fido2],
capability: Capability.fido2,
header: '${l10n.s_fingerprints_get_started} (1/2)',
message: l10n.p_set_fingerprints_desc,
keyActionsBuilder: hasActions ? _buildActions : null,
@ -116,17 +116,28 @@ class _FidoLockedPage extends ConsumerWidget {
if (state.forcePinChange) {
return MessagePage(
title: l10n.s_fingerprints,
capabilities: const [Capability.fido2],
capability: Capability.fido2,
header: l10n.s_pin_change_required,
message: l10n.l_pin_change_required_desc,
keyActionsBuilder: hasActions ? _buildActions : null,
keyActionsBadge: fidoShowActionsNotifier(state),
actions: [
ActionChip(
label: Text(l10n.s_change_pin),
onPressed: () async {
await showBlurDialog(
context: context,
builder: (context) => FidoPinDialog(node.path, state));
},
avatar: const Icon(Icons.pin_outlined),
)
],
);
}
return AppPage(
title: l10n.s_fingerprints,
capabilities: const [Capability.fido2],
capability: Capability.fido2,
keyActionsBuilder: hasActions ? _buildActions : null,
builder: (context, _) => Column(
children: [
@ -179,7 +190,7 @@ class _FidoUnlockedPageState extends ConsumerState<_FidoUnlockedPage> {
)
],
title: l10n.s_fingerprints,
capabilities: const [Capability.fido2],
capability: Capability.fido2,
header: '${l10n.s_fingerprints_get_started} (2/2)',
message: l10n.l_add_one_or_more_fps,
keyActionsBuilder: hasActions
@ -239,7 +250,7 @@ class _FidoUnlockedPageState extends ConsumerState<_FidoUnlockedPage> {
},
builder: (context) => AppPage(
title: l10n.s_fingerprints,
capabilities: const [Capability.fido2],
capability: Capability.fido2,
detailViewBuilder: fingerprint != null
? (context) => Column(
crossAxisAlignment: CrossAxisAlignment.stretch,

View File

@ -37,6 +37,7 @@ import '../state.dart';
import 'actions.dart';
import 'credential_dialog.dart';
import 'key_actions.dart';
import 'pin_dialog.dart';
import 'pin_entry_form.dart';
class PasskeysScreen extends ConsumerWidget {
@ -56,10 +57,11 @@ class PasskeysScreen extends ConsumerWidget {
final enabled = deviceData
.info.config.enabledCapabilities[deviceData.node.transport] ??
0;
if (Capability.fido2.value & enabled == 0) {
return MessagePage(
title: l10n.s_passkeys,
capabilities: const [Capability.fido2],
capability: Capability.fido2,
header: l10n.s_fido_disabled,
message: l10n.l_webauthn_req_fido2,
);
@ -92,7 +94,7 @@ class _FidoLockedPage extends ConsumerWidget {
if (!state.hasPin) {
return MessagePage(
title: l10n.s_passkeys,
capabilities: const [Capability.fido2],
capability: Capability.fido2,
header: state.credMgmt
? l10n.l_no_discoverable_accounts
: l10n.l_ready_to_use,
@ -105,7 +107,7 @@ class _FidoLockedPage extends ConsumerWidget {
if (!state.credMgmt && state.bioEnroll == null) {
return MessagePage(
title: l10n.s_passkeys,
capabilities: const [Capability.fido2],
capability: Capability.fido2,
header: l10n.l_ready_to_use,
message: l10n.l_register_sk_on_websites,
keyActionsBuilder: hasActions ? _buildActions : null,
@ -115,8 +117,19 @@ class _FidoLockedPage extends ConsumerWidget {
if (state.forcePinChange) {
return MessagePage(
actions: [
ActionChip(
label: Text(l10n.s_change_pin),
onPressed: () async {
await showBlurDialog(
context: context,
builder: (context) => FidoPinDialog(node.path, state));
},
avatar: const Icon(Icons.pin_outlined),
)
],
title: l10n.s_passkeys,
capabilities: const [Capability.fido2],
capability: Capability.fido2,
header: l10n.s_pin_change_required,
message: l10n.l_pin_change_required_desc,
keyActionsBuilder: hasActions ? _buildActions : null,
@ -126,7 +139,7 @@ class _FidoLockedPage extends ConsumerWidget {
return AppPage(
title: l10n.s_passkeys,
capabilities: const [Capability.fido2],
capability: Capability.fido2,
keyActionsBuilder: hasActions ? _buildActions : null,
builder: (context, _) => Column(
children: [
@ -164,7 +177,7 @@ class _FidoUnlockedPageState extends ConsumerState<_FidoUnlockedPage> {
// TODO: Special handling for credMgmt not supported
return MessagePage(
title: l10n.s_passkeys,
capabilities: const [Capability.fido2],
capability: Capability.fido2,
header: l10n.l_no_discoverable_accounts,
message: l10n.l_register_sk_on_websites,
keyActionsBuilder: hasActions
@ -184,7 +197,7 @@ class _FidoUnlockedPageState extends ConsumerState<_FidoUnlockedPage> {
if (credentials.isEmpty) {
return MessagePage(
title: l10n.s_passkeys,
capabilities: const [Capability.fido2],
capability: Capability.fido2,
header: l10n.l_no_discoverable_accounts,
message: l10n.l_register_sk_on_websites,
keyActionsBuilder: hasActions
@ -233,7 +246,7 @@ class _FidoUnlockedPageState extends ConsumerState<_FidoUnlockedPage> {
},
builder: (context) => AppPage(
title: l10n.s_passkeys,
capabilities: const [Capability.fido2],
capability: Capability.fido2,
detailViewBuilder: credential != null
? (context) => Column(
crossAxisAlignment: CrossAxisAlignment.stretch,

View File

@ -28,7 +28,7 @@ class WebAuthnScreen extends StatelessWidget {
final l10n = AppLocalizations.of(context)!;
return MessagePage(
title: l10n.s_webauthn,
capabilities: const [Capability.u2f],
capability: Capability.u2f,
header: l10n.l_ready_to_use,
message: l10n.l_register_sk_on_websites,
);

View File

@ -83,7 +83,7 @@ class _LockedView extends ConsumerWidget {
final hasActions = ref.watch(featureProvider)(features.actions);
return AppPage(
title: AppLocalizations.of(context)!.s_accounts,
capabilities: const [Capability.oath],
capability: Capability.oath,
keyActionsBuilder: hasActions
? (context) => oathBuildActions(context, devicePath, oathState, ref)
: null,
@ -175,7 +175,7 @@ class _UnlockedViewState extends ConsumerState<_UnlockedView> {
)
],
title: l10n.s_accounts,
capabilities: const [Capability.oath],
capability: Capability.oath,
key: keys.noAccountsView,
header: l10n.l_authenticator_get_started,
message: l10n.p_no_accounts_desc,
@ -249,7 +249,7 @@ class _UnlockedViewState extends ConsumerState<_UnlockedView> {
},
builder: (context) => AppPage(
title: l10n.s_accounts,
capabilities: const [Capability.oath],
capability: Capability.oath,
keyActionsBuilder: hasActions
? (context) => oathBuildActions(
context,

View File

@ -93,7 +93,7 @@ class _OtpScreenState extends ConsumerState<OtpScreen> {
},
child: AppPage(
title: l10n.s_slots,
capabilities: const [Capability.otp],
capability: Capability.otp,
detailViewBuilder: selected != null
? (context) => Column(
crossAxisAlignment: CrossAxisAlignment.stretch,

View File

@ -106,7 +106,7 @@ class _PivScreenState extends ConsumerState<PivScreen> {
},
child: AppPage(
title: l10n.s_certificates,
capabilities: const [Capability.piv],
capability: Capability.piv,
detailViewBuilder: selected != null
? (context) => Column(
crossAxisAlignment: CrossAxisAlignment.stretch,