{"id":16426376,"url":"https://github.com/cgossain/appcontroller","last_synced_at":"2026-05-01T03:32:44.263Z","repository":{"id":56902153,"uuid":"46538935","full_name":"cgossain/AppController","owner":"cgossain","description":"A lightweight controller for managing transitions between \"unauthenticated\" and \"authenticated\" interfaces on iOS, written in Swift.","archived":false,"fork":false,"pushed_at":"2024-08-30T15:01:22.000Z","size":203,"stargazers_count":0,"open_issues_count":0,"forks_count":1,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-06-02T07:20:05.374Z","etag":null,"topics":["authentication","ios","login","logout","transition","transitions","ui","uikit"],"latest_commit_sha":null,"homepage":"","language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/cgossain.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2015-11-20T04:19:23.000Z","updated_at":"2024-08-30T15:01:27.000Z","dependencies_parsed_at":"2025-02-12T03:31:33.788Z","dependency_job_id":"40b54a21-d9ce-4019-bcd8-424c7bb5ce79","html_url":"https://github.com/cgossain/AppController","commit_stats":null,"previous_names":[],"tags_count":26,"template":false,"template_full_name":null,"purl":"pkg:github/cgossain/AppController","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cgossain%2FAppController","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cgossain%2FAppController/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cgossain%2FAppController/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cgossain%2FAppController/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/cgossain","download_url":"https://codeload.github.com/cgossain/AppController/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cgossain%2FAppController/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":259490506,"owners_count":22865763,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["authentication","ios","login","logout","transition","transitions","ui","uikit"],"created_at":"2024-10-11T08:08:57.086Z","updated_at":"2026-05-01T03:32:39.218Z","avatar_url":"https://github.com/cgossain.png","language":"Swift","funding_links":[],"categories":[],"sub_categories":[],"readme":"# AppController\n\nAppController was originaly inspired by the architecture described in [this blog post](http://dev.teeps.org/blog/2015/3/27/how-to-architect-your-ios-app).\n\nThe AppController is a lightweight controller for managing transitions between \"unauthenticated\" and \"authenticated\" interfaces on iOS. Many apps implement this lazily by presenting an authentication sheet above the main app interface. This is fine for some applications, however if you're looking for something more robust, the structure implemented by AppController offers a clean and clear separation of concerns between interfaces for each authentication state. It manages interface transitions using Apple approved view controller containment API, and removes the unused view hierarchy from memory once the transition is complete. \n\nBy keeping your \"unauthenticated\"  and \"authenticated\" view hierarchies completely separate, you can write cleaner code and build more compelling onboarding experiences.\n\nThe included example project showcases the core functionality of this library.\n\n[![CI Status](https://img.shields.io/travis/cgossain/AppController.svg?style=flat)](https://travis-ci.org/cgossain/AppController)\n[![Version](https://img.shields.io/cocoapods/v/AppController.svg?style=flat)](https://cocoapods.org/pods/AppController)\n[![License](https://img.shields.io/cocoapods/l/AppController.svg?style=flat)](https://cocoapods.org/pods/AppController)\n[![Platform](https://img.shields.io/cocoapods/p/AppController.svg?style=flat)](https://cocoapods.org/pods/AppController)\n\n## Requirements\n* iOS 10.3\n* Swift 5.0\n\n## Installation\n\nAppController is available through [CocoaPods](http://cocoapods.org). To install\nit, simply add the following line to your Podfile:\n\n```ruby\npod \"AppController\"\n```\n\n## Usage\n\n### AppControllerInterfaceProviding\n\n`AppControllerInterfaceProviding` is a protocol that vends your view hierarchies for the `unauthenticated` and `authenticated` states. It also provides configuration settings for the transition.\n\n```\nclass MyAwesomeInterfaceProvider: AppControllerInterfaceProviding {\n\n    func configuration(for appController: AppController, traitCollection: UITraitCollection) -\u003e AppController.Configuration {\n      // return a configuration model for the transition\n      // note that the default configuration is being returned here, but it can be further configured\n      return AppController.Configuration()\n    }\n\n    func loggedOutInterfaceViewController(for appController: AppController) -\u003e UIViewController {\n        // create and return your logged out interface view controller\n        let welcomeViewController = WelcomeViewController()\n        return welcomeViewController\n    }\n\n    func loggedInInterfaceViewController(for appController: AppController) -\u003e UIViewController {\n        // create and return your logged in interface view controller\n        let tabBarController = UITabBarController()\n        return tabBarController\n    }\n\n    func isInitiallyLoggedIn(for: AppController) -\u003e Bool {\n        // return `true` if the \"logged in\" interface should be initially loaded instead\n        return false\n    }\n\n}\n```\n\n### AppViewController\n\n`AppViewController` is a custom container view controller where transitions between your `unauthenticated` and `authenticated` states are performed.\n\nYou do not need to interact with this view controller directly.\n\n### AppController\n\n`AppController` is the object that manages the entire transition. \n\nYou create an instance of AppController, and then call its `installRootViewController(in:)` method passing in your window object. This installs an instance of `AppViewController` (that is managed by the AppController) as the root view controller of your window object.\n\n```\nimport UIKit\nimport AppController\n\n@UIApplicationMain\nclass AppDelegate: UIResponder, UIApplicationDelegate {\n\n    var window: UIWindow?\n    let myAwesomeInterfaceProvider = MyAwesomeInterfaceProvider()\n\n    lazy var appController: AppController = {\n        let controller = AppController(interfaceProvider: self.myAwesomeInterfaceProvider)\n\n        // do stuff just before login transition...\n        controller.willLoginHandler = { [unowned self] (targetViewController) in\n\n        }\n\n        // do stuff right after login transition...\n        controller.didLoginHandler = { [unowned self] in\n\n        }\n\n        // do stuff just before logout transition...\n        controller.willLogoutHandler = { [unowned self] (targetViewController) in\n\n        }\n\n        // do stuff right after logout transition...\n        controller.didLogoutHandler = { [unowned self] in\n\n        }\n\n        return controller\n    }()\n\n    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -\u003e Bool {\n        let myWindow = UIWindow()\n        window = myWindow\n\n        // install the app controllers' root view controller as the root view controller of the window\n        appController.installRootViewController(in: myWindow)\n\n        return true\n    }\n\n}\n```\n\n### Performing the Transitions\n\nTransition to the `authenticated` view hierarchy:\n\n```\nAppController.login()\n```\n\nTransition to the `unauthenticated` view hierarchy:\n\n```\nAppController.logout()\n```\n\n### Storyboard Support\n\nIf you use a storyboard file, you can easily configure the AppController to use it. Just ensure the `initialViewController` is an `AppViewController`, and add Storyboard IDs for you're \"logged out\" and \"logged in\" interfaces contained in storyboard file.\n\n```\nimport UIKit\nimport AppController\n\n@UIApplicationMain\nclass AppDelegate: UIResponder, UIApplicationDelegate {\n\n    var window: UIWindow?\n\n    lazy var appController: AppController = {\n        return AppController(storyboardName: \"Main\", loggedOutInterfaceID: \"\u003cStoryboad ID of `unauthenticated` view hierarchy\u003e\", loggedInInterfaceID: \"\u003cStoryboad ID of `authenticated` view hierarchy\u003e\")\n    }()\n\n    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -\u003e Bool {\n        // install the app controllers' root view controller as the root view controller of the window\n        appController.installRootViewController(in: window!)\n\n        return true\n    }\n\n}\n```\n\n## Author\n\nChristian Gossain, cgossain@gmail.com\n\n## License\n\nAppController is available under the MIT license. See the LICENSE file for more info.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcgossain%2Fappcontroller","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcgossain%2Fappcontroller","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcgossain%2Fappcontroller/lists"}