Skip to content

Feature/swiftui view without rx #9

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 23 commits into
base: master
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
12 changes: 2 additions & 10 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,26 +18,18 @@ let package = Package(
url: "https://github.com/dgrzeszczak/Loaders",
.upToNextMajor(from: "1.2.0")
),
.package(
url: "https://github.com/ReactiveX/RxSwift",
.upToNextMajor(from: "6.0.0")
),
.package(
url: "https://github.com/ReMVVM/ReMVVM",
.upToNextMajor(from: "3.0.0")
),
//.package(path: "../ReMVVM"),
.package(url: "https://github.com/ReMVVM/ReMVVMRxSwift",
.upToNextMajor(from: "1.0.0")
),
// .package(path: "../ReMVVMRxSwift"),
//.package(path: "../ReMVVM")
],
targets: [
// Targets are the basic building blocks of a package. A target can define a module or a test suite.
// Targets can depend on other targets in this package, and on products in packages which this package depends on.
.target(
name: "ReMVVMExt",
dependencies: ["RxSwift", "RxCocoa", "RxRelay", "Loaders", .product(name: "ReMVVMCore", package: "ReMVVM"), "ReMVVMRxSwift"],
dependencies: ["Loaders", .product(name: "ReMVVMCore", package: "ReMVVM")],
path: "ReMVVMExt/Sources",
exclude: [])
]
Expand Down
57 changes: 16 additions & 41 deletions ReMVVMExt/Sources/ReMVVMExtension.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
//

import ReMVVMCore
import RxSwift
import UIKit

public struct NavigationStateIOS<ApplicationState>: NavigationState {
Expand Down Expand Up @@ -49,11 +48,12 @@ private enum AppNavigationReducer<State, R>: Reducer where R: Reducer, R.State =
public enum ReMVVMExtension {

public static func initialize<ApplicationState, R>(with state: ApplicationState,
window: UIWindow,
uiStateConfig: UIStateConfig,
stateMappers: [StateMapper<ApplicationState>] = [],
reducer: R.Type,
middleware: [AnyMiddleware]) -> AnyStore where R: Reducer, R.State == ApplicationState, R.Action == StoreAction {
window: UIWindow,
uiStateConfig: UIStateConfig,
stateMappers: [StateMapper<ApplicationState>] = [],
reducer: R.Type,
middleware: [AnyMiddleware],
logger: Logger = .noLogger) -> AnyStore where R: Reducer, R.State == ApplicationState, R.Action == StoreAction {

let appMapper = StateMapper<NavigationStateIOS<ApplicationState>>(for: \.appState)
let stateMappers = [appMapper] + stateMappers.map { $0.map(with: \.appState) }
Expand All @@ -63,15 +63,17 @@ public enum ReMVVMExtension {
uiStateConfig: uiStateConfig,
stateMappers: stateMappers,
reducer: AppNavigationReducer<ApplicationState, R>.self,
middleware: middleware)
middleware: middleware,
logger: logger)
}

public static func initialize<State, R>(with state: State,
window: UIWindow,
uiStateConfig: UIStateConfig,
stateMappers: [StateMapper<State>] = [],
reducer: R.Type,
middleware: [AnyMiddleware]) -> AnyStore where State: NavigationState, R: Reducer, R.State == State, R.Action == StoreAction {
window: UIWindow,
uiStateConfig: UIStateConfig,
stateMappers: [StateMapper<State>] = [],
reducer: R.Type,
middleware: [AnyMiddleware],
logger: Logger = .noLogger) -> AnyStore where State: NavigationState, R: Reducer, R.State == State, R.Action == StoreAction {

let uiState = UIState(window: window, config: uiStateConfig)

Expand All @@ -88,37 +90,10 @@ public enum ReMVVMExtension {
let store = Store<State>(with: state,
reducer: reducer,
middleware: middleware,
stateMappers: stateMappers)
stateMappers: stateMappers,
logger: logger)

store.add(observer: EndEditingFormListener<State>(uiState: uiState))
ReMVVM.initialize(with: store)
return store.any
}
}

public final class EndEditingFormListener<State: StoreState>: StateObserver {

let uiState: UIState
var disposeBag = DisposeBag()

public init(uiState: UIState) {
self.uiState = uiState
}

public func willReduce(state: State) {
uiState.rootViewController.view.endEditing(true)
uiState.modalControllers.last?.view.endEditing(true)
}

public func didReduce(state: State, oldState: State?) {
disposeBag = DisposeBag()

uiState.navigationController?.rx
.methodInvoked(#selector(UINavigationController.popViewController(animated:)))
.subscribe(onNext: { [unowned self] _ in
self.uiState.rootViewController.view.endEditing(true)
self.uiState.modalControllers.last?.view.endEditing(true)
})
.disposed(by: disposeBag)
}
}
2 changes: 2 additions & 0 deletions ReMVVMExt/Sources/Reducers/DismissModalReducer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ public struct DismissModalReducer: Reducer {
public static func reduce(state: Navigation, with action: DismissModal) -> Navigation {

var modals = state.modals

guard !modals.isEmpty else { return Navigation(root: state.root, modals: modals) }
if action.dismissAllViews {
modals.removeAll()
} else {
Expand Down
4 changes: 2 additions & 2 deletions ReMVVMExt/Sources/Reducers/PopReducer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ public struct PopReducer: Reducer {

private static func updateStateTree(_ stateTree: Navigation, for mode: PopMode) -> Navigation {
switch mode {
case .popToRoot:
case .popToRoot, .resetStack:
return popStateTree(stateTree, dropCount: stateTree.topStack.count - 1)
case .pop(let count):
return popStateTree(stateTree, dropCount: count)
Expand Down Expand Up @@ -69,7 +69,7 @@ public struct PopMiddleware<State: NavigationState>: Middleware {
// side effect

switch action.mode {
case .popToRoot:
case .popToRoot, .resetStack:
self.uiState.navigationController?.popToRootViewController(animated: action.animated)
case .pop(let count):
if count > 1 {
Expand Down
6 changes: 5 additions & 1 deletion ReMVVMExt/Sources/Reducers/PushReducer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,11 @@ public struct PushReducer: Reducer {
}

private static func updateStack(_ stack: [ViewModelFactory], for pop: PopMode?) -> [ViewModelFactory] {
guard let popMode = pop, stack.count > 1 else { return stack }
guard let popMode = pop, stack.count > 0 else { return stack }

switch popMode {
case .resetStack:
return []
case .pop(let count):
let dropCount = min(count, stack.count)
return Array(stack.dropLast(dropCount))
Expand Down Expand Up @@ -84,6 +86,8 @@ public struct PushMiddleware<State: NavigationState>: Middleware {
if let pop = action.pop {
var viewControllers = navigationController.viewControllers
switch pop {
case .resetStack:
viewControllers = []
case .popToRoot:
viewControllers = viewControllers.dropLast(viewControllers.count - 1)
case .pop(let count):
Expand Down
14 changes: 14 additions & 0 deletions ReMVVMExt/Sources/Reducers/ShowModalReducer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,12 @@ public struct ShowModalMiddleware<State: NavigationState>: Middleware {
let uiState = self.uiState

var controller: UIViewController?

// block if previously modal is not finish dismiss animation
if uiState.modalControllers.last?.isBeingDismissed == true {
return
}

// block if already on screen
// TODO use some id maybe ?
if !action.showOverSelfType {
Expand Down Expand Up @@ -70,6 +76,14 @@ public struct ShowModalMiddleware<State: NavigationState>: Middleware {
}

newModal.modalPresentationStyle = action.presentationStyle

if #available(iOS 15.0, *) {

if newModal.modalPresentationStyle == .pageSheet || newModal.modalPresentationStyle == .formSheet, let cornerRadius = action.preferredCornerRadius {
newModal.sheetPresentationController?.preferredCornerRadius = cornerRadius
}
}

uiState.present(newModal, animated: action.controllerInfo.animated)
}
}
Expand Down
1 change: 0 additions & 1 deletion ReMVVMExt/Sources/Reducers/ShowOnRootReducer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ public struct ShowOnRootMiddleware<State: NavigationState>: Middleware {

interceptor.next { _ in // newState - state variable is used below
// side effect

uiState.setRoot(controller: action.controllerInfo.loader.load(),
animated: action.controllerInfo.animated,
navigationBarHidden: action.navigationBarHidden)
Expand Down
12 changes: 9 additions & 3 deletions ReMVVMExt/Sources/Reducers/ShowTabReducer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,12 @@ struct ShowReducer: Reducer {
let factory = action.controllerInfo.factory ?? state.factory
if action.navigationType == state.root.navigationType { //check the type is the same
stacks = state.root.stacks.map {
guard $0.0 == current, $0.1.isEmpty else { return $0 }
guard $0.0 == current, $0.1.isEmpty else {
if action.resetStack { return ($0.0, [factory]) }
return $0
}
return ($0.0, [factory])

}
} else {
stacks = action.navigationType.map {
Expand All @@ -52,7 +56,7 @@ public struct ShowMiddleware<State: NavigationState>: Middleware {

public func onNext(for state: State, action: Show, interceptor: Interceptor<Show, State>, dispatcher: Dispatcher) {

guard state.navigation.root.currentItem != action.item else {
guard state.navigation.root.currentItem != action.item || action.resetStack else {

dispatcher.dispatch(action: Pop(mode: .popToRoot, animated: true))
return
Expand All @@ -79,7 +83,9 @@ public struct ShowMiddleware<State: NavigationState>: Middleware {
}

//set up current if empty (or reset)
if let top = containerController.currentNavigationController, top.viewControllers.isEmpty {
if let top = containerController.currentNavigationController,
top.viewControllers.isEmpty
|| action.resetStack {
top.setViewControllers([action.controllerInfo.loader.load()],
animated: false)
}
Expand Down
Loading