// // HomeCollectionModels.swift // suixinkan // import Foundation import UIKit /// 首页 CollectionView 分区标识。 enum HomeCollectionSection: Hashable { case workStatus case locationReport case quickActions case store case commonApps } /// 首页 CollectionView 条目标识;各区块使用独立 case,避免 Diffable 去重。 enum HomeCollectionItem: Hashable { case workStatus case locationReport case quickActions case store case menu(HomeMenuItem) } /// 首页 CollectionView 布局与 snapshot 构建工具。 enum HomeCollectionLayoutBuilder { private static let menuColumns = 3 private static let menuSpacing: CGFloat = 15 private static let menuAspectRatio: CGFloat = 1.3 private static let sectionSpacing = AppSpacing.sm /// 构建 Compositional Layout,按当前分区类型返回 section 布局。 static func makeLayout(sections: [HomeCollectionSection]) -> UICollectionViewCompositionalLayout { UICollectionViewCompositionalLayout { sectionIndex, environment in let section = sectionIndex < sections.count ? sections[sectionIndex] : .commonApps switch section { case .workStatus: return fullWidthSection(height: 84) case .locationReport: return fullWidthSection(height: 132) case .quickActions: return fullWidthSection(height: 72) case .store: return fullWidthSection(height: 96) case .commonApps: return menuGridSection(environment: environment) } } } /// 根据 ViewModel 状态构建 Diffable Snapshot。 static func makeSnapshot( showWorkBlock: Bool, showStore: Bool, storeItem: StoreItem?, commonMenus: [HomeMenuItem] ) -> NSDiffableDataSourceSnapshot { var snapshot = NSDiffableDataSourceSnapshot() if showWorkBlock { snapshot.appendSections([.workStatus, .locationReport, .quickActions]) snapshot.appendItems([.workStatus], toSection: .workStatus) snapshot.appendItems([.locationReport], toSection: .locationReport) snapshot.appendItems([.quickActions], toSection: .quickActions) } if showStore, storeItem != nil { snapshot.appendSections([.store]) snapshot.appendItems([.store], toSection: .store) } let menus = commonMenus + [HomeMenuItem.moreFunctions] snapshot.appendSections([.commonApps]) snapshot.appendItems(menus.map { HomeCollectionItem.menu($0) }, toSection: .commonApps) return snapshot } /// 当前 snapshot 对应的分区顺序,供 layout 使用。 static func sectionOrder( showWorkBlock: Bool, showStore: Bool, storeItem: StoreItem? ) -> [HomeCollectionSection] { var sections: [HomeCollectionSection] = [] if showWorkBlock { sections.append(contentsOf: [.workStatus, .locationReport, .quickActions]) } if showStore, storeItem != nil { sections.append(.store) } sections.append(.commonApps) return sections } private static let horizontalInset = AppSpacing.screenHorizontalInset private static func fullWidthSection(height: CGFloat) -> NSCollectionLayoutSection { let itemSize = NSCollectionLayoutSize( widthDimension: .fractionalWidth(1), heightDimension: .absolute(height) ) let item = NSCollectionLayoutItem(layoutSize: itemSize) let groupSize = NSCollectionLayoutSize( widthDimension: .fractionalWidth(1), heightDimension: .absolute(height) ) let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitems: [item]) let section = NSCollectionLayoutSection(group: group) section.contentInsets = NSDirectionalEdgeInsets( top: 0, leading: horizontalInset, bottom: sectionSpacing, trailing: horizontalInset ) return section } private static func menuGridSection(environment: NSCollectionLayoutEnvironment) -> NSCollectionLayoutSection { let availableWidth = environment.container.effectiveContentSize.width - horizontalInset * 2 let totalSpacing = menuSpacing * CGFloat(menuColumns - 1) let itemWidth = max(0, (availableWidth - totalSpacing) / CGFloat(menuColumns)) let itemHeight = itemWidth / menuAspectRatio let itemSize = NSCollectionLayoutSize( widthDimension: .absolute(itemWidth), heightDimension: .absolute(itemHeight) ) let item = NSCollectionLayoutItem(layoutSize: itemSize) let groupSize = NSCollectionLayoutSize( widthDimension: .fractionalWidth(1), heightDimension: .absolute(itemHeight) ) let group = NSCollectionLayoutGroup.horizontal( layoutSize: groupSize, repeatingSubitem: item, count: menuColumns ) group.interItemSpacing = .fixed(menuSpacing) let section = NSCollectionLayoutSection(group: group) section.interGroupSpacing = menuSpacing section.contentInsets = NSDirectionalEdgeInsets( top: 0, leading: horizontalInset, bottom: sectionSpacing, trailing: horizontalInset ) let headerSize = NSCollectionLayoutSize( widthDimension: .fractionalWidth(1), heightDimension: .absolute(36) ) let header = NSCollectionLayoutBoundarySupplementaryItem( layoutSize: headerSize, elementKind: UICollectionView.elementKindSectionHeader, alignment: .top ) section.boundarySupplementaryItems = [header] return section } }