Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Incrementally Open Sourcing

Incrementally Open Sourcing

Given at Swift Summit on October 30th, 2017.
http://swiftsummit.com

207a7a8631646945d43efa994164216d?s=128

Anat Gilboa

October 30, 2017
Tweet

Transcript

  1. anat gilboa incrementally open sourcing your app lessons learned

  2. timeline 1. idea 2. defining questions 3. development 4. additional

    questions 5. more development 6. repeat steps 4 & 5 as needed 7. fin.
  3. where it all began…

  4. where it all began… ❖ meal rescheduler

  5. where it all began… ❖ meal rescheduler ❖ date picker

    initialized by a set of available delivery windows for an order shipment
  6. where it all began…

  7. where it all began…

  8. where it all began…

  9. None
  10. None
  11. what to open source?

  12. defining questions ❖ presentation requirements? ❖ custom transition animation ❖

    cell requirements? ❖ use protocols? ❖ dated ❖ selectable ❖ overlay requirements? ❖ customizability
  13. development

  14. development

  15. development UIViewController

  16. development UIViewController UIView

  17. class RescheduleDeliveryViewController: UIViewController { fileprivate let calendarView: UICollectionView fileprivate let

    titleLabel: UILabel fileprivate let messageLabel: UILabel fileprivate let rescheduleButton: UIButton fileprivate let selectedDayOverlay: RescheduleDeliveryOverlayView fileprivate let viewModel: RescheduleDeliveryViewModel 
 } development
  18. class HorizontalScrollingPickerView: UIView { fileprivate let calendarView: UICollectionView fileprivate let

    selectedDayOverlay: HorizontalScrollingPickerOverlayView fileprivate let viewModel: HorizontalScrollingPickerViewModel 
 } development
  19. question

  20. lessons ‣ take the first step: create the cocoapod, carthage

    framework, swift package
  21. None
  22. pod lib create HorizontalScrollingPickerView

  23. pod lib create HorizontalScrollingPickerView

  24. pod lib create HorizontalScrollingPickerView

  25. HorizontalScrollingPickerView/ - Assets/ - Classes/ Example/ - HorizontalScrollingPickerView/ - HorizontalScrollingPickerView.xcodeproj

    - HorizontalScrollingPickerView.xcworkspace - Podfile - Podfile.lock - Pods/ - Tests/ README.md LICENSE HorizontalScrollingPickerView.podspec
  26. None
  27. development

  28. development

  29. lessons ‣ take the first step: create the cocoapod, carthage

    framework, swift package ‣ take your time
  30. question how are we going to present each cell?

  31. question Dated how are we going to present each cell?

  32. question Dated Not Dated how are we going to present

    each cell?
  33. question Dated Not Dated protocol Dated { let date: Date

    { get set } } how are we going to present each cell?
  34. question Dated Not Dated protocol Dated { let date: Date

    { get set } } ❓ how are we going to present each cell?
  35. func scrollViewDidScroll(_ scrollView: UIScrollView) { // HorizontalScrollingPickerView magic UIView.transition(with: rescheduleButton,

    duration: 0.1, options: [.beginFromCurrentState, .transitionCrossDissolve], animations: { [weak self] _ in guard let `self` = self else { return } if (some condition is true) { self.rescheduleButton.isEnabled = true self.rescheduleButton.setTitle(self.viewModel.rescheduleButtonText, for: .normal) } else { self.rescheduleButton.isEnabled = false self.rescheduleButton.setTitle(self.viewModel.rescheduleButtonText, for: .disabled) } self.generateFeedback() }, completion: nil) }
  36. lessons ‣ make the first step: create the cocoapod, carthage

    framework, swift package ‣ take your time ‣ design the api as one you would want to use
  37. None
  38. None
  39. delegate dataSource

  40. public protocol HorizontalScrollingPickerViewDelegate: class { /// UICollectionViewDelegate function that allows

    the consumer to respond to any selection events func collectionView(_ view: HorizontalScrollingPickerView, didSelectItemAt indexPath: IndexPath) /// UIScrollView function that allows the consumer to respond to scrolling events beginning func scrollViewWillBeginDragging(_ view: HorizontalScrollingPickerView) /// UIScrollView function that allows the consumer to respond to scrolling events ending func scrollViewWillEndDragging(_ view: HorizontalScrollingPickerView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) /// UIScrollView function that allows the consumer to respond to `scrollViewDidScroll` func scrollViewDidScroll(_ scrollView: UIScrollView) }
  41. public protocol HorizontalScrollingPickerViewDelegate: class { /// Configuration function to be

    called with consumer's implemented custom UICollectionViewCell. func configure(cell: UICollectionViewCell, for: IndexPath) }
  42. public protocol HorizontalScrollingPickerViewDelegate: class { /// Configuration function to be

    called with consumer's implemented custom UICollectionViewCell. func configure(cell: UICollectionViewCell, for: IndexPath) } public func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "DayCell", for: indexPath) // PROBLEM: HorizontalScrollingPickerViewCell -> we need to use a protocol instead… guard let scrollableCell = cell as? HorizontalScrollingPickerViewCell else { return cell } scrollableCell.viewModel = viewModel?.cellViewModels[indexPath.item] return scrollableCell }
  43. public class HorizontalScrollingPickerViewModel { public let cellViewModels: [HorizontalScrollingPickerViewCellViewModel] var selectedCellViewModel:

    HorizontalScrollingPickerViewCellViewModel? func select(cellViewModel: HorizontalScrollingPickerViewCellViewModel) { selectedCellViewModel = cellViewModel } public init(cellViewModels: [HorizontalScrollingPickerViewCellViewModel]) { self.cellViewModels = cellViewModels } }
  44. class HorizontalScrollingPickerViewModel { var cellViewModels: [Selectable] var selectedCellViewModel: Selectable? func

    select(cellViewModel: Selectable) { selectedCellViewModel = cellViewModel } init(cellViewModels: [Selectable]) { self.cellViewModels = cellViewModels } }
  45. class HorizontalScrollingPickerViewModel { var cellViewModels: [Selectable] var selectedCellViewModel: Selectable? func

    select(cellViewModel: Selectable) { selectedCellViewModel = cellViewModel } init(cellViewModels: [Selectable]) { self.cellViewModels = cellViewModels } } public protocol Selectable { var isSelectable: Bool { get set } }
  46. class HorizontalScrollingPickerViewModel { var cells: [Selectable] var selectedCell: Selectable? func

    select(cell: Selectable) { selectedCell = cell } init(cells: [Selectable]) { self.cells = cells } } public protocol Selectable { var isSelectable: Bool { get set } }
  47. public class HorizontalScrollingPickerViewCell: UICollectionViewCell, Selectable { public var isSelectable =

    true static let cellSize = CGSize(width: 76, height: 94) public override init(frame: CGRect) { super.init(frame: frame) backgroundColor = .white contentView.layer.borderColor = UIColor.black.withAlphaComponent(0.08).cgColor contentView.layer.borderWidth = 1.0 } public required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } } HorizontalScrollingPickerViewCell
  48. public class HorizontalScrollingPickerView: UIView { public var cellSize: CGSize? {

    didSet { guard let size = cellSize else { return } selectedItemOverlay.snp.updateConstraints { make in make.size.equalTo(size) } collectionView.snp.updateConstraints { make in make.height.equalTo(size.height) } setNeedsLayout() } } } extension HorizontalScrollingPickerView: UICollectionViewDelegateFlowLayout { public func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { return cellSize ?? PickerViewCell.cellSize } } HorizontalScrollingPickerViewCell
  49. selectedItemOverlay.snp.updateConstraints { make in make.size.equalTo(size) } collectionView.snp.updateConstraints { make in

    make.height.equalTo(size.height) } import SnapKit
  50. lessons ‣ make the first step: create the cocoapod, carthage

    framework, swift package ‣ take your time ‣ design the api as one you would want to use ‣ choose your dependencies wisely
  51. lessons ‣ make the first step: create the cocoapod, carthage

    framework, swift package ‣ take your time ‣ design the api as one you would want to use ‣ choose your dependencies wisely
  52. HorizontalScrollingPickerView.podspec s.dependency 'SnapKit', '~> 3.2.0' s.dependency 'SwiftHEXColors', '~> 1.1.0'

  53. question

  54. feedback

  55. feedback

  56. feedback

  57. audit your code

  58. audit your code HUDTransitionAnimationController HUDTransitionPresentationController

  59. audit your code HUDTransitionAnimationController HUDTransitionPresentationController

  60. audit your code

  61. audit your code

  62. audit your code UIColor+Extensions

  63. audit your code

  64. lessons ‣ make the first step: create the cocoapod, carthage

    framework, swift package ‣ take your time ‣ design the api as one you would want to use ‣ choose your dependencies wisely ‣ (recommended) get another pair of on it
  65. fin?

  66. ‣ try to figure out the name of your library

    in the first shot ‣ renaming sucks tips & tricks
  67. ‣ try to figure out the name of your library

    in the first shot ‣ renaming sucks ‣ CocoaPods does this funny thing where it makes an initial commit for you tips & tricks
  68. None
  69. None
  70. where do we go from here?

  71. None
  72. thanks!