How to detect inactivity or no user interaction in iOS App. For showing separate Screen like an Overlay or something like a screensaver.
With the following link
link that used to present screen overlay when the app became inactive
I'm able to show the screen saver in the app. But with normal dismiss view controller code not being able to dismiss the presented view controller.
we are presenting the custom overlay using
// The callback for when the timeout was fired.
func applicationDidTimout(notification: NSNotification) {
let storyboard = UIStoryboard(name: "MyStoryboard", bundle: nil)
let vc =
storyboard.instantiateViewControllerWithIdentifier("myStoryboardIdentifier")
UIApplication.shared.keyWindow?.rootViewController = vc
}
The problem that we are facing in this is. Once the View is presented we are not able to dismiss or remove the view controller.
From @Prabhat Kesara's comment and @Vanessa Forney answer in the helper link. I come with the below solution and it is working fine. If someone comes with the requirement like this they can use this
import UIKit
import Foundation
extension NSNotification.Name {
public static let TimeOutUserInteraction: NSNotification.Name = NSNotification.Name(rawValue: "TimeOutUserInteraction")
}
class UserInterractionSetup: UIApplication {
static let ApplicationDidTimoutNotification = "AppTimout"
// The timeout in seconds for when to fire the idle timer.
let timeoutInSeconds: TimeInterval = 1 * 60 //5 * 60 //
var idleTimer: Timer?
// Listen for any touch. If the screen receives a touch, the timer is reset.
override func sendEvent(_ event: UIEvent) {
super.sendEvent(event)
if idleTimer != nil {
self.resetIdleTimer()
}
if let touches = event.allTouches {
for touch in touches {
if touch.phase == UITouch.Phase.began {
self.resetIdleTimer()
}
}
}
}
// Resent the timer because there was user interaction.
func resetIdleTimer() {
if let idleTimer = idleTimer {
// print("1")
let root = UIApplication.shared.keyWindow?.rootViewController
root?.dismiss(animated: true, completion: nil)
idleTimer.invalidate()
}
idleTimer = Timer.scheduledTimer(timeInterval: timeoutInSeconds, target: self, selector: #selector(self.idleTimerExceeded), userInfo: nil, repeats: false)
}
// If the timer reaches the limit as defined in timeoutInSeconds, post this notification.
@objc func idleTimerExceeded() {
print("Time Out")
NotificationCenter.default.post(name:Notification.Name.TimeOutUserInteraction, object: nil)
let screenSaverVC = UIStoryboard(name:"ScreenSaver", bundle:nil).instantiateViewController(withIdentifier:"LandingPageViewController") as! LandingPageViewController
if let presentVc = TopMostViewController.sharedInstance.topMostViewController(controller: screenSaverVC){
let root: UINavigationController = UIApplication.shared.keyWindow!.rootViewController as! UINavigationController
if let topView = root.viewControllers.last?.presentedViewController {
topView.dismiss(animated: false) {
root.viewControllers.last?.navigationController?.present(presentVc, animated: true, completion: nil)
}
}else if let topViewNavigation = root.viewControllers.last {
topViewNavigation.navigationController?.present(presentVc, animated: true, completion: nil)
}
}
}
}
the difficulty I was faced was presenting overlay or screensaver above an already presented a view. That case, also we are handling in the above solution.
Happy coding :)