Skip to content

Instantly share code, notes, and snippets.

@TesteurManiak
Last active August 14, 2024 08:04
Show Gist options
  • Select an option

  • Save TesteurManiak/6d3a832af7f9aa0e89ac7a19156431fd to your computer and use it in GitHub Desktop.

Select an option

Save TesteurManiak/6d3a832af7f9aa0e89ac7a19156431fd to your computer and use it in GitHub Desktop.
A widget that will detect inactivity of the user.
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