diff --git a/waosSwift.xcodeproj/project.pbxproj b/waosSwift.xcodeproj/project.pbxproj index 4c4e82c..fa408f9 100644 --- a/waosSwift.xcodeproj/project.pbxproj +++ b/waosSwift.xcodeproj/project.pbxproj @@ -8,6 +8,8 @@ /* Begin PBXBuildFile section */ BF00138B237427670044C01A /* Eureka.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF00138A237427660044C01A /* Eureka.swift */; }; + BF01C99B2621935A00143475 /* UIScrollView+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF01C99A2621935A00143475 /* UIScrollView+Rx.swift */; }; + BF01C9A12621937800143475 /* UIScrollView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF01C9A02621937800143475 /* UIScrollView.swift */; }; BF058D772282BCAC00E2A077 /* AuthSigninController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF058D762282BCAC00E2A077 /* AuthSigninController.swift */; }; BF058D792282BCB600E2A077 /* AuthFlow.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF058D782282BCB600E2A077 /* AuthFlow.swift */; }; BF058D7B2282BCC500E2A077 /* AuthSigninReactor.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF058D7A2282BCC500E2A077 /* AuthSigninReactor.swift */; }; @@ -209,6 +211,8 @@ /* Begin PBXFileReference section */ BF00138A237427660044C01A /* Eureka.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Eureka.swift; sourceTree = ""; }; + BF01C99A2621935A00143475 /* UIScrollView+Rx.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIScrollView+Rx.swift"; sourceTree = ""; }; + BF01C9A02621937800143475 /* UIScrollView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIScrollView.swift; sourceTree = ""; }; BF05418D2361964F008628CF /* waosSwift.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = waosSwift.entitlements; sourceTree = ""; }; BF058D762282BCAC00E2A077 /* AuthSigninController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthSigninController.swift; sourceTree = ""; }; BF058D782282BCB600E2A077 /* AuthFlow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthFlow.swift; sourceTree = ""; }; @@ -755,8 +759,8 @@ children = ( BF4A2F88225C9AFF0001B4CE /* app */, BF4A2F4F225B7C200001B4CE /* core */, - BF058D712282BC5300E2A077 /* auth */, BF4A2F5C225B7C200001B4CE /* onBoarding */, + BF058D712282BC5300E2A077 /* auth */, BF4A2F77225BB65E0001B4CE /* tasks */, BF4A2F78225BB6690001B4CE /* secondController */, BF10C81B25F78B8C00327730 /* users */, @@ -878,6 +882,7 @@ BF1D704C245F561100F8EA36 /* Data.swift */, BFBBE1AD2566F4D50067510D /* UIButton.swift */, BFA1E4582587C9FF009210B5 /* UINavigationController.swift */, + BF01C9A02621937800143475 /* UIScrollView.swift */, ); path = Extensions; sourceTree = ""; @@ -1076,6 +1081,7 @@ BF62ADA623E45ECC000D5225 /* UIAlertController+Rx.swift */, BFBA338B2403FBB500CF9299 /* UIImageView+Kingfisher.swift */, BF1211B926038C3800C57F1F /* SwiftSpinner+Rx.swift */, + BF01C99A2621935A00143475 /* UIScrollView+Rx.swift */, ); path = Rx; sourceTree = ""; @@ -1396,6 +1402,7 @@ BF4A2F87225C8F160001B4CE /* UILocalizations.swift in Sources */, BF058D7E2282BCDD00E2A077 /* AuthService.swift in Sources */, BF9A3674228DFDAE00EE2AB8 /* TasksResponses.swift in Sources */, + BF01C9A12621937800143475 /* UIScrollView.swift in Sources */, BF8C6727227C43E80012B5A8 /* Array+SectionModel.swift in Sources */, BF71BD9322A12A2E002CF9DE /* Validations.swift in Sources */, BF4A2F71225BB2CD0001B4CE /* CoreFlow.swift in Sources */, @@ -1439,6 +1446,7 @@ BF7975042531E8B700B92B0D /* UITextField.swift in Sources */, BF8C672C2280177E0012B5A8 /* UICollectionView+ReusableKit.swift in Sources */, BFA92D2F237C050C006A3B8D /* CoreFormController.swift in Sources */, + BF01C99B2621935A00143475 /* UIScrollView+Rx.swift in Sources */, BF5BA0F0251206FA005DCDDD /* ASAuthorizationControllerProxy.swift in Sources */, BFCAA248250A7CE40065FB69 /* AuthForgotController.swift in Sources */, BF00138B237427670044C01A /* Eureka.swift in Sources */, diff --git a/waosSwift/lib/helpers/Extensions/UIScrollView.swift b/waosSwift/lib/helpers/Extensions/UIScrollView.swift new file mode 100644 index 0000000..68ecef4 --- /dev/null +++ b/waosSwift/lib/helpers/Extensions/UIScrollView.swift @@ -0,0 +1,45 @@ +/** + * Dependencies + */ + +import UIKit + +/** + * Dependencies + */ + +extension UIScrollView { + + func isBottom(toleranceHeight: CGFloat) -> Bool { + return contentOffset.y > contentSize.height - frame.height + contentInset.bottom - toleranceHeight + } + + func isNeedScroll() -> Bool { + return (contentSize.width > self.frame.width) || + (contentSize.height > self.frame.height) + } + + func scrollToBottom(animation: Bool) { + scrollToBottom(offset: 0, animation: animation) + } + + func scrollToBottom(offset: CGFloat, animation: Bool) { + UIView.animate(withDuration: animation ? 0.25 : 0) { + self.contentOffset = CGPoint(x: self.contentOffset.x, + y: self.contentSize.height - self.frame.size.height + self.contentInset.bottom + offset) + } + } + + var remaining: CGPoint { + let horizontal = self.contentSize.width - self.frame.width - self.contentOffset.x + let vertical = self.contentSize.height - self.frame.height - self.contentOffset.y + return CGPoint(x: horizontal, y: vertical) + } + + func setCurrentPage(_ page: Int, animated: Bool) { + var rect = bounds + rect.origin.x = rect.width * CGFloat(page) + rect.origin.y = 0 + scrollRectToVisible(rect, animated: animated) + } +} diff --git a/waosSwift/lib/helpers/Rx/UIScrollView+Rx.swift b/waosSwift/lib/helpers/Rx/UIScrollView+Rx.swift new file mode 100644 index 0000000..fca99bc --- /dev/null +++ b/waosSwift/lib/helpers/Rx/UIScrollView+Rx.swift @@ -0,0 +1,34 @@ +/** + * Dependencies + */ +import UIKit +import RxCocoa +import RxSwift + +/** + * Dependencies + */ + +extension Reactive where Base: UIScrollView { + + var currentPage: Observable { + return didEndDecelerating.map({ + let pageWidth = self.base.frame.width + let pageHorizontal = floor((self.base.contentOffset.x - pageWidth / 2) / pageWidth) + 1 + let pageHeight = self.base.frame.height + let pageVertical = floor((self.base.contentOffset.y - pageHeight / 2) / pageHeight) + 1 + return Int(pageHorizontal != 0 ? pageHorizontal : pageVertical != 0 ? pageVertical : 0 ) + }) + } + + var isReachedBottom: ControlEvent { + let source = self.contentOffset + .filter { [weak base = self.base] _ in + guard let base = base else { return false } + return base.isBottom(toleranceHeight: base.frame.height / 2) + } + .map { _ in Void() } + return ControlEvent(events: source) + } + +} diff --git a/waosSwift/modules/auth/controllers/AuthForgotController.swift b/waosSwift/modules/auth/controllers/AuthForgotController.swift index 1015a7c..c89b018 100644 --- a/waosSwift/modules/auth/controllers/AuthForgotController.swift +++ b/waosSwift/modules/auth/controllers/AuthForgotController.swift @@ -87,6 +87,7 @@ final class AuthForgotController: CoreController, View, Stepper { self.view.addSubview(self.labelSuccess) // config self.view.backgroundColor = Metric.primary + self.navigationController?.clear() } override func setupConstraints() { diff --git a/waosSwift/modules/auth/controllers/AuthSignupController.swift b/waosSwift/modules/auth/controllers/AuthSignupController.swift index a99d226..2ed8eab 100644 --- a/waosSwift/modules/auth/controllers/AuthSignupController.swift +++ b/waosSwift/modules/auth/controllers/AuthSignupController.swift @@ -108,6 +108,7 @@ final class AuthSignUpController: CoreController, View, Stepper { self.view.addSubview(self.labelErrors) // config self.view.backgroundColor = Metric.primary + self.navigationController?.clear() } override func setupConstraints() { diff --git a/waosSwift/modules/onBoarding/controllers/OnBoardingController.swift b/waosSwift/modules/onBoarding/controllers/OnBoardingController.swift index 344bf01..f5a71aa 100755 --- a/waosSwift/modules/onBoarding/controllers/OnBoardingController.swift +++ b/waosSwift/modules/onBoarding/controllers/OnBoardingController.swift @@ -115,20 +115,14 @@ private extension OnboardingController { // MARK: views (View -> View) func bindView(_ reactor: OnboardingReactor) { - pageControl.rx.controlEvent(.valueChanged) + self.pageControl.rx.controlEvent(.valueChanged) .subscribe(onNext: { [weak self] in - guard let currentPage = self?.pageControl.currentPage else { - return - } - self?.scrollView.setCurrentPage(currentPage, animated: true) - }) - .disposed(by: self.disposeBag) - - scrollView.rx.currentPage - .subscribe(onNext: { [weak self] in - self?.pageControl.currentPage = $0 + self?.scrollView.setCurrentPage(self?.pageControl.currentPage ?? 0, animated: true) }) .disposed(by: self.disposeBag) + self.scrollView.rx.currentPage + .bind(to: self.pageControl.rx.currentPage) + .disposed(by: disposeBag) } // MARK: actions (View -> Reactor) @@ -167,22 +161,3 @@ private extension OnboardingController { .disposed(by: self.disposeBag) } } - -extension Reactive where Base: UIScrollView { - var currentPage: Observable { - return didEndDecelerating.map({ - let pageWidth = self.base.frame.width - let page = floor((self.base.contentOffset.x - pageWidth / 2) / pageWidth) + 1 - return Int(page) - }) - } -} - -extension UIScrollView { - func setCurrentPage(_ page: Int, animated: Bool) { - var rect = bounds - rect.origin.x = rect.width * CGFloat(page) - rect.origin.y = 0 - scrollRectToVisible(rect, animated: animated) - } -}