mirror of
https://github.com/Yubico/yubioath-flutter.git
synced 2024-12-24 02:33:44 +03:00
250 lines
6.4 KiB
Dart
Executable File
250 lines
6.4 KiB
Dart
Executable File
/*
|
|
* 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';
|
|
|
|
import 'package:flutter/material.dart';
|
|
import 'package:local_notifier/local_notifier.dart';
|
|
|
|
import '../message.dart';
|
|
|
|
abstract class UserInteractionController {
|
|
void updateContent({String? title, String? description, Widget? icon});
|
|
void close();
|
|
}
|
|
|
|
class _UserInteractionController extends UserInteractionController
|
|
with ChangeNotifier {
|
|
final void Function() onClosed;
|
|
String title;
|
|
String description;
|
|
Widget? icon;
|
|
_UserInteractionController({
|
|
required this.onClosed,
|
|
required this.title,
|
|
required this.description,
|
|
this.icon,
|
|
});
|
|
|
|
@override
|
|
void close() {
|
|
onClosed();
|
|
}
|
|
|
|
@override
|
|
void updateContent({String? title, String? description, Widget? icon}) {
|
|
if (title != null) {
|
|
this.title = title;
|
|
}
|
|
if (description != null) {
|
|
this.description = description;
|
|
}
|
|
if (icon != null) {
|
|
this.icon = icon;
|
|
}
|
|
notifyListeners();
|
|
}
|
|
}
|
|
|
|
class _UserInteractionDialog extends StatefulWidget {
|
|
final _UserInteractionController controller;
|
|
const _UserInteractionDialog({required this.controller});
|
|
|
|
@override
|
|
State<_UserInteractionDialog> createState() => _UserInteractionDialogState();
|
|
}
|
|
|
|
class _UserInteractionDialogState extends State<_UserInteractionDialog> {
|
|
void _rebuild() {
|
|
Timer.run(() => setState(() {}));
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
Widget? icon = widget.controller.icon;
|
|
final theme = Theme.of(context);
|
|
|
|
return AlertDialog(
|
|
scrollable: true,
|
|
content: SizedBox(
|
|
width: 100,
|
|
child: Column(
|
|
mainAxisSize: MainAxisSize.min,
|
|
mainAxisAlignment: MainAxisAlignment.center,
|
|
children: [
|
|
if (icon != null)
|
|
Padding(
|
|
padding: const EdgeInsets.all(24),
|
|
child: IconTheme(
|
|
data: IconTheme.of(context).copyWith(size: 36),
|
|
child: icon,
|
|
),
|
|
),
|
|
Text(
|
|
widget.controller.title,
|
|
style: theme.textTheme.titleLarge,
|
|
textAlign: TextAlign.center,
|
|
),
|
|
Text(
|
|
widget.controller.description,
|
|
textAlign: TextAlign.center,
|
|
style: theme.textTheme.bodyMedium!.copyWith(
|
|
color: theme.colorScheme.onSurfaceVariant,
|
|
),
|
|
softWrap: true,
|
|
),
|
|
],
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
@override
|
|
void initState() {
|
|
super.initState();
|
|
widget.controller.addListener(_rebuild);
|
|
}
|
|
|
|
@override
|
|
void dispose() {
|
|
widget.controller.removeListener(_rebuild);
|
|
super.dispose();
|
|
}
|
|
}
|
|
|
|
/// Opens a modal dialog informing the user to take some action.
|
|
/// The dialog content can be updated programmatically via the returned
|
|
/// [UserInteractionController].
|
|
///
|
|
/// An optional [onCancel] function can be provided to allow the user to cancel
|
|
/// the action by tapping outside of the dialog (or pressing Back, etc.).
|
|
UserInteractionController promptUserInteraction(
|
|
BuildContext context, {
|
|
required String title,
|
|
required String description,
|
|
Widget? icon,
|
|
void Function()? onCancel,
|
|
bool headless = false,
|
|
}) {
|
|
if (headless) {
|
|
// No support for icon or onCancel.
|
|
return _notificationUserInteraction(context,
|
|
title: title, description: description);
|
|
} else {
|
|
return _dialogUserInteraction(context,
|
|
title: title, description: description, icon: icon, onCancel: onCancel);
|
|
}
|
|
}
|
|
|
|
UserInteractionController _dialogUserInteraction(
|
|
BuildContext context, {
|
|
required String title,
|
|
required String description,
|
|
Widget? icon,
|
|
void Function()? onCancel,
|
|
}) {
|
|
var completed = false;
|
|
var wasPopped = false;
|
|
final controller = _UserInteractionController(
|
|
title: title,
|
|
description: description,
|
|
icon: icon,
|
|
onClosed: () {
|
|
completed = true;
|
|
if (!wasPopped) {
|
|
Navigator.of(context).pop();
|
|
}
|
|
},
|
|
);
|
|
showBlurDialog(
|
|
context: context,
|
|
routeSettings: const RouteSettings(name: 'user_interaction_prompt'),
|
|
builder: (context) {
|
|
return PopScope(
|
|
canPop: onCancel != null,
|
|
onPopInvokedWithResult: (didPop, _) {
|
|
if (didPop) {
|
|
wasPopped = true;
|
|
if (!completed && onCancel != null) {
|
|
onCancel();
|
|
}
|
|
}
|
|
},
|
|
child: _UserInteractionDialog(
|
|
controller: controller,
|
|
));
|
|
});
|
|
|
|
return controller;
|
|
}
|
|
|
|
class _NotificationUserInteractionController extends UserInteractionController {
|
|
String title;
|
|
String description;
|
|
Widget? icon;
|
|
LocalNotification _notification;
|
|
_NotificationUserInteractionController({
|
|
required this.title,
|
|
required this.description,
|
|
}) : _notification = LocalNotification(
|
|
title: title,
|
|
body: description,
|
|
)..show();
|
|
|
|
@override
|
|
void close() {
|
|
_notification.close();
|
|
}
|
|
|
|
Future<void> _doUpdateNotification() async {
|
|
await _notification.close();
|
|
await Future.delayed(const Duration(milliseconds: 200));
|
|
_notification = LocalNotification(title: title, body: description);
|
|
await _notification.show();
|
|
}
|
|
|
|
@override
|
|
void updateContent({String? title, String? description, Widget? icon}) {
|
|
bool changed = false;
|
|
if (title != null) {
|
|
this.title = title;
|
|
changed = true;
|
|
}
|
|
if (description != null) {
|
|
this.description = description;
|
|
changed = true;
|
|
}
|
|
if (icon != null) {
|
|
this.icon = icon;
|
|
}
|
|
|
|
if (changed) {
|
|
_doUpdateNotification();
|
|
}
|
|
}
|
|
}
|
|
|
|
UserInteractionController _notificationUserInteraction(
|
|
BuildContext context, {
|
|
required String title,
|
|
required String description,
|
|
}) {
|
|
return _NotificationUserInteractionController(
|
|
title: title,
|
|
description: description,
|
|
);
|
|
}
|