diff --git a/CHANGELOG.md b/CHANGELOG.md index e8216cdc..f99da122 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ### 1.27.0 - **Add**: Tag like filter collection view +- **ADD**: List like filter table view ### 1.26.0 diff --git a/TIEcommerce/Sources/Filters/FiltersCollectionCell/Models/FilterCellStateAppearance.swift b/TIEcommerce/Sources/Filters/Cells/Models/FilterCellStateAppearance.swift similarity index 89% rename from TIEcommerce/Sources/Filters/FiltersCollectionCell/Models/FilterCellStateAppearance.swift rename to TIEcommerce/Sources/Filters/Cells/Models/FilterCellStateAppearance.swift index 785fbced..ef80c2e1 100644 --- a/TIEcommerce/Sources/Filters/FiltersCollectionCell/Models/FilterCellStateAppearance.swift +++ b/TIEcommerce/Sources/Filters/Cells/Models/FilterCellStateAppearance.swift @@ -20,6 +20,7 @@ // THE SOFTWARE. // +import TIUIKitCore import UIKit public struct FilterCellStateAppearance { @@ -32,12 +33,15 @@ public struct FilterCellStateAppearance { public let contentInsets: UIEdgeInsets public let cornerRadius: CGFloat + public let stateImages: UIControl.StateImages? + public init(borderColor: UIColor, backgroundColor: UIColor, fontColor: UIColor, borderWidth: CGFloat, contentInsets: UIEdgeInsets = .init(top: 4, left: 8, bottom: 4, right: 8), - cornerRadius: CGFloat = 6) { + cornerRadius: CGFloat = 6, + stateImages: UIControl.StateImages? = nil) { self.borderColor = borderColor self.backgroundColor = backgroundColor @@ -45,5 +49,6 @@ public struct FilterCellStateAppearance { self.borderWidth = borderWidth self.contentInsets = contentInsets self.cornerRadius = cornerRadius + self.stateImages = stateImages } } diff --git a/TIEcommerce/Sources/Filters/FiltersCollectionCell/Models/FilterCellViewModelProtocol.swift b/TIEcommerce/Sources/Filters/Cells/Protocols/FilterCellViewModelProtocol.swift similarity index 100% rename from TIEcommerce/Sources/Filters/FiltersCollectionCell/Models/FilterCellViewModelProtocol.swift rename to TIEcommerce/Sources/Filters/Cells/Protocols/FilterCellViewModelProtocol.swift diff --git a/TIEcommerce/Sources/Filters/FiltersCollectionCell/ViewModels/DefaultFilterCellViewModel.swift b/TIEcommerce/Sources/Filters/Cells/ViewModels/DefaultFilterCellViewModel.swift similarity index 100% rename from TIEcommerce/Sources/Filters/FiltersCollectionCell/ViewModels/DefaultFilterCellViewModel.swift rename to TIEcommerce/Sources/Filters/Cells/ViewModels/DefaultFilterCellViewModel.swift diff --git a/TIEcommerce/Sources/Filters/FiltersCollectionView/Models/DefaultFilterPropertyValue.swift b/TIEcommerce/Sources/Filters/FilterModels/DefaultFilterPropertyValue.swift similarity index 100% rename from TIEcommerce/Sources/Filters/FiltersCollectionView/Models/DefaultFilterPropertyValue.swift rename to TIEcommerce/Sources/Filters/FilterModels/DefaultFilterPropertyValue.swift diff --git a/TIEcommerce/Sources/Filters/FiltersCollectionView/Protocols/FilterPropertyValueRepresenter.swift b/TIEcommerce/Sources/Filters/FilterModels/Protocols/FilterPropertyValueRepresenter.swift similarity index 100% rename from TIEcommerce/Sources/Filters/FiltersCollectionView/Protocols/FilterPropertyValueRepresenter.swift rename to TIEcommerce/Sources/Filters/FilterModels/Protocols/FilterPropertyValueRepresenter.swift diff --git a/TIEcommerce/Sources/Filters/FiltersCollectionView/ViewModels/BaseFilterViewModel.swift b/TIEcommerce/Sources/Filters/FiltersViewModel/BaseFilterViewModel.swift similarity index 96% rename from TIEcommerce/Sources/Filters/FiltersCollectionView/ViewModels/BaseFilterViewModel.swift rename to TIEcommerce/Sources/Filters/FiltersViewModel/BaseFilterViewModel.swift index a41f13fd..a56bc3a2 100644 --- a/TIEcommerce/Sources/Filters/FiltersCollectionView/ViewModels/BaseFilterViewModel.swift +++ b/TIEcommerce/Sources/Filters/FiltersViewModel/BaseFilterViewModel.swift @@ -42,6 +42,7 @@ open class BaseFilterViewModel: + UITableView, + InitializableViewProtocol, + Updatable, + UITableViewDelegate where CellType.ViewModelType: FilterCellViewModelProtocol & Hashable { + + public enum DefaultSection: String { + case main + } + + public typealias DataSource = UITableViewDiffableDataSource + public typealias Snapshot = NSDiffableDataSourceSnapshot + + public let viewModel: BaseFilterViewModel + + public lazy var tableViewDataSource = createDataSource() + + // MARK: - Init + + public init(viewModel: BaseFilterViewModel, + allowsMultipleSelection: Bool = true, + style: UITableView.Style = .plain) { + + self.viewModel = viewModel + + super.init(frame: .zero, style: style) + + self.allowsMultipleSelection = allowsMultipleSelection + + initializeView() + viewDidLoad() + } + + @available(*, unavailable) + required public init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + // MARK: - Life cycle + + open func addViews() { + // override in subclass + } + + open func configureLayout() { + // override in subclass + } + + open func bindViews() { + delegate = self + } + + open func configureAppearance() { + alwaysBounceVertical = false + } + + open func localize() { + // override in subclass + } + + open func viewDidLoad() { + registerCell() + + viewModel.filtersCollection = self + } + + open func viewDidAppear() { + applySnapshot() + } + + // MARK: - UITableViewDelegate + + public func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { + filterDidTapped(atIndexPath: indexPath) + } + + public func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) { + filterDidTapped(atIndexPath: indexPath) + } + + // MARK: - Updatable + + open func update() { + applySnapshot() + } + + // MARK: - Open methods + + open func registerCell() { + register(CellType.self, forCellReuseIdentifier: CellType.reuseIdentifier) + } + + open func filterDidTapped(atIndexPath indexPath: IndexPath) { + let changes = viewModel.filterDidSelected(atIndexPath: indexPath) + + applyChanges(changes) + } + + open func applySnapshot() { + var snapshot = Snapshot() + + snapshot.appendSections([DefaultSection.main.rawValue]) + snapshot.appendItems(viewModel.cellsViewModels, toSection: DefaultSection.main.rawValue) + + tableViewDataSource.apply(snapshot, animatingDifferences: true) + } + + open func createDataSource() -> DataSource { + let cellProvider: DataSource.CellProvider = { tableView, indexPath, itemIdentifier in + let cell = tableView.dequeueReusableCell(withIdentifier: CellType.reuseIdentifier, for: indexPath) as? CellType + + cell?.configure(with: itemIdentifier) + + return cell + } + + return .init(tableView: self, cellProvider: cellProvider) + } + + open func applyChanges(_ changes: [BaseFilterViewModel.Change]) { + changes.forEach { change in + guard let cell = cellForRow(at: change.indexPath) as? CellType else { + return + } + + cell.configure(with: change.viewModel) + + if let selectableCell = cell as? Selectable { + selectableCell.setSelected(change.viewModel.isSelected) + } + + change.viewModel.isSelected + ? selectRow(at: change.indexPath, animated: false, scrollPosition: ScrollPosition.none) + : deselectRow(at: change.indexPath, animated: false) + } + } +} diff --git a/TIEcommerce/Sources/Filters/FiltersViews/ListFilters/FiltersTableView/DefaultFilterTableView.swift b/TIEcommerce/Sources/Filters/FiltersViews/ListFilters/FiltersTableView/DefaultFilterTableView.swift new file mode 100644 index 00000000..94ec557d --- /dev/null +++ b/TIEcommerce/Sources/Filters/FiltersViews/ListFilters/FiltersTableView/DefaultFilterTableView.swift @@ -0,0 +1,24 @@ +// +// Copyright (c) 2022 Touch Instinct +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the Software), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +@available(iOS 13.0, *) +public typealias DefaultFiltersTableView = BaseFiltersTableView diff --git a/TIEcommerce/Sources/Filters/FiltersViews/ListFilters/FiltersTableViewCell/DefaultFilterTableViewCell.swift b/TIEcommerce/Sources/Filters/FiltersViews/ListFilters/FiltersTableViewCell/DefaultFilterTableViewCell.swift new file mode 100644 index 00000000..759c9270 --- /dev/null +++ b/TIEcommerce/Sources/Filters/FiltersViews/ListFilters/FiltersTableViewCell/DefaultFilterTableViewCell.swift @@ -0,0 +1,112 @@ +// +// Copyright (c) 2022 Touch Instinct +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the Software), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +import TISwiftUtils +import TIUIElements +import TIUIKitCore +import UIKit + +open class DefaultFilterTableViewCell: ContainerTableViewCell, ConfigurableView, Selectable { + + open var selectedStateAppearance: FilterCellStateAppearance { + .defaultSelectedRowAppearance + } + + open var normalStateAppearance: FilterCellStateAppearance { + .defaultRowAppearance + } + + open override var isSelected: Bool { + didSet { + let appearance = isSelected ? selectedStateAppearance : normalStateAppearance + updateAppearance(with: appearance) + wrappedView.setSelected(isSelected) + } + } + + // MARK: Life cycle + + open override func configureAppearance() { + super.configureAppearance() + + updateAppearance(with: normalStateAppearance) + } + + // MARK: - ConfigurableView + + open func configure(with viewModel: DefaultFilterCellViewModel) { + wrappedView.text = viewModel.title + } + + // MARK: - Open methods + + open func updateAppearance(with appearance: FilterCellStateAppearance) { + contentInsets = appearance.contentInsets + wrappedView.textColor = appearance.fontColor + wrappedView.images = appearance.stateImages ?? [:] + + backgroundColor = appearance.backgroundColor + layer.borderColor = appearance.borderColor.cgColor + layer.borderWidth = appearance.borderWidth + layer.round(corners: .allCorners, radius: appearance.cornerRadius) + } +} + +extension FilterCellStateAppearance { + + @available(iOS 13, *) + private static let defaultStateImages: UIControl.StateImages = [.normal: nil, + .selected: UIImage(systemName: "checkmark")] + private static let defaultContentInsets = UIEdgeInsets(top: 16, left: 8, bottom: 16, right: 8) + + static var defaultSelectedRowAppearance: FilterCellStateAppearance { + var stateImages: UIControl.StateImages? + + if #available(iOS 13, *) { + stateImages = defaultStateImages + } + + return .init(borderColor: .clear, + backgroundColor: .white, + fontColor: .black, + borderWidth: .zero, + contentInsets: defaultContentInsets, + cornerRadius: .zero, + stateImages: stateImages) + } + + static var defaultRowAppearance: FilterCellStateAppearance { + var stateImages: UIControl.StateImages? + + if #available(iOS 13, *) { + stateImages = defaultStateImages + } + + return .init(borderColor: .clear, + backgroundColor: .white, + fontColor: .black, + borderWidth: .zero, + contentInsets: defaultContentInsets, + cornerRadius: .zero, + stateImages: stateImages) + } +} diff --git a/TIEcommerce/Sources/Filters/FiltersViews/ListFilters/FiltersTableViewCell/DefaultPickerView.swift b/TIEcommerce/Sources/Filters/FiltersViews/ListFilters/FiltersTableViewCell/DefaultPickerView.swift new file mode 100644 index 00000000..a0bdff15 --- /dev/null +++ b/TIEcommerce/Sources/Filters/FiltersViews/ListFilters/FiltersTableViewCell/DefaultPickerView.swift @@ -0,0 +1,92 @@ +// +// Copyright (c) 2022 Touch Instinct +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the Software), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +import TIUIElements +import TIUIKitCore +import TISwiftUtils +import UIKit + +open class DefaultPickerView: BaseInitializableView, Selectable { + + private let titleLabel = UILabel() + private let selectionStateImageView = UIImageView() + + open var images: UIControl.StateImages = [:] { + didSet { + if images.contains(where: { $0.key == .highlighted }) { + selectionStateImageView.highlightedImage = images[.highlighted] ?? nil + } + } + } + + open var text: String? { + get { + titleLabel.text + } + set { + titleLabel.text = newValue + } + } + + open var textColor: UIColor { + get { + titleLabel.textColor + } + set { + titleLabel.textColor = newValue + } + } + + open var isSelected: Bool = false { + didSet { + selectionStateImageView.image = images[isSelected ? .selected : .normal] ?? nil + } + } + + open var defaultImageSize: CGFloat { + 20 + } + + open override func addViews() { + super.addViews() + + addSubviews(titleLabel, selectionStateImageView) + } + + open override func configureLayout() { + super.configureLayout() + + titleLabel.translatesAutoresizingMaskIntoConstraints = false + selectionStateImageView.translatesAutoresizingMaskIntoConstraints = false + + NSLayoutConstraint.activate([ + titleLabel.leadingAnchor.constraint(equalTo: leadingAnchor), + titleLabel.centerYAnchor.constraint(equalTo: centerYAnchor), + titleLabel.heightAnchor.constraint(equalTo: heightAnchor), + + selectionStateImageView.trailingAnchor.constraint(equalTo: trailingAnchor), + selectionStateImageView.centerYAnchor.constraint(equalTo: centerYAnchor), + selectionStateImageView.heightAnchor.constraint(equalToConstant: defaultImageSize), + selectionStateImageView.widthAnchor.constraint(equalToConstant: defaultImageSize) + ]) + } +} diff --git a/TIEcommerce/Sources/Filters/FiltersCollectionCell/Views/DefaultFilterCollectionCell.swift b/TIEcommerce/Sources/Filters/FiltersViews/TagsFilters/FiltersCollectionCell/DefaultFilterCollectionCell.swift similarity index 100% rename from TIEcommerce/Sources/Filters/FiltersCollectionCell/Views/DefaultFilterCollectionCell.swift rename to TIEcommerce/Sources/Filters/FiltersViews/TagsFilters/FiltersCollectionCell/DefaultFilterCollectionCell.swift diff --git a/TIEcommerce/Sources/Filters/FiltersCollectionView/Helpers/UICollectionViewLayout+DefaultLayout.swift b/TIEcommerce/Sources/Filters/FiltersViews/TagsFilters/FiltersCollectionView/Helpers/UICollectionViewLayout+DefaultLayout.swift similarity index 100% rename from TIEcommerce/Sources/Filters/FiltersCollectionView/Helpers/UICollectionViewLayout+DefaultLayout.swift rename to TIEcommerce/Sources/Filters/FiltersViews/TagsFilters/FiltersCollectionView/Helpers/UICollectionViewLayout+DefaultLayout.swift diff --git a/TIEcommerce/Sources/Filters/FiltersCollectionView/Models/FiltersLayoutConfiguration.swift b/TIEcommerce/Sources/Filters/FiltersViews/TagsFilters/FiltersCollectionView/Models/FiltersLayoutConfiguration.swift similarity index 100% rename from TIEcommerce/Sources/Filters/FiltersCollectionView/Models/FiltersLayoutConfiguration.swift rename to TIEcommerce/Sources/Filters/FiltersViews/TagsFilters/FiltersCollectionView/Models/FiltersLayoutConfiguration.swift diff --git a/TIEcommerce/Sources/Filters/FiltersCollectionView/Views/BaseFiltersCollectionView.swift b/TIEcommerce/Sources/Filters/FiltersViews/TagsFilters/FiltersCollectionView/Views/BaseFiltersCollectionView.swift similarity index 96% rename from TIEcommerce/Sources/Filters/FiltersCollectionView/Views/BaseFiltersCollectionView.swift rename to TIEcommerce/Sources/Filters/FiltersViews/TagsFilters/FiltersCollectionView/Views/BaseFiltersCollectionView.swift index 832ffbd1..9fa9e155 100644 --- a/TIEcommerce/Sources/Filters/FiltersCollectionView/Views/BaseFiltersCollectionView.swift +++ b/TIEcommerce/Sources/Filters/FiltersViews/TagsFilters/FiltersCollectionView/Views/BaseFiltersCollectionView.swift @@ -68,14 +68,14 @@ open class BaseFiltersCollectionView.Change]) { + open func applyChanges(_ changes: [BaseFilterViewModel.Change]) { changes.forEach { change in guard let cell = cellForItem(at: change.indexPath) as? CellType else { return diff --git a/TIEcommerce/Sources/Filters/FiltersCollectionView/Views/DefaultFiltersCollectionView.swift b/TIEcommerce/Sources/Filters/FiltersViews/TagsFilters/FiltersCollectionView/Views/DefaultFiltersCollectionView.swift similarity index 100% rename from TIEcommerce/Sources/Filters/FiltersCollectionView/Views/DefaultFiltersCollectionView.swift rename to TIEcommerce/Sources/Filters/FiltersViews/TagsFilters/FiltersCollectionView/Views/DefaultFiltersCollectionView.swift diff --git a/TIEcommerce/Sources/Filters/Protocols/FiltersPickerDelegate.swift b/TIEcommerce/Sources/Filters/Protocols/FiltersPickerDelegate.swift new file mode 100644 index 00000000..af1a15ad --- /dev/null +++ b/TIEcommerce/Sources/Filters/Protocols/FiltersPickerDelegate.swift @@ -0,0 +1,25 @@ +// +// Copyright (c) 2022 Touch Instinct +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the Software), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +public protocol FiltersPickerDelegate: AnyObject { + func filters(didSelected filters: [FilterPropertyValueRepresenter]) +} diff --git a/TISwiftUtils/Sources/Protocols/Selectable.swift b/TISwiftUtils/Sources/Protocols/Selectable.swift new file mode 100644 index 00000000..f9dc585d --- /dev/null +++ b/TISwiftUtils/Sources/Protocols/Selectable.swift @@ -0,0 +1,33 @@ +// +// Copyright (c) 2022 Touch Instinct +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the Software), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +public protocol Selectable: AnyObject { + var isSelected: Bool { get set } + + func setSelected(_ isSelected: Bool) +} + +public extension Selectable { + func setSelected(_ isSelected: Bool) { + self.isSelected = isSelected + } +} diff --git a/TIUIElements/Sources/Wrappers/ContainerTableViewCell.swift b/TIUIElements/Sources/Wrappers/ContainerTableViewCell.swift index f22aed9e..3892e327 100644 --- a/TIUIElements/Sources/Wrappers/ContainerTableViewCell.swift +++ b/TIUIElements/Sources/Wrappers/ContainerTableViewCell.swift @@ -41,7 +41,7 @@ open class ContainerTableViewCell: BaseInitializableCell, WrappedV override open func addViews() { super.addViews() - addSubview(wrappedView) + contentView.addSubview(wrappedView) } override open func configureLayout() { diff --git a/TIUIKitCore/Sources/Protocols/ReuseIdentifierProtocol.swift b/TIUIKitCore/Sources/Protocols/ReuseIdentifierProtocol.swift index 46e7e17f..c0e04c2c 100644 --- a/TIUIKitCore/Sources/Protocols/ReuseIdentifierProtocol.swift +++ b/TIUIKitCore/Sources/Protocols/ReuseIdentifierProtocol.swift @@ -32,3 +32,9 @@ extension UICollectionViewCell: ReuseIdentifierProtocol { .init(describing: Self.self) } } + +extension UITableViewCell: ReuseIdentifierProtocol { + public static var reuseIdentifier: String { + .init(describing: Self.self) + } +}