Skip to content

Instantly share code, notes, and snippets.

@Jimmy-Prime
Created October 22, 2021 07:32
Show Gist options
  • Save Jimmy-Prime/934994e40d63f7ea701ca5353828cd07 to your computer and use it in GitHub Desktop.
Save Jimmy-Prime/934994e40d63f7ea701ca5353828cd07 to your computer and use it in GitHub Desktop.
// Model
typealias ChannelID = Int
struct ChannelGroup {
var name: String
var channels: [ChannelID]
}
// View's Model
struct SideBarGroup: Hashable {
let id: UUID
let name: String
}
struct SideBarChannel: Hashable {
let channelID: ChannelID
let name: String
let purpose: String
}
struct SideBarData: Hashable {
let expanded: Bool
let group: SideBarGroup
let channels: [SideBarChannel]
}
protocol SideBarContentView {
func setSideBarData(data: [SideBarData])
}
// View (UIKit)
import UIKit
class SideBarViewController: UIViewController {
private enum SideBarListItem: Hashable {
case group(SideBarGroup)
case channel(SideBarChannel)
}
private var dataSource: UICollectionViewDiffableDataSource<Int, SideBarListItem>!
override func viewDidLoad() {
super.viewDidLoad()
// View
let layout = UICollectionViewCompositionalLayout.list(using: .init(appearance: .sidebar))
let collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout)
view.addSubview(collectionView)
collectionView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
collectionView.topAnchor.constraint(equalTo: view.topAnchor),
collectionView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
collectionView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
collectionView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
])
// DataSource
let groupCellRegistration = UICollectionView.CellRegistration<UICollectionViewListCell, SideBarGroup> { cell, indexPath, group in
var content = UIListContentConfiguration.sidebarCell()
content.text = group.name
cell.contentConfiguration = content
cell.accessories = [.outlineDisclosure()]
}
let channelCellRegistration = UICollectionView.CellRegistration<UICollectionViewListCell, SideBarChannel> { cell, indexPath, channel in
var content = UIListContentConfiguration.sidebarSubtitleCell()
content.text = channel.name
content.secondaryText = channel.purpose
cell.contentConfiguration = content
cell.indentationLevel = 0
}
dataSource = .init(collectionView: collectionView) { collectionView, indexPath, item in
switch item {
case let .group(group):
return collectionView.dequeueConfiguredReusableCell(using: groupCellRegistration, for: indexPath, item: group)
case let .channel(channel):
return collectionView.dequeueConfiguredReusableCell(using: channelCellRegistration, for: indexPath, item: channel)
}
}
applyEmptySectionSnapshot()
}
}
extension SideBarViewController: SideBarContentView {
func setSideBarData(data: [SideBarData]) {
var snapshot = NSDiffableDataSourceSectionSnapshot<SideBarListItem>()
for datum in data {
let group = SideBarListItem.group(datum.group)
snapshot.append([group])
let channels = datum.channels.map(SideBarListItem.channel)
snapshot.append(channels, to: group)
}
let groups = data.filter(\.expanded).map(\.group).map(SideBarListItem.group)
snapshot.expand(groups)
dataSource.apply(snapshot, to: 0)
}
private func applyEmptySectionSnapshot() {
var snapshot = NSDiffableDataSourceSnapshot<Int, SideBarListItem>()
snapshot.appendSections([0])
dataSource.apply(snapshot, animatingDifferences: false)
}
}
// View (SwiftUI)
import SwiftUI
struct SideBarView: View, SideBarContentView {
@State private var data: [SideBarData] = []
var body: some View {
List {
ForEach(data, id: \.self) { datum in
DisclosureGroup(
isExpanded: .constant(datum.expanded),
content: {
ForEach(datum.channels, id: \.self) { channel in
VStack(alignment: .leading) {
Text(channel.name)
Text(channel.purpose)
.foregroundColor(.secondary)
}
}
},
label: {
Text(datum.group.name)
.font(.headline)
}
)
}
}
.listStyle(.sidebar)
}
func setSideBarData(data: [SideBarData]) {
self.data = data
}
}
struct SideBarView_Preview: PreviewProvider {
static var previews: some View {
SideBarView()
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment