Skip to content

Add FlatSection #21

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 52 commits into
base: 2.0-beta
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 12 commits
Commits
Show all changes
52 commits
Select commit Hold shift + click to select a range
3946a41
Add FlatSection
JosephDuffy Dec 22, 2020
babdadf
Mark `append(_:)` public
JosephDuffy Dec 22, 2020
59daa65
Add `section(at:)`
JosephDuffy Dec 22, 2020
c4fe225
Add support for flat UI sections, with mixed cells
JosephDuffy Dec 22, 2020
aa527de
Aid migration from `CollectionSectionProvider`
JosephDuffy Dec 22, 2020
0b5350f
Add `public init` to `FlatSection`
JosephDuffy Dec 22, 2020
d3dee27
Fix `section(at:)` logic
JosephDuffy Dec 22, 2020
66d5fed
Conform `FlatSection` to `CustomReflectable`
JosephDuffy Dec 22, 2020
f51dc04
Become update delegate of inserted children
JosephDuffy Dec 22, 2020
e1e7fd5
Add more insert and removal functions
JosephDuffy Dec 22, 2020
c597da9
Remove associated type from `CollectionElement`
JosephDuffy Dec 22, 2020
fd21a2f
Add header invalidation
JosephDuffy Dec 23, 2020
ec63ce7
[SBI-519] Fix crash due to using removed section inside didEndDisplay…
bill201207 Dec 24, 2020
ad9dc00
[SBI-519] Cache registered nib names to avoid multiple redundant call…
bill201207 Dec 24, 2020
7320206
Merge pull request #1 from opennetltd/hotfix/SBI-519-ComposedUI-issues
bill201207 Dec 24, 2020
7b27a38
Merge branch 'main' of github.com:opennetltd/Composed into feature/Fl…
JosephDuffy Dec 28, 2020
f0ab34c
Fix test compilation
JosephDuffy Dec 28, 2020
06449c3
Fix `cellSectionMap` for per-row cells
JosephDuffy Dec 28, 2020
f6a4b2c
Delegate `SelectionHandler` calls to children
JosephDuffy Dec 28, 2020
eb3a33a
Add `FlatUICollectionViewSection`
JosephDuffy Dec 28, 2020
986674a
Support adding `SectionProvider`s to `FlatSection`
JosephDuffy Dec 29, 2020
ad73a5a
Reload header when `header` is set
JosephDuffy Dec 29, 2020
f6cd79c
Cache nib registrations to improve performance
JosephDuffy Jan 1, 2021
b35ea17
Merge branch 'cache-nib-registrations'
JosephDuffy Jan 1, 2021
1614657
Merge branch 'main' into feature/FlatSection
JosephDuffy Jan 1, 2021
ecdd0fa
Fix `SectionProvider` sections not being removed
JosephDuffy Jan 4, 2021
fd0fb6a
Account for child `AggregateSectionProvider`s
JosephDuffy Jan 4, 2021
ee87162
Update `sectionOffset(for:)` to return an optional
JosephDuffy Jan 4, 2021
9684f62
Fix `ComposedSectionProvider` compilation
JosephDuffy Jan 4, 2021
987e496
Account for empty sections
JosephDuffy Jan 4, 2021
ad450d5
Remove `defer`s to ease debugging
JosephDuffy Jan 4, 2021
c1a438e
Become delegate of inserted sections
JosephDuffy Jan 5, 2021
00cfff2
Document `sectionIndex(of:)`
JosephDuffy Jan 5, 2021
90db5e5
Call `willAppear` for headers/footers
JosephDuffy Jan 5, 2021
e7c88de
Configure headers/footers on appear
JosephDuffy Jan 5, 2021
c52b6e4
Fix element offset when inserting in `FlatSection`
JosephDuffy Jan 7, 2021
e45ea84
Fix incorrect index when provider removes sections
JosephDuffy Jan 11, 2021
9e1b8bd
Mark `updateDelegate` as `weak`
JosephDuffy Jan 12, 2021
710efde
Remove/reduce some `FlatSection` bugs
JosephDuffy Jan 12, 2021
f1cdd0d
Add foundation of `FlatSection` tests
JosephDuffy Jan 12, 2021
42c05c9
Do not check to unset update delegate of sections
JosephDuffy Jan 12, 2021
3fb3c8f
Remove `Child` from public API
JosephDuffy Jan 12, 2021
a9a3c94
Add more `FlatSection` tests
JosephDuffy Jan 12, 2021
791b088
Change `index` to `childIndex`
JosephDuffy Jan 12, 2021
a1cafc9
Remove check for unsetting update delegate
JosephDuffy Jan 12, 2021
f49d0c5
Add more `FlatSection` tests
JosephDuffy Jan 12, 2021
0345565
Propagate updates from sections
JosephDuffy Jan 13, 2021
eb49837
Fix incorrect header and footer in flat sections
JosephDuffy Jan 18, 2021
6e3c578
Add support for footers
JosephDuffy Jan 19, 2021
5532266
Merge branch '2.0-beta' into feature/FlatSection
JosephDuffy Jan 19, 2021
75df0f0
Unset `updateDelegate` on section provider removal
JosephDuffy Feb 1, 2021
1813669
Update assertion message to ease debugging
JosephDuffy Feb 8, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions Sources/Composed/Core/Section.swift
Original file line number Diff line number Diff line change
Expand Up @@ -82,4 +82,9 @@ public protocol SectionUpdateDelegate: class {
/// - destinationIndex: The final index where the element will be moved to
func section(_ section: Section, move sourceIndex: Int, to destinationIndex: Int)

/// Notifies the delegate that the section invalidated its header.
/// - Parameters:
/// - section: The section where the move should be performed
func sectionDidInvalidateHeader(_ section: Section)

}
10 changes: 10 additions & 0 deletions Sources/Composed/Core/SectionProviderMapping.swift
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,11 @@ public protocol SectionProviderMappingDelegate: class {
/// - destinationIndexPath: The final indexPath
func mapping(_ mapping: SectionProviderMapping, move sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath)

/// Notifies the delegate that the section invalidated its header.
/// - Parameters:
/// - sectionIndex: The index of the section that invalidated its header.
func mappingDidInvalidateHeader(at sectionIndex: Int)

}

/// An object that encapsulates the logic required to map `SectionProvider`s to a global context,
Expand Down Expand Up @@ -229,6 +234,11 @@ public final class SectionProviderMapping: SectionProviderUpdateDelegate, Sectio
delegate?.mapping(self, didMoveElementsAt: [(source, destination)])
}

public func sectionDidInvalidateHeader(_ section: Section) {
guard let sectionOffset = self.sectionOffset(of: section) else { return }
delegate?.mappingDidInvalidateHeader(at: sectionOffset)
}

// Rebuilds the cached providers to improve lookup performance.
// This is generally only required when a sections are either inserted or removed, so it should be fairly efficient.
private func rebuildSectionOffsets() {
Expand Down
176 changes: 176 additions & 0 deletions Sources/Composed/Sections/FlatSection.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
/// A section that flattens each of its children in to a single section.
open class FlatSection: Section, CustomReflectable {
open private(set) var children: [Section] = []

public var numberOfElements: Int {
children.map(\.numberOfElements).reduce(0, +)
}

public var updateDelegate: SectionUpdateDelegate?

public var customMirror: Mirror {
Mirror(
self,
children: [
"children": children,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see your trickery haha

]
)
}

public init() {}

public func append(_ section: Section) {
updateDelegate?.willBeginUpdating(self)

let indexOfFirstChildElement = numberOfElements
children.append(section)
section.updateDelegate = self

(0..<section.numberOfElements)
.map { $0 + indexOfFirstChildElement }
.forEach { index in
updateDelegate?.section(self, didInsertElementAt: index)
}

updateDelegate?.didEndUpdating(self)
}

public func insert(_ section: Section, at index: Int) {
updateDelegate?.willBeginUpdating(self)

let sectionOffset = index > 0
? offset(for: children[index - 1])!
: 0
children.insert(section, at: index)
section.updateDelegate = self

(0..<section.numberOfElements)
.map { $0 + sectionOffset }
.forEach { index in
updateDelegate?.section(self, didInsertElementAt: index)
}

updateDelegate?.didEndUpdating(self)
}

public func insert(_ section: Section, after existingSection: Section) {
guard let existingSectionIndex = children.firstIndex(where: { $0 === existingSection }) else { return }

insert(section, at: existingSectionIndex + 1)
}

public func remove(_ section: Section) {
guard let index = children.firstIndex(where: { $0 === section }) else { return }

updateDelegate?.willBeginUpdating(self)

let sectionOffset = offset(for: section)!
children.remove(at: index)
if section.updateDelegate === self {
section.updateDelegate = nil
}

(0..<section.numberOfElements).forEach { index in
updateDelegate?.section(self, didRemoveElementAt: index + sectionOffset)
}

updateDelegate?.didEndUpdating(self)
}

public func section(at index: Int) -> (section: Section, offset: Int)? {
var offset = 0

for child in children {
if offset == index {
return (child, offset)
} else if index < offset + child.numberOfElements {
return (child, offset)
}

offset += child.numberOfElements
}

return nil
}

private func offset(for section: Section) -> Int? {
var offset = 0

for child in children {
if child === section {
return offset
}

offset += child.numberOfElements
}

return nil
}

private func indexesRange(for section: Section) -> Range<Int>? {
guard let sectionOffset = offset(for: section) else { return nil }
return (sectionOffset..<sectionOffset + section.numberOfElements)
}
}

extension FlatSection: SectionUpdateDelegate {
public func willBeginUpdating(_ section: Section) {
updateDelegate?.willBeginUpdating(self)
}

public func didEndUpdating(_ section: Section) {
updateDelegate?.didEndUpdating(self)
}

public func invalidateAll(_ section: Section) {
updateDelegate?.invalidateAll(self)
}

public func section(_ section: Section, didInsertElementAt index: Int) {
guard let sectionOffset = offset(for: section) else { return }
updateDelegate?.section(self, didInsertElementAt: sectionOffset + index)
}

public func section(_ section: Section, didRemoveElementAt index: Int) {
guard let sectionOffset = offset(for: section) else { return }
updateDelegate?.section(self, didRemoveElementAt: sectionOffset + index)
}

public func section(_ section: Section, didUpdateElementAt index: Int) {
guard let sectionOffset = offset(for: section) else { return }
updateDelegate?.section(self, didUpdateElementAt: sectionOffset + index)
}

public func section(_ section: Section, didMoveElementAt index: Int, to newIndex: Int) {
guard let sectionOffset = offset(for: section) else { return }
updateDelegate?.section(self, didMoveElementAt: sectionOffset + index, to: newIndex + index)
}

public func selectedIndexes(in section: Section) -> [Int] {
guard let allSelectedIndexes = updateDelegate?.selectedIndexes(in: self) else { return [] }
guard let sectionIndexes = indexesRange(for: section) else { return [] }

return allSelectedIndexes
.filter(sectionIndexes.contains(_:))
.map { $0 - sectionIndexes.startIndex }
}

public func section(_ section: Section, select index: Int) {
guard let sectionOffset = offset(for: section) else { return }
updateDelegate?.section(self, select: sectionOffset + index)
}

public func section(_ section: Section, deselect index: Int) {
guard let sectionOffset = offset(for: section) else { return }
updateDelegate?.section(self, deselect: sectionOffset + index)
}

public func section(_ section: Section, move sourceIndex: Int, to destinationIndex: Int) {
guard let sectionOffset = offset(for: section) else { return }
updateDelegate?.section(self, move: sourceIndex + sectionOffset, to: destinationIndex + sectionOffset)
}

public func sectionDidInvalidateHeader(_ section: Section) {
// Headers of children are currently ignored.
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import ComposedUI

@available(iOS 13.0, *)
/// Conform your section to this protocol to provide a layout section for a `UICollectionViewCompositionalLayout`
public protocol CompositionalLayoutHandler: CollectionSectionProvider {
public protocol CompositionalLayoutHandler: UICollectionViewSection {

/// Return a layout section for this section
/// - Parameter environment: The current environment for this layout
Expand Down
2 changes: 1 addition & 1 deletion Sources/ComposedLayouts/CollectionFlowLayoutHandler.swift
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ public struct CollectionFlowLayoutEnvironment {
}

/// Conform your section to this protocol to override sizing and metric values for a `UICollectionViewFlowLayout`
public protocol CollectionFlowLayoutHandler: CollectionSectionProvider {
public protocol CollectionFlowLayoutHandler: UICollectionViewSection {

/// Return the size for the element at the specified index
/// - Parameters:
Expand Down
Loading