Giter Club home page Giter Club logo

compass's Introduction

โš ๏ธ DEPRECATED, NO LONGER MAINTAINED

Compass logo

Version Carthage Compatible License Platform CI Status Swift

Compass helps you setup a central navigation system for your application. This has many benefits, one of them being that controllers can now be decoupled, meaning that the list that presents the detail no longer knows about what its presenting. Controllers become agnostic and views stay stupid. The user experience stays the same but the logic and separation of concerns become clearer. The outcome is that your application will become more modular by default. Anything could potentially be presented from anywhere, but remember, with great power comes great responsibility.

Getting Started

Below are tutorials on how to use Compass

Setup

Step 1

First you need to register a URL scheme for your application.

Step 2

Now you need to configure Compass to use that URL scheme, a good place to do this is in your AppDelegate. Then configure all the routes you wish you support.

func application(_ application: UIApplication,
                 didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
  Navigator.scheme = "compass"
  Navigator.routes = ["profile:{username}", "login:{username}", "logout"]
  return true
}

Step 3

Register your location request handler

Navigator.handle = { [weak self] location in
  let arguments = location.arguments

  let rootController = self?.window.rootViewController as? UINavigationController

  switch location.path {
    case "profile:{username}":
      let profileController = ProfileController(title: arguments["username"])
      rootController?.pushViewController(profileController, animated: true)
    case "login:{username}":
      let loginController = LoginController(title: arguments["username"])
      rootController?.pushViewController(loginController, animated: true)
    case "logout":
      self?.clearLoginSession()
      self?.switchToLoginScreen()
    default: 
      break
  }
}

Step 4

Anywhere in your application, you can just use Navigator to navigate

@IBOutlet func logoutButtonTouched() {
  Navigator.navigate(urn: "logout")
}

Step 5

Optional. If you want to support deep linking, set up your application to respond to the URLs. Setting it up this way would mean that you could open any view from a push notification depending on the contents of the payload.

func application(_ app: UIApplication,
                 open url: URL,
                 options: [UIApplicationOpenURLOptionsKey : Any]) -> Bool {
  do {
    try Navigator.navigate(url: url)
  } catch {
    // Handle error
  }

  return true
}

Compass life hacks

Tip 1. Router

We also have some conventional tools for you that could be used to organize your route handling code and avoid huge switch cases.

  • Implement Routable protocol to keep your single route navigation code in one place:
struct ProfileRoute: Routable {

  func navigate(to location: Location, from currentController: CurrentController) throws {
    guard let username = location.arguments["username"] else { return }

    let profileController = ProfileController(title: username)
    currentController.navigationController?.pushViewController(profileController, animated: true)
  }
}
  • Create a Router instance and register your routes. Think of Router as a composite Routable
let router = Router()
router.routes = [
  "profile:{username}": ProfileRoute(),
  "logout": LogoutRoute()
]
  • Parse URL with Compass and navigate to the route with a help of your Router instance.
func application(_ app: UIApplication,
                 open url: URL,
                 options: [UIApplicationOpenURLOptionsKey : Any]) -> Bool {
  
  return handle(url)
}

func handle(_ url: URL) -> Bool {
  guard let location = Navigator.parse(url) else {
    return false
  }

  router.navigate(to: location, from: navigationController)

  return true
}

Tip 2. Multiple routers

You could set up multiple routers depending on app states. For example, you could have 2 routers for pre and post login.

let preLoginRouter = Router()
preLoginRouter.routes = [
  "profile:{username}" : ProfileRoute()
]

let postLoginRouter = Router()
postLoginRouter.routes = [
  "login:{username}" : LoginRoute()
]

let router = hasLoggedIn ? postLoginRouter : preLoginRouter
router.navigate(to: location, from: navigationController)

Installation

Compass is available through CocoaPods. To install it, simply add the following line to your Podfile:

pod 'Compass'

Compass is also available through Carthage. To install just write into your Cartfile:

github "hyperoslo/Compass"

Author

Hyper Interaktiv AS, [email protected]

Credits

The idea behind Compass came from John Sundell's tech talk "Components & View Models in the Cloud - how Spotify builds native, dynamic UIs"

License

Compass is available under the MIT license. See the LICENSE file for more info.

compass's People

Contributors

esetnik avatar jessearmand avatar joshfuggle avatar onmyway133 avatar pferruggiaro avatar ramongilabert avatar timkurvers avatar vadymmarkov avatar ykeisuke avatar zenangst avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

compass's Issues

Namespaces

It looks like the Compass module has the same name as the Compass struct. This causes a problem if the user target also has defined types like Location and Router because they cannot be specified like Compass.Location and Compass.Router. I think to fix this it would be necessary to rename the module something like CompassKit.

https://twitter.com/geeklu/status/674153362200256512

How To

I am a bit confused as to how to actually use this.

if I have a route in the form of "profile: {userId}"

and I call Navigator.navigate(urn: ? )

What am I supposed to be passing in there?

I know how to use single word routes, but not sure how to actually pass information in

I have tried stuff like "profile/userId/1" and "profile:userId:1" and "profile:userId/1" and "profile: {1}" and so on but it always errors going into my catch

How to pas more than one id

For controllers need couple parameters. Is it possible to pass parameters like
userId{userId}, taskId{taskId}
?

navigate(urn: String), urn?

Is urn correct?

public static func navigate(urn: String, scheme: String = Compass.scheme) {
  let stringURL = "\(scheme)\(urn)"
  guard let url = NSURL(string: stringURL) else { return }

  UIApplication.sharedApplication().openURL(url)
}

Return clean argument keys

Personally I think it looks kinda weird that the delimiter is included in the arguments dictionary that you get when you resolve arguments. I'd like to strip it out from the key entirely.

Before

Compass.parse(url) { route, arguments in
  XCTAssertEqual("login:{username}:{password}", route)
  XCTAssertEqual(arguments["{username}"], "JohnHyperseed")
  XCTAssertEqual(arguments["{password}"], "secret")
}

After

Compass.parse(url) { route, arguments in
  XCTAssertEqual("login:{username}:{password}", route)
  XCTAssertEqual(arguments["username"], "JohnHyperseed")
  XCTAssertEqual(arguments["password"], "secret")
}

Possible improvement to argument routes

I've been playing around with the idea to change the syntax for arguments in the routes; instead of using {}, you could use the dollar sign as a prefix delimiter to determine if it's a argument or not.

So this would mean that the route would look like;
profile:$user instead of profile:{user}.

What do you think?

Compass 6.0 Roadmap

We will convert Compass to be in Swift 4 soon. This is not really big changes, but we can take this advantage to do some refactoring. Some are breaking changes. My proposals are

  • Refactor Navigator to be used as instance. And inject scheme and Router into it. An app usually does not need many Navigator, and use can just set it as the current one. This also promotes the use of Router
let navigator = Navigator(scheme: "compass", routers: routers)
Navigator.current = navigator
  • Right now Navigator and Router seem to confuse users. Like we declare Router, but also configure Navigator.routes. The above Navigator instance will make the composition clear Navigator -> Router -> Routable
  • Refactor Router to be more flexible. Not all routers depend on currentController, some like preLogin prefers to switch rootViewController
  • Remove ErrorRoutable, as we can handle via try catch with navigate function

What do you think @hyperoslo/ios ?

Support Xcode 8 + Swift 2.3

Hi guys, ill submit a conversion to swift 2.3 too, can you open another branch?
I think this should be version 3.1.0 and the swift 3 should be 4.0.0. What do you guys think?
Thanks

Passig multiple arguments

How can I pass two or more parameters so that later they would be available using

location.arguments["param1"]
location.arguments["param2"]

is it possible? Or I should use only payload for this case?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.