diff --git a/Examples/KarrotListKitSampleApp/KarrotListKitSampleApp/Samples/VerticalLayout/VerticalLayoutItemComponent.swift b/Examples/KarrotListKitSampleApp/KarrotListKitSampleApp/Samples/VerticalLayout/VerticalLayoutItemComponent.swift index bcf72c3..baa1ade 100644 --- a/Examples/KarrotListKitSampleApp/KarrotListKitSampleApp/Samples/VerticalLayout/VerticalLayoutItemComponent.swift +++ b/Examples/KarrotListKitSampleApp/KarrotListKitSampleApp/Samples/VerticalLayout/VerticalLayoutItemComponent.swift @@ -23,8 +23,4 @@ struct VerticalLayoutItemComponent: Component { func render(in content: VerticalLayoutItemView, coordinator: ()) { content.viewModel = viewModel } - - var layoutMode: ContentLayoutMode { - .flexibleHeight(estimatedHeight: 54.0) - } } diff --git a/Examples/KarrotListKitSampleApp/KarrotListKitSampleApp/Samples/VerticalLayout/VerticalLayoutListView.swift b/Examples/KarrotListKitSampleApp/KarrotListKitSampleApp/Samples/VerticalLayout/VerticalLayoutListView.swift index 4fd0e78..b436c57 100644 --- a/Examples/KarrotListKitSampleApp/KarrotListKitSampleApp/Samples/VerticalLayout/VerticalLayoutListView.swift +++ b/Examples/KarrotListKitSampleApp/KarrotListKitSampleApp/Samples/VerticalLayout/VerticalLayoutListView.swift @@ -76,7 +76,21 @@ final class VerticalLayoutListView: UIView { ) } } - .withSectionLayout(.vertical) + .withSectionLayout { context in + let size = NSCollectionLayoutSize( + widthDimension: .fractionalWidth(1.0), + heightDimension: .estimated(44.0) + ) + let item = NSCollectionLayoutItem( + layoutSize: size + ) + let group = NSCollectionLayoutGroup.vertical( + layoutSize: size, + subitems: [item] + ) + + return NSCollectionLayoutSection(group: group) + } }.onRefresh { [weak self] _ in self?.resetViewModels() }.onReachEnd(offsetFromEnd: .relativeToContainerSize(multiplier: 1.0)) { [weak self] _ in diff --git a/README.md b/README.md index d4d9f22..3ff744f 100644 --- a/README.md +++ b/README.md @@ -81,10 +81,6 @@ struct ButtonComponent: Component { func render(in content: Button, coordinator: Coordinator) { content.configure(viewModel: viewModel) } - - var layoutMode: ContentLayoutMode { - .flexibleHeight(estimatedHeight: 44.0) - } } ``` @@ -114,7 +110,20 @@ let list = List { } .withHeader(ButtonComponent(viewModel: .init(title: "Header"))) .withFooter(ButtonComponent(viewModel: .init(title: "Footer"))) - .withSectionLayout(.vertical(spacing: 12.0)) + .withSectionLayout { context in + let size = NSCollectionLayoutSize( + widthDimension: .fractionalWidth(1.0), + heightDimension: .estimated(44.0) + ) + let item = NSCollectionLayoutItem( + layoutSize: size + ) + let group = NSCollectionLayoutGroup.vertical( + layoutSize: size, + subitems: [item] + ) + return NSCollectionLayoutSection(group: group) + } } collectionViewAdapter.apply( @@ -147,9 +156,6 @@ The size of a View is actually adjusted when the View is displayed on the screen struct ButtonComponent: Component { typealias Content = Button // ... - var layoutMode: ContentLayoutMode { - .flexibleHeight(estimatedHeight: 44.0) - } } final class Button: UIControl { diff --git a/Sources/KarrotListKit/Adapter/CollectionViewAdapter.swift b/Sources/KarrotListKit/Adapter/CollectionViewAdapter.swift index 6e65ba3..6466636 100644 --- a/Sources/KarrotListKit/Adapter/CollectionViewAdapter.swift +++ b/Sources/KarrotListKit/Adapter/CollectionViewAdapter.swift @@ -41,8 +41,6 @@ final public class CollectionViewAdapter: NSObject { completion: (() -> Void)? )? - private var componentSizeStorage: ComponentSizeStorage = ComponentSizeStorageImpl() - var list: List? private lazy var pullToRefreshControl: UIRefreshControl = { @@ -351,10 +349,6 @@ extension CollectionViewAdapter: CollectionViewLayoutAdapterDataSource { public func sectionItem(at index: Int) -> Section? { list?.sections[safe: index] } - - public func sizeStorage() -> ComponentSizeStorage { - componentSizeStorage - } } // MARK: - UICollectionViewDelegate @@ -697,12 +691,6 @@ extension CollectionViewAdapter: UICollectionViewDataSource { return UICollectionViewCell() } - cell.onSizeChanged = { [weak self] size in - self?.componentSizeStorage.setCellSize( - (size, item.component.viewModel), - for: item.id - ) - } cell.cancellables = prefetchingIndexPathOperations.removeValue(forKey: indexPath) cell.render(component: item.component) @@ -731,12 +719,6 @@ extension CollectionViewAdapter: UICollectionViewDataSource { return UICollectionReusableView() } - headerView.onSizeChanged = { [weak self] size in - self?.componentSizeStorage.setHeaderSize( - (size, header.component.viewModel), - for: section.id - ) - } headerView.render(component: header.component) return headerView @@ -757,12 +739,6 @@ extension CollectionViewAdapter: UICollectionViewDataSource { return UICollectionReusableView() } - footerView.onSizeChanged = { [weak self] size in - self?.componentSizeStorage.setFooterSize( - (size, footer.component.viewModel), - for: section.id - ) - } footerView.render(component: footer.component) return footerView diff --git a/Sources/KarrotListKit/Adapter/CollectionViewLayoutAdaptable.swift b/Sources/KarrotListKit/Adapter/CollectionViewLayoutAdaptable.swift index e0009aa..0d068c8 100644 --- a/Sources/KarrotListKit/Adapter/CollectionViewLayoutAdaptable.swift +++ b/Sources/KarrotListKit/Adapter/CollectionViewLayoutAdaptable.swift @@ -17,10 +17,6 @@ public protocol CollectionViewLayoutAdapterDataSource: AnyObject { /// - Parameter index: The index of the section to return. /// - Returns: The section at the index. func sectionItem(at index: Int) -> Section? - - /// Returns the ComponentSizeStorage that managing the cached size information. - /// - Returns: The ComponentSizeStorage that managing the cached size information. - func sizeStorage() -> ComponentSizeStorage } /// The `CollectionViewLayoutAdaptable` interface serves as an adapter between the UICollectionViewCompositionalLayout logic and the `KarrotListKit` layout logic @@ -83,8 +79,7 @@ public class CollectionViewLayoutAdapter: CollectionViewLayoutAdaptable { return sectionItem.layout( index: index, - environment: environment, - sizeStorage: dataSource.sizeStorage() + environment: environment ) } } diff --git a/Sources/KarrotListKit/Adapter/ComponentSizeStorage.swift b/Sources/KarrotListKit/Adapter/ComponentSizeStorage.swift deleted file mode 100644 index fb8e8a2..0000000 --- a/Sources/KarrotListKit/Adapter/ComponentSizeStorage.swift +++ /dev/null @@ -1,81 +0,0 @@ -// -// Copyright (c) 2024 Danggeun Market Inc. -// - -import Foundation - -/// A protocol that defines the functionality for storing the sizes of components. -public protocol ComponentSizeStorage { - - /// A typealias for a tuple containing a CGSize and AnyViewModel. - typealias SizeContext = (size: CGSize, viewModel: AnyViewModel) - - /// Retrieves the size of a cell. - /// - Parameter hash: The hash value of the cell. - /// - Returns: The size context of the cell. - func cellSize(for hash: AnyHashable) -> SizeContext? - - /// Retrieves the size of a header. - /// - Parameter hash: The hash value of the header. - /// - Returns: The size context of the header. - func headerSize(for hash: AnyHashable) -> SizeContext? - - /// Retrieves the size of a footer. - /// - Parameter hash: The hash value of the footer. - /// - Returns: The size context of the footer. - func footerSize(for hash: AnyHashable) -> SizeContext? - - /// Sets the size of a cell. - /// - Parameters: - /// - size: The size context to set. - /// - hash: The hash value of the cell. - func setCellSize(_ size: SizeContext, for hash: AnyHashable) - - /// Sets the size of a header. - /// - Parameters: - /// - size: The size context to set. - /// - hash: The hash value of the header. - func setHeaderSize(_ size: SizeContext, for hash: AnyHashable) - - /// Sets the size of a footer. - /// - Parameters: - /// - size: The size context to set. - /// - hash: The hash value of the footer. - func setFooterSize(_ size: SizeContext, for hash: AnyHashable) -} - -final class ComponentSizeStorageImpl: ComponentSizeStorage { - - /// A dictionary to store the sizes of cells. - var cellSizeStore = [AnyHashable: SizeContext]() - - /// A dictionary to store the sizes of headers. - var headerSizeStore = [AnyHashable: SizeContext]() - - /// A dictionary to store the sizes of footers. - var footerSizeStore = [AnyHashable: SizeContext]() - - func cellSize(for hash: AnyHashable) -> SizeContext? { - cellSizeStore[hash] - } - - func headerSize(for hash: AnyHashable) -> SizeContext? { - headerSizeStore[hash] - } - - func footerSize(for hash: AnyHashable) -> SizeContext? { - footerSizeStore[hash] - } - - func setCellSize(_ size: SizeContext, for hash: AnyHashable) { - cellSizeStore[hash] = size - } - - func setHeaderSize(_ size: SizeContext, for hash: AnyHashable) { - headerSizeStore[hash] = size - } - - func setFooterSize(_ size: SizeContext, for hash: AnyHashable) { - footerSizeStore[hash] = size - } -} diff --git a/Sources/KarrotListKit/Component/AnyComponent.swift b/Sources/KarrotListKit/Component/AnyComponent.swift index 5a356d3..6b18d74 100644 --- a/Sources/KarrotListKit/Component/AnyComponent.swift +++ b/Sources/KarrotListKit/Component/AnyComponent.swift @@ -36,11 +36,6 @@ public struct AnyComponent: Component, Equatable { box.base } - /// The layout mode of the component's content. - public var layoutMode: ContentLayoutMode { - box.layoutMode - } - /// A reuse identifier for the component. public var reuseIdentifier: String { box.reuseIdentifier @@ -116,7 +111,6 @@ private protocol ComponentBox { var base: Base { get } var reuseIdentifier: String { get } - var layoutMode: ContentLayoutMode { get } var viewModel: Base.ViewModel { get } func renderContent(coordinator: Any) -> UIView @@ -135,10 +129,6 @@ private struct AnyComponentBox: ComponentBox { baseComponent.viewModel } - var layoutMode: ContentLayoutMode { - baseComponent.layoutMode - } - var baseComponent: Base var base: Base { diff --git a/Sources/KarrotListKit/Component/Component.swift b/Sources/KarrotListKit/Component/Component.swift index 5f43abe..95c1f65 100644 --- a/Sources/KarrotListKit/Component/Component.swift +++ b/Sources/KarrotListKit/Component/Component.swift @@ -26,9 +26,6 @@ public protocol Component { /// A reuse identifier for the component. var reuseIdentifier: String { get } - /// The layout mode of the component's content. - var layoutMode: ContentLayoutMode { get } - /// Creates the content object and configures its initial state. /// /// - Parameter coordinator: The coordinator to use for rendering the content. diff --git a/Sources/KarrotListKit/Component/ContentLayoutMode.swift b/Sources/KarrotListKit/Component/ContentLayoutMode.swift deleted file mode 100644 index 551b8f6..0000000 --- a/Sources/KarrotListKit/Component/ContentLayoutMode.swift +++ /dev/null @@ -1,30 +0,0 @@ -// -// Copyright (c) 2024 Danggeun Market Inc. -// - -import Foundation - -/// An enumeration that defines how a `Component`'s content should be laid out in a `UICollectionView`. -public enum ContentLayoutMode: Equatable { - - /// The content's width and height are adjusted to fit the size of the parent container. - case fitContainer - - /// The content's width is determined by the parent container, and its height is adjusted to fit the size of the content itself. - /// An estimated height is provided for use before the actual height is calculated. - /// - /// - Parameter estimatedHeight: The estimated height of the content. - case flexibleHeight(estimatedHeight: CGFloat) - - /// The content's height is determined by the parent container, and its width is adjusted to fit the size of the content itself. - /// An estimated width is provided for use before the actual width is calculated. - /// - /// - Parameter estimatedWidth: The estimated width of the content. - case flexibleWidth(estimatedWidth: CGFloat) - - /// Both the content's width and height are adjusted to fit the size of the content itself. - /// An estimated size is provided for use before the actual size is calculated. - /// - /// - Parameter estimatedSize: The estimated size of the content. - case fitContent(estimatedSize: CGSize) -} diff --git a/Sources/KarrotListKit/Layout/CompositionalLayoutSectionFactory.swift b/Sources/KarrotListKit/Layout/CompositionalLayoutSectionFactory.swift index c71a7f5..bff255d 100644 --- a/Sources/KarrotListKit/Layout/CompositionalLayoutSectionFactory.swift +++ b/Sources/KarrotListKit/Layout/CompositionalLayoutSectionFactory.swift @@ -15,8 +15,7 @@ public protocol CompositionalLayoutSectionFactory { typealias LayoutContext = ( section: Section, index: Int, - environment: NSCollectionLayoutEnvironment, - sizeStorage: ComponentSizeStorage + environment: NSCollectionLayoutEnvironment ) /// A type that represents a layout closure for section. @@ -26,171 +25,4 @@ public protocol CompositionalLayoutSectionFactory { /// /// - Returns: layout closure for section func makeSectionLayout() -> SectionLayout? - - /// Make layout items for cells. - /// - /// - Parameters: - /// - cells: cells for size calculation - /// - sizeStorage: The storage that cached size of the cell component. - /// - Returns: layout items for cells - func layoutCellItems(cells: [Cell], sizeStorage: ComponentSizeStorage) -> [NSCollectionLayoutItem] - - /// Make layout item for a section header. - /// - /// - Parameters: - /// - section: The section that contains header - /// - sizeStorage: The storage that cached size of the header component. - /// - Returns: layout item for header - func layoutHeaderItem(section: Section, sizeStorage: ComponentSizeStorage) - -> NSCollectionLayoutBoundarySupplementaryItem? - - /// Make layout item for a section footer. - /// - /// - Parameters: - /// - section: The section that contains footer - /// - sizeStorage: The storage that cached size of the footer component. - /// - Returns: layout item for footer - func layoutFooterItem(section: Section, sizeStorage: ComponentSizeStorage) - -> NSCollectionLayoutBoundarySupplementaryItem? -} - -extension CompositionalLayoutSectionFactory { - - /// Default Implementation factory method for cells - /// - /// - Parameters: - /// - cells: cells for size calculation - /// - sizeStorage: The storage that cached size of the cell component. - /// - Returns: layout items for cells - public func layoutCellItems(cells: [Cell], sizeStorage: ComponentSizeStorage) -> [NSCollectionLayoutItem] { - cells.map { - if let sizeContext = sizeStorage.cellSize(for: $0.id), - sizeContext.viewModel == $0.component.viewModel { - return NSCollectionLayoutItem(layoutSize: makeLayoutSize( - mode: $0.component.layoutMode, - size: sizeContext.size - )) - } else { - return NSCollectionLayoutItem( - layoutSize: makeLayoutSize(mode: $0.component.layoutMode) - ) - } - } - } - - /// Default Implementation factory method for header - /// - /// - Parameters: - /// - section: The section that contains header - /// - sizeStorage: The storage that cached size of the header component. - /// - Returns: layout item for header - public func layoutHeaderItem( - section: Section, - sizeStorage: ComponentSizeStorage - ) -> NSCollectionLayoutBoundarySupplementaryItem? { - guard let header = section.header else { - return nil - } - - if let sizeContext = sizeStorage.headerSize(for: section.id), - sizeContext.viewModel == header.component.viewModel { - return NSCollectionLayoutBoundarySupplementaryItem( - layoutSize: makeLayoutSize( - mode: header.component.layoutMode, - size: sizeContext.size - ), - elementKind: header.kind, - alignment: header.alignment - ) - } else { - return NSCollectionLayoutBoundarySupplementaryItem( - layoutSize: makeLayoutSize(mode: header.component.layoutMode), - elementKind: header.kind, - alignment: header.alignment - ) - } - } - - /// Default Implementation factory method for footer - /// - /// - Parameters: - /// - section: The section that contains footer - /// - sizeStorage: The storage that cached size of the footer component. - /// - Returns: layout item for footer - public func layoutFooterItem( - section: Section, - sizeStorage: ComponentSizeStorage - ) -> NSCollectionLayoutBoundarySupplementaryItem? { - guard let footer = section.footer else { - return nil - } - - if let sizeContext = sizeStorage.footerSize(for: section.id), - sizeContext.viewModel == footer.component.viewModel { - return NSCollectionLayoutBoundarySupplementaryItem( - layoutSize: makeLayoutSize( - mode: footer.component.layoutMode, - size: sizeContext.size - ), - elementKind: footer.kind, - alignment: footer.alignment - ) - } else { - return NSCollectionLayoutBoundarySupplementaryItem( - layoutSize: makeLayoutSize(mode: footer.component.layoutMode), - elementKind: footer.kind, - alignment: footer.alignment - ) - } - } - - private func makeLayoutSize(mode: ContentLayoutMode) -> NSCollectionLayoutSize { - switch mode { - case .fitContainer: - return .init( - widthDimension: .fractionalWidth(1.0), - heightDimension: .fractionalHeight(1.0) - ) - case .flexibleWidth(let estimatedWidth): - return .init( - widthDimension: .estimated(estimatedWidth), - heightDimension: .fractionalHeight(1.0) - ) - case .flexibleHeight(let estimatedHeight): - return .init( - widthDimension: .fractionalWidth(1.0), - heightDimension: .estimated(estimatedHeight) - ) - case .fitContent(let estimatedSize): - return .init( - widthDimension: .estimated(estimatedSize.width), - heightDimension: .estimated(estimatedSize.height) - ) - } - } - - private func makeLayoutSize(mode: ContentLayoutMode, size: CGSize) -> NSCollectionLayoutSize { - switch mode { - case .fitContainer: - return .init( - widthDimension: .fractionalWidth(1.0), - heightDimension: .fractionalHeight(1.0) - ) - case .flexibleWidth: - return .init( - widthDimension: .estimated(size.width), - heightDimension: .fractionalHeight(1.0) - ) - case .flexibleHeight: - return .init( - widthDimension: .fractionalWidth(1.0), - heightDimension: .estimated(size.height) - ) - case .fitContent: - return .init( - widthDimension: .estimated(size.width), - heightDimension: .estimated(size.height) - ) - } - } } diff --git a/Sources/KarrotListKit/Layout/DefaultCompositionalLayoutSectionFactory.swift b/Sources/KarrotListKit/Layout/DefaultCompositionalLayoutSectionFactory.swift deleted file mode 100644 index ba53dbb..0000000 --- a/Sources/KarrotListKit/Layout/DefaultCompositionalLayoutSectionFactory.swift +++ /dev/null @@ -1,153 +0,0 @@ -// -// Copyright (c) 2024 Danggeun Market Inc. -// - -import UIKit - -/// This object provides default layout factories -/// -/// You can use the default layouts to implement easily and quickly different styles layout -/// If you need to create a custom layout, implement an object that conform `CompositionalLayoutSectionFactory`. -public struct DefaultCompositionalLayoutSectionFactory: CompositionalLayoutSectionFactory { - - /// The LayoutSpec enum defines the type of layouts that can be provided. - public enum LayoutSpec { - - /// A vertical layout with specified spacing. - case vertical(spacing: CGFloat) - - /// A horizontal layout with specified spacing and scrolling behavior. - case horizontal( - spacing: CGFloat, - scrollingBehavior: UICollectionLayoutSectionOrthogonalScrollingBehavior - ) - - /// A vertical grid layout with specified number of items in a row, item spacing, and line spacing. - case verticalGrid(numberOfItemsInRow: Int, itemSpacing: CGFloat, lineSpacing: CGFloat) - } - - private let spec: LayoutSpec - - /// Creates a vertical layout - public static var vertical: Self = .init(spec: .vertical(spacing: 0)) - - /// Creates a horizontal layout - public static var horizontal: Self = .init(spec: .horizontal(spacing: 0, scrollingBehavior: .continuous)) - - /// Creates a vertical layout with specified spacing. - /// - Parameter spacing: The spacing between items in the layout. Default value is `0.0`. - public static func vertical(spacing: CGFloat) -> Self { - .init(spec: .vertical(spacing: spacing)) - } - - /// Creates a horizontal layout. - /// - Parameters: - /// - spacing: The spacing between items in the layout. Default value is 0.0. - /// - scrollingBehavior: The behavior of the layout when scrolling. Default value is .continuous. - public static func horizontal( - spacing: CGFloat, - scrollingBehavior: UICollectionLayoutSectionOrthogonalScrollingBehavior = .continuous - ) -> Self { - .init(spec: .horizontal(spacing: spacing, scrollingBehavior: scrollingBehavior)) - } - - /// Creates a vertical grid layout. - /// - Parameters: - /// - numberOfItemsInRow: The number of items in a row. - /// - itemSpacing: The spacing between items in the layout. - /// - lineSpacing: The spacing between lines in the layout. - public static func verticalGrid( - numberOfItemsInRow: Int, - itemSpacing: CGFloat, - lineSpacing: CGFloat - ) -> Self { - .init( - spec: .verticalGrid( - numberOfItemsInRow: numberOfItemsInRow, - itemSpacing: itemSpacing, - lineSpacing: lineSpacing - ) - ) - } - - private var sectionContentInsets: NSDirectionalEdgeInsets? - private var headerPinToVisibleBounds: Bool? - private var footerPinToVisibleBounds: Bool? - private var visibleItemsInvalidationHandler: NSCollectionLayoutSectionVisibleItemsInvalidationHandler? - - /// Creates a section layout based on the specified layout spec. - /// - /// - Returns: layout closure for section - public func makeSectionLayout() -> SectionLayout? { - switch spec { - case .vertical(let spacing): - return VerticalLayout(spacing: spacing) - .insets(sectionContentInsets) - .headerPinToVisibleBounds(headerPinToVisibleBounds) - .footerPinToVisibleBounds(footerPinToVisibleBounds) - .withVisibleItemsInvalidationHandler(visibleItemsInvalidationHandler) - .makeSectionLayout() - case .horizontal(let spacing, let scrollingBehavior): - return HorizontalLayout(spacing: spacing, scrollingBehavior: scrollingBehavior) - .insets(sectionContentInsets) - .headerPinToVisibleBounds(headerPinToVisibleBounds) - .footerPinToVisibleBounds(footerPinToVisibleBounds) - .withVisibleItemsInvalidationHandler(visibleItemsInvalidationHandler) - .makeSectionLayout() - case .verticalGrid(let numberOfItemsInRow, let itemSpacing, let lineSpacing): - return VerticalGridLayout( - numberOfItemsInRow: numberOfItemsInRow, - itemSpacing: itemSpacing, - lineSpacing: lineSpacing - ) - .insets(sectionContentInsets) - .headerPinToVisibleBounds(headerPinToVisibleBounds) - .footerPinToVisibleBounds(footerPinToVisibleBounds) - .withVisibleItemsInvalidationHandler(visibleItemsInvalidationHandler) - .makeSectionLayout() - } - } - - /// Sets the insets for the section. - /// - /// - Parameters: - /// - insets: insets for section - public func withSectionContentInsets(_ insets: NSDirectionalEdgeInsets) -> Self { - var copy = self - copy.sectionContentInsets = insets - return copy - } - - /// Sets whether the header should pin to visible bounds. - /// - /// - Parameters: - /// - pinToVisibleBounds: A Boolean value that indicates whether a header is pinned to the top - public func withHeaderPinToVisibleBounds(_ pinToVisibleBounds: Bool) -> Self { - var copy = self - copy.headerPinToVisibleBounds = pinToVisibleBounds - return copy - } - - /// Sets whether the footer should pin to visible bounds. - /// - /// - Parameters: - /// - pinToVisibleBounds: A Boolean value that indicates whether a footer is pinned to the bottom - public func withFooterPinToVisibleBounds(_ pinToVisibleBounds: Bool) -> Self { - var copy = self - copy.footerPinToVisibleBounds = pinToVisibleBounds - return copy - } - - /// Sets the handler for invalidating visible items. - /// - /// - Parameters: - /// - handler: visible items invalidation handler - public func withVisibleItemsInvalidationHandler( - _ visibleItemsInvalidationHandler: NSCollectionLayoutSectionVisibleItemsInvalidationHandler? - ) - -> Self { - var copy = self - copy.visibleItemsInvalidationHandler = visibleItemsInvalidationHandler - return copy - } -} diff --git a/Sources/KarrotListKit/Layout/HorizontalLayout.swift b/Sources/KarrotListKit/Layout/HorizontalLayout.swift deleted file mode 100644 index d3025d4..0000000 --- a/Sources/KarrotListKit/Layout/HorizontalLayout.swift +++ /dev/null @@ -1,116 +0,0 @@ -// -// Copyright (c) 2024 Danggeun Market Inc. -// - -import UIKit - -/// This layout supports horizontal scrolling. -/// -/// If the width and height of the Cell are both fit to the size of the content, this layout can be used to horizontal scrolling style UI. -/// - Note: when using a horizontal layout, the layout mode of the component must be Fit Content. -public struct HorizontalLayout: CompositionalLayoutSectionFactory { - - private let spacing: CGFloat - private let scrollingBehavior: UICollectionLayoutSectionOrthogonalScrollingBehavior - private var sectionInsets: NSDirectionalEdgeInsets? - private var headerPinToVisibleBounds: Bool? - private var footerPinToVisibleBounds: Bool? - private var visibleItemsInvalidationHandler: NSCollectionLayoutSectionVisibleItemsInvalidationHandler? - - /// Initializes a new horizontal layout. - /// - Parameters: - /// - spacing: The spacing between items in the layout. Default value is 0.0. - /// - scrollingBehavior: The behavior of the layout when scrolling. Default value is .continuous. - public init( - spacing: CGFloat = 0.0, - scrollingBehavior: UICollectionLayoutSectionOrthogonalScrollingBehavior = .continuous - ) { - self.spacing = spacing - self.scrollingBehavior = scrollingBehavior - } - - /// Creates a layout for a section. - public func makeSectionLayout() -> SectionLayout? { - { context -> NSCollectionLayoutSection? in - let group = NSCollectionLayoutGroup.horizontal( - layoutSize: .init( - widthDimension: .estimated(context.environment.container.contentSize.width), - heightDimension: .estimated(context.environment.container.contentSize.height) - ), - subitems: layoutCellItems(cells: context.section.cells, sizeStorage: context.sizeStorage) - ) - group.interItemSpacing = .fixed(spacing) - - - let section = NSCollectionLayoutSection(group: group) - if let sectionInsets { - section.contentInsets = sectionInsets - } - - if let visibleItemsInvalidationHandler { - section.visibleItemsInvalidationHandler = visibleItemsInvalidationHandler - } - - section.orthogonalScrollingBehavior = scrollingBehavior - - let headerItem = layoutHeaderItem(section: context.section, sizeStorage: context.sizeStorage) - if let headerPinToVisibleBounds { - headerItem?.pinToVisibleBounds = headerPinToVisibleBounds - } - - let footerItem = layoutFooterItem(section: context.section, sizeStorage: context.sizeStorage) - if let footerPinToVisibleBounds { - footerItem?.pinToVisibleBounds = footerPinToVisibleBounds - } - - section.boundarySupplementaryItems = [ - headerItem, - footerItem, - ].compactMap { $0 } - - return section - } - } - - /// Sets the insets for the section. - /// - /// - Parameters: - /// - insets: insets for section - public func insets(_ insets: NSDirectionalEdgeInsets?) -> Self { - var copy = self - copy.sectionInsets = insets - return copy - } - - /// Sets whether the header should pin to visible bounds. - /// - /// - Parameters: - /// - pinToVisibleBounds: A Boolean value that indicates whether a header is pinned to the top - public func headerPinToVisibleBounds(_ pinToVisibleBounds: Bool?) -> Self { - var copy = self - copy.headerPinToVisibleBounds = pinToVisibleBounds - return copy - } - - /// Sets whether the footer should pin to visible bounds. - /// - /// - Parameters: - /// - pinToVisibleBounds: A Boolean value that indicates whether a footer is pinned to the bottom - public func footerPinToVisibleBounds(_ pinToVisibleBounds: Bool?) -> Self { - var copy = self - copy.footerPinToVisibleBounds = pinToVisibleBounds - return copy - } - - /// Sets the handler for invalidating visible items. - /// - /// - Parameters: - /// - handler: visible items invalidation handler - public func withVisibleItemsInvalidationHandler( - _ handler: NSCollectionLayoutSectionVisibleItemsInvalidationHandler? - ) -> Self { - var copy = self - copy.visibleItemsInvalidationHandler = handler - return copy - } -} diff --git a/Sources/KarrotListKit/Layout/VerticalGridLayout.swift b/Sources/KarrotListKit/Layout/VerticalGridLayout.swift deleted file mode 100644 index 975e19c..0000000 --- a/Sources/KarrotListKit/Layout/VerticalGridLayout.swift +++ /dev/null @@ -1,144 +0,0 @@ -// -// Copyright (c) 2024 Danggeun Market Inc. -// - -import UIKit - -/// This layout supports grid-style vertical scrolling. -/// -/// If the number of Cells to be displayed in a row is specified, This layout makes it easy to implement. -/// - Note: when using a vertical grid layout, the layout mode of the component must be Flexible High. -public struct VerticalGridLayout: CompositionalLayoutSectionFactory { - - private let numberOfItemsInRow: Int - private let itemSpacing: CGFloat - private let lineSpacing: CGFloat - private var sectionInsets: NSDirectionalEdgeInsets? - private var headerPinToVisibleBounds: Bool? - private var footerPinToVisibleBounds: Bool? - private var visibleItemsInvalidationHandler: NSCollectionLayoutSectionVisibleItemsInvalidationHandler? - - /// Initializes a new vertical grid layout. - /// - Parameters: - /// - numberOfItemsInRow: The number of items in a row. - /// - itemSpacing: The spacing between items in the layout. - /// - lineSpacing: The spacing between lines in the layout. - public init( - numberOfItemsInRow: Int, - itemSpacing: CGFloat, - lineSpacing: CGFloat - ) { - self.numberOfItemsInRow = numberOfItemsInRow - self.itemSpacing = itemSpacing - self.lineSpacing = lineSpacing - } - - /// Creates a layout for a section. - public func makeSectionLayout() -> SectionLayout? { - { context -> NSCollectionLayoutSection? in - var verticalGroupHeight: CGFloat = 0 - let horizontalGroups = context.section.cells.chunks(ofCount: numberOfItemsInRow).map { chunkedCells in - let horizontalGroupHeight = layoutCellItems(cells: Array(chunkedCells), sizeStorage: context.sizeStorage) - .max { layout1, layout2 in - layout1.layoutSize.heightDimension.dimension < layout2.layoutSize.heightDimension.dimension - }?.layoutSize.heightDimension ?? .estimated(context.environment.container.contentSize.height) - - verticalGroupHeight += horizontalGroupHeight.dimension - - let layoutGroup = NSCollectionLayoutGroup.horizontal( - layoutSize: .init( - widthDimension: .fractionalWidth(1.0), - heightDimension: horizontalGroupHeight - ), - subitem: NSCollectionLayoutItem( - layoutSize: .init( - widthDimension: .fractionalWidth(1.0 / CGFloat(numberOfItemsInRow)), - heightDimension: horizontalGroupHeight - ) - ), - count: numberOfItemsInRow - ) - layoutGroup.interItemSpacing = .fixed(itemSpacing) - - return layoutGroup - } - - let group = NSCollectionLayoutGroup.vertical( - layoutSize: .init( - widthDimension: .fractionalWidth(1.0), - heightDimension: .estimated(verticalGroupHeight) - ), - subitems: horizontalGroups - ) - group.interItemSpacing = .fixed(lineSpacing) - - let section = NSCollectionLayoutSection(group: group) - if let sectionInsets { - section.contentInsets = sectionInsets - } - - if let visibleItemsInvalidationHandler { - section.visibleItemsInvalidationHandler = visibleItemsInvalidationHandler - } - - let headerItem = layoutHeaderItem(section: context.section, sizeStorage: context.sizeStorage) - if let headerPinToVisibleBounds { - headerItem?.pinToVisibleBounds = headerPinToVisibleBounds - } - - let footerItem = layoutFooterItem(section: context.section, sizeStorage: context.sizeStorage) - if let footerPinToVisibleBounds { - footerItem?.pinToVisibleBounds = footerPinToVisibleBounds - } - - section.boundarySupplementaryItems = [ - headerItem, - footerItem, - ].compactMap { $0 } - - return section - } - } - - /// Sets the insets for the section. - /// - /// - Parameters: - /// - insets: insets for section - public func insets(_ insets: NSDirectionalEdgeInsets?) -> Self { - var copy = self - copy.sectionInsets = insets - return copy - } - - /// Sets whether the header should pin to visible bounds. - /// - /// - Parameters: - /// - pinToVisibleBounds: A Boolean value that indicates whether a header is pinned to the top - public func headerPinToVisibleBounds(_ pinToVisibleBounds: Bool?) -> Self { - var copy = self - copy.headerPinToVisibleBounds = pinToVisibleBounds - return copy - } - - /// Sets whether the footer should pin to visible bounds. - /// - /// - Parameters: - /// - pinToVisibleBounds: A Boolean value that indicates whether a footer is pinned to the bottom - public func footerPinToVisibleBounds(_ pinToVisibleBounds: Bool?) -> Self { - var copy = self - copy.footerPinToVisibleBounds = pinToVisibleBounds - return copy - } - - /// Sets the handler for invalidating visible items. - /// - /// - Parameters: - /// - handler: visible items invalidation handler - public func withVisibleItemsInvalidationHandler( - _ handler: NSCollectionLayoutSectionVisibleItemsInvalidationHandler? - ) -> Self { - var copy = self - copy.visibleItemsInvalidationHandler = handler - return copy - } -} diff --git a/Sources/KarrotListKit/Layout/VerticalLayout.swift b/Sources/KarrotListKit/Layout/VerticalLayout.swift deleted file mode 100644 index 394924f..0000000 --- a/Sources/KarrotListKit/Layout/VerticalLayout.swift +++ /dev/null @@ -1,106 +0,0 @@ -// -// Copyright (c) 2024 Danggeun Market Inc. -// - -import UIKit - -/// This layout supports vertical scrolling. -/// -/// If the width of the Cell is the same as the width of the CollectionView and the height is fit to the size of the content, this layout can be used to vertical scrolling style UI. -/// - Note: when using a vertical layout, the layout mode of the component must be Flexible High. -public struct VerticalLayout: CompositionalLayoutSectionFactory { - - private let spacing: CGFloat - private var sectionInsets: NSDirectionalEdgeInsets? - private var headerPinToVisibleBounds: Bool? - private var footerPinToVisibleBounds: Bool? - private var visibleItemsInvalidationHandler: NSCollectionLayoutSectionVisibleItemsInvalidationHandler? - - /// Initializes a new vertical layout. - /// - Parameter spacing: The spacing between items in the layout. Default value is `0.0`. - public init(spacing: CGFloat = 0.0) { - self.spacing = spacing - } - - /// Creates a layout for a section. - public func makeSectionLayout() -> SectionLayout? { - { context -> NSCollectionLayoutSection? in - let group = NSCollectionLayoutGroup.vertical( - layoutSize: .init( - widthDimension: .fractionalWidth(1.0), - heightDimension: .estimated(context.environment.container.contentSize.height) - ), - subitems: layoutCellItems(cells: context.section.cells, sizeStorage: context.sizeStorage) - ) - group.interItemSpacing = .fixed(spacing) - - let section = NSCollectionLayoutSection(group: group) - if let sectionInsets { - section.contentInsets = sectionInsets - } - - if let visibleItemsInvalidationHandler { - section.visibleItemsInvalidationHandler = visibleItemsInvalidationHandler - } - - let headerItem = layoutHeaderItem(section: context.section, sizeStorage: context.sizeStorage) - if let headerPinToVisibleBounds { - headerItem?.pinToVisibleBounds = headerPinToVisibleBounds - } - - let footerItem = layoutFooterItem(section: context.section, sizeStorage: context.sizeStorage) - if let footerPinToVisibleBounds { - footerItem?.pinToVisibleBounds = footerPinToVisibleBounds - } - - section.boundarySupplementaryItems = [ - headerItem, - footerItem, - ].compactMap { $0 } - - return section - } - } - - /// Sets the insets for the section. - /// - /// - Parameters: - /// - insets: insets for section - public func insets(_ insets: NSDirectionalEdgeInsets?) -> Self { - var copy = self - copy.sectionInsets = insets - return copy - } - - /// Sets whether the header should pin to visible bounds. - /// - /// - Parameters: - /// - pinToVisibleBounds: A Boolean value that indicates whether a header is pinned to the top - public func headerPinToVisibleBounds(_ pinToVisibleBounds: Bool?) -> Self { - var copy = self - copy.headerPinToVisibleBounds = pinToVisibleBounds - return copy - } - - /// Sets whether the footer should pin to visible bounds. - /// - /// - Parameters: - /// - pinToVisibleBounds: A Boolean value that indicates whether a footer is pinned to the bottom - public func footerPinToVisibleBounds(_ pinToVisibleBounds: Bool?) -> Self { - var copy = self - copy.footerPinToVisibleBounds = pinToVisibleBounds - return copy - } - - /// Sets the handler for invalidating visible items. - /// - /// - Parameters: - /// - handler: visible items invalidation handler - public func withVisibleItemsInvalidationHandler( - _ handler: NSCollectionLayoutSectionVisibleItemsInvalidationHandler? - ) -> Self { - var copy = self - copy.visibleItemsInvalidationHandler = handler - return copy - } -} diff --git a/Sources/KarrotListKit/Section.swift b/Sources/KarrotListKit/Section.swift index 9b2011b..203e58d 100644 --- a/Sources/KarrotListKit/Section.swift +++ b/Sources/KarrotListKit/Section.swift @@ -81,16 +81,6 @@ public struct Section: Identifiable, ListingViewEventHandler { return copy } - /// The modifier that sets the layout for the Section. - /// - /// - Parameters: - /// - defaultLayoutMaker: The basic layout factory provided by the framework. - public func withSectionLayout(_ defaultLayoutMaker: DefaultCompositionalLayoutSectionFactory) -> Self { - var copy = self - copy.sectionLayout = defaultLayoutMaker.makeSectionLayout() - return copy - } - /// The modifier that sets the Header for the Section. /// /// - Parameters: @@ -129,14 +119,13 @@ public struct Section: Identifiable, ListingViewEventHandler { func layout( index: Int, - environment: NSCollectionLayoutEnvironment, - sizeStorage: ComponentSizeStorage + environment: NSCollectionLayoutEnvironment ) -> NSCollectionLayoutSection? { if sectionLayout == nil { assertionFailure("Please specify a valid section layout") } - return sectionLayout?((self, index, environment, sizeStorage)) + return sectionLayout?((self, index, environment)) } } diff --git a/Sources/KarrotListKit/View/UICollectionComponentReusableView.swift b/Sources/KarrotListKit/View/UICollectionComponentReusableView.swift index e855cfa..3c635f2 100644 --- a/Sources/KarrotListKit/View/UICollectionComponentReusableView.swift +++ b/Sources/KarrotListKit/View/UICollectionComponentReusableView.swift @@ -12,8 +12,6 @@ final class UICollectionComponentReusableView: UICollectionReusableView, Compone var renderedComponent: AnyComponent? - var onSizeChanged: ((CGSize) -> Void)? - private var previousBounds: CGSize = .zero // MARK: - Initializing @@ -71,10 +69,6 @@ final class UICollectionComponentReusableView: UICollectionReusableView, Compone let size = renderedContent.sizeThatFits(bounds.size) - if renderedComponent != nil { - onSizeChanged?(size) - } - attributes.frame.size = size return attributes diff --git a/Sources/KarrotListKit/View/UICollectionViewComponentCell.swift b/Sources/KarrotListKit/View/UICollectionViewComponentCell.swift index 03f08ba..7b85b09 100644 --- a/Sources/KarrotListKit/View/UICollectionViewComponentCell.swift +++ b/Sources/KarrotListKit/View/UICollectionViewComponentCell.swift @@ -15,8 +15,6 @@ public final class UICollectionViewComponentCell: UICollectionViewCell, Componen var cancellables: [AnyCancellable]? - var onSizeChanged: ((CGSize) -> Void)? - private var previousBounds: CGSize = .zero // MARK: - Initializing @@ -80,10 +78,6 @@ public final class UICollectionViewComponentCell: UICollectionViewCell, Componen let size = renderedContent.sizeThatFits(contentView.bounds.size) - if renderedComponent != nil { - onSizeChanged?(size) - } - attributes.frame.size = size return attributes diff --git a/Tests/KarrotListKitTests/AnyComponentTests.swift b/Tests/KarrotListKitTests/AnyComponentTests.swift index 6b43611..ace7fc0 100644 --- a/Tests/KarrotListKitTests/AnyComponentTests.swift +++ b/Tests/KarrotListKitTests/AnyComponentTests.swift @@ -14,7 +14,6 @@ final class AnyComponentTests: XCTestCase { let anyComponent = AnyComponent(component) // when & then - XCTAssertEqual(component.layoutMode, anyComponent.layoutMode) XCTAssertEqual(component.reuseIdentifier, anyComponent.reuseIdentifier) } diff --git a/Tests/KarrotListKitTests/CollectionViewAdapterTests.swift b/Tests/KarrotListKitTests/CollectionViewAdapterTests.swift index 52561ac..935700f 100644 --- a/Tests/KarrotListKitTests/CollectionViewAdapterTests.swift +++ b/Tests/KarrotListKitTests/CollectionViewAdapterTests.swift @@ -20,8 +20,9 @@ final class CollectionViewAdapterTests: XCTestCase { final class CollectionViewMock: UICollectionView { + private let _window = UIWindow() override var window: UIWindow? { - .init() + _window } var contentSizeHandler: (() -> CGSize)? @@ -1173,122 +1174,6 @@ extension CollectionViewAdapterTests { } } -// MARK: - SizeStorage - -extension CollectionViewAdapterTests { - - func test_given_dequeued_cell_when_calculate_size_then_store_size() { - // given - let cellID = UUID() - let collectionView = CollectionViewMock(layoutAdapter: CollectionViewLayoutAdapter()) - var component = ComponentStub() - component.viewModelStub = .init() - let viewStub = ViewStub() - viewStub.sizeThatFitsStub = CGSize(width: 44.0, height: 44.0) - component.contentStub = viewStub - let sut = sut(collectionView: collectionView) - sut.apply( - List { - Section(id: UUID()) { - Cell(id: cellID, component: component) - } - } - ) - - let cell = collectionView - .dataSource? - .collectionView( - collectionView, - cellForItemAt: IndexPath(item: 0, section: 0) - ) as! UICollectionViewComponentCell - - // when - _ = cell.preferredLayoutAttributesFitting( - UICollectionViewLayoutAttributes(forCellWith: IndexPath(item: 0, section: 0)) - ) - - // then - XCTAssertEqual( - sut.sizeStorage().cellSize(for: cellID)?.size, - CGSize(width: 44.0, height: 44.0) - ) - } - - func test_given_dequeued_header_when_calculate_size_then_store_size() { - // given - let sectionID = UUID() - let collectionView = CollectionViewMock(layoutAdapter: CollectionViewLayoutAdapter()) - var component = ComponentStub() - component.viewModelStub = .init() - let viewStub = ViewStub() - viewStub.sizeThatFitsStub = CGSize(width: 44.0, height: 44.0) - component.contentStub = viewStub - let sut = sut(collectionView: collectionView) - sut.apply( - List { - Section(id: sectionID, cells: []) - .withHeader(component) - } - ) - - let header = collectionView - .dataSource? - .collectionView?( - collectionView, - viewForSupplementaryElementOfKind: UICollectionView.elementKindSectionHeader, - at: IndexPath(item: 0, section: 0) - ) as! UICollectionComponentReusableView - - // when - _ = header.preferredLayoutAttributesFitting( - UICollectionViewLayoutAttributes(forCellWith: IndexPath(item: 0, section: 0)) - ) - - // then - XCTAssertEqual( - sut.sizeStorage().headerSize(for: sectionID)?.size, - CGSize(width: 44.0, height: 44.0) - ) - } - - func test_given_dequeued_footer_when_calculate_size_then_store_size() { - // given - let sectionID = UUID() - let collectionView = CollectionViewMock(layoutAdapter: CollectionViewLayoutAdapter()) - var component = ComponentStub() - component.viewModelStub = .init() - let viewStub = ViewStub() - viewStub.sizeThatFitsStub = CGSize(width: 44.0, height: 44.0) - component.contentStub = viewStub - let sut = sut(collectionView: collectionView) - sut.apply( - List { - Section(id: sectionID, cells: []) - .withFooter(component) - } - ) - let header = collectionView - .dataSource? - .collectionView?( - collectionView, - viewForSupplementaryElementOfKind: UICollectionView.elementKindSectionFooter, - at: IndexPath(item: 0, section: 0) - ) as! UICollectionComponentReusableView - - // when - _ = header.preferredLayoutAttributesFitting( - UICollectionViewLayoutAttributes(forCellWith: IndexPath(item: 0, section: 0)) - ) - - // then - XCTAssertEqual( - sut.sizeStorage().footerSize(for: sectionID)?.size, - CGSize(width: 44.0, height: 44.0) - ) - } -} - - // MARK: - Reached End Event Trigger extension CollectionViewAdapterTests { diff --git a/Tests/KarrotListKitTests/CollectionViewLayoutAdapterTests.swift b/Tests/KarrotListKitTests/CollectionViewLayoutAdapterTests.swift index 8158f6b..d696da3 100644 --- a/Tests/KarrotListKitTests/CollectionViewLayoutAdapterTests.swift +++ b/Tests/KarrotListKitTests/CollectionViewLayoutAdapterTests.swift @@ -16,38 +16,12 @@ final class CollectionViewLayoutAdapterTests: XCTestCase { var traitCollection: UITraitCollection { .init() } } - final class ComponentSizeStorageDummy: ComponentSizeStorage { - - func cellSize(for hash: AnyHashable) -> SizeContext? { - nil - } - - func headerSize(for hash: AnyHashable) -> SizeContext? { - nil - } - - func footerSize(for hash: AnyHashable) -> SizeContext? { - nil - } - - func setCellSize(_ size: SizeContext, for hash: AnyHashable) {} - - func setHeaderSize(_ size: SizeContext, for hash: AnyHashable) {} - - func setFooterSize(_ size: SizeContext, for hash: AnyHashable) {} - } - final class CollectionViewLayoutAdapterDataSourceStub: CollectionViewLayoutAdapterDataSource { var section: Section? func sectionItem(at index: Int) -> Section? { section } - - var sizeStorageStub: ComponentSizeStorage! - func sizeStorage() -> ComponentSizeStorage { - sizeStorageStub - } } func sut() -> CollectionViewLayoutAdapter { @@ -123,7 +97,6 @@ extension CollectionViewLayoutAdapterTests { func test_given_valid_section_when_sectionLayout_then_return_sectionLayout() { let dataSource = CollectionViewLayoutAdapterDataSourceStub() - dataSource.sizeStorageStub = ComponentSizeStorageDummy() dataSource.section = Section( id: UUID(), cells: [Cell(id: UUID(), component: DummyComponent())] diff --git a/Tests/KarrotListKitTests/ComponentTests.swift b/Tests/KarrotListKitTests/ComponentTests.swift index aa85299..7cc5152 100644 --- a/Tests/KarrotListKitTests/ComponentTests.swift +++ b/Tests/KarrotListKitTests/ComponentTests.swift @@ -12,7 +12,6 @@ final class ComponentTests: XCTestCase { struct ViewModel: Equatable {} typealias Content = UIView typealias Coordinator = Void - var layoutMode: ContentLayoutMode { fatalError() } var viewModel: ViewModel = .init() func renderContent(coordinator: Coordinator) -> UIView { fatalError() } func render(in content: UIView, coordinator: Coordinator) { fatalError() } diff --git a/Tests/KarrotListKitTests/ResultBuildersTests.swift b/Tests/KarrotListKitTests/ResultBuildersTests.swift index 3b7441d..2af9ea5 100644 --- a/Tests/KarrotListKitTests/ResultBuildersTests.swift +++ b/Tests/KarrotListKitTests/ResultBuildersTests.swift @@ -12,7 +12,6 @@ final class ResultBuildersTests: XCTestCase { struct ViewModel: Equatable {} typealias Content = UIView typealias Coordinator = Void - var layoutMode: ContentLayoutMode { fatalError() } var viewModel: ViewModel = .init() func renderContent(coordinator: Coordinator) -> UIView { fatalError() } func render(in content: UIView, coordinator: Coordinator) { fatalError() } diff --git a/Tests/KarrotListKitTests/TestDoubles/ComponentTestDouble.swift b/Tests/KarrotListKitTests/TestDoubles/ComponentTestDouble.swift index 751e97a..4c81aa9 100644 --- a/Tests/KarrotListKitTests/TestDoubles/ComponentTestDouble.swift +++ b/Tests/KarrotListKitTests/TestDoubles/ComponentTestDouble.swift @@ -13,10 +13,6 @@ struct DummyComponent: Component, ComponentResourcePrefetchable { typealias Content = UIView typealias Coordinator = Void - var layoutMode: ContentLayoutMode { - .flexibleHeight(estimatedHeight: 44.0) - } - var viewModel: ViewModel = .init() func renderContent(coordinator: Coordinator) -> UIView { @@ -38,12 +34,6 @@ struct ComponentStub: Component { var viewModel: ViewModel { viewModelStub } - - var layoutMode: ContentLayoutMode { - layoutModeStub - } - - var layoutModeStub: ContentLayoutMode! var viewModelStub: ViewModel! var contentStub: UIView! @@ -67,10 +57,6 @@ class ComponentSpy: Component { .init() } - var layoutMode: ContentLayoutMode { - .fitContainer - } - var renderContentCallCount = 0 func renderContent(coordinator: Coordinator) -> UIView { renderContentCallCount += 1