Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- //
- // SavedImagesViewController.swift
- // Kuoter
- //
- // Created by Leone Parise Vieira da Silva on 01/10/16.
- // Copyright © 2016 Kuoter. All rights reserved.
- //
- import UIKit
- import RxDataSources
- import RxCocoa
- import RxSwift
- import RealmSwift
- import MisterFusion
- import Alamofire
- import RxAlamofire
- import Photos
- import SVProgressHUD
- import Async
- private let cellId = "ImageCellId"
- class SavedImagesViewController:RxViewController<SavedImagesViewModel>, NavigationAwareViewController, AlertViewControllerType {
- @IBOutlet weak var collectionView:GridCollectionView!
- @IBOutlet weak var deleteButton:UIBarButtonItem!
- @IBOutlet weak var saveButton:UIBarButtonItem!
- @IBOutlet weak var toolBar:UIToolbar!
- @IBOutlet weak var toolBarBottom: NSLayoutConstraint!
- private var dataSource:RxCollectionViewSectionedAnimatedDataSource<ImageSection>!
- private var emptyView:UIView!
- override func viewDidLoad() {
- emptyView = R.nib.savedImagesEmptyView.firstView(owner: self)!
- self.view.addLayoutSubview(emptyView, andConstraints:
- self.emptyView.Top |-| self.top, self.emptyView.Left, self.emptyView.Right, self.emptyView.Bottom
- )
- title = "Images I saved"
- track(AppEvents.savedImagesOpen)
- collectionView.columns = 3
- collectionView.registerClass(ImageCollectionViewCell.self, forCellWithReuseIdentifier: cellId)
- collectionView.allowsMultipleSelection = true
- dataSource = RxCollectionViewSectionedAnimatedDataSource<ImageSection>()
- dataSource.animationConfiguration = AnimationConfiguration(insertAnimation: .Fade,
- reloadAnimation: .Fade,
- deleteAnimation: .Fade)
- dataSource.configureCell = { ds, collectionView, indexPath, item in
- let cell = collectionView.dequeueReusableCellWithReuseIdentifier(cellId, forIndexPath: indexPath) as! ImageCollectionViewCell
- cell.imageURL = item.url
- cell.selected = item.selected
- if item.selected {
- collectionView.selectItemAtIndexPath(indexPath, animated: false, scrollPosition: .None)
- } else {
- collectionView.deselectItemAtIndexPath(indexPath, animated: false)
- }
- return cell
- }
- setupSideMenu()
- super.viewDidLoad()
- }
- override func bindToViewModel() {
- viewModel.images.bindTo(collectionView.rx_itemsWithDataSource(dataSource))
- .addDisposableTo(rx_disposeBag)
- collectionView.rx_modelSelected(ImageItem.self).bindTo(viewModel.inputs.addItem)
- .addDisposableTo(rx_disposeBag)
- collectionView.rx_modelDeselected(ImageItem.self).bindTo(viewModel.inputs.deleteItem)
- .addDisposableTo(rx_disposeBag)
- viewModel.empty.bindTo(emptyView.rx_visible)
- .addDisposableTo(rx_disposeBag)
- deleteButton.rx_tap
- .track(AppEvents.imageDelete)
- .bindTo(viewModel.inputs.delete)
- .addDisposableTo(rx_disposeBag)
- saveButton.rx_tap
- .track(AppEvents.imageGallerySave)
- .bindTo(viewModel.inputs.save)
- .addDisposableTo(rx_disposeBag)
- viewModel.toolbarVisible.subscribeNext { [unowned self] (visible) in
- self.toggleToolbar(visible, animated: true)
- }.addDisposableTo(rx_disposeBag)
- viewModel.saveResult.subscribeNext {[weak self] (result) in
- switch result {
- case .Success:
- Async.main(after: 0.4){
- SVProgressHUD.showSuccessWithStatus("Images saved!")
- }
- case .Failure:
- self?.showAlert(title: "Oh oh!", message: "An error happened when we tried to save images to your gallery. Check your settings and try again")
- }
- }.addDisposableTo(rx_disposeBag)
- viewModel.executing
- .drive(SVProgressHUD.rx_visible)
- .addDisposableTo(rx_disposeBag)
- super.bindToViewModel()
- }
- private func toggleToolbar(visible:Bool, animated:Bool = true) {
- toolBarBottom.constant = visible ? 0 : -50
- if animated {
- UIView.animateWithDuration(0.3) { [unowned self] in
- self.view.layoutIfNeeded()
- }
- } else {
- self.view.layoutIfNeeded()
- }
- }
- }
- class SavedImagesViewModel:RxViewModel {
- let inputs = (
- addItem:PublishSubject<ImageItem>(),
- deleteItem:PublishSubject<ImageItem>(),
- delete:PublishSubject<Void>(),
- save:PublishSubject<Void>()
- )
- var images:Observable<[ImageSection]>!
- var toolbarVisible:Observable<Bool>!
- var empty:Observable<Bool>!
- var saveResult:Observable<RxResult<Void>>!
- private var selected = Variable<Set<ImageItem>>(Set<ImageItem>())
- init(imageManager:ImageManager) {
- super.init()
- images = imageManager.rx_savedImages
- .map{ images in images.map{ $0.asImageItem } }
- .map{ [ImageSection(items:$0)] }
- toolbarVisible = selected.asObservable().map{ $0.count > 0 }
- inputs.addItem.subscribeNext {[unowned self] (item) in
- self.selected.value.insert(item)
- item.selected = true
- }.addDisposableTo(rx_disposeBag)
- inputs.deleteItem.subscribeNext { [unowned self] (item) in
- self.selected.value.remove(item)
- item.selected = false
- }.addDisposableTo(rx_disposeBag)
- inputs.delete.withLatestFrom(selected.asObservable())
- .doOnNext{ (selected) in
- for item in selected {
- try imageManager.deleteImage(item.url)
- }
- }
- .subscribeNext {[unowned self] (selected) in
- self.selected.value = Set()
- }
- .addDisposableTo(rx_disposeBag)
- empty = images.map{ $0[0].items.count == 0 }
- // MARK: Save images to gallery
- func downloadImages(images:Set<ImageItem>) -> Observable<[UIImage]> {
- return images.map{ item -> Observable<UIImage?> in
- Alamofire.request(.GET, item.url)
- .rx_data()
- .map{ UIImage(data:$0) }
- }.zip { (images) -> [UIImage] in
- images.flatMap{ $0 }
- .filter{ $0 != nil }
- .map{ $0! }
- }
- .trackActivity(self.activityIndicator)
- .observeOn(MainScheduler.instance)
- }
- func saveImages(images:[UIImage]) -> Observable<Void> {
- let library = PHPhotoLibrary.sharedPhotoLibrary()
- return images.map { image -> Observable<Bool> in
- library.rx_saveImage(image)
- }.zip { _ in
- return true
- }
- .mapToVoid()
- .trackActivity(self.activityIndicator)
- .observeOn(MainScheduler.instance)
- }
- saveResult = inputs.save.withLatestFrom(selected.asObservable())
- .flatMapLatest(downloadImages)
- .flatMapLatest(saveImages)
- .shareReplayLatestWhileConnected()
- .mapToResult()
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement