Last active
August 14, 2024 08:04
-
-
Save TesteurManiak/6d3a832af7f9aa0e89ac7a19156431fd to your computer and use it in GitHub Desktop.
A widget that will detect inactivity of the user.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import 'package:async/async.dart'; | |
| import 'package:flutter/material.dart'; | |
| final navigatorKey = GlobalKey<NavigatorState>(); | |
| class InactivityObserver extends StatefulWidget { | |
| const InactivityObserver({ | |
| super.key, | |
| required this.inactivityTimeout, | |
| required this.child, | |
| }); | |
| final Duration inactivityTimeout; | |
| final Widget child; | |
| @override | |
| State<InactivityObserver> createState() => _InactivityObserverState(); | |
| } | |
| class _InactivityObserverState extends State<InactivityObserver> { | |
| late final timer = RestartableTimer( | |
| widget.inactivityTimeout, | |
| onInactivityTimeout, | |
| ); | |
| @override | |
| void initState() { | |
| super.initState(); | |
| // This is needed to initialize the timer after the first frame. | |
| WidgetsBinding.instance.addPostFrameCallback((_) { | |
| timer.reset(); | |
| }); | |
| } | |
| @override | |
| void dispose() { | |
| timer.cancel(); | |
| super.dispose(); | |
| } | |
| @override | |
| Widget build(BuildContext context) { | |
| return Listener( | |
| onPointerDown: (details) => timer.reset(), | |
| // TODO: add other events that should reset the timer. | |
| child: widget.child, | |
| ); | |
| } | |
| void onInactivityTimeout() { | |
| final localContext = navigatorKey.currentContext; | |
| // If there is no navigator, we can't show a dialog and should reset the | |
| // timer. | |
| if (localContext == null) return timer.reset(); | |
| const InactivityDialog().showMe(localContext).whenComplete(() { | |
| timer.reset(); | |
| }); | |
| } | |
| } | |
| class InactivityDialog extends StatelessWidget with ShowableDialogMixin { | |
| const InactivityDialog({super.key}); | |
| @override | |
| Widget build(BuildContext context) { | |
| return AlertDialog( | |
| title: const Text('Inactivity detected'), | |
| content: const Text( | |
| 'You have been inactive for a while. Do you want to continue?', | |
| ), | |
| actions: [ | |
| TextButton( | |
| onPressed: () => Navigator.pop(context), | |
| child: const Text("I'm still here!"), | |
| ), | |
| ], | |
| ); | |
| } | |
| } | |
| mixin ShowableDialogMixin on Widget { | |
| Future<T?> showMe<T>(BuildContext context) { | |
| return showDialog<T>( | |
| context: context, | |
| builder: (context) => this, | |
| ); | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment