Skip to content

Add tutorial1-completed #510

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions ios/tutorials/tutorial1-completed/Podfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
platform :ios, '9.0'

use_frameworks!
inhibit_all_warnings!

target 'TicTacToe' do
pod 'RIBs', :path => '../../../'
pod 'SnapKit'

end
21 changes: 21 additions & 0 deletions ios/tutorials/tutorial1-completed/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# RIBs Tutorial 1: Creating a RIB

This project is the starting point for [tutorial 1](https://github.com/uber/RIBs/wiki/iOS-Tutorial-1) that will get you aquatinted with the RIBs architecture.

### Getting started

Install tooling, unless you've done so already:

```
<RIBs path>/ios/tooling/install-xcode-template.sh
```

Then, install pods for the tutorial:

```
gem install cocoapods # In case you don't have it
cd <RIBs path>/ios/tutorials/tutorial1
pod install
```

Then, open the TicTacToe.xcworkspace that was generated by `pod install` and follow the steps described in [tutorial 1](https://github.com/uber/RIBs/wiki/iOS-Tutorial-1) on the RIBs wiki.
443 changes: 443 additions & 0 deletions ios/tutorials/tutorial1-completed/TicTacToe.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
//
// Copyright (c) 2017. Uber Technologies
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

import RIBs

class AppComponent: Component<EmptyDependency>, RootDependency {

init() {
super.init(dependency: EmptyComponent())
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
//
// Copyright (c) 2017. Uber Technologies
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

import RIBs
import UIKit

/// Game app delegate.
@UIApplicationMain
public class AppDelegate: UIResponder, UIApplicationDelegate {

/// The window.
public var window: UIWindow?

/// Tells the delegate that the launch process is almost done and the app is almost ready to run.
///
/// - parameter application: Your singleton app object.
/// - parameter launchOptions: A dictionary indicating the reason the app was launched (if any). The contents of
/// this dictionary may be empty in situations where the user launched the app directly. For information about
/// the possible keys in this dictionary and how to handle them, see Launch Options Keys.
/// - returns: false if the app cannot handle the URL resource or continue a user activity, otherwise return true.
public func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
let window = UIWindow(frame: UIScreen.main.bounds)
self.window = window

let launchRouter = RootBuilder(dependency: AppComponent()).build()
self.launchRouter = launchRouter
launchRouter.launch(from: window)

return true
}

// MARK: - Private

private var launchRouter: LaunchRouting?
}
45 changes: 45 additions & 0 deletions ios/tutorials/tutorial1-completed/TicTacToe/Info.plist
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIcons</key>
<dict/>
<key>CFBundleIcons~ipad</key>
<dict/>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>UIRequiredDeviceCapabilities</key>
<array>
<string>armv7</string>
</array>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
</dict>
</plist>
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
//
// Copyright (c) 2017. Uber Technologies
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

import RIBs

protocol LoggedOutDependency: Dependency {
// TODO: Declare the set of dependencies required by this RIB, but cannot be
// created by this RIB.
}

final class LoggedOutComponent: Component<LoggedOutDependency> {

// TODO: Declare 'fileprivate' dependencies that are only used by this RIB.
}

// MARK: - Builder

protocol LoggedOutBuildable: Buildable {
func build(withListener listener: LoggedOutListener) -> LoggedOutRouting
}

final class LoggedOutBuilder: Builder<LoggedOutDependency>, LoggedOutBuildable {

override init(dependency: LoggedOutDependency) {
super.init(dependency: dependency)
}

func build(withListener listener: LoggedOutListener) -> LoggedOutRouting {
let component = LoggedOutComponent(dependency: dependency)
let viewController = LoggedOutViewController()
let interactor = LoggedOutInteractor(presenter: viewController)
interactor.listener = listener
return LoggedOutRouter(interactor: interactor, viewController: viewController)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
//
// Copyright (c) 2017. Uber Technologies
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

import RIBs
import RxSwift

protocol LoggedOutRouting: ViewableRouting {
// TODO: Declare methods the interactor can invoke to manage sub-tree via the router.
}

protocol LoggedOutPresentable: Presentable {
var listener: LoggedOutPresentableListener? { get set }
// TODO: Declare methods the interactor can invoke the presenter to present data.
}

protocol LoggedOutListener: AnyObject {
// TODO: Declare methods the interactor can invoke to communicate with other RIBs.
}

final class LoggedOutInteractor: PresentableInteractor<LoggedOutPresentable>, LoggedOutInteractable, LoggedOutPresentableListener {

weak var router: LoggedOutRouting?
weak var listener: LoggedOutListener?

func login(withPlayer1Name player1Name: String?, player2Name: String?) {
let player1NameWithDefault = playerName(player1Name, withDefaultName: "Player 1")
let player2NameWithDefault = playerName(player2Name, withDefaultName: "Player 2")

print("\(player1NameWithDefault) vs \(player2NameWithDefault)")
}

private func playerName(_ name: String?, withDefaultName defaultName: String) -> String {
if let name = name {
return name.isEmpty ? defaultName : name
} else {
return defaultName
}
}

// TODO: Add additional dependencies to constructor. Do not perform any logic
// in constructor.
override init(presenter: LoggedOutPresentable) {
super.init(presenter: presenter)
presenter.listener = self
}

override func didBecomeActive() {
super.didBecomeActive()
// TODO: Implement business logic here.
}

override func willResignActive() {
super.willResignActive()
// TODO: Pause any business logic.
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
//
// Copyright (c) 2017. Uber Technologies
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

import RIBs

protocol LoggedOutInteractable: Interactable {
var router: LoggedOutRouting? { get set }
var listener: LoggedOutListener? { get set }
}

protocol LoggedOutViewControllable: ViewControllable {
// TODO: Declare methods the router invokes to manipulate the view hierarchy.
}

final class LoggedOutRouter: ViewableRouter<LoggedOutInteractable, LoggedOutViewControllable>, LoggedOutRouting {

// TODO: Constructor inject child builder protocols to allow building children.
override init(interactor: LoggedOutInteractable, viewController: LoggedOutViewControllable) {
super.init(interactor: interactor, viewController: viewController)
interactor.router = self
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
//
// Copyright (c) 2017. Uber Technologies
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

import RIBs
import RxSwift
import UIKit
import SnapKit

protocol LoggedOutPresentableListener: AnyObject {
func login(withPlayer1Name player1Name: String?, player2Name: String?)
}

final class LoggedOutViewController: UIViewController, LoggedOutPresentable, LoggedOutViewControllable {

weak var listener: LoggedOutPresentableListener?

private var player1Field: UITextField?
private var player2Field: UITextField?

override func viewDidLoad() {
super.viewDidLoad()

view.backgroundColor = UIColor.white
let playerFields = buildPlayerFields()
buildLoginButton(withPlayer1Field: playerFields.player1Field, player2Field: playerFields.player2Field)
}

private func buildPlayerFields() -> (player1Field: UITextField, player2Field: UITextField) {
let player1Field = UITextField()
self.player1Field = player1Field
player1Field.borderStyle = UITextBorderStyle.line
view.addSubview(player1Field)
player1Field.placeholder = "Player 1 name"
player1Field.snp.makeConstraints { (maker: ConstraintMaker) in
maker.top.equalTo(self.view).offset(100)
maker.leading.trailing.equalTo(self.view).inset(40)
maker.height.equalTo(40)
}

let player2Field = UITextField()
self.player2Field = player2Field
player2Field.borderStyle = UITextBorderStyle.line
view.addSubview(player2Field)
player2Field.placeholder = "Player 2 name"
player2Field.snp.makeConstraints { (maker: ConstraintMaker) in
maker.top.equalTo(player1Field.snp.bottom).offset(20)
maker.left.right.height.equalTo(player1Field)
}

return (player1Field, player2Field)
}

private func buildLoginButton(withPlayer1Field player1Field: UITextField, player2Field: UITextField) {
let loginButton = UIButton()
view.addSubview(loginButton)
loginButton.snp.makeConstraints { (maker: ConstraintMaker) in
maker.top.equalTo(player2Field.snp.bottom).offset(20)
maker.left.right.height.equalTo(player1Field)
}
loginButton.setTitle("Login", for: .normal)
loginButton.setTitleColor(UIColor.white, for: .normal)
loginButton.backgroundColor = UIColor.black
loginButton.addTarget(self, action: #selector(didTapLoginButton), for: .touchUpInside)
}

@objc private func didTapLoginButton() {
listener?.login(withPlayer1Name: player1Field?.text, player2Name: player2Field?.text)
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading