@@ -2,4 +2,16 @@ |
||
| 2 | 2 |
<Bucket |
| 3 | 3 |
type = "1" |
| 4 | 4 |
version = "2.0"> |
| 5 |
+ <Breakpoints> |
|
| 6 |
+ <BreakpointProxy |
|
| 7 |
+ BreakpointExtensionID = "Xcode.Breakpoint.ExceptionBreakpoint"> |
|
| 8 |
+ <BreakpointContent |
|
| 9 |
+ shouldBeEnabled = "Yes" |
|
| 10 |
+ ignoreCount = "0" |
|
| 11 |
+ continueAfterRunningActions = "No" |
|
| 12 |
+ scope = "0" |
|
| 13 |
+ stopOnStyle = "0"> |
|
| 14 |
+ </BreakpointContent> |
|
| 15 |
+ </BreakpointProxy> |
|
| 16 |
+ </Breakpoints> |
|
| 5 | 17 |
</Bucket> |
@@ -73,7 +73,6 @@ class NetworkApi {
|
||
| 73 | 73 |
if status == 200 {
|
| 74 | 74 |
observer(.success(data)) |
| 75 | 75 |
} else {
|
| 76 |
- print(json) |
|
| 77 | 76 |
Toast.show(message: (json["description"] as? String) ?? "") |
| 78 | 77 |
observer(.error(BusinessError(id: status))) |
| 79 | 78 |
} |
@@ -95,7 +94,6 @@ class NetworkApi {
|
||
| 95 | 94 |
.responseJSON { (res) in
|
| 96 | 95 |
switch res.result {
|
| 97 | 96 |
case .success(let json): |
| 98 |
- print(json) |
|
| 99 | 97 |
guard let json = json as? [String: AnyObject], |
| 100 | 98 |
let data = resource.parse(json) else {
|
| 101 | 99 |
observer(.error(ParseError())) |
@@ -23,7 +23,7 @@ struct WXUserInfoRemoteAPI: UserInfoRemoteAPI {
|
||
| 23 | 23 |
let photoPath = "https://wx.qlogo.cn/mmopen/vi_32/Q0j4TwGTfTJibSYLgvXpMakvD9FaCqfiaWqcMiaiaz905YxWPuO4hy8F2lGheV7kVr9vKKXFgmL1S5s4QJgxwuwtVw/132" //swiftlint:disable:this line_length |
| 24 | 24 |
return Single.create(subscribe: { (observer) in
|
| 25 | 25 |
observer(.success(UserInfo(json: ["user_id": "fiDz2Ms" as AnyObject, |
| 26 |
- "userName": "郑剑飞" as AnyObject, |
|
| 26 |
+ "nickname": "郑剑飞" as AnyObject, |
|
| 27 | 27 |
"photoPath": photoPath as AnyObject]))) |
| 28 | 28 |
return Disposables.create() |
| 29 | 29 |
}) |
@@ -39,9 +39,9 @@ public class HomeViewModel {
|
||
| 39 | 39 |
return _hasMoreData.asObservable() |
| 40 | 40 |
} |
| 41 | 41 |
|
| 42 |
- public var contents: Observable<[AnimatableSectionModel<Int, PhotoItem>]> {
|
|
| 42 |
+ public var contents: Observable<[AnimatableSectionModel<String, PhotoItem>]> {
|
|
| 43 | 43 |
return _items.map({ model in
|
| 44 |
- return [AnimatableSectionModel(model: 0, items: model)] |
|
| 44 |
+ return [AnimatableSectionModel(model: "photoItem", items: model)] |
|
| 45 | 45 |
}) |
| 46 | 46 |
} |
| 47 | 47 |
|
@@ -88,6 +88,7 @@ public class HomeViewModel {
|
||
| 88 | 88 |
self._items.accept(self._items.value + result.data) |
| 89 | 89 |
}, onError: {[weak self] (_) in
|
| 90 | 90 |
guard let `self` = self else { return }
|
| 91 |
+ self.page -= 1 |
|
| 91 | 92 |
self._isLoading.onNext(false) |
| 92 | 93 |
}).disposed(by: disposeBag) |
| 93 | 94 |
} |
@@ -97,9 +98,13 @@ public class HomeViewModel {
|
||
| 97 | 98 |
let width = item.photo_thumbnail_w |
| 98 | 99 |
let height = item.photo_thumbnail_h |
| 99 | 100 |
|
| 100 |
-// header 42, footer: 32 |
|
| 101 |
+ /// header 42, footer: 32 |
|
| 101 | 102 |
return CGSize(width: width, height: height + 74) |
| 102 | 103 |
} |
| 104 |
+ |
|
| 105 |
+ public func clear() {
|
|
| 106 |
+ _items.accept([]) |
|
| 107 |
+ } |
|
| 103 | 108 |
|
| 104 | 109 |
private func setNotification() {
|
| 105 | 110 |
NotificationCenter.default.rx.notification(.GroupItemsChanged).subscribe(onNext: { (notification) in
|
@@ -138,14 +143,6 @@ public class HomeViewModel {
|
||
| 138 | 143 |
|
| 139 | 144 |
//coordinator delegate |
| 140 | 145 |
extension HomeViewModel {
|
| 141 |
- public func scanQR() {
|
|
| 142 |
- delegate?.scanQR() |
|
| 143 |
- } |
|
| 144 |
- |
|
| 145 |
- public func createGroup() {
|
|
| 146 |
- delegate?.createGroup() |
|
| 147 |
- } |
|
| 148 |
- |
|
| 149 | 146 |
public func didSelect(_ currIndex: Int) {
|
| 150 | 147 |
delegate?.didSelect(_items.value, currIndex: currIndex) |
| 151 | 148 |
} |
@@ -67,4 +67,10 @@ public class MessageViewModel {
|
||
| 67 | 67 |
} |
| 68 | 68 |
}).disposed(by: disposeBag) |
| 69 | 69 |
} |
| 70 |
+ |
|
| 71 |
+ public func clear() {
|
|
| 72 |
+ sysReadedTip.accept(false) |
|
| 73 |
+ thumbupReadedTip.accept(false) |
|
| 74 |
+ commentReadedTip.accept(false) |
|
| 75 |
+ } |
|
| 70 | 76 |
} |
@@ -18,6 +18,7 @@ public class UserInfoViewModel {
|
||
| 18 | 18 |
|
| 19 | 19 |
public var isLoggedIn: Observable<Void> {
|
| 20 | 20 |
return shareUserInfo.asObservable() |
| 21 |
+ .distinctUntilChanged({ $0.userId == $1.userId })
|
|
| 21 | 22 |
.filter { $0.userId != "" }
|
| 22 | 23 |
.flatMapLatest { _ in
|
| 23 | 24 |
return Observable.just(()) |
@@ -48,8 +49,10 @@ public class UserInfoViewModel {
|
||
| 48 | 49 |
guestRemoteAPI: GuestUserInfoRemoteAPI(), |
| 49 | 50 |
wxRemoteAPI: WXUserInfoRemoteAPI()) |
| 50 | 51 |
|
| 51 |
- shareUserInfo.asObservable().subscribe(onNext: { (userInfo) in
|
|
| 52 |
- ShareUserId = userInfo.userId |
|
| 52 |
+ shareUserInfo.asObservable() |
|
| 53 |
+ .distinctUntilChanged({ $0.userId == $1.userId })
|
|
| 54 |
+ .subscribe(onNext: { (userInfo) in
|
|
| 55 |
+ ShareUserId = userInfo.userId |
|
| 53 | 56 |
}).disposed(by: disposeBag) |
| 54 | 57 |
|
| 55 | 58 |
guestLoginBtnTapped.subscribe {[unowned self] _ in
|
@@ -12,10 +12,11 @@ public final class WaterfallFlowLayout: UICollectionViewLayout {
|
||
| 12 | 12 |
|
| 13 | 13 |
private var minColumn: Int = 0 |
| 14 | 14 |
private var itemWidth: CGFloat = -1 |
| 15 |
- private var columnHeights = [CGFloat]() |
|
| 15 |
+ private var columnHeights: [CGFloat] = [] |
|
| 16 | 16 |
private var minColumnHeight: CGFloat = 0 |
| 17 | 17 |
private(set) var configuration = WaterfallFlowConfiguration() |
| 18 |
- private var attributesArr = [UICollectionViewLayoutAttributes]() |
|
| 18 |
+ private var attributesArr: [UICollectionViewLayoutAttributes] = [] |
|
| 19 |
+ private var isNeedLayout: Bool = true |
|
| 19 | 20 |
override public init() {
|
| 20 | 21 |
super.init() |
| 21 | 22 |
} |
@@ -24,7 +25,7 @@ public final class WaterfallFlowLayout: UICollectionViewLayout {
|
||
| 24 | 25 |
self.init() |
| 25 | 26 |
self.configuration = configuration |
| 26 | 27 |
} |
| 27 |
- |
|
| 28 |
+ |
|
| 28 | 29 |
required init?(coder aDecoder: NSCoder) {
|
| 29 | 30 |
super.init(coder: aDecoder) |
| 30 | 31 |
} |
@@ -39,7 +40,7 @@ public final class WaterfallFlowLayout: UICollectionViewLayout {
|
||
| 39 | 40 |
} |
| 40 | 41 |
|
| 41 | 42 |
override public func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
|
| 42 |
- guard attributesArr.count <= indexPath.row else {
|
|
| 43 |
+ guard attributesArr.count <= indexPath.row, isNeedLayout else {
|
|
| 43 | 44 |
return attributesArr[indexPath.row] |
| 44 | 45 |
} |
| 45 | 46 |
|
@@ -59,11 +60,10 @@ public final class WaterfallFlowLayout: UICollectionViewLayout {
|
||
| 59 | 60 |
|
| 60 | 61 |
fileprivate func initialize() {
|
| 61 | 62 |
guard collectionView?.numberOfSections == 1, |
| 62 |
- let itemCount = collectionView?.numberOfItems(inSection: 0), |
|
| 63 |
- itemCount != 0 else { return }
|
|
| 63 |
+ let itemCount = collectionView?.numberOfItems(inSection: 0) else { return }
|
|
| 64 | 64 |
|
| 65 | 65 |
let originIndex: Int |
| 66 |
- if attributesArr.count >= itemCount || itemWidth == -1 {
|
|
| 66 |
+ if attributesArr.count != itemCount || itemCount == 0 || itemWidth == -1 || isNeedLayout {
|
|
| 67 | 67 |
minColumn = 0 |
| 68 | 68 |
originIndex = 0 |
| 69 | 69 |
minColumnHeight = 0 |
@@ -73,6 +73,12 @@ public final class WaterfallFlowLayout: UICollectionViewLayout {
|
||
| 73 | 73 |
} else {
|
| 74 | 74 |
originIndex = attributesArr.count |
| 75 | 75 |
} |
| 76 |
+ |
|
| 77 |
+ if itemCount == 0 {
|
|
| 78 |
+ columnHeights = [] |
|
| 79 |
+ return |
|
| 80 |
+ } |
|
| 81 |
+ |
|
| 76 | 82 |
for i in originIndex..<itemCount {
|
| 77 | 83 |
guard let attributes = layoutAttributesForItem(at: IndexPath(row: i, section: 0)) |
| 78 | 84 |
else { continue }
|
@@ -81,9 +87,9 @@ public final class WaterfallFlowLayout: UICollectionViewLayout {
|
||
| 81 | 87 |
} |
| 82 | 88 |
|
| 83 | 89 |
fileprivate func calculateViewSize() -> CGSize {
|
| 84 |
- guard let collectionView = collectionView, |
|
| 90 |
+ guard let v = collectionView, |
|
| 85 | 91 |
let maxH = columnHeights.max() else { return CGSize.zero }
|
| 86 |
- return CGSize(width: collectionView.bounds.width, height: maxH + configuration.rowSpace) |
|
| 92 |
+ return CGSize(width: v.bounds.width, height: maxH + configuration.rowSpace) |
|
| 87 | 93 |
} |
| 88 | 94 |
|
| 89 | 95 |
fileprivate func calculateItemX() -> CGFloat {
|
@@ -117,4 +123,9 @@ public final class WaterfallFlowLayout: UICollectionViewLayout {
|
||
| 117 | 123 |
columnHeights[minColumn] = minColumnHeight |
| 118 | 124 |
(minColumn, minColumnHeight) = columnHeights.enumerated().min(by: { $0.1 < $1.1 }) ?? (0, 0)
|
| 119 | 125 |
} |
| 126 |
+ |
|
| 127 |
+ /// called at collectionView reload |
|
| 128 |
+ func setNeedsLayout() {
|
|
| 129 |
+ isNeedLayout = true |
|
| 130 |
+ } |
|
| 120 | 131 |
} |
@@ -41,9 +41,8 @@ public final class AppCoordinator: BaseCoordinator<Void> {
|
||
| 41 | 41 |
extension AppCoordinator: ContainerViewControllerDelegate {
|
| 42 | 42 |
func presentLogin() {
|
| 43 | 43 |
let vc = makeLoginViewController() |
| 44 |
- coordinate(to: LoginCoordinator(vc, |
|
| 45 |
- rootViewController: containerViewController)) |
|
| 46 |
- .subscribe(onNext: { (_) in
|
|
| 44 |
+ coordinate(to: LoginCoordinator(vc)) |
|
| 45 |
+ .subscribe(onNext: { _ in
|
|
| 47 | 46 |
vc.removeFromParentAndView() |
| 48 | 47 |
}).disposed(by: disposeBag) |
| 49 | 48 |
navigationController.addFullScreen(childViewController: vc) |
@@ -58,7 +57,7 @@ extension AppCoordinator: ContainerViewControllerDelegate {
|
||
| 58 | 57 |
} |
| 59 | 58 |
} |
| 60 | 59 |
|
| 61 |
-fileprivate extension AppCoordinator {
|
|
| 60 |
+extension AppCoordinator {
|
|
| 62 | 61 |
func makeContainerViewController() {
|
| 63 | 62 |
containerViewController.userInfo = shareUserInfoViewModel |
| 64 | 63 |
containerViewController.delegate = self |
@@ -100,7 +99,7 @@ fileprivate extension AppCoordinator {
|
||
| 100 | 99 |
} |
| 101 | 100 |
} |
| 102 | 101 |
|
| 103 |
-fileprivate extension AppCoordinator {
|
|
| 102 |
+extension AppCoordinator {
|
|
| 104 | 103 |
func makeMineViewController() -> MineViewController {
|
| 105 | 104 |
let vc = MineViewController.instantiate() |
| 106 | 105 |
vc.userInfoViewModel = shareUserInfoViewModel |
@@ -63,6 +63,7 @@ final class GroupViewController: UIViewController {
|
||
| 63 | 63 |
collectionView.register(UINib(nibName: "PhotoCell", |
| 64 | 64 |
bundle: Bundle(identifier: "com.Paiai-iOS")), |
| 65 | 65 |
forCellWithReuseIdentifier: "photoCell") |
| 66 |
+ collectionView.alwaysBounceVertical = true |
|
| 66 | 67 |
setup() |
| 67 | 68 |
binding() |
| 68 | 69 |
setupNavigationBar() |
@@ -36,7 +36,7 @@ final class HomeViewController: UIViewController {
|
||
| 36 | 36 |
collectionView.register(UINib(nibName: "PhotoCell", |
| 37 | 37 |
bundle: Bundle(identifier: "com.Paiai-iOS")), |
| 38 | 38 |
forCellWithReuseIdentifier: "photoCell") |
| 39 |
- |
|
| 39 |
+ collectionView.alwaysBounceVertical = true |
|
| 40 | 40 |
setup() |
| 41 | 41 |
binding() |
| 42 | 42 |
} |
@@ -69,12 +69,12 @@ final class HomeViewController: UIViewController {
|
||
| 69 | 69 |
/// UI bindings |
| 70 | 70 |
fileprivate extension HomeViewController {
|
| 71 | 71 |
|
| 72 |
- var dataSource: RxCollectionViewSectionedAnimatedDataSource<AnimatableSectionModel<Int, PhotoItem>> {
|
|
| 73 |
- return RxCollectionViewSectionedAnimatedDataSource<AnimatableSectionModel<Int, PhotoItem>>( |
|
| 72 |
+ var dataSource: RxCollectionViewSectionedAnimatedDataSource<AnimatableSectionModel<String, PhotoItem>> {
|
|
| 73 |
+ return RxCollectionViewSectionedAnimatedDataSource<AnimatableSectionModel<String, PhotoItem>>( |
|
| 74 | 74 |
configureCell: {(_, collectionView, indexPath, item) -> UICollectionViewCell in
|
| 75 |
- let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "photoCell", |
|
| 76 |
- for: indexPath) as! PhotoCell |
|
| 77 |
- cell.setInfo(item, source: .home) |
|
| 75 |
+ let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "photoCell", |
|
| 76 |
+ for: indexPath) as! PhotoCell |
|
| 77 |
+ cell.setInfo(item, source: .home) |
|
| 78 | 78 |
return cell |
| 79 | 79 |
}) |
| 80 | 80 |
} |
@@ -111,14 +111,16 @@ fileprivate extension HomeViewController {
|
||
| 111 | 111 |
func bindUserInfoViewModelToView() {
|
| 112 | 112 |
userInfoViewModel.isLoggedIn |
| 113 | 113 |
.asDriver(onErrorJustReturn: ()) |
| 114 |
- .drive(onNext: { (_) in
|
|
| 114 |
+ .drive(onNext: {[unowned self] _ in
|
|
| 115 |
+ self.viewModel.clear() |
|
| 115 | 116 |
self.collectionView.startRefreshing(at: .top) |
| 116 | 117 |
}).disposed(by: disposeBag) |
| 117 | 118 |
} |
| 118 | 119 |
|
| 119 | 120 |
func bindViewModelToCollectionView() {
|
| 120 | 121 |
viewModel.contents |
| 121 |
- .bind(to: collectionView.rx.items(dataSource: dataSource)) |
|
| 122 |
+ .asDriver(onErrorDriveWith: .empty()) |
|
| 123 |
+ .drive(collectionView.rx.items(dataSource: dataSource)) |
|
| 122 | 124 |
.disposed(by: disposeBag) |
| 123 | 125 |
} |
| 124 | 126 |
|
@@ -10,21 +10,17 @@ import UIKit |
||
| 10 | 10 |
import RxSwift |
| 11 | 11 |
import PaiaiDataKit |
| 12 | 12 |
|
| 13 |
-class LoginCoordinator: BaseCoordinator<UserInfo> {
|
|
| 14 |
- private let rootViewController: UIViewController |
|
| 13 |
+class LoginCoordinator: BaseCoordinator<Void> {
|
|
| 15 | 14 |
private let loginViewController: LoginViewController |
| 16 | 15 |
|
| 17 |
- init(_ loginViewController: LoginViewController, |
|
| 18 |
- rootViewController: UIViewController) {
|
|
| 19 |
- self.rootViewController = rootViewController |
|
| 16 |
+ init(_ loginViewController: LoginViewController) {
|
|
| 20 | 17 |
self.loginViewController = loginViewController |
| 21 | 18 |
|
| 22 | 19 |
super.init(navigationController: UINavigationController(), viewController: loginViewController) |
| 23 | 20 |
} |
| 24 | 21 |
|
| 25 |
- override func start() -> Observable<UserInfo> {
|
|
| 26 |
- let viewModel = UserInfoViewModel() |
|
| 27 |
- loginViewController.userInfoViewModel = viewModel |
|
| 28 |
- return viewModel.shareUserInfo.asObservable() |
|
| 22 |
+ override func start() -> Observable<Void> {
|
|
| 23 |
+ |
|
| 24 |
+ return loginViewController.userInfoViewModel.loginCompleted |
|
| 29 | 25 |
} |
| 30 | 26 |
} |
@@ -39,7 +39,6 @@ extension LoginViewController {
|
||
| 39 | 39 |
func binding() {
|
| 40 | 40 |
bindInteraction() |
| 41 | 41 |
bindScrollViewDelegate() |
| 42 |
- bindUserInfoViewModelToView() |
|
| 43 | 42 |
} |
| 44 | 43 |
|
| 45 | 44 |
func bindInteraction() {
|
@@ -52,12 +51,6 @@ extension LoginViewController {
|
||
| 52 | 51 |
.disposed(by: disposeBag) |
| 53 | 52 |
} |
| 54 | 53 |
|
| 55 |
- func bindUserInfoViewModelToView() {
|
|
| 56 |
- userInfoViewModel.loginCompleted.subscribe {[unowned self] _ in
|
|
| 57 |
- self.removeFromParentAndView() |
|
| 58 |
- }.disposed(by: disposeBag) |
|
| 59 |
- } |
|
| 60 |
- |
|
| 61 | 54 |
func bindScrollViewDelegate() {
|
| 62 | 55 |
scrollView.rx.didEndDecelerating |
| 63 | 56 |
.asDriver() |
@@ -59,6 +59,7 @@ extension MessageViewController {
|
||
| 59 | 59 |
userInfoViewModel.isLoggedIn |
| 60 | 60 |
.asDriver(onErrorJustReturn: ()) |
| 61 | 61 |
.drive(onNext: {[unowned self] (_) in
|
| 62 |
+ self.viewModel.clear() |
|
| 62 | 63 |
self.viewModel.reload() |
| 63 | 64 |
}).disposed(by: disposeBag) |
| 64 | 65 |
} |
@@ -33,10 +33,15 @@ extension MineCoordinator: MineViewControllerDelegate {
|
||
| 33 | 33 |
func logout() {
|
| 34 | 34 |
mineViewController.dismissController() |
| 35 | 35 |
didCancel.onNext(()) |
| 36 |
- |
|
| 37 |
- let vc = makeLoginViewController() |
|
| 38 |
- vc.userInfoViewModel = mineViewController.userInfoViewModel |
|
| 39 |
- navigationController.addFullScreen(childViewController: vc) |
|
| 36 |
+ |
|
| 37 |
+ guard let coordinator = parentCoordinator as? AppCoordinator else { return }
|
|
| 38 |
+ |
|
| 39 |
+ let vc = coordinator.makeLoginViewController() |
|
| 40 |
+ let loginCoordinator = LoginCoordinator(vc) |
|
| 41 |
+ coordinator.coordinate(to: loginCoordinator).subscribe { _ in
|
|
| 42 |
+ vc.dismissController() |
|
| 43 |
+ }.disposed(by: disposeBag) |
|
| 44 |
+ navigationController.presentController(vc) |
|
| 40 | 45 |
} |
| 41 | 46 |
|
| 42 | 47 |
func didSelect(_ item: MineItem) {
|
@@ -58,9 +63,6 @@ extension MineCoordinator: MineViewControllerDelegate {
|
||
| 58 | 63 |
self.didCancel.onNext(()) |
| 59 | 64 |
}).disposed(by: disposeBag) |
| 60 | 65 |
} |
| 61 |
- |
|
| 62 |
- func loginout() {
|
|
| 63 |
- } |
|
| 64 | 66 |
} |
| 65 | 67 |
|
| 66 | 68 |
extension MineCoordinator: MineGroupViewModelDelegate {
|
@@ -74,12 +76,6 @@ extension MineCoordinator: MineGroupViewModelDelegate {
|
||
| 74 | 76 |
} |
| 75 | 77 |
|
| 76 | 78 |
fileprivate extension MineCoordinator {
|
| 77 |
- func makeLoginViewController() -> LoginViewController {
|
|
| 78 |
- let vc = LoginViewController.instantiate() |
|
| 79 |
-// vc.userInfoViewModel = shareUserInfoViewModel |
|
| 80 |
- return vc |
|
| 81 |
- } |
|
| 82 |
- |
|
| 83 | 79 |
func makeMineGroupViewController() -> MineGroupViewController {
|
| 84 | 80 |
let vc = MineGroupViewController.instantiate() |
| 85 | 81 |
vc.viewModel = MineGroupViewModel() |
@@ -20,6 +20,7 @@ public class BaseCoordinator<ResultType> {
|
||
| 20 | 20 |
|
| 21 | 21 |
private let identifier = UUID() |
| 22 | 22 |
private var childCoordinators = [UUID: Any]() |
| 23 |
+ var parentCoordinator: (Any)? = nil |
|
| 23 | 24 |
|
| 24 | 25 |
init(navigationController: UINavigationController, viewController: UIViewController) {
|
| 25 | 26 |
self.viewController = viewController |
@@ -37,6 +38,7 @@ public class BaseCoordinator<ResultType> {
|
||
| 37 | 38 |
|
| 38 | 39 |
func coordinate<T>(to coordinator: BaseCoordinator<T>) -> Observable<T> {
|
| 39 | 40 |
store(coordinator: coordinator) |
| 41 |
+ coordinator.parentCoordinator = self |
|
| 40 | 42 |
return coordinator.start() |
| 41 | 43 |
.do(onNext: { [weak self] _ in
|
| 42 | 44 |
self?.free(coordinator: coordinator) |