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

178 lines
6.7 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';
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 registerOathActions(
node.path,
2023-02-10 19:37:42 +03:00
ref: ref,
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 Actions(
actions: {
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))
DeleteIntent:
CallbackAction<DeleteIntent>(onInvoke: (intent) async {
final deleted =
await (Actions.invoke(context, intent) as Future<dynamic>?);
// Pop the account dialog if deleted
final withContext = ref.read(withContextProvider);
if (deleted == true) {
await withContext((context) async {
Navigator.of(context).pop();
});
}
return deleted;
}),
},
child: Shortcuts(
shortcuts: itemShortcuts(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(),
),
],
2023-08-18 17:51:42 +03:00
),
),
Text(
helper.title,
style: Theme.of(context).textTheme.headlineSmall,
softWrap: true,
textAlign: TextAlign.center,
),
if (subtitle != null)
Text(
subtitle,
softWrap: true,
textAlign: TextAlign.center,
// This is what ListTile uses for subtitle
style: Theme.of(context)
.textTheme
.bodyMedium!
.copyWith(
2023-08-18 17:51:42 +03:00
color: Theme.of(context)
.textTheme
.bodySmall!
.color,
),
),
],
),
),
ActionListSection.fromMenuActions(
context,
AppLocalizations.of(context)!.s_actions,
actions: helper.buildActions(),
),
],
2023-06-09 15:46:16 +03:00
),
),
2023-02-10 19:37:42 +03:00
),
),
2023-02-10 19:37:42 +03:00
);
},
2022-03-02 10:23:29 +03:00
);
}
}