Skip to content

Commit

Permalink
minor(HomePresent): CompositionalCollectionView binding test
Browse files Browse the repository at this point in the history
  • Loading branch information
dodo849 committed Jul 16, 2024
1 parent 05a1047 commit 355b762
Show file tree
Hide file tree
Showing 9 changed files with 112 additions and 69 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,16 @@ import UIKit
import DesignSystem

import RxSwift
import RxCocoa
import SnapKit
import Then

public class AnnouncementPageView: BaseView {
// MARK: Data source

// MARK: UI Component
// viewmodel을 두고...? section에 전달...

private lazy var banner = NofficeBanner().then {
$0.userName = "이즌"
$0.todayPrefixText = "활기찬"
Expand Down Expand Up @@ -53,7 +56,9 @@ public class AnnouncementPageView: BaseView {
AnnouncementItem(identifier: UUID().uuidString, value: "Item4") { _ in

}
]
],
headerBinding: { view in
}
),
OrganizationSection(
identifier: UUID().uuidString,
Expand All @@ -71,7 +76,7 @@ public class AnnouncementPageView: BaseView {
AnnouncementItem(identifier: UUID().uuidString, value: "Item4") { _ in

}
]
], headerBinding: { _ in }
)
]

Expand All @@ -91,5 +96,13 @@ public class AnnouncementPageView: BaseView {
to: sectionsSubject.asObservable()
)
.disposed(by: disposeBag)

if let item = sections[1].items[0] as? AnnouncementItem {
item.onTapAnnouncementCard
.subscribe(onNext: {
print("a먕!!!")
})
.disposed(by: disposeBag)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,9 @@ import DesignSystem
import Assets

import RxSwift
import RxGesture

struct OrganizationSection: CompositionalSection {
typealias Header = OrganizationSectionHeaderView

var layout: CompositionalLayout = .init(
groupLayout: .init(
size: .init(width: .fractionalWidth(0.8), height: .absolute(300)),
Expand All @@ -32,15 +31,18 @@ struct OrganizationSection: CompositionalSection {
var identifier: String
let organizationName: String
var items: [any CompositionalItem]
let headerBinding: (OrganizationSectionHeaderView) -> Void

init(
identifier: String,
organizationName: String,
items: [any CompositionalItem]
items: [any CompositionalItem],
headerBinding: @escaping (OrganizationSectionHeaderView) -> Void
) {
self.items = items
self.identifier = identifier
self.organizationName = organizationName
self.headerBinding = headerBinding
}

func hash(into hasher: inout Hasher) {
Expand All @@ -50,12 +52,19 @@ struct OrganizationSection: CompositionalSection {
}

final class AnnouncementItem: CompositionalItem {
// MARK: Compositional
let binding: (AnnouncementItemCell) -> Void

// MARK: Data
var identifier: String = UUID().uuidString
var value: String = ""

let onTapAnnouncementCard = PublishSubject<Void>()

// MARK: DisposeBag
let disposeBag = DisposeBag()

// MARK: Initializer
init(
identifier: String,
value: String,
Expand All @@ -66,29 +75,33 @@ final class AnnouncementItem: CompositionalItem {
self.binding = binding
}

// MARK: Hasher
func hash(into hasher: inout Hasher) {
hasher.combine(identifier)
hasher.combine(value)
}
}

final class AnnouncementItemCell: UIView, CompositionalItemCell {
var itemType: AnnouncementItem.Type {
return Item.self
}

// MARK: UI Component
lazy var organizationCard = NofficeGroupCard()

// MARK: Initializer
required init?(coder: NSCoder) {
super.init(coder: coder)
setup()
bind()
}

override init(frame: CGRect) {
super.init(frame: frame)
setup()

}

private var disposeBag = DisposeBag()

// MARK: Setup
private func setup() {
addSubview(organizationCard)

Expand All @@ -97,14 +110,23 @@ final class AnnouncementItemCell: UIView, CompositionalItemCell {
}
}

private func bind() {

}

func configure(with item: AnnouncementItem) {

organizationCard.rx.tapGesture()
.when(.recognized)
.map { _ in }
.bind(to: item.onTapAnnouncementCard)
.disposed(by: disposeBag)
}
}

class OrganizationSectionHeaderView: UIView, CompositionalReusableView {
typealias Section = OrganizationSection

// MARK: UI Component
private lazy var label = UILabel().then {
$0.textColor = .grey800
$0.textAlignment = .left
Expand All @@ -126,6 +148,7 @@ class OrganizationSectionHeaderView: UIView, CompositionalReusableView {
setup()
}

// MARK: Setup
private func setup() {
addSubview(label)
addSubview(icon)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,15 @@ import SnapKit

public protocol CompositionalReusableView: UIView {
associatedtype Section: CompositionalSection
/**
The identifier used when registering a cell in the collection view.
By default, it uses the name of the implementation.
*/
var reusableIdentifier: String { get }

/// Configure the cell using the provided item of type ``CollectionViewItem``.
///
/// - Parameter item: The item to configure the cell with.
func configure(with section: Section)
}

Expand All @@ -25,7 +33,15 @@ public extension CompositionalReusableView {
// MARK: - Helper component
public class EmptyReusableView: UICollectionReusableView, CompositionalReusableView {
public typealias Section = EmptyCompositionalSection

public var reusableIdentifier: String { return "EmptyReusableView" }

public var binding: (EmptyCompositionalSection) -> Void = { _ in }

public func bind(section: EmptyCompositionalSection) {
// do nothing
}

public func configure(with section: EmptyCompositionalSection) { }
}

Expand Down Expand Up @@ -66,6 +82,10 @@ final class CollectionViewResuableViewContainer: UICollectionReusableView {

view.configure(with: section)

if let view = view as? S.Header.Section.Header {
section.headerBind(view: view)
}

case .footer:
guard let view = currentView as? S.Footer else {
fatalError("""
Expand All @@ -80,6 +100,10 @@ final class CollectionViewResuableViewContainer: UICollectionReusableView {
}

view.configure(with: section)

if let view = view as? S.Footer.Section.Footer {
section.footerBind(view: view)
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,12 @@ public protocol CompositionalSection: Hashable {

var headerType: Header.Type { get }
var footerType: Footer.Type { get }

var headerBinding: (Header) -> Void { get }
var footerBinding: (Footer) -> Void { get }

func headerBind(view: Header)
func footerBind(view: Footer)
}

public extension CompositionalSection {
Expand All @@ -33,6 +39,22 @@ public extension CompositionalSection {
static func == (lhs: Self, rhs: Self) -> Bool {
return lhs.hashValue == rhs.hashValue
}

var headerBinding: (Header) -> Void {
return { _ in }
}

var footerBinding: (Footer) -> Void {
return { _ in }
}

func headerBind(view: Header) {
headerBinding(view)
}

func footerBind(view: Footer) {
footerBinding(view)
}
}

// MARK: - Helper component
Expand Down Expand Up @@ -90,57 +112,3 @@ public struct CompositionalSectionWrapper: Hashable {
hasher.combine(wrappee.hashValue)
}
}

// public struct AnyCompositionalSection: CompositionalSection {
// public var items: [any CompositionalItem]
// public var layout: CompositionalLayout
//
// private let _sectionType: any CompositionalSection.Type
// private let _hashInto: (inout Hasher) -> Void
//
// public init<S: CompositionalSection>(_ section: S) {
// self.items = section.items
// self.layout = section.layout
// self._hashInto = section.hash
// }
//
// public func hash(into hasher: inout Hasher) {
// _hashInto(&hasher)
// }
//
// public var headerType: Header.Type {
// return _sectionType.Header.self
// }
//
// var footerType: Footer.Type {
//
// }
// }

// extension CompositionalSection {
/**
It is a helper method for using AnyCompositionalSection

```swift
let collectionView = CompositionalCollectionView()

let sectionsSubject = BehaviorSubject<[AnyCompositionalSection]>(value: sections)

collectionView.bindSections(
by: sectionsSubject.asObservable()
)
.disposed(by: disposeBag)

let sections = [
Section(
items: [ ... ]
).asAnySection() // ✅
]

self.sectionsSubject.onNext(sections)
```
*/
// public func asAnySection() -> AnyCompositionalSection {
// return AnyCompositionalSection(self)
// }
// }
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@ final public class CompositionalCollectionView: UIView, UICollectionViewDelegate

// MARK: CollectionView & DataSource
private var collectionView: UICollectionView!
private var dataSource: UICollectionViewDiffableDataSource<CompositionalSectionWrapper, CollectionViewItemWrapper>!
private var dataSource: UICollectionViewDiffableDataSource<
CompositionalSectionWrapper, CollectionViewItemWrapper
>!

// MARK: Injected data
private var sections: [CompositionalSectionWrapper] = [] {
Expand Down Expand Up @@ -73,7 +75,9 @@ final public class CompositionalCollectionView: UIView, UICollectionViewDelegate

/// Set the diffable datasource and cell dequeue logic
private func configureDatasource() {
dataSource = UICollectionViewDiffableDataSource<CompositionalSectionWrapper, CollectionViewItemWrapper>(
dataSource = UICollectionViewDiffableDataSource<
CompositionalSectionWrapper, CollectionViewItemWrapper
>(
collectionView: collectionView
) { [weak self] (collectionView, indexPath, itemWrapper) in
guard let self = self else { return UICollectionViewCell() }
Expand All @@ -97,7 +101,9 @@ final public class CompositionalCollectionView: UIView, UICollectionViewDelegate
}

// Set the supplementary view provider
dataSource.supplementaryViewProvider = { [weak self] (collectionView, kind, indexPath) -> UICollectionReusableView? in
dataSource.supplementaryViewProvider = { [weak self] (
collectionView, kind, indexPath
) -> UICollectionReusableView? in
guard let self = self else { return nil }

let section = self.dataSource.snapshot().sectionIdentifiers[indexPath.section]
Expand All @@ -116,7 +122,7 @@ final public class CompositionalCollectionView: UIView, UICollectionViewDelegate
let view = headerType.init()

headerView.setContainedView(view)
headerView.configure(with: section.wrappee, type: .header)
headerView.configure(with: section.wrappee, type: .header) // include bind

return headerView
} else if kind == UICollectionView.elementKindSectionFooter {
Expand All @@ -133,7 +139,7 @@ final public class CompositionalCollectionView: UIView, UICollectionViewDelegate
let view = footerType.init()

footerView.setContainedView(view)
footerView.configure(with: section.wrappee, type: .footer)
footerView.configure(with: section.wrappee, type: .footer) // include bind

return footerView
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,12 @@ extension TestCompositionalLayoutViewController {
}

class SectionHeader: UIView, CompositionalReusableView {
var binding: (TestCompositionalLayoutViewController.Section) -> Void = { _ in }

func bind(section: TestCompositionalLayoutViewController.Section) {

}

typealias Section = TestCompositionalLayoutViewController.Section

var reusableIdentifier: String = "SectionHeader"
Expand Down
1 change: 1 addition & 0 deletions Tuist/Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ let package = Package(
.package(url: "https://github.com/lukepistrol/SwiftLintPlugin", from: "0.55.0"),
.package(url: "https://github.com/Swinject/Swinject.git", from: "2.9.0"),
.package(url: "https://github.com/ReactiveX/RxSwift.git", from: "6.7.0"),
.package(url: "https://github.com/RxSwiftCommunity/RxGesture.git", from: "4.0.0"),
.package(url: "https://github.com/SnapKit/SnapKit.git", from: "5.7.0"),
.package(url: "https://github.com/devxoul/Then.git", from: "3.0.0"),
.package(url: "https://github.com/Alamofire/Alamofire.git", from: "5.9.0")
Expand Down
Loading

0 comments on commit 355b762

Please sign in to comment.