Skip to content

Commit cf1f566

Browse files
committed
updated
1 parent 2763237 commit cf1f566

File tree

9 files changed

+162
-251
lines changed

9 files changed

+162
-251
lines changed

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,10 +44,10 @@ tableViewDataSource.reorderingHandlers.didReorder = { [weak self] transaction, _
4444

4545
### Empty datasource view
4646

47-
`emptyCollectionView` and `emptyTableView` displays the provided view when the datasource doesn't contain any items:
47+
`emptyView` displays the provided view when the datasource doesn't contain any items:
4848

4949
```swift
50-
diffableDataSource.emptyTableView = myEmptyView
50+
diffableDataSource.emptyView = myEmptyView
5151
```
5252

5353
Alternatively you can use `emptyContentConfiguration` and provide an `UIContentConfiguration`:

Sources/AdvancedCollectionTableView-iOS/CollectionView/DataSource/UICollectionViewDiffableDataSource+.swift

Lines changed: 68 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -65,26 +65,82 @@ extension UICollectionViewDiffableDataSource {
6565
}
6666
#endif
6767

68-
/*
69-
/// The view that is displayed when the datasource doesn't contain any items.
70-
public var emptyCollectionView: UIView? {
71-
get { getAssociatedValue(key: "emptyCollectionView", object: self, initialValue: nil) }
68+
/**
69+
The view that is displayed when the datasource doesn't contain any items.
70+
71+
When using this property, ``emptyContentConfiguration`` is set to `nil`.
72+
73+
- Note: The empty view is only used, when you apply your snapshots using ``UIKit/UICollectionViewDiffableDataSource/apply(_:_:completion:)``.
74+
\
75+
\
76+
You have to provide a snapshot and an apply option (either `.animated`, `nonAnimated` or `usingReloadedData`). For example:
77+
\
78+
\
79+
```dataSource.apply(snapshot, .animated)```
80+
*/
81+
public var emptyView: UIView? {
82+
get { getAssociatedValue(key: "emptyView", object: self, initialValue: nil) }
83+
set {
84+
guard emptyView != newValue else { return }
85+
if newValue != nil {
86+
emptyContentConfiguration = nil
87+
} else {
88+
emptyView?.removeFromSuperview()
89+
}
90+
set(associatedValue: newValue, key: "emptyView", object: self)
91+
updateEmptyView()
92+
}
93+
}
94+
95+
/**
96+
The content configuration that content view is displayed when the datasource doesn't contain any items.
97+
98+
When using this property, ``emptyView`` is set to `nil`.
99+
100+
- Note: The empty content configuration is only used, when you apply your snapshots using ``UIKit/UICollectionViewDiffableDataSource/apply(_:_:completion:)``.
101+
\
102+
\
103+
You have to provide a snapshot and an apply option (either `.animated`, `nonAnimated` or `usingReloadedData`). For example:
104+
\
105+
\
106+
```dataSource.apply(snapshot, .animated)```
107+
*/
108+
public var emptyContentConfiguration: UIContentConfiguration? {
109+
get { getAssociatedValue(key: "emptyContentConfiguration", object: self, initialValue: nil) }
72110
set {
73-
guard emptyCollectionView != newValue else { return }
74-
set(associatedValue: newValue, key: "emptyCollectionView", object: self)
75-
updateEmptyCollectionView()
111+
if let configuration = newValue {
112+
emptyView?.removeFromSuperview()
113+
emptyView = nil
114+
if let emptyContentView = self.emptyContentView {
115+
emptyContentView.contentConfiguration = configuration
116+
} else {
117+
emptyContentView = .init(configuration: configuration)
118+
}
119+
} else {
120+
emptyContentView?.removeFromSuperview()
121+
emptyContentView = nil
122+
}
123+
set(associatedValue: newValue, key: "emptyContentConfiguration", object: self)
124+
updateEmptyView()
76125
}
77126
}
78127

79-
func updateEmptyCollectionView() {
128+
var emptyContentView: ContentConfigurationView? {
129+
get { getAssociatedValue(key: "emptyContentView", object: self, initialValue: nil) }
130+
set { set(associatedValue: newValue, key: "emptyContentView", object: self) }
131+
}
132+
133+
func updateEmptyView() {
80134
let snapshot = snapshot()
81135
if !snapshot.itemIdentifiers.isEmpty && !snapshot.sectionIdentifiers.isEmpty {
82-
emptyCollectionView?.removeFromSuperview()
83-
} else if let emptyCollectionView = self.emptyCollectionView {
84-
collectionView?.addSubview(withConstraint: emptyCollectionView)
136+
emptyView?.removeFromSuperview()
137+
emptyContentView?.removeFromSuperview()
138+
} else if let emptyView = self.emptyView, emptyView.superview != collectionView {
139+
collectionView?.addSubview(withConstraint: emptyView)
140+
} else if let emptyContentView = self.emptyContentView, emptyContentView.superview != collectionView {
141+
collectionView?.addSubview(withConstraint: emptyContentView)
85142
}
86143
}
87-
*/
88144

89145
var delegate: Delegate? {
90146
get { getAssociatedValue(key: "delegate", object: self, initialValue: nil) }

Sources/AdvancedCollectionTableView-iOS/CollectionView/DataSource/UICollectionViewDiffableDataSource+Registration.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,5 +56,6 @@ public extension UICollectionViewDiffableDataSource {
5656
}
5757
}
5858
}
59+
updateEmptyView()
5960
}
6061
}

Sources/AdvancedCollectionTableView-iOS/CollectionView/UICollectionViewLayout+.swift

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,8 @@
55
// Created by Florian Zand on 11.02.24.
66
//
77

8-
9-
#if os(iOS)
108
import UIKit
9+
#if os(iOS)
1110

1211
extension UICollectionViewLayout {
1312
/**
@@ -47,4 +46,39 @@ extension UICollectionViewLayout {
4746
return UICollectionViewCompositionalLayout.list(using: configuration)
4847
}
4948
}
49+
#elseif os(tvOS)
50+
extension UICollectionViewLayout {
51+
/**
52+
Creates a compositional layout that contains only list sections.
53+
54+
- Parameters:
55+
- appearance: The overall appearance of the list.
56+
- headerMode: The type of header to use for the list.
57+
- footerMode: The type of footer to use for the list.
58+
*/
59+
public static func list(_ appearance: UICollectionLayoutListConfiguration.Appearance, headerMode: UICollectionLayoutListConfiguration.HeaderMode = .none, footerMode: UICollectionLayoutListConfiguration.FooterMode = .none) -> UICollectionViewCompositionalLayout {
60+
var configuration = UICollectionLayoutListConfiguration(appearance: appearance)
61+
configuration.headerMode = headerMode
62+
configuration.footerMode = footerMode
63+
return UICollectionViewCompositionalLayout.list(using: configuration)
64+
}
65+
66+
/**
67+
Creates a compositional layout that contains only list sections.
68+
69+
- Parameters:
70+
- appearance: The overall appearance of the list.
71+
- headerMode: The type of header to use for the list.
72+
- headerTopPadding: The header top padding.
73+
- footerMode: The type of footer to use for the list.
74+
*/
75+
@available(iOS 15.0, tvOS 15.0, *)
76+
public static func list(_ appearance: UICollectionLayoutListConfiguration.Appearance, headerMode: UICollectionLayoutListConfiguration.HeaderMode = .none, headerTopPadding: CGFloat?, footerMode: UICollectionLayoutListConfiguration.FooterMode = .none) -> UICollectionViewCompositionalLayout {
77+
var configuration = UICollectionLayoutListConfiguration(appearance: appearance)
78+
configuration.headerMode = headerMode
79+
configuration.footerMode = footerMode
80+
configuration.headerTopPadding = headerTopPadding
81+
return UICollectionViewCompositionalLayout.list(using: configuration)
82+
}
83+
}
5084
#endif

Sources/AdvancedCollectionTableView-iOS/Extensions/NSObject+Observe.swift

Lines changed: 0 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -13,17 +13,6 @@ extension NSObjectProtocol where Self: NSObject {
1313
/**
1414
Observes changes for a property identified by the given key path.
1515

16-
Example usage:
17-
18-
```swift
19-
let textField = NSTextField()
20-
21-
let stringValueObservation = textField.observeChanges(for: \.stringValue) {
22-
oldValue, newValue in
23-
// handle changed value
24-
}
25-
```
26-
2716
- Parameters:
2817
- keyPath: The key path of the property to observe.
2918
- sendInitalValue: A Boolean value indicating whether the handler should get called with the inital value of the observed property.
@@ -43,17 +32,6 @@ extension NSObjectProtocol where Self: NSObject {
4332
/**
4433
Observes changes for a property identified by the given key path.
4534

46-
Example usage:
47-
48-
```swift
49-
let textField = NSTextField()
50-
51-
let stringValueObservation = textField.observeChanges(for: \.stringValue, uniqueValues: true) {
52-
oldValue, newValue in
53-
// handle changed value
54-
}
55-
```
56-
5735
- Parameters:
5836
- keyPath: The key path of the property to observe.
5937
- sendInitalValue: A Boolean value indicating whether the handler should get called with the inital value of the observed property.
@@ -78,30 +56,4 @@ extension NSObjectProtocol where Self: NSObject {
7856
}
7957
}
8058
}
81-
82-
/**
83-
Observes the deinitialization of the object and calls the specified handler.
84-
85-
- Parameter handler: A closure that will be called when the object deinitializas.
86-
*/
87-
func observeDeinit(_ handler: @escaping () -> ()) {
88-
deinitCallback.callbacks.append(handler)
89-
}
90-
91-
/// Removes all deinitialization observers.
92-
func removeAllDeinitObservers() {
93-
deinitCallback.callbacks.removeAll()
94-
}
95-
96-
fileprivate var deinitCallback: DeinitCallback {
97-
get { getAssociatedValue(key: "deinitCallback", object: self, initialValue: DeinitCallback()) }
98-
}
99-
}
100-
101-
@objc fileprivate class DeinitCallback: NSObject {
102-
var callbacks: [() -> ()] = []
103-
104-
deinit {
105-
callbacks.forEach({ $0() })
106-
}
10759
}

Sources/AdvancedCollectionTableView-iOS/Extensions/Swizzle.swift

Lines changed: 0 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -16,31 +16,10 @@ extension Selector {
1616
Swizzle.SelectorPair(old: lhs, new: rhs)
1717
}
1818

19-
static func <-> (lhs: Selector, rhs: String) -> Swizzle.SelectorPair {
20-
Swizzle.SelectorPair(old: lhs, new: Selector(rhs))
21-
}
22-
2319
/// Creates a selector pair for swizzleing from the first and second static selector.
2420
static func <~> (lhs: Selector, rhs: Selector) -> Swizzle.SelectorPair {
2521
Swizzle.SelectorPair(old: lhs, new: rhs, static: true)
2622
}
27-
28-
/// Creates a selector pair for swizzleing from the first and second static selector.
29-
static func <~> (lhs: Selector, rhs: String) -> Swizzle.SelectorPair {
30-
Swizzle.SelectorPair(old: lhs, new: Selector(rhs), static: true)
31-
}
32-
}
33-
34-
extension String {
35-
/// Creates a selector pair for swizzleing from the first and second selector.
36-
static func <-> (lhs: String, rhs: Selector) -> Swizzle.SelectorPair {
37-
Swizzle.SelectorPair(old: Selector(lhs), new: rhs)
38-
}
39-
40-
/// Creates a selector pair for swizzleing from the first and second static selector.
41-
static func <~> (lhs: String, rhs: Selector) -> Swizzle.SelectorPair {
42-
Swizzle.SelectorPair(old: Selector(lhs), new: rhs, static: true)
43-
}
4423
}
4524

4625
/**
@@ -91,36 +70,6 @@ struct Swizzle {
9170
try self.init(type, swizzlePairs: [makeSelectorPairs()])
9271
}
9372

94-
/**
95-
Swizzles selectors of the class with the specified name.
96-
97-
- Parameters:
98-
- className: The name of the class.
99-
- makeSelectorPairs: The swizzle selector pairs.
100-
101-
- Throws:Throws if swizzling fails.
102-
- Returns: A `Swizzle` object for the specified values.
103-
*/
104-
@discardableResult
105-
init(_ className: String, @Builder _ makeSelectorPairs: () -> [SelectorPair]) throws {
106-
try self.init(className, swizzlePairs: makeSelectorPairs())
107-
}
108-
109-
/**
110-
Swizzles selectors of the class with the specified name.
111-
112-
- Parameters:
113-
- className: The name of the class.
114-
- makeSelectorPairs: The swizzle selector pairs.
115-
116-
- Throws:Throws if swizzling fails.
117-
- Returns: A `Swizzle` object for the specified values.
118-
*/
119-
@discardableResult
120-
init(_ className: String, @Builder _ makeSelectorPairs: () -> SelectorPair) throws {
121-
try self.init(className, swizzlePairs: [makeSelectorPairs()])
122-
}
123-
12473
@discardableResult
12574
init(_ class_: AnyClass, swizzlePairs: [SelectorPair]) throws {
12675
guard object_isClass(class_) else {
@@ -129,14 +78,6 @@ struct Swizzle {
12978
try swizzle(type: class_, pairs: swizzlePairs)
13079
}
13180

132-
@discardableResult
133-
init(_ className: String, swizzlePairs: [SelectorPair], reset _: Bool = false) throws {
134-
guard let class_ = NSClassFromString(className) else {
135-
throw Error.missingClass(className)
136-
}
137-
try swizzle(type: class_, pairs: swizzlePairs)
138-
}
139-
14081
private func swizzle(
14182
type: AnyObject.Type,
14283
pairs: [SelectorPair]

0 commit comments

Comments
 (0)