Jelajahi Sumber

update library

Marino Faggiana 6 tahun lalu
induk
melakukan
ae0edf5216
54 mengubah file dengan 887 tambahan dan 352 penghapusan
  1. 4 4
      Cartfile.resolved
  2. 50 7
      Carthage/Checkouts/Sheeeeeeeeet/RELEASE_NOTES.md
  3. 1 1
      Carthage/Checkouts/Sheeeeeeeeet/Sheeeeeeeeet.podspec
  4. 67 102
      Carthage/Checkouts/Sheeeeeeeeet/Sheeeeeeeeet/ActionSheet/ActionSheet.swift
  5. 1 1
      Carthage/Checkouts/Sheeeeeeeeet/Sheeeeeeeeet/ActionSheet/ActionSheet.xib
  6. 7 0
      Carthage/Checkouts/Sheeeeeeeeet/Sheeeeeeeeet/ActionSheet/ActionSheetItemHandler.swift
  7. 23 65
      Carthage/Checkouts/Sheeeeeeeeet/Sheeeeeeeeet/Appearance/ActionSheetAppearance.swift
  8. 2 2
      Carthage/Checkouts/Sheeeeeeeeet/Sheeeeeeeeet/Appearance/Items/ActionSheetLinkItemAppearance.swift
  9. 3 3
      Carthage/Checkouts/Sheeeeeeeeet/Sheeeeeeeeet/Appearance/Items/ActionSheetMultiSelectToggleItemAppearance.swift
  10. 7 5
      Carthage/Checkouts/Sheeeeeeeeet/Sheeeeeeeeet/Appearance/Items/ActionSheetSelectItemAppearance.swift
  11. 1 1
      Carthage/Checkouts/Sheeeeeeeeet/Sheeeeeeeeet/Extensions/UIView+Nib.swift
  12. 2 2
      Carthage/Checkouts/Sheeeeeeeeet/Sheeeeeeeeet/Info.plist
  13. 1 0
      Carthage/Checkouts/Sheeeeeeeeet/Sheeeeeeeeet/Items/ActionSheetItem.swift
  14. 2 0
      Carthage/Checkouts/Sheeeeeeeeet/Sheeeeeeeeet/Items/Items/ActionSheetMultiSelectItem.swift
  15. 4 1
      Carthage/Checkouts/Sheeeeeeeeet/Sheeeeeeeeet/Items/Items/ActionSheetSelectItem.swift
  16. 0 5
      Carthage/Checkouts/Sheeeeeeeeet/Sheeeeeeeeet/Presenters/ActionSheetPopoverPresenter.swift
  17. 0 2
      Carthage/Checkouts/Sheeeeeeeeet/Sheeeeeeeeet/Presenters/ActionSheetStandardPresenter.swift
  18. 8 2
      Carthage/Checkouts/Sheeeeeeeeet/SheeeeeeeeetExample/AppDelegate+Appearance.swift
  19. 7 0
      Carthage/Checkouts/Sheeeeeeeeet/SheeeeeeeeetExample/Cells/MyCollectionViewCell.swift
  20. 7 0
      Carthage/Checkouts/Sheeeeeeeeet/SheeeeeeeeetExample/Cells/MyCustomViewCell.swift
  21. 6 0
      Carthage/Checkouts/Sheeeeeeeeet/SheeeeeeeeetExample/Extensions/UIColor+Hex.swift
  22. 2 2
      Carthage/Checkouts/Sheeeeeeeeet/SheeeeeeeeetExample/Info.plist
  23. 7 0
      Carthage/Checkouts/Sheeeeeeeeet/SheeeeeeeeetExample/Options/FoodOption+ActionSheetItems.swift
  24. 6 1
      Carthage/Checkouts/Sheeeeeeeeet/SheeeeeeeeetExample/Options/FoodOption.swift
  25. 6 1
      Carthage/Checkouts/Sheeeeeeeeet/SheeeeeeeeetExample/Options/TableViewOption.swift
  26. 7 0
      Carthage/Checkouts/Sheeeeeeeeet/SheeeeeeeeetExample/ViewController/ViewController+Alerts.swift
  27. 8 0
      Carthage/Checkouts/Sheeeeeeeeet/SheeeeeeeeetExample/ViewController/ViewController+TableView.swift
  28. 4 4
      Carthage/Checkouts/Sheeeeeeeeet/SheeeeeeeeetExample/ViewController/ViewController.swift
  29. 12 44
      Carthage/Checkouts/Sheeeeeeeeet/SheeeeeeeeetTests/ActionSheet/ActionSheetTests.swift
  30. 14 8
      Carthage/Checkouts/Sheeeeeeeeet/SheeeeeeeeetTests/ActionSheet/MockActionSheet.swift
  31. 2 2
      Carthage/Checkouts/Sheeeeeeeeet/SheeeeeeeeetTests/Info.plist
  32. 9 4
      Carthage/Checkouts/Sheeeeeeeeet/SheeeeeeeeetTests/Items/ActionSheetItemTests.swift
  33. 0 2
      Carthage/Checkouts/Sheeeeeeeeet/SheeeeeeeeetTests/Presenters/ActionSheetPopoverPresenterTests.swift
  34. 9 0
      Carthage/Checkouts/TLPhotoPicker/Example/TLPhotoPicker/CustomPhotoPickerViewController.swift
  35. 1 1
      Carthage/Checkouts/TLPhotoPicker/TLPhotoPicker.podspec
  36. 5 0
      Carthage/Checkouts/TLPhotoPicker/TLPhotoPicker/Classes/TLAssetsCollection.swift
  37. 1 3
      Carthage/Checkouts/TLPhotoPicker/TLPhotoPicker/Classes/TLPhotoLibrary.swift
  38. 13 12
      Carthage/Checkouts/TLPhotoPicker/TLPhotoPicker/Classes/TLPhotosPickerViewController.swift
  39. 52 0
      Carthage/Checkouts/realm-cocoa/CHANGELOG.md
  40. 153 6
      Carthage/Checkouts/realm-cocoa/Realm/ObjectServerTests/RLMObjectServerTests.mm
  41. 50 2
      Carthage/Checkouts/realm-cocoa/Realm/ObjectServerTests/SwiftObjectServerTests.swift
  42. 3 1
      Carthage/Checkouts/realm-cocoa/Realm/RLMRealm_Private.h
  43. 10 0
      Carthage/Checkouts/realm-cocoa/Realm/RLMRealm_Private.hpp
  44. 19 10
      Carthage/Checkouts/realm-cocoa/Realm/RLMResults.mm
  45. 4 1
      Carthage/Checkouts/realm-cocoa/Realm/RLMResults_Private.hpp
  46. 78 19
      Carthage/Checkouts/realm-cocoa/Realm/RLMSyncSubscription.h
  47. 179 8
      Carthage/Checkouts/realm-cocoa/Realm/RLMSyncSubscription.mm
  48. 2 2
      Carthage/Checkouts/realm-cocoa/Realm/Realm-Info.plist
  49. 1 1
      Carthage/Checkouts/realm-cocoa/RealmSwift/RealmCollection.swift
  50. 8 0
      Carthage/Checkouts/realm-cocoa/RealmSwift/Util.swift
  51. 1 1
      Carthage/Checkouts/realm-cocoa/build.sh
  52. 1 1
      Carthage/Checkouts/realm-cocoa/dependencies.list
  53. 9 3
      iOSClient/Main/Create cloud/NCCreateFormUploadScanDocument.swift
  54. 8 10
      iOSClient/Scan/ScanCollectionView.swift

+ 4 - 4
Cartfile.resolved

@@ -2,14 +2,14 @@ github "ChangbaDevs/KTVHTTPCache" "1.1.7"
 github "CocoaLumberjack/CocoaLumberjack" "3.4.2"
 github "MortimerGoro/MGSwipeTableCell" "1.6.8"
 github "SVGKit/SVGKit" "bfe62f6d45f55c9fe39619d9e91fed1844c59da6"
-github "WeTransfer/WeScan" "v0.9.1"
+github "WeTransfer/WeScan" "1.0.0"
 github "calimarkus/JDStatusBarNotification" "1.6.0"
-github "danielsaidi/Sheeeeeeeeet" "1.0.2"
+github "danielsaidi/Sheeeeeeeeet" "1.1.0"
 github "dzenbot/DZNEmptyDataSet" "v1.8.1"
 github "ealeksandrov/EAIntroView" "2.12.0"
 github "ealeksandrov/EARestrictedScrollView" "1.1.0"
 github "jdg/MBProgressHUD" "1.1.0"
 github "kishikawakatsumi/UICKeyChainStore" "v2.1.2"
-github "realm/realm-cocoa" "v3.12.0"
+github "realm/realm-cocoa" "v3.13.1"
 github "sgr-ksmt/PDFGenerator" "2.1.1"
-github "tilltue/TLPhotoPicker" "1.7.8"
+github "tilltue/TLPhotoPicker" "1.8.0"

+ 50 - 7
Carthage/Checkouts/Sheeeeeeeeet/RELEASE_NOTES.md

@@ -1,20 +1,66 @@
 # Release Notes
 
+
+## 1.1.0
+
+This version increases the action sheet integrity by restricting what you can do
+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.
+
+
+### New Features
+
+@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
+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).
+
+
+### Breaking Changes - ActionSheet:
+
+* 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
+integrity of the item and button separation logic.
+
+* The code no longer contains any `didSet` events, since these events called the
+same functionality many times. Call `refresh` if you change any outlets manually
+from now on.
+
+* Since the `didSet` events have been removed, `refreshHeaderVisibility` is only
+called once and has therefore been moved into `refreshHeader`.
+
+* Since the `didSet` events have been removed, `refreshButtonsVisibility` is now
+only called once and has therefore been moved into `refreshButtons`.
+
+* A small delay in `handleTap(on:)`, that should not be needed, has been removed.
+Let me know if it causes any side-effects.
+
+
+
+## 1.0.3
+
+This version removes a debug print that I used to ensure that action sheets were
+properly deinitialized after being dismissed.
+
+
+
 ## 1.0.2
 
-This version adds new background color properties to the action sheet appearance,
-to make it possible to set the background color of the table views.
+This version adds new background color properties to the action sheet appearance
+class. They can be used to set the background color of an entire sheet.
 
 This version fixes a bug, where the background color behind an action sheet went
 black when the action sheet was presented in a split view.
 
 
+
 ## 1.0.1
 
 This version fixes a bug, where the presenters incorrectly updated the scrolling
 behavior of the action sheet when rotating the device.
 
 
+
 ## 1.0.0
 
 Sheeeeeeeeet 1.0.0 is finally here, with many internal changes and some external.
@@ -26,14 +72,14 @@ instead of manual calculations, which means that popover scrolling etc. works by
 how the constraints are setup, instead of relying on manual calculations.
 
 This should result in much more robust action sheets, but it requires testing on
-a wide range of devices and orientations before it can be released as a 1.0.
+a wide range of devices and orientations, so please let me know if there are any
+issues with this approach.
 
 `IMPORTANT` The button item values have changed. Insted of `true` and `nil` they
 now have a strong `ButtonType` value. You can still create custom buttons with a
 custom value, though. You can also use the new `isOkButton` and `isCancelButton`
 extensions to quickly see if a user tapped "OK" or "Cancel".
 
-
 ### Breaking changes
 
 Since the presentation logic has been rewritten from scratch, you have to adjust
@@ -50,7 +96,6 @@ so changing your code to the new standard should be easy.
 * `ActionSheetItem.handleTap(in:)` no longer has a `cell` parameter
 * `ActionSheetStandardPresenter` is renamed to `ActionSheetStandardPresenter`
 
-
 ### New features
 
 * `ActionSheetAppearance` has new properties, which adds new way to style sheets.
@@ -58,7 +103,6 @@ so changing your code to the new standard should be easy.
 to `ActionSheetItem`. They can be used to quickly check if a cancel or ok button
 was tapped, instead of having to check if the item can be cast to a button type. 
 
-
 ### Bug fixes
 
 * The big presentation adjustments solves the scrolling issues that occured with
@@ -66,7 +110,6 @@ popovers and many items.
 * The `hideSeparator()` function is adjusted to behave correctly when the device
 is rotated.
 
-
 ### Deprecated logic
 
 Instead of deprecating presentation-related properties and functions that are no

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

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

+ 67 - 102
Carthage/Checkouts/Sheeeeeeeeet/Sheeeeeeeeet/ActionSheet/ActionSheet.swift

@@ -12,19 +12,25 @@
  use it to create action sheets and present them in any view
  controller, from any source view or bar button item.
  
- To create an action sheet, just call the initializer with a
- list of items and buttons and a block that should be called
- whenever an item is selected.
  
+ ## Creating action sheet instances
  
- ## Items
+ You create instances of this class by providing `init(...)`
+ with the items to present and an action to call whenever an
+ item is selected. If you must have an action sheet instance
+ before you can setup its items (this may happen when you're
+ subclassing), you can setup the items afterwards by calling
+ the `setup(items:)` function.
  
- You provide an action sheet with a collection of items when
- you create it. The sheet will automatically split the items
- into items and buttons. You can also create an action sheet
- with an empty item collection, then call `setup(items:)` at
- a later time. This is sometimes required if you must create
- the action sheet before you can create the items.
+ 
+ ## Subclassing
+ 
+ This class can be subclassed, which is a good practice when
+ you want to use your own models in a controlled way. If you
+ have a podcast app, you could have a `SleepTimerActionSheet`
+ 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.
  
  
  ## Presentation
@@ -32,28 +38,16 @@
  You can inject a custom presenter if you want to change how
  the sheet is presented and dismissed. The default presenter
  for iPhone devices is `ActionSheetStandardPresenter`, while
- iPad devices get `ActionSheetPopoverPresenter` instead.
- 
- 
- ## Subclassing
- 
- `ActionSheet` can be subclassed, which may be nice whenever
- you want to use your own domain model. For instance, if you
- want to present a list of `Food` items, you should create a
- `FoodActionSheet` sheet, then populate it with `Food` items.
- The selected value will then be of the type `Food`. You can
- either override the initializers or the `setup` function to
- change how you populate the sheet with items.
+ iPad devices most often get an `ActionSheetPopoverPresenter`.
  
  
  ## Appearance
  
- Sheeeeeeeeet's action sheet appearance if easily customized.
- To change the global appearance for every sheet in your app,
- just modify `ActionSheetAppearance.standard`. To change the
- appearance of a single action sheet, modify the `appearance`
- property. To change the appearance of a single item, modify
- its `customAppearance` property.
+ 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.
  
  
  ## Handling item selections
@@ -61,14 +55,14 @@
  The `selectAction` is triggered when a user taps an item in
  the action sheet. It provides you with the action sheet and
  the selected item. It is very important to use `[weak self]`
- in this block to avoid memory leaks.
+ in this block, to avoid memory leaks.
  
  
  ## Handling item taps
  
  Action sheets receive a call to `handleTap(on:)` every time
- an item is tapped. You can override it when you create your
- own action sheet subclasses, but you probably shouldn't.
+ an item is tapped. You can override it if you, for instance,
+ want to perform any animations before calling `super`.
  
  */
 
@@ -77,28 +71,33 @@ import UIKit
 open class ActionSheet: UIViewController {
     
     
+    // MARK: - Deprecated Members
+    
+    @available(*, deprecated, message: "setupItemsAndButtons(with:) is deprecated and will be removed shortly. Use `setup(items:)` instead")
+    open func setupItemsAndButtons(with items: [ActionSheetItem]) { setup(items: items) }
+    
+    @available(*, deprecated, message: "itemSelectAction is deprecated and will be removed in shortly. Use `selectAction` instead")
+    open var itemSelectAction: SelectAction { return selectAction }
+    
+    
     // MARK: - Initialization
     
     public init(
-        items: [ActionSheetItem],
+        items: [ActionSheetItem] = [],
         presenter: ActionSheetPresenter = ActionSheet.defaultPresenter,
         action: @escaping SelectAction) {
         self.presenter = presenter
         selectAction = action
-        super.init(nibName: ActionSheet.className, bundle: Bundle(for: ActionSheet.self))
+        super.init(nibName: ActionSheet.className, bundle: ActionSheet.bundle)
         setup(items: items)
-        setup()
     }
     
     public required init?(coder aDecoder: NSCoder) {
         presenter = ActionSheet.defaultPresenter
         selectAction = { _, _ in print("itemSelectAction is not set") }
         super.init(coder: aDecoder)
-        setup()
     }
     
-    deinit { print("\(type(of: self)) deinit") }
-    
     
     // MARK: - Setup
     
@@ -110,14 +109,16 @@ open class ActionSheet: UIViewController {
         reloadData()
     }
     
-    @available(*, deprecated, message: "setupItemsAndButtons(with:) is deprecated. Use setup(items:) instead")
-    open func setupItemsAndButtons(with items: [ActionSheetItem]) {
-        setup(items: items)
-    }
-    
     
     // MARK: - View Controller Lifecycle
     
+    open override func viewDidLoad() {
+        super.viewDidLoad()
+        setup()
+        setup(itemsTableView, with: itemHandler)
+        setup(buttonsTableView, with: buttonHandler)
+    }
+    
     open override func viewDidLayoutSubviews() {
         super.viewDidLayoutSubviews()
         refresh()
@@ -129,83 +130,61 @@ open class ActionSheet: UIViewController {
     public typealias SelectAction = (ActionSheet, ActionSheetItem) -> ()
     
     
-    // MARK: - Properties
-    
-    open var appearance = ActionSheetAppearance(copy: .standard)
+    // MARK: - Init properties
     
-    public let presenter: ActionSheetPresenter
-
+    public var presenter: ActionSheetPresenter
     public var selectAction: SelectAction
     
-    @available(*, deprecated, message: "itemSelectAction is deprecated. Use selectAction instead")
-    open var itemSelectAction: SelectAction { return selectAction }
-    
     
-    // MARK: - Margin Outlets
+    // MARK: - Appearance
     
-    @IBOutlet weak var topMargin: NSLayoutConstraint?
-    @IBOutlet weak var leftMargin: NSLayoutConstraint?
-    @IBOutlet weak var rightMargin: NSLayoutConstraint?
-    @IBOutlet weak var bottomMargin: NSLayoutConstraint?
+    public var appearance = ActionSheetAppearance(copy: .standard)
     
     
-    // MARK: - View Outlets
+    // MARK: - Outlets
     
     @IBOutlet weak var backgroundView: UIView?
     @IBOutlet weak var stackView: UIStackView?
     
+    @IBOutlet weak var topMargin: NSLayoutConstraint?
+    @IBOutlet weak var leftMargin: NSLayoutConstraint?
+    @IBOutlet weak var rightMargin: NSLayoutConstraint?
+    @IBOutlet weak var bottomMargin: NSLayoutConstraint?
+    
     
     // MARK: - Header Properties
     
-    open var headerView: UIView? {
-        didSet { refresh() }
-    }
+    open var headerView: UIView?
     
-    @IBOutlet weak var headerViewContainer: UIView? {
-        didSet {
-            headerViewContainer?.backgroundColor = .clear
-            refreshHeaderVisibility()
-        }
-    }
+    @IBOutlet weak var headerViewContainer: UIView?
     
-    @IBOutlet weak var headerViewContainerHeight: NSLayoutConstraint! {
-        didSet { refreshHeaderVisibility() }
-    }
+    @IBOutlet weak var headerViewContainerHeight: NSLayoutConstraint?
     
     
     // MARK: - Item Properties
     
-    public var items = [ActionSheetItem]()
+    public internal(set) var items = [ActionSheetItem]()
     
     public var itemsHeight: CGFloat { return totalHeight(for: items) }
     
     public lazy var itemHandler = ActionSheetItemHandler(actionSheet: self, itemType: .items)
     
-    @IBOutlet weak var itemsTableView: ActionSheetTableView? {
-        didSet { setup(itemsTableView, with: itemHandler) }
-    }
+    @IBOutlet weak var itemsTableView: ActionSheetTableView?
     
     @IBOutlet weak var itemsTableViewHeight: NSLayoutConstraint?
     
     
     // MARK: - Button Properties
     
-    public var buttons = [ActionSheetButton]()
+    public internal(set) var buttons = [ActionSheetButton]()
     
     public var buttonsHeight: CGFloat { return totalHeight(for: buttons) }
     
     public lazy var buttonHandler = ActionSheetItemHandler(actionSheet: self, itemType: .buttons)
     
-    @IBOutlet weak var buttonsTableView: ActionSheetTableView? {
-        didSet {
-            setup(buttonsTableView, with: buttonHandler)
-            refreshButtonsVisibility()
-        }
-    }
+    @IBOutlet weak var buttonsTableView: ActionSheetTableView?
     
-    @IBOutlet weak var buttonsTableViewHeight: NSLayoutConstraint? {
-        didSet { refreshButtonsVisibility() }
-    }
+    @IBOutlet weak var buttonsTableViewHeight: NSLayoutConstraint?
     
     
     // MARK: - Presentation Functions
@@ -219,9 +198,9 @@ open class ActionSheet: UIViewController {
         presenter.present(sheet: self, in: vc.rootViewController, from: view, completion: completion)
     }
 
-    open func present(in vc: UIViewController, from barButtonItem: UIBarButtonItem, completion: @escaping () -> () = {}) {
+    open func present(in vc: UIViewController, from item: UIBarButtonItem, completion: @escaping () -> () = {}) {
         refresh()
-        presenter.present(sheet: self, in: vc.rootViewController, from: barButtonItem, completion: completion)
+        presenter.present(sheet: self, in: vc.rootViewController, from: item, completion: completion)
     }
 
     
@@ -237,17 +216,13 @@ open class ActionSheet: UIViewController {
     }
     
     open func refreshHeader() {
-        refreshHeaderVisibility()
         let height = headerView?.frame.height ?? 0
         headerViewContainerHeight?.constant = height
+        headerViewContainer?.isHidden = headerView == nil
         guard let view = headerView else { return }
         headerViewContainer?.addSubviewToFill(view)
     }
     
-    open func refreshHeaderVisibility() {
-        headerViewContainer?.isHidden = headerView == nil
-    }
-    
     open func refreshItems() {
         items.forEach { $0.applyAppearance(appearance) }
         itemsTableView?.backgroundColor = appearance.itemsBackgroundColor
@@ -256,26 +231,20 @@ open class ActionSheet: UIViewController {
     }
     
     open func refreshButtons() {
-        refreshButtonsVisibility()
+        buttonsTableView?.isHidden = buttons.count == 0
         buttons.forEach { $0.applyAppearance(appearance) }
         buttonsTableView?.backgroundColor = appearance.buttonsBackgroundColor
         buttonsTableView?.separatorColor = appearance.buttonsSeparatorColor
         buttonsTableViewHeight?.constant = buttonsHeight
     }
     
-    open func refreshButtonsVisibility() {
-        buttonsTableView?.isHidden = buttons.count == 0
-    }
-    
     
     // MARK: - Protected Functions
     
     open func handleTap(on item: ActionSheetItem) {
         reloadData()
-        guard item.tapBehavior == .dismiss else { return selectAction(self, item) }
-        DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(100)) {
-            self.dismiss { self.selectAction(self, item) }
-        }
+        if item.tapBehavior != .dismiss { return selectAction(self, item) }
+        self.dismiss { self.selectAction(self, item) }
     }
     
     open func margin(at margin: ActionSheetMargin) -> CGFloat {
@@ -310,10 +279,6 @@ private extension ActionSheet {
         tableView?.delegate = handler
         tableView?.dataSource = handler
         tableView?.alwaysBounceVertical = false
-        setupAppearance(for: tableView)
-    }
-    
-    func setupAppearance(for tableView: UITableView?) {
         tableView?.estimatedRowHeight = 44
         tableView?.rowHeight = UITableView.automaticDimension
         tableView?.cellLayoutMarginsFollowReadableWidth = false

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

@@ -41,7 +41,7 @@
                     <subviews>
                         <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Eio-5P-omJ">
                             <rect key="frame" x="0.0" y="0.0" width="375" height="150"/>
-                            <color key="backgroundColor" red="0.45104343879999997" green="1" blue="0.29922929650000002" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                            <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
                             <constraints>
                                 <constraint firstAttribute="height" constant="150" id="ZKw-6e-7h3"/>
                             </constraints>

+ 7 - 0
Carthage/Checkouts/Sheeeeeeeeet/Sheeeeeeeeet/ActionSheet/ActionSheetItemHandler.swift

@@ -6,6 +6,13 @@
 //  Copyright © 2017 Daniel Saidi. All rights reserved.
 //
 
+/*
+ 
+ This class is used as data source and delegate for the item
+ and button table views of the action sheet class.
+ 
+ */
+
 import UIKit
 
 open class ActionSheetItemHandler: NSObject {

+ 23 - 65
Carthage/Checkouts/Sheeeeeeeeet/Sheeeeeeeeet/Appearance/ActionSheetAppearance.swift

@@ -34,20 +34,15 @@ open class ActionSheetAppearance {
         groupMargins = copy.groupMargins
         
         backgroundColor = copy.backgroundColor
-        itemsBackgroundColor = copy.itemsBackgroundColor ?? backgroundColor
-        buttonsSeparatorColor = copy.buttonsSeparatorColor ?? backgroundColor
-        
         separatorColor = copy.separatorColor
+        itemsBackgroundColor = copy.itemsBackgroundColor ?? backgroundColor
         itemsSeparatorColor = copy.itemsSeparatorColor ?? separatorColor
+        buttonsSeparatorColor = copy.buttonsSeparatorColor ?? backgroundColor
         buttonsSeparatorColor = copy.buttonsSeparatorColor ?? separatorColor
         
-        item = ActionSheetItemAppearance(copy: copy.item)
         popover = ActionSheetPopoverAppearance(copy: copy.popover)
         
-        cancelButton = ActionSheetCancelButtonAppearance(copy: copy.cancelButton)
-        dangerButton = ActionSheetDangerButtonAppearance(copy: copy.dangerButton)
-        okButton = ActionSheetOkButtonAppearance(copy: copy.okButton)
-        
+        item = ActionSheetItemAppearance(copy: copy.item)
         collectionItem = ActionSheetCollectionItemAppearance(copy: copy.collectionItem)
         customItem = ActionSheetCustomItemAppearance(copy: copy.customItem)
         linkItem = ActionSheetLinkItemAppearance(copy: copy.linkItem)
@@ -56,6 +51,10 @@ open class ActionSheetAppearance {
         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)
@@ -80,72 +79,31 @@ open class ActionSheetAppearance {
     
     public static var standard = ActionSheetAppearance()
     
-    public lazy var item: ActionSheetItemAppearance = {
-        return ActionSheetItemAppearance()
-    }()
-    
-    public lazy var popover: ActionSheetPopoverAppearance = {
-        return ActionSheetPopoverAppearance(width: 300)
-    }()
-    
-    
-    // MARK: - Buttons
-    
-    public lazy var cancelButton: ActionSheetCancelButtonAppearance = {
-        return ActionSheetCancelButtonAppearance(copy: item)
-    }()
-    
-    public lazy var dangerButton: ActionSheetDangerButtonAppearance = {
-        return ActionSheetDangerButtonAppearance(copy: item)
-    }()
-    
-    public lazy var okButton: ActionSheetOkButtonAppearance = {
-        return ActionSheetOkButtonAppearance(copy: item)
-    }()
+    public lazy var popover = ActionSheetPopoverAppearance(width: 300)
     
     
     // MARK: - Items
     
-    public lazy var collectionItem: ActionSheetCollectionItemAppearance = {
-        return ActionSheetCollectionItemAppearance(copy: item)
-    }()
-    
-    public lazy var customItem: ActionSheetCustomItemAppearance = {
-        return ActionSheetCustomItemAppearance(copy: item)
-    }()
-    
-    public lazy var linkItem: ActionSheetLinkItemAppearance = {
-        return ActionSheetLinkItemAppearance(copy: item)
-    }()
-    
-    public lazy var multiSelectItem: ActionSheetMultiSelectItemAppearance = {
-        return ActionSheetMultiSelectItemAppearance(copy: selectItem)
-    }()
+    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)
     
-    public lazy var multiSelectToggleItem: ActionSheetMultiSelectToggleItemAppearance = {
-        return ActionSheetMultiSelectToggleItemAppearance(copy: item)
-    }()
     
-    public lazy var selectItem: ActionSheetSelectItemAppearance = {
-        return ActionSheetSelectItemAppearance(copy: item)
-    }()
+    // MARK: - Buttons
     
-    public lazy var singleSelectItem: ActionSheetSingleSelectItemAppearance = {
-        return ActionSheetSingleSelectItemAppearance(copy: selectItem)
-    }()
+    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 = {
-        return ActionSheetSectionMarginAppearance(copy: item)
-    }()
-    
-    public lazy var sectionTitle: ActionSheetSectionTitleAppearance = {
-        return ActionSheetSectionTitleAppearance(copy: item)
-    }()
-    
-    public lazy var title: ActionSheetTitleAppearance = {
-        return ActionSheetTitleAppearance(copy: item)
-    }()
+    public lazy var sectionMargin = ActionSheetSectionMarginAppearance(copy: item)
+    public lazy var sectionTitle = ActionSheetSectionTitleAppearance(copy: item)
+    public lazy var title = ActionSheetTitleAppearance(copy: item)
 }

+ 2 - 2
Carthage/Checkouts/Sheeeeeeeeet/Sheeeeeeeeet/Appearance/Items/ActionSheetLinkItemAppearance.swift

@@ -19,8 +19,8 @@ open class ActionSheetLinkItemAppearance: ActionSheetItemAppearance {
     
     public override init(copy: ActionSheetItemAppearance) {
         super.init(copy: copy)
-        guard let copy = copy as? ActionSheetLinkItemAppearance else { return }
-        linkIcon = copy.linkIcon
+        let copy = copy as? ActionSheetLinkItemAppearance
+        linkIcon = copy?.linkIcon
     }
     
     

+ 3 - 3
Carthage/Checkouts/Sheeeeeeeeet/Sheeeeeeeeet/Appearance/Items/ActionSheetMultiSelectToggleItemAppearance.swift

@@ -19,9 +19,9 @@ open class ActionSheetMultiSelectToggleItemAppearance: ActionSheetItemAppearance
     
     public override init(copy: ActionSheetItemAppearance) {
         super.init(copy: copy)
-        guard let copy = copy as? ActionSheetMultiSelectToggleItemAppearance else { return }
-        deselectAllTextColor = copy.deselectAllTextColor
-        selectAllTextColor = copy.selectAllTextColor
+        let copy = copy as? ActionSheetMultiSelectToggleItemAppearance
+        deselectAllTextColor = copy?.deselectAllTextColor
+        selectAllTextColor = copy?.selectAllTextColor
     }
     
     

+ 7 - 5
Carthage/Checkouts/Sheeeeeeeeet/Sheeeeeeeeet/Appearance/Items/ActionSheetSelectItemAppearance.swift

@@ -34,11 +34,12 @@ open class ActionSheetSelectItemAppearance: ActionSheetItemAppearance {
         super.init(copy: copy)
         selectedTextColor = copy.textColor
         selectedTintColor = copy.tintColor
-        guard let copy = copy as? ActionSheetSelectItemAppearance else { return }
-        selectedIcon = copy.selectedIcon
-        selectedTextColor = copy.selectedTextColor ?? selectedTextColor
-        selectedTintColor = copy.selectedTintColor ?? selectedTintColor
-        selectedIconTintColor = copy.selectedIconTintColor ?? selectedTintColor
+        let copy = copy as? ActionSheetSelectItemAppearance
+        selectedIcon = copy?.selectedIcon
+        selectedTextColor = copy?.selectedTextColor ?? selectedTextColor
+        selectedTintColor = copy?.selectedTintColor ?? selectedTintColor
+        selectedIconTintColor = copy?.selectedIconTintColor ?? selectedTintColor
+        unselectedIcon = copy?.unselectedIcon
     }
     
     
@@ -48,4 +49,5 @@ open class ActionSheetSelectItemAppearance: ActionSheetItemAppearance {
     public var selectedIconTintColor: UIColor?
     public var selectedTextColor: UIColor?
     public var selectedTintColor: UIColor?
+    public var unselectedIcon: UIImage?
 }

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

@@ -11,6 +11,6 @@ import UIKit
 extension UIView {
     
     static var defaultNib: UINib {
-        return UINib(nibName: className, bundle: Bundle(for: self))
+        return UINib(nibName: className, bundle: self.bundle)
     }
 }

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

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

+ 1 - 0
Carthage/Checkouts/Sheeeeeeeeet/Sheeeeeeeeet/Items/ActionSheetItem.swift

@@ -46,6 +46,7 @@ open class ActionSheetItem: NSObject {
         self.tapBehavior = tapBehavior
         self.appearance = ActionSheetItemAppearance(copy: appearance)
         super.init()
+        if subtitle != nil { self.cellStyle = .value1}
     }
     
     

+ 2 - 0
Carthage/Checkouts/Sheeeeeeeeet/Sheeeeeeeeet/Items/Items/ActionSheetMultiSelectItem.swift

@@ -32,12 +32,14 @@ open class ActionSheetMultiSelectItem: ActionSheetSelectItem {
     
     public init(
         title: String,
+        subtitle: String? = nil,
         isSelected: Bool,
         group: String = "",
         value: Any? = nil,
         image: UIImage? = nil) {
         super.init(
             title: title,
+            subtitle: subtitle,
             isSelected: isSelected,
             group: group,
             value: value,

+ 4 - 1
Carthage/Checkouts/Sheeeeeeeeet/Sheeeeeeeeet/Items/Items/ActionSheetSelectItem.swift

@@ -33,6 +33,7 @@ open class ActionSheetSelectItem: ActionSheetItem {
     
     public init(
         title: String,
+        subtitle: String? = nil,
         isSelected: Bool,
         group: String = "",
         value: Any? = nil,
@@ -42,6 +43,7 @@ open class ActionSheetSelectItem: ActionSheetItem {
         self.group = group
         super.init(
             title: title,
+            subtitle: subtitle,
             value: value,
             image: image,
             tapBehavior: tapBehavior)
@@ -69,7 +71,8 @@ open class ActionSheetSelectItem: ActionSheetItem {
     open override func applyAppearance(to cell: UITableViewCell) {
         super.applyAppearance(to: cell)
         guard let appearance = selectAppearance else { return }
-        cell.accessoryView = isSelected ? UIImageView(image: appearance.selectedIcon) : nil
+        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

+ 0 - 5
Carthage/Checkouts/Sheeeeeeeeet/Sheeeeeeeeet/Presenters/ActionSheetPopoverPresenter.swift

@@ -23,11 +23,6 @@ import UIKit
 open class ActionSheetPopoverPresenter: NSObject, ActionSheetPresenter {
     
     
-    // MARK: - Initialization
-    
-    deinit { print("\(type(of: self)) deinit") }
-    
-    
     // MARK: - Properties
     
     open var events = ActionSheetPresenterEvents()

+ 0 - 2
Carthage/Checkouts/Sheeeeeeeeet/Sheeeeeeeeet/Presenters/ActionSheetStandardPresenter.swift

@@ -22,8 +22,6 @@ open class ActionSheetStandardPresenter: ActionSheetPresenter {
     
     public init() {}
     
-    deinit { print("\(type(of: self)) deinit") }
-    
     
     // MARK: - Properties
     

+ 8 - 2
Carthage/Checkouts/Sheeeeeeeeet/SheeeeeeeeetExample/AppDelegate+Appearance.swift

@@ -6,6 +6,13 @@
 //  Copyright © 2018 Daniel Saidi. All rights reserved.
 //
 
+/*
+ 
+ This extension isolates how the example app applies colors,
+ fonts etc to the example action sheets.
+ 
+ */
+
 import UIKit
 import Sheeeeeeeeet
 
@@ -47,16 +54,15 @@ extension AppDelegate {
         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.selectedIcon = UIImage(named: "ic_checkmark")
         appearance.singleSelectItem.selectedTintColor = green
         appearance.singleSelectItem.selectedTextColor = purple
         appearance.singleSelectItem.selectedIconTintColor = blue
         
-        appearance.multiSelectItem.selectedIcon = UIImage(named: "ic_checkmark")
         appearance.multiSelectItem.selectedTintColor = purple
         appearance.multiSelectItem.selectedTextColor = blue
         appearance.multiSelectItem.selectedIconTintColor = green

+ 7 - 0
Carthage/Checkouts/Sheeeeeeeeet/SheeeeeeeeetExample/Cells/MyCollectionViewCell.swift

@@ -6,6 +6,13 @@
 //  Copyright © 2018 Jonas Ullström. All rights reserved.
 //
 
+/*
+ 
+ This cell is used by the example app, to populate the cells
+ of the `CollectionActionSheet` example action sheet.
+ 
+ */
+
 import UIKit
 import Sheeeeeeeeet
 

+ 7 - 0
Carthage/Checkouts/Sheeeeeeeeet/SheeeeeeeeetExample/Cells/MyCustomViewCell.swift

@@ -6,6 +6,13 @@
 //  Copyright © 2018 Daniel Saidi. All rights reserved.
 //
 
+/*
+ 
+ This cell is used by the example app, as the custom view in
+ the `CustomActionSheet` example action sheet.
+ 
+ */
+
 import Sheeeeeeeeet
 
 class MyCustomViewCell: ActionSheetItemCell, ActionSheetCustomItemCell {

+ 6 - 0
Carthage/Checkouts/Sheeeeeeeeet/SheeeeeeeeetExample/Extensions/UIColor+Hex.swift

@@ -6,6 +6,12 @@
 //  Copyright © 2016 Daniel Saidi. All rights reserved.
 //
 
+/*
+ 
+ This extension is used to create colors in the example app.
+ 
+ */
+
 import UIKit
 
 

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

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

+ 7 - 0
Carthage/Checkouts/Sheeeeeeeeet/SheeeeeeeeetExample/Options/FoodOption+ActionSheetItems.swift

@@ -6,6 +6,13 @@
 //  Copyright © 2018 Jonas Ullström. All rights reserved.
 //
 
+/*
+ 
+ This file contains food option extensions, that can be used
+ to create action sheet items in the example app.
+ 
+ */
+
 import Sheeeeeeeeet
 
 extension FoodOption {

+ 6 - 1
Carthage/Checkouts/Sheeeeeeeeet/SheeeeeeeeetExample/Options/FoodOption.swift

@@ -6,7 +6,12 @@
 //  Copyright © 2017 Daniel Saidi. All rights reserved.
 //
 
-// This enum is only used to populate our example sheets.
+/*
+ 
+ This enum is used to create food action sheet options, that
+ are presented in the example action sheets.
+ 
+ */
 
 import Sheeeeeeeeet
 

+ 6 - 1
Carthage/Checkouts/Sheeeeeeeeet/SheeeeeeeeetExample/Options/TableViewOption.swift

@@ -6,7 +6,12 @@
 //  Copyright © 2017 Daniel Saidi. All rights reserved.
 //
 
-// This enum is only used to populate our example table view.
+/*
+ 
+ This enum is used by the example app, to populate the table
+ view in the main example view controller.
+ 
+ */
 
 import UIKit
 

+ 7 - 0
Carthage/Checkouts/Sheeeeeeeeet/SheeeeeeeeetExample/ViewController/ViewController+Alerts.swift

@@ -6,6 +6,13 @@
 //  Copyright © 2017 Daniel Saidi. All rights reserved.
 //
 
+/*
+ 
+ These extensions are only used by the example app, to alert
+ which options a user selects in the example action sheets.
+ 
+ */
+
 import UIKit
 import Sheeeeeeeeet
 

+ 8 - 0
Carthage/Checkouts/Sheeeeeeeeet/SheeeeeeeeetExample/ViewController/ViewController+TableView.swift

@@ -6,9 +6,17 @@
 //  Copyright © 2017 Daniel Saidi. All rights reserved.
 //
 
+/*
+ 
+ These extensions are only used by the example app, to setup
+ the main view controller's table view handling.
+ 
+ */
+
 import UIKit
 import Sheeeeeeeeet
 
+
 // MARK: - UITableViewDataSource
 
 extension ViewController: UITableViewDataSource {

+ 4 - 4
Carthage/Checkouts/Sheeeeeeeeet/SheeeeeeeeetExample/ViewController/ViewController.swift

@@ -9,11 +9,11 @@
 /*
  
  To make the example easier to overview, the view controller
- has been split up into extension files.
+ has been split up into multiple files.
  
- Action sheet appearance is setup by `AppDelegate` using the
- `DemoAppearance` class. You can play around with it to view
- how sheets and items are affected by appearance changes.
+ The action sheet appearance is setup by `AppDelegate`, with
+ the `AppDelegate+Appearance` extension. You can play around
+ with it to see how it affects the example sheets and items.
  
  */
 

+ 12 - 44
Carthage/Checkouts/Sheeeeeeeeet/SheeeeeeeeetTests/ActionSheet/ActionSheetTests.swift

@@ -6,6 +6,8 @@
 //  Copyright © 2017 Daniel Saidi. All rights reserved.
 //
 
+//  TODO: Improve these tests, since much logic has changed.
+
 import Quick
 import Nimble
 @testable import Sheeeeeeeeet
@@ -100,32 +102,6 @@ class ActionSheetTests: QuickSpec {
         }
         
         
-        // MARK: - Header Properties
-        
-        describe("header view") {
-            
-            it("refreshes the sheet when set") {
-                let sheet = createSheet()
-                expect(sheet.refreshInvokeCount).to(equal(0))
-                sheet.headerView = UIView()
-                
-                expect(sheet.refreshInvokeCount).to(equal(1))
-            }
-        }
-        
-        describe("header view container") {
-            
-            it("gets clear background color when set") {
-                let sheet = createSheet()
-                let view = UIView()
-                view.backgroundColor = .red
-                sheet.headerViewContainer = view
-                
-                expect(view.backgroundColor).to(equal(.clear))
-            }
-        }
-        
-        
         // MARK: - Item Properties
         
         describe("items height") {
@@ -164,10 +140,11 @@ class ActionSheetTests: QuickSpec {
         
         describe("item table view") {
             
-            it("is correctly setup when set") {
+            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))
@@ -216,10 +193,11 @@ class ActionSheetTests: QuickSpec {
         
         describe("button table view") {
             
-            it("is correctly setup when set") {
+            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))
@@ -329,8 +307,6 @@ class ActionSheetTests: QuickSpec {
                 sheet.itemsTableView = itemsView
                 sheet.buttonsTableView = buttonsView
                 sheet.stackView = stackView
-                sheet.refreshButtonsVisibilityInvokeCount = 0
-                sheet.refreshHeaderVisibilityInvokeCount = 0
             }
             
             context("sheet") {
@@ -362,8 +338,7 @@ class ActionSheetTests: QuickSpec {
                 
                 it("refreshes header visibility") {
                     sheet.refresh()
-                    
-                    expect(sheet.refreshHeaderVisibilityInvokeCount).to(equal(1))
+                    expect(sheet.refreshHeaderInvokeCount).to(equal(1))
                 }
                 
                 it("adds header view to header container") {
@@ -371,7 +346,6 @@ class ActionSheetTests: QuickSpec {
                     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())
@@ -381,15 +355,13 @@ class ActionSheetTests: QuickSpec {
             context("header visibility") {
                 
                 it("hides header container if header view is nil") {
-                    sheet.refreshHeaderVisibility()
-                    
+                    sheet.refreshHeader()
                     expect(headerViewContainer.isHidden).to(beTrue())
                 }
                 
                 it("shows header container if header view is nil") {
                     sheet.headerView = UIView(frame: .zero)
-                    sheet.refreshHeaderVisibility()
-                    
+                    sheet.refreshHeader()
                     expect(headerViewContainer.isHidden).to(beFalse())
                 }
             }
@@ -431,8 +403,7 @@ class ActionSheetTests: QuickSpec {
                 
                 it("refreshes buttons visibility") {
                     sheet.refresh()
-                    
-                    expect(sheet.refreshButtonsVisibilityInvokeCount).to(equal(1))
+                    expect(sheet.refreshButtonsInvokeCount).to(equal(1))
                 }
                 
                 it("applies appearances to all buttons") {
@@ -469,15 +440,13 @@ class ActionSheetTests: QuickSpec {
             context("button visibility") {
                 
                 it("hides buttons if sheet has no buttons") {
-                    sheet.refreshButtonsVisibility()
-                    
+                    sheet.refreshButtons()
                     expect(buttonsView.isHidden).to(beTrue())
                 }
                 
                 it("shows buttons if sheet has buttons") {
                     sheet.setup(items: [MockActionSheetButton(title: "foo", value: true)])
-                    sheet.refreshButtonsVisibility()
-                    
+                    sheet.refreshButtons()
                     expect(buttonsView.isHidden).to(beFalse())
                 }
             }
@@ -513,7 +482,6 @@ class ActionSheetTests: QuickSpec {
                 let item = createItem("")
                 item.tapBehavior = .dismiss
                 sheet.handleTap(on: item)
-
 //                expect(count).toEventually(equal(1), time)        TODO
 //                expect(sheet.dismissInvokeCount).to(equal(1))     TODO
             }

+ 14 - 8
Carthage/Checkouts/Sheeeeeeeeet/SheeeeeeeeetTests/ActionSheet/MockActionSheet.swift

@@ -7,8 +7,9 @@ class MockActionSheet: ActionSheet {
     var handleTapInvokeItems = [ActionSheetItem]()
     var prepareForPresentationInvokeCount = 0
     var refreshInvokeCount = 0
-    var refreshButtonsVisibilityInvokeCount = 0
-    var refreshHeaderVisibilityInvokeCount = 0
+    var refreshButtonsInvokeCount = 0
+    var refreshItemsInvokeCount = 0
+    var refreshHeaderInvokeCount = 0
     var reloadDataInvokeCount = 0
     
     override func dismiss(completion: @escaping () -> ()) {
@@ -27,14 +28,19 @@ class MockActionSheet: ActionSheet {
         refreshInvokeCount += 1
     }
     
-    override func refreshButtonsVisibility() {
-        super.refreshButtonsVisibility()
-        refreshButtonsVisibilityInvokeCount += 1
+    override func refreshButtons() {
+        super.refreshButtons()
+        refreshButtonsInvokeCount += 1
     }
     
-    override func refreshHeaderVisibility() {
-        super.refreshHeaderVisibility()
-        refreshHeaderVisibilityInvokeCount += 1
+    override func refreshItems() {
+        super.refreshItems()
+        refreshItemsInvokeCount += 1
+    }
+    
+    override func refreshHeader() {
+        super.refreshHeader()
+        refreshHeaderInvokeCount += 1
     }
     
     override func reloadData() {

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

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

+ 9 - 4
Carthage/Checkouts/Sheeeeeeeeet/SheeeeeeeeetTests/Items/ActionSheetItemTests.swift

@@ -74,8 +74,8 @@ class ActionSheetItemTests: QuickSpec {
     
     override func spec() {
         
-        func createItem() -> MockActionSheetItem {
-            return MockActionSheetItem(title: "foo", subtitle: "bar", value: true, image: UIImage())
+        func createItem(subtitle: String? = nil) -> MockActionSheetItem {
+            return MockActionSheetItem(title: "foo", subtitle: subtitle, value: true, image: UIImage())
             
         }
         
@@ -125,10 +125,15 @@ class ActionSheetItemTests: QuickSpec {
         
         describe("cell style") {
             
-            it("is default") {
-                let item = createItem()
+            it("is default if no subtitle is set") {
+                let item = createItem(subtitle: nil)
                 expect(item.cellStyle).to(equal(.default))
             }
+            
+            it("is value1 if subtitle is set") {
+                let item = createItem(subtitle: "bar")
+                expect(item.cellStyle).to(equal(.value1))
+            }
         }
         
         describe("custom appearance") {

+ 0 - 2
Carthage/Checkouts/Sheeeeeeeeet/SheeeeeeeeetTests/Presenters/ActionSheetPopoverPresenterTests.swift

@@ -6,8 +6,6 @@
 //  Copyright © 2018 Daniel Saidi. All rights reserved.
 //
 
-//  TODO: Write more tests
-
 import Quick
 import Nimble
 @testable import Sheeeeeeeeet

+ 9 - 0
Carthage/Checkouts/TLPhotoPicker/Example/TLPhotoPicker/CustomPhotoPickerViewController.swift

@@ -21,4 +21,13 @@ class CustomPhotoPickerViewController: TLPhotosPickerViewController {
             self?.dismissCompletion?()
         }
     }
+    /*
+    override func maxCheck() -> Bool {
+        let imageCount = self.selectedAssets.filter{ $0.phAsset?.mediaType == .image }.count
+        let videoCount = self.selectedAssets.filter{ $0.phAsset?.mediaType == .video }.count
+        if imageCount > 3 || videoCount > 1 {
+            return true
+        }
+        return false
+    }*/
 }

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

@@ -8,7 +8,7 @@
 
 Pod::Spec.new do |s|
   s.name             = 'TLPhotoPicker'
-  s.version          = '1.7.8'
+  s.version          = '1.8.0'
   s.summary          = 'multiple phassets picker for iOS lib. like facebook'
 
 # This description is used to generate tags and improve search results.

+ 5 - 0
Carthage/Checkouts/TLPhotoPicker/TLPhotoPicker/Classes/TLAssetsCollection.swift

@@ -271,6 +271,11 @@ public struct TLPHAsset {
     init(asset: PHAsset?) {
         self.phAsset = asset
     }
+
+    public static func asset(with localIdentifier: String) -> TLPHAsset? {
+        let fetchResult = PHAsset.fetchAssets(withLocalIdentifiers: [localIdentifier], options: nil)
+        return TLPHAsset(asset: fetchResult.firstObject)
+    }
 }
 
 extension TLPHAsset: Equatable {

+ 1 - 3
Carthage/Checkouts/TLPhotoPicker/TLPhotoPicker/Classes/TLPhotoLibrary.swift

@@ -143,9 +143,7 @@ extension TLPhotoLibrary {
             options.merge(predicate: notVideoPredicate)
         }
         if configure.allowedLivePhotos == false {
-            let notLivePhotoPredicate = NSPredicate(format: "mediaType = %i OR mediaSubtype != %i",
-                                                    PHAssetMediaType.video.rawValue,
-                                                    PHAssetMediaSubtype.photoLive.rawValue)
+            let notLivePhotoPredicate = NSPredicate(format: "NOT ((mediaSubtype & %d) != 0)", PHAssetMediaSubtype.photoLive.rawValue)
             options.merge(predicate: notLivePhotoPredicate)
         }
         if let maxVideoDuration = configure.maxVideoDuration {

+ 13 - 12
Carthage/Checkouts/TLPhotoPicker/TLPhotoPicker/Classes/TLPhotosPickerViewController.swift

@@ -239,6 +239,19 @@ open class TLPhotosPickerViewController: UIViewController {
             initPhotoLibrary()
         }
     }
+    
+    open func maxCheck() -> Bool {
+        if self.configure.singleSelectedMode {
+            self.selectedAssets.removeAll()
+            self.orderUpdateCells()
+        }
+        if let max = self.configure.maxSelectedAssets, max <= self.selectedAssets.count {
+            self.delegate?.didExceedMaximumNumberOfSelection(picker: self)
+            self.didExceedMaximumNumberOfSelection?(self)
+            return true
+        }
+        return false
+    }
 }
 
 // MARK: - UI & UI Action
@@ -419,18 +432,6 @@ extension TLPhotosPickerViewController {
         return true
     }
     
-    fileprivate func maxCheck() -> Bool {
-        if self.configure.singleSelectedMode {
-            self.selectedAssets.removeAll()
-            self.orderUpdateCells()
-        }
-        if let max = self.configure.maxSelectedAssets, max <= self.selectedAssets.count {
-            self.delegate?.didExceedMaximumNumberOfSelection(picker: self)
-            self.didExceedMaximumNumberOfSelection?(self)
-            return true
-        }
-        return false
-    }
     fileprivate func focusFirstCollection() {
         if self.focusedCollection == nil, let collection = self.collections.first {
             self.focusedCollection = collection

+ 52 - 0
Carthage/Checkouts/realm-cocoa/CHANGELOG.md

@@ -1,3 +1,31 @@
+3.13.1 Release notes (2019-01-03)
+=============================================================
+
+### Fixed
+
+* Fix a crash when iterating over `Realm.subscriptions()` using for-in.
+  (Since 3.13.0, PR [#6050](https://github.com/realm/realm-cocoa/pull/6050)).
+
+### Compatibility
+
+* File format: Generates Realms with format v9 (Reads and upgrades all previous formats)
+* Realm Object Server: 3.11.0 or later.
+
+3.13.0 Release notes (2018-12-14)
+=============================================================
+
+### Enhancements
+
+* Add `Realm.subscriptions()`/`-[RLMRealm subscriptions]` and
+  `Realm.subscription(named:)`/`-[RLMRealm subscriptionWithName:]` to enable
+  looking up existing query-based sync subscriptions.
+  (PR: https://github.com/realm/realm-cocoa/pull/6029).
+
+### Compatibility
+
+* File format: Generates Realms with format v9 (Reads and upgrades all previous formats)
+* Realm Object Server: 3.11.0 or later.
+
 3.12.0 Release notes (2018-11-26)
 =============================================================
 
@@ -11,11 +39,20 @@
   (PR: https://github.com/realm/realm-cocoa/pull/6007).
 * Add Xcode 10.1 binary to the prebuilt package.
 
+### Fixed
+
+* None.
+
 ### Compatibility
 
 * File format: Generates Realms with format v9 (Reads and upgrades all previous formats)
 * Realm Object Server: 3.11.0 or later.
 
+### Internal
+
+* None.
+
+
 3.11.2 Release notes (2018-11-15)
 =============================================================
 
@@ -42,9 +79,18 @@
 * File format: Generates Realms with format v9 (Reads and upgrades all previous formats)
 * Realm Object Server: 3.11.0 or later.
 
+### Internal
+
+* None.
+
+
 3.11.1 Release notes (2018-10-19)
 =============================================================
 
+### Enhancements
+
+* None.
+
 ### Fixed
 
 * Fix `SyncUser.requestEmailConfirmation` not triggering the email confirmation
@@ -60,6 +106,11 @@
 * File format: Generates Realms with format v9 (Reads and upgrades all previous formats)
 * Realm Object Server: 3.11.0 or later.
 
+### Internal
+
+* None.
+
+
 3.11.0 Release notes (2018-10-04)
 =============================================================
 
@@ -89,6 +140,7 @@
 ### Internal
 * Update to Sync 3.12.2.
 
+
 3.10.0 Release notes (2018-09-19)
 =============================================================
 

+ 153 - 6
Carthage/Checkouts/realm-cocoa/Realm/ObjectServerTests/RLMObjectServerTests.mm

@@ -60,6 +60,12 @@
 }
 @end
 
+@implementation PersonObject
++ (NSDictionary *)linkingObjectsProperties {
+    return @{@"parents": [RLMPropertyDescriptor descriptorWithClass:PersonObject.class propertyName:@"children"]};
+}
+@end
+
 @interface RLMObjectServerTests : RLMSyncTestCase
 @end
 
@@ -1783,6 +1789,10 @@
 
 #pragma mark - Partial sync
 
+- (void)waitForKeyPath:(NSString *)keyPath object:(id)object value:(id)value {
+    [self waitForExpectations:@[[[XCTKVOExpectation alloc] initWithKeyPath:keyPath object:object expectedValue:value]] timeout:20.0];
+}
+
 - (void)testPartialSync {
     // Make credentials.
     NSString *name = NSStringFromSelector(_cmd);
@@ -1833,8 +1843,7 @@
         RLMSyncSubscription *subscription = [objects subscribeWithName:@"query"];
 
         // Wait for the results to become available.
-        XCTestExpectation *ex = [[XCTKVOExpectation alloc] initWithKeyPath:@"state" object:subscription expectedValue:@(RLMSyncSubscriptionStateComplete)];
-        [self waitForExpectations:@[ex] timeout:20.0];
+        [self waitForKeyPath:@"state" object:subscription value:@(RLMSyncSubscriptionStateComplete)];
 
         // Verify that we got what we're looking for
         XCTAssertEqual(objects.count, 4U);
@@ -1853,17 +1862,155 @@
         RLMSyncSubscription *subscription2 = [objects2 subscribeWithName:@"query"];
 
         // Wait for the error to be reported.
-        XCTestExpectation *ex2 = [[XCTKVOExpectation alloc] initWithKeyPath:@"state" object:subscription2 expectedValue:@(RLMSyncSubscriptionStateError)];
-        [self waitForExpectations:@[ex2] timeout:20.0];
+        [self waitForKeyPath:@"state" object:subscription2 value:@(RLMSyncSubscriptionStateError)];
         XCTAssertNotNil(subscription2.error);
 
         // Unsubscribe from the query, and ensure that it correctly transitions to the invalidated state.
         [subscription unsubscribe];
-        XCTestExpectation *ex3 = [[XCTKVOExpectation alloc] initWithKeyPath:@"state" object:subscription expectedValue:@(RLMSyncSubscriptionStateInvalidated)];
-        [self waitForExpectations:@[ex3] timeout:20.0];
+        [self waitForKeyPath:@"state" object:subscription value:@(RLMSyncSubscriptionStateInvalidated)];
     }
 }
 
+- (RLMRealm *)partialRealmWithName:(SEL)sel {
+    NSString *name = NSStringFromSelector(sel);
+    NSURL *server = [RLMObjectServerTests authServerURL];
+    RLMSyncCredentials *creds = [RLMObjectServerTests basicCredentialsWithName:name register:YES];
+    RLMSyncUser *user = [self logInUserForCredentials:creds server:server];
+    RLMRealmConfiguration *configuration = [user configuration];
+    return [self openRealmWithConfiguration:configuration];
+}
+
+- (void)testAllSubscriptionsReportsNewlyCreatedSubscription {
+    RLMRealm *realm = [self partialRealmWithName:_cmd];
+    XCTAssertEqual(0U, realm.subscriptions.count);
+
+    RLMSyncSubscription *subscription = [[PartialSyncObjectA objectsInRealm:realm where:@"number > 5"]
+                                         subscribeWithName:@"query"];
+    // Should still be 0 because the subscription is created asynchronously
+    XCTAssertEqual(0U, realm.subscriptions.count);
+
+    [self waitForKeyPath:@"state" object:subscription value:@(RLMSyncSubscriptionStateComplete)];
+    XCTAssertEqual(1U, realm.subscriptions.count);
+
+    RLMSyncSubscription *subscription2 = realm.subscriptions.firstObject;
+    XCTAssertEqualObjects(@"query", subscription2.name);
+    XCTAssertEqual(RLMSyncSubscriptionStateComplete, subscription2.state);
+    XCTAssertNil(subscription2.error);
+}
+
+- (void)testAllSubscriptionsDoesNotReportLocalError {
+    RLMRealm *realm = [self partialRealmWithName:_cmd];
+    RLMSyncSubscription *subscription1 = [[PartialSyncObjectA objectsInRealm:realm where:@"number > 5"]
+                                         subscribeWithName:@"query"];
+    [self waitForKeyPath:@"state" object:subscription1 value:@(RLMSyncSubscriptionStateComplete)];
+    RLMSyncSubscription *subscription2 = [[PartialSyncObjectA objectsInRealm:realm where:@"number > 6"]
+                                         subscribeWithName:@"query"];
+    [self waitForKeyPath:@"state" object:subscription2 value:@(RLMSyncSubscriptionStateError)];
+    XCTAssertEqual(1U, realm.subscriptions.count);
+}
+
+- (void)testAllSubscriptionsReportsServerError {
+    RLMRealm *realm = [self partialRealmWithName:_cmd];
+    RLMSyncSubscription *subscription = [[PersonObject objectsInRealm:realm where:@"SUBQUERY(parents, $p1, $p1.age < 31 AND SUBQUERY($p1.parents, $p2, $p2.age > 35 AND $p2.name == 'Michael').@count > 0).@count > 0"]
+                                          subscribeWithName:@"query"];
+    XCTAssertEqual(0U, realm.subscriptions.count);
+    [self waitForKeyPath:@"state" object:subscription value:@(RLMSyncSubscriptionStateError)];
+    XCTAssertEqual(1U, realm.subscriptions.count);
+
+    RLMSyncSubscription *subscription2 = realm.subscriptions.lastObject;
+    XCTAssertEqualObjects(@"query", subscription2.name);
+    XCTAssertEqual(RLMSyncSubscriptionStateError, subscription2.state);
+    XCTAssertNotNil(subscription2.error);
+}
+
+- (void)testUnsubscribeUsingOriginalSubscriptionObservingFetched {
+    RLMRealm *realm = [self partialRealmWithName:_cmd];
+    RLMSyncSubscription *original = [[PartialSyncObjectA allObjectsInRealm:realm] subscribeWithName:@"query"];
+    [self waitForKeyPath:@"state" object:original value:@(RLMSyncSubscriptionStateComplete)];
+    XCTAssertEqual(1U, realm.subscriptions.count);
+    RLMSyncSubscription *fetched = realm.subscriptions.firstObject;
+
+    [original unsubscribe];
+    [self waitForKeyPath:@"state" object:fetched value:@(RLMSyncSubscriptionStateInvalidated)];
+    XCTAssertEqual(0U, realm.subscriptions.count);
+    XCTAssertEqual(RLMSyncSubscriptionStateInvalidated, original.state);
+}
+
+- (void)testUnsubscribeUsingFetchedSubscriptionObservingFetched {
+    RLMRealm *realm = [self partialRealmWithName:_cmd];
+    RLMSyncSubscription *original = [[PartialSyncObjectA allObjectsInRealm:realm] subscribeWithName:@"query"];
+    [self waitForKeyPath:@"state" object:original value:@(RLMSyncSubscriptionStateComplete)];
+    XCTAssertEqual(1U, realm.subscriptions.count);
+    RLMSyncSubscription *fetched = realm.subscriptions.firstObject;
+
+    [fetched unsubscribe];
+    [self waitForKeyPath:@"state" object:fetched value:@(RLMSyncSubscriptionStateInvalidated)];
+    XCTAssertEqual(0U, realm.subscriptions.count);
+    XCTAssertEqual(RLMSyncSubscriptionStateInvalidated, original.state);
+}
+
+- (void)testUnsubscribeUsingFetchedSubscriptionObservingOriginal {
+    RLMRealm *realm = [self partialRealmWithName:_cmd];
+    RLMSyncSubscription *original = [[PartialSyncObjectA allObjectsInRealm:realm] subscribeWithName:@"query"];
+    [self waitForKeyPath:@"state" object:original value:@(RLMSyncSubscriptionStateComplete)];
+    XCTAssertEqual(1U, realm.subscriptions.count);
+    RLMSyncSubscription *fetched = realm.subscriptions.firstObject;
+
+    [fetched unsubscribe];
+    [self waitForKeyPath:@"state" object:original value:@(RLMSyncSubscriptionStateInvalidated)];
+    XCTAssertEqual(0U, realm.subscriptions.count);
+    XCTAssertEqual(RLMSyncSubscriptionStateInvalidated, fetched.state);
+}
+
+- (void)testSubscriptionWithName {
+    RLMRealm *realm = [self partialRealmWithName:_cmd];
+    XCTAssertNil([realm subscriptionWithName:@"query"]);
+
+    RLMSyncSubscription *subscription = [[PartialSyncObjectA allObjectsInRealm:realm] subscribeWithName:@"query"];
+    XCTAssertNil([realm subscriptionWithName:@"query"]);
+
+    [self waitForKeyPath:@"state" object:subscription value:@(RLMSyncSubscriptionStateComplete)];
+    XCTAssertNotNil([realm subscriptionWithName:@"query"]);
+    XCTAssertNil([realm subscriptionWithName:@"query2"]);
+
+    RLMSyncSubscription *subscription2 = [realm subscriptionWithName:@"query"];
+    XCTAssertEqualObjects(@"query", subscription2.name);
+    XCTAssertEqual(RLMSyncSubscriptionStateComplete, subscription2.state);
+    XCTAssertNil(subscription2.error);
+
+    [subscription unsubscribe];
+    XCTAssertNotNil([realm subscriptionWithName:@"query"]);
+
+    [self waitForKeyPath:@"state" object:subscription value:@(RLMSyncSubscriptionStateInvalidated)];
+    XCTAssertNil([realm subscriptionWithName:@"query"]);
+    XCTAssertEqual(RLMSyncSubscriptionStateInvalidated, subscription2.state);
+}
+
+- (void)testSortAndFilterSubscriptions {
+    RLMRealm *realm = [self partialRealmWithName:_cmd];
+
+    [self waitForKeyPath:@"state" object:[[PartialSyncObjectA allObjectsInRealm:realm] subscribeWithName:@"query 1"]
+                   value:@(RLMSyncSubscriptionStateComplete)];
+    [self waitForKeyPath:@"state" object:[[PartialSyncObjectA allObjectsInRealm:realm] subscribeWithName:@"query 2"]
+                   value:@(RLMSyncSubscriptionStateComplete)];
+    [self waitForKeyPath:@"state" object:[[PartialSyncObjectB allObjectsInRealm:realm] subscribeWithName:@"query 3"]
+                   value:@(RLMSyncSubscriptionStateComplete)];
+    RLMResults *unsupportedQuery = [PersonObject objectsInRealm:realm where:@"SUBQUERY(parents, $p1, $p1.age < 31 AND SUBQUERY($p1.parents, $p2, $p2.age > 35 AND $p2.name == 'Michael').@count > 0).@count > 0"];
+    [self waitForKeyPath:@"state" object:[unsupportedQuery subscribeWithName:@"query 4"]
+                   value:@(RLMSyncSubscriptionStateError)];
+
+    auto subscriptions = realm.subscriptions;
+    XCTAssertEqual(4U, subscriptions.count);
+    XCTAssertEqual(0U, ([subscriptions objectsWhere:@"name = %@", @"query 0"].count));
+    XCTAssertEqualObjects(@"query 1", ([subscriptions objectsWhere:@"name = %@", @"query 1"].firstObject.name));
+    XCTAssertEqual(3U, ([subscriptions objectsWhere:@"status = %@", @(RLMSyncSubscriptionStateComplete)].count));
+    XCTAssertEqual(1U, ([subscriptions objectsWhere:@"status = %@", @(RLMSyncSubscriptionStateError)].count));
+
+    XCTAssertThrows([subscriptions sortedResultsUsingKeyPath:@"name" ascending:NO]);
+    XCTAssertThrows([subscriptions sortedResultsUsingDescriptors:@[]]);
+    XCTAssertThrows([subscriptions distinctResultsUsingKeyPaths:@[@"name"]]);
+}
+
 #pragma mark - Certificate pinning
 
 - (void)attemptLoginWithUsername:(NSString *)userName callback:(void (^)(RLMSyncUser *, NSError *))callback {

+ 50 - 2
Carthage/Checkouts/realm-cocoa/Realm/ObjectServerTests/SwiftObjectServerTests.swift

@@ -441,8 +441,6 @@ class SwiftObjectServerTests: SwiftSyncTestCase {
 
     // MARK: - Partial sync
 
-// Partial sync subscriptions are only available in Swift 3.2 and newer.
-#if swift(>=3.2)
     func populateTestRealm(_ username: String) {
         autoreleasepool {
             let credentials = SyncCredentials.usernamePassword(username: username, password: "a", register: true)
@@ -539,6 +537,36 @@ class SwiftObjectServerTests: SwiftSyncTestCase {
         }
     }
 
+    func testPartialSyncSubscriptions() {
+        let credentials = SyncCredentials.usernamePassword(username: #function, password: "a", register: true)
+        let user = try! synchronouslyLogInUser(for: credentials, server: authURL)
+        let realm = try! synchronouslyOpenRealm(configuration: user.configuration())
+
+        XCTAssertEqual(realm.subscriptions().count, 0)
+        XCTAssertNil(realm.subscription(named: "query"))
+
+        let subscription = realm.objects(SwiftPartialSyncObjectA.self).filter("number > 5").subscribe(named: "query")
+        XCTAssertEqual(realm.subscriptions().count, 0)
+        XCTAssertNil(realm.subscription(named: "query"))
+        waitForState(subscription, .complete)
+
+        XCTAssertEqual(realm.subscriptions().count, 1)
+        let sub2 = realm.subscriptions().first!
+        XCTAssertEqual(sub2.name, "query")
+        XCTAssertEqual(sub2.state, .complete)
+        let sub3 = realm.subscription(named: "query")!
+        XCTAssertEqual(sub3.name, "query")
+        XCTAssertEqual(sub3.state, .complete)
+        for sub in realm.subscriptions() {
+            XCTAssertEqual(sub.name, "query")
+            XCTAssertEqual(sub.state, .complete)
+        }
+
+        XCTAssertNil(realm.subscription(named: "not query"))
+    }
+
+// Partial sync subscriptions are only available in Swift 3.2 and newer.
+#if swift(>=3.2)
     func waitForState<T>(_ subscription: SyncSubscription<T>, _ desiredState: SyncSubscriptionState) {
         let ex = expectation(description: "Waiting for state \(desiredState)")
         let token = subscription.observe(\.state, options: .initial) { state in
@@ -560,6 +588,26 @@ class SwiftObjectServerTests: SwiftSyncTestCase {
         waitForExpectations(timeout: 20.0)
         token.invalidate()
     }
+#else
+    func waitForState<T>(_ subscription: SyncSubscription<T>, _ desiredState: SyncSubscriptionState) {
+        for _ in 0..<20 {
+            if subscription.state == desiredState {
+                return
+            }
+            RunLoop.current.run(until: Date().addingTimeInterval(1.0))
+        }
+        XCTFail("waitForState(\(subscription), \(desiredState)) timed out")
+    }
+
+    func waitForError<T>(_ subscription: SyncSubscription<T>) {
+        for _ in 0..<20 {
+            if case .error(_) = subscription.state {
+                return
+            }
+            RunLoop.current.run(until: Date().addingTimeInterval(1.0))
+        }
+        XCTFail("waitForError(\(subscription)) timed out")
+    }
 #endif // Swift >= 3.2
 
     // MARK: - Certificate Pinning

+ 3 - 1
Carthage/Checkouts/realm-cocoa/Realm/RLMRealm_Private.h

@@ -18,7 +18,7 @@
 
 #import <Realm/RLMRealm.h>
 
-@class RLMFastEnumerator;
+@class RLMFastEnumerator, RLMSyncSubscription;
 
 NS_ASSUME_NONNULL_BEGIN
 
@@ -27,6 +27,8 @@ FOUNDATION_EXTERN void RLMDisableSyncToDisk(void);
 
 FOUNDATION_EXTERN NSData * _Nullable RLMRealmValidatedEncryptionKey(NSData *key);
 
+FOUNDATION_EXTERN RLMSyncSubscription *RLMCastToSyncSubscription(id obj);
+
 // Translate an in-flight exception resulting from an operation on a SharedGroup to
 // an NSError or NSException (if error is nil)
 void RLMRealmTranslateException(NSError **error);

+ 10 - 0
Carthage/Checkouts/realm-cocoa/Realm/RLMRealm_Private.hpp

@@ -19,16 +19,26 @@
 #import "RLMRealm_Private.h"
 
 #import "RLMClassInfo.hpp"
+#import "object_schema.hpp"
 
 namespace realm {
     class Group;
     class Realm;
 }
+struct RLMResultsSetInfo {
+    realm::ObjectSchema osObjectSchema;
+    RLMObjectSchema *rlmObjectSchema;
+    RLMClassInfo info;
+
+    RLMResultsSetInfo(__unsafe_unretained RLMRealm *const realm);
+    static RLMClassInfo& get(__unsafe_unretained RLMRealm *const realm);
+};
 
 @interface RLMRealm () {
     @public
     std::shared_ptr<realm::Realm> _realm;
     RLMSchemaInfo _info;
+    std::unique_ptr<RLMResultsSetInfo> _resultsSetInfo;
 }
 
 // FIXME - group should not be exposed

+ 19 - 10
Carthage/Checkouts/realm-cocoa/Realm/RLMResults.mm

@@ -111,19 +111,29 @@ void RLMThrowResultsError(NSString *aggregateMethod) {
     }
 }
 
+- (instancetype)initWithObjectInfo:(RLMClassInfo&)info
+                           results:(realm::Results&&)results {
+    if (self = [super init]) {
+        _results = std::move(results);
+        _realm = info.realm;
+        _info = &info;
+    }
+    return self;
+}
+
 + (instancetype)resultsWithObjectInfo:(RLMClassInfo&)info
-                              results:(realm::Results)results {
-    RLMResults *ar = [[self alloc] initPrivate];
-    ar->_results = std::move(results);
-    ar->_realm = info.realm;
-    ar->_info = &info;
-    return ar;
+                              results:(realm::Results&&)results {
+    return [[self alloc] initWithObjectInfo:info results:std::move(results)];
 }
 
 + (instancetype)emptyDetachedResults {
     return [[self alloc] initPrivate];
 }
 
+- (instancetype)subresultsWithResults:(realm::Results)results {
+    return [self.class resultsWithObjectInfo:*_info results:std::move(results)];
+}
+
 static inline void RLMResultsValidateInWriteTransaction(__unsafe_unretained RLMResults *const ar) {
     ar->_realm->_realm->verify_thread();
     ar->_realm->_realm->verify_in_write();
@@ -349,7 +359,7 @@ static inline void RLMResultsValidateInWriteTransaction(__unsafe_unretained RLMR
             @throw RLMException(@"Querying is currently only implemented for arrays of Realm Objects");
         }
         auto query = RLMPredicateToQuery(predicate, _info->rlmObjectSchema, _realm.schema, _realm.group);
-        return [RLMResults resultsWithObjectInfo:*_info results:_results.filter(std::move(query))];
+        return [self subresultsWithResults:_results.filter(std::move(query))];
     });
 }
 
@@ -365,8 +375,7 @@ static inline void RLMResultsValidateInWriteTransaction(__unsafe_unretained RLMR
         if (_results.get_mode() == Results::Mode::Empty) {
             return self;
         }
-        return [RLMResults resultsWithObjectInfo:*_info
-                                         results:_results.sort(RLMSortDescriptorsToKeypathArray(properties))];
+        return [self subresultsWithResults:_results.sort(RLMSortDescriptorsToKeypathArray(properties))];
     });
 }
 
@@ -387,7 +396,7 @@ static inline void RLMResultsValidateInWriteTransaction(__unsafe_unretained RLMR
             keyPathsVector.push_back(keyPath.UTF8String);
         }
         
-        return [RLMResults resultsWithObjectInfo:*_info results:_results.distinct(keyPathsVector)];
+        return [self subresultsWithResults:_results.distinct(keyPathsVector)];
     });
 }
 

+ 4 - 1
Carthage/Checkouts/realm-cocoa/Realm/RLMResults_Private.hpp

@@ -38,7 +38,10 @@ NS_ASSUME_NONNULL_BEGIN
  */
 - (instancetype)initWithResults:(realm::Results)results;
 
-+ (instancetype)resultsWithObjectInfo:(RLMClassInfo&)info results:(realm::Results)results;
+- (instancetype)initWithObjectInfo:(RLMClassInfo&)info results:(realm::Results&&)results;
++ (instancetype)resultsWithObjectInfo:(RLMClassInfo&)info results:(realm::Results&&)results;
+
+- (instancetype)subresultsWithResults:(realm::Results)results;
 @end
 
 NS_ASSUME_NONNULL_END

+ 78 - 19
Carthage/Checkouts/realm-cocoa/Realm/RLMSyncSubscription.h

@@ -16,6 +16,7 @@
 //
 ////////////////////////////////////////////////////////////////////////////
 
+#import <Realm/RLMRealm.h>
 #import <Realm/RLMResults.h>
 
 NS_ASSUME_NONNULL_BEGIN
@@ -54,30 +55,38 @@ typedef NS_ENUM(NSInteger, RLMSyncSubscriptionState) {
 /**
  `RLMSyncSubscription` represents a subscription to a set of objects in a synced Realm.
 
- When partial sync is enabled for a synced Realm, the only objects that the server synchronizes to the
- client are those that match a sync subscription registered by that client. A subscription consists of
- of a query (represented by an `RLMResults`) and an optional name.
+ When query-based sync is enabled for a synchronized Realm, the server only
+ synchronizes objects to the client when they match a sync subscription
+ registered by that client. A subscription consists of of a query (represented
+ by an `RLMResults`) and an optional name.
 
- The state of the subscription can be observed using [Key-Value Observing](https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/KeyValueObserving/KeyValueObserving.html) on the `state` property.
+ The state of the subscription can be observed using
+ [Key-Value Observing](https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/KeyValueObserving/KeyValueObserving.html)
+ on the `state` property.
 
- Subscriptions are created using `-[RLMResults subscribe]` or `-[RLMResults subscribeWithName:]`.
+ Subscriptions are created using `-[RLMResults subscribe]` or
+ `-[RLMResults subscribeWithName:]`. Existing subscriptions for a Realm can be
+ looked up with `-[RLMRealm subscriptions]` or `-[RLMRealm subscriptionWithName:]`.
  */
 @interface RLMSyncSubscription : NSObject
 
 /**
  The unique name for this subscription.
 
- This will be `nil` if a name was not provided when the subscription was created.
+ This will be `nil` if this object was created with `-[RLMResults subscribe]`.
+ Subscription objects read from a Realm with `-[RLMRealm subscriptions]` will
+ always have a non-`nil` name and subscriptions which were not explicitly named
+ will have an automatically generated one.
  */
 @property (nonatomic, readonly, nullable) NSString *name;
 
 /**
- The state of the subscription. See `RLMSyncSubscriptionState`.
+ The current state of the subscription. See `RLMSyncSubscriptionState`.
  */
 @property (nonatomic, readonly) RLMSyncSubscriptionState state;
 
 /**
- The error associated with this subscription, if any.
+ The error which occurred when registering this subscription, if any.
 
  Will be non-nil only when `state` is `RLMSyncSubscriptionStateError`.
  */
@@ -86,10 +95,15 @@ typedef NS_ENUM(NSInteger, RLMSyncSubscriptionState) {
 /**
  Remove this subscription.
 
- Removing a subscription will delete all objects from the local Realm that were matched
- only by that subscription and not any remaining subscriptions. The deletion is performed
- by the server, and so has no immediate impact on the contents of the local Realm. If the
- device is currently offline, the removal will not be processed until the device returns online.
+ Removing a subscription will delete all objects from the local Realm that were
+ matched only by that subscription and not any remaining subscriptions. The
+ deletion is performed by the server, and so has no immediate impact on the
+ contents of the local Realm. If the device is currently offline, the removal
+ will not be processed until the device returns online.
+
+ Unsubscribing is an asynchronous operation and will not immediately remove the
+ subscription from the Realm's list of subscriptions. Observe the state property
+ to be notified of when the subscription has actually been removed.
  */
 - (void)unsubscribe;
 
@@ -123,9 +137,11 @@ typedef NS_ENUM(NSInteger, RLMSyncSubscriptionState) {
  notified of when the subscription has been processed by the server and
  all objects matching the query are available.
 
- The subscription will not be explicitly named.
+ The subscription will not be explicitly named. A name will be automatically
+ generated for internal use. The exact format of this name may change without
+ warning and should not be depended on.
 
- @return The subscription
+ @return An object representing the newly-created subscription.
 
  @see RLMSyncSubscription
 */
@@ -148,9 +164,14 @@ typedef NS_ENUM(NSInteger, RLMSyncSubscriptionState) {
  performing the same subscription twice followed by removing it once will
  result in no subscription existing.
 
- @param subscriptionName The name of the subscription
+ The newly created subscription will not be reported by
+ `-[RLMRealm subscriptions]` or `-[RLMRealm subscriptionWithName:]` until
+ `state` has transitioned from `RLMSyncSubscriptionStateCreating` to any of the
+ other states.
 
- @return The subscription
+ @param subscriptionName The name of the subscription.
+
+ @return An object representing the newly-created subscription.
 
  @see RLMSyncSubscription
 */
@@ -173,14 +194,17 @@ typedef NS_ENUM(NSInteger, RLMSyncSubscriptionState) {
  performing the same subscription twice followed by removing it once will
  result in no subscription existing.
 
+ The newly created subscription will not be reported by
+ `-[RLMRealm subscriptions]` or `-[RLMRealm subscriptionWithName:]` until
+ `state` has transitioned from `RLMSyncSubscriptionStateCreating` to any of the
+ other states.
+
  The number of top-level matches may optionally be limited. This limit
  respects the sort and distinct order of the query being subscribed to,
  if any. Please note that the limit does not count or apply to objects
  which are added indirectly due to being linked to by the objects in the
  subscription. If the limit is larger than the number of objects which
- match the query, all objects will be included. Limiting a subscription
- requires ROS 3.10.1 or newer, and will fail with an invalid predicate
- error with older versions.
+ match the query, all objects will be included.
 
  @param subscriptionName The name of the subscription
  @param limit The maximum number of objects to include in the subscription.
@@ -192,4 +216,39 @@ typedef NS_ENUM(NSInteger, RLMSyncSubscriptionState) {
 - (RLMSyncSubscription *)subscribeWithName:(nullable NSString *)subscriptionName limit:(NSUInteger)limit;
 @end
 
+/**
+ Support for managing existing subscriptions to object queries in a Realm.
+ */
+@interface RLMRealm (SyncSubscription)
+/**
+ Get a list of the query-based sync subscriptions made for this Realm.
+
+ This list includes all subscriptions which are currently in the states `Pending`,
+ `Created`, and `Error`. Newly created subscriptions which are still in the
+ `Creating` state are not included, and calling this immediately after calling
+ `-[RLMResults subscribe]` will typically not include that subscription. Similarly,
+ because unsubscription happens asynchronously, this may continue to include
+ subscriptions after `-[RLMSyncSubscription unsubscribe]` is called on them.
+
+ This method can only be called on a Realm which is using query-based sync and
+ will throw an exception if called on a non-synchronized or full-sync Realm.
+ */
+- (RLMResults<RLMSyncSubscription *> *)subscriptions;
+
+/**
+ Look up a specific query-based sync subscription by name.
+
+ Subscriptions are created asynchronously, so calling this immediately after
+ calling `subscribeWithName:` on a `RLMResults` will typically return `nil`.
+ Only subscriptions which are currently in the states `Pending`, `Created`,
+ and `Error` can be retrieved with this method.
+
+ This method can only be called on a Realm which is using query-based sync and
+ will throw an exception if called on a non-synchronized or full-sync Realm.
+
+ @return The named subscription, or `nil` if no subscription exists with that name.
+ */
+- (nullable RLMSyncSubscription *)subscriptionWithName:(NSString *)name;
+@end
+
 NS_ASSUME_NONNULL_END

+ 179 - 8
Carthage/Checkouts/realm-cocoa/Realm/RLMSyncSubscription.mm

@@ -18,17 +18,19 @@
 
 #import "RLMSyncSubscription.h"
 
+#import "RLMObjectSchema_Private.hpp"
+#import "RLMObject_Private.hpp"
+#import "RLMProperty_Private.hpp"
 #import "RLMRealm_Private.hpp"
 #import "RLMResults_Private.hpp"
 #import "RLMUtil.hpp"
 
+#import "object_store.hpp"
 #import "sync/partial_sync.hpp"
 
 using namespace realm;
 
 @interface RLMSyncSubscription ()
-- (instancetype)initWithName:(NSString *)name results:(Results const&)results realm:(RLMRealm *)realm;
-
 @property (nonatomic, readwrite) RLMSyncSubscriptionState state;
 @property (nonatomic, readwrite, nullable) NSError *error;
 @end
@@ -45,11 +47,16 @@ using namespace realm;
 
     _name = [name copy];
     _realm = realm;
-    _subscription = partial_sync::subscribe(results, name ? util::make_optional<std::string>(name.UTF8String) : util::none);
+    try {
+        _subscription = partial_sync::subscribe(results, name ? util::make_optional<std::string>(name.UTF8String) : util::none);
+    }
+    catch (std::exception const& e) {
+        @throw RLMException(e);
+    }
     self.state = (RLMSyncSubscriptionState)_subscription->state();
-    __weak RLMSyncSubscription *weakSelf = self;
+    __weak auto weakSelf = self;
     _token = _subscription->add_notification_callback([weakSelf] {
-        RLMSyncSubscription *self = weakSelf;
+        auto self = weakSelf;
         if (!self)
             return;
 
@@ -71,8 +78,19 @@ using namespace realm;
         }
 
         auto status = (RLMSyncSubscriptionState)self->_subscription->state();
-        if (status != self.state)
-            self.state = (RLMSyncSubscriptionState)status;
+        if (status != self.state) {
+            if (status == RLMSyncSubscriptionStateCreating) {
+                // If a subscription is deleted without going through this
+                // object's unsubscribe() method the subscription will transition
+                // back to Creating rather than Invalidated since it doesn't
+                // have a good way to track that it previously existed
+                if (self.state != RLMSyncSubscriptionStateInvalidated)
+                    self.state = RLMSyncSubscriptionStateInvalidated;
+            }
+            else {
+                self.state = status;
+            }
+        }
     });
 
     return self;
@@ -83,8 +101,135 @@ using namespace realm;
 }
 @end
 
-@implementation RLMResults (SyncSubscription)
+@interface RLMSyncSubscriptionObject : RLMObjectBase
+@end
+@implementation RLMSyncSubscriptionObject {
+    util::Optional<NotificationToken> _token;
+    Object _obj;
+}
+
+- (NSString *)name {
+    return _row.is_attached() ? RLMStringDataToNSString(_row.get_string(_row.get_column_index("name"))) : nil;
+}
+
+- (RLMSyncSubscriptionState)state {
+    if (!_row.is_attached()) {
+        return RLMSyncSubscriptionStateInvalidated;
+    }
+    return (RLMSyncSubscriptionState)_row.get_int(_row.get_column_index("status"));
+}
+
+- (NSError *)error {
+    if (!_row.is_attached()) {
+        return nil;
+    }
+    StringData err = _row.get_string(_row.get_column_index("error_message"));
+    if (!err.size()) {
+        return nil;
+    }
+    return [NSError errorWithDomain:RLMErrorDomain
+                               code:RLMErrorFail
+                           userInfo:@{NSLocalizedDescriptionKey: RLMStringDataToNSString(err)}];
+}
+
+- (NSString *)descriptionWithMaxDepth:(NSUInteger)depth {
+    if (depth == 0) {
+        return @"<Maximum depth exceeded>";
+    }
+
+    auto objectType = _row.get_string(_row.get_column_index("matches_property"));
+    objectType = objectType.substr(0, objectType.size() - strlen("_matches"));
+    return [NSString stringWithFormat:@"RLMSyncSubscription {\n\tname = %@\n\tobjectType = %@\n\tquery = %@\n\tstatus = %@\n\terror = %@\n}",
+            self.name, RLMStringDataToNSString(objectType),
+            RLMStringDataToNSString(_row.get_string(_row.get_column_index("query"))),
+            @(self.state), self.error];
+}
+
+- (void)unsubscribe {
+    if (_row) {
+        partial_sync::unsubscribe(Object(_realm->_realm, *_info->objectSchema, _row));
+    }
+}
+
+- (void)addObserver:(id)observer
+         forKeyPath:(NSString *)keyPath
+            options:(NSKeyValueObservingOptions)options
+            context:(void *)context {
+    // Make the `state` property observable by using an object notifier to
+    // trigger changes. The normal KVO mechanisms don't work for this class due
+    // to it not being a normal part of the schema.
+    if (!_token) {
+        struct {
+            __weak RLMSyncSubscriptionObject *weakSelf;
+
+            void before(realm::CollectionChangeSet const&) {
+                @autoreleasepool {
+                    [weakSelf willChangeValueForKey:@"state"];
+                }
+            }
+
+            void after(realm::CollectionChangeSet const&) {
+                @autoreleasepool {
+                    [weakSelf didChangeValueForKey:@"state"];
+                }
+            }
+
+            void error(std::exception_ptr) {}
+        } callback{self};
+        _obj = Object(_realm->_realm, *_info->objectSchema, _row);
+        _token = _obj.add_notification_callback(callback);
+    }
+    [super addObserver:observer forKeyPath:keyPath options:options context:context];
+}
+@end
 
+// RLMClassInfo stores pointers into the schema rather than owning the objects
+// it points to, so for a ClassInfo that's not part of the schema we need a
+// wrapper object that owns them
+RLMResultsSetInfo::RLMResultsSetInfo(__unsafe_unretained RLMRealm *const realm)
+: osObjectSchema(ObjectSchema(realm->_realm->read_group(), partial_sync::result_sets_type_name))
+, rlmObjectSchema([RLMObjectSchema objectSchemaForObjectStoreSchema:osObjectSchema])
+, info(realm, rlmObjectSchema, &osObjectSchema)
+{
+    rlmObjectSchema.accessorClass = [RLMSyncSubscriptionObject class];
+}
+
+RLMClassInfo& RLMResultsSetInfo::get(__unsafe_unretained RLMRealm *const realm) {
+    if (!realm->_resultsSetInfo) {
+        realm->_resultsSetInfo = std::make_unique<RLMResultsSetInfo>(realm);
+    }
+    return realm->_resultsSetInfo->info;
+}
+
+@interface RLMSubscriptionResults : RLMResults
+@end
+
+@implementation RLMSubscriptionResults
++ (instancetype)resultsWithRealm:(RLMRealm *)realm {
+    auto table = ObjectStore::table_for_object_type(realm->_realm->read_group(), partial_sync::result_sets_type_name);
+    if (!table) {
+        @throw RLMException(@"-[RLMRealm subscriptions] can only be called on a Realm using query-based sync");
+    }
+    // The server automatically adds a few subscriptions for the permissions
+    // types which we want to hide. They're just an implementation detail and
+    // deleting them won't work out well for the user.
+    auto query = table->where().ends_with(table->get_column_index("matches_property"), "_matches");
+    return [self resultsWithObjectInfo:RLMResultsSetInfo::get(realm)
+                               results:Results(realm->_realm, std::move(query))];
+}
+
+// These operations require a valid schema for the type. It's unclear how they
+// would be useful so it's probably not worth fixing this.
+- (RLMResults *)sortedResultsUsingDescriptors:(__unused NSArray<RLMSortDescriptor *> *)properties {
+    @throw RLMException(@"Sorting subscription results is currently not implemented");
+}
+
+- (RLMResults *)distinctResultsUsingKeyPaths:(__unused NSArray<NSString *> *)keyPaths {
+    @throw RLMException(@"Distincting subscription results is currently not implemented");
+}
+@end
+
+@implementation RLMResults (SyncSubscription)
 - (RLMSyncSubscription *)subscribe {
     return [[RLMSyncSubscription alloc] initWithName:nil results:_results realm:self.realm];
 }
@@ -96,5 +241,31 @@ using namespace realm;
 - (RLMSyncSubscription *)subscribeWithName:(NSString *)subscriptionName limit:(NSUInteger)limit {
     return [[RLMSyncSubscription alloc] initWithName:subscriptionName results:_results.limit(limit) realm:self.realm];
 }
+@end
+
+@implementation RLMRealm (SyncSubscription)
+- (RLMResults<RLMSyncSubscription *> *)subscriptions {
+    [self verifyThread];
+    return [RLMSubscriptionResults resultsWithRealm:self];
+}
 
+- (nullable RLMSyncSubscription *)subscriptionWithName:(NSString *)name {
+    [self verifyThread];
+    auto& info = RLMResultsSetInfo::get(self);
+    if (!info.table()) {
+        @throw RLMException(@"-[RLMRealm subcriptionWithName:] can only be called on a Realm using query-based sync");
+    }
+    auto row = info.table()->find_first(info.table()->get_column_index("name"),
+                                        RLMStringDataWithNSString(name));
+    if (row == npos) {
+        return nil;
+    }
+    RLMObjectBase *acc = RLMCreateManagedAccessor(info.rlmObjectSchema.accessorClass, self, &info);
+    acc->_row = info.table()->get(row);
+    return (RLMSyncSubscription *)acc;
+}
 @end
+
+RLMSyncSubscription *RLMCastToSyncSubscription(id obj) {
+    return obj;
+}

+ 2 - 2
Carthage/Checkouts/realm-cocoa/Realm/Realm-Info.plist

@@ -17,11 +17,11 @@
 	<key>CFBundlePackageType</key>
 	<string>FMWK</string>
 	<key>CFBundleShortVersionString</key>
-	<string>3.12.0</string>
+	<string>3.13.1</string>
 	<key>CFBundleSignature</key>
 	<string>????</string>
 	<key>CFBundleVersion</key>
-	<string>3.12.0</string>
+	<string>3.13.1</string>
 	<key>NSHumanReadableCopyright</key>
 	<string>Copyright © 2014 Realm. All rights reserved.</string>
 	<key>NSPrincipalClass</key>

+ 1 - 1
Carthage/Checkouts/realm-cocoa/RealmSwift/RealmCollection.swift

@@ -43,7 +43,7 @@ public struct RLMIterator<Element: RealmCollectionValue>: IteratorProtocol {
             }
             return unsafeBitCast(next, to: Optional<Element>.self)
         }
-        return next as! Element?
+        return dynamicBridgeCast(fromObjectiveC: next as Any)
     }
 }
 

+ 8 - 0
Carthage/Checkouts/realm-cocoa/RealmSwift/Util.swift

@@ -83,11 +83,19 @@ extension Object {
 
 // MARK: CustomObjectiveCBridgeable
 
+fileprivate extension SyncSubscription {
+    fileprivate convenience init(_ rlmSubscription: Any) {
+        self.init(RLMCastToSyncSubscription(rlmSubscription as AnyObject))
+    }
+}
+
 internal func dynamicBridgeCast<T>(fromObjectiveC x: Any) -> T {
     if T.self == DynamicObject.self {
         return unsafeBitCast(x as AnyObject, to: T.self)
     } else if let bridgeableType = T.self as? CustomObjectiveCBridgeable.Type {
         return bridgeableType.bridging(objCValue: x) as! T
+    } else if T.self == SyncSubscription<Object>.self {
+        return SyncSubscription<Object>(x) as! T
     } else {
         return x as! T
     }

+ 1 - 1
Carthage/Checkouts/realm-cocoa/build.sh

@@ -1055,7 +1055,7 @@ EOM
         else
             export sha=$GITHUB_PR_SOURCE_BRANCH
             export CONFIGURATION=$configuration
-            export REALM_EXTRA_BUILD_ARGUMENTS='GCC_GENERATE_DEBUGGING_SYMBOLS=NO'
+            export REALM_EXTRA_BUILD_ARGUMENTS='GCC_GENERATE_DEBUGGING_SYMBOLS=NO -allowProvisioningUpdates'
             sh build.sh prelaunch-simulator
 
             source $(brew --prefix nvm)/nvm.sh

+ 1 - 1
Carthage/Checkouts/realm-cocoa/dependencies.list

@@ -1,4 +1,4 @@
-VERSION=3.12.0
+VERSION=3.13.1
 REALM_CORE_VERSION=5.12.1
 REALM_SYNC_VERSION=3.13.3
 REALM_OBJECT_SERVER_VERSION=3.13.1

+ 9 - 3
iOSClient/Main/Create cloud/NCCreateFormUploadScanDocument.swift

@@ -504,9 +504,15 @@ 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 fileNamePath = CCUtility.getDirectoryScan() + "/" + fileName
         
-        do {
-            try results.scannedImage.pngData()?.write(to: NSURL.fileURL(withPath: fileNamePath), options: .atomic)
-        } catch { }
+        if (results.doesUserPreferEnhancedImage && results.enhancedImage != nil) {
+            do {
+                try results.enhancedImage!.pngData()?.write(to: NSURL.fileURL(withPath: fileNamePath), options: .atomic)
+            } catch { }
+        } else {
+            do {
+                try results.scannedImage.pngData()?.write(to: NSURL.fileURL(withPath: fileNamePath), options: .atomic)
+            } catch { }
+        }
         
         scanner.dismiss(animated: true, completion: {
             if (self.openScan) {

+ 8 - 10
iOSClient/Scan/ScanCollectionView.swift

@@ -52,7 +52,7 @@ class DragDropViewController: UIViewController {
         case grayScale
         case bn
     }
-    private var filter: typeFilter = typeFilter.grayScale
+    private var filter: typeFilter = typeFilter.original
     
     override var canBecomeFirstResponder: Bool { return true }
     
@@ -73,9 +73,10 @@ class DragDropViewController: UIViewController {
         cancel.title = NSLocalizedString("_cancel_", comment: "")
         save.title = NSLocalizedString("_save_", comment: "")
         labelTitlePDFzone.text = NSLocalizedString("_scan_label_document_zone_", comment: "")
-        segmentControlFilter.setTitle(NSLocalizedString("_filter_grayscale_", comment: ""), forSegmentAt: 0)
-        segmentControlFilter.setTitle(NSLocalizedString("_filter_bn_", comment: ""), forSegmentAt: 1)
-        segmentControlFilter.setTitle(NSLocalizedString("_filter_original_", comment: ""), forSegmentAt: 2)
+        
+        segmentControlFilter.setTitle(NSLocalizedString("_filter_original_", comment: ""), forSegmentAt: 0)
+        segmentControlFilter.setTitle(NSLocalizedString("_filter_grayscale_", comment: ""), forSegmentAt: 1)
+        segmentControlFilter.setTitle(NSLocalizedString("_filter_bn_", comment: ""), forSegmentAt: 2)
 
         add.setImage(CCGraphics.changeThemingColorImage(UIImage(named: "add"), multiplier:2, color: NCBrandColor.sharedInstance.brand), for: .normal)
         
@@ -134,14 +135,11 @@ class DragDropViewController: UIViewController {
         switch segmentControlFilter.selectedSegmentIndex
         {
         case 0:
-            // Grayscale
-            filter = typeFilter.grayScale
+            filter = typeFilter.original
         case 1:
-            // Original
-            filter = typeFilter.bn
+            filter = typeFilter.grayScale
         case 2:
-            // Original
-            filter = typeFilter.original
+            filter = typeFilter.bn
         default:
             break
         }