mirror of
https://github.com/Yubico/yubioath-flutter.git
synced 2024-12-23 10:11:52 +03:00
Fix state of details column.
This commit is contained in:
parent
b50ada490a
commit
0e709f0085
@ -39,102 +39,110 @@ import 'fingerprint_dialog.dart';
|
||||
import 'key_actions.dart';
|
||||
import 'rename_fingerprint_dialog.dart';
|
||||
|
||||
final _selectedItem = StateProvider<Object?>(
|
||||
(ref) => null,
|
||||
);
|
||||
|
||||
Widget _registerFingerprintActions(
|
||||
DevicePath devicePath,
|
||||
Fingerprint fingerprint, {
|
||||
required WidgetRef ref,
|
||||
required Widget Function(BuildContext context) builder,
|
||||
Map<Type, Action<Intent>> actions = const {},
|
||||
}) {
|
||||
final hasFeature = ref.watch(featureProvider);
|
||||
return Actions(
|
||||
actions: {
|
||||
if (hasFeature(features.fingerprintsEdit))
|
||||
EditIntent: CallbackAction<EditIntent>(onInvoke: (_) async {
|
||||
final renamed = await ref.read(withContextProvider)(
|
||||
(context) => showBlurDialog<Fingerprint>(
|
||||
context: context,
|
||||
builder: (context) => RenameFingerprintDialog(
|
||||
devicePath,
|
||||
fingerprint,
|
||||
),
|
||||
));
|
||||
if (renamed != null && ref.read(_selectedItem) == fingerprint) {
|
||||
ref.read(_selectedItem.notifier).state = renamed;
|
||||
}
|
||||
return renamed;
|
||||
}),
|
||||
if (hasFeature(features.fingerprintsDelete))
|
||||
DeleteIntent: CallbackAction<DeleteIntent>(onInvoke: (_) async {
|
||||
final deleted = await ref.read(withContextProvider)(
|
||||
(context) => showBlurDialog<bool?>(
|
||||
context: context,
|
||||
builder: (context) => DeleteFingerprintDialog(
|
||||
devicePath,
|
||||
fingerprint,
|
||||
),
|
||||
));
|
||||
if (deleted == true && ref.read(_selectedItem) == fingerprint) {
|
||||
ref.read(_selectedItem.notifier).state = null;
|
||||
}
|
||||
return deleted;
|
||||
}),
|
||||
...actions,
|
||||
},
|
||||
child: Builder(builder: builder),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _registerCredentialActions(
|
||||
DevicePath devicePath,
|
||||
FidoCredential credential, {
|
||||
required WidgetRef ref,
|
||||
required Widget Function(BuildContext context) builder,
|
||||
Map<Type, Action<Intent>> actions = const {},
|
||||
}) {
|
||||
final hasFeature = ref.watch(featureProvider);
|
||||
return Actions(
|
||||
actions: {
|
||||
if (hasFeature(features.credentialsDelete))
|
||||
DeleteIntent: CallbackAction<DeleteIntent>(onInvoke: (_) async {
|
||||
final deleted = await ref.read(withContextProvider)(
|
||||
(context) => showBlurDialog<bool?>(
|
||||
context: context,
|
||||
builder: (context) => DeleteCredentialDialog(
|
||||
devicePath,
|
||||
credential,
|
||||
),
|
||||
),
|
||||
);
|
||||
if (deleted == true && ref.read(_selectedItem) == credential) {
|
||||
ref.read(_selectedItem.notifier).state = null;
|
||||
}
|
||||
return deleted;
|
||||
}),
|
||||
...actions,
|
||||
},
|
||||
child: Builder(builder: builder),
|
||||
);
|
||||
}
|
||||
|
||||
class FidoUnlockedPage extends ConsumerWidget {
|
||||
class FidoUnlockedPage extends ConsumerStatefulWidget {
|
||||
final DeviceNode node;
|
||||
final FidoState state;
|
||||
|
||||
const FidoUnlockedPage(this.node, this.state, {super.key});
|
||||
FidoUnlockedPage(this.node, this.state) : super(key: ObjectKey(node.path));
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
ConsumerState<ConsumerStatefulWidget> createState() =>
|
||||
_FidoUnlockedPageState();
|
||||
}
|
||||
|
||||
class _FidoUnlockedPageState extends ConsumerState<FidoUnlockedPage> {
|
||||
Object? _selected;
|
||||
|
||||
Widget _registerFingerprintActions(
|
||||
Fingerprint fingerprint, {
|
||||
required WidgetRef ref,
|
||||
required Widget Function(BuildContext context) builder,
|
||||
Map<Type, Action<Intent>> actions = const {},
|
||||
}) {
|
||||
final hasFeature = ref.watch(featureProvider);
|
||||
return Actions(
|
||||
actions: {
|
||||
if (hasFeature(features.fingerprintsEdit))
|
||||
EditIntent: CallbackAction<EditIntent>(onInvoke: (_) async {
|
||||
final renamed = await ref.read(withContextProvider)(
|
||||
(context) => showBlurDialog<Fingerprint>(
|
||||
context: context,
|
||||
builder: (context) => RenameFingerprintDialog(
|
||||
widget.node.path,
|
||||
fingerprint,
|
||||
),
|
||||
));
|
||||
if (_selected == fingerprint && renamed != null) {
|
||||
setState(() {
|
||||
_selected = renamed;
|
||||
});
|
||||
}
|
||||
return renamed;
|
||||
}),
|
||||
if (hasFeature(features.fingerprintsDelete))
|
||||
DeleteIntent: CallbackAction<DeleteIntent>(onInvoke: (_) async {
|
||||
final deleted = await ref.read(withContextProvider)(
|
||||
(context) => showBlurDialog<bool?>(
|
||||
context: context,
|
||||
builder: (context) => DeleteFingerprintDialog(
|
||||
widget.node.path,
|
||||
fingerprint,
|
||||
),
|
||||
));
|
||||
if (_selected == fingerprint && deleted == true) {
|
||||
setState(() {
|
||||
_selected = null;
|
||||
});
|
||||
}
|
||||
return deleted;
|
||||
}),
|
||||
...actions,
|
||||
},
|
||||
child: Builder(builder: builder),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _registerCredentialActions(
|
||||
FidoCredential credential, {
|
||||
required WidgetRef ref,
|
||||
required Widget Function(BuildContext context) builder,
|
||||
Map<Type, Action<Intent>> actions = const {},
|
||||
}) {
|
||||
final hasFeature = ref.watch(featureProvider);
|
||||
return Actions(
|
||||
actions: {
|
||||
if (hasFeature(features.credentialsDelete))
|
||||
DeleteIntent: CallbackAction<DeleteIntent>(onInvoke: (_) async {
|
||||
final deleted = await ref.read(withContextProvider)(
|
||||
(context) => showBlurDialog<bool?>(
|
||||
context: context,
|
||||
builder: (context) => DeleteCredentialDialog(
|
||||
widget.node.path,
|
||||
credential,
|
||||
),
|
||||
),
|
||||
);
|
||||
if (_selected == credential && deleted == true) {
|
||||
setState(() {
|
||||
_selected = null;
|
||||
});
|
||||
}
|
||||
return deleted;
|
||||
}),
|
||||
...actions,
|
||||
},
|
||||
child: Builder(builder: builder),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final l10n = AppLocalizations.of(context)!;
|
||||
final selected = ref.watch(_selectedItem);
|
||||
final selected = _selected;
|
||||
List<Widget Function(bool expanded)> children = [];
|
||||
|
||||
if (state.credMgmt) {
|
||||
final data = ref.watch(credentialProvider(node.path)).asData;
|
||||
if (widget.state.credMgmt) {
|
||||
final data = ref.watch(credentialProvider(widget.node.path)).asData;
|
||||
if (data == null) {
|
||||
return _buildLoadingPage(context);
|
||||
}
|
||||
@ -143,13 +151,14 @@ class FidoUnlockedPage extends ConsumerWidget {
|
||||
children.add((_) => ListTitle(l10n.s_passkeys));
|
||||
children.addAll(
|
||||
creds.map((cred) => (expanded) => _registerCredentialActions(
|
||||
node.path,
|
||||
cred,
|
||||
ref: ref,
|
||||
actions: {
|
||||
OpenIntent: CallbackAction<OpenIntent>(onInvoke: (_) {
|
||||
if (expanded) {
|
||||
ref.read(_selectedItem.notifier).state = cred;
|
||||
setState(() {
|
||||
_selected = cred;
|
||||
});
|
||||
return null;
|
||||
} else {
|
||||
return showBlurDialog(
|
||||
@ -170,8 +179,8 @@ class FidoUnlockedPage extends ConsumerWidget {
|
||||
}
|
||||
|
||||
int nFingerprints = 0;
|
||||
if (state.bioEnroll != null) {
|
||||
final data = ref.watch(fingerprintProvider(node.path)).asData;
|
||||
if (widget.state.bioEnroll != null) {
|
||||
final data = ref.watch(fingerprintProvider(widget.node.path)).asData;
|
||||
if (data == null) {
|
||||
return _buildLoadingPage(context);
|
||||
}
|
||||
@ -181,13 +190,14 @@ class FidoUnlockedPage extends ConsumerWidget {
|
||||
children.add((_) => ListTitle(l10n.s_fingerprints));
|
||||
children.addAll(
|
||||
fingerprints.map((fp) => (expanded) => _registerFingerprintActions(
|
||||
node.path,
|
||||
fp,
|
||||
ref: ref,
|
||||
actions: {
|
||||
OpenIntent: CallbackAction<OpenIntent>(onInvoke: (_) {
|
||||
if (expanded) {
|
||||
ref.read(_selectedItem.notifier).state = fp;
|
||||
setState(() {
|
||||
_selected = fp;
|
||||
});
|
||||
return null;
|
||||
} else {
|
||||
return showBlurDialog(
|
||||
@ -214,7 +224,9 @@ class FidoUnlockedPage extends ConsumerWidget {
|
||||
actions: {
|
||||
EscapeIntent: CallbackAction<EscapeIntent>(onInvoke: (intent) {
|
||||
if (selected != null) {
|
||||
ref.read(_selectedItem.notifier).state = null;
|
||||
setState(() {
|
||||
_selected = null;
|
||||
});
|
||||
} else {
|
||||
Actions.invoke(context, intent);
|
||||
}
|
||||
@ -225,7 +237,7 @@ class FidoUnlockedPage extends ConsumerWidget {
|
||||
title: Text(l10n.s_webauthn),
|
||||
keyActionsBuilder: switch (selected) {
|
||||
FidoCredential credential => (context) =>
|
||||
_registerCredentialActions(node.path, credential,
|
||||
_registerCredentialActions(credential,
|
||||
ref: ref,
|
||||
builder: (context) => Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
@ -274,7 +286,6 @@ class FidoUnlockedPage extends ConsumerWidget {
|
||||
],
|
||||
)),
|
||||
Fingerprint fingerprint => (context) => _registerFingerprintActions(
|
||||
node.path,
|
||||
fingerprint,
|
||||
ref: ref,
|
||||
builder: (context) => Column(
|
||||
@ -309,11 +320,11 @@ class FidoUnlockedPage extends ConsumerWidget {
|
||||
),
|
||||
),
|
||||
_ => hasActions
|
||||
? (context) =>
|
||||
fidoBuildActions(context, node, state, nFingerprints)
|
||||
? (context) => fidoBuildActions(
|
||||
context, widget.node, widget.state, nFingerprints)
|
||||
: null
|
||||
},
|
||||
keyActionsBadge: fidoShowActionsNotifier(state),
|
||||
keyActionsBadge: fidoShowActionsNotifier(widget.state),
|
||||
builder: (context, expanded) => Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: children.map((f) => f(expanded)).toList()),
|
||||
@ -321,7 +332,7 @@ class FidoUnlockedPage extends ConsumerWidget {
|
||||
);
|
||||
}
|
||||
|
||||
if (state.bioEnroll != null) {
|
||||
if (widget.state.bioEnroll != null) {
|
||||
return MessagePage(
|
||||
title: Text(l10n.s_webauthn),
|
||||
graphic: Icon(Icons.fingerprint,
|
||||
@ -329,9 +340,10 @@ class FidoUnlockedPage extends ConsumerWidget {
|
||||
header: l10n.s_no_fingerprints,
|
||||
message: l10n.l_add_one_or_more_fps,
|
||||
keyActionsBuilder: hasActions
|
||||
? (context) => fidoBuildActions(context, node, state, 0)
|
||||
? (context) =>
|
||||
fidoBuildActions(context, widget.node, widget.state, 0)
|
||||
: null,
|
||||
keyActionsBadge: fidoShowActionsNotifier(state),
|
||||
keyActionsBadge: fidoShowActionsNotifier(widget.state),
|
||||
);
|
||||
}
|
||||
|
||||
@ -342,9 +354,9 @@ class FidoUnlockedPage extends ConsumerWidget {
|
||||
header: l10n.l_no_discoverable_accounts,
|
||||
message: l10n.l_register_sk_on_websites,
|
||||
keyActionsBuilder: hasActions
|
||||
? (context) => fidoBuildActions(context, node, state, 0)
|
||||
? (context) => fidoBuildActions(context, widget.node, widget.state, 0)
|
||||
: null,
|
||||
keyActionsBadge: fidoShowActionsNotifier(state),
|
||||
keyActionsBadge: fidoShowActionsNotifier(widget.state),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -37,20 +37,23 @@ import 'actions.dart';
|
||||
import 'key_actions.dart';
|
||||
import 'slot_dialog.dart';
|
||||
|
||||
final _selectedSlot = StateProvider<OtpSlot?>(
|
||||
(ref) => null,
|
||||
);
|
||||
|
||||
class OtpScreen extends ConsumerWidget {
|
||||
class OtpScreen extends ConsumerStatefulWidget {
|
||||
final DevicePath devicePath;
|
||||
|
||||
const OtpScreen(this.devicePath, {super.key});
|
||||
OtpScreen(this.devicePath) : super(key: ObjectKey(devicePath));
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
ConsumerState<ConsumerStatefulWidget> createState() => _OtpScreenState();
|
||||
}
|
||||
|
||||
class _OtpScreenState extends ConsumerState<OtpScreen> {
|
||||
SlotId? _selected;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final l10n = AppLocalizations.of(context)!;
|
||||
final hasFeature = ref.watch(featureProvider);
|
||||
return ref.watch(otpStateProvider(devicePath)).when(
|
||||
return ref.watch(otpStateProvider(widget.devicePath)).when(
|
||||
loading: () => MessagePage(
|
||||
title: Text(l10n.s_slots),
|
||||
graphic: const CircularProgressIndicator(),
|
||||
@ -59,12 +62,16 @@ class OtpScreen extends ConsumerWidget {
|
||||
error: (error, _) =>
|
||||
AppFailurePage(title: Text(l10n.s_slots), cause: error),
|
||||
data: (otpState) {
|
||||
final selected = ref.watch(_selectedSlot);
|
||||
final selected = _selected != null
|
||||
? otpState.slots.firstWhere((e) => e.slot == _selected)
|
||||
: null;
|
||||
return Actions(
|
||||
actions: {
|
||||
EscapeIntent: CallbackAction<EscapeIntent>(onInvoke: (intent) {
|
||||
if (selected != null) {
|
||||
ref.read(_selectedSlot.notifier).state = null;
|
||||
setState(() {
|
||||
_selected = null;
|
||||
});
|
||||
} else {
|
||||
Actions.invoke(context, intent);
|
||||
}
|
||||
@ -75,7 +82,7 @@ class OtpScreen extends ConsumerWidget {
|
||||
title: Text(l10n.s_slots),
|
||||
keyActionsBuilder: selected != null
|
||||
? (context) => registerOtpActions(
|
||||
devicePath,
|
||||
widget.devicePath,
|
||||
selected,
|
||||
ref: ref,
|
||||
builder: (context) => Column(
|
||||
@ -119,36 +126,45 @@ class OtpScreen extends ConsumerWidget {
|
||||
),
|
||||
)
|
||||
: (hasFeature(features.actions)
|
||||
? (context) =>
|
||||
otpBuildActions(context, devicePath, otpState, ref)
|
||||
? (context) => otpBuildActions(
|
||||
context, widget.devicePath, otpState, ref)
|
||||
: null),
|
||||
builder: (context, expanded) {
|
||||
// De-select if window is resized to be non-expanded.
|
||||
if (!expanded) {
|
||||
Timer.run(() {
|
||||
ref.read(_selectedSlot.notifier).state = null;
|
||||
setState(() {
|
||||
_selected = null;
|
||||
});
|
||||
});
|
||||
}
|
||||
return Column(children: [
|
||||
ListTitle(l10n.s_slots),
|
||||
...otpState.slots.map((e) => registerOtpActions(devicePath, e,
|
||||
ref: ref,
|
||||
actions: {
|
||||
OpenIntent:
|
||||
CallbackAction<OpenIntent>(onInvoke: (_) async {
|
||||
if (expanded) {
|
||||
ref.read(_selectedSlot.notifier).state = e;
|
||||
} else {
|
||||
await showBlurDialog(
|
||||
context: context,
|
||||
barrierColor: Colors.transparent,
|
||||
builder: (context) => SlotDialog(e.slot),
|
||||
);
|
||||
}
|
||||
return null;
|
||||
}),
|
||||
},
|
||||
builder: (context) => _SlotListItem(e, expanded)))
|
||||
...otpState.slots
|
||||
.map((e) => registerOtpActions(widget.devicePath, e,
|
||||
ref: ref,
|
||||
actions: {
|
||||
OpenIntent:
|
||||
CallbackAction<OpenIntent>(onInvoke: (_) async {
|
||||
if (expanded) {
|
||||
setState(() {
|
||||
_selected = e.slot;
|
||||
});
|
||||
} else {
|
||||
await showBlurDialog(
|
||||
context: context,
|
||||
barrierColor: Colors.transparent,
|
||||
builder: (context) => SlotDialog(e.slot),
|
||||
);
|
||||
}
|
||||
return null;
|
||||
}),
|
||||
},
|
||||
builder: (context) => _SlotListItem(
|
||||
e,
|
||||
expanded: expanded,
|
||||
selected: e == selected,
|
||||
)))
|
||||
]);
|
||||
},
|
||||
),
|
||||
@ -160,8 +176,10 @@ class OtpScreen extends ConsumerWidget {
|
||||
class _SlotListItem extends ConsumerWidget {
|
||||
final OtpSlot otpSlot;
|
||||
final bool expanded;
|
||||
final bool selected;
|
||||
|
||||
const _SlotListItem(this.otpSlot, this.expanded);
|
||||
const _SlotListItem(this.otpSlot,
|
||||
{required this.expanded, required this.selected});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
@ -170,7 +188,6 @@ class _SlotListItem extends ConsumerWidget {
|
||||
final colorScheme = Theme.of(context).colorScheme;
|
||||
final isConfigured = otpSlot.isConfigured;
|
||||
final hasFeature = ref.watch(featureProvider);
|
||||
final selected = ref.watch(_selectedSlot) == otpSlot;
|
||||
|
||||
return AppListItem(
|
||||
selected: selected,
|
||||
|
@ -39,20 +39,23 @@ import 'cert_info_view.dart';
|
||||
import 'key_actions.dart';
|
||||
import 'slot_dialog.dart';
|
||||
|
||||
final _selectedSlot = StateProvider<PivSlot?>(
|
||||
(ref) => null,
|
||||
);
|
||||
|
||||
class PivScreen extends ConsumerWidget {
|
||||
class PivScreen extends ConsumerStatefulWidget {
|
||||
final DevicePath devicePath;
|
||||
|
||||
const PivScreen(this.devicePath, {super.key});
|
||||
PivScreen(this.devicePath) : super(key: ObjectKey(devicePath));
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
ConsumerState<ConsumerStatefulWidget> createState() => _PivScreenState();
|
||||
}
|
||||
|
||||
class _PivScreenState extends ConsumerState<PivScreen> {
|
||||
SlotId? _selected;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final l10n = AppLocalizations.of(context)!;
|
||||
final hasFeature = ref.watch(featureProvider);
|
||||
return ref.watch(pivStateProvider(devicePath)).when(
|
||||
return ref.watch(pivStateProvider(widget.devicePath)).when(
|
||||
loading: () => MessagePage(
|
||||
title: Text(l10n.s_certificates),
|
||||
graphic: const CircularProgressIndicator(),
|
||||
@ -63,8 +66,11 @@ class PivScreen extends ConsumerWidget {
|
||||
cause: error,
|
||||
),
|
||||
data: (pivState) {
|
||||
final pivSlots = ref.watch(pivSlotsProvider(devicePath)).asData;
|
||||
final selected = ref.watch(_selectedSlot);
|
||||
final pivSlots =
|
||||
ref.watch(pivSlotsProvider(widget.devicePath)).asData;
|
||||
final selected = _selected != null
|
||||
? pivSlots?.value.firstWhere((e) => e.slot == _selected)
|
||||
: null;
|
||||
final theme = Theme.of(context);
|
||||
final textTheme = theme.textTheme;
|
||||
// This is what ListTile uses for subtitle
|
||||
@ -75,7 +81,9 @@ class PivScreen extends ConsumerWidget {
|
||||
actions: {
|
||||
EscapeIntent: CallbackAction<EscapeIntent>(onInvoke: (intent) {
|
||||
if (selected != null) {
|
||||
ref.read(_selectedSlot.notifier).state = null;
|
||||
setState(() {
|
||||
_selected = null;
|
||||
});
|
||||
} else {
|
||||
Actions.invoke(context, intent);
|
||||
}
|
||||
@ -87,7 +95,7 @@ class PivScreen extends ConsumerWidget {
|
||||
keyActionsBuilder: selected != null
|
||||
// TODO: Reuse slot dialog
|
||||
? (context) => registerPivActions(
|
||||
devicePath,
|
||||
widget.devicePath,
|
||||
pivState,
|
||||
selected,
|
||||
ref: ref,
|
||||
@ -127,20 +135,22 @@ class PivScreen extends ConsumerWidget {
|
||||
),
|
||||
if (hasFeature(features.actions)) ...[
|
||||
pivBuildActions(
|
||||
context, devicePath, pivState, ref),
|
||||
context, widget.devicePath, pivState, ref),
|
||||
],
|
||||
],
|
||||
),
|
||||
)
|
||||
: (hasFeature(features.actions)
|
||||
? (context) =>
|
||||
pivBuildActions(context, devicePath, pivState, ref)
|
||||
? (context) => pivBuildActions(
|
||||
context, widget.devicePath, pivState, ref)
|
||||
: null),
|
||||
builder: (context, expanded) {
|
||||
// De-select if window is resized to be non-expanded.
|
||||
if (!expanded) {
|
||||
Timer.run(() {
|
||||
ref.read(_selectedSlot.notifier).state = null;
|
||||
setState(() {
|
||||
_selected = null;
|
||||
});
|
||||
});
|
||||
}
|
||||
return Column(
|
||||
@ -148,7 +158,7 @@ class PivScreen extends ConsumerWidget {
|
||||
ListTitle(l10n.s_certificates),
|
||||
if (pivSlots?.hasValue == true)
|
||||
...pivSlots!.value.map((e) => registerPivActions(
|
||||
devicePath,
|
||||
widget.devicePath,
|
||||
pivState,
|
||||
e,
|
||||
ref: ref,
|
||||
@ -156,7 +166,9 @@ class PivScreen extends ConsumerWidget {
|
||||
OpenIntent: CallbackAction<OpenIntent>(
|
||||
onInvoke: (_) async {
|
||||
if (expanded) {
|
||||
ref.read(_selectedSlot.notifier).state = e;
|
||||
setState(() {
|
||||
_selected = e.slot;
|
||||
});
|
||||
} else {
|
||||
await showBlurDialog(
|
||||
context: context,
|
||||
@ -167,8 +179,11 @@ class PivScreen extends ConsumerWidget {
|
||||
return null;
|
||||
}),
|
||||
},
|
||||
builder: (context) =>
|
||||
_CertificateListItem(e, expanded),
|
||||
builder: (context) => _CertificateListItem(
|
||||
e,
|
||||
expanded: expanded,
|
||||
selected: e == selected,
|
||||
),
|
||||
)),
|
||||
],
|
||||
);
|
||||
@ -183,8 +198,10 @@ class PivScreen extends ConsumerWidget {
|
||||
class _CertificateListItem extends ConsumerWidget {
|
||||
final PivSlot pivSlot;
|
||||
final bool expanded;
|
||||
final bool selected;
|
||||
|
||||
const _CertificateListItem(this.pivSlot, this.expanded);
|
||||
const _CertificateListItem(this.pivSlot,
|
||||
{required this.expanded, required this.selected});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
@ -193,7 +210,6 @@ class _CertificateListItem extends ConsumerWidget {
|
||||
final l10n = AppLocalizations.of(context)!;
|
||||
final colorScheme = Theme.of(context).colorScheme;
|
||||
final hasFeature = ref.watch(featureProvider);
|
||||
final selected = ref.watch(_selectedSlot) == pivSlot;
|
||||
|
||||
return AppListItem(
|
||||
selected: selected,
|
||||
|
Loading…
Reference in New Issue
Block a user