Click the button bellow to display an alert box.
24 | 25 | 26 | 27 | 32 | 33 | 34 | 35 | """ 36 | rxPageTitle.accept(title) 37 | rxSourceType.accept(WebViewSuorceType.html.rawValue) 38 | rxSource.accept(html) 39 | } 40 | 41 | override func webView(_ webView: WKWebView, runJavaScriptAlertPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping () -> Void) { 42 | let alert = UIAlertController(title: "runJavaScriptAlertPanelWithMessage", 43 | message: message, 44 | preferredStyle: .alert) 45 | alert.addAction(UIAlertAction(title: "OK", 46 | style: .default, 47 | handler: { _ in 48 | completionHandler() 49 | })) 50 | navigationService.push(to: alert, options: .modal()) 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /MVVMExample/MVVMExample/Page/MVVMExamples/CollectionPage/SimpleCollectionPage.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SimpleCollectionPage.swift 3 | // MVVMExample 4 | // 5 | // Created by pham.minh.tien on 5/17/20. 6 | // Copyright © 2020 Sun*. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import MVVM 11 | import RxCocoa 12 | import RxSwift 13 | 14 | class SimpleCollectionPage: BaseCollectionPage { 15 | let addBtn = UIBarButtonItem(barButtonSystemItem: .add, target: nil, action: nil) 16 | 17 | override func viewDidLoad() { 18 | super.viewDidLoad() 19 | // Do any additional setup after loading the view. 20 | navigationItem.rightBarButtonItem = addBtn 21 | } 22 | 23 | override func bindViewAndViewModel() { 24 | super.bindViewAndViewModel() 25 | guard let viewModel = viewModel as? CollectionPageViewModel else { 26 | return 27 | } 28 | 29 | viewModel.rxPageTitle ~> self.rx.title => disposeBag 30 | addBtn.rx.bind(to: viewModel.addAction, input: ()) 31 | } 32 | 33 | override func getItemSource() -> RxCollection? { 34 | guard let viewModel = viewModel as? CollectionPageViewModel else { 35 | return nil 36 | } 37 | return viewModel.itemsSource 38 | } 39 | 40 | override func registerNibWithColletion(_ collectionView: UICollectionView) { 41 | collectionView.register(collectionViewCell: SimpleCollectionViewCell.self) 42 | collectionView.register(headerType: HeaderCollectionView.self) 43 | } 44 | 45 | override func cellIdentifier(_ cellViewModel: Any, _ isClass: Bool = false) -> String { 46 | return isClass ? SimpleCollectionViewCell.className : SimpleCollectionViewCell.identifier 47 | } 48 | 49 | override func headerIdentifier(_ headerViewModel: Any, _ returnClassName: Bool = false) -> String? { 50 | return returnClassName ? HeaderCollectionView.className : HeaderCollectionView.identifier 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /MVVMExample/MVVMExample/Page/MVVMExamples/SimpleListPage/ListPageExamplePage.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ListPageExamplePage.swift 3 | // MVVMExample 4 | // 5 | // Created by pham.minh.tien on 5/14/20. 6 | // Copyright © 2020 Sun*. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import MVVM 11 | import RxCocoa 12 | import RxSwift 13 | import Action 14 | 15 | class ListPageExamplePage: BaseListPage { 16 | let addBtn = UIBarButtonItem(barButtonSystemItem: .add, target: nil, action: nil) 17 | 18 | override func viewDidLoad() { 19 | super.viewDidLoad() 20 | enableBackButton = true 21 | // Do any additional setup after loading the view. 22 | navigationItem.rightBarButtonItem = addBtn 23 | } 24 | 25 | override func setupTableView(_ tableView: UITableView) { 26 | super.setupTableView(tableView) 27 | /// separatorStyle disabled in BaseListPage 28 | tableView.separatorStyle = .singleLine 29 | tableView.estimatedRowHeight = 200 30 | tableView.register(cellType: SimpleTableCell.self) 31 | } 32 | 33 | override func bindViewAndViewModel() { 34 | super.bindViewAndViewModel() 35 | guard let viewModel = viewModel as? ListPageExampleViewModel else { 36 | return 37 | } 38 | viewModel.rxPageTitle ~> rx.title => disposeBag 39 | addBtn.rx.bind(to: viewModel.addAction, input: ()) 40 | } 41 | 42 | override func cellIdentifier(_ cellViewModel: Any, _ returnClassName: Bool = false) -> String { 43 | return returnClassName ? SimpleTableCell.className : SimpleTableCell.identifier 44 | } 45 | 46 | override func getItemSource() -> RxCollection? { 47 | guard let viewModel = viewModel as? ListPageExampleViewModel else { 48 | return nil 49 | } 50 | return viewModel.itemsSource 51 | } 52 | 53 | override func destroy() { 54 | super.destroy() 55 | viewModel?.destroy() 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /MVVMExample/MVVMExample/Page/TableOfContent/TableOfContentsPage.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NonGenericExampleMenusPage.swift 3 | // MVVM_Example 4 | // 5 | // Created by pham.minh.tien on 5/3/20. 6 | // Copyright © 2020 CocoaPods. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import MVVM 11 | import RxCocoa 12 | import RxSwift 13 | import Action 14 | 15 | class TableOfContentsPage: BaseListPage { 16 | override func viewDidLoad() { 17 | super.viewDidLoad() 18 | // Do any additional setup after loading the view. 19 | enableBackButton = !(navigationController?.viewControllers.count == 1) 20 | } 21 | 22 | override func setupTableView(_ tableView: UITableView) { 23 | super.setupTableView(tableView) 24 | tableView.estimatedRowHeight = 200 25 | tableView.separatorStyle = .singleLine 26 | tableView.register(cellType: MenuTableViewCell.self) 27 | } 28 | // Register event: Connect view to ViewModel. 29 | override func bindViewAndViewModel() { 30 | super.bindViewAndViewModel() 31 | guard let viewModel = viewModel as? TableOfContentViewModelType else { 32 | return 33 | } 34 | viewModel.inputs.rxPageTitle ~> rx.title => disposeBag 35 | } 36 | 37 | override func destroy() { 38 | super.destroy() 39 | viewModel?.destroy() 40 | } 41 | 42 | override func cellIdentifier(_ cellViewModel: Any, _ returnClassName: Bool = false) -> String { 43 | return MenuTableViewCell.identifier(returnClassName) 44 | } 45 | 46 | override func getItemSource() -> RxCollection? { 47 | guard let viewModel = viewModel as? TableOfContentViewModelType else { 48 | return nil 49 | } 50 | return viewModel.outputs.itemsSource 51 | } 52 | 53 | /// Not recommended for use. override selectedItemDidChange on ViewModel. 54 | override func selectedItemDidChange(_ cellViewModel: Any, _ indexPath: IndexPath) {} 55 | } 56 | -------------------------------------------------------------------------------- /MVVM/Classes/Core/Base/Pages/NavigationPage.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NavigationPage.swift 3 | // MVVM 4 | // 5 | 6 | import UIKit 7 | import RxSwift 8 | 9 | open class NavigationPage: UINavigationController, UIGestureRecognizerDelegate, ITransitionView, IDestroyable { 10 | public var animatorDelegate: AnimatorDelegate? 11 | public var disposeBag: DisposeBag? = DisposeBag() 12 | /** 13 | Request to update status bar content color 14 | */ 15 | public var statusBarStyle: UIStatusBarStyle = .default { 16 | didSet { setNeedsStatusBarAppearanceUpdate() } 17 | } 18 | 19 | open override var preferredStatusBarStyle: UIStatusBarStyle { 20 | return statusBarStyle 21 | } 22 | 23 | open override func viewDidLoad() { 24 | super.viewDidLoad() 25 | delegate = self 26 | interactivePopGestureRecognizer?.delegate = self 27 | } 28 | 29 | public func destroy() { 30 | viewControllers.forEach { ($0 as? IDestroyable)?.destroy() } 31 | } 32 | } 33 | 34 | extension NavigationPage: UINavigationControllerDelegate { 35 | public func navigationController(_ navigationController: UINavigationController, 36 | animationControllerFor operation: UINavigationController.Operation, 37 | from fromVC: UIViewController, 38 | to toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? { 39 | var animatorDelegate: AnimatorDelegate? 40 | switch operation { 41 | case .push: 42 | animatorDelegate = (toVC as? ITransitionView)?.animatorDelegate 43 | 44 | case .pop: 45 | animatorDelegate = (fromVC as? ITransitionView)?.animatorDelegate 46 | 47 | default: 48 | animatorDelegate = nil 49 | } 50 | 51 | animatorDelegate?.animator.isPresenting = operation == .push 52 | return animatorDelegate?.animator 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /MVVMExample/MVVMExample/Page/MVVMExamples/ContactPage/EditContactPage/ViewModel/ContactEditPageViewModel.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ContactEditPageViewModel.swift 3 | // MVVMExample 4 | // 5 | // Created by pham.minh.tien on 5/22/20. 6 | // Copyright © 2020 Sun*. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import MVVM 11 | import Action 12 | import RxSwift 13 | import RxCocoa 14 | 15 | class ContactEditPageViewModel: BaseViewModel { 16 | lazy var cancelAction: Action