feature/v1
swift 90 lines 2.88 KB
Raw
1 //
2 // TVCategorySection.swift
3 // JomloCV tvOS Example
4 //
5 // Created by Seto Elkahfi on 2026-01-27.
6 // Copyright © 2026 Seto Elkahfi. All rights reserved.
7 //
8
9 import JomloCollectionView
10 import UIKit
11
12 /// A horizontally scrolling row of large category tiles for TV navigation.
13 @MainActor
14 final class TVCategorySection: JomloSection {
15
16 let identifier = JomloSectionID("tv-categories")
17 var onReloadNeeded: (@MainActor @Sendable () -> Void)?
18
19 private let categoryItems: [TVCategoryItem]
20
21 init(items: [TVCategoryItem]) {
22 self.categoryItems = items
23 }
24
25 func items() -> [any JomloItem] {
26 categoryItems
27 }
28
29 func layoutSection(
30 environment: NSCollectionLayoutEnvironment,
31 sectionIndex: Int
32 ) -> NSCollectionLayoutSection {
33 let itemSize = NSCollectionLayoutSize(
34 widthDimension: .fractionalWidth(1.0),
35 heightDimension: .fractionalHeight(1.0)
36 )
37 let item = NSCollectionLayoutItem(layoutSize: itemSize)
38
39 let groupSize = NSCollectionLayoutSize(
40 widthDimension: .absolute(280),
41 heightDimension: .absolute(180)
42 )
43 let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitems: [item])
44
45 let section = NSCollectionLayoutSection(group: group)
46 section.orthogonalScrollingBehavior = .continuous
47 section.interGroupSpacing = 35
48 section.contentInsets = NSDirectionalEdgeInsets(
49 top: 10, leading: 80, bottom: 50, trailing: 80)
50
51 let headerSize = NSCollectionLayoutSize(
52 widthDimension: .fractionalWidth(1.0),
53 heightDimension: .absolute(60)
54 )
55 let header = NSCollectionLayoutBoundarySupplementaryItem(
56 layoutSize: headerSize,
57 elementKind: UICollectionView.elementKindSectionHeader,
58 alignment: .top
59 )
60 section.boundarySupplementaryItems = [header]
61
62 return section
63 }
64
65 func cell(
66 for item: any JomloItem,
67 in collectionView: UICollectionView,
68 at indexPath: IndexPath
69 ) -> UICollectionViewCell {
70 guard let catItem = item as? TVCategoryItem else { return UICollectionViewCell() }
71 return collectionView.dequeueJomloCell(TVCategoryCell.self, for: indexPath, item: catItem)
72 }
73
74 func supplementaryView(
75 ofKind kind: String,
76 in collectionView: UICollectionView,
77 at indexPath: IndexPath
78 ) -> UICollectionReusableView? {
79 guard kind == UICollectionView.elementKindSectionHeader else { return nil }
80 guard
81 let header = collectionView.dequeueReusableSupplementaryView(
82 ofKind: kind,
83 withReuseIdentifier: TVSectionHeaderView.reuseIdentifier,
84 for: indexPath
85 ) as? TVSectionHeaderView
86 else { return nil }
87 header.configure(title: "Browse")
88 return header
89 }
90 }