Created
July 19, 2023 16:26
-
-
Save minsOne/256bbe28c54ff3a67fbeb14953b71711 to your computer and use it in GitHub Desktop.
RIBs+SwiftUI
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import RIBs | |
import RxSwift | |
protocol HomeRouting: ViewableRouting {} | |
protocol HomePresentable: Presentable { | |
var listener: HomePresentableListener? { get set } | |
func update(state: HomeViewState) | |
} | |
protocol HomeListener: AnyObject {} | |
final class HomeInteractor: PresentableInteractor<HomePresentable>, HomeInteractable, HomePresentableListener { | |
weak var router: HomeRouting? | |
weak var listener: HomeListener? | |
override init(presenter: HomePresentable) { | |
super.init(presenter: presenter) | |
presenter.listener = self | |
} | |
func request(action: HomeViewAction) { | |
let state: HomeViewState | |
switch action { | |
case .viewDidLoad: | |
state = .init(title: "ViewDidLoad Action", | |
desc: "Number \(Int.random(in: 0 ... 5))") | |
case .tap1: | |
state = .init(title: "Tap1 Action", | |
desc: "Tap1 Number \(Int.random(in: 0 ... 5))") | |
case .tap2: | |
state = .init(title: "Tap2 Action", | |
desc: "Tap2 Number \(Int.random(in: 0 ... 5))") | |
} | |
presenter.update(state: state) | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Foundation | |
import SwiftUI | |
class HomeViewModel: ObservableObject { | |
typealias State = HomeViewState | |
typealias Action = HomeViewAction | |
weak var listener: HomePresentableListener? | |
@Published var state: State | |
init(listener: HomePresentableListener? = nil, | |
state: State) | |
{ | |
self.listener = listener | |
self.state = state | |
} | |
func update(state: State) { | |
self.state = state | |
} | |
func request(action: Action) { | |
listener?.request(action: action) | |
} | |
} | |
struct HomeView: View { | |
@ObservedObject var viewModel: HomeViewModel | |
var body: some View { | |
HStack { | |
Spacer() | |
VStack(alignment: .center) { | |
Spacer() | |
Button("Tap1 Action Button") { | |
viewModel.request(action: .tap1) | |
} | |
Button("Tap2 Action Button") { | |
viewModel.request(action: .tap2) | |
} | |
Spacer() | |
.frame(height: 10) | |
Text(viewModel.state.title) | |
.onChange(of: viewModel.state.title) { _ in | |
print("title changed to \(viewModel.state.desc)!") | |
} | |
.font(.title) | |
.border(.gray) | |
Spacer() | |
.frame(height: 10) | |
Text(viewModel.state.desc) | |
.onChange(of: viewModel.state.desc) { _ in | |
print("desc changed to \(viewModel.state.desc)!") | |
} | |
.font(.title) | |
.border(.gray) | |
Spacer() | |
} | |
Spacer() | |
} | |
.border(Color.blue) | |
.padding() | |
} | |
} | |
#if DEBUG | |
struct HomeView_Previews: PreviewProvider { | |
typealias State = HomeViewState | |
typealias Action = HomeViewAction | |
typealias ViewModel = HomeViewModel | |
class Listener: HomePresentableListener { | |
var viewModel: ViewModel? { | |
didSet { viewModel?.listener = self } | |
} | |
func request(action: Action) { | |
let state: State | |
switch action { | |
case .viewDidLoad: | |
state = .init(title: "Preview ViewDidLoad Action", | |
desc: "Number \(Int.random(in: 0 ... 5))") | |
case .tap1: | |
state = .init(title: "Preview Tap1 Action", | |
desc: "Tap1 Number \(Int.random(in: 0 ... 5))") | |
case .tap2: | |
state = .init(title: "Preview Tap2 Action", | |
desc: "Tap2 Number \(Int.random(in: 0 ... 5))") | |
} | |
viewModel?.update(state: state) | |
} | |
} | |
static let listener = Listener() | |
static var previews: some View { | |
let state = State(title: "Hello", desc: "World") | |
let view = HomeView(viewModel: .init(state: state)) | |
listener.viewModel = view.viewModel | |
return view | |
} | |
} | |
#endif |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import UIKit | |
import SwiftUI | |
protocol HomePresentableListener: AnyObject { | |
func request(action: HomeViewAction) | |
} | |
final class HomeViewController: UIViewController, HomePresentable, HomeViewControllable { | |
weak var listener: HomePresentableListener? { | |
didSet { | |
viewModel.listener = listener | |
} | |
} | |
let viewModel = HomeViewModel(state: .init(title: "Hello", desc: "World")) | |
override func viewDidLoad() { | |
super.viewDidLoad() | |
title = "Hello World" | |
HomeView(viewModel: viewModel) | |
.attachTo(ViewController: self) | |
listener?.request(action: .viewDidLoad) | |
} | |
public func update(state: HomeViewState) { | |
viewModel.update(state: state) | |
} | |
} | |
extension View { | |
func attachTo(ViewController parentViewController: UIViewController) { | |
let contentVC = UIHostingController(rootView: self) | |
let parentVC = parentViewController | |
parentVC.addChild(contentVC) | |
contentVC.view.translatesAutoresizingMaskIntoConstraints = false | |
parentVC.view.addSubview(contentVC.view) | |
contentVC.didMove(toParent: parentVC) | |
NSLayoutConstraint.activate([ | |
contentVC.view.topAnchor.constraint(equalTo: parentVC.view.topAnchor), | |
contentVC.view.bottomAnchor.constraint(equalTo: parentVC.view.bottomAnchor), | |
contentVC.view.leadingAnchor.constraint(equalTo: parentVC.view.leadingAnchor), | |
contentVC.view.trailingAnchor.constraint(equalTo: parentVC.view.trailingAnchor), | |
]) | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Foundation | |
struct HomeViewState { | |
var title: String | |
var desc: String | |
} | |
enum HomeViewAction { | |
case viewDidLoad | |
case tap1 | |
case tap2 | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment