1

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.

SARATH SASI
  • 1,355
  • 14
  • 36
  • 1
    Instead of replacing root viewController present the screen saver screen modally on rootviewcontroller. so that once user touch the screen you can dismiss the screensaver view controller. and you are back to business. – Prabhat Kasera Nov 20 '18 at 09:25
  • 1
    awesome it worked. Thank you very much for the comment :) – SARATH SASI Nov 20 '18 at 09:33
  • Sorry for my question, but you reducing in specific way brightness of display when you showing overlay, or what? Or its only "Block device to save energy" information? Can you explain? – DennyDog Nov 20 '18 at 10:42
  • @DennyDog no no it is for showing details in a presented view controller. Something more like a small one-page advertisement. – SARATH SASI Nov 21 '18 at 06:38
  • @DennyDog In the latest device like iPhone X and all we can use this to save energy by showing a completely black screen as you said. I think that also will be a great idea. (specifically in amoled displays) – SARATH SASI Nov 21 '18 at 06:40
  • @PrabhatKasera Adding the accumulated answer – SARATH SASI Nov 21 '18 at 07:15

1 Answers1

2

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 :)

SARATH SASI
  • 1,355
  • 14
  • 36
  • Is there any chance you could post how all the pieces fit together in your solution (AppDelegate.swift, the main ViewController, etc)? I'm trying to do something very similar to your situation and can't seem to piece it all together. – Case Silva Oct 16 '19 at 15:46