window_focus 1.1.0 copy "window_focus: ^1.1.0" to clipboard
window_focus: ^1.1.0 copied to clipboard

Window Focus is a convenient plugin for Flutter that allows you to track user inactivity and obtain information about the title of the active window on Mac OS and Windows.

example/lib/main.dart

import 'dart:async';
import 'dart:developer';

import 'package:flutter/material.dart';
import 'package:url_launcher/url_launcher.dart';

import 'package:window_focus/window_focus.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatefulWidget {
  const MyApp({super.key});

  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  String activeWindowTitle = 'Unknown';
  bool userIdle = false;
  final _windowFocusPlugin = WindowFocus(debug: true,duration: const Duration(seconds: 5));
  final _messangerKey = GlobalKey<ScaffoldMessengerState>();
  DateTime? lastUpdateTime;
  final textController=TextEditingController();
  final idleTimeOutInSeconds=1;

  List<TimeAppDto> items = [];
  Duration allTime = const Duration();
  Duration idleTime = const Duration();
  late Timer _timer;

  @override
  void initState() {
    super.initState();

    _windowFocusPlugin.addFocusChangeListener((p0) {
      _handleFocusChange(p0.appName);
    });
    _windowFocusPlugin.addUserActiveListener((p0) {
      print('>>>>${p0}');
      setState(() {
        userIdle = p0;
      });
    });
    _startTimer();
  }

  void _startTimer() {
    _timer = Timer.periodic(const Duration(seconds: 1), (timer) {
      _updateActiveAppTime();
      setState(() {
        allTime += const Duration(seconds: 1);

        if (!userIdle) {
          idleTime += const Duration(seconds: 1);
        }
      });
    });
  }

  void _updateActiveAppTime({bool forceUpdate = false}) {
    if (!userIdle) return;
    if (lastUpdateTime == null) return;


    final now = DateTime.now();
    final elapsed = now.difference(lastUpdateTime!);
    if (elapsed < const Duration(seconds: 1) && !forceUpdate) return;

    final existingIndex =
        items.indexWhere((item) => item.appName == activeWindowTitle);
    if (existingIndex != -1) {
      final existingItem = items[existingIndex];
      items[existingIndex] = existingItem.copyWith(
        timeUse: existingItem.timeUse + elapsed,
      );
      setState(() {

      });
    } else {
      items.add(TimeAppDto(appName: activeWindowTitle, timeUse: elapsed));
    }
    lastUpdateTime = now;
    setState(() {});
  }

  void _handleFocusChange(String newAppName) {
    final now = DateTime.now();

    if (activeWindowTitle != newAppName) {
      _updateActiveAppTime(forceUpdate: true);
    }
    activeWindowTitle = newAppName;
    lastUpdateTime = now;

    setState(() {});
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        scaffoldMessengerKey: _messangerKey,
        home: Scaffold(
          appBar: AppBar(
            title: const Text('Window in focus plugin example app'),
          ),
          body: Row(
            children: [
              Expanded(
                child: Padding(
                  padding: const EdgeInsets.all(8.0),
                  child: Column(
                    mainAxisAlignment: MainAxisAlignment.start,
                    crossAxisAlignment: CrossAxisAlignment.start,
                    children: <Widget>[
                      Text('Window title in focus: $activeWindowTitle\n'),
                      Text('User is idle: ${!userIdle}\n'),
                      Text('Total Time: ${_formatDuration(allTime)}'),
                      const SizedBox(height: 10),
                      Text('Idle Time: ${_formatDuration(idleTime)}'),
                      const SizedBox(height: 10),
                      Text(
                          'Active Time: ${_formatDuration(allTime - idleTime)}'),
                      Form(
                          child: Row(
                        children: [
                          Expanded(
                            child: TextFormField(
                              decoration: const InputDecoration(
                                  label: Text('Time in second')),
                            ),
                          ),
                          ElevatedButton(
                            onPressed: () async{
                              Duration duration = await _windowFocusPlugin.idleThreshold;
                              print(duration);
                            },
                            child: const Text('Save timeOut'),
                          )
                        ],
                      ))
                    ],
                  ),
                ),
              ),
              Expanded(
                child: Container(
                  padding: const EdgeInsets.all(8.0),
                  margin: const EdgeInsets.only(right: 8),
                  decoration: const BoxDecoration(
                    color: Colors.white,
                    borderRadius: BorderRadius.all(
                      Radius.circular(
                        24,
                      ),
                    ),
                  ),
                  child: ListView.builder(
                      itemBuilder: (context,index){
                        return ListTile(
                          title: Text(items[index].appName),
                          trailing: Text(formatDurationToHHMM(items[index].timeUse,)),
                        );
                      },
                    itemCount: items.length,
                  ),
                ),
              )
            ],
          ),
          bottomNavigationBar: TextButton(
              child: Text('Subscribe to my telegram channel @kotelnikoff_dev'),
              onPressed: () async {
                if (await canLaunchUrl(
                    Uri.parse('https://telegram.me/kotelnikoff_dev'))) {
                  await launchUrl(
                      Uri.parse('https://telegram.me/kotelnikoff_dev'));
                } else {
                  _messangerKey.currentState!.showSnackBar(const SnackBar(
                    content: Text('Oh! My Telegram Chanel @kotelnikoff_dev!'),
                  ));
                }
              }),
        ),
    );
  }

  void addInactivityThreshold(BuildContext context) async {
    try {
      Duration duration = await _windowFocusPlugin.idleThreshold;
      duration += const Duration(seconds: 5);
      _windowFocusPlugin.setIdleThreshold(duration: duration);

      _messangerKey.currentState!.showSnackBar(SnackBar(
        content: Text(
            'Great! new inactivity threshold ${duration.inSeconds} seconds'),
      ));
    } catch (e, s) {
      print(e);
      print(s);
    }
  }
  String formatDurationToHHMM(Duration duration) {
    final hours = duration.inHours;
    final minutes = duration.inMinutes.remainder(60);
    final seconds = duration.inSeconds.remainder(60);

    if (hours > 0) {
      return '${hours.toString().padLeft(2, '0')}:'
          '${minutes.toString().padLeft(2, '0')}:'
          '${seconds.toString().padLeft(2, '0')}';
    } else {
      return '${minutes.toString().padLeft(2, '0')}:'
          '${seconds.toString().padLeft(2, '0')}';
    }
  }

  String _formatDuration(Duration duration) {
    return duration.toString().split('.').first.padLeft(8, "0");
  }

  @override
  void dispose() {
    _timer.cancel();
    _windowFocusPlugin.dispose();
    super.dispose();
  }
}

class TimeAppDto {
  final String appName;
  final Duration timeUse;

  TimeAppDto({required this.appName, required this.timeUse});

  TimeAppDto copyWith({
    String? appName,
    Duration? timeUse,
  }) {
    return TimeAppDto(
      appName: appName ?? this.appName,
      timeUse: timeUse ?? this.timeUse,
    );
  }

  @override
  int get hashCode {
    return timeUse.hashCode^appName.hashCode;
  }

  @override
  bool operator ==(Object other) {
    return other is TimeAppDto && other.timeUse == timeUse && other.appName == appName;

  }
}
2
likes
150
points
43
downloads

Publisher

verified publisherkotelnikoff.dev

Weekly Downloads

Window Focus is a convenient plugin for Flutter that allows you to track user inactivity and obtain information about the title of the active window on Mac OS and Windows.

Repository (GitHub)
View/report issues

Documentation

API reference

License

MIT (license)

Dependencies

flutter, plugin_platform_interface

More

Packages that depend on window_focus

Packages that implement window_focus