yubioath-flutter/lib/oath/views/account_dialog.dart

174 lines
6.4 KiB
Dart
Raw Normal View History

2022-10-04 13:12:54 +03:00
/*
* Copyright (C) 2022 Yubico.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import 'dart:async';
2022-03-02 10:23:29 +03:00
import 'package:flutter/material.dart';
2023-02-28 13:34:29 +03:00
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
2022-03-02 10:23:29 +03:00
2022-07-04 13:56:31 +03:00
import '../../app/message.dart';
2022-06-10 14:49:02 +03:00
import '../../app/shortcuts.dart';
2022-05-12 09:34:51 +03:00
import '../../app/state.dart';
2023-06-09 15:46:16 +03:00
import '../../app/views/action_list.dart';
import '../../app/views/fs_dialog.dart';
import '../../core/models.dart';
import '../../core/state.dart';
2024-04-25 16:26:33 +03:00
import '../../widgets/tooltip_if_truncated.dart';
import '../features.dart' as features;
2022-03-02 10:23:29 +03:00
import '../models.dart';
2023-02-10 19:37:42 +03:00
import '../state.dart';
import 'account_helper.dart';
import 'actions.dart';
2022-03-02 10:23:29 +03:00
2023-02-10 19:37:42 +03:00
class AccountDialog extends ConsumerWidget {
2022-03-02 10:23:29 +03:00
final OathCredential credential;
2022-05-12 10:56:55 +03:00
const AccountDialog(this.credential, {super.key});
2022-03-02 10:23:29 +03:00
@override
Widget build(BuildContext context, WidgetRef ref) {
// TODO: Solve this in a cleaner way
2023-02-10 19:37:42 +03:00
final node = ref.watch(currentDeviceDataProvider).valueOrNull?.node;
if (node == null) {
// The rest of this method assumes there is a device, and will throw an exception if not.
// This will never be shown, as the dialog will be immediately closed
return const SizedBox();
}
final hasFeature = ref.watch(featureProvider);
2023-02-10 19:37:42 +03:00
final helper = AccountHelper(context, ref, credential);
final subtitle = helper.subtitle;
return OathActions(
devicePath: node.path,
actions: (context) => {
if (hasFeature(features.accountsRename))
EditIntent<OathCredential>:
CallbackAction<EditIntent<OathCredential>>(
onInvoke: (intent) async {
final renamed =
await (Actions.invoke(context, intent) as Future<dynamic>?);
if (renamed is OathCredential) {
// Replace the dialog with the renamed credential
final withContext = ref.read(withContextProvider);
await withContext((context) async {
Navigator.of(context).pop();
await showBlurDialog(
context: context,
builder: (context) {
return AccountDialog(renamed);
},
);
});
}
return renamed;
}),
if (hasFeature(features.accountsDelete))
2024-02-05 17:01:23 +03:00
DeleteIntent<OathCredential>:
CallbackAction<DeleteIntent<OathCredential>>(
onInvoke: (intent) async {
final deleted =
await (Actions.invoke(context, intent) as Future<dynamic>?);
// Pop the account dialog if deleted
if (deleted == true) {
2024-02-05 17:01:23 +03:00
await ref.read(withContextProvider)((context) async {
Navigator.of(context).pop();
});
}
return deleted;
}),
},
2023-02-10 19:37:42 +03:00
builder: (context) {
if (helper.code == null &&
(isDesktop || node.transport == Transport.usb)) {
Timer.run(() {
// Only call if credential hasn't been deleted/renamed
if (ref.read(credentialsProvider)?.contains(credential) == true) {
Actions.invoke(
context, RefreshIntent<OathCredential>(credential));
}
2023-02-10 19:37:42 +03:00
});
}
return ItemShortcuts(
item: credential,
child: FocusScope(
autofocus: true,
child: FsDialog(
child: Column(
children: [
Padding(
padding: const EdgeInsets.symmetric(
horizontal: 12, vertical: 32),
child: Column(
children: [
Padding(
padding: const EdgeInsets.symmetric(vertical: 16),
child: Row(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
IconTheme(
data: IconTheme.of(context).copyWith(size: 24),
child: helper.buildCodeIcon(),
),
const SizedBox(width: 8.0),
DefaultTextStyle.merge(
style: const TextStyle(fontSize: 28),
child: helper.buildCodeLabel(),
),
],
),
),
2024-04-25 16:26:33 +03:00
TooltipIfTruncated(
text: helper.title,
style: TextStyle(
fontSize: Theme.of(context)
.textTheme
.headlineSmall
?.fontSize),
),
if (subtitle != null)
2024-04-25 16:26:33 +03:00
TooltipIfTruncated(
text: subtitle,
// This is what ListTile uses for subtitle
style: Theme.of(context)
.textTheme
.bodyMedium!
.copyWith(
color: Theme.of(context)
2024-04-25 16:26:33 +03:00
.colorScheme
.onSurfaceVariant,
),
),
],
),
),
ActionListSection.fromMenuActions(
context,
AppLocalizations.of(context)!.s_actions,
actions: helper.buildActions(),
),
],
),
2023-02-10 19:37:42 +03:00
),
),
2023-02-10 19:37:42 +03:00
);
},
2022-03-02 10:23:29 +03:00
);
}
}