flutter_inactive_timer 4.0.0
flutter_inactive_timer: ^4.0.0 copied to clipboard
Detect user inactivity on Windows and macOS desktop apps: configurable timeout, percentage or fixed-lead-time warnings, and a live countdown for auto-logout and session timeouts.
4.0.0 #
Breaking #
-
No longer a Flutter plugin, and no longer a Flutter package at all — this is now a pure Dart package. The idle duration is read straight from the OS through
dart:ffiinstead of a method channel, so the package ships no Swift, C++, podspec or CMake, and depends on neitherflutternorplugin_platform_interface. See ADR-0004 and ADR-0005.No source changes for typical use.
FlutterInactiveTimer, its callbacks andremaining()are unchanged and return the same values, and the package keeps its name.Migration:
flutter clean # then rebuildA stale build directory can still carry the old plugin registration, which now has nothing to register.
The upside beyond a smaller build: the timer now works in a Dart CLI or server program as well as a Flutter app.
-
MethodChannelFlutterInactiveTimeris removed, andFlutterInactiveTimerPlatformis a plain abstract class rather than aPlatformInterface. Both only matter if you wrote your own platform:// 3.x class MyPlatform with MockPlatformInterfaceMixin implements FlutterInactiveTimerPlatform { ... } // 4.0.0 class MyPlatform extends FlutterInactiveTimerPlatform { ... }The seam itself is unchanged — implement
getIdleDuration(). Extend the class, do not implement it:getIdleDuration()has a default body, so anextendssubclass keeps compiling if the interface ever gains a member. The runtime token that used to enforce this went withplugin_platform_interface; breaking the rule is now a compile error instead of a silent one.
Why this is safe #
Both implementations were built side by side and read in the same batch on real machines before the native code was deleted. They reported the same value to the millisecond on Windows and on macOS, the latter under the example app's App Sandbox. The CI runs that established this are recorded in ADR-0004, along with a rejected macOS alternative that was ~9ms off and did not ship.
Added #
example_cli/— the same timer as a command-line program, run withdart runand no Flutter SDK involved. CI runs it on Windows and macOS, so the Flutter-free claim stays honest.
Internal #
- One named
IdleSourceper platform binding:GetLastInputInfo/GetTickCount64on Windows, IOKitHIDIdleTimeon macOS. Each binding's arithmetic and failure rule are pure functions, unit tested on any host; only the irreducible FFI plumbing is platform-bound. - The example app's
Idle Sourcetab and an on-device integration test are the only places the bindings execute — the Dart CI job runs on Linux and opens neitheruser32.dllnor IOKit. The test asserts the idle clock advances in step with wall-clock time while there is no input, which catches a binding reporting the wrong unit. - Tests run on
dart testwithpackage:test; coverage comes fromdart test --coverageandpackage:coverage. The Dart CI job installs no Flutter at all, so a Flutter-only dependency cannot creep back unnoticed. The native CI jobs (gtest, XCTest) are gone with the code they tested. - Linting moved from
flutter_lintstolints.
3.0.0 #
Breaking #
-
The Notification's timing is now a
NotificationTriggerpassed asnotification:, replacing thenotificationPerinteger. It is a sealed type with two kinds:NotifyAtPercent(int percent)— fire atpercent% of the timeout (the oldnotificationPerbehavior).NotifyBefore(Duration before)— fire a fixed lead time before the timeout, independent of its length (new).
notificationis optional;null(the default) means no Notification, only the timeout fires — replacing the oldnotificationPer: 0. See ADR-0002. -
timeoutDurationis now aDurationinstead of anintnumber of seconds, so the whole API speaks one time type.Migration:
// 2.x FlutterInactiveTimer(timeoutDuration: 60, notificationPer: 50, ...); // 3.0.0 FlutterInactiveTimer( timeoutDuration: Duration(seconds: 60), notification: NotifyAtPercent(50), ..., );
Features #
NotifyBefore(Duration)schedules the Notification a fixed lead time before the timeout (e.g.NotifyBefore(Duration(seconds: 120))on a 5-minute timeout fires at 3 minutes).beforemust be>= 0and shorter than the timeout (asserted in debug); a value>=the timeout safely clamps to firing at monitoring start.Future<Duration> remaining()returns the time left before timeout, for driving a live countdown (e.g. a "logs out in 04:59" label). It reads the current idle duration, so the countdown resets on user activity — and stays correct inrequireExplicitContinuelock, where a naivetimeout - idlewould not. ReturnsDuration.zerowhen not monitoring. It is a pull API: drive it from your own periodic ticker; the timer keeps none of its own. See ADR-0003.
2.0.0 #
Breaking #
- The native method channel now exposes a single
getIdleDuration()method (milliseconds since the last user input) in place of the previousgetSystemTickCount()+getLastInputTime()pair. This removes a Windows bug where the two calls used different clock widths (64-bitGetTickCount64vs 32-bitGetLastInputInfo), producing incorrect inactivity after ~49.7 days of uptime. See ADR-0001. CustomFlutterInactiveTimerPlatformimplementations must now implementgetIdleDuration().
Features #
- Added
FlutterInactiveTimer.dispose()for deterministic teardown: it cancels the active timer and releases the instance so it (and its callbacks) can be garbage collected. UnlikestopMonitoring()(a resumable pause), a disposed timer cannot be restarted. Call it from your widget'sState.dispose.
Internal #
- Extracted the scheduling and notification logic into a pure, side-effect-free
InactivityPolicy(with a sealedInactivityDecision), making the timing rules unit-testable without mocking timers or the platform channel.FlutterInactiveTimeris now a thin shell over it. FlutterInactiveTimergained optionalplatformandclockconstructor parameters for dependency injection in tests; production defaults are unchanged.- Hardened the scheduling loop with a generation guard so an in-flight check that is superseded by
stopMonitoring/startMonitoring/continueSession/disposecannot arm a stale timer. Guarantees at most one live timer under overlapping calls (regression-tested).
1.2.0 #
Behavior fix (breaking) #
notificationPernow consistently means "percent of timeout elapsed", matching the documented behavior. The scheduler previously interpreted it as "percent remaining", so notifications fired at the wrong time (e.g.timeoutDuration=60, notificationPer=10fired at 54s instead of 6s) and triggered a 1ms busy-loop wheneverper > 50. Callers that relied on the old reversed meaning will see firing times change — adjust yournotificationPeraccordingly.
Features #
- Added optional
onActivecallback. Fires when the user becomes active again after a notification has been delivered — both on detected user input (whenrequireExplicitContinueis false) and oncontinueSession()calls. Existing constructors remain source-compatible (the parameter is optional).
Improvements #
- Post-notification scheduling now polls at a 500ms cap when
requireExplicitContinueis false, bounding the latency between user return andonActivefiring. Previously the next check could be scheduled up totimeoutDuration × (100 - per)%away, which made UI recovery feel broken on longer timeouts. requireExplicitContinue=truecontinues to schedule a single check at timeout (input is ignored in that mode, so polling buys nothing).
Tests #
- Rewrote the test suite with
fake_asyncfor real behavioral verification of timer scheduling, notification timing, user-activity reset, explicit continue,onActivetriggers, and the 500ms polling cap.
Example #
MultiModeDemonow usesonActiveto restore the status label when the user returns, instead of leaving it stuck at "Almost inactive!".
1.1.4 #
- Fix: ensure stopMonitoring() fully stops during async inactivity checks
1.1.3 #
- update license
1.1.2 #
- update license
1.1.1 #
- update macos target version
1.1.0 #
macOS Support Added #
- Added native macOS implementation using IOKit HIDIdleTime
- Now fully supports both Windows and macOS platforms
- Updated platform configuration in pubspec.yaml
- Added example code for macOS
1.0.0 #
Initial Release #
- Added support for detecting user inactivity in Windows desktop applications
- Implemented customizable timeout duration for inactivity detection
- Added notification threshold feature to alert users before timeout occurs
- Included callback functions for handling inactivity detection and notifications
- Implemented option to require explicit user confirmation to continue session after notification
- Added ability to start and stop inactivity monitoring
- Added continueSession method to explicitly reset timer when required