Browse Source

update carthage

Marino Faggiana 6 years ago
parent
commit
709d5c6151
82 changed files with 1948 additions and 1692 deletions
  1. 1 1
      Cartfile
  2. 1 1
      Cartfile.resolved
  3. 1 1
      Carthage/Checkouts/Sheeeeeeeeet/.travis.yml
  4. 1 2
      Carthage/Checkouts/Sheeeeeeeeet/Fastlane/Fastfile
  5. 60 2
      Carthage/Checkouts/Sheeeeeeeeet/RELEASE_NOTES.md
  6. 1 1
      Carthage/Checkouts/Sheeeeeeeeet/Sheeeeeeeeet.podspec
  7. 63 56
      Carthage/Checkouts/Sheeeeeeeeet/Sheeeeeeeeet/ActionSheet/ActionSheet.swift
  8. 4 4
      Carthage/Checkouts/Sheeeeeeeeet/Sheeeeeeeeet/ActionSheet/ActionSheet.xib
  9. 5 2
      Carthage/Checkouts/Sheeeeeeeeet/Sheeeeeeeeet/ActionSheet/ActionSheetItemHandler.swift
  10. 5 6
      Carthage/Checkouts/Sheeeeeeeeet/Sheeeeeeeeet/ActionSheet/ActionSheetMargin.swift
  11. 0 109
      Carthage/Checkouts/Sheeeeeeeeet/Sheeeeeeeeet/Appearance/ActionSheetAppearance.swift
  12. 0 54
      Carthage/Checkouts/Sheeeeeeeeet/Sheeeeeeeeet/Appearance/ActionSheetItemAppearance.swift
  13. 0 28
      Carthage/Checkouts/Sheeeeeeeeet/Sheeeeeeeeet/Appearance/ActionSheetPopoverAppearance.swift
  14. 0 11
      Carthage/Checkouts/Sheeeeeeeeet/Sheeeeeeeeet/Appearance/Buttons/ActionSheetButtonAppearance.swift
  15. 0 11
      Carthage/Checkouts/Sheeeeeeeeet/Sheeeeeeeeet/Appearance/Buttons/ActionSheetCancelButtonAppearance.swift
  16. 0 22
      Carthage/Checkouts/Sheeeeeeeeet/Sheeeeeeeeet/Appearance/Buttons/ActionSheetDangerButtonAppearance.swift
  17. 0 11
      Carthage/Checkouts/Sheeeeeeeeet/Sheeeeeeeeet/Appearance/Buttons/ActionSheetOkButtonAppearance.swift
  18. 0 11
      Carthage/Checkouts/Sheeeeeeeeet/Sheeeeeeeeet/Appearance/Items/ActionSheetCollectionItemAppearance.swift
  19. 0 11
      Carthage/Checkouts/Sheeeeeeeeet/Sheeeeeeeeet/Appearance/Items/ActionSheetCustomItemAppearance.swift
  20. 0 30
      Carthage/Checkouts/Sheeeeeeeeet/Sheeeeeeeeet/Appearance/Items/ActionSheetLinkItemAppearance.swift
  21. 0 11
      Carthage/Checkouts/Sheeeeeeeeet/Sheeeeeeeeet/Appearance/Items/ActionSheetMultiSelectItemAppearance.swift
  22. 0 32
      Carthage/Checkouts/Sheeeeeeeeet/Sheeeeeeeeet/Appearance/Items/ActionSheetMultiSelectToggleItemAppearance.swift
  23. 0 53
      Carthage/Checkouts/Sheeeeeeeeet/Sheeeeeeeeet/Appearance/Items/ActionSheetSelectItemAppearance.swift
  24. 0 11
      Carthage/Checkouts/Sheeeeeeeeet/Sheeeeeeeeet/Appearance/Items/ActionSheetSingleSelectItemAppearance.swift
  25. 0 25
      Carthage/Checkouts/Sheeeeeeeeet/Sheeeeeeeeet/Appearance/Titles/ActionSheetSectionMarginAppearance.swift
  26. 0 11
      Carthage/Checkouts/Sheeeeeeeeet/Sheeeeeeeeet/Appearance/Titles/ActionSheetSectionTitleAppearance.swift
  27. 0 11
      Carthage/Checkouts/Sheeeeeeeeet/Sheeeeeeeeet/Appearance/Titles/ActionSheetTitleAppearance.swift
  28. 3 0
      Carthage/Checkouts/Sheeeeeeeeet/Sheeeeeeeeet/Extensions/NSObject+ClassName.swift
  29. 4 1
      Carthage/Checkouts/Sheeeeeeeeet/Sheeeeeeeeet/Extensions/UIView+Nib.swift
  30. 3 0
      Carthage/Checkouts/Sheeeeeeeeet/Sheeeeeeeeet/Extensions/UIView+Subviews.swift
  31. 3 0
      Carthage/Checkouts/Sheeeeeeeeet/Sheeeeeeeeet/Extensions/UIViewController+RootViewController.swift
  32. 2 2
      Carthage/Checkouts/Sheeeeeeeeet/Sheeeeeeeeet/Info.plist
  33. 116 37
      Carthage/Checkouts/Sheeeeeeeeet/Sheeeeeeeeet/Items/ActionSheetItem.swift
  34. 21 7
      Carthage/Checkouts/Sheeeeeeeeet/Sheeeeeeeeet/Items/Buttons/ActionSheetButton.swift
  35. 16 3
      Carthage/Checkouts/Sheeeeeeeeet/Sheeeeeeeeet/Items/Buttons/ActionSheetCancelButton.swift
  36. 18 4
      Carthage/Checkouts/Sheeeeeeeeet/Sheeeeeeeeet/Items/Buttons/ActionSheetDangerButton.swift
  37. 17 4
      Carthage/Checkouts/Sheeeeeeeeet/Sheeeeeeeeet/Items/Buttons/ActionSheetOkButton.swift
  38. 60 15
      Carthage/Checkouts/Sheeeeeeeeet/Sheeeeeeeeet/Items/Items/ActionSheetCollectionItem.swift
  39. 28 14
      Carthage/Checkouts/Sheeeeeeeeet/Sheeeeeeeeet/Items/Items/ActionSheetCustomItem.swift
  40. 25 9
      Carthage/Checkouts/Sheeeeeeeeet/Sheeeeeeeeet/Items/Items/ActionSheetLinkItem.swift
  41. 14 3
      Carthage/Checkouts/Sheeeeeeeeet/Sheeeeeeeeet/Items/Items/ActionSheetMultiSelectItem.swift
  42. 42 15
      Carthage/Checkouts/Sheeeeeeeeet/Sheeeeeeeeet/Items/Items/ActionSheetMultiSelectToggleItem.swift
  43. 84 17
      Carthage/Checkouts/Sheeeeeeeeet/Sheeeeeeeeet/Items/Items/ActionSheetSelectItem.swift
  44. 15 2
      Carthage/Checkouts/Sheeeeeeeeet/Sheeeeeeeeet/Items/Items/ActionSheetSingleSelectItem.swift
  45. 15 7
      Carthage/Checkouts/Sheeeeeeeeet/Sheeeeeeeeet/Items/Titles/ActionSheetSectionMargin.swift
  46. 15 8
      Carthage/Checkouts/Sheeeeeeeeet/Sheeeeeeeeet/Items/Titles/ActionSheetSectionTitle.swift
  47. 19 6
      Carthage/Checkouts/Sheeeeeeeeet/Sheeeeeeeeet/Items/Titles/ActionSheetTitle.swift
  48. 6 16
      Carthage/Checkouts/Sheeeeeeeeet/Sheeeeeeeeet/Presenters/ActionSheetPopoverPresenter.swift
  49. 6 9
      Carthage/Checkouts/Sheeeeeeeeet/Sheeeeeeeeet/Presenters/ActionSheetPresenter.swift
  50. 14 7
      Carthage/Checkouts/Sheeeeeeeeet/Sheeeeeeeeet/Presenters/ActionSheetStandardPresenter.swift
  51. 0 34
      Carthage/Checkouts/Sheeeeeeeeet/Sheeeeeeeeet/Views/ActionSheetCollectionItemCell.swift
  52. 0 46
      Carthage/Checkouts/Sheeeeeeeeet/Sheeeeeeeeet/Views/ActionSheetCollectionItemCell.xib
  53. 0 27
      Carthage/Checkouts/Sheeeeeeeeet/Sheeeeeeeeet/Views/ActionSheetCollectionItemContentCell.swift
  54. 0 22
      Carthage/Checkouts/Sheeeeeeeeet/Sheeeeeeeeet/Views/ActionSheetCustomItemCell.swift
  55. 0 19
      Carthage/Checkouts/Sheeeeeeeeet/Sheeeeeeeeet/Views/ActionSheetItemCell.swift
  56. 89 63
      Carthage/Checkouts/Sheeeeeeeeet/SheeeeeeeeetExample/AppDelegate+Appearance.swift
  57. 2 2
      Carthage/Checkouts/Sheeeeeeeeet/SheeeeeeeeetExample/Info.plist
  58. 2 2
      Carthage/Checkouts/Sheeeeeeeeet/SheeeeeeeeetTests/ActionSheet/ActionSheet+PresenterTests.swift
  59. 21 17
      Carthage/Checkouts/Sheeeeeeeeet/SheeeeeeeeetTests/ActionSheet/ActionSheetItemHandlerTests.swift
  60. 14 7
      Carthage/Checkouts/Sheeeeeeeeet/SheeeeeeeeetTests/ActionSheet/ActionSheetMarginTests.swift
  61. 358 300
      Carthage/Checkouts/Sheeeeeeeeet/SheeeeeeeeetTests/ActionSheet/ActionSheetTests.swift
  62. 22 0
      Carthage/Checkouts/Sheeeeeeeeet/SheeeeeeeeetTests/ActionSheet/MockActionSheet.swift
  63. 4 4
      Carthage/Checkouts/Sheeeeeeeeet/SheeeeeeeeetTests/Extensions/NSObject+ClassNameTests.swift
  64. 2 2
      Carthage/Checkouts/Sheeeeeeeeet/SheeeeeeeeetTests/Info.plist
  65. 90 135
      Carthage/Checkouts/Sheeeeeeeeet/SheeeeeeeeetTests/Items/ActionSheetItemTests.swift
  66. 41 38
      Carthage/Checkouts/Sheeeeeeeeet/SheeeeeeeeetTests/Items/Buttons/ActionSheetButtonTests.swift
  67. 16 20
      Carthage/Checkouts/Sheeeeeeeeet/SheeeeeeeeetTests/Items/Buttons/ActionSheetCancelButtonTests.swift
  68. 16 20
      Carthage/Checkouts/Sheeeeeeeeet/SheeeeeeeeetTests/Items/Buttons/ActionSheetDangerButtonTests.swift
  69. 16 20
      Carthage/Checkouts/Sheeeeeeeeet/SheeeeeeeeetTests/Items/Buttons/ActionSheetOkButtonTests.swift
  70. 24 10
      Carthage/Checkouts/Sheeeeeeeeet/SheeeeeeeeetTests/Items/Items/ActionSheetLinkItemTests.swift
  71. 46 15
      Carthage/Checkouts/Sheeeeeeeeet/SheeeeeeeeetTests/Items/Items/ActionSheetMultiSelectItemTests.swift
  72. 59 11
      Carthage/Checkouts/Sheeeeeeeeet/SheeeeeeeeetTests/Items/Items/ActionSheetMultiSelectToggleItemTests.swift
  73. 83 38
      Carthage/Checkouts/Sheeeeeeeeet/SheeeeeeeeetTests/Items/Items/ActionSheetSelectItemTests.swift
  74. 29 63
      Carthage/Checkouts/Sheeeeeeeeet/SheeeeeeeeetTests/Items/Items/ActionSheetSingleSelectItemTests.swift
  75. 2 17
      Carthage/Checkouts/Sheeeeeeeeet/SheeeeeeeeetTests/Items/Mocks/MockActionSheetItem.swift
  76. 15 11
      Carthage/Checkouts/Sheeeeeeeeet/SheeeeeeeeetTests/Items/Titles/ActionSheetSectionMarginTests.swift
  77. 13 14
      Carthage/Checkouts/Sheeeeeeeeet/SheeeeeeeeetTests/Items/Titles/ActionSheetSectionTitleTests.swift
  78. 13 15
      Carthage/Checkouts/Sheeeeeeeeet/SheeeeeeeeetTests/Items/Titles/ActionSheetTitleTests.swift
  79. 175 4
      Carthage/Checkouts/Sheeeeeeeeet/SheeeeeeeeetTests/Presenters/ActionSheetPopoverPresenterTests.swift
  80. 81 1
      Carthage/Checkouts/Sheeeeeeeeet/SheeeeeeeeetTests/Presenters/ActionSheetStandardPresenterTests.swift
  81. 20 1
      Carthage/Checkouts/Sheeeeeeeeet/SheeeeeeeeetTests/Views/MockTableView.swift
  82. 7 0
      iOSClient/Main/Create cloud/NCCreateFormUploadScanDocument.swift

+ 1 - 1
Cartfile

@@ -1,6 +1,6 @@
 github "tilltue/TLPhotoPicker"
 github "tilltue/TLPhotoPicker"
 github "kishikawakatsumi/UICKeyChainStore"
 github "kishikawakatsumi/UICKeyChainStore"
-github "danielsaidi/Sheeeeeeeeet"
+github "danielsaidi/Sheeeeeeeeet" == 1.2.2
 github "sgr-ksmt/PDFGenerator" ~> 2.1
 github "sgr-ksmt/PDFGenerator" ~> 2.1
 github "MortimerGoro/MGSwipeTableCell"
 github "MortimerGoro/MGSwipeTableCell"
 github "dzenbot/DZNEmptyDataSet"
 github "dzenbot/DZNEmptyDataSet"

+ 1 - 1
Cartfile.resolved

@@ -4,7 +4,7 @@ github "MortimerGoro/MGSwipeTableCell" "1.6.8"
 github "SVGKit/SVGKit" "bfe62f6d45f55c9fe39619d9e91fed1844c59da6"
 github "SVGKit/SVGKit" "bfe62f6d45f55c9fe39619d9e91fed1844c59da6"
 github "WeTransfer/WeScan" "v0.9.1"
 github "WeTransfer/WeScan" "v0.9.1"
 github "calimarkus/JDStatusBarNotification" "1.6.0"
 github "calimarkus/JDStatusBarNotification" "1.6.0"
-github "danielsaidi/Sheeeeeeeeet" "1.1.0"
+github "danielsaidi/Sheeeeeeeeet" "1.2.2"
 github "dzenbot/DZNEmptyDataSet" "v1.8.1"
 github "dzenbot/DZNEmptyDataSet" "v1.8.1"
 github "ealeksandrov/EAIntroView" "2.12.0"
 github "ealeksandrov/EAIntroView" "2.12.0"
 github "ealeksandrov/EARestrictedScrollView" "1.1.0"
 github "ealeksandrov/EARestrictedScrollView" "1.1.0"

+ 1 - 1
Carthage/Checkouts/Sheeeeeeeeet/.travis.yml

@@ -11,5 +11,5 @@ before_install:
 
 
 script:
 script:
   - set -o pipefail && xcodebuild -project "Sheeeeeeeeet.xcodeproj" -scheme "Sheeeeeeeeet" -sdk "iphonesimulator" | xcpretty -c
   - set -o pipefail && xcodebuild -project "Sheeeeeeeeet.xcodeproj" -scheme "Sheeeeeeeeet" -sdk "iphonesimulator" | xcpretty -c
-  - pod lib lint
+  - pod lib lint --allow-warnings
   - fastlane test
   - fastlane test

+ 1 - 2
Carthage/Checkouts/Sheeeeeeeeet/Fastlane/Fastfile

@@ -14,7 +14,6 @@ platform :ios do
     test
     test
     version = version_bump_podspec(path: "Sheeeeeeeeet.podspec", version_number: options[:name])
     version = version_bump_podspec(path: "Sheeeeeeeeet.podspec", version_number: options[:name])
     increment_version_number(version_number: version)
     increment_version_number(version_number: version)
-    increment_build_number(build_number: `date "+%y%m%d%H%M"`)
 
 
     git_commit(
     git_commit(
       path: [
       path: [
@@ -28,7 +27,7 @@ platform :ios do
     add_git_tag(tag: version)
     add_git_tag(tag: version)
     push_git_tags()
     push_git_tags()
     push_to_git_remote()
     push_to_git_remote()
-    pod_push()
+#pod_push()
   end
   end
 
 
   
   

+ 60 - 2
Carthage/Checkouts/Sheeeeeeeeet/RELEASE_NOTES.md

@@ -1,6 +1,61 @@
 # Release Notes
 # Release Notes
 
 
 
 
+## 1.2.2
+
+This hotfix adds two new properties to `ActionSheetSelectItem`, that can be used
+to style the selected fonts: `selectedTitleFont` and `selectedSubtitleFont`.
+
+
+## 1.2.1
+
+This hotfix fixes a font bug in the title item and color bugs in the select item. 
+
+
+## 1.2.0
+
+This is a huge update, that completely rewrites how action sheet appearances are
+handled. Instead of the old appearance model, Sheeeeeeeeet now relies on the iOS
+appearance proxy model as much as possible.
+
+The old appearance model is still around, but has been marked as deprecated, and
+will be removed in `1.4.0`. Make sure that you switch over to the new appearance
+model as soon as possible. Have a look at the example app and [here][Appearance]
+to see how you should customize the action sheet appearance from now on.
+
+In short, item appearance customizations are handled in three different ways now:
+
+* Item appearances such as colors and fonts, are customized with cell properties,
+for instance: `ActionSheetSelectItemCell.appearance().titleColor = .green`.
+* Item heights are now customized by setting the `height` property of every item
+type you want to customize, for instance: `ActionSheetTitle.height = 22`.
+* Action sheet margins, insets etc. are now customized by setting the properties
+of each `ActionSheet` instance. If you want to change the default values for all
+action sheets in your app, you have to subclass `ActionSheet`.
+
+All built-in action sheet items now have their own cells. Your custom items only
+have to use custom cells if you want to apply custom item appearances to them.
+
+Sheeeeeeeeet now contains several new views, which are used by the action sheets:
+
+  * `ActionSheetTableView`
+  * `ActionSheetItemTableView`
+  * `ActionSheetButtonTableView`
+  * `ActionSheetBackgroundView`
+  * `ActionSheetStackView`
+
+The new classes make it easy to modify the appearance of these views, since they
+have appearance properties as well. For instance, to change the corner radius of
+the table views, just type: `ActionSheetTableView.appearance().cornerRadius = 8`.
+
+`ActionSheet` has two new extensions: 
+  * `items<T>(ofType:)`
+  * `scrollToFirstSelectedItem(at:)`
+
+This new version has also rebuilt all unit tests from scratch. They are now more
+robust and easier to maintain.
+
+
 ## 1.1.0
 ## 1.1.0
 
 
 This version increases the action sheet integrity by restricting what you can do
 This version increases the action sheet integrity by restricting what you can do
@@ -8,7 +63,7 @@ with it. This involves some breaking changes, but they should not affect you. If
 you think any new rule is bad or affect you, please let me know.
 you think any new rule is bad or affect you, please let me know.
 
 
 
 
-### New Features
+**New Features**
 
 
 @sebbo176 has added support for subtitles in the various select items, which now
 @sebbo176 has added support for subtitles in the various select items, which now
 also changes the cell style of an item if the subtitle is set. He has also added
 also changes the cell style of an item if the subtitle is set. He has also added
@@ -16,7 +71,7 @@ an unselected icon to the select items, which means that you can now have images
 for unselected items as well (e.g. an unchecked checkbox).
 for unselected items as well (e.g. an unchecked checkbox).
 
 
 
 
-### Breaking Changes - ActionSheet:
+**Breaking Changes - ActionSheet:**
 
 
 * The `items` and `buttons` properties are now `internal(set)`, which means that
 * The `items` and `buttons` properties are now `internal(set)`, which means that
 they can only be set with `init(...)` or with `setup(items:)`. This protects the
 they can only be set with `init(...)` or with `setup(items:)`. This protects the
@@ -377,3 +432,6 @@ Select items can now have a separate select tint color for the left icon.
 
 
 We have added a subtitle to the section title item and clarified the examples by
 We have added a subtitle to the section title item and clarified the examples by
 moving action sheets into their own separate classes.
 moving action sheets into their own separate classes.
+
+
+[Appearance]: https://github.com/danielsaidi/Sheeeeeeeeet/blob/master/Readmes/Appearance.md

+ 1 - 1
Carthage/Checkouts/Sheeeeeeeeet/Sheeeeeeeeet.podspec

@@ -2,7 +2,7 @@
 
 
 Pod::Spec.new do |s|
 Pod::Spec.new do |s|
   s.name             = 'Sheeeeeeeeet'
   s.name             = 'Sheeeeeeeeet'
-  s.version          = '1.1.0.1'
+  s.version          = '1.2.2'
   s.summary          = 'Sheeeeeeeeet is a Swift library for custom iOS action sheets.'
   s.summary          = 'Sheeeeeeeeet is a Swift library for custom iOS action sheets.'
 
 
   s.description      = <<-DESC
   s.description      = <<-DESC

+ 63 - 56
Carthage/Checkouts/Sheeeeeeeeet/Sheeeeeeeeet/ActionSheet/ActionSheet.swift

@@ -29,8 +29,35 @@
  you want to use your own models in a controlled way. If you
  you want to use your own models in a controlled way. If you
  have a podcast app, you could have a `SleepTimerActionSheet`
  have a podcast app, you could have a `SleepTimerActionSheet`
  that automatically sets up its `SleepTimerTime` options and
  that automatically sets up its `SleepTimerTime` options and
- streamlines how you work with a sleep timer. This is a good
- way to setup the base action sheet for specific use cases.
+ streamlines how you work with a sleep timer.
+ 
+ 
+ ## Appearance
+ 
+ Customizing the appearance of the various action sheet item
+ types in Sheeeeeeeeet (as well as of your own custom items),
+ is mainly done using the iOS appearance proxy for each item
+ cell type. For instance, to change the title text color for
+ all `ActionSheetSelectItem` instances (including subclasses),
+ type `ActionSheetSelectItem.appearance().titleColor`. It is
+ also possible to set these properties for each item as well.
+ 
+ While most appearance is modified on a cell level, some are
+ not. For instance, some views in `Views` have apperances of
+ their own (e.g. `ActionSheetHeaderView.cornerRadius`). This
+ means that you can change more than cell appearance. Have a
+ look at the readme for more info on what you can customize.
+ 
+ Action sheet insets, margins and widths are not part of the
+ appearance model, but have to be changed for each sheet. If
+ you want to change these values for each sheet in youer app,
+ I recommend subclassing `ActionSheet` and set these values.
+ 
+ Neither item heights are part of the appearance model. Item
+ heights are instead changed by setting the static height of
+ each item type, e.g. `ActionSheetTitleItem.height = 20`. It
+ is not part of the cell appearance model since an item must
+ know about the height before it creates any cells.
  
  
  
  
  ## Presentation
  ## Presentation
@@ -38,16 +65,7 @@
  You can inject a custom presenter if you want to change how
  You can inject a custom presenter if you want to change how
  the sheet is presented and dismissed. The default presenter
  the sheet is presented and dismissed. The default presenter
  for iPhone devices is `ActionSheetStandardPresenter`, while
  for iPhone devices is `ActionSheetStandardPresenter`, while
- iPad devices most often get an `ActionSheetPopoverPresenter`.
- 
- 
- ## Appearance
- 
- To change the global appearance for all action sheets, just
- modify the `ActionSheetAppearance.standard` to look the way
- you want. To change the appearance of a single action sheet,
- modify its `appearance` property. To change the appearances
- of single items, modify their `customAppearance` property.
+ iPad devices (most often) use `ActionSheetPopoverPresenter`.
  
  
  
  
  ## Handling item selections
  ## Handling item selections
@@ -55,7 +73,7 @@
  The `selectAction` is triggered when a user taps an item in
  The `selectAction` is triggered when a user taps an item in
  the action sheet. It provides you with the action sheet and
  the action sheet. It provides you with the action sheet and
  the selected item. It is very important to use `[weak self]`
  the selected item. It is very important to use `[weak self]`
- in this block, to avoid memory leaks.
+ in these action closures, to avoid memory leaks.
  
  
  
  
  ## Handling item taps
  ## Handling item taps
@@ -71,13 +89,14 @@ import UIKit
 open class ActionSheet: UIViewController {
 open class ActionSheet: UIViewController {
     
     
     
     
-    // MARK: - Deprecated Members
-    
-    @available(*, deprecated, message: "setupItemsAndButtons(with:) is deprecated and will be removed shortly. Use `setup(items:)` instead")
+    // MARK: - Deprecated - Remove in 1.4.0 ****************
+    @available(*, deprecated, message: "appearance will be removed in 1.4.0. Use the new appearance model instead")
+    public var appearance = ActionSheetAppearance(copy: .standard)
+    @available(*, deprecated, message: "setupItemsAndButtons(with:) will be removed in 1.4.0. Use `setup(items:)` instead")
     open func setupItemsAndButtons(with items: [ActionSheetItem]) { setup(items: items) }
     open func setupItemsAndButtons(with items: [ActionSheetItem]) { setup(items: items) }
-    
-    @available(*, deprecated, message: "itemSelectAction is deprecated and will be removed in shortly. Use `selectAction` instead")
+    @available(*, deprecated, message: "itemSelectAction will be removed in 1.4.0. Use `selectAction` instead")
     open var itemSelectAction: SelectAction { return selectAction }
     open var itemSelectAction: SelectAction { return selectAction }
+    // MARK: - Deprecated - Remove in 1.4.0 ****************
     
     
     
     
     // MARK: - Initialization
     // MARK: - Initialization
@@ -101,7 +120,9 @@ open class ActionSheet: UIViewController {
     
     
     // MARK: - Setup
     // MARK: - Setup
     
     
-    open func setup() {}
+    open func setup() {
+        preferredContentSize.width = preferredPopoverWidth
+    }
     
     
     open func setup(items: [ActionSheetItem]) {
     open func setup(items: [ActionSheetItem]) {
         self.items = items.filter { !($0 is ActionSheetButton) }
         self.items = items.filter { !($0 is ActionSheetButton) }
@@ -138,13 +159,21 @@ open class ActionSheet: UIViewController {
     
     
     // MARK: - Appearance
     // MARK: - Appearance
     
     
-    public var appearance = ActionSheetAppearance(copy: .standard)
+    public var minimumContentInsets = UIEdgeInsets(top: 15, left: 15, bottom: 15, right: 15)
+    public var preferredPopoverWidth: CGFloat = 300
+    public var sectionMargins: CGFloat = 15
     
     
     
     
     // MARK: - Outlets
     // MARK: - Outlets
     
     
-    @IBOutlet weak var backgroundView: UIView?
+    @IBOutlet weak var backgroundView: ActionSheetBackgroundView?
     @IBOutlet weak var stackView: UIStackView?
     @IBOutlet weak var stackView: UIStackView?
+    @IBOutlet weak var headerViewContainer: ActionSheetHeaderView?
+    @IBOutlet weak var headerViewContainerHeight: NSLayoutConstraint?
+    @IBOutlet weak var itemsTableView: ActionSheetItemTableView?
+    @IBOutlet weak var itemsTableViewHeight: NSLayoutConstraint?
+    @IBOutlet weak var buttonsTableView: ActionSheetButtonTableView?
+    @IBOutlet weak var buttonsTableViewHeight: NSLayoutConstraint?
     
     
     @IBOutlet weak var topMargin: NSLayoutConstraint?
     @IBOutlet weak var topMargin: NSLayoutConstraint?
     @IBOutlet weak var leftMargin: NSLayoutConstraint?
     @IBOutlet weak var leftMargin: NSLayoutConstraint?
@@ -156,10 +185,6 @@ open class ActionSheet: UIViewController {
     
     
     open var headerView: UIView?
     open var headerView: UIView?
     
     
-    @IBOutlet weak var headerViewContainer: UIView?
-    
-    @IBOutlet weak var headerViewContainerHeight: NSLayoutConstraint?
-    
     
     
     // MARK: - Item Properties
     // MARK: - Item Properties
     
     
@@ -169,10 +194,6 @@ open class ActionSheet: UIViewController {
     
     
     public lazy var itemHandler = ActionSheetItemHandler(actionSheet: self, itemType: .items)
     public lazy var itemHandler = ActionSheetItemHandler(actionSheet: self, itemType: .items)
     
     
-    @IBOutlet weak var itemsTableView: ActionSheetTableView?
-    
-    @IBOutlet weak var itemsTableViewHeight: NSLayoutConstraint?
-    
     
     
     // MARK: - Button Properties
     // MARK: - Button Properties
     
     
@@ -182,10 +203,6 @@ open class ActionSheet: UIViewController {
     
     
     public lazy var buttonHandler = ActionSheetItemHandler(actionSheet: self, itemType: .buttons)
     public lazy var buttonHandler = ActionSheetItemHandler(actionSheet: self, itemType: .buttons)
     
     
-    @IBOutlet weak var buttonsTableView: ActionSheetTableView?
-    
-    @IBOutlet weak var buttonsTableViewHeight: NSLayoutConstraint?
-    
     
     
     // MARK: - Presentation Functions
     // MARK: - Presentation Functions
     
     
@@ -207,11 +224,11 @@ open class ActionSheet: UIViewController {
     // MARK: - Refresh Functions
     // MARK: - Refresh Functions
     
     
     open func refresh() {
     open func refresh() {
-        applyRoundCorners()
+        applyLegacyAppearance()
         refreshHeader()
         refreshHeader()
         refreshItems()
         refreshItems()
         refreshButtons()
         refreshButtons()
-        stackView?.spacing = appearance.groupMargins
+        stackView?.spacing = sectionMargins
         presenter.refreshActionSheet()
         presenter.refreshActionSheet()
     }
     }
     
     
@@ -224,17 +241,13 @@ open class ActionSheet: UIViewController {
     }
     }
     
     
     open func refreshItems() {
     open func refreshItems() {
-        items.forEach { $0.applyAppearance(appearance) }
-        itemsTableView?.backgroundColor = appearance.itemsBackgroundColor
-        itemsTableView?.separatorColor = appearance.itemsSeparatorColor
+        items.forEach { $0.applyAppearance(appearance) }    // TODO: Deprecated - Remove in 1.4.0
         itemsTableViewHeight?.constant = itemsHeight
         itemsTableViewHeight?.constant = itemsHeight
     }
     }
     
     
     open func refreshButtons() {
     open func refreshButtons() {
         buttonsTableView?.isHidden = buttons.count == 0
         buttonsTableView?.isHidden = buttons.count == 0
-        buttons.forEach { $0.applyAppearance(appearance) }
-        buttonsTableView?.backgroundColor = appearance.buttonsBackgroundColor
-        buttonsTableView?.separatorColor = appearance.buttonsSeparatorColor
+        buttons.forEach { $0.applyAppearance(appearance) }  // TODO: Deprecated - Remove in 1.4.0
         buttonsTableViewHeight?.constant = buttonsHeight
         buttonsTableViewHeight?.constant = buttonsHeight
     }
     }
     
     
@@ -248,8 +261,13 @@ open class ActionSheet: UIViewController {
     }
     }
     
     
     open func margin(at margin: ActionSheetMargin) -> CGFloat {
     open func margin(at margin: ActionSheetMargin) -> CGFloat {
-        let minimum = appearance.contentInset
-        return margin.value(in: view.superview, minimum: minimum)
+        let view: UIView! = self.view.superview ?? self.view
+        switch margin {
+        case .top: return margin.value(in: view, minimum: minimumContentInsets.top)
+        case .left: return margin.value(in: view, minimum: minimumContentInsets.left)
+        case .right: return margin.value(in: view, minimum: minimumContentInsets.right)
+        case .bottom: return margin.value(in: view, minimum: minimumContentInsets.bottom)
+        }
     }
     }
 
 
     open func reloadData() {
     open func reloadData() {
@@ -263,18 +281,6 @@ open class ActionSheet: UIViewController {
 
 
 private extension ActionSheet {
 private extension ActionSheet {
     
     
-    func applyRoundCorners() {
-        applyRoundCorners(to: headerView)
-        applyRoundCorners(to: headerViewContainer)
-        applyRoundCorners(to: itemsTableView)
-        applyRoundCorners(to: buttonsTableView)
-    }
-
-    func applyRoundCorners(to view: UIView?) {
-        view?.clipsToBounds = true
-        view?.layer.cornerRadius = appearance.cornerRadius
-    }
-    
     func setup(_ tableView: UITableView?, with handler: ActionSheetItemHandler) {
     func setup(_ tableView: UITableView?, with handler: ActionSheetItemHandler) {
         tableView?.delegate = handler
         tableView?.delegate = handler
         tableView?.dataSource = handler
         tableView?.dataSource = handler
@@ -285,6 +291,7 @@ private extension ActionSheet {
     }
     }
     
     
     func totalHeight(for items: [ActionSheetItem]) -> CGFloat {
     func totalHeight(for items: [ActionSheetItem]) -> CGFloat {
-        return items.reduce(0) { $0 + $1.appearance.height }
+        let height = items.reduce(0) { $0 + $1.height }
+        return height
     }
     }
 }
 }

+ 4 - 4
Carthage/Checkouts/Sheeeeeeeeet/Sheeeeeeeeet/ActionSheet/ActionSheet.xib

@@ -32,28 +32,28 @@
             <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
             <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
             <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
             <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
             <subviews>
             <subviews>
-                <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="SY3-WL-g9a">
+                <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="SY3-WL-g9a" customClass="ActionSheetBackgroundView" customModule="Sheeeeeeeeet" customModuleProvider="target">
                     <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
                     <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
                     <color key="backgroundColor" white="0.0" alpha="0.40000000000000002" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
                     <color key="backgroundColor" white="0.0" alpha="0.40000000000000002" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
                 </view>
                 </view>
                 <stackView opaque="NO" contentMode="scaleToFill" axis="vertical" spacing="20" translatesAutoresizingMaskIntoConstraints="NO" id="a3t-st-aTv">
                 <stackView opaque="NO" contentMode="scaleToFill" axis="vertical" spacing="20" translatesAutoresizingMaskIntoConstraints="NO" id="a3t-st-aTv">
                     <rect key="frame" x="0.0" y="277" width="375" height="390"/>
                     <rect key="frame" x="0.0" y="277" width="375" height="390"/>
                     <subviews>
                     <subviews>
-                        <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Eio-5P-omJ">
+                        <view clipsSubviews="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Eio-5P-omJ" customClass="ActionSheetHeaderView" customModule="Sheeeeeeeeet" customModuleProvider="target">
                             <rect key="frame" x="0.0" y="0.0" width="375" height="150"/>
                             <rect key="frame" x="0.0" y="0.0" width="375" height="150"/>
                             <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
                             <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
                             <constraints>
                             <constraints>
                                 <constraint firstAttribute="height" constant="150" id="ZKw-6e-7h3"/>
                                 <constraint firstAttribute="height" constant="150" id="ZKw-6e-7h3"/>
                             </constraints>
                             </constraints>
                         </view>
                         </view>
-                        <tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" style="plain" separatorStyle="default" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="28" sectionFooterHeight="28" translatesAutoresizingMaskIntoConstraints="NO" id="iQT-dy-e7d" customClass="ActionSheetTableView" customModule="Sheeeeeeeeet" customModuleProvider="target">
+                        <tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" style="plain" separatorStyle="default" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="28" sectionFooterHeight="28" translatesAutoresizingMaskIntoConstraints="NO" id="iQT-dy-e7d" customClass="ActionSheetItemTableView" customModule="Sheeeeeeeeet" customModuleProvider="target">
                             <rect key="frame" x="0.0" y="170" width="375" height="100"/>
                             <rect key="frame" x="0.0" y="170" width="375" height="100"/>
                             <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
                             <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
                             <constraints>
                             <constraints>
                                 <constraint firstAttribute="height" priority="900" constant="100" id="929-kf-L2B"/>
                                 <constraint firstAttribute="height" priority="900" constant="100" id="929-kf-L2B"/>
                             </constraints>
                             </constraints>
                         </tableView>
                         </tableView>
-                        <tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" scrollEnabled="NO" style="plain" separatorStyle="default" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="28" sectionFooterHeight="28" translatesAutoresizingMaskIntoConstraints="NO" id="4ww-lg-Kl7" customClass="ActionSheetTableView" customModule="Sheeeeeeeeet" customModuleProvider="target">
+                        <tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" scrollEnabled="NO" style="plain" separatorStyle="default" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="28" sectionFooterHeight="28" translatesAutoresizingMaskIntoConstraints="NO" id="4ww-lg-Kl7" customClass="ActionSheetButtonTableView" customModule="Sheeeeeeeeet" customModuleProvider="target">
                             <rect key="frame" x="0.0" y="290" width="375" height="100"/>
                             <rect key="frame" x="0.0" y="290" width="375" height="100"/>
                             <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
                             <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
                             <constraints>
                             <constraints>

+ 5 - 2
Carthage/Checkouts/Sheeeeeeeeet/Sheeeeeeeeet/ActionSheet/ActionSheetItemHandler.swift

@@ -68,12 +68,15 @@ extension ActionSheetItemHandler: UITableViewDataSource {
     
     
     public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
     public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
         guard let item = self.item(at: indexPath) else { return UITableViewCell(frame: .zero) }
         guard let item = self.item(at: indexPath) else { return UITableViewCell(frame: .zero) }
-        return item.cell(for: tableView)
+        let cell = item.cell(for: tableView)
+        item.applyAppearance(to: cell)                      // TODO: Deprecated - Remove in 1.4.0
+        cell.refresh(with: item)
+        return cell
     }
     }
     
     
     public func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
     public func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
         guard let item = self.item(at: indexPath) else { return 0 }
         guard let item = self.item(at: indexPath) else { return 0 }
-        return CGFloat(item.appearance.height)
+        return CGFloat(item.height)
     }
     }
 }
 }
 
 

+ 5 - 6
Carthage/Checkouts/Sheeeeeeeeet/Sheeeeeeeeet/ActionSheet/ActionSheetMargin.swift

@@ -9,10 +9,10 @@
 import UIKit
 import UIKit
 
 
 public enum ActionSheetMargin {
 public enum ActionSheetMargin {
+    
     case top, left, right, bottom
     case top, left, right, bottom
     
     
-    func value(in view: UIView?) -> CGFloat? {
-        guard let view = view else { return nil }
+    func value(in view: UIView) -> CGFloat {
         if #available(iOS 11.0, *) {
         if #available(iOS 11.0, *) {
             let insets = view.safeAreaInsets
             let insets = view.safeAreaInsets
             switch self {
             switch self {
@@ -22,12 +22,11 @@ public enum ActionSheetMargin {
             case .bottom: return insets.bottom
             case .bottom: return insets.bottom
             }
             }
         } else {
         } else {
-            return nil
+            return 0
         }
         }
     }
     }
     
     
-    func value(in view: UIView?, minimum: CGFloat) -> CGFloat {
-        guard let value = self.value(in: view) else { return minimum }
-        return max(value, minimum)
+    func value(in view: UIView, minimum: CGFloat) -> CGFloat {
+        return max(value(in: view), minimum)
     }
     }
 }
 }

+ 0 - 109
Carthage/Checkouts/Sheeeeeeeeet/Sheeeeeeeeet/Appearance/ActionSheetAppearance.swift

@@ -1,109 +0,0 @@
-//
-//  ActionSheetAppearance.swift
-//  Sheeeeeeeeet
-//
-//  Created by Daniel Saidi on 2017-11-18.
-//  Copyright © 2017 Daniel Saidi. All rights reserved.
-//
-
-/*
- 
- This class is used to specify the appearance for all action
- sheets and action sheet items provided by Sheeeeeeeeet. Use
- `ActionSheetAppearance.standard` to style all action sheets
- in an entire app. You can then apply individual appearances
- to individual action sheets and item types.
- 
- The `item` appearance property is used as the base template
- for all other item appearances.
- 
- */
-
-import UIKit
-
-open class ActionSheetAppearance {
-    
-    
-    // MARK: - Initialization
-    
-    public init() {}
-    
-    public init(copy: ActionSheetAppearance) {
-        cornerRadius = copy.cornerRadius
-        contentInset = copy.contentInset
-        groupMargins = copy.groupMargins
-        
-        backgroundColor = copy.backgroundColor
-        separatorColor = copy.separatorColor
-        itemsBackgroundColor = copy.itemsBackgroundColor ?? backgroundColor
-        itemsSeparatorColor = copy.itemsSeparatorColor ?? separatorColor
-        buttonsSeparatorColor = copy.buttonsSeparatorColor ?? backgroundColor
-        buttonsSeparatorColor = copy.buttonsSeparatorColor ?? separatorColor
-        
-        popover = ActionSheetPopoverAppearance(copy: copy.popover)
-        
-        item = ActionSheetItemAppearance(copy: copy.item)
-        collectionItem = ActionSheetCollectionItemAppearance(copy: copy.collectionItem)
-        customItem = ActionSheetCustomItemAppearance(copy: copy.customItem)
-        linkItem = ActionSheetLinkItemAppearance(copy: copy.linkItem)
-        multiSelectItem = ActionSheetMultiSelectItemAppearance(copy: copy.multiSelectItem)
-        multiSelectToggleItem = ActionSheetMultiSelectToggleItemAppearance(copy: copy.multiSelectToggleItem)
-        selectItem = ActionSheetSelectItemAppearance(copy: copy.selectItem)
-        singleSelectItem = ActionSheetSingleSelectItemAppearance(copy: copy.singleSelectItem)
-        
-        cancelButton = ActionSheetCancelButtonAppearance(copy: copy.cancelButton)
-        dangerButton = ActionSheetDangerButtonAppearance(copy: copy.dangerButton)
-        okButton = ActionSheetOkButtonAppearance(copy: copy.okButton)
-        
-        sectionMargin = ActionSheetSectionMarginAppearance(copy: copy.sectionMargin)
-        sectionTitle = ActionSheetSectionTitleAppearance(copy: copy.sectionTitle)
-        title = ActionSheetTitleAppearance(copy: copy.title)
-    }
-    
-    
-    // MARK: - Properties
-    
-    public var cornerRadius: CGFloat = 10
-    public var contentInset: CGFloat = 15
-    public var groupMargins: CGFloat = 15
-    
-    public var backgroundColor: UIColor?
-    public var separatorColor: UIColor?
-    public var itemsBackgroundColor: UIColor?
-    public var itemsSeparatorColor: UIColor?
-    public var buttonsBackgroundColor: UIColor?
-    public var buttonsSeparatorColor: UIColor?
-    
-    
-    // MARK: - Appearance Properties
-    
-    public static var standard = ActionSheetAppearance()
-    
-    public lazy var popover = ActionSheetPopoverAppearance(width: 300)
-    
-    
-    // MARK: - Items
-    
-    public lazy var item = ActionSheetItemAppearance()
-    public lazy var collectionItem = ActionSheetCollectionItemAppearance(copy: item)
-    public lazy var customItem = ActionSheetCustomItemAppearance(copy: item)
-    public lazy var linkItem = ActionSheetLinkItemAppearance(copy: item)
-    public lazy var multiSelectItem = ActionSheetMultiSelectItemAppearance(copy: selectItem)
-    public lazy var multiSelectToggleItem = ActionSheetMultiSelectToggleItemAppearance(copy: item)
-    public lazy var selectItem = ActionSheetSelectItemAppearance(copy: item)
-    public lazy var singleSelectItem = ActionSheetSingleSelectItemAppearance(copy: selectItem)
-    
-    
-    // MARK: - Buttons
-    
-    public lazy var cancelButton = ActionSheetCancelButtonAppearance(copy: item)
-    public lazy var dangerButton = ActionSheetDangerButtonAppearance(copy: item)
-    public lazy var okButton = ActionSheetOkButtonAppearance(copy: item)
-    
-    
-    // MARK: - Titles
-    
-    public lazy var sectionMargin = ActionSheetSectionMarginAppearance(copy: item)
-    public lazy var sectionTitle = ActionSheetSectionTitleAppearance(copy: item)
-    public lazy var title = ActionSheetTitleAppearance(copy: item)
-}

+ 0 - 54
Carthage/Checkouts/Sheeeeeeeeet/Sheeeeeeeeet/Appearance/ActionSheetItemAppearance.swift

@@ -1,54 +0,0 @@
-//
-//  ActionSheetItemAppearance.swift
-//  Sheeeeeeeeet
-//
-//  Created by Daniel Saidi on 2017-11-24.
-//  Copyright © 2017 Daniel Saidi. All rights reserved.
-//
-
-import UIKit
-
-open class ActionSheetItemAppearance {
-    
-    
-    // MARK: - Initialization
-    
-    public init() {}
-    
-    public init(copy: ActionSheetItemAppearance) {
-        backgroundColor = copy.backgroundColor
-        font = copy.font
-        height = copy.height
-        separatorInsets = copy.separatorInsets
-        textColor = copy.textColor
-        tintColor = copy.tintColor
-        subtitleFont = copy.subtitleFont
-        subtitleTextColor = copy.subtitleTextColor
-    }
-    
-    
-    // MARK: - Properties
-    
-    public var backgroundColor: UIColor?
-    public var font: UIFont?
-    public var height: CGFloat = 50
-    public var separatorInsets: UIEdgeInsets = .zero
-    public var textColor: UIColor?
-    public var tintColor: UIColor?
-    public var subtitleFont: UIFont?
-    public var subtitleTextColor: UIColor?
-}
-
-
-// MARK: - Public Extensions
-
-public extension ActionSheetItemAppearance {
-    
-    public static var noSeparator: UIEdgeInsets {
-        return UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 100_000)
-    }
-    
-    public func hideSeparator() {
-        separatorInsets = ActionSheetItemAppearance.noSeparator
-    }
-}

+ 0 - 28
Carthage/Checkouts/Sheeeeeeeeet/Sheeeeeeeeet/Appearance/ActionSheetPopoverAppearance.swift

@@ -1,28 +0,0 @@
-//
-//  ActionSheetPopoverAppearance.swift
-//  Sheeeeeeeeet
-//
-//  Created by Daniel Saidi on 2017-11-24.
-//  Copyright © 2017 Daniel Saidi. All rights reserved.
-//
-
-import UIKit
-
-open class ActionSheetPopoverAppearance {
-    
-    
-    // MARK: - Initialization
-    
-    public init(width: CGFloat) {
-        self.width = width
-    }
-    
-    public init(copy: ActionSheetPopoverAppearance) {
-        self.width = copy.width
-    }
-    
-    
-    // MARK: - Properties
-    
-    public var width: CGFloat
-}

+ 0 - 11
Carthage/Checkouts/Sheeeeeeeeet/Sheeeeeeeeet/Appearance/Buttons/ActionSheetButtonAppearance.swift

@@ -1,11 +0,0 @@
-//
-//  ActionSheetButtonAppearance.swift
-//  Sheeeeeeeeet
-//
-//  Created by Daniel Saidi on 2017-11-24.
-//  Copyright © 2017 Daniel Saidi. All rights reserved.
-//
-
-import UIKit
-
-open class ActionSheetButtonAppearance: ActionSheetItemAppearance {}

+ 0 - 11
Carthage/Checkouts/Sheeeeeeeeet/Sheeeeeeeeet/Appearance/Buttons/ActionSheetCancelButtonAppearance.swift

@@ -1,11 +0,0 @@
-//
-//  ActionSheetCancelButtonAppearance.swift
-//  Sheeeeeeeeet
-//
-//  Created by Daniel Saidi on 2017-11-24.
-//  Copyright © 2017 Daniel Saidi. All rights reserved.
-//
-
-import UIKit
-
-open class ActionSheetCancelButtonAppearance: ActionSheetButtonAppearance {}

+ 0 - 22
Carthage/Checkouts/Sheeeeeeeeet/Sheeeeeeeeet/Appearance/Buttons/ActionSheetDangerButtonAppearance.swift

@@ -1,22 +0,0 @@
-//
-//  ActionSheetDangerButtonAppearance.swift
-//  Sheeeeeeeeet
-//
-//  Created by Daniel Saidi on 2017-11-27.
-//  Copyright © 2017 Daniel Saidi. All rights reserved.
-//
-
-import UIKit
-
-open class ActionSheetDangerButtonAppearance: ActionSheetButtonAppearance {
-    
-    public override init() {
-        super.init()
-        textColor = .red
-    }
-    
-    public override init(copy: ActionSheetItemAppearance) {
-        super.init(copy: copy)
-        textColor = .red
-    }
-}

+ 0 - 11
Carthage/Checkouts/Sheeeeeeeeet/Sheeeeeeeeet/Appearance/Buttons/ActionSheetOkButtonAppearance.swift

@@ -1,11 +0,0 @@
-//
-//  ActionSheetOkButtonAppearance.swift
-//  Sheeeeeeeeet
-//
-//  Created by Daniel Saidi on 2017-11-24.
-//  Copyright © 2017 Daniel Saidi. All rights reserved.
-//
-
-import UIKit
-
-open class ActionSheetOkButtonAppearance: ActionSheetButtonAppearance {}

+ 0 - 11
Carthage/Checkouts/Sheeeeeeeeet/Sheeeeeeeeet/Appearance/Items/ActionSheetCollectionItemAppearance.swift

@@ -1,11 +0,0 @@
-//
-//  ActionSheetCollectionItemAppearance.swift
-//  SheeeeeeeeetExample
-//
-//  Created by Jonas Ullström (ullstrm) on 2018-02-23.
-//  Copyright © 2018 Jonas Ullström. All rights reserved.
-//
-
-import Foundation
-
-open class ActionSheetCollectionItemAppearance: ActionSheetItemAppearance {}

+ 0 - 11
Carthage/Checkouts/Sheeeeeeeeet/Sheeeeeeeeet/Appearance/Items/ActionSheetCustomItemAppearance.swift

@@ -1,11 +0,0 @@
-//
-//  ActionSheetCustomItemAppearance.swift
-//  Sheeeeeeeeet
-//
-//  Created by Daniel Saidi on 2018-10-08.
-//  Copyright © 2018 Daniel Saidi. All rights reserved.
-//
-
-import Foundation
-
-open class ActionSheetCustomItemAppearance: ActionSheetItemAppearance {}

+ 0 - 30
Carthage/Checkouts/Sheeeeeeeeet/Sheeeeeeeeet/Appearance/Items/ActionSheetLinkItemAppearance.swift

@@ -1,30 +0,0 @@
-//
-//  ActionSheetLinkItemAppearance.swift
-//  Sheeeeeeeeet
-//
-//  Created by Daniel Saidi on 2017-11-24.
-//  Copyright © 2017 Daniel Saidi. All rights reserved.
-//
-
-import UIKit
-
-open class ActionSheetLinkItemAppearance: ActionSheetItemAppearance {
-    
-    
-    // MARK: - Initialization
-    
-    public override init() {
-        super.init()
-    }
-    
-    public override init(copy: ActionSheetItemAppearance) {
-        super.init(copy: copy)
-        let copy = copy as? ActionSheetLinkItemAppearance
-        linkIcon = copy?.linkIcon
-    }
-    
-    
-    // MARK: - Properties
-    
-    public var linkIcon: UIImage?
-}

+ 0 - 11
Carthage/Checkouts/Sheeeeeeeeet/Sheeeeeeeeet/Appearance/Items/ActionSheetMultiSelectItemAppearance.swift

@@ -1,11 +0,0 @@
-//
-//  ActionSheetMultiSelectItemAppearance.swift
-//  Sheeeeeeeeet
-//
-//  Created by Daniel Saidi on 2018-03-31.
-//  Copyright © 2018 Daniel Saidi. All rights reserved.
-//
-
-import Foundation
-
-open class ActionSheetMultiSelectItemAppearance: ActionSheetSelectItemAppearance {}

+ 0 - 32
Carthage/Checkouts/Sheeeeeeeeet/Sheeeeeeeeet/Appearance/Items/ActionSheetMultiSelectToggleItemAppearance.swift

@@ -1,32 +0,0 @@
-//
-//  ActionSheetMultiSelectToggleItemAppearance.swift
-//  Sheeeeeeeeet
-//
-//  Created by Daniel Saidi on 2018-03-31.
-//  Copyright © 2018 Daniel Saidi. All rights reserved.
-//
-
-import UIKit
-
-open class ActionSheetMultiSelectToggleItemAppearance: ActionSheetItemAppearance {
-    
-    
-    // MARK: - Initialization
-    
-    public override init() {
-        super.init()
-    }
-    
-    public override init(copy: ActionSheetItemAppearance) {
-        super.init(copy: copy)
-        let copy = copy as? ActionSheetMultiSelectToggleItemAppearance
-        deselectAllTextColor = copy?.deselectAllTextColor
-        selectAllTextColor = copy?.selectAllTextColor
-    }
-    
-    
-    // MARK: - Properties
-    
-    public var deselectAllTextColor: UIColor?
-    public var selectAllTextColor: UIColor?
-}

+ 0 - 53
Carthage/Checkouts/Sheeeeeeeeet/Sheeeeeeeeet/Appearance/Items/ActionSheetSelectItemAppearance.swift

@@ -1,53 +0,0 @@
-//
-//  ActionSheetSelectItemAppearance.swift
-//  Sheeeeeeeeet
-//
-//  Created by Daniel Saidi on 2017-11-24.
-//  Copyright © 2017 Daniel Saidi. All rights reserved.
-//
-
-/*
- 
- This appearance inherits the base appearance and applies to
- select items. The additional properties are applied when an
- item is selected:
- 
- * `selectedIcon` is displayed rightmost, e.g. a checkmark
- * `selectedTextColor` is applied to the text (duh)
- * `selectedTintColor` is applied to both icons if they are rendered as template images
- * `selectedIconTintColor` can override `selectedTintColor` for the selected icon
- 
- */
-
-import UIKit
-
-open class ActionSheetSelectItemAppearance: ActionSheetItemAppearance {
-    
-    
-    // MARK: - Initialization
-    
-    public override init() {
-        super.init()
-    }
-    
-    public override init(copy: ActionSheetItemAppearance) {
-        super.init(copy: copy)
-        selectedTextColor = copy.textColor
-        selectedTintColor = copy.tintColor
-        let copy = copy as? ActionSheetSelectItemAppearance
-        selectedIcon = copy?.selectedIcon
-        selectedTextColor = copy?.selectedTextColor ?? selectedTextColor
-        selectedTintColor = copy?.selectedTintColor ?? selectedTintColor
-        selectedIconTintColor = copy?.selectedIconTintColor ?? selectedTintColor
-        unselectedIcon = copy?.unselectedIcon
-    }
-    
-    
-    // MARK: - Properties
-    
-    public var selectedIcon: UIImage?
-    public var selectedIconTintColor: UIColor?
-    public var selectedTextColor: UIColor?
-    public var selectedTintColor: UIColor?
-    public var unselectedIcon: UIImage?
-}

+ 0 - 11
Carthage/Checkouts/Sheeeeeeeeet/Sheeeeeeeeet/Appearance/Items/ActionSheetSingleSelectItemAppearance.swift

@@ -1,11 +0,0 @@
-//
-//  ActionSheetSingleSelectItemAppearance.swift
-//  Sheeeeeeeeet
-//
-//  Created by Daniel Saidi on 2018-03-19.
-//  Copyright © 2018 Daniel Saidi. All rights reserved.
-//
-
-import Foundation
-
-open class ActionSheetSingleSelectItemAppearance: ActionSheetSelectItemAppearance {}

+ 0 - 25
Carthage/Checkouts/Sheeeeeeeeet/Sheeeeeeeeet/Appearance/Titles/ActionSheetSectionMarginAppearance.swift

@@ -1,25 +0,0 @@
-//
-//  ActionSheetSectionMarginAppearance.swift
-//  Sheeeeeeeeet
-//
-//  Created by Daniel Saidi on 2017-11-27.
-//  Copyright © 2017 Daniel Saidi. All rights reserved.
-//
-
-import Foundation
-
-open class ActionSheetSectionMarginAppearance: ActionSheetItemAppearance {
-    
-    
-    // MARK: - Initialization
-    
-    public override init() {
-        super.init()
-        hideSeparator()
-    }
-    
-    public override init(copy: ActionSheetItemAppearance) {
-        super.init(copy: copy)
-        hideSeparator()
-    }
-}

+ 0 - 11
Carthage/Checkouts/Sheeeeeeeeet/Sheeeeeeeeet/Appearance/Titles/ActionSheetSectionTitleAppearance.swift

@@ -1,11 +0,0 @@
-//
-//  ActionSheetSectionTitleAppearance.swift
-//  Sheeeeeeeeet
-//
-//  Created by Daniel Saidi on 2017-11-19.
-//  Copyright © 2017 Daniel Saidi. All rights reserved.
-//
-
-import Foundation
-
-open class ActionSheetSectionTitleAppearance: ActionSheetItemAppearance {}

+ 0 - 11
Carthage/Checkouts/Sheeeeeeeeet/Sheeeeeeeeet/Appearance/Titles/ActionSheetTitleAppearance.swift

@@ -1,11 +0,0 @@
-//
-//  ActionSheetTitleAppearance.swift
-//  Sheeeeeeeeet
-//
-//  Created by Daniel Saidi on 2017-11-19.
-//  Copyright © 2017 Daniel Saidi. All rights reserved.
-//
-
-import Foundation
-
-open class ActionSheetTitleAppearance: ActionSheetItemAppearance { }

+ 3 - 0
Carthage/Checkouts/Sheeeeeeeeet/Sheeeeeeeeet/Extensions/NSObject+ClassName.swift

@@ -6,6 +6,9 @@
 //  Copyright © 2017 Daniel Saidi. All rights reserved.
 //  Copyright © 2017 Daniel Saidi. All rights reserved.
 //
 //
 
 
+//  This file contains internal util functions for resolving
+//  the class name of classes and class instances.
+
 import UIKit
 import UIKit
 
 
 extension NSObject {
 extension NSObject {

+ 4 - 1
Carthage/Checkouts/Sheeeeeeeeet/Sheeeeeeeeet/Extensions/UIView+Nib.swift

@@ -6,11 +6,14 @@
 //  Copyright © 2018 Daniel Saidi. All rights reserved.
 //  Copyright © 2018 Daniel Saidi. All rights reserved.
 //
 //
 
 
+//  This file contains internal util functions for resolving
+//  the default nib of a certain view instance.
+
 import UIKit
 import UIKit
 
 
 extension UIView {
 extension UIView {
     
     
     static var defaultNib: UINib {
     static var defaultNib: UINib {
-        return UINib(nibName: className, bundle: self.bundle)
+        return UINib(nibName: className, bundle: bundle)
     }
     }
 }
 }

+ 3 - 0
Carthage/Checkouts/Sheeeeeeeeet/Sheeeeeeeeet/Extensions/UIView+Subviews.swift

@@ -6,6 +6,9 @@
 //  Copyright © 2018 Daniel Saidi. All rights reserved.
 //  Copyright © 2018 Daniel Saidi. All rights reserved.
 //
 //
 
 
+//  This file contains an internal function that can be used
+//  to add subviews in a way that lets them fill the parent.
+
 import UIKit
 import UIKit
 
 
 extension UIView {
 extension UIView {

+ 3 - 0
Carthage/Checkouts/Sheeeeeeeeet/Sheeeeeeeeet/Extensions/UIViewController+RootViewController.swift

@@ -6,6 +6,9 @@
 //  Copyright © 2017 Daniel Saidi. All rights reserved.
 //  Copyright © 2017 Daniel Saidi. All rights reserved.
 //
 //
 
 
+//  This file contains internal util functions for resolving
+//  the root view controller for the current app.
+
 import UIKit
 import UIKit
 
 
 extension UIViewController {
 extension UIViewController {

+ 2 - 2
Carthage/Checkouts/Sheeeeeeeeet/Sheeeeeeeeet/Info.plist

@@ -15,9 +15,9 @@
 	<key>CFBundlePackageType</key>
 	<key>CFBundlePackageType</key>
 	<string>FMWK</string>
 	<string>FMWK</string>
 	<key>CFBundleShortVersionString</key>
 	<key>CFBundleShortVersionString</key>
-	<string>1.1.0</string>
+	<string>1.2.2</string>
 	<key>CFBundleVersion</key>
 	<key>CFBundleVersion</key>
-	<string>1901101458</string>
+	<string>1</string>
 	<key>NSPrincipalClass</key>
 	<key>NSPrincipalClass</key>
 	<string></string>
 	<string></string>
 </dict>
 </dict>

+ 116 - 37
Carthage/Checkouts/Sheeeeeeeeet/Sheeeeeeeeet/Items/ActionSheetItem.swift

@@ -9,8 +9,47 @@
 /*
 /*
  
  
  This class represents a regular action sheet item, like the
  This class represents a regular action sheet item, like the
- ones used in UIAlertController. It has a title, an optional
- value and an optional image. All other items builds on this.
+ one used in UIAlertController. It has a title as well as an
+ optional subtitle, value and image. All other items inherit
+ this class, even if they don't make use of these properties.
+ 
+ 
+ ## Subclassing
+ 
+ You can subclass any item class and customize it in any way
+ you need. If you need your subclass to use a different cell,
+ just override `cell(for:)` to return the cell you need.
+ 
+ 
+ ## Appearance
+ 
+ Customizing the appearance of the various action sheet item
+ types in Sheeeeeeeeet (as well as of your own custom items),
+ is mainly done using the iOS appearance proxy for each item
+ cell type. For instance, to change the title text color for
+ all `ActionSheetSelectItem` instances (including subclasses),
+ type `ActionSheetSelectItem.appearance().titleColor`. It is
+ also possible to set these properties for each item as well.
+ 
+ While most appearance is modified on a cell level, some are
+ not. For instance, some views in `Views` have apperances of
+ their own (e.g. `ActionSheetHeaderView.cornerRadius`). This
+ means that you can change more than cell appearance. Have a
+ look at the readme for more info on what you can customize.
+ 
+ Action sheet insets, margins and widths are not part of the
+ appearance model, but have to be changed for each sheet. If
+ you want to change these values for each sheet in youer app,
+ I recommend subclassing `ActionSheet` and set these values.
+ 
+ Neither item heights are part of the appearance model. Item
+ heights are instead changed by setting the static height of
+ each item type, e.g. `ActionSheetTitleItem.height = 20`. It
+ is not part of the cell appearance model since an item must
+ know about the height before it creates any cells.
+ 
+ 
+ ## Tap behavior
  
  
  The default tap behavior of action sheet items is "dismiss",
  The default tap behavior of action sheet items is "dismiss",
  which means that the action sheet will dismiss itself after
  which means that the action sheet will dismiss itself after
@@ -18,16 +57,23 @@
  don't want the action sheet to be dismissed when an item is
  don't want the action sheet to be dismissed when an item is
  tapped. Some item types uses `.none` by default.
  tapped. Some item types uses `.none` by default.
  
  
- The item appearance is set by the sheet. It either uses the
- global appearance or an individual instance. To use a fully
- custom appearances for a single action sheet item, just set
- the `customAppearance` property.
- 
  */
  */
 
 
 import UIKit
 import UIKit
 
 
 open class ActionSheetItem: NSObject {
 open class ActionSheetItem: NSObject {
+
+    
+    // MARK: - Deprecated - Remove in 1.4.0 ****************
+    @available(*, deprecated, message: "appearance will be removed in 1.4.0. Use the new appearance model instead.")
+    public lazy internal(set) var appearance = ActionSheetItemAppearance(copy: ActionSheetAppearance.standard.item)
+    @available(*, deprecated, message: "customAppearance will be removed in 1.4.0. Use the new appearance model instead.")
+    public var customAppearance: ActionSheetItemAppearance?
+    @available(*, deprecated, message: "applyAppearance will be removed in 1.4.0. Use the new appearance model instead.")
+    open func applyAppearance(_ appearance: ActionSheetAppearance) { self.appearance = customAppearance ?? ActionSheetItemAppearance(copy: appearance.item) }
+    @available(*, deprecated, message: "applyAppearance(to:) will be removed in 1.4.0. Use the new appearance model instead.")
+    open func applyAppearance(to cell: UITableViewCell) { applyLegacyAppearance(to: cell) }
+    // MARK: - Deprecated - Remove in 1.4.0 ****************
     
     
     
     
     // MARK: - Initialization
     // MARK: - Initialization
@@ -38,15 +84,13 @@ open class ActionSheetItem: NSObject {
         value: Any? = nil,
         value: Any? = nil,
         image: UIImage? = nil,
         image: UIImage? = nil,
         tapBehavior: TapBehavior = .dismiss) {
         tapBehavior: TapBehavior = .dismiss) {
-        let appearance = ActionSheetAppearance.standard.item
         self.title = title
         self.title = title
         self.subtitle = subtitle
         self.subtitle = subtitle
         self.value = value
         self.value = value
         self.image = image
         self.image = image
         self.tapBehavior = tapBehavior
         self.tapBehavior = tapBehavior
-        self.appearance = ActionSheetItemAppearance(copy: appearance)
+        self.cellStyle = subtitle == nil ? .default : .value1
         super.init()
         super.init()
-        if subtitle != nil { self.cellStyle = .value1}
     }
     }
     
     
     
     
@@ -59,7 +103,6 @@ open class ActionSheetItem: NSObject {
 
 
     // MARK: - Properties
     // MARK: - Properties
     
     
-    public internal(set) var appearance: ActionSheetItemAppearance
     public var image: UIImage?
     public var image: UIImage?
     public var subtitle: String?
     public var subtitle: String?
     public var tapBehavior: TapBehavior
     public var tapBehavior: TapBehavior
@@ -67,40 +110,76 @@ open class ActionSheetItem: NSObject {
     public var value: Any?
     public var value: Any?
     
     
     public var cellReuseIdentifier: String { return className }
     public var cellReuseIdentifier: String { return className }
-    public var cellStyle: UITableViewCell.CellStyle = .default
-    public var customAppearance: ActionSheetItemAppearance?
+    public var cellStyle: UITableViewCell.CellStyle
     
     
     
     
-    // MARK: - Functions
+    // MARK: - Height Logic
+    
+    private static var heights = [String: CGFloat]()
     
     
-    open func applyAppearance(_ appearance: ActionSheetAppearance) {
-        self.appearance = customAppearance ?? ActionSheetItemAppearance(copy: appearance.item)
+    public static var height: CGFloat {
+        get { return heights[className] ?? 50 }
+        set { heights[className] = newValue }
     }
     }
     
     
-    open func applyAppearance(to cell: UITableViewCell) {
-        if let color = appearance.backgroundColor {
-            cell.backgroundColor = color
-        }
-        cell.imageView?.image = image
-        cell.selectionStyle = .default
-        cell.separatorInset = appearance.separatorInsets
-        cell.tintColor = appearance.tintColor
-        cell.textLabel?.text = title
-        cell.textLabel?.textAlignment = .left
-        cell.textLabel?.textColor = appearance.textColor
-        cell.textLabel?.font = appearance.font
-        cell.detailTextLabel?.text = subtitle
-        cell.detailTextLabel?.font = appearance.subtitleFont
-        cell.detailTextLabel?.textColor = appearance.subtitleTextColor
+    public var height: CGFloat {
+        return type(of: self).height
     }
     }
     
     
-    open func cell(for tableView: UITableView) -> UITableViewCell {
-        let id = cellReuseIdentifier
-        let cell = tableView.dequeueReusableCell(withIdentifier: id) as? ActionSheetItemCell
-            ?? ActionSheetItemCell(style: cellStyle, reuseIdentifier: id)
-        applyAppearance(to: cell)
-        return cell
+    
+    // MARK: - Functions
+    
+    open func cell(for tableView: UITableView) -> ActionSheetItemCell {
+        return ActionSheetItemCell(style: cellStyle, reuseIdentifier: cellReuseIdentifier)
     }
     }
     
     
     open func handleTap(in actionSheet: ActionSheet) {}
     open func handleTap(in actionSheet: ActionSheet) {}
 }
 }
+
+
+// MARK: -
+
+open class ActionSheetItemCell: UITableViewCell {
+    
+    
+    // MARK: - Layout
+    
+    open override func didMoveToWindow() {
+        super.didMoveToWindow()
+        refresh()
+    }
+    
+    
+    // MARK: - Appearance Properties
+    
+    @objc public dynamic var titleColor: UIColor?
+    @objc public dynamic var titleFont: UIFont?
+    @objc public dynamic var subtitleColor: UIColor?
+    @objc public dynamic var subtitleFont: UIFont?
+    
+    
+    // MARK: - Private Properties
+    
+    public private(set) weak var item: ActionSheetItem?
+    
+    
+    // MARK: - Functions
+    
+    open func refresh() {
+        guard let item = item else { return }
+        imageView?.image = item.image
+        selectionStyle = item.tapBehavior == .none ? .none : .default
+        textLabel?.font = titleFont
+        textLabel?.text = item.title
+        textLabel?.textAlignment = .left
+        textLabel?.textColor = titleColor
+        detailTextLabel?.font = subtitleFont
+        detailTextLabel?.text = item.subtitle
+        detailTextLabel?.textColor = subtitleColor
+    }
+    
+    func refresh(with item: ActionSheetItem) {
+        self.item = item
+        refresh()
+    }
+}

+ 21 - 7
Carthage/Checkouts/Sheeeeeeeeet/Sheeeeeeeeet/Items/Buttons/ActionSheetButton.swift

@@ -10,7 +10,7 @@
  
  
  This class is a base class for all action sheet buttons. It
  This class is a base class for all action sheet buttons. It
  is not intended to be used directly. Instead, use the built
  is not intended to be used directly. Instead, use the built
- in buttons or subclass it to create your own button type.
+ in buttons or subclass it to create your own buttons.
  
  
  */
  */
 
 
@@ -19,6 +19,14 @@ import UIKit
 open class ActionSheetButton: ActionSheetItem {
 open class ActionSheetButton: ActionSheetItem {
     
     
     
     
+    // MARK: - Deprecated - Remove in 1.4.0 ****************
+    @available(*, deprecated, message: "applyAppearance will be removed in 1.4.0. Use the new appearance model instead.")
+    open override func applyAppearance(_ appearance: ActionSheetAppearance) {
+        self.appearance = customAppearance ?? ActionSheetButtonAppearance(copy: appearance.okButton)
+    }
+    // MARK: - Deprecated - Remove in 1.4.0 ****************
+    
+    
     // MARK: - Initialization
     // MARK: - Initialization
     
     
     public init(title: String, value: Any?) {
     public init(title: String, value: Any?) {
@@ -39,18 +47,24 @@ open class ActionSheetButton: ActionSheetItem {
     
     
     // MARK: - Functions
     // MARK: - Functions
     
     
-    open override func applyAppearance(_ appearance: ActionSheetAppearance) {
-        self.appearance = customAppearance ?? ActionSheetButtonAppearance(copy: appearance.okButton)
+    open override func cell(for tableView: UITableView) -> ActionSheetItemCell {
+        return ActionSheetButtonCell(style: .default, reuseIdentifier: cellReuseIdentifier)
     }
     }
+}
+
+
+// MARK: -
+
+open class ActionSheetButtonCell: ActionSheetItemCell {
     
     
-    open override func applyAppearance(to cell: UITableViewCell) {
-        super.applyAppearance(to: cell)
-        cell.textLabel?.textAlignment = .center
+    open override func refresh() {
+        super.refresh()
+        textLabel?.textAlignment = .center
     }
     }
 }
 }
 
 
 
 
-// MARK: - ActionSheetItem Extensions
+// MARK: - Button Extensions
 
 
 public extension ActionSheetItem {
 public extension ActionSheetItem {
     
     

+ 16 - 3
Carthage/Checkouts/Sheeeeeeeeet/Sheeeeeeeeet/Items/Buttons/ActionSheetCancelButton.swift

@@ -11,7 +11,7 @@
  Cancel buttons have no special behavior, but can be used in
  Cancel buttons have no special behavior, but can be used in
  sheets where a user applies changes by tapping an OK button.
  sheets where a user applies changes by tapping an OK button.
  
  
- The value of a cancel button is `ButtonType.cancel`.
+ The value of a cancel button is `.cancel`.
  
  
  */
  */
 
 
@@ -20,6 +20,14 @@ import UIKit
 open class ActionSheetCancelButton: ActionSheetButton {
 open class ActionSheetCancelButton: ActionSheetButton {
     
     
     
     
+    // MARK: - Deprecated - Remove in 1.4.0 ****************
+    @available(*, deprecated, message: "applyAppearance will be removed in 1.4.0. Use the new appearance model instead.")
+    open override func applyAppearance(_ appearance: ActionSheetAppearance) {
+        self.appearance = customAppearance ?? ActionSheetCancelButtonAppearance(copy: appearance.cancelButton)
+    }
+    // MARK: - Deprecated - Remove in 1.4.0 ****************
+    
+    
     // MARK: - Initialization
     // MARK: - Initialization
     
     
     public init(title: String) {
     public init(title: String) {
@@ -29,7 +37,12 @@ open class ActionSheetCancelButton: ActionSheetButton {
     
     
     // MARK: - Functions
     // MARK: - Functions
     
     
-    open override func applyAppearance(_ appearance: ActionSheetAppearance) {
-        self.appearance = customAppearance ?? ActionSheetCancelButtonAppearance(copy: appearance.cancelButton)
+    open override func cell(for tableView: UITableView) -> ActionSheetItemCell {
+        return ActionSheetCancelButtonCell(style: .default, reuseIdentifier: cellReuseIdentifier)
     }
     }
 }
 }
+
+
+// MARK: - 
+
+open class ActionSheetCancelButtonCell: ActionSheetButtonCell {}

+ 18 - 4
Carthage/Checkouts/Sheeeeeeeeet/Sheeeeeeeeet/Items/Buttons/ActionSheetDangerButton.swift

@@ -10,9 +10,10 @@
  
  
  Danger buttons have no special behavior, but can be used to
  Danger buttons have no special behavior, but can be used to
  indicate that the effect of the action sheet is destructive.
  indicate that the effect of the action sheet is destructive.
- They are basically just OK buttons with a "red alert" style.
+ They should be styled as "dangerous" (e.g. red text), using
+ the appearance proxy.
  
  
- The value of a danger button is `ButtonType.ok`.
+ The value of a danger button is `.ok`.
  
  
  */
  */
 
 
@@ -21,9 +22,22 @@ import UIKit
 open class ActionSheetDangerButton: ActionSheetOkButton {
 open class ActionSheetDangerButton: ActionSheetOkButton {
     
     
     
     
-    // MARK: - Functions
-    
+    // MARK: - Deprecated - Remove in 1.4.0 ****************
+    @available(*, deprecated, message: "applyAppearance will be removed in 1.4.0. Use the new appearance model instead.")
     open override func applyAppearance(_ appearance: ActionSheetAppearance) {
     open override func applyAppearance(_ appearance: ActionSheetAppearance) {
         self.appearance = customAppearance ?? ActionSheetDangerButtonAppearance(copy: appearance.dangerButton)
         self.appearance = customAppearance ?? ActionSheetDangerButtonAppearance(copy: appearance.dangerButton)
     }
     }
+    // MARK: - Deprecated - Remove in 1.4.0 ****************
+    
+    
+    // MARK: - Functions
+    
+    open override func cell(for tableView: UITableView) -> ActionSheetItemCell {
+        return ActionSheetDangerButtonCell(style: .default, reuseIdentifier: cellReuseIdentifier)
+    }
 }
 }
+
+
+// MARK: -
+
+open class ActionSheetDangerButtonCell: ActionSheetButtonCell {}

+ 17 - 4
Carthage/Checkouts/Sheeeeeeeeet/Sheeeeeeeeet/Items/Buttons/ActionSheetOkButton.swift

@@ -9,9 +9,9 @@
 /*
 /*
  
  
  OK buttons have no special behavior, but can be used when a
  OK buttons have no special behavior, but can be used when a
- user should apply action sheet changes by tapping an button.
+ user should apply action sheet changes by tapping a button.
  
  
- The value of an OK button is `ButtonType.ok`.
+ The value of an OK button is `.ok`.
  
  
  */
  */
 
 
@@ -20,6 +20,14 @@ import UIKit
 open class ActionSheetOkButton: ActionSheetButton {
 open class ActionSheetOkButton: ActionSheetButton {
     
     
     
     
+    // MARK: - Deprecated - Remove in 1.4.0 ****************
+    @available(*, deprecated, message: "applyAppearance will be removed in 1.4.0. Use the new appearance model instead.")
+    open override func applyAppearance(_ appearance: ActionSheetAppearance) {
+        self.appearance = customAppearance ?? ActionSheetOkButtonAppearance(copy: appearance.okButton)
+    }
+    // MARK: - Deprecated - Remove in 1.4.0 ****************
+    
+    
     // MARK: - Initialization
     // MARK: - Initialization
     
     
     public init(title: String) {
     public init(title: String) {
@@ -29,7 +37,12 @@ open class ActionSheetOkButton: ActionSheetButton {
     
     
     // MARK: - Functions
     // MARK: - Functions
     
     
-    open override func applyAppearance(_ appearance: ActionSheetAppearance) {
-        self.appearance = customAppearance ?? ActionSheetOkButtonAppearance(copy: appearance.okButton)
+    open override func cell(for tableView: UITableView) -> ActionSheetItemCell {
+        return ActionSheetOkButtonCell(style: .default, reuseIdentifier: cellReuseIdentifier)
     }
     }
 }
 }
+
+
+// MARK: - 
+
+open class ActionSheetOkButtonCell: ActionSheetButtonCell {}

+ 60 - 15
Carthage/Checkouts/Sheeeeeeeeet/Sheeeeeeeeet/Items/Items/ActionSheetCollectionItem.swift

@@ -17,11 +17,29 @@
  action sheet items. If you look at `cell(for: ...)`, you'll
  action sheet items. If you look at `cell(for: ...)`, you'll
  see that it uses `ActionSheetCollectionItemCell` for its id.
  see that it uses `ActionSheetCollectionItemCell` for its id.
  
  
+ TODO: Unit test
+ 
  */
  */
 
 
 import Foundation
 import Foundation
 
 
-open class ActionSheetCollectionItem<T>: ActionSheetItem, UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout where T: ActionSheetCollectionItemContentCell {
+open class ActionSheetCollectionItem<T: ActionSheetCollectionItemContentCell>: ActionSheetItem, UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout {
+    
+    
+    // MARK: - Deprecated - Remove in 1.4.0 ****************
+    @available(*, deprecated, message: "applyAppearance will be removed in 1.4.0. Use the new appearance model instead.")
+    open override func applyAppearance(_ appearance: ActionSheetAppearance) {
+        super.applyAppearance(appearance)
+        self.appearance = ActionSheetCollectionItemAppearance(copy: appearance.collectionItem)
+        self.appearance.height = T.defaultSize.height + T.topInset + T.bottomInset + 0.5
+    }
+    @available(*, deprecated, message: "applyAppearance(to:) will be removed in 1.4.0. Use the new appearance model instead.")
+    open override func applyAppearance(to cell: UITableViewCell) {
+        super.applyAppearance(to: cell)
+        guard let itemCell = cell as? ActionSheetCollectionItemCell else { return }
+        itemCell.setup(withNib: T.nib, owner: self)
+    }
+    // MARK: - Deprecated - Remove in 1.4.0 ****************
     
     
     
     
     // MARK: - Initialization
     // MARK: - Initialization
@@ -46,6 +64,7 @@ open class ActionSheetCollectionItem<T>: ActionSheetItem, UICollectionViewDataSo
     
     
     // MARK: - Properties
     // MARK: - Properties
     
     
+    public override var height: CGFloat { return T.defaultSize.height }
     public let itemCellType: T.Type
     public let itemCellType: T.Type
     public let itemCount: Int
     public let itemCount: Int
     public private(set) var selectionAction: CellAction
     public private(set) var selectionAction: CellAction
@@ -54,21 +73,11 @@ open class ActionSheetCollectionItem<T>: ActionSheetItem, UICollectionViewDataSo
     
     
     // MARK: - Functions
     // MARK: - Functions
     
     
-    open override func applyAppearance(_ appearance: ActionSheetAppearance) {
-        super.applyAppearance(appearance)
-        self.appearance = ActionSheetCollectionItemAppearance(copy: appearance.collectionItem)
-        self.appearance.height = T.defaultSize.height + T.topInset + T.bottomInset + 0.5
-    }
-    
-    open override func applyAppearance(to cell: UITableViewCell) {
-        super.applyAppearance(to: cell)
-        guard let itemCell = cell as? ActionSheetCollectionItemCell else { return }
-        itemCell.setup(withNib: T.nib, owner: self)
-    }
-    
-    open override func cell(for tableView: UITableView) -> UITableViewCell {
+    open override func cell(for tableView: UITableView) -> ActionSheetItemCell {
         tableView.register(ActionSheetCollectionItemCell.nib, forCellReuseIdentifier: cellReuseIdentifier)
         tableView.register(ActionSheetCollectionItemCell.nib, forCellReuseIdentifier: cellReuseIdentifier)
-        return super.cell(for: tableView)
+        let cell = tableView.dequeueReusableCell(withIdentifier: cellReuseIdentifier)
+        guard let typedCell = cell as? ActionSheetCollectionItemCell else { fatalError("Invalid cell type created by superclass") }
+        return typedCell
     }
     }
     
     
     open func extendSelectionAction(toReload actionSheet: ActionSheet) {
     open func extendSelectionAction(toReload actionSheet: ActionSheet) {
@@ -127,3 +136,39 @@ open class ActionSheetCollectionItem<T>: ActionSheetItem, UICollectionViewDataSo
         return 0
         return 0
     }
     }
 }
 }
+
+
+// MARK: -
+
+open class ActionSheetCollectionItemCell: ActionSheetItemCell {
+    
+    
+    // MARK: - Properties
+    
+    static let itemCellIdentifier = ActionSheetCollectionItemCell.className
+    
+    static let nib = ActionSheetCollectionItemCell.defaultNib
+    
+    
+    // MARK: - Outlets
+    
+    @IBOutlet weak var collectionView: UICollectionView! {
+        didSet {
+            let flow = UICollectionViewFlowLayout()
+            flow.scrollDirection = .horizontal
+            collectionView.collectionViewLayout = flow
+        }
+    }
+    
+    
+    // MARK: - Functions
+    
+    func setup(withNib nib: UINib, owner: UICollectionViewDataSource & UICollectionViewDelegate) {
+        let id = ActionSheetCollectionItemCell.itemCellIdentifier
+        collectionView.contentInset = .zero
+        collectionView.register(nib, forCellWithReuseIdentifier: id)
+        collectionView.dataSource = owner
+        collectionView.delegate = owner
+        collectionView.reloadData()
+    }
+}

+ 28 - 14
Carthage/Checkouts/Sheeeeeeeeet/Sheeeeeeeeet/Items/Items/ActionSheetCustomItem.swift

@@ -8,16 +8,27 @@
 
 
 /*
 /*
  
  
- Custom items can be used to present any view in your sheets.
- Just specify the view type you want to use and make sure it
- inherits `ActionSheetItemCell`, and that it also implements
- `ActionSheetCustomItemCell`.
+ Custom items can be used to present any views in your sheet.
+ It can use any view that inherits `ActionSheetItemCell` and
+ implements `ActionSheetCustomItemCell`.
+ 
+ TODO: Unit test
  
  
  */
  */
 
 
 import UIKit
 import UIKit
 
 
-public class ActionSheetCustomItem<T>: ActionSheetItem where T: ActionSheetCustomItemCell {
+public class ActionSheetCustomItem<T: ActionSheetCustomItemCell>: ActionSheetItem {
+    
+    
+    // MARK: - Deprecated - Remove in 1.4.0 ****************
+    @available(*, deprecated, message: "applyAppearance will be removed in 1.4.0. Use the new appearance model instead.")
+    public override func applyAppearance(_ appearance: ActionSheetAppearance) {
+        super.applyAppearance(appearance)
+        self.appearance = ActionSheetCustomItemAppearance(copy: appearance.customItem)
+        self.appearance.height = T.defaultSize.height
+    }
+    // MARK: - Deprecated - Remove in 1.4.0 ****************
     
     
     
     
     // MARK: - Initialization
     // MARK: - Initialization
@@ -41,24 +52,27 @@ public class ActionSheetCustomItem<T>: ActionSheetItem where T: ActionSheetCusto
     
     
     // MARK: - Properties
     // MARK: - Properties
     
     
+    public override var height: CGFloat { return T.defaultSize.height }
     public let cellType: T.Type
     public let cellType: T.Type
     public let setupAction: SetupAction
     public let setupAction: SetupAction
     
     
     
     
     // MARK: - Functions
     // MARK: - Functions
     
     
-    public override func applyAppearance(_ appearance: ActionSheetAppearance) {
-        super.applyAppearance(appearance)
-        self.appearance = ActionSheetCustomItemAppearance(copy: appearance.customItem)
-        self.appearance.height = T.defaultSize.height
-    }
-    
-    open override func cell(for tableView: UITableView) -> UITableViewCell {
+    open override func cell(for tableView: UITableView) -> ActionSheetItemCell {
         tableView.register(T.nib, forCellReuseIdentifier: cellReuseIdentifier)
         tableView.register(T.nib, forCellReuseIdentifier: cellReuseIdentifier)
-        let cell = super.cell(for: tableView)
-        cell.selectionStyle = .none
+        let cell = tableView.dequeueReusableCell(withIdentifier: cellReuseIdentifier)
         guard let typedCell = cell as? T else { fatalError("Invalid cell type created by superclass") }
         guard let typedCell = cell as? T else { fatalError("Invalid cell type created by superclass") }
         setupAction(typedCell)
         setupAction(typedCell)
         return typedCell
         return typedCell
     }
     }
 }
 }
+
+
+// MARK: -
+
+public protocol ActionSheetCustomItemCell where Self: ActionSheetItemCell {
+    
+    static var nib: UINib { get }
+    static var defaultSize: CGSize { get }
+}

+ 25 - 9
Carthage/Checkouts/Sheeeeeeeeet/Sheeeeeeeeet/Items/Items/ActionSheetLinkItem.swift

@@ -18,23 +18,39 @@ import UIKit
 open class ActionSheetLinkItem: ActionSheetItem {
 open class ActionSheetLinkItem: ActionSheetItem {
     
     
     
     
-    // MARK: - Properties
-    
+    // MARK: - Deprecated - Remove in 1.4.0 ****************
+    @available(*, deprecated, message: "linkAppearance will be removed in 1.4.0. Use the new appearance model instead.")
     open var linkAppearance: ActionSheetLinkItemAppearance? {
     open var linkAppearance: ActionSheetLinkItemAppearance? {
         return appearance as? ActionSheetLinkItemAppearance
         return appearance as? ActionSheetLinkItemAppearance
     }
     }
+    @available(*, deprecated, message: "applyAppearance will be removed in 1.4.0. Use the new appearance model instead.")
+    open override func applyAppearance(_ appearance: ActionSheetAppearance) {
+        super.applyAppearance(appearance)
+        self.appearance = ActionSheetLinkItemAppearance(copy: appearance.linkItem)
+    }
+    // MARK: - Deprecated - Remove in 1.4.0 ****************
     
     
     
     
     // MARK: - Functions
     // MARK: - Functions
     
     
-    open override func applyAppearance(_ appearance: ActionSheetAppearance) {
-        super.applyAppearance(appearance)
-        self.appearance = ActionSheetLinkItemAppearance(copy: appearance.linkItem)
+    open override func cell(for tableView: UITableView) -> ActionSheetItemCell {
+        return ActionSheetLinkItemCell(style: cellStyle, reuseIdentifier: cellReuseIdentifier)
     }
     }
+}
+
+
+open class ActionSheetLinkItemCell: ActionSheetItemCell {
+    
+    
+    // MARK: - Appearance Properties
+    
+    @objc public dynamic var linkIcon: UIImage?
+    
+    
+    // MARK: - Functions
     
     
-    open override func applyAppearance(to cell: UITableViewCell) {
-        super.applyAppearance(to: cell)
-        guard let appearance = linkAppearance else { return }
-        cell.accessoryView = UIImageView(image: appearance.linkIcon)
+    open override func refresh() {
+        super.refresh()
+        accessoryView = UIImageView(image: linkIcon)
     }
     }
 }
 }

+ 14 - 3
Carthage/Checkouts/Sheeeeeeeeet/Sheeeeeeeeet/Items/Items/ActionSheetMultiSelectItem.swift

@@ -28,6 +28,15 @@ import UIKit
 open class ActionSheetMultiSelectItem: ActionSheetSelectItem {
 open class ActionSheetMultiSelectItem: ActionSheetSelectItem {
     
     
     
     
+    // MARK: - Deprecated - Remove in 1.4.0 ****************
+    @available(*, deprecated, message: "applyAppearance will be removed in 1.4.0. Use the new appearance model instead.")
+    open override func applyAppearance(_ appearance: ActionSheetAppearance) {
+        super.applyAppearance(appearance)
+        self.appearance = ActionSheetMultiSelectItemAppearance(copy: appearance.multiSelectItem)
+    }
+    // MARK: - Deprecated - Remove in 1.4.0 ****************
+    
+    
     // MARK: - Initialization
     // MARK: - Initialization
     
     
     public init(
     public init(
@@ -50,9 +59,8 @@ open class ActionSheetMultiSelectItem: ActionSheetSelectItem {
     
     
     // MARK: - Functions
     // MARK: - Functions
     
     
-    open override func applyAppearance(_ appearance: ActionSheetAppearance) {
-        super.applyAppearance(appearance)
-        self.appearance = ActionSheetMultiSelectItemAppearance(copy: appearance.multiSelectItem)
+    open override func cell(for tableView: UITableView) -> ActionSheetItemCell {
+        return ActionSheetMultiSelectItemCell(style: cellStyle, reuseIdentifier: cellReuseIdentifier)
     }
     }
     
     
     open override func handleTap(in actionSheet: ActionSheet) {
     open override func handleTap(in actionSheet: ActionSheet) {
@@ -62,3 +70,6 @@ open class ActionSheetMultiSelectItem: ActionSheetSelectItem {
         items.forEach { $0.updateState(for: actionSheet) }
         items.forEach { $0.updateState(for: actionSheet) }
     }
     }
 }
 }
+
+
+open class ActionSheetMultiSelectItemCell: ActionSheetSelectItemCell {}

+ 42 - 15
Carthage/Checkouts/Sheeeeeeeeet/Sheeeeeeeeet/Items/Items/ActionSheetMultiSelectToggleItem.swift

@@ -24,6 +24,15 @@ import UIKit
 open class ActionSheetMultiSelectToggleItem: ActionSheetItem {
 open class ActionSheetMultiSelectToggleItem: ActionSheetItem {
     
     
     
     
+    // MARK: - Deprecated - Remove in 1.4.0 ****************
+    @available(*, deprecated, message: "applyAppearance will be removed in 1.4.0. Use the new appearance model instead.")
+    open override func applyAppearance(_ appearance: ActionSheetAppearance) {
+        super.applyAppearance(appearance)
+        self.appearance = ActionSheetMultiSelectToggleItemAppearance(copy: appearance.multiSelectToggleItem)
+    }
+    // MARK: - Deprecated - Remove in 1.4.0 ****************
+    
+    
     // MARK: - Initialization
     // MARK: - Initialization
     
     
     public init(title: String, state: State, group: String, selectAllTitle: String, deselectAllTitle: String) {
     public init(title: String, state: State, group: String, selectAllTitle: String, deselectAllTitle: String) {
@@ -31,9 +40,7 @@ open class ActionSheetMultiSelectToggleItem: ActionSheetItem {
         self.state = state
         self.state = state
         self.deselectAllTitle = deselectAllTitle
         self.deselectAllTitle = deselectAllTitle
         self.selectAllTitle = selectAllTitle
         self.selectAllTitle = selectAllTitle
-        super.init(
-            title: title,
-            tapBehavior: .none)
+        super.init(title: title, tapBehavior: .none)
         cellStyle = .value1
         cellStyle = .value1
     }
     }
     
     
@@ -55,18 +62,8 @@ open class ActionSheetMultiSelectToggleItem: ActionSheetItem {
     
     
     // MARK: - Functions
     // MARK: - Functions
     
     
-    open override func applyAppearance(_ appearance: ActionSheetAppearance) {
-        super.applyAppearance(appearance)
-        self.appearance = ActionSheetMultiSelectToggleItemAppearance(copy: appearance.multiSelectToggleItem)
-    }
-    
-    open override func applyAppearance(to cell: UITableViewCell) {
-        super.applyAppearance(to: cell)
-        guard let appearance = appearance as? ActionSheetMultiSelectToggleItemAppearance else { return }
-        let isSelectAll = state == .selectAll
-        subtitle = isSelectAll ? selectAllTitle : deselectAllTitle
-        appearance.subtitleTextColor = isSelectAll ? appearance.selectAllTextColor : appearance.deselectAllTextColor
-        super.applyAppearance(to: cell)
+    open override func cell(for tableView: UITableView) -> ActionSheetItemCell {
+        return ActionSheetMultiSelectToggleItemCell(style: cellStyle, reuseIdentifier: cellReuseIdentifier)
     }
     }
     
     
     open override func handleTap(in actionSheet: ActionSheet) {
     open override func handleTap(in actionSheet: ActionSheet) {
@@ -81,6 +78,36 @@ open class ActionSheetMultiSelectToggleItem: ActionSheetItem {
     open func updateState(for actionSheet: ActionSheet) {
     open func updateState(for actionSheet: ActionSheet) {
         let selectItems = actionSheet.items.compactMap { $0 as? ActionSheetMultiSelectItem }
         let selectItems = actionSheet.items.compactMap { $0 as? ActionSheetMultiSelectItem }
         let items = selectItems.filter { $0.group == group }
         let items = selectItems.filter { $0.group == group }
+        guard items.count > 0 else { return state = .selectAll }
         state = items.contains { !$0.isSelected } ? .selectAll : .deselectAll
         state = items.contains { !$0.isSelected } ? .selectAll : .deselectAll
     }
     }
 }
 }
+
+
+// MARK: - 
+
+open class ActionSheetMultiSelectToggleItemCell: ActionSheetItemCell {
+    
+    
+    // MARK: - Appearance Properties
+    
+    @objc public dynamic var deselectAllImage: UIColor?
+    @objc public dynamic var deselectAllSubtitleColor: UIColor?
+    @objc public dynamic var deselectAllTitleColor: UIColor?
+    @objc public dynamic var selectAllImage: UIColor?
+    @objc public dynamic var selectAllSubtitleColor: UIColor?
+    @objc public dynamic var selectAllTitleColor: UIColor?
+    
+    
+    // MARK: - Public Functions
+    
+    open override func refresh() {
+        super.refresh()
+        guard let item = item as? ActionSheetMultiSelectToggleItem else { return }
+        let isSelectAll = item.state == .selectAll
+        item.subtitle = isSelectAll ? item.selectAllTitle : item.deselectAllTitle
+        titleColor = isSelectAll ? selectAllTitleColor : deselectAllTitleColor
+        subtitleColor = isSelectAll ? selectAllSubtitleColor : deselectAllSubtitleColor
+        super.refresh()
+    }
+}

+ 84 - 17
Carthage/Checkouts/Sheeeeeeeeet/Sheeeeeeeeet/Items/Items/ActionSheetSelectItem.swift

@@ -29,6 +29,15 @@ import UIKit
 open class ActionSheetSelectItem: ActionSheetItem {
 open class ActionSheetSelectItem: ActionSheetItem {
     
     
     
     
+    // MARK: - Deprecated - Remove in 1.4.0 ****************
+    @available(*, deprecated, message: "applyAppearance will be removed in 1.4.0. Use the new appearance model instead.")
+    open override func applyAppearance(_ appearance: ActionSheetAppearance) {
+        super.applyAppearance(appearance)
+        self.appearance = ActionSheetSelectItemAppearance(copy: appearance.selectItem)
+    }
+    // MARK: - Deprecated - Remove in 1.4.0 ****************
+    
+    
     // MARK: - Initialization
     // MARK: - Initialization
     
     
     public init(
     public init(
@@ -53,33 +62,91 @@ open class ActionSheetSelectItem: ActionSheetItem {
     // MARK: - Properties
     // MARK: - Properties
     
     
     open var group: String
     open var group: String
-    
     open var isSelected: Bool
     open var isSelected: Bool
     
     
-    open var selectAppearance: ActionSheetSelectItemAppearance? {
-        return appearance as? ActionSheetSelectItemAppearance
+    
+    // MARK: - Functions
+    
+    open override func cell(for tableView: UITableView) -> ActionSheetItemCell {
+        return ActionSheetSelectItemCell(style: cellStyle, reuseIdentifier: cellReuseIdentifier)
     }
     }
     
     
+    open override func handleTap(in actionSheet: ActionSheet) {
+        super.handleTap(in: actionSheet)
+        isSelected = !isSelected
+    }
+}
+
+
+// MARK: -
+
+open class ActionSheetSelectItemCell: ActionSheetItemCell {
+    
+    
+    // MARK: - Appearance Properties
+    
+    @objc public dynamic var selectedIcon: UIImage?
+    @objc public dynamic var selectedIconColor: UIColor?
+    @objc public dynamic var selectedSubtitleColor: UIColor?
+    @objc public dynamic var selectedSubtitleFont: UIFont?
+    @objc public dynamic var selectedTitleColor: UIColor?
+    @objc public dynamic var selectedTitleFont: UIFont?
+    @objc public dynamic var selectedTintColor: UIColor?
+    @objc public dynamic var unselectedIcon: UIImage?
+    @objc public dynamic var unselectedIconColor: UIColor?
+    
     
     
     // MARK: - Functions
     // MARK: - Functions
     
     
-    open override func applyAppearance(_ appearance: ActionSheetAppearance) {
-        super.applyAppearance(appearance)
-        self.appearance = ActionSheetSelectItemAppearance(copy: appearance.selectItem)
+    open override func refresh() {
+        super.refresh()
+        guard let item = item as? ActionSheetSelectItem else { return }
+        applyAccessoryView(for: item)
+        applyAccessoryViewColor(for: item)
+        applySubtitleColor(for: item)
+        applySubtitleFont(for: item)
+        applyTintColor(for: item)
+        applyTitleColor(for: item)
+        applyTitleFont(for: item)
     }
     }
+}
+
+
+private extension ActionSheetSelectItemCell {
     
     
-    open override func applyAppearance(to cell: UITableViewCell) {
-        super.applyAppearance(to: cell)
-        guard let appearance = selectAppearance else { return }
-        let accessoryImage = isSelected ? appearance.selectedIcon : appearance.unselectedIcon
-        cell.accessoryView = UIImageView(image: accessoryImage)
-        cell.accessoryView?.tintColor = isSelected ? appearance.selectedIconTintColor : appearance.tintColor
-        cell.tintColor = isSelected ? appearance.selectedTintColor : appearance.tintColor
-        cell.textLabel?.textColor = isSelected ? appearance.selectedTextColor : appearance.textColor
+    func applyAccessoryView(for item: ActionSheetSelectItem) {
+        guard let image = item.isSelected ? selectedIcon : unselectedIcon else { return }
+        accessoryView = UIImageView(image: image)
     }
     }
     
     
-    open override func handleTap(in actionSheet: ActionSheet) {
-        super.handleTap(in: actionSheet)
-        isSelected = !isSelected
+    func applyAccessoryViewColor(for item: ActionSheetSelectItem) {
+        guard let color = item.isSelected ? selectedIconColor : unselectedIconColor else { return }
+        accessoryView?.tintColor = color
+    }
+    
+    func applySubtitleColor(for item: ActionSheetSelectItem) {
+        guard let color = item.isSelected ? selectedSubtitleColor : subtitleColor else { return }
+        detailTextLabel?.textColor = color
+    }
+    
+    func applySubtitleFont(for item: ActionSheetSelectItem) {
+        guard let font = item.isSelected ? selectedSubtitleFont : subtitleFont else { return }
+        detailTextLabel?.font = font
+    }
+    
+    func applyTintColor(for item: ActionSheetSelectItem) {
+        let defaultTint = type(of: self).appearance().tintColor
+        guard let color = item.isSelected ? selectedTintColor : defaultTint else { return }
+        tintColor = color
+    }
+    
+    func applyTitleColor(for item: ActionSheetSelectItem) {
+        guard let color = item.isSelected ? selectedTitleColor : titleColor else { return }
+        textLabel?.textColor = color
+    }
+    
+    func applyTitleFont(for item: ActionSheetSelectItem) {
+        guard let font = item.isSelected ? selectedTitleFont : titleFont else { return }
+        textLabel?.font = font
     }
     }
 }
 }

+ 15 - 2
Carthage/Checkouts/Sheeeeeeeeet/Sheeeeeeeeet/Items/Items/ActionSheetSingleSelectItem.swift

@@ -23,12 +23,20 @@ import UIKit
 open class ActionSheetSingleSelectItem: ActionSheetSelectItem {
 open class ActionSheetSingleSelectItem: ActionSheetSelectItem {
     
     
     
     
-     // MARK: - Functions
-    
+    // MARK: - Deprecated - Remove in 1.4.0 ****************
+    @available(*, deprecated, message: "applyAppearance will be removed in 1.4.0. Use the new appearance model instead.")
     open override func applyAppearance(_ appearance: ActionSheetAppearance) {
     open override func applyAppearance(_ appearance: ActionSheetAppearance) {
         super.applyAppearance(appearance)
         super.applyAppearance(appearance)
         self.appearance = ActionSheetSingleSelectItemAppearance(copy: appearance.singleSelectItem)
         self.appearance = ActionSheetSingleSelectItemAppearance(copy: appearance.singleSelectItem)
     }
     }
+    // MARK: - Deprecated - Remove in 1.4.0 ****************
+    
+    
+    // MARK: - Functions
+    
+    open override func cell(for tableView: UITableView) -> ActionSheetItemCell {
+        return ActionSheetSingleSelectItemCell(style: cellStyle, reuseIdentifier: cellReuseIdentifier)
+    }
     
     
     open override func handleTap(in actionSheet: ActionSheet) {
     open override func handleTap(in actionSheet: ActionSheet) {
         super.handleTap(in: actionSheet)
         super.handleTap(in: actionSheet)
@@ -38,3 +46,8 @@ open class ActionSheetSingleSelectItem: ActionSheetSelectItem {
         isSelected = true
         isSelected = true
     }
     }
 }
 }
+
+
+// MARK: -
+
+open class ActionSheetSingleSelectItemCell: ActionSheetSelectItemCell {}

+ 15 - 7
Carthage/Checkouts/Sheeeeeeeeet/Sheeeeeeeeet/Items/Titles/ActionSheetSectionMargin.swift

@@ -19,6 +19,14 @@ import UIKit
 open class ActionSheetSectionMargin: ActionSheetItem {
 open class ActionSheetSectionMargin: ActionSheetItem {
     
     
     
     
+    // MARK: - Deprecated - Remove in 1.4.0 ****************
+    @available(*, deprecated, message: "applyAppearance will be removed in 1.4.0. Use the new appearance model instead.")
+    open override func applyAppearance(_ appearance: ActionSheetAppearance) {
+        self.appearance = ActionSheetSectionMarginAppearance(copy: appearance.sectionMargin)
+    }
+    // MARK: - Deprecated - Remove in 1.4.0 ****************
+    
+    
     // MARK: - Initialization
     // MARK: - Initialization
     
     
     public init() {
     public init() {
@@ -28,12 +36,12 @@ open class ActionSheetSectionMargin: ActionSheetItem {
     
     
     // MARK: - Functions
     // MARK: - Functions
     
     
-    open override func applyAppearance(_ appearance: ActionSheetAppearance) {
-        self.appearance = ActionSheetSectionMarginAppearance(copy: appearance.sectionMargin)
-    }
-    
-    open override func applyAppearance(to cell: UITableViewCell) {
-        super.applyAppearance(to: cell)
-        cell.selectionStyle = .none
+    open override func cell(for tableView: UITableView) -> ActionSheetItemCell {
+        return ActionSheetSectionMarginCell(style: cellStyle, reuseIdentifier: cellReuseIdentifier)
     }
     }
 }
 }
+
+
+// MARK: -
+
+open class ActionSheetSectionMarginCell: ActionSheetItemCell {}

+ 15 - 8
Carthage/Checkouts/Sheeeeeeeeet/Sheeeeeeeeet/Items/Titles/ActionSheetSectionTitle.swift

@@ -23,22 +23,29 @@ import UIKit
 open class ActionSheetSectionTitle: ActionSheetItem {
 open class ActionSheetSectionTitle: ActionSheetItem {
     
     
     
     
+    // MARK: - Deprecated - Remove in 1.4.0 ****************
+    @available(*, deprecated, message: "applyAppearance will be removed in 1.4.0. Use the new appearance model instead.")
+    open override func applyAppearance(_ appearance: ActionSheetAppearance) {
+        self.appearance = ActionSheetSectionTitleAppearance(copy: appearance.sectionTitle)
+    }
+    // MARK: - Deprecated - Remove in 1.4.0 ****************
+    
+    
     // MARK: - Initialization
     // MARK: - Initialization
     
     
     public init(title: String, subtitle: String? = nil) {
     public init(title: String, subtitle: String? = nil) {
         super.init(title: title, subtitle: subtitle, tapBehavior: .none)
         super.init(title: title, subtitle: subtitle, tapBehavior: .none)
-        cellStyle = .value1
     }
     }
     
     
     
     
     // MARK: - Functions
     // MARK: - Functions
     
     
-    open override func applyAppearance(_ appearance: ActionSheetAppearance) {
-        self.appearance = ActionSheetSectionTitleAppearance(copy: appearance.sectionTitle)
-    }
-    
-    open override func applyAppearance(to cell: UITableViewCell) {
-        super.applyAppearance(to: cell)
-        cell.selectionStyle = .none
+    open override func cell(for tableView: UITableView) -> ActionSheetItemCell {
+        return ActionSheetSectionTitleCell(style: cellStyle, reuseIdentifier: cellReuseIdentifier)
     }
     }
 }
 }
+
+
+// MARK: -
+
+open class ActionSheetSectionTitleCell: ActionSheetItemCell {}

+ 19 - 6
Carthage/Checkouts/Sheeeeeeeeet/Sheeeeeeeeet/Items/Titles/ActionSheetTitle.swift

@@ -19,6 +19,14 @@ import UIKit
 open class ActionSheetTitle: ActionSheetItem {
 open class ActionSheetTitle: ActionSheetItem {
     
     
     
     
+    // MARK: - Deprecated - Remove in 1.4.0 ****************
+    @available(*, deprecated, message: "applyAppearance will be removed in 1.4.0. Use the new appearance model instead.")
+    open override func applyAppearance(_ appearance: ActionSheetAppearance) {
+        self.appearance = ActionSheetTitleAppearance(copy: appearance.title)
+    }
+    // MARK: - Deprecated - Remove in 1.4.0 ****************
+    
+    
     // MARK: - Initialization
     // MARK: - Initialization
     
     
     public init(title: String) {
     public init(title: String) {
@@ -28,13 +36,18 @@ open class ActionSheetTitle: ActionSheetItem {
     
     
     // MARK: - Functions
     // MARK: - Functions
     
     
-    open override func applyAppearance(_ appearance: ActionSheetAppearance) {
-        self.appearance = ActionSheetTitleAppearance(copy: appearance.title)
+    open override func cell(for tableView: UITableView) -> ActionSheetItemCell {
+        return ActionSheetTitleCell(style: cellStyle, reuseIdentifier: cellReuseIdentifier)
     }
     }
+}
+
+
+// MARK: -
+
+open class ActionSheetTitleCell: ActionSheetItemCell {
     
     
-    open override func applyAppearance(to cell: UITableViewCell) {
-        super.applyAppearance(to: cell)
-        cell.selectionStyle = .none
-        cell.textLabel?.textAlignment = .center
+    open override func refresh() {
+        super.refresh()
+        textLabel?.textAlignment = .center
     }
     }
 }
 }

+ 6 - 16
Carthage/Checkouts/Sheeeeeeeeet/Sheeeeeeeeet/Presenters/ActionSheetPopoverPresenter.swift

@@ -8,8 +8,8 @@
 
 
 /*
 /*
  
  
- This presenter will present action sheets as popovers, just
- as a regular UIAlertController is displayed on the iPad.
+ This presenter presents action sheets in a popover, just as
+ regular UIAlertControllers are displayed on an iPad.
  
  
  Since popovers have an arrow that should use the same color
  Since popovers have an arrow that should use the same color
  as the rest of the popover view, this presenter will remove
  as the rest of the popover view, this presenter will remove
@@ -28,8 +28,8 @@ open class ActionSheetPopoverPresenter: NSObject, ActionSheetPresenter {
     open var events = ActionSheetPresenterEvents()
     open var events = ActionSheetPresenterEvents()
     open var isDismissableWithTapOnBackground = true
     open var isDismissableWithTapOnBackground = true
     
     
-    private var actionSheet: ActionSheet?
-    private weak var popover: UIPopoverPresentationController?
+    var actionSheet: ActionSheet?
+    weak var popover: UIPopoverPresentationController?
     
     
     
     
     // MARK: - ActionSheetPresenter
     // MARK: - ActionSheetPresenter
@@ -59,16 +59,7 @@ open class ActionSheetPopoverPresenter: NSObject, ActionSheetPresenter {
         guard let sheet = actionSheet else { return }
         guard let sheet = actionSheet else { return }
         sheet.headerViewContainer?.isHidden = true
         sheet.headerViewContainer?.isHidden = true
         sheet.buttonsTableView?.isHidden = true
         sheet.buttonsTableView?.isHidden = true
-        refreshPopoverAppearance(for: sheet)
-    }
-    
-    
-    // MARK: - Protected Functions
-    
-    open func refreshPopoverAppearance(for sheet: ActionSheet) {
-        let width = sheet.appearance.popover.width
-        let height = sheet.itemsHeight
-        sheet.preferredContentSize = CGSize(width: width, height: height)
+        sheet.preferredContentSize.height = sheet.itemsHeight
         popover?.backgroundColor = sheet.itemsTableView?.backgroundColor
         popover?.backgroundColor = sheet.itemsTableView?.backgroundColor
     }
     }
 }
 }
@@ -92,7 +83,6 @@ extension ActionSheetPopoverPresenter: UIPopoverPresentationControllerDelegate {
 extension ActionSheetPopoverPresenter {
 extension ActionSheetPopoverPresenter {
     
     
     func popover(for sheet: ActionSheet, in vc: UIViewController) -> UIPopoverPresentationController? {
     func popover(for sheet: ActionSheet, in vc: UIViewController) -> UIPopoverPresentationController? {
-        sheet.modalPresentationStyle = .popover
         let popover = sheet.popoverPresentationController
         let popover = sheet.popoverPresentationController
         popover?.delegate = self
         popover?.delegate = self
         return popover
         return popover
@@ -100,9 +90,9 @@ extension ActionSheetPopoverPresenter {
     
     
     func setupSheetForPresentation(_ sheet: ActionSheet) {
     func setupSheetForPresentation(_ sheet: ActionSheet) {
         self.actionSheet = sheet
         self.actionSheet = sheet
-        sheet.headerView = nil
         sheet.items = popoverItems(for: sheet)
         sheet.items = popoverItems(for: sheet)
         sheet.buttons = []
         sheet.buttons = []
+        sheet.modalPresentationStyle = .popover
     }
     }
 }
 }
 
 

+ 6 - 9
Carthage/Checkouts/Sheeeeeeeeet/Sheeeeeeeeet/Presenters/ActionSheetPresenter.swift

@@ -8,16 +8,13 @@
 
 
 /*
 /*
  
  
- Action sheet presenters are used by Sheeeeeeeeet to present
- action sheets in different ways, e.g. with a default bottom
- slide, showing a popover from the tapped view etc.
+ Action sheet presenters are used to present and dismiss any
+ action sheet in different ways, for instance with a default
+ slide-in, showing the sheet in a popover etc.
  
  
- When implementing this protocol, `present(in:from:)` is the
- standard way to present an action sheet, while `dismiss` is
- the standard way to dismiss it.
- 
- `isDismissableWithTapOnBackground` is used to specify if an
- action sheet can be dismissed by tapping on the background.
+ Instead of a delegate, the presenter protocol uses an event
+ property that has events that you can subscribe to, by just
+ setting the action blocks in the event struct.
  
  
  */
  */
 
 

+ 14 - 7
Carthage/Checkouts/Sheeeeeeeeet/Sheeeeeeeeet/Presenters/ActionSheetStandardPresenter.swift

@@ -8,8 +8,9 @@
 
 
 /*
 /*
  
  
- This presenter will present action sheets as regular iPhone
- action sheets, from the bottom of the screen.
+ This presenter presents action sheets as regular iOS action
+ sheets, which are presented with a slide-in from the bottom
+ of the screen.
  
  
  */
  */
 
 
@@ -28,7 +29,9 @@ open class ActionSheetStandardPresenter: ActionSheetPresenter {
     public var events = ActionSheetPresenterEvents()
     public var events = ActionSheetPresenterEvents()
     public var isDismissableWithTapOnBackground = true
     public var isDismissableWithTapOnBackground = true
     
     
-    private var actionSheet: ActionSheet?
+    var actionSheet: ActionSheet?
+    var animationDelay: TimeInterval = 0
+    var animationDuration: TimeInterval = 0.3
     
     
     
     
     // MARK: - ActionSheetPresenter
     // MARK: - ActionSheetPresenter
@@ -53,6 +56,7 @@ open class ActionSheetStandardPresenter: ActionSheetPresenter {
     open func present(sheet: ActionSheet, in vc: UIViewController, completion: @escaping () -> ()) {
     open func present(sheet: ActionSheet, in vc: UIViewController, completion: @escaping () -> ()) {
         actionSheet = sheet
         actionSheet = sheet
         addActionSheetView(from: sheet, to: vc.view)
         addActionSheetView(from: sheet, to: vc.view)
+        addBackgroundViewTapAction(to: sheet.backgroundView)
         presentBackgroundView()
         presentBackgroundView()
         presentActionSheet(completion: completion)
         presentActionSheet(completion: completion)
     }
     }
@@ -71,7 +75,6 @@ open class ActionSheetStandardPresenter: ActionSheetPresenter {
     open func addActionSheetView(from sheet: ActionSheet, to view: UIView) {
     open func addActionSheetView(from sheet: ActionSheet, to view: UIView) {
         sheet.view.frame = view.frame
         sheet.view.frame = view.frame
         view.addSubview(sheet.view)
         view.addSubview(sheet.view)
-        addBackgroundViewTapAction(to: sheet.backgroundView)
     }
     }
 
 
     open func addBackgroundViewTapAction(to view: UIView?) {
     open func addBackgroundViewTapAction(to view: UIView?) {
@@ -86,7 +89,12 @@ open class ActionSheetStandardPresenter: ActionSheetPresenter {
     }
     }
     
     
     open func animate(_ animation: @escaping () -> (), completion: (() -> ())?) {
     open func animate(_ animation: @escaping () -> (), completion: (() -> ())?) {
-        UIView.animate(withDuration: 0.3, delay: 0, options: [.curveEaseOut], animations: animation) { _ in completion?() }
+        guard animationDuration >= 0 else { return }
+        UIView.animate(
+            withDuration: animationDuration,
+            delay: animationDelay,
+            options: [.curveEaseOut],
+            animations: animation) { _ in completion?() }
     }
     }
     
     
     open func presentActionSheet(completion: @escaping () -> ()) {
     open func presentActionSheet(completion: @escaping () -> ()) {
@@ -106,8 +114,7 @@ open class ActionSheetStandardPresenter: ActionSheetPresenter {
 
 
     open func removeActionSheet(completion: @escaping () -> ()) {
     open func removeActionSheet(completion: @escaping () -> ()) {
         guard let view = actionSheet?.stackView else { return }
         guard let view = actionSheet?.stackView else { return }
-        let frame = view.frame
-        let animation = { view.frame.origin.y += frame.height + 100 }
+        let animation = { view.frame.origin.y += view.frame.height + 100 }
         animate(animation) { completion() }
         animate(animation) { completion() }
     }
     }
 
 

+ 0 - 34
Carthage/Checkouts/Sheeeeeeeeet/Sheeeeeeeeet/Views/ActionSheetCollectionItemCell.swift

@@ -1,34 +0,0 @@
-import Foundation
-
-open class ActionSheetCollectionItemCell: ActionSheetItemCell {
-    
-    
-    // MARK: - Properties
-    
-    static let itemCellIdentifier = ActionSheetCollectionItemCell.className
-    
-    static let nib = ActionSheetCollectionItemCell.defaultNib
-    
-    
-    // MARK: - Outlets
-    
-    @IBOutlet weak var collectionView: UICollectionView! {
-        didSet {
-            let flow = UICollectionViewFlowLayout()
-            flow.scrollDirection = .horizontal
-            collectionView.collectionViewLayout = flow
-        }
-    }
-    
-    
-    // MARK: - Functions
-    
-    func setup(withNib nib: UINib, owner: UICollectionViewDataSource & UICollectionViewDelegate) {
-        let id = ActionSheetCollectionItemCell.itemCellIdentifier
-        collectionView.contentInset = .zero
-        collectionView.register(nib, forCellWithReuseIdentifier: id)
-        collectionView.dataSource = owner
-        collectionView.delegate = owner
-        collectionView.reloadData()
-    }
-}

+ 0 - 46
Carthage/Checkouts/Sheeeeeeeeet/Sheeeeeeeeet/Views/ActionSheetCollectionItemCell.xib

@@ -1,46 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="13771" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
-    <device id="retina4_7" orientation="portrait">
-        <adaptation id="fullscreen"/>
-    </device>
-    <dependencies>
-        <deployment identifier="iOS"/>
-        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13772"/>
-        <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
-    </dependencies>
-    <objects>
-        <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
-        <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
-        <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" rowHeight="196" id="moX-qQ-Gyn" customClass="ActionSheetCollectionItemCell" customModule="Sheeeeeeeeet" customModuleProvider="target">
-            <rect key="frame" x="0.0" y="0.0" width="452" height="196"/>
-            <autoresizingMask key="autoresizingMask"/>
-            <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="moX-qQ-Gyn" id="qre-fe-O26">
-                <rect key="frame" x="0.0" y="0.0" width="452" height="195.5"/>
-                <autoresizingMask key="autoresizingMask"/>
-                <subviews>
-                    <collectionView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" dataMode="none" translatesAutoresizingMaskIntoConstraints="NO" id="eSV-yW-MpO">
-                        <rect key="frame" x="0.0" y="0.0" width="452" height="195.5"/>
-                        <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
-                        <collectionViewFlowLayout key="collectionViewLayout" minimumLineSpacing="10" minimumInteritemSpacing="10" id="UCY-qV-avs">
-                            <size key="itemSize" width="50" height="50"/>
-                            <size key="headerReferenceSize" width="0.0" height="0.0"/>
-                            <size key="footerReferenceSize" width="0.0" height="0.0"/>
-                            <inset key="sectionInset" minX="0.0" minY="0.0" maxX="0.0" maxY="0.0"/>
-                        </collectionViewFlowLayout>
-                    </collectionView>
-                </subviews>
-                <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
-                <constraints>
-                    <constraint firstAttribute="bottom" secondItem="eSV-yW-MpO" secondAttribute="bottom" id="Dnr-ur-bHp"/>
-                    <constraint firstAttribute="trailing" secondItem="eSV-yW-MpO" secondAttribute="trailing" id="Hbt-ZB-Gy8"/>
-                    <constraint firstItem="eSV-yW-MpO" firstAttribute="top" secondItem="qre-fe-O26" secondAttribute="top" id="OuY-7J-7R1"/>
-                    <constraint firstItem="eSV-yW-MpO" firstAttribute="leading" secondItem="qre-fe-O26" secondAttribute="leading" id="h5Z-mf-v8W"/>
-                </constraints>
-            </tableViewCellContentView>
-            <connections>
-                <outlet property="collectionView" destination="eSV-yW-MpO" id="s1m-Z2-HwO"/>
-            </connections>
-            <point key="canvasLocation" x="-28" y="-15"/>
-        </tableViewCell>
-    </objects>
-</document>

+ 0 - 27
Carthage/Checkouts/Sheeeeeeeeet/Sheeeeeeeeet/Views/ActionSheetCollectionItemContentCell.swift

@@ -1,27 +0,0 @@
-//
-//  ActionSheetCollectionItemContentCell.swift
-//  Sheeeeeeeeet
-//
-//  Created by Jonas Ullström (ullstrm) on 2018-03-01.
-//  Copyright © 2018 Jonas Ullström. All rights reserved.
-//
-
-/*
- 
- This protocol must be implemented by any cell that is to be
- used together with an `ActionSheetCollectionItem`.
- 
- */
-
-import UIKit
-
-public protocol ActionSheetCollectionItemContentCell where Self: UICollectionViewCell {
-    
-    static var nib: UINib { get }
-    static var defaultSize: CGSize { get }
-    static var leftInset: CGFloat { get }
-    static var rightInset: CGFloat { get }
-    static var topInset: CGFloat { get }
-    static var bottomInset: CGFloat { get }
-    static var itemSpacing: CGFloat { get }
-}

+ 0 - 22
Carthage/Checkouts/Sheeeeeeeeet/Sheeeeeeeeet/Views/ActionSheetCustomItemCell.swift

@@ -1,22 +0,0 @@
-//
-//  ActionSheetCustomItemCell.swift
-//  Sheeeeeeeeet
-//
-//  Created by Daniel Saidi on 2018-10-08.
-//  Copyright © 2018 Daniel Saidi. All rights reserved.
-//
-
-/*
- 
- This protocol must be implemented by any cell that is to be
- used together with an `ActionSheetCustomItem`.
- 
- */
-
-import UIKit
-
-public protocol ActionSheetCustomItemCell where Self: ActionSheetItemCell {
-    
-    static var nib: UINib { get }
-    static var defaultSize: CGSize { get }
-}

+ 0 - 19
Carthage/Checkouts/Sheeeeeeeeet/Sheeeeeeeeet/Views/ActionSheetItemCell.swift

@@ -1,19 +0,0 @@
-//
-//  ActionSheetItemCell.swift
-//  Sheeeeeeeeet
-//
-//  Created by Daniel Saidi on 2017-11-24.
-//  Copyright © 2017 Daniel Saidi. All rights reserved.
-//
-
-/*
- 
- This is the base class for all different cell types in this
- library. It makes it possible to set a global appearance on
- all item cells, using `ActionSheetItemCell.appearance()`.
- 
- */
-
-import UIKit
-
-open class ActionSheetItemCell: UITableViewCell {}

+ 89 - 63
Carthage/Checkouts/Sheeeeeeeeet/SheeeeeeeeetExample/AppDelegate+Appearance.swift

@@ -19,68 +19,94 @@ import Sheeeeeeeeet
 extension AppDelegate {
 extension AppDelegate {
     
     
     func applyAppearance() {
     func applyAppearance() {
-        
-        let blue = UIColor(hex: 0x0FA2F5)
-        let green = UIColor(hex: 0x81c03f)
-        let pink = UIColor(hex: 0xec5f72)
-        let purple = UIColor(hex: 0xd9007b)
-        let red = UIColor(hex: 0xff3333)
-        
-        let robotoBlack = "Roboto-Black"
-        let robotoMedium = "Roboto-Medium"
-        let robotoRegular = "Roboto-Regular"
-        
-        let appearance = ActionSheetAppearance.standard
-        
-//        appearance.popover.width = 500
-        
-        appearance.item.font = UIFont(name: robotoRegular, size: 17)
-        appearance.item.textColor = .darkText
-        appearance.item.tintColor = .darkGray
-        appearance.item.subtitleFont = UIFont(name: robotoRegular, size: 14)
-        appearance.item.subtitleTextColor = blue
-        
-//        appearance.separatorColor = .red
-//        appearance.itemsSeparatorColor = .blue
-//        appearance.buttonsSeparatorColor = .green
-        
-        appearance.title.hideSeparator()
-        appearance.title.font = UIFont(name: robotoMedium, size: 15)
-        
-        appearance.sectionTitle.hideSeparator()
-        appearance.sectionTitle.font = UIFont(name: robotoMedium, size: 13)
-        appearance.sectionTitle.height = 20
-        
-        appearance.sectionMargin.height = 20
-        
-        appearance.selectItem.selectedIcon = UIImage(named: "ic_checkmark")
-        appearance.selectItem.unselectedIcon = UIImage(named: "ic_empty")
-        appearance.selectItem.selectedTintColor = blue
-        appearance.selectItem.selectedTextColor = green
-        appearance.selectItem.selectedIconTintColor = purple
-        
-        appearance.singleSelectItem.selectedTintColor = green
-        appearance.singleSelectItem.selectedTextColor = purple
-        appearance.singleSelectItem.selectedIconTintColor = blue
-        
-        appearance.multiSelectItem.selectedTintColor = purple
-        appearance.multiSelectItem.selectedTextColor = blue
-        appearance.multiSelectItem.selectedIconTintColor = green
-        
-        appearance.multiSelectToggleItem.hideSeparator()
-        appearance.multiSelectToggleItem.font = UIFont(name: robotoMedium, size: 13)
-        appearance.multiSelectToggleItem.selectAllTextColor = .lightGray
-        appearance.multiSelectToggleItem.deselectAllTextColor = red
-        
-        appearance.linkItem.linkIcon = UIImage(named: "ic_arrow_right")
-        
-        appearance.okButton.textColor = .darkGray
-        appearance.okButton.font = UIFont(name: robotoBlack, size: 17)
-        
-        appearance.dangerButton.textColor = pink
-        appearance.dangerButton.font = UIFont(name: robotoMedium, size: 17)
-        
-        appearance.cancelButton.textColor = .lightGray
-        appearance.cancelButton.font = UIFont(name: robotoMedium, size: 17)
+        applyViewAppearances()
+        applyColors()
+        applyFonts()
+        applyHeights()
+        applyIcons()
+        applySelectItemAppearances()
+        applySeparatorInsets()
+        applyPopoverWidth()
+    }
+}
+
+
+private extension AppDelegate {
+    
+    func applyViewAppearances() {
+//        ActionSheetBackgroundView.appearance().backgroundColor = .purple
+        ActionSheetHeaderView.appearance().cornerRadius = 10
+        ActionSheetTableView.appearance().cornerRadius = 10
+//        ActionSheetTableView.appearance().separatorLineColor = .purple
+//        ActionSheetItemTableView.appearance().cornerRadius = 20
+//        ActionSheetTableView.appearance(whenContainedInInstancesOf: [MultiSelectActionSheet.self]).cornerRadius = 20
+    }
+    
+    func applyColors() {
+        ActionSheetItemCell.appearance().titleColor = .darkText
+        ActionSheetItemCell.appearance().subtitleColor = .exampleBlue
+        ActionSheetItemCell.appearance().tintColor = .darkText
+//        ActionSheetItemCell.appearance().separatorColor = .red
+//        ActionSheetItemCell.appearance().backgroundColor = red
+//        ActionSheetItemCell.appearance(whenContainedInInstancesOf: [ActionSheetItemTableView.self]).backgroundColor = .purple
+        ActionSheetOkButtonCell.appearance().titleColor = .darkGray
+        ActionSheetCancelButtonCell.appearance().titleColor = .lightGray
+        ActionSheetDangerButtonCell.appearance().titleColor = .examplePink
+    }
+    
+    func applyFonts() {
+        ActionSheetItemCell.appearance().titleFont = .robotoRegular(size: 17)
+        ActionSheetItemCell.appearance().subtitleFont = .robotoRegular(size: 14)
+        ActionSheetLinkItemCell.appearance().titleFont = .robotoRegular(size: 17)
+        ActionSheetMultiSelectToggleItemCell.appearance().titleFont = .robotoMedium(size: 13)
+        ActionSheetSectionTitleCell.appearance().titleFont = .robotoMedium(size: 13)
+        ActionSheetTitleCell.appearance().titleFont = .robotoMedium(size: 15)
+        ActionSheetOkButtonCell.appearance().titleFont = .robotoBlack(size: 17)
+        ActionSheetDangerButtonCell.appearance().titleFont = .robotoMedium(size: 17)
+        ActionSheetCancelButtonCell.appearance().titleFont = .robotoRegular(size: 17)
+    }
+    
+    func applyHeights() {
+        ActionSheetSectionTitle.height = 20
+        ActionSheetSectionMargin.height = 20
+    }
+    
+    func applyIcons() {
+        ActionSheetLinkItemCell.appearance().linkIcon = UIImage(named: "ic_arrow_right")
+    }
+    
+    func applySelectItemAppearances() {
+        ActionSheetSelectItemCell.appearance().selectedIcon = UIImage(named: "ic_checkmark")
+        ActionSheetSelectItemCell.appearance().unselectedIcon = UIImage(named: "ic_empty")
+        ActionSheetSelectItemCell.appearance().selectedTintColor = .exampleBlue
+        ActionSheetSelectItemCell.appearance().selectedTitleColor = .exampleGreen
+        ActionSheetSelectItemCell.appearance().selectedIconColor = .examplePurple
+        
+        ActionSheetSingleSelectItemCell.appearance().selectedTintColor = .exampleGreen
+        ActionSheetSingleSelectItemCell.appearance().selectedTitleFont = .robotoMedium(size: 35)
+        ActionSheetSingleSelectItemCell.appearance().selectedSubtitleFont = .robotoMedium(size: 25)
+        ActionSheetSingleSelectItemCell.appearance().selectedTitleColor = .examplePurple
+        ActionSheetSingleSelectItemCell.appearance().selectedIconColor = .exampleBlue
+        
+        ActionSheetMultiSelectItemCell.appearance().tintColor = UIColor.darkText.withAlphaComponent(0.4)
+        ActionSheetMultiSelectItemCell.appearance().titleColor = UIColor.darkText.withAlphaComponent(0.4)
+        ActionSheetMultiSelectItemCell.appearance().selectedTintColor = .examplePurple
+        ActionSheetMultiSelectItemCell.appearance().selectedTitleColor = .exampleBlue
+        ActionSheetMultiSelectItemCell.appearance().selectedIconColor = .exampleGreen
+        
+        ActionSheetMultiSelectToggleItemCell.appearance().selectAllSubtitleColor = .lightGray
+        ActionSheetMultiSelectToggleItemCell.appearance().deselectAllSubtitleColor = .exampleRed
+    }
+    
+    func applySeparatorInsets() {
+        ActionSheetItemCell.appearance().separatorInset = .zero
+        ActionSheetTitleCell.appearance().separatorInset = .hiddenSeparator
+        ActionSheetSectionTitleCell.appearance().separatorInset = .hiddenSeparator
+        ActionSheetSectionMarginCell.appearance().separatorInset = .hiddenSeparator
+        ActionSheetMultiSelectToggleItemCell.appearance().separatorInset = .hiddenSeparator
+    }
+    
+    func applyPopoverWidth() {
+//        ActionSheet.preferredPopoverWidth = 700
     }
     }
 }
 }

+ 2 - 2
Carthage/Checkouts/Sheeeeeeeeet/SheeeeeeeeetExample/Info.plist

@@ -15,9 +15,9 @@
 	<key>CFBundlePackageType</key>
 	<key>CFBundlePackageType</key>
 	<string>APPL</string>
 	<string>APPL</string>
 	<key>CFBundleShortVersionString</key>
 	<key>CFBundleShortVersionString</key>
-	<string>1.1.0</string>
+	<string>1.2.2</string>
 	<key>CFBundleVersion</key>
 	<key>CFBundleVersion</key>
-	<string>1901101458</string>
+	<string>1</string>
 	<key>LSRequiresIPhoneOS</key>
 	<key>LSRequiresIPhoneOS</key>
 	<true/>
 	<true/>
 	<key>UIAppFonts</key>
 	<key>UIAppFonts</key>

+ 2 - 2
Carthage/Checkouts/Sheeeeeeeeet/SheeeeeeeeetTests/ActionSheet/ActionSheet+PresenterTests.swift

@@ -8,7 +8,7 @@ class ActionSheet_PresenterTests: QuickSpec {
         
         
         describe("default presenter") {
         describe("default presenter") {
             
             
-            func getDifferentIdiom() -> UIUserInterfaceIdiom {
+            func getReversedIdiom() -> UIUserInterfaceIdiom {
                 switch UIDevice.current.userInterfaceIdiom {
                 switch UIDevice.current.userInterfaceIdiom {
                 case .phone: return .pad
                 case .phone: return .pad
                 case .pad: return .phone
                 case .pad: return .phone
@@ -26,7 +26,7 @@ class ActionSheet_PresenterTests: QuickSpec {
             }
             }
             
             
             it("is different from other idioms") {
             it("is different from other idioms") {
-                let idiom = getDifferentIdiom()
+                let idiom = getReversedIdiom()
                 let idiomPresenter = idiom.defaultPresenter
                 let idiomPresenter = idiom.defaultPresenter
                 let defaultPresenter = ActionSheet.defaultPresenter
                 let defaultPresenter = ActionSheet.defaultPresenter
                 let isSameKind = type(of: defaultPresenter) == type(of: idiomPresenter)
                 let isSameKind = type(of: defaultPresenter) == type(of: idiomPresenter)

+ 21 - 17
Carthage/Checkouts/Sheeeeeeeeet/SheeeeeeeeetTests/ActionSheet/ActionSheetItemHandlerTests.swift

@@ -14,8 +14,8 @@ class ActionSheetItemHandlerTests: QuickSpec {
     
     
     override func spec() {
     override func spec() {
         
         
-        func tableView() -> MockTableView {
-            return MockTableView(frame: .zero)
+        func createTableView() -> MockItemTableView {
+            return MockItemTableView(frame: .zero)
         }
         }
         
         
         var sheet: MockActionSheet!
         var sheet: MockActionSheet!
@@ -32,6 +32,7 @@ class ActionSheetItemHandlerTests: QuickSpec {
             handler = ActionSheetItemHandler(actionSheet: sheet, itemType: .items)
             handler = ActionSheetItemHandler(actionSheet: sheet, itemType: .items)
         }
         }
         
         
+        
         describe("configured with item type") {
         describe("configured with item type") {
             
             
             beforeEach {
             beforeEach {
@@ -46,6 +47,7 @@ class ActionSheetItemHandlerTests: QuickSpec {
             }
             }
         }
         }
         
         
+        
         describe("configured with button type") {
         describe("configured with button type") {
             
             
             beforeEach {
             beforeEach {
@@ -59,7 +61,8 @@ class ActionSheetItemHandlerTests: QuickSpec {
             }
             }
         }
         }
         
         
-        describe("as table view data source") {
+        
+        describe("when used as table view data source") {
             
             
             it("returns correct item at index") {
             it("returns correct item at index") {
                 let path1 = IndexPath(row: 0, section: 0)
                 let path1 = IndexPath(row: 0, section: 0)
@@ -69,54 +72,55 @@ class ActionSheetItemHandlerTests: QuickSpec {
             }
             }
             
             
             it("has correct section count") {
             it("has correct section count") {
-                let sections = handler.numberOfSections(in: tableView())
+                let sections = handler.numberOfSections(in: createTableView())
                 expect(sections).to(equal(1))
                 expect(sections).to(equal(1))
             }
             }
             
             
             it("has correct row count") {
             it("has correct row count") {
-                let rows = handler.tableView(tableView(), numberOfRowsInSection: 0)
+                let rows = handler.tableView(createTableView(), numberOfRowsInSection: 0)
                 expect(rows).to(equal(2))
                 expect(rows).to(equal(2))
             }
             }
             
             
             it("returns correct cell for existing item") {
             it("returns correct cell for existing item") {
                 let path = IndexPath(row: 0, section: 0)
                 let path = IndexPath(row: 0, section: 0)
-                item1.cell = UITableViewCell(frame: .zero)
-                let result = handler.tableView(tableView(), cellForRowAt: path)
+                item1.cell = ActionSheetItemCell(frame: .zero)
+                let result = handler.tableView(createTableView(), cellForRowAt: path)
                 expect(result).to(be(item1.cell))
                 expect(result).to(be(item1.cell))
             }
             }
             
             
             it("returns fallback cell for existing item") {
             it("returns fallback cell for existing item") {
                 let path = IndexPath(row: 1, section: 1)
                 let path = IndexPath(row: 1, section: 1)
-                let result = handler.tableView(tableView(), cellForRowAt: path)
+                let result = handler.tableView(createTableView(), cellForRowAt: path)
                 expect(result).toNot(beNil())
                 expect(result).toNot(beNil())
             }
             }
             
             
             it("returns correct height for existing item") {
             it("returns correct height for existing item") {
                 let path = IndexPath(row: 0, section: 0)
                 let path = IndexPath(row: 0, section: 0)
-                item1.appearance.height = 123
-                let result = handler.tableView(tableView(), heightForRowAt: path)
+                MockActionSheetItem.height = 123
+                let result = handler.tableView(createTableView(), heightForRowAt: path)
                 expect(result).to(equal(123))
                 expect(result).to(equal(123))
             }
             }
             
             
             it("returns zero height for existing item") {
             it("returns zero height for existing item") {
                 let path = IndexPath(row: 1, section: 1)
                 let path = IndexPath(row: 1, section: 1)
-                let result = handler.tableView(tableView(), heightForRowAt: path)
+                let result = handler.tableView(createTableView(), heightForRowAt: path)
                 expect(result).to(equal(0))
                 expect(result).to(equal(0))
             }
             }
         }
         }
         
         
-        describe("as table view delegate") {
+        
+        describe("when used as table view delegate") {
             
             
             it("does not deselect row for invalid path") {
             it("does not deselect row for invalid path") {
                 let path = IndexPath(row: 1, section: 1)
                 let path = IndexPath(row: 1, section: 1)
-                let view = tableView()
+                let view = createTableView()
                 handler.tableView(view, didSelectRowAt: path)
                 handler.tableView(view, didSelectRowAt: path)
                 expect(view.deselectRowInvokeCount).to(equal(0))
                 expect(view.deselectRowInvokeCount).to(equal(0))
             }
             }
             
             
             it("deselects row for valid path") {
             it("deselects row for valid path") {
                 let path = IndexPath(row: 0, section: 0)
                 let path = IndexPath(row: 0, section: 0)
-                let view = tableView()
+                let view = createTableView()
                 handler.tableView(view, didSelectRowAt: path)
                 handler.tableView(view, didSelectRowAt: path)
                 expect(view.deselectRowInvokeCount).to(equal(1))
                 expect(view.deselectRowInvokeCount).to(equal(1))
                 expect(view.deselectRowInvokePaths.count).to(equal(1))
                 expect(view.deselectRowInvokePaths.count).to(equal(1))
@@ -128,13 +132,13 @@ class ActionSheetItemHandlerTests: QuickSpec {
             it("does not handle tap if missing action sheet") {
             it("does not handle tap if missing action sheet") {
                 sheet = nil
                 sheet = nil
                 let path = IndexPath(row: 0, section: 0)
                 let path = IndexPath(row: 0, section: 0)
-                handler.tableView(tableView(), didSelectRowAt: path)
+                handler.tableView(createTableView(), didSelectRowAt: path)
                 expect(item1.handleTapInvokeCount).to(equal(0))
                 expect(item1.handleTapInvokeCount).to(equal(0))
             }
             }
             
             
             it("handles item tap for existing action sheet") {
             it("handles item tap for existing action sheet") {
                 let path = IndexPath(row: 0, section: 0)
                 let path = IndexPath(row: 0, section: 0)
-                handler.tableView(tableView(), didSelectRowAt: path)
+                handler.tableView(createTableView(), didSelectRowAt: path)
                 expect(item1.handleTapInvokeCount).to(equal(1))
                 expect(item1.handleTapInvokeCount).to(equal(1))
                 expect(item1.handleTapInvokeActionSheets.count).to(equal(1))
                 expect(item1.handleTapInvokeActionSheets.count).to(equal(1))
                 expect(item1.handleTapInvokeActionSheets[0]).to(be(sheet))
                 expect(item1.handleTapInvokeActionSheets[0]).to(be(sheet))
@@ -142,7 +146,7 @@ class ActionSheetItemHandlerTests: QuickSpec {
 
 
             it("handles sheet item tap for existing action sheet") {
             it("handles sheet item tap for existing action sheet") {
                 let path = IndexPath(row: 0, section: 0)
                 let path = IndexPath(row: 0, section: 0)
-                handler.tableView(tableView(), didSelectRowAt: path)
+                handler.tableView(createTableView(), didSelectRowAt: path)
                 expect(sheet.handleTapInvokeCount).to(equal(1))
                 expect(sheet.handleTapInvokeCount).to(equal(1))
                 expect(sheet.handleTapInvokeItems.count).to(equal(1))
                 expect(sheet.handleTapInvokeItems.count).to(equal(1))
                 expect(sheet.handleTapInvokeItems[0]).to(be(item1))
                 expect(sheet.handleTapInvokeItems[0]).to(be(item1))

+ 14 - 7
Carthage/Checkouts/Sheeeeeeeeet/SheeeeeeeeetTests/ActionSheet/ActionSheetMarginTests.swift

@@ -31,16 +31,23 @@ class ActionSheetMarginTests: QuickSpec {
         
         
         describe("value with minimum fallback in view") {
         describe("value with minimum fallback in view") {
             
             
-            func value(for margin: ActionSheetMargin) -> CGFloat? {
+            func value(for margin: ActionSheetMargin, minimum: CGFloat) -> CGFloat {
                 let view = UIView(frame: .zero)
                 let view = UIView(frame: .zero)
-                return margin.value(in: view, minimum: 10)
+                return margin.value(in: view, minimum: minimum)
             }
             }
             
             
-            it("returns safe area inset value") {
-                expect(value(for: .top)).to(equal(10))
-                expect(value(for: .left)).to(equal(10))
-                expect(value(for: .right)).to(equal(10))
-                expect(value(for: .bottom)).to(equal(10))
+            it("returns safe area inset if it is greater than minimum value") {
+                expect(value(for: .top, minimum: -1)).to(equal(0))
+                expect(value(for: .left, minimum: -1)).to(equal(0))
+                expect(value(for: .right, minimum: -1)).to(equal(0))
+                expect(value(for: .bottom, minimum: -1)).to(equal(0))
+            }
+            
+            it("returns minimum value if it is greater than safe area insets") {
+                expect(value(for: .top, minimum: 10)).to(equal(10))
+                expect(value(for: .left, minimum: 10)).to(equal(10))
+                expect(value(for: .right, minimum: 10)).to(equal(10))
+                expect(value(for: .bottom, minimum: 10)).to(equal(10))
             }
             }
         }
         }
     }
     }

+ 358 - 300
Carthage/Checkouts/Sheeeeeeeeet/SheeeeeeeeetTests/ActionSheet/ActionSheetTests.swift

@@ -6,8 +6,6 @@
 //  Copyright © 2017 Daniel Saidi. All rights reserved.
 //  Copyright © 2017 Daniel Saidi. All rights reserved.
 //
 //
 
 
-//  TODO: Improve these tests, since much logic has changed.
-
 import Quick
 import Quick
 import Nimble
 import Nimble
 @testable import Sheeeeeeeeet
 @testable import Sheeeeeeeeet
@@ -16,121 +14,237 @@ class ActionSheetTests: QuickSpec {
     
     
     override func spec() {
     override func spec() {
         
         
-        func createButton(_ title: String) -> ActionSheetButton {
-            return ActionSheetOkButton(title: title)
-        }
-        
-        func createItem(_ title: String) -> ActionSheetItem {
-            return ActionSheetItem(title: title)
-        }
+        var sheet: MockActionSheet!
         
         
         func createSheet(_ items: [ActionSheetItem] = []) -> MockActionSheet {
         func createSheet(_ items: [ActionSheetItem] = []) -> MockActionSheet {
             return MockActionSheet(items: items, action: { _, _ in })
             return MockActionSheet(items: items, action: { _, _ in })
         }
         }
         
         
-        func createTableView() -> ActionSheetTableView {
-            return ActionSheetTableView(frame: .zero)
+        
+        // MARK: - Initialization
+        
+        describe("created instance") {
+            
+            context("default behavior") {
+                
+                it("use default presenter") {
+                    sheet = createSheet()
+                    let isStandard = sheet.presenter is ActionSheetStandardPresenter
+                    let isPopover = sheet.presenter is ActionSheetPopoverPresenter
+                    let isValid = isStandard || isPopover
+                    
+                    expect(isValid).to(beTrue())
+                }
+                
+                it("applies no items and buttons") {
+                    sheet = createSheet()
+                    
+                    expect(sheet.items.count).to(equal(0))
+                    expect(sheet.buttons.count).to(equal(0))
+                }
+                
+            }
+            
+            context("custom properties") {
+                
+                it("uses provided presenter") {
+                    let presenter = ActionSheetPopoverPresenter()
+                    sheet = MockActionSheet(items: [], presenter: presenter, action: { _, _ in })
+                    
+                    expect(sheet.presenter).to(be(presenter))
+                }
+                
+                it("sets up provided items and buttons") {
+                    let items = [ActionSheetItem(title: "foo")]
+                    sheet = createSheet(items)
+                    
+                    expect(sheet.setupItemsInvokeCount).to(equal(1))
+                    expect(sheet.setupItemsInvokeItems[0]).to(be(items))
+                }
+            }
+            
+            it("uses provided action") {
+                var counter = 0
+                sheet = MockActionSheet(items: []) { _, _  in counter += 1 }
+                sheet.selectAction(sheet, ActionSheetItem(title: "foo"))
+                
+                expect(counter).to(equal(1))
+            }
         }
         }
         
         
         
         
-        // MARK: - Initialization
+        describe("setup") {
+            
+            beforeEach {
+                sheet = createSheet()
+            }
+            
+            it("applies default preferred popover width") {
+                sheet.setup()
+                
+                expect(sheet.preferredContentSize.width).to(equal(300))
+            }
+            
+            it("applies custom preferred popover width") {
+                sheet.preferredPopoverWidth = 200
+                sheet.setup()
+                
+                expect(sheet.preferredContentSize.width).to(equal(200))
+            }
+        }
+        
         
         
-        describe("when initialized with parameters") {
+        describe("setup items") {
+            
+            beforeEach {
+                sheet = createSheet()
+            }
             
             
-            it("applies provided items") {
-                let item1 = createItem("foo")
-                let item2 = createItem("bar")
-                let sheet = createSheet([item1, item2])
+            it("applies empty collection") {
+                sheet.setup(items: [])
                 
                 
-                expect(sheet.items.count).to(equal(2))
-                expect(sheet.items[0]).to(be(item1))
-                expect(sheet.items[1]).to(be(item2))
+                expect(sheet.items.count).to(equal(0))
+                expect(sheet.buttons.count).to(equal(0))
             }
             }
-
-            it("separates provided items and buttons") {
-                let button = createButton("Sheeeeeeeeet")
-                let item1 = createItem("foo")
-                let item2 = createItem("bar")
-                let sheet = createSheet([button, item1, item2])
-
+            
+            it("separates items and buttons") {
+                let item1 = ActionSheetItem(title: "foo")
+                let item2 = ActionSheetItem(title: "bar")
+                let button = ActionSheetOkButton(title: "baz")
+                sheet.setup(items: [button, item1, item2])
+                
                 expect(sheet.items.count).to(equal(2))
                 expect(sheet.items.count).to(equal(2))
                 expect(sheet.items[0]).to(be(item1))
                 expect(sheet.items[0]).to(be(item1))
                 expect(sheet.items[1]).to(be(item2))
                 expect(sheet.items[1]).to(be(item2))
                 expect(sheet.buttons.count).to(equal(1))
                 expect(sheet.buttons.count).to(equal(1))
                 expect(sheet.buttons[0]).to(be(button))
                 expect(sheet.buttons[0]).to(be(button))
             }
             }
-
-            it("applies default presenter if none is provided") {
-                let sheet = createSheet()
-                let isStandard = sheet.presenter is ActionSheetStandardPresenter
-                let isPopover = sheet.presenter is ActionSheetPopoverPresenter
-                let isValid = isStandard || isPopover
+            
+            it("reloads data") {
+                sheet.reloadDataInvokeCount = 0
+                sheet.setup(items: [])
                 
                 
-                expect(isValid).to(beTrue())
+                expect(sheet.reloadDataInvokeCount).to(equal(1))
             }
             }
-
-            it("applies provided presenter") {
-                let presenter = ActionSheetPopoverPresenter()
-                let sheet = MockActionSheet(items: [], presenter: presenter, action: { _, _ in })
+        }
+        
+        
+        describe("loading view") {
+            
+            var itemsTableView: ActionSheetItemTableView!
+            var buttonsTableView: ActionSheetButtonTableView!
+            
+            beforeEach {
+                sheet = createSheet()
+                itemsTableView = ActionSheetItemTableView(frame: .zero)
+                buttonsTableView = ActionSheetButtonTableView(frame: .zero)
+                sheet.itemsTableView = itemsTableView
+                sheet.buttonsTableView = buttonsTableView
+                sheet.viewDidLoad()
+            }
+            
+            it("sets up action sheet") {
+                expect(sheet.setupInvokeCount).to(equal(1))
+            }
+            
+            it("sets up items table view") {
+                expect(itemsTableView.delegate).to(be(sheet.itemHandler))
+                expect(itemsTableView.dataSource).to(be(sheet.itemHandler))
+                expect(itemsTableView.alwaysBounceVertical).to(beFalse())
+                expect(itemsTableView.estimatedRowHeight).to(equal(44))
+                expect(itemsTableView.rowHeight).to(equal(UITableView.automaticDimension))
+                expect(itemsTableView.cellLayoutMarginsFollowReadableWidth).to(beFalse())
+            }
+            
+            it("sets up buttons table view") {
+                expect(buttonsTableView.delegate).to(be(sheet.buttonHandler))
+                expect(buttonsTableView.dataSource).to(be(sheet.buttonHandler))
+                expect(itemsTableView.alwaysBounceVertical).to(beFalse())
+                expect(buttonsTableView.estimatedRowHeight).to(equal(44))
+                expect(buttonsTableView.rowHeight).to(equal(UITableView.automaticDimension))
+                expect(buttonsTableView.cellLayoutMarginsFollowReadableWidth).to(beFalse())
+            }
+        }
+        
+        
+        describe("laying out subviews") {
+            
+            it("refreshes sheet") {
+                sheet = createSheet()
+                sheet.viewDidLayoutSubviews()
                 
                 
-                expect(sheet.presenter).to(be(presenter))
+                expect(sheet.refreshInvokeCount).to(equal(1))
             }
             }
-
-            it("applies provided action") {
-                var counter = 0
-                let sheet = MockActionSheet(items: []) { _, _  in counter += 1 }
-                sheet.selectAction(sheet, createItem("foo"))
+        }
+        
+        
+        describe("minimum content insets") {
+            
+            it("has correct default value") {
+                sheet = createSheet()
+                let expected = UIEdgeInsets(top: 15, left: 15, bottom: 15, right: 15)
                 
                 
-                expect(counter).to(equal(1))
+                expect(sheet.minimumContentInsets).to(equal(expected))
             }
             }
         }
         }
         
         
         
         
-        // MARK: - Properties
-
-        describe("appearance") {
+        describe("preferred popover width") {
             
             
-            it("is initially a copy of standard appearance") {
-                let original = ActionSheetAppearance.standard.popover.width
-                ActionSheetAppearance.standard.popover.width = -1
-                let sheet = createSheet()
-                let appearance = sheet.appearance
-                ActionSheetAppearance.standard.popover.width = original
+            it("has correct default value") {
+                sheet = createSheet()
+                let expected: CGFloat = 300
                 
                 
-                expect(appearance.popover.width).to(equal(-1))
+                expect(sheet.preferredPopoverWidth).to(equal(expected))
             }
             }
         }
         }
         
         
         
         
-        // MARK: - Item Properties
+        describe("section margins") {
+            
+            it("has correct default value") {
+                sheet = createSheet()
+                let expected: CGFloat = 15
+                
+                expect(sheet.sectionMargins).to(equal(expected))
+            }
+        }
+        
         
         
         describe("items height") {
         describe("items height") {
             
             
-            it("is sum of all item appearances") {
-                let item1 = createItem("foo")
-                let item2 = createItem("bar")
-                let item3 = createButton("baz")
-                item1.appearance.height = 100
-                item2.appearance.height = 110
-                item3.appearance.height = 120
-                let sheet = createSheet([item1, item2, item3])
-                
-                expect(sheet.itemsHeight).to(equal(210))
+            beforeEach {
+                ActionSheetItem.height = 100
+                ActionSheetSingleSelectItem.height = 110
+                ActionSheetMultiSelectItem.height = 120
+                ActionSheetOkButton.height = 120
+            }
+            
+            it("is sum of all items") {
+                let item1 = ActionSheetItem(title: "foo")
+                let item2 = ActionSheetSingleSelectItem(title: "bar", isSelected: true)
+                let item3 = ActionSheetMultiSelectItem(title: "baz", isSelected: false)
+                let button = ActionSheetOkButton(title: "ok")
+                sheet = createSheet([item1, item2, item3, button])
+                
+                expect(sheet.itemsHeight).to(equal(330))
             }
             }
         }
         }
         
         
+        
         describe("item handler") {
         describe("item handler") {
             
             
             it("has correct item type") {
             it("has correct item type") {
-                let sheet = createSheet()
+                sheet = createSheet()
+                
                 expect(sheet.itemHandler.itemType).to(equal(.items))
                 expect(sheet.itemHandler.itemType).to(equal(.items))
             }
             }
             
             
             it("has correct items") {
             it("has correct items") {
-                let item1 = createItem("foo")
-                let item2 = createItem("bar")
-                let item3 = createButton("baz")
-                let sheet = createSheet([item1, item2, item3])
+                let item1 = ActionSheetItem(title: "foo")
+                let item2 = ActionSheetItem(title: "bar")
+                let button = ActionSheetOkButton(title: "ok")
+                sheet = createSheet([item1, item2, button])
                 
                 
                 expect(sheet.itemHandler.items.count).to(equal(2))
                 expect(sheet.itemHandler.items.count).to(equal(2))
                 expect(sheet.itemHandler.items[0]).to(be(item1))
                 expect(sheet.itemHandler.items[0]).to(be(item1))
@@ -138,93 +252,64 @@ class ActionSheetTests: QuickSpec {
             }
             }
         }
         }
         
         
-        describe("item table view") {
+        
+        describe("items height") {
             
             
-            it("is correctly setup when view is loaded") {
-                let sheet = createSheet()
-                let view = createTableView()
-                sheet.itemsTableView = view
-                sheet.viewDidLoad()
-                
-                expect(view.delegate).to(be(sheet.itemHandler))
-                expect(view.dataSource).to(be(sheet.itemHandler))
-                expect(view.estimatedRowHeight).to(equal(44))
-                expect(view.rowHeight).to(equal(UITableView.automaticDimension))
-                expect(view.cellLayoutMarginsFollowReadableWidth).to(beFalse())
+            beforeEach {
+                ActionSheetItem.height = 100
+                ActionSheetOkButton.height = 110
+                ActionSheetDangerButton.height = 120
+                ActionSheetCancelButton.height = 130
             }
             }
-        }
-        
-        
-        // MARK: - Button Properties
-        
-        describe("buttons height") {
             
             
-            it("is sum of all button appearances") {
-                let item1 = createItem("foo")
-                let item2 = createButton("bar")
-                let item3 = createButton("baz")
-                item1.appearance.height = 100
-                item2.appearance.height = 110
-                item3.appearance.height = 120
-                let sheet = createSheet([item1, item2, item3])
-                
-                expect(sheet.buttonsHeight).to(equal(230))
+            it("is sum of all items") {
+                let item = ActionSheetItem(title: "foo")
+                let button1 = ActionSheetOkButton(title: "ok")
+                let button2 = ActionSheetDangerButton(title: "ok")
+                let button3 = ActionSheetCancelButton(title: "ok")
+                sheet = createSheet([item, button1, button2, button3])
+                
+                expect(sheet.buttonsHeight).to(equal(360))
             }
             }
         }
         }
         
         
-        describe("button handler") {
+        
+        describe("item handler") {
             
             
             it("has correct item type") {
             it("has correct item type") {
-                let sheet = createSheet()
+                sheet = createSheet()
+                
                 expect(sheet.buttonHandler.itemType).to(equal(.buttons))
                 expect(sheet.buttonHandler.itemType).to(equal(.buttons))
             }
             }
             
             
             it("has correct items") {
             it("has correct items") {
-                let item1 = createItem("foo")
-                let item2 = createButton("bar")
-                let item3 = createButton("baz")
-                let sheet = createSheet([item1, item2, item3])
+                let item = ActionSheetItem(title: "foo")
+                let button1 = ActionSheetOkButton(title: "ok")
+                let button2 = ActionSheetOkButton(title: "ok")
+                sheet = createSheet([item, button1, button2])
                 
                 
                 expect(sheet.buttonHandler.items.count).to(equal(2))
                 expect(sheet.buttonHandler.items.count).to(equal(2))
-                expect(sheet.buttonHandler.items[0]).to(be(item2))
-                expect(sheet.buttonHandler.items[1]).to(be(item3))
+                expect(sheet.buttonHandler.items[0]).to(be(button1))
+                expect(sheet.buttonHandler.items[1]).to(be(button2))
             }
             }
         }
         }
         
         
-        describe("button table view") {
-            
-            it("is correctly setup when view is loaded") {
-                let sheet = createSheet()
-                let view = createTableView()
-                sheet.buttonsTableView = view
-                sheet.viewDidLoad()
-                
-                expect(view.delegate).to(be(sheet.buttonHandler))
-                expect(view.dataSource).to(be(sheet.buttonHandler))
-                expect(view.estimatedRowHeight).to(equal(44))
-                expect(view.rowHeight).to(equal(UITableView.automaticDimension))
-                expect(view.cellLayoutMarginsFollowReadableWidth).to(beFalse())
-            }
-        }
-        
-        
-        // MARK: - Presentation Functions
         
         
         context("presentation") {
         context("presentation") {
             
             
             var presenter: MockActionSheetPresenter!
             var presenter: MockActionSheetPresenter!
             
             
-            func createSheet() -> MockActionSheet {
+            beforeEach {
                 presenter = MockActionSheetPresenter()
                 presenter = MockActionSheetPresenter()
-                return MockActionSheet(items: [], presenter: presenter, action: { _, _ in })
+                sheet = createSheet()
+                sheet.presenter = presenter
             }
             }
             
             
             describe("when dismissed") {
             describe("when dismissed") {
                 
                 
-                it("dismisses itself by calling presenter") {
+                it("it calls presenter") {
                     var counter = 0
                     var counter = 0
                     let completion = { counter += 1 }
                     let completion = { counter += 1 }
-                    let sheet = createSheet()
                     sheet.dismiss(completion: completion)
                     sheet.dismiss(completion: completion)
                     presenter.dismissInvokeCompletions[0]()
                     presenter.dismissInvokeCompletions[0]()
                     
                     
@@ -236,16 +321,14 @@ class ActionSheetTests: QuickSpec {
             describe("when presented from view") {
             describe("when presented from view") {
                 
                 
                 it("refreshes itself") {
                 it("refreshes itself") {
-                    let sheet = createSheet()
                     sheet.present(in: UIViewController(), from: UIView())
                     sheet.present(in: UIViewController(), from: UIView())
                     
                     
                     expect(sheet.refreshInvokeCount).to(equal(1))
                     expect(sheet.refreshInvokeCount).to(equal(1))
                 }
                 }
                 
                 
-                it("presents itself by calling presenter") {
+                it("calls presenter") {
                     var counter = 0
                     var counter = 0
                     let completion = { counter += 1 }
                     let completion = { counter += 1 }
-                    let sheet = createSheet()
                     let vc = UIViewController()
                     let vc = UIViewController()
                     let view = UIView()
                     let view = UIView()
                     sheet.present(in: vc, from: view, completion: completion)
                     sheet.present(in: vc, from: view, completion: completion)
@@ -261,16 +344,14 @@ class ActionSheetTests: QuickSpec {
             describe("when presented from bar button item") {
             describe("when presented from bar button item") {
                 
                 
                 it("refreshes itself") {
                 it("refreshes itself") {
-                    let sheet = createSheet()
                     sheet.present(in: UIViewController(), from: UIBarButtonItem())
                     sheet.present(in: UIViewController(), from: UIBarButtonItem())
                     
                     
                     expect(sheet.refreshInvokeCount).to(equal(1))
                     expect(sheet.refreshInvokeCount).to(equal(1))
                 }
                 }
                 
                 
-                it("presents itself by calling presenter") {
+                it("calls presenter") {
                     var counter = 0
                     var counter = 0
                     let completion = { counter += 1 }
                     let completion = { counter += 1 }
-                    let sheet = createSheet()
                     let vc = UIViewController()
                     let vc = UIViewController()
                     let item = UIBarButtonItem()
                     let item = UIBarButtonItem()
                     sheet.present(in: vc, from: item, completion: completion)
                     sheet.present(in: vc, from: item, completion: completion)
@@ -285,191 +366,153 @@ class ActionSheetTests: QuickSpec {
         }
         }
         
         
         
         
-        // MARK: - Refresh Functions
-        
-        describe("when refreshing") {
+        describe("refreshing") {
             
             
-            var sheet: MockActionSheet!
-            var headerViewContainer: UIView!
-            var itemsView: ActionSheetTableView!
-            var buttonsView: ActionSheetTableView!
+            var presenter: MockActionSheetPresenter!
             var stackView: UIStackView!
             var stackView: UIStackView!
             
             
             beforeEach {
             beforeEach {
+                presenter = MockActionSheetPresenter()
+                stackView = UIStackView()
                 sheet = createSheet()
                 sheet = createSheet()
-                sheet.appearance.groupMargins = 123
-                sheet.appearance.cornerRadius = 90
-                headerViewContainer = UIView(frame: .zero)
-                itemsView = createTableView()
-                buttonsView = createTableView()
-                stackView = UIStackView(frame: .zero)
-                sheet.headerViewContainer = headerViewContainer
-                sheet.itemsTableView = itemsView
-                sheet.buttonsTableView = buttonsView
                 sheet.stackView = stackView
                 sheet.stackView = stackView
+                sheet.presenter = presenter
+                sheet.refresh()
             }
             }
             
             
-            context("sheet") {
-                
-                it("applies round corners") {
-                    sheet.refresh()
-                    
-                    expect(headerViewContainer.layer.cornerRadius).to(equal(90))
-                    expect(itemsView.layer.cornerRadius).to(equal(90))
-                    expect(buttonsView.layer.cornerRadius).to(equal(90))
-                }
-                
-                it("applies stack view spacing") {
-                    sheet.refresh()
-                    
-                    expect(sheet.stackView?.spacing).to(equal(123))
-                }
-                
-                it("asks presenter to refresh sheet") {
-                    let presenter = MockActionSheetPresenter()
-                    let sheet = MockActionSheet(items: [], presenter: presenter) { (_, _) in }
-                    sheet.refresh()
-                    
-                    expect(presenter.refreshActionSheetInvokeCount).to(equal(1))
-                }
+            it("refreshes header") {
+                expect(sheet.refreshHeaderInvokeCount).to(equal(1))
             }
             }
             
             
-            context("header") {
-                
-                it("refreshes header visibility") {
-                    sheet.refresh()
-                    expect(sheet.refreshHeaderInvokeCount).to(equal(1))
-                }
-                
-                it("adds header view to header container") {
-                    let header = UIView(frame: .zero)
-                    sheet.headerView = header
-                    expect(header.constraints.count).to(equal(0))
-                    sheet.refresh()
-                    expect(headerViewContainer.subviews.count).to(equal(1))
-                    expect(headerViewContainer.subviews[0]).to(be(header))
-                    expect(header.translatesAutoresizingMaskIntoConstraints).to(beFalse())
-                }
+            it("refreshes items") {
+                expect(sheet.refreshItemsInvokeCount).to(equal(1))
             }
             }
             
             
-            context("header visibility") {
-                
-                it("hides header container if header view is nil") {
-                    sheet.refreshHeader()
-                    expect(headerViewContainer.isHidden).to(beTrue())
-                }
-                
-                it("shows header container if header view is nil") {
-                    sheet.headerView = UIView(frame: .zero)
-                    sheet.refreshHeader()
-                    expect(headerViewContainer.isHidden).to(beFalse())
-                }
+            it("refreshes buttons") {
+                expect(sheet.refreshButtonsInvokeCount).to(equal(1))
             }
             }
             
             
-            context("items") {
-                
-                it("applies appearances to all items") {
-                    let item1 = MockActionSheetItem(title: "foo")
-                    let item2 = MockActionSheetItem(title: "foo")
-                    sheet.setup(items: [item1, item2])
-                    sheet.refresh()
-                    
-                    expect(item1.applyAppearanceInvokeCount).to(equal(1))
-                    expect(item2.applyAppearanceInvokeCount).to(equal(1))
-                    expect(item1.applyAppearanceInvokeAppearances[0]).to(be(sheet.appearance))
-                    expect(item2.applyAppearanceInvokeAppearances[0]).to(be(sheet.appearance))
-                }
-                
-                it("applies background color") {
-                    sheet.appearance.itemsBackgroundColor = .yellow
-                    let view = createTableView()
-                    sheet.itemsTableView = view
-                    sheet.refresh()
-                    
-                    expect(view.backgroundColor).to(equal(.yellow))
-                }
-                
-                it("applies separator color") {
-                    sheet.appearance.itemsSeparatorColor = .yellow
-                    let view = createTableView()
-                    sheet.itemsTableView = view
-                    sheet.refresh()
-
-                    expect(view.separatorColor).to(equal(.yellow))
-                }
+            it("applies stack view spacing") {
+                expect(stackView.spacing).to(equal(15))
             }
             }
             
             
-            context("buttons") {
-                
-                it("refreshes buttons visibility") {
-                    sheet.refresh()
-                    expect(sheet.refreshButtonsInvokeCount).to(equal(1))
-                }
-                
-                it("applies appearances to all buttons") {
-                    let item1 = MockActionSheetButton(title: "foo", value: true)
-                    let item2 = MockActionSheetButton(title: "foo", value: true)
-                    sheet.setup(items: [item1, item2])
-                    sheet.refresh()
-                    
-                    expect(item1.applyAppearanceInvokeCount).to(equal(1))
-                    expect(item2.applyAppearanceInvokeCount).to(equal(1))
-                    expect(item1.applyAppearanceInvokeAppearances[0]).to(be(sheet.appearance))
-                    expect(item2.applyAppearanceInvokeAppearances[0]).to(be(sheet.appearance))
-                }
-                
-                it("applies background color") {
-                    sheet.appearance.buttonsBackgroundColor = .yellow
-                    let view = createTableView()
-                    sheet.buttonsTableView = view
-                    sheet.refresh()
-                    
-                    expect(view.backgroundColor).to(equal(.yellow))
-                }
-                
-                it("applies separator color") {
-                    sheet.appearance.buttonsSeparatorColor = .yellow
-                    let view = createTableView()
-                    sheet.buttonsTableView = view
-                    sheet.refresh()
-                    
-                    expect(view.separatorColor).to(equal(.yellow))
-                }
+            it("calls presenter to refresh itself") {
+                expect(presenter.refreshActionSheetInvokeCount).to(equal(1))
+            }
+        }
+        
+        
+        describe("refreshing header") {
+            
+            var container: ActionSheetHeaderView!
+            var height: NSLayoutConstraint!
+            
+            beforeEach {
+                container = ActionSheetHeaderView()
+                height = NSLayoutConstraint()
+                sheet = createSheet()
+                sheet.headerViewContainer = container
+                sheet.headerViewContainerHeight = height
             }
             }
             
             
-            context("button visibility") {
+            it("refreshes correctly if header view is nil") {
+                sheet.refreshHeader()
                 
                 
-                it("hides buttons if sheet has no buttons") {
-                    sheet.refreshButtons()
-                    expect(buttonsView.isHidden).to(beTrue())
-                }
+                expect(container.isHidden).to(beTrue())
+                expect(container.subviews.count).to(equal(0))
+                expect(height.constant).to(equal(0))
+            }
+            
+            it("refreshes correctly if header view is set") {
+                let view = UIView(frame: CGRect(x: 0, y: 0, width: 100, height: 200))
+                sheet.headerView = view
+                sheet.refreshHeader()
+                
+                expect(container.isHidden).to(beFalse())
+                expect(container.subviews.count).to(equal(1))
+                expect(container.subviews[0]).to(be(view))
+                expect(height.constant).to(equal(200))
+            }
+        }
+        
+        
+        describe("refreshing items") {
+            
+            var height: NSLayoutConstraint!
+            
+            beforeEach {
+                height = NSLayoutConstraint()
+                sheet = createSheet()
+                sheet.itemsTableViewHeight = height
+                ActionSheetItem.height = 12
+                ActionSheetOkButton.height = 13
+            }
+            
+            it("refreshes correctly if no items are set") {
+                sheet.refreshItems()
                 
                 
-                it("shows buttons if sheet has buttons") {
-                    sheet.setup(items: [MockActionSheetButton(title: "foo", value: true)])
-                    sheet.refreshButtons()
-                    expect(buttonsView.isHidden).to(beFalse())
-                }
+                expect(height.constant).to(equal(0))
+            }
+            
+            it("refreshes correctly if items are set") {
+                let item1 = ActionSheetItem(title: "foo")
+                let item2 = ActionSheetItem(title: "foo")
+                let button = ActionSheetOkButton(title: "foo")
+                sheet.setup(items: [item1, item2, button])
+                sheet.refreshItems()
+                
+                expect(height.constant).to(equal(24))
             }
             }
         }
         }
         
         
         
         
-        // MARK: - Protected Functions
+        describe("refreshing buttons") {
+            
+            var height: NSLayoutConstraint!
+            
+            beforeEach {
+                height = NSLayoutConstraint()
+                sheet = createSheet()
+                sheet.buttonsTableViewHeight = height
+                ActionSheetItem.height = 12
+                ActionSheetOkButton.height = 13
+            }
+            
+            it("refreshes correctly if no items are set") {
+                sheet.refreshButtons()
+                
+                expect(height.constant).to(equal(0))
+            }
+            
+            it("refreshes correctly if items are set") {
+                let item = ActionSheetItem(title: "foo")
+                let button1 = ActionSheetOkButton(title: "foo")
+                let button2 = ActionSheetOkButton(title: "foo")
+                sheet.setup(items: [item, button1, button2])
+                sheet.refreshButtons()
+                
+                expect(height.constant).to(equal(26))
+            }
+        }
+        
         
         
         describe("handling tap on item") {
         describe("handling tap on item") {
             
             
-            it("reloads data") {
-                let sheet = createSheet()
+            beforeEach {
+                sheet = createSheet()
                 sheet.reloadDataInvokeCount = 0
                 sheet.reloadDataInvokeCount = 0
-                sheet.handleTap(on: createItem(""))
+            }
+            
+            it("reloads data") {
+                sheet.handleTap(on: ActionSheetItem(title: ""))
                 
                 
                 expect(sheet.reloadDataInvokeCount).to(equal(1))
                 expect(sheet.reloadDataInvokeCount).to(equal(1))
             }
             }
             
             
             it("calls select action without dismiss if item has none tap action") {
             it("calls select action without dismiss if item has none tap action") {
                 var count = 0
                 var count = 0
-                let sheet = MockActionSheet(items: []) { (_, _) in count += 1 }
-                let item = createItem("")
-                item.tapBehavior = .none
+                sheet = MockActionSheet { (_, _) in count += 1 }
+                let item = ActionSheetItem(title: "", tapBehavior: .none)
                 sheet.handleTap(on: item)
                 sheet.handleTap(on: item)
                 
                 
                 expect(count).to(equal(1))
                 expect(count).to(equal(1))
@@ -478,34 +521,49 @@ class ActionSheetTests: QuickSpec {
             
             
             it("calls select action after dismiss if item has dismiss tap action") {
             it("calls select action after dismiss if item has dismiss tap action") {
                 var count = 0
                 var count = 0
-                let sheet = MockActionSheet(items: []) { (_, _) in count += 1 }
-                let item = createItem("")
-                item.tapBehavior = .dismiss
+                sheet = MockActionSheet { (_, _) in count += 1 }
+                let item = ActionSheetItem(title: "", tapBehavior: .dismiss)
                 sheet.handleTap(on: item)
                 sheet.handleTap(on: item)
-//                expect(count).toEventually(equal(1), time)        TODO
-//                expect(sheet.dismissInvokeCount).to(equal(1))     TODO
+                
+                expect(count).to(equal(1))
+                expect(sheet.dismissInvokeCount).to(equal(1))
             }
             }
         }
         }
         
         
+        
         describe("margin at position") {
         describe("margin at position") {
             
             
-            it("uses apperance if no superview value exists") {
+            beforeEach {
+                sheet = createSheet()
+            }
+            
+            it("ignores custom edge margins with smaller value than the default ones") {
                 let sheet = createSheet()
                 let sheet = createSheet()
-                sheet.appearance.contentInset = 80
+                sheet.minimumContentInsets = UIEdgeInsets(top: -1, left: -1, bottom: -1, right: -1)
                 
                 
-                expect(sheet.margin(at: .top)).to(equal(80))
-                expect(sheet.margin(at: .left)).to(equal(80))
-                expect(sheet.margin(at: .right)).to(equal(80))
-                expect(sheet.margin(at: .bottom)).to(equal(80))
+                expect(sheet.margin(at: .top)).to(equal(sheet.view.safeAreaInsets.top))
+                expect(sheet.margin(at: .left)).to(equal(sheet.view.safeAreaInsets.left))
+                expect(sheet.margin(at: .right)).to(equal(sheet.view.safeAreaInsets.right))
+                expect(sheet.margin(at: .bottom)).to(equal(sheet.view.safeAreaInsets.bottom))
+            }
+
+            it("uses custom edge margins with greated value than the default ones") {
+                let sheet = createSheet()
+                sheet.minimumContentInsets = UIEdgeInsets(top: 111, left: 222, bottom: 333, right: 444)
+                
+                expect(sheet.margin(at: .top)).to(equal(111))
+                expect(sheet.margin(at: .left)).to(equal(222))
+                expect(sheet.margin(at: .bottom)).to(equal(333))
+                expect(sheet.margin(at: .right)).to(equal(444))
             }
             }
         }
         }
         
         
         describe("reloading data") {
         describe("reloading data") {
             
             
             it("reloads both table views") {
             it("reloads both table views") {
-                let view1 = MockTableView(frame: .zero)
-                let view2 = MockTableView(frame: .zero)
-                let sheet = createSheet()
+                let view1 = MockItemTableView(frame: .zero)
+                let view2 = MockButtonTableView(frame: .zero)
+                sheet = createSheet()
                 sheet.itemsTableView = view1
                 sheet.itemsTableView = view1
                 sheet.buttonsTableView = view2
                 sheet.buttonsTableView = view2
                 sheet.reloadData()
                 sheet.reloadData()

+ 22 - 0
Carthage/Checkouts/Sheeeeeeeeet/SheeeeeeeeetTests/ActionSheet/MockActionSheet.swift

@@ -11,6 +11,17 @@ class MockActionSheet: ActionSheet {
     var refreshItemsInvokeCount = 0
     var refreshItemsInvokeCount = 0
     var refreshHeaderInvokeCount = 0
     var refreshHeaderInvokeCount = 0
     var reloadDataInvokeCount = 0
     var reloadDataInvokeCount = 0
+    var setupInvokeCount = 0
+    var setupItemsInvokeCount = 0
+    var setupItemsInvokeItems = [[ActionSheetItem]]()
+    
+    
+    private var _presentingViewController: UIViewController?
+    override var presentingViewController: UIViewController? {
+        get { return _presentingViewController }
+        set { _presentingViewController = newValue }
+    }
+    
     
     
     override func dismiss(completion: @escaping () -> ()) {
     override func dismiss(completion: @escaping () -> ()) {
         super.dismiss { completion() }
         super.dismiss { completion() }
@@ -47,4 +58,15 @@ class MockActionSheet: ActionSheet {
         super.reloadData()
         super.reloadData()
         reloadDataInvokeCount += 1
         reloadDataInvokeCount += 1
     }
     }
+    
+    override func setup() {
+        super.setup()
+        setupInvokeCount += 1
+    }
+    
+    override func setup(items: [ActionSheetItem]) {
+        super.setup(items: items)
+        setupItemsInvokeCount += 1
+        setupItemsInvokeItems.append(items)
+    }
 }
 }

+ 4 - 4
Carthage/Checkouts/Sheeeeeeeeet/SheeeeeeeeetTests/Extensions/NSObject+ClassNameTests.swift

@@ -20,15 +20,15 @@ class NSObject_ClassNameTests: QuickSpec {
                 expect(ActionSheet.className).to(equal("ActionSheet"))
                 expect(ActionSheet.className).to(equal("ActionSheet"))
             }
             }
             
             
-            it("is valid for inherited type") {
-                expect(TestSheet.className).to(equal("TestSheet"))
-            }
-            
             it("is valid for base type instance") {
             it("is valid for base type instance") {
                 let obj = ActionSheet(items: []) { _, _ in }
                 let obj = ActionSheet(items: []) { _, _ in }
                 expect(obj.className).to(equal("ActionSheet"))
                 expect(obj.className).to(equal("ActionSheet"))
             }
             }
             
             
+            it("is valid for inherited type") {
+                expect(TestSheet.className).to(equal("TestSheet"))
+            }
+            
             it("is valid for inherited type instance") {
             it("is valid for inherited type instance") {
                 let obj = TestSheet(items: []) { _, _ in }
                 let obj = TestSheet(items: []) { _, _ in }
                 expect(obj.className).to(equal("TestSheet"))
                 expect(obj.className).to(equal("TestSheet"))

+ 2 - 2
Carthage/Checkouts/Sheeeeeeeeet/SheeeeeeeeetTests/Info.plist

@@ -15,8 +15,8 @@
 	<key>CFBundlePackageType</key>
 	<key>CFBundlePackageType</key>
 	<string>BNDL</string>
 	<string>BNDL</string>
 	<key>CFBundleShortVersionString</key>
 	<key>CFBundleShortVersionString</key>
-	<string>1.1.0</string>
+	<string>1.2.2</string>
 	<key>CFBundleVersion</key>
 	<key>CFBundleVersion</key>
-	<string>1901101458</string>
+	<string>1901161647</string>
 </dict>
 </dict>
 </plist>
 </plist>

+ 90 - 135
Carthage/Checkouts/Sheeeeeeeeet/SheeeeeeeeetTests/Items/ActionSheetItemTests.swift

@@ -8,194 +8,149 @@
 
 
 import Quick
 import Quick
 import Nimble
 import Nimble
-import Sheeeeeeeeet
+@testable import Sheeeeeeeeet
 
 
 class ActionSheetItemTests: QuickSpec {
 class ActionSheetItemTests: QuickSpec {
     
     
-    func prepareStandardAppearance() {
-        let appearance = ActionSheetAppearance.standard.item
-        appearance.backgroundColor = .red
-        appearance.font = UIFont.systemFont(ofSize: 31)
-        appearance.height = 314
-        appearance.separatorInsets = UIEdgeInsets(top: 1, left: 20, bottom: 3, right: 40)
-        appearance.textColor = .green
-        appearance.tintColor = .blue
-        appearance.subtitleFont = UIFont.systemFont(ofSize: 34)
-        appearance.subtitleTextColor = .yellow
-    }
-    
-    func restoreStandardAppearance() {
-        let appearance = ActionSheetAppearance.standard.item
-        appearance.backgroundColor = nil
-        appearance.font = nil
-        appearance.height = 50
-        appearance.separatorInsets = .zero
-        appearance.textColor = nil
-        appearance.tintColor = nil
-        appearance.subtitleFont = nil
-        appearance.subtitleTextColor = nil
-    }
-    
-    func compare(
-        _ appearance1: ActionSheetItemAppearance,
-        _ appearance2: ActionSheetItemAppearance,
-        textColor: UIColor? = nil) -> Bool {
-        let textColor = textColor ?? appearance2.textColor
-        return appearance1.backgroundColor == appearance2.backgroundColor
-            && appearance1.font == appearance2.font
-            && appearance1.height == appearance2.height
-            && appearance1.separatorInsets == appearance2.separatorInsets
-            && appearance1.textColor == textColor
-            && appearance1.tintColor == appearance2.tintColor
-            && appearance1.subtitleFont == appearance2.subtitleFont
-            && appearance1.subtitleTextColor == appearance2.subtitleTextColor
-    }
-    
-    func compare(
-        _ cell: UITableViewCell,
-        item: ActionSheetItem,
-        appearance: ActionSheetItemAppearance,
-        textColor: UIColor? = nil,
-        textAlignment: NSTextAlignment = .left) -> Bool {
-        let compareColor = textColor ?? appearance.textColor
-        return cell.imageView?.image == item.image
-            && cell.selectionStyle == .default
-            //&& cell.separatorInset == appearance.item.separatorInsets))
-            && cell.tintColor == appearance.tintColor
-            && cell.textLabel?.text == item.title
-            && cell.textLabel?.textAlignment == textAlignment
-            && cell.textLabel?.textColor == compareColor
-            && cell.textLabel?.font == appearance.font
-            && cell.detailTextLabel?.text == item.subtitle
-            && cell.detailTextLabel?.textColor == appearance.subtitleTextColor
-            && cell.detailTextLabel?.font == appearance.subtitleFont
-    }
-    
-    
     override func spec() {
     override func spec() {
         
         
         func createItem(subtitle: String? = nil) -> MockActionSheetItem {
         func createItem(subtitle: String? = nil) -> MockActionSheetItem {
             return MockActionSheetItem(title: "foo", subtitle: subtitle, value: true, image: UIImage())
             return MockActionSheetItem(title: "foo", subtitle: subtitle, value: true, image: UIImage())
-            
         }
         }
         
         
         func createItem(_ tapBehavior: ActionSheetItem.TapBehavior) -> MockActionSheetItem {
         func createItem(_ tapBehavior: ActionSheetItem.TapBehavior) -> MockActionSheetItem {
             return MockActionSheetItem(title: "foo", subtitle: "bar", value: true, image: UIImage(), tapBehavior: tapBehavior)
             return MockActionSheetItem(title: "foo", subtitle: "bar", value: true, image: UIImage(), tapBehavior: tapBehavior)
         }
         }
         
         
-        beforeEach {
-            self.prepareStandardAppearance()
-        }
-        
-        afterEach {
-            self.restoreStandardAppearance()
-        }
-        
-        describe("when created") {
+        describe("created instance") {
+            
+            it("applies default values") {
+                let item = ActionSheetItem(title: "foo")
+                
+                expect(item.title).to(equal("foo"))
+                expect(item.subtitle).to(beNil())
+                expect(item.value).to(beNil())
+                expect(item.image).to(beNil())
+                expect(item.tapBehavior).to(equal(.dismiss))
+                expect(item.cellStyle).to(equal(.default))
+            }
             
             
             it("applies provided values") {
             it("applies provided values") {
-                let item = createItem(.none)
+                let image = UIImage()
+                let item = ActionSheetItem(title: "foo", subtitle: "bar", value: true, image: image, tapBehavior: .none)
+                
                 expect(item.title).to(equal("foo"))
                 expect(item.title).to(equal("foo"))
                 expect(item.subtitle).to(equal("bar"))
                 expect(item.subtitle).to(equal("bar"))
                 expect(item.value as? Bool).to(equal(true))
                 expect(item.value as? Bool).to(equal(true))
-                expect(item.image).toNot(beNil())
+                expect(item.image).to(be(image))
                 expect(item.tapBehavior).to(equal(ActionSheetItem.TapBehavior.none))
                 expect(item.tapBehavior).to(equal(ActionSheetItem.TapBehavior.none))
-            }
-            
-            it("uses dismiss tap behavior by default") {
-                let item = createItem()
-                expect(item.tapBehavior).to(equal(ActionSheetItem.TapBehavior.dismiss))
-            }
-            
-            it("copies standard item appearance initially") {
-                let item = createItem()
-                let standard = ActionSheetAppearance.standard.item
-                let isEqual = self.compare(item.appearance, standard)
-                expect(isEqual).to(beTrue())
+                expect(item.cellStyle).to(equal(.value1))
             }
             }
         }
         }
         
         
+        
         describe("cell reuse identifier") {
         describe("cell reuse identifier") {
             
             
             it("is class name") {
             it("is class name") {
                 let item = createItem()
                 let item = createItem()
+                
                 expect(item.cellReuseIdentifier).to(equal("MockActionSheetItem"))
                 expect(item.cellReuseIdentifier).to(equal("MockActionSheetItem"))
             }
             }
         }
         }
         
         
-        describe("cell style") {
+        
+        describe("height") {
             
             
-            it("is default if no subtitle is set") {
-                let item = createItem(subtitle: nil)
-                expect(item.cellStyle).to(equal(.default))
+            let preset = CustomItem.height
+            
+            afterEach {
+                CustomItem.height = preset
             }
             }
             
             
-            it("is value1 if subtitle is set") {
-                let item = createItem(subtitle: "bar")
-                expect(item.cellStyle).to(equal(.value1))
+            it("uses standard height if no custom value is registered") {
+                expect(ActionSheetItem.height).to(equal(50))
             }
             }
-        }
-        
-        describe("custom appearance") {
             
             
-            it("is nil by default") {
-                let item = createItem()
-                expect(item.customAppearance).to(beNil())
+            it("only uses custom height for registered type") {
+                CustomItem.height = 123
+                
+                expect(CustomItem.height).to(equal(123))
+                expect(CustomItem(title: "").height).to(equal(123))
+                expect(ActionSheetItem.height).to(equal(50))
             }
             }
         }
         }
         
         
-        describe("applying appearance") {
-            
-            it("applies standard copy if no custom appearance is set") {
-                let item = createItem()
-                item.applyAppearance(ActionSheetAppearance.standard)
-                expect(self.compare(item.appearance, ActionSheetAppearance.standard.item)).to(beTrue())
-            }
+        
+        describe("resolving cell") {
             
             
-            it("applies custom appearance if set") {
+            it("returns correct cell") {
                 let item = createItem()
                 let item = createItem()
-                let standard = ActionSheetAppearance.standard
-                let custom = ActionSheetAppearance(copy: standard)
-                custom.item.backgroundColor = .yellow
-                item.customAppearance = custom.item
-                item.applyAppearance(standard)
-                expect(item.appearance).to(be(custom.item))
+                let cell = item.cell(for: UITableView(frame: .zero))
+                
+                expect(cell.reuseIdentifier).to(equal(item.cellReuseIdentifier))
             }
             }
         }
         }
+    }
+}
+
+
+class ActionSheetItemCellTests: QuickSpec {
+    
+    override func spec() {
         
         
-        describe("applying appearance to cell") {
-            
-            it("applies correct style") {
-                let item = createItem()
-                let appearance = ActionSheetAppearance.standard
-                let cell = UITableViewCell(style: .subtitle, reuseIdentifier: "Cell")
-                item.applyAppearance(appearance)
-                item.applyAppearance(to: cell)
-                expect(self.compare(cell, item: item, appearance: appearance.item)).to(beTrue())
-            }
+        var cell: ActionSheetItemCell!
+        var item: ActionSheetItem! {
+            didSet { cell = item.cell(for: UITableView()) }
         }
         }
         
         
+        beforeEach {
+            item = ActionSheetItem(title: "foo")
+        }
         
         
         
         
-        describe("resolving cell") {
+        describe("moving to window") {
             
             
-            func tableView() -> UITableView {
-                return UITableView(frame: .zero)
+            it("refreshes cell") {
+                cell.refresh(with: item)
+                cell.textLabel?.text = ""
+                cell.didMoveToWindow()
+                
+                expect(cell.textLabel?.text).to(equal("foo"))
             }
             }
+        }
+        
+        
+        describe("refreshing") {
             
             
-            it("always returns a cell even if table view fails to dequeue") {
-                let item = createItem()
-                let cell = item.cell(for: tableView())
-                expect(cell).toNot(beNil())
+            it("aborts if cell has no item reference") {
+                cell.refresh()
+                
+                expect(cell.textLabel?.text).to(beNil())
             }
             }
             
             
-            it("applies appearance to cell") {
-                let item = createItem()
-                let cell = item.cell(for: tableView())
-                expect(item.applyAppearanceInvokeCount).to(equal(1))
-                expect(item.applyAppearanceInvokeCells.count).to(equal(1))
-                expect(item.applyAppearanceInvokeCells[0]).to(be(cell))
+            it("refreshes if cell has item reference") {
+                let image = UIImage()
+                item = ActionSheetItem(title: "foo", subtitle: "bar", value: "baz", image: image)
+                cell.titleColor = .yellow
+                cell.titleFont = .boldSystemFont(ofSize: 1)
+                cell.subtitleColor = .brown
+                cell.subtitleFont = .boldSystemFont(ofSize: 2)
+                
+                cell.refresh(with: item)
+                
+                expect(cell.imageView?.image).to(be(image))
+                expect(cell.selectionStyle).to(equal(.default))
+                expect(cell.textLabel?.font).toNot(beNil())
+                expect(cell.textLabel?.font).to(be(cell.titleFont))
+                expect(cell.textLabel?.text).to(equal("foo"))
+                expect(cell.textLabel?.textAlignment).to(equal(.left))
+                expect(cell.detailTextLabel?.font).toNot(beNil())
+                expect(cell.detailTextLabel?.font).to(be(cell.subtitleFont))
+                expect(cell.detailTextLabel?.text).to(equal("bar"))
             }
             }
         }
         }
     }
     }
 }
 }
+
+
+private class CustomItem: ActionSheetItem {}

+ 41 - 38
Carthage/Checkouts/Sheeeeeeeeet/SheeeeeeeeetTests/Items/Buttons/ActionSheetButtonTests.swift

@@ -10,73 +10,76 @@ import Quick
 import Nimble
 import Nimble
 import Sheeeeeeeeet
 import Sheeeeeeeeet
 
 
-class ActionSheetButtonTests: ActionSheetItemTests {
+class ActionSheetButtonTests: QuickSpec {
     
     
     override func spec() {
     override func spec() {
         
         
         var item: ActionSheetButton!
         var item: ActionSheetButton!
         
         
-        beforeEach {
-            item = ActionSheetButton(title: "foo", type: .ok)
-            self.prepareStandardAppearance()
-        }
-        
-        afterEach {
-            self.restoreStandardAppearance()
-        }
         
         
         describe("when created with value") {
         describe("when created with value") {
             
             
-            beforeEach {
+            it("is correctly setup") {
                 item = ActionSheetButton(title: "foo", value: "bar")
                 item = ActionSheetButton(title: "foo", value: "bar")
-            }
-            
-            it("applies provided values") {
+                
                 expect(item.title).to(equal("foo"))
                 expect(item.title).to(equal("foo"))
                 expect(item.value as? String).to(equal("bar"))
                 expect(item.value as? String).to(equal("bar"))
-            }
-            
-            it("is correctly setup") {
                 expect(item.isOkButton).to(beFalse())
                 expect(item.isOkButton).to(beFalse())
             }
             }
         }
         }
         
         
-        describe("when created with type") {
+        
+        describe("when created with button type") {
             
             
-            it("applies provided values") {
+            it("is correctly setup") {
+                item = ActionSheetButton(title: "foo", type: .ok)
+                
                 expect(item.title).to(equal("foo"))
                 expect(item.title).to(equal("foo"))
+                expect(item.value as? ActionSheetButton.ButtonType).to(equal(.ok))
             }
             }
+        }
+        
+        
+        describe("cell") {
             
             
-            it("is correctly setup") {
-                expect(item.value as? ActionSheetButton.ButtonType).to(equal(.ok))
-                expect(item.isOkButton).to(beTrue())
+            it("is of correct type") {
+                item = ActionSheetButton(title: "foo", type: .ok)
+                let cell = item.cell(for: UITableView())
+                
+                expect(cell is ActionSheetButtonCell).to(beTrue())
+                expect(cell.reuseIdentifier).to(equal(item.cellReuseIdentifier))
             }
             }
         }
         }
         
         
-        describe("applying appearance") {
+        
+        describe("button type") {
             
             
-            it("applies standard copy if no custom appearance is set") {
-                item.applyAppearance(ActionSheetAppearance.standard)
-                expect(self.compare(item.appearance, ActionSheetAppearance.standard.okButton)).to(beTrue())
+            func createItem(type: ActionSheetButton.ButtonType) -> ActionSheetButton {
+                return ActionSheetButton(title: "foo", type: type)
             }
             }
             
             
-            it("applies custom appearance if set") {
-                let standard = ActionSheetAppearance.standard
-                let custom = ActionSheetAppearance(copy: standard)
-                item.customAppearance = custom.okButton
-                item.applyAppearance(standard)
-                expect(item.appearance).to(be(custom.okButton))
+            it("is correct for each button type") {
+                expect(createItem(type: .cancel).isOkButton).to(beFalse())
+                expect(createItem(type: .cancel).isCancelButton).to(beTrue())
+                expect(createItem(type: .ok).isOkButton).to(beTrue())
+                expect(createItem(type: .ok).isCancelButton).to(beFalse())
             }
             }
         }
         }
+    }
+}
+
+
+class ActionSheetButtonCellTests: QuickSpec {
+    
+    override func spec() {
         
         
-        describe("applying appearance to cell") {
+        describe("refreshing") {
             
             
-            it("applies correct style") {
-                let appearance = ActionSheetAppearance.standard
-                let cell = UITableViewCell(style: .subtitle, reuseIdentifier: "Cell")
-                item.applyAppearance(appearance)
-                item.applyAppearance(to: cell)
-                expect(self.compare(cell, item: item, appearance: appearance.okButton, textAlignment: .center)).to(beTrue())
+            it("center aligns text label") {
+                let item = ActionSheetButton(title: "", value: nil)
+                let cell = item.cell(for: UITableView())
+                cell.refresh()
+                expect(cell.textLabel?.textAlignment).to(equal(.center))
             }
             }
         }
         }
     }
     }

+ 16 - 20
Carthage/Checkouts/Sheeeeeeeeet/SheeeeeeeeetTests/Items/Buttons/ActionSheetCancelButtonTests.swift

@@ -10,37 +10,33 @@ import Quick
 import Nimble
 import Nimble
 import Sheeeeeeeeet
 import Sheeeeeeeeet
 
 
-class ActionSheetCancelButtonTests: ActionSheetItemTests {
+class ActionSheetCancelButtonTests: QuickSpec {
     
     
     override func spec() {
     override func spec() {
         
         
-        let item = ActionSheetCancelButton(title: "foo")
+        var item: ActionSheetCancelButton!
         
         
-        describe("when created") {
-            
-            it("applies provided values") {
-                expect(item.title).to(equal("foo"))
-            }
+        beforeEach {
+            item = ActionSheetCancelButton(title: "cancel")
+        }
+        
+        
+        describe("created instance") {
             
             
             it("is correctly setup") {
             it("is correctly setup") {
+                expect(item.title).to(equal("cancel"))
                 expect(item.value as? ActionSheetButton.ButtonType).to(equal(.cancel))
                 expect(item.value as? ActionSheetButton.ButtonType).to(equal(.cancel))
-                expect(item.isCancelButton).to(beTrue())
             }
             }
         }
         }
         
         
-        describe("applying appearance") {
-            
-            it("applies standard copy if no custom appearance is set") {
-                item.applyAppearance(ActionSheetAppearance.standard)
-                expect(self.compare(item.appearance, ActionSheetAppearance.standard.cancelButton)).to(beTrue())
-            }
+        
+        describe("cell") {
             
             
-            it("applies custom appearance if set") {
-                let standard = ActionSheetAppearance.standard
-                let custom = ActionSheetAppearance(copy: standard)
-                item.customAppearance = custom.cancelButton
-                item.applyAppearance(standard)
-                expect(item.appearance).to(be(custom.cancelButton))
+            it("is of correct type") {
+                let cell = item.cell(for: UITableView())
+                
+                expect(cell is ActionSheetCancelButtonCell).to(beTrue())
+                expect(cell.reuseIdentifier).to(equal(item.cellReuseIdentifier))
             }
             }
         }
         }
     }
     }

+ 16 - 20
Carthage/Checkouts/Sheeeeeeeeet/SheeeeeeeeetTests/Items/Buttons/ActionSheetDangerButtonTests.swift

@@ -10,37 +10,33 @@ import Quick
 import Nimble
 import Nimble
 import Sheeeeeeeeet
 import Sheeeeeeeeet
 
 
-class ActionSheetDangerButtonTests: ActionSheetItemTests {
+class ActionSheetDangerButtonTests: QuickSpec {
     
     
     override func spec() {
     override func spec() {
         
         
-        let item = ActionSheetDangerButton(title: "foo")
+        var item: ActionSheetDangerButton!
         
         
-        describe("when created") {
-            
-            it("applies provided values") {
-                expect(item.title).to(equal("foo"))
-            }
+        beforeEach {
+            item = ActionSheetDangerButton(title: "danger")
+        }
+        
+        
+        describe("created instance") {
             
             
             it("is correctly setup") {
             it("is correctly setup") {
+                expect(item.title).to(equal("danger"))
                 expect(item.value as? ActionSheetButton.ButtonType).to(equal(.ok))
                 expect(item.value as? ActionSheetButton.ButtonType).to(equal(.ok))
-                expect(item.isOkButton).to(beTrue())
             }
             }
         }
         }
         
         
-        describe("applying appearance") {
-            
-            it("applies standard copy if no custom appearance is set") {
-                item.applyAppearance(ActionSheetAppearance.standard)
-                expect(self.compare(item.appearance, ActionSheetAppearance.standard.dangerButton, textColor: .red)).to(beTrue())
-            }
+        
+        describe("cell") {
             
             
-            it("applies custom appearance if set") {
-                let standard = ActionSheetAppearance.standard
-                let custom = ActionSheetAppearance(copy: standard)
-                item.customAppearance = custom.dangerButton
-                item.applyAppearance(standard)
-                expect(item.appearance).to(be(custom.dangerButton))
+            it("is of correct type") {
+                let cell = item.cell(for: UITableView())
+                
+                expect(cell is ActionSheetDangerButtonCell).to(beTrue())
+                expect(cell.reuseIdentifier).to(equal(item.cellReuseIdentifier))
             }
             }
         }
         }
     }
     }

+ 16 - 20
Carthage/Checkouts/Sheeeeeeeeet/SheeeeeeeeetTests/Items/Buttons/ActionSheetOkButtonTests.swift

@@ -10,37 +10,33 @@ import Quick
 import Nimble
 import Nimble
 import Sheeeeeeeeet
 import Sheeeeeeeeet
 
 
-class ActionSheetOkButtonTests: ActionSheetItemTests {
+class ActionSheetOkButtonTests: QuickSpec {
     
     
     override func spec() {
     override func spec() {
         
         
-        let item = ActionSheetOkButton(title: "foo")
+        var item: ActionSheetOkButton!
         
         
-        describe("when created") {
-            
-            it("applies provided values") {
-                expect(item.title).to(equal("foo"))
-            }
+        beforeEach {
+            item = ActionSheetOkButton(title: "ok")
+        }
+        
+        
+        describe("created instance") {
             
             
             it("is correctly setup") {
             it("is correctly setup") {
+                expect(item.title).to(equal("ok"))
                 expect(item.value as? ActionSheetButton.ButtonType).to(equal(.ok))
                 expect(item.value as? ActionSheetButton.ButtonType).to(equal(.ok))
-                expect(item.isOkButton).to(beTrue())
             }
             }
         }
         }
         
         
-        describe("applying appearance") {
-            
-            it("applies standard copy if no custom appearance is set") {
-                item.applyAppearance(ActionSheetAppearance.standard)
-                expect(self.compare(item.appearance, ActionSheetAppearance.standard.okButton)).to(beTrue())
-            }
+        
+        describe("cell") {
             
             
-            it("applies custom appearance if set") {
-                let standard = ActionSheetAppearance.standard
-                let custom = ActionSheetAppearance(copy: standard)
-                item.customAppearance = custom.okButton
-                item.applyAppearance(standard)
-                expect(item.appearance).to(be(custom.okButton))
+            it("is of correct type") {
+                let cell = item.cell(for: UITableView())
+                
+                expect(cell is ActionSheetOkButtonCell).to(beTrue())
+                expect(cell.reuseIdentifier).to(equal(item.cellReuseIdentifier))
             }
             }
         }
         }
     }
     }

+ 24 - 10
Carthage/Checkouts/Sheeeeeeeeet/SheeeeeeeeetTests/Items/Items/ActionSheetLinkItemTests.swift

@@ -14,21 +14,35 @@ class ActionSheetLinkItemTests: QuickSpec {
     
     
     override func spec() {
     override func spec() {
         
         
-        let item = ActionSheetLinkItem(title: "foo", value: true, image: UIImage())
-        
-        describe("when created") {
+        describe("cell") {
             
             
-            it("applies provided values") {
-                expect(item.title).to(equal("foo"))
-                expect(item.value as? Bool).to(equal(true))
-                expect(item.image).toNot(beNil())
+            it("is of correct type") {
+                let item = ActionSheetLinkItem(title: "foo")
+                let cell = item.cell(for: UITableView())
+                
+                expect(cell is ActionSheetLinkItemCell).to(beTrue())
+                expect(cell.reuseIdentifier).to(equal(item.cellReuseIdentifier))
             }
             }
         }
         }
+    }
+}
+
+
+class ActionSheetLinkItemCellTests: QuickSpec {
+    
+    override func spec() {
         
         
-        describe("tap behavior") {
+        describe("refreshing") {
             
             
-            it("is dismiss") {
-                expect(item.tapBehavior).to(equal(ActionSheetItem.TapBehavior.dismiss))
+            it("applies accessory view with link icon") {
+                let item = ActionSheetLinkItem(title: "foo")
+                let cell = item.cell(for: UITableView()) as? ActionSheetLinkItemCell
+                cell?.linkIcon = UIImage()
+                cell?.refresh()
+                let imageView = cell?.accessoryView as? UIImageView
+                
+                expect(imageView?.image).toNot(beNil())
+                expect(imageView?.image).to(be(cell?.linkIcon))
             }
             }
         }
         }
     }
     }

+ 46 - 15
Carthage/Checkouts/Sheeeeeeeeet/SheeeeeeeeetTests/Items/Items/ActionSheetMultiSelectItemTests.swift

@@ -14,31 +14,62 @@ class ActionSheetMultiSelectItemTests: QuickSpec {
     
     
     override func spec() {
     override func spec() {
         
         
-        func getItem(isSelected: Bool, group: String = "") -> ActionSheetMultiSelectItem {
-            return ActionSheetMultiSelectItem(title: "foo", isSelected: isSelected, group: group, value: true, image: UIImage())
-        }
-        
-        describe("when created") {
+        describe("instance") {
+            
+            it("can be created with default values") {
+                let item = ActionSheetMultiSelectItem(title: "foo", isSelected: false)
+                expect(item.title).to(equal("foo"))
+                expect(item.isSelected).to(beFalse())
+                expect(item.group).to(equal(""))
+                expect(item.value).to(beNil())
+                expect(item.image).to(beNil())
+                expect(item.tapBehavior).to(equal(ActionSheetItem.TapBehavior.none))
+            }
             
             
-            it("applies provided values") {
-                let item = getItem(isSelected: true, group: "my group")
+            it("can be created with custom values") {
+                let item = ActionSheetMultiSelectItem(title: "foo", isSelected: true, group: "group", value: true, image: UIImage())
                 expect(item.title).to(equal("foo"))
                 expect(item.title).to(equal("foo"))
-                expect(item.group).to(equal("my group"))
+                expect(item.isSelected).to(beTrue())
+                expect(item.group).to(equal("group"))
                 expect(item.value as? Bool).to(equal(true))
                 expect(item.value as? Bool).to(equal(true))
                 expect(item.image).toNot(beNil())
                 expect(item.image).toNot(beNil())
+                expect(item.tapBehavior).to(equal(ActionSheetItem.TapBehavior.none))
             }
             }
+        }
+        
+        
+        describe("cell") {
             
             
-            it("applies provided selection state") {
-                expect(getItem(isSelected: true).isSelected).to(beTrue())
-                expect(getItem(isSelected: false).isSelected).to(beFalse())
+            it("is of correct type") {
+                let item = ActionSheetMultiSelectItem(title: "foo", isSelected: false)
+                let cell = item.cell(for: UITableView())
+                
+                expect(cell is ActionSheetMultiSelectItemCell).to(beTrue())
+                expect(cell.reuseIdentifier).to(equal(item.cellReuseIdentifier))
             }
             }
         }
         }
         
         
-        describe("tap behavior") {
+        
+        describe("handling tap") {
             
             
-            it("is none") {
-                let item = getItem(isSelected: true)
-                expect(item.tapBehavior).to(equal(ActionSheetItem.TapBehavior.none))
+            it("updates toggle item in the same group") {
+                let item1 = ActionSheetMultiSelectItem(title: "foo", isSelected: false, group: "group 1")
+                let item2 = ActionSheetMultiSelectItem(title: "bar", isSelected: false, group: "group 2")
+                let item3 = ActionSheetMultiSelectItem(title: "baz", isSelected: false, group: "group 1")
+                let toggle1 = ActionSheetMultiSelectToggleItem(title: "toggle 1", state: .selectAll, group: "group 1", selectAllTitle: "", deselectAllTitle: "")
+                let toggle2 = ActionSheetMultiSelectToggleItem(title: "toggle 2", state: .selectAll, group: "group 2", selectAllTitle: "", deselectAllTitle: "")
+                let items = [item1, item2, item3, toggle1, toggle2]
+                let sheet = ActionSheet(items: items) { (_, _) in }
+                
+                item1.handleTap(in: sheet)
+                expect(toggle1.state).to(equal(.selectAll))
+                expect(toggle2.state).to(equal(.selectAll))
+                item2.handleTap(in: sheet)
+                expect(toggle1.state).to(equal(.selectAll))
+                expect(toggle2.state).to(equal(.deselectAll))
+                item3.handleTap(in: sheet)
+                expect(toggle1.state).to(equal(.deselectAll))
+                expect(toggle2.state).to(equal(.deselectAll))
             }
             }
         }
         }
     }
     }

+ 59 - 11
Carthage/Checkouts/Sheeeeeeeeet/SheeeeeeeeetTests/Items/Items/ActionSheetMultiSelectToggleItemTests.swift

@@ -14,32 +14,80 @@ class ActionSheetMultiSelectToggleItemTests: QuickSpec {
     
     
     override func spec() {
     override func spec() {
         
         
-        func getItem(group: String = "") -> ActionSheetMultiSelectToggleItem {
+        func createItem(group: String) -> ActionSheetMultiSelectToggleItem {
             return ActionSheetMultiSelectToggleItem(title: "foo", state: .selectAll, group: group, selectAllTitle: "select all", deselectAllTitle: "deselect all")
             return ActionSheetMultiSelectToggleItem(title: "foo", state: .selectAll, group: group, selectAllTitle: "select all", deselectAllTitle: "deselect all")
         }
         }
         
         
-        describe("when created") {
+        describe("instance") {
             
             
-            it("applies provided values") {
-                let item = getItem(group: "my group")
+            it("can be created with custom values") {
+                let item = createItem(group: "group")
                 expect(item.title).to(equal("foo"))
                 expect(item.title).to(equal("foo"))
-                expect(item.group).to(equal("my group"))
+                expect(item.state).to(equal(.selectAll))
+                expect(item.group).to(equal("group"))
+                expect(item.value).to(beNil())
                 expect(item.selectAllTitle).to(equal("select all"))
                 expect(item.selectAllTitle).to(equal("select all"))
                 expect(item.deselectAllTitle).to(equal("deselect all"))
                 expect(item.deselectAllTitle).to(equal("deselect all"))
+                expect(item.tapBehavior).to(equal(ActionSheetItem.TapBehavior.none))
             }
             }
         }
         }
         
         
-        describe("cell style") {
+    
+        describe("cell") {
             
             
-            it("is value1") {
-                expect(getItem().cellStyle).to(equal(UITableViewCell.CellStyle.value1))
+            it("is of correct type") {
+                let item = createItem(group: "group")
+                let cell = item.cell(for: UITableView())
+                
+                expect(cell is ActionSheetMultiSelectToggleItemCell).to(beTrue())
+                expect(cell.reuseIdentifier).to(equal(item.cellReuseIdentifier))
             }
             }
         }
         }
         
         
-        describe("tap behavior") {
+        
+        describe("handling tap") {
+            
+            var sheet: ActionSheet!
+            var item1: ActionSheetMultiSelectItem!
+            var item2: ActionSheetMultiSelectItem!
+            var item3: ActionSheetMultiSelectItem!
+            var toggle1: ActionSheetMultiSelectToggleItem!
+            var toggle2: ActionSheetMultiSelectToggleItem!
+            
+            beforeEach {
+                item1 = ActionSheetMultiSelectItem(title: "foo", isSelected: false, group: "group 1")
+                item2 = ActionSheetMultiSelectItem(title: "bar", isSelected: false, group: "group 2")
+                item3 = ActionSheetMultiSelectItem(title: "baz", isSelected: false, group: "group 1")
+                toggle1 = createItem(group: "group 1")
+                toggle2 = createItem(group: "group 3")
+                sheet = ActionSheet(items: [item1, item2, item3, toggle1, toggle2]) { (_, _) in }
+            }
+            
+            it("resets state if no matching items exist in sheet") {
+                toggle2.state = .deselectAll
+                toggle2.handleTap(in: sheet)
+                expect(toggle2.state).to(equal(.selectAll))
+            }
             
             
-            it("is none") {
-                expect(getItem().tapBehavior).to(equal(ActionSheetItem.TapBehavior.none))
+            it("toggles select items in the same group") {
+                toggle1.handleTap(in: sheet)
+                expect(item1.isSelected).to(beTrue())
+                expect(item2.isSelected).to(beFalse())
+                expect(item3.isSelected).to(beTrue())
+                expect(toggle1.state).to(equal(.deselectAll))
+                expect(toggle2.state).to(equal(.selectAll))
+                toggle1.handleTap(in: sheet)
+                expect(item1.isSelected).to(beFalse())
+                expect(item2.isSelected).to(beFalse())
+                expect(item3.isSelected).to(beFalse())
+                expect(toggle1.state).to(equal(.selectAll))
+                expect(toggle2.state).to(equal(.selectAll))
+                toggle2.handleTap(in: sheet)
+                expect(item1.isSelected).to(beFalse())
+                expect(item2.isSelected).to(beFalse())
+                expect(item3.isSelected).to(beFalse())
+                expect(toggle1.state).to(equal(.selectAll))
+                expect(toggle2.state).to(equal(.selectAll))
             }
             }
         }
         }
     }
     }

+ 83 - 38
Carthage/Checkouts/Sheeeeeeeeet/SheeeeeeeeetTests/Items/Items/ActionSheetSelectItemTests.swift

@@ -8,71 +8,116 @@
 
 
 import Quick
 import Quick
 import Nimble
 import Nimble
-import Sheeeeeeeeet
+@testable import Sheeeeeeeeet
 
 
 class ActionSheetSelectItemTests: QuickSpec {
 class ActionSheetSelectItemTests: QuickSpec {
     
     
     override func spec() {
     override func spec() {
         
         
-        func getItem(isSelected: Bool = false) -> ActionSheetSelectItem {
-            return ActionSheetSelectItem(title: "foo", isSelected: isSelected, value: true, image: UIImage())
-        }
         
         
-        describe("when created") {
+        describe("instance") {
+            
+            it("can be created with default values") {
+                let item = ActionSheetSelectItem(title: "foo", isSelected: false)
+                expect(item.title).to(equal("foo"))
+                expect(item.isSelected).to(beFalse())
+                expect(item.group).to(equal(""))
+                expect(item.value).to(beNil())
+                expect(item.image).to(beNil())
+                expect(item.tapBehavior).to(equal(ActionSheetItem.TapBehavior.dismiss))
+            }
             
             
-            it("applies provided values") {
-                let item = ActionSheetSelectItem(title: "foo", isSelected: true, group: "my group", value: true, image: UIImage(), tapBehavior: .none)
+            it("can be created with custom values") {
+                let item = ActionSheetSelectItem(title: "foo", isSelected: true, group: "group", value: true, image: UIImage())
                 expect(item.title).to(equal("foo"))
                 expect(item.title).to(equal("foo"))
                 expect(item.isSelected).to(beTrue())
                 expect(item.isSelected).to(beTrue())
-                expect(item.group).to(equal("my group"))
+                expect(item.group).to(equal("group"))
                 expect(item.value as? Bool).to(equal(true))
                 expect(item.value as? Bool).to(equal(true))
                 expect(item.image).toNot(beNil())
                 expect(item.image).toNot(beNil())
-                expect(item.tapBehavior).to(equal(ActionSheetItem.TapBehavior.none))
+                expect(item.tapBehavior).to(equal(ActionSheetItem.TapBehavior.dismiss))
             }
             }
+        }
+        
+        
+        describe("cell") {
             
             
-            it("applies provided selection state") {
-                expect(getItem(isSelected: true).isSelected).to(beTrue())
-                expect(getItem(isSelected: false).isSelected).to(beFalse())
+            it("is of correct type") {
+                let item = ActionSheetSelectItem(title: "foo", isSelected: false)
+                let cell = item.cell(for: UITableView())
+                
+                expect(cell is ActionSheetSelectItemCell).to(beTrue())
+                expect(cell.reuseIdentifier).to(equal(item.cellReuseIdentifier))
             }
             }
         }
         }
         
         
-        describe("tap behavior") {
+        
+        describe("handling tap") {
             
             
-            it("is dismiss by default") {
-                let item = getItem()
-                expect(item.tapBehavior).to(equal(ActionSheetItem.TapBehavior.dismiss))
+            it("toggles selected state") {
+                let item = ActionSheetSelectItem(title: "foo", isSelected: false)
+                let sheet = ActionSheet { _, _ in }
+                item.handleTap(in: sheet)
+                expect(item.isSelected).to(beTrue())
+                item.handleTap(in: sheet)
+                expect(item.isSelected).to(beFalse())
             }
             }
         }
         }
+    }
+}
+
+
+class ActionSheetSelectItemCellTests: QuickSpec {
+    
+    override func spec() {
         
         
-        describe("when tapped") {
+        describe("refreshing") {
             
             
-            var sheet: ActionSheet!
+            var item: ActionSheetSelectItem!
+            var cell: ActionSheetSelectItemCell!
             
             
             beforeEach {
             beforeEach {
-                sheet = ActionSheet(items: [
-                    getItem(isSelected: true),
-                    getItem(isSelected: false)
-                    ], action: { _, _ in })
+                let label = UILabel()
+                item = ActionSheetSelectItem(title: "foo", isSelected: false)
+                cell = item.cell(for: UITableView()) as? ActionSheetSelectItemCell
+                cell.tintColor = UIColor.purple.withAlphaComponent(0.1)
+                cell.titleColor = UIColor.yellow.withAlphaComponent(0.1)
+                cell.titleFont = .systemFont(ofSize: 11)
+                cell.subtitleColor = UIColor.red.withAlphaComponent(0.1)
+                cell.subtitleFont = .systemFont(ofSize: 12)
+                cell.selectedIcon = UIImage()
+                cell.selectedIconColor = .green
+                cell.selectedTintColor = .purple
+                cell.selectedTitleColor = .yellow
+                cell.selectedTitleFont = .systemFont(ofSize: 13)
+                cell.selectedSubtitleColor = .red
+                cell.selectedSubtitleFont = .systemFont(ofSize: 14)
+                cell.unselectedIcon = UIImage()
+                cell.unselectedIconColor = UIColor.green.withAlphaComponent(0.1)
+                cell.refresh(with: item)
             }
             }
             
             
-            it("selects unselected item") {
-                let item = getItem(isSelected: false)
-                item.handleTap(in: sheet)
-                expect(item.isSelected).to(beTrue())
+            it("refreshes correctly for selected item") {
+                item.isSelected = true
+                cell.refresh()
+                expect((cell.accessoryView as? UIImageView)?.image).to(be(cell.selectedIcon))
+                expect(cell.accessoryView?.tintColor).to(be(cell.selectedIconColor))
+                expect(cell.tintColor).to(be(cell.selectedTintColor))
+                expect(cell.textLabel?.textColor).to(be(cell.selectedTitleColor))
+                expect(cell.textLabel?.font).to(be(cell.selectedTitleFont))
+//                expect(cell.detailTextLabel?.textColor).to(be(cell.selectedSubtitleColor))
+//                expect(cell.detailTextLabel?.font).to(be(cell.selectedSubtitleFont))
             }
             }
             
             
-            it("deselects selected item") {
-                let item = getItem(isSelected: true)
-                item.handleTap(in: sheet)
-                expect(item.isSelected).to(beFalse())
-            }
-            
-            it("does not affect other sheet items") {
-                let item = getItem(isSelected: true)
-                item.handleTap(in: sheet)
-                let items = sheet.items.compactMap { $0 as? ActionSheetSelectItem }
-                expect(items.first!.isSelected).to(beTrue())
-                expect(items.last!.isSelected).to(beFalse())
+            it("refreshes correctly for unselected item") {
+                item.isSelected = false
+                cell.refresh()
+                expect((cell.accessoryView as? UIImageView)?.image).to(be(cell.unselectedIcon))
+                expect(cell.accessoryView?.tintColor).to(be(cell.unselectedIconColor))
+                expect(cell.tintColor).to(be(cell.tintColor))
+                expect(cell.textLabel?.textColor).to(be(cell.titleColor))
+                expect(cell.textLabel?.font).to(be(cell.titleFont))
+//                expect(cell.detailTextLabel?.textColor).to(be(cell.subtitleColor))
+//                expect(cell.detailTextLabel?.font).to(be(cell.subtitleFont))
             }
             }
         }
         }
     }
     }

+ 29 - 63
Carthage/Checkouts/Sheeeeeeeeet/SheeeeeeeeetTests/Items/Items/ActionSheetSingleSelectItemTests.swift

@@ -14,73 +14,39 @@ class ActionSheetSingleSelectItemTests: QuickSpec {
     
     
     override func spec() {
     override func spec() {
         
         
-        func getItem(isSelected: Bool = false, group: String = "") -> ActionSheetSingleSelectItem {
-            return ActionSheetSingleSelectItem(title: "foo", isSelected: isSelected, group: group, value: true, image: UIImage())
-        }
-        
-        describe("when created") {
-            
-            it("applies provided values") {
-                let item = ActionSheetSingleSelectItem(title: "foo", isSelected: true, group: "my group", value: true, image: UIImage(), tapBehavior: .none)
-                expect(item.title).to(equal("foo"))
-                expect(item.isSelected).to(beTrue())
-                expect(item.group).to(equal("my group"))
-                expect(item.value as? Bool).to(equal(true))
-                expect(item.image).toNot(beNil())
-                expect(item.tapBehavior).to(equal(ActionSheetItem.TapBehavior.none))
-            }
-            
-            it("applies provided selection state") {
-                expect(getItem(isSelected: true).isSelected).to(beTrue())
-                expect(getItem(isSelected: false).isSelected).to(beFalse())
+        describe("cell") {
+            
+            it("is of correct type") {
+                let item = ActionSheetSingleSelectItem(title: "foo", isSelected: false)
+                let cell = item.cell(for: UITableView())
+                
+                expect(cell is ActionSheetSingleSelectItemCell).to(beTrue())
+                expect(cell.reuseIdentifier).to(equal(item.cellReuseIdentifier))
             }
             }
         }
         }
         
         
-        describe("tap behavior") {
-            
-            it("is dismiss by default") {
-                let item = getItem()
-                expect(item.tapBehavior).to(equal(ActionSheetItem.TapBehavior.dismiss))
-            }
-        }
         
         
-        describe("when tapped") {
-            
-            var sheet: ActionSheet!
-            
-            beforeEach {
-                sheet = ActionSheet(items: [
-                    getItem(isSelected: true, group: "foo"),
-                    getItem(isSelected: false, group: "foo"),
-                    getItem(isSelected: true, group: "bar"),
-                    getItem(isSelected: false, group: "bar"),
-                    getItem(isSelected: true, group: "baz"),
-                    getItem(isSelected: false, group: "baz")
-                    ], action: { _, _ in })
-            }
-            
-            it("selects unselected item") {
-                let item = getItem(isSelected: false)
-                item.handleTap(in: sheet)
-                expect(item.isSelected).to(beTrue())
-            }
-            
-            it("does not deselect selected item") {
-                let item = getItem(isSelected: true)
-                item.handleTap(in: sheet)
-                expect(item.isSelected).to(beTrue())
-            }
-            
-            it("does not affect sheet items in other groups") {
-                let item = getItem(isSelected: false, group: "baz")
-                item.handleTap(in: sheet)
-                let items = sheet.items.compactMap { $0 as? ActionSheetSingleSelectItem }
-                expect(items[0].isSelected).to(beTrue())
-                expect(items[1].isSelected).to(beFalse())
-                expect(items[2].isSelected).to(beTrue())
-                expect(items[3].isSelected).to(beFalse())
-                expect(items[4].isSelected).to(beFalse())
-                expect(items[5].isSelected).to(beFalse())
+        describe("handling tap") {
+            
+            it("deselects other single select items in the same group") {
+                let item1 = ActionSheetSingleSelectItem(title: "foo", isSelected: false, group: "group 1")
+                let item2 = ActionSheetSingleSelectItem(title: "bar", isSelected: false, group: "group 2")
+                let item3 = ActionSheetSingleSelectItem(title: "baz", isSelected: false, group: "group 1")
+                let items = [item1, item2, item3]
+                let sheet = ActionSheet(items: items) { (_, _) in }
+                
+                item1.handleTap(in: sheet)
+                expect(item1.isSelected).to(beTrue())
+                expect(item2.isSelected).to(beFalse())
+                expect(item3.isSelected).to(beFalse())
+                item2.handleTap(in: sheet)
+                expect(item1.isSelected).to(beTrue())
+                expect(item2.isSelected).to(beTrue())
+                expect(item3.isSelected).to(beFalse())
+                item3.handleTap(in: sheet)
+                expect(item1.isSelected).to(beFalse())
+                expect(item2.isSelected).to(beTrue())
+                expect(item3.isSelected).to(beTrue())
             }
             }
         }
         }
     }
     }

+ 2 - 17
Carthage/Checkouts/Sheeeeeeeeet/SheeeeeeeeetTests/Items/Mocks/MockActionSheetItem.swift

@@ -10,25 +10,10 @@ import Sheeeeeeeeet
 
 
 class MockActionSheetItem: ActionSheetItem {
 class MockActionSheetItem: ActionSheetItem {
     
     
-    var applyAppearanceInvokeCount = 0
-    var applyAppearanceInvokeAppearances = [ActionSheetAppearance]()
-    var applyAppearanceInvokeCells = [UITableViewCell]()
     var handleTapInvokeCount = 0
     var handleTapInvokeCount = 0
     var handleTapInvokeActionSheets = [ActionSheet]()
     var handleTapInvokeActionSheets = [ActionSheet]()
     
     
-    var cell: UITableViewCell?
-    
-    override func applyAppearance(_ appearance: ActionSheetAppearance) {
-        super.applyAppearance(appearance)
-        applyAppearanceInvokeCount += 1
-        applyAppearanceInvokeAppearances.append(appearance)
-    }
-    
-    override func applyAppearance(to cell: UITableViewCell) {
-        super.applyAppearance(to: cell)
-        applyAppearanceInvokeCount += 1
-        applyAppearanceInvokeCells.append(cell)
-    }
+    var cell: ActionSheetItemCell?
     
     
     override func handleTap(in actionSheet: ActionSheet) {
     override func handleTap(in actionSheet: ActionSheet) {
         super.handleTap(in: actionSheet)
         super.handleTap(in: actionSheet)
@@ -36,7 +21,7 @@ class MockActionSheetItem: ActionSheetItem {
         handleTapInvokeActionSheets.append(actionSheet)
         handleTapInvokeActionSheets.append(actionSheet)
     }
     }
     
     
-    override func cell(for tableView: UITableView) -> UITableViewCell {
+    override func cell(for tableView: UITableView) -> ActionSheetItemCell {
         return cell ?? super.cell(for: tableView)
         return cell ?? super.cell(for: tableView)
     }
     }
 }
 }

+ 15 - 11
Carthage/Checkouts/Sheeeeeeeeet/SheeeeeeeeetTests/Items/Titles/ActionSheetSectionMarginTests.swift

@@ -14,27 +14,31 @@ class ActionSheetSectionMarginTests: QuickSpec {
     
     
     override func spec() {
     override func spec() {
         
         
-        let item = ActionSheetSectionMargin()
+        var item: ActionSheetSectionMargin!
         
         
-        describe("when created") {
+        beforeEach {
+            item = ActionSheetSectionMargin()
+        }
+        
+        
+        describe("instance") {
             
             
-            it("applies provided values") {
+            it("is correctly configured") {
                 expect(item.title).to(equal(""))
                 expect(item.title).to(equal(""))
                 expect(item.value).to(beNil())
                 expect(item.value).to(beNil())
                 expect(item.image).to(beNil())
                 expect(item.image).to(beNil())
-            }
-            
-            it("applies non-provided values") {
                 expect(item.tapBehavior).to(equal(ActionSheetItem.TapBehavior.none))
                 expect(item.tapBehavior).to(equal(ActionSheetItem.TapBehavior.none))
             }
             }
         }
         }
         
         
-        describe("applying appearance to cell") {
+        
+        describe("cell") {
             
             
-            it("is correctly configures cell") {
-                let cell = UITableViewCell()
-                item.applyAppearance(to: cell)
-                expect(cell.selectionStyle).to(equal(UITableViewCell.SelectionStyle.none))
+            it("is of correct type") {
+                let cell = item.cell(for: UITableView())
+                
+                expect(cell is ActionSheetSectionMarginCell).to(beTrue())
+                expect(cell.reuseIdentifier).to(equal(item.cellReuseIdentifier))
             }
             }
         }
         }
     }
     }

+ 13 - 14
Carthage/Checkouts/Sheeeeeeeeet/SheeeeeeeeetTests/Items/Titles/ActionSheetSectionTitleTests.swift

@@ -14,29 +14,28 @@ class ActionSheetSectionTitleTests: QuickSpec {
     
     
     override func spec() {
     override func spec() {
         
         
-        let item = ActionSheetSectionTitle(title: "foo", subtitle: "bar")
+        var item: ActionSheetSectionTitle!
         
         
-        describe("when created") {
+        describe("instance") {
             
             
-            it("applies provided values") {
+            it("is correctly configured") {
+                item = ActionSheetSectionTitle(title: "foo", subtitle: "bar")
+                
                 expect(item.title).to(equal("foo"))
                 expect(item.title).to(equal("foo"))
                 expect(item.subtitle).to(equal("bar"))
                 expect(item.subtitle).to(equal("bar"))
-                expect(item.value).to(beNil())
-                expect(item.image).to(beNil())
-            }
-            
-            it("applies non-provided values") {
-                expect(item.cellStyle).to(equal(UITableViewCell.CellStyle.value1))
                 expect(item.tapBehavior).to(equal(ActionSheetItem.TapBehavior.none))
                 expect(item.tapBehavior).to(equal(ActionSheetItem.TapBehavior.none))
             }
             }
         }
         }
         
         
-        describe("applying appearance to cell") {
+        
+        describe("cell") {
             
             
-            it("is correctly configures cell") {
-                let cell = UITableViewCell()
-                item.applyAppearance(to: cell)
-                expect(cell.selectionStyle).to(equal(UITableViewCell.SelectionStyle.none))
+            it("is of correct type") {
+                item = ActionSheetSectionTitle(title: "foo")
+                let cell = item.cell(for: UITableView())
+                
+                expect(cell is ActionSheetSectionTitleCell).to(beTrue())
+                expect(cell.reuseIdentifier).to(equal(item.cellReuseIdentifier))
             }
             }
         }
         }
     }
     }

+ 13 - 15
Carthage/Checkouts/Sheeeeeeeeet/SheeeeeeeeetTests/Items/Titles/ActionSheetTitleTests.swift

@@ -14,29 +14,27 @@ class ActionSheetTitleTests: QuickSpec {
     
     
     override func spec() {
     override func spec() {
         
         
-        let item = ActionSheetTitle(title: "foo")
+        var item: ActionSheetTitle!
         
         
-        describe("when created") {
+        describe("instance") {
             
             
-            it("applies provided values") {
+            it("is correctly configured") {
+                item = ActionSheetTitle(title: "foo")
+                
                 expect(item.title).to(equal("foo"))
                 expect(item.title).to(equal("foo"))
-                expect(item.value).to(beNil())
-                expect(item.image).to(beNil())
-                expect(item.tapBehavior).to(equal(ActionSheetItem.TapBehavior.none))
-            }
-            
-            it("applies non-provided values") {
                 expect(item.tapBehavior).to(equal(ActionSheetItem.TapBehavior.none))
                 expect(item.tapBehavior).to(equal(ActionSheetItem.TapBehavior.none))
             }
             }
         }
         }
         
         
-        describe("applying appearance to cell") {
+        
+        describe("cell") {
             
             
-            it("is correctly configures cell") {
-                let cell = UITableViewCell()
-                item.applyAppearance(to: cell)
-                expect(cell.selectionStyle).to(equal(UITableViewCell.SelectionStyle.none))
-                expect(cell.textLabel?.textAlignment).to(equal(NSTextAlignment.center))
+            it("is of correct type") {
+                item = ActionSheetTitle(title: "foo")
+                let cell = item.cell(for: UITableView())
+                
+                expect(cell is ActionSheetTitleCell).to(beTrue())
+                expect(cell.reuseIdentifier).to(equal(item.cellReuseIdentifier))
             }
             }
         }
         }
     }
     }

+ 175 - 4
Carthage/Checkouts/Sheeeeeeeeet/SheeeeeeeeetTests/Presenters/ActionSheetPopoverPresenterTests.swift

@@ -15,8 +15,11 @@ class ActionSheetPopoverPresenterTests: QuickSpec {
     override func spec() {
     override func spec() {
         
         
         var presenter: ActionSheetPopoverPresenter!
         var presenter: ActionSheetPopoverPresenter!
-        var sheet: ActionSheet!
+        var sheet: MockActionSheet!
         var headerView: UIView!
         var headerView: UIView!
+        var headerViewContainer: ActionSheetHeaderView!
+        var itemView: ActionSheetItemTableView!
+        var buttonView: ActionSheetButtonTableView!
         
         
         beforeEach {
         beforeEach {
             let items: [ActionSheetItem] = [
             let items: [ActionSheetItem] = [
@@ -25,12 +28,23 @@ class ActionSheetPopoverPresenterTests: QuickSpec {
                 ActionSheetOkButton(title: "ok"),
                 ActionSheetOkButton(title: "ok"),
                 ActionSheetMultiSelectItem(title: "item 2", isSelected: true)
                 ActionSheetMultiSelectItem(title: "item 2", isSelected: true)
             ]
             ]
+            
             headerView = UIView(frame: .zero)
             headerView = UIView(frame: .zero)
-            sheet = ActionSheet(items: items) { (_, _) in }
+            headerViewContainer = ActionSheetHeaderView(frame: .zero)
+            itemView = ActionSheetItemTableView(frame: .zero)
+            buttonView = ActionSheetButtonTableView(frame: .zero)
+            
+            sheet = MockActionSheet(items: items) { (_, _) in }
+            sheet.headerViewContainer = headerViewContainer
             sheet.headerView = headerView
             sheet.headerView = headerView
+            sheet.itemsTableView = itemView
+            sheet.buttonsTableView = buttonView
+            
             presenter = ActionSheetPopoverPresenter()
             presenter = ActionSheetPopoverPresenter()
+            presenter.actionSheet = sheet
         }
         }
         
         
+        
         describe("background tap dismissal") {
         describe("background tap dismissal") {
             
             
             it("is enabled by default") {
             it("is enabled by default") {
@@ -38,14 +52,171 @@ class ActionSheetPopoverPresenterTests: QuickSpec {
             }
             }
         }
         }
         
         
+        
+        describe("dismissing") {
+            
+            it("completes dismissal directly if action sheet has no presenting view controller") {
+                var count = 0
+                presenter.dismiss { count += 1 }
+                
+                expect(count).to(equal(1))
+                expect(presenter.actionSheet).to(beNil())
+            }
+            
+            it("completes dismissal after presenting view controller has finished dismissing") {
+                var count = 0
+                let vc = MockViewController()
+                sheet.presentingViewController = vc
+                presenter.dismiss { count += 1 }
+                
+                expect(vc.dismissInvokeCount).to(equal(1))
+                expect(vc.dismissInvokeAnimateds).to(equal([true]))
+                expect(vc.dismissInvokeCompletions.count).to(equal(1))
+                expect(count).to(equal(0))
+                expect(presenter.actionSheet).toNot(beNil())
+                
+                vc.completeDismissal()
+                
+                expect(count).to(equal(1))
+                expect(presenter.actionSheet).to(beNil())
+            }
+        }
+        
+        
+        describe("presenting action sheet from view") {
+            
+            var vc: MockViewController!
+            var view: UIView!
+            var completion: (() -> ())!
+            
+            beforeEach {
+                vc = MockViewController()
+                view = UIView(frame: CGRect(x: 1, y: 2, width: 3, height: 4))
+                completion = {}
+                presenter.present(sheet: sheet, in: vc, from: view, completion: completion)
+            }
+            
+            it("sets up sheet for popover presentation") {
+                expect(sheet.items.count).to(equal(3))
+                expect(sheet.buttons.count).to(equal(0))
+                expect(sheet.modalPresentationStyle).to(equal(.popover))
+            }
+            
+            it("sets up popover presentation controller") {
+                expect(presenter.popover?.delegate).to(be(presenter))
+                expect(presenter.popover?.sourceView).to(be(view))
+                expect(presenter.popover?.sourceRect).to(equal(view.bounds))
+            }
+            
+            it("performs presentation") {
+                expect(vc.presentInvokeCount).to(equal(1))
+                expect(vc.presentInvokeVcs).to(equal([sheet]))
+                expect(vc.presentInvokeAnimateds).to(equal([true]))
+                expect(vc.presentInvokeCompletions.count).to(equal(1))
+            }
+        }
+        
+        
+        describe("presenting action sheet from bar button item") {
+            
+            var vc: MockViewController!
+            var item: UIBarButtonItem!
+            var completion: (() -> ())!
+            
+            beforeEach {
+                vc = MockViewController()
+                item = UIBarButtonItem(customView: UIView(frame: .zero))
+                completion = {}
+                presenter.present(sheet: sheet, in: vc, from: item, completion: completion)
+            }
+            
+            it("sets up sheet for popover presentation") {
+                expect(sheet.items.count).to(equal(3))
+                expect(sheet.buttons.count).to(equal(0))
+                expect(sheet.modalPresentationStyle).to(equal(.popover))
+            }
+            
+            it("sets up popover presentation controller") {
+                expect(presenter.popover?.delegate).to(be(presenter))
+                expect(presenter.popover?.barButtonItem).to(be(item))
+                expect(presenter.popover?.sourceRect).to(equal(.zero))
+            }
+            
+            it("performs presentation") {
+                expect(vc.presentInvokeCount).to(equal(1))
+                expect(vc.presentInvokeVcs).to(equal([sheet]))
+                expect(vc.presentInvokeAnimateds).to(equal([true]))
+                expect(vc.presentInvokeCompletions.count).to(equal(1))
+            }
+        }
+        
+        
+        describe("refreshing action sheet") {
+            
+            beforeEach {
+                sheet.itemsTableView?.backgroundColor = .red
+                presenter.present(sheet: sheet, in: UIViewController(), from: UIView()) {}
+                presenter.refreshActionSheet()
+            }
+            
+            it("hides unused views") {
+                expect(sheet.buttonsTableView?.isHidden).to(beTrue())
+                expect(sheet.headerViewContainer?.isHidden).to(beTrue())
+            }
+            
+            it("resizes popover") {
+                expect(sheet.preferredContentSize.height).to(equal(150))
+            }
+            
+            it("applies color to popover arrow") {
+                expect(presenter.popover?.backgroundColor).to(equal(.red))
+            }
+        }
+        
+        
+        describe("popover should dismiss") {
+            
+            var popover: UIPopoverPresentationController!
+            var presenting: MockViewController!
+            var dismissEventCount: Int!
+            
+            beforeEach {
+                popover = UIPopoverPresentationController(presentedViewController: UIViewController(), presenting: nil)
+                presenting = MockViewController()
+                sheet.presentingViewController = presenting
+                dismissEventCount = 0
+                presenter.events.didDismissWithBackgroundTap = { dismissEventCount += 1 }
+            }
+            
+            it("aborts and returns false if background tap is disabled") {
+                presenter.isDismissableWithTapOnBackground = false
+                let result = presenter.popoverPresentationControllerShouldDismissPopover(popover)
+                
+                expect(result).to(beFalse())
+                expect(dismissEventCount).to(equal(0))
+                expect(presenting.dismissInvokeCount).to(equal(0))
+            }
+            
+            it("completes and returns false if background tap is enabled") {
+                presenter.isDismissableWithTapOnBackground = true
+                let result = presenter.popoverPresentationControllerShouldDismissPopover(popover)
+                
+                expect(result).to(beFalse())
+                expect(dismissEventCount).to(equal(1))
+                expect(presenting.dismissInvokeCount).to(equal(1))
+            }
+            
+        }
+        
+        
         describe("setting up sheet for popover presentation") {
         describe("setting up sheet for popover presentation") {
             
             
             beforeEach {
             beforeEach {
                 presenter.setupSheetForPresentation(sheet)
                 presenter.setupSheetForPresentation(sheet)
             }
             }
             
             
-            it("removes header view") {
-                expect(sheet.headerView).to(beNil())
+            it("sets popover style") {
+                expect(sheet.modalPresentationStyle).to(equal(.popover))
             }
             }
             
             
             it("moves non-cancel buttons last into items group") {
             it("moves non-cancel buttons last into items group") {

+ 81 - 1
Carthage/Checkouts/Sheeeeeeeeet/SheeeeeeeeetTests/Presenters/ActionSheetStandardPresenterTests.swift

@@ -8,23 +8,103 @@
 
 
 import Quick
 import Quick
 import Nimble
 import Nimble
-import Sheeeeeeeeet
+@testable import Sheeeeeeeeet
 
 
 class ActionSheetStandardPresenterTests: QuickSpec {
 class ActionSheetStandardPresenterTests: QuickSpec {
     
     
     override func spec() {
     override func spec() {
         
         
         var presenter: ActionSheetStandardPresenter!
         var presenter: ActionSheetStandardPresenter!
+        var sheet: MockActionSheet!
+        var backgroundView: ActionSheetBackgroundView!
+        var stackView: UIStackView!
         
         
         beforeEach {
         beforeEach {
+            backgroundView = ActionSheetBackgroundView(frame: .zero)
+            stackView = UIStackView(frame: CGRect(x: 0, y: 0, width: 0, height: 100))
+            
+            sheet = MockActionSheet(items: []) { _, _ in }
+            sheet.backgroundView = backgroundView
+            sheet.stackView = stackView
+            
             presenter = ActionSheetStandardPresenter()
             presenter = ActionSheetStandardPresenter()
+            presenter.animationDuration = 0
+            presenter.actionSheet = sheet
         }
         }
         
         
+        
         describe("background tap dismissal") {
         describe("background tap dismissal") {
             
             
             it("is enabled by default") {
             it("is enabled by default") {
                 expect(presenter.isDismissableWithTapOnBackground).to(beTrue())
                 expect(presenter.isDismissableWithTapOnBackground).to(beTrue())
             }
             }
         }
         }
+        
+        
+        describe("dismissing action sheet") {
+            
+            var counter: Int!
+            
+            beforeEach {
+                counter = 0
+                presenter.dismiss { counter += 1 }
+            }
+            
+            it("calls completion directly") {
+                expect(counter).to(equal(1))
+            }
+            
+            it("removes background view") {
+                expect(backgroundView.alpha).to(equal(0))
+            }
+            
+            it("removes action sheet") {
+                expect(stackView.frame.origin.y).to(equal(200))
+                expect(sheet.view.superview).to(beNil())
+                expect(presenter.actionSheet).toEventually(beNil())
+            }
+        }
+        
+        
+        describe("presenting action sheet") {
+            
+            var vc: MockViewController!
+            var counter: Int!
+            
+            beforeEach {
+                vc = MockViewController()
+                vc.view.frame = CGRect(x: 1, y: 2, width: 3, height: 4)
+                counter = 0
+                presenter.present(sheet: sheet, in: vc) { counter += 1 }
+            }
+            
+            it("sets action sheet") {
+                expect(presenter.actionSheet).to(be(sheet))
+            }
+            
+            it("adds actio sheet to vc view") {
+                expect(sheet.view.frame).to(equal(vc.view.frame))
+                expect(vc.view.subviews).to(contain(sheet.view))
+            }
+            
+            it("adds tap gesture to background view") {
+                expect(sheet.backgroundView?.isUserInteractionEnabled).to(beTrue())
+                //expect(backgroundView.gestureRecognizers?.count).to(equal(1))
+            }
+            
+            it("presents background view") {
+                presenter.animationDuration = -1
+                presenter.present(sheet: sheet, in: vc) {}
+                expect(sheet.backgroundView?.alpha).to(equal(0))
+                presenter.animationDuration = 0
+                presenter.present(sheet: sheet, in: vc) {}
+                expect(sheet.backgroundView?.alpha).to(equal(1))
+            }
+            
+            it("presents stack view") {
+                presenter.present(sheet: sheet, in: vc) {}
+                expect(sheet.stackView?.frame.origin.y).to(equal(277))
+            }
+        }
     }
     }
 }
 }

+ 20 - 1
Carthage/Checkouts/Sheeeeeeeeet/SheeeeeeeeetTests/Views/MockTableView.swift

@@ -9,7 +9,7 @@
 import UIKit
 import UIKit
 import Sheeeeeeeeet
 import Sheeeeeeeeet
 
 
-class MockTableView: ActionSheetTableView {
+class MockItemTableView: ActionSheetItemTableView {
 
 
     var deselectRowInvokeCount = 0
     var deselectRowInvokeCount = 0
     var deselectRowInvokePaths = [IndexPath]()
     var deselectRowInvokePaths = [IndexPath]()
@@ -27,3 +27,22 @@ class MockTableView: ActionSheetTableView {
         reloadDataInvokeCount += 1
         reloadDataInvokeCount += 1
     }
     }
 }
 }
+
+class MockButtonTableView: ActionSheetButtonTableView {
+    
+    var deselectRowInvokeCount = 0
+    var deselectRowInvokePaths = [IndexPath]()
+    var deselectRowInvokeAnimated = [Bool]()
+    var reloadDataInvokeCount = 0
+    
+    override func deselectRow(at indexPath: IndexPath, animated: Bool) {
+        deselectRowInvokeCount += 1
+        deselectRowInvokePaths.append(indexPath)
+        deselectRowInvokeAnimated.append(animated)
+    }
+    
+    override func reloadData() {
+        super.reloadData()
+        reloadDataInvokeCount += 1
+    }
+}

+ 7 - 0
iOSClient/Main/Create cloud/NCCreateFormUploadScanDocument.swift

@@ -504,6 +504,7 @@ class NCCreateScanDocument : NSObject, ImageScannerControllerDelegate {
         let fileName = CCUtility.createFileName("scan.png", fileDate: Date(), fileType: PHAssetMediaType.image, keyFileName: k_keyFileNameMask, keyFileNameType: k_keyFileNameType, keyFileNameOriginal: k_keyFileNameOriginal)!
         let fileName = CCUtility.createFileName("scan.png", fileDate: Date(), fileType: PHAssetMediaType.image, keyFileName: k_keyFileNameMask, keyFileNameType: k_keyFileNameType, keyFileNameOriginal: k_keyFileNameOriginal)!
         let fileNamePath = CCUtility.getDirectoryScan() + "/" + fileName
         let fileNamePath = CCUtility.getDirectoryScan() + "/" + fileName
         
         
+        /* V 1.0
         if (results.doesUserPreferEnhancedImage && results.enhancedImage != nil) {
         if (results.doesUserPreferEnhancedImage && results.enhancedImage != nil) {
             do {
             do {
                 try results.enhancedImage!.pngData()?.write(to: NSURL.fileURL(withPath: fileNamePath), options: .atomic)
                 try results.enhancedImage!.pngData()?.write(to: NSURL.fileURL(withPath: fileNamePath), options: .atomic)
@@ -513,6 +514,12 @@ class NCCreateScanDocument : NSObject, ImageScannerControllerDelegate {
                 try results.scannedImage.pngData()?.write(to: NSURL.fileURL(withPath: fileNamePath), options: .atomic)
                 try results.scannedImage.pngData()?.write(to: NSURL.fileURL(withPath: fileNamePath), options: .atomic)
             } catch { }
             } catch { }
         }
         }
+        */
+        
+        // 0.9.1
+        do {
+            try results.scannedImage.pngData()?.write(to: NSURL.fileURL(withPath: fileNamePath), options: .atomic)
+        } catch { }
         
         
         scanner.dismiss(animated: true, completion: {
         scanner.dismiss(animated: true, completion: {
             if (self.openScan) {
             if (self.openScan) {