5

I have searched answers in stackoverflow and none of them matches my needs. I am creating time tracking app on Swift Cocoa macOS, like Hubstaff time tracking app. At the moment runs a timer and I want to detect user's inactivity after x period of time and to send a Notification that he has been Idle x period of time. I'm new to iOS and macOS development. Can I have an example of how to do it?

Here is my code:

import Cocoa

class ViewController: NSViewController {

@IBOutlet weak var label: NSTextField!
@IBOutlet weak var playImage: NSButton!

var timer : Timer!
var isTimerWorking : Bool = false
var startTime : Date!

override func viewDidLoad() {
    super.viewDidLoad()
}

@IBAction func playPause(_ sender: NSButton) {

    if isTimerWorking {
        endTimer()
        playImage.image = NSImage(named: NSImage.Name("play"))
        sender.state = .off
    } else {
        startTimer()
        playImage.image = NSImage(named: NSImage.Name("stop"))
        sender.state = .off
    }
}

func startTimer() {
    startTime = Date()
    timer = Timer.scheduledTimer(
        timeInterval: 1.0,
        target: self,
        selector: #selector(self.timerCounter),
        userInfo: nil,
        repeats: true
    )
    isTimerWorking = true
}

func endTimer() {
    if timer != nil {
        timer.invalidate()
        label.stringValue = "00:00:00"
    }
    isTimerWorking = false
}

@objc func timerCounter() {
    let currentTime = Date().timeIntervalSince(startTime)
    let hour   = Int(fmod(currentTime/3600, 60))
    let minute = Int(fmod(currentTime/60,   60))
    let second = Int(fmod(currentTime,      60))
    let hourValue   = String(format:"%02d", hour)
    let minuteValue = String(format:"%02d", minute)
    let secondValue = String(format:"%02d", second)
    label.stringValue = "\(hourValue):\(minuteValue):\(secondValue)"
}
}
  • You probably want to use Date(). If you insist on using a Timer() see this link. https://stackoverflow.com/questions/42319172/swift-3-how-to-make-timer-work-in-background – Jeff Nov 30 '18 at 14:39
  • 1
    Possible duplicate of [Detect user activity in Cocoa app (taps, clicks, ...)](https://stackoverflow.com/questions/31734686/detect-user-activity-in-cocoa-app-taps-clicks) – Willeke Nov 30 '18 at 23:23
  • @Willeke I want to detect User's activity on a Mac instead on app. App will work minimized. – Alexandru Vorojbit Dec 03 '18 at 13:13
  • You need some code somewhere, if not in an app where does the code run? – Willeke Dec 03 '18 at 21:11
  • @Willeke of course in app. I'm new to this, that why it would be awesome if I'll get an example of how can I do it. – Alexandru Vorojbit Dec 04 '18 at 19:21
  • Add a global event monitor, start a timer and replace the timer or adjust the fire date when an event is received. – Willeke Dec 04 '18 at 23:39
  • @Willeke Thank you very much, I'll give it a try. – Alexandru Vorojbit Dec 05 '18 at 11:14
  • @Willeke: I think, the OP's question is different from the question you link to, at least the headline suggests that. – Gab Jun 20 '20 at 16:57
  • @gabriel The solution is the same. The accepted answer to this question is a translation of one of the answers to the linked question. – Willeke Jun 20 '20 at 17:07

1 Answers1

18

In my own time tracking app I am using

var lastEvent:CFTimeInterval = 0
lastEvent = CGEventSource.secondsSinceLastEventType(CGEventSourceStateID.hidSystemState, eventType: CGEventType(rawValue: ~0)!)

print(lastEvent)

to get the user idle time.

Marc T.
  • 5,090
  • 1
  • 23
  • 40
  • 1
    Any idea why this would cause my app (a launch daemon) to freeze if it gets called before a user logs into the OS? – Tagnal Aug 12 '20 at 06:07
  • @Tagnal ever figure it out? thx for the warning – aehlke Sep 15 '22 at 01:17
  • @aehlke no sorry. I just modified my code so that it only does the above call if a user is logged into the system. – Tagnal Oct 27 '22 at 23:37