Slather logo

Coverage for "ChangeItem.swift" : 34.44%

(31 of 90 relevant lines covered)

ChatLayout/Classes/Core/Model/ChangeItem.swift

1
//
2
// ChatLayout
3
// ChangeItem.swift
4
// https://github.com/ekazaev/ChatLayout
5
//
6
// Created by Eugene Kazaev in 2020-2022.
7
// Distributed under the MIT license.
8
//
9
// Become a sponsor:
10
// https://github.com/sponsors/ekazaev
11
//
12
13
import Foundation
14
import UIKit
15
16
/// Internal replacement for `UICollectionViewUpdateItem`.
17
enum ChangeItem: Equatable {
18
19
    /// Delete section at `sectionIndex`
20
    case sectionDelete(sectionIndex: Int)
21
22
    /// Delete item at `itemIndexPath`
23
    case itemDelete(itemIndexPath: IndexPath)
24
25
    /// Insert section at `sectionIndex`
26
    case sectionInsert(sectionIndex: Int)
27
28
    /// Insert item at `itemIndexPath`
29
    case itemInsert(itemIndexPath: IndexPath)
30
31
    /// Reload section at `sectionIndex`
32
    case sectionReload(sectionIndex: Int)
33
34
    /// Reload item at `itemIndexPath`
35
    case itemReload(itemIndexPath: IndexPath)
36
37
    /// Move section from `initialSectionIndex` to `finalSectionIndex`
38
    case sectionMove(initialSectionIndex: Int, finalSectionIndex: Int)
39
40
    /// Move item from `initialItemIndexPath` to `finalItemIndexPath`
41
    case itemMove(initialItemIndexPath: IndexPath, finalItemIndexPath: IndexPath)
42
43
    init?(with updateItem: UICollectionViewUpdateItem) {
!
44
        let updateAction = updateItem.updateAction
!
45
        let indexPathBeforeUpdate = updateItem.indexPathBeforeUpdate
!
46
        let indexPathAfterUpdate = updateItem.indexPathAfterUpdate
!
47
        switch updateAction {
!
48
        case .none:
!
49
            return nil
!
50
        case .move:
!
51
            guard let indexPathBeforeUpdate = indexPathBeforeUpdate,
!
52
                  let indexPathAfterUpdate = indexPathAfterUpdate else {
!
53
                assertionFailure("`indexPathBeforeUpdate` and `indexPathAfterUpdate` cannot be `nil` for a `.move` update action.")
!
54
                return nil
!
55
            }
!
56
            if indexPathBeforeUpdate.item == NSNotFound, indexPathAfterUpdate.item == NSNotFound {
!
57
                self = .sectionMove(initialSectionIndex: indexPathBeforeUpdate.section, finalSectionIndex: indexPathAfterUpdate.section)
!
58
            } else {
!
59
                self = .itemMove(initialItemIndexPath: indexPathBeforeUpdate, finalItemIndexPath: indexPathAfterUpdate)
!
60
            }
!
61
        case .insert:
!
62
            guard let indexPath = indexPathAfterUpdate else {
!
63
                assertionFailure("`indexPathAfterUpdate` cannot be `nil` for an `.insert` update action.")
!
64
                return nil
!
65
            }
!
66
            if indexPath.item == NSNotFound {
!
67
                self = .sectionInsert(sectionIndex: indexPath.section)
!
68
            } else {
!
69
                self = .itemInsert(itemIndexPath: indexPath)
!
70
            }
!
71
        case .delete:
!
72
            guard let indexPath = indexPathBeforeUpdate else {
!
73
                assertionFailure("`indexPathBeforeUpdate` cannot be `nil` for a `.delete` update action.")
!
74
                return nil
!
75
            }
!
76
            if indexPath.item == NSNotFound {
!
77
                self = .sectionDelete(sectionIndex: indexPath.section)
!
78
            } else {
!
79
                self = .itemDelete(itemIndexPath: indexPath)
!
80
            }
!
81
        case .reload:
!
82
            guard let indexPath = indexPathAfterUpdate else {
!
83
                assertionFailure("`indexPathAfterUpdate` cannot be `nil` for a `.reload` update action.")
!
84
                return nil
!
85
            }
!
86
!
87
            if indexPath.item == NSNotFound {
!
88
                self = .sectionReload(sectionIndex: indexPath.section)
!
89
            } else {
!
90
                self = .itemReload(itemIndexPath: indexPath)
!
91
            }
!
92
        @unknown default:
!
93
            return nil
!
94
        }
!
95
    }
!
96
97
    private var rawValue: Int {
12x
98
        switch self {
12x
99
        case .sectionReload:
12x
100
            return 0
!
101
        case .itemReload:
12x
102
            return 1
4x
103
        case .sectionDelete:
12x
104
            return 2
!
105
        case .itemDelete:
12x
106
            return 3
3x
107
        case .sectionInsert:
12x
108
            return 4
!
109
        case .itemInsert:
12x
110
            return 5
3x
111
        case .sectionMove:
12x
112
            return 6
!
113
        case .itemMove:
12x
114
            return 7
2x
115
        }
12x
116
    }
12x
117
118
}
119
120
extension ChangeItem: Comparable {
121
122
    static func < (lhs: ChangeItem, rhs: ChangeItem) -> Bool {
123
        switch (lhs, rhs) {
124
        case let (.sectionDelete(sectionIndex: lIndex), .sectionDelete(sectionIndex: rIndex)):
125
            return lIndex < rIndex
1x
126
        case let (.itemDelete(itemIndexPath: lIndexPath), .itemDelete(itemIndexPath: rIndexPath)):
127
            return lIndexPath < rIndexPath
99900x
128
        case let (.sectionInsert(sectionIndex: lIndex), .sectionInsert(sectionIndex: rIndex)):
129
            return lIndex < rIndex
1x
130
        case let (.itemInsert(itemIndexPath: lIndexPath), .itemInsert(itemIndexPath: rIndexPath)):
131
            return lIndexPath < rIndexPath
99900x
132
        case let (.sectionReload(sectionIndex: lIndex), .sectionReload(sectionIndex: rIndex)):
133
            return lIndex < rIndex
3x
134
        case let (.itemReload(itemIndexPath: lIndexPath), .itemReload(itemIndexPath: rIndexPath)):
135
            return lIndexPath < rIndexPath
10200x
136
        case let (.sectionMove(initialSectionIndex: lInitialSectionIndex, finalSectionIndex: lFinalSectionIndex),
137
                  .sectionMove(initialSectionIndex: rInitialSectionIndex, finalSectionIndex: rFinalSectionIndex)):
1x
138
            if lInitialSectionIndex == rInitialSectionIndex {
1x
139
                return lFinalSectionIndex < rFinalSectionIndex
!
140
            } else {
1x
141
                return lInitialSectionIndex < rInitialSectionIndex
1x
142
            }
143
        case let (.itemMove(initialItemIndexPath: lInitialIndexPath, finalItemIndexPath: lFinalIndexPath),
144
                  .itemMove(initialItemIndexPath: rInitialIndexPath, finalItemIndexPath: rFinalIndexPath)):
2x
145
            if lInitialIndexPath == rInitialIndexPath {
2x
146
                return lFinalIndexPath < rFinalIndexPath
!
147
            } else {
2x
148
                return lInitialIndexPath < rInitialIndexPath
2x
149
            }
150
        default:
151
            return lhs.rawValue < rhs.rawValue
6x
152
        }
153
    }
154
155
}