// // MailViewController.swift // // Created by Jeremy Koch // Copyright © 2017 Jeremy Koch. All rights reserved. // import UIKit import SwipeCellKit class MailCollectioViewController: UICollectionViewController, UICollectionViewDelegateFlowLayout { var emails: [Email] = [] var defaultOptions = SwipeTableOptions() var isSwipeRightEnabled = true var buttonDisplayMode: ButtonDisplayMode = .titleAndImage var buttonStyle: ButtonStyle = .backgroundColor // MARK: - Lifecycle override func viewDidLoad() { // let flow = collectionView?.collectionViewLayout as! UICollectionViewFlowLayout // flow.estimatedItemSize = CGSize(width: 320, height: 100) navigationItem.rightBarButtonItem = editButtonItem view.layoutMargins.left = 32 resetData() } // MARK: - Collection view data source override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { return emails.count } override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "MailCell", for: indexPath) as! MailCollectionCell cell.delegate = self cell.selectedBackgroundView = createSelectedBackgroundView() let email = emails[indexPath.row] cell.fromLabel.text = email.from cell.dateLabel.text = email.relativeDateString cell.subjectLabel.text = email.subject cell.bodyLabel.text = email.body cell.unread = email.unread cell.canDelete = true return cell } func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { return CGSize(width: collectionView.bounds.width, height: 120) } // MARK: - Actions @IBAction func moreTapped(_ sender: Any) { let controller = UIAlertController(title: "Swipe Transition Style", message: nil, preferredStyle: .actionSheet) controller.addAction(UIAlertAction(title: "Border", style: .default, handler: { _ in self.defaultOptions.transitionStyle = .border })) controller.addAction(UIAlertAction(title: "Drag", style: .default, handler: { _ in self.defaultOptions.transitionStyle = .drag })) controller.addAction(UIAlertAction(title: "Reveal", style: .default, handler: { _ in self.defaultOptions.transitionStyle = .reveal })) controller.addAction(UIAlertAction(title: "\(isSwipeRightEnabled ? "Disable" : "Enable") Swipe Right", style: .default, handler: { _ in self.isSwipeRightEnabled = !self.isSwipeRightEnabled })) controller.addAction(UIAlertAction(title: "Button Display Mode", style: .default, handler: { _ in self.buttonDisplayModeTapped() })) controller.addAction(UIAlertAction(title: "Button Style", style: .default, handler: { _ in self.buttonStyleTapped() })) controller.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: nil)) controller.addAction(UIAlertAction(title: "Reset", style: .destructive, handler: { _ in self.resetData() })) present(controller, animated: true, completion: nil) } func buttonDisplayModeTapped() { let controller = UIAlertController(title: "Button Display Mode", message: nil, preferredStyle: .actionSheet) controller.addAction(UIAlertAction(title: "Image + Title", style: .default, handler: { _ in self.buttonDisplayMode = .titleAndImage })) controller.addAction(UIAlertAction(title: "Image Only", style: .default, handler: { _ in self.buttonDisplayMode = .imageOnly })) controller.addAction(UIAlertAction(title: "Title Only", style: .default, handler: { _ in self.buttonDisplayMode = .titleOnly })) controller.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: nil)) present(controller, animated: true, completion: nil) } func buttonStyleTapped() { let controller = UIAlertController(title: "Button Style", message: nil, preferredStyle: .actionSheet) controller.addAction(UIAlertAction(title: "Background Color", style: .default, handler: { _ in self.buttonStyle = .backgroundColor self.defaultOptions.transitionStyle = .border })) controller.addAction(UIAlertAction(title: "Circular", style: .default, handler: { _ in self.buttonStyle = .circular self.defaultOptions.transitionStyle = .reveal })) controller.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: nil)) present(controller, animated: true, completion: nil) } // MARK: - Helpers func createSelectedBackgroundView() -> UIView { let view = UIView() view.backgroundColor = UIColor.lightGray.withAlphaComponent(0.2) return view } func resetData() { emails = mockEmails emails.forEach { $0.unread = false } collectionView?.reloadData() } } extension MailCollectioViewController: SwipeCollectionViewCellDelegate { func collectionView(_ collectionView: UICollectionView, editActionsForRowAt indexPath: IndexPath, for orientation: SwipeActionsOrientation) -> [SwipeAction]? { let email = emails[indexPath.row] if orientation == .left { guard isSwipeRightEnabled else { return nil } let read = SwipeAction(style: .default, title: nil) { action, indexPath in let updatedStatus = !email.unread email.unread = updatedStatus let cell = collectionView.cellForItem(at: indexPath) as! MailCollectionCell cell.setUnread(updatedStatus, animated: true) } read.hidesWhenSelected = true read.accessibilityLabel = email.unread ? "Mark as Read" : "Mark as Unread" let descriptor: ActionDescriptor = email.unread ? .read : .unread configure(action: read, with: descriptor) return [read] } else { let flag = SwipeAction(style: .default, title: nil, handler: nil) flag.hidesWhenSelected = true configure(action: flag, with: .flag) let delete = SwipeAction(style: .destructive, title: nil) { action, indexPath in self.emails.remove(at: indexPath.row) } configure(action: delete, with: .trash) let cell = collectionView.cellForItem(at: indexPath) as! MailCollectionCell let closure: (UIAlertAction) -> Void = { _ in cell.hideSwipe(animated: true) } let more = SwipeAction(style: .default, title: nil) { action, indexPath in let controller = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet) controller.addAction(UIAlertAction(title: "Reply", style: .default, handler: closure)) controller.addAction(UIAlertAction(title: "Forward", style: .default, handler: closure)) controller.addAction(UIAlertAction(title: "Mark...", style: .default, handler: closure)) controller.addAction(UIAlertAction(title: "Notify Me...", style: .default, handler: closure)) controller.addAction(UIAlertAction(title: "Move Message...", style: .default, handler: closure)) controller.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: closure)) self.present(controller, animated: true, completion: nil) } configure(action: more, with: .more) return [delete, flag, more] } } func collectionView(_ collectionView: UICollectionView, editActionsOptionsForRowAt indexPath: IndexPath, for orientation: SwipeActionsOrientation) -> SwipeTableOptions { var options = SwipeTableOptions() options.expansionStyle = orientation == .left ? .selection : .destructive options.transitionStyle = defaultOptions.transitionStyle switch buttonStyle { case .backgroundColor: options.buttonSpacing = 11 case .circular: options.buttonSpacing = 4 options.backgroundColor = #colorLiteral(red: 0.9467939734, green: 0.9468161464, blue: 0.9468042254, alpha: 1) } return options } func configure(action: SwipeAction, with descriptor: ActionDescriptor) { action.title = descriptor.title(forDisplayMode: buttonDisplayMode) action.image = descriptor.image(forStyle: buttonStyle, displayMode: buttonDisplayMode) switch buttonStyle { case .backgroundColor: action.backgroundColor = descriptor.color case .circular: action.backgroundColor = .clear action.textColor = descriptor.color action.font = .systemFont(ofSize: 13) action.transitionDelegate = ScaleTransition.default } } }